up
This commit is contained in:
@@ -3,6 +3,7 @@ package routers
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"ops/models"
|
"ops/models"
|
||||||
|
"slices"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"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"`
|
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:是否全日事件"`
|
||||||
BgColor string `gorm:"size:50;default:#3788d9;comment:背景颜色"`
|
BgColor string `gorm:"size:50;default:#3788d9;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:创建时间"`
|
||||||
@@ -89,6 +91,7 @@ type fromAddCalendarEvent struct {
|
|||||||
Start *time.Time `json:"start" binding:"required"`
|
Start *time.Time `json:"start" binding:"required"`
|
||||||
End *time.Time `json:"end" binding:"required"`
|
End *time.Time `json:"end" binding:"required"`
|
||||||
Color string `json:"color"`
|
Color string `json:"color"`
|
||||||
|
Is_public bool `json:"is_public"`
|
||||||
Remark string `json:"remark"`
|
Remark string `json:"remark"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,6 +101,7 @@ type fromUpdateCalendarEvent struct {
|
|||||||
Start *time.Time `json:"start" binding:"required"`
|
Start *time.Time `json:"start" binding:"required"`
|
||||||
End *time.Time `json:"end" binding:"required"`
|
End *time.Time `json:"end" binding:"required"`
|
||||||
Color string `json:"color"`
|
Color string `json:"color"`
|
||||||
|
Is_public bool `json:"is_public"`
|
||||||
Remark string `json:"remark"`
|
Remark string `json:"remark"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,11 +109,43 @@ type fromDeleteCalendarEvent struct {
|
|||||||
ID uint `json:"id" binding:"required"`
|
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() {
|
func ApiCalendarInit() {
|
||||||
// 初始化数据表
|
// 初始化数据表
|
||||||
models.DB.AutoMigrate(&TabCalendar{})
|
models.DB.AutoMigrate(&TabCalendar{})
|
||||||
models.DB.AutoMigrate(&TabCalendarEvent{})
|
models.DB.AutoMigrate(&TabCalendarEvent{})
|
||||||
models.DB.AutoMigrate(&TabCalendarLog{})
|
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) {
|
func ApiCalendar(r *gin.RouterGroup) {
|
||||||
@@ -152,12 +188,41 @@ func ApiCalendar(r *gin.RouterGroup) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// 获取日历列表
|
// 获取日历列表(不需要登录)
|
||||||
r.POST("/calendar/list", func(ctx *gin.Context) {
|
r.POST("/calendar/list", func(ctx *gin.Context) {
|
||||||
|
isAuth, user, _ := AuthenticationAuthority(ctx)
|
||||||
|
|
||||||
var calendars []TabCalendar
|
var calendars []TabCalendar
|
||||||
models.DB.Where("deleted_at IS NULL").Order("created_at DESC").Find(&calendars)
|
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,
|
StartDate: from.Start,
|
||||||
EndDate: from.End,
|
EndDate: from.End,
|
||||||
BgColor: from.Color,
|
BgColor: from.Color,
|
||||||
|
IsPublic: from.Is_public,
|
||||||
Remark: from.Remark,
|
Remark: from.Remark,
|
||||||
}
|
}
|
||||||
if event.BgColor == "" {
|
if event.BgColor == "" {
|
||||||
@@ -352,6 +418,7 @@ func ApiCalendar(r *gin.RouterGroup) {
|
|||||||
StartDate: from.Start,
|
StartDate: from.Start,
|
||||||
EndDate: from.End,
|
EndDate: from.End,
|
||||||
BgColor: from.Color,
|
BgColor: from.Color,
|
||||||
|
IsPublic: from.Is_public,
|
||||||
Remark: from.Remark,
|
Remark: from.Remark,
|
||||||
}
|
}
|
||||||
if newEvent.BgColor == "" {
|
if newEvent.BgColor == "" {
|
||||||
|
|||||||
@@ -462,6 +462,8 @@ func ApiSysAdmin(r *gin.RouterGroup) {
|
|||||||
WarehouseUpdateAdminsCash()
|
WarehouseUpdateAdminsCash()
|
||||||
case "customer_admin":
|
case "customer_admin":
|
||||||
CustomerUpdateAdminsCash()
|
CustomerUpdateAdminsCash()
|
||||||
|
case "calendar_admin":
|
||||||
|
CalendarUpdateAdminsCash()
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnJson(ctx, "apiOK", nil)
|
ReturnJson(ctx, "apiOK", nil)
|
||||||
|
|||||||
@@ -339,7 +339,7 @@ func AuthenticationAuthority(ctx *gin.Context) (bool, TabUser, map[string]interf
|
|||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
ReturnJson(ctx, "userCookieError", nil)
|
//ReturnJson(ctx, "userCookieError", nil)
|
||||||
return false, user, nil
|
return false, user, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -638,6 +638,7 @@
|
|||||||
"remark_placeholder": "Enter remark",
|
"remark_placeholder": "Enter remark",
|
||||||
"event_save_success": "Event saved successfully",
|
"event_save_success": "Event saved successfully",
|
||||||
"event_delete_success": "Event deleted 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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -638,6 +638,7 @@
|
|||||||
"remark_placeholder": "请输入备注",
|
"remark_placeholder": "请输入备注",
|
||||||
"event_save_success": "事件保存成功",
|
"event_save_success": "事件保存成功",
|
||||||
"event_delete_success": "事件删除成功",
|
"event_delete_success": "事件删除成功",
|
||||||
"confirm_delete_event": "确定要删除此事件吗?"
|
"confirm_delete_event": "确定要删除此事件吗?",
|
||||||
|
"is_public_event": "公共日程"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ const eventData = ref({
|
|||||||
startDate: "",
|
startDate: "",
|
||||||
endDate: "",
|
endDate: "",
|
||||||
color: "#3788d9",
|
color: "#3788d9",
|
||||||
|
isPublic: false,
|
||||||
isEditing: false,
|
isEditing: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
})
|
})
|
||||||
@@ -77,13 +78,14 @@ function closeEventModal() {
|
|||||||
showModal.value = false
|
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 = {
|
eventData.value = {
|
||||||
id: id,
|
id: id,
|
||||||
title: title,
|
title: title,
|
||||||
startDate: dateStr,
|
startDate: dateStr,
|
||||||
endDate: dataEnd,
|
endDate: dataEnd,
|
||||||
color: color,
|
color: color,
|
||||||
|
isPublic: isPublic,
|
||||||
isEditing: isEditing,
|
isEditing: isEditing,
|
||||||
isEditable: isEditable,
|
isEditable: isEditable,
|
||||||
}
|
}
|
||||||
@@ -97,6 +99,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?.isPublic || false,
|
||||||
true,
|
true,
|
||||||
info.event.durationEditable,
|
info.event.durationEditable,
|
||||||
)
|
)
|
||||||
@@ -142,6 +145,7 @@ async function saveEvent() {
|
|||||||
: DateUtils.toRealEnd(eventData.value.endDate),
|
: DateUtils.toRealEnd(eventData.value.endDate),
|
||||||
),
|
),
|
||||||
schedule_type: scheduleType,
|
schedule_type: scheduleType,
|
||||||
|
is_public: eventData.value.isPublic,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
result = await calendarApi.addEvent({
|
result = await calendarApi.addEvent({
|
||||||
@@ -154,6 +158,7 @@ async function saveEvent() {
|
|||||||
: DateUtils.toRealEnd(eventData.value.endDate),
|
: DateUtils.toRealEnd(eventData.value.endDate),
|
||||||
),
|
),
|
||||||
schedule_type: scheduleType,
|
schedule_type: scheduleType,
|
||||||
|
is_public: eventData.value.isPublic,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -563,6 +568,20 @@ onMounted(() => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 公共日程开关 -->
|
||||||
|
<div class="mb-4 flex items-center justify-between">
|
||||||
|
<span class="text-gray-700">{{ t('calendar.is_public_event') }}</span>
|
||||||
|
<label class="relative inline-flex items-center cursor-pointer">
|
||||||
|
<input
|
||||||
|
v-model="eventData.isPublic"
|
||||||
|
type="checkbox"
|
||||||
|
class="sr-only peer"
|
||||||
|
:disabled="!eventData.isEditable"
|
||||||
|
/>
|
||||||
|
<div class="w-11 h-6 bg-gray-300 peer-focus:outline-none peer-focus:ring-2 peer-focus:ring-cyan-300 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-cyan-600 peer-disabled:opacity-50 peer-disabled:cursor-not-allowed"></div>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 底部固定 -->
|
<!-- 底部固定 -->
|
||||||
|
|||||||
Reference in New Issue
Block a user