重构 Wave3 详情与移动体验(05-28-frontend-ux-wave3-business-mobile)

这个提交包含在:
2026-05-29 07:57:17 +08:00
父节点 85c298e25a
当前提交 2b5fd6b1b7
共修改 17 个文件,包含 1087 行新增和 32 行删除
+29 -6
查看文件
@@ -25,6 +25,8 @@ import { PageHeader } from "../components/common/PageHeader";
import { StatusBadge } from "../components/common/StatusBadge";
import { DateTextInput } from "../components/common/DateTextInput";
import { WorkspaceNotice } from "../components/patterns/ListWorkspace";
import { MetricCard } from "../components/patterns/MetricCard";
import { PageScaffold } from "../components/patterns/PageScaffold";
import { Button } from "../components/ui/button";
import { Input } from "../components/ui/input";
import { Label } from "../components/ui/label";
@@ -244,6 +246,10 @@ export function ContractsRegistryPage() {
? "保留现有责任人"
: "默认当前用户";
const amountInvalid = Boolean(editor.amount.trim()) && !AMOUNT_PATTERN.test(editor.amount.trim());
const activeContractCount = visibleContracts.filter((item) => item.status === "active").length;
const draftContractCount = visibleContracts.filter((item) => item.status === "draft").length;
const archivedContractCount = visibleContracts.filter((item) => item.status === "archived").length;
const expiringContractCount = expiringQuery.data?.total ?? expiringItems.length;
const refreshAll = async () => {
await Promise.all([
@@ -305,10 +311,18 @@ export function ContractsRegistryPage() {
});
return (
<div className="space-y-6">
<PageScaffold>
<PageHeader
eyebrow="合同"
title="合同台账"
subtitle="维护合同元数据、生命周期、到期预警与导出,不在 OA 存放涉密正文附件。"
meta={
<>
<span className="info-chip">可见 {visibleContracts.length} 份</span>
<span className="info-chip">30 天到期 {expiringContractCount} 份</span>
<span className="info-chip">私密正文不入库</span>
</>
}
actions={
<div className="flex flex-wrap gap-2">
<Button
@@ -334,12 +348,21 @@ export function ContractsRegistryPage() {
}
/>
<div className="card-std space-y-4 p-6">
<section className="ops-status-strip grid gap-4 md:grid-cols-2 xl:grid-cols-4" data-testid="contracts-registry-summary">
<MetricCard title="可见合同" value={visibleContracts.length} note={filters.projectId ? "已按项目过滤" : "当前筛选结果"} />
<MetricCard title="生效中" value={activeContractCount} note="需要关注到期和责任人" />
<MetricCard title="草稿" value={draftContractCount} note="补齐摘要、金额和归档位置" tone={draftContractCount > 0 ? "warning" : "neutral"} />
<MetricCard title="已归档" value={archivedContractCount} note="只保留台账和线下档案索引" />
</section>
<div className="detail-command-panel space-y-4" data-testid="contracts-registry-command">
<div className="flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between">
<div>
<div className="text-sm text-zinc-500">到期预警</div>
<div className="text-sm text-zinc-500">生命周期焦点</div>
<div className="mt-1 text-3xl font-semibold text-zinc-900">{expiringQuery.data?.total ?? 0}</div>
<div className="text-sm text-zinc-600">份合同将在 {EXPIRING_DAYS} 天内到期</div>
<div className="text-sm text-zinc-600">
份合同将在 {EXPIRING_DAYS} 天内到期;续约会生成草稿合同,导出仅用于授权复核。
</div>
</div>
<div className="flex flex-wrap gap-2">
<Button
@@ -759,7 +782,7 @@ export function ContractsRegistryPage() {
<div className="space-y-3">
{visibleContracts.map((item) => (
<div key={item.id} className="rounded-lg border border-zinc-200 p-4">
<div key={item.id} className="detail-evidence-card bg-white" data-testid="contracts-registry-row">
<div className="flex flex-col gap-4 md:flex-row md:items-start md:justify-between">
<div className="space-y-2">
<div className="flex flex-wrap items-center gap-3">
@@ -832,7 +855,7 @@ export function ContractsRegistryPage() {
</div>
</div>
</div>
</div>
</PageScaffold>
);
}