feat(reimbursement-small-team-form-validation): 完善小团队报销填报校验
这个提交包含在:
@@ -38,7 +38,7 @@ import { isWecomWebView } from "../lib/runtimeContext";
|
||||
import { openFileInBrowser, previewFileInWecom } from "../lib/wecomFilePreview";
|
||||
import { hasCompleteTravelSummary } from "../lib/reimbursementTravel";
|
||||
import { useAuth } from "../auth/AuthContext";
|
||||
import { hasPermission } from "../auth/permissions";
|
||||
import { hasAnyPermission, hasPermission } from "../auth/permissions";
|
||||
import { CardSkeleton } from "../components/common/CardSkeleton";
|
||||
import { ConfirmDialog } from "../components/common/ConfirmDialog";
|
||||
import { useUnsavedChangesGuard } from "../components/common/UnsavedChangesGuard";
|
||||
@@ -47,6 +47,8 @@ import { AttachmentDeleteConfirmDialog } from "../components/common/AttachmentDe
|
||||
import { useAttachmentDownloadReasonDialog } from "../components/common/useAttachmentDownloadReasonDialog";
|
||||
import { RiskFlagsCard } from "../components/common/RiskFlagsCard";
|
||||
import { ReimbursementTravelSummary } from "../components/reimbursements/ReimbursementTravelSummary";
|
||||
import { ReimbursementHeaderEditor } from "../components/reimbursements/ReimbursementHeaderEditor";
|
||||
import { ReimbursementOperationalHints } from "../components/reimbursements/ReimbursementOperationalHints";
|
||||
import { ProcessingProgress } from "../components/patterns/ProcessingProgress";
|
||||
import { StatusBadge } from "../components/common/StatusBadge";
|
||||
import { Button } from "../components/ui/button";
|
||||
@@ -174,9 +176,10 @@ export function ReimbursementDetailPage() {
|
||||
const canViewOwnInvoice = hasPermission(permissions, "invoice.view_own");
|
||||
const canViewAllExpense = hasPermission(permissions, "expense.view_all");
|
||||
const canDeleteExpense = hasPermission(permissions, "expense.delete_own");
|
||||
const canAccessAssets = hasAnyPermission(permissions, ["asset.view_own", "asset.view_all", "asset.manage", "asset.transfer", "asset.inventory"]);
|
||||
|
||||
const reimbursementPrecheckQuery = useQuery({
|
||||
enabled: Boolean(reimbursementId) && canSubmitExpense && ["draft", "rejected"].includes(detailQuery.data?.status ?? ""),
|
||||
enabled: Boolean(reimbursementId) && canSubmitExpense && Boolean(detailQuery.data),
|
||||
queryKey: ["reimbursements", reimbursementId, "precheck"],
|
||||
queryFn: () => precheckReimbursement(reimbursementId),
|
||||
});
|
||||
@@ -1101,7 +1104,7 @@ export function ReimbursementDetailPage() {
|
||||
<div data-testid="reimbursement-business-summary">
|
||||
<div className="detail-fact-grid xl:grid-cols-3" data-testid="reimbursement-summary">
|
||||
<div className="detail-fact-card">
|
||||
<div className="detail-fact-card__label">金额</div>
|
||||
<div className="detail-fact-card__label">报销总额</div>
|
||||
<div className="detail-fact-card__value">{formatMoney(detail.totalAmount)}</div>
|
||||
</div>
|
||||
<div className="detail-fact-card">
|
||||
@@ -1129,11 +1132,12 @@ export function ReimbursementDetailPage() {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{detail.description ? (
|
||||
<div className="mt-3 rounded-lg border border-zinc-200 bg-zinc-50 px-3 py-2 text-sm text-zinc-600">
|
||||
{detail.description}
|
||||
</div>
|
||||
) : null}
|
||||
<ReimbursementHeaderEditor
|
||||
reimbursementId={reimbursementId}
|
||||
reimbursementDate={detail.reimbursementDate}
|
||||
description={detail.description}
|
||||
editable={Boolean(canEditItems && isReimbursementParticipant)}
|
||||
/>
|
||||
<ReimbursementTravelSummary
|
||||
detail={detail}
|
||||
reimbursementId={reimbursementId}
|
||||
@@ -1339,8 +1343,20 @@ export function ReimbursementDetailPage() {
|
||||
</TableRow>
|
||||
)}
|
||||
</TableBody>
|
||||
<tfoot className="border-t border-zinc-200 bg-zinc-50 font-medium text-zinc-900">
|
||||
<tr>
|
||||
<TableCell colSpan={2}>共 {detail.items.length} 条明细</TableCell>
|
||||
<TableCell>{formatMoney(detail.totalAmount)}</TableCell>
|
||||
<TableCell colSpan={2}>报销合计</TableCell>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</Table>
|
||||
</div>
|
||||
<ReimbursementOperationalHints
|
||||
precheck={reimbursementPrecheckQuery.data}
|
||||
items={detail.items}
|
||||
canAccessAssets={canAccessAssets}
|
||||
/>
|
||||
|
||||
{itemEditor ? (
|
||||
<ReimbursementItemEditor
|
||||
|
||||
在新工单中引用
屏蔽一个用户