feat(小宝预警): 增加权限与数据键

This commit is contained in:
Script Generator
2026-06-29 17:13:54 +08:00
parent 5a41904ba6
commit 46a002f817
6 changed files with 79 additions and 5 deletions

View File

@@ -9,6 +9,8 @@ export const APP_DATA_KEYS = [
'task-categories',
'task-worklogs',
'work-activities',
'xiaobao-risk-insights',
'xiaobao-risk-snapshots',
'overtime',
] as const;

View File

@@ -43,6 +43,15 @@ export const PERMISSION_GROUPS: PermissionGroup[] = [
{ action: 'export', label: '导出', permission: 'overtime:export' },
],
},
{
module: 'xiaobao.warning',
moduleLabel: '小宝预警',
category: 'main',
actions: [
{ action: 'view', label: '查看', permission: 'xiaobao.warning:view' },
{ action: 'manage', label: '管理', permission: 'xiaobao.warning:manage' },
],
},
{ module: 'member', moduleLabel: '成员', category: 'main', actions: std4('member') },
{ module: 'role', moduleLabel: '角色', category: 'main', actions: std4('role') },
{ module: 'version.req', moduleLabel: '需求 Tab', category: 'version_tab', actions: stdTab('version.req') },
@@ -67,6 +76,7 @@ export const DEFAULT_ROLE_PERMISSIONS: Record<string, string[]> = {
...std4('requirement').map((a) => a.permission),
'version.req:view', 'version.req:manage',
'version.product_plan:view', 'version.product_plan:manage',
'xiaobao.warning:view', 'xiaobao.warning:manage',
'overtime:view', 'member:view', 'role:view',
'version.research:view', 'version.ui_plan:view', 'version.devtask:view',
'version.testcase:view', 'version.bug:view',
@@ -76,6 +86,7 @@ export const DEFAULT_ROLE_PERMISSIONS: Record<string, string[]> = {
'version.devtask:view', 'version.devtask:manage',
'version.bug:view', 'version.bug:edit',
'version.research:view', 'version.product_plan:view', 'version.ui_plan:view', 'version.testcase:view',
'xiaobao.warning:view',
'overtime:view', 'overtime:create',
],
'role-test': [
@@ -83,6 +94,7 @@ export const DEFAULT_ROLE_PERMISSIONS: Record<string, string[]> = {
'version.testcase:view', 'version.testcase:manage',
'version.bug:view', 'version.bug:create', 'version.bug:edit', 'version.bug:delete',
'version.research:view', 'version.product_plan:view', 'version.ui_plan:view', 'version.devtask:view',
'xiaobao.warning:view',
'overtime:view', 'overtime:create',
],
'role-design': [
@@ -90,6 +102,7 @@ export const DEFAULT_ROLE_PERMISSIONS: Record<string, string[]> = {
'version.ui_plan:view', 'version.ui_plan:manage',
'version.research:view', 'version.product_plan:view', 'version.devtask:view',
'version.testcase:view', 'version.bug:view',
'xiaobao.warning:view',
'overtime:view', 'overtime:create',
],
};

View File

@@ -0,0 +1,38 @@
import assert from 'node:assert/strict';
import test from 'node:test';
import type { RoleItem } from './members';
import { mergePresetRolePermissions } from './role-permission-migration';
test('mergePresetRolePermissions adds new preset permissions to existing product manager role', () => {
const roles: RoleItem[] = [
{
id: 'role-pm',
name: '产品经理',
createdAt: '2024-01-01',
permissions: ['product:view'],
},
];
const result = mergePresetRolePermissions(roles);
assert.equal(result.changed, true);
assert.ok(result.roles[0].permissions.includes('product:view'));
assert.ok(result.roles[0].permissions.includes('xiaobao.warning:view'));
assert.ok(result.roles[0].permissions.includes('xiaobao.warning:manage'));
});
test('mergePresetRolePermissions keeps custom role permissions unchanged', () => {
const roles: RoleItem[] = [
{
id: 'role-custom',
name: '自定义角色',
createdAt: '2024-01-01',
permissions: ['version:view'],
},
];
const result = mergePresetRolePermissions(roles);
assert.equal(result.changed, false);
assert.deepEqual(result.roles[0].permissions, ['version:view']);
});

View File

@@ -0,0 +1,15 @@
import type { RoleItem } from './members';
import { DEFAULT_ROLE_PERMISSIONS } from './permissions';
export function mergePresetRolePermissions(roles: RoleItem[]): { roles: RoleItem[]; changed: boolean } {
let changed = false;
const next = roles.map((role) => {
const defaults = DEFAULT_ROLE_PERMISSIONS[role.id];
if (!defaults || role.permissions.includes('*')) return role;
const merged = Array.from(new Set([...role.permissions, ...defaults]));
if (merged.length === role.permissions.length) return role;
changed = true;
return { ...role, permissions: merged };
});
return { roles: next, changed };
}

View File

@@ -11,6 +11,8 @@ export type ServerDataKey =
| 'task-categories'
| 'task-worklogs'
| 'work-activities'
| 'xiaobao-risk-insights'
| 'xiaobao-risk-snapshots'
| 'overtime';
interface ServerDataResponse<T> {

View File

@@ -10,6 +10,7 @@ import {
sanitizeSystemAdminPatch,
} from '@/lib/member-system';
import { DEFAULT_ROLE_PERMISSIONS } from '@/lib/permissions';
import { mergePresetRolePermissions } from '@/lib/role-permission-migration';
import { loadServerData, saveServerData } from '@/lib/server-data';
const PRESET_DEPARTMENTS: Department[] = [
@@ -81,13 +82,16 @@ export const useMemberStore = create<MemberState>((set, get) => ({
}
return r;
});
const permissionMerged = mergePresetRolePermissions(migratedRoles);
const rolesWithNewDefaults = permissionMerged.roles;
const adminRole = PRESET_ROLES.find((r) => r.id === SYSTEM_ADMIN_ROLE_ID)!;
const roles = migratedRoles.some((r) => r.id === SYSTEM_ADMIN_ROLE_ID)
? migratedRoles.map((r) => r.id === SYSTEM_ADMIN_ROLE_ID ? { ...adminRole, ...r, isSystem: true, permissions: DEFAULT_ROLE_PERMISSIONS[SYSTEM_ADMIN_ROLE_ID] } : r)
: [adminRole, ...migratedRoles];
const roles = rolesWithNewDefaults.some((r) => r.id === SYSTEM_ADMIN_ROLE_ID)
? rolesWithNewDefaults.map((r) => r.id === SYSTEM_ADMIN_ROLE_ID ? { ...adminRole, ...r, isSystem: true, permissions: DEFAULT_ROLE_PERMISSIONS[SYSTEM_ADMIN_ROLE_ID] } : r)
: [adminRole, ...rolesWithNewDefaults];
const rolesChanged =
roles.length !== migratedRoles.length ||
roles.some((role, index) => JSON.stringify(role) !== JSON.stringify(migratedRoles[index]));
permissionMerged.changed ||
roles.length !== rolesWithNewDefaults.length ||
roles.some((role, index) => JSON.stringify(role) !== JSON.stringify(rolesWithNewDefaults[index]));
const ensured = ensureSystemAdminMember(cached.members);
const next = {
departments: cached.departments,