fix(menu): show dashboard overview as root item
This commit is contained in:
@@ -14,9 +14,7 @@ type Menu struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var adminMenus = []Menu{
|
var adminMenus = []Menu{
|
||||||
{Identity: "dashboard", GroupCode: "dashboard", Name: "数据概述", Icon: "icon-dashboard", Path: "/dashboard", SortNo: 10, Status: common.StatusEnable},
|
{Identity: "dashboard_overview", GroupCode: "dashboard", Name: "数据概览", Icon: "icon-dashboard", Path: "/dashboard/overview", SortNo: 10, Status: common.StatusEnable},
|
||||||
{Identity: "dashboard_overview", ParentIdentity: "dashboard", GroupCode: "dashboard", Name: "运营概览", Path: "/dashboard/overview", SortNo: 1, Status: common.StatusEnable},
|
|
||||||
{Identity: "dashboard_reports", ParentIdentity: "dashboard", GroupCode: "dashboard", Name: "订单报表", Path: "/dashboard/reports", SortNo: 2, Status: common.StatusEnable},
|
|
||||||
{Identity: "profile", GroupCode: "profile", Name: "配送点资料", Icon: "icon-storage", Path: "/profile", SortNo: 20, Status: common.StatusEnable},
|
{Identity: "profile", GroupCode: "profile", Name: "配送点资料", Icon: "icon-storage", Path: "/profile", SortNo: 20, Status: common.StatusEnable},
|
||||||
{Identity: "delivery_profile", ParentIdentity: "profile", GroupCode: "profile", Name: "本点资料", Path: "/profile/basic", SortNo: 1, Status: common.StatusEnable},
|
{Identity: "delivery_profile", ParentIdentity: "profile", GroupCode: "profile", Name: "本点资料", Path: "/profile/basic", SortNo: 1, Status: common.StatusEnable},
|
||||||
{Identity: "staff", GroupCode: "staff", Name: "配送人员管理", Icon: "icon-user-group", Path: "/staff", SortNo: 30, Status: common.StatusEnable},
|
{Identity: "staff", GroupCode: "staff", Name: "配送人员管理", Icon: "icon-user-group", Path: "/staff", SortNo: 30, Status: common.StatusEnable},
|
||||||
|
|||||||
@@ -21,3 +21,28 @@ func TestMenusExcludeInventoryAndEcommerce(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMenuContainsDashboardRoutes(t *testing.T) {
|
||||||
|
want := map[string]string{
|
||||||
|
"dashboard_overview": "/dashboard/overview",
|
||||||
|
}
|
||||||
|
for _, menu := range MenusForRole("admin") {
|
||||||
|
if path, ok := want[menu.Identity]; ok {
|
||||||
|
if menu.Path != path {
|
||||||
|
t.Fatalf("menu %q path = %q, want %q", menu.Identity, menu.Path, path)
|
||||||
|
}
|
||||||
|
delete(want, menu.Identity)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(want) != 0 {
|
||||||
|
t.Fatalf("missing dashboard menus: %#v", want)
|
||||||
|
}
|
||||||
|
for _, menu := range MenusForRole("admin") {
|
||||||
|
if menu.Identity == "dashboard_overview" && (menu.ParentIdentity != "" || menu.Icon != "icon-dashboard") {
|
||||||
|
t.Fatalf("dashboard overview must be a first-level icon menu: %#v", menu)
|
||||||
|
}
|
||||||
|
if menu.Identity == "dashboard" || menu.Identity == "dashboard_reports" {
|
||||||
|
t.Fatalf("legacy dashboard menu must not be returned: %#v", menu)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package gas
|
package gas
|
||||||
|
|
||||||
import "git.apinb.com/heqiapp/platforms/backend/api/internal/logic/common"
|
import "git.apinb.com/heqiapp/platforms/backend/api/internal/logic/common"
|
||||||
|
|
||||||
@@ -15,9 +15,7 @@ type Menu struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var adminMenus = []Menu{
|
var adminMenus = []Menu{
|
||||||
{Identity: "dashboard", GroupCode: "dashboard", Name: "数据概述", Icon: "icon-dashboard", Path: "/dashboard", SortNo: 10, Status: common.StatusEnable},
|
{Identity: "dashboard_overview", GroupCode: "dashboard", Name: "数据概览", Icon: "icon-dashboard", Path: "/dashboard/overview", SortNo: 10, Status: common.StatusEnable},
|
||||||
{Identity: "dashboard_overview", ParentIdentity: "dashboard", GroupCode: "dashboard", Name: "运营概览", Path: "/dashboard/overview", SortNo: 1, Status: common.StatusEnable},
|
|
||||||
{Identity: "dashboard_reports", ParentIdentity: "dashboard", GroupCode: "dashboard", Name: "统计报表", Path: "/dashboard/reports", SortNo: 2, Status: common.StatusEnable},
|
|
||||||
{Identity: "delivery", GroupCode: "delivery", Name: "配送点管理", Icon: "icon-storage", Path: "/delivery", SortNo: 20, Status: common.StatusEnable},
|
{Identity: "delivery", GroupCode: "delivery", Name: "配送点管理", Icon: "icon-storage", Path: "/delivery", SortNo: 20, Status: common.StatusEnable},
|
||||||
{Identity: "delivery_basic", ParentIdentity: "delivery", GroupCode: "delivery", Name: "配送点列表", Path: "/delivery/points", SortNo: 1, Status: common.StatusEnable},
|
{Identity: "delivery_basic", ParentIdentity: "delivery", GroupCode: "delivery", Name: "配送点列表", Path: "/delivery/points", SortNo: 1, Status: common.StatusEnable},
|
||||||
{Identity: "staff", GroupCode: "staff", Name: "工作人员管理", Icon: "icon-user-group", Path: "/staff", SortNo: 30, Status: common.StatusEnable},
|
{Identity: "staff", GroupCode: "staff", Name: "工作人员管理", Icon: "icon-user-group", Path: "/staff", SortNo: 30, Status: common.StatusEnable},
|
||||||
|
|||||||
@@ -24,3 +24,28 @@ func TestMenuContainsContractAndDeliveryManagement(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMenuContainsDashboardRoutes(t *testing.T) {
|
||||||
|
want := map[string]string{
|
||||||
|
"dashboard_overview": "/dashboard/overview",
|
||||||
|
}
|
||||||
|
for _, menu := range MenusForRole("admin") {
|
||||||
|
if path, ok := want[menu.Identity]; ok {
|
||||||
|
if menu.Path != path {
|
||||||
|
t.Fatalf("menu %q path = %q, want %q", menu.Identity, menu.Path, path)
|
||||||
|
}
|
||||||
|
delete(want, menu.Identity)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(want) != 0 {
|
||||||
|
t.Fatalf("missing dashboard menus: %#v", want)
|
||||||
|
}
|
||||||
|
for _, menu := range MenusForRole("admin") {
|
||||||
|
if menu.Identity == "dashboard_overview" && (menu.ParentIdentity != "" || menu.Icon != "icon-dashboard") {
|
||||||
|
t.Fatalf("dashboard overview must be a first-level icon menu: %#v", menu)
|
||||||
|
}
|
||||||
|
if menu.Identity == "dashboard" || menu.Identity == "dashboard_reports" {
|
||||||
|
t.Fatalf("legacy dashboard menu must not be returned: %#v", menu)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -21,9 +21,7 @@ type Menu struct {
|
|||||||
// PlatformMenus 使用二维数据组织菜单;每一行表示一个菜单分组。
|
// PlatformMenus 使用二维数据组织菜单;每一行表示一个菜单分组。
|
||||||
var PlatformMenus = [][]Menu{
|
var PlatformMenus = [][]Menu{
|
||||||
{
|
{
|
||||||
{Identity: "dashboard", GroupCode: "dashboard", Name: "工作台", Icon: "icon-dashboard", Path: "/dashboard", SortNo: 10, Status: common.StatusEnable},
|
{Identity: "dashboard_overview", GroupCode: "dashboard", Name: "数据概览", Icon: "icon-dashboard", Path: "/dashboard/overview", SortNo: 10, Status: common.StatusEnable},
|
||||||
{Identity: "dashboard_overview", ParentIdentity: "dashboard", GroupCode: "dashboard", Name: "数据概览", Path: "/dashboard/overview", SortNo: 1, Status: common.StatusEnable},
|
|
||||||
{Identity: "dashboard_reports", ParentIdentity: "dashboard", GroupCode: "dashboard", Name: "统计报表", Path: "/dashboard/reports", SortNo: 2, Status: common.StatusEnable},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
{Identity: "organization", GroupCode: "organization", Name: "机构管理", Icon: "icon-storage", Path: "/organization", SortNo: 20, Status: common.StatusEnable},
|
{Identity: "organization", GroupCode: "organization", Name: "机构管理", Icon: "icon-storage", Path: "/organization", SortNo: 20, Status: common.StatusEnable},
|
||||||
@@ -128,6 +126,10 @@ func LoadPlatformMenus(roleCode string) ([]Menu, error) {
|
|||||||
allowed := make(map[string]struct{}, len(identities))
|
allowed := make(map[string]struct{}, len(identities))
|
||||||
for _, identity := range identities {
|
for _, identity := range identities {
|
||||||
allowed[identity] = struct{}{}
|
allowed[identity] = struct{}{}
|
||||||
|
// 兼容历史角色保存的 dashboard 父菜单或报表菜单授权。
|
||||||
|
if identity == "dashboard" || identity == "dashboard_reports" {
|
||||||
|
allowed["dashboard_overview"] = struct{}{}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for _, menu := range menus {
|
for _, menu := range menus {
|
||||||
if _, ok := allowed[menu.Identity]; ok && menu.ParentIdentity != "" {
|
if _, ok := allowed[menu.Identity]; ok && menu.ParentIdentity != "" {
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ func TestPlatformMenusAreStaticTwoDimensionalData(t *testing.T) {
|
|||||||
}
|
}
|
||||||
seen := make(map[string]bool)
|
seen := make(map[string]bool)
|
||||||
for _, group := range PlatformMenus {
|
for _, group := range PlatformMenus {
|
||||||
if len(group) < 2 {
|
if len(group) == 0 {
|
||||||
t.Fatal("each platform menu group must include a first-level menu and at least one second-level menu")
|
t.Fatal("platform menu groups must not be empty")
|
||||||
}
|
}
|
||||||
parent := group[0]
|
parent := group[0]
|
||||||
if parent.ParentIdentity != "" {
|
if parent.ParentIdentity != "" {
|
||||||
@@ -39,3 +39,24 @@ func TestRootLoadsAllStaticPlatformMenus(t *testing.T) {
|
|||||||
t.Fatalf("root menu count = %d, want %d", len(menus), len(AllPlatformMenus()))
|
t.Fatalf("root menu count = %d, want %d", len(menus), len(AllPlatformMenus()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPlatformMenuContainsDashboardRoutes(t *testing.T) {
|
||||||
|
want := map[string]string{
|
||||||
|
"dashboard_overview": "/dashboard/overview",
|
||||||
|
}
|
||||||
|
for _, menu := range AllPlatformMenus() {
|
||||||
|
if path, ok := want[menu.Identity]; ok {
|
||||||
|
if menu.Path != path {
|
||||||
|
t.Fatalf("menu %q path = %q, want %q", menu.Identity, menu.Path, path)
|
||||||
|
}
|
||||||
|
delete(want, menu.Identity)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(want) != 0 {
|
||||||
|
t.Fatalf("missing dashboard menus: %#v", want)
|
||||||
|
}
|
||||||
|
menu, ok := FindPlatformMenu("dashboard_overview")
|
||||||
|
if !ok || menu.ParentIdentity != "" || menu.Icon != "icon-dashboard" {
|
||||||
|
t.Fatalf("dashboard overview must be a first-level icon menu: %#v", menu)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export default function useMenuTree() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// leaf node
|
// leaf node
|
||||||
if (element.meta?.hideChildrenInMenu || !element.children) {
|
if (element.meta?.hideChildrenInMenu || !element.children?.length) {
|
||||||
element.children = [];
|
element.children = [];
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,9 +12,9 @@ const group = (path: string, name: string, title: string, icon: string, order: n
|
|||||||
});
|
});
|
||||||
|
|
||||||
const routes: AppRouteRecordRaw[] = [
|
const routes: AppRouteRecordRaw[] = [
|
||||||
{ path: '/dashboard', name: 'dashboard', component: DEFAULT_LAYOUT, redirect: '/dashboard/overview', meta: { title: '数据概述', requiresAuth: true, icon: 'icon-dashboard', order: 10, menuCode: 'dashboard' }, children: [
|
{ path: '/dashboard', name: 'dashboard', component: DEFAULT_LAYOUT, redirect: '/dashboard/overview', meta: { title: '数据概览', requiresAuth: true, icon: 'icon-dashboard', order: 10, menuCode: 'dashboard', hideInMenu: true }, children: [
|
||||||
{ path: 'overview', name: 'dashboard-overview', component: () => import('@/views/dashboard/DashboardPage.vue'), meta: { title: '运营概览', requiresAuth: true, menuCode: 'dashboard_overview' } },
|
{ path: 'overview', name: 'dashboard-overview', component: () => import('@/views/dashboard/DashboardPage.vue'), meta: { title: '运营概览', requiresAuth: true, menuCode: 'dashboard_overview' } },
|
||||||
{ path: 'reports', name: 'dashboard-reports', component: () => import('@/views/dashboard/ReportPage.vue'), meta: { title: '订单报表', requiresAuth: true, menuCode: 'dashboard_reports' } },
|
{ path: 'reports', name: 'dashboard-reports', component: () => import('@/views/dashboard/ReportPage.vue'), meta: { title: '订单报表', requiresAuth: true, menuCode: 'dashboard_overview', hideInMenu: true, activeMenu: 'dashboard-overview' } },
|
||||||
] },
|
] },
|
||||||
group('profile', 'profile', '配送点资料', 'icon-storage', 20, [
|
group('profile', 'profile', '配送点资料', 'icon-storage', 20, [
|
||||||
child('profile', 'basic', '本点资料', '/delivery_profile', 'delivery_profile'),
|
child('profile', 'basic', '本点资料', '/delivery_profile', 'delivery_profile'),
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export default function useMenuTree() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// leaf node
|
// leaf node
|
||||||
if (element.meta?.hideChildrenInMenu || !element.children) {
|
if (element.meta?.hideChildrenInMenu || !element.children?.length) {
|
||||||
element.children = [];
|
element.children = [];
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,10 +43,10 @@ const routes: AppRouteRecordRaw[] = [
|
|||||||
name: 'dashboard',
|
name: 'dashboard',
|
||||||
component: DEFAULT_LAYOUT,
|
component: DEFAULT_LAYOUT,
|
||||||
redirect: '/dashboard/overview',
|
redirect: '/dashboard/overview',
|
||||||
meta: { title: '数据概述', requiresAuth: true, icon: 'icon-dashboard', order: 10, menuCode: 'dashboard' },
|
meta: { title: '数据概览', requiresAuth: true, icon: 'icon-dashboard', order: 10, menuCode: 'dashboard', hideInMenu: true },
|
||||||
children: [
|
children: [
|
||||||
{ path: 'overview', name: 'dashboard-overview', component: () => import('@/views/dashboard/DashboardPage.vue'), meta: { title: '运营概览', requiresAuth: true, menuCode: 'dashboard_overview' } },
|
{ path: 'overview', name: 'dashboard-overview', component: () => import('@/views/dashboard/DashboardPage.vue'), meta: { title: '运营概览', requiresAuth: true, menuCode: 'dashboard_overview' } },
|
||||||
{ path: 'reports', name: 'dashboard-reports', component: () => import('@/views/dashboard/ReportPage.vue'), meta: { title: '统计报表', requiresAuth: true, menuCode: 'dashboard_reports' } },
|
{ path: 'reports', name: 'dashboard-reports', component: () => import('@/views/dashboard/ReportPage.vue'), meta: { title: '统计报表', requiresAuth: true, menuCode: 'dashboard_overview', hideInMenu: true, activeMenu: 'dashboard-overview' } },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
group('delivery', 'delivery', '配送点管理', 'icon-storage', 20, [
|
group('delivery', 'delivery', '配送点管理', 'icon-storage', 20, [
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export default function useMenuTree() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// leaf node
|
// leaf node
|
||||||
if (element.meta?.hideChildrenInMenu || !element.children) {
|
if (element.meta?.hideChildrenInMenu || !element.children?.length) {
|
||||||
element.children = [];
|
element.children = [];
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,10 +53,10 @@ const routes: AppRouteRecordRaw[] = [
|
|||||||
name: 'dashboard',
|
name: 'dashboard',
|
||||||
component: DEFAULT_LAYOUT,
|
component: DEFAULT_LAYOUT,
|
||||||
redirect: '/dashboard/overview',
|
redirect: '/dashboard/overview',
|
||||||
meta: { title: '首页', requiresAuth: true, icon: 'icon-dashboard', order: 0, menuCode: 'dashboard' },
|
meta: { title: '数据概览', requiresAuth: true, icon: 'icon-dashboard', order: 0, menuCode: 'dashboard', hideInMenu: true },
|
||||||
children: [
|
children: [
|
||||||
{ path: 'overview', name: 'dashboard-overview', component: () => import('@/views/dashboard/DashboardPage.vue'), meta: { title: '数据概览', requiresAuth: true, menuCode: 'dashboard_overview' } },
|
{ path: 'overview', name: 'dashboard-overview', component: () => import('@/views/dashboard/DashboardPage.vue'), meta: { title: '数据概览', requiresAuth: true, menuCode: 'dashboard_overview' } },
|
||||||
{ path: 'reports', name: 'dashboard-reports', component: () => import('@/views/dashboard/ReportPage.vue'), meta: { title: '统计报表', requiresAuth: true, menuCode: 'dashboard_reports' } },
|
{ path: 'reports', name: 'dashboard-reports', component: () => import('@/views/dashboard/ReportPage.vue'), meta: { title: '统计报表', requiresAuth: true, menuCode: 'dashboard_overview', hideInMenu: true, activeMenu: 'dashboard-overview' } },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
group('organization', 'organization', '机构管理', 'icon-storage', 10, [
|
group('organization', 'organization', '机构管理', 'icon-storage', 10, [
|
||||||
|
|||||||
Reference in New Issue
Block a user