R49 合同台账增强:金额分类、筛选、到期预警、续约与导出

这个提交包含在:
2026-04-05 11:21:15 +08:00
父节点 a960c9b57f
当前提交 ff0a677bf3
共修改 10 个文件,包含 2214 行新增和 168 行删除
+82 -7
查看文件
@@ -1,38 +1,88 @@
import { apiRequestData } from "./http";
import { apiRequestBlob, apiRequestData } from "./http";
import type { ConfidentialityLevel, EmployeeBasic } from "./projects";
export type ContractRegistryType = "purchase" | "sales" | "service" | "framework" | "other";
export type ContractRegistryPersistedStatus = "draft" | "active" | "archived";
export type ContractRegistryStatus = ContractRegistryPersistedStatus | "expired";
export type ContractRegistryExportFormat = "csv" | "xlsx";
export type ContractRegistryFilters = {
projectId?: string;
status?: ContractRegistryStatus;
contractType?: ContractRegistryType;
counterpartyName?: string;
expiryDateFrom?: string;
expiryDateTo?: string;
};
export type ContractRegistryItem = {
id: string;
contractNo: string;
projectId: string | null;
contractType: ContractRegistryType;
counterpartyName: string;
summary: string;
amount: string | null;
currency: string;
signedDate: string | null;
effectiveDate: string | null;
expiryDate: string | null;
confidentialityLevel: ConfidentialityLevel;
archiveLocation: string;
offlineArchiveNo: string | null;
ownerEmployeeId: string;
status: string;
status: ContractRegistryStatus;
persistedStatus: ContractRegistryPersistedStatus;
createdAt: string | null;
updatedAt: string | null;
owner: EmployeeBasic | null;
project: { id: string; projectNo: string; name: string } | null;
};
export async function fetchContractsRegistry(projectId?: string) {
const suffix = projectId ? `?projectId=${encodeURIComponent(projectId)}` : "";
return apiRequestData<{ items: ContractRegistryItem[] }>(`/api/contracts-registry${suffix}`);
function buildFiltersSearch(filters?: ContractRegistryFilters | string) {
const normalized =
typeof filters === "string"
? { projectId: filters }
: (filters ?? {});
const search = new URLSearchParams();
if (normalized.projectId) search.set("projectId", normalized.projectId);
if (normalized.status) search.set("status", normalized.status);
if (normalized.contractType) search.set("contractType", normalized.contractType);
if (normalized.counterpartyName) search.set("counterpartyName", normalized.counterpartyName);
if (normalized.expiryDateFrom) search.set("expiryDateFrom", normalized.expiryDateFrom);
if (normalized.expiryDateTo) search.set("expiryDateTo", normalized.expiryDateTo);
const suffix = search.toString();
return suffix ? `?${suffix}` : "";
}
export async function fetchContractsRegistry(filters?: ContractRegistryFilters | string) {
return apiRequestData<{ items: ContractRegistryItem[] }>(`/api/contracts-registry${buildFiltersSearch(filters)}`);
}
export async function fetchExpiringContracts(days = 30) {
return apiRequestData<{ days: number; total: number; items: ContractRegistryItem[] }>(
`/api/contracts-registry/expiring?days=${encodeURIComponent(String(days))}`,
);
}
export async function createContractRegistry(payload: {
contractNo: string;
projectId?: string | null;
contractType: ContractRegistryType;
counterpartyName: string;
summary: string;
amount?: string | null;
currency?: string;
signedDate?: string | null;
effectiveDate?: string | null;
expiryDate?: string | null;
confidentialityLevel?: ConfidentialityLevel;
archiveLocation: string;
offlineArchiveNo?: string | null;
ownerEmployeeId?: string;
status?: string;
status?: ContractRegistryPersistedStatus;
}) {
return apiRequestData<{ item: ContractRegistryItem }>("/api/contracts-registry", {
method: "POST",
@@ -45,13 +95,19 @@ export async function patchContractRegistry(
payload: Partial<{
contractNo: string;
projectId: string | null;
contractType: ContractRegistryType;
counterpartyName: string;
summary: string;
amount: string | null;
currency: string;
signedDate: string | null;
effectiveDate: string | null;
expiryDate: string | null;
confidentialityLevel: ConfidentialityLevel;
archiveLocation: string;
offlineArchiveNo: string | null;
ownerEmployeeId: string;
status: string;
status: ContractRegistryPersistedStatus;
}>,
) {
return apiRequestData<{ item: ContractRegistryItem }>(`/api/contracts-registry/${id}`, {
@@ -59,3 +115,22 @@ export async function patchContractRegistry(
body: JSON.stringify(payload),
});
}
export async function renewContractRegistry(id: string) {
return apiRequestData<{ item: ContractRegistryItem; sourceItem: ContractRegistryItem }>(
`/api/contracts-registry/${id}/renew`,
{
method: "POST",
},
);
}
export async function exportContractsRegistry(params: ContractRegistryFilters & { format: ContractRegistryExportFormat }) {
return apiRequestBlob("/api/exports/contracts-registry", {
method: "POST",
headers: {
"content-type": "application/json",
},
body: JSON.stringify(params),
});
}