refactor(ui): [UI8] 彻底移除遗留Card并补充下拉框中文化
这个提交包含在:
@@ -1,13 +1,12 @@
|
|||||||
import { Skeleton } from "../ui/skeleton";
|
import { Skeleton } from "../ui/skeleton";
|
||||||
import { Card } from "../ui/card";
|
|
||||||
|
|
||||||
export function CardSkeleton({ lines = 6 }: { lines?: number }) {
|
export function CardSkeleton({ lines = 6 }: { lines?: number }) {
|
||||||
return (
|
return (
|
||||||
<Card className="space-y-3 p-6">
|
<div className="card-std space-y-3 p-6">
|
||||||
<Skeleton className="h-5 w-48" />
|
<Skeleton className="h-5 w-48" />
|
||||||
{Array.from({ length: lines }, (_, i) => (
|
{Array.from({ length: lines }, (_, i) => (
|
||||||
<Skeleton key={i} className="h-4 w-full" />
|
<Skeleton key={i} className="h-4 w-full" />
|
||||||
))}
|
))}
|
||||||
</Card>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { Component, type ErrorInfo, type ReactNode } from "react";
|
import { Component, type ErrorInfo, type ReactNode } from "react";
|
||||||
import { Card } from "../ui/card";
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
@@ -32,7 +31,7 @@ export class ErrorBoundary extends Component<Props, State> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
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>
|
<h2 className="text-lg font-semibold text-zinc-900">页面渲染出错</h2>
|
||||||
<p className="text-sm text-zinc-600">
|
<p className="text-sm text-zinc-600">
|
||||||
{this.state.error?.message ?? "发生了未知错误"}
|
{this.state.error?.message ?? "发生了未知错误"}
|
||||||
@@ -55,7 +54,7 @@ export class ErrorBoundary extends Component<Props, State> {
|
|||||||
返回首页
|
返回首页
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -42,7 +42,7 @@
|
|||||||
|
|
||||||
/* Cards */
|
/* Cards */
|
||||||
.card-std {
|
.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 {
|
.card-title {
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ export function ApprovalRulesPage() {
|
|||||||
</p>
|
</p>
|
||||||
) : null}
|
) : 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>
|
<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="grid gap-3 md:grid-cols-2 lg:grid-cols-3">
|
||||||
@@ -280,7 +280,7 @@ export function ApprovalRulesPage() {
|
|||||||
</div>
|
</div>
|
||||||
</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>
|
<h3 className="text-base font-semibold text-zinc-900">规则列表</h3>
|
||||||
|
|
||||||
{listQuery.isLoading ? <TableSkeleton columns={6} rows={5} /> : null}
|
{listQuery.isLoading ? <TableSkeleton columns={6} rows={5} /> : null}
|
||||||
|
|||||||
@@ -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">
|
<div className="grid gap-3 md:grid-cols-3">
|
||||||
<label className="text-sm text-zinc-700">
|
<label className="text-sm text-zinc-700">
|
||||||
Action
|
Action
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import { useAuth } from "../auth/AuthContext";
|
|||||||
import { hasPermission } from "../auth/permissions";
|
import { hasPermission } from "../auth/permissions";
|
||||||
import { PageHeader } from "../components/common/PageHeader";
|
import { PageHeader } from "../components/common/PageHeader";
|
||||||
import { Button } from "../components/ui/button";
|
import { Button } from "../components/ui/button";
|
||||||
import { Card } from "../components/ui/card";
|
|
||||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "../components/ui/table";
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "../components/ui/table";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { TableSkeleton } from "../components/common/TableSkeleton";
|
import { TableSkeleton } from "../components/common/TableSkeleton";
|
||||||
@@ -118,7 +117,7 @@ export function BudgetsPage() {
|
|||||||
return (
|
return (
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<PageHeader title="预算管理" subtitle="你当前没有预算权限,请联系管理员开通。" />
|
<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>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -138,7 +137,7 @@ export function BudgetsPage() {
|
|||||||
</p>
|
</p>
|
||||||
) : null}
|
) : 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>
|
<h3 className="text-base font-semibold text-zinc-900">筛选条件</h3>
|
||||||
<div className="grid gap-3 md:grid-cols-3">
|
<div className="grid gap-3 md:grid-cols-3">
|
||||||
<select
|
<select
|
||||||
@@ -150,8 +149,8 @@ export function BudgetsPage() {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<option value="">全部状态</option>
|
<option value="">全部状态</option>
|
||||||
<option value="active">active</option>
|
<option value="active">生效中</option>
|
||||||
<option value="archived">archived</option>
|
<option value="archived">已归档</option>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select
|
<select
|
||||||
@@ -181,7 +180,7 @@ export function BudgetsPage() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{canManageBudget ? (
|
{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>
|
<h3 className="text-base font-semibold text-zinc-900">新建预算池</h3>
|
||||||
<div className="grid gap-3 md:grid-cols-3">
|
<div className="grid gap-3 md:grid-cols-3">
|
||||||
<input
|
<input
|
||||||
@@ -253,7 +252,7 @@ export function BudgetsPage() {
|
|||||||
</div>
|
</div>
|
||||||
) : null}
|
) : 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>
|
<h3 className="text-base font-semibold text-zinc-900">预算池列表</h3>
|
||||||
|
|
||||||
{budgetsQuery.isLoading ? <TableSkeleton columns={7} rows={4} /> : null}
|
{budgetsQuery.isLoading ? <TableSkeleton columns={7} rows={4} /> : null}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import { isApiError } from "../api/types";
|
|||||||
import { mapApiErrorMessage } from "../api/errorMessages";
|
import { mapApiErrorMessage } from "../api/errorMessages";
|
||||||
import { useAuth } from "../auth/AuthContext";
|
import { useAuth } from "../auth/AuthContext";
|
||||||
import { Button } from "../components/ui/button";
|
import { Button } from "../components/ui/button";
|
||||||
import { Card } from "../components/ui/card";
|
|
||||||
import { Input } from "../components/ui/input";
|
import { Input } from "../components/ui/input";
|
||||||
import { Label } from "../components/ui/label";
|
import { Label } from "../components/ui/label";
|
||||||
|
|
||||||
@@ -43,7 +42,7 @@ export function ChangePasswordPage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
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">
|
<div className="mb-6 space-y-2">
|
||||||
<p className="text-xs font-semibold uppercase tracking-wide text-primary">hyb-oa</p>
|
<p className="text-xs font-semibold uppercase tracking-wide text-primary">hyb-oa</p>
|
||||||
<h1 className="text-2xl font-bold text-zinc-900">修改密码</h1>
|
<h1 className="text-2xl font-bold text-zinc-900">修改密码</h1>
|
||||||
@@ -109,7 +108,7 @@ export function ChangePasswordPage() {
|
|||||||
{submitting ? "提交中..." : "确认修改"}
|
{submitting ? "提交中..." : "确认修改"}
|
||||||
</Button>
|
</Button>
|
||||||
</form>
|
</form>
|
||||||
</Card>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ import { useAuth } from "../auth/AuthContext";
|
|||||||
import { hasPermission } from "../auth/permissions";
|
import { hasPermission } from "../auth/permissions";
|
||||||
import { PageHeader } from "../components/common/PageHeader";
|
import { PageHeader } from "../components/common/PageHeader";
|
||||||
import { Button } from "../components/ui/button";
|
import { Button } from "../components/ui/button";
|
||||||
import { Card } from "../components/ui/card";
|
|
||||||
import { downloadBlob } from "../lib/download";
|
import { downloadBlob } from "../lib/download";
|
||||||
|
|
||||||
function currentDateString() {
|
function currentDateString() {
|
||||||
@@ -116,10 +115,10 @@ export function DashboardPage() {
|
|||||||
return (
|
return (
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<PageHeader title="仪表盘" subtitle="你当前没有看板权限,请联系管理员开通。" />
|
<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-700">当前用户:{me?.name ?? "-"}</p>
|
||||||
<p className="text-zinc-500">所需权限:report.dashboard.view</p>
|
<p className="text-zinc-500">所需权限:report.dashboard.view</p>
|
||||||
</Card>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -163,7 +162,7 @@ export function DashboardPage() {
|
|||||||
</p>
|
</p>
|
||||||
) : null}
|
) : 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="grid gap-3 md:grid-cols-4">
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
<label className="text-xs text-zinc-600" htmlFor="dashboard-date-from">
|
<label className="text-xs text-zinc-600" htmlFor="dashboard-date-from">
|
||||||
@@ -226,28 +225,28 @@ export function DashboardPage() {
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</div>
|
||||||
|
|
||||||
<div className="grid gap-4 md:grid-cols-4">
|
<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="text-xs text-zinc-500">报销单总数</p>
|
||||||
<p className="mt-1 text-2xl font-semibold text-zinc-900">
|
<p className="mt-1 text-2xl font-semibold text-zinc-900">
|
||||||
{loading ? "..." : overviewQuery.data?.totalCount ?? 0}
|
{loading ? "..." : overviewQuery.data?.totalCount ?? 0}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</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="text-xs text-zinc-500">报销总金额</p>
|
||||||
<p className="mt-1 text-2xl font-semibold text-zinc-900">
|
<p className="mt-1 text-2xl font-semibold text-zinc-900">
|
||||||
{loading ? "..." : toCurrency(overviewQuery.data?.totalAmount)}
|
{loading ? "..." : toCurrency(overviewQuery.data?.totalAmount)}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</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="text-xs text-zinc-500">已付款金额</p>
|
||||||
<p className="mt-1 text-2xl font-semibold text-zinc-900">
|
<p className="mt-1 text-2xl font-semibold text-zinc-900">
|
||||||
{loading ? "..." : toCurrency(overviewQuery.data?.paidAmount)}
|
{loading ? "..." : toCurrency(overviewQuery.data?.paidAmount)}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</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="text-xs text-zinc-500">审批中数量</p>
|
||||||
<p className="mt-1 text-2xl font-semibold text-zinc-900">
|
<p className="mt-1 text-2xl font-semibold text-zinc-900">
|
||||||
{loading ? "..." : overviewQuery.data?.reviewingCount ?? 0}
|
{loading ? "..." : overviewQuery.data?.reviewingCount ?? 0}
|
||||||
@@ -256,7 +255,7 @@ export function DashboardPage() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid gap-4 lg:grid-cols-2">
|
<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>
|
<h3 className="text-base font-semibold text-zinc-900">费用趋势</h3>
|
||||||
{trendPoints.length ? (
|
{trendPoints.length ? (
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
@@ -283,7 +282,7 @@ export function DashboardPage() {
|
|||||||
)}
|
)}
|
||||||
</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">费用分类 TopN</h3>
|
<h3 className="text-base font-semibold text-zinc-900">费用分类 TopN</h3>
|
||||||
{topCategories.length ? (
|
{topCategories.length ? (
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
@@ -313,7 +312,7 @@ export function DashboardPage() {
|
|||||||
</div>
|
</div>
|
||||||
</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>
|
<h3 className="text-base font-semibold text-zinc-900">审批效率</h3>
|
||||||
<p className="text-zinc-700">
|
<p className="text-zinc-700">
|
||||||
已统计通过单据:
|
已统计通过单据:
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import { PageHeader } from "../components/common/PageHeader";
|
|||||||
import { TableSkeleton } from "../components/common/TableSkeleton";
|
import { TableSkeleton } from "../components/common/TableSkeleton";
|
||||||
import { StatusBadge } from "../components/common/StatusBadge";
|
import { StatusBadge } from "../components/common/StatusBadge";
|
||||||
import { Button } from "../components/ui/button";
|
import { Button } from "../components/ui/button";
|
||||||
import { Input } from "../components/ui/input";
|
|
||||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "../components/ui/table";
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "../components/ui/table";
|
||||||
|
|
||||||
export function DelegationsPage() {
|
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>
|
<p className="rounded-lg border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-600">{error}</p>
|
||||||
) : null}
|
) : 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>
|
<h3 className="text-base font-semibold text-zinc-900">创建委派</h3>
|
||||||
|
|
||||||
<div className="grid gap-3 md:grid-cols-2">
|
<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")}
|
onChange={(event) => setScope(event.target.value as "all" | "reimbursement_submit")}
|
||||||
value={scope}
|
value={scope}
|
||||||
>
|
>
|
||||||
<option value="all">all</option>
|
<option value="all">任意单据(全权代理)</option>
|
||||||
<option value="reimbursement_submit">reimbursement_submit</option>
|
<option value="reimbursement_submit">仅限提交报销单</option>
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label className="space-y-1 text-sm md:col-span-2">
|
<label className="space-y-1 text-sm md:col-span-2">
|
||||||
<span className="font-medium text-zinc-700">有效期结束(可选)</span>
|
<span className="font-medium text-zinc-700">有效期结束(可选)</span>
|
||||||
<Input
|
<input
|
||||||
|
className="input-std"
|
||||||
data-testid="delegations-create-valid-to"
|
data-testid="delegations-create-valid-to"
|
||||||
onChange={(event) => setValidTo(event.target.value)}
|
onChange={(event) => setValidTo(event.target.value)}
|
||||||
type="datetime-local"
|
type="datetime-local"
|
||||||
@@ -139,7 +139,7 @@ export function DelegationsPage() {
|
|||||||
</div>
|
</div>
|
||||||
</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">
|
<div className="flex flex-wrap items-center justify-between gap-2">
|
||||||
<h3 className="text-base font-semibold text-zinc-900">我的委派</h3>
|
<h3 className="text-base font-semibold text-zinc-900">我的委派</h3>
|
||||||
<select
|
<select
|
||||||
@@ -150,11 +150,11 @@ export function DelegationsPage() {
|
|||||||
}
|
}
|
||||||
value={status}
|
value={status}
|
||||||
>
|
>
|
||||||
<option value="active">active</option>
|
<option value="active">生效中</option>
|
||||||
<option value="scheduled">scheduled</option>
|
<option value="scheduled">未开始</option>
|
||||||
<option value="expired">expired</option>
|
<option value="expired">已失效</option>
|
||||||
<option value="revoked">revoked</option>
|
<option value="revoked">已撤销</option>
|
||||||
<option value="all">all</option>
|
<option value="all">全状态</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ export function DepartmentsPage() {
|
|||||||
</p>
|
</p>
|
||||||
) : null}
|
) : 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">
|
<div className="flex items-center justify-between gap-3">
|
||||||
<h3 className="text-base font-semibold text-zinc-900">新建部门</h3>
|
<h3 className="text-base font-semibold text-zinc-900">新建部门</h3>
|
||||||
<Button
|
<Button
|
||||||
@@ -163,7 +163,7 @@ export function DepartmentsPage() {
|
|||||||
</div>
|
</div>
|
||||||
</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>
|
<h3 className="text-base font-semibold text-zinc-900">部门列表</h3>
|
||||||
|
|
||||||
{listQuery.isLoading ? <TableSkeleton columns={4} rows={4} /> : null}
|
{listQuery.isLoading ? <TableSkeleton columns={4} rows={4} /> : null}
|
||||||
|
|||||||
@@ -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>
|
<p className="rounded-lg border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-600">{error}</p>
|
||||||
) : null}
|
) : 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>
|
<h3 className="text-base font-semibold text-zinc-900">开关列表</h3>
|
||||||
|
|
||||||
{flagsQuery.isLoading ? <TableSkeleton columns={6} rows={2} /> : null}
|
{flagsQuery.isLoading ? <TableSkeleton columns={6} rows={2} /> : null}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import { mapApiErrorMessage } from "../api/errorMessages";
|
|||||||
import { isApiError } from "../api/types";
|
import { isApiError } from "../api/types";
|
||||||
import { useAuth } from "../auth/AuthContext";
|
import { useAuth } from "../auth/AuthContext";
|
||||||
import { Button } from "../components/ui/button";
|
import { Button } from "../components/ui/button";
|
||||||
import { Card } from "../components/ui/card";
|
|
||||||
import { Input } from "../components/ui/input";
|
import { Input } from "../components/ui/input";
|
||||||
import { Label } from "../components/ui/label";
|
import { Label } from "../components/ui/label";
|
||||||
|
|
||||||
@@ -59,7 +58,7 @@ export function LoginPage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
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">
|
<div className="mb-6">
|
||||||
<p className="text-xs font-semibold uppercase tracking-wide text-primary">hyb-oa</p>
|
<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>
|
<h1 className="mt-2 text-2xl font-bold text-zinc-900">登录工作台</h1>
|
||||||
@@ -106,6 +105,6 @@ export function LoginPage() {
|
|||||||
{submitting ? "登录中..." : "登录"}
|
{submitting ? "登录中..." : "登录"}
|
||||||
</Button>
|
</Button>
|
||||||
</form>
|
</form>
|
||||||
</Card>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import {
|
|||||||
import { PageHeader } from "../components/common/PageHeader";
|
import { PageHeader } from "../components/common/PageHeader";
|
||||||
import { Button } from "../components/ui/button";
|
import { Button } from "../components/ui/button";
|
||||||
import { Spinner } from "../components/ui/spinner";
|
import { Spinner } from "../components/ui/spinner";
|
||||||
import { Card } from "../components/ui/card";
|
|
||||||
import { Textarea } from "../components/ui/textarea";
|
import { Textarea } from "../components/ui/textarea";
|
||||||
|
|
||||||
type MobileAction = "approve" | "reject" | "return" | "transfer";
|
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>
|
<p className="rounded-lg border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-600">{error}</p>
|
||||||
) : null}
|
) : 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>
|
<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}
|
{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>
|
</button>
|
||||||
))}
|
))}
|
||||||
</div>
|
</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>
|
<h3 className="text-base font-semibold text-zinc-900">任务详情与动作</h3>
|
||||||
|
|
||||||
{!selectedTaskId ? <p className="text-sm text-zinc-500">请先选择任务。</p> : null}
|
{!selectedTaskId ? <p className="text-sm text-zinc-500">请先选择任务。</p> : null}
|
||||||
@@ -229,7 +228,7 @@ export function MobileApprovalsPage() {
|
|||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</Card>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import { isApiError } from "../api/types";
|
|||||||
import { PageHeader } from "../components/common/PageHeader";
|
import { PageHeader } from "../components/common/PageHeader";
|
||||||
import { Button } from "../components/ui/button";
|
import { Button } from "../components/ui/button";
|
||||||
import { Spinner } from "../components/ui/spinner";
|
import { Spinner } from "../components/ui/spinner";
|
||||||
import { Card } from "../components/ui/card";
|
|
||||||
import {
|
import {
|
||||||
enqueueInvoiceUpload,
|
enqueueInvoiceUpload,
|
||||||
listQueuedInvoiceUploads,
|
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>
|
<p className="rounded-lg border border-emerald-200 bg-emerald-50 px-3 py-2 text-sm text-emerald-700">{message}</p>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
<Card className="space-y-3 p-4">
|
<div className="card-std space-y-3 p-4">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<h3 className="text-base font-semibold text-zinc-900">拍照/选择文件</h3>
|
<h3 className="text-base font-semibold text-zinc-900">拍照/选择文件</h3>
|
||||||
<span className={isOnline ? "text-emerald-600" : "text-orange-600"}>
|
<span className={isOnline ? "text-emerald-600" : "text-orange-600"}>
|
||||||
@@ -212,9 +211,9 @@ export function MobileCapturePage() {
|
|||||||
{syncMutation.isPending ? "同步中..." : "同步队列"}
|
{syncMutation.isPending ? "同步中..." : "同步队列"}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</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">
|
<div className="flex items-center justify-between">
|
||||||
<h3 className="text-base font-semibold text-zinc-900">离线上传队列</h3>
|
<h3 className="text-base font-semibold text-zinc-900">离线上传队列</h3>
|
||||||
<span className="text-sm text-zinc-500">{queuedCountLabel}</span>
|
<span className="text-sm text-zinc-500">{queuedCountLabel}</span>
|
||||||
@@ -246,7 +245,7 @@ export function MobileCapturePage() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</Card>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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">
|
<div className="flex flex-col gap-3 md:flex-row md:items-center md:justify-between">
|
||||||
<Tabs
|
<Tabs
|
||||||
data-testid="notifications-filter-tabs"
|
data-testid="notifications-filter-tabs"
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ import { CardSkeleton } from "../components/common/CardSkeleton";
|
|||||||
import { ConfirmDialog } from "../components/common/ConfirmDialog";
|
import { ConfirmDialog } from "../components/common/ConfirmDialog";
|
||||||
import { PageHeader } from "../components/common/PageHeader";
|
import { PageHeader } from "../components/common/PageHeader";
|
||||||
import { Button } from "../components/ui/button";
|
import { Button } from "../components/ui/button";
|
||||||
import { Card } from "../components/ui/card";
|
|
||||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "../components/ui/table";
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "../components/ui/table";
|
||||||
import { ReimbursementActions, type PayPayload } from "./reimbursement-detail/ReimbursementActions";
|
import { ReimbursementActions, type PayPayload } from "./reimbursement-detail/ReimbursementActions";
|
||||||
import {
|
import {
|
||||||
@@ -195,9 +194,9 @@ export function ReimbursementDetailPage() {
|
|||||||
|
|
||||||
if (!reimbursementId) {
|
if (!reimbursementId) {
|
||||||
return (
|
return (
|
||||||
<Card className="p-6">
|
<div className="card-std p-6">
|
||||||
<p className="text-sm text-red-600">缺少 reimbursementId 参数。</p>
|
<p className="text-sm text-red-600">缺少 reimbursementId 参数。</p>
|
||||||
</Card>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,12 +214,12 @@ export function ReimbursementDetailPage() {
|
|||||||
: "加载报销详情失败";
|
: "加载报销详情失败";
|
||||||
|
|
||||||
return (
|
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>
|
<p className="text-sm text-red-600">{message}</p>
|
||||||
<Button asChild variant="secondary">
|
<Button asChild variant="secondary">
|
||||||
<Link to="/reimbursements">返回报销列表</Link>
|
<Link to="/reimbursements">返回报销列表</Link>
|
||||||
</Button>
|
</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>报销ID:{detail.id}</div>
|
||||||
<div>报销日期:{detail.reimbursementDate ?? "-"}</div>
|
<div>报销日期:{detail.reimbursementDate ?? "-"}</div>
|
||||||
<div>金额:{detail.totalAmount ?? "-"}</div>
|
<div>金额:{detail.totalAmount ?? "-"}</div>
|
||||||
<div>提交人:{detail.submitter?.name ?? "-"}</div>
|
<div>提交人:{detail.submitter?.name ?? "-"}</div>
|
||||||
<div>报销人:{detail.owner?.name ?? "-"}</div>
|
<div>报销人:{detail.owner?.name ?? "-"}</div>
|
||||||
<div>说明:{detail.description || "-"}</div>
|
<div>说明:{detail.description || "-"}</div>
|
||||||
</Card>
|
</div>
|
||||||
|
|
||||||
{budgetHint ? (
|
{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>
|
<h3 className="text-base font-semibold text-zinc-900">预算提示</h3>
|
||||||
<div>预算池:{budgetHint.budgetCode} / {budgetHint.budgetName}</div>
|
<div>预算池:{budgetHint.budgetCode} / {budgetHint.budgetName}</div>
|
||||||
<div>
|
<div>
|
||||||
@@ -310,10 +309,10 @@ export function ReimbursementDetailPage() {
|
|||||||
) : (
|
) : (
|
||||||
<p className="text-zinc-500">当前预算充足,可继续提交。</p>
|
<p className="text-zinc-500">当前预算充足,可继续提交。</p>
|
||||||
)}
|
)}
|
||||||
</Card>
|
</div>
|
||||||
) : null}
|
) : 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="flex flex-col gap-3 md:flex-row md:items-center md:justify-between">
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
<h3 className="text-base font-semibold text-zinc-900">报销明细</h3>
|
<h3 className="text-base font-semibold text-zinc-900">报销明细</h3>
|
||||||
@@ -418,7 +417,7 @@ export function ReimbursementDetailPage() {
|
|||||||
isPending={itemSaveMutation.isPending}
|
isPending={itemSaveMutation.isPending}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
</Card>
|
</div>
|
||||||
|
|
||||||
<ReimbursementActions
|
<ReimbursementActions
|
||||||
status={detail.status}
|
status={detail.status}
|
||||||
@@ -430,7 +429,7 @@ export function ReimbursementDetailPage() {
|
|||||||
onPay={(payload) => mutation.mutate({ action: "pay", payload })}
|
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>
|
<h3 className="text-base font-semibold text-zinc-900">关联票据</h3>
|
||||||
{(detail.invoices ?? []).length ? (
|
{(detail.invoices ?? []).length ? (
|
||||||
<div className="space-y-2 text-sm">
|
<div className="space-y-2 text-sm">
|
||||||
@@ -446,7 +445,7 @@ export function ReimbursementDetailPage() {
|
|||||||
) : (
|
) : (
|
||||||
<p className="text-sm text-zinc-500">暂无关联票据</p>
|
<p className="text-sm text-zinc-500">暂无关联票据</p>
|
||||||
)}
|
)}
|
||||||
</Card>
|
</div>
|
||||||
|
|
||||||
<ConfirmDialog
|
<ConfirmDialog
|
||||||
open={Boolean(confirmDeleteItemId)}
|
open={Boolean(confirmDeleteItemId)}
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ import {
|
|||||||
} from "../api/users";
|
} from "../api/users";
|
||||||
import { PageHeader } from "../components/common/PageHeader";
|
import { PageHeader } from "../components/common/PageHeader";
|
||||||
import { Button } from "../components/ui/button";
|
import { Button } from "../components/ui/button";
|
||||||
import { Card } from "../components/ui/card";
|
|
||||||
import { Input } from "../components/ui/input";
|
import { Input } from "../components/ui/input";
|
||||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "../components/ui/table";
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "../components/ui/table";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
@@ -177,7 +176,7 @@ export function UserManagementPage() {
|
|||||||
</p>
|
</p>
|
||||||
) : null}
|
) : 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">
|
<div className="flex flex-wrap items-center gap-2">
|
||||||
<Input
|
<Input
|
||||||
data-testid="users-search"
|
data-testid="users-search"
|
||||||
@@ -298,7 +297,7 @@ export function UserManagementPage() {
|
|||||||
onPageChange={setPage}
|
onPageChange={setPage}
|
||||||
testIdPrefix="users"
|
testIdPrefix="users"
|
||||||
/>
|
/>
|
||||||
</Card>
|
</div>
|
||||||
|
|
||||||
<UserRoleDialog
|
<UserRoleDialog
|
||||||
open={Boolean(roleDialogUser)}
|
open={Boolean(roleDialogUser)}
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import { CardSkeleton } from "../components/common/CardSkeleton";
|
|||||||
import { PageHeader } from "../components/common/PageHeader";
|
import { PageHeader } from "../components/common/PageHeader";
|
||||||
import { StatusBadge } from "../components/common/StatusBadge";
|
import { StatusBadge } from "../components/common/StatusBadge";
|
||||||
import { Button } from "../components/ui/button";
|
import { Button } from "../components/ui/button";
|
||||||
import { Card } from "../components/ui/card";
|
|
||||||
import { Textarea } from "../components/ui/textarea";
|
import { Textarea } from "../components/ui/textarea";
|
||||||
|
|
||||||
export function WorkflowTaskDetailPage() {
|
export function WorkflowTaskDetailPage() {
|
||||||
@@ -98,9 +97,9 @@ export function WorkflowTaskDetailPage() {
|
|||||||
|
|
||||||
if (!taskId) {
|
if (!taskId) {
|
||||||
return (
|
return (
|
||||||
<Card className="p-6">
|
<div className="card-std p-6">
|
||||||
<p className="text-sm text-red-600">缺少 taskId 参数。</p>
|
<p className="text-sm text-red-600">缺少 taskId 参数。</p>
|
||||||
</Card>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,7 +119,7 @@ export function WorkflowTaskDetailPage() {
|
|||||||
: "加载失败,请返回列表重试";
|
: "加载失败,请返回列表重试";
|
||||||
|
|
||||||
return (
|
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>
|
<p className="text-sm text-red-600">{message}</p>
|
||||||
<Button
|
<Button
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
@@ -129,7 +128,7 @@ export function WorkflowTaskDetailPage() {
|
|||||||
>
|
>
|
||||||
返回待办列表
|
返回待办列表
|
||||||
</Button>
|
</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>状态:<StatusBadge status={detail.task.status} /></div>
|
||||||
<div>实例:{detail.workflowInstance?.id ?? "-"}</div>
|
<div>实例:{detail.workflowInstance?.id ?? "-"}</div>
|
||||||
<div>报销单号:{detail.reimbursement?.formNumber ?? "-"}</div>
|
<div>报销单号:{detail.reimbursement?.formNumber ?? "-"}</div>
|
||||||
<div>报销金额:{detail.reimbursement?.totalAmount ?? "-"}</div>
|
<div>报销金额:{detail.reimbursement?.totalAmount ?? "-"}</div>
|
||||||
<div>提交人:{detail.reimbursement?.submitter?.name ?? "-"}</div>
|
<div>提交人:{detail.reimbursement?.submitter?.name ?? "-"}</div>
|
||||||
<div>报销人:{detail.reimbursement?.owner?.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>
|
<h3 className="text-base font-semibold text-zinc-900">审批动作</h3>
|
||||||
|
|
||||||
{actionError ? (
|
{actionError ? (
|
||||||
@@ -253,9 +252,9 @@ export function WorkflowTaskDetailPage() {
|
|||||||
提交转审
|
提交转审
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</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>
|
<h3 className="text-base font-semibold text-zinc-900">处理历史</h3>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
{detail.history.length ? (
|
{detail.history.length ? (
|
||||||
@@ -272,7 +271,7 @@ export function WorkflowTaskDetailPage() {
|
|||||||
<p className="text-sm text-zinc-500">暂无历史记录</p>
|
<p className="text-sm text-zinc-500">暂无历史记录</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ export function WorkflowTasksPage() {
|
|||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
<PageHeader title="待我处理" subtitle="审批待办列表(支持筛选与详情动作联动)。" />
|
<PageHeader title="待我处理" subtitle="审批待办列表(支持筛选与详情动作联动)。" />
|
||||||
|
|
||||||
<div className="card-std space-y-4">
|
<div className="card-std p-6 space-y-4">
|
||||||
<Tabs
|
<Tabs
|
||||||
data-testid="workflow-tasks-status-tabs"
|
data-testid="workflow-tasks-status-tabs"
|
||||||
value={status}
|
value={status}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ export function InvoiceBindCard({
|
|||||||
setSelectedReimbursementId,
|
setSelectedReimbursementId,
|
||||||
}: InvoiceBindCardProps) {
|
}: InvoiceBindCardProps) {
|
||||||
return (
|
return (
|
||||||
<div className="card-std space-y-4">
|
<div className="card-std p-6 space-y-4">
|
||||||
<h3 className="card-title">绑定报销</h3>
|
<h3 className="card-title">绑定报销</h3>
|
||||||
<select
|
<select
|
||||||
className="select-std"
|
className="select-std"
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ export function InvoiceDetailPanel({
|
|||||||
}: InvoiceDetailPanelProps) {
|
}: InvoiceDetailPanelProps) {
|
||||||
return (
|
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>
|
<h3 className="card-title">详情轮询</h3>
|
||||||
{detail ? (
|
{detail ? (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ export function InvoiceListCard({
|
|||||||
signedUrlMutation,
|
signedUrlMutation,
|
||||||
}: InvoiceListCardProps) {
|
}: InvoiceListCardProps) {
|
||||||
return (
|
return (
|
||||||
<div className="card-std space-y-4">
|
<div className="card-std p-6 space-y-4">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<h3 className="card-title">筛选与列表</h3>
|
<h3 className="card-title">筛选与列表</h3>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export function InvoiceUploadCard({
|
|||||||
setUploadOwnerEmployeeId,
|
setUploadOwnerEmployeeId,
|
||||||
}: InvoiceUploadCardProps) {
|
}: InvoiceUploadCardProps) {
|
||||||
return (
|
return (
|
||||||
<div className="card-std space-y-4">
|
<div className="card-std p-6 space-y-4">
|
||||||
<h3 className="card-title">上传票据(VAT OCR)</h3>
|
<h3 className="card-title">上传票据(VAT OCR)</h3>
|
||||||
{showProxyOwnerSelector ? (
|
{showProxyOwnerSelector ? (
|
||||||
<select
|
<select
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import type { ReimbursementStatus } from "../../api/reimbursements";
|
import type { ReimbursementStatus } from "../../api/reimbursements";
|
||||||
import { Button } from "../../components/ui/button";
|
import { Button } from "../../components/ui/button";
|
||||||
import { Card } from "../../components/ui/card";
|
|
||||||
import { Input } from "../../components/ui/input";
|
import { Input } from "../../components/ui/input";
|
||||||
import { Textarea } from "../../components/ui/textarea";
|
import { Textarea } from "../../components/ui/textarea";
|
||||||
|
|
||||||
@@ -38,7 +37,7 @@ export function ReimbursementActions({
|
|||||||
const [paymentChannel, setPaymentChannel] = useState<PaymentChannel>("bank");
|
const [paymentChannel, setPaymentChannel] = useState<PaymentChannel>("bank");
|
||||||
|
|
||||||
return (
|
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>
|
<h3 className="text-base font-semibold text-zinc-900">可执行动作</h3>
|
||||||
|
|
||||||
{actionError ? (
|
{actionError ? (
|
||||||
@@ -126,6 +125,6 @@ export function ReimbursementActions({
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : 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""]",无
|
||||||
|
在新工单中引用
屏蔽一个用户