优化项目管理

This commit is contained in:
2026-09-13 22:31:42 +08:00
parent 2f6cdbb3cd
commit a8c09c1db5
30 changed files with 1654 additions and 346 deletions
+66
View File
@@ -6,6 +6,8 @@ import (
"server/models"
"server/pkg/jwtutil"
"github.com/beego/beego/v2/client/orm"
)
// CRM 客户 / 供应商的删除权限规则:
@@ -70,3 +72,67 @@ func isTenantAdmin(userID int, tenantID int) bool {
}
return rights == "" || rights == "[]" || rights == "null"
}
// ========================== CRM 数据范围(用户级隔离) ==========================
//
// 数据可见范围约定(仅作用于用户级业务数据):
// - 平台管理员 / 租户管理员(含未分配角色、角色未配置权限等全权限情形)→ 可见租户内全部数据;
// - 其他用户 → 仅可见「负责人是自己」或「由自己创建」的数据。
//
// 租户共享数据不在此列,始终对全租户可见:供应商、客户公海、产品列表、产品分类。
// 后续如需按角色配置数据范围,只需扩展 crmScopeSelfOnly 的判定。
// crmScopeSelfOnly 判断当前用户是否只能看「本人」数据(true=仅本人)。
func crmScopeSelfOnly(claims *jwtutil.Claims) bool {
if claims == nil {
return true
}
if claims.UserType == "platform" {
return false
}
return !isTenantAdmin(claims.UserID, claims.TenantId)
}
// crmApplyOwnerScope 为列表查询条件追加数据范围限制(需要「仅本人」时)。
// 需要用户级隔离的模块请在构造完 tenant 条件后调用。
func crmApplyOwnerScope(cond *orm.Condition, claims *jwtutil.Claims) *orm.Condition {
if !crmScopeSelfOnly(claims) {
return cond
}
uid := pipelineUID(claims)
return cond.AndCond(orm.NewCondition().
Or("owner_user_id", uid).
Or("create_user_id", uid))
}
// canAccessCrmRecord 判断当前用户是否有权访问(查看 / 编辑 / 删除)指定记录。
// ownerUserID / createUserID 为记录的负责人与创建人(历史数据可能为空)。
func canAccessCrmRecord(claims *jwtutil.Claims, ownerUserID, createUserID string) bool {
if claims == nil {
return false
}
// 平台 / 租户管理员可访问全部
if !crmScopeSelfOnly(claims) {
return true
}
uid := pipelineUID(claims)
if ownerUserID != "" && ownerUserID == uid {
return true
}
return createUserID != "" && createUserID == uid
}
// crmNameDuplicated 判断同租户内是否已存在同名记录(不含软删除),用于创建时的唯一性校验。
// model 传 new(models.XXX);nameField 为数据库列名(如 clue_name)。
func crmNameDuplicated(model interface{}, tenantID, nameField, name string) bool {
name = strings.TrimSpace(name)
if name == "" || strings.TrimSpace(tenantID) == "" || models.Orm == nil {
return false
}
cnt, err := models.Orm.QueryTable(model).
Filter("tenant_id", tenantID).
Filter("delete_time__isnull", true).
Filter(nameField, name).
Count()
return err == nil && cnt > 0
}