实现业务附件受控入库 V1(05-28-business-attachment-governance-v1)

这个提交包含在:
2026-05-28 19:44:15 +08:00
父节点 2c067866ef
当前提交 52e5284954
共修改 25 个文件,包含 1119 行新增和 21 行删除
+4 -1
查看文件
@@ -1,4 +1,5 @@
import { apiRequestBlob, apiRequestData, type ApiBlobResponse } from "./http";
import { buildAttachmentFileUrl, type AttachmentGovernanceFields } from "../lib/attachmentGovernance";
import type { RiskFlag } from "./feeControl";
export type PaymentBatchEntityType = "reimbursement" | "travel_order";
@@ -64,6 +65,7 @@ export type PaymentBatchReceiptAttachment = {
mimeType: string;
fileSize: number;
fileSha256: string;
} & AttachmentGovernanceFields & {
uploadedBy: {
id: string;
employeeNo: string;
@@ -162,8 +164,9 @@ export function paymentBatchReceiptAttachmentFileUrl(batchId: string, attachment
export async function downloadPaymentBatchReceiptAttachment(
batchId: string,
attachmentId: string,
reason?: string,
): Promise<ApiBlobResponse> {
return apiRequestBlob(paymentBatchReceiptAttachmentFileUrl(batchId, attachmentId));
return apiRequestBlob(buildAttachmentFileUrl(paymentBatchReceiptAttachmentFileUrl(batchId, attachmentId), reason));
}
export async function deletePaymentBatchReceiptAttachment(batchId: string, attachmentId: string) {
+5 -2
查看文件
@@ -1,4 +1,5 @@
import { apiRequestData } from "./http";
import type { AttachmentGovernanceFields } from "../lib/attachmentGovernance";
import type { PrecheckResponse, RiskFlag } from "./feeControl";
export type PurchaseRequestStatus = "draft" | "reviewing" | "approved" | "rejected" | "cancelled";
@@ -89,6 +90,8 @@ export type PurchaseAttachment = {
originalName: string;
mimeType: string;
fileSize: number;
fileSha256: string | null;
} & AttachmentGovernanceFields & {
uploadedBy: string;
createdAt: string | null;
uploader: {
@@ -383,12 +386,12 @@ export async function deletePurchaseAttachment(purchaseRequestId: string, attach
);
}
export async function issuePurchaseAttachmentSignedUrl(purchaseRequestId: string, attachmentId: string) {
export async function issuePurchaseAttachmentSignedUrl(purchaseRequestId: string, attachmentId: string, reason?: string) {
return apiRequestData<{ signedUrl: string; expiresAt: string }>(
`/api/purchase-requests/${purchaseRequestId}/attachments/${attachmentId}/signed-url`,
{
method: "POST",
body: JSON.stringify({}),
body: JSON.stringify(reason ? { reason } : {}),
},
);
}
+4 -2
查看文件
@@ -1,5 +1,6 @@
import { apiRequestBlob, apiRequestData } from "./http";
import type { ExpenseStandardCheck, PrecheckResponse, RiskFlag } from "./feeControl";
import { buildAttachmentFileUrl, type AttachmentGovernanceFields } from "../lib/attachmentGovernance";
export type ReimbursementStatus =
| "draft"
@@ -182,6 +183,7 @@ export type ReimbursementDetail = {
mimeType: string;
fileSize: number;
fileSha256: string;
} & AttachmentGovernanceFields & {
uploadedBy: {
id: string;
name: string;
@@ -516,8 +518,8 @@ export function reimbursementAttachmentFileUrl(reimbursementId: string, attachme
return `/api/reimbursements/${reimbursementId}/attachments/${attachmentId}/file`;
}
export async function downloadReimbursementAttachment(reimbursementId: string, attachmentId: string) {
return apiRequestBlob(reimbursementAttachmentFileUrl(reimbursementId, attachmentId));
export async function downloadReimbursementAttachment(reimbursementId: string, attachmentId: string, reason?: string) {
return apiRequestBlob(buildAttachmentFileUrl(reimbursementAttachmentFileUrl(reimbursementId, attachmentId), reason));
}