feat: 添加部门管理功能、主题切换和多语言支持

refactor(dashboard): 重构用户管理页面和路由结构

feat(server): 实现部门管理API和RBAC增强功能

docs: 更新用户手册和管理员指南文档

style: 统一图标使用和组件命名规范

test: 添加部门服务和数据隔离测试用例

chore: 更新依赖和配置文件
This commit is contained in:
2026-03-28 22:52:12 +08:00
parent 22308fe042
commit d327706087
87 changed files with 21372 additions and 4806 deletions

View File

@@ -264,6 +264,132 @@ export class HierarchyService {
logger.info(`[Hierarchy] Deleted department ${departmentId}`);
}
/**
* [BE-MT002-04-01] 设置部门负责人
*/
static async assignDepartmentManager(
departmentId: string,
tenantId: string,
managerId: string,
assignedBy: string
): Promise<Department> {
const department = await db('cf_department')
.where('id', departmentId)
.where('tenant_id', tenantId)
.first();
if (!department) {
throw new Error('部门不存在');
}
const user = await db('cf_user')
.where('id', managerId)
.where('tenant_id', tenantId)
.where('status', 'ACTIVE')
.first();
if (!user) {
throw new Error('用户不存在或未激活');
}
await db('cf_department')
.where('id', departmentId)
.where('tenant_id', tenantId)
.update({
manager_id: managerId,
updated_at: new Date(),
});
const updatedDepartment = await db('cf_department')
.where('id', departmentId)
.where('tenant_id', tenantId)
.first();
await this.clearHierarchyCache(tenantId);
await EventBusService.publish({
type: 'hierarchy.department.manager_assigned',
data: {
departmentId,
tenantId,
managerId,
assignedBy,
timestamp: new Date(),
}
});
logger.info(`[Hierarchy] Assigned manager ${managerId} to department ${departmentId}`);
return updatedDepartment;
}
/**
* [BE-MT002-04-02] 获取部门负责人
*/
static async getDepartmentManager(departmentId: string, tenantId: string): Promise<any> {
const department = await db('cf_department')
.where('id', departmentId)
.where('tenant_id', tenantId)
.first();
if (!department || !department.manager_id) {
return null;
}
const manager = await db('cf_user')
.where('id', department.manager_id)
.where('tenant_id', tenantId)
.select('id', 'username', 'email', 'role', 'status')
.first();
return manager;
}
/**
* [BE-MT002-04-03] 获取部门统计信息
*/
static async getDepartmentStats(departmentId: string, tenantId: string): Promise<any> {
const department = await db('cf_department')
.where('id', departmentId)
.where('tenant_id', tenantId)
.first();
if (!department) {
throw new Error('部门不存在');
}
const [userCount, shopCount, subDepartmentCount] = await Promise.all([
db('cf_user')
.where('department_id', departmentId)
.where('tenant_id', tenantId)
.count('id as count')
.first(),
db('cf_shop')
.where('department_id', departmentId)
.where('tenant_id', tenantId)
.count('id as count')
.first(),
db('cf_department')
.where('parent_id', departmentId)
.where('tenant_id', tenantId)
.count('id as count')
.first(),
]);
return {
departmentId,
departmentName: department.name,
userCount: Number(userCount?.count || 0),
shopCount: Number(shopCount?.count || 0),
subDepartmentCount: Number(subDepartmentCount?.count || 0),
managerId: department.manager_id,
status: department.status,
createdAt: department.created_at,
};
}
/**
* [BE-MT002-05] 创建店铺
*/