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

这个提交包含在:
2026-05-28 19:44:15 +08:00
父节点 2c067866ef
当前提交 52e5284954
共修改 25 个文件,包含 1119 行新增和 21 行删除
+91
查看文件
@@ -0,0 +1,91 @@
export type AttachmentGovernanceStatus =
| "draft"
| "under_approval"
| "pending_review"
| "approved"
| "archived"
| "returned"
| "rejected"
| "quarantined";
export type AttachmentSensitivityLevel =
| "public"
| "internal"
| "confidential"
| "restricted"
| "index_only";
export type BusinessAttachmentType =
| "contract_draft"
| "contract_stamped"
| "invoice"
| "receipt"
| "quote"
| "acceptance"
| "delivery"
| "policy_document"
| "supporting_material"
| "other";
export type AttachmentDownloadPolicy = "standard" | "reason_required" | "restricted";
export type AttachmentGovernanceFields = {
governanceStatus: AttachmentGovernanceStatus | string;
sensitivityLevel: AttachmentSensitivityLevel | string;
attachmentType: BusinessAttachmentType | string;
downloadPolicy: AttachmentDownloadPolicy | string;
reviewedBy: string | null;
reviewedAt: string | null;
reviewNote: string | null;
archivedBy: string | null;
archivedAt: string | null;
archiveNote: string | null;
};
export const GOVERNANCE_STATUS_LABEL: Record<string, string> = {
draft: "草稿",
under_approval: "审批中",
pending_review: "待复核",
approved: "已通过",
archived: "已归档",
returned: "已退回",
rejected: "已拒绝",
quarantined: "已隔离",
};
export const SENSITIVITY_LEVEL_LABEL: Record<string, string> = {
public: "公开",
internal: "内部",
confidential: "保密",
restricted: "受限",
index_only: "仅索引",
};
export const ATTACHMENT_TYPE_LABEL: Record<string, string> = {
contract_draft: "合同稿",
contract_stamped: "盖章件",
invoice: "发票",
receipt: "回单",
quote: "报价",
acceptance: "验收",
delivery: "交付物",
policy_document: "制度资料",
supporting_material: "补充材料",
other: "其他",
};
export function attachmentRequiresDownloadReason(attachment: Pick<AttachmentGovernanceFields, "downloadPolicy" | "sensitivityLevel">) {
return (
attachment.downloadPolicy === "reason_required" ||
attachment.downloadPolicy === "restricted" ||
attachment.sensitivityLevel === "confidential" ||
attachment.sensitivityLevel === "restricted"
);
}
export function buildAttachmentFileUrl(path: string, reason?: string) {
const trimmed = reason?.trim();
if (!trimmed) return path;
const params = new URLSearchParams({ reason: trimmed });
return `${path}${path.includes("?") ? "&" : "?"}${params.toString()}`;
}