refactor(web): 侧栏「用户与组织」更名为「用户管理」

背景:
- 管理中心侧栏菜单名为「用户与组织」,与「角色管理」「部门管理」的命名方式不一致;
- 页面标题、面包屑仍沿用旧名,三处展示不统一;
- A1 文档与代码注释中该功能域本来即称「用户管理」。

改动:
- nav-config:菜单 label 改为「用户管理」,description 改为「成员账号、部门归属与登录状态」;
- breadcrumbs:用户新建 / 详情子路由的面包屑 2 处同步;
- UsersPage:页面 h1 同步;
- nav-config.spec / breadcrumbs.spec / e2e a1-identity 的标签与 heading 断言同步;
- 11-前端路由与目录规范、AppLayout 注释同步;PRD P-01 功能名保持「用户与组织管理」不变。

影响面:
- 仅前端文案与对应断言;路由、权限点、接口、数据均不变。

回滚方式:
- 回滚本提交即恢复原「用户与组织」文案与断言。

验证证据:
- pnpm format:check / lint / typecheck 通过;
- pnpm test:web 120/120 通过;
- Chrome 1440×900 实机:侧栏、面包屑、页面标题均显示「用户管理」。
This commit is contained in:
Stev_Wang committed 2026-11-03 15:54:13 +08:00
1 parent 3e384febf3
commit f849e443d7
8 files changed
+14 -14

No files matched your search

+1 -1
View File
@@ -11,7 +11,7 @@ import { PageBreadcrumbs } from './PageBreadcrumbs';
import { SideNav } from './SideNav'; import { SideNav } from './SideNav';
import { TopBar } from './TopBar'; import { TopBar } from './TopBar';
/** 用户与组织、部门管理为「满高主从布局」,由页面自己控制内部滚动 */ /** 用户管理、部门管理为「满高主从布局」,由页面自己控制内部滚动 */
function isFlushRoute(pathname: string): boolean { function isFlushRoute(pathname: string): boolean {
return ( return (
pathname === ROUTES.system.users || pathname === ROUTES.system.users ||
+1 -1
View File
@@ -32,7 +32,7 @@ describe('面包屑子路由补全', () => {
expect(getUserSectionTrail('/system/users/new')?.map((entry) => entry.label)).toEqual([ expect(getUserSectionTrail('/system/users/new')?.map((entry) => entry.label)).toEqual([
'工作台', '工作台',
'管理中心', '管理中心',
'用户与组织', '用户管理',
'新建用户', '新建用户',
]); ]);
expect(getUserSectionTrail('/system/users/01HZZZZZZZZZZZZZZZZZZZZZZZ')).not.toBeNull(); expect(getUserSectionTrail('/system/users/01HZZZZZZZZZZZZZZZZZZZZZZZ')).not.toBeNull();
+3 -3
View File
@@ -25,14 +25,14 @@ export function getRoleSectionTrail(pathname: string): BreadcrumbEntry[] | null
/** /**
* 用户模块下的子路由(新建 / 详情)不在 nav-config 的菜单项里, * 用户模块下的子路由(新建 / 详情)不在 nav-config 的菜单项里,
* 这里补齐面包屑:工作台 / 管理中心 / 用户与组织 / 当前页。 * 这里补齐面包屑:工作台 / 管理中心 / 用户管理 / 当前页。
*/ */
export function getUserSectionTrail(pathname: string): BreadcrumbEntry[] | null { export function getUserSectionTrail(pathname: string): BreadcrumbEntry[] | null {
if (pathname === ROUTES.system.userNew) { if (pathname === ROUTES.system.userNew) {
return [ return [
{ key: 'home', label: '工作台', path: ROUTES.home }, { key: 'home', label: '工作台', path: ROUTES.home },
{ key: 'system', label: '管理中心' }, { key: 'system', label: '管理中心' },
{ key: 'users', label: '用户与组织', path: ROUTES.system.users }, { key: 'users', label: '用户管理', path: ROUTES.system.users },
{ key: 'user-new', label: '新建用户' }, { key: 'user-new', label: '新建用户' },
]; ];
} }
@@ -40,7 +40,7 @@ export function getUserSectionTrail(pathname: string): BreadcrumbEntry[] | null
return [ return [
{ key: 'home', label: '工作台', path: ROUTES.home }, { key: 'home', label: '工作台', path: ROUTES.home },
{ key: 'system', label: '管理中心' }, { key: 'system', label: '管理中心' },
{ key: 'users', label: '用户与组织', path: ROUTES.system.users }, { key: 'users', label: '用户管理', path: ROUTES.system.users },
{ key: 'user-detail', label: '成员详情' }, { key: 'user-detail', label: '成员详情' },
]; ];
} }
+3 -3
View File
@@ -26,8 +26,8 @@ describe('导航配置', () => {
expect(modules.map((module) => module.key)).toEqual(['dashboard']); expect(modules.map((module) => module.key)).toEqual(['dashboard']);
}); });
it('子路由(/system/users/new、/system/users/:id)也归属用户与组织', () => { it('子路由(/system/users/new、/system/users/:id)也归属用户管理', () => {
expect(findActiveNav(NAV_MODULES, '/system/users/new')?.item?.label).toBe('用户与组织'); expect(findActiveNav(NAV_MODULES, '/system/users/new')?.item?.label).toBe('用户管理');
expect(findActiveNav(NAV_MODULES, '/system/users/01HZZZZZZZZZZZZZZZZZZZZZZZ')?.module.key).toBe( expect(findActiveNav(NAV_MODULES, '/system/users/01HZZZZZZZZZZZZZZZZZZZZZZZ')?.module.key).toBe(
'system', 'system',
); );
@@ -63,7 +63,7 @@ describe('导航配置', () => {
it('面包屑从导航配置派生', () => { it('面包屑从导航配置派生', () => {
expect(getBreadcrumbs(NAV_MODULES, '/')).toEqual([{ key: 'home', label: '工作台', path: '/' }]); expect(getBreadcrumbs(NAV_MODULES, '/')).toEqual([{ key: 'home', label: '工作台', path: '/' }]);
const breadcrumbs = getBreadcrumbs(NAV_MODULES, '/system/users'); const breadcrumbs = getBreadcrumbs(NAV_MODULES, '/system/users');
expect(breadcrumbs.map((entry) => entry.label)).toEqual(['工作台', '管理中心', '用户与组织']); expect(breadcrumbs.map((entry) => entry.label)).toEqual(['工作台', '管理中心', '用户管理']);
const deptBreadcrumbs = getBreadcrumbs(NAV_MODULES, '/system/departments'); const deptBreadcrumbs = getBreadcrumbs(NAV_MODULES, '/system/departments');
expect(deptBreadcrumbs.map((entry) => entry.label)).toEqual(['工作台', '管理中心', '部门管理']); expect(deptBreadcrumbs.map((entry) => entry.label)).toEqual(['工作台', '管理中心', '部门管理']);
}); });
+2 -2
View File
@@ -249,11 +249,11 @@ export const NAV_MODULES: readonly NavModule[] = [
items: [ items: [
{ {
key: 'users', key: 'users',
label: '用户与组织', label: '用户管理',
path: '/system/users', path: '/system/users',
icon: IconUser, icon: IconUser,
permission: Permission.USER_VIEW, permission: Permission.USER_VIEW,
description: '账号、组织与登录状态', description: '成员账号、部门归属与登录状态',
}, },
{ {
key: 'departments', key: 'departments',
@@ -31,7 +31,7 @@ function UsersHeader(): ReactNode {
return ( return (
<header className="lx-users__header"> <header className="lx-users__header">
<div> <div>
<h1>用户与组织</h1> <h1>用户管理</h1>
<p>管理成员账号、角色与客户归属</p> <p>管理成员账号、角色与客户归属</p>
</div> </div>
<Can permission={Permission.USER_MANAGE}> <Can permission={Permission.USER_MANAGE}>
@@ -63,7 +63,7 @@ apps/web/src/pages/
├─ assets/ # 资产(对应 /assets) ├─ assets/ # 资产(对应 /assets)
├─ delivery/ # 交付(对应 /delivery) ├─ delivery/ # 交付(对应 /delivery)
├─ system/ # 管理中心(对应 /system) ├─ system/ # 管理中心(对应 /system)
│ └─ users/ # 用户与组织(对应 /system/users) │ └─ users/ # 用户管理(对应 /system/users)
│ ├─ UsersPage.tsx │ ├─ UsersPage.tsx
│ ├─ UserNewPage.tsx │ ├─ UserNewPage.tsx
│ ├─ UserListPanel.tsx │ ├─ UserListPanel.tsx
+2 -2
View File
@@ -408,7 +408,7 @@ async function submitLogin(page: Page): Promise<void> {
async function expectUsersPage(page: Page): Promise<void> { async function expectUsersPage(page: Page): Promise<void> {
await expect(page.getByTestId('app-shell')).toBeVisible(); await expect(page.getByTestId('app-shell')).toBeVisible();
await expect(page.getByRole('heading', { name: '用户与组织' })).toBeVisible(); await expect(page.getByRole('heading', { name: '用户管理' })).toBeVisible();
} }
async function readSession(page: Page): Promise<SessionSnapshot> { async function readSession(page: Page): Promise<SessionSnapshot> {
@@ -641,7 +641,7 @@ test('④ 停用后旧会话被拒(40301),再登录提示「账号已停
await page.goto('/system/users'); await page.goto('/system/users');
await expect(page).toHaveURL(/\/login/); await expect(page).toHaveURL(/\/login/);
await expect(page.locator('.lx-login__notice')).toContainText('账号已被停用'); await expect(page.locator('.lx-login__notice')).toContainText('账号已被停用');
await expect(page.getByRole('heading', { name: '用户与组织' })).toHaveCount(0); await expect(page.getByRole('heading', { name: '用户管理' })).toHaveCount(0);
await expect await expect
.poll( .poll(
async () => async () =>