R49 合同台账增强:金额分类、筛选、到期预警、续约与导出
这个提交包含在:
@@ -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),
|
||||
});
|
||||
}
|
||||
|
||||
在新工单中引用
屏蔽一个用户