# System Permission Org View Authorization Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Add `脑图模式 / 组织树模式` to system permission organization management, move personnel authorization/account creation onto org personnel nodes, and simplify the maintenance tab into role-only maintenance.
**Architecture:** Keep the existing backend permission APIs and refactor the frontend around two organization views that share one data source. `SystemPermissionView.vue` owns data loading, drawers, authorization submission, and role maintenance; a new focused `OrgPermissionTree.vue` renders the Ruoyi-like left-tree/right-personnel-list organization tree mode.
**Tech Stack:** Vue 3 `
```
- [ ] **Step 3: Add scoped styles**
Add this style block:
```vue
```
- [ ] **Step 4: Run static test and verify current next failure**
Run:
```bash
node frontend/scripts/test-system-permission-management-ui.mjs
```
Expected result:
```text
AssertionError
```
The component-specific assertions should pass; failures should now point to `SystemPermissionView.vue` still using the old page structure.
---
### Task 3: Refactor SystemPermissionView Page Structure
**Files:**
- Modify: `frontend/src/views/SystemPermissionView.vue`
- [ ] **Step 1: Import the new component**
Add the import beside `OrgMindMap`:
```js
import OrgPermissionTree from "../components/OrgPermissionTree.vue";
```
- [ ] **Step 2: Replace top copy and tabs**
Change the hero copy to:
```vue
组织架构负责公司层级、人员授权和系统账号;角色维护负责菜单权限和业务身份。
```
Change the top tab labels to:
```vue
组织架构
角色维护
```
Keep `permissionMainTab` values as `"org"` and `"maintenance"` to minimize routing/state churn.
- [ ] **Step 3: Add organization mode switch**
Add this state near `permissionMainTab`:
```js
const orgViewMode = ref("mindmap");
```
Inside the organization section header, add this switch before the status pill:
```vue
```
- [ ] **Step 4: Render mind map or tree mode**
Wrap the existing `OrgMindMap` with:
```vue
```
Add this computed near `orgNodeCount`:
```js
const selectedOrgNodeId = computed(() => selectedNode.value?.node_id || orgNodes.value[0]?.node_id || "");
```
- [ ] **Step 5: Hide mind-map-only toolbar in tree mode**
Change the toolbar container to:
```vue
```
Keep `放大`、`缩小`、`一屏展示`、`刷新` unchanged.
- [ ] **Step 6: Replace maintenance page with role-only page**
Remove the nested `system-permission-sub-tabs` block and remove the `maintenanceSubTab === 'users'` table panel.
The maintenance section header should become:
```vue
角色权限
角色维护
角色用于配置菜单权限和业务身份;人员授权请回到组织架构中对人员节点操作。
```
Remove:
```js
const maintenanceSubTab = ref("users");
const userRowsForTable = computed(() => users.value);
const {
page: userPage,
pageSize: userPageSize,
rows: paginatedUsers
} = usePagination(userRowsForTable);
```
Keep:
```js
const users = ref([]);
```
because authorization needs it to detect existing system accounts.
- [ ] **Step 7: Run static test and verify authorization assertions still fail**
Run:
```bash
node frontend/scripts/test-system-permission-management-ui.mjs
```
Expected result:
```text
AssertionError
```
The remaining failure should be around missing authorization drawer functions/state.
---
### Task 4: Add Personnel Authorization Drawer and Logic
**Files:**
- Modify: `frontend/src/views/SystemPermissionView.vue`
- [ ] **Step 1: Add authorization state**
Add these declarations near existing drawer state:
```js
const showAuthorizeDrawer = ref(false);
const authorizingEmployee = ref(null);
const authorizeForm = reactive({
role_ids: [],
password: "",
status: "ACTIVE"
});
```
Add these computed values near `selectedEmployee`:
```js
const authorizingSystemUser = computed(() => {
const employeeId = authorizingEmployee.value?.employee_id;
if (!employeeId) {
return null;
}
return users.value.find((user) => String(user.employee_id) === String(employeeId)) || null;
});
const authorizingEmployeePhone = computed(() =>
authorizingEmployee.value?.mobile || authorizingSystemUser.value?.mobile || authorizingSystemUser.value?.username || ""
);
```
- [ ] **Step 2: Add authorization drawer template**
Insert this drawer before the role drawer:
```vue
```
- [ ] **Step 3: Add open and submit functions**
Add these functions near `removeOrgEmployee`:
```js
function openAuthorizeDrawer(employee) {
const existingUser = users.value.find((user) => String(user.employee_id) === String(employee?.employee_id));
authorizingEmployee.value = employee;
authorizeForm.role_ids = existingUser?.role_ids?.length
? existingUser.role_ids.map(String)
: (employee?.role_ids || []).map(String);
authorizeForm.password = "";
authorizeForm.status = existingUser?.status || "ACTIVE";
showAuthorizeDrawer.value = true;
}
async function submitAuthorizeUser() {
if (!authorizingEmployee.value?.employee_id) {
notifyError("请选择有效人员");
return;
}
if (!authorizingEmployeePhone.value) {
notifyError("该人员没有电话号码,不能作为账号");
return;
}
if (!authorizeForm.role_ids.length) {
notifyError("请选择角色");
return;
}
if (!authorizingSystemUser.value && (!authorizeForm.password || authorizeForm.password.length < 6)) {
notifyError("密码最少6位");
return;
}
try {
if (authorizingSystemUser.value) {
await putResource(`/system-permissions/users/${authorizingSystemUser.value.user_id}/roles`, {
role_ids: authorizeForm.role_ids.map(Number)
});
if (authorizingSystemUser.value.status !== authorizeForm.status) {
await putResource(`/system-permissions/users/${authorizingSystemUser.value.user_id}/status`, {
status: authorizeForm.status
});
}
notifySuccess("人员角色授权已更新");
} else {
await postResource("/system-permissions/users", {
employee_id: Number(authorizingEmployee.value.employee_id),
role_ids: authorizeForm.role_ids.map(Number),
password: authorizeForm.password,
status: authorizeForm.status
});
notifySuccess("系统账号已创建并授权");
}
showAuthorizeDrawer.value = false;
authorizingEmployee.value = null;
await loadAll();
} catch (error) {
notifyError(error.message || "人员授权失败");
}
}
```
- [ ] **Step 4: Update employee context menu actions**
Change `nodeActions(node)` employee branch to:
```js
if (node.employee_id) {
return [
{ key: "authorizeEmployee", label: "授权" },
{ key: "removeEmployee", label: "移除" }
];
}
```
Add this branch to `runNodeAction`:
```js
} else if (actionKey === "authorizeEmployee") {
openAuthorizeDrawer(node);
```
- [ ] **Step 5: Remove standalone user drawer code**
Delete the old drawer controlled by:
```js
showUserDrawer
createUserForm
openUserDrawer
submitCreateUser
syncSelectedEmployeePhone
resetPassword
toggleUserStatus
formatRoleNames(user)
```
Do not delete `users`, `loadAll()` user loading, or `employeeOptions`.
- [ ] **Step 6: Run static test**
Run:
```bash
node frontend/scripts/test-system-permission-management-ui.mjs
```
Expected result:
```text
all assertions pass
```
If the script prints no output and exits `0`, treat it as pass.
---
### Task 5: Add Styling for Switch, Tree Layout, and Authorization Summary
**Files:**
- Modify: `frontend/src/views/SystemPermissionView.vue`
- [ ] **Step 1: Add view switch styles**
Add this CSS near `.mindmap-toolbar`:
```css
.org-view-switch {
display: inline-flex;
gap: 6px;
padding: 6px;
border: 1px solid rgba(37, 99, 235, 0.12);
border-radius: 999px;
background: rgba(239, 246, 255, 0.92);
}
.org-view-switch button {
border: 0;
border-radius: 999px;
padding: 8px 12px;
background: transparent;
color: #475569;
font-size: 13px;
font-weight: 800;
cursor: pointer;
}
.org-view-switch button.active {
background: #ffffff;
color: #1d4ed8;
box-shadow: 0 10px 20px rgba(37, 99, 235, 0.14);
}
```
- [ ] **Step 2: Add authorization summary styles**
Add this CSS near drawer styles:
```css
.authorize-summary {
display: grid;
gap: 8px;
border: 1px solid rgba(37, 99, 235, 0.12);
border-radius: 16px;
padding: 12px;
background: #f8fbff;
color: #475569;
font-size: 13px;
font-weight: 700;
}
```
- [ ] **Step 3: Remove obsolete sub-tab styles**
Delete CSS blocks for:
```css
.system-permission-sub-tabs
.system-permission-sub-tabs button
.system-permission-sub-tabs button.active
```
Also remove the mobile media override for `.system-permission-sub-tabs`.
- [ ] **Step 4: Run frontend build**
Run:
```bash
cd frontend && npm run build
```
Expected result:
```text
✓ built
```
Chunk-size warnings are acceptable if the build exits `0`.
---
### Task 6: Backend Regression Verification
**Files:**
- Test only: `backend/tests/test_system_permission_management.py`
- [ ] **Step 1: Run backend permission tests**
Run:
```bash
cd backend && python -m pytest tests/test_system_permission_management.py -q
```
Expected result:
```text
passed
```
- [ ] **Step 2: If tests fail due to local environment only, capture the exact blocker**
Acceptable environment blockers include missing Python packages or unavailable virtual environment. Record the exact error text in the execution summary. Do not change backend code unless a real regression is identified.
---
### Task 7: Browser Verification
**Files:**
- No file changes.
- [ ] **Step 1: Start or reuse frontend dev server**
Run:
```bash
cd frontend && npm run dev -- --host 127.0.0.1 --port 5173
```
Expected result:
```text
Local: http://127.0.0.1:5173/
```
- [ ] **Step 2: Verify page structure in browser**
Open:
```text
http://127.0.0.1:5173/system-permissions
```
Verify:
- Top tabs are `组织架构` and `角色维护`.
- `组织架构` has `脑图模式 / 组织树模式`.
- `脑图模式` still shows mind-map toolbar.
- `组织树模式` shows left organization tree and right personnel table.
- `角色维护` does not show standalone system personnel table.
- [ ] **Step 3: Verify personnel authorization interaction**
In browser:
- In mind-map mode, expand a node with personnel, right-click a personnel leaf, verify menu shows `授权` and `移除`.
- Click `授权`, verify drawer displays phone/account, organization, account status, role selector, and password only when no account exists.
- In tree mode, select an org node with personnel, verify row actions show `授权` and `移除`.
Expected result:
```text
Both modes can reach the same authorization drawer.
```
---
## Self-Review
- Spec coverage:
- Organization view switch: Task 3.
- Tree mode UI: Task 2 and Task 7.
- Mind-map employee right-click `授权/移除`: Task 4.
- Role-only maintenance tab: Task 3.
- Account creation and role update from personnel node: Task 4.
- Tests and verification: Tasks 1, 5, 6, 7.
- Placeholder scan:
- No `TBD`, `TODO`, or vague implementation-only placeholders remain.
- Type consistency:
- `orgViewMode`, `showAuthorizeDrawer`, `authorizingEmployee`, `authorizeForm`, and `selectedOrgNodeId` are introduced before use.
- `OrgPermissionTree` emits `select-node`, `node-contextmenu`, `add-employee`, `authorize-employee`, `remove-employee`; `SystemPermissionView.vue` listens to the same names.
- Existing backend endpoint names match `backend/app/api/routes/system_permissions.py`.