فهرست منبع

feat(机构管理): 机构管理员管理能力落地

iwt 3 هفته پیش
والد
کامیت
726cc149e0

+ 32 - 0
cfc-web/src/router/index.js

@@ -3,6 +3,7 @@ import VueRouter from 'vue-router'
 import Layout from '@/views/Layout.vue'
 import axios from 'axios'
 import { getEffectivePermissions, hasPermission, getRoleHomePage } from '@/utils/permissions'
+import { orgMy } from '@/api/org'
 
 Vue.use(VueRouter)
 
@@ -1016,6 +1017,37 @@ router.beforeEach(async (to, from, next) => {
     }
   }
 
+  // 3.6 组织管理员(org_admin 且不含平台角色)路由分流:规范第五节
+  const rolesStr2 = localStorage.getItem('roles')
+  if (rolesStr2) {
+    const roleList2 = JSON.parse(rolesStr2)
+    const isOrgAdminOnly = roleList2.indexOf('org_admin') >= 0
+      && roleList2.indexOf('admin') < 0 && roleList2.indexOf('operator') < 0 && roleList2.indexOf('finance') < 0
+    if (isOrgAdminOnly) {
+      // 访问首页/列表页 → 重定向到自身组织大屏
+      if (to.path === '/dashboard' || to.path === '/org') {
+        let cachedOrgId = localStorage.getItem('orgId')
+        if (cachedOrgId) {
+          return next('/org/' + cachedOrgId + '/dashboard')
+        }
+        try {
+          const orgRes = await orgMy()
+          if (orgRes && orgRes.data && orgRes.data.id) {
+            localStorage.setItem('orgId', orgRes.data.id)
+            return next('/org/' + orgRes.data.id + '/dashboard')
+          }
+          return next({ path: '/login', replace: true })
+        } catch (e2) {
+          return next({ path: '/login', replace: true })
+        }
+      }
+      // 仅允许 org 相关路由;其他管理端路由拦截
+      if (to.path !== '/403' && to.path !== '/login' && !to.path.startsWith('/org/')) {
+        return next({ path: '/403', replace: true })
+      }
+    }
+  }
+
   // 4. 权限检查:如果路由有 perm 要求,检查用户权限
   const requiredPerm = to.meta && to.meta.perm
   if (requiredPerm) {

+ 4 - 4
cfc-web/src/utils/permissions.js

@@ -9,10 +9,10 @@
 const ROLE_PERMISSIONS = {
   // 超管:全部权限
   admin: ['*'],
-  // 运营:审核全量、活动全量、任务全量、家庭/商城/知识/测评只读
-  operator: ['dashboard', 'audit:*', 'activity:*', 'task:*', 'assessment:read', 'family:read', 'commerce:read', 'articles:read', 'knowledge:read', 'plan:*'],
-  // 财务:财务/退款/提现、订单只读、CF值、商城营销、业务管理
-  finance: ['dashboard', 'finance:*', 'audit:withdraw', 'audit:refund', 'commerce:read', 'commerce:orders:read', 'biz:*', 'cf-value:*'],
+  // 运营:审核全量、活动全量、任务全量、家庭/商城/知识/测评只读、组织管理
+  operator: ['dashboard', 'audit:*', 'activity:*', 'task:*', 'assessment:read', 'family:read', 'commerce:read', 'articles:read', 'knowledge:read', 'plan:*', 'org:*'],
+  // 财务:财务/退款/提现、订单只读、CF值、商城营销、业务管理、组织管理
+  finance: ['dashboard', 'finance:*', 'audit:withdraw', 'audit:refund', 'commerce:read', 'commerce:orders:read', 'biz:*', 'cf-value:*', 'org:*'],
   // 管家:家庭客服 + 规划师 + 营养师权限并集(getEffectivePermissions 中自动并入 teacher/nutritionist)
   butler: ['dashboard', 'family:*', 'task:*', 'reward:*', 'service:*', 'growth:*', 'biz:*',
            'assessment:dan', 'health:*', 'diet:*', 'report:audit', 'plan:*'],

+ 2 - 0
cfc-web/src/views/Layout.vue

@@ -356,6 +356,8 @@ export default {
               children: [
                 { path: '/virtual-teams', label: '虚拟团队', icon: 'el-icon-s-custom', perm: 'system:base' },
               ]},
+            // --- 组织管理(平台运营创建组织;org_admin 由路由守卫分流到自身组织大屏) ---
+            { path: '/org', label: '组织管理', icon: 'el-icon-office-building', perm: 'system:org' },
           ]},
       ],
       // 需要保持列表状态的页面组件 name(进入编辑/详情返回时保留筛选、页码、勾选)。

+ 29 - 1
cfc-web/src/views/Login.vue

@@ -218,6 +218,7 @@
 <script>
 import { adminLogin, getAccountRoles } from '@/api/auth'
 import { getRoleHomePage } from '@/utils/permissions'
+import { orgMy } from '@/api/org'
 import SliderCaptcha from '@/components/SliderCaptcha'
 
 export default {
@@ -342,8 +343,35 @@ export default {
             console.log('登录成功')
           }
         await this.$nextTick()
+        // A-1 组织管理员(org_admin 且不含平台角色)登录后直跳自身组织的大屏
+        const rolesArr = res.data.roles || [role]
+        if (rolesArr.indexOf('org_admin') >= 0 && rolesArr.indexOf('admin') < 0
+            && rolesArr.indexOf('operator') < 0 && rolesArr.indexOf('finance') < 0) {
+          try {
+            const orgRes = await orgMy()
+            if (orgRes && orgRes.data && orgRes.data.id) {
+              this.$router.replace({ path: '/org/' + orgRes.data.id + '/dashboard' })
+            } else if (orgRes && this.$message) {
+              this.$message.error(orgRes.message || '组织已停用或未关联,无法进入管理端')
+              localStorage.removeItem('token')
+              localStorage.removeItem('roles')
+              localStorage.removeItem('role')
+              this.resetCaptcha()
+            }
+          } catch (eOrg) {
+            // 组织已停用/未关联:my-org 返回错误 → 清理登录态回到登录页(错误提示由 request 拦截器弹出)
+            localStorage.removeItem('token')
+            localStorage.removeItem('roles')
+            localStorage.removeItem('role')
+            if (this.$message) {
+              this.$message.error((eOrg && eOrg.message) ? eOrg.message : '组织已停用,无法进入管理端')
+            }
+            this.resetCaptcha()
+          }
+          return
+        }
         // B-6 按所选登录身份跳转:入驻角色进个人工作台,平台角色进首页
-        const redirectRole = getRoleHomePage([role])
+        const redirectRole = getRoleHomePage(rolesArr)
         this.$router.replace({ path: redirectRole })
         } catch (e) {
           const msg = e && e.message ? e.message : '登录失败,请检查账号密码'

+ 7 - 1
cfc-web/src/views/admin/org/Dashboard.vue

@@ -118,12 +118,18 @@ export default {
   },
   methods: {
     async loadMyOrg() {
+      // 平台角色路由 /org/:id/dashboard 直接带 orgId;org_admin 走 my-org 获取自身组织
+      const routeOrgId = this.$route.params.id
+      if (routeOrgId) {
+        this.orgId = routeOrgId
+        this.loadStats()
+        return
+      }
       try {
         const res = await orgMy()
         if (res.data && res.data.id) {
           this.orgId = res.data.id
           this.orgName = res.data.name
-          this.$refs && this.$refs.header && (this.$refs.header.title = '组织大屏 — ' + res.data.name)
           this.loadStats()
         } else if (res.data && res.data.status === 'disabled') {
           this.$message.error('组织已停用,无法查看统计大屏')