重构采购申请任务化页面(purchase-request-task-layout)

这个提交包含在:
2026-05-30 10:29:49 +08:00
父节点 e0aa2ead30
当前提交 b1121c14fe
共修改 6 个文件,包含 727 行新增和 267 行删除
@@ -43,6 +43,22 @@ function purchaseProgressFallback(status: string | undefined) {
return "/mobile/approvals?progress=reviewing";
}
function resolveMobilePurchaseEvidence(detail: {
supplierId: string | null;
legalEntityId: string | null;
costCenterId: string | null;
documentCategoryId: string | null;
budgetPoolId: string | null;
projectId: string | null;
}) {
if (!detail.supplierId) return "待补供应商";
if (!detail.legalEntityId || !detail.costCenterId) return "待补法体 / 成本中心";
if (!detail.documentCategoryId) return "待补单据分类";
if (!detail.budgetPoolId) return "预算池未匹配";
if (!detail.projectId) return "未关联项目";
return "基础依据已齐,附件在材料区核对";
}
export function MobilePurchaseRequestDetailPage() {
const { purchaseRequestId = "" } = useParams();
@@ -59,6 +75,7 @@ export function MobilePurchaseRequestDetailPage() {
? `当前在 ${detail.pendingWorkflow.task.stepName},可从审批详情处理;本页用于核对采购依据。`
: resolvePurchaseStatusHint(detail)
: "";
const assetCandidateCount = detail?.items.filter((item) => item.isAssetCandidate).length ?? 0;
return (
<PageScaffold className="space-y-3 pb-4">
@@ -105,6 +122,10 @@ export function MobilePurchaseRequestDetailPage() {
<div className="text-xs text-zinc-500">当前节点</div>
<div className="mt-1 truncate font-medium text-zinc-900">{detail.pendingWorkflow?.task?.stepName ?? "-"}</div>
</div>
<div>
<div className="text-xs text-zinc-500">材料摘要</div>
<div className="mt-1 truncate font-medium text-zinc-900">{resolveMobilePurchaseEvidence(detail)}</div>
</div>
</div>
<div className="mobile-subcard bg-white text-sm">
<div className="text-xs font-semibold text-zinc-500">下一步</div>
@@ -112,6 +133,28 @@ export function MobilePurchaseRequestDetailPage() {
</div>
</section>
<section className="mobile-card" data-testid="mobile-purchase-detail-related">
<h3 className="text-base font-semibold text-zinc-900">关联与后续</h3>
<div className="mobile-field-list mt-3">
<div className="mobile-field-row">
<div className="mobile-field-label">关联项目</div>
<div className="mobile-field-value">
{detail.project ? `${detail.project.projectNo} · ${detail.project.name}` : "未关联项目"}
</div>
</div>
<div className="mobile-field-row">
<div className="mobile-field-label">资产候选</div>
<div className="mobile-field-value">
{assetCandidateCount > 0 ? `${assetCandidateCount} 项,后续由管理员核对后手动建卡` : "无"}
</div>
</div>
<div className="mobile-field-row">
<div className="mobile-field-label">付款 / 应付</div>
<div className="mobile-field-value">仅查看状态,付款状态回到财务页面查看</div>
</div>
</div>
</section>
<section className="mobile-card" data-testid="mobile-purchase-detail-fields">
<h3 className="text-base font-semibold text-zinc-900">业务信息</h3>
<div className="mobile-field-list mt-3">
@@ -38,6 +38,31 @@ function formatDate(value: string | null | undefined) {
return value ? value.slice(0, 10) : "-";
}
function resolvePurchaseListNextStep(status: PurchaseRequestStatus) {
if (status === "draft") return "继续完善采购材料";
if (status === "reviewing") return "查看审批进度";
if (status === "rejected") return "按意见补材料";
if (status === "approved") return "核对到货 / 归档";
return "查看取消记录";
}
function resolvePurchaseListEvidence(item: PurchaseRequestSummary) {
if (!item.supplierId) return "待补供应商";
if (!item.legalEntityId || !item.costCenterId) return "待补法体 / 成本中心";
if (!item.documentCategoryId) return "待补单据分类";
if (!item.budgetPoolId) return "预算池未匹配";
if (!item.projectId) return "未关联项目";
return "基础依据已齐";
}
function resolveMobileEmptyState(status: PurchaseRequestStatus) {
if (status === "draft") return "暂无采购草稿";
if (status === "reviewing") return "暂无审批中的采购";
if (status === "rejected") return "暂无需要补材料的采购";
if (status === "approved") return "暂无已通过采购";
return "暂无已取消采购";
}
function PurchaseRequestCard({
item,
currentMobileSource,
@@ -74,6 +99,10 @@ function PurchaseRequestCard({
item.expectedDeliveryDate ? `到货:${formatDate(item.expectedDeliveryDate)}` : null,
])}
</div>
<div className="mt-3 rounded-lg bg-slate-50 px-3 py-2 text-xs leading-5 text-zinc-600">
<div>材料:{resolvePurchaseListEvidence(item)}</div>
<div>下一步:{resolvePurchaseListNextStep(item.status)}</div>
</div>
</Link>
);
}
@@ -116,9 +145,11 @@ export function MobilePurchaseRequestsPage() {
return (
<PageScaffold className="space-y-4">
<PageHeader title="采购" />
<PageHeader title="我的采购" />
<section className="mobile-card">
<div className="text-sm font-semibold text-zinc-900">当前采购任务</div>
<div className="mt-1 text-xs leading-5 text-zinc-500">手机端只看状态、材料摘要和下一步;台账筛选、全范围和导出留在电脑端。</div>
<div className="mobile-info-grid">
<div>
<div className="text-xs text-zinc-500">当前列表</div>
@@ -150,7 +181,7 @@ export function MobilePurchaseRequestsPage() {
</div>
) : null}
{!listQuery.isLoading && !listQuery.isError && !items.length ? (
<div className="mobile-empty-state">暂无采购申请</div>
<div className="mobile-empty-state">{resolveMobileEmptyState(status)}</div>
) : null}
{items.map((item) => (
<PurchaseRequestCard currentMobileSource={currentMobileSource} item={item} key={item.id} />
文件差异内容过多而无法显示 加载差异