@@ -1,121 +1,475 @@
/**
* 数据库种子数据脚本
* 用于初始化开发环境的测试用户
*/
import { PrismaClient } from '@prisma/client' ;
import { PrismaClient , UserRole , TenantType , TenantStatus } from '@prisma/client' ;
import bcrypt from 'bcryptjs' ;
import { v4 as uuidv4 } from 'uuid' ;
const prisma = new PrismaClient ( ) ;
async function main() {
console . log ( '🌱 开始初始化数据库种子数据...' ) ;
// 默认密码
const DEFAULT_PASSWORD = '123456' ;
// 创建测试用户
const mockUser = await prisma . user . upsert ( {
where : { id : 'user-mock-001' } ,
async function main() {
console . log ( '🌱 开始创建种子数据...\n' ) ;
// 加密默认密码
const hashedDefaultPassword = await bcrypt . hash ( DEFAULT_PASSWORD , 10 ) ;
// ============================================
// 1. 创建内部租户(运营团队专用)
// ============================================
console . log ( '📌 创建内部租户...' ) ;
const internalTenant = await prisma . tenants . upsert ( {
where : { code : 'yizhengxun' } ,
update : { } ,
create : {
id : 'user-mock-001' ,
email : 'test@example.com ' ,
password : '$2b$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN8/LewY5GyYIkYvKx7ES' , // password: "password123"
name : '测试用户' ,
role : 'user' ,
status : 'active' ,
kbQuota : 3 ,
kbUsed : 0 ,
isTrial : true ,
trialEndsAt : new Date ( Date . now ( ) + 30 * 24 * 60 * 60 * 1000 ) , // 30天后
id : uuidv4 ( ) ,
code : 'yizhengxun ' ,
name : '壹证循科技' ,
type : TenantType . INTERNAL ,
status : TenantStatus.ACTIVE ,
config : {
logo : null ,
backgroundImage : null ,
primaryColor : '#1890ff' ,
systemName : 'AI临床研究平台 - 运营管理端' ,
} ,
total_quota : BigInt ( 999999999 ) ,
updated_at : new Date ( ) ,
} ,
} ) ;
console . log ( ` ✅ 内部租户创建成功: ${ internalTenant . name } ` ) ;
console . log ( '✅ 测试用户创建成功:' , {
id : mockUser.id ,
email : mockUser.email ,
name : mockUser.name ,
} ) ;
// 可选:创建管理员用户
const adminUser = await prisma . user . upsert ( {
where : { email : 'admin@example.com' } ,
// ============================================
// 1.5 创建公共租户(个人用户池)
// ============================================
console . log ( '📌 创建公共租户(个人用户)...' ) ;
const publicTenant = await prisma . tenants . upsert ( {
where : { code : 'public' } ,
update : { } ,
create : {
id : 'user-admin-001' ,
email : 'admin@example.com ' ,
password : '$2b$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN8/LewY5GyYIkYvKx7ES' , // password: "password123"
nam e: '管理员' ,
role : 'admin' ,
id : uuidv4 ( ) ,
code : 'public ' ,
name : '个人用户' ,
typ e: TenantType . PUBLIC ,
status : TenantStatus.ACTIVE ,
config : {
logo : null ,
backgroundImage : null ,
primaryColor : '#1890ff' ,
systemName : 'AI临床研究平台' ,
} ,
total_quota : BigInt ( 100000 ) ,
updated_at : new Date ( ) ,
} ,
} ) ;
console . log ( ` ✅ 公共租户创建成功: ${ publicTenant . name } ` ) ;
// 为公共租户开放部分模块
const publicModules = [ 'PKB' , 'RVW' ] ;
for ( const moduleCode of publicModules ) {
await prisma . tenant_modules . upsert ( {
where : { tenant_id_module_code : { tenant_id : publicTenant.id , module_code : moduleCode } } ,
update : { } ,
create : {
id : uuidv4 ( ) ,
tenant_id : publicTenant.id ,
module_code : moduleCode ,
is_enabled : true ,
} ,
} ) ;
}
console . log ( ` ✅ 公共租户模块订阅: ${ publicModules . join ( ', ' ) } ` ) ;
// ============================================
// 2. 创建超级管理员
// ============================================
console . log ( '📌 创建超级管理员...' ) ;
const superAdmin = await prisma . User . upsert ( {
where : { phone : '13800000001' } ,
update : { } ,
create : {
phone : '13800000001' ,
password : hashedDefaultPassword ,
is_default_password : false ,
name : '超级管理员' ,
tenant_id : internalTenant.id ,
role : UserRole.SUPER_ADMIN ,
status : 'active' ,
kbQuota : 10 ,
kbUsed : 0 ,
isTrial : false ,
} ,
} ) ;
console . log ( ` ✅ 超级管理员创建成功: ${ superAdmin . phone } ` ) ;
console . log ( '✅ 管理员用户创建成功:' , {
id : adminUser.id ,
email : adminUser.email ,
name : adminUser.name ,
// ============================================
// 3. 创建Prompt工程师账号
// ============================================
console . log ( '📌 创建Prompt工程师账号...' ) ;
const promptEngineer = await prisma . User . upsert ( {
where : { phone : '13800000002' } ,
update : { } ,
create : {
phone : '13800000002' ,
password : hashedDefaultPassword ,
is_default_password : false ,
name : 'Prompt工程师' ,
tenant_id : internalTenant.id ,
role : UserRole.PROMPT_ENGINEER ,
status : 'active' ,
isTrial : false ,
} ,
} ) ;
console . log ( ` ✅ Prompt工程师创建成功: ${ promptEngineer . phone } ` ) ;
// ============================================
// 4. 创建示例租户(医院)
// ============================================
console . log ( '📌 创建示例租户(医院)...' ) ;
const hospitalTenant = await prisma . tenants . upsert ( {
where : { code : 'demo-hospital' } ,
update : { } ,
create : {
id : uuidv4 ( ) ,
code : 'demo-hospital' ,
name : '示范医院' ,
type : TenantType . HOSPITAL ,
status : TenantStatus.ACTIVE ,
config : {
logo : null ,
backgroundImage : null ,
primaryColor : '#1890ff' ,
systemName : '示范医院临床研究平台' ,
} ,
total_quota : BigInt ( 1000000 ) ,
contact_name : '张主任' ,
contact_phone : '13800138000' ,
contact_email : 'zhang@demo-hospital.com' ,
updated_at : new Date ( ) ,
} ,
} ) ;
console . log ( ` ✅ 示例医院租户创建成功: ${ hospitalTenant . name } ` ) ;
// ============================================
// 5. 创建医院科室
// ============================================
console . log ( '📌 创建医院科室...' ) ;
const cardiology = await prisma . departments . upsert ( {
where : { id : 'dept-cardiology' } ,
update : { } ,
create : {
id : 'dept-cardiology' ,
tenant_id : hospitalTenant.id ,
name : '心内科' ,
description : '心血管内科' ,
updated_at : new Date ( ) ,
} ,
} ) ;
const neurology = await prisma . departments . upsert ( {
where : { id : 'dept-neurology' } ,
update : { } ,
create : {
id : 'dept-neurology' ,
tenant_id : hospitalTenant.id ,
name : '神经内科' ,
description : '神经内科' ,
updated_at : new Date ( ) ,
} ,
} ) ;
console . log ( ` ✅ 科室创建成功: 心内科、神经内科 ` ) ;
// ============================================
// 6. 创建示例租户(药企)
// ============================================
console . log ( '📌 创建示例租户(药企)...' ) ;
const pharmaTenant = await prisma . tenants . upsert ( {
where : { code : 'demo-pharma' } ,
update : { } ,
create : {
id : uuidv4 ( ) ,
code : 'demo-pharma' ,
name : '示范药企' ,
type : TenantType . PHARMA ,
status : TenantStatus.ACTIVE ,
config : {
logo : null ,
backgroundImage : null ,
primaryColor : '#52c41a' ,
systemName : '示范药企IIT管理平台' ,
} ,
total_quota : BigInt ( 2000000 ) ,
contact_name : '李经理' ,
contact_phone : '13900139000' ,
contact_email : 'li@demo-pharma.com' ,
updated_at : new Date ( ) ,
} ,
} ) ;
console . log ( ` ✅ 示例药企租户创建成功: ${ pharmaTenant . name } ` ) ;
// ============================================
// 7. 创建医院管理员
// ============================================
console . log ( '📌 创建医院管理员...' ) ;
const hospitalAdmin = await prisma . User . upsert ( {
where : { phone : '13800138001' } ,
update : { } ,
create : {
phone : '13800138001' ,
password : hashedDefaultPassword ,
is_default_password : true ,
name : '张主任' ,
tenant_id : hospitalTenant.id ,
department_id : cardiology.id ,
role : UserRole.HOSPITAL_ADMIN ,
status : 'active' ,
isTrial : false ,
} ,
} ) ;
console . log ( ` ✅ 医院管理员创建成功: ${ hospitalAdmin . phone } ( ${ hospitalAdmin . name } ) ` ) ;
// 创建租户成员关系
await prisma . tenant_members . upsert ( {
where : { tenant_id_user_id : { tenant_id : hospitalTenant.id , user_id : hospitalAdmin.id } } ,
update : { } ,
create : {
id : uuidv4 ( ) ,
tenant_id : hospitalTenant.id ,
user_id : hospitalAdmin.id ,
role : UserRole.HOSPITAL_ADMIN ,
} ,
} ) ;
console . log ( '\n🎉 数据库种子数据初始化完成!\n' ) ;
console . log ( '📝 测试账号信息:' ) ;
console . log ( ' 邮箱: test@example.com' ) ;
console . log ( ' 密码: password123 ' ) ;
console . log ( ' 用户ID: user-mock-001\n' ) ;
console . log ( '📝 管理员账号信息:' ) ;
console . log ( ' 邮箱: admin@example.com' ) ;
console . log ( ' 密码: password123' ) ;
console . log ( ' 用户ID: user-admin-001\n' ) ;
// ============================================
// 8. 创建普通医生用户
// ============================================
console . log ( '📌 创建普通医生用户... ' ) ;
const doctor1 = await prisma . User . upsert ( {
where : { phone : '13800138002' } ,
update : { } ,
create : {
phone : '13800138002' ,
password : hashedDefaultPassword ,
is_default_password : true ,
name : '李医生' ,
tenant_id : hospitalTenant.id ,
department_id : cardiology.id ,
role : UserRole.USER ,
status : 'active' ,
isTrial : false ,
} ,
} ) ;
const doctor2 = await prisma . User . upsert ( {
where : { phone : '13800138003' } ,
update : { } ,
create : {
phone : '13800138003' ,
password : hashedDefaultPassword ,
is_default_password : true ,
name : '王医生' ,
tenant_id : hospitalTenant.id ,
department_id : neurology.id ,
role : UserRole.USER ,
status : 'active' ,
isTrial : false ,
} ,
} ) ;
console . log ( ` ✅ 普通用户创建成功: ${ doctor1 . name } 、 ${ doctor2 . name } ` ) ;
// 创建租户成员关系
for ( const user of [ doctor1 , doctor2 ] ) {
await prisma . tenant_members . upsert ( {
where : { tenant_id_user_id : { tenant_id : hospitalTenant.id , user_id : user.id } } ,
update : { } ,
create : {
id : uuidv4 ( ) ,
tenant_id : hospitalTenant.id ,
user_id : user.id ,
role : UserRole.USER ,
} ,
} ) ;
}
// ============================================
// 9. 创建权限数据
// ============================================
console . log ( '📌 创建权限数据...' ) ;
const permissionsData = [
// Prompt管理权限
{ code : 'prompt:view' , name : '查看Prompt' , description : '查看Prompt列表和历史版本' , module : 'prompt' } ,
{ code : 'prompt:edit' , name : '编辑Prompt' , description : '创建/修改DRAFT版本' , module : 'prompt' } ,
{ code : 'prompt:debug' , name : '调试Prompt' , description : '开启调试模式(核心权限)' , module : 'prompt' } ,
{ code : 'prompt:publish' , name : '发布Prompt' , description : '发布DRAFT为ACTIVE' , module : 'prompt' } ,
// 租户管理权限
{ code : 'tenant:view' , name : '查看租户' , description : '查看租户列表' , module : 'tenant' } ,
{ code : 'tenant:create' , name : '创建租户' , description : '创建新租户' , module : 'tenant' } ,
{ code : 'tenant:edit' , name : '编辑租户' , description : '编辑租户信息' , module : 'tenant' } ,
{ code : 'tenant:delete' , name : '删除租户' , description : '删除租户' , module : 'tenant' } ,
// 用户管理权限
{ code : 'user:view' , name : '查看用户' , description : '查看用户列表' , module : 'user' } ,
{ code : 'user:create' , name : '创建用户' , description : '创建新用户' , module : 'user' } ,
{ code : 'user:edit' , name : '编辑用户' , description : '编辑用户信息' , module : 'user' } ,
{ code : 'user:delete' , name : '删除用户' , description : '删除用户' , module : 'user' } ,
// 配额管理权限
{ code : 'quota:view' , name : '查看配额' , description : '查看配额使用情况' , module : 'quota' } ,
{ code : 'quota:allocate' , name : '分配配额' , description : '分配配额给科室/用户' , module : 'quota' } ,
// 审计日志权限
{ code : 'audit:view' , name : '查看审计日志' , description : '查看操作审计日志' , module : 'audit' } ,
] ;
for ( const perm of permissionsData ) {
await prisma . permissions . upsert ( {
where : { code : perm.code } ,
update : { } ,
create : perm ,
} ) ;
}
console . log ( ` ✅ ${ permissionsData . length } 个权限创建成功 ` ) ;
// ============================================
// 10. 创建角色-权限关联
// ============================================
console . log ( '📌 创建角色-权限关联...' ) ;
const allPermissions = await prisma . permissions . findMany ( ) ;
const permissionMap = new Map ( allPermissions . map ( p = > [ p . code , p . id ] ) ) ;
// SUPER_ADMIN 拥有所有权限
for ( const perm of allPermissions ) {
await prisma . role_permissions . upsert ( {
where : { role_permission_id : { role : UserRole.SUPER_ADMIN , permission_id : perm.id } } ,
update : { } ,
create : {
role : UserRole.SUPER_ADMIN ,
permission_id : perm.id ,
} ,
} ) ;
}
// PROMPT_ENGINEER 拥有Prompt相关权限
const promptPermCodes = [ 'prompt:view' , 'prompt:edit' , 'prompt:debug' , 'prompt:publish' ] ;
for ( const code of promptPermCodes ) {
const permId = permissionMap . get ( code ) ;
if ( permId ) {
await prisma . role_permissions . upsert ( {
where : { role_permission_id : { role : UserRole.PROMPT_ENGINEER , permission_id : permId } } ,
update : { } ,
create : {
role : UserRole.PROMPT_ENGINEER ,
permission_id : permId ,
} ,
} ) ;
}
}
// HOSPITAL_ADMIN 拥有用户、配额、审计权限
const hospitalAdminPermCodes = [ 'user:view' , 'user:create' , 'user:edit' , 'quota:view' , 'quota:allocate' , 'audit:view' ] ;
for ( const code of hospitalAdminPermCodes ) {
const permId = permissionMap . get ( code ) ;
if ( permId ) {
await prisma . role_permissions . upsert ( {
where : { role_permission_id : { role : UserRole.HOSPITAL_ADMIN , permission_id : permId } } ,
update : { } ,
create : {
role : UserRole.HOSPITAL_ADMIN ,
permission_id : permId ,
} ,
} ) ;
}
}
console . log ( ' ✅ 角色-权限关联创建成功' ) ;
// ============================================
// 11. 跳过Prompt模板( 表尚未创建)
// ============================================
console . log ( '📌 跳过Prompt模板创建( capability_schema.prompt_templates 尚未创建)' ) ;
// ============================================
// 12. 创建租户模块订阅
// ============================================
console . log ( '📌 创建租户模块订阅...' ) ;
const hospitalModules = [ 'ASL' , 'DC' , 'PKB' , 'AIA' , 'RVW' ] ;
for ( const moduleCode of hospitalModules ) {
await prisma . tenant_modules . upsert ( {
where : { tenant_id_module_code : { tenant_id : hospitalTenant.id , module_code : moduleCode } } ,
update : { } ,
create : {
id : uuidv4 ( ) ,
tenant_id : hospitalTenant.id ,
module_code : moduleCode ,
is_enabled : true ,
} ,
} ) ;
}
// 药企只订阅IIT和DC
const pharmaModules = [ 'IIT' , 'DC' ] ;
for ( const moduleCode of pharmaModules ) {
await prisma . tenant_modules . upsert ( {
where : { tenant_id_module_code : { tenant_id : pharmaTenant.id , module_code : moduleCode } } ,
update : { } ,
create : {
id : uuidv4 ( ) ,
tenant_id : pharmaTenant.id ,
module_code : moduleCode ,
is_enabled : true ,
} ,
} ) ;
}
console . log ( ' ✅ 租户模块订阅创建成功' ) ;
// ============================================
// 完成
// ============================================
console . log ( '\n🎉 种子数据创建完成!\n' ) ;
console . log ( '╔════════════════════════════════════════════════════════════╗' ) ;
console . log ( '║ 📝 测试账号信息 ║' ) ;
console . log ( '╠════════════════════════════════════════════════════════════╣' ) ;
console . log ( '║ 🔐 登录方式1: 手机号 + 验证码 ║' ) ;
console . log ( '║ 🔐 登录方式2: 手机号 + 密码 ║' ) ;
console . log ( '╠════════════════════════════════════════════════════════════╣' ) ;
console . log ( '║ 【运营管理员】 ║' ) ;
console . log ( '║ 超级管理员: 13800000001 / 123456 ║' ) ;
console . log ( '║ Prompt工程师: 13800000002 / 123456 ║' ) ;
console . log ( '╠════════════════════════════════════════════════════════════╣' ) ;
console . log ( '║ 【医院端 - demo-hospital】 ║' ) ;
console . log ( '║ 医院管理员: 13800138001 / 123456 (张主任) ║' ) ;
console . log ( '║ 普通医生: 13800138002 / 123456 (李医生·心内科) ║' ) ;
console . log ( '║ 普通医生: 13800138003 / 123456 (王医生·神内科) ║' ) ;
console . log ( '╠════════════════════════════════════════════════════════════╣' ) ;
console . log ( '║ 【药企端 - demo-pharma】 ║' ) ;
console . log ( '║ (暂无用户,可通过管理端添加) ║' ) ;
console . log ( '╠════════════════════════════════════════════════════════════╣' ) ;
console . log ( '║ 【个人用户 - public】 ║' ) ;
console . log ( '║ 通用登录入口: /login ║' ) ;
console . log ( '║ 可用模块: PKB, RVW ║' ) ;
console . log ( '╚════════════════════════════════════════════════════════════╝' ) ;
console . log ( '\n📌 租户专属登录URL: ' ) ;
console . log ( ' - 通用登录: /login' ) ;
console . log ( ' - 医院端: /t/demo-hospital/login' ) ;
console . log ( ' - 药企端: /t/demo-pharma/login' ) ;
console . log ( '\n⚠️ 提示:普通用户首次登录会提示修改默认密码' ) ;
}
main ( )
. catch ( ( e ) = > {
console . error ( '❌ 初始化种子数据失败:' , e ) ;
process . exit ( 1 ) ;
} )
. finally ( async ( ) = > {
. then ( async ( ) = > {
await prisma . $disconnect ( ) ;
} )
. catch ( async ( e ) = > {
console . error ( '❌ 种子数据创建失败:' , e ) ;
await prisma . $disconnect ( ) ;
process . exit ( 1 ) ;
} ) ;