|
|
@@ -0,0 +1,1112 @@
|
|
|
+// prisma/mongo/seed-admin.ts
|
|
|
+import { PrismaClient, MenuType, AdType } from '@prisma/mongo/client';
|
|
|
+import type { Prisma } from '@prisma/mongo/client';
|
|
|
+
|
|
|
+const prisma = new PrismaClient();
|
|
|
+
|
|
|
+// =============================================================================
|
|
|
+// MENU SEEDS DATA
|
|
|
+// =============================================================================
|
|
|
+
|
|
|
+interface SeedMenu {
|
|
|
+ legacyId: number;
|
|
|
+ legacyParentId: number | null;
|
|
|
+ title: string;
|
|
|
+ type: MenuType;
|
|
|
+ name: string;
|
|
|
+ path: string;
|
|
|
+ icon: string | null;
|
|
|
+ componentKey?: string | null;
|
|
|
+ order: number;
|
|
|
+ meta?: Prisma.JsonValue;
|
|
|
+}
|
|
|
+
|
|
|
+const MENU_SEEDS: SeedMenu[] = [
|
|
|
+ // ======================
|
|
|
+ // 营销中心 (Marketing)
|
|
|
+ // ======================
|
|
|
+ {
|
|
|
+ legacyId: 1,
|
|
|
+ legacyParentId: null,
|
|
|
+ title: '营销中心',
|
|
|
+ type: 'DIRECTORY',
|
|
|
+ name: 'Marketing Management',
|
|
|
+ path: '/marketing',
|
|
|
+ icon: 'i-carbon:application-web',
|
|
|
+ order: 100,
|
|
|
+ meta: {
|
|
|
+ title: '营销中心',
|
|
|
+ i18n: 'route.general.root',
|
|
|
+ icon: 'i-carbon:application-web',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ legacyId: 2,
|
|
|
+ legacyParentId: 1,
|
|
|
+ title: '视频管理',
|
|
|
+ type: 'MENU',
|
|
|
+ name: 'videoList',
|
|
|
+ path: '/marketing/video',
|
|
|
+ icon: 'i-carbon:video',
|
|
|
+ order: 1,
|
|
|
+ meta: {
|
|
|
+ title: '视频管理',
|
|
|
+ i18n: 'route.general.video.root',
|
|
|
+ icon: 'i-carbon:video',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ legacyId: 3,
|
|
|
+ legacyParentId: 2,
|
|
|
+ title: '视频列表',
|
|
|
+ type: 'SUBMENU',
|
|
|
+ name: 'videoList',
|
|
|
+ path: '/marketing/videoList',
|
|
|
+ icon: null,
|
|
|
+ componentKey: '@/views/marketing_center/video_mgnt/list.vue',
|
|
|
+ order: 1,
|
|
|
+ meta: {
|
|
|
+ title: '视频列表',
|
|
|
+ i18n: 'route.general.video.list',
|
|
|
+ sidebar: false,
|
|
|
+ breadcrumb: false,
|
|
|
+ cache: ['videoCreate', 'videoEdit'],
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ legacyId: 4,
|
|
|
+ legacyParentId: 2,
|
|
|
+ title: '新增视频',
|
|
|
+ type: 'SUBMENU',
|
|
|
+ name: 'videoCreate',
|
|
|
+ path: '/marketing/video/detail',
|
|
|
+ icon: null,
|
|
|
+ componentKey: '@/views/marketing_center/video_mgnt/detail.vue',
|
|
|
+ order: 2,
|
|
|
+ meta: {
|
|
|
+ title: '新增视频',
|
|
|
+ i18n: 'route.general.video.create',
|
|
|
+ sidebar: false,
|
|
|
+ activeMenu: '/marketing/videoList',
|
|
|
+ cache: true,
|
|
|
+ noCache: 'videoList',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ legacyId: 5,
|
|
|
+ legacyParentId: 2,
|
|
|
+ title: '编辑视频',
|
|
|
+ type: 'SUBMENU',
|
|
|
+ name: 'videoEdit',
|
|
|
+ path: '/marketing/video/detail/:id',
|
|
|
+ icon: null,
|
|
|
+ componentKey: '@/views/marketing_center/video_mgnt/detail.vue',
|
|
|
+ order: 3,
|
|
|
+ meta: {
|
|
|
+ title: '编辑视频',
|
|
|
+ i18n: 'route.general.video.edit',
|
|
|
+ sidebar: false,
|
|
|
+ activeMenu: '/marketing/videoList',
|
|
|
+ cache: true,
|
|
|
+ noCache: 'videoList',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ legacyId: 6,
|
|
|
+ legacyParentId: 1,
|
|
|
+ title: '分类管理',
|
|
|
+ type: 'MENU',
|
|
|
+ name: 'categoryList',
|
|
|
+ path: '/marketing/category',
|
|
|
+ icon: 'i-carbon:category',
|
|
|
+ order: 2,
|
|
|
+ meta: {
|
|
|
+ title: '分类管理',
|
|
|
+ i18n: 'route.general.category.root',
|
|
|
+ icon: 'i-carbon:category',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ legacyId: 7,
|
|
|
+ legacyParentId: 6,
|
|
|
+ title: '分类列表',
|
|
|
+ type: 'SUBMENU',
|
|
|
+ name: 'categoryList',
|
|
|
+ path: '/marketing/categoryList',
|
|
|
+ icon: null,
|
|
|
+ componentKey: '@/views/marketing_center/category_mgnt/list.vue',
|
|
|
+ order: 1,
|
|
|
+ meta: {
|
|
|
+ title: '分类列表',
|
|
|
+ i18n: 'route.general.category.list',
|
|
|
+ sidebar: false,
|
|
|
+ breadcrumb: false,
|
|
|
+ cache: ['categoryCreate', 'categoryEdit'],
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ legacyId: 8,
|
|
|
+ legacyParentId: 6,
|
|
|
+ title: '新增分类',
|
|
|
+ type: 'SUBMENU',
|
|
|
+ name: 'categoryCreate',
|
|
|
+ path: '/marketing/category/detail',
|
|
|
+ icon: null,
|
|
|
+ componentKey: '@/views/marketing_center/category_mgnt/detail.vue',
|
|
|
+ order: 2,
|
|
|
+ meta: {
|
|
|
+ title: '新增分类',
|
|
|
+ i18n: 'route.general.category.create',
|
|
|
+ sidebar: false,
|
|
|
+ activeMenu: '/marketing/categoryList',
|
|
|
+ cache: true,
|
|
|
+ noCache: 'categoryList',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ legacyId: 9,
|
|
|
+ legacyParentId: 6,
|
|
|
+ title: '编辑分类',
|
|
|
+ type: 'SUBMENU',
|
|
|
+ name: 'categoryEdit',
|
|
|
+ path: '/marketing/category/detail/:id',
|
|
|
+ icon: null,
|
|
|
+ componentKey: '@/views/marketing_center/category_mgnt/detail.vue',
|
|
|
+ order: 3,
|
|
|
+ meta: {
|
|
|
+ title: '编辑分类',
|
|
|
+ i18n: 'route.general.category.edit',
|
|
|
+ sidebar: false,
|
|
|
+ activeMenu: '/marketing/categoryList',
|
|
|
+ cache: true,
|
|
|
+ noCache: 'categoryList',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ legacyId: 10,
|
|
|
+ legacyParentId: 1,
|
|
|
+ title: '标签管理',
|
|
|
+ type: 'MENU',
|
|
|
+ name: 'tagList',
|
|
|
+ path: '/marketing/tag',
|
|
|
+ icon: 'i-carbon:tag',
|
|
|
+ order: 3,
|
|
|
+ meta: {
|
|
|
+ title: '标签管理',
|
|
|
+ i18n: 'route.general.tag.root',
|
|
|
+ icon: 'i-carbon:tag',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ legacyId: 11,
|
|
|
+ legacyParentId: 10,
|
|
|
+ title: '标签列表',
|
|
|
+ type: 'SUBMENU',
|
|
|
+ name: 'tagList',
|
|
|
+ path: '/marketing/tagList',
|
|
|
+ icon: null,
|
|
|
+ componentKey: '@/views/marketing_center/tag_mgnt/list.vue',
|
|
|
+ order: 1,
|
|
|
+ meta: {
|
|
|
+ title: '标签列表',
|
|
|
+ i18n: 'route.general.tag.list',
|
|
|
+ sidebar: false,
|
|
|
+ breadcrumb: false,
|
|
|
+ cache: ['tagCreate', 'tagEdit'],
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ legacyId: 12,
|
|
|
+ legacyParentId: 10,
|
|
|
+ title: '新增标签',
|
|
|
+ type: 'SUBMENU',
|
|
|
+ name: 'tagCreate',
|
|
|
+ path: '/marketing/tag/detail',
|
|
|
+ icon: null,
|
|
|
+ componentKey: '@/views/marketing_center/tag_mgnt/detail.vue',
|
|
|
+ order: 2,
|
|
|
+ meta: {
|
|
|
+ title: '新增标签',
|
|
|
+ i18n: 'route.general.tag.create',
|
|
|
+ sidebar: false,
|
|
|
+ activeMenu: '/marketing/tagList',
|
|
|
+ cache: true,
|
|
|
+ noCache: 'tagList',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ legacyId: 13,
|
|
|
+ legacyParentId: 10,
|
|
|
+ title: '编辑标签',
|
|
|
+ type: 'SUBMENU',
|
|
|
+ name: 'tagEdit',
|
|
|
+ path: '/marketing/tag/detail/:id',
|
|
|
+ icon: null,
|
|
|
+ componentKey: '@/views/marketing_center/tag_mgnt/detail.vue',
|
|
|
+ order: 3,
|
|
|
+ meta: {
|
|
|
+ title: '编辑标签',
|
|
|
+ i18n: 'route.general.tag.edit',
|
|
|
+ sidebar: false,
|
|
|
+ activeMenu: '/marketing/tagList',
|
|
|
+ cache: true,
|
|
|
+ noCache: 'tagList',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ legacyId: 14,
|
|
|
+ legacyParentId: 1,
|
|
|
+ title: '广告管理',
|
|
|
+ type: 'MENU',
|
|
|
+ name: 'adsList',
|
|
|
+ path: '/marketing/ads',
|
|
|
+ icon: 'i-carbon:image-copy',
|
|
|
+ order: 4,
|
|
|
+ meta: {
|
|
|
+ title: '广告管理',
|
|
|
+ i18n: 'route.general.ads.root',
|
|
|
+ icon: 'i-carbon:image-copy',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ legacyId: 15,
|
|
|
+ legacyParentId: 14,
|
|
|
+ title: '广告列表',
|
|
|
+ type: 'SUBMENU',
|
|
|
+ name: 'adsList',
|
|
|
+ path: '/marketing/adsList',
|
|
|
+ icon: null,
|
|
|
+ componentKey: '@/views/marketing_center/ads_mgnt/list.vue',
|
|
|
+ order: 1,
|
|
|
+ meta: {
|
|
|
+ title: '广告列表',
|
|
|
+ i18n: 'route.general.ads.list',
|
|
|
+ sidebar: false,
|
|
|
+ breadcrumb: false,
|
|
|
+ cache: ['adsCreate', 'adsEdit'],
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ legacyId: 16,
|
|
|
+ legacyParentId: 14,
|
|
|
+ title: '新增广告',
|
|
|
+ type: 'SUBMENU',
|
|
|
+ name: 'adsCreate',
|
|
|
+ path: '/marketing/ads/detail',
|
|
|
+ icon: null,
|
|
|
+ componentKey: '@/views/marketing_center/ads_mgnt/detail.vue',
|
|
|
+ order: 2,
|
|
|
+ meta: {
|
|
|
+ title: '新增广告',
|
|
|
+ i18n: 'route.general.ads.create',
|
|
|
+ sidebar: false,
|
|
|
+ activeMenu: '/marketing/adsList',
|
|
|
+ cache: true,
|
|
|
+ noCache: 'adsList',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ legacyId: 17,
|
|
|
+ legacyParentId: 14,
|
|
|
+ title: '编辑广告',
|
|
|
+ type: 'SUBMENU',
|
|
|
+ name: 'adsEdit',
|
|
|
+ path: '/marketing/ads/detail/:id',
|
|
|
+ icon: null,
|
|
|
+ componentKey: '@/views/marketing_center/ads_mgnt/detail.vue',
|
|
|
+ order: 3,
|
|
|
+ meta: {
|
|
|
+ title: '编辑广告',
|
|
|
+ i18n: 'route.general.ads.edit',
|
|
|
+ sidebar: false,
|
|
|
+ activeMenu: '/marketing/adsList',
|
|
|
+ cache: true,
|
|
|
+ noCache: 'adsList',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ legacyId: 18,
|
|
|
+ legacyParentId: 1,
|
|
|
+ title: '参数管理',
|
|
|
+ type: 'MENU',
|
|
|
+ name: 'paramList',
|
|
|
+ path: '/marketing/param',
|
|
|
+ icon: 'i-carbon:settings',
|
|
|
+ order: 5,
|
|
|
+ meta: {
|
|
|
+ title: '参数管理',
|
|
|
+ i18n: 'route.general.param.root',
|
|
|
+ icon: 'i-carbon:settings',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ legacyId: 19,
|
|
|
+ legacyParentId: 18,
|
|
|
+ title: '参数列表',
|
|
|
+ type: 'SUBMENU',
|
|
|
+ name: 'paramList',
|
|
|
+ path: '/marketing/paramList',
|
|
|
+ icon: null,
|
|
|
+ componentKey: '@/views/marketing_center/param_mgnt/list.vue',
|
|
|
+ order: 1,
|
|
|
+ meta: {
|
|
|
+ title: '参数列表',
|
|
|
+ i18n: 'route.general.param.list',
|
|
|
+ sidebar: false,
|
|
|
+ breadcrumb: false,
|
|
|
+ cache: ['paramCreate', 'paramEdit'],
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ legacyId: 20,
|
|
|
+ legacyParentId: 18,
|
|
|
+ title: '新增参数',
|
|
|
+ type: 'SUBMENU',
|
|
|
+ name: 'paramCreate',
|
|
|
+ path: '/marketing/param/detail',
|
|
|
+ icon: null,
|
|
|
+ componentKey: '@/views/marketing_center/param_mgnt/detail.vue',
|
|
|
+ order: 2,
|
|
|
+ meta: {
|
|
|
+ title: '新增参数',
|
|
|
+ i18n: 'route.general.param.create',
|
|
|
+ sidebar: false,
|
|
|
+ activeMenu: '/marketing/paramList',
|
|
|
+ cache: true,
|
|
|
+ noCache: 'paramList',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ legacyId: 21,
|
|
|
+ legacyParentId: 18,
|
|
|
+ title: '编辑参数',
|
|
|
+ type: 'SUBMENU',
|
|
|
+ name: 'paramEdit',
|
|
|
+ path: '/marketing/param/detail/:id',
|
|
|
+ icon: null,
|
|
|
+ componentKey: '@/views/marketing_center/param_mgnt/detail.vue',
|
|
|
+ order: 3,
|
|
|
+ meta: {
|
|
|
+ title: '编辑参数',
|
|
|
+ i18n: 'route.general.param.edit',
|
|
|
+ sidebar: false,
|
|
|
+ activeMenu: '/marketing/paramList',
|
|
|
+ cache: true,
|
|
|
+ noCache: 'paramList',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ legacyId: 22,
|
|
|
+ legacyParentId: 1,
|
|
|
+ title: '渠道管理',
|
|
|
+ type: 'MENU',
|
|
|
+ name: 'channelList',
|
|
|
+ path: '/marketing/channel',
|
|
|
+ icon: 'i-carbon:network-3',
|
|
|
+ order: 6,
|
|
|
+ meta: {
|
|
|
+ title: '渠道管理',
|
|
|
+ i18n: 'route.general.channel.root',
|
|
|
+ icon: 'i-carbon:network-3',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ legacyId: 23,
|
|
|
+ legacyParentId: 22,
|
|
|
+ title: '渠道列表',
|
|
|
+ type: 'SUBMENU',
|
|
|
+ name: 'channelList',
|
|
|
+ path: '/marketing/channelList',
|
|
|
+ icon: null,
|
|
|
+ componentKey: '@/views/marketing_center/channel_mgnt/list.vue',
|
|
|
+ order: 1,
|
|
|
+ meta: {
|
|
|
+ title: '渠道列表',
|
|
|
+ i18n: 'route.general.channel.list',
|
|
|
+ sidebar: false,
|
|
|
+ breadcrumb: false,
|
|
|
+ cache: ['channelCreate', 'channelEdit'],
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ legacyId: 24,
|
|
|
+ legacyParentId: 22,
|
|
|
+ title: '新增渠道',
|
|
|
+ type: 'SUBMENU',
|
|
|
+ name: 'channelCreate',
|
|
|
+ path: '/marketing/channel/detail',
|
|
|
+ icon: null,
|
|
|
+ componentKey: '@/views/marketing_center/channel_mgnt/detail.vue',
|
|
|
+ order: 2,
|
|
|
+ meta: {
|
|
|
+ title: '新增渠道',
|
|
|
+ i18n: 'route.general.channel.create',
|
|
|
+ sidebar: false,
|
|
|
+ activeMenu: '/marketing/channelList',
|
|
|
+ cache: true,
|
|
|
+ noCache: 'channelList',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ legacyId: 25,
|
|
|
+ legacyParentId: 22,
|
|
|
+ title: '编辑渠道',
|
|
|
+ type: 'SUBMENU',
|
|
|
+ name: 'channelEdit',
|
|
|
+ path: '/marketing/channel/detail/:id',
|
|
|
+ icon: null,
|
|
|
+ componentKey: '@/views/marketing_center/channel_mgnt/detail.vue',
|
|
|
+ order: 3,
|
|
|
+ meta: {
|
|
|
+ title: '编辑渠道',
|
|
|
+ i18n: 'route.general.channel.edit',
|
|
|
+ sidebar: false,
|
|
|
+ activeMenu: '/marketing/channelList',
|
|
|
+ cache: true,
|
|
|
+ noCache: 'channelList',
|
|
|
+ },
|
|
|
+ },
|
|
|
+
|
|
|
+ // ======================
|
|
|
+ // 数据中心 (Data Center)
|
|
|
+ // ======================
|
|
|
+ {
|
|
|
+ legacyId: 26,
|
|
|
+ legacyParentId: null,
|
|
|
+ title: '数据中心',
|
|
|
+ type: 'DIRECTORY',
|
|
|
+ name: 'Data Center',
|
|
|
+ path: '/datacenter',
|
|
|
+ icon: 'i-carbon:data-vis-4',
|
|
|
+ order: 200,
|
|
|
+ meta: {
|
|
|
+ title: '数据中心',
|
|
|
+ i18n: 'route.general.root',
|
|
|
+ icon: 'i-carbon:data-vis-4',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ legacyId: 27,
|
|
|
+ legacyParentId: 26,
|
|
|
+ title: 'APP访问记录',
|
|
|
+ type: 'MENU',
|
|
|
+ name: 'appAccessList',
|
|
|
+ path: '/datacenter/appAccessRecord',
|
|
|
+ icon: 'i-carbon:mobile',
|
|
|
+ order: 1,
|
|
|
+ meta: {
|
|
|
+ title: 'APP访问记录',
|
|
|
+ i18n: 'route.general.appAccessRecord.root',
|
|
|
+ icon: 'i-carbon:mobile',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ legacyId: 28,
|
|
|
+ legacyParentId: 27,
|
|
|
+ title: 'APP访问记录',
|
|
|
+ type: 'SUBMENU',
|
|
|
+ name: 'appAccessList',
|
|
|
+ path: '/datacenter/appAccessList',
|
|
|
+ icon: null,
|
|
|
+ componentKey: '@/views/data_center/appAccess_records/list.vue',
|
|
|
+ order: 1,
|
|
|
+ meta: {
|
|
|
+ title: 'APP访问记录',
|
|
|
+ i18n: 'route.general.appAccessRecord.list',
|
|
|
+ sidebar: false,
|
|
|
+ breadcrumb: false,
|
|
|
+ cache: ['appAccessRecordCreate', 'appAccessRecordEdit'],
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ legacyId: 29,
|
|
|
+ legacyParentId: 26,
|
|
|
+ title: '广告点击记录',
|
|
|
+ type: 'MENU',
|
|
|
+ name: 'adsAccessList',
|
|
|
+ path: '/datacenter/adsAccessRecord',
|
|
|
+ icon: 'i-carbon:touch-1',
|
|
|
+ order: 2,
|
|
|
+ meta: {
|
|
|
+ title: '广告点击记录',
|
|
|
+ i18n: 'route.general.adsAccessRecord.root',
|
|
|
+ icon: 'i-carbon:touch-1',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ legacyId: 30,
|
|
|
+ legacyParentId: 29,
|
|
|
+ title: '广告点击记录',
|
|
|
+ type: 'SUBMENU',
|
|
|
+ name: 'adsAccessList',
|
|
|
+ path: '/datacenter/adsAccessList',
|
|
|
+ icon: null,
|
|
|
+ componentKey: '@/views/data_center/adsAccess_records/list.vue',
|
|
|
+ order: 1,
|
|
|
+ meta: {
|
|
|
+ title: '广告点击记录',
|
|
|
+ i18n: 'route.general.category.list',
|
|
|
+ sidebar: false,
|
|
|
+ breadcrumb: false,
|
|
|
+ cache: ['adsAccessRecordCreate', 'adsAccessRecordEdit'],
|
|
|
+ },
|
|
|
+ },
|
|
|
+
|
|
|
+ // ======================
|
|
|
+ // 统计中心 (Stats Center)
|
|
|
+ // ======================
|
|
|
+ {
|
|
|
+ legacyId: 31,
|
|
|
+ legacyParentId: null,
|
|
|
+ title: '统计中心',
|
|
|
+ type: 'DIRECTORY',
|
|
|
+ name: 'Statistics Management',
|
|
|
+ path: '/stats',
|
|
|
+ icon: 'i-carbon:chart-line',
|
|
|
+ order: 300,
|
|
|
+ meta: {
|
|
|
+ title: '统计中心',
|
|
|
+ i18n: 'route.general.root',
|
|
|
+ icon: 'i-carbon:chart-line',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ legacyId: 32,
|
|
|
+ legacyParentId: 31,
|
|
|
+ title: '每日统计',
|
|
|
+ type: 'MENU',
|
|
|
+ name: 'dailyStats',
|
|
|
+ path: '/stats/dailyStats',
|
|
|
+ icon: 'i-carbon:calendar',
|
|
|
+ order: 1,
|
|
|
+ meta: {
|
|
|
+ title: '每日统计',
|
|
|
+ i18n: 'route.general.dailyStats.root',
|
|
|
+ icon: 'i-carbon:calendar',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ legacyId: 33,
|
|
|
+ legacyParentId: 32,
|
|
|
+ title: '每日统计',
|
|
|
+ type: 'SUBMENU',
|
|
|
+ name: 'dailyStatsList',
|
|
|
+ path: '/stats/dailyStatsList',
|
|
|
+ icon: null,
|
|
|
+ componentKey: '@/views/stats_center/daily_stats/list.vue',
|
|
|
+ order: 1,
|
|
|
+ meta: {
|
|
|
+ title: '每日统计',
|
|
|
+ i18n: 'route.general.video.list',
|
|
|
+ sidebar: false,
|
|
|
+ breadcrumb: false,
|
|
|
+ cache: ['videoCreate', 'videoEdit'],
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ legacyId: 34,
|
|
|
+ legacyParentId: 31,
|
|
|
+ title: '广告统计',
|
|
|
+ type: 'MENU',
|
|
|
+ name: 'adsStatsList',
|
|
|
+ path: '/stats/adsStats',
|
|
|
+ icon: 'i-carbon:chart-bar',
|
|
|
+ order: 2,
|
|
|
+ meta: {
|
|
|
+ title: '广告统计',
|
|
|
+ i18n: 'route.general.adsStats.root',
|
|
|
+ icon: 'i-carbon:chart-bar',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ legacyId: 35,
|
|
|
+ legacyParentId: 34,
|
|
|
+ title: '广告统计',
|
|
|
+ type: 'SUBMENU',
|
|
|
+ name: 'adsStatsList',
|
|
|
+ path: '/stats/adsStatsList',
|
|
|
+ icon: null,
|
|
|
+ componentKey: '@/views/stats_center/ads_stats/list.vue',
|
|
|
+ order: 1,
|
|
|
+ meta: {
|
|
|
+ title: '广告统计',
|
|
|
+ i18n: 'route.general.adsStats.list',
|
|
|
+ sidebar: false,
|
|
|
+ breadcrumb: false,
|
|
|
+ cache: ['adsStatsCreate', 'adsStatsEdit'],
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ legacyId: 36,
|
|
|
+ legacyParentId: 31,
|
|
|
+ title: '广告汇总',
|
|
|
+ type: 'MENU',
|
|
|
+ name: 'adsStatsSummary',
|
|
|
+ path: '/stats/adsStatsSummary',
|
|
|
+ icon: 'i-carbon:chart-pie',
|
|
|
+ componentKey: '@/views/stats_center/ads_stats_summary/list.vue',
|
|
|
+ order: 3,
|
|
|
+ meta: {
|
|
|
+ title: '广告汇总',
|
|
|
+ i18n: 'route.general.adsStatsSummary.root',
|
|
|
+ icon: 'i-carbon:chart-pie',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ legacyId: 37,
|
|
|
+ legacyParentId: 36,
|
|
|
+ title: '广告汇总',
|
|
|
+ type: 'SUBMENU',
|
|
|
+ name: 'adsStatsSummaryList',
|
|
|
+ path: '/stats/adsStatsSummaryList',
|
|
|
+ icon: null,
|
|
|
+ componentKey: '@/views/stats_center/ads_stats_summary/list.vue',
|
|
|
+ order: 1,
|
|
|
+ meta: {
|
|
|
+ title: '广告汇总',
|
|
|
+ i18n: 'route.general.adsStatsSummary.list',
|
|
|
+ sidebar: false,
|
|
|
+ breadcrumb: false,
|
|
|
+ cache: ['adsStatsSummaryCreate', 'adsStatsSummaryEdit'],
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ legacyId: 38,
|
|
|
+ legacyParentId: 31,
|
|
|
+ title: '渠道统计',
|
|
|
+ type: 'MENU',
|
|
|
+ name: 'channelStatsList',
|
|
|
+ path: '/stats/channelStats',
|
|
|
+ icon: 'i-carbon:flow',
|
|
|
+ order: 4,
|
|
|
+ meta: {
|
|
|
+ title: '渠道统计',
|
|
|
+ i18n: 'route.general.channelStats.root',
|
|
|
+ icon: 'i-carbon:flow',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ legacyId: 39,
|
|
|
+ legacyParentId: 38,
|
|
|
+ title: '渠道统计',
|
|
|
+ type: 'SUBMENU',
|
|
|
+ name: 'channelStatsList',
|
|
|
+ path: '/stats/channelStatsList',
|
|
|
+ icon: null,
|
|
|
+ componentKey: '@/views/stats_center/channel_stats/list.vue',
|
|
|
+ order: 1,
|
|
|
+ meta: {
|
|
|
+ title: '渠道统计',
|
|
|
+ i18n: 'route.general.channel.list',
|
|
|
+ sidebar: false,
|
|
|
+ breadcrumb: false,
|
|
|
+ cache: ['channelCreate', 'channelEdit'],
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ legacyId: 40,
|
|
|
+ legacyParentId: 31,
|
|
|
+ title: '渠道汇总',
|
|
|
+ type: 'MENU',
|
|
|
+ name: 'channelStatsSummaryList',
|
|
|
+ path: '/stats/channelStatsSummary',
|
|
|
+ icon: 'i-carbon:report',
|
|
|
+ order: 5,
|
|
|
+ meta: {
|
|
|
+ title: '渠道汇总',
|
|
|
+ i18n: 'route.general.channelStatsSummary.root',
|
|
|
+ icon: 'i-carbon:report',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ legacyId: 41,
|
|
|
+ legacyParentId: 40,
|
|
|
+ title: '渠道汇总',
|
|
|
+ type: 'SUBMENU',
|
|
|
+ name: 'channelStatsSummaryList',
|
|
|
+ path: '/stats/channelStatsSummaryList',
|
|
|
+ icon: null,
|
|
|
+ componentKey: '@/views/stats_center/channel_stats_summary/list.vue',
|
|
|
+ order: 1,
|
|
|
+ meta: {
|
|
|
+ title: '参数列表',
|
|
|
+ i18n: 'route.general.param.list',
|
|
|
+ sidebar: false,
|
|
|
+ breadcrumb: false,
|
|
|
+ cache: ['channelStatsSummaryCreate', 'channelStatsSummaryEdit'],
|
|
|
+ },
|
|
|
+ },
|
|
|
+
|
|
|
+ // ======================
|
|
|
+ // 系统管理 (System)
|
|
|
+ // ======================
|
|
|
+ {
|
|
|
+ legacyId: 42,
|
|
|
+ legacyParentId: null,
|
|
|
+ title: '账号管理',
|
|
|
+ type: 'DIRECTORY',
|
|
|
+ name: 'Sytem Management',
|
|
|
+ path: '/system',
|
|
|
+ icon: 'i-carbon:user-admin',
|
|
|
+ order: 400,
|
|
|
+ meta: {
|
|
|
+ title: '账号管理',
|
|
|
+ i18n: 'route.general.root',
|
|
|
+ icon: 'i-carbon:user-admin',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ legacyId: 43,
|
|
|
+ legacyParentId: 42,
|
|
|
+ title: '账号列表',
|
|
|
+ type: 'MENU',
|
|
|
+ name: 'userList',
|
|
|
+ path: '/system/users',
|
|
|
+ icon: 'i-carbon:user-multiple',
|
|
|
+ componentKey: '@/views/system_mgnt/users/list.vue',
|
|
|
+ order: 1,
|
|
|
+ meta: {
|
|
|
+ title: '账号列表',
|
|
|
+ i18n: 'route.general.manager.root',
|
|
|
+ icon: 'i-carbon:user-multiple',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ legacyId: 44,
|
|
|
+ legacyParentId: 42,
|
|
|
+ title: '角色列表',
|
|
|
+ type: 'MENU',
|
|
|
+ name: 'roleList',
|
|
|
+ path: '/system/roles',
|
|
|
+ icon: 'i-carbon:user-role',
|
|
|
+ order: 2,
|
|
|
+ meta: {
|
|
|
+ title: '角色列表',
|
|
|
+ i18n: 'route.general.role.root',
|
|
|
+ icon: 'i-carbon:user-role',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ legacyId: 45,
|
|
|
+ legacyParentId: 44,
|
|
|
+ title: '角色列表',
|
|
|
+ type: 'SUBMENU',
|
|
|
+ name: 'roleList',
|
|
|
+ path: '/system/roleList',
|
|
|
+ icon: null,
|
|
|
+ componentKey: '@/views/system_mgnt/roles/list.vue',
|
|
|
+ order: 1,
|
|
|
+ meta: {
|
|
|
+ title: '角色列表',
|
|
|
+ i18n: 'route.general.role.list',
|
|
|
+ sidebar: false,
|
|
|
+ breadcrumb: false,
|
|
|
+ cache: ['roleCreate', 'roleEdit'],
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ legacyId: 46,
|
|
|
+ legacyParentId: 44,
|
|
|
+ title: '新增角色',
|
|
|
+ type: 'SUBMENU',
|
|
|
+ name: 'roleCreate',
|
|
|
+ path: '/system/roles/detail',
|
|
|
+ icon: null,
|
|
|
+ componentKey: '@/views/system_mgnt/roles/detail.vue',
|
|
|
+ order: 2,
|
|
|
+ meta: {
|
|
|
+ title: '新增角色',
|
|
|
+ i18n: 'route.general.role.create',
|
|
|
+ sidebar: false,
|
|
|
+ activeMenu: '/system/roleList',
|
|
|
+ cache: true,
|
|
|
+ noCache: 'roleList',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ legacyId: 47,
|
|
|
+ legacyParentId: 44,
|
|
|
+ title: '编辑角色',
|
|
|
+ type: 'SUBMENU',
|
|
|
+ name: 'roleEdit',
|
|
|
+ path: '/system/roles/detail/:id',
|
|
|
+ icon: null,
|
|
|
+ componentKey: '@/views/system_mgnt/roles/detail.vue',
|
|
|
+ order: 3,
|
|
|
+ meta: {
|
|
|
+ title: '编辑角色',
|
|
|
+ i18n: 'route.general.role.edit',
|
|
|
+ sidebar: false,
|
|
|
+ activeMenu: '/system/roleList',
|
|
|
+ cache: true,
|
|
|
+ noCache: 'roleList',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ legacyId: 48,
|
|
|
+ legacyParentId: 42,
|
|
|
+ title: '权限列表',
|
|
|
+ type: 'MENU',
|
|
|
+ name: 'menus',
|
|
|
+ path: '/system/menus',
|
|
|
+ icon: 'i-carbon:list-boxes',
|
|
|
+ order: 3,
|
|
|
+ meta: {
|
|
|
+ title: '权限列表',
|
|
|
+ i18n: 'route.general.menu.root',
|
|
|
+ icon: 'i-carbon:list-boxes',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ legacyId: 49,
|
|
|
+ legacyParentId: 48,
|
|
|
+ title: '菜单列表',
|
|
|
+ type: 'SUBMENU',
|
|
|
+ name: 'menuList',
|
|
|
+ path: '/system/menuList',
|
|
|
+ icon: null,
|
|
|
+ componentKey: '@/views/system_mgnt/menus/list.vue',
|
|
|
+ order: 1,
|
|
|
+ meta: {
|
|
|
+ title: '菜单列表',
|
|
|
+ i18n: 'route.general.menu.list',
|
|
|
+ sidebar: false,
|
|
|
+ breadcrumb: false,
|
|
|
+ cache: ['menuCreate', 'menuEdit'],
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ legacyId: 50,
|
|
|
+ legacyParentId: 48,
|
|
|
+ title: '新增菜单',
|
|
|
+ type: 'SUBMENU',
|
|
|
+ name: 'menuCreate',
|
|
|
+ path: '/system/menus/detail',
|
|
|
+ icon: null,
|
|
|
+ componentKey: '@/views/system_mgnt/menus/detail.vue',
|
|
|
+ order: 2,
|
|
|
+ meta: {
|
|
|
+ title: '新增菜单',
|
|
|
+ i18n: 'route.general.menu.create',
|
|
|
+ sidebar: false,
|
|
|
+ activeMenu: '/system/menuList',
|
|
|
+ cache: true,
|
|
|
+ noCache: 'menuList',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ legacyId: 51,
|
|
|
+ legacyParentId: 48,
|
|
|
+ title: '编辑菜单',
|
|
|
+ type: 'SUBMENU',
|
|
|
+ name: 'menuEdit',
|
|
|
+ path: '/system/menus/detail/:id',
|
|
|
+ icon: null,
|
|
|
+ componentKey: '@/views/system_mgnt/menus/detail.vue',
|
|
|
+ order: 3,
|
|
|
+ meta: {
|
|
|
+ title: '编辑菜单',
|
|
|
+ i18n: 'route.general.menu.edit',
|
|
|
+ sidebar: false,
|
|
|
+ activeMenu: '/system/menuList',
|
|
|
+ cache: true,
|
|
|
+ noCache: 'menuList',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ legacyId: 52,
|
|
|
+ legacyParentId: 42,
|
|
|
+ title: 'Redis监控',
|
|
|
+ type: 'MENU',
|
|
|
+ name: 'redisMonitor',
|
|
|
+ path: '/system/redisMonitor',
|
|
|
+ icon: 'i-carbon:list-boxes',
|
|
|
+ order: 4,
|
|
|
+ meta: {
|
|
|
+ title: 'Redis监控',
|
|
|
+ i18n: 'route.general.redisMonitor.list',
|
|
|
+ icon: 'i-carbon:list-boxes',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ legacyId: 53,
|
|
|
+ legacyParentId: 52,
|
|
|
+ title: 'Redis列表',
|
|
|
+ type: 'SUBMENU',
|
|
|
+ name: 'redisList',
|
|
|
+ path: '/system/redisList',
|
|
|
+ icon: null,
|
|
|
+ componentKey: '@/views/system_mgnt/redisMonitor/list.vue',
|
|
|
+ order: 1,
|
|
|
+ meta: {
|
|
|
+ title: 'Redis列表',
|
|
|
+ i18n: 'route.general.redisMonitor.list',
|
|
|
+ sidebar: false,
|
|
|
+ breadcrumb: false,
|
|
|
+ cache: ['redisCreate', 'redisEdit'],
|
|
|
+ },
|
|
|
+ },
|
|
|
+];
|
|
|
+
|
|
|
+// =============================================================================
|
|
|
+// HELPER FUNCTIONS
|
|
|
+// =============================================================================
|
|
|
+
|
|
|
+/**
|
|
|
+ * Get default action permissions based on menu type
|
|
|
+ */
|
|
|
+function getDefaultPermissions(type: MenuType) {
|
|
|
+ switch (type) {
|
|
|
+ case 'DIRECTORY':
|
|
|
+ return { canView: 1, canCreate: 0, canUpdate: 0, canDelete: 0 };
|
|
|
+ case 'MENU':
|
|
|
+ case 'SUBMENU':
|
|
|
+ return { canView: 1, canCreate: 1, canUpdate: 1, canDelete: 1 };
|
|
|
+ case 'BUTTON':
|
|
|
+ return { canView: 0, canCreate: 1, canUpdate: 0, canDelete: 0 };
|
|
|
+ default:
|
|
|
+ return { canView: 0, canCreate: 0, canUpdate: 0, canDelete: 0 };
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Seed menus with multi-pass insertion to handle parent-child relationships
|
|
|
+ */
|
|
|
+async function seedMenus() {
|
|
|
+ console.log('📝 Seeding menus...');
|
|
|
+
|
|
|
+ await prisma.$runCommandRaw({
|
|
|
+ delete: 'sys_api_permission',
|
|
|
+ deletes: [{ q: {}, limit: 0 }],
|
|
|
+ });
|
|
|
+ await prisma.$runCommandRaw({
|
|
|
+ delete: 'sys_menu',
|
|
|
+ deletes: [{ q: {}, limit: 0 }],
|
|
|
+ });
|
|
|
+
|
|
|
+ const legacyIdToNewId = new Map<number, string>();
|
|
|
+ const inserted = new Set<number>();
|
|
|
+
|
|
|
+ // Multi-pass insertion: insert records whose parent is either null or already inserted
|
|
|
+ while (inserted.size < MENU_SEEDS.length) {
|
|
|
+ let progress = false;
|
|
|
+
|
|
|
+ for (const seed of MENU_SEEDS) {
|
|
|
+ if (inserted.has(seed.legacyId)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // If has a parent, but parent not inserted yet → skip this round
|
|
|
+ if (
|
|
|
+ seed.legacyParentId !== null &&
|
|
|
+ !legacyIdToNewId.has(seed.legacyParentId)
|
|
|
+ ) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ const parentId =
|
|
|
+ seed.legacyParentId === null
|
|
|
+ ? null
|
|
|
+ : legacyIdToNewId.get(seed.legacyParentId)!;
|
|
|
+
|
|
|
+ const permissions = getDefaultPermissions(seed.type);
|
|
|
+ const menuCreateData: Prisma.SysMenuUncheckedCreateInput = {
|
|
|
+ parentId,
|
|
|
+ title: seed.title,
|
|
|
+ status: true,
|
|
|
+ type: seed.type,
|
|
|
+ order: seed.order,
|
|
|
+ frontendAuth: seed.path,
|
|
|
+ path: seed.path,
|
|
|
+ name: seed.name,
|
|
|
+ icon: seed.icon,
|
|
|
+ redirect: null,
|
|
|
+ componentKey: seed.componentKey ?? null,
|
|
|
+ meta: seed.meta ?? undefined,
|
|
|
+ ...permissions,
|
|
|
+ };
|
|
|
+
|
|
|
+ const created = await prisma.sysMenu.upsert({
|
|
|
+ // Use unique index on frontendAuth to identify menu
|
|
|
+ where: { frontendAuth: seed.path },
|
|
|
+ update: {
|
|
|
+ parentId,
|
|
|
+ title: seed.title,
|
|
|
+ status: true,
|
|
|
+ type: seed.type,
|
|
|
+ order: seed.order,
|
|
|
+ // keep frontendAuth as path
|
|
|
+ path: seed.path,
|
|
|
+ name: seed.name,
|
|
|
+ icon: seed.icon,
|
|
|
+ redirect: null,
|
|
|
+ componentKey: seed.componentKey ?? null,
|
|
|
+ // meta undefined means do not overwrite; if provided, update
|
|
|
+ ...(seed.meta !== undefined
|
|
|
+ ? { meta: seed.meta as Prisma.InputJsonValue }
|
|
|
+ : {}),
|
|
|
+ ...permissions,
|
|
|
+ },
|
|
|
+ create: {
|
|
|
+ ...menuCreateData,
|
|
|
+ },
|
|
|
+ });
|
|
|
+
|
|
|
+ legacyIdToNewId.set(seed.legacyId, created.id);
|
|
|
+ inserted.add(seed.legacyId);
|
|
|
+ progress = true;
|
|
|
+
|
|
|
+ console.log(
|
|
|
+ ` ✓ Menu [${seed.type.padEnd(9)}] ${seed.name.padEnd(25)} → ID: ${created.id}`,
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!progress) {
|
|
|
+ // Nothing could be inserted in this pass → some parentId is invalid or cyclic
|
|
|
+ const pending = MENU_SEEDS.filter((s) => !inserted.has(s.legacyId)).map(
|
|
|
+ (s) => ({
|
|
|
+ legacyId: s.legacyId,
|
|
|
+ legacyParentId: s.legacyParentId,
|
|
|
+ name: s.name,
|
|
|
+ }),
|
|
|
+ );
|
|
|
+
|
|
|
+ console.error('❌ Could not resolve parents for menus:', pending);
|
|
|
+ throw new Error(
|
|
|
+ 'Menu seeding aborted: unresolved parent relationships. Check legacyParentId values.',
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ console.log('✅ Menus seeded successfully');
|
|
|
+ console.log(` - Total menus: ${inserted.size}`);
|
|
|
+}
|
|
|
+
|
|
|
+// =============================================================================
|
|
|
+// MAIN EXECUTION
|
|
|
+// =============================================================================
|
|
|
+
|
|
|
+async function main() {
|
|
|
+ console.log('🌱 Starting menus seeding...\n');
|
|
|
+
|
|
|
+ try {
|
|
|
+ console.log('seeding menus...');
|
|
|
+ await seedMenus();
|
|
|
+ console.log('');
|
|
|
+
|
|
|
+ console.log('\n🎉 Menus seeding completed successfully!');
|
|
|
+ } catch (error) {
|
|
|
+ console.error('\n❌ Error during seeding:', error);
|
|
|
+ throw error;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+main()
|
|
|
+ .then(async () => {
|
|
|
+ await prisma.$disconnect();
|
|
|
+ })
|
|
|
+ .catch(async (e) => {
|
|
|
+ console.error(e);
|
|
|
+ await prisma.$disconnect();
|
|
|
+ process.exit(1);
|
|
|
+ });
|