Complete Phase 2 identity & authentication module: - Organization CRUD with tree structure (parent_id + materialized path) - Department CRUD nested under organizations with tree support - Position CRUD nested under departments - User management page with table, create/edit modal, role assignment - Organization architecture page with 3-panel tree layout - Frontend API layer for orgs/depts/positions - Sidebar navigation updated with organization menu item - Fix parse_ttl edge case for strings ending in 'd' (e.g. "invalid")
169 lines
3.6 KiB
TypeScript
169 lines
3.6 KiB
TypeScript
import client from './client';
|
|
|
|
// --- Organization types ---
|
|
|
|
export interface OrganizationInfo {
|
|
id: string;
|
|
name: string;
|
|
code?: string;
|
|
parent_id?: string;
|
|
path?: string;
|
|
level: number;
|
|
sort_order: number;
|
|
children: OrganizationInfo[];
|
|
}
|
|
|
|
export interface CreateOrganizationRequest {
|
|
name: string;
|
|
code?: string;
|
|
parent_id?: string;
|
|
sort_order?: number;
|
|
}
|
|
|
|
export interface UpdateOrganizationRequest {
|
|
name?: string;
|
|
code?: string;
|
|
sort_order?: number;
|
|
}
|
|
|
|
// --- Department types ---
|
|
|
|
export interface DepartmentInfo {
|
|
id: string;
|
|
org_id: string;
|
|
name: string;
|
|
code?: string;
|
|
parent_id?: string;
|
|
manager_id?: string;
|
|
path?: string;
|
|
sort_order: number;
|
|
children: DepartmentInfo[];
|
|
}
|
|
|
|
export interface CreateDepartmentRequest {
|
|
name: string;
|
|
code?: string;
|
|
parent_id?: string;
|
|
manager_id?: string;
|
|
sort_order?: number;
|
|
}
|
|
|
|
export interface UpdateDepartmentRequest {
|
|
name?: string;
|
|
code?: string;
|
|
manager_id?: string;
|
|
sort_order?: number;
|
|
}
|
|
|
|
// --- Position types ---
|
|
|
|
export interface PositionInfo {
|
|
id: string;
|
|
dept_id: string;
|
|
name: string;
|
|
code?: string;
|
|
level: number;
|
|
sort_order: number;
|
|
}
|
|
|
|
export interface CreatePositionRequest {
|
|
name: string;
|
|
code?: string;
|
|
level?: number;
|
|
sort_order?: number;
|
|
}
|
|
|
|
export interface UpdatePositionRequest {
|
|
name?: string;
|
|
code?: string;
|
|
level?: number;
|
|
sort_order?: number;
|
|
}
|
|
|
|
// --- Organization API ---
|
|
|
|
export async function listOrgTree() {
|
|
const { data } = await client.get<{ success: boolean; data: OrganizationInfo[] }>(
|
|
'/organizations',
|
|
);
|
|
return data.data;
|
|
}
|
|
|
|
export async function createOrg(req: CreateOrganizationRequest) {
|
|
const { data } = await client.post<{ success: boolean; data: OrganizationInfo }>(
|
|
'/organizations',
|
|
req,
|
|
);
|
|
return data.data;
|
|
}
|
|
|
|
export async function updateOrg(id: string, req: UpdateOrganizationRequest) {
|
|
const { data } = await client.put<{ success: boolean; data: OrganizationInfo }>(
|
|
`/organizations/${id}`,
|
|
req,
|
|
);
|
|
return data.data;
|
|
}
|
|
|
|
export async function deleteOrg(id: string) {
|
|
await client.delete(`/organizations/${id}`);
|
|
}
|
|
|
|
// --- Department API ---
|
|
|
|
export async function listDeptTree(orgId: string) {
|
|
const { data } = await client.get<{ success: boolean; data: DepartmentInfo[] }>(
|
|
`/organizations/${orgId}/departments`,
|
|
);
|
|
return data.data;
|
|
}
|
|
|
|
export async function createDept(orgId: string, req: CreateDepartmentRequest) {
|
|
const { data } = await client.post<{ success: boolean; data: DepartmentInfo }>(
|
|
`/organizations/${orgId}/departments`,
|
|
req,
|
|
);
|
|
return data.data;
|
|
}
|
|
|
|
export async function deleteDept(id: string) {
|
|
await client.delete(`/departments/${id}`);
|
|
}
|
|
|
|
export async function updateDept(id: string, req: UpdateDepartmentRequest) {
|
|
const { data } = await client.put<{ success: boolean; data: DepartmentInfo }>(
|
|
`/departments/${id}`,
|
|
req,
|
|
);
|
|
return data.data;
|
|
}
|
|
|
|
// --- Position API ---
|
|
|
|
export async function listPositions(deptId: string) {
|
|
const { data } = await client.get<{ success: boolean; data: PositionInfo[] }>(
|
|
`/departments/${deptId}/positions`,
|
|
);
|
|
return data.data;
|
|
}
|
|
|
|
export async function createPosition(deptId: string, req: CreatePositionRequest) {
|
|
const { data } = await client.post<{ success: boolean; data: PositionInfo }>(
|
|
`/departments/${deptId}/positions`,
|
|
req,
|
|
);
|
|
return data.data;
|
|
}
|
|
|
|
export async function deletePosition(id: string) {
|
|
await client.delete(`/positions/${id}`);
|
|
}
|
|
|
|
export async function updatePosition(id: string, req: UpdatePositionRequest) {
|
|
const { data } = await client.put<{ success: boolean; data: PositionInfo }>(
|
|
`/positions/${id}`,
|
|
req,
|
|
);
|
|
return data.data;
|
|
}
|