econtrol-tools-calendar 1.0.9 → 1.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -16
- package/dist/calendar.js +69 -22
- package/dist/calendar.js.map +1 -1
- package/dist/calendar.umd.cjs +69 -22
- package/dist/calendar.umd.cjs.map +1 -1
- package/dist/style.css +140 -140
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -97,6 +97,10 @@ const holidays = {
|
|
|
97
97
|
|
|
98
98
|
// 事件处理函数
|
|
99
99
|
function handleEventAdded(event: EventInput) {
|
|
100
|
+
// 如果事件没有ID,生成一个唯一ID(事件ID应该由外部提供)
|
|
101
|
+
if (!event.id) {
|
|
102
|
+
event.id = `event-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
103
|
+
}
|
|
100
104
|
events.value.push(event);
|
|
101
105
|
ElMessage.success("事件已添加");
|
|
102
106
|
}
|
|
@@ -109,9 +113,11 @@ function handleEventUpdated(event: EventInput) {
|
|
|
109
113
|
}
|
|
110
114
|
}
|
|
111
115
|
|
|
112
|
-
function handleEventDeleted(
|
|
113
|
-
events.value = events.value.filter((e) => e.id !==
|
|
114
|
-
ElMessage.success("
|
|
116
|
+
function handleEventDeleted(event: EventInput) {
|
|
117
|
+
events.value = events.value.filter((e) => e.id !== event.id);
|
|
118
|
+
ElMessage.success(`事件"${event.title}"已删除`);
|
|
119
|
+
// 可以在这里调用 API 删除事件
|
|
120
|
+
// await deleteEventFromAPI(event);
|
|
115
121
|
}
|
|
116
122
|
|
|
117
123
|
function handleEventsChange(newEvents: EventInput[]) {
|
|
@@ -217,8 +223,9 @@ interface HolidayData {
|
|
|
217
223
|
| `quickAddSaved` | `event: EventInput` | 快速添加事件保存后触发 |
|
|
218
224
|
| `eventAdded` | `event: EventInput` | 事件添加后触发 |
|
|
219
225
|
| `eventUpdated` | `event: EventInput` | 事件更新后触发 |
|
|
220
|
-
| `eventDeleted` | `
|
|
226
|
+
| `eventDeleted` | `event: EventInput` | 事件删除后触发,包含完整的事件详情 |
|
|
221
227
|
| `eventsChange` | `events: EventInput[]` | 事件列表变化后触发,包含当前所有事件 |
|
|
228
|
+
| `deviceClick` | `deviceId: string` | 点击设备名称时触发,传递设备 ID |
|
|
222
229
|
|
|
223
230
|
### EventInput 类型
|
|
224
231
|
|
|
@@ -337,6 +344,10 @@ const quickAddTimeRange = ref({
|
|
|
337
344
|
|
|
338
345
|
// 事件处理函数
|
|
339
346
|
function handleEventAdded(event: EventInput) {
|
|
347
|
+
// 如果事件没有ID,生成一个唯一ID(事件ID应该由外部提供)
|
|
348
|
+
if (!event.id) {
|
|
349
|
+
event.id = `event-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
350
|
+
}
|
|
340
351
|
events.value.push(event);
|
|
341
352
|
ElMessage.success("事件已添加");
|
|
342
353
|
// 可以在这里调用 API 保存事件
|
|
@@ -353,11 +364,11 @@ function handleEventUpdated(event: EventInput) {
|
|
|
353
364
|
}
|
|
354
365
|
}
|
|
355
366
|
|
|
356
|
-
function handleEventDeleted(
|
|
357
|
-
events.value = events.value.filter((e) => e.id !==
|
|
358
|
-
ElMessage.success("
|
|
367
|
+
function handleEventDeleted(event: EventInput) {
|
|
368
|
+
events.value = events.value.filter((e) => e.id !== event.id);
|
|
369
|
+
ElMessage.success(`事件"${event.title}"已删除`);
|
|
359
370
|
// 可以在这里调用 API 删除事件
|
|
360
|
-
// await deleteEventFromAPI(
|
|
371
|
+
// await deleteEventFromAPI(event);
|
|
361
372
|
}
|
|
362
373
|
|
|
363
374
|
function handleEventsChange(newEvents: EventInput[]) {
|
|
@@ -366,6 +377,12 @@ function handleEventsChange(newEvents: EventInput[]) {
|
|
|
366
377
|
// await syncEventsToAPI(newEvents);
|
|
367
378
|
}
|
|
368
379
|
|
|
380
|
+
function handleDeviceClick(deviceId: string) {
|
|
381
|
+
console.log("点击了设备:", deviceId);
|
|
382
|
+
// 可以在这里处理设备点击逻辑,比如打开设备详情页面、跳转路由等
|
|
383
|
+
// router.push(`/device/${deviceId}`);
|
|
384
|
+
}
|
|
385
|
+
|
|
369
386
|
function handleQuickAddSaved(event: EventInput) {
|
|
370
387
|
console.log("快速添加的事件:", event);
|
|
371
388
|
// 处理快速添加逻辑
|
|
@@ -387,8 +404,9 @@ function handleQuickAddSaved(event: EventInput) {
|
|
|
387
404
|
:userinfo="userinfo"
|
|
388
405
|
@event-added="(event) => handleEventAdded(device.id, event)"
|
|
389
406
|
@event-updated="(event) => handleEventUpdated(device.id, event)"
|
|
390
|
-
@event-deleted="(
|
|
407
|
+
@event-deleted="(event) => handleEventDeleted(device.id, event)"
|
|
391
408
|
@events-change="(events) => handleEventsChange(device.id, events)"
|
|
409
|
+
@device-click="(deviceId) => handleDeviceClick(deviceId)"
|
|
392
410
|
/>
|
|
393
411
|
</div>
|
|
394
412
|
</template>
|
|
@@ -426,17 +444,27 @@ function handleEventUpdated(deviceId: string, event: EventInput) {
|
|
|
426
444
|
}
|
|
427
445
|
}
|
|
428
446
|
|
|
429
|
-
function handleEventDeleted(deviceId: string,
|
|
447
|
+
function handleEventDeleted(deviceId: string, event: EventInput) {
|
|
430
448
|
if (deviceEvents.value[deviceId]) {
|
|
431
449
|
deviceEvents.value[deviceId] = deviceEvents.value[deviceId].filter(
|
|
432
|
-
(e) => e.id !==
|
|
450
|
+
(e) => e.id !== event.id
|
|
433
451
|
);
|
|
452
|
+
ElMessage.success(`事件"${event.title}"已删除`);
|
|
453
|
+
// 可以在这里调用 API 删除事件
|
|
454
|
+
// await deleteEventFromAPI(event);
|
|
434
455
|
}
|
|
435
456
|
}
|
|
457
|
+
}
|
|
436
458
|
|
|
437
459
|
function handleEventsChange(deviceId: string, events: EventInput[]) {
|
|
438
460
|
deviceEvents.value[deviceId] = events;
|
|
439
461
|
}
|
|
462
|
+
|
|
463
|
+
function handleDeviceClick(deviceId: string) {
|
|
464
|
+
console.log("点击了设备:", deviceId);
|
|
465
|
+
// 可以在这里处理设备点击逻辑,比如打开设备详情页面、跳转路由等
|
|
466
|
+
// router.push(`/device/${deviceId}`);
|
|
467
|
+
}
|
|
440
468
|
</script>
|
|
441
469
|
```
|
|
442
470
|
|
|
@@ -521,15 +549,17 @@ pnpm preview
|
|
|
521
549
|
|
|
522
550
|
2. **事件格式**:事件的时间格式必须使用 ISO 8601 格式(`YYYY-MM-DDTHH:mm:ss`),例如:`"2025-01-15T10:00:00"`。
|
|
523
551
|
|
|
524
|
-
3.
|
|
552
|
+
3. **事件 ID**:组件不会自动生成事件 ID,事件 ID 应该由外部(App.vue)的事件列表提供。当组件 emit `eventAdded` 事件时,如果事件没有 ID,父组件应该生成 ID 并更新 `events` prop。
|
|
553
|
+
|
|
554
|
+
4. **权限控制**:通过 `userinfo` prop 控制事件的可编辑性,只有 `extendedProps.organizerId` 匹配 `userinfo.userid` 的事件才能被修改。
|
|
525
555
|
|
|
526
|
-
|
|
556
|
+
5. **用户信息**:组件会显示 `username` 作为预订人,并在事件数据中保存 `username` 和 `organizerId`。
|
|
527
557
|
|
|
528
|
-
|
|
558
|
+
6. **设备信息**:组件头部显示设备名称(`deviceInfo.name`),设备 ID(`deviceId`)作为关键字段保存在事件数据中。
|
|
529
559
|
|
|
530
|
-
|
|
560
|
+
7. **时间冲突**:当 `allowOverlap` 为 `false` 时,组件会自动检查时间冲突,不允许创建重叠的事件。
|
|
531
561
|
|
|
532
|
-
|
|
562
|
+
8. **节假日显示**:节假日数据格式为 `{ "YYYY-MM-DD": "节假日名称" }`,传入 `holidays` prop 后会在日历上高亮显示。
|
|
533
563
|
|
|
534
564
|
## 📄 许可证
|
|
535
565
|
|
package/dist/calendar.js
CHANGED
|
@@ -100,7 +100,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
100
100
|
holidays: { default: null },
|
|
101
101
|
events: { default: () => [] }
|
|
102
102
|
},
|
|
103
|
-
emits: ["quickAddSaved", "eventAdded", "eventUpdated", "eventDeleted", "eventsChange"],
|
|
103
|
+
emits: ["quickAddSaved", "eventAdded", "eventUpdated", "eventDeleted", "eventsChange", "deviceClick"],
|
|
104
104
|
setup(__props, { emit: __emit }) {
|
|
105
105
|
const emit = __emit;
|
|
106
106
|
const props = __props;
|
|
@@ -200,11 +200,45 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
200
200
|
const eventOrganizerId = ((_a = event.extendedProps) == null ? void 0 : _a.organizerId) || "";
|
|
201
201
|
return eventOrganizerId === currentUserId.value;
|
|
202
202
|
}
|
|
203
|
-
|
|
203
|
+
function normalizeEventTime(time) {
|
|
204
|
+
if (!time) return void 0;
|
|
205
|
+
if (time instanceof Date) {
|
|
206
|
+
return time;
|
|
207
|
+
}
|
|
208
|
+
if (typeof time === "number") {
|
|
209
|
+
return new Date(time);
|
|
210
|
+
}
|
|
211
|
+
if (typeof time === "string") {
|
|
212
|
+
if (time.includes("T")) {
|
|
213
|
+
return time;
|
|
214
|
+
}
|
|
215
|
+
const dateOnlyPattern = /^\d{4}-\d{2}-\d{2}$/;
|
|
216
|
+
if (dateOnlyPattern.test(time)) {
|
|
217
|
+
const normalizedTime = `${time} 00:00:00`;
|
|
218
|
+
return formatToISO(normalizedTime);
|
|
219
|
+
}
|
|
220
|
+
const dateTimePattern = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/;
|
|
221
|
+
if (dateTimePattern.test(time)) {
|
|
222
|
+
return formatToISO(time);
|
|
223
|
+
}
|
|
224
|
+
return time;
|
|
225
|
+
}
|
|
226
|
+
return time;
|
|
227
|
+
}
|
|
228
|
+
function normalizeEvent(event) {
|
|
229
|
+
return {
|
|
230
|
+
...event,
|
|
231
|
+
start: normalizeEventTime(event.start),
|
|
232
|
+
end: normalizeEventTime(event.end)
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
const events = ref(
|
|
236
|
+
(props.events || []).map((event) => normalizeEvent(event))
|
|
237
|
+
);
|
|
204
238
|
watch(
|
|
205
239
|
() => props.events,
|
|
206
240
|
(newEvents) => {
|
|
207
|
-
events.value =
|
|
241
|
+
events.value = (newEvents || []).map((event) => normalizeEvent(event));
|
|
208
242
|
},
|
|
209
243
|
{ deep: true, immediate: true }
|
|
210
244
|
);
|
|
@@ -803,7 +837,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
803
837
|
if (!props.deviceId) {
|
|
804
838
|
return;
|
|
805
839
|
}
|
|
806
|
-
|
|
840
|
+
emit("deviceClick", props.deviceId);
|
|
807
841
|
}
|
|
808
842
|
function handleAddEvent() {
|
|
809
843
|
if (props.isOccupied) {
|
|
@@ -869,15 +903,15 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
869
903
|
ElMessage.error("该时间段与其他事件冲突,请选择其他时间");
|
|
870
904
|
return;
|
|
871
905
|
}
|
|
872
|
-
const eventId = `event-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
873
906
|
const taskId = formData.taskid || props.taskid || "";
|
|
907
|
+
const tempEventId = taskId && taskId === props.taskid ? taskId : void 0;
|
|
874
908
|
const colorInfo = assignEventColor(
|
|
875
909
|
startStr,
|
|
876
910
|
endStr,
|
|
877
911
|
void 0,
|
|
878
912
|
currentUser.value,
|
|
879
|
-
|
|
880
|
-
//
|
|
913
|
+
tempEventId,
|
|
914
|
+
// 传入临时ID用于颜色分配(如果taskid匹配)
|
|
881
915
|
taskId
|
|
882
916
|
// 传入 taskid 用于颜色分配
|
|
883
917
|
);
|
|
@@ -887,7 +921,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
887
921
|
const eventOrganizerId = currentUserId.value;
|
|
888
922
|
const editable = !currentUserId.value || eventOrganizerId === currentUserId.value;
|
|
889
923
|
const newEvent = {
|
|
890
|
-
id
|
|
924
|
+
// 不设置 id,由外部 App.vue 的事件列表提供
|
|
891
925
|
title: props.quickAddTaskName,
|
|
892
926
|
start: startISO,
|
|
893
927
|
end: endISO,
|
|
@@ -1083,21 +1117,15 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1083
1117
|
ElMessage.error("该时间段与其他事件冲突,请选择其他时间");
|
|
1084
1118
|
return;
|
|
1085
1119
|
}
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
if (formData.taskid && formData.taskid.trim() && formData.taskid === props.taskid) {
|
|
1089
|
-
eventId = formData.taskid;
|
|
1090
|
-
} else {
|
|
1091
|
-
eventId = `event-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
1092
|
-
}
|
|
1093
|
-
}
|
|
1120
|
+
const eventId = (_b = editingEvent.value) == null ? void 0 : _b.id;
|
|
1121
|
+
const tempEventId = eventId || (formData.taskid && formData.taskid === props.taskid ? formData.taskid : void 0);
|
|
1094
1122
|
const colorInfo = assignEventColor(
|
|
1095
1123
|
formData.start,
|
|
1096
1124
|
formData.end,
|
|
1097
1125
|
(_c = editingEvent.value) == null ? void 0 : _c.id,
|
|
1098
1126
|
formData.organizer || currentUser.value,
|
|
1099
|
-
|
|
1100
|
-
//
|
|
1127
|
+
tempEventId,
|
|
1128
|
+
// 传入临时ID用于颜色分配(编辑时使用eventId,新增时如果taskid匹配使用taskid)
|
|
1101
1129
|
formData.taskid
|
|
1102
1130
|
// 传入 taskid 用于颜色分配
|
|
1103
1131
|
);
|
|
@@ -1167,8 +1195,9 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1167
1195
|
const eventOrganizerId = formData.organizerId || currentUserId.value;
|
|
1168
1196
|
const editable = !currentUserId.value || eventOrganizerId === currentUserId.value;
|
|
1169
1197
|
const newEvent = {
|
|
1170
|
-
id
|
|
1171
|
-
//
|
|
1198
|
+
// 不设置 id,由外部 App.vue 的事件列表提供
|
|
1199
|
+
// 如果 taskid 匹配 props.taskid,可以设置 id 为 taskid(可选)
|
|
1200
|
+
...formData.taskid && formData.taskid === props.taskid ? { id: formData.taskid } : {},
|
|
1172
1201
|
title: formData.title,
|
|
1173
1202
|
start: startISO,
|
|
1174
1203
|
end: endISO,
|
|
@@ -1198,12 +1227,26 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1198
1227
|
resetForm();
|
|
1199
1228
|
}
|
|
1200
1229
|
function handleDelete() {
|
|
1230
|
+
var _a, _b, _c;
|
|
1201
1231
|
if (editingEvent.value) {
|
|
1202
1232
|
const eventId = editingEvent.value.id;
|
|
1233
|
+
const deletedEvent = {
|
|
1234
|
+
id: eventId || "",
|
|
1235
|
+
title: editingEvent.value.title,
|
|
1236
|
+
start: ((_a = editingEvent.value.start) == null ? void 0 : _a.toISOString()) || "",
|
|
1237
|
+
end: (_b = editingEvent.value.end) == null ? void 0 : _b.toISOString(),
|
|
1238
|
+
allDay: editingEvent.value.allDay || false,
|
|
1239
|
+
backgroundColor: editingEvent.value.backgroundColor,
|
|
1240
|
+
borderColor: editingEvent.value.borderColor,
|
|
1241
|
+
editable: (_c = editingEvent.value.extendedProps) == null ? void 0 : _c.editable,
|
|
1242
|
+
extendedProps: {
|
|
1243
|
+
...editingEvent.value.extendedProps || {}
|
|
1244
|
+
}
|
|
1245
|
+
};
|
|
1203
1246
|
editingEvent.value.remove();
|
|
1204
1247
|
dialogVisible.value = false;
|
|
1205
1248
|
resetForm();
|
|
1206
|
-
emit("eventDeleted",
|
|
1249
|
+
emit("eventDeleted", deletedEvent);
|
|
1207
1250
|
const newEventsList = events.value.filter((e) => e.id !== eventId);
|
|
1208
1251
|
emit("eventsChange", newEventsList);
|
|
1209
1252
|
}
|
|
@@ -1465,6 +1508,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1465
1508
|
"value-format": "YYYY-MM-DD HH:mm:ss",
|
|
1466
1509
|
"disabled-date": disabledPastDate,
|
|
1467
1510
|
key: `start-${formData.start || "empty"}`,
|
|
1511
|
+
"append-to-body": "",
|
|
1512
|
+
"z-index": 3001,
|
|
1468
1513
|
style: { "width": "100%" }
|
|
1469
1514
|
}, null, 8, ["modelValue"]))
|
|
1470
1515
|
]),
|
|
@@ -1481,6 +1526,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1481
1526
|
"value-format": "YYYY-MM-DD HH:mm:ss",
|
|
1482
1527
|
"disabled-date": disabledPastDate,
|
|
1483
1528
|
key: `end-${formData.end || "empty"}`,
|
|
1529
|
+
"append-to-body": "",
|
|
1530
|
+
"z-index": 3001,
|
|
1484
1531
|
style: { "width": "100%" }
|
|
1485
1532
|
}, null, 8, ["modelValue"]))
|
|
1486
1533
|
]),
|
|
@@ -1612,7 +1659,7 @@ const _export_sfc = (sfc, props) => {
|
|
|
1612
1659
|
}
|
|
1613
1660
|
return target;
|
|
1614
1661
|
};
|
|
1615
|
-
const SCalendarComponent = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-
|
|
1662
|
+
const SCalendarComponent = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-c28885e3"]]);
|
|
1616
1663
|
function getHolidays(year) {
|
|
1617
1664
|
const holidays = {};
|
|
1618
1665
|
if (year === 2026) {
|