refactor(ui): [UI8] 彻底移除遗留Card并补充下拉框中文化

这个提交包含在:
2026-03-06 10:09:18 +08:00
父节点 5a6a6f67c9
当前提交 3883f14a48
共修改 25 个文件,包含 87 行新增和 95 行删除
@@ -1,13 +1,12 @@
import { Skeleton } from "../ui/skeleton";
import { Card } from "../ui/card";
export function CardSkeleton({ lines = 6 }: { lines?: number }) {
return (
<Card className="space-y-3 p-6">
<div className="card-std space-y-3 p-6">
<Skeleton className="h-5 w-48" />
{Array.from({ length: lines }, (_, i) => (
<Skeleton key={i} className="h-4 w-full" />
))}
</Card>
</div>
);
}
@@ -1,5 +1,4 @@
import { Component, type ErrorInfo, type ReactNode } from "react";
import { Card } from "../ui/card";
type Props = {
children: ReactNode;
@@ -32,7 +31,7 @@ export class ErrorBoundary extends Component<Props, State> {
}
return (
<Card className="mx-auto mt-12 max-w-lg space-y-4 p-6 text-center">
<div className="card-std mx-auto mt-12 max-w-lg space-y-4 p-6 text-center">
<h2 className="text-lg font-semibold text-zinc-900">页面渲染出错</h2>
<p className="text-sm text-zinc-600">
{this.state.error?.message ?? "发生了未知错误"}
@@ -55,7 +54,7 @@ export class ErrorBoundary extends Component<Props, State> {
返回首页
</button>
</div>
</Card>
</div>
);
}
+1 -1
查看文件
@@ -42,7 +42,7 @@
/* Cards */
.card-std {
@apply bg-white p-6 rounded-xl shadow-sm ring-1 ring-zinc-900/5 transition-all;
@apply bg-white rounded-xl shadow-sm ring-1 ring-zinc-900/5 transition-all;
}
.card-title {
+2 -2
查看文件
@@ -155,7 +155,7 @@ export function ApprovalRulesPage() {
</p>
) : null}
<div className="card-std space-y-4">
<div className="card-std p-6 space-y-4">
<h3 className="text-base font-semibold text-zinc-900">新建审批规则</h3>
<div className="grid gap-3 md:grid-cols-2 lg:grid-cols-3">
@@ -280,7 +280,7 @@ export function ApprovalRulesPage() {
</div>
</div>
<div className="card-std space-y-4">
<div className="card-std p-6 space-y-4">
<h3 className="text-base font-semibold text-zinc-900">规则列表</h3>
{listQuery.isLoading ? <TableSkeleton columns={6} rows={5} /> : null}
+1 -1
查看文件
@@ -135,7 +135,7 @@ export function AuditLogsPage() {
}
/>
<section className="card-std space-y-4">
<section className="card-std p-6 space-y-4">
<div className="grid gap-3 md:grid-cols-3">
<label className="text-sm text-zinc-700">
Action
+6 -7
查看文件
@@ -8,7 +8,6 @@ import { useAuth } from "../auth/AuthContext";
import { hasPermission } from "../auth/permissions";
import { PageHeader } from "../components/common/PageHeader";
import { Button } from "../components/ui/button";
import { Card } from "../components/ui/card";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "../components/ui/table";
import { toast } from "sonner";
import { TableSkeleton } from "../components/common/TableSkeleton";
@@ -118,7 +117,7 @@ export function BudgetsPage() {
return (
<div className="space-y-4">
<PageHeader title="预算管理" subtitle="你当前没有预算权限,请联系管理员开通。" />
<Card className="p-6 text-sm text-zinc-600">所需权限:budget.view 或 budget.manage</Card>
<div className="card-std p-6 text-sm text-zinc-600">所需权限:budget.view 或 budget.manage</div>
</div>
);
}
@@ -138,7 +137,7 @@ export function BudgetsPage() {
</p>
) : null}
<div className="card-std space-y-3">
<div className="card-std p-6 space-y-3">
<h3 className="text-base font-semibold text-zinc-900">筛选条件</h3>
<div className="grid gap-3 md:grid-cols-3">
<select
@@ -150,8 +149,8 @@ export function BudgetsPage() {
}}
>
<option value="">全部状态</option>
<option value="active">active</option>
<option value="archived">archived</option>
<option value="active">生效中</option>
<option value="archived">已归档</option>
</select>
<select
@@ -181,7 +180,7 @@ export function BudgetsPage() {
</div>
{canManageBudget ? (
<div className="card-std space-y-3">
<div className="card-std p-6 space-y-3">
<h3 className="text-base font-semibold text-zinc-900">新建预算池</h3>
<div className="grid gap-3 md:grid-cols-3">
<input
@@ -253,7 +252,7 @@ export function BudgetsPage() {
</div>
) : null}
<div className="card-std space-y-3">
<div className="card-std p-6 space-y-3">
<h3 className="text-base font-semibold text-zinc-900">预算池列表</h3>
{budgetsQuery.isLoading ? <TableSkeleton columns={7} rows={4} /> : null}
+2 -3
查看文件
@@ -4,7 +4,6 @@ import { isApiError } from "../api/types";
import { mapApiErrorMessage } from "../api/errorMessages";
import { useAuth } from "../auth/AuthContext";
import { Button } from "../components/ui/button";
import { Card } from "../components/ui/card";
import { Input } from "../components/ui/input";
import { Label } from "../components/ui/label";
@@ -43,7 +42,7 @@ export function ChangePasswordPage() {
}
return (
<Card className="space-y-6 border-primary-100 p-6">
<div className="card-std space-y-6 border-primary-100 p-6">
<div className="mb-6 space-y-2">
<p className="text-xs font-semibold uppercase tracking-wide text-primary">hyb-oa</p>
<h1 className="text-2xl font-bold text-zinc-900">修改密码</h1>
@@ -109,7 +108,7 @@ export function ChangePasswordPage() {
{submitting ? "提交中..." : "确认修改"}
</Button>
</form>
</Card>
</div>
);
}
+11 -12
查看文件
@@ -16,7 +16,6 @@ import { useAuth } from "../auth/AuthContext";
import { hasPermission } from "../auth/permissions";
import { PageHeader } from "../components/common/PageHeader";
import { Button } from "../components/ui/button";
import { Card } from "../components/ui/card";
import { downloadBlob } from "../lib/download";
function currentDateString() {
@@ -116,10 +115,10 @@ export function DashboardPage() {
return (
<div className="space-y-4">
<PageHeader title="仪表盘" subtitle="你当前没有看板权限,请联系管理员开通。" />
<Card className="space-y-2 p-6 text-sm">
<div className="card-std space-y-2 p-6 text-sm">
<p className="text-zinc-700">当前用户:{me?.name ?? "-"}</p>
<p className="text-zinc-500">所需权限:report.dashboard.view</p>
</Card>
</div>
</div>
);
}
@@ -163,7 +162,7 @@ export function DashboardPage() {
</p>
) : null}
<Card className="space-y-4 p-6">
<div className="card-std space-y-4 p-6">
<div className="grid gap-3 md:grid-cols-4">
<div className="space-y-1">
<label className="text-xs text-zinc-600" htmlFor="dashboard-date-from">
@@ -226,28 +225,28 @@ export function DashboardPage() {
</Button>
</div>
</div>
</Card>
</div>
<div className="grid gap-4 md:grid-cols-4">
<div className="card-std space-y-1">
<div className="card-std p-4 space-y-1">
<p className="text-xs text-zinc-500">报销单总数</p>
<p className="mt-1 text-2xl font-semibold text-zinc-900">
{loading ? "..." : overviewQuery.data?.totalCount ?? 0}
</p>
</div>
<div className="card-std space-y-1">
<div className="card-std p-4 space-y-1">
<p className="text-xs text-zinc-500">报销总金额</p>
<p className="mt-1 text-2xl font-semibold text-zinc-900">
{loading ? "..." : toCurrency(overviewQuery.data?.totalAmount)}
</p>
</div>
<div className="card-std space-y-1">
<div className="card-std p-4 space-y-1">
<p className="text-xs text-zinc-500">已付款金额</p>
<p className="mt-1 text-2xl font-semibold text-zinc-900">
{loading ? "..." : toCurrency(overviewQuery.data?.paidAmount)}
</p>
</div>
<div className="card-std space-y-1">
<div className="card-std p-4 space-y-1">
<p className="text-xs text-zinc-500">审批中数量</p>
<p className="mt-1 text-2xl font-semibold text-zinc-900">
{loading ? "..." : overviewQuery.data?.reviewingCount ?? 0}
@@ -256,7 +255,7 @@ export function DashboardPage() {
</div>
<div className="grid gap-4 lg:grid-cols-2">
<div className="card-std space-y-4">
<div className="card-std p-6 space-y-4">
<h3 className="text-base font-semibold text-zinc-900">费用趋势</h3>
{trendPoints.length ? (
<div className="space-y-2">
@@ -283,7 +282,7 @@ export function DashboardPage() {
)}
</div>
<div className="card-std space-y-4">
<div className="card-std p-6 space-y-4">
<h3 className="text-base font-semibold text-zinc-900">费用分类 TopN</h3>
{topCategories.length ? (
<div className="space-y-2">
@@ -313,7 +312,7 @@ export function DashboardPage() {
</div>
</div>
<div className="card-std space-y-2 text-sm">
<div className="card-std p-6 space-y-2 text-sm">
<h3 className="text-base font-semibold text-zinc-900">审批效率</h3>
<p className="text-zinc-700">
已统计通过单据:
+11 -11
查看文件
@@ -9,7 +9,6 @@ import { PageHeader } from "../components/common/PageHeader";
import { TableSkeleton } from "../components/common/TableSkeleton";
import { StatusBadge } from "../components/common/StatusBadge";
import { Button } from "../components/ui/button";
import { Input } from "../components/ui/input";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "../components/ui/table";
export function DelegationsPage() {
@@ -79,7 +78,7 @@ export function DelegationsPage() {
<p className="rounded-lg border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-600">{error}</p>
) : null}
<div className="card-std space-y-4">
<div className="card-std p-6 space-y-4">
<h3 className="text-base font-semibold text-zinc-900">创建委派</h3>
<div className="grid gap-3 md:grid-cols-2">
@@ -111,14 +110,15 @@ export function DelegationsPage() {
onChange={(event) => setScope(event.target.value as "all" | "reimbursement_submit")}
value={scope}
>
<option value="all">all</option>
<option value="reimbursement_submit">reimbursement_submit</option>
<option value="all">任意单据(全权代理)</option>
<option value="reimbursement_submit">仅限提交报销单</option>
</select>
</label>
<label className="space-y-1 text-sm md:col-span-2">
<span className="font-medium text-zinc-700">有效期结束(可选)</span>
<Input
<input
className="input-std"
data-testid="delegations-create-valid-to"
onChange={(event) => setValidTo(event.target.value)}
type="datetime-local"
@@ -139,7 +139,7 @@ export function DelegationsPage() {
</div>
</div>
<div className="card-std space-y-4">
<div className="card-std p-6 space-y-4">
<div className="flex flex-wrap items-center justify-between gap-2">
<h3 className="text-base font-semibold text-zinc-900">我的委派</h3>
<select
@@ -150,11 +150,11 @@ export function DelegationsPage() {
}
value={status}
>
<option value="active">active</option>
<option value="scheduled">scheduled</option>
<option value="expired">expired</option>
<option value="revoked">revoked</option>
<option value="all">all</option>
<option value="active">生效中</option>
<option value="scheduled">未开始</option>
<option value="expired">已失效</option>
<option value="revoked">已撤销</option>
<option value="all">全状态</option>
</select>
</div>
+2 -2
查看文件
@@ -101,7 +101,7 @@ export function DepartmentsPage() {
</p>
) : null}
<div className="card-std space-y-4">
<div className="card-std p-6 space-y-4">
<div className="flex items-center justify-between gap-3">
<h3 className="text-base font-semibold text-zinc-900">新建部门</h3>
<Button
@@ -163,7 +163,7 @@ export function DepartmentsPage() {
</div>
</div>
<div className="card-std space-y-4">
<div className="card-std p-6 space-y-4">
<h3 className="text-base font-semibold text-zinc-900">部门列表</h3>
{listQuery.isLoading ? <TableSkeleton columns={4} rows={4} /> : null}
+1 -1
查看文件
@@ -138,7 +138,7 @@ export function FeatureFlagsPage() {
<p className="rounded-lg border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-600">{error}</p>
) : null}
<div className="card-std space-y-4">
<div className="card-std p-6 space-y-4">
<h3 className="text-base font-semibold text-zinc-900">开关列表</h3>
{flagsQuery.isLoading ? <TableSkeleton columns={6} rows={2} /> : null}
+2 -3
查看文件
@@ -4,7 +4,6 @@ import { mapApiErrorMessage } from "../api/errorMessages";
import { isApiError } from "../api/types";
import { useAuth } from "../auth/AuthContext";
import { Button } from "../components/ui/button";
import { Card } from "../components/ui/card";
import { Input } from "../components/ui/input";
import { Label } from "../components/ui/label";
@@ -59,7 +58,7 @@ export function LoginPage() {
}
return (
<Card className="space-y-6 border-primary-100 p-6">
<div className="card-std space-y-6 border-primary-100 p-6">
<div className="mb-6">
<p className="text-xs font-semibold uppercase tracking-wide text-primary">hyb-oa</p>
<h1 className="mt-2 text-2xl font-bold text-zinc-900">登录工作台</h1>
@@ -106,6 +105,6 @@ export function LoginPage() {
{submitting ? "登录中..." : "登录"}
</Button>
</form>
</Card>
</div>
);
}
+4 -5
查看文件
@@ -15,7 +15,6 @@ import {
import { PageHeader } from "../components/common/PageHeader";
import { Button } from "../components/ui/button";
import { Spinner } from "../components/ui/spinner";
import { Card } from "../components/ui/card";
import { Textarea } from "../components/ui/textarea";
type MobileAction = "approve" | "reject" | "return" | "transfer";
@@ -107,7 +106,7 @@ export function MobileApprovalsPage() {
<p className="rounded-lg border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-600">{error}</p>
) : null}
<Card className="space-y-3 p-4" data-testid="mobile-approvals-list">
<div className="card-std space-y-3 p-4" data-testid="mobile-approvals-list">
<h3 className="text-base font-semibold text-zinc-900">待办任务</h3>
{tasksQuery.isLoading ? <div className="flex items-center gap-2 text-sm text-zinc-500"><Spinner size="sm" />加载中...</div> : null}
@@ -135,9 +134,9 @@ export function MobileApprovalsPage() {
</button>
))}
</div>
</Card>
</div>
<Card className="space-y-3 p-4" data-testid="mobile-approvals-detail">
<div className="card-std space-y-3 p-4" data-testid="mobile-approvals-detail">
<h3 className="text-base font-semibold text-zinc-900">任务详情与动作</h3>
{!selectedTaskId ? <p className="text-sm text-zinc-500">请先选择任务。</p> : null}
@@ -229,7 +228,7 @@ export function MobileApprovalsPage() {
</div>
</>
)}
</Card>
</div>
</div>
);
}
+4 -5
查看文件
@@ -7,7 +7,6 @@ import { isApiError } from "../api/types";
import { PageHeader } from "../components/common/PageHeader";
import { Button } from "../components/ui/button";
import { Spinner } from "../components/ui/spinner";
import { Card } from "../components/ui/card";
import {
enqueueInvoiceUpload,
listQueuedInvoiceUploads,
@@ -140,7 +139,7 @@ export function MobileCapturePage() {
<p className="rounded-lg border border-emerald-200 bg-emerald-50 px-3 py-2 text-sm text-emerald-700">{message}</p>
) : null}
<Card className="space-y-3 p-4">
<div className="card-std space-y-3 p-4">
<div className="flex items-center justify-between">
<h3 className="text-base font-semibold text-zinc-900">拍照/选择文件</h3>
<span className={isOnline ? "text-emerald-600" : "text-orange-600"}>
@@ -212,9 +211,9 @@ export function MobileCapturePage() {
{syncMutation.isPending ? "同步中..." : "同步队列"}
</Button>
</div>
</Card>
</div>
<Card className="space-y-3 p-4" data-testid="mobile-capture-queue">
<div className="card-std space-y-3 p-4" data-testid="mobile-capture-queue">
<div className="flex items-center justify-between">
<h3 className="text-base font-semibold text-zinc-900">离线上传队列</h3>
<span className="text-sm text-zinc-500">{queuedCountLabel}</span>
@@ -246,7 +245,7 @@ export function MobileCapturePage() {
</div>
</div>
))}
</Card>
</div>
</div>
);
}
+1 -1
查看文件
@@ -79,7 +79,7 @@ export function NotificationsPage() {
}
/>
<div className="card-std space-y-4">
<div className="card-std p-6 space-y-4">
<div className="flex flex-col gap-3 md:flex-row md:items-center md:justify-between">
<Tabs
data-testid="notifications-filter-tabs"
+12 -13
查看文件
@@ -21,7 +21,6 @@ import { CardSkeleton } from "../components/common/CardSkeleton";
import { ConfirmDialog } from "../components/common/ConfirmDialog";
import { PageHeader } from "../components/common/PageHeader";
import { Button } from "../components/ui/button";
import { Card } from "../components/ui/card";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "../components/ui/table";
import { ReimbursementActions, type PayPayload } from "./reimbursement-detail/ReimbursementActions";
import {
@@ -195,9 +194,9 @@ export function ReimbursementDetailPage() {
if (!reimbursementId) {
return (
<Card className="p-6">
<div className="card-std p-6">
<p className="text-sm text-red-600">缺少 reimbursementId 参数。</p>
</Card>
</div>
);
}
@@ -215,12 +214,12 @@ export function ReimbursementDetailPage() {
: "加载报销详情失败";
return (
<Card className="space-y-3 p-6">
<div className="card-std space-y-3 p-6">
<p className="text-sm text-red-600">{message}</p>
<Button asChild variant="secondary">
<Link to="/reimbursements">返回报销列表</Link>
</Button>
</Card>
</div>
);
}
@@ -281,17 +280,17 @@ export function ReimbursementDetailPage() {
}
/>
<Card className="space-y-2 p-6 text-sm" data-testid="reimbursement-summary">
<div className="card-std space-y-2 p-6 text-sm" data-testid="reimbursement-summary">
<div>报销ID:{detail.id}</div>
<div>报销日期:{detail.reimbursementDate ?? "-"}</div>
<div>金额:{detail.totalAmount ?? "-"}</div>
<div>提交人:{detail.submitter?.name ?? "-"}</div>
<div>报销人:{detail.owner?.name ?? "-"}</div>
<div>说明:{detail.description || "-"}</div>
</Card>
</div>
{budgetHint ? (
<Card className="space-y-2 p-6 text-sm" data-testid="reimbursement-budget-hint">
<div className="card-std space-y-2 p-6 text-sm" data-testid="reimbursement-budget-hint">
<h3 className="text-base font-semibold text-zinc-900">预算提示</h3>
<div>预算池:{budgetHint.budgetCode} / {budgetHint.budgetName}</div>
<div>
@@ -310,10 +309,10 @@ export function ReimbursementDetailPage() {
) : (
<p className="text-zinc-500">当前预算充足,可继续提交。</p>
)}
</Card>
</div>
) : null}
<Card className="space-y-4 p-6" data-testid="reimbursement-items">
<div className="card-std space-y-4 p-6" data-testid="reimbursement-items">
<div className="flex flex-col gap-3 md:flex-row md:items-center md:justify-between">
<div className="space-y-1">
<h3 className="text-base font-semibold text-zinc-900">报销明细</h3>
@@ -418,7 +417,7 @@ export function ReimbursementDetailPage() {
isPending={itemSaveMutation.isPending}
/>
) : null}
</Card>
</div>
<ReimbursementActions
status={detail.status}
@@ -430,7 +429,7 @@ export function ReimbursementDetailPage() {
onPay={(payload) => mutation.mutate({ action: "pay", payload })}
/>
<Card className="space-y-2 p-6" data-testid="reimbursement-invoices">
<div className="card-std space-y-2 p-6" data-testid="reimbursement-invoices">
<h3 className="text-base font-semibold text-zinc-900">关联票据</h3>
{(detail.invoices ?? []).length ? (
<div className="space-y-2 text-sm">
@@ -446,7 +445,7 @@ export function ReimbursementDetailPage() {
) : (
<p className="text-sm text-zinc-500">暂无关联票据</p>
)}
</Card>
</div>
<ConfirmDialog
open={Boolean(confirmDeleteItemId)}
+2 -3
查看文件
@@ -16,7 +16,6 @@ import {
} from "../api/users";
import { PageHeader } from "../components/common/PageHeader";
import { Button } from "../components/ui/button";
import { Card } from "../components/ui/card";
import { Input } from "../components/ui/input";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "../components/ui/table";
import { toast } from "sonner";
@@ -177,7 +176,7 @@ export function UserManagementPage() {
</p>
) : null}
<Card className="space-y-4 p-6">
<div className="card-std space-y-4 p-6">
<div className="flex flex-wrap items-center gap-2">
<Input
data-testid="users-search"
@@ -298,7 +297,7 @@ export function UserManagementPage() {
onPageChange={setPage}
testIdPrefix="users"
/>
</Card>
</div>
<UserRoleDialog
open={Boolean(roleDialogUser)}
+10 -11
查看文件
@@ -18,7 +18,6 @@ import { CardSkeleton } from "../components/common/CardSkeleton";
import { PageHeader } from "../components/common/PageHeader";
import { StatusBadge } from "../components/common/StatusBadge";
import { Button } from "../components/ui/button";
import { Card } from "../components/ui/card";
import { Textarea } from "../components/ui/textarea";
export function WorkflowTaskDetailPage() {
@@ -98,9 +97,9 @@ export function WorkflowTaskDetailPage() {
if (!taskId) {
return (
<Card className="p-6">
<div className="card-std p-6">
<p className="text-sm text-red-600">缺少 taskId 参数。</p>
</Card>
</div>
);
}
@@ -120,7 +119,7 @@ export function WorkflowTaskDetailPage() {
: "加载失败,请返回列表重试";
return (
<Card className="space-y-3 p-6">
<div className="card-std space-y-3 p-6">
<p className="text-sm text-red-600">{message}</p>
<Button
variant="secondary"
@@ -129,7 +128,7 @@ export function WorkflowTaskDetailPage() {
>
返回待办列表
</Button>
</Card>
</div>
);
}
@@ -147,16 +146,16 @@ export function WorkflowTaskDetailPage() {
}
/>
<Card className="space-y-2 p-6 text-sm" data-testid="workflow-task-summary">
<div className="card-std space-y-2 p-6 text-sm" data-testid="workflow-task-summary">
<div>状态:<StatusBadge status={detail.task.status} /></div>
<div>实例:{detail.workflowInstance?.id ?? "-"}</div>
<div>报销单号:{detail.reimbursement?.formNumber ?? "-"}</div>
<div>报销金额:{detail.reimbursement?.totalAmount ?? "-"}</div>
<div>提交人:{detail.reimbursement?.submitter?.name ?? "-"}</div>
<div>报销人:{detail.reimbursement?.owner?.name ?? "-"}</div>
</Card>
</div>
<Card className="space-y-4 p-6">
<div className="card-std space-y-4 p-6">
<h3 className="text-base font-semibold text-zinc-900">审批动作</h3>
{actionError ? (
@@ -253,9 +252,9 @@ export function WorkflowTaskDetailPage() {
提交转审
</Button>
</div>
</Card>
</div>
<Card className="space-y-3 p-6">
<div className="card-std space-y-3 p-6">
<h3 className="text-base font-semibold text-zinc-900">处理历史</h3>
<div className="space-y-2">
{detail.history.length ? (
@@ -272,7 +271,7 @@ export function WorkflowTaskDetailPage() {
<p className="text-sm text-zinc-500">暂无历史记录</p>
)}
</div>
</Card>
</div>
</div>
);
}
+1 -1
查看文件
@@ -37,7 +37,7 @@ export function WorkflowTasksPage() {
<div className="space-y-6">
<PageHeader title="待我处理" subtitle="审批待办列表(支持筛选与详情动作联动)。" />
<div className="card-std space-y-4">
<div className="card-std p-6 space-y-4">
<Tabs
data-testid="workflow-tasks-status-tabs"
value={status}
@@ -23,7 +23,7 @@ export function InvoiceBindCard({
setSelectedReimbursementId,
}: InvoiceBindCardProps) {
return (
<div className="card-std space-y-4">
<div className="card-std p-6 space-y-4">
<h3 className="card-title">绑定报销</h3>
<select
className="select-std"
@@ -69,7 +69,7 @@ export function InvoiceDetailPanel({
}: InvoiceDetailPanelProps) {
return (
<>
<div className="card-std space-y-4" data-testid="invoice-detail-panel">
<div className="card-std p-6 space-y-4" data-testid="invoice-detail-panel">
<h3 className="card-title">详情轮询</h3>
{detail ? (
<>
@@ -32,7 +32,7 @@ export function InvoiceListCard({
signedUrlMutation,
}: InvoiceListCardProps) {
return (
<div className="card-std space-y-4">
<div className="card-std p-6 space-y-4">
<div className="flex items-center justify-between">
<h3 className="card-title">筛选与列表</h3>
<div className="flex items-center gap-2">
@@ -22,7 +22,7 @@ export function InvoiceUploadCard({
setUploadOwnerEmployeeId,
}: InvoiceUploadCardProps) {
return (
<div className="card-std space-y-4">
<div className="card-std p-6 space-y-4">
<h3 className="card-title">上传票据(VAT OCR)</h3>
{showProxyOwnerSelector ? (
<select
@@ -1,7 +1,6 @@
import { useState } from "react";
import type { ReimbursementStatus } from "../../api/reimbursements";
import { Button } from "../../components/ui/button";
import { Card } from "../../components/ui/card";
import { Input } from "../../components/ui/input";
import { Textarea } from "../../components/ui/textarea";
@@ -38,7 +37,7 @@ export function ReimbursementActions({
const [paymentChannel, setPaymentChannel] = useState<PaymentChannel>("bank");
return (
<Card className="space-y-4 p-6">
<div className="card-std space-y-4 p-6">
<h3 className="text-base font-semibold text-zinc-900">可执行动作</h3>
{actionError ? (
@@ -126,6 +125,6 @@ export function ReimbursementActions({
</Button>
</div>
) : null}
</Card>
</div>
);
}
@@ -0,0 +1,4 @@
ID,Title,Description,Acceptance,Test_Method,Tools,Dev_Status,Review1_Status,Regression_Status,Files,Dependencies,Notes
UI8-0,UI翻新阶段8验收建档,创建并校验本轮遗留Card组件与边缘文案中文化Issue CSV,CSV校验通过,python3 /home/shunli/.codex/skills/plan/scripts/validate_issues_csv.py issues/2026-03-06_10-09-00-ui-refresh-stage8.csv,manual,TODO,TODO,TODO,issues/2026-03-06_10-09-00-ui-refresh-stage8.csv,[],none
UI8-1,清理残余的Card与混用UI,修复Dashboard及15个遗留页面中的shadcn Card引入混用问题及样式调整,全站所有遗留被替换为 card-std 且Typecheck通过,cd client && npm run typecheck && npm run build,manual,DONE,DONE,DONE,client/src/pages/**,"[""UI8-0""]",确保剥离 p-6 后的样式无异常
UI8-2,下拉框中文化,修复Budgets和Delegations等的选项文案中文化,文案完成对应本地化不影响value传入后端,手动校验下拉框显示,manual,DONE,DONE,DONE,client/src/pages/BudgetsPage.tsx|client/src/pages/DelegationsPage.tsx,"[""UI8-0""]",无
1 ID Title Description Acceptance Test_Method Tools Dev_Status Review1_Status Regression_Status Files Dependencies Notes
2 UI8-0 UI翻新阶段8验收建档 创建并校验本轮遗留Card组件与边缘文案中文化Issue CSV CSV校验通过 python3 /home/shunli/.codex/skills/plan/scripts/validate_issues_csv.py issues/2026-03-06_10-09-00-ui-refresh-stage8.csv manual TODO TODO TODO issues/2026-03-06_10-09-00-ui-refresh-stage8.csv [] none
3 UI8-1 清理残余的Card与混用UI 修复Dashboard及15个遗留页面中的shadcn Card引入混用问题及样式调整 全站所有遗留被替换为 card-std 且Typecheck通过 cd client && npm run typecheck && npm run build manual DONE DONE DONE client/src/pages/** ["UI8-0"] 确保剥离 p-6 后的样式无异常
4 UI8-2 下拉框中文化 修复Budgets和Delegations等的选项文案中文化 文案完成对应本地化不影响value传入后端 手动校验下拉框显示 manual DONE DONE DONE client/src/pages/BudgetsPage.tsx|client/src/pages/DelegationsPage.tsx ["UI8-0"] 无