5.9 KiB
2026-05-06 日志
日历事件日程类型功能
修改内容
-
后端
routers/apiCalendar.go:TabCalendarEvent结构体新增ScheduleType string字段(默认值 work)addevent/updateevent接口解析并保存schedule_type参数
-
前端
CalendarDetail.vue:eventData新增scheduleType字段openEventModal/editEvent传递scheduleTypeselectColor函数联动更新scheduleTypesaveEvent/eventDrop提交schedule_typegetEvents返回数据附加extendedProps.scheduleType- 模态框显示日程类型标签
-
i18n:
zh-CN.json: 新增event_type: "日程类型"en.json: 新增event_type: "Event Type"
日程类型选项
- work - 工作
- duty - 值班
- exam - 考试
- standby - 备用
- personal_holiday - 个人假期
- public_holiday - 公众假期
注意事项
- GORM AutoMigrate 会自动添加新字段
- 前端颜色选择与日程类型联动
修复:calendar/events jsonErr
问题:fromGetCalendarEvents 的 start/end 是 *time.Time 类型,无法直接解析字符串格式的日期。
修复:改为直接用类型断言解析字符串,用 time.Parse("2006-01-02", ...) 解析。
优化:BgColor 弃用,前端根据 ScheduleType 渲染颜色
前端:添加 getColorByScheduleType() 函数,getEvents 中使用 scheduleType 映射颜色。
后端:只存储 ScheduleType,不处理颜色逻辑。颜色完全由前端 colorOptions 控制。
CalendarDetail 滚动标题快照对比
功能:每次 getEvents 存快照,数据变化或宽度变化时重新计算标题滚动。
实现:
pageData.lastEventsSnapshot:存储上一次的 JSON 快照getEvents()末尾对比快照,变化则setTimeout(recalcScrollTitles, 150)ResizeObserver监听日历容器宽度变化,防抖 150ms 后重算applyScrollToTitle():清除旧状态 → 测量 overflow → 设置--scroll-distance和data-truncated属性
CalendarList 编辑/删除按钮改用 canEdit
改动:
CalendarList.vue:编辑/删除按钮v-if条件从calendar.UserID === userStore.userInfo?.ID改为calendar.canEdit- 移除废弃的
useUserStore导入
CalendarList 删除改用 ConfirmDialog 组件
改动:
CalendarList.vue导入并使用ConfirmDialog组件- 新增
showDeleteModal+deletingCalendar状态 deleteCalendar()改为打开确认弹窗,confirmDelete()执行实际删除 API- i18n 新增
calendar.confirm_delete_message:zh-CN「确定要删除日历「{name}」吗?此操作不可撤销。」,en 英文版
新增日历管理页面 /calendars/admin
功能:系统管理员查看所有日历列表,包含日程数量、创建者、创建时间。
新增文件:
src/views/calendar/CalendarAdminList.vue- 日历管理列表组件
路由修改 src/router/index.js:
- 新增
/calendars/admin路由,指向CalendarAdminList.vue - 设置
meta: { requireSysAdmin: true }要求管理员权限
SysAdminView.vue:
tabs数组新增{ id: 'calendar', label: t('calendar.admin_title'), to: '/calendars/admin' }
i18n 新增:
zh-CN.json:calendar.admin_title = "日历管理",calendar.event_count = "日程数量"en.json:calendar.admin_title = "Calendar Admin",calendar.event_count = "Event Count"
修复:CalendarAdminList eventCounts 未定义
问题:模板访问 eventCounts[calendar.ID] 但 eventCounts 从未声明,且 fetchEventCounts 未被调用。
修复:后端已直接返回 event_count 字段,改为模板直接用 calendar.event_count ?? 0,删除多余的 eventCounts ref 和 fetchEventCounts 函数。
新增:后端 TabCalendarEventUserBind 绑定表
文件:routers/binds.go
- 新增
TabCalendarEventUserBind结构体(EventID/UserID/CreatorID/CreatedAt) - 在
BindsInitAutoMigrate 中注册
新增:日历右键菜单(复制/粘贴日程)
文件:CalendarDetail.vue
功能:
- 右键日程事件弹出上下文菜单,显示「复制日程」「粘贴日程」
- 复制:将日程数据存入
clipboardref - 粘贴:以 clipboard 数据调用
addEventAPI 创建新日程 - 点击任意位置关闭菜单
实现:
contextMenuref 管理菜单显示/位置/事件数据clipboardref 存储复制的日程eventDidMount中为每个事件绑定contextmenu事件onMounted注册全局 click 关闭菜单,onBeforeUnmount移除- i18n 新增
calendar.copy_event/paste_event/copy_success/paste_success/no_event_to_paste
修复:粘贴多天日程时结束日期少1天
问题:Ctrl+V 粘贴大于1天的日程时,目标结束日期少1天。
原因:pasteToDate 中用 new Date(targetEndMs).toISOString().split('T')[0] 计算目标结束日期,toISOString() 输出 UTC 时间,在 UTC+8 时区下日期会往前偏移1天。
修复(CalendarDetail.vue pasteToDate 函数):
- 改用天数差
Math.round((origEndDate - origStartDate) / 86400000)替代毫秒差 - 用本地日期方法
targetEndDate.setDate(targetEndDate.getDate() + diffDays)+ 手动拼接YYYY-MM-DD,替代toISOString().split('T')[0]
修复:Ctrl+C 无法复制大于1天的日程
问题:Ctrl+C 复制多天日程后粘贴无效果。
根因:calendarOptions.value.events 中多天事件的 end 是 DateUtils.toCalendarEnd() 返回的 Date 对象(非字符串)。Ctrl+C 直接 selectedEvent.end || selectedEvent.start 存入 clipboard,导致 pasteToDate 调用 clipboard.value.end.split('T')[0] 时 Date 对象没有 split 方法而报错。单天事件因走 isSameDay 分支不解析 end,所以不受影响。
修复(CalendarDetail.vue handleKeyDown Ctrl+C 分支):
- 检测
end是否为 Date 实例,如果是则用本地日期方法转为YYYY-MM-DD字符串再存入 clipboard