feat: 加班/版本/项目调整 + 角色权限设计

加班记录:
- 加班人默认回显当前用户且不可改
- 列表加创建日期列
- 移除编辑功能(创建即提交,仅可删除)
- 提交时校验结束>开始

版本列表:
- 移除顶部 9 个状态 tab + 表格状态列
- 仅保留搜索、项目、优先级筛选

项目列表:
- 行内显示进度未达 100% 的版本(与版本页同源算法)
- 新增 lib/version-progress.ts 抽出公共进度计算

角色权限:
- RoleItem 加 permissions 字段
- 新建 lib/permissions.ts: 14 组 37 个权限点 + 默认 5 角色映射 + hasPermission
- 角色表单内嵌权限矩阵(主模块 4 件套 + Tab 二档 + Bug Tab 4 档)+ 全选/反选/仅查看快捷
- 新建 components/auth/Guard.tsx: RouteGuard + PermissionGuard + useHasPermission + AccessDenied
- Sidebar 菜单按 view 权限过滤
- 7 个主路由(products/projects/versions/requirements/overtime/admin/members/roles)包 RouteGuard
- 版本详情 Tab 按 view 权限过滤,自动跳转到第一个有权限的 Tab
- 默认未登录/无角色按只读最严格
- 超管 role-admin: ['*'] 通配符,permissions 不可改

通用:
- 新建 components/FieldError.tsx 统一表单错误文案
- PlanTab 提交时校验结束>开始

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Script Generator
2026-06-16 19:15:28 +08:00
parent 1f5bed0c79
commit c2f2fed82c
18 changed files with 1023 additions and 231 deletions

View File

@@ -0,0 +1,142 @@
# 加班/版本/项目模块小幅调整设计
## Context
针对已上线的加班记录、版本列表、项目列表、全局日期校验做一组明确的小幅调整。所有需求点边界已通过澄清确认,方案直接,无需架构层面权衡。
## 决策摘要
| 项 | 决策 |
|---|---|
| 加班"已提交"定义 | 创建即提交,所有记录不可编辑只可删除 |
| "创建日期"取值 | `OvertimeRecord.createdAt`(表单提交日期) |
| 加班人字段 | 默认回显 `useAuthStore` 当前用户 + `disabled` 不可改 |
| 版本列表移除范围 | 顶部 9 个状态 tab + 表格"状态"列 |
| 项目页"未达 100%"取值 | 整体进度(与版本页同源算法) < 100% |
| 日期校验提示 | 提交时验证 + 表单项下方红色文案 |
## 1. 加班记录模块(`apps/web/app/overtime/page.tsx`
**字段调整**
- `OvertimeModal` `useAuthStore` 引用初始化 `person = useAuthStore(s => s.user?.name) ?? ''`
- 加班人 input `disabled` + 灰底`bg-zinc-50`
- 编辑时仍以 record `person` 为准虽然这条路径会被移除
**列表表头**
- "备注"列前插入"创建日期"
- 单元格读 `r.createdAt`已是 `YYYY-MM-DD` 格式直接显示
**编辑功能移除**
- 删除`editing` state`handleEdit` 函数表格"编辑"按钮`OvertimeModal` `initial` 编辑分支保留 `initial: null` 用于校验空表单状态或直接简化签名移除 initial
- `handleCreate` 简化为 `setShowModal(true)`
- `OvertimeModal` props 删除 `initial`简化为新建专用
**日期校验**
- 提交时检查 `endTime > startTime`失败设 `formError = '结束时间必须晚于开始时间'`
- 在结束时间 input 下方显示红色文案 `<p className="text-[11px] text-red-500 mt-1">{formError}</p>`
## 2. 全局日期校验
**通用错误提示组件**新增 `apps/web/components/FieldError.tsx`
```tsx
interface Props { message?: string }
export function FieldError({ message }: Props) {
if (!message) return null;
return <p className="mt-1 text-[11px] text-red-500">{message}</p>;
}
```
**应用范围**提交时校验下方红色文案
- `apps/web/app/overtime/page.tsx` OvertimeModal 结束时间下方
- `apps/web/components/version/PlanTab.tsx` 计划开始/结束日期对按现有结构定位
- `apps/web/components/dev-task/DevTaskCreateModal.tsx` 已有 `startBeforeEnd` 校验统一改为用 `<FieldError>` 显示在预计截止下方
- `apps/web/components/dev-task/DevTaskDetailDrawer.tsx` 详情抽屉编辑如有日期对编辑
**跳过**
- `apps/web/app/versions/page.tsx` NewVersionModal 仅有截止日期无开始
- `apps/web/components/dev-task/WorklogPanel.tsx` 仅单 date 字段
## 3. 版本列表(`apps/web/app/versions/page.tsx`
**移除**
- `STATUS_TABS` 常量line 39-50
- 顶部状态 tab JSX line 275-281
- 表头"状态"line 346
- 表格"状态"单元格line 419-424
- `statusFilter` state 和过滤分支保留 search/projectFilter/priorityFilter 三个
**保留**项目筛选下拉优先级筛选下拉搜索框
**整体进度** 列保留——它本身就反映状态信息
## 4. 项目页(`apps/web/app/projects/page.tsx`
**计算 versionProgressMap**
- `ProjectsPage` 加同款 `versionProgressMap` useMemo versions/page.tsx line 141-212 同源算法
- 需要 import `useVersionPlanStore``useDevTaskStore``useTestCaseStore``useRequirementStore``STATUS_PROGRESS``getEstimateHours`
- 抽出公共函数 `apps/web/lib/version-progress.ts`
```ts
export function calcVersionProgress(
versionId: string,
plans: VersionPlan[],
requirements: Requirement[],
devTasks: DevTask[],
testCases: TestCase[],
): number;
export function buildVersionProgressMap(
versions: VersionWithContext[],
plans, requirements, devTasks, testCases,
): Record<string, number>;
```
versions/page.tsx 现有逻辑替换为调用这个工具避免两份
**ProjectRow 改动**
- 接收 `versionProgressMap: Record<string, number>` prop
- `activeVersions = filter(v => (versionProgressMap[v.id] ?? 0) < 100)`
- `releasedCount` 改为 `completedCount = filter(v => (versionProgressMap[v.id] ?? 0) >= 100)`
- "+N 已发布"改为"+N 已完成"
**Legend 调整**
- 现有图例 `开发中 / 规划中 / 已发布` 颜色与版本状态绑定VersionChip 也是继续保留 chip 内部颜色逻辑仅过滤维度变了Legend 文案保持不变这是 chip 颜色含义说明)。
## 数据流
```
overview / requirements / plans / devTasks / testCases
└── lib/version-progress.ts
├── buildVersionProgressMap(versions, ...)
│ └── Record<versionId, percent>
├── versions/page.tsx 整体进度列
└── projects/page.tsx ProjectRow 过滤未完成版本
```
## 实施清单
新增
- `apps/web/components/FieldError.tsx`
- `apps/web/lib/version-progress.ts`
修改
- `apps/web/app/overtime/page.tsx`加班人禁用 + 创建日期列 + 移除编辑 + 日期校验
- `apps/web/components/version/PlanTab.tsx`日期校验
- `apps/web/components/dev-task/DevTaskCreateModal.tsx`统一校验文案样式
- `apps/web/components/dev-task/DevTaskDetailDrawer.tsx`如有日期对编辑则加校验
- `apps/web/app/versions/page.tsx`移除状态 tab/ + 改用 version-progress.ts
- `apps/web/app/projects/page.tsx` progressMap + ProjectRow 过滤口径
## 验证
1. `pnpm type-check` 0 错误
2. `pnpm build` 14 个页面成功
3. 加班记录新建表单加班人为当前登录用户名且不可改列表有"创建日期"任何记录无"编辑"按钮"删除"
4. 加班/计划/开发任务表单截止 < 开始时提交下方显示红色文案不能提交
5. 版本列表顶部无状态 tab表头无状态列只有项目+优先级两个下拉
6. 项目列表每行显示进度未达 100% 的版本 chip已完成数量在末尾"+N 已完成"