Files
yunzerwebsiteallinone/go/controllers/backend_crm_permission.go
T
2026-09-13 22:31:42 +08:00

139 lines
4.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package controllers
import (
"fmt"
"strings"
"server/models"
"server/pkg/jwtutil"
"github.com/beego/beego/v2/client/orm"
)
// CRM 客户 / 供应商的删除权限规则:
// 1. 平台管理员(UserType=platform)可删除;
// 2. 租户管理员(绑定「租户管理员」角色,或未分配角色/角色未配置权限等既有"全权限"情形)可删除;
// 3. 记录的创建人可删除自己创建的记录。
// 其余用户一律禁止删除。删除本身为软删除(置 delete_time)。
// canDeleteCrmRecord 判断当前用户是否有权删除指定记录。
// createUserID 为记录的创建人用户ID(历史数据可能为空)。
func canDeleteCrmRecord(claims *jwtutil.Claims, createUserID string) bool {
if claims == nil {
return false
}
// 平台管理员
if claims.UserType == "platform" {
return true
}
// 创建人本人
uid := fmt.Sprintf("%d", claims.UserID)
if createUserID != "" && createUserID == uid {
return true
}
// 租户管理员 / 具备全权限的租户用户
return isTenantAdmin(claims.UserID, claims.TenantId)
}
// isTenantAdmin 判断用户在指定租户内是否具备管理员(全权限)身份。
// 判定与既有权限约定保持一致:
// - 未分配角色(group_id=0)视为全权限;
// - 角色名为「租户管理员」视为管理员;
// - 角色未配置 rights(空/空数组/null)视为全权限。
func isTenantAdmin(userID int, tenantID int) bool {
if tenantID <= 0 || models.Orm == nil {
return false
}
var tu models.SystemTenantUser
if err := models.Orm.QueryTable(new(models.SystemTenantUser)).
Filter("uid", userID).
Filter("tid", tenantID).
Filter("delete_time__isnull", true).
One(&tu); err != nil {
return false
}
if tu.GroupID == 0 {
return true
}
var role models.AdminRole
if err := models.Orm.QueryTable(new(models.AdminRole)).
Filter("id", tu.GroupID).
Filter("cid", 2).
Filter("tenant_id", tenantID).
One(&role); err != nil {
return false
}
if role.Name == "租户管理员" {
return true
}
rights := ""
if role.Rights != nil {
rights = strings.TrimSpace(*role.Rights)
}
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
}