734 lines
19 KiB
Go
734 lines
19 KiB
Go
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,
|
||
}, "")
|
||
}
|