fix(ui): [UI7-2] 统一全局 Design Tokens,移除冗余字体,修复异常色值引用

这个提交包含在:
2026-03-06 09:48:37 +08:00
父节点 62fd2a5398
当前提交 73b51ac068
共修改 39 个文件,包含 253 行新增和 250 行删除
+15 -15
查看文件
@@ -157,7 +157,7 @@ export function ApprovalRulesPage() {
) : null}
<Card className="space-y-4 p-6">
<h3 className="text-base font-semibold text-slate-900">新建审批规则</h3>
<h3 className="text-base font-semibold text-zinc-900">新建审批规则</h3>
<div className="grid gap-3 md:grid-cols-2 lg:grid-cols-3">
<div className="space-y-1">
@@ -209,7 +209,7 @@ export function ApprovalRulesPage() {
<select
id="level1Role"
data-testid="approval-rules-create-level1"
className="h-11 w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm"
className="h-11 w-full rounded-lg border border-zinc-300 bg-white px-3 py-2 text-sm"
value={level1Role}
onChange={(event) => setLevel1Role(event.target.value as ApprovalRoleCode)}
>
@@ -226,7 +226,7 @@ export function ApprovalRulesPage() {
<select
id="level2Role"
data-testid="approval-rules-create-level2"
className="h-11 w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm"
className="h-11 w-full rounded-lg border border-zinc-300 bg-white px-3 py-2 text-sm"
value={level2Role}
onChange={(event) => setLevel2Role(event.target.value as ApprovalRoleCode)}
>
@@ -244,7 +244,7 @@ export function ApprovalRulesPage() {
<select
id="level3Role"
data-testid="approval-rules-create-level3"
className="h-11 w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm"
className="h-11 w-full rounded-lg border border-zinc-300 bg-white px-3 py-2 text-sm"
value={level3Role}
onChange={(event) => setLevel3Role(event.target.value as ApprovalRoleCode)}
>
@@ -282,7 +282,7 @@ export function ApprovalRulesPage() {
</Card>
<Card className="space-y-4 p-6">
<h3 className="text-base font-semibold text-slate-900">规则列表</h3>
<h3 className="text-base font-semibold text-zinc-900">规则列表</h3>
{listQuery.isLoading ? <TableSkeleton columns={6} rows={5} /> : null}
@@ -299,7 +299,7 @@ export function ApprovalRulesPage() {
) : null}
{!listQuery.isLoading && !listQuery.isError ? (
<div className="rounded-lg border border-slate-200">
<div className="rounded-lg border border-zinc-200">
<Table data-testid="approval-rules-table">
<TableHeader>
<tr>
@@ -316,18 +316,18 @@ export function ApprovalRulesPage() {
rules.map((rule) => (
<TableRow key={rule.id} data-testid="approval-rule-row">
<TableCell>
<div className="font-medium text-slate-900">{rule.name}</div>
<div className="font-mono text-xs text-slate-500">{rule.id}</div>
<div className="font-medium text-zinc-900">{rule.name}</div>
<div className="font-mono text-xs text-zinc-500">{rule.id}</div>
</TableCell>
<TableCell className="text-sm text-slate-700">
<TableCell className="text-sm text-zinc-700">
{formatAmount(rule.minAmount)} ~ {rule.maxAmount ? formatAmount(rule.maxAmount) : "∞"}
</TableCell>
<TableCell className="text-sm text-slate-700">
<TableCell className="text-sm text-zinc-700">
{[rule.level1Role, rule.level2Role, rule.level3Role].filter(Boolean).join(" -> ") || "-"}
</TableCell>
<TableCell>{rule.priority}</TableCell>
<TableCell className="text-sm">
{rule.enabled ? <span className="text-emerald-600">启用</span> : <span className="text-slate-500">停用</span>}
{rule.enabled ? <span className="text-emerald-600">启用</span> : <span className="text-zinc-500">停用</span>}
</TableCell>
<TableCell>
<div className="flex flex-wrap gap-2">
@@ -359,7 +359,7 @@ export function ApprovalRulesPage() {
))
) : (
<TableRow>
<TableCell className="py-3 text-slate-500" colSpan={6}>
<TableCell className="py-3 text-zinc-500" colSpan={6}>
暂无审批规则
</TableCell>
</TableRow>
@@ -430,7 +430,7 @@ export function ApprovalRulesPage() {
<select
id="editRuleLevel1"
data-testid="approval-rule-edit-level1"
className="h-11 w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm"
className="h-11 w-full rounded-lg border border-zinc-300 bg-white px-3 py-2 text-sm"
value={level1Role}
onChange={(event) => setLevel1Role(event.target.value as ApprovalRoleCode)}
>
@@ -447,7 +447,7 @@ export function ApprovalRulesPage() {
<select
id="editRuleLevel2"
data-testid="approval-rule-edit-level2"
className="h-11 w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm"
className="h-11 w-full rounded-lg border border-zinc-300 bg-white px-3 py-2 text-sm"
value={level2Role}
onChange={(event) => setLevel2Role(event.target.value as ApprovalRoleCode)}
>
@@ -465,7 +465,7 @@ export function ApprovalRulesPage() {
<select
id="editRuleLevel3"
data-testid="approval-rule-edit-level3"
className="h-11 w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm"
className="h-11 w-full rounded-lg border border-zinc-300 bg-white px-3 py-2 text-sm"
value={level3Role}
onChange={(event) => setLevel3Role(event.target.value as ApprovalRoleCode)}
>
+11 -11
查看文件
@@ -137,10 +137,10 @@ export function AuditLogsPage() {
<section className="card-std space-y-4">
<div className="grid gap-3 md:grid-cols-3">
<label className="text-sm text-slate-700">
<label className="text-sm text-zinc-700">
Action
<input
className="mt-1 w-full rounded-lg border border-slate-300 px-3 py-2"
className="mt-1 w-full rounded-lg border border-zinc-300 px-3 py-2"
onChange={(event) => {
setPage(1);
setActionFilter(event.target.value.trim());
@@ -150,10 +150,10 @@ export function AuditLogsPage() {
/>
</label>
<label className="text-sm text-slate-700">
<label className="text-sm text-zinc-700">
Target Type
<input
className="mt-1 w-full rounded-lg border border-slate-300 px-3 py-2"
className="mt-1 w-full rounded-lg border border-zinc-300 px-3 py-2"
onChange={(event) => {
setPage(1);
setTargetTypeFilter(event.target.value.trim());
@@ -163,9 +163,9 @@ export function AuditLogsPage() {
/>
</label>
<div className="text-sm text-slate-700">
<div className="text-sm text-zinc-700">
结果统计
<div className="mt-1 rounded-lg border border-slate-200 bg-slate-50 px-3 py-2 text-slate-900">
<div className="mt-1 rounded-lg border border-zinc-200 bg-zinc-50 px-3 py-2 text-zinc-900">
共 {data?.total ?? 0} 条
</div>
</div>
@@ -177,9 +177,9 @@ export function AuditLogsPage() {
</p>
) : null}
<div className="overflow-x-auto rounded-lg border border-slate-200">
<div className="overflow-x-auto rounded-lg border border-zinc-200">
<table className="min-w-full text-left text-sm">
<thead className="bg-slate-50 text-slate-600">
<thead className="bg-zinc-50 text-zinc-600">
<tr>
<th className="px-3 py-2">时间</th>
<th className="px-3 py-2">Action</th>
@@ -199,12 +199,12 @@ export function AuditLogsPage() {
{!loading && data?.items?.length ? (
data.items.map((item) => (
<tr className="border-t border-slate-100" key={item.id}>
<tr className="border-t border-zinc-100" key={item.id}>
<td className="px-3 py-2">{new Date(item.createdAt).toLocaleString()}</td>
<td className="px-3 py-2">{item.action}</td>
<td className="px-3 py-2">
<div>{item.actorName || item.actorId}</div>
<div className="text-xs text-slate-500">{item.actorEmail}</div>
<div className="text-xs text-zinc-500">{item.actorEmail}</div>
</td>
<td className="px-3 py-2">
{item.targetType}
@@ -217,7 +217,7 @@ export function AuditLogsPage() {
{!loading && !(data?.items?.length ?? 0) ? (
<tr>
<td className="px-3 py-3 text-slate-500" colSpan={5}>
<td className="px-3 py-3 text-zinc-500" colSpan={5}>
暂无数据
</td>
</tr>
+18 -18
查看文件
@@ -118,7 +118,7 @@ export function BudgetsPage() {
return (
<div className="space-y-4">
<PageHeader title="预算管理" subtitle="你当前没有预算权限,请联系管理员开通。" />
<Card className="p-6 text-sm text-slate-600">所需权限:budget.view 或 budget.manage</Card>
<Card className="p-6 text-sm text-zinc-600">所需权限:budget.view 或 budget.manage</Card>
</div>
);
}
@@ -139,10 +139,10 @@ export function BudgetsPage() {
) : null}
<Card className="space-y-3 p-6">
<h3 className="text-base font-semibold text-slate-900">筛选条件</h3>
<h3 className="text-base font-semibold text-zinc-900">筛选条件</h3>
<div className="grid gap-3 md:grid-cols-3">
<select
className="h-11 rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm"
className="h-11 rounded-lg border border-zinc-300 bg-white px-3 py-2 text-sm"
value={status}
onChange={(event) => {
setStatus(event.target.value as "active" | "archived" | "");
@@ -155,7 +155,7 @@ export function BudgetsPage() {
</select>
<select
className="h-11 rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm"
className="h-11 rounded-lg border border-zinc-300 bg-white px-3 py-2 text-sm"
value={departmentId}
onChange={(event) => {
setDepartmentId(event.target.value);
@@ -182,22 +182,22 @@ export function BudgetsPage() {
{canManageBudget ? (
<Card className="space-y-3 p-6">
<h3 className="text-base font-semibold text-slate-900">新建预算池</h3>
<h3 className="text-base font-semibold text-zinc-900">新建预算池</h3>
<div className="grid gap-3 md:grid-cols-3">
<input
className="h-11 rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm"
className="h-11 rounded-lg border border-zinc-300 bg-white px-3 py-2 text-sm"
placeholder="编码(例如 BGT-2026-RD)"
value={code}
onChange={(event) => setCode(event.target.value)}
/>
<input
className="h-11 rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm"
className="h-11 rounded-lg border border-zinc-300 bg-white px-3 py-2 text-sm"
placeholder="名称"
value={name}
onChange={(event) => setName(event.target.value)}
/>
<select
className="h-11 rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm"
className="h-11 rounded-lg border border-zinc-300 bg-white px-3 py-2 text-sm"
value={formDepartmentId}
onChange={(event) => setFormDepartmentId(event.target.value)}
>
@@ -209,25 +209,25 @@ export function BudgetsPage() {
))}
</select>
<input
className="h-11 rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm"
className="h-11 rounded-lg border border-zinc-300 bg-white px-3 py-2 text-sm"
type="date"
value={periodStart}
onChange={(event) => setPeriodStart(event.target.value)}
/>
<input
className="h-11 rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm"
className="h-11 rounded-lg border border-zinc-300 bg-white px-3 py-2 text-sm"
type="date"
value={periodEnd}
onChange={(event) => setPeriodEnd(event.target.value)}
/>
<input
className="h-11 rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm"
className="h-11 rounded-lg border border-zinc-300 bg-white px-3 py-2 text-sm"
placeholder="预算总额(例如 100000.00)"
value={allocatedAmount}
onChange={(event) => setAllocatedAmount(event.target.value)}
/>
<input
className="h-11 rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm"
className="h-11 rounded-lg border border-zinc-300 bg-white px-3 py-2 text-sm"
type="number"
min={1}
max={100}
@@ -254,13 +254,13 @@ export function BudgetsPage() {
) : null}
<Card className="space-y-3 p-6">
<h3 className="text-base font-semibold text-slate-900">预算池列表</h3>
<h3 className="text-base font-semibold text-zinc-900">预算池列表</h3>
{budgetsQuery.isLoading ? <TableSkeleton columns={7} rows={4} /> : null}
{!budgetsQuery.isLoading ? (
<>
<div className="rounded-lg border border-slate-200">
<div className="rounded-lg border border-zinc-200">
<Table>
<TableHeader>
<TableRow>
@@ -277,7 +277,7 @@ export function BudgetsPage() {
{(budgetsQuery.data?.items ?? []).length ? (
(budgetsQuery.data?.items ?? []).map((item) => (
<TableRow key={item.id}>
<TableCell className="font-medium text-slate-900">{item.code}</TableCell>
<TableCell className="font-medium text-zinc-900">{item.code}</TableCell>
<TableCell>{item.name}</TableCell>
<TableCell><StatusBadge status={item.status} /></TableCell>
<TableCell>
@@ -285,7 +285,7 @@ export function BudgetsPage() {
</TableCell>
<TableCell>
{item.usedAmount} / {item.allocatedAmount}
<div className="text-xs text-slate-500">剩余 {item.remainingAmount}</div>
<div className="text-xs text-zinc-500">剩余 {item.remainingAmount}</div>
</TableCell>
<TableCell>{item.warningThresholdPercent}%</TableCell>
<TableCell>
@@ -300,14 +300,14 @@ export function BudgetsPage() {
归档
</Button>
) : (
<span className="text-xs text-slate-400">-</span>
<span className="text-xs text-zinc-400">-</span>
)}
</TableCell>
</TableRow>
))
) : (
<TableRow>
<TableCell className="py-3 text-slate-500" colSpan={7}>
<TableCell className="py-3 text-zinc-500" colSpan={7}>
暂无预算池
</TableCell>
</TableRow>
+1 -1
查看文件
@@ -46,7 +46,7 @@ export function ChangePasswordPage() {
<Card className="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-slate-900">修改密码</h1>
<h1 className="text-2xl font-bold text-zinc-900">修改密码</h1>
<p className="text-sm text-secondary">
为了账号安全,请先修改初始密码后再进入系统。
</p>
+29 -29
查看文件
@@ -117,8 +117,8 @@ export function DashboardPage() {
<div className="space-y-4">
<PageHeader title="仪表盘" subtitle="你当前没有看板权限,请联系管理员开通。" />
<Card className="space-y-2 p-6 text-sm">
<p className="text-slate-700">当前用户:{me?.name ?? "-"}</p>
<p className="text-slate-500">所需权限:report.dashboard.view</p>
<p className="text-zinc-700">当前用户:{me?.name ?? "-"}</p>
<p className="text-zinc-500">所需权限:report.dashboard.view</p>
</Card>
</div>
);
@@ -166,36 +166,36 @@ export function DashboardPage() {
<Card className="space-y-4 p-6">
<div className="grid gap-3 md:grid-cols-4">
<div className="space-y-1">
<label className="text-xs text-slate-600" htmlFor="dashboard-date-from">
<label className="text-xs text-zinc-600" htmlFor="dashboard-date-from">
开始日期
</label>
<input
id="dashboard-date-from"
className="h-11 w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm"
className="h-11 w-full rounded-lg border border-zinc-300 bg-white px-3 py-2 text-sm"
type="date"
value={dateFrom}
onChange={(event) => setDateFrom(event.target.value)}
/>
</div>
<div className="space-y-1">
<label className="text-xs text-slate-600" htmlFor="dashboard-date-to">
<label className="text-xs text-zinc-600" htmlFor="dashboard-date-to">
结束日期
</label>
<input
id="dashboard-date-to"
className="h-11 w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm"
className="h-11 w-full rounded-lg border border-zinc-300 bg-white px-3 py-2 text-sm"
type="date"
value={dateTo}
onChange={(event) => setDateTo(event.target.value)}
/>
</div>
<div className="space-y-1">
<label className="text-xs text-slate-600" htmlFor="dashboard-department-id">
<label className="text-xs text-zinc-600" htmlFor="dashboard-department-id">
部门
</label>
<select
id="dashboard-department-id"
className="h-11 w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm"
className="h-11 w-full rounded-lg border border-zinc-300 bg-white px-3 py-2 text-sm"
value={departmentId}
onChange={(event) => setDepartmentId(event.target.value)}
>
@@ -230,26 +230,26 @@ export function DashboardPage() {
<div className="grid gap-4 md:grid-cols-4">
<Card className="p-4">
<p className="text-xs text-slate-500">报销单总数</p>
<p className="mt-1 text-2xl font-semibold text-slate-900">
<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>
</Card>
<Card className="p-4">
<p className="text-xs text-slate-500">报销总金额</p>
<p className="mt-1 text-2xl font-semibold text-slate-900">
<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>
</Card>
<Card className="p-4">
<p className="text-xs text-slate-500">已付款金额</p>
<p className="mt-1 text-2xl font-semibold text-slate-900">
<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>
</Card>
<Card className="p-4">
<p className="text-xs text-slate-500">审批中数量</p>
<p className="mt-1 text-2xl font-semibold text-slate-900">
<p className="text-xs text-zinc-500">审批中数量</p>
<p className="mt-1 text-2xl font-semibold text-zinc-900">
{loading ? "..." : overviewQuery.data?.reviewingCount ?? 0}
</p>
</Card>
@@ -257,7 +257,7 @@ export function DashboardPage() {
<div className="grid gap-4 lg:grid-cols-2">
<Card className="space-y-3 p-6">
<h3 className="text-base font-semibold text-slate-900">费用趋势</h3>
<h3 className="text-base font-semibold text-zinc-900">费用趋势</h3>
{trendPoints.length ? (
<div className="space-y-2">
{trendPoints.map((item) => {
@@ -265,13 +265,13 @@ export function DashboardPage() {
const width = `${Math.max(5, Math.round((amount / maxTrendAmount) * 100))}%`;
return (
<div key={item.date} className="space-y-1">
<div className="flex items-center justify-between text-xs text-slate-600">
<div className="flex items-center justify-between text-xs text-zinc-600">
<span>{item.date}</span>
<span>
{toCurrency(item.amount)} / {item.count} 笔
</span>
</div>
<div className="h-2 rounded-full bg-slate-100">
<div className="h-2 rounded-full bg-zinc-100">
<div className="h-2 rounded-full bg-primary" style={{ width }} />
</div>
</div>
@@ -279,12 +279,12 @@ export function DashboardPage() {
})}
</div>
) : (
<p className="text-sm text-slate-500">暂无趋势数据</p>
<p className="text-sm text-zinc-500">暂无趋势数据</p>
)}
</Card>
<Card className="space-y-3 p-6">
<h3 className="text-base font-semibold text-slate-900">费用分类 TopN</h3>
<h3 className="text-base font-semibold text-zinc-900">费用分类 TopN</h3>
{topCategories.length ? (
<div className="space-y-2">
{topCategories.map((item) => {
@@ -292,7 +292,7 @@ export function DashboardPage() {
const width = `${Math.max(5, Math.round((amount / maxCategoryAmount) * 100))}%`;
return (
<div key={item.code} className="space-y-1">
<div className="flex items-center justify-between text-xs text-slate-600">
<div className="flex items-center justify-between text-xs text-zinc-600">
<span>
{item.name} ({item.code})
</span>
@@ -300,7 +300,7 @@ export function DashboardPage() {
{toCurrency(item.amount)} / {item.count} 笔
</span>
</div>
<div className="h-2 rounded-full bg-slate-100">
<div className="h-2 rounded-full bg-zinc-100">
<div className="h-2 rounded-full bg-emerald-500" style={{ width }} />
</div>
</div>
@@ -308,22 +308,22 @@ export function DashboardPage() {
})}
</div>
) : (
<p className="text-sm text-slate-500">暂无分类统计</p>
<p className="text-sm text-zinc-500">暂无分类统计</p>
)}
</Card>
</div>
<Card className="space-y-2 p-6 text-sm">
<h3 className="text-base font-semibold text-slate-900">审批效率</h3>
<p className="text-slate-700">
<h3 className="text-base font-semibold text-zinc-900">审批效率</h3>
<p className="text-zinc-700">
已统计通过单据:
<span className="ml-1 font-medium text-slate-900">
<span className="ml-1 font-medium text-zinc-900">
{approvalEfficiencyQuery.data?.approvedCount ?? 0}
</span>
</p>
<p className="text-slate-700">
<p className="text-zinc-700">
平均审批耗时(小时):
<span className="ml-1 font-medium text-slate-900">
<span className="ml-1 font-medium text-zinc-900">
{approvalEfficiencyQuery.data?.averageHours?.toFixed(2) ?? "0.00"}
</span>
</p>
+15 -15
查看文件
@@ -81,13 +81,13 @@ export function DelegationsPage() {
) : null}
<Card className="space-y-4 p-6">
<h3 className="text-base font-semibold text-slate-900">创建委派</h3>
<h3 className="text-base font-semibold text-zinc-900">创建委派</h3>
<div className="grid gap-3 md:grid-cols-2">
<label className="space-y-1 text-sm">
<span className="font-medium text-slate-700">委派给(审批人候选)</span>
<span className="font-medium text-zinc-700">委派给(审批人候选)</span>
<select
className="h-11 w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm"
className="h-11 w-full rounded-lg border border-zinc-300 bg-white px-3 py-2 text-sm"
data-testid="delegations-create-delegate"
onChange={(event) => setDelegateEmployeeId(event.target.value)}
value={delegateEmployeeId}
@@ -99,15 +99,15 @@ export function DelegationsPage() {
</option>
))}
</select>
<p className="text-xs text-slate-500">
<p className="text-xs text-zinc-500">
说明:当前 MVP 未接入员工搜索,这里先复用“转审候选”列表作为可选目标。
</p>
</label>
<label className="space-y-1 text-sm">
<span className="font-medium text-slate-700">范围</span>
<span className="font-medium text-zinc-700">范围</span>
<select
className="h-11 w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm"
className="h-11 w-full rounded-lg border border-zinc-300 bg-white px-3 py-2 text-sm"
data-testid="delegations-create-scope"
onChange={(event) => setScope(event.target.value as "all" | "reimbursement_submit")}
value={scope}
@@ -118,7 +118,7 @@ export function DelegationsPage() {
</label>
<label className="space-y-1 text-sm md:col-span-2">
<span className="font-medium text-slate-700">有效期结束(可选)</span>
<span className="font-medium text-zinc-700">有效期结束(可选)</span>
<Input
data-testid="delegations-create-valid-to"
onChange={(event) => setValidTo(event.target.value)}
@@ -142,9 +142,9 @@ export function DelegationsPage() {
<Card className="space-y-4 p-6">
<div className="flex flex-wrap items-center justify-between gap-2">
<h3 className="text-base font-semibold text-slate-900">我的委派</h3>
<h3 className="text-base font-semibold text-zinc-900">我的委派</h3>
<select
className="h-11 rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm"
className="h-11 rounded-lg border border-zinc-300 bg-white px-3 py-2 text-sm"
data-testid="delegations-status-filter"
onChange={(event) =>
setStatus(event.target.value as "active" | "scheduled" | "expired" | "revoked" | "all")
@@ -175,8 +175,8 @@ export function DelegationsPage() {
{listQuery.data ? (
<div className="space-y-6">
<div>
<p className="mb-2 text-sm font-medium text-slate-800">我发起的委派</p>
<div className="rounded-lg border border-slate-200">
<p className="mb-2 text-sm font-medium text-zinc-800">我发起的委派</p>
<div className="rounded-lg border border-zinc-200">
<Table data-testid="delegations-initiated-table">
<TableHeader>
<tr>
@@ -211,7 +211,7 @@ export function DelegationsPage() {
))
) : (
<TableRow>
<TableCell className="py-3 text-slate-500" colSpan={5}>
<TableCell className="py-3 text-zinc-500" colSpan={5}>
暂无数据
</TableCell>
</TableRow>
@@ -222,8 +222,8 @@ export function DelegationsPage() {
</div>
<div>
<p className="mb-2 text-sm font-medium text-slate-800">我接收的委派</p>
<div className="rounded-lg border border-slate-200">
<p className="mb-2 text-sm font-medium text-zinc-800">我接收的委派</p>
<div className="rounded-lg border border-zinc-200">
<Table data-testid="delegations-received-table">
<TableHeader>
<tr>
@@ -245,7 +245,7 @@ export function DelegationsPage() {
))
) : (
<TableRow>
<TableCell className="py-3 text-slate-500" colSpan={4}>
<TableCell className="py-3 text-zinc-500" colSpan={4}>
暂无数据
</TableCell>
</TableRow>
+9 -9
查看文件
@@ -104,7 +104,7 @@ export function DepartmentsPage() {
<Card className="space-y-4 p-6">
<div className="flex items-center justify-between gap-3">
<h3 className="text-base font-semibold text-slate-900">新建部门</h3>
<h3 className="text-base font-semibold text-zinc-900">新建部门</h3>
<Button
data-testid="departments-toggle-archived"
variant="secondary"
@@ -136,7 +136,7 @@ export function DepartmentsPage() {
<select
id="deptParent"
data-testid="departments-create-parent"
className="h-11 w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm"
className="h-11 w-full rounded-lg border border-zinc-300 bg-white px-3 py-2 text-sm"
value={parentId}
onChange={(event) => setParentId(event.target.value)}
>
@@ -165,7 +165,7 @@ export function DepartmentsPage() {
</Card>
<Card className="space-y-4 p-6">
<h3 className="text-base font-semibold text-slate-900">部门列表</h3>
<h3 className="text-base font-semibold text-zinc-900">部门列表</h3>
{listQuery.isLoading ? <TableSkeleton columns={4} rows={4} /> : null}
@@ -182,7 +182,7 @@ export function DepartmentsPage() {
) : null}
{!listQuery.isLoading && !listQuery.isError ? (
<div className="rounded-lg border border-slate-200">
<div className="rounded-lg border border-zinc-200">
<Table data-testid="departments-table">
<TableHeader>
<tr>
@@ -199,11 +199,11 @@ export function DepartmentsPage() {
return (
<TableRow data-testid="department-row" key={item.id}>
<TableCell>
<div className="font-medium text-slate-900">{item.name}</div>
<div className="text-xs text-slate-500 font-mono">{item.id}</div>
<div className="font-medium text-zinc-900">{item.name}</div>
<div className="text-xs text-zinc-500 font-mono">{item.id}</div>
</TableCell>
<TableCell>{parentName}</TableCell>
<TableCell className="text-xs text-slate-600">
<TableCell className="text-xs text-zinc-600">
{item.archivedAt ? item.archivedAt.slice(0, 19).replace("T", " ") : "-"}
</TableCell>
<TableCell>
@@ -219,7 +219,7 @@ export function DepartmentsPage() {
归档
</Button>
) : (
<span className="text-xs text-slate-500">已归档</span>
<span className="text-xs text-zinc-500">已归档</span>
)}
</TableCell>
</TableRow>
@@ -227,7 +227,7 @@ export function DepartmentsPage() {
})
) : (
<TableRow>
<TableCell className="py-3 text-slate-500" colSpan={4}>
<TableCell className="py-3 text-zinc-500" colSpan={4}>
暂无部门
</TableCell>
</TableRow>
+16 -16
查看文件
@@ -140,7 +140,7 @@ export function FeatureFlagsPage() {
) : null}
<Card className="space-y-4 p-6">
<h3 className="text-base font-semibold text-slate-900">开关列表</h3>
<h3 className="text-base font-semibold text-zinc-900">开关列表</h3>
{flagsQuery.isLoading ? <TableSkeleton columns={6} rows={2} /> : null}
@@ -157,7 +157,7 @@ export function FeatureFlagsPage() {
) : null}
{!flagsQuery.isLoading && !flagsQuery.isError ? (
<div className="rounded-lg border border-slate-200">
<div className="rounded-lg border border-zinc-200">
<Table data-testid="feature-flags-table">
<TableHeader>
<tr>
@@ -177,8 +177,8 @@ export function FeatureFlagsPage() {
return (
<TableRow key={item.flagKey} data-testid={`feature-flag-row-${item.flagKey}`}>
<TableCell>
<div className="font-medium text-slate-900">{toDisplayName(item.flagKey)}</div>
<div className="font-mono text-xs text-slate-500">{item.flagKey}</div>
<div className="font-medium text-zinc-900">{toDisplayName(item.flagKey)}</div>
<div className="font-mono text-xs text-zinc-500">{item.flagKey}</div>
</TableCell>
<TableCell className="text-sm">
@@ -194,14 +194,14 @@ export function FeatureFlagsPage() {
{item.effectiveEnabled ? "ON" : "OFF"}
</span>
</div>
<div className="text-xs text-slate-500">reason: {item.effectiveReason}</div>
<div className="text-xs text-zinc-500">reason: {item.effectiveReason}</div>
</TableCell>
<TableCell className="space-y-2 text-sm">
<div>
<Label className="mb-1 block text-xs text-slate-500">override</Label>
<Label className="mb-1 block text-xs text-zinc-500">override</Label>
<select
className="h-10 w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm"
className="h-10 w-full rounded-lg border border-zinc-300 bg-white px-3 py-2 text-sm"
value={draft.overrideMode}
onChange={(event) =>
patchDraft(item.flagKey, (prev) => ({
@@ -219,9 +219,9 @@ export function FeatureFlagsPage() {
</div>
<div>
<Label className="mb-1 block text-xs text-slate-500">rollout</Label>
<Label className="mb-1 block text-xs text-zinc-500">rollout</Label>
<select
className="h-10 w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm"
className="h-10 w-full rounded-lg border border-zinc-300 bg-white px-3 py-2 text-sm"
value={draft.rolloutType}
onChange={(event) =>
patchDraft(item.flagKey, (prev) => ({
@@ -247,7 +247,7 @@ export function FeatureFlagsPage() {
{draft.rolloutType === "department_allowlist" ? (
<div className="space-y-2">
<select
className="h-10 w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm"
className="h-10 w-full rounded-lg border border-zinc-300 bg-white px-3 py-2 text-sm"
value=""
onChange={(event) => {
const selected = event.target.value;
@@ -266,12 +266,12 @@ export function FeatureFlagsPage() {
))}
</select>
<div className="max-h-24 overflow-auto rounded border border-slate-200 p-2 text-xs">
<div className="max-h-24 overflow-auto rounded border border-zinc-200 p-2 text-xs">
{draft.departmentIds.length ? (
draft.departmentIds.map((departmentId) => (
<div
key={departmentId}
className="mb-1 flex items-center justify-between rounded bg-slate-50 px-2 py-1"
className="mb-1 flex items-center justify-between rounded bg-zinc-50 px-2 py-1"
>
<span>{departmentsById.get(departmentId) ?? departmentId}</span>
<button
@@ -289,18 +289,18 @@ export function FeatureFlagsPage() {
</div>
))
) : (
<p className="text-slate-500">暂无白名单部门</p>
<p className="text-zinc-500">暂无白名单部门</p>
)}
</div>
</div>
) : (
<span className="text-slate-500">全量</span>
<span className="text-zinc-500">全量</span>
)}
</TableCell>
<TableCell>
<textarea
className="min-h-24 w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm"
className="min-h-24 w-full rounded-lg border border-zinc-300 bg-white px-3 py-2 text-sm"
placeholder="填写本次变更说明"
value={draft.note}
onChange={(event) =>
@@ -310,7 +310,7 @@ export function FeatureFlagsPage() {
}))
}
/>
<p className="mt-1 text-xs text-slate-500">version: {draft.version}</p>
<p className="mt-1 text-xs text-zinc-500">version: {draft.version}</p>
</TableCell>
<TableCell>
+1 -1
查看文件
@@ -5,7 +5,7 @@ export function ForbiddenPage() {
<div className="flex min-h-screen items-center justify-center bg-background-light p-6">
<div className="card-std max-w-lg text-center">
<p className="text-sm font-semibold uppercase tracking-wide text-primary">403</p>
<h1 className="mt-2 text-2xl font-bold text-slate-900">无权限访问</h1>
<h1 className="mt-2 text-2xl font-bold text-zinc-900">无权限访问</h1>
<p className="mt-2 text-sm text-secondary">
当前账号没有访问该页面的权限,请联系管理员或返回可访问页面。
</p>
+2 -2
查看文件
@@ -62,9 +62,9 @@ export function LoginPage() {
<Card className="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-slate-900">登录工作台</h1>
<h1 className="mt-2 text-2xl font-bold text-zinc-900">登录工作台</h1>
<p className="mt-2 text-sm text-secondary">使用邮箱/手机号与密码登录。</p>
<p className="mt-1 text-xs text-slate-500">忘记密码:请联系管理员重置。</p>
<p className="mt-1 text-xs text-zinc-500">忘记密码:请联系管理员重置。</p>
</div>
<form className="space-y-4" onSubmit={handleSubmit}>
+13 -13
查看文件
@@ -108,12 +108,12 @@ export function MobileApprovalsPage() {
) : null}
<Card className="space-y-3 p-4" data-testid="mobile-approvals-list">
<h3 className="text-base font-semibold text-slate-900">待办任务</h3>
<h3 className="text-base font-semibold text-zinc-900">待办任务</h3>
{tasksQuery.isLoading ? <div className="flex items-center gap-2 text-sm text-slate-500"><Spinner size="sm" />加载中...</div> : null}
{tasksQuery.isLoading ? <div className="flex items-center gap-2 text-sm text-zinc-500"><Spinner size="sm" />加载中...</div> : null}
{!tasksQuery.isLoading && pendingTasks.length === 0 ? (
<p className="text-sm text-slate-500">暂无待办任务。</p>
<p className="text-sm text-zinc-500">暂无待办任务。</p>
) : null}
<div className="space-y-2">
@@ -123,32 +123,32 @@ export function MobileApprovalsPage() {
className={`w-full rounded-lg border px-3 py-2 text-left text-sm ${
selectedTaskId === task.id
? "border-primary bg-primary-50 text-primary"
: "border-slate-200 bg-white text-slate-800"
: "border-zinc-200 bg-white text-zinc-800"
}`}
data-testid={`mobile-approvals-task-${task.id}`}
onClick={() => setSelectedTaskId(task.id)}
type="button"
>
<div className="font-medium">{task.stepName}</div>
<div className="text-xs text-slate-500">任务ID: {task.id}</div>
<div className="text-xs text-slate-500">状态: {task.status}</div>
<div className="text-xs text-zinc-500">任务ID: {task.id}</div>
<div className="text-xs text-zinc-500">状态: {task.status}</div>
</button>
))}
</div>
</Card>
<Card className="space-y-3 p-4" data-testid="mobile-approvals-detail">
<h3 className="text-base font-semibold text-slate-900">任务详情与动作</h3>
<h3 className="text-base font-semibold text-zinc-900">任务详情与动作</h3>
{!selectedTaskId ? <p className="text-sm text-slate-500">请先选择任务。</p> : null}
{!selectedTaskId ? <p className="text-sm text-zinc-500">请先选择任务。</p> : null}
{selectedTaskId && detailQuery.isLoading ? (
<p className="text-sm text-slate-500">加载任务详情中...</p>
<p className="text-sm text-zinc-500">加载任务详情中...</p>
) : null}
{selectedTask && (
<>
<div className="rounded-lg border border-slate-200 p-3 text-sm">
<div className="rounded-lg border border-zinc-200 p-3 text-sm">
<div>任务状态:{selectedTask.task.status}</div>
<div>步骤:{selectedTask.task.stepName}</div>
<div>报销单号:{selectedTask.reimbursement?.formNumber ?? "-"}</div>
@@ -193,10 +193,10 @@ export function MobileApprovalsPage() {
</Button>
</div>
<div className="space-y-2 rounded-lg border border-slate-200 p-3 text-sm">
<p className="font-medium text-slate-800">转审</p>
<div className="space-y-2 rounded-lg border border-zinc-200 p-3 text-sm">
<p className="font-medium text-zinc-800">转审</p>
<select
className="h-10 w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm"
className="h-10 w-full rounded-lg border border-zinc-300 bg-white px-3 py-2 text-sm"
data-testid="mobile-approvals-transfer-to"
onChange={(event) => setTransferToApproverId(event.target.value)}
value={transferToApproverId}
+9 -9
查看文件
@@ -142,7 +142,7 @@ export function MobileCapturePage() {
<Card className="space-y-3 p-4">
<div className="flex items-center justify-between">
<h3 className="text-base font-semibold text-slate-900">拍照/选择文件</h3>
<h3 className="text-base font-semibold text-zinc-900">拍照/选择文件</h3>
<span className={isOnline ? "text-emerald-600" : "text-orange-600"}>
{isOnline ? "在线" : "离线"}
</span>
@@ -160,7 +160,7 @@ export function MobileCapturePage() {
type="file"
/>
<div className="text-sm text-slate-600">
<div className="text-sm text-zinc-600">
当前文件:{selectedFile ? `${selectedFile.name} (${Math.ceil(selectedFile.size / 1024)} KB)` : "未选择"}
</div>
@@ -216,20 +216,20 @@ export function MobileCapturePage() {
<Card className="space-y-3 p-4" data-testid="mobile-capture-queue">
<div className="flex items-center justify-between">
<h3 className="text-base font-semibold text-slate-900">离线上传队列</h3>
<span className="text-sm text-slate-500">{queuedCountLabel}</span>
<h3 className="text-base font-semibold text-zinc-900">离线上传队列</h3>
<span className="text-sm text-zinc-500">{queuedCountLabel}</span>
</div>
{queueQuery.isLoading ? <div className="flex items-center gap-2 text-sm text-slate-500"><Spinner size="sm" />加载中...</div> : null}
{queueQuery.isLoading ? <div className="flex items-center gap-2 text-sm text-zinc-500"><Spinner size="sm" />加载中...</div> : null}
{!queueQuery.isLoading && queuedItems.length === 0 ? (
<p className="text-sm text-slate-500">暂无待上传文件。</p>
<p className="text-sm text-zinc-500">暂无待上传文件。</p>
) : null}
{queuedItems.map((item) => (
<div key={item.id} className="rounded-lg border border-slate-200 px-3 py-2 text-sm">
<div className="font-medium text-slate-800">{item.fileName}</div>
<div className="text-slate-500">创建时间:{formatTime(item.createdAt)}</div>
<div key={item.id} className="rounded-lg border border-zinc-200 px-3 py-2 text-sm">
<div className="font-medium text-zinc-800">{item.fileName}</div>
<div className="text-zinc-500">创建时间:{formatTime(item.createdAt)}</div>
<div className="mt-2">
<Button
data-testid={`mobile-capture-remove-${item.id}`}
+1 -1
查看文件
@@ -5,7 +5,7 @@ export function NotFoundPage() {
<div className="flex min-h-screen items-center justify-center bg-background-light p-6">
<div className="card-std max-w-lg text-center">
<p className="text-sm font-semibold uppercase tracking-wide text-primary">404</p>
<h1 className="mt-2 text-2xl font-bold text-slate-900">页面不存在</h1>
<h1 className="mt-2 text-2xl font-bold text-zinc-900">页面不存在</h1>
<p className="mt-2 text-sm text-secondary">请检查地址,或返回工作台首页继续操作。</p>
<div className="mt-5 flex justify-center">
<Link className="btn-primary" to="/dashboard">
+7 -7
查看文件
@@ -102,7 +102,7 @@ export function NotificationsPage() {
</TabsList>
</Tabs>
<div className="text-sm text-slate-600">
<div className="text-sm text-zinc-600">
未读 {listQuery.data?.unreadCount ?? 0} 条
</div>
</div>
@@ -122,7 +122,7 @@ export function NotificationsPage() {
) : null}
{!listQuery.isLoading && !listQuery.isError ? (
<div className="rounded-lg border border-slate-200">
<div className="rounded-lg border border-zinc-200">
<Table data-testid="notifications-table">
<TableHeader>
<tr>
@@ -139,15 +139,15 @@ export function NotificationsPage() {
return (
<TableRow data-testid="notification-row" key={item.id}>
<TableCell>
<div className="font-medium text-slate-900">{item.title}</div>
<div className="font-medium text-zinc-900">{item.title}</div>
{item.body ? (
<div className="mt-1 text-xs text-slate-500">{item.body}</div>
<div className="mt-1 text-xs text-zinc-500">{item.body}</div>
) : null}
</TableCell>
<TableCell className="text-xs text-slate-600">
<TableCell className="text-xs text-zinc-600">
{item.createdAt.slice(0, 19).replace("T", " ")}
</TableCell>
<TableCell className="text-xs text-slate-600">
<TableCell className="text-xs text-zinc-600">
{item.readAt ? "已读" : "未读"}
</TableCell>
<TableCell>
@@ -177,7 +177,7 @@ export function NotificationsPage() {
})
) : (
<TableRow>
<TableCell className="py-3 text-slate-500" colSpan={4}>
<TableCell className="py-3 text-zinc-500" colSpan={4}>
暂无通知
</TableCell>
</TableRow>
+7 -7
查看文件
@@ -10,30 +10,30 @@ export function ProfilePage() {
<section className="card-std">
<h3 className="card-title">个人信息</h3>
<dl className="grid gap-3 text-sm text-slate-700 md:grid-cols-2">
<dl className="grid gap-3 text-sm text-zinc-700 md:grid-cols-2">
<div>
<dt className="text-secondary">姓名</dt>
<dd className="font-medium text-slate-900">{me?.name ?? "-"}</dd>
<dd className="font-medium text-zinc-900">{me?.name ?? "-"}</dd>
</div>
<div>
<dt className="text-secondary">员工号</dt>
<dd className="font-medium text-slate-900">{me?.employeeNo ?? "-"}</dd>
<dd className="font-medium text-zinc-900">{me?.employeeNo ?? "-"}</dd>
</div>
<div>
<dt className="text-secondary">邮箱</dt>
<dd className="font-medium text-slate-900">{me?.email ?? "-"}</dd>
<dd className="font-medium text-zinc-900">{me?.email ?? "-"}</dd>
</div>
<div>
<dt className="text-secondary">手机号</dt>
<dd className="font-medium text-slate-900">{me?.phone ?? "-"}</dd>
<dd className="font-medium text-zinc-900">{me?.phone ?? "-"}</dd>
</div>
<div>
<dt className="text-secondary">部门ID</dt>
<dd className="font-medium text-slate-900">{me?.departmentId ?? "-"}</dd>
<dd className="font-medium text-zinc-900">{me?.departmentId ?? "-"}</dd>
</div>
<div>
<dt className="text-secondary">直属上级ID</dt>
<dd className="font-medium text-slate-900">{me?.directManagerId ?? "-"}</dd>
<dd className="font-medium text-zinc-900">{me?.directManagerId ?? "-"}</dd>
</div>
</dl>
</section>
+14 -14
查看文件
@@ -292,7 +292,7 @@ export function ReimbursementDetailPage() {
{budgetHint ? (
<Card className="space-y-2 p-6 text-sm" data-testid="reimbursement-budget-hint">
<h3 className="text-base font-semibold text-slate-900">预算提示</h3>
<h3 className="text-base font-semibold text-zinc-900">预算提示</h3>
<div>预算池:{budgetHint.budgetCode} / {budgetHint.budgetName}</div>
<div>
本次提交后预计占用:{budgetHint.nextUsedAmount} / {budgetHint.allocatedAmount}
@@ -308,7 +308,7 @@ export function ReimbursementDetailPage() {
当前金额已达到预算预警阈值,提交后会记录预算预警审计。
</p>
) : (
<p className="text-slate-500">当前预算充足,可继续提交。</p>
<p className="text-zinc-500">当前预算充足,可继续提交。</p>
)}
</Card>
) : null}
@@ -316,8 +316,8 @@ export function ReimbursementDetailPage() {
<Card className="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-slate-900">报销明细</h3>
<p className="text-xs text-slate-500">明细变更会自动重算总金额。</p>
<h3 className="text-base font-semibold text-zinc-900">报销明细</h3>
<p className="text-xs text-zinc-500">明细变更会自动重算总金额。</p>
</div>
{canEditItems ? (
@@ -331,7 +331,7 @@ export function ReimbursementDetailPage() {
新增明细
</Button>
) : (
<p className="text-xs text-slate-500">当前状态不可编辑明细</p>
<p className="text-xs text-zinc-500">当前状态不可编辑明细</p>
)}
</div>
@@ -344,7 +344,7 @@ export function ReimbursementDetailPage() {
</p>
) : null}
<div className="rounded-lg border border-slate-200">
<div className="rounded-lg border border-zinc-200">
<Table data-testid="reimbursement-items-table">
<TableHeader>
<tr>
@@ -360,10 +360,10 @@ export function ReimbursementDetailPage() {
detail.items.map((item) => (
<TableRow data-testid="reimbursement-item-row" key={item.id}>
<TableCell>
<div className="font-medium text-slate-900">
<div className="font-medium text-zinc-900">
{item.expenseType?.name ?? item.expenseTypeId}
</div>
<div className="text-xs text-slate-500">{item.expenseType?.code ?? "-"}</div>
<div className="text-xs text-zinc-500">{item.expenseType?.code ?? "-"}</div>
</TableCell>
<TableCell>{item.expenseDate ?? "-"}</TableCell>
<TableCell>{item.amount}</TableCell>
@@ -397,7 +397,7 @@ export function ReimbursementDetailPage() {
))
) : (
<TableRow>
<TableCell className="py-3 text-slate-500" colSpan={5}>
<TableCell className="py-3 text-zinc-500" colSpan={5}>
暂无明细
</TableCell>
</TableRow>
@@ -431,20 +431,20 @@ export function ReimbursementDetailPage() {
/>
<Card className="space-y-2 p-6" data-testid="reimbursement-invoices">
<h3 className="text-base font-semibold text-slate-900">关联票据</h3>
<h3 className="text-base font-semibold text-zinc-900">关联票据</h3>
{(detail.invoices ?? []).length ? (
<div className="space-y-2 text-sm">
{detail.invoices.map((item) => (
<div className="rounded-lg border border-slate-200 px-3 py-2" key={item.id}>
<div className="font-medium text-slate-900">{item.id}</div>
<div className="text-slate-600">
<div className="rounded-lg border border-zinc-200 px-3 py-2" key={item.id}>
<div className="font-medium text-zinc-900">{item.id}</div>
<div className="text-zinc-600">
状态 {item.status} / 发票 {item.invoiceCode || "-"}-{item.invoiceNumber || "-"}
</div>
</div>
))}
</div>
) : (
<p className="text-sm text-slate-500">暂无关联票据</p>
<p className="text-sm text-zinc-500">暂无关联票据</p>
)}
</Card>
+1 -1
查看文件
@@ -97,7 +97,7 @@ export function ReimbursementsPage() {
<div className="flex flex-col gap-2 sm:flex-row sm:items-center">
{showProxyOwnerSelector ? (
<select
className="h-11 rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm"
className="h-11 rounded-lg border border-zinc-300 bg-white px-3 py-2 text-sm"
data-testid="reimbursements-owner-select"
onChange={(event) => setProxyOwnerEmployeeId(event.target.value)}
value={proxyOwnerEmployeeId}
+6 -6
查看文件
@@ -189,7 +189,7 @@ export function UserManagementPage() {
placeholder="搜索工号/姓名/手机号/邮箱"
/>
<select
className="h-11 rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm"
className="h-11 rounded-lg border border-zinc-300 bg-white px-3 py-2 text-sm"
data-testid="users-status-filter"
value={status}
onChange={(e) => {
@@ -216,7 +216,7 @@ export function UserManagementPage() {
</p>
) : null}
<div className="rounded-lg border border-slate-200">
<div className="rounded-lg border border-zinc-200">
<Table data-testid="users-table">
<TableHeader>
<tr>
@@ -232,14 +232,14 @@ export function UserManagementPage() {
listQuery.data?.items.map((item) => (
<TableRow data-testid="users-row" key={item.id}>
<TableCell>
<div className="font-medium text-slate-900">
<div className="font-medium text-zinc-900">
{item.employeeNo} / {item.name}
</div>
<div className="text-xs text-slate-500 font-mono">{item.id}</div>
<div className="text-xs text-zinc-500 font-mono">{item.id}</div>
</TableCell>
<TableCell className="text-sm">
<div>{item.email}</div>
<div className="text-slate-500">{item.phone}</div>
<div className="text-zinc-500">{item.phone}</div>
</TableCell>
<TableCell><StatusBadge status={item.status} /></TableCell>
<TableCell className="text-xs">{formatRoleCodes(item.roleCodes)}</TableCell>
@@ -283,7 +283,7 @@ export function UserManagementPage() {
))
) : (
<TableRow>
<TableCell colSpan={5} className="py-3 text-slate-500">
<TableCell colSpan={5} className="py-3 text-zinc-500">
暂无数据
</TableCell>
</TableRow>
+14 -14
查看文件
@@ -157,7 +157,7 @@ export function WorkflowTaskDetailPage() {
</Card>
<Card className="space-y-4 p-6">
<h3 className="text-base font-semibold text-slate-900">审批动作</h3>
<h3 className="text-base font-semibold text-zinc-900">审批动作</h3>
{actionError ? (
<p
@@ -179,8 +179,8 @@ export function WorkflowTaskDetailPage() {
</Button>
</div>
<div className="space-y-2 rounded-lg border border-slate-200 p-4">
<p className="text-sm font-medium text-slate-800">驳回</p>
<div className="space-y-2 rounded-lg border border-zinc-200 p-4">
<p className="text-sm font-medium text-zinc-800">驳回</p>
<Textarea
data-testid="workflow-task-reject-comment"
onChange={(event) => setRejectComment(event.target.value)}
@@ -198,8 +198,8 @@ export function WorkflowTaskDetailPage() {
</Button>
</div>
<div className="space-y-2 rounded-lg border border-slate-200 p-4">
<p className="text-sm font-medium text-slate-800">退回</p>
<div className="space-y-2 rounded-lg border border-zinc-200 p-4">
<p className="text-sm font-medium text-zinc-800">退回</p>
<Textarea
data-testid="workflow-task-return-comment"
onChange={(event) => setReturnComment(event.target.value)}
@@ -217,10 +217,10 @@ export function WorkflowTaskDetailPage() {
</Button>
</div>
<div className="space-y-2 rounded-lg border border-slate-200 p-4">
<p className="text-sm font-medium text-slate-800">转审</p>
<div className="space-y-2 rounded-lg border border-zinc-200 p-4">
<p className="text-sm font-medium text-zinc-800">转审</p>
<select
className="h-11 w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm"
className="h-11 w-full rounded-lg border border-zinc-300 bg-white px-3 py-2 text-sm"
data-testid="workflow-task-transfer-to-approver"
onChange={(event) => setSelectedApprover(event.target.value)}
value={selectedApprover}
@@ -256,20 +256,20 @@ export function WorkflowTaskDetailPage() {
</Card>
<Card className="space-y-3 p-6">
<h3 className="text-base font-semibold text-slate-900">处理历史</h3>
<h3 className="text-base font-semibold text-zinc-900">处理历史</h3>
<div className="space-y-2">
{detail.history.length ? (
detail.history.map((item) => (
<div className="rounded-lg border border-slate-200 px-3 py-2 text-sm" key={item.id}>
<div className="font-medium text-slate-900">
<div className="rounded-lg border border-zinc-200 px-3 py-2 text-sm" key={item.id}>
<div className="font-medium text-zinc-900">
{item.action} · {item.actorName || item.actorId}
</div>
<div className="text-slate-600">{item.comment || "-"}</div>
<div className="text-xs text-slate-500">{item.createdAt || "-"}</div>
<div className="text-zinc-600">{item.comment || "-"}</div>
<div className="text-xs text-zinc-500">{item.createdAt || "-"}</div>
</div>
))
) : (
<p className="text-sm text-slate-500">暂无历史记录</p>
<p className="text-sm text-zinc-500">暂无历史记录</p>
)}
</div>
</Card>
+4 -4
查看文件
@@ -78,7 +78,7 @@ export function WorkflowTasksPage() {
) : null}
{!query.isLoading && !query.isError ? (
<div className="rounded-lg border border-slate-200">
<div className="rounded-lg border border-zinc-200">
<Table data-testid="workflow-tasks-table">
<TableHeader>
<tr>
@@ -94,8 +94,8 @@ export function WorkflowTasksPage() {
query.data?.items.map((task) => (
<TableRow data-testid="workflow-task-row" key={task.id}>
<TableCell>
<div className="font-medium text-slate-900">{task.stepName}</div>
<div className="text-xs text-slate-500">{task.id}</div>
<div className="font-medium text-zinc-900">{task.stepName}</div>
<div className="text-xs text-zinc-500">{task.id}</div>
</TableCell>
<TableCell className="font-mono text-xs">
{task.workflowInstance?.entityId}
@@ -116,7 +116,7 @@ export function WorkflowTasksPage() {
))
) : (
<TableRow>
<TableCell className="py-3 text-slate-500" colSpan={5}>
<TableCell className="py-3 text-zinc-500" colSpan={5}>
暂无数据
</TableCell>
</TableRow>
@@ -39,7 +39,7 @@ export function ReimbursementActions({
return (
<Card className="space-y-4 p-6">
<h3 className="text-base font-semibold text-slate-900">可执行动作</h3>
<h3 className="text-base font-semibold text-zinc-900">可执行动作</h3>
{actionError ? (
<p
@@ -61,8 +61,8 @@ export function ReimbursementActions({
</Button>
</div>
<div className="space-y-2 rounded-lg border border-slate-200 p-4">
<p className="text-sm font-medium text-slate-800">撤回报销</p>
<div className="space-y-2 rounded-lg border border-zinc-200 p-4">
<p className="text-sm font-medium text-zinc-800">撤回报销</p>
<Textarea
data-testid="reimbursement-withdraw-comment"
onChange={(event) => setWithdrawComment(event.target.value)}
@@ -81,8 +81,8 @@ export function ReimbursementActions({
</div>
{canPay ? (
<div className="space-y-2 rounded-lg border border-slate-200 p-4">
<p className="text-sm font-medium text-slate-800">财务支付</p>
<div className="space-y-2 rounded-lg border border-zinc-200 p-4">
<p className="text-sm font-medium text-zinc-800">财务支付</p>
<Input
data-testid="reimbursement-pay-voucher-no"
onChange={(event) => setPaymentVoucherNo(event.target.value)}
@@ -96,7 +96,7 @@ export function ReimbursementActions({
value={paymentDate}
/>
<select
className="h-11 w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm"
className="h-11 w-full rounded-lg border border-zinc-300 bg-white px-3 py-2 text-sm"
data-testid="reimbursement-pay-channel"
onChange={(event) =>
setPaymentChannel(event.target.value as PaymentChannel)
@@ -59,13 +59,13 @@ export function ReimbursementItemEditor({
};
return (
<div className="space-y-3 rounded-lg border border-slate-200 p-4" data-testid="reimbursement-item-editor">
<p className="text-sm font-medium text-slate-800">
<div className="space-y-3 rounded-lg border border-zinc-200 p-4" data-testid="reimbursement-item-editor">
<p className="text-sm font-medium text-zinc-800">
{mode === "create" ? "新增明细" : "编辑明细"}
</p>
{expenseTypesLoading ? (
<p className="text-sm text-slate-500">加载费用类型中...</p>
<p className="text-sm text-zinc-500">加载费用类型中...</p>
) : null}
{expenseTypesError ? (
@@ -74,11 +74,11 @@ export function ReimbursementItemEditor({
<div className="grid gap-3 md:grid-cols-4">
<div className="space-y-1">
<label className="text-xs text-slate-600" htmlFor="expenseTypeId">
<label className="text-xs text-zinc-600" htmlFor="expenseTypeId">
费用类型
</label>
<select
className="h-11 w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm"
className="h-11 w-full rounded-lg border border-zinc-300 bg-white px-3 py-2 text-sm"
data-testid="reimbursement-item-expense-type"
disabled={expenseTypes.length === 0 || isPending}
id="expenseTypeId"
@@ -95,7 +95,7 @@ export function ReimbursementItemEditor({
</div>
<div className="space-y-1">
<label className="text-xs text-slate-600" htmlFor="expenseDate">
<label className="text-xs text-zinc-600" htmlFor="expenseDate">
发生日期
</label>
<Input
@@ -109,7 +109,7 @@ export function ReimbursementItemEditor({
</div>
<div className="space-y-1">
<label className="text-xs text-slate-600" htmlFor="amount">
<label className="text-xs text-zinc-600" htmlFor="amount">
金额
</label>
<Input
@@ -123,7 +123,7 @@ export function ReimbursementItemEditor({
</div>
<div className="space-y-1 md:col-span-4">
<label className="text-xs text-slate-600" htmlFor="itemDescription">
<label className="text-xs text-zinc-600" htmlFor="itemDescription">
说明
</label>
<Textarea
@@ -167,7 +167,7 @@ export function CreateUserDialog({
<select
id="departmentId"
data-testid="users-create-department"
className="h-11 w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm"
className="h-11 w-full rounded-lg border border-zinc-300 bg-white px-3 py-2 text-sm"
value={departmentId}
onChange={(event) => setDepartmentId(event.target.value)}
>
@@ -187,7 +187,7 @@ export function CreateUserDialog({
<select
id="directManagerId"
data-testid="users-create-direct-manager"
className="h-11 w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm"
className="h-11 w-full rounded-lg border border-zinc-300 bg-white px-3 py-2 text-sm"
value={directManagerId}
onChange={(event) => setDirectManagerId(event.target.value)}
>