新增几大中心功能

This commit is contained in:
Administrator
2026-04-23 15:29:07 +08:00
parent 5c2a146a44
commit c6354ee065
123 changed files with 13074 additions and 229 deletions

View File

@@ -0,0 +1,223 @@
package system
import (
"context"
. "git.echol.cn/loser/Go-Web-Template/server/model/system"
"git.echol.cn/loser/Go-Web-Template/server/service/system"
"github.com/pkg/errors"
"gorm.io/gorm"
)
// 该 initializer 用于把「菜单 DB 数据」与「前端文件路由」对齐:
// - 按 Name 精准匹配,幂等修正 path/parent/component避免出现“前端显示与实际路由不一致”的别名情况。
// - 若缺少必要父级/子级菜单,则补齐到目标结构。
//
// 注意:它不会删除菜单,只做修正/补齐,避免误伤线上已有配置。
const initOrderMenuRepair = initOrderMenu + 1
type menuRepair struct{}
func init() {
system.RegisterInit(initOrderMenuRepair, &menuRepair{})
}
func (m *menuRepair) InitializerName() string {
return "sys_base_menus_repair"
}
func (m *menuRepair) MigrateTable(ctx context.Context) (context.Context, error) {
// 仅修复数据,不建表
return ctx, nil
}
func (m *menuRepair) TableCreated(ctx context.Context) bool {
// 仅修复数据,不参与建表逻辑
return true
}
func (m *menuRepair) DataInserted(ctx context.Context) bool {
// 每次都允许运行(幂等修复),因此返回 false 以触发 InitializeData
return false
}
type menuSeed struct {
level uint
hidden bool
parentName string // 空表示根节点
path string
name string
component string
sort int
title string
icon string
}
func ensureMenu(tx *gorm.DB, seed menuSeed, parentID uint) (*SysBaseMenu, error) {
var menu SysBaseMenu
err := tx.Where("name = ?", seed.name).First(&menu).Error
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
return nil, err
}
if errors.Is(err, gorm.ErrRecordNotFound) {
menu = SysBaseMenu{
MenuLevel: seed.level,
ParentId: parentID,
Path: seed.path,
Name: seed.name,
Hidden: seed.hidden,
Component: seed.component,
Sort: seed.sort,
Meta: Meta{
Title: seed.title,
Icon: seed.icon,
},
}
if err := tx.Create(&menu).Error; err != nil {
return nil, err
}
return &menu, nil
}
updates := map[string]any{
"menu_level": seed.level,
"parent_id": parentID,
"path": seed.path,
"component": seed.component,
}
if err := tx.Model(&menu).Updates(updates).Error; err != nil {
return nil, err
}
// 尽量不覆盖用户自定义标题/图标:仅在为空时补齐
metaUpdates := map[string]any{}
if menu.Meta.Title == "" && seed.title != "" {
metaUpdates["title"] = seed.title
}
if menu.Meta.Icon == "" && seed.icon != "" {
metaUpdates["icon"] = seed.icon
}
if len(metaUpdates) > 0 {
if err := tx.Model(&menu).Updates(metaUpdates).Error; err != nil {
return nil, err
}
}
return &menu, nil
}
func (m *menuRepair) InitializeData(ctx context.Context) (next context.Context, err error) {
db, ok := ctx.Value("db").(*gorm.DB)
if !ok {
return ctx, system.ErrMissingDBContext
}
seeds := []menuSeed{
// 父级(若不存在则补齐)
{
level: 0,
hidden: false,
path: "userCenter",
name: "userCenter",
component: "features/discovery/ModuleLandingPage:userCenter",
sort: 2,
title: "用户中心",
icon: "AppstoreOutlined",
},
{
level: 0,
hidden: false,
path: "opsConfig",
name: "opsConfig",
component: "features/discovery/ModuleLandingPage:opsConfig",
sort: 6,
title: "运营配置",
icon: "SettingOutlined",
},
{
level: 0,
hidden: false,
path: "common",
name: "common",
component: "features/discovery/ModuleLandingPage:common",
sort: 6,
title: "公共能力",
icon: "AppstoreOutlined",
},
// 子级(目标规范路径)
{
level: 1,
hidden: false,
parentName: "userCenter",
path: "appLoginLog",
name: "appLoginLog",
component: "features/appLoginLogs/AppLoginLogsPage",
sort: 99,
title: "登录日志",
icon: "FileTextOutlined",
},
{
level: 1,
hidden: false,
parentName: "opsConfig",
path: "sysParamChangeLog",
name: "sysParamChangeLog",
component: "features/params/SysParamChangeLogPage",
sort: 99,
title: "参数变更日志",
icon: "SettingOutlined",
},
{
level: 1,
hidden: false,
parentName: "common",
path: "upload",
name: "upload",
component: "features/media/MediaLibraryPage",
sort: 1,
title: "媒体库(上传下载)",
icon: "UploadOutlined",
},
}
err = db.Transaction(func(tx *gorm.DB) error {
byName := map[string]*SysBaseMenu{}
// 先确保父级存在(包含 common 也一起修正 component/path
for _, seed := range seeds {
if seed.level != 0 {
continue
}
menu, err := ensureMenu(tx, seed, 0)
if err != nil {
return errors.Wrap(err, "ensure parent menu failed")
}
byName[seed.name] = menu
}
// 再确保子级存在并挂载到父级
for _, seed := range seeds {
if seed.level == 0 {
continue
}
parent := byName[seed.parentName]
if parent == nil {
return errors.Errorf("missing parent menu %s for %s", seed.parentName, seed.name)
}
if _, err := ensureMenu(tx, seed, parent.ID); err != nil {
return errors.Wrap(err, "ensure child menu failed")
}
}
return nil
})
if err != nil {
return ctx, err
}
return ctx, nil
}