做字典管理
This commit is contained in:
@@ -0,0 +1,815 @@
|
||||
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,
|
||||
}, "")
|
||||
}
|
||||
@@ -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,
|
||||
}, "")
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
-- =============================================================
|
||||
-- 数据字典 —— 平台端 / 租户端各一套
|
||||
--
|
||||
-- 表清单:
|
||||
-- yz_platform_dict 平台端「字典列表」(字典类型)
|
||||
-- yz_platform_dict_item 平台端「字典项」
|
||||
-- yz_backend_dict 租户端「字典列表」(按 tenant_id 租户隔离)
|
||||
-- yz_backend_dict_item 租户端「字典项」
|
||||
--
|
||||
-- 设计说明:
|
||||
-- 1. 平台端字典与租户端字典完全独立:平台端字典供平台系统自身使用
|
||||
-- (不按租户隔离);租户端字典是每个租户可自行维护的业务选项
|
||||
-- (如供应商类型、结算方式),按 tenant_id 隔离,与
|
||||
-- yz_backend_erp_supplier 的隔离方式保持一致。
|
||||
-- 2. 字典项通过 dict_id 关联字典;租户端额外冗余 tenant_id,
|
||||
-- 便于不带 JOIN 直接按租户过滤,写入时须与父字典 tenant_id 一致。
|
||||
-- 3. tag_type 对应前端 el-tag 的 type(primary/success/warning/danger/info),
|
||||
-- 留空表示该项在列表里不渲染彩色标签。
|
||||
-- 4. 与 yz_backend_erp_* / yz_backend_crm_* 等表一致,这里只建普通索引、
|
||||
-- 不建唯一索引:一是软删除(delete_time)后编码仍会占用唯一键,
|
||||
-- 二是库中既有表也普遍不用唯一索引。dict_code / item_value 的唯一性
|
||||
-- 由后端接口在写入时校验。
|
||||
-- 5. 不显式指定 COLLATE,沿用库默认排序规则,避免 JOIN 时报
|
||||
-- Illegal mix of collations。
|
||||
--
|
||||
-- 执行方式:人工在数据库执行,代码中不做任何自动建表 / 补列。
|
||||
-- 说明:下方 DDL 幂等(IF NOT EXISTS),可重复执行。
|
||||
-- =============================================================
|
||||
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
|
||||
-- =============================================================
|
||||
-- 平台端
|
||||
-- =============================================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `yz_platform_dict` (
|
||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
`dict_name` VARCHAR(100) NOT NULL DEFAULT '' COMMENT '字典名称,如:供应商类型',
|
||||
`dict_code` VARCHAR(100) NOT NULL DEFAULT '' COMMENT '字典编码(业务唯一标识,后端按此取字典),如:supplier_type',
|
||||
`remark` VARCHAR(500) NOT NULL DEFAULT '' COMMENT '备注',
|
||||
`sort` INT NOT NULL DEFAULT 0 COMMENT '排序,数字越小越靠前',
|
||||
`status` TINYINT NOT NULL DEFAULT 1 COMMENT '状态:1 启用 0 停用',
|
||||
`create_user_id` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '创建人用户ID',
|
||||
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_time` DATETIME DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`delete_time` DATETIME DEFAULT NULL COMMENT '删除时间(软删除)',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_dict_code` (`dict_code`),
|
||||
KEY `idx_status_sort` (`status`, `sort`, `id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='平台端-数据字典(字典列表)';
|
||||
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `yz_platform_dict_item` (
|
||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
`dict_id` BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '所属字典ID(yz_platform_dict.id)',
|
||||
`item_label` VARCHAR(100) NOT NULL DEFAULT '' COMMENT '字典项名称(显示文案),如:原材料供应商',
|
||||
`item_value` VARCHAR(100) NOT NULL DEFAULT '' COMMENT '字典项值(业务入库值),如:1',
|
||||
`tag_type` VARCHAR(20) NOT NULL DEFAULT '' COMMENT '标签色(el-tag type):primary/success/warning/danger/info,留空不渲染标签',
|
||||
`sort` INT NOT NULL DEFAULT 0 COMMENT '排序,数字越小越靠前',
|
||||
`status` TINYINT NOT NULL DEFAULT 1 COMMENT '状态:1 启用 0 停用',
|
||||
`is_default` TINYINT NOT NULL DEFAULT 0 COMMENT '是否默认选中:0 否 1 是',
|
||||
`remark` VARCHAR(500) NOT NULL DEFAULT '' COMMENT '备注',
|
||||
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_time` DATETIME DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`delete_time` DATETIME DEFAULT NULL COMMENT '删除时间(软删除)',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_dict_sort` (`dict_id`, `sort`, `id`),
|
||||
KEY `idx_dict_value` (`dict_id`, `item_value`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='平台端-字典项';
|
||||
|
||||
|
||||
-- =============================================================
|
||||
-- 租户端(按 tenant_id 隔离)
|
||||
-- =============================================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `yz_backend_dict` (
|
||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
`tenant_id` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '租户ID(同 yz_backend_erp_supplier.tenant_id)',
|
||||
`dict_name` VARCHAR(100) NOT NULL DEFAULT '' COMMENT '字典名称,如:供应商类型',
|
||||
`dict_code` VARCHAR(100) NOT NULL DEFAULT '' COMMENT '字典编码(租户内唯一),如:supplier_type',
|
||||
`remark` VARCHAR(500) NOT NULL DEFAULT '' COMMENT '备注',
|
||||
`sort` INT NOT NULL DEFAULT 0 COMMENT '排序,数字越小越靠前',
|
||||
`status` TINYINT NOT NULL DEFAULT 1 COMMENT '状态:1 启用 0 停用',
|
||||
`create_user_id` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '创建人用户ID',
|
||||
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_time` DATETIME DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`delete_time` DATETIME DEFAULT NULL COMMENT '删除时间(软删除)',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_tenant_dict_code` (`tenant_id`, `dict_code`),
|
||||
KEY `idx_tenant_status_sort` (`tenant_id`, `status`, `sort`, `id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='租户端-数据字典(字典列表)';
|
||||
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `yz_backend_dict_item` (
|
||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
`tenant_id` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '租户ID,须与所属字典一致',
|
||||
`dict_id` BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '所属字典ID(yz_backend_dict.id)',
|
||||
`item_label` VARCHAR(100) NOT NULL DEFAULT '' COMMENT '字典项名称(显示文案),如:原材料供应商',
|
||||
`item_value` VARCHAR(100) NOT NULL DEFAULT '' COMMENT '字典项值(业务入库值),如:1',
|
||||
`tag_type` VARCHAR(20) NOT NULL DEFAULT '' COMMENT '标签色(el-tag type):primary/success/warning/danger/info,留空不渲染标签',
|
||||
`sort` INT NOT NULL DEFAULT 0 COMMENT '排序,数字越小越靠前',
|
||||
`status` TINYINT NOT NULL DEFAULT 1 COMMENT '状态:1 启用 0 停用',
|
||||
`is_default` TINYINT NOT NULL DEFAULT 0 COMMENT '是否默认选中:0 否 1 是',
|
||||
`remark` VARCHAR(500) NOT NULL DEFAULT '' COMMENT '备注',
|
||||
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_time` DATETIME DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`delete_time` DATETIME DEFAULT NULL COMMENT '删除时间(软删除)',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_tenant_dict_sort` (`tenant_id`, `dict_id`, `sort`, `id`),
|
||||
KEY `idx_tenant_dict_value` (`tenant_id`, `dict_id`, `item_value`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='租户端-字典项';
|
||||
@@ -0,0 +1,448 @@
|
||||
-- =============================================================
|
||||
-- 租户端数据字典 —— 初始数据(系统内置,全局共享)
|
||||
--
|
||||
-- 表:yz_backend_dict / yz_backend_dict_item(建表见 create_dict.sql)
|
||||
--
|
||||
-- 重要:本文件写入的是 tenant_id = '0' 的「全局内置字典」,与 yz_system_admin_role
|
||||
-- 中 tenant_id=0 的全局租户角色同一套约定:
|
||||
-- - 所有租户都能通过 /backend/dict/options/:code 读到;
|
||||
-- - 租户若需要改动,请按相同 dict_code 新建一份自己的字典(读接口优先取租户自己的,
|
||||
-- 字典管理页里全局字典显示为「内置」只读)。
|
||||
--
|
||||
-- 内容来源:backend 前端散落的硬编码映射,其中 CRM 部分取自 views/apps/crm/dict.js。
|
||||
-- 幂等:字典按 (tenant_id='0', dict_code) 判重,字典项按 (dict_id, item_value) 判重,可重复执行。
|
||||
-- 说明:未给出标签色的字典项 tag_type 留空,可在「系统设置 → 数据字典」里按需补。
|
||||
-- =============================================================
|
||||
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
|
||||
-- =============================================================
|
||||
-- 1. 字典列表(全局内置)
|
||||
-- =============================================================
|
||||
|
||||
INSERT INTO `yz_backend_dict` (`tenant_id`, `dict_name`, `dict_code`, `remark`, `sort`, `status`, `create_user_id`, `create_time`)
|
||||
SELECT '0', t.dict_name, t.dict_code, t.remark, t.sort, 1, 'sql', NOW()
|
||||
FROM (
|
||||
SELECT '通用状态' AS dict_name, 'common_status' AS dict_code, '0 禁用 / 1 正常 / 2 冻结 / 3 已注销(客户、供应商等共用)' AS remark, 10 AS sort
|
||||
UNION ALL SELECT '往来单位等级' AS dict_name, 'common_object_level' AS dict_code, '客户/供应商等级' AS remark, 20 AS sort
|
||||
UNION ALL SELECT '性别' AS dict_name, 'common_gender' AS dict_code, '0 未知 / 1 男 / 2 女' AS remark, 30 AS sort
|
||||
UNION ALL SELECT '通用启用状态' AS dict_name, 'common_enable_status' AS dict_code, '1 启用 / 0 禁用' AS remark, 40 AS sort
|
||||
UNION ALL SELECT '待办状态' AS dict_name, 'common_todo_status' AS dict_code, '0 待办 / 1 已完成' AS remark, 50 AS sort
|
||||
UNION ALL SELECT '优先级' AS dict_name, 'common_priority' AS dict_code, '日程优先级' AS remark, 60 AS sort
|
||||
UNION ALL SELECT '联系人类型' AS dict_name, 'common_contact_type' AS dict_code, '1 企业 / 2 个人' AS remark, 70 AS sort
|
||||
UNION ALL SELECT '提醒渠道' AS dict_name, 'common_notify_channel' AS dict_code, '站内提醒的推送渠道(remind_channels)' AS remark, 80 AS sort
|
||||
UNION ALL SELECT '移入公海原因' AS dict_name, 'crm_pool_reason' AS dict_code, 'CRM 客户移入公海的原因' AS remark, 90 AS sort
|
||||
UNION ALL SELECT '联系人关联类型' AS dict_name, 'erp_related_type' AS dict_code, '1 客户 / 2 供应商' AS remark, 100 AS sort
|
||||
UNION ALL SELECT '客户类型' AS dict_name, 'erp_customer_type' AS dict_code, 'crm/dict.js CUSTOMER_TYPE_OPTIONS' AS remark, 110 AS sort
|
||||
UNION ALL SELECT '供应商类型' AS dict_name, 'erp_supplier_type' AS dict_code, '与 CRM 供应商类型共用' AS remark, 120 AS sort
|
||||
UNION ALL SELECT '线索来源' AS dict_name, 'crm_clue_source' AS dict_code, '' AS remark, 130 AS sort
|
||||
UNION ALL SELECT '线索状态' AS dict_name, 'crm_clue_status' AS dict_code, '' AS remark, 140 AS sort
|
||||
UNION ALL SELECT '线索级别' AS dict_name, 'crm_clue_level' AS dict_code, '' AS remark, 150 AS sort
|
||||
UNION ALL SELECT '商机阶段' AS dict_name, 'crm_business_stage' AS dict_code, '' AS remark, 160 AS sort
|
||||
UNION ALL SELECT '商机状态' AS dict_name, 'crm_business_status' AS dict_code, '' AS remark, 170 AS sort
|
||||
UNION ALL SELECT '跟进类型' AS dict_name, 'crm_follow_type' AS dict_code, '' AS remark, 180 AS sort
|
||||
UNION ALL SELECT '跟进关联类型' AS dict_name, 'crm_pipeline_related_type' AS dict_code, '' AS remark, 190 AS sort
|
||||
UNION ALL SELECT '项目状态' AS dict_name, 'crm_project_status' AS dict_code, '' AS remark, 200 AS sort
|
||||
UNION ALL SELECT '项目类型' AS dict_name, 'crm_project_type' AS dict_code, '' AS remark, 210 AS sort
|
||||
UNION ALL SELECT '合同分类' AS dict_name, 'crm_contract_category' AS dict_code, '' AS remark, 220 AS sort
|
||||
UNION ALL SELECT '合同状态' AS dict_name, 'crm_contract_status' AS dict_code, '' AS remark, 230 AS sort
|
||||
UNION ALL SELECT '合同形式' AS dict_name, 'crm_contract_party_count' AS dict_code, '2 双方 / 3 三方 / 4 四方' AS remark, 240 AS sort
|
||||
UNION ALL SELECT '我方角色' AS dict_name, 'crm_contract_our_role' AS dict_code, '' AS remark, 250 AS sort
|
||||
UNION ALL SELECT '合同产品类别' AS dict_name, 'crm_contract_product_category' AS dict_code, '' AS remark, 260 AS sort
|
||||
UNION ALL SELECT '回款周期' AS dict_name, 'crm_payback_cycle' AS dict_code, '' AS remark, 270 AS sort
|
||||
UNION ALL SELECT '回款方式' AS dict_name, 'crm_payback_method' AS dict_code, '' AS remark, 280 AS sort
|
||||
UNION ALL SELECT '回款计划状态' AS dict_name, 'crm_payback_status' AS dict_code, '' AS remark, 290 AS sort
|
||||
UNION ALL SELECT '回款明细状态' AS dict_name, 'crm_payback_item_status' AS dict_code, '' AS remark, 300 AS sort
|
||||
UNION ALL SELECT '产品状态' AS dict_name, 'crm_product_status' AS dict_code, '1 启用 / 0 停用' AS remark, 310 AS sort
|
||||
UNION ALL SELECT '产品单位' AS dict_name, 'crm_product_unit' AS dict_code, '计量单位,偏业务参数,可自行增删' AS remark, 320 AS sort
|
||||
UNION ALL SELECT '产品研发方式' AS dict_name, 'crm_product_dev_mode' AS dict_code, '' AS remark, 330 AS sort
|
||||
UNION ALL SELECT '招标状态' AS dict_name, 'crm_tender_status' AS dict_code, '' AS remark, 340 AS sort
|
||||
UNION ALL SELECT '招标方式' AS dict_name, 'crm_tender_type' AS dict_code, '' AS remark, 350 AS sort
|
||||
UNION ALL SELECT '招标结果' AS dict_name, 'crm_tender_result_type' AS dict_code, '' AS remark, 360 AS sort
|
||||
UNION ALL SELECT '招标供应商状态' AS dict_name, 'crm_tender_supplier_status' AS dict_code, '' AS remark, 370 AS sort
|
||||
UNION ALL SELECT '招标公告类型' AS dict_name, 'crm_tender_announce_type' AS dict_code, '' AS remark, 380 AS sort
|
||||
UNION ALL SELECT '评标方式' AS dict_name, 'crm_evaluation_method' AS dict_code, '' AS remark, 390 AS sort
|
||||
UNION ALL SELECT '评标结果' AS dict_name, 'crm_evaluation_result' AS dict_code, '' AS remark, 400 AS sort
|
||||
UNION ALL SELECT '投标状态' AS dict_name, 'crm_bid_status' AS dict_code, '' AS remark, 410 AS sort
|
||||
UNION ALL SELECT '投标方式' AS dict_name, 'crm_bid_type' AS dict_code, '' AS remark, 420 AS sort
|
||||
UNION ALL SELECT '投标来源' AS dict_name, 'crm_bid_source_type' AS dict_code, '' AS remark, 430 AS sort
|
||||
UNION ALL SELECT '投标结果' AS dict_name, 'crm_bid_result_type' AS dict_code, '' AS remark, 440 AS sort
|
||||
UNION ALL SELECT '投标任务类型' AS dict_name, 'crm_bid_task_type' AS dict_code, '' AS remark, 450 AS sort
|
||||
UNION ALL SELECT '投标任务状态' AS dict_name, 'crm_bid_task_status' AS dict_code, '' AS remark, 460 AS sort
|
||||
UNION ALL SELECT '投标模板类型' AS dict_name, 'crm_bid_template_type' AS dict_code, '' AS remark, 470 AS sort
|
||||
UNION ALL SELECT '投标报价状态' AS dict_name, 'crm_bid_quote_status' AS dict_code, '' AS remark, 480 AS sort
|
||||
UNION ALL SELECT '投标文件状态' AS dict_name, 'crm_bid_document_status' AS dict_code, '' AS remark, 490 AS sort
|
||||
UNION ALL SELECT '投标费用类型' AS dict_name, 'crm_bid_expense_type' AS dict_code, '' AS remark, 500 AS sort
|
||||
UNION ALL SELECT '竞争对手类型' AS dict_name, 'crm_competitor_type' AS dict_code, '' AS remark, 510 AS sort
|
||||
UNION ALL SELECT '资质类型' AS dict_name, 'crm_qualification_type' AS dict_code, '' AS remark, 520 AS sort
|
||||
UNION ALL SELECT '资质状态' AS dict_name, 'crm_qualification_status' AS dict_code, '' AS remark, 530 AS sort
|
||||
UNION ALL SELECT '收付款状态' AS dict_name, 'crm_payment_status' AS dict_code, '' AS remark, 540 AS sort
|
||||
UNION ALL SELECT '审批类型' AS dict_name, 'crm_approval_type' AS dict_code, '' AS remark, 550 AS sort
|
||||
UNION ALL SELECT '审批状态' AS dict_name, 'crm_approval_status' AS dict_code, '' AS remark, 560 AS sort
|
||||
UNION ALL SELECT '账套会计准则' AS dict_name, 'erp_account_set_standard' AS dict_code, '1 企业会计准则 / 2 小企业会计准则' AS remark, 570 AS sort
|
||||
UNION ALL SELECT '账套本位币' AS dict_name, 'erp_account_set_currency' AS dict_code, '账套支持的币种' AS remark, 580 AS sort
|
||||
UNION ALL SELECT '职位类型' AS dict_name, 'erp_position_type' AS dict_code, '0 普通职位 / 1 主管 / 2 负责人' AS remark, 590 AS sort
|
||||
UNION ALL SELECT '员工账号状态' AS dict_name, 'common_employee_status' AS dict_code, '1 正常 / 0 禁用 / 2 离职' AS remark, 600 AS sort
|
||||
UNION ALL SELECT '用工状态' AS dict_name, 'oa_employee_hire_status' AS dict_code, '人事档案:1 试用 / 2 正式 / 3 离职' AS remark, 610 AS sort
|
||||
UNION ALL SELECT '婚姻状况' AS dict_name, 'oa_employee_marital' AS dict_code, '人事档案' AS remark, 620 AS sort
|
||||
UNION ALL SELECT '报销单状态' AS dict_name, 'oa_reimburse_status' AS dict_code, '0 草稿 / 1 审批中 / 2 已通过 / 3 已驳回 / 4 已撤回 / 5 已打款' AS remark, 630 AS sort
|
||||
UNION ALL SELECT '薪酬单状态' AS dict_name, 'oa_compensation_status' AS dict_code, '0 草稿 / 1 已确认 / 2 已发放 / 3 已作废' AS remark, 640 AS sort
|
||||
UNION ALL SELECT '薪酬项类型' AS dict_name, 'oa_compensation_item_type' AS dict_code, '1 增项 / 2 扣项' AS remark, 650 AS sort
|
||||
UNION ALL SELECT '公告类型' AS dict_name, 'oa_notice_type' AS dict_code, '0 通知 / 1 公告 / 2 活动' AS remark, 660 AS sort
|
||||
UNION ALL SELECT '公告状态' AS dict_name, 'oa_notice_status' AS dict_code, '0 草稿 / 1 已发布 / 2 已下架' AS remark, 670 AS sort
|
||||
UNION ALL SELECT 'OA文档状态' AS dict_name, 'oa_doc_status' AS dict_code, '0 草稿 / 1 已发布 / 2 已归档' AS remark, 680 AS sort
|
||||
UNION ALL SELECT 'OA文档关联类型' AS dict_name, 'oa_doc_relation' AS dict_code, 'reference 引用 / related 相关 / version 版本 / belong 从属' AS remark, 690 AS sort
|
||||
UNION ALL SELECT 'OA文档可见性' AS dict_name, 'oa_doc_visibility' AS dict_code, '0 租户公开 / 1 私密' AS remark, 700 AS sort
|
||||
UNION ALL SELECT '登录方式' AS dict_name, 'system_login_type' AS dict_code, '登录日志' AS remark, 710 AS sort
|
||||
UNION ALL SELECT '请求方法' AS dict_name, 'system_http_method' AS dict_code, '操作日志' AS remark, 720 AS sort
|
||||
UNION ALL SELECT '菜单类型' AS dict_name, 'system_menu_type' AS dict_code, '1 目录 / 2 菜单 / 3 按钮' AS remark, 730 AS sort
|
||||
UNION ALL SELECT '订购单状态' AS dict_name, 'common_order_status' AS dict_code, '产品/套餐购买单状态' AS remark, 740 AS sort
|
||||
UNION ALL SELECT '前台导航类型' AS dict_name, 'cms_front_menu_type' AS dict_code, '1 目录 / 2 页面 / 3 外链 / 4 单页' AS remark, 750 AS sort
|
||||
UNION ALL SELECT '需求状态' AS dict_name, 'cms_demand_status' AS dict_code, '1 待处理 / 2 处理中 / 3 已完成 / 4 已拒绝' AS remark, 760 AS sort
|
||||
UNION ALL SELECT '域名核验状态' AS dict_name, 'tenant_domain_verify_status' AS dict_code, '0 未检测 / 1 已通过 / 2 未通过' AS remark, 770 AS sort
|
||||
UNION ALL SELECT '域名证书状态' AS dict_name, 'tenant_domain_ssl_status' AS dict_code, '0 待处理 / 1 签发中 / 2 已签发 / 3 签发失败' AS remark, 780 AS sort
|
||||
) AS t
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM `yz_backend_dict` AS d
|
||||
WHERE d.tenant_id = '0' AND d.dict_code = t.dict_code AND d.delete_time IS NULL
|
||||
);
|
||||
|
||||
|
||||
-- =============================================================
|
||||
-- 2. 字典项(全局内置)
|
||||
-- =============================================================
|
||||
|
||||
INSERT INTO `yz_backend_dict_item` (`tenant_id`, `dict_id`, `item_label`, `item_value`, `tag_type`, `sort`, `status`, `is_default`, `create_time`)
|
||||
SELECT '0', d.id, t.item_label, t.item_value, t.tag_type, t.sort, 1, 0, NOW()
|
||||
FROM (
|
||||
SELECT 'common_status' AS dict_code, '正常' AS item_label, '1' AS item_value, 'success' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'common_status' AS dict_code, '禁用' AS item_label, '0' AS item_value, 'info' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'common_status' AS dict_code, '冻结' AS item_label, '2' AS item_value, 'warning' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'common_status' AS dict_code, '已注销' AS item_label, '3' AS item_value, 'danger' AS tag_type, 40 AS sort
|
||||
UNION ALL SELECT 'common_object_level' AS dict_code, '核心' AS item_label, '1' AS item_value, 'danger' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'common_object_level' AS dict_code, '重要' AS item_label, '2' AS item_value, 'warning' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'common_object_level' AS dict_code, '普通' AS item_label, '3' AS item_value, 'info' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'common_object_level' AS dict_code, '潜在' AS item_label, '4' AS item_value, '' AS tag_type, 40 AS sort
|
||||
UNION ALL SELECT 'common_gender' AS dict_code, '未知' AS item_label, '0' AS item_value, '' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'common_gender' AS dict_code, '男' AS item_label, '1' AS item_value, '' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'common_gender' AS dict_code, '女' AS item_label, '2' AS item_value, '' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'common_enable_status' AS dict_code, '禁用' AS item_label, '0' AS item_value, 'info' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'common_enable_status' AS dict_code, '启用' AS item_label, '1' AS item_value, 'success' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'common_todo_status' AS dict_code, '待办' AS item_label, '0' AS item_value, 'info' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'common_todo_status' AS dict_code, '已完成' AS item_label, '1' AS item_value, 'success' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'common_priority' AS dict_code, '重要' AS item_label, '1' AS item_value, 'warning' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'common_priority' AS dict_code, '紧急' AS item_label, '2' AS item_value, 'danger' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'common_contact_type' AS dict_code, '企业' AS item_label, '1' AS item_value, '' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'common_contact_type' AS dict_code, '个人' AS item_label, '2' AS item_value, '' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'common_notify_channel' AS dict_code, '短信' AS item_label, 'SMS' AS item_value, 'success' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'common_notify_channel' AS dict_code, '邮件' AS item_label, 'EMAIL' AS item_value, 'warning' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'common_notify_channel' AS dict_code, 'Bark推送' AS item_label, 'BARK' AS item_value, 'danger' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'common_notify_channel' AS dict_code, '站内信' AS item_label, 'SITE_MSG' AS item_value, 'primary' AS tag_type, 40 AS sort
|
||||
UNION ALL SELECT 'crm_pool_reason' AS dict_code, '长期未跟进' AS item_label, '长期未跟进' AS item_value, '' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'crm_pool_reason' AS dict_code, '合作终止' AS item_label, '合作终止' AS item_value, '' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'crm_pool_reason' AS dict_code, '重复建档' AS item_label, '重复建档' AS item_value, '' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'crm_pool_reason' AS dict_code, '负责人离职' AS item_label, '负责人离职' AS item_value, '' AS tag_type, 40 AS sort
|
||||
UNION ALL SELECT 'crm_pool_reason' AS dict_code, '手动释放' AS item_label, '手动释放' AS item_value, '' AS tag_type, 50 AS sort
|
||||
UNION ALL SELECT 'crm_pool_reason' AS dict_code, '其他' AS item_label, '其他' AS item_value, '' AS tag_type, 60 AS sort
|
||||
UNION ALL SELECT 'erp_related_type' AS dict_code, '客户' AS item_label, '1' AS item_value, '' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'erp_related_type' AS dict_code, '供应商' AS item_label, '2' AS item_value, '' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'erp_customer_type' AS dict_code, '企业' AS item_label, '1' AS item_value, 'primary' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'erp_customer_type' AS dict_code, '政府机构' AS item_label, '2' AS item_value, 'warning' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'erp_customer_type' AS dict_code, '国企' AS item_label, '3' AS item_value, 'success' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'erp_customer_type' AS dict_code, '教育机构' AS item_label, '4' AS item_value, 'info' AS tag_type, 40 AS sort
|
||||
UNION ALL SELECT 'erp_customer_type' AS dict_code, '个人' AS item_label, '5' AS item_value, 'info' AS tag_type, 50 AS sort
|
||||
UNION ALL SELECT 'erp_supplier_type' AS dict_code, '原材料供应商' AS item_label, '1' AS item_value, 'primary' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'erp_supplier_type' AS dict_code, '设备供应商' AS item_label, '2' AS item_value, 'warning' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'erp_supplier_type' AS dict_code, '服务供应商' AS item_label, '3' AS item_value, 'success' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'erp_supplier_type' AS dict_code, '其他' AS item_label, '4' AS item_value, 'info' AS tag_type, 40 AS sort
|
||||
UNION ALL SELECT 'crm_clue_source' AS dict_code, '官网咨询' AS item_label, '1' AS item_value, '' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'crm_clue_source' AS dict_code, '电话咨询' AS item_label, '2' AS item_value, '' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'crm_clue_source' AS dict_code, '朋友介绍' AS item_label, '3' AS item_value, '' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'crm_clue_source' AS dict_code, '展会活动' AS item_label, '4' AS item_value, '' AS tag_type, 40 AS sort
|
||||
UNION ALL SELECT 'crm_clue_source' AS dict_code, '广告投放' AS item_label, '5' AS item_value, '' AS tag_type, 50 AS sort
|
||||
UNION ALL SELECT 'crm_clue_source' AS dict_code, '陌生拜访' AS item_label, '6' AS item_value, '' AS tag_type, 60 AS sort
|
||||
UNION ALL SELECT 'crm_clue_source' AS dict_code, '其他' AS item_label, '7' AS item_value, '' AS tag_type, 70 AS sort
|
||||
UNION ALL SELECT 'crm_clue_status' AS dict_code, '跟进中' AS item_label, '1' AS item_value, '' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'crm_clue_status' AS dict_code, '已转化' AS item_label, '2' AS item_value, '' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'crm_clue_status' AS dict_code, '已废弃' AS item_label, '3' AS item_value, '' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'crm_clue_level' AS dict_code, '重点' AS item_label, '1' AS item_value, '' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'crm_clue_level' AS dict_code, '普通' AS item_label, '2' AS item_value, '' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'crm_clue_level' AS dict_code, '非优先' AS item_label, '3' AS item_value, '' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'crm_business_stage' AS dict_code, '初步接洽' AS item_label, '1' AS item_value, '' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'crm_business_stage' AS dict_code, '需求确认' AS item_label, '2' AS item_value, '' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'crm_business_stage' AS dict_code, '方案报价' AS item_label, '3' AS item_value, '' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'crm_business_stage' AS dict_code, '商务谈判' AS item_label, '4' AS item_value, '' AS tag_type, 40 AS sort
|
||||
UNION ALL SELECT 'crm_business_stage' AS dict_code, '赢单' AS item_label, '5' AS item_value, '' AS tag_type, 50 AS sort
|
||||
UNION ALL SELECT 'crm_business_stage' AS dict_code, '输单' AS item_label, '6' AS item_value, '' AS tag_type, 60 AS sort
|
||||
UNION ALL SELECT 'crm_business_status' AS dict_code, '跟进中' AS item_label, '1' AS item_value, '' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'crm_business_status' AS dict_code, '已转化项目' AS item_label, '2' AS item_value, '' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'crm_business_status' AS dict_code, '已关闭' AS item_label, '3' AS item_value, '' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'crm_follow_type' AS dict_code, '电话' AS item_label, '1' AS item_value, '' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'crm_follow_type' AS dict_code, '微信' AS item_label, '2' AS item_value, '' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'crm_follow_type' AS dict_code, '上门' AS item_label, '3' AS item_value, '' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'crm_follow_type' AS dict_code, '邮件' AS item_label, '4' AS item_value, '' AS tag_type, 40 AS sort
|
||||
UNION ALL SELECT 'crm_follow_type' AS dict_code, '其他' AS item_label, '5' AS item_value, '' AS tag_type, 50 AS sort
|
||||
UNION ALL SELECT 'crm_pipeline_related_type' AS dict_code, '线索' AS item_label, '1' AS item_value, '' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'crm_pipeline_related_type' AS dict_code, '商机' AS item_label, '2' AS item_value, '' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'crm_pipeline_related_type' AS dict_code, '项目' AS item_label, '3' AS item_value, '' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'crm_project_status' AS dict_code, '未开始' AS item_label, '1' AS item_value, '' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'crm_project_status' AS dict_code, '进行中' AS item_label, '2' AS item_value, '' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'crm_project_status' AS dict_code, '已完成' AS item_label, '3' AS item_value, '' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'crm_project_status' AS dict_code, '已暂停' AS item_label, '4' AS item_value, '' AS tag_type, 40 AS sort
|
||||
UNION ALL SELECT 'crm_project_status' AS dict_code, '异常' AS item_label, '5' AS item_value, '' AS tag_type, 50 AS sort
|
||||
UNION ALL SELECT 'crm_project_type' AS dict_code, '单一项目' AS item_label, '1' AS item_value, '' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'crm_project_type' AS dict_code, '上下游项目' AS item_label, '2' AS item_value, '' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'crm_project_type' AS dict_code, '上中游项目' AS item_label, '3' AS item_value, '' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'crm_contract_category' AS dict_code, '开发合同' AS item_label, '1' AS item_value, '' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'crm_contract_category' AS dict_code, '服务合同' AS item_label, '2' AS item_value, '' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'crm_contract_category' AS dict_code, '销售合同' AS item_label, '3' AS item_value, '' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'crm_contract_category' AS dict_code, '租赁合同' AS item_label, '4' AS item_value, '' AS tag_type, 40 AS sort
|
||||
UNION ALL SELECT 'crm_contract_category' AS dict_code, '采购合同' AS item_label, '5' AS item_value, '' AS tag_type, 50 AS sort
|
||||
UNION ALL SELECT 'crm_contract_category' AS dict_code, '运维合同' AS item_label, '6' AS item_value, '' AS tag_type, 60 AS sort
|
||||
UNION ALL SELECT 'crm_contract_category' AS dict_code, '咨询合同' AS item_label, '7' AS item_value, '' AS tag_type, 70 AS sort
|
||||
UNION ALL SELECT 'crm_contract_category' AS dict_code, '其他' AS item_label, '8' AS item_value, '' AS tag_type, 80 AS sort
|
||||
UNION ALL SELECT 'crm_contract_status' AS dict_code, '草稿' AS item_label, '1' AS item_value, '' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'crm_contract_status' AS dict_code, '已完成' AS item_label, '2' AS item_value, '' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'crm_contract_status' AS dict_code, '履约中' AS item_label, '4' AS item_value, '' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'crm_contract_status' AS dict_code, '异常' AS item_label, '5' AS item_value, '' AS tag_type, 40 AS sort
|
||||
UNION ALL SELECT 'crm_contract_status' AS dict_code, '已作废' AS item_label, '3' AS item_value, '' AS tag_type, 50 AS sort
|
||||
UNION ALL SELECT 'crm_contract_party_count' AS dict_code, '双方合同' AS item_label, '2' AS item_value, '' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'crm_contract_party_count' AS dict_code, '三方合同' AS item_label, '3' AS item_value, '' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'crm_contract_party_count' AS dict_code, '四方合同' AS item_label, '4' AS item_value, '' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'crm_contract_our_role' AS dict_code, '甲方' AS item_label, '1' AS item_value, 'danger' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'crm_contract_our_role' AS dict_code, '乙方' AS item_label, '2' AS item_value, 'primary' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'crm_contract_our_role' AS dict_code, '丙方' AS item_label, '3' AS item_value, 'warning' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'crm_contract_our_role' AS dict_code, '丁方' AS item_label, '4' AS item_value, 'success' AS tag_type, 40 AS sort
|
||||
UNION ALL SELECT 'crm_contract_product_category' AS dict_code, '硬件(货物)' AS item_label, '1' AS item_value, '' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'crm_contract_product_category' AS dict_code, '软件(许可)' AS item_label, '2' AS item_value, '' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'crm_contract_product_category' AS dict_code, '服务' AS item_label, '3' AS item_value, '' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'crm_contract_product_category' AS dict_code, '开发' AS item_label, '4' AS item_value, '' AS tag_type, 40 AS sort
|
||||
UNION ALL SELECT 'crm_contract_product_category' AS dict_code, '其他' AS item_label, '5' AS item_value, '' AS tag_type, 50 AS sort
|
||||
UNION ALL SELECT 'crm_payback_cycle' AS dict_code, '月度' AS item_label, '1' AS item_value, '' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'crm_payback_cycle' AS dict_code, '季度' AS item_label, '2' AS item_value, '' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'crm_payback_cycle' AS dict_code, '年度' AS item_label, '3' AS item_value, '' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'crm_payback_cycle' AS dict_code, '进度' AS item_label, '4' AS item_value, '' AS tag_type, 40 AS sort
|
||||
UNION ALL SELECT 'crm_payback_cycle' AS dict_code, '自定义' AS item_label, '5' AS item_value, '' AS tag_type, 50 AS sort
|
||||
UNION ALL SELECT 'crm_payback_method' AS dict_code, '对公转账' AS item_label, '1' AS item_value, '' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'crm_payback_method' AS dict_code, '网银转账' AS item_label, '2' AS item_value, '' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'crm_payback_method' AS dict_code, '现金' AS item_label, '3' AS item_value, '' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'crm_payback_method' AS dict_code, '支票' AS item_label, '4' AS item_value, '' AS tag_type, 40 AS sort
|
||||
UNION ALL SELECT 'crm_payback_method' AS dict_code, '支付宝' AS item_label, '5' AS item_value, '' AS tag_type, 50 AS sort
|
||||
UNION ALL SELECT 'crm_payback_method' AS dict_code, '微信' AS item_label, '6' AS item_value, '' AS tag_type, 60 AS sort
|
||||
UNION ALL SELECT 'crm_payback_method' AS dict_code, '其他' AS item_label, '7' AS item_value, '' AS tag_type, 70 AS sort
|
||||
UNION ALL SELECT 'crm_payback_status' AS dict_code, '进行中' AS item_label, '1' AS item_value, '' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'crm_payback_status' AS dict_code, '已完成' AS item_label, '2' AS item_value, '' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'crm_payback_item_status' AS dict_code, '未回款' AS item_label, '1' AS item_value, '' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'crm_payback_item_status' AS dict_code, '部分回款' AS item_label, '2' AS item_value, '' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'crm_payback_item_status' AS dict_code, '已回款' AS item_label, '3' AS item_value, '' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'crm_product_status' AS dict_code, '启用' AS item_label, '1' AS item_value, 'success' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'crm_product_status' AS dict_code, '停用' AS item_label, '0' AS item_value, 'info' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'crm_product_unit' AS dict_code, '套' AS item_label, '套' AS item_value, '' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'crm_product_unit' AS dict_code, '台' AS item_label, '台' AS item_value, '' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'crm_product_unit' AS dict_code, '个' AS item_label, '个' AS item_value, '' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'crm_product_unit' AS dict_code, '件' AS item_label, '件' AS item_value, '' AS tag_type, 40 AS sort
|
||||
UNION ALL SELECT 'crm_product_unit' AS dict_code, '批' AS item_label, '批' AS item_value, '' AS tag_type, 50 AS sort
|
||||
UNION ALL SELECT 'crm_product_unit' AS dict_code, '次' AS item_label, '次' AS item_value, '' AS tag_type, 60 AS sort
|
||||
UNION ALL SELECT 'crm_product_unit' AS dict_code, '人月' AS item_label, '人月' AS item_value, '' AS tag_type, 70 AS sort
|
||||
UNION ALL SELECT 'crm_product_unit' AS dict_code, '人天' AS item_label, '人天' AS item_value, '' AS tag_type, 80 AS sort
|
||||
UNION ALL SELECT 'crm_product_unit' AS dict_code, '年' AS item_label, '年' AS item_value, '' AS tag_type, 90 AS sort
|
||||
UNION ALL SELECT 'crm_product_dev_mode' AS dict_code, '自行研发' AS item_label, 'self' AS item_value, 'success' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'crm_product_dev_mode' AS dict_code, '外协研发' AS item_label, 'outsource' AS item_value, 'warning' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'crm_tender_status' AS dict_code, '草稿' AS item_label, '0' AS item_value, '' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'crm_tender_status' AS dict_code, '公告中' AS item_label, '1' AS item_value, '' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'crm_tender_status' AS dict_code, '报名中' AS item_label, '2' AS item_value, '' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'crm_tender_status' AS dict_code, '投标中' AS item_label, '3' AS item_value, '' AS tag_type, 40 AS sort
|
||||
UNION ALL SELECT 'crm_tender_status' AS dict_code, '开标中' AS item_label, '4' AS item_value, '' AS tag_type, 50 AS sort
|
||||
UNION ALL SELECT 'crm_tender_status' AS dict_code, '评标中' AS item_label, '5' AS item_value, '' AS tag_type, 60 AS sort
|
||||
UNION ALL SELECT 'crm_tender_status' AS dict_code, '已定标' AS item_label, '6' AS item_value, '' AS tag_type, 70 AS sort
|
||||
UNION ALL SELECT 'crm_tender_status' AS dict_code, '已归档' AS item_label, '7' AS item_value, '' AS tag_type, 80 AS sort
|
||||
UNION ALL SELECT 'crm_tender_type' AS dict_code, '公开招标' AS item_label, '1' AS item_value, '' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'crm_tender_type' AS dict_code, '邀请招标' AS item_label, '2' AS item_value, '' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'crm_tender_type' AS dict_code, '竞争性谈判' AS item_label, '3' AS item_value, '' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'crm_tender_type' AS dict_code, '询比采购' AS item_label, '4' AS item_value, '' AS tag_type, 40 AS sort
|
||||
UNION ALL SELECT 'crm_tender_type' AS dict_code, '单一来源' AS item_label, '5' AS item_value, '' AS tag_type, 50 AS sort
|
||||
UNION ALL SELECT 'crm_tender_result_type' AS dict_code, '定标' AS item_label, '1' AS item_value, '' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'crm_tender_result_type' AS dict_code, '流标' AS item_label, '2' AS item_value, '' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'crm_tender_result_type' AS dict_code, '废标' AS item_label, '3' AS item_value, '' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'crm_tender_supplier_status' AS dict_code, '待审核' AS item_label, '1' AS item_value, '' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'crm_tender_supplier_status' AS dict_code, '已通过' AS item_label, '2' AS item_value, '' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'crm_tender_supplier_status' AS dict_code, '已拒绝' AS item_label, '3' AS item_value, '' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'crm_tender_supplier_status' AS dict_code, '已退标' AS item_label, '4' AS item_value, '' AS tag_type, 40 AS sort
|
||||
UNION ALL SELECT 'crm_tender_announce_type' AS dict_code, '招标公告' AS item_label, '1' AS item_value, '' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'crm_tender_announce_type' AS dict_code, '变更公告' AS item_label, '2' AS item_value, '' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'crm_tender_announce_type' AS dict_code, '中标公告' AS item_label, '3' AS item_value, '' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'crm_tender_announce_type' AS dict_code, '终止公告' AS item_label, '4' AS item_value, '' AS tag_type, 40 AS sort
|
||||
UNION ALL SELECT 'crm_evaluation_method' AS dict_code, '综合评估法' AS item_label, '1' AS item_value, '' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'crm_evaluation_method' AS dict_code, '最低价法' AS item_label, '2' AS item_value, '' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'crm_evaluation_method' AS dict_code, '性价比法' AS item_label, '3' AS item_value, '' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'crm_evaluation_result' AS dict_code, '待评' AS item_label, '0' AS item_value, '' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'crm_evaluation_result' AS dict_code, '合格' AS item_label, '1' AS item_value, '' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'crm_evaluation_result' AS dict_code, '不合格' AS item_label, '2' AS item_value, '' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'crm_evaluation_result' AS dict_code, '废标' AS item_label, '3' AS item_value, '' AS tag_type, 40 AS sort
|
||||
UNION ALL SELECT 'crm_bid_status' AS dict_code, '草稿' AS item_label, '0' AS item_value, '' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'crm_bid_status' AS dict_code, '立项审批中' AS item_label, '1' AS item_value, '' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'crm_bid_status' AS dict_code, '投标中' AS item_label, '2' AS item_value, '' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'crm_bid_status' AS dict_code, '已开标' AS item_label, '3' AS item_value, '' AS tag_type, 40 AS sort
|
||||
UNION ALL SELECT 'crm_bid_status' AS dict_code, '中标' AS item_label, '4' AS item_value, '' AS tag_type, 50 AS sort
|
||||
UNION ALL SELECT 'crm_bid_status' AS dict_code, '落标' AS item_label, '5' AS item_value, '' AS tag_type, 60 AS sort
|
||||
UNION ALL SELECT 'crm_bid_status' AS dict_code, '已转合同' AS item_label, '6' AS item_value, '' AS tag_type, 70 AS sort
|
||||
UNION ALL SELECT 'crm_bid_status' AS dict_code, '已归档' AS item_label, '7' AS item_value, '' AS tag_type, 80 AS sort
|
||||
UNION ALL SELECT 'crm_bid_type' AS dict_code, '公开招标' AS item_label, '1' AS item_value, '' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'crm_bid_type' AS dict_code, '邀请招标' AS item_label, '2' AS item_value, '' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'crm_bid_type' AS dict_code, '竞争性谈判' AS item_label, '3' AS item_value, '' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'crm_bid_type' AS dict_code, '询比采购' AS item_label, '4' AS item_value, '' AS tag_type, 40 AS sort
|
||||
UNION ALL SELECT 'crm_bid_type' AS dict_code, '单一来源' AS item_label, '5' AS item_value, '' AS tag_type, 50 AS sort
|
||||
UNION ALL SELECT 'crm_bid_source_type' AS dict_code, '独立创建' AS item_label, '0' AS item_value, '' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'crm_bid_source_type' AS dict_code, '商机' AS item_label, '1' AS item_value, '' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'crm_bid_source_type' AS dict_code, '项目' AS item_label, '2' AS item_value, '' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'crm_bid_result_type' AS dict_code, '中标' AS item_label, '1' AS item_value, '' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'crm_bid_result_type' AS dict_code, '未中标' AS item_label, '2' AS item_value, '' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'crm_bid_result_type' AS dict_code, '废标' AS item_label, '3' AS item_value, '' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'crm_bid_result_type' AS dict_code, '流标' AS item_label, '4' AS item_value, '' AS tag_type, 40 AS sort
|
||||
UNION ALL SELECT 'crm_bid_task_type' AS dict_code, '商务' AS item_label, '1' AS item_value, '' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'crm_bid_task_type' AS dict_code, '技术' AS item_label, '2' AS item_value, '' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'crm_bid_task_type' AS dict_code, '报价' AS item_label, '3' AS item_value, '' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'crm_bid_task_type' AS dict_code, '法务' AS item_label, '4' AS item_value, '' AS tag_type, 40 AS sort
|
||||
UNION ALL SELECT 'crm_bid_task_type' AS dict_code, '财务' AS item_label, '5' AS item_value, '' AS tag_type, 50 AS sort
|
||||
UNION ALL SELECT 'crm_bid_task_type' AS dict_code, '其他' AS item_label, '6' AS item_value, '' AS tag_type, 60 AS sort
|
||||
UNION ALL SELECT 'crm_bid_task_status' AS dict_code, '未开始' AS item_label, '0' AS item_value, '' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'crm_bid_task_status' AS dict_code, '进行中' AS item_label, '1' AS item_value, '' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'crm_bid_task_status' AS dict_code, '已完成' AS item_label, '2' AS item_value, '' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'crm_bid_task_status' AS dict_code, '已逾期' AS item_label, '3' AS item_value, '' AS tag_type, 40 AS sort
|
||||
UNION ALL SELECT 'crm_bid_task_status' AS dict_code, '已取消' AS item_label, '4' AS item_value, '' AS tag_type, 50 AS sort
|
||||
UNION ALL SELECT 'crm_bid_template_type' AS dict_code, '技术标' AS item_label, '1' AS item_value, '' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'crm_bid_template_type' AS dict_code, '商务标' AS item_label, '2' AS item_value, '' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'crm_bid_template_type' AS dict_code, '综合标' AS item_label, '3' AS item_value, '' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'crm_bid_quote_status' AS dict_code, '草稿' AS item_label, '1' AS item_value, '' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'crm_bid_quote_status' AS dict_code, '待审批' AS item_label, '2' AS item_value, '' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'crm_bid_quote_status' AS dict_code, '已审批' AS item_label, '3' AS item_value, '' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'crm_bid_quote_status' AS dict_code, '已使用' AS item_label, '4' AS item_value, '' AS tag_type, 40 AS sort
|
||||
UNION ALL SELECT 'crm_bid_document_status' AS dict_code, '编辑中' AS item_label, '1' AS item_value, '' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'crm_bid_document_status' AS dict_code, '待审核' AS item_label, '2' AS item_value, '' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'crm_bid_document_status' AS dict_code, '已定稿' AS item_label, '3' AS item_value, '' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'crm_bid_document_status' AS dict_code, '已提交' AS item_label, '4' AS item_value, '' AS tag_type, 40 AS sort
|
||||
UNION ALL SELECT 'crm_bid_expense_type' AS dict_code, '标书费' AS item_label, '1' AS item_value, '' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'crm_bid_expense_type' AS dict_code, '保证金' AS item_label, '2' AS item_value, '' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'crm_bid_expense_type' AS dict_code, '差旅费' AS item_label, '3' AS item_value, '' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'crm_bid_expense_type' AS dict_code, '咨询费' AS item_label, '4' AS item_value, '' AS tag_type, 40 AS sort
|
||||
UNION ALL SELECT 'crm_bid_expense_type' AS dict_code, '代理费' AS item_label, '5' AS item_value, '' AS tag_type, 50 AS sort
|
||||
UNION ALL SELECT 'crm_bid_expense_type' AS dict_code, '其他' AS item_label, '6' AS item_value, '' AS tag_type, 60 AS sort
|
||||
UNION ALL SELECT 'crm_competitor_type' AS dict_code, '同类厂商' AS item_label, '1' AS item_value, '' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'crm_competitor_type' AS dict_code, '关联企业' AS item_label, '2' AS item_value, '' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'crm_competitor_type' AS dict_code, '其他' AS item_label, '3' AS item_value, '' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'crm_qualification_type' AS dict_code, '营业执照' AS item_label, '1' AS item_value, '' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'crm_qualification_type' AS dict_code, '资质证书' AS item_label, '2' AS item_value, '' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'crm_qualification_type' AS dict_code, '业绩证明' AS item_label, '3' AS item_value, '' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'crm_qualification_type' AS dict_code, '认证证书' AS item_label, '4' AS item_value, '' AS tag_type, 40 AS sort
|
||||
UNION ALL SELECT 'crm_qualification_type' AS dict_code, '其他' AS item_label, '5' AS item_value, '' AS tag_type, 50 AS sort
|
||||
UNION ALL SELECT 'crm_qualification_status' AS dict_code, '有效' AS item_label, '1' AS item_value, '' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'crm_qualification_status' AS dict_code, '即将过期' AS item_label, '2' AS item_value, '' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'crm_qualification_status' AS dict_code, '失效' AS item_label, '0' AS item_value, '' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'crm_payment_status' AS dict_code, '未付' AS item_label, '0' AS item_value, '' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'crm_payment_status' AS dict_code, '已付' AS item_label, '1' AS item_value, '' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'crm_payment_status' AS dict_code, '已退还' AS item_label, '2' AS item_value, '' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'crm_payment_status' AS dict_code, '已抵扣' AS item_label, '3' AS item_value, '' AS tag_type, 40 AS sort
|
||||
UNION ALL SELECT 'crm_approval_type' AS dict_code, '立项审批' AS item_label, '1' AS item_value, '' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'crm_approval_type' AS dict_code, '报价审批' AS item_label, '2' AS item_value, '' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'crm_approval_type' AS dict_code, '合同审批' AS item_label, '3' AS item_value, '' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'crm_approval_status' AS dict_code, '待审批' AS item_label, '0' AS item_value, '' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'crm_approval_status' AS dict_code, '已通过' AS item_label, '1' AS item_value, '' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'crm_approval_status' AS dict_code, '已拒绝' AS item_label, '2' AS item_value, '' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'crm_approval_status' AS dict_code, '已撤回' AS item_label, '3' AS item_value, '' AS tag_type, 40 AS sort
|
||||
UNION ALL SELECT 'erp_account_set_standard' AS dict_code, '企业会计准则' AS item_label, '1' AS item_value, 'primary' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'erp_account_set_standard' AS dict_code, '小企业会计准则' AS item_label, '2' AS item_value, 'info' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'erp_account_set_currency' AS dict_code, '人民币' AS item_label, 'CNY' AS item_value, '' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'erp_account_set_currency' AS dict_code, '美元' AS item_label, 'USD' AS item_value, '' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'erp_account_set_currency' AS dict_code, '欧元' AS item_label, 'EUR' AS item_value, '' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'erp_account_set_currency' AS dict_code, '港币' AS item_label, 'HKD' AS item_value, '' AS tag_type, 40 AS sort
|
||||
UNION ALL SELECT 'erp_position_type' AS dict_code, '普通职位' AS item_label, '0' AS item_value, 'info' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'erp_position_type' AS dict_code, '主管' AS item_label, '1' AS item_value, 'warning' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'erp_position_type' AS dict_code, '负责人' AS item_label, '2' AS item_value, 'primary' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'common_employee_status' AS dict_code, '禁用' AS item_label, '0' AS item_value, 'info' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'common_employee_status' AS dict_code, '正常' AS item_label, '1' AS item_value, 'success' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'common_employee_status' AS dict_code, '离职' AS item_label, '2' AS item_value, 'danger' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'oa_employee_hire_status' AS dict_code, '试用' AS item_label, '1' AS item_value, 'warning' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'oa_employee_hire_status' AS dict_code, '正式' AS item_label, '2' AS item_value, 'success' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'oa_employee_hire_status' AS dict_code, '离职' AS item_label, '3' AS item_value, 'danger' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'oa_employee_marital' AS dict_code, '未知' AS item_label, '0' AS item_value, '' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'oa_employee_marital' AS dict_code, '未婚' AS item_label, '1' AS item_value, '' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'oa_employee_marital' AS dict_code, '已婚' AS item_label, '2' AS item_value, '' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'oa_employee_marital' AS dict_code, '离异' AS item_label, '3' AS item_value, '' AS tag_type, 40 AS sort
|
||||
UNION ALL SELECT 'oa_employee_marital' AS dict_code, '丧偶' AS item_label, '4' AS item_value, '' AS tag_type, 50 AS sort
|
||||
UNION ALL SELECT 'oa_reimburse_status' AS dict_code, '草稿' AS item_label, '0' AS item_value, 'info' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'oa_reimburse_status' AS dict_code, '审批中' AS item_label, '1' AS item_value, 'warning' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'oa_reimburse_status' AS dict_code, '已通过' AS item_label, '2' AS item_value, 'success' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'oa_reimburse_status' AS dict_code, '已驳回' AS item_label, '3' AS item_value, 'danger' AS tag_type, 40 AS sort
|
||||
UNION ALL SELECT 'oa_reimburse_status' AS dict_code, '已撤回' AS item_label, '4' AS item_value, 'info' AS tag_type, 50 AS sort
|
||||
UNION ALL SELECT 'oa_reimburse_status' AS dict_code, '已打款' AS item_label, '5' AS item_value, 'success' AS tag_type, 60 AS sort
|
||||
UNION ALL SELECT 'oa_compensation_status' AS dict_code, '草稿' AS item_label, '0' AS item_value, 'info' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'oa_compensation_status' AS dict_code, '已确认' AS item_label, '1' AS item_value, 'warning' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'oa_compensation_status' AS dict_code, '已发放' AS item_label, '2' AS item_value, 'success' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'oa_compensation_status' AS dict_code, '已作废' AS item_label, '3' AS item_value, 'danger' AS tag_type, 40 AS sort
|
||||
UNION ALL SELECT 'oa_compensation_item_type' AS dict_code, '增项' AS item_label, '1' AS item_value, '' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'oa_compensation_item_type' AS dict_code, '扣项' AS item_label, '2' AS item_value, '' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'oa_notice_type' AS dict_code, '通知' AS item_label, '0' AS item_value, 'info' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'oa_notice_type' AS dict_code, '公告' AS item_label, '1' AS item_value, 'primary' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'oa_notice_type' AS dict_code, '活动' AS item_label, '2' AS item_value, 'success' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'oa_notice_status' AS dict_code, '草稿' AS item_label, '0' AS item_value, 'info' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'oa_notice_status' AS dict_code, '已发布' AS item_label, '1' AS item_value, 'success' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'oa_notice_status' AS dict_code, '已下架' AS item_label, '2' AS item_value, 'warning' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'oa_doc_status' AS dict_code, '草稿' AS item_label, '0' AS item_value, 'warning' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'oa_doc_status' AS dict_code, '已发布' AS item_label, '1' AS item_value, 'success' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'oa_doc_status' AS dict_code, '已归档' AS item_label, '2' AS item_value, 'info' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'oa_doc_relation' AS dict_code, '引用' AS item_label, 'reference' AS item_value, '' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'oa_doc_relation' AS dict_code, '相关' AS item_label, 'related' AS item_value, '' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'oa_doc_relation' AS dict_code, '版本' AS item_label, 'version' AS item_value, '' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'oa_doc_relation' AS dict_code, '从属' AS item_label, 'belong' AS item_value, '' AS tag_type, 40 AS sort
|
||||
UNION ALL SELECT 'oa_doc_visibility' AS dict_code, '租户公开' AS item_label, '0' AS item_value, '' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'oa_doc_visibility' AS dict_code, '私密' AS item_label, '1' AS item_value, '' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'system_login_type' AS dict_code, '密码登录' AS item_label, 'password' AS item_value, '' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'system_login_type' AS dict_code, '短信验证码' AS item_label, 'sms' AS item_value, '' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'system_login_type' AS dict_code, '邮箱验证码' AS item_label, 'email' AS item_value, '' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'system_http_method' AS dict_code, 'GET' AS item_label, 'GET' AS item_value, 'info' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'system_http_method' AS dict_code, 'POST' AS item_label, 'POST' AS item_value, 'success' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'system_http_method' AS dict_code, 'PUT' AS item_label, 'PUT' AS item_value, 'warning' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'system_http_method' AS dict_code, 'DELETE' AS item_label, 'DELETE' AS item_value, 'danger' AS tag_type, 40 AS sort
|
||||
UNION ALL SELECT 'system_http_method' AS dict_code, 'PATCH' AS item_label, 'PATCH' AS item_value, 'primary' AS tag_type, 50 AS sort
|
||||
UNION ALL SELECT 'system_menu_type' AS dict_code, '目录' AS item_label, '1' AS item_value, 'primary' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'system_menu_type' AS dict_code, '菜单' AS item_label, '2' AS item_value, 'success' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'system_menu_type' AS dict_code, '按钮' AS item_label, '3' AS item_value, 'warning' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'common_order_status' AS dict_code, '待支付' AS item_label, 'pending' AS item_value, 'warning' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'common_order_status' AS dict_code, '已支付' AS item_label, 'paid' AS item_value, 'primary' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'common_order_status' AS dict_code, '已开通' AS item_label, 'activated' AS item_value, 'success' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'common_order_status' AS dict_code, '已关闭' AS item_label, 'closed' AS item_value, 'info' AS tag_type, 40 AS sort
|
||||
UNION ALL SELECT 'cms_front_menu_type' AS dict_code, '目录' AS item_label, '1' AS item_value, 'primary' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'cms_front_menu_type' AS dict_code, '页面' AS item_label, '2' AS item_value, 'success' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'cms_front_menu_type' AS dict_code, '外链' AS item_label, '3' AS item_value, 'info' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'cms_front_menu_type' AS dict_code, '单页' AS item_label, '4' AS item_value, 'warning' AS tag_type, 40 AS sort
|
||||
UNION ALL SELECT 'cms_demand_status' AS dict_code, '待处理' AS item_label, '1' AS item_value, 'info' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'cms_demand_status' AS dict_code, '处理中' AS item_label, '2' AS item_value, 'warning' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'cms_demand_status' AS dict_code, '已完成' AS item_label, '3' AS item_value, 'success' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'cms_demand_status' AS dict_code, '已拒绝' AS item_label, '4' AS item_value, 'danger' AS tag_type, 40 AS sort
|
||||
UNION ALL SELECT 'tenant_domain_verify_status' AS dict_code, '未检测' AS item_label, '0' AS item_value, 'info' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'tenant_domain_verify_status' AS dict_code, '已通过' AS item_label, '1' AS item_value, 'success' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'tenant_domain_verify_status' AS dict_code, '未通过' AS item_label, '2' AS item_value, 'danger' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'tenant_domain_ssl_status' AS dict_code, '待处理' AS item_label, '0' AS item_value, 'info' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'tenant_domain_ssl_status' AS dict_code, '签发中' AS item_label, '1' AS item_value, 'warning' AS tag_type, 20 AS sort
|
||||
UNION ALL SELECT 'tenant_domain_ssl_status' AS dict_code, '已签发' AS item_label, '2' AS item_value, 'success' AS tag_type, 30 AS sort
|
||||
UNION ALL SELECT 'tenant_domain_ssl_status' AS dict_code, '签发失败' AS item_label, '3' AS item_value, 'danger' AS tag_type, 40 AS sort
|
||||
) AS t
|
||||
JOIN `yz_backend_dict` AS d
|
||||
ON d.tenant_id = '0' AND d.dict_code = t.dict_code AND d.delete_time IS NULL
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM `yz_backend_dict_item` AS i
|
||||
WHERE i.dict_id = d.id AND i.item_value = t.item_value AND i.delete_time IS NULL
|
||||
);
|
||||
|
||||
|
||||
-- =============================================================
|
||||
-- 3. 校验
|
||||
-- =============================================================
|
||||
|
||||
SELECT d.dict_name, d.dict_code, COUNT(i.id) AS item_count
|
||||
FROM `yz_backend_dict` d
|
||||
LEFT JOIN `yz_backend_dict_item` i ON i.dict_id = d.id AND i.delete_time IS NULL
|
||||
WHERE d.tenant_id = '0' AND d.delete_time IS NULL
|
||||
GROUP BY d.id, d.dict_name, d.dict_code
|
||||
ORDER BY d.sort, d.id;
|
||||
@@ -0,0 +1,305 @@
|
||||
-- =============================================================
|
||||
-- 平台端数据字典 —— 初始数据
|
||||
--
|
||||
-- 表:yz_platform_dict / yz_platform_dict_item(建表见 create_dict.sql)
|
||||
-- 内容来源:platform 前端散落的硬编码映射(值→文案 / 标签色),
|
||||
-- 以及各平台端接口返回的状态字段取值。
|
||||
--
|
||||
-- 幂等:
|
||||
-- - 字典按 dict_code 判重,已存在则跳过;
|
||||
-- - 字典项按 (dict_id, item_value) 判重,已存在则跳过。
|
||||
-- 因此可重复执行,不会产生重复数据。
|
||||
--
|
||||
-- 说明:
|
||||
-- - tag_type 对应前端 el-tag 的 type,留空表示不渲染彩色标签;
|
||||
-- - sort 按 10 递增,便于后续插入新字典项;
|
||||
-- - 执行完这份数据后,前端改为调用 /platform/dict/options/:code 读取。
|
||||
-- =============================================================
|
||||
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
|
||||
-- =============================================================
|
||||
-- 1. 字典列表
|
||||
-- =============================================================
|
||||
|
||||
INSERT INTO `yz_platform_dict` (`dict_name`, `dict_code`, `remark`, `sort`, `status`, `create_user_id`, `create_time`)
|
||||
SELECT t.dict_name, t.dict_code, t.remark, t.sort, 1, 'sql', NOW()
|
||||
FROM (
|
||||
-- 通用
|
||||
SELECT '通用启用状态' AS dict_name, 'common_enable_status' AS dict_code, '1 启用 / 0 停用,部分页面把 0 显示为「禁用」' AS remark, 10 AS sort
|
||||
UNION ALL SELECT '是否' , 'common_yes_no' , '1 是 / 0 否' , 20
|
||||
-- 支付
|
||||
UNION ALL SELECT '支付渠道' , 'payment_channel' , 'yz_platform_payment_channel.channel' , 100
|
||||
UNION ALL SELECT '支付单状态' , 'payment_order_status' , 'yz_platform_payment_order.status' , 110
|
||||
UNION ALL SELECT '支付订单类型' , 'payment_order_type' , 'yz_platform_payment_order.order_type' , 120
|
||||
UNION ALL SELECT '支付渠道状态' , 'payment_channel_state' , '渠道配置页展示状态:启用/停用/未配置' , 130
|
||||
UNION ALL SELECT '对账处理状态' , 'payment_reconcile_status' , 'yz_platform_payment_reconcile_diff.handle_status' , 140
|
||||
UNION ALL SELECT '对账差异类型' , 'payment_reconcile_diff_type', 'yz_platform_payment_reconcile_diff.diff_type' , 150
|
||||
UNION ALL SELECT '佣金状态' , 'payment_commission_status', 'yz_platform_commission_order.status' , 160
|
||||
UNION ALL SELECT '佣金发放方式' , 'payment_commission_pay_method', 'yz_platform_commission_order.pay_method' , 170
|
||||
UNION ALL SELECT '佣金计算方式' , 'payment_calc_type' , 'yz_platform_commission_rule.calc_type' , 180
|
||||
-- 通知 / 短信
|
||||
UNION ALL SELECT '通知渠道' , 'notification_channel' , '站内提醒的推送渠道' , 200
|
||||
UNION ALL SELECT '短信任务状态' , 'sms_task_status' , 'yz_system_sms_task.status' , 210
|
||||
-- 系统
|
||||
UNION ALL SELECT '请求方法' , 'http_method' , '操作日志的 HTTP 方法' , 220
|
||||
UNION ALL SELECT '登录方式' , 'login_type' , '登录日志的登录方式' , 230
|
||||
UNION ALL SELECT '菜单类型' , 'menu_type' , 'yz_system_menu.type' , 240
|
||||
-- 官网内容
|
||||
UNION ALL SELECT '导航类型' , 'website_nav_type' , 'yz_platform_website_nav.type' , 250
|
||||
UNION ALL SELECT '评论状态' , 'comment_status' , 'yz_platform_website_comment.status' , 260
|
||||
UNION ALL SELECT '文章状态' , 'article_status' , 'yz_platform_website_article.status' , 270
|
||||
UNION ALL SELECT '公告类型' , 'notice_type' , 'yz_platform_website_notice.type' , 280
|
||||
UNION ALL SELECT '公告状态' , 'notice_status' , 'yz_platform_website_notice.status' , 290
|
||||
-- 账号池 / Cursor
|
||||
UNION ALL SELECT '账号池平台' , 'account_pool_platform' , '账号来源平台(本地/闲鱼/淘宝…)' , 300
|
||||
UNION ALL SELECT '账号池数据类型' , 'account_pool_data_type' , '账号密码 / 账号密码+Token / Token' , 310
|
||||
UNION ALL SELECT '账号池提取状态' , 'account_pool_extract_status', '账号池记录的提取状态' , 320
|
||||
UNION ALL SELECT 'Cursor 设备状态' , 'cursor_equipment_status' , 'yz_platform_cursor_equipment.status' , 330
|
||||
UNION ALL SELECT 'Cursor 激活码状态' , 'cursor_activation_status' , 'yz_platform_cursor_activation_code.status' , 340
|
||||
UNION ALL SELECT '提取记录状态' , 'cursor_extract_record_status', 'Cursor 设备提取记录的状态' , 350
|
||||
UNION ALL SELECT '激活记录状态' , 'cursor_activation_record_status', 'Cursor 设备激活记录的状态' , 360
|
||||
-- 模块商店
|
||||
UNION ALL SELECT '模块发布状态' , 'moduleshop_publish_status' , '模块商店上下架状态' , 370
|
||||
UNION ALL SELECT '模块分类状态' , 'moduleshop_category_status' , '模块商店分类启用状态' , 380
|
||||
-- 投诉工单
|
||||
UNION ALL SELECT '投诉工单状态' , 'complain_status' , 'yz_platform_complaint.status' , 390
|
||||
-- 统一认证
|
||||
UNION ALL SELECT '接入应用类型' , 'auth_app_type' , 'yz_auth_client.app_type' , 400
|
||||
UNION ALL SELECT '认证域' , 'auth_realm' , '租户域 / 平台域' , 410
|
||||
UNION ALL SELECT '登录验证方式' , 'auth_verify_type' , '图形验证码 / 短信 / 邮箱 / 极验 / 不开启' , 420
|
||||
-- 域名
|
||||
UNION ALL SELECT '域名类型' , 'domain_type' , 'yz_system_tenant_domain.domain_type' , 430
|
||||
UNION ALL SELECT '域名状态' , 'domain_status' , 'yz_system_tenant_domain.status' , 440
|
||||
-- 租户 / 组织
|
||||
UNION ALL SELECT '员工状态' , 'employee_status' , 'yz_backend_employee.account_status' , 450
|
||||
UNION ALL SELECT '性别' , 'gender' , '用户/员工性别' , 460
|
||||
UNION ALL SELECT '角色分类' , 'role_category' , 'yz_system_admin_role.cid:1 平台角色 / 2 租户角色' , 470
|
||||
UNION ALL SELECT '角色来源' , 'role_source' , 'yz_system_admin_role.is_custom' , 480
|
||||
UNION ALL SELECT '站内信接收对象' , 'sitereminder_target_type' , 'yz_system_reminder_list.target_type' , 490
|
||||
) AS t
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM `yz_platform_dict` AS d
|
||||
WHERE d.dict_code = t.dict_code AND d.delete_time IS NULL
|
||||
);
|
||||
|
||||
|
||||
-- =============================================================
|
||||
-- 2. 字典项
|
||||
-- =============================================================
|
||||
|
||||
INSERT INTO `yz_platform_dict_item` (`dict_id`, `item_label`, `item_value`, `tag_type`, `sort`, `status`, `is_default`, `create_time`)
|
||||
SELECT d.id, t.item_label, t.item_value, t.tag_type, t.sort, 1, 0, NOW()
|
||||
FROM (
|
||||
-- 通用启用状态
|
||||
SELECT 'common_enable_status' AS dict_code, '启用' AS item_label, '1' AS item_value, 'success' AS tag_type, 10 AS sort
|
||||
UNION ALL SELECT 'common_enable_status' , '停用' , '0' , 'info' , 20
|
||||
-- 是否
|
||||
UNION ALL SELECT 'common_yes_no' , '是' , '1' , 'success' , 10
|
||||
UNION ALL SELECT 'common_yes_no' , '否' , '0' , 'info' , 20
|
||||
-- 支付渠道
|
||||
UNION ALL SELECT 'payment_channel' , '微信支付' , 'wechat' , '' , 10
|
||||
UNION ALL SELECT 'payment_channel' , '支付宝' , 'alipay' , '' , 20
|
||||
UNION ALL SELECT 'payment_channel' , '银联' , 'unionpay' , '' , 30
|
||||
UNION ALL SELECT 'payment_channel' , '云闪付' , 'cloudpay' , '' , 40
|
||||
UNION ALL SELECT 'payment_channel' , 'PayPal' , 'paypal' , '' , 50
|
||||
-- 支付单状态
|
||||
UNION ALL SELECT 'payment_order_status' , '已创建' , 'created' , 'info' , 10
|
||||
UNION ALL SELECT 'payment_order_status' , '待支付' , 'pending' , 'warning' , 20
|
||||
UNION ALL SELECT 'payment_order_status' , '支付中' , 'paying' , 'warning' , 30
|
||||
UNION ALL SELECT 'payment_order_status' , '支付成功' , 'paid' , 'success' , 40
|
||||
UNION ALL SELECT 'payment_order_status' , '支付成功' , 'success' , 'success' , 50
|
||||
UNION ALL SELECT 'payment_order_status' , '支付失败' , 'failed' , 'danger' , 60
|
||||
UNION ALL SELECT 'payment_order_status' , '已关闭' , 'closed' , 'info' , 70
|
||||
UNION ALL SELECT 'payment_order_status' , '已超时' , 'timeout' , 'info' , 80
|
||||
UNION ALL SELECT 'payment_order_status' , '退款中' , 'refunding' , 'warning' , 90
|
||||
UNION ALL SELECT 'payment_order_status' , '已退款' , 'refunded' , 'info' , 100
|
||||
UNION ALL SELECT 'payment_order_status' , '部分退款' , 'partial_refunded' , 'warning' , 110
|
||||
-- 支付订单类型
|
||||
UNION ALL SELECT 'payment_order_type' , '平台使用费' , 'platform_usage' , '' , 10
|
||||
UNION ALL SELECT 'payment_order_type' , '模块购买' , 'module_shop' , '' , 20
|
||||
UNION ALL SELECT 'payment_order_type' , '服务费' , 'service_fee' , '' , 30
|
||||
-- 支付渠道状态
|
||||
UNION ALL SELECT 'payment_channel_state' , '已启用' , 'enabled' , 'success' , 10
|
||||
UNION ALL SELECT 'payment_channel_state' , '已停用' , 'disabled' , 'info' , 20
|
||||
UNION ALL SELECT 'payment_channel_state' , '未配置' , 'unconfigured' , 'warning' , 30
|
||||
-- 对账处理状态
|
||||
UNION ALL SELECT 'payment_reconcile_status' , '待处理' , 'unhandled' , 'warning' , 10
|
||||
UNION ALL SELECT 'payment_reconcile_status' , '处理中' , 'handling' , 'primary' , 20
|
||||
UNION ALL SELECT 'payment_reconcile_status' , '已处理' , 'handled' , 'success' , 30
|
||||
UNION ALL SELECT 'payment_reconcile_status' , '已忽略' , 'ignored' , 'info' , 40
|
||||
-- 对账差异类型
|
||||
UNION ALL SELECT 'payment_reconcile_diff_type' , '长款' , 'long' , 'warning' , 10
|
||||
UNION ALL SELECT 'payment_reconcile_diff_type' , '短款' , 'short' , 'danger' , 20
|
||||
UNION ALL SELECT 'payment_reconcile_diff_type' , '状态不一致' , 'status_mismatch' , 'warning' , 30
|
||||
-- 佣金状态
|
||||
UNION ALL SELECT 'payment_commission_status' , '应付' , 'payable' , 'warning' , 10
|
||||
UNION ALL SELECT 'payment_commission_status' , '已付' , 'settled' , 'success' , 20
|
||||
UNION ALL SELECT 'payment_commission_status' , '税务处理中' , 'tax_processing' , 'primary' , 30
|
||||
UNION ALL SELECT 'payment_commission_status' , '已作废' , 'canceled' , 'info' , 40
|
||||
-- 佣金发放方式
|
||||
UNION ALL SELECT 'payment_commission_pay_method', '余额抵扣' , 'balance' , '' , 10
|
||||
UNION ALL SELECT 'payment_commission_pay_method', '银行转账' , 'bank' , '' , 20
|
||||
UNION ALL SELECT 'payment_commission_pay_method', '人工发放' , 'manual' , '' , 30
|
||||
UNION ALL SELECT 'payment_commission_pay_method', '下期抵扣' , 'offset' , '' , 40
|
||||
-- 佣金计算方式
|
||||
UNION ALL SELECT 'payment_calc_type' , '按比例' , 'percent' , 'primary' , 10
|
||||
UNION ALL SELECT 'payment_calc_type' , '固定金额' , 'fixed' , 'success' , 20
|
||||
UNION ALL SELECT 'payment_calc_type' , '阶梯' , 'tiered' , 'warning' , 30
|
||||
-- 通知渠道
|
||||
UNION ALL SELECT 'notification_channel' , '短信' , 'SMS' , 'success' , 10
|
||||
UNION ALL SELECT 'notification_channel' , '邮件' , 'EMAIL' , 'warning' , 20
|
||||
UNION ALL SELECT 'notification_channel' , 'Bark推送' , 'BARK' , 'danger' , 30
|
||||
UNION ALL SELECT 'notification_channel' , '站内信' , 'SITE_MSG' , 'primary' , 40
|
||||
-- 短信任务状态
|
||||
UNION ALL SELECT 'sms_task_status' , '待发送' , '0' , 'info' , 10
|
||||
UNION ALL SELECT 'sms_task_status' , '发送中' , '1' , 'warning' , 20
|
||||
UNION ALL SELECT 'sms_task_status' , '发送失败' , '2' , 'danger' , 30
|
||||
UNION ALL SELECT 'sms_task_status' , '发送成功' , '3' , 'success' , 40
|
||||
-- 请求方法
|
||||
UNION ALL SELECT 'http_method' , 'GET' , 'GET' , 'info' , 10
|
||||
UNION ALL SELECT 'http_method' , 'POST' , 'POST' , 'success' , 20
|
||||
UNION ALL SELECT 'http_method' , 'PUT' , 'PUT' , 'warning' , 30
|
||||
UNION ALL SELECT 'http_method' , 'DELETE' , 'DELETE' , 'danger' , 40
|
||||
UNION ALL SELECT 'http_method' , 'PATCH' , 'PATCH' , 'primary' , 50
|
||||
-- 登录方式
|
||||
UNION ALL SELECT 'login_type' , '密码登录' , 'password' , '' , 10
|
||||
UNION ALL SELECT 'login_type' , '短信验证码' , 'sms' , '' , 20
|
||||
UNION ALL SELECT 'login_type' , '邮箱验证码' , 'email' , '' , 30
|
||||
-- 菜单类型
|
||||
UNION ALL SELECT 'menu_type' , '目录' , '1' , 'primary' , 10
|
||||
UNION ALL SELECT 'menu_type' , '页面' , '2' , 'success' , 20
|
||||
UNION ALL SELECT 'menu_type' , '接口' , '3' , 'info' , 30
|
||||
-- 导航类型
|
||||
UNION ALL SELECT 'website_nav_type' , '目录' , '1' , 'primary' , 10
|
||||
UNION ALL SELECT 'website_nav_type' , '页面' , '2' , 'success' , 20
|
||||
UNION ALL SELECT 'website_nav_type' , '外链' , '3' , 'info' , 30
|
||||
UNION ALL SELECT 'website_nav_type' , '单页' , '4' , 'warning' , 40
|
||||
-- 评论状态
|
||||
UNION ALL SELECT 'comment_status' , '待审核' , '0' , 'warning' , 10
|
||||
UNION ALL SELECT 'comment_status' , '已通过' , '1' , 'success' , 20
|
||||
UNION ALL SELECT 'comment_status' , '已拒绝' , '2' , 'danger' , 30
|
||||
-- 文章状态
|
||||
UNION ALL SELECT 'article_status' , '草稿' , '0' , 'info' , 10
|
||||
UNION ALL SELECT 'article_status' , '待审核' , '1' , 'warning' , 20
|
||||
UNION ALL SELECT 'article_status' , '已发布' , '2' , 'success' , 30
|
||||
UNION ALL SELECT 'article_status' , '已隐藏' , '3' , 'danger' , 40
|
||||
-- 公告类型
|
||||
UNION ALL SELECT 'notice_type' , '通知公告' , '1' , '' , 10
|
||||
UNION ALL SELECT 'notice_type' , '活动公告' , '2' , '' , 20
|
||||
UNION ALL SELECT 'notice_type' , '系统维护' , '3' , '' , 30
|
||||
-- 公告状态
|
||||
UNION ALL SELECT 'notice_status' , '草稿' , '0' , 'info' , 10
|
||||
UNION ALL SELECT 'notice_status' , '已发布' , '1' , 'success' , 20
|
||||
UNION ALL SELECT 'notice_status' , '已下线' , '2' , 'warning' , 30
|
||||
-- 账号池平台
|
||||
UNION ALL SELECT 'account_pool_platform' , '本地' , 'local' , 'info' , 10
|
||||
UNION ALL SELECT 'account_pool_platform' , '闲鱼' , 'xianyu' , 'warning' , 20
|
||||
UNION ALL SELECT 'account_pool_platform' , '拼多多' , 'pinduoduo' , 'danger' , 30
|
||||
UNION ALL SELECT 'account_pool_platform' , '京东' , 'jingdong' , 'primary' , 40
|
||||
UNION ALL SELECT 'account_pool_platform' , '抖音' , 'douyin' , 'success' , 50
|
||||
UNION ALL SELECT 'account_pool_platform' , '淘宝' , 'taobao' , 'info' , 60
|
||||
UNION ALL SELECT 'account_pool_platform' , '自有商城' , 'ziyoushangcheng' , 'warning' , 70
|
||||
UNION ALL SELECT 'account_pool_platform' , '续杯' , 'xubei' , 'primary' , 80
|
||||
-- 账号池数据类型
|
||||
UNION ALL SELECT 'account_pool_data_type' , '账号密码' , 'account' , 'success' , 10
|
||||
UNION ALL SELECT 'account_pool_data_type' , '账号密码+Token' , 'account_tk' , 'primary' , 20
|
||||
UNION ALL SELECT 'account_pool_data_type' , 'Token' , 'tk' , 'warning' , 30
|
||||
-- 账号池提取状态
|
||||
UNION ALL SELECT 'account_pool_extract_status' , '未提取' , '0' , 'info' , 10
|
||||
UNION ALL SELECT 'account_pool_extract_status' , '补号' , '2' , 'warning' , 20
|
||||
UNION ALL SELECT 'account_pool_extract_status' , '续杯' , '3' , 'primary' , 30
|
||||
UNION ALL SELECT 'account_pool_extract_status' , '已提取' , 'extracted' , 'success' , 40
|
||||
-- Cursor 设备状态
|
||||
UNION ALL SELECT 'cursor_equipment_status' , '已激活' , 'active' , 'success' , 10
|
||||
UNION ALL SELECT 'cursor_equipment_status' , '未激活' , 'inactive' , 'info' , 20
|
||||
UNION ALL SELECT 'cursor_equipment_status' , '禁用' , 'disabled' , 'danger' , 30
|
||||
UNION ALL SELECT 'cursor_equipment_status' , '已过期' , 'expired' , 'warning' , 40
|
||||
-- Cursor 激活码状态
|
||||
UNION ALL SELECT 'cursor_activation_status' , '未使用' , '0' , 'info' , 10
|
||||
UNION ALL SELECT 'cursor_activation_status' , '已使用' , '1' , 'success' , 20
|
||||
UNION ALL SELECT 'cursor_activation_status' , '已过期' , '2' , 'warning' , 30
|
||||
UNION ALL SELECT 'cursor_activation_status' , '已禁用' , '3' , 'danger' , 40
|
||||
-- 提取记录状态
|
||||
UNION ALL SELECT 'cursor_extract_record_status', '未提取' , '0' , 'info' , 10
|
||||
UNION ALL SELECT 'cursor_extract_record_status', '已提取' , '1' , 'success' , 20
|
||||
UNION ALL SELECT 'cursor_extract_record_status', '补号' , '2' , 'warning' , 30
|
||||
UNION ALL SELECT 'cursor_extract_record_status', '异常' , '3' , 'danger' , 40
|
||||
-- 激活记录状态
|
||||
UNION ALL SELECT 'cursor_activation_record_status', '失败' , '0' , 'danger' , 10
|
||||
UNION ALL SELECT 'cursor_activation_record_status', '成功' , '1' , 'success' , 20
|
||||
-- 模块发布状态
|
||||
UNION ALL SELECT 'moduleshop_publish_status' , '草稿' , '0' , 'info' , 10
|
||||
UNION ALL SELECT 'moduleshop_publish_status' , '已发布' , '1' , 'success' , 20
|
||||
UNION ALL SELECT 'moduleshop_publish_status' , '已撤回' , '2' , 'warning' , 30
|
||||
-- 模块分类状态
|
||||
UNION ALL SELECT 'moduleshop_category_status' , '禁用' , '0' , 'info' , 10
|
||||
UNION ALL SELECT 'moduleshop_category_status' , '启用' , '1' , 'success' , 20
|
||||
-- 投诉工单状态
|
||||
UNION ALL SELECT 'complain_status' , '待处理' , '0' , 'warning' , 10
|
||||
UNION ALL SELECT 'complain_status' , '处理中' , '1' , 'warning' , 20
|
||||
UNION ALL SELECT 'complain_status' , '已回复' , '2' , 'success' , 30
|
||||
UNION ALL SELECT 'complain_status' , '已关闭' , '3' , 'info' , 40
|
||||
-- 接入应用类型
|
||||
UNION ALL SELECT 'auth_app_type' , 'Web 后端' , '1' , '' , 10
|
||||
UNION ALL SELECT 'auth_app_type' , 'SPA' , '2' , '' , 20
|
||||
UNION ALL SELECT 'auth_app_type' , '原生 APP' , '3' , '' , 30
|
||||
UNION ALL SELECT 'auth_app_type' , '小程序' , '4' , '' , 40
|
||||
-- 认证域
|
||||
UNION ALL SELECT 'auth_realm' , '租户域' , 'tenant' , '' , 10
|
||||
UNION ALL SELECT 'auth_realm' , '平台域' , 'platform' , '' , 20
|
||||
-- 登录验证方式
|
||||
UNION ALL SELECT 'auth_verify_type' , '图形验证码' , 'captcha' , '' , 10
|
||||
UNION ALL SELECT 'auth_verify_type' , '短信验证码' , 'sms' , '' , 20
|
||||
UNION ALL SELECT 'auth_verify_type' , '邮箱验证码' , 'email' , '' , 30
|
||||
UNION ALL SELECT 'auth_verify_type' , '极验人机验证' , 'geetest' , '' , 40
|
||||
UNION ALL SELECT 'auth_verify_type' , '不开启' , 'none' , '' , 50
|
||||
-- 域名类型
|
||||
UNION ALL SELECT 'domain_type' , '平台二级域名' , '1' , '' , 10
|
||||
UNION ALL SELECT 'domain_type' , '自有域名' , '2' , '' , 20
|
||||
-- 域名状态
|
||||
UNION ALL SELECT 'domain_status' , '审核中' , '0' , 'warning' , 10
|
||||
UNION ALL SELECT 'domain_status' , '已生效' , '1' , 'success' , 20
|
||||
UNION ALL SELECT 'domain_status' , '已禁用' , '2' , 'info' , 30
|
||||
-- 员工状态
|
||||
UNION ALL SELECT 'employee_status' , '启用' , '1' , 'success' , 10
|
||||
UNION ALL SELECT 'employee_status' , '禁用' , '0' , 'info' , 20
|
||||
UNION ALL SELECT 'employee_status' , '离职' , '2' , 'danger' , 30
|
||||
-- 性别
|
||||
UNION ALL SELECT 'gender' , '保密' , '0' , 'info' , 10
|
||||
UNION ALL SELECT 'gender' , '男' , '1' , 'primary' , 20
|
||||
UNION ALL SELECT 'gender' , '女' , '2' , 'danger' , 30
|
||||
-- 角色分类
|
||||
UNION ALL SELECT 'role_category' , '平台角色' , '1' , 'primary' , 10
|
||||
UNION ALL SELECT 'role_category' , '租户角色' , '2' , 'warning' , 20
|
||||
-- 角色来源
|
||||
UNION ALL SELECT 'role_source' , '预置' , '0' , 'info' , 10
|
||||
UNION ALL SELECT 'role_source' , '自建' , '1' , 'warning' , 20
|
||||
-- 站内信接收对象
|
||||
UNION ALL SELECT 'sitereminder_target_type' , '全平台(所有人)' , 'all' , 'danger' , 10
|
||||
UNION ALL SELECT 'sitereminder_target_type' , '平台端(所有人)' , 'platform' , 'primary' , 20
|
||||
UNION ALL SELECT 'sitereminder_target_type' , '租户端(所有租户)' , 'tenant_all' , 'success' , 30
|
||||
UNION ALL SELECT 'sitereminder_target_type' , '租户角色' , 'tenant_role' , 'warning' , 40
|
||||
UNION ALL SELECT 'sitereminder_target_type' , '租户' , 'tenant' , 'warning' , 50
|
||||
UNION ALL SELECT 'sitereminder_target_type' , '租户用户' , 'tenant_user' , 'info' , 60
|
||||
UNION ALL SELECT 'sitereminder_target_type' , '平台角色' , 'role' , 'warning' , 70
|
||||
) AS t
|
||||
JOIN `yz_platform_dict` AS d
|
||||
ON d.dict_code = t.dict_code AND d.delete_time IS NULL
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM `yz_platform_dict_item` AS i
|
||||
WHERE i.dict_id = d.id AND i.item_value = t.item_value AND i.delete_time IS NULL
|
||||
);
|
||||
|
||||
|
||||
-- =============================================================
|
||||
-- 3. 校验
|
||||
-- =============================================================
|
||||
|
||||
SELECT d.dict_name, d.dict_code, COUNT(i.id) AS item_count
|
||||
FROM `yz_platform_dict` d
|
||||
LEFT JOIN `yz_platform_dict_item` i ON i.dict_id = d.id AND i.delete_time IS NULL
|
||||
WHERE d.delete_time IS NULL
|
||||
GROUP BY d.id, d.dict_name, d.dict_code
|
||||
ORDER BY d.sort, d.id;
|
||||
@@ -0,0 +1,45 @@
|
||||
package models
|
||||
|
||||
import "time"
|
||||
|
||||
// BackendDict 租户端数据字典(字典列表): yz_backend_dict
|
||||
// 表结构见 docs/sql/create_dict.sql。租户隔离字段 tenant_id 与 yz_backend_erp_supplier 一致。
|
||||
type BackendDict struct {
|
||||
ID uint64 `orm:"column(id);pk;auto" json:"id"`
|
||||
TenantID string `orm:"column(tenant_id);size(64)" json:"tenant_id"`
|
||||
DictName string `orm:"column(dict_name);size(100)" json:"dict_name"`
|
||||
DictCode string `orm:"column(dict_code);size(100)" json:"dict_code"`
|
||||
Remark string `orm:"column(remark);size(500)" json:"remark"`
|
||||
Sort int `orm:"column(sort);default(0)" json:"sort"`
|
||||
Status int8 `orm:"column(status);default(1)" json:"status"`
|
||||
CreateUserID string `orm:"column(create_user_id);size(64)" json:"create_user_id"`
|
||||
CreateTime time.Time `orm:"column(create_time);type(datetime);auto_now_add" json:"create_time"`
|
||||
UpdateTime *time.Time `orm:"column(update_time);type(datetime);null" json:"update_time"`
|
||||
DeleteTime *time.Time `orm:"column(delete_time);type(datetime);null" json:"delete_time"`
|
||||
}
|
||||
|
||||
func (m *BackendDict) TableName() string {
|
||||
return "yz_backend_dict"
|
||||
}
|
||||
|
||||
// BackendDictItem 租户端字典项: yz_backend_dict_item
|
||||
// tenant_id 冗余自所属字典,写入时由后端保证与字典一致。
|
||||
type BackendDictItem struct {
|
||||
ID uint64 `orm:"column(id);pk;auto" json:"id"`
|
||||
TenantID string `orm:"column(tenant_id);size(64)" json:"tenant_id"`
|
||||
DictID uint64 `orm:"column(dict_id);default(0)" json:"dict_id"`
|
||||
ItemLabel string `orm:"column(item_label);size(100)" json:"item_label"`
|
||||
ItemValue string `orm:"column(item_value);size(100)" json:"item_value"`
|
||||
TagType string `orm:"column(tag_type);size(20)" json:"tag_type"`
|
||||
Sort int `orm:"column(sort);default(0)" json:"sort"`
|
||||
Status int8 `orm:"column(status);default(1)" json:"status"`
|
||||
IsDefault int8 `orm:"column(is_default);default(0)" json:"is_default"`
|
||||
Remark string `orm:"column(remark);size(500)" json:"remark"`
|
||||
CreateTime time.Time `orm:"column(create_time);type(datetime);auto_now_add" json:"create_time"`
|
||||
UpdateTime *time.Time `orm:"column(update_time);type(datetime);null" json:"update_time"`
|
||||
DeleteTime *time.Time `orm:"column(delete_time);type(datetime);null" json:"delete_time"`
|
||||
}
|
||||
|
||||
func (m *BackendDictItem) TableName() string {
|
||||
return "yz_backend_dict_item"
|
||||
}
|
||||
@@ -210,6 +210,12 @@ func Init(_ string) {
|
||||
new(AuthTenantIdp),
|
||||
new(AuthTenantAuthConfig),
|
||||
new(AuthLoginLog),
|
||||
|
||||
// 数据字典(docs/sql/create_dict.sql):平台端 / 租户端各一套
|
||||
new(PlatformDict),
|
||||
new(PlatformDictItem),
|
||||
new(BackendDict),
|
||||
new(BackendDictItem),
|
||||
)
|
||||
|
||||
// 创建全局 Ormer
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
package models
|
||||
|
||||
import "time"
|
||||
|
||||
// PlatformDict 平台端数据字典(字典列表): yz_platform_dict
|
||||
// 表结构见 docs/sql/create_dict.sql(人工执行建表,代码不做自动建表)。
|
||||
type PlatformDict struct {
|
||||
ID uint64 `orm:"column(id);pk;auto" json:"id"`
|
||||
DictName string `orm:"column(dict_name);size(100)" json:"dict_name"`
|
||||
DictCode string `orm:"column(dict_code);size(100)" json:"dict_code"`
|
||||
Remark string `orm:"column(remark);size(500)" json:"remark"`
|
||||
Sort int `orm:"column(sort);default(0)" json:"sort"`
|
||||
Status int8 `orm:"column(status);default(1)" json:"status"`
|
||||
CreateUserID string `orm:"column(create_user_id);size(64)" json:"create_user_id"`
|
||||
CreateTime time.Time `orm:"column(create_time);type(datetime);auto_now_add" json:"create_time"`
|
||||
UpdateTime *time.Time `orm:"column(update_time);type(datetime);null" json:"update_time"`
|
||||
DeleteTime *time.Time `orm:"column(delete_time);type(datetime);null" json:"delete_time"`
|
||||
}
|
||||
|
||||
func (m *PlatformDict) TableName() string {
|
||||
return "yz_platform_dict"
|
||||
}
|
||||
|
||||
// PlatformDictItem 平台端字典项: yz_platform_dict_item
|
||||
type PlatformDictItem struct {
|
||||
ID uint64 `orm:"column(id);pk;auto" json:"id"`
|
||||
DictID uint64 `orm:"column(dict_id);default(0)" json:"dict_id"`
|
||||
ItemLabel string `orm:"column(item_label);size(100)" json:"item_label"`
|
||||
ItemValue string `orm:"column(item_value);size(100)" json:"item_value"`
|
||||
TagType string `orm:"column(tag_type);size(20)" json:"tag_type"`
|
||||
Sort int `orm:"column(sort);default(0)" json:"sort"`
|
||||
Status int8 `orm:"column(status);default(1)" json:"status"`
|
||||
IsDefault int8 `orm:"column(is_default);default(0)" json:"is_default"`
|
||||
Remark string `orm:"column(remark);size(500)" json:"remark"`
|
||||
CreateTime time.Time `orm:"column(create_time);type(datetime);auto_now_add" json:"create_time"`
|
||||
UpdateTime *time.Time `orm:"column(update_time);type(datetime);null" json:"update_time"`
|
||||
DeleteTime *time.Time `orm:"column(delete_time);type(datetime);null" json:"delete_time"`
|
||||
}
|
||||
|
||||
func (m *PlatformDictItem) TableName() string {
|
||||
return "yz_platform_dict_item"
|
||||
}
|
||||
@@ -14,6 +14,7 @@ func Register() {
|
||||
RegisterPaymentRoutes()
|
||||
RegisterProductRoutes()
|
||||
RegisterWechatMpRoutes()
|
||||
RegisterDictRoutes()
|
||||
}
|
||||
|
||||
// RegisterProductRoutes 注册租户端「产品购买」路由。
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package backend
|
||||
|
||||
import (
|
||||
"server/controllers"
|
||||
|
||||
beego "github.com/beego/beego/v2/server/web"
|
||||
)
|
||||
|
||||
// RegisterDictRoutes 注册租户端数据字典路由(表结构见 docs/sql/create_dict.sql)。
|
||||
// 租户隔离由 JWT 里的租户ID 完成,前端不传 tenant_id。
|
||||
func RegisterDictRoutes() {
|
||||
// 字典列表(字典类型)
|
||||
beego.Router("/backend/dict/types", &controllers.BackendDictController{}, "get:ListTypes;post:CreateType")
|
||||
beego.Router("/backend/dict/types/:id", &controllers.BackendDictController{}, "put:UpdateType;delete:DeleteType")
|
||||
|
||||
// 字典项
|
||||
beego.Router("/backend/dict/items", &controllers.BackendDictController{}, "get:ListItems;post:CreateItem")
|
||||
beego.Router("/backend/dict/items/:id", &controllers.BackendDictController{}, "put:UpdateItem;delete:DeleteItem")
|
||||
beego.Router("/backend/dict/items/:id/status", &controllers.BackendDictController{}, "post:ToggleItemStatus")
|
||||
|
||||
// 业务读取:单个编码 / 批量(指定编码)/ 全量(前端预热)
|
||||
beego.Router("/backend/dict/options/:code", &controllers.BackendDictController{}, "get:Options")
|
||||
beego.Router("/backend/dict/options", &controllers.BackendDictController{}, "get:OptionsAll;post:OptionsBatch")
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package backend
|
||||
|
||||
import "testing"
|
||||
|
||||
// TestRegisterDictRoutes 确认字典路由能完成注册且不与既有路由冲突。
|
||||
// beego 在注册重复/歧义路由或非法方法名时会 panic,这里通过实际注册来兜住这类错误。
|
||||
func TestRegisterDictRoutes(t *testing.T) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
t.Fatalf("注册租户端字典路由失败: %v", r)
|
||||
}
|
||||
}()
|
||||
|
||||
RegisterDictRoutes()
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package platform
|
||||
|
||||
import (
|
||||
"server/controllers"
|
||||
|
||||
beego "github.com/beego/beego/v2/server/web"
|
||||
)
|
||||
|
||||
// RegisterDictRoutes 注册平台端数据字典路由(表结构见 docs/sql/create_dict.sql)。
|
||||
func RegisterDictRoutes() {
|
||||
// 字典列表(字典类型)
|
||||
beego.Router("/platform/dict/types", &controllers.PlatformDictController{}, "get:ListTypes;post:CreateType")
|
||||
beego.Router("/platform/dict/types/:id", &controllers.PlatformDictController{}, "put:UpdateType;delete:DeleteType")
|
||||
|
||||
// 字典项
|
||||
beego.Router("/platform/dict/items", &controllers.PlatformDictController{}, "get:ListItems;post:CreateItem")
|
||||
beego.Router("/platform/dict/items/:id", &controllers.PlatformDictController{}, "put:UpdateItem;delete:DeleteItem")
|
||||
beego.Router("/platform/dict/items/:id/status", &controllers.PlatformDictController{}, "post:ToggleItemStatus")
|
||||
|
||||
// 业务读取:单个编码 / 批量(指定编码)/ 全量(前端预热)
|
||||
beego.Router("/platform/dict/options/:code", &controllers.PlatformDictController{}, "get:Options")
|
||||
beego.Router("/platform/dict/options", &controllers.PlatformDictController{}, "get:OptionsAll;post:OptionsBatch")
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package platform
|
||||
|
||||
import "testing"
|
||||
|
||||
// TestRegisterDictRoutes 确认字典路由能完成注册且不与既有路由冲突。
|
||||
// beego 在注册重复/歧义路由或非法方法名时会 panic,这里通过实际注册来兜住这类错误。
|
||||
func TestRegisterDictRoutes(t *testing.T) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
t.Fatalf("注册平台端字典路由失败: %v", r)
|
||||
}
|
||||
}()
|
||||
|
||||
RegisterDictRoutes()
|
||||
}
|
||||
@@ -14,6 +14,9 @@ func Register() {
|
||||
// 微信公众号(服务号):配置 / 绑定 / 粉丝 / 推送 / 微信服务器回调
|
||||
RegisterWechatMpRoutes()
|
||||
|
||||
// 数据字典(字典列表 / 字典项)
|
||||
RegisterDictRoutes()
|
||||
|
||||
// 统一认证中心 - 租户登录策略配置
|
||||
beego.Router("/platform/authConfig/detail", &controllers.PlatformAuthConfigController{}, "get:Detail")
|
||||
beego.Router("/platform/authConfig/save", &controllers.PlatformAuthConfigController{}, "post:Save")
|
||||
|
||||
Reference in New Issue
Block a user