feat(版本): 完善研发计划与预警已读
关键改动: - 增加版本表单、发布校验和调研方向进度规则 - 扩展小宝预警已读状态、风险签名和今日证据 - 补充组长权限、加班查看范围、活动记录与相关测试 Co-Authored-By: Codex GPT-5 <codex@openai.com>
This commit is contained in:
97
apps/web/lib/overtime.test.ts
Normal file
97
apps/web/lib/overtime.test.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
|
||||
import {
|
||||
filterOvertimeRecordsForViewer,
|
||||
type OvertimeRecord,
|
||||
} from './overtime';
|
||||
import type { Department, Member, RoleItem } from './members';
|
||||
import type { AuthUser } from './auth-user';
|
||||
|
||||
const departments: Department[] = [
|
||||
{ id: 'dept-tech', name: 'Tech', order: 1, createdAt: '2024-01-01' },
|
||||
{ id: 'dept-front', name: 'Frontend', parentId: 'dept-tech', order: 1, createdAt: '2024-01-01' },
|
||||
{ id: 'dept-back', name: 'Backend', parentId: 'dept-tech', order: 2, createdAt: '2024-01-01' },
|
||||
{ id: 'dept-product', name: 'Product', order: 2, createdAt: '2024-01-01' },
|
||||
];
|
||||
|
||||
const members: Member[] = [
|
||||
member('m-lead', 'Lead', 'dept-tech', 'role-lead'),
|
||||
member('m-front', 'Frontend Alice', 'dept-front', 'role-dev'),
|
||||
member('m-back', 'Backend Bob', 'dept-back', 'role-dev'),
|
||||
member('m-pm', 'PM Carol', 'dept-product', 'role-pm'),
|
||||
];
|
||||
|
||||
const records: OvertimeRecord[] = [
|
||||
record('ot-front', 'Frontend Alice'),
|
||||
record('ot-back', 'Backend Bob'),
|
||||
record('ot-pm', 'PM Carol'),
|
||||
];
|
||||
|
||||
test('filterOvertimeRecordsForViewer limits non-admin viewers to their department tree', () => {
|
||||
const visible = filterOvertimeRecordsForViewer(records, {
|
||||
viewer: toAuthUser(members[0]),
|
||||
viewerRole: role('role-lead', ['overtime:view']),
|
||||
members,
|
||||
departments,
|
||||
});
|
||||
|
||||
assert.deepEqual(visible.map((item) => item.id), ['ot-front', 'ot-back']);
|
||||
});
|
||||
|
||||
test('filterOvertimeRecordsForViewer lets wildcard admin view every department', () => {
|
||||
const visible = filterOvertimeRecordsForViewer(records, {
|
||||
viewer: toAuthUser(members[0]),
|
||||
viewerRole: role('role-admin', ['*']),
|
||||
members,
|
||||
departments,
|
||||
});
|
||||
|
||||
assert.deepEqual(visible.map((item) => item.id), ['ot-front', 'ot-back', 'ot-pm']);
|
||||
});
|
||||
|
||||
function member(id: string, name: string, departmentId: string, roleId: string): Member {
|
||||
return {
|
||||
id,
|
||||
name,
|
||||
departmentId,
|
||||
roleId,
|
||||
phone: '',
|
||||
email: '',
|
||||
password: '',
|
||||
createdAt: '2024-01-01',
|
||||
};
|
||||
}
|
||||
|
||||
function record(id: string, person: string): OvertimeRecord {
|
||||
return {
|
||||
id,
|
||||
person,
|
||||
projectId: 'project-1',
|
||||
startTime: '2026-06-01T19:00',
|
||||
endTime: '2026-06-01T21:00',
|
||||
duration: 2,
|
||||
reasonId: 'reason-1',
|
||||
createdAt: '2026-06-01',
|
||||
};
|
||||
}
|
||||
|
||||
function role(id: string, permissions: string[]): RoleItem {
|
||||
return {
|
||||
id,
|
||||
name: id,
|
||||
createdAt: '2024-01-01',
|
||||
permissions,
|
||||
};
|
||||
}
|
||||
|
||||
function toAuthUser(member: Member): AuthUser {
|
||||
return {
|
||||
id: member.id,
|
||||
name: member.name,
|
||||
roleId: member.roleId,
|
||||
departmentId: member.departmentId,
|
||||
phone: member.phone,
|
||||
email: member.email,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user