Files
EasyGoAdmin_GoFrame_EleVue/internal/logic/config.go
T
2026-10-20 11:37:25 +08:00

296 lines
8.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package logic
import (
"context"
"fmt"
"strings"
"easygoadmin/api/v1"
"easygoadmin/internal/dao"
"easygoadmin/internal/service"
"easygoadmin/utility/upload"
)
// ============================== 配置业务实现 ==============================
// sConfig 配置业务实现
// 实现 service.IConfig 接口,承载配置模块的业务逻辑
type sConfig struct{}
// configSpec 配置模块声明
//
// List 含嵌套配置项,采用手写实现
var configSpec = ModuleSpec[v1.ConfigItem, v1.ConfigItem, v1.ConfigDetailRes]{
Model: dao.Config.Ctx,
LikeFields: []string{"name", "code"},
OrderBy: "sort, id",
}
func init() {
service.RegisterConfig(&sConfig{})
}
// Page 配置分页
// 按查询条件分页返回配置列表
func (s *sConfig) Page(ctx context.Context, req *v1.ConfigPageReq) (res *v1.ConfigPageRes, err error) {
list, total, err := configSpec.Page(ctx, req, req.GetPageNo(), req.GetPageSize())
if err != nil {
return nil, err
}
return v1.NewPageData(req.GetPageNo(), req.GetPageSize(), total, derefSlice(list)), nil
}
// List 配置列表(含配置项)
// 返回配置列表,每项携带其下的配置项集合
func (s *sConfig) List(ctx context.Context, req *v1.ConfigListReq) (res v1.ConfigListRes, err error) {
m := dao.Config.Ctx(ctx)
if req.Keyword != "" {
kw := "%" + req.Keyword + "%"
m = m.WhereLike("name", kw).WhereOrLike("code", kw)
}
rows, err := m.Order("sort, id").All()
if err != nil {
return nil, err
}
itemsByConfig, err := s.itemsGrouped(ctx)
if err != nil {
return nil, err
}
list := make([]v1.ConfigWithItems, 0, len(rows))
for _, r := range rows {
cid := r["id"].Int64()
list = append(list, v1.ConfigWithItems{
ConfigItem: v1.ConfigItem{
Id: cid,
Name: r["name"].String(),
Code: r["code"].String(),
Sort: r["sort"].Int(),
Note: r["note"].String(),
CreateUser: r["create_user"].String(),
},
Items: itemsByConfig[cid],
})
}
return list, nil
}
// Detail 配置详情
// 按配置ID查询详情及其下的配置项集合
func (s *sConfig) Detail(ctx context.Context, req *v1.ConfigDetailReq) (res *v1.ConfigDetailRes, err error) {
return configSpec.Detail(ctx, req.Id, req)
}
// Add 新增配置
// 校验配置编码唯一后新增,返回新记录ID
func (s *sConfig) Add(ctx context.Context, req *v1.ConfigAddReq) (res *v1.IdRes, err error) {
if err = CheckUnique(ctx, dao.Config.Ctx(ctx), "code", req.Code, 0, "配置编码"); err != nil {
return nil, err
}
result, err := dao.Config.Ctx(ctx).Data(map[string]any{
"name": req.Name,
"code": req.Code,
"sort": req.Sort,
"note": req.Note,
}).Insert()
if err != nil {
return nil, err
}
idv, _ := result.LastInsertId()
return &v1.IdRes{Id: idv}, nil
}
// Update 修改配置
// 按配置ID更新记录
func (s *sConfig) Update(ctx context.Context, req *v1.ConfigUpdateReq) (res *v1.ConfigUpdateRes, err error) {
if _, err = dao.Config.Ctx(ctx).Where("id", req.Id).Data(map[string]any{
"name": req.Name,
"code": req.Code,
"sort": req.Sort,
"note": req.Note,
}).Update(); err != nil {
return nil, err
}
return &v1.ConfigUpdateRes{}, nil
}
// Delete 删除配置
// 按配置ID删除记录,并连带删除其下配置项
func (s *sConfig) Delete(ctx context.Context, req *v1.ConfigDeleteReq) (res *v1.ConfigDeleteRes, err error) {
if err = configSpec.Delete(ctx, req.Id); err != nil {
return nil, err
}
if _, err = dao.ConfigItem.Ctx(ctx).Where("config_id", req.Id).Delete(); err != nil {
return nil, err
}
return &v1.ConfigDeleteRes{}, nil
}
// BatchDelete 批量删除配置
// 按配置ID列表批量删除记录,并连带删除其下配置项
func (s *sConfig) BatchDelete(ctx context.Context, req *v1.ConfigBatchDeleteReq) (res *v1.ConfigBatchDeleteRes, err error) {
if err = configSpec.BatchDelete(ctx, req.Ids); err != nil {
return nil, err
}
if _, err = dao.ConfigItem.Ctx(ctx).WhereIn("config_id", req.Ids).Delete(); err != nil {
return nil, err
}
return &v1.ConfigBatchDeleteRes{}, nil
}
// WebIndex 网站配置聚合
//
// 按配置分组返回,供网站配置页渲染;
// 文件类字段拼接访问URL,options 解析为 param 映射
func (s *sConfig) WebIndex(ctx context.Context, req *v1.ConfigWebIndexReq) (res *v1.ConfigWebIndexRes, err error) {
configs, err := dao.Config.Ctx(ctx).Order("sort, id").All()
if err != nil {
return nil, err
}
items, err := dao.ConfigItem.Ctx(ctx).Order("sort, id").All()
if err != nil {
return nil, err
}
byConfig := make(map[int64][]v1.ConfigWebItem, len(configs))
for _, r := range items {
value := r["value"].String()
typ := r["type"].String()
options := r["options"].String()
item := v1.ConfigWebItem{
Id: r["id"].Int64(),
Name: r["name"].String(),
Code: r["code"].String(),
Value: value,
Type: typ,
Options: options,
Param: parseConfigOptions(options),
}
switch typ {
case "image":
item.Value = upload.GetFileUrl(ctx, value)
case "file":
item.Value = configItemFileURL(ctx, value)
case "images":
item.ValueList = configItemListURLs(ctx, value, false)
case "files":
item.ValueList = configItemListURLs(ctx, value, true)
case "ueditor":
item.Value = ExpandContentFields(ctx, value)
}
cid := r["config_id"].Int64()
byConfig[cid] = append(byConfig[cid], item)
}
groups := make([]v1.ConfigWebGroup, 0, len(configs))
for _, c := range configs {
cid := c["id"].Int64()
groups = append(groups, v1.ConfigWebGroup{
ConfigName: c["name"].String(),
DataList: byConfig[cid],
})
}
return &groups, nil
}
// WebSave 批量保存网站配置
//
// 接收配置项编码到值的映射;
// 文件类字段执行转正与剥离域名,富文本执行本地化
func (s *sConfig) WebSave(ctx context.Context, req *v1.ConfigWebSaveReq) (res *v1.ConfigWebSaveRes, err error) {
for code, raw := range req.Data {
one, e := dao.ConfigItem.Ctx(ctx).Where("code", code).One()
if e != nil {
return nil, e
}
if len(one) == 0 {
continue // 未知编码跳过(前端可能携带非配置项字段)
}
value := configItemSaveValue(ctx, one["type"].String(), configValueToString(raw))
if _, e = dao.ConfigItem.Ctx(ctx).Where("id", one["id"].Int64()).Data("value", value).Update(); e != nil {
return nil, e
}
}
return &v1.ConfigWebSaveRes{}, nil
}
// parseConfigOptions 解析选项串
// 将 "value=name,value=name" 格式解析为值与显示名的映射
func parseConfigOptions(options string) map[string]string {
param := make(map[string]string)
if options == "" {
return param
}
for _, pair := range strings.Split(options, ",") {
pair = strings.TrimSpace(pair)
if pair == "" {
continue
}
value, name, found := strings.Cut(pair, "=")
if !found {
continue
}
param[strings.TrimSpace(value)] = strings.TrimSpace(name)
}
return param
}
// configValueToString 前端表单值归一化为字符串
// 多选或多图为数组时按逗号拼接
func configValueToString(v any) string {
switch t := v.(type) {
case nil:
return ""
case string:
return t
case []any:
parts := make([]string, 0, len(t))
for _, e := range t {
parts = append(parts, fmt.Sprintf("%v", e))
}
return strings.Join(parts, ",")
default:
return fmt.Sprintf("%v", t)
}
}
// itemsByConfigId 查询单个配置的配置项
func (s *sConfig) itemsByConfigId(ctx context.Context, configId int64) ([]v1.ConfigItemRow, error) {
rows, err := dao.ConfigItem.Ctx(ctx).Where("config_id", configId).Order("sort, id").All()
if err != nil {
return nil, err
}
items := make([]v1.ConfigItemRow, 0, len(rows))
for _, r := range rows {
items = append(items, v1.ConfigItemRow{
Id: r["id"].Int64(),
Name: r["name"].String(),
Code: r["code"].String(),
Value: r["value"].String(),
Type: r["type"].String(),
Status: r["status"].Int(),
Sort: r["sort"].Int(),
})
}
return items, nil
}
// itemsGrouped 全量配置项按 config_id 分组
func (s *sConfig) itemsGrouped(ctx context.Context) (map[int64][]v1.ConfigItemRow, error) {
result := make(map[int64][]v1.ConfigItemRow)
rows, err := dao.ConfigItem.Ctx(ctx).Order("sort, id").All()
if err != nil {
return nil, err
}
for _, r := range rows {
cid := r["config_id"].Int64()
result[cid] = append(result[cid], v1.ConfigItemRow{
Id: r["id"].Int64(),
Name: r["name"].String(),
Code: r["code"].String(),
Value: r["value"].String(),
Type: r["type"].String(),
Status: r["status"].Int(),
Sort: r["sort"].Int(),
})
}
return result, nil
}