feat: 实现需求管理、加班记录、成员/角色管理模块

- 需求模块:完整 CRUD、状态流转(采纳/拒绝/关闭)、详情抽屉、产品→项目级联选择
- 加班记录:产品→项目→版本三级联动、月份筛选(MonthPicker)、CSV 导出
- 成员管理:左右布局(部门树+成员列表)、手机号脱敏、初始密码自动生成及规则设置
- 角色管理:卡片列表、系统角色保护、CRUD
- 通用组件:FilterSelect 下拉、MonthPicker 月份选择器、Pagination 分页
- 样式统一:状态标签加 border、日期输入现代化、筛选组件风格一致

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Script Generator
2026-06-09 18:16:18 +08:00
parent 24ba61f929
commit 9a0b16a8f1
36 changed files with 4355 additions and 272 deletions

View File

@@ -7,6 +7,7 @@ import { useProductStore } from '@/stores/useProductStore';
import { flattenProjects, ProjectWithContext } from '@/lib/derive';
import { VersionChip } from '@/components/version/VersionChip';
import { VersionStatus } from '@/lib/version-status';
import { Pagination, usePagination } from '@/components/Pagination';
export default function ProjectsPage() {
const router = useRouter();
@@ -29,6 +30,8 @@ export default function ProjectsPage() {
});
}, [allProjects, search, productFilter]);
const { paged, page, setPage, total, pageSize, setPageSize } = usePagination(filtered, 20);
const productOptions = useMemo(
() => overview.map((p) => ({ id: p.id, name: p.name })),
[overview]
@@ -90,10 +93,13 @@ export default function ProjectsPage() {
{filtered.length === 0 ? (
<EmptyState />
) : (
<div className="overflow-hidden rounded-2xl border border-[var(--line)] bg-[var(--bg-card)] shadow-[var(--shadow-sm)]">
{filtered.map((proj) => (
<ProjectRow key={proj.id} proj={proj} onClick={() => router.push(`/projects/${proj.id}`)} />
))}
<div>
<div className="overflow-hidden rounded-2xl border border-[var(--line)] bg-[var(--bg-card)] shadow-[var(--shadow-sm)]">
{paged.map((proj) => (
<ProjectRow key={proj.id} proj={proj} onClick={() => router.push(`/projects/${proj.id}`)} />
))}
</div>
<Pagination total={total} page={page} pageSize={pageSize} onChange={setPage} onPageSizeChange={setPageSize} />
</div>
)}
</div>