feat: 完成 R13/R14/R15/R16 小团队管理核心能力

这个提交包含在:
2026-03-21 20:31:34 +08:00
父节点 0826693a8f
当前提交 1e52f1c225
共修改 47 个文件,包含 4298 行新增和 306 行删除
+160
查看文件
@@ -24,6 +24,79 @@ export type EmployeeListResponse = {
items: EmployeeSummary[];
};
export type EmployeeLifecycleEvent = {
id: string;
employeeId: string;
eventType: "onboard" | "regularize" | "transfer" | "offboard";
effectiveDate: string | null;
payloadJson: Record<string, unknown> | null;
createdAt: string | null;
createdBy: string | null;
};
export type EmployeeChecklistTask = {
id: string;
employeeId: string;
scene: "onboarding" | "offboarding" | "transfer";
taskType:
| "account_setup"
| "asset_issue"
| "policy_ack"
| "asset_return"
| "access_revoke"
| "expense_clearance"
| "handover_note";
title: string;
status: "pending" | "completed" | "skipped";
dueDate: string | null;
completedAt: string | null;
completedBy: string | null;
payloadJson: Record<string, unknown> | null;
createdAt: string | null;
};
export type EmployeeProfile = {
employee: {
id: string;
employeeNo: string;
name: string;
phone: string;
email: string;
status: EmployeeStatus;
employmentStatus: "onboarding" | "probation" | "active" | "offboarding" | "inactive";
departmentId: string;
title: string;
directManagerId: string | null;
hireDate: string | null;
probationEndDate: string | null;
lastWorkingDate: string | null;
workLocation: string | null;
emergencyContactName: string | null;
emergencyContactPhone: string | null;
notes: string | null;
archivedAt: string | null;
roleCodes: string[];
department: { id: string; name: string } | null;
directManager: { id: string; employeeNo: string; name: string } | null;
};
lifecycle: {
events: EmployeeLifecycleEvent[];
checklistTasks: EmployeeChecklistTask[];
blockers: {
openAssetCount: number;
pendingWorkflowTaskCount: number;
canCompleteOffboarding: boolean;
};
};
assignedAssets: Array<{
id: string;
assetNo: string;
name: string;
status: string;
location: string | null;
}>;
};
export async function fetchEmployees(params: {
page: number;
pageSize: number;
@@ -39,3 +112,90 @@ export async function fetchEmployees(params: {
return apiRequestData<EmployeeListResponse>(`/api/employees?${search.toString()}`);
}
export async function fetchEmployeeProfile(employeeId: string) {
return apiRequestData<EmployeeProfile>(`/api/employees/${employeeId}/profile`);
}
export async function patchEmployeeProfile(
employeeId: string,
payload: Partial<{
departmentId: string;
directManagerId: string | null;
title: string;
probationEndDate: string | null;
lastWorkingDate: string | null;
workLocation: string | null;
emergencyContactName: string | null;
emergencyContactPhone: string | null;
notes: string | null;
}>,
) {
return apiRequestData<EmployeeProfile>(`/api/employees/${employeeId}/profile`, {
method: "PATCH",
body: JSON.stringify(payload),
});
}
export async function startEmployeeOnboarding(
employeeId: string,
payload: { effectiveDate?: string; probationEndDate?: string | null; notes?: string | null } = {},
) {
return apiRequestData<EmployeeProfile>(`/api/employees/${employeeId}/onboarding/start`, {
method: "POST",
body: JSON.stringify(payload),
});
}
export async function regularizeEmployee(
employeeId: string,
payload: { effectiveDate?: string; notes?: string | null } = {},
) {
return apiRequestData<EmployeeProfile>(`/api/employees/${employeeId}/regularize`, {
method: "POST",
body: JSON.stringify(payload),
});
}
export async function transferEmployee(
employeeId: string,
payload: {
effectiveDate?: string;
departmentId?: string;
directManagerId?: string | null;
title?: string;
notes?: string | null;
} = {},
) {
return apiRequestData<EmployeeProfile>(`/api/employees/${employeeId}/transfer`, {
method: "POST",
body: JSON.stringify(payload),
});
}
export async function startEmployeeOffboarding(
employeeId: string,
payload: { effectiveDate?: string; lastWorkingDate?: string | null; notes?: string | null } = {},
) {
return apiRequestData<EmployeeProfile>(`/api/employees/${employeeId}/offboarding/start`, {
method: "POST",
body: JSON.stringify(payload),
});
}
export async function fetchEmployeeLifecycle(employeeId: string) {
return apiRequestData<EmployeeProfile["lifecycle"]>(`/api/employees/${employeeId}/lifecycle`);
}
export async function completeEmployeeChecklistTask(employeeId: string, taskId: string) {
return apiRequestData<EmployeeProfile["lifecycle"]>(`/api/employees/${employeeId}/checklist-tasks/${taskId}/complete`, {
method: "POST",
body: JSON.stringify({}),
});
}
export async function skipEmployeeChecklistTask(employeeId: string, taskId: string) {
return apiRequestData<EmployeeProfile["lifecycle"]>(`/api/employees/${employeeId}/checklist-tasks/${taskId}/skip`, {
method: "POST",
body: JSON.stringify({}),
});
}