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

这个提交包含在:
2026-05-29 07:57:17 +08:00
父节点 85c298e25a
当前提交 2b5fd6b1b7
共修改 17 个文件,包含 1087 行新增和 32 行删除
@@ -169,6 +169,34 @@ function itemLabel(item: ReimbursementItem) {
return desc ? `${typeName} · ${desc}` : typeName;
}
function resolveMobileReimbursementNextStep(input: {
status: ReimbursementStatus;
canEdit: boolean;
itemCount: number;
invoiceCount: number;
attachmentCount: number;
}) {
if (input.canEdit && input.itemCount === 0) {
return "先添加报销明细,再绑定发票或补充附件。";
}
if (input.canEdit && input.invoiceCount === 0) {
return "建议先添加或上传发票,提交前会做完整性检查。";
}
if (input.status === "draft" || input.status === "rejected") {
return "核对金额、发票和附件后,使用底部按钮提交审批。";
}
if (input.status === "reviewing") {
return "正在审批中,可查看节点和历史;需要补材料时按审批意见处理。";
}
if (input.status === "approved") {
return "已通过审批,等待财务付款和归档。";
}
if (input.status === "paid") {
return "已完成付款,本页用于查看发票、附件和审批留痕。";
}
return input.attachmentCount > 0 ? "查看附件、发票和审批记录。" : "查看当前报销状态和审批记录。";
}
export function MobileReimbursementDetailPage() {
const { reimbursementId = "" } = useParams();
const navigate = useNavigate();
@@ -813,6 +841,13 @@ export function MobileReimbursementDetailPage() {
const showSubmitAction = Boolean(canEdit && canSubmitExpense);
const showStickyActions = Boolean(showSubmitAction || canOpenInvoiceDialog);
const showSecondaryActions = Boolean(actionError || canDeleteDraft || !canEdit);
const detailNextStep = resolveMobileReimbursementNextStep({
status: detail.status,
canEdit,
itemCount: detail.items.length,
invoiceCount: detail.invoices.length,
attachmentCount: detail.attachments?.length ?? 0,
});
return (
<PageScaffold
@@ -838,9 +873,20 @@ export function MobileReimbursementDetailPage() {
testId="mobile-reimbursement-detail-header"
/>
<section className="mobile-card">
<div className="text-xs text-zinc-500">合计金额</div>
<div className="mt-1 text-3xl font-semibold text-zinc-900">{formatCurrency(detail.totalAmount)}</div>
<section className="mobile-card mobile-focus-card mobile-page-stack" data-testid="mobile-reimbursement-detail-focus">
<div className="mobile-section-header mobile-section-header--top">
<div className="min-w-0">
<h2 className="mobile-section-title">当前办理摘要</h2>
<p className="mobile-list-card__subtitle mt-1">{detailNextStep}</p>
</div>
<span className={cn("rounded-full px-2.5 py-1 text-xs font-medium", STATUS_TONE[detail.status])}>
{STATUS_LABEL[detail.status]}
</span>
</div>
<div>
<div className="text-xs text-zinc-500">合计金额</div>
<div className="mt-1 text-3xl font-semibold text-zinc-900">{formatCurrency(detail.totalAmount)}</div>
</div>
<div className="mobile-metric-grid mt-4 text-sm">
<div className="rounded-lg bg-zinc-50 px-3 py-2">
<div className="text-xs text-zinc-500">明细</div>