更新代码

This commit is contained in:
2026-09-15 10:44:31 +08:00
parent 9875832019
commit 943c3708b0
125 changed files with 2009 additions and 1728 deletions
-2
View File
@@ -31,7 +31,6 @@ func EnsureCrmProjectDocCategory(tid int, projectID uint64, projectName string,
return 0, nil
}
models.EnsureOaDocumentTables()
models.EnsureOaDocDefaultCategories(tid)
// 1. 已绑定且分类仍有效:直接返回
@@ -165,7 +164,6 @@ type ProjectDocFolder struct {
// CrmProjectDocFolderTree 构建项目文件夹树(根为项目文件夹,含全部子孙文件夹)。
// 「项目文档」下的同名文件夹即项目根,用户在项目内新建的文件夹为其子分类。
func CrmProjectDocFolderTree(a OaDocActor, rootID uint64) ([]*ProjectDocFolder, error) {
models.EnsureOaDocumentTables()
empty := []*ProjectDocFolder{}
if rootID == 0 {
return empty, nil
-4
View File
@@ -39,7 +39,6 @@ func FindDuplicate(source, scope string, tid, tuid uint64, md5Str string) (*mode
if md5Str == "" {
return nil, nil
}
models.EnsureSystemFileStorageColumns()
qs := models.Orm.QueryTable(new(models.SystemFile)).
Filter("source", source).
@@ -63,7 +62,6 @@ func FindDuplicate(source, scope string, tid, tuid uint64, md5Str string) (*mode
// CreateFileRecord 写入文件记录(同步写入归属与存储字段)
func CreateFileRecord(p FileUploadParams) (uint64, error) {
models.EnsureSystemFileStorageColumns()
uid := p.Uid
row := &models.SystemFile{
@@ -197,7 +195,6 @@ func SoftDeleteFiles(ids []uint64) (int64, error) {
if len(ids) == 0 {
return 0, nil
}
models.EnsureSystemFileStorageColumns()
return models.Orm.QueryTable(new(models.SystemFile)).
Filter("id__in", ids).
Filter("delete_time__isnull", true).
@@ -209,7 +206,6 @@ func DeleteFilesPermanently(ids []uint64) (int64, error) {
if len(ids) == 0 {
return 0, nil
}
models.EnsureSystemFileStorageColumns()
return models.Orm.QueryTable(new(models.SystemFile)).
Filter("id__in", ids).
Delete()
-20
View File
@@ -55,8 +55,6 @@ type OaDocActor struct {
// NewOaDocActor 构造访问者上下文。
// uid 为 backend 端 JWT 的 UserID,即 yz_system_tenant_user.uid。
func NewOaDocActor(tid int, uid uint64) OaDocActor {
models.EnsureOaDocumentTables()
models.EnsureTenantUserOrgColumn()
// 补建租户自己的系统内置分类(项目文档),按 tid 隔离
models.EnsureOaDocDefaultCategories(tid)
@@ -363,7 +361,6 @@ func oaDocApplyUncategorized(qs orm.QuerySeter, a OaDocActor, scope string) orm.
// scope="shared" 返回共享空间树(租户级),scope="personal" 返回当前用户的私密空间树。
// 系统内置分类(项目文档)置顶;数量统计受可见性约束:无权限的私密文档不计入。
func OaDocCategoryTree(a OaDocActor, scope string) ([]*OaDocCategoryItem, error) {
models.EnsureOaDocumentTables()
scope = oaDocScopeOf(scope)
var list []models.OaDocCategory
@@ -416,7 +413,6 @@ func OaDocCategoryTree(a OaDocActor, scope string) ([]*OaDocCategoryItem, error)
// visibility<0 时按范围自动取对应可见性(共享→公开,私密→私密);可见性约束同样生效:无权限的私密文档不计入。
// scope="all" 时跨两个空间统计(不限定 visibility)。
func OaDocCountByCategory(a OaDocActor, scope string, visibility int) (map[uint64]int64, error) {
models.EnsureOaDocumentTables()
scope = oaDocScopeOf(scope)
sql := "SELECT category_id, COUNT(*) AS cnt FROM yz_backend_oa_doc WHERE tid = ? AND is_deleted = 0"
@@ -461,7 +457,6 @@ func oaDocIsReservedName(name string) bool {
// scope="shared" 创建到共享空间(user_id=0,租户级);scope="personal" 创建到当前用户的私密空间(user_id=uid)。
// 父级分类必须与目标空间一致,否则视为不存在。
func OaDocCategoryCreate(a OaDocActor, scope string, parentID uint64, name, remark string, sort int) (*models.OaDocCategory, error) {
models.EnsureOaDocumentTables()
scope = oaDocScopeOf(scope)
name = strings.TrimSpace(name)
@@ -499,7 +494,6 @@ func OaDocCategoryCreate(a OaDocActor, scope string, parentID uint64, name, rema
// OaDocCategoryUpdate 修改分类名称/备注/排序,parentID < 0 表示不调整父级。
func OaDocCategoryUpdate(a OaDocActor, id uint64, name, remark string, sort int, parentID int64) (*models.OaDocCategory, error) {
models.EnsureOaDocumentTables()
var item models.OaDocCategory
if err := oaDocCategoryBaseAny(a.Tid).Filter("id", id).One(&item); err != nil {
@@ -608,7 +602,6 @@ func oaDocCategoryIDsWithChildren(a OaDocActor, scope string, rootID uint64) ([]
// OaDocCategoryDelete 删除分类:系统内置分类、存在子分类或文档时拒绝删除。
// 共享空间分类任何租户成员均可删除(内置分类除外);私密空间分类仅本人可删除。
func OaDocCategoryDelete(a OaDocActor, id uint64) error {
models.EnsureOaDocumentTables()
var item models.OaDocCategory
if err := oaDocCategoryBaseAny(a.Tid).Filter("id", id).One(&item); err != nil {
@@ -709,7 +702,6 @@ type OaDocListParams struct {
// OaDocList 分页查询文档(自动应用可见性与范围过滤)。
func OaDocList(a OaDocActor, p OaDocListParams) ([]models.OaDoc, int64, error) {
models.EnsureOaDocumentTables()
scope := oaDocScopeOf(p.Scope)
qs := oaDocApplyVisible(oaDocBase(a.Tid), a)
@@ -790,7 +782,6 @@ func OaDocList(a OaDocActor, p OaDocListParams) ([]models.OaDoc, int64, error) {
// OaDocGet 读取文档详情(不累加查看次数)。私密文档对无权限者返回未找到。
func OaDocGet(a OaDocActor, id uint64) (*models.OaDoc, error) {
models.EnsureOaDocumentTables()
var item models.OaDoc
qs := oaDocApplyVisible(oaDocBase(a.Tid).Filter("id", id), a)
@@ -854,7 +845,6 @@ type OaDocSaveParams struct {
// OaDocCreate 新增文档。
// 若未传标题则回退为原始文件名(去扩展名);doc_type 由扩展名推断。
func OaDocCreate(a OaDocActor, operatorName string, p OaDocSaveParams) (*models.OaDoc, error) {
models.EnsureOaDocumentTables()
tid := a.Tid
title := strings.TrimSpace(p.Title)
@@ -925,7 +915,6 @@ func visibilityOf(v int8) int8 {
// OaDocUpdate 编辑文档(仅更新传入的字段)。
func OaDocUpdate(a OaDocActor, id uint64, p OaDocSaveParams) (*models.OaDoc, error) {
models.EnsureOaDocumentTables()
var item models.OaDoc
if err := oaDocApplyVisible(oaDocBase(a.Tid).Filter("id", id), a).One(&item); err != nil {
@@ -1034,7 +1023,6 @@ func OaDocUpdate(a OaDocActor, id uint64, p OaDocSaveParams) (*models.OaDoc, err
// OaDocDelete 批量软删除文档,并清理与被删文档相关的关联关系。
// 仅对"可见且可管理"的文档生效;若给定 ID 全部无权操作则返回 ErrDocNoPermission。
func OaDocDelete(a OaDocActor, ids []uint64) (int64, error) {
models.EnsureOaDocumentTables()
ids = normalizeIDs(ids)
if len(ids) == 0 {
@@ -1078,7 +1066,6 @@ func OaDocDelete(a OaDocActor, ids []uint64) (int64, error) {
// OaDocMove 批量移动文档到目标分类(0 表示未分类)。仅对可管理文档生效。
func OaDocMove(a OaDocActor, ids []uint64, categoryID uint64) (int64, error) {
models.EnsureOaDocumentTables()
ids = normalizeIDs(ids)
if len(ids) == 0 {
@@ -1121,7 +1108,6 @@ func OaDocMove(a OaDocActor, ids []uint64, categoryID uint64) (int64, error) {
// OaDocToggleStar 收藏 / 取消收藏切换,返回切换后的状态。
func OaDocToggleStar(a OaDocActor, id uint64) (int8, error) {
models.EnsureOaDocumentTables()
var item models.OaDoc
if err := oaDocApplyVisible(oaDocBase(a.Tid).Filter("id", id), a).One(&item); err != nil {
@@ -1165,7 +1151,6 @@ type OaDocTypeCount struct {
// OaDocStats 文档库概览:总数、状态分布、类型分布、最近更新与热门文档。
// scope 限定统计口径("shared" 共享文档空间 / "personal" 私密文档空间 / "all" 跨空间);可见性约束同样生效。
func OaDocStats(a OaDocActor, scope string) (*OaDocStatsResult, error) {
models.EnsureOaDocumentTables()
scope = oaDocScopeOf(scope)
vis := int8(-1)
@@ -1290,7 +1275,6 @@ type OaDocLinkItem struct {
// OaDocLinkCreate 建立两个文档之间的关联。
func OaDocLinkCreate(a OaDocActor, creatorID, sourceID, targetID uint64, relation, remark string) (*models.OaDocLink, error) {
models.EnsureOaDocumentTables()
tid := a.Tid
if sourceID == 0 || targetID == 0 {
@@ -1345,7 +1329,6 @@ func OaDocLinkCreate(a OaDocActor, creatorID, sourceID, targetID uint64, relatio
// OaDocLinkDelete 删除关联关系(同时清理反向关系,保证图谱双向一致)。
func OaDocLinkDelete(a OaDocActor, id uint64) error {
models.EnsureOaDocumentTables()
tid := a.Tid
var item models.OaDocLink
@@ -1380,7 +1363,6 @@ func OaDocLinkDelete(a OaDocActor, id uint64) error {
// OaDocLinkList 查询与某文档相关的全部关联(含反向),all 为 true 时返回租户全部关联。
// 仅返回两端文档对当前访问者均可见的关联,避免私密文档被越权探查。
func OaDocLinkList(a OaDocActor, docID uint64, all bool) ([]OaDocLinkItem, error) {
models.EnsureOaDocumentTables()
sql := `
SELECT l.id, l.tid, l.source_id, l.target_id, l.relation, l.remark, l.create_time,
@@ -1576,7 +1558,6 @@ type OaDocMemberItem struct {
// OaDocMembers 查询租户内用户(用于私密文档共享选人)。
func OaDocMembers(tid int, keyword string, limit int) ([]OaDocMemberItem, error) {
models.EnsureOaDocumentTables()
if limit < 1 || limit > 200 {
limit = 100
}
@@ -1705,7 +1686,6 @@ type OaDocGraphResult struct {
// - kind=doc :文档之间的关联关系(yz_backend_oa_doc_link)
// - kind=belong :文档到所属分类的归属关系,使孤立文档也能在图谱中定位
func OaDocGraph(a OaDocActor, p OaDocGraphParams) (*OaDocGraphResult, error) {
models.EnsureOaDocumentTables()
limit := p.Limit
if limit < 1 || limit > 1000 {
+204 -111
View File
@@ -2,6 +2,7 @@ package services
import (
"context"
"encoding/json"
"fmt"
"strconv"
"time"
@@ -89,83 +90,213 @@ func SaveSiteReminderConfig(retentionDays int, autoRead int8) error {
return nil
}
// SendSiteReminder 发送站内信
// targetType: platform (平台端), tenant_all (管理端所有用户), role (平台角色), tenant (特定租户)
func SendSiteReminder(title, content string, senderID uint64, senderType string, targetType string, targetRoleID uint64, targetTenantID uint64) error {
var receiverIDs []uint64
var receiverType string
// reminderReceiver 站内信接收人(用户ID + 所属端类型)
type reminderReceiver struct {
ID uint64
Type string // platform-平台端 tenant-租户端
}
// queryEnabledAdminUserIDs 查询启用的平台用户ID;cond 为附加过滤条件(可为 nil)。
func queryEnabledAdminUserIDs(cond *orm.Condition) ([]uint64, error) {
qs := models.Orm.QueryTable(new(models.AdminUser)).
Filter("status", 1).
Filter("delete_time__isnull", true)
if cond != nil {
qs = qs.SetCond(orm.NewCondition().
And("status", 1).
And("delete_time__isnull", true).
AndCond(cond))
}
var list []models.AdminUser
if _, err := qs.All(&list, "id"); err != nil {
return nil, err
}
ids := make([]uint64, 0, len(list))
for _, u := range list {
ids = append(ids, u.ID)
}
return ids, nil
}
// queryEnabledTenantUserIDs 查询启用的租户用户ID;cond 为附加过滤条件(可为 nil)。
func queryEnabledTenantUserIDs(cond *orm.Condition) ([]uint64, error) {
qs := models.Orm.QueryTable(new(models.SystemTenantUser)).
Filter("status", 1).
Filter("delete_time__isnull", true)
if cond != nil {
qs = qs.SetCond(orm.NewCondition().
And("status", 1).
And("delete_time__isnull", true).
AndCond(cond))
}
var list []models.SystemTenantUser
if _, err := qs.All(&list, "id"); err != nil {
return nil, err
}
ids := make([]uint64, 0, len(list))
for _, u := range list {
ids = append(ids, u.ID)
}
return ids, nil
}
// marshalTargetIDs 将多选目标ID序列化为 JSON 字符串(空列表返回 nil)。
func marshalTargetIDs(targetIDs []uint64) *string {
if len(targetIDs) == 0 {
return nil
}
b, err := json.Marshal(targetIDs)
if err != nil {
return nil
}
s := string(b)
return &s
}
// legacyTargetColumns 旧字段兼容写入:role → target_role_id,tenant → target_tenant_id(取首个)
func legacyTargetColumns(targetType string, targetIDs []uint64) (roleID, tenantID uint64) {
if len(targetIDs) == 0 {
return 0, 0
}
switch targetType {
case "platform":
receiverType = "platform"
var list []models.AdminUser
_, err := models.Orm.QueryTable(new(models.AdminUser)).Filter("status", 1).Filter("delete_time__isnull", true).All(&list, "id")
if err != nil {
return fmt.Errorf("查询平台用户失败: %w", err)
}
for _, u := range list {
receiverIDs = append(receiverIDs, u.ID)
}
case "tenant_all":
receiverType = "tenant"
var list []models.SystemTenantUser
_, err := models.Orm.QueryTable(new(models.SystemTenantUser)).Filter("status", 1).Filter("delete_time__isnull", true).All(&list, "id")
if err != nil {
return fmt.Errorf("查询租户用户失败: %w", err)
}
for _, u := range list {
receiverIDs = append(receiverIDs, u.ID)
}
case "role":
receiverType = "platform"
var list []models.AdminUser
_, err := models.Orm.QueryTable(new(models.AdminUser)).Filter("status", 1).Filter("role_id", targetRoleID).Filter("delete_time__isnull", true).All(&list, "id")
if err != nil {
return fmt.Errorf("根据角色查询用户失败: %w", err)
}
for _, u := range list {
receiverIDs = append(receiverIDs, u.ID)
}
return targetIDs[0], 0
case "tenant":
receiverType = "tenant"
var list []models.SystemTenantUser
_, err := models.Orm.QueryTable(new(models.SystemTenantUser)).Filter("status", 1).Filter("tid", targetTenantID).Filter("delete_time__isnull", true).All(&list, "id")
if err != nil {
return fmt.Errorf("根据租户查询用户失败: %w", err)
return 0, targetIDs[0]
}
return 0, 0
}
// resolveReminderReceivers 解析接收目标 → 接收人集合(按端区分类型,已去重)。
// targetType:
// all 全平台(平台端 + 租户端所有启用用户)
// platform 平台端所有启用用户
// tenant_all 租户端所有租户的启用用户
// tenant_role 指定租户角色(可多选)下的启用用户
// tenant 指定租户(可多选)下的启用用户
// tenant_user 指定租户用户(可多选)
// role 兼容旧数据:指定平台角色(可多选)下的启用用户
func resolveReminderReceivers(targetType string, targetIDs []uint64) ([]reminderReceiver, error) {
receivers := make([]reminderReceiver, 0)
seen := map[string]bool{}
appendIDs := func(ids []uint64, rtype string) {
for _, id := range ids {
if id == 0 {
continue
}
key := fmt.Sprintf("%s_%d", rtype, id)
if seen[key] {
continue
}
seen[key] = true
receivers = append(receivers, reminderReceiver{ID: id, Type: rtype})
}
for _, u := range list {
receiverIDs = append(receiverIDs, u.ID)
}
default:
return fmt.Errorf("未知的发送目标类型: %s", targetType)
}
if len(receiverIDs) == 0 {
switch targetType {
case "all": // 全平台:平台端 + 租户端所有启用用户
adminIDs, err := queryEnabledAdminUserIDs(nil)
if err != nil {
return nil, fmt.Errorf("查询平台用户失败: %w", err)
}
tenantIDs, err := queryEnabledTenantUserIDs(nil)
if err != nil {
return nil, fmt.Errorf("查询租户用户失败: %w", err)
}
appendIDs(adminIDs, "platform")
appendIDs(tenantIDs, "tenant")
case "platform": // 平台端所有启用用户
adminIDs, err := queryEnabledAdminUserIDs(nil)
if err != nil {
return nil, fmt.Errorf("查询平台用户失败: %w", err)
}
appendIDs(adminIDs, "platform")
case "tenant_all": // 租户端所有租户的启用用户
tenantIDs, err := queryEnabledTenantUserIDs(nil)
if err != nil {
return nil, fmt.Errorf("查询租户用户失败: %w", err)
}
appendIDs(tenantIDs, "tenant")
case "tenant_role": // 指定租户角色(可多选)下的启用用户
if len(targetIDs) == 0 {
return nil, fmt.Errorf("请选择接收的租户角色")
}
tenantIDs, err := queryEnabledTenantUserIDs(orm.NewCondition().And("group_id__in", targetIDs))
if err != nil {
return nil, fmt.Errorf("根据租户角色查询用户失败: %w", err)
}
appendIDs(tenantIDs, "tenant")
case "tenant": // 指定租户(可多选)下的启用用户
if len(targetIDs) == 0 {
return nil, fmt.Errorf("请选择接收的租户")
}
tenantIDs, err := queryEnabledTenantUserIDs(orm.NewCondition().And("tid__in", targetIDs))
if err != nil {
return nil, fmt.Errorf("根据租户查询用户失败: %w", err)
}
appendIDs(tenantIDs, "tenant")
case "tenant_user": // 指定租户用户(可多选)
if len(targetIDs) == 0 {
return nil, fmt.Errorf("请选择接收的租户用户")
}
tenantIDs, err := queryEnabledTenantUserIDs(orm.NewCondition().And("id__in", targetIDs))
if err != nil {
return nil, fmt.Errorf("查询租户用户失败: %w", err)
}
appendIDs(tenantIDs, "tenant")
case "role": // 兼容旧数据:平台角色(可多选)下的启用用户
if len(targetIDs) == 0 {
return nil, fmt.Errorf("请选择接收的角色")
}
adminIDs, err := queryEnabledAdminUserIDs(orm.NewCondition().And("role_id__in", targetIDs))
if err != nil {
return nil, fmt.Errorf("根据角色查询用户失败: %w", err)
}
appendIDs(adminIDs, "platform")
default:
return nil, fmt.Errorf("未知的发送目标类型: %s", targetType)
}
return receivers, nil
}
// SendSiteReminder 发送站内信
// targetType: all (全平台), platform (平台端), tenant_all (租户端所有租户),
// tenant_role (租户角色), tenant (指定租户), tenant_user (指定租户用户), role (平台角色-旧)
func SendSiteReminder(title, content string, senderID uint64, senderType string, targetType string, targetIDs []uint64) error {
receivers, err := resolveReminderReceivers(targetType, targetIDs)
if err != nil {
return err
}
if len(receivers) == 0 {
return nil
}
targetIDsJSON := marshalTargetIDs(targetIDs)
legacyRoleID, legacyTenantID := legacyTargetColumns(targetType, targetIDs)
now := time.Now()
batchID := fmt.Sprintf("%d_%d", now.UnixNano(), senderID)
var reminders []models.SystemReminderList
for _, rid := range receiverIDs {
reminders := make([]models.SystemReminderList, 0, len(receivers))
for _, r := range receivers {
reminders = append(reminders, models.SystemReminderList{
Title: title,
Content: content,
SenderID: senderID,
SenderType: senderType,
ReceiverID: rid,
ReceiverType: receiverType,
ReceiverID: r.ID,
ReceiverType: r.Type,
IsRead: 0,
CreateTime: &now,
BatchID: batchID,
TargetType: targetType,
TargetRoleID: targetRoleID,
TargetTenantID: targetTenantID,
TargetIDs: targetIDsJSON,
TargetRoleID: legacyRoleID,
TargetTenantID: legacyTenantID,
})
}
// 批量插入
_, err := models.Orm.InsertMulti(100, reminders)
_, err = models.Orm.InsertMulti(100, reminders)
return err
}
@@ -280,7 +411,7 @@ func ListSentReminders(senderID uint64, page, pageSize int) ([]models.SystemRemi
}
// UpdateSentReminder 更新已发出的消息(更新该批次下所有接收者的消息,支持修改目标接收群体)
func UpdateSentReminder(batchID string, title, content, targetType string, targetRoleID, targetTenantID uint64) error {
func UpdateSentReminder(batchID string, title, content, targetType string, targetIDs []uint64) error {
// 1. 获取当前发送者ID (从该批次中任意一条记录中获取)
var firstRecord models.SystemReminderList
err := models.Orm.QueryTable(new(models.SystemReminderList)).Filter("batch_id", batchID).Limit(1).One(&firstRecord)
@@ -291,54 +422,14 @@ func UpdateSentReminder(batchID string, title, content, targetType string, targe
senderType := firstRecord.SenderType
// 2. 根据新的目标接收群体获取接收人列表
var receiverIDs []uint64
var receiverType string
switch targetType {
case "platform":
receiverType = "platform"
var list []models.AdminUser
_, err := models.Orm.QueryTable(new(models.AdminUser)).Filter("status", 1).Filter("delete_time__isnull", true).All(&list, "id")
if err != nil {
return fmt.Errorf("查询平台用户失败: %w", err)
}
for _, u := range list {
receiverIDs = append(receiverIDs, u.ID)
}
case "tenant_all":
receiverType = "tenant"
var list []models.SystemTenantUser
_, err := models.Orm.QueryTable(new(models.SystemTenantUser)).Filter("status", 1).Filter("delete_time__isnull", true).All(&list, "id")
if err != nil {
return fmt.Errorf("查询租户用户失败: %w", err)
}
for _, u := range list {
receiverIDs = append(receiverIDs, u.ID)
}
case "role":
receiverType = "platform"
var list []models.AdminUser
_, err := models.Orm.QueryTable(new(models.AdminUser)).Filter("status", 1).Filter("role_id", targetRoleID).Filter("delete_time__isnull", true).All(&list, "id")
if err != nil {
return fmt.Errorf("根据角色查询用户失败: %w", err)
}
for _, u := range list {
receiverIDs = append(receiverIDs, u.ID)
}
case "tenant":
receiverType = "tenant"
var list []models.SystemTenantUser
_, err := models.Orm.QueryTable(new(models.SystemTenantUser)).Filter("status", 1).Filter("tid", targetTenantID).Filter("delete_time__isnull", true).All(&list, "id")
if err != nil {
return fmt.Errorf("根据租户查询用户失败: %w", err)
}
for _, u := range list {
receiverIDs = append(receiverIDs, u.ID)
}
default:
return fmt.Errorf("未知的发送目标类型: %s", targetType)
receivers, err := resolveReminderReceivers(targetType, targetIDs)
if err != nil {
return err
}
targetIDsJSON := marshalTargetIDs(targetIDs)
legacyRoleID, legacyTenantID := legacyTargetColumns(targetType, targetIDs)
// 3. 获取该批次中现有的所有记录 (包括已删除的)
var existingRecords []models.SystemReminderList
_, err = models.Orm.QueryTable(new(models.SystemReminderList)).Filter("batch_id", batchID).All(&existingRecords)
@@ -354,8 +445,8 @@ func UpdateSentReminder(batchID string, title, content, targetType string, targe
}
newReceiverMap := make(map[string]bool)
for _, rid := range receiverIDs {
key := fmt.Sprintf("%s_%d", receiverType, rid)
for _, r := range receivers {
key := fmt.Sprintf("%s_%d", r.Type, r.ID)
newReceiverMap[key] = true
}
@@ -377,16 +468,17 @@ func UpdateSentReminder(batchID string, title, content, targetType string, targe
// B. 对于仍然在新接收者列表中的用户,更新标题、内容、以及 target 信息;如果原来被删除了,清除 delete_time
var newInserts []models.SystemReminderList
for _, rid := range receiverIDs {
key := fmt.Sprintf("%s_%d", receiverType, rid)
for _, r := range receivers {
key := fmt.Sprintf("%s_%d", r.Type, r.ID)
if rec, exists := existingMap[key]; exists {
rec.Title = title
rec.Content = content
rec.TargetType = targetType
rec.TargetRoleID = targetRoleID
rec.TargetTenantID = targetTenantID
cols := []string{"Title", "Content", "TargetType", "TargetRoleID", "TargetTenantID"}
rec.TargetIDs = targetIDsJSON
rec.TargetRoleID = legacyRoleID
rec.TargetTenantID = legacyTenantID
cols := []string{"Title", "Content", "TargetType", "TargetIDs", "TargetRoleID", "TargetTenantID"}
if rec.DeleteTime != nil {
rec.DeleteTime = nil
rec.IsRead = 0
@@ -403,14 +495,15 @@ func UpdateSentReminder(batchID string, title, content, targetType string, targe
Content: content,
SenderID: senderID,
SenderType: senderType,
ReceiverID: rid,
ReceiverType: receiverType,
ReceiverID: r.ID,
ReceiverType: r.Type,
IsRead: 0,
CreateTime: &now,
BatchID: batchID,
TargetType: targetType,
TargetRoleID: targetRoleID,
TargetTenantID: targetTenantID,
TargetIDs: targetIDsJSON,
TargetRoleID: legacyRoleID,
TargetTenantID: legacyTenantID,
})
}
}
-4
View File
@@ -8,10 +8,6 @@ import (
// BindTenantUser 绑定用户到租户(若已存在则更新状态/默认值)
func BindTenantUser(tid, uid uint64, account, name, phone, email *string, sex *uint8, birth *string, password *string, isDefault, status int8, remark *string) (uint64, error) {
// 确保 group_id(角色)列存在,避免老表插入时报 Unknown column。
// INSERT 会带上该列,列不存在会直接失败,故必须在写入前补齐。
models.EnsureTenantUserGroupColumn()
var existed models.SystemTenantUser
err := models.Orm.QueryTable(new(models.SystemTenantUser)).
Filter("tid", tid).