feat: 增加DEFAULT_USER_PASSWORD,作为创建用户时的默认密码,添加p-limit库,添加DB_PARALLEL_LIMIT = 32环境变量作为“数据库批次操作默认并发数” 限制只有超级管理员才能创建超级管理员用户 删除用户时可以级联删除SelectionLog 添加zustand全局状态管理 一对多的院系管理功能 ,支持增删改查院系管理员信息、用户可以在header中切换管理的院系

This commit is contained in:
2025-11-18 20:07:42 +08:00
parent 7f3190a223
commit 2a80a44972
31 changed files with 1651 additions and 96 deletions

View File

@@ -3,9 +3,13 @@ import bcrypt from 'bcryptjs'
import { Permissions, ALL_PERMISSIONS } from '../src/constants/permissions'
import fs from 'fs'
import path from 'path'
import pLimit from 'p-limit'
const prisma = new PrismaClient()
// 从环境变量获取并发限制默认为16
const dbParallelLimit = pLimit(parseInt(process.env.DB_PARALLEL_LIMIT || '16', 10))
// 解析 JSON 文件并导入院系数据
async function importDepartments() {
const jsonPath = path.join(__dirname, 'init_data', '院系.json')
@@ -16,7 +20,7 @@ async function importDepartments() {
await Promise.all(
departments.map((dept: any) => {
return prisma.dept.upsert({
return dbParallelLimit(() => prisma.dept.upsert({
where: { code: dept.id },
update: {
name: dept.name,
@@ -27,7 +31,7 @@ async function importDepartments() {
name: dept.name,
fullName: dept.full_name,
},
})
}))
})
)
console.log('院系数据导入完成')
@@ -37,13 +41,15 @@ async function main() {
console.log('开始数据库初始化...')
// 插入权限
for (const permName of ALL_PERMISSIONS) {
await prisma.permission.upsert({
where: { name: permName },
update: {},
create: { name: permName },
await Promise.all(
ALL_PERMISSIONS.map((permName) => {
return dbParallelLimit(() => prisma.permission.upsert({
where: { name: permName },
update: {},
create: { name: permName },
}))
})
}
)
// 角色与权限映射
const rolePermissionsMap: Record<string, string[]> = {
@@ -51,18 +57,20 @@ async function main() {
}
// 插入角色
for (const [roleName, perms] of Object.entries(rolePermissionsMap)) {
await prisma.role.upsert({
where: { name: roleName },
update: {},
create: {
name: roleName,
permissions: {
connect: perms.map((name) => ({ name })),
await Promise.all(
Object.entries(rolePermissionsMap).map(([roleName, perms]) => {
return dbParallelLimit(() => prisma.role.upsert({
where: { name: roleName },
update: {},
create: {
name: roleName,
permissions: {
connect: perms.map((name) => ({ name })),
},
},
},
}))
})
}
)
await importDepartments()
@@ -74,33 +82,37 @@ async function main() {
{ id: 'unknown', name: '未知用户', status: '在校', deptCode: '00001', roleNames: [] },
]
for (const u of usersToCreate) {
const password = await bcrypt.hash(u.password ?? '123456', 12)
await prisma.user.upsert({
where: { id: u.id },
update: {
name: u.name,
status: u.status,
deptCode: u.deptCode,
password,
isSuperAdmin: u.isSuperAdmin ?? false,
roles: {
set: u.roleNames.map((name) => ({ name })),
},
},
create: {
id: u.id,
name: u.name,
status: u.status,
deptCode: u.deptCode,
password,
isSuperAdmin: u.isSuperAdmin ?? false,
roles: {
connect: u.roleNames.map((name) => ({ name })),
},
},
await Promise.all(
usersToCreate.map((u) => {
return dbParallelLimit(async () => {
const password = await bcrypt.hash(u.password || process.env.USER_DEFAULT_PASSWORD || 'jeep4ahxahx7ee7U', 12)
await prisma.user.upsert({
where: { id: u.id },
update: {
name: u.name,
status: u.status,
deptCode: u.deptCode,
password,
isSuperAdmin: u.isSuperAdmin ?? false,
roles: {
set: u.roleNames.map((name) => ({ name })),
},
},
create: {
id: u.id,
name: u.name,
status: u.status,
deptCode: u.deptCode,
password,
isSuperAdmin: u.isSuperAdmin ?? false,
roles: {
connect: u.roleNames.map((name) => ({ name })),
},
},
})
})
})
}
)
// 插入文件类型(仅开发环境)
const fileTypes = [
@@ -125,18 +137,19 @@ async function main() {
{ id: 'OTHER', name: '其他', description: '无法归入以上分类的文件' },
]
for (let index = 0; index < fileTypes.length; index++) {
const fileType = fileTypes[index]
await prisma.devFileType.upsert({
where: { id: fileType.id },
update: {
name: fileType.name,
description: fileType.description,
order: (index + 1) * 10,
},
create: {...fileType, order: (index + 1) * 10},
await Promise.all(
fileTypes.map((fileType, index) => {
return dbParallelLimit(() => prisma.devFileType.upsert({
where: { id: fileType.id },
update: {
name: fileType.name,
description: fileType.description,
order: (index + 1) * 10,
},
create: {...fileType, order: (index + 1) * 10},
}))
})
}
)
console.log('文件类型数据初始化完成')
// 插入依赖包类型(仅开发环境)
@@ -152,18 +165,19 @@ async function main() {
{ id: 'NODEJS_CORE', name: 'Node.js核心', description: 'Node.js运行时内置的模块用于底层操作如文件系统、路径处理等例如fs、path、child_process、util、module、os、http、crypto、events、stream、process、net、url、assert。' },
]
for (let index = 0; index < pkgTypes.length; index++) {
const pkgType = pkgTypes[index]
await prisma.devPkgType.upsert({
where: { id: pkgType.id },
update: {
name: pkgType.name,
description: pkgType.description,
order: (index + 1) * 10,
},
create: {...pkgType, order: (index + 1) * 10},
await Promise.all(
pkgTypes.map((pkgType, index) => {
return dbParallelLimit(() => prisma.devPkgType.upsert({
where: { id: pkgType.id },
update: {
name: pkgType.name,
description: pkgType.description,
order: (index + 1) * 10,
},
create: {...pkgType, order: (index + 1) * 10},
}))
})
}
)
console.log('依赖包类型数据初始化完成')
console.log('数据库初始化完成')
@@ -177,4 +191,4 @@ main()
console.error(e)
await prisma.$disconnect()
process.exit(1)
})
})