Sfoglia il codice sorgente

refactor(admin): 重构菜单分组+权限体系

- Layout菜单按职能分9组: 首页/家庭运营/任务中心/审核中心/商城营销/内容中心/健康饮食/规划师工作台/系统配置
- permissions: nutritionist增加diet:*权限, 组级权限匹配(无冒号prefix)
- router: rewards perm改family:rewards, 新增wishes路由, 审核菜单perm细分(audit:package/guide/vendor)
Sisyphus 2 mesi fa
parent
commit
029cdb60e5
3 ha cambiato i file con 103 aggiunte e 85 eliminazioni
  1. 22 16
      cfc-web/src/router/index.js
  2. 15 5
      cfc-web/src/utils/permissions.js
  3. 66 64
      cfc-web/src/views/Layout.vue

+ 22 - 16
cfc-web/src/router/index.js

@@ -72,7 +72,13 @@ const routes = [
         path: 'rewards',
         name: 'Rewards',
         component: () => import('@/views/Rewards.vue'),
-        meta: { title: '奖励列表', perm: 'reward:list' }
+        meta: { title: '奖励列表', perm: 'family:rewards' }
+      },
+      {
+        path: 'wishes',
+        name: 'Wishes',
+        component: () => import('@/views/Wishes.vue'),
+        meta: { title: '心愿管理', perm: 'family:wishes' }
       },
       // 成长规划师管理
       {
@@ -135,13 +141,13 @@ const routes = [
         path: 'package-audit',
         name: 'PackageAudit',
         component: () => import('@/views/PackageAudit.vue'),
-        meta: { title: '套餐审核', perm: 'system:audit' }
+        meta: { title: '套餐审核', perm: 'audit:package' }
       },
       {
         path: 'guide-audit',
         name: 'GuideAudit',
         component: () => import('@/views/GuideAudit.vue'),
-        meta: { title: '成长规划师审核', perm: 'system:audit' }
+        meta: { title: '成长规划师审核', perm: 'audit:guide' }
       },
       {
         path: 'operation-logs',
@@ -190,19 +196,19 @@ const routes = [
         path: 'vendor-review',
         name: 'VendorReview',
         component: () => import('@/views/admin/VendorReview.vue'),
-        meta: { title: '服务商审核', perm: 'system:audit' }
+        meta: { title: '服务商审核', perm: 'audit:vendor' }
       },
       {
         path: 'product-manage',
         name: 'ProductManage',
         component: () => import('@/views/admin/ProductManage.vue'),
-        meta: { title: '商品管理', perm: 'system:products' }
+        meta: { title: '商品管理', perm: 'commerce:products' }
       },
       {
         path: 'order-manage',
         name: 'OrderManage',
         component: () => import('@/views/admin/OrderManage.vue'),
-        meta: { title: '订单管理', perm: 'system:orders' }
+        meta: { title: '订单管理', perm: 'commerce:orders' }
       },
       {
       path: 'sys-config',
@@ -214,7 +220,7 @@ const routes = [
       path: 'energy-sandbox',
       name: 'EnergySandbox',
       component: () => import('@/views/admin/EnergySandbox.vue'),
-      meta: { title: '五维能量', perm: 'system:energy' }
+      meta: { title: '五维能量', perm: 'energy' }
     },
       // ========== 文章管理 ==========
       {
@@ -240,13 +246,13 @@ const routes = [
         path: 'product-profit-rate',
         name: 'ProductProfitRate',
         component: () => import('@/views/admin/ProductProfitRate.vue'),
-        meta: { title: '产品利润率', perm: 'system:products' }
+        meta: { title: '产品利润率', perm: 'commerce:profit-rate' }
       },
       {
         path: 'withdraw-audit',
         name: 'WithdrawAudit',
         component: () => import('@/views/admin/WithdrawAudit.vue'),
-        meta: { title: '提现审核', perm: 'system:audit' }
+        meta: { title: '提现审核', perm: 'audit:withdraw' }
       },
       {
         path: 'education-systems',
@@ -283,31 +289,31 @@ const routes = [
         path: 'danshop-category',
         name: 'DanShopCategory',
         component: () => import('@/views/admin/DanShopCategoryManage'),
-        meta: { title: '商品分类管理', perm: 'system:danshop' }
+        meta: { title: '商品分类管理', perm: 'danshop:category' }
       },
       {
         path: 'danshop-profit-rule',
         name: 'DanShopProfitRule',
         component: () => import('@/views/admin/DanShopProfitRuleConfig'),
-        meta: { title: '分润规则配置', perm: 'system:danshop' }
+        meta: { title: '分润规则配置', perm: 'danshop:profit-rule' }
       },
       {
         path: 'danshop-logistics',
         name: 'DanShopLogistics',
         component: () => import('@/views/admin/DanShopLogisticsManage'),
-        meta: { title: '物流管理', perm: 'system:danshop' }
+        meta: { title: '物流管理', perm: 'danshop:logistics' }
       },
       {
         path: 'danshop-product',
         name: 'DanShopProduct',
         component: () => import('@/views/admin/ProductManage.vue'),
-        meta: { title: 'DanShop商品', perm: 'system:products' }
+        meta: { title: 'DanShop商品', perm: 'danshop:product' }
       },
       {
         path: 'danshop-order',
         name: 'DanShopOrder',
         component: () => import('@/views/admin/OrderManage.vue'),
-        meta: { title: 'DanShop订单', perm: 'system:orders' }
+        meta: { title: 'DanShop订单', perm: 'danshop:order' }
       },
       // ========== 饮食管理 (admin) ==========
       {
@@ -387,13 +393,13 @@ const routes = [
         path: 'coupon',
         name: 'CouponManagement',
         component: () => import('@/views/admin/CouponManagement'),
-        meta: { title: '优惠券管理', perm: 'system:coupon' }
+        meta: { title: '优惠券管理', perm: 'marketing:coupon' }
       },
       {
         path: 'promotion',
         name: 'PromotionManagement',
         component: () => import('@/views/admin/PromotionManagement'),
-        meta: { title: '推广管理', perm: 'system:promotion' }
+        meta: { title: '推广管理', perm: 'marketing:promotion' }
       },
       {
         path: 'dimension-config',

+ 15 - 5
cfc-web/src/utils/permissions.js

@@ -5,7 +5,7 @@
 const ROLE_PERMISSIONS = {
   admin: ['*'],
   teacher: ['dashboard', 'service:*', 'growth:*', 'biz:*', 'assessment:*', 'messages'],
-  nutritionist: ['dashboard', 'service:family', 'health:*', 'assessment:dan', 'energy'],
+  nutritionist: ['dashboard', 'service:family', 'health:*', 'diet:*', 'assessment:dan', 'energy'],
   article_manager: ['dashboard', 'articles:*'],
   activity_manager: ['dashboard', 'activity:*'],
 }
@@ -38,6 +38,7 @@ export function getEffectivePermissions(roles) {
  * 匹配规则:
  * - 如果 userPerms 包含 '*' → 返回 true
  * - 如果 required 是 'prefix:sub' 且 userPerms 包含 'prefix:*' → 返回 true
+ * - 如果 required 是 'prefix'(无冒号)且 userPerms 包含 'prefix:*' → 返回 true(组级权限)
  * - 如果 userPerms 包含 required → 返回 true
  * - 否则返回 false
  */
@@ -48,10 +49,19 @@ export function hasPermission(userPerms, required) {
   // 精确匹配
   if (userPerms.includes(required)) return true
 
-  // 前缀通配匹配: required = 'articles:manage', 检查 'articles:*' 是否在 userPerms 中
-  const colonIndex = required.indexOf(':')
-  if (colonIndex > 0) {
-    const prefix = required.substring(0, colonIndex) + ':*'
+  // 如果 required 不含冒号(组级权限如 'health', 'audit'),
+  // 检查 userPerms 中是否有 'required:*' 前缀通配
+  var colonIndex = required.indexOf(':')
+  if (colonIndex < 0) {
+    var groupWildcard = required + ':*'
+    if (userPerms.includes(groupWildcard)) return true
+    // 也检查是否有任何以 'required:' 开头的权限
+    for (var i = 0; i < userPerms.length; i++) {
+      if (userPerms[i].indexOf(required + ':') === 0) return true
+    }
+  } else {
+    // 前缀通配匹配: required = 'articles:manage', 检查 'articles:*' 是否在 userPerms 中
+    var prefix = required.substring(0, colonIndex) + ':*'
     if (userPerms.includes(prefix)) return true
   }
 

+ 66 - 64
cfc-web/src/views/Layout.vue

@@ -134,109 +134,111 @@ export default {
   data() {
     return {
       menuItems: [
-        // 全局通用
+        // ===== 1. 首页 (ALL) =====
         { path: '/dashboard', label: '首页', icon: 'el-icon-s-home', perm: 'dashboard' },
 
-        // admin 专属
-        { title: '家庭管理', icon: 'el-icon-s-home', perm: 'family:*',
+        // ===== 2. 家庭运营 (admin) =====
+        { title: '家庭运营', icon: 'el-icon-s-custom', perm: 'operation',
           children: [
-            { path: '/families', label: '家庭列表', icon: 'el-icon-s-home', perm: 'family:list' },
-            { path: '/children', label: '孩子管理', icon: 'el-icon-s-custom', perm: 'family:children' },
-            { path: '/points', label: '积分管理', icon: 'el-icon-s-money', perm: 'family:points' },
+            { path: '/families', label: '家庭列表', icon: 'el-icon-s-custom', perm: 'family:list' },
+            { path: '/children', label: '孩子管理', icon: 'el-icon-user-solid', perm: 'family:children' },
+            { path: '/points', label: '积分管理', icon: 'el-icon-s-finance', perm: 'family:points' },
+            { path: '/wishes', label: '心愿管理', icon: 'el-icon-star-off', perm: 'family:wishes' },
+            { path: '/rewards', label: '奖励管理', icon: 'el-icon-s-goods', perm: 'reward:list' },
           ]},
-        { title: '任务管理', icon: 'el-icon-s-order', perm: 'task:*',
+
+        // ===== 3. 任务中心 (admin) =====
+        { title: '任务中心', icon: 'el-icon-s-order', perm: 'task:*',
           children: [
             { path: '/tasks', label: '任务列表', icon: 'el-icon-s-order', perm: 'task:list' },
             { path: '/task-templates', label: '任务模板', icon: 'el-icon-document', perm: 'task:templates' },
             { path: '/growth-task', label: '成长任务管理', icon: 'el-icon-s-management', perm: 'task:list' },
           ]},
-        { title: '奖励管理', icon: 'el-icon-s-goods', perm: 'reward:*',
-          children: [
-            { path: '/rewards', label: '奖励列表', icon: 'el-icon-s-goods', perm: 'reward:list' },
-          ]},
 
-        // teacher + nutritionist 共享
-        { title: '我的家庭', icon: 'el-icon-s-home', perm: 'service:family',
+        // ===== 4. 审核中心 (admin) =====
+        { title: '审核中心', icon: 'el-icon-s-check', perm: 'audit',
           children: [
-            { path: '/my-families', label: '授权家庭', icon: 'el-icon-s-home', perm: 'service:family' },
+            { path: '/package-audit', label: '套餐审核', icon: 'el-icon-document-checked', perm: 'audit:package' },
+            { path: '/guide-audit', label: '规划师审核', icon: 'el-icon-document-checked', perm: 'audit:guide' },
+            { path: '/vendor-review', label: '服务商审核', icon: 'el-icon-document-checked', perm: 'audit:vendor' },
+            { path: '/withdraw-audit', label: '提现审核', icon: 'el-icon-document-checked', perm: 'audit:withdraw' },
           ]},
 
-        // teacher 专属
-        { path: '/growth-records', label: '成长记录', icon: 'el-icon-document', perm: 'growth:records' },
-        { path: '/growth-plans', label: '成长计划', icon: 'el-icon-document', perm: 'growth:plans' },
-        { title: '服务管理', icon: 'el-icon-s-home', perm: 'service:*',
-          children: [
-            { path: '/teacher-families', label: '我的家庭', icon: 'el-icon-s-home', perm: 'service:families' },
-            { path: '/teacher-team', label: '我的团队', icon: 'el-icon-s-custom', perm: 'service:team' },
-          ]},
-        { title: '业务管理', icon: 'el-icon-s-marketing', perm: 'biz:*',
+        // ===== 5. 商城营销 (admin) =====
+        { title: '商城营销', icon: 'el-icon-s-goods', perm: 'commerce',
           children: [
-            { path: '/teacher-packages', label: '套餐管理', icon: 'el-icon-s-marketing', perm: 'biz:packages' },
-            { path: '/teacher-orders', label: '订单佣金', icon: 'el-icon-s-order', perm: 'biz:orders' },
+            { path: '/product-manage', label: '商品管理', icon: 'el-icon-s-goods', perm: 'commerce:products' },
+            { path: '/order-manage', label: '订单管理', icon: 'el-icon-s-order', perm: 'commerce:orders' },
+            { path: '/product-profit-rate', label: '产品利润率', icon: 'el-icon-data-line', perm: 'commerce:profit' },
+            { path: '/coupon', label: '优惠券管理', icon: 'el-icon-ticket', perm: 'marketing:coupon' },
+            { path: '/promotion', label: '推广管理', icon: 'el-icon-s-marketing', perm: 'marketing:promotion' },
+            { path: '/danshop-category', label: 'DanShop分类', icon: 'el-icon-menu', perm: 'danshop:category' },
+            { path: '/danshop-profit-rule', label: 'DanShop分润', icon: 'el-icon-s-finance', perm: 'danshop:profit' },
+            { path: '/danshop-logistics', label: 'DanShop物流', icon: 'el-icon-truck', perm: 'danshop:logistics' },
           ]},
-        { title: '测评管理', icon: 'el-icon-edit', perm: 'assessment:*',
+
+        // ===== 6. 内容中心 (admin + article_manager + activity_manager) =====
+        { title: '内容中心', icon: 'el-icon-document', perm: 'content',
           children: [
-            { path: '/teacher-assessment', label: 'DAN测评', icon: 'el-icon-edit', perm: 'assessment:dan' },
-            { path: '/teacher-consult', label: '家长咨询', icon: 'el-icon-chat-dot-round', perm: 'assessment:consult' },
+            { path: '/article-categories', label: '文章分类', icon: 'el-icon-folder', perm: 'articles:categories' },
+            { path: '/article-manage', label: '文章管理', icon: 'el-icon-document', perm: 'articles:manage' },
+            { path: '/activities', label: '活动列表', icon: 'el-icon-date', perm: 'activity:list' },
+            { path: '/activity-review', label: '活动审核', icon: 'el-icon-document-checked', perm: 'activity:review' },
           ]},
-        { path: '/teacher-messages', label: '消息中心', icon: 'el-icon-chat-dot-round', perm: 'messages' },
 
-        // nutritionist 专属
-        { title: '健康档案', icon: 'el-icon-document', perm: 'health:*',
+        // ===== 7. 健康饮食 (admin + nutritionist) =====
+        { title: '健康饮食', icon: 'el-icon-first-aid-kit', perm: 'health',
           children: [
             { path: '/health-reports', label: '健康报告', icon: 'el-icon-document', perm: 'health:reports' },
             { path: '/health-indicators', label: '健康指标', icon: 'el-icon-data-line', perm: 'health:indicators' },
             { path: '/health-checkins', label: '健康打卡', icon: 'el-icon-s-order', perm: 'health:checkins' },
             { path: '/nutrition-mappings', label: '营养素映射', icon: 'el-icon-connection', perm: 'health:mappings' },
+            { path: '/energy-sandbox', label: '五维能量', icon: 'el-icon-data-line', perm: 'energy' },
+            { path: '/foods', label: '食材管理', icon: 'el-icon-apple', perm: 'diet:foods' },
+            { path: '/recipes', label: '食谱管理', icon: 'el-icon-dish', perm: 'diet:recipes' },
+            { path: '/seasonal-foods', label: '应季食材', icon: 'el-icon-sunny', perm: 'diet:seasonal' },
           ]},
-        { path: '/energy-sandbox', label: '五维能量', icon: 'el-icon-data-line', perm: 'energy' },
 
-        // article_manager 专属
-        { title: '文章管理', icon: 'el-icon-document', perm: 'articles:*',
+        // ===== 8. 规划师工作台 (teacher) =====
+        { path: '/teacher-dashboard', label: '工作台', icon: 'el-icon-s-home', perm: 'service:*' },
+        { title: '家庭服务', icon: 'el-icon-s-custom', perm: 'service:*',
           children: [
-            { path: '/article-categories', label: '文章分类', icon: 'el-icon-document', perm: 'articles:categories' },
-            { path: '/article-manage', label: '文章管理', icon: 'el-icon-document', perm: 'articles:manage' },
+            { path: '/my-families', label: '我的家庭', icon: 'el-icon-s-custom', perm: 'service:family' },
+            { path: '/teacher-team', label: '我的团队', icon: 'el-icon-s-custom', perm: 'service:team' },
           ]},
-
-        // activity_manager 专属
-        { title: '活动管理', icon: 'el-icon-s-home', perm: 'activity:*',
+        { title: '业务管理', icon: 'el-icon-s-marketing', perm: 'biz:*',
           children: [
-            { path: '/activities', label: '活动列表', icon: 'el-icon-s-home', perm: 'activity:list' },
-            { path: '/activity-review', label: '活动审核', icon: 'el-icon-s-check', perm: 'activity:review' },
+            { path: '/teacher-packages', label: '套餐管理', icon: 'el-icon-s-goods', perm: 'biz:packages' },
+            { path: '/teacher-orders', label: '订单佣金', icon: 'el-icon-s-order', perm: 'biz:orders' },
           ]},
-
-        // diet 管理 (admin)
-        { title: '饮食管理', icon: 'el-icon-s-management', perm: 'diet:*',
+        { title: '测评咨询', icon: 'el-icon-edit', perm: 'assessment:*',
           children: [
-            { path: '/foods', label: '食材管理', icon: 'el-icon-s-management', perm: 'diet:foods' },
-            { path: '/recipes', label: '食谱管理', icon: 'el-icon-s-management', perm: 'diet:recipes' },
-            { path: '/seasonal-foods', label: '应季食材', icon: 'el-icon-s-management', perm: 'diet:seasonal' },
+            { path: '/teacher-assessment', label: 'DAN测评', icon: 'el-icon-edit', perm: 'assessment:dan' },
+            { path: '/teacher-consult', label: '家长咨询', icon: 'el-icon-chat-dot-round', perm: 'assessment:consult' },
           ]},
+        { path: '/growth-records', label: '成长记录', icon: 'el-icon-document', perm: 'growth:records' },
+        { path: '/growth-plans', label: '成长计划', icon: 'el-icon-document', perm: 'growth:plans' },
+        { path: '/teacher-messages', label: '消息中心', icon: 'el-icon-chat-dot-round', perm: 'messages' },
 
-        // system 管理 (仅 admin)
-        { title: '系统管理', icon: 'el-icon-s-tools', perm: 'system:*',
+        // ===== 9. 系统配置 (admin) =====
+        { title: '系统配置', icon: 'el-icon-s-tools', perm: 'system:*',
           children: [
+            { path: '/sys-config', label: '系统配置', icon: 'el-icon-s-tools', perm: 'system:config' },
             { path: '/users', label: '用户管理', icon: 'el-icon-user', perm: 'system:users' },
-            { path: '/package-audit', label: '套餐审核', icon: 'el-icon-s-check', perm: 'system:audit' },
-            { path: '/guide-audit', label: '规划师审核', icon: 'el-icon-s-check', perm: 'system:audit' },
-            { path: '/vendor-review', label: '服务商审核', icon: 'el-icon-s-check', perm: 'system:audit' },
             { path: '/operation-logs', label: '操作日志', icon: 'el-icon-s-order', perm: 'system:logs' },
-            { path: '/product-manage', label: '商品管理', icon: 'el-icon-s-goods', perm: 'system:products' },
-            { path: '/order-manage', label: '订单管理', icon: 'el-icon-s-order', perm: 'system:orders' },
-            { path: '/danshop-category', label: 'DanShop分类', icon: 'el-icon-s-goods', perm: 'system:danshop' },
-            { path: '/danshop-profit-rule', label: '分润规则', icon: 'el-icon-s-marketing', perm: 'system:danshop' },
-            { path: '/danshop-logistics', label: '物流管理', icon: 'el-icon-s-order', perm: 'system:danshop' },
-            { path: '/sys-config', label: '系统配置', icon: 'el-icon-s-tools', perm: 'system:config' },
-            { path: '/energy-sandbox', label: '五维能量', icon: 'el-icon-data-line', perm: 'system:energy' },
+            { path: '/dimension-config', label: '维度配置', icon: 'el-icon-data-line', perm: 'system:config' },
+            { path: '/knowledge-base', label: '知识库管理', icon: 'el-icon-reading', perm: 'system:config' },
+            { path: '/relationship-types', label: '关系类型', icon: 'el-icon-share', perm: 'system:config' },
             { path: '/education-systems', label: '教育体系', icon: 'el-icon-s-management', perm: 'system:education' },
+            { path: '/service-types', label: '服务类型', icon: 'el-icon-s-management', perm: 'system:config' },
+            { path: '/service-contents', label: '服务内容', icon: 'el-icon-s-management', perm: 'system:config' },
+            { path: '/package-templates', label: '套餐模板', icon: 'el-icon-s-management', perm: 'system:config' },
+            { path: '/assessment-admin', label: '测评管理', icon: 'el-icon-edit', perm: 'assessment:dan' },
+            { path: '/health-norm-config', label: '健康常模', icon: 'el-icon-data-line', perm: 'system:config' },
+            { path: '/health-data-source', label: '健康数据源', icon: 'el-icon-data-line', perm: 'system:config' },
             { path: '/zodiac-configs', label: '星座配置', icon: 'el-icon-s-management', perm: 'system:config' },
             { path: '/bazi-configs', label: '八字配置', icon: 'el-icon-s-management', perm: 'system:config' },
             { path: '/blood-type-configs', label: '血型配置', icon: 'el-icon-s-management', perm: 'system:config' },
-            { path: '/promotion', label: '推广管理', icon: 'el-icon-s-marketing', perm: 'system:promotion' },
-            { path: '/coupon', label: '优惠券管理', icon: 'el-icon-s-management', perm: 'system:coupon' },
-            { path: '/relationship-types', label: '关系类型', icon: 'el-icon-s-management', perm: 'system:config' },
-            { path: '/health-norm-config', label: '健康维度常模', icon: 'el-icon-s-management', perm: 'system:config' },
-            { path: '/health-data-source', label: '健康数据源', icon: 'el-icon-s-management', perm: 'system:config' },
           ]},
       ],
       profileDialogVisible: false,