R45 A2-A7 员工附件与培训证书管理

这个提交包含在:
2026-03-29 13:31:53 +08:00
父节点 d11f5593d1
当前提交 48f395e18d
共修改 14 个文件,包含 2291 行新增和 22 行删除
+146 -1
查看文件
@@ -1,9 +1,12 @@
import { apiRequestData } from "./http";
import { apiRequestBlob, apiRequestData, type ApiBlobResponse } from "./http";
export type EmployeeStatus = "active" | "archived";
export type EmployeeEmploymentStatus = "onboarding" | "probation" | "active" | "offboarding" | "inactive";
export type EmployeeContractType = "labor" | "nda" | "non_compete" | "internship";
export type EmployeeContractStatus = "active" | "expired" | "terminated";
export type EmployeeTrainingType = "internal" | "external" | "online";
export type EmployeeTrainingStatus = "planned" | "in_progress" | "completed" | "cancelled";
export type EmployeeCertificateStatus = "valid" | "expired";
export type EmployeeDepartmentSummary = {
id: string;
@@ -87,6 +90,7 @@ export type EmployeeContract = {
endDate: string | null;
terminatedDate: string | null;
attachmentPath: string | null;
attachmentUrl: string | null;
status: EmployeeContractStatus;
createdAt: string | null;
createdBy: string | null;
@@ -94,6 +98,37 @@ export type EmployeeContract = {
updatedBy: string | null;
};
export type EmployeeTraining = {
id: string;
employeeId: string;
name: string;
trainingType: EmployeeTrainingType;
startDate: string | null;
endDate: string | null;
status: EmployeeTrainingStatus;
notes: string | null;
createdAt: string | null;
createdBy: string | null;
updatedAt: string | null;
updatedBy: string | null;
};
export type EmployeeCertificate = {
id: string;
employeeId: string;
name: string;
issuer: string;
obtainedDate: string | null;
expiryDate: string | null;
certificateNo: string | null;
attachmentPath: string | null;
status: EmployeeCertificateStatus;
createdAt: string | null;
createdBy: string | null;
updatedAt: string | null;
updatedBy: string | null;
};
export type OrganizationTreeNode = {
id: string;
employeeNo: string;
@@ -209,6 +244,12 @@ export type EmployeeStatsResponse = {
dateTo: string;
count: number;
};
certificateSummary: {
dateFrom: string;
dateTo: string;
validHolderCount: number;
expiringSoonCount: number;
};
};
export type BatchTransferDepartmentPayload = {
@@ -255,6 +296,12 @@ export async function uploadEmployeeAvatar(employeeId: string, file: File) {
});
}
export async function deleteEmployeeAvatar(employeeId: string) {
return apiRequestData<{ employeeId: string; avatarUrl: string | null }>(`/api/employees/${employeeId}/avatar`, {
method: "DELETE",
});
}
export async function patchEmployeeProfile(
employeeId: string,
payload: Partial<{
@@ -373,6 +420,104 @@ export async function patchEmployeeContract(
});
}
export async function uploadEmployeeContractAttachment(employeeId: string, contractId: string, file: File) {
const formData = new FormData();
formData.append("file", file);
return apiRequestData<EmployeeContract>(`/api/employees/${employeeId}/contracts/${contractId}/attachment`, {
method: "PUT",
body: formData,
});
}
export async function downloadEmployeeContractAttachment(attachmentUrl: string): Promise<ApiBlobResponse> {
return apiRequestBlob(attachmentUrl);
}
export async function deleteEmployeeContract(employeeId: string, contractId: string) {
return apiRequestData<{ contractId: string; deleted: boolean }>(`/api/employees/${employeeId}/contracts/${contractId}`, {
method: "DELETE",
});
}
export async function fetchEmployeeTrainings(employeeId: string) {
return apiRequestData<{ items: EmployeeTraining[] }>(`/api/employees/${employeeId}/trainings`);
}
export async function createEmployeeTraining(
employeeId: string,
payload: {
name: string;
trainingType: EmployeeTrainingType;
startDate: string;
endDate?: string | null;
status: EmployeeTrainingStatus;
notes?: string | null;
},
) {
return apiRequestData<EmployeeTraining>(`/api/employees/${employeeId}/trainings`, {
method: "POST",
body: JSON.stringify(payload),
});
}
export async function patchEmployeeTraining(
employeeId: string,
trainingId: string,
payload: Partial<{
name: string;
trainingType: EmployeeTrainingType;
startDate: string;
endDate: string | null;
status: EmployeeTrainingStatus;
notes: string | null;
}>,
) {
return apiRequestData<EmployeeTraining>(`/api/employees/${employeeId}/trainings/${trainingId}`, {
method: "PATCH",
body: JSON.stringify(payload),
});
}
export async function fetchEmployeeCertificates(employeeId: string) {
return apiRequestData<{ items: EmployeeCertificate[] }>(`/api/employees/${employeeId}/certificates`);
}
export async function createEmployeeCertificate(
employeeId: string,
payload: {
name: string;
issuer: string;
obtainedDate: string;
expiryDate?: string | null;
certificateNo?: string | null;
attachmentPath?: string | null;
},
) {
return apiRequestData<EmployeeCertificate>(`/api/employees/${employeeId}/certificates`, {
method: "POST",
body: JSON.stringify(payload),
});
}
export async function patchEmployeeCertificate(
employeeId: string,
certificateId: string,
payload: Partial<{
name: string;
issuer: string;
obtainedDate: string;
expiryDate: string | null;
certificateNo: string | null;
attachmentPath: string | null;
}>,
) {
return apiRequestData<EmployeeCertificate>(`/api/employees/${employeeId}/certificates/${certificateId}`, {
method: "PATCH",
body: JSON.stringify(payload),
});
}
export async function completeEmployeeChecklistTask(employeeId: string, taskId: string) {
return apiRequestData<EmployeeProfile["lifecycle"]>(`/api/employees/${employeeId}/checklist-tasks/${taskId}/complete`, {
method: "POST",