diff --git a/backend/my_work/routers/apiCalendar.go b/backend/my_work/routers/apiCalendar.go index a93a141..746de6c 100644 --- a/backend/my_work/routers/apiCalendar.go +++ b/backend/my_work/routers/apiCalendar.go @@ -3,6 +3,7 @@ package routers import ( "encoding/json" "ops/models" + "slices" "time" "github.com/gin-gonic/gin" @@ -35,6 +36,7 @@ type TabCalendarEvent struct { EndDate *time.Time `gorm:"size:10;not null;index;comment:结束日期 YYYY-MM-DD"` IsAllDay bool `gorm:"default:true;comment:是否全日事件"` BgColor string `gorm:"size:50;default:#3788d9;comment:背景颜色"` + IsPublic bool `gorm:"default:false;comment:是否为公共日程"` Remark string `gorm:"type:text;comment:备注"` CreatedAt *time.Time `gorm:"type:datetime;autoCreateTime;comment:创建时间"` @@ -89,27 +91,61 @@ type fromAddCalendarEvent struct { Start *time.Time `json:"start" binding:"required"` End *time.Time `json:"end" binding:"required"` Color string `json:"color"` + Is_public bool `json:"is_public"` Remark string `json:"remark"` } type fromUpdateCalendarEvent struct { - ID uint `json:"id" binding:"required"` - Title string `json:"title" binding:"required"` - Start *time.Time `json:"start" binding:"required"` - End *time.Time `json:"end" binding:"required"` - Color string `json:"color"` - Remark string `json:"remark"` + ID uint `json:"id" binding:"required"` + Title string `json:"title" binding:"required"` + Start *time.Time `json:"start" binding:"required"` + End *time.Time `json:"end" binding:"required"` + Color string `json:"color"` + Is_public bool `json:"is_public"` + Remark string `json:"remark"` } type fromDeleteCalendarEvent struct { ID uint `json:"id" binding:"required"` } +var ( + calendarUserGroup TabUserGroups + calendarAdmins []uint +) + +// CalendarUpdateAdminsCash 更新客户管理员缓存 +func CalendarUpdateAdminsCash() { + calendarAdmins = nil + calendarAdmins = append(calendarAdmins, 1) // id=1 系统管理员默认拥有所有权限 + var binds []TabUserGroupBinds + models.DB.Where("group_id = ?", calendarUserGroup.ID).Find(&binds) + for _, item := range binds { + if !slices.Contains(calendarAdmins, item.UserID) { + calendarAdmins = append(calendarAdmins, item.UserID) + } + } +} + +// canModifyCustomer 判断是否有权限修改/删除客户(创建者或管理员) +func canModifyCalendar(userID, creatorUserID uint) bool { + if slices.Contains(calendarAdmins, userID) { + return true + } + return userID == creatorUserID +} + func ApiCalendarInit() { // 初始化数据表 models.DB.AutoMigrate(&TabCalendar{}) models.DB.AutoMigrate(&TabCalendarEvent{}) models.DB.AutoMigrate(&TabCalendarLog{}) + + // 自动创建 calendar_admin 用户组 + models.DB.Where("name = ?", "calendar_admin").FirstOrCreate(&calendarUserGroup, TabUserGroups{ + Name: "calendar_admin", + Type: "usergroup", + }) } func ApiCalendar(r *gin.RouterGroup) { @@ -152,12 +188,41 @@ func ApiCalendar(r *gin.RouterGroup) { } }) - // 获取日历列表 + // 获取日历列表(不需要登录) r.POST("/calendar/list", func(ctx *gin.Context) { + isAuth, user, _ := AuthenticationAuthority(ctx) var calendars []TabCalendar models.DB.Where("deleted_at IS NULL").Order("created_at DESC").Find(&calendars) - ReturnJson(ctx, "apiOK", gin.H{"list": calendars}) + + type CalendarWithEdit struct { + TabCalendar + CanEdit bool `json:"canEdit"` + } + var result []CalendarWithEdit + for _, cal := range calendars { + // 私有日历:只有创建者可见 + if !cal.IsPublic { + if !isAuth || cal.UserID != user.ID { + continue + } + result = append(result, CalendarWithEdit{ + TabCalendar: cal, + CanEdit: true, + }) + continue + } + // 公开日历 + canEdit := false + if isAuth { + canEdit = canModifyCalendar(user.ID, cal.UserID) + } + result = append(result, CalendarWithEdit{ + TabCalendar: cal, + CanEdit: canEdit, + }) + } + ReturnJson(ctx, "apiOK", gin.H{"list": result}) }) @@ -303,6 +368,7 @@ func ApiCalendar(r *gin.RouterGroup) { StartDate: from.Start, EndDate: from.End, BgColor: from.Color, + IsPublic: from.Is_public, Remark: from.Remark, } if event.BgColor == "" { @@ -352,6 +418,7 @@ func ApiCalendar(r *gin.RouterGroup) { StartDate: from.Start, EndDate: from.End, BgColor: from.Color, + IsPublic: from.Is_public, Remark: from.Remark, } if newEvent.BgColor == "" { diff --git a/backend/my_work/routers/apiSysAdmin.go b/backend/my_work/routers/apiSysAdmin.go index 30a328e..3783548 100644 --- a/backend/my_work/routers/apiSysAdmin.go +++ b/backend/my_work/routers/apiSysAdmin.go @@ -164,7 +164,7 @@ func ApiSysAdmin(r *gin.RouterGroup) { return } - var params struct { + var params struct { GroupID float64 `json:"group_id" mapstructure:"group_id"` Page float64 `json:"page" mapstructure:"page"` PageSize float64 `json:"page_size" mapstructure:"page_size"` @@ -462,6 +462,8 @@ func ApiSysAdmin(r *gin.RouterGroup) { WarehouseUpdateAdminsCash() case "customer_admin": CustomerUpdateAdminsCash() + case "calendar_admin": + CalendarUpdateAdminsCash() } ReturnJson(ctx, "apiOK", nil) diff --git a/backend/my_work/routers/apiUsers.go b/backend/my_work/routers/apiUsers.go index f7274a4..a78b58d 100644 --- a/backend/my_work/routers/apiUsers.go +++ b/backend/my_work/routers/apiUsers.go @@ -339,7 +339,7 @@ func AuthenticationAuthority(ctx *gin.Context) (bool, TabUser, map[string]interf } } else { - ReturnJson(ctx, "userCookieError", nil) + //ReturnJson(ctx, "userCookieError", nil) return false, user, nil } diff --git a/frontend/ops_vue_js/src/i18n/en.json b/frontend/ops_vue_js/src/i18n/en.json index 2882dc7..0e6d2df 100644 --- a/frontend/ops_vue_js/src/i18n/en.json +++ b/frontend/ops_vue_js/src/i18n/en.json @@ -638,6 +638,7 @@ "remark_placeholder": "Enter remark", "event_save_success": "Event saved successfully", "event_delete_success": "Event deleted successfully", - "confirm_delete_event": "Are you sure you want to delete this event?" + "confirm_delete_event": "Are you sure you want to delete this event?", + "is_public_event": "Public Event" } } diff --git a/frontend/ops_vue_js/src/i18n/zh-CN.json b/frontend/ops_vue_js/src/i18n/zh-CN.json index fac28c8..b5b0974 100644 --- a/frontend/ops_vue_js/src/i18n/zh-CN.json +++ b/frontend/ops_vue_js/src/i18n/zh-CN.json @@ -638,6 +638,7 @@ "remark_placeholder": "请输入备注", "event_save_success": "事件保存成功", "event_delete_success": "事件删除成功", - "confirm_delete_event": "确定要删除此事件吗?" + "confirm_delete_event": "确定要删除此事件吗?", + "is_public_event": "公共日程" } } diff --git a/frontend/ops_vue_js/src/views/calendar/CalendarDetail.vue b/frontend/ops_vue_js/src/views/calendar/CalendarDetail.vue index 08b4d78..c5e578d 100644 --- a/frontend/ops_vue_js/src/views/calendar/CalendarDetail.vue +++ b/frontend/ops_vue_js/src/views/calendar/CalendarDetail.vue @@ -37,6 +37,7 @@ const eventData = ref({ startDate: "", endDate: "", color: "#3788d9", + isPublic: false, isEditing: false, isEditable: false, }) @@ -77,13 +78,14 @@ function closeEventModal() { showModal.value = false } -function openEventModal(dateStr, dataEnd, id = 0, title = "", color = "#3788d9", isEditing = false, isEditable = true) { +function openEventModal(dateStr, dataEnd, id = 0, title = "", color = "#3788d9", isPublic = false, isEditing = false, isEditable = true) { eventData.value = { id: id, title: title, startDate: dateStr, endDate: dataEnd, color: color, + isPublic: isPublic, isEditing: isEditing, isEditable: isEditable, } @@ -97,6 +99,7 @@ function editEvent(info) { parseInt(info.event.id), info.event.title, info.event.backgroundColor, + info.event.extendedProps?.isPublic || false, true, info.event.durationEditable, ) @@ -142,6 +145,7 @@ async function saveEvent() { : DateUtils.toRealEnd(eventData.value.endDate), ), schedule_type: scheduleType, + is_public: eventData.value.isPublic, }) } else { result = await calendarApi.addEvent({ @@ -154,6 +158,7 @@ async function saveEvent() { : DateUtils.toRealEnd(eventData.value.endDate), ), schedule_type: scheduleType, + is_public: eventData.value.isPublic, }) } @@ -563,6 +568,20 @@ onMounted(() => { + + +