This commit is contained in:
2026-05-06 18:55:17 +08:00
parent 7369fe4117
commit fcc6acbcee
5 changed files with 91 additions and 34 deletions
+32
View File
@@ -0,0 +1,32 @@
# 2026-05-06 日志
## 日历事件日程类型功能
### 修改内容
- **后端** `routers/apiCalendar.go`:
- `TabCalendarEvent` 结构体新增 `ScheduleType string` 字段(默认值 work
- `addevent`/`updateevent` 接口解析并保存 `schedule_type` 参数
- **前端** `CalendarDetail.vue`:
- `eventData` 新增 `scheduleType` 字段
- `openEventModal`/`editEvent` 传递 `scheduleType`
- `selectColor` 函数联动更新 `scheduleType`
- `saveEvent`/`eventDrop` 提交 `schedule_type`
- `getEvents` 返回数据附加 `extendedProps.scheduleType`
- 模态框显示日程类型标签
- **i18n**:
- `zh-CN.json`: 新增 `event_type: "日程类型"`
- `en.json`: 新增 `event_type: "Event Type"`
### 日程类型选项
- work - 工作
- duty - 值班
- exam - 考试
- standby - 备用
- personal_holiday - 个人假期
- public_holiday - 公众假期
### 注意事项
- GORM AutoMigrate 会自动添加新字段
- 前端颜色选择与日程类型联动
+35 -25
View File
@@ -27,17 +27,17 @@ type TabCalendar struct {
// TabCalendarEvent 日历事件表 // TabCalendarEvent 日历事件表
type TabCalendarEvent struct { type TabCalendarEvent struct {
ID uint `gorm:"primarykey"` ID uint `gorm:"primarykey"`
CalendarID uint `gorm:"not null;index;comment:关联日历ID"` CalendarID uint `gorm:"not null;index;comment:关联日历ID"`
UserID uint `gorm:"not null;comment:创建人ID"` UserID uint `gorm:"not null;comment:创建人ID"`
//UsersID []uint `gorm:"type:json; null;comment:其他关联用户ID"` Title string `gorm:"size:200;not null;comment:事件标题"`
Title string `gorm:"size:200;not null;comment:事件标题"` StartDate *time.Time `gorm:"size:10;not null;index;comment:开始日期 YYYY-MM-DD"`
StartDate *time.Time `gorm:"size:10;not null;index;comment:开始日期 YYYY-MM-DD"` EndDate *time.Time `gorm:"size:10;not null;index;comment:结束日期 YYYY-MM-DD"`
EndDate *time.Time `gorm:"size:10;not null;index;comment:结束日期 YYYY-MM-DD"` IsAllDay bool `gorm:"default:true;comment:是否全日事件"`
IsAllDay bool `gorm:"default:true;comment:是否全日事件"` ScheduleType string `gorm:"size:50;default:work;comment:日程类型: work-工作 duty-值班 exam-考试 standby-待命 personal_holiday-调休 personal_holiday-公假"`
BgColor string `gorm:"size:50;default:#3788d9;comment:背景颜色"` BgColor string `gorm:"size:50;default:#3788d9;comment:背景颜色"`
IsPublic bool `gorm:"default:false;comment:是否为公共日程"` IsPublic bool `gorm:"default:false;comment:是否为公共日程"`
Remark string `gorm:"type:text;comment:备注"` Remark string `gorm:"type:text;comment:备注"`
CreatedAt *time.Time `gorm:"type:datetime;autoCreateTime;comment:创建时间"` CreatedAt *time.Time `gorm:"type:datetime;autoCreateTime;comment:创建时间"`
UpdatedAt *time.Time `gorm:"type:datetime;autoUpdateTime;comment:最后修改时间"` UpdatedAt *time.Time `gorm:"type:datetime;autoUpdateTime;comment:最后修改时间"`
@@ -376,19 +376,24 @@ func ApiCalendar(r *gin.RouterGroup) {
color, _ := data["color"].(string) color, _ := data["color"].(string)
remark, _ := data["remark"].(string) remark, _ := data["remark"].(string)
isPublic, _ := data["is_public"].(bool) isPublic, _ := data["is_public"].(bool)
scheduleType, _ := data["schedule_type"].(string)
if scheduleType == "" {
scheduleType = "work"
}
startDate, _ := time.Parse("2006-01-02 15:04:05", startStr) startDate, _ := time.Parse("2006-01-02 15:04:05", startStr)
endDate, _ := time.Parse("2006-01-02 15:04:05", endStr) endDate, _ := time.Parse("2006-01-02 15:04:05", endStr)
event := TabCalendarEvent{ event := TabCalendarEvent{
CalendarID: calendarID, CalendarID: calendarID,
UserID: user.ID, UserID: user.ID,
Title: title, Title: title,
StartDate: &startDate, StartDate: &startDate,
EndDate: &endDate, EndDate: &endDate,
BgColor: color, ScheduleType: scheduleType,
IsPublic: isPublic, BgColor: color,
Remark: remark, IsPublic: isPublic,
Remark: remark,
} }
if event.BgColor == "" { if event.BgColor == "" {
event.BgColor = calendar.Color event.BgColor = calendar.Color
@@ -442,17 +447,22 @@ func ApiCalendar(r *gin.RouterGroup) {
color, _ := data["color"].(string) color, _ := data["color"].(string)
remark, _ := data["remark"].(string) remark, _ := data["remark"].(string)
isPublic, _ := data["is_public"].(bool) isPublic, _ := data["is_public"].(bool)
scheduleType, _ := data["schedule_type"].(string)
if scheduleType == "" {
scheduleType = "work"
}
startDate, _ := time.Parse("2006-01-02 15:04:05", startStr) startDate, _ := time.Parse("2006-01-02 15:04:05", startStr)
endDate, _ := time.Parse("2006-01-02 15:04:05", endStr) endDate, _ := time.Parse("2006-01-02 15:04:05", endStr)
newEvent := TabCalendarEvent{ newEvent := TabCalendarEvent{
Title: title, Title: title,
StartDate: &startDate, StartDate: &startDate,
EndDate: &endDate, EndDate: &endDate,
BgColor: color, ScheduleType: scheduleType,
IsPublic: isPublic, BgColor: color,
Remark: remark, IsPublic: isPublic,
Remark: remark,
} }
if newEvent.BgColor == "" { if newEvent.BgColor == "" {
// 获取日历颜色 // 获取日历颜色
+1
View File
@@ -312,6 +312,7 @@
"standby": "Standby", "standby": "Standby",
"personal_holiday": "Personal Holiday", "personal_holiday": "Personal Holiday",
"public_holiday": "Public Holiday", "public_holiday": "Public Holiday",
"event_type": "Event Type",
"to": "To", "to": "To",
"close": "Close", "close": "Close",
"copy": "Copy", "copy": "Copy",
+1
View File
@@ -312,6 +312,7 @@
"standby": "备用", "standby": "备用",
"personal_holiday": "个人假期", "personal_holiday": "个人假期",
"public_holiday": "公众假期", "public_holiday": "公众假期",
"event_type": "日程类型",
"to": "至", "to": "至",
"close": "关闭", "close": "关闭",
"copy": "复制", "copy": "复制",
@@ -37,6 +37,7 @@ const eventData = ref({
startDate: "", startDate: "",
endDate: "", endDate: "",
color: "#3788d9", color: "#3788d9",
scheduleType: "work",
isPublic: false, isPublic: false,
isEditing: false, isEditing: false,
isEditable: false, isEditable: false,
@@ -78,13 +79,14 @@ function closeEventModal() {
showModal.value = false showModal.value = false
} }
function openEventModal(dateStr, dataEnd, id = 0, title = "", color = "#3788d9", isPublic = false, isEditing = false, isEditable = true) { function openEventModal(dateStr, dataEnd, id = 0, title = "", color = "#3788d9", scheduleType = "work", isPublic = false, isEditing = false, isEditable = true) {
eventData.value = { eventData.value = {
id: id, id: id,
title: title, title: title,
startDate: dateStr, startDate: dateStr,
endDate: dataEnd, endDate: dataEnd,
color: color, color: color,
scheduleType: scheduleType,
isPublic: isPublic, isPublic: isPublic,
isEditing: isEditing, isEditing: isEditing,
isEditable: isEditable, isEditable: isEditable,
@@ -99,6 +101,7 @@ function editEvent(info) {
parseInt(info.event.id), parseInt(info.event.id),
info.event.title, info.event.title,
info.event.backgroundColor, info.event.backgroundColor,
info.event.extendedProps?.scheduleType || "work",
info.event.extendedProps?.isPublic || false, info.event.extendedProps?.isPublic || false,
true, true,
info.event.durationEditable, info.event.durationEditable,
@@ -108,6 +111,11 @@ function editEvent(info) {
function selectColor(colorValue) { function selectColor(colorValue) {
if (eventData.value.isEditable) { if (eventData.value.isEditable) {
eventData.value.color = colorValue eventData.value.color = colorValue
// 根据颜色更新日程类型
const selectedColor = colorOptions.value.find(c => c.value === colorValue)
if (selectedColor) {
eventData.value.scheduleType = selectedColor.type
}
} }
} }
@@ -129,9 +137,6 @@ async function saveEvent() {
return return
} }
const selectedColor = colorOptions.value.find(c => c.value === eventData.value.color)
const scheduleType = selectedColor ? selectedColor.type : "work"
try { try {
let result let result
if (eventData.value.isEditing) { if (eventData.value.isEditing) {
@@ -144,7 +149,7 @@ async function saveEvent() {
? eventData.value.endDate ? eventData.value.endDate
: DateUtils.toRealEnd(eventData.value.endDate), : DateUtils.toRealEnd(eventData.value.endDate),
), ),
schedule_type: scheduleType, schedule_type: eventData.value.scheduleType,
is_public: eventData.value.isPublic, is_public: eventData.value.isPublic,
}) })
} else { } else {
@@ -157,7 +162,7 @@ async function saveEvent() {
? eventData.value.endDate ? eventData.value.endDate
: DateUtils.toRealEnd(eventData.value.endDate), : DateUtils.toRealEnd(eventData.value.endDate),
), ),
schedule_type: scheduleType, schedule_type: eventData.value.scheduleType,
is_public: eventData.value.isPublic, is_public: eventData.value.isPublic,
}) })
} }
@@ -218,6 +223,10 @@ async function getEvents() {
backgroundColor: item.BgColor, backgroundColor: item.BgColor,
borderColor: item.ID === pageData.value.seleEventID ? "#000000" : "#F7F7F7", borderColor: item.ID === pageData.value.seleEventID ? "#000000" : "#F7F7F7",
allDay: true, allDay: true,
extendedProps: {
scheduleType: item.ScheduleType || "work",
isPublic: item.IsPublic || false,
},
}) })
}) })
} }
@@ -391,8 +400,6 @@ const calendarOptions = ref({
eventDrop(info) { eventDrop(info) {
// 拖拽后直接更新 // 拖拽后直接更新
const selectedColor = colorOptions.value.find(c => c.value === info.event.backgroundColor)
const scheduleType = selectedColor ? selectedColor.type : "work"
const startStr = info.event.startStr const startStr = info.event.startStr
const endStr = info.event.end ? info.event.endStr : startStr const endStr = info.event.end ? info.event.endStr : startStr
calendarApi.updateEvent({ calendarApi.updateEvent({
@@ -400,7 +407,7 @@ const calendarOptions = ref({
title: info.event.title, title: info.event.title,
start: toDatetime(startStr), start: toDatetime(startStr),
end: toDatetime(startStr === endStr ? endStr : DateUtils.toRealEnd(endStr)), end: toDatetime(startStr === endStr ? endStr : DateUtils.toRealEnd(endStr)),
schedule_type: scheduleType, schedule_type: info.event.extendedProps?.scheduleType || "work",
}).then(r => { }).then(r => {
if (r.errCode !== 0) toast.error(t('message.server_error')) if (r.errCode !== 0) toast.error(t('message.server_error'))
else getEvents() else getEvents()
@@ -569,6 +576,12 @@ onMounted(() => {
</div> </div>
</div> </div>
<!-- 日程类型标签 -->
<div class="mb-4 px-1">
<span class="text-sm text-gray-600">{{ t('schedule.event_type') }}: </span>
<span class="text-sm font-medium" :style="{ color: eventData.color }">{{ t('schedule.' + eventData.scheduleType) || eventData.scheduleType }}</span>
</div>
<!-- 公共日程开关 --> <!-- 公共日程开关 -->
<div class="mb-4 flex items-center justify-between"> <div class="mb-4 flex items-center justify-between">
<span class="text-gray-700">{{ t('calendar.is_public_event') }}</span> <span class="text-gray-700">{{ t('calendar.is_public_event') }}</span>