OneBot: Leantime 改造版源码(BOM/Univer 表格/AI 接管/品牌替换等)
This commit is contained in:
489
app/Domain/Calendar/Js/calendarController.js
Normal file
489
app/Domain/Calendar/Js/calendarController.js
Normal file
@@ -0,0 +1,489 @@
|
||||
leantime.calendarController = (function () {
|
||||
|
||||
var closeModal = false;
|
||||
|
||||
// Latest todo-draggable initializer, refreshed on each initWidgetCalendar() call. The single
|
||||
// global htmx.onLoad handler (registered once) calls THIS, so reloading the calendar widget
|
||||
// rewires drag/drop to the current calendar instance instead of a stale closure.
|
||||
var latestTodoDraggableInit = null;
|
||||
|
||||
//Functions
|
||||
var initCalendar = function (userEvents) {
|
||||
|
||||
var date = new Date();
|
||||
var d = date.getDate();
|
||||
var m = date.getMonth();
|
||||
var y = date.getFullYear();
|
||||
|
||||
var heightWindow = jQuery("body").height() - 260;
|
||||
|
||||
var calendar = jQuery('#calendar').fullCalendar({
|
||||
timeZone: leantime.i18n.__("usersettings.timezone"),
|
||||
height: heightWindow,
|
||||
header: {
|
||||
left: 'prev,next today',
|
||||
center: 'title',
|
||||
right: 'month,agendaWeek,agendaDay,listDay'
|
||||
},
|
||||
titleFormat: {
|
||||
month: 'MMMM yyyy',
|
||||
week: "MMM d[ yyyy]{ '—'[ MMM] d yyyy}",
|
||||
day: 'dddd, MMM d, yyyy'
|
||||
},
|
||||
columnFormat: {
|
||||
month: leantime.i18n.__("language.columnFormatMonth"),
|
||||
week: leantime.i18n.__("language.columnFormatWeek"),
|
||||
day: leantime.i18n.__("language.columnFormatday")
|
||||
},
|
||||
timeFormat: { // for event elements
|
||||
'': leantime.dateHelper.getFormatFromSettings("timeformat", "luxon")
|
||||
},
|
||||
// locale
|
||||
isRTL: leantime.i18n.__("language.isRTL") == "false" ? 0 : 1,
|
||||
firstDay: leantime.i18n.__("language.firstDayOfWeek"),
|
||||
monthNames: leantime.i18n.__("language.monthNames").split(","),
|
||||
monthNamesShort: leantime.i18n.__("language.monthNamesShort").split(","),
|
||||
dayNames: leantime.i18n.__("language.dayNames").split(","),
|
||||
dayNamesShort: leantime.i18n.__("language.dayNamesShort").split(","),
|
||||
buttonText: {
|
||||
prev: '«',
|
||||
next: '»',
|
||||
prevYear: ' << ',
|
||||
nextYear: ' >> ',
|
||||
today: leantime.i18n.__("buttons.today"),
|
||||
month: leantime.i18n.__("buttons.month"),
|
||||
week: leantime.i18n.__("buttons.week"),
|
||||
day: leantime.i18n.__("buttons.day")
|
||||
},
|
||||
select: function (start, end, allDay) {
|
||||
var title = prompt(leantime.i18n.__("label.event_title"));
|
||||
if (title) {
|
||||
calendar.fullCalendar(
|
||||
'renderEvent',
|
||||
{
|
||||
title: title,
|
||||
start: start,
|
||||
end: end,
|
||||
allDay: allDay
|
||||
},
|
||||
true // make the event "stick"
|
||||
);
|
||||
}
|
||||
calendar.fullCalendar('unselect');
|
||||
},
|
||||
events: userEvents,
|
||||
eventColor: '#0866c6'
|
||||
});
|
||||
};
|
||||
|
||||
var initEventDatepickers = function () {
|
||||
|
||||
jQuery(document).ready(function () {
|
||||
|
||||
Date.prototype.addDays = function (days) {
|
||||
this.setDate(this.getDate() + days);
|
||||
return this;
|
||||
};
|
||||
jQuery.datepicker.setDefaults(
|
||||
{ beforeShow: function (i) {
|
||||
if (jQuery(i).attr('readonly')) {
|
||||
return false; } } }
|
||||
);
|
||||
|
||||
var dateFormat = leantime.dateHelper.getFormatFromSettings("dateformat", "jquery");
|
||||
|
||||
from = jQuery("#event_date_from")
|
||||
.datepicker(
|
||||
{
|
||||
numberOfMonths: 1,
|
||||
dateFormat: leantime.dateHelper.getFormatFromSettings("dateformat", "jquery"),
|
||||
dayNames: leantime.i18n.__("language.dayNames").split(","),
|
||||
dayNamesMin: leantime.i18n.__("language.dayNamesMin").split(","),
|
||||
dayNamesShort: leantime.i18n.__("language.dayNamesShort").split(","),
|
||||
monthNames: leantime.i18n.__("language.monthNames").split(","),
|
||||
currentText: leantime.i18n.__("language.currentText"),
|
||||
closeText: leantime.i18n.__("language.closeText"),
|
||||
buttonText: leantime.i18n.__("language.buttonText"),
|
||||
isRTL: leantime.i18n.__("language.isRTL") === "true" ? 1 : 0,
|
||||
nextText: leantime.i18n.__("language.nextText"),
|
||||
prevText: leantime.i18n.__("language.prevText"),
|
||||
weekHeader: leantime.i18n.__("language.weekHeader"),
|
||||
firstDay: leantime.i18n.__("language.firstDayOfWeek"),
|
||||
}
|
||||
)
|
||||
.on(
|
||||
"change",
|
||||
function (date) {
|
||||
to.datepicker("option", "minDate", getDate(this));
|
||||
|
||||
if (jQuery("#event_date_to").val() == '') {
|
||||
jQuery("#event_date_to").val(jQuery("#event_date_from").val());
|
||||
}
|
||||
}
|
||||
),
|
||||
|
||||
to = jQuery("#event_date_to").datepicker(
|
||||
{
|
||||
numberOfMonths: 1,
|
||||
dateFormat: leantime.dateHelper.getFormatFromSettings("dateformat", "jquery"),
|
||||
dayNames: leantime.i18n.__("language.dayNames").split(","),
|
||||
dayNamesMin: leantime.i18n.__("language.dayNamesMin").split(","),
|
||||
dayNamesShort: leantime.i18n.__("language.dayNamesShort").split(","),
|
||||
monthNames: leantime.i18n.__("language.monthNames").split(","),
|
||||
currentText: leantime.i18n.__("language.currentText"),
|
||||
closeText: leantime.i18n.__("language.closeText"),
|
||||
buttonText: leantime.i18n.__("language.buttonText"),
|
||||
isRTL: leantime.i18n.__("language.isRTL") === "true" ? 1 : 0,
|
||||
nextText: leantime.i18n.__("language.nextText"),
|
||||
prevText: leantime.i18n.__("language.prevText"),
|
||||
weekHeader: leantime.i18n.__("language.weekHeader"),
|
||||
firstDay: leantime.i18n.__("language.firstDayOfWeek"),
|
||||
}
|
||||
)
|
||||
.on(
|
||||
"change",
|
||||
function () {
|
||||
from.datepicker("option", "maxDate", getDate(this));
|
||||
}
|
||||
);
|
||||
|
||||
function getDate( element )
|
||||
{
|
||||
var date;
|
||||
try {
|
||||
date = jQuery.datepicker.parseDate(dateFormat, element.value);
|
||||
} catch ( error ) {
|
||||
date = null;
|
||||
console.log(error);
|
||||
}
|
||||
return date;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
};
|
||||
|
||||
var initExportModal = function () {
|
||||
|
||||
var exportModalConfig = {
|
||||
sizes: {
|
||||
minW: 400,
|
||||
minH: 350
|
||||
},
|
||||
resizable: true,
|
||||
autoSizable: true,
|
||||
callbacks: {
|
||||
afterShowCont: function () {
|
||||
|
||||
jQuery(".formModal").nyroModal(exportModalConfig);
|
||||
},
|
||||
beforeClose: function () {
|
||||
location.reload();
|
||||
}
|
||||
|
||||
|
||||
},
|
||||
titleFromIframe: true
|
||||
};
|
||||
jQuery(".exportModal").nyroModal(exportModalConfig);
|
||||
|
||||
}
|
||||
|
||||
var initWidgetCalendar = function (element, initialView) {
|
||||
|
||||
let calendarEl = document.querySelector(element);
|
||||
let userDateFormat = leantime.dateHelper.getFormatFromSettings("dateformat", "luxon");
|
||||
let userTimeFormat = leantime.dateHelper.getFormatFromSettings("timeformat", "luxon");
|
||||
|
||||
|
||||
const calendar = new FullCalendar.Calendar(calendarEl, {
|
||||
timeZone: leantime.i18n.__("usersettings.timezone"),
|
||||
height: 'calc(100% - 65px)',
|
||||
stickyHeaderDates: true,
|
||||
initialView: initialView,
|
||||
eventStartEditable: true,
|
||||
dayHeaderFormat: userDateFormat,
|
||||
eventTimeFormat: userTimeFormat,
|
||||
slotLabelFormat: userTimeFormat,
|
||||
firstDay: leantime.i18n.__("language.firstDayOfWeek"),
|
||||
views: {
|
||||
multiMonthOneMonth: {
|
||||
type: 'multiMonth',
|
||||
duration: {months: 1},
|
||||
multiMonthTitleFormat: {month: 'long', year: 'numeric'},
|
||||
dayHeaderFormat: {weekday: 'short'},
|
||||
},
|
||||
timeGridDay: {
|
||||
dayHeaders: false
|
||||
},
|
||||
listWeek: {
|
||||
listDayFormat: {weekday: 'long'},
|
||||
listDaySideFormat: leantime.dateHelper.getFormatFromSettings("dateformat", "luxon"),
|
||||
}
|
||||
},
|
||||
droppable: true,
|
||||
eventSources: eventSources,
|
||||
|
||||
editable: true,
|
||||
headerToolbar: false,
|
||||
nowIndicator: true,
|
||||
bootstrapFontAwesome: {
|
||||
close: 'fa-times',
|
||||
prev: 'fa-chevron-left',
|
||||
next: 'fa-chevron-right',
|
||||
prevYear: 'fa-angle-double-left',
|
||||
nextYear: 'fa-angle-double-right'
|
||||
},
|
||||
eventDrop: function (event) {
|
||||
if (event.event.extendedProps.enitityType == "ticket") {
|
||||
leantime.rpc('Tickets.Tickets.patchTicket', {
|
||||
id: event.event.extendedProps.enitityId,
|
||||
values: {
|
||||
editFrom: luxon.DateTime.fromJSDate(event.event.start).toFormat(userDateFormat),
|
||||
timeFrom: luxon.DateTime.fromJSDate(event.event.start).toFormat(userTimeFormat),
|
||||
editTo: luxon.DateTime.fromJSDate(event.event.end).toFormat(userDateFormat),
|
||||
timeTo: luxon.DateTime.fromJSDate(event.event.end).toFormat(userTimeFormat),
|
||||
}
|
||||
}).catch(function (error) {
|
||||
jQuery.growl({ message: (error && error.message) ? error.message : leantime.i18n.__("short_notifications.not_saved"), style: "error" });
|
||||
event.revert();
|
||||
console.error('Could not update ticket dates', error);
|
||||
});
|
||||
} else if (event.event.extendedProps.enitityType == "event") {
|
||||
leantime.rpc('Calendar.Calendar.patch', {
|
||||
id: event.event.extendedProps.enitityId,
|
||||
params: {
|
||||
dateFrom: event.event.startStr,
|
||||
dateTo: event.event.endStr
|
||||
}
|
||||
}).then(function (success) {
|
||||
// Denied/failed update resolves to false — undo the visual move.
|
||||
if (! success) { event.revert(); }
|
||||
}).catch(function (error) {
|
||||
console.error('Could not update event dates', error);
|
||||
event.revert();
|
||||
})
|
||||
}
|
||||
},
|
||||
eventResize: function (event) {
|
||||
if (event.event.extendedProps.enitityType == "ticket") {
|
||||
leantime.rpc('Tickets.Tickets.patchTicket', {
|
||||
id: event.event.extendedProps.enitityId,
|
||||
values: {
|
||||
editFrom: luxon.DateTime.fromJSDate(event.event.start).toFormat(userDateFormat),
|
||||
timeFrom: luxon.DateTime.fromJSDate(event.event.start).toFormat(userTimeFormat),
|
||||
editTo: luxon.DateTime.fromJSDate(event.event.end).toFormat(userDateFormat),
|
||||
timeTo: luxon.DateTime.fromJSDate(event.event.end).toFormat(userTimeFormat),
|
||||
}
|
||||
}).catch(function (error) {
|
||||
jQuery.growl({ message: (error && error.message) ? error.message : leantime.i18n.__("short_notifications.not_saved"), style: "error" });
|
||||
event.revert();
|
||||
console.error('Could not update ticket dates', error);
|
||||
});
|
||||
} else if (event.event.extendedProps.enitityType == "event") {
|
||||
leantime.rpc('Calendar.Calendar.patch', {
|
||||
id: event.event.extendedProps.enitityId,
|
||||
params: {
|
||||
dateFrom: event.event.startStr,
|
||||
dateTo: event.event.endStr
|
||||
}
|
||||
}).then(function (success) {
|
||||
// Denied/failed update resolves to false — undo the visual move.
|
||||
if (! success) { event.revert(); }
|
||||
}).catch(function (error) {
|
||||
console.error('Could not update event dates', error);
|
||||
event.revert();
|
||||
})
|
||||
}
|
||||
|
||||
},
|
||||
eventReceive: function (event) {
|
||||
|
||||
leantime.rpc('Tickets.Tickets.patchTicket', {
|
||||
id: event.event.id,
|
||||
values: {
|
||||
editFrom: luxon.DateTime.fromJSDate(event.event.start).toFormat(userDateFormat),
|
||||
timeFrom: luxon.DateTime.fromJSDate(event.event.start).toFormat(userTimeFormat),
|
||||
editTo: luxon.DateTime.fromJSDate(event.event.end).toFormat(userDateFormat),
|
||||
timeTo: luxon.DateTime.fromJSDate(event.event.end).toFormat(userTimeFormat),
|
||||
}
|
||||
}).catch(function (error) {
|
||||
jQuery.growl({ message: (error && error.message) ? error.message : leantime.i18n.__("short_notifications.not_saved"), style: "error" });
|
||||
event.revert();
|
||||
console.error('Could not update ticket dates', error);
|
||||
});
|
||||
|
||||
},
|
||||
eventDragStart: function (event) {
|
||||
|
||||
},
|
||||
eventDidMount: function (info) {
|
||||
|
||||
if (info.isDraggable === false) {
|
||||
jQuery(info.el).addClass("locked");
|
||||
}
|
||||
|
||||
if (info.event.extendedProps.location != null
|
||||
&& info.event.extendedProps.location != ""
|
||||
&& info.event.extendedProps.location.indexOf("http") == 0
|
||||
) {
|
||||
//jQuery(info.el).prepend("<div class='pull-right'><a href='"+info.event.extendedProps.location+"'>Join Call</a></div>")
|
||||
jQuery(info.el).attr("href", info.event.extendedProps.location);
|
||||
jQuery(info.el).attr("target", "_blank");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
jQuery(document).ready(function () {
|
||||
//let tickets = jQuery("#yourToDoContainer")[0];
|
||||
|
||||
// Set up draggable for each ticket box
|
||||
// setupDraggableTickets();
|
||||
//
|
||||
// Initialize the ThirdPartyDraggable for the todo container
|
||||
|
||||
if(jQuery("#yourToDoContainer").length > 0) {
|
||||
initializeThirdPartyDraggable(jQuery("#yourToDoContainer")[0]);
|
||||
}
|
||||
|
||||
initButtons();
|
||||
|
||||
calendar.scrollToTime(Date.now());
|
||||
|
||||
|
||||
});
|
||||
|
||||
// function setupDraggableTickets() {
|
||||
// jQuery("#yourToDoContainer").find(".ticketBox").each(function () {
|
||||
// setupTicketDraggable(jQuery(this));
|
||||
// });
|
||||
// }
|
||||
//
|
||||
// function setupTicketDraggable(ticketElement) {
|
||||
// var currentTicket = ticketElement;
|
||||
// currentTicket.data('event', {
|
||||
// id: currentTicket.attr("data-val"),
|
||||
// title: currentTicket.find(".titleContainer strong").text(),
|
||||
// color: 'var(--accent2)',
|
||||
// enitityType: "ticket",
|
||||
// url: '#/tickets/showTicket/' + currentTicket.attr("data-val"),
|
||||
// });
|
||||
//
|
||||
// currentTicket.draggable({
|
||||
//
|
||||
// zIndex: 999999,
|
||||
// revert: true, // will cause the event to go back to its
|
||||
// revertDuration: 0, // original position after the drag
|
||||
// helper: "clone",
|
||||
// appendTo: '.maincontent',
|
||||
// cursor: "grab",
|
||||
// cursorAt: {bottom: 5, right: 5},
|
||||
// distance: 10, // Minimum distance before drag starts
|
||||
// delay: 150, // Small delay to allow for sortable to initialize first
|
||||
// });
|
||||
// }
|
||||
|
||||
function initializeThirdPartyDraggable(element) {
|
||||
|
||||
var tickets = element;
|
||||
if (tickets) {
|
||||
new FullCalendar.ThirdPartyDraggable(tickets, {
|
||||
itemSelector: '.draggable-todo',
|
||||
mirrorClass: 'dragging-mirror',
|
||||
eventDragMinDistance: 10,
|
||||
mirrorSelector: function (el) {
|
||||
return el.closest('.ticketBox');
|
||||
},
|
||||
eventData: function (eventEl) {
|
||||
|
||||
let ticketEventData = jQuery(eventEl).data("event");
|
||||
|
||||
return {
|
||||
id: ticketEventData.id,
|
||||
title: ticketEventData.title,
|
||||
color: ticketEventData.color,
|
||||
enitityType: "ticket",
|
||||
duration: '01:00',
|
||||
url: ticketEventData.url,
|
||||
};
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
calendar.scrollToTime(Date.now());
|
||||
};
|
||||
|
||||
// Point the shared reference at THIS init's closure (bound to the current calendar instance).
|
||||
latestTodoDraggableInit = initializeThirdPartyDraggable;
|
||||
|
||||
function initButtons() {
|
||||
|
||||
calendar.setOption('locale', leantime.i18n.__("language.code"));
|
||||
calendar.render();
|
||||
|
||||
calendar.scrollToTime(Date.now());
|
||||
|
||||
jQuery('.minCalendar .fc-prev-button').click(function () {
|
||||
calendar.prev();
|
||||
calendar.getCurrentData()
|
||||
});
|
||||
jQuery('.minCalendar .fc-next-button').click(function () {
|
||||
calendar.next();
|
||||
});
|
||||
jQuery('.minCalendar .fc-today-button').click(function () {
|
||||
calendar.today();
|
||||
});
|
||||
jQuery(".minCalendar .calendarViewSelect").on("click", function (e) {
|
||||
|
||||
var newView = jQuery(this).data("value");
|
||||
calendar.changeView(newView);
|
||||
|
||||
// Show the day selector only in day view
|
||||
if (newView === 'timeGridDay') {
|
||||
jQuery('.day-selector').show();
|
||||
} else {
|
||||
jQuery('.day-selector').hide();
|
||||
}
|
||||
|
||||
leantime.rpc('Api.Api.setSubmenuState', {
|
||||
submenu: "dashboardCalendarView",
|
||||
state: newView
|
||||
}).catch(function (e) { console.error('Could not update submenu state', e); });
|
||||
|
||||
});
|
||||
|
||||
// Initialize day selector buttons (only active in day view)
|
||||
jQuery('.day-button').on('click', function() {
|
||||
var date = jQuery(this).data('date');
|
||||
calendar.gotoDate(date);
|
||||
|
||||
// Update active state
|
||||
jQuery('.day-button').removeClass('active');
|
||||
jQuery(this).addClass('active');
|
||||
});
|
||||
}
|
||||
|
||||
// Register once. This runs inside an init function that HTMX re-invokes on every
|
||||
// swap, so without the guard each load stacked another global onLoad handler
|
||||
// (handler leak → compounding churn on the dashboard).
|
||||
if (!window.leantime._calendarTodoOnLoadRegistered) {
|
||||
window.leantime._calendarTodoOnLoadRegistered = true;
|
||||
htmx.onLoad(function (content) {
|
||||
// Find any todo containers that were loaded via HTMX. Call the LATEST initializer so
|
||||
// drag/drop binds to the current calendar instance, not the one from first init.
|
||||
if (content.id == "yourToDoContainer" && latestTodoDraggableInit) {
|
||||
latestTodoDraggableInit(content);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Make public what you want to have public, everything else is private
|
||||
return {
|
||||
initCalendar:initCalendar,
|
||||
initEventDatepickers:initEventDatepickers,
|
||||
initExportModal:initExportModal,
|
||||
initWidgetCalendar:initWidgetCalendar
|
||||
};
|
||||
})();
|
||||
Reference in New Issue
Block a user