feat: 添加独立其他设置菜单及有效端参数保存
This commit is contained in:
@@ -1,14 +1,59 @@
|
||||
package business
|
||||
|
||||
import (
|
||||
"gorm.io/gorm"
|
||||
databusiness "kra/internal/data/business"
|
||||
datasystem "kra/internal/data/system"
|
||||
"kra/internal/modules/surface"
|
||||
"kra/pkg/database/migration"
|
||||
"kra/pkg/module"
|
||||
)
|
||||
|
||||
func Definition() module.Definition {
|
||||
return module.Definition{Name: "business", Migrations: databusiness.Migrations(), Surface: module.Surface{
|
||||
settingsMenu := module.Menu{Name: "sw_OtherSettings", Path: "OtherSettings", Component: "view/sw/OtherSettings.vue", Title: "其他设置", Icon: databusiness.MenuIcon("sw_OtherSettings"), Sort: 5}
|
||||
migrations := append(databusiness.Migrations(), migration.Step{ID: "202611040016_business_other_settings_surface", Migrate: func(db *gorm.DB) error {
|
||||
// First-install menus are created by the normal seed flow.
|
||||
if !db.Migrator().HasTable("sys_authorities") {
|
||||
return nil
|
||||
}
|
||||
var admins int64
|
||||
if err := db.Table("sys_authorities").Where("authority_id=888 AND deleted_at IS NULL").Count(&admins).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if admins == 0 {
|
||||
return nil
|
||||
}
|
||||
return db.Transaction(func(tx *gorm.DB) error {
|
||||
menu := settingsMenu
|
||||
var alert struct{ Sort int }
|
||||
result := tx.Table("sys_base_menus").Select("sort").Where("name=? AND parent_id=0 AND deleted_at IS NULL", "sw_AlertCenter").Limit(1).Find(&alert)
|
||||
if result.Error != nil {
|
||||
return result.Error
|
||||
}
|
||||
if result.RowsAffected > 0 {
|
||||
menu.Sort = alert.Sort + 1
|
||||
}
|
||||
var collisions int64
|
||||
if err := tx.Table("sys_base_menus").Where("parent_id=0 AND deleted_at IS NULL AND name<>? AND sort=?", menu.Name, menu.Sort).Count(&collisions).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if collisions > 0 {
|
||||
if err := tx.Table("sys_base_menus").Where("parent_id=0 AND deleted_at IS NULL AND name<>? AND sort>=?", menu.Name, menu.Sort).Update("sort", gorm.Expr("sort + 1")).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return datasystem.EnsureAdminSurface(tx, module.Surface{
|
||||
Menus: []module.Menu{menu},
|
||||
APIs: []module.API{
|
||||
{Path: "/sw/settings/effectiveness", Method: "GET", Group: "其他设置", Description: "获取有效端判定参数"},
|
||||
{Path: "/sw/settings/effectiveness", Method: "PUT", Group: "其他设置", Description: "保存有效端判定参数"},
|
||||
},
|
||||
}, 888)
|
||||
})
|
||||
}})
|
||||
return module.Definition{Name: "business", Migrations: migrations, Surface: module.Surface{
|
||||
Menus: []module.Menu{
|
||||
settingsMenu,
|
||||
{Name: "sw_RankingAnalysis", Path: "RankingAnalysis", ParentName: "sw_DataAnalysis", Component: "view/sw/RankingAnalysis.vue", Title: "排行榜", Icon: databusiness.MenuIcon("sw_RankingAnalysis"), Sort: 6},
|
||||
{Name: "sw_ServerAnalysis", Path: "ServerAnalysis", ParentName: "sw_DataAnalysis", Component: "view/sw/ServerAnalysis.vue", Title: "区服分析", Icon: databusiness.MenuIcon("sw_ServerAnalysis"), Sort: 5},
|
||||
{Name: "sw_ChannelDataStatistics", Path: "ChannelDataStatistics", ParentName: "sw_DataAnalysis", Component: "view/sw/ChannelDataStatistics.vue", Title: "渠道数据统计", Icon: databusiness.MenuIcon("sw_ChannelDataStatistics"), Sort: 1},
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
package business
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/glebarez/sqlite"
|
||||
"gorm.io/gorm"
|
||||
datasystem "kra/internal/data/system"
|
||||
)
|
||||
|
||||
func TestOtherSettingsUpgradeAddsStandaloneMenuForSuperAdmin(t *testing.T) {
|
||||
db, err := gorm.Open(sqlite.Open(filepath.Join(t.TempDir(), "settings.db")), &gorm.Config{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
pool, _ := db.DB()
|
||||
t.Cleanup(func() { _ = pool.Close() })
|
||||
for _, step := range datasystem.Migrations() {
|
||||
if err := step.Migrate(db); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
if err := db.Exec("INSERT INTO sys_authorities(authority_id,authority_name,parent_id) VALUES(888,'admin',0),(901,'business',888)").Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := db.Exec("INSERT INTO sys_base_menus(name,title,parent_id,sort) VALUES('sw_AlertCenter','预警中心',0,4),('permission','权限管理',0,5)").Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for attempt := 0; attempt < 2; attempt++ {
|
||||
for _, step := range Definition().Migrations {
|
||||
if err := step.Migrate(db); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
var menu struct {
|
||||
ID, ParentID uint
|
||||
Sort int
|
||||
Title, Component string
|
||||
}
|
||||
if err := db.Table("sys_base_menus").Where("name=?", "sw_OtherSettings").Take(&menu).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if menu.ParentID != 0 || menu.Sort != 5 || menu.Title != "其他设置" || menu.Component != "view/sw/OtherSettings.vue" {
|
||||
t.Fatalf("必须是独立菜单: %+v", menu)
|
||||
}
|
||||
var permissionSort int
|
||||
if err := db.Table("sys_base_menus").Select("sort").Where("name='permission'").Scan(&permissionSort).Error; err != nil || permissionSort != 6 {
|
||||
t.Fatal("其他设置必须紧接预警中心,后续菜单只应顺延一次")
|
||||
}
|
||||
var roles []uint
|
||||
if err := db.Table("sys_authority_menus").Where("sys_base_menu_id=?", menu.ID).Pluck("sys_authority_authority_id", &roles).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(roles) != 1 || roles[0] != 888 {
|
||||
t.Fatalf("只有超管应收到菜单,重复升级不能重复授权: %v", roles)
|
||||
}
|
||||
var count int64
|
||||
if err := db.Table("casbin_rule").Where("ptype='p' AND v1=? AND v0='888'", "/sw/settings/effectiveness").Count(&count).Error; err != nil || count != 2 {
|
||||
t.Fatal("超管读写 API 授权缺失或重复")
|
||||
}
|
||||
if err := db.Table("casbin_rule").Where("ptype='p' AND v1=? AND v0<>'888'", "/sw/settings/effectiveness").Count(&count).Error; err != nil || count != 0 {
|
||||
t.Fatal("不应向商务账号开放设置 API")
|
||||
}
|
||||
}
|
||||
@@ -25,16 +25,16 @@ func TestCatalogContainsBuiltInModulesInDependencyOrder(t *testing.T) {
|
||||
t.Fatalf("definition[%d] = %q, want %q", index, got, name)
|
||||
}
|
||||
}
|
||||
if got := catalog.MigrationSteps(); len(got) != 28 {
|
||||
t.Fatalf("module migrations = %d, want 28", len(got))
|
||||
if got := catalog.MigrationSteps(); len(got) != 30 {
|
||||
t.Fatalf("module migrations = %d, want 30", len(got))
|
||||
}
|
||||
var menus, apis int
|
||||
for _, definition := range catalog.Definitions {
|
||||
menus += len(definition.Surface.Menus)
|
||||
apis += len(definition.Surface.APIs)
|
||||
}
|
||||
if menus != 18 || apis != 69 {
|
||||
t.Fatalf("admin surface = %d menus/%d APIs, want 18/69", menus, apis)
|
||||
if menus != 19 || apis != 71 {
|
||||
t.Fatalf("admin surface = %d menus/%d APIs, want 19/71", menus, apis)
|
||||
}
|
||||
if got := catalog.DefaultTimedTasks(); len(got) != 2 {
|
||||
t.Fatalf("default timed tasks = %d, want 2", len(got))
|
||||
|
||||
Reference in New Issue
Block a user