diff --git a/backend/src/routes/department.routes.ts b/backend/src/routes/department.routes.ts index c5aeb44..501af7c 100644 --- a/backend/src/routes/department.routes.ts +++ b/backend/src/routes/department.routes.ts @@ -21,6 +21,24 @@ const updateDeptSchema = createDeptSchema.partial() /** 获取部门树 */ router.get('/', authMiddleware, async (req: AuthRequest, res, next) => { try { + // 兼容历史组织:若无任何部门,自动创建根部门(公司名) + const existing = await prisma.department.findFirst({ where: { orgId: req.user!.orgId! } }) + if (!existing) { + const org = await prisma.organization.findUnique({ where: { id: req.user!.orgId! } }) + if (org) { + await prisma.department.create({ + data: { + orgId: org.id, + name: org.name, + parentId: null, + level: 0, + sortOrder: 0, + description: '组织根节点', + createdBy: req.user!.id, + }, + }) + } + } const departments = await prisma.department.findMany({ where: { orgId: req.user!.orgId! }, orderBy: [{ sortOrder: 'asc' }, { createdAt: 'asc' }], @@ -37,7 +55,12 @@ router.post('/', authMiddleware, async (req: AuthRequest, res, next) => { try { const data = createDeptSchema.parse(req.body) // 空字符串视为无父部门,统一转为 null - const parentId = data.parentId && data.parentId.trim() !== '' ? data.parentId : null + let parentId = data.parentId && data.parentId.trim() !== '' ? data.parentId : null + // 若未指定父部门,默认挂到根部门(level=0)下 + if (!parentId) { + const root = await prisma.department.findFirst({ where: { orgId: req.user!.orgId!, parentId: null }, orderBy: { sortOrder: 'asc' } }) + if (root) parentId = root.id + } let level = 0 if (parentId) { const parent = await prisma.department.findFirst({ where: { id: parentId, orgId: req.user!.orgId! } }) diff --git a/backend/src/services/auth.service.ts b/backend/src/services/auth.service.ts index 378b363..a5bd8b5 100644 --- a/backend/src/services/auth.service.ts +++ b/backend/src/services/auth.service.ts @@ -27,6 +27,19 @@ export async function register(orgName: string, phone: string, password: string) }, }) + // 自动创建根部门(公司名),作为组织架构的顶层节点 + await prisma.department.create({ + data: { + orgId: org.id, + name: orgName, + parentId: null, + level: 0, + sortOrder: 0, + description: '组织根节点', + createdBy: user.id, + }, + }) + await prisma.user.update({ where: { id: user.id }, data: { lastLoginAt: new Date() }, diff --git a/frontend/src/pages/OrgChart.tsx b/frontend/src/pages/OrgChart.tsx index 0d748f7..f95043c 100644 --- a/frontend/src/pages/OrgChart.tsx +++ b/frontend/src/pages/OrgChart.tsx @@ -61,10 +61,13 @@ export default function OrgChart() { } const renderTree = (items: any[], parentId: string | null, level: number = 0) => { - return items.filter(d => d.parentId === parentId).map(d => ( + return items.filter(d => d.parentId === parentId).map(d => { + // 根部门(level=0 且无父部门)为公司节点,不可编辑/删除 + const isRoot = d.level === 0 && !d.parentId + return (
{items.some(c => c.parentId === d.id) ? ( @@ -74,29 +77,35 @@ export default function OrgChart() { ) : ( )} - + {d.name} + {isRoot && 公司} {d._count?.employees || 0}人 - - + {!isRoot && ( + <> + + + + )}
{expanded.has(d.id) && renderTree(items, d.id, level + 1)}
- )) + ) + }) } return ( @@ -130,7 +139,9 @@ export default function OrgChart() { 部门列表