feat(client): 部门管理与员工创建增强(F32)
- 新增部门管理页:列表/创建/归档 - 用户创建支持选择部门与直属上级 - 补齐 departments/employees API 封装与导航入口
这个提交包含在:
@@ -0,0 +1,52 @@
|
||||
import { apiRequestData } from "./http";
|
||||
|
||||
export type DepartmentItem = {
|
||||
id: string;
|
||||
name: string;
|
||||
parentId: string | null;
|
||||
archivedAt: string | null;
|
||||
createdAt: string | null;
|
||||
updatedAt: string | null;
|
||||
};
|
||||
|
||||
export type DepartmentTreeNode = DepartmentItem & {
|
||||
children: DepartmentTreeNode[];
|
||||
};
|
||||
|
||||
export type DepartmentListResponse = {
|
||||
includeArchived: boolean;
|
||||
items: DepartmentItem[];
|
||||
tree: DepartmentTreeNode[];
|
||||
};
|
||||
|
||||
export async function fetchDepartments(params: { includeArchived?: boolean } = {}) {
|
||||
const search = new URLSearchParams();
|
||||
if (params.includeArchived != null) {
|
||||
search.set("includeArchived", params.includeArchived ? "1" : "0");
|
||||
}
|
||||
|
||||
const qs = search.toString();
|
||||
return apiRequestData<DepartmentListResponse>(`/api/departments${qs ? `?${qs}` : ""}`);
|
||||
}
|
||||
|
||||
export async function createDepartment(payload: { name: string; parentId?: string | null }) {
|
||||
return apiRequestData<DepartmentItem>("/api/departments", {
|
||||
method: "POST",
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
}
|
||||
|
||||
export async function updateDepartment(departmentId: string, payload: { name?: string; parentId?: string | null }) {
|
||||
return apiRequestData<DepartmentItem>(`/api/departments/${departmentId}`, {
|
||||
method: "PATCH",
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
}
|
||||
|
||||
export async function archiveDepartment(departmentId: string) {
|
||||
return apiRequestData<DepartmentItem>(`/api/departments/${departmentId}/archive`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({}),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
import { apiRequestData } from "./http";
|
||||
|
||||
export type EmployeeStatus = "active" | "archived";
|
||||
|
||||
export type EmployeeSummary = {
|
||||
id: string;
|
||||
employeeNo: string;
|
||||
name: string;
|
||||
phone: string;
|
||||
email: string;
|
||||
status: EmployeeStatus;
|
||||
departmentId: string;
|
||||
directManagerId: string | null;
|
||||
title: string;
|
||||
roleCodes: string[];
|
||||
createdAt: string | null;
|
||||
updatedAt: string | null;
|
||||
};
|
||||
|
||||
export type EmployeeListResponse = {
|
||||
page: number;
|
||||
pageSize: number;
|
||||
total: number;
|
||||
items: EmployeeSummary[];
|
||||
};
|
||||
|
||||
export async function fetchEmployees(params: {
|
||||
page: number;
|
||||
pageSize: number;
|
||||
status?: EmployeeStatus;
|
||||
q?: string;
|
||||
}) {
|
||||
const search = new URLSearchParams();
|
||||
search.set("page", String(params.page));
|
||||
search.set("pageSize", String(params.pageSize));
|
||||
if (params.status) search.set("status", params.status);
|
||||
if (params.q) search.set("q", params.q);
|
||||
|
||||
return apiRequestData<EmployeeListResponse>(`/api/employees?${search.toString()}`);
|
||||
}
|
||||
|
||||
+2
-1
@@ -44,6 +44,8 @@ export async function createUser(payload: {
|
||||
phone: string;
|
||||
email: string;
|
||||
password: string;
|
||||
departmentId?: string;
|
||||
directManagerId?: string | null;
|
||||
roles: string[];
|
||||
}) {
|
||||
return apiRequestData<UserSummary>("/api/users", {
|
||||
@@ -80,4 +82,3 @@ export async function setUserRoles(userId: string, roles: string[]) {
|
||||
body: JSON.stringify({ roles }),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
在新工单中引用
屏蔽一个用户