更新角色管理相关内容

This commit is contained in:
2026-09-09 15:04:34 +08:00
parent de7225b61e
commit fef0233cc4
24 changed files with 1442 additions and 116 deletions
+188 -16
View File
@@ -2,6 +2,7 @@ package controllers
import (
"encoding/json"
"fmt"
"io"
"regexp"
"strconv"
@@ -289,14 +290,103 @@ func (c *BackendOaScheduleController) Stats() {
}
type oaSchedulePayload struct {
Title string `json:"title"`
Content string `json:"content"`
ScheduleDate string `json:"schedule_date"`
StartTime string `json:"start_time"`
EndTime string `json:"end_time"`
AllDay int8 `json:"all_day"`
Color string `json:"color"`
Priority int8 `json:"priority"`
Title string `json:"title"`
Content string `json:"content"`
ScheduleDate string `json:"schedule_date"`
StartTime string `json:"start_time"`
EndTime string `json:"end_time"`
AllDay int8 `json:"all_day"`
Color string `json:"color"`
Priority int8 `json:"priority"`
// 提醒绑定:开启后会在提醒工具生成一条提醒任务,并把其 ID 回写到 ReminderID。
ReminderEnabled bool `json:"reminder_enabled"`
ReminderTime string `json:"reminder_time"`
RemindChannels []string `json:"remind_channels"`
AdvanceMinutes int `json:"advance_minutes"`
}
// oaReminderChannels 允许的提醒渠道集合。
var oaReminderChannels = map[string]bool{
"SMS": true, "EMAIL": true, "BARK": true, "SITE_MSG": true,
}
// createOaScheduleReminder 为 OA 日程创建一条绑定的提醒任务。
// 复用提醒工具的数据模型(yz_backend_schedule + yz_backend_schedule_reminder):
// 生成一条 BackendSchedule,再按渠道逐条生成提醒记录,返回 BackendSchedule.ID
// 作为 OA 日程的 reminder_id。EMAIL/BARK 渠道会附带确认回执令牌与重复发送配置。
func createOaScheduleReminder(tid int, userID uint64, title, content, reminderTime string, channels []string, advanceMinutes int) (uint64, error) {
if strings.TrimSpace(reminderTime) == "" {
return 0, fmt.Errorf("提醒时间不能为空")
}
schedTime, err := time.ParseInLocation("2006-01-02 15:04:05", reminderTime, time.Local)
if err != nil {
return 0, fmt.Errorf("提醒时间格式不合法")
}
if advanceMinutes < 0 {
advanceMinutes = 0
}
title = strings.TrimSpace(title)
if title == "" {
title = "日程提醒"
}
bs := models.BackendSchedule{
Tid: tid,
Title: title,
Content: content,
ScheduleTime: schedTime,
UserID: userID,
}
schedID, err := models.Orm.Insert(&bs)
if err != nil {
return 0, fmt.Errorf("创建提醒任务失败: %v", err)
}
now := time.Now()
for _, ch := range channels {
ch = strings.ToUpper(strings.TrimSpace(ch))
if !oaReminderChannels[ch] {
continue
}
firstSend := schedTime.Add(-time.Duration(advanceMinutes) * time.Minute)
reminder := models.BackendScheduleReminder{
Tid: tid,
ScheduleID: uint64(schedID),
RemindChannel: ch,
AdvanceMinutes: advanceMinutes,
NextRemindTime: firstSend,
ReceiverUserID: userID,
RemindStatus: 0,
CreateTime: now,
UpdateTime: now,
}
if ch == "EMAIL" || ch == "BARK" {
token := backendGenerateToken()
reminder.AckToken = &token
reminder.RepeatIntervalMinutes = 10
reminder.MaxSendCount = 5
} else {
reminder.RepeatIntervalMinutes = 0
reminder.MaxSendCount = 1
}
if _, err := models.Orm.Insert(&reminder); err != nil {
return 0, fmt.Errorf("创建提醒失败: %v", err)
}
}
return uint64(schedID), nil
}
// deleteBoundReminder 软删除 OA 日程绑定的提醒任务及其提醒记录。
// 删除日程或关闭提醒时使用,避免提醒工具里残留孤立任务。
func deleteBoundReminder(scheduleID uint64) {
if scheduleID == 0 {
return
}
_, _ = models.Orm.QueryTable(new(models.BackendSchedule)).
Filter("id", scheduleID).Delete()
_, _ = models.Orm.QueryTable(new(models.BackendScheduleReminder)).
Filter("schedule_id", scheduleID).
Update(map[string]interface{}{"IsDeleted": 1, "UpdateTime": time.Now()})
}
// oaScheduleImage 日程相关图片(截图/照片),只存文件引用,不存二进制。
@@ -393,6 +483,29 @@ func (c *BackendOaScheduleController) parseOaSchedulePayload() (oaSchedulePayloa
if payload.Color == "" {
payload.Color = "#409EFF"
}
// 提醒绑定校验:开启提醒时必须选择渠道且提醒时间合法。
if payload.ReminderEnabled {
validChannels := make([]string, 0, len(payload.RemindChannels))
for _, ch := range payload.RemindChannels {
ch = strings.ToUpper(strings.TrimSpace(ch))
if oaReminderChannels[ch] {
validChannels = append(validChannels, ch)
}
}
payload.RemindChannels = validChannels
if len(validChannels) == 0 {
c.oasJsonErr(400, 400, "请至少选择一个提醒渠道")
return payload, false
}
if _, err := time.ParseInLocation("2006-01-02 15:04:05", payload.ReminderTime, time.Local); err != nil {
c.oasJsonErr(400, 400, "提醒时间格式不合法,支持 YYYY-MM-DD HH:mm:ss")
return payload, false
}
if payload.AdvanceMinutes < 0 {
payload.AdvanceMinutes = 0
}
}
return payload, true
}
@@ -432,6 +545,30 @@ func (c *BackendOaScheduleController) Create() {
return
}
// 开启提醒:生成绑定的提醒任务,并把其 ID 回写到日程。
if payload.ReminderEnabled {
rid, rerr := createOaScheduleReminder(
claims.TenantId,
uint64(claims.UserID),
payload.Title,
payload.Content,
payload.ReminderTime,
payload.RemindChannels,
payload.AdvanceMinutes,
)
if rerr != nil {
// 回滚已创建的日程,避免产生孤立日程
_, _ = models.Orm.QueryTable(new(models.OaSchedule)).Filter("id", item.ID).Delete()
c.oasJsonErr(500, 500, rerr.Error())
return
}
item.ReminderID = rid
if _, err := models.Orm.Update(item, "ReminderID"); err != nil {
c.oasJsonErr(500, 500, "保存失败")
return
}
}
c.oasOk(item)
}
@@ -477,9 +614,34 @@ func (c *BackendOaScheduleController) Update() {
item.Priority = payload.Priority
item.UpdateTime = &now
// 重新绑定提醒:先创建新提醒,成功后再删除旧提醒(关闭提醒则清掉绑定)。
// 顺序反过来可避免"新提醒创建失败却删掉了原提醒"导致提醒丢失。
if payload.ReminderEnabled {
rid, rerr := createOaScheduleReminder(
claims.TenantId,
uint64(claims.UserID),
payload.Title,
payload.Content,
payload.ReminderTime,
payload.RemindChannels,
payload.AdvanceMinutes,
)
if rerr != nil {
c.oasJsonErr(500, 500, rerr.Error())
return
}
if item.ReminderID > 0 {
deleteBoundReminder(item.ReminderID)
}
item.ReminderID = rid
} else if item.ReminderID > 0 {
deleteBoundReminder(item.ReminderID)
item.ReminderID = 0
}
if _, err := models.Orm.Update(&item,
"Title", "Content", "ScheduleDate", "StartTime", "EndTime",
"AllDay", "Color", "Priority", "UpdateTime"); err != nil {
"AllDay", "Color", "Priority", "ReminderID", "UpdateTime"); err != nil {
c.oasJsonErr(500, 500, "保存失败")
return
}
@@ -555,21 +717,31 @@ func (c *BackendOaScheduleController) Delete() {
}
now := time.Now()
n, err := models.Orm.QueryTable(new(models.OaSchedule)).
var item models.OaSchedule
err = models.Orm.QueryTable(new(models.OaSchedule)).
Filter("id", id).
Filter("is_deleted", 0).
Filter("tid", claims.TenantId).
Filter("user_id", claims.UserID).
Update(map[string]interface{}{
"IsDeleted": int8(1),
"DeleteTime": now,
"UpdateTime": now,
})
if err != nil || n == 0 {
One(&item)
if err != nil {
c.oasJsonErr(404, 404, "日程不存在或已删除")
return
}
// 先删除绑定的提醒任务,避免提醒工具里残留孤立任务
if item.ReminderID > 0 {
deleteBoundReminder(item.ReminderID)
}
item.IsDeleted = 1
item.DeleteTime = &now
item.UpdateTime = &now
if _, err := models.Orm.Update(&item, "IsDeleted", "DeleteTime", "UpdateTime"); err != nil {
c.oasJsonErr(500, 500, "删除失败")
return
}
c.oasOk(nil)
}
+2
View File
@@ -138,9 +138,11 @@ func (c *BackendRoleController) CreateRole() {
status = *p.Status
}
rights := normalizeRights(p.Rights)
// 租户端创建的角色一律标记为“自定义角色”,与系统/平台预置角色区分,并按租户隔离
role := &models.AdminRole{
TenantID: tid,
Cid: 2,
IsCustom: 1,
Name: p.Name,
Status: status,
Rights: rights,