做字典管理
This commit is contained in:
@@ -0,0 +1,733 @@
|
||||
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"
|
||||
)
|
||||
|
||||
// PlatformDictController 平台端数据字典:字典列表 + 字典项
|
||||
//
|
||||
// 表:yz_platform_dict / yz_platform_dict_item(建表 SQL:docs/sql/create_dict.sql)。
|
||||
// 平台端字典不按租户隔离;租户端字典见 BackendDictController(/backend/dict/*)。
|
||||
type PlatformDictController struct {
|
||||
beego.Controller
|
||||
}
|
||||
|
||||
// dictCodeRe 字典编码:字母开头,仅字母/数字/下划线
|
||||
var dictCodeRe = regexp.MustCompile(`^[a-zA-Z][a-zA-Z0-9_]{0,99}$`)
|
||||
|
||||
// dictTagTypes 字典项标签色(与前端 el-tag 的 type 对齐),空串表示不渲染标签
|
||||
var dictTagTypes = map[string]bool{
|
||||
"": true,
|
||||
"primary": true,
|
||||
"success": true,
|
||||
"warning": true,
|
||||
"danger": true,
|
||||
"info": true,
|
||||
}
|
||||
|
||||
func (c *PlatformDictController) 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 != "platform" {
|
||||
return nil, fmt.Errorf("无权访问")
|
||||
}
|
||||
return claims, nil
|
||||
}
|
||||
|
||||
func (c *PlatformDictController) 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 *PlatformDictController) 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()
|
||||
}
|
||||
|
||||
// dictPageSize 统一分页参数处理:page 从 1 开始,pageSize 限制在 1~100
|
||||
func dictPageSize(c *beego.Controller) (page, pageSize, offset int) {
|
||||
page, _ = c.GetInt("page", 1)
|
||||
pageSize, _ = c.GetInt("pageSize", 20)
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
if pageSize < 1 || pageSize > 100 {
|
||||
pageSize = 20
|
||||
}
|
||||
return page, pageSize, (page - 1) * pageSize
|
||||
}
|
||||
|
||||
type dictTypePayload struct {
|
||||
DictName string `json:"dict_name"`
|
||||
DictCode string `json:"dict_code"`
|
||||
Remark string `json:"remark"`
|
||||
Sort int `json:"sort"`
|
||||
Status *int8 `json:"status"`
|
||||
}
|
||||
|
||||
type dictItemPayload 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"`
|
||||
}
|
||||
|
||||
func parseDictTypeBody(c *beego.Controller) (*dictTypePayload, error) {
|
||||
body, _ := io.ReadAll(c.Ctx.Request.Body)
|
||||
var p dictTypePayload
|
||||
if err := json.Unmarshal(body, &p); err != nil {
|
||||
return nil, fmt.Errorf("参数错误")
|
||||
}
|
||||
p.DictName = strings.TrimSpace(p.DictName)
|
||||
p.DictCode = strings.TrimSpace(p.DictCode)
|
||||
p.Remark = strings.TrimSpace(p.Remark)
|
||||
return &p, nil
|
||||
}
|
||||
|
||||
func parseDictItemBody(c *beego.Controller) (*dictItemPayload, error) {
|
||||
body, _ := io.ReadAll(c.Ctx.Request.Body)
|
||||
var p dictItemPayload
|
||||
if err := json.Unmarshal(body, &p); err != nil {
|
||||
return nil, fmt.Errorf("参数错误")
|
||||
}
|
||||
p.ItemLabel = strings.TrimSpace(p.ItemLabel)
|
||||
p.ItemValue = strings.TrimSpace(p.ItemValue)
|
||||
p.TagType = strings.TrimSpace(p.TagType)
|
||||
p.Remark = strings.TrimSpace(p.Remark)
|
||||
return &p, nil
|
||||
}
|
||||
|
||||
func dictPathID(c *beego.Controller) uint64 {
|
||||
id, _ := strconv.ParseUint(c.Ctx.Input.Param(":id"), 10, 64)
|
||||
return id
|
||||
}
|
||||
|
||||
/* ---------------- 字典列表 ---------------- */
|
||||
|
||||
// ListTypes GET /platform/dict/types
|
||||
// 参数:page / pageSize / keyword(名称或编码模糊)/ status
|
||||
func (c *PlatformDictController) ListTypes() {
|
||||
if _, err := c.dictClaims(); 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"))
|
||||
|
||||
cond := orm.NewCondition().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.PlatformDict)).SetCond(cond)
|
||||
total, err := qs.Count()
|
||||
if err != nil {
|
||||
c.dictErr(500, 500, "查询失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
var list []models.PlatformDict
|
||||
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,
|
||||
}, "")
|
||||
}
|
||||
|
||||
// CreateType POST /platform/dict/types
|
||||
func (c *PlatformDictController) CreateType() {
|
||||
claims, err := c.dictClaims()
|
||||
if err != nil {
|
||||
c.dictErr(401, 401, err.Error())
|
||||
return
|
||||
}
|
||||
p, err := parseDictTypeBody(&c.Controller)
|
||||
if err != nil {
|
||||
c.dictErr(400, 400, err.Error())
|
||||
return
|
||||
}
|
||||
if p.DictName == "" {
|
||||
c.dictErr(400, 400, "字典名称不能为空")
|
||||
return
|
||||
}
|
||||
if !dictCodeRe.MatchString(p.DictCode) {
|
||||
c.dictErr(400, 400, "字典编码以字母开头,只能包含字母、数字与下划线")
|
||||
return
|
||||
}
|
||||
exist, _ := models.Orm.QueryTable(new(models.PlatformDict)).
|
||||
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.PlatformDict{
|
||||
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 /platform/dict/types/:id
|
||||
// 编码是业务取值依据,不允许修改。
|
||||
func (c *PlatformDictController) UpdateType() {
|
||||
if _, err := c.dictClaims(); err != nil {
|
||||
c.dictErr(401, 401, err.Error())
|
||||
return
|
||||
}
|
||||
id := dictPathID(&c.Controller)
|
||||
if id == 0 {
|
||||
c.dictErr(400, 400, "无效的ID")
|
||||
return
|
||||
}
|
||||
p, err := parseDictTypeBody(&c.Controller)
|
||||
if err != nil {
|
||||
c.dictErr(400, 400, err.Error())
|
||||
return
|
||||
}
|
||||
if p.DictName == "" {
|
||||
c.dictErr(400, 400, "字典名称不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
var row models.PlatformDict
|
||||
if err := models.Orm.QueryTable(new(models.PlatformDict)).
|
||||
Filter("id", id).
|
||||
Filter("delete_time__isnull", true).
|
||||
One(&row); err != nil {
|
||||
c.dictErr(404, 404, "字典不存在")
|
||||
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 /platform/dict/types/:id
|
||||
// 字典下还有字典项时拒绝删除,避免留下孤儿数据。
|
||||
func (c *PlatformDictController) DeleteType() {
|
||||
if _, err := c.dictClaims(); 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.PlatformDict
|
||||
if err := models.Orm.QueryTable(new(models.PlatformDict)).
|
||||
Filter("id", id).
|
||||
Filter("delete_time__isnull", true).
|
||||
One(&row); err != nil {
|
||||
c.dictErr(404, 404, "字典不存在")
|
||||
return
|
||||
}
|
||||
cnt, _ := models.Orm.QueryTable(new(models.PlatformDictItem)).
|
||||
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.PlatformDict)).
|
||||
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 /platform/dict/items
|
||||
// 参数:dict_id(必填)/ page / pageSize / keyword(名称或值模糊)/ status
|
||||
func (c *PlatformDictController) ListItems() {
|
||||
if _, err := c.dictClaims(); err != nil {
|
||||
c.dictErr(401, 401, err.Error())
|
||||
return
|
||||
}
|
||||
dictID, _ := c.GetInt64("dict_id")
|
||||
if dictID <= 0 {
|
||||
c.dictErr(400, 400, "dict_id 不能为空")
|
||||
return
|
||||
}
|
||||
page, pageSize, offset := dictPageSize(&c.Controller)
|
||||
keyword := strings.TrimSpace(c.GetString("keyword"))
|
||||
status := strings.TrimSpace(c.GetString("status"))
|
||||
|
||||
cond := orm.NewCondition().
|
||||
And("delete_time__isnull", true).
|
||||
And("dict_id", dictID)
|
||||
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.PlatformDictItem)).SetCond(cond)
|
||||
total, err := qs.Count()
|
||||
if err != nil {
|
||||
c.dictErr(500, 500, "查询失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
var list []models.PlatformDictItem
|
||||
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 /platform/dict/items
|
||||
func (c *PlatformDictController) CreateItem() {
|
||||
if _, err := c.dictClaims(); err != nil {
|
||||
c.dictErr(401, 401, err.Error())
|
||||
return
|
||||
}
|
||||
p, err := parseDictItemBody(&c.Controller)
|
||||
if err != nil {
|
||||
c.dictErr(400, 400, err.Error())
|
||||
return
|
||||
}
|
||||
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 !dictTagTypes[p.TagType] {
|
||||
c.dictErr(400, 400, "标签色只能是 primary/success/warning/danger/info 之一")
|
||||
return
|
||||
}
|
||||
|
||||
var dict models.PlatformDict
|
||||
if err := models.Orm.QueryTable(new(models.PlatformDict)).
|
||||
Filter("id", p.DictID).
|
||||
Filter("delete_time__isnull", true).
|
||||
One(&dict); err != nil {
|
||||
c.dictErr(404, 404, "字典不存在")
|
||||
return
|
||||
}
|
||||
cnt, _ := models.Orm.QueryTable(new(models.PlatformDictItem)).
|
||||
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.PlatformDictItem{
|
||||
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 /platform/dict/items/:id
|
||||
// 字典项值是业务入库值,不允许修改,避免存量数据对不上。
|
||||
func (c *PlatformDictController) UpdateItem() {
|
||||
if _, err := c.dictClaims(); err != nil {
|
||||
c.dictErr(401, 401, err.Error())
|
||||
return
|
||||
}
|
||||
id := dictPathID(&c.Controller)
|
||||
if id == 0 {
|
||||
c.dictErr(400, 400, "无效的ID")
|
||||
return
|
||||
}
|
||||
p, err := parseDictItemBody(&c.Controller)
|
||||
if err != nil {
|
||||
c.dictErr(400, 400, err.Error())
|
||||
return
|
||||
}
|
||||
if p.ItemLabel == "" {
|
||||
c.dictErr(400, 400, "字典项名称不能为空")
|
||||
return
|
||||
}
|
||||
if !dictTagTypes[p.TagType] {
|
||||
c.dictErr(400, 400, "标签色只能是 primary/success/warning/danger/info 之一")
|
||||
return
|
||||
}
|
||||
|
||||
var row models.PlatformDictItem
|
||||
if err := models.Orm.QueryTable(new(models.PlatformDictItem)).
|
||||
Filter("id", id).
|
||||
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 /platform/dict/items/:id/status
|
||||
func (c *PlatformDictController) ToggleItemStatus() {
|
||||
if _, err := c.dictClaims(); 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
|
||||
}
|
||||
|
||||
var row models.PlatformDictItem
|
||||
if err := models.Orm.QueryTable(new(models.PlatformDictItem)).
|
||||
Filter("id", id).
|
||||
Filter("delete_time__isnull", true).
|
||||
One(&row); err != nil {
|
||||
c.dictErr(404, 404, "字典项不存在")
|
||||
return
|
||||
}
|
||||
now := time.Now()
|
||||
if _, err := models.Orm.QueryTable(new(models.PlatformDictItem)).
|
||||
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 /platform/dict/items/:id
|
||||
func (c *PlatformDictController) DeleteItem() {
|
||||
if _, err := c.dictClaims(); 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.PlatformDictItem
|
||||
if err := models.Orm.QueryTable(new(models.PlatformDictItem)).
|
||||
Filter("id", id).
|
||||
Filter("delete_time__isnull", true).
|
||||
One(&row); err != nil {
|
||||
c.dictErr(404, 404, "字典项不存在")
|
||||
return
|
||||
}
|
||||
now := time.Now()
|
||||
if _, err := models.Orm.QueryTable(new(models.PlatformDictItem)).
|
||||
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 /platform/dict/options
|
||||
// 一次取回全部「启用」字典的字典项,供前端登录后预热缓存:
|
||||
// 之后页面按任意 dict_code 都能同步读到,新增字典不用改前端。
|
||||
func (c *PlatformDictController) OptionsAll() {
|
||||
if _, err := c.dictClaims(); err != nil {
|
||||
c.dictErr(401, 401, err.Error())
|
||||
return
|
||||
}
|
||||
result := map[string][]models.PlatformDictItem{}
|
||||
|
||||
var dicts []models.PlatformDict
|
||||
if _, err := models.Orm.QueryTable(new(models.PlatformDict)).
|
||||
Filter("status", 1).
|
||||
Filter("delete_time__isnull", true).
|
||||
All(&dicts); err != nil {
|
||||
c.dictErr(500, 500, "查询失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
if len(dicts) == 0 {
|
||||
c.dictOk(map[string]interface{}{"dicts": result}, "")
|
||||
return
|
||||
}
|
||||
|
||||
ids := make([]uint64, 0, len(dicts))
|
||||
codeByID := make(map[uint64]string, len(dicts))
|
||||
for _, d := range dicts {
|
||||
ids = append(ids, d.ID)
|
||||
codeByID[d.ID] = d.DictCode
|
||||
result[d.DictCode] = []models.PlatformDictItem{}
|
||||
}
|
||||
|
||||
var items []models.PlatformDictItem
|
||||
if _, err := models.Orm.QueryTable(new(models.PlatformDictItem)).
|
||||
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 /platform/dict/options
|
||||
// 一次取多个字典的启用项,供前端预加载(body: {"codes":["payment_channel",...]})。
|
||||
// 编码不存在或已停用时返回空数组,前端不必再单独重试。
|
||||
// 注意:这里刻意与 GET /options/:code 分开成「同段不同方法」,避免静态段与通配段同级。
|
||||
func (c *PlatformDictController) OptionsBatch() {
|
||||
if _, err := c.dictClaims(); 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.PlatformDictItem{}
|
||||
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.PlatformDictItem{}
|
||||
codes = append(codes, code)
|
||||
}
|
||||
if len(codes) == 0 {
|
||||
c.dictOk(map[string]interface{}{"dicts": result}, "")
|
||||
return
|
||||
}
|
||||
|
||||
// 先按编码取字典,再按字典ID一次取回全部字典项,避免逐个字典查一轮(N+1)
|
||||
var dicts []models.PlatformDict
|
||||
if _, err := models.Orm.QueryTable(new(models.PlatformDict)).
|
||||
Filter("dict_code__in", codes).
|
||||
Filter("status", 1).
|
||||
Filter("delete_time__isnull", true).
|
||||
All(&dicts); err != nil {
|
||||
c.dictErr(500, 500, "查询失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
if len(dicts) == 0 {
|
||||
c.dictOk(map[string]interface{}{"dicts": result}, "")
|
||||
return
|
||||
}
|
||||
|
||||
ids := make([]uint64, 0, len(dicts))
|
||||
codeByID := make(map[uint64]string, len(dicts))
|
||||
for _, d := range dicts {
|
||||
ids = append(ids, d.ID)
|
||||
codeByID[d.ID] = d.DictCode
|
||||
}
|
||||
|
||||
var items []models.PlatformDictItem
|
||||
if _, err := models.Orm.QueryTable(new(models.PlatformDictItem)).
|
||||
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 /platform/dict/options/:code
|
||||
// 业务页面按编码取选项:只返回「字典与字典项都启用」的项,按 sort 升序。
|
||||
func (c *PlatformDictController) Options() {
|
||||
if _, err := c.dictClaims(); err != nil {
|
||||
c.dictErr(401, 401, err.Error())
|
||||
return
|
||||
}
|
||||
code := strings.TrimSpace(c.Ctx.Input.Param(":code"))
|
||||
if code == "" {
|
||||
c.dictErr(400, 400, "字典编码不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
var dict models.PlatformDict
|
||||
if err := models.Orm.QueryTable(new(models.PlatformDict)).
|
||||
Filter("dict_code", code).
|
||||
Filter("status", 1).
|
||||
Filter("delete_time__isnull", true).
|
||||
One(&dict); err != nil {
|
||||
c.dictErr(404, 404, "字典不存在或已停用")
|
||||
return
|
||||
}
|
||||
|
||||
var list []models.PlatformDictItem
|
||||
if _, err := models.Orm.QueryTable(new(models.PlatformDictItem)).
|
||||
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,
|
||||
}, "")
|
||||
}
|
||||
Reference in New Issue
Block a user