Files
yunzerwebsiteallinone/go/controllers/backend_dict.go
T
2026-09-28 23:16:26 +08:00

816 lines
22 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 (
"encoding/json"
"fmt"
"io"
"regexp"
"strconv"
"strings"
"time"
"server/models"
"server/pkg/jwtutil"
"github.com/beego/beego/v2/client/orm"
beego "github.com/beego/beego/v2/server/web"
)
// BackendDictController 租户端数据字典:字典列表 + 字典项
//
// 表:yz_backend_dict / yz_backend_dict_item(建表 SQL:docs/sql/create_dict.sql)。
// 按 tenant_id 隔离(取 JWT 里的租户ID,前端不传),与 yz_backend_erp_supplier 一致。
// 平台端字典见 PlatformDictController(/platform/dict/*)。
type BackendDictController struct {
beego.Controller
}
// globalDictTenantID 全局内置字典的租户标记:所有租户可见、只读,
// 与 yz_system_admin_role 中 tenant_id=0 的「全局租户角色」同一套约定。
// 租户要改动时就按相同 dict_code 建一份自己的字典覆盖它。
const globalDictTenantID = "0"
var backendDictCodeRe = regexp.MustCompile(`^[a-zA-Z][a-zA-Z0-9_]{0,99}$`)
var backendDictTagTypes = map[string]bool{
"": true,
"primary": true,
"success": true,
"warning": true,
"danger": true,
"info": true,
}
func (c *BackendDictController) dictClaims() (*jwtutil.Claims, error) {
auth := c.Ctx.Request.Header.Get("Authorization")
if auth == "" {
return nil, fmt.Errorf("未登录")
}
parts := strings.SplitN(auth, " ", 2)
if len(parts) != 2 || parts[0] != "Bearer" {
return nil, fmt.Errorf("认证信息格式错误")
}
claims, err := jwtutil.ParseToken(parts[1])
if err != nil {
return nil, fmt.Errorf("无效的token")
}
if claims.UserType != "backend" {
return nil, fmt.Errorf("无权访问")
}
return claims, nil
}
func (c *BackendDictController) dictErr(httpStatus, bizCode int, msg string) {
c.Ctx.Output.SetStatus(httpStatus)
c.Data["json"] = map[string]interface{}{"code": bizCode, "msg": msg}
_ = c.ServeJSON()
}
func (c *BackendDictController) dictOk(data interface{}, msg string) {
if msg == "" {
msg = "success"
}
resp := map[string]interface{}{"code": 200, "msg": msg}
if data != nil {
resp["data"] = data
}
c.Data["json"] = resp
_ = c.ServeJSON()
}
type backendDictTypePayload struct {
DictName string `json:"dict_name"`
DictCode string `json:"dict_code"`
Remark string `json:"remark"`
Sort int `json:"sort"`
Status *int8 `json:"status"`
}
type backendDictItemPayload struct {
DictID uint64 `json:"dict_id"`
ItemLabel string `json:"item_label"`
ItemValue string `json:"item_value"`
TagType string `json:"tag_type"`
Remark string `json:"remark"`
Sort int `json:"sort"`
Status *int8 `json:"status"`
IsDefault *int8 `json:"is_default"`
}
// backendDictRow 字典列表行:在实体上追加「是否全局内置」,供前端禁用编辑/删除
type backendDictRow struct {
models.BackendDict
IsGlobal bool `json:"is_global"`
}
// dictTenantScope 当前请求可见的字典租户范围:全局内置 + 本租户自己的
func dictTenantScope(claims *jwtutil.Claims) []string {
return []string{globalDictTenantID, strconv.Itoa(claims.TenantId)}
}
// findVisibleDict 按编码取当前租户可见的字典:优先本租户自己的,没有再回落全局内置
func findVisibleDict(tenantID, code string) (*models.BackendDict, error) {
var dicts []models.BackendDict
if _, err := models.Orm.QueryTable(new(models.BackendDict)).
Filter("dict_code", code).
Filter("tenant_id__in", []string{globalDictTenantID, tenantID}).
Filter("status", 1).
Filter("delete_time__isnull", true).
All(&dicts); err != nil {
return nil, err
}
for i := range dicts {
if dicts[i].TenantID == tenantID {
return &dicts[i], nil
}
}
if len(dicts) > 0 {
return &dicts[0], nil
}
return nil, orm.ErrNoRows
}
// isGlobalDictRow 全局内置字典:任何租户都不允许修改 / 删除
func isGlobalDictRow(tenantID string) bool { return tenantID == globalDictTenantID }
/* ---------------- 字典列表 ---------------- */
// ListTypes GET /backend/dict/types
func (c *BackendDictController) ListTypes() {
claims, err := c.dictClaims()
if err != nil {
c.dictErr(401, 401, err.Error())
return
}
page, pageSize, offset := dictPageSize(&c.Controller)
keyword := strings.TrimSpace(c.GetString("keyword"))
status := strings.TrimSpace(c.GetString("status"))
// 可见范围:全局内置 + 本租户自己的(同编码时两条都会出现,各自带 is_global 标记)
cond := orm.NewCondition().
And("tenant_id__in", dictTenantScope(claims)).
And("delete_time__isnull", true)
if keyword != "" {
cond = cond.AndCond(orm.NewCondition().
Or("dict_name__contains", keyword).
Or("dict_code__contains", keyword))
}
if status != "" {
if v, err := strconv.Atoi(status); err == nil {
cond = cond.And("status", v)
}
}
qs := models.Orm.QueryTable(new(models.BackendDict)).SetCond(cond)
total, err := qs.Count()
if err != nil {
c.dictErr(500, 500, "查询失败: "+err.Error())
return
}
var list []models.BackendDict
if _, err := qs.OrderBy("sort", "id").Limit(pageSize, offset).All(&list); err != nil {
c.dictErr(500, 500, "查询失败: "+err.Error())
return
}
rows := make([]backendDictRow, 0, len(list))
for _, r := range list {
rows = append(rows, backendDictRow{BackendDict: r, IsGlobal: isGlobalDictRow(r.TenantID)})
}
c.dictOk(map[string]interface{}{
"list": rows,
"total": total,
"page": page,
"pageSize": pageSize,
}, "")
}
// CreateType POST /backend/dict/types
func (c *BackendDictController) CreateType() {
claims, err := c.dictClaims()
if err != nil {
c.dictErr(401, 401, err.Error())
return
}
body, _ := io.ReadAll(c.Ctx.Request.Body)
var p backendDictTypePayload
if err := json.Unmarshal(body, &p); err != nil {
c.dictErr(400, 400, "参数错误")
return
}
p.DictName = strings.TrimSpace(p.DictName)
p.DictCode = strings.TrimSpace(p.DictCode)
p.Remark = strings.TrimSpace(p.Remark)
if p.DictName == "" {
c.dictErr(400, 400, "字典名称不能为空")
return
}
if !backendDictCodeRe.MatchString(p.DictCode) {
c.dictErr(400, 400, "字典编码以字母开头,只能包含字母、数字与下划线")
return
}
tenantID := fmt.Sprintf("%d", claims.TenantId)
exist, _ := models.Orm.QueryTable(new(models.BackendDict)).
Filter("tenant_id", tenantID).
Filter("dict_code", p.DictCode).
Filter("delete_time__isnull", true).
Count()
if exist > 0 {
c.dictErr(400, 400, "字典编码已存在")
return
}
status := int8(1)
if p.Status != nil {
status = *p.Status
}
now := time.Now()
row := &models.BackendDict{
TenantID: tenantID,
DictName: p.DictName,
DictCode: p.DictCode,
Remark: p.Remark,
Sort: p.Sort,
Status: status,
CreateUserID: strconv.Itoa(claims.UserID),
UpdateTime: &now,
}
id, err := models.Orm.Insert(row)
if err != nil {
c.dictErr(500, 500, "新增失败: "+err.Error())
return
}
row.ID = uint64(id)
c.dictOk(row, "新增成功")
}
// UpdateType PUT /backend/dict/types/:id
// 编码是业务取值依据,不允许修改。
func (c *BackendDictController) UpdateType() {
claims, err := c.dictClaims()
if err != nil {
c.dictErr(401, 401, err.Error())
return
}
id := dictPathID(&c.Controller)
if id == 0 {
c.dictErr(400, 400, "无效的ID")
return
}
body, _ := io.ReadAll(c.Ctx.Request.Body)
var p backendDictTypePayload
if err := json.Unmarshal(body, &p); err != nil {
c.dictErr(400, 400, "参数错误")
return
}
p.DictName = strings.TrimSpace(p.DictName)
p.Remark = strings.TrimSpace(p.Remark)
if p.DictName == "" {
c.dictErr(400, 400, "字典名称不能为空")
return
}
var row models.BackendDict
if err := models.Orm.QueryTable(new(models.BackendDict)).
Filter("id", id).
Filter("tenant_id__in", dictTenantScope(claims)).
Filter("delete_time__isnull", true).
One(&row); err != nil {
c.dictErr(404, 404, "字典不存在")
return
}
if isGlobalDictRow(row.TenantID) {
c.dictErr(403, 403, "系统内置字典不可修改,如需调整请在当前租户下按相同编码新建一份")
return
}
now := time.Now()
row.DictName = p.DictName
row.Remark = p.Remark
row.Sort = p.Sort
if p.Status != nil {
row.Status = *p.Status
}
row.UpdateTime = &now
if _, err := models.Orm.Update(&row); err != nil {
c.dictErr(500, 500, "保存失败: "+err.Error())
return
}
c.dictOk(row, "保存成功")
}
// DeleteType DELETE /backend/dict/types/:id
// 字典下还有字典项时拒绝删除,避免留下孤儿数据。
func (c *BackendDictController) DeleteType() {
claims, err := c.dictClaims()
if err != nil {
c.dictErr(401, 401, err.Error())
return
}
id := dictPathID(&c.Controller)
if id == 0 {
c.dictErr(400, 400, "无效的ID")
return
}
var row models.BackendDict
if err := models.Orm.QueryTable(new(models.BackendDict)).
Filter("id", id).
Filter("tenant_id__in", dictTenantScope(claims)).
Filter("delete_time__isnull", true).
One(&row); err != nil {
c.dictErr(404, 404, "字典不存在")
return
}
if isGlobalDictRow(row.TenantID) {
c.dictErr(403, 403, "系统内置字典不可删除,如需调整请在当前租户下按相同编码新建一份")
return
}
cnt, _ := models.Orm.QueryTable(new(models.BackendDictItem)).
Filter("dict_id", id).
Filter("delete_time__isnull", true).
Count()
if cnt > 0 {
c.dictErr(400, 400, fmt.Sprintf("该字典下还有 %d 个字典项,请先删除字典项", cnt))
return
}
now := time.Now()
if _, err := models.Orm.QueryTable(new(models.BackendDict)).
Filter("id", id).
Update(orm.Params{"delete_time": now, "update_time": now}); err != nil {
c.dictErr(500, 500, "删除失败: "+err.Error())
return
}
c.dictOk(nil, "删除成功")
}
/* ---------------- 字典项 ---------------- */
// ListItems GET /backend/dict/items
func (c *BackendDictController) ListItems() {
claims, err := c.dictClaims()
if err != nil {
c.dictErr(401, 401, err.Error())
return
}
dictID, _ := c.GetInt64("dict_id")
if dictID <= 0 {
c.dictErr(400, 400, "dict_id 不能为空")
return
}
// 字典必须在本租户可见范围内(自己的或全局内置),避免越权读取他人字典
var dict models.BackendDict
if err := models.Orm.QueryTable(new(models.BackendDict)).
Filter("id", dictID).
Filter("tenant_id__in", dictTenantScope(claims)).
Filter("delete_time__isnull", true).
One(&dict); err != nil {
c.dictErr(404, 404, "字典不存在")
return
}
page, pageSize, offset := dictPageSize(&c.Controller)
keyword := strings.TrimSpace(c.GetString("keyword"))
status := strings.TrimSpace(c.GetString("status"))
// 字典项跟随所属字典的租户:全局内置字典的项对所有租户可见
cond := orm.NewCondition().
And("tenant_id", dict.TenantID).
And("dict_id", dictID).
And("delete_time__isnull", true)
if keyword != "" {
cond = cond.AndCond(orm.NewCondition().
Or("item_label__contains", keyword).
Or("item_value__contains", keyword))
}
if status != "" {
if v, err := strconv.Atoi(status); err == nil {
cond = cond.And("status", v)
}
}
qs := models.Orm.QueryTable(new(models.BackendDictItem)).SetCond(cond)
total, err := qs.Count()
if err != nil {
c.dictErr(500, 500, "查询失败: "+err.Error())
return
}
var list []models.BackendDictItem
if _, err := qs.OrderBy("sort", "id").Limit(pageSize, offset).All(&list); err != nil {
c.dictErr(500, 500, "查询失败: "+err.Error())
return
}
c.dictOk(map[string]interface{}{
"list": list,
"total": total,
"page": page,
"pageSize": pageSize,
}, "")
}
// CreateItem POST /backend/dict/items
func (c *BackendDictController) CreateItem() {
claims, err := c.dictClaims()
if err != nil {
c.dictErr(401, 401, err.Error())
return
}
body, _ := io.ReadAll(c.Ctx.Request.Body)
var p backendDictItemPayload
if err := json.Unmarshal(body, &p); err != nil {
c.dictErr(400, 400, "参数错误")
return
}
p.ItemLabel = strings.TrimSpace(p.ItemLabel)
p.ItemValue = strings.TrimSpace(p.ItemValue)
p.TagType = strings.TrimSpace(p.TagType)
p.Remark = strings.TrimSpace(p.Remark)
if p.DictID == 0 {
c.dictErr(400, 400, "dict_id 不能为空")
return
}
if p.ItemLabel == "" {
c.dictErr(400, 400, "字典项名称不能为空")
return
}
if p.ItemValue == "" {
c.dictErr(400, 400, "字典项值不能为空")
return
}
if !backendDictTagTypes[p.TagType] {
c.dictErr(400, 400, "标签色只能是 primary/success/warning/danger/info 之一")
return
}
tenantID := fmt.Sprintf("%d", claims.TenantId)
var dict models.BackendDict
if err := models.Orm.QueryTable(new(models.BackendDict)).
Filter("id", p.DictID).
Filter("tenant_id__in", dictTenantScope(claims)).
Filter("delete_time__isnull", true).
One(&dict); err != nil {
c.dictErr(404, 404, "字典不存在")
return
}
if isGlobalDictRow(dict.TenantID) {
c.dictErr(403, 403, "系统内置字典不可新增字典项,如需调整请在当前租户下按相同编码新建一份")
return
}
cnt, _ := models.Orm.QueryTable(new(models.BackendDictItem)).
Filter("tenant_id", tenantID).
Filter("dict_id", p.DictID).
Filter("item_value", p.ItemValue).
Filter("delete_time__isnull", true).
Count()
if cnt > 0 {
c.dictErr(400, 400, "同一字典下的字典项值不能重复")
return
}
status := int8(1)
if p.Status != nil {
status = *p.Status
}
isDefault := int8(0)
if p.IsDefault != nil {
isDefault = *p.IsDefault
}
now := time.Now()
row := &models.BackendDictItem{
TenantID: tenantID,
DictID: p.DictID,
ItemLabel: p.ItemLabel,
ItemValue: p.ItemValue,
TagType: p.TagType,
Sort: p.Sort,
Status: status,
IsDefault: isDefault,
Remark: p.Remark,
UpdateTime: &now,
}
id, err := models.Orm.Insert(row)
if err != nil {
c.dictErr(500, 500, "新增失败: "+err.Error())
return
}
row.ID = uint64(id)
c.dictOk(row, "新增成功")
}
// UpdateItem PUT /backend/dict/items/:id
// 字典项值是业务入库值,不允许修改,避免存量数据对不上。
func (c *BackendDictController) UpdateItem() {
claims, err := c.dictClaims()
if err != nil {
c.dictErr(401, 401, err.Error())
return
}
id := dictPathID(&c.Controller)
if id == 0 {
c.dictErr(400, 400, "无效的ID")
return
}
body, _ := io.ReadAll(c.Ctx.Request.Body)
var p backendDictItemPayload
if err := json.Unmarshal(body, &p); err != nil {
c.dictErr(400, 400, "参数错误")
return
}
p.ItemLabel = strings.TrimSpace(p.ItemLabel)
p.TagType = strings.TrimSpace(p.TagType)
p.Remark = strings.TrimSpace(p.Remark)
if p.ItemLabel == "" {
c.dictErr(400, 400, "字典项名称不能为空")
return
}
if !backendDictTagTypes[p.TagType] {
c.dictErr(400, 400, "标签色只能是 primary/success/warning/danger/info 之一")
return
}
var row models.BackendDictItem
if err := models.Orm.QueryTable(new(models.BackendDictItem)).
Filter("id", id).
Filter("tenant_id", fmt.Sprintf("%d", claims.TenantId)).
Filter("delete_time__isnull", true).
One(&row); err != nil {
c.dictErr(404, 404, "字典项不存在")
return
}
now := time.Now()
row.ItemLabel = p.ItemLabel
row.TagType = p.TagType
row.Sort = p.Sort
row.Remark = p.Remark
if p.Status != nil {
row.Status = *p.Status
}
if p.IsDefault != nil {
row.IsDefault = *p.IsDefault
}
row.UpdateTime = &now
if _, err := models.Orm.Update(&row); err != nil {
c.dictErr(500, 500, "保存失败: "+err.Error())
return
}
c.dictOk(row, "保存成功")
}
// ToggleItemStatus POST /backend/dict/items/:id/status
func (c *BackendDictController) ToggleItemStatus() {
claims, err := c.dictClaims()
if err != nil {
c.dictErr(401, 401, err.Error())
return
}
id := dictPathID(&c.Controller)
if id == 0 {
c.dictErr(400, 400, "无效的ID")
return
}
body, _ := io.ReadAll(c.Ctx.Request.Body)
var p struct {
Status *int8 `json:"status"`
}
if err := json.Unmarshal(body, &p); err != nil || p.Status == nil {
c.dictErr(400, 400, "参数错误")
return
}
if *p.Status != 0 && *p.Status != 1 {
c.dictErr(400, 400, "状态只能是 0 或 1")
return
}
tenantID := fmt.Sprintf("%d", claims.TenantId)
var row models.BackendDictItem
if err := models.Orm.QueryTable(new(models.BackendDictItem)).
Filter("id", id).
Filter("tenant_id", tenantID).
Filter("delete_time__isnull", true).
One(&row); err != nil {
c.dictErr(404, 404, "字典项不存在")
return
}
now := time.Now()
if _, err := models.Orm.QueryTable(new(models.BackendDictItem)).
Filter("id", id).
Update(orm.Params{"status": *p.Status, "update_time": now}); err != nil {
c.dictErr(500, 500, "操作失败: "+err.Error())
return
}
c.dictOk(nil, "操作成功")
}
// DeleteItem DELETE /backend/dict/items/:id
func (c *BackendDictController) DeleteItem() {
claims, err := c.dictClaims()
if err != nil {
c.dictErr(401, 401, err.Error())
return
}
id := dictPathID(&c.Controller)
if id == 0 {
c.dictErr(400, 400, "无效的ID")
return
}
var row models.BackendDictItem
if err := models.Orm.QueryTable(new(models.BackendDictItem)).
Filter("id", id).
Filter("tenant_id", fmt.Sprintf("%d", claims.TenantId)).
Filter("delete_time__isnull", true).
One(&row); err != nil {
c.dictErr(404, 404, "字典项不存在")
return
}
now := time.Now()
if _, err := models.Orm.QueryTable(new(models.BackendDictItem)).
Filter("id", id).
Update(orm.Params{"delete_time": now, "update_time": now}); err != nil {
c.dictErr(500, 500, "删除失败: "+err.Error())
return
}
c.dictOk(nil, "删除成功")
}
/* ---------------- 业务读取 ---------------- */
// OptionsAll GET /backend/dict/options
// 一次取回本租户可见的全部「启用」字典项(全局内置 + 本租户自己的,同编码租户优先),
// 供前端登录后预热缓存:之后页面按任意 dict_code 都能同步读到。
func (c *BackendDictController) OptionsAll() {
claims, err := c.dictClaims()
if err != nil {
c.dictErr(401, 401, err.Error())
return
}
tenantID := strconv.Itoa(claims.TenantId)
result := map[string][]models.BackendDictItem{}
var dicts []models.BackendDict
if _, err := models.Orm.QueryTable(new(models.BackendDict)).
Filter("tenant_id__in", dictTenantScope(claims)).
Filter("status", 1).
Filter("delete_time__isnull", true).
All(&dicts); err != nil {
c.dictErr(500, 500, "查询失败: "+err.Error())
return
}
// 同编码优先本租户:先记录全局,再用租户自己的覆盖
chosen := map[string]uint64{}
for _, d := range dicts {
if _, ok := chosen[d.DictCode]; !ok || d.TenantID == tenantID {
chosen[d.DictCode] = d.ID
}
}
if len(chosen) == 0 {
c.dictOk(map[string]interface{}{"dicts": result}, "")
return
}
ids := make([]uint64, 0, len(chosen))
codeByID := make(map[uint64]string, len(chosen))
for code, id := range chosen {
ids = append(ids, id)
codeByID[id] = code
result[code] = []models.BackendDictItem{}
}
var items []models.BackendDictItem
if _, err := models.Orm.QueryTable(new(models.BackendDictItem)).
Filter("dict_id__in", ids).
Filter("status", 1).
Filter("delete_time__isnull", true).
OrderBy("sort", "id").
All(&items); err != nil {
c.dictErr(500, 500, "查询失败: "+err.Error())
return
}
for _, it := range items {
code := codeByID[it.DictID]
result[code] = append(result[code], it)
}
c.dictOk(map[string]interface{}{"dicts": result}, "")
}
// OptionsBatch POST /backend/dict/options
// 一次取多个字典的启用项,供前端预加载(body: {"codes":[...]})。
// 同编码时优先本租户自己的字典,没有再回落全局内置字典。
func (c *BackendDictController) OptionsBatch() {
claims, err := c.dictClaims()
if err != nil {
c.dictErr(401, 401, err.Error())
return
}
body, _ := io.ReadAll(c.Ctx.Request.Body)
var p struct {
Codes []string `json:"codes"`
}
if err := json.Unmarshal(body, &p); err != nil {
c.dictErr(400, 400, "参数错误")
return
}
result := map[string][]models.BackendDictItem{}
codes := make([]string, 0, len(p.Codes))
for _, code := range p.Codes {
code = strings.TrimSpace(code)
if code == "" {
continue
}
if _, ok := result[code]; ok {
continue
}
result[code] = []models.BackendDictItem{}
codes = append(codes, code)
}
if len(codes) == 0 {
c.dictOk(map[string]interface{}{"dicts": result}, "")
return
}
tenantID := strconv.Itoa(claims.TenantId)
var dicts []models.BackendDict
if _, err := models.Orm.QueryTable(new(models.BackendDict)).
Filter("dict_code__in", codes).
Filter("tenant_id__in", dictTenantScope(claims)).
Filter("status", 1).
Filter("delete_time__isnull", true).
All(&dicts); err != nil {
c.dictErr(500, 500, "查询失败: "+err.Error())
return
}
// 同编码优先本租户:先记录全局,再用租户自己的覆盖
chosen := map[string]uint64{}
for _, d := range dicts {
if _, ok := chosen[d.DictCode]; !ok || d.TenantID == tenantID {
chosen[d.DictCode] = d.ID
}
}
if len(chosen) == 0 {
c.dictOk(map[string]interface{}{"dicts": result}, "")
return
}
ids := make([]uint64, 0, len(chosen))
codeByID := make(map[uint64]string, len(chosen))
for code, id := range chosen {
ids = append(ids, id)
codeByID[id] = code
}
var items []models.BackendDictItem
if _, err := models.Orm.QueryTable(new(models.BackendDictItem)).
Filter("dict_id__in", ids).
Filter("status", 1).
Filter("delete_time__isnull", true).
OrderBy("sort", "id").
All(&items); err != nil {
c.dictErr(500, 500, "查询失败: "+err.Error())
return
}
for _, it := range items {
code := codeByID[it.DictID]
result[code] = append(result[code], it)
}
c.dictOk(map[string]interface{}{"dicts": result}, "")
}
// Options GET /backend/dict/options/:code
// 业务页面按编码取选项:只返回「字典与字典项都启用」的项,按 sort 升序。
func (c *BackendDictController) Options() {
claims, err := c.dictClaims()
if err != nil {
c.dictErr(401, 401, err.Error())
return
}
code := strings.TrimSpace(c.Ctx.Input.Param(":code"))
if code == "" {
c.dictErr(400, 400, "字典编码不能为空")
return
}
// 优先取本租户自己的字典,没有再回落全局内置字典
dict, err := findVisibleDict(strconv.Itoa(claims.TenantId), code)
if err != nil {
c.dictErr(404, 404, "字典不存在或已停用")
return
}
var list []models.BackendDictItem
if _, err := models.Orm.QueryTable(new(models.BackendDictItem)).
Filter("dict_id", dict.ID).
Filter("status", 1).
Filter("delete_time__isnull", true).
OrderBy("sort", "id").
All(&list); err != nil {
c.dictErr(500, 500, "查询失败: "+err.Error())
return
}
c.dictOk(map[string]interface{}{
"dict_id": dict.ID,
"dict_code": dict.DictCode,
"dict_name": dict.DictName,
"list": list,
}, "")
}