feat(auth): add org/dept/position management, user page, and Phase 2 completion
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")
This commit is contained in:
168
apps/web/src/api/orgs.ts
Normal file
168
apps/web/src/api/orgs.ts
Normal file
@@ -0,0 +1,168 @@
|
||||
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;
|
||||
}
|
||||
Reference in New Issue
Block a user