/** * 一次性校正脚本:按花名册自动激活 + 同步角色(全量) * * 规则(与 lib/auto-personnel-rules.ts 一致): * - 有活跃绑定 + 花名册在职(非 RESIGNED)→ 自动激活(status=active, isActive=true) * - M 级(levelType='M')或 isLeadership → DEPT_ADMIN;否则 USER * - 不降级 SYSTEM_ADMIN / ADMIN(人工授予的高权限保持不变) * * 用法:npx tsx --env-file=.env scripts/backfill-auto-personnel.ts # 预演(默认) * npx tsx --env-file=.env scripts/backfill-auto-personnel.ts --apply # 实际写入 */ import { prisma } from '@/lib/prisma' import { getAuthoritativePersonnelForUser, shouldAutoActivate, deriveRoleFromPersonnel, } from '@/lib/auto-personnel-rules' const APPLY = process.argv.includes('--apply') ;(async () => { console.log(APPLY ? '=== 实际写入模式 ===' : '=== 预演模式(不写入)===') const users = await prisma.user.findMany({ where: { archivedAt: null }, select: { id: true, username: true, realName: true, role: true, status: true, isActive: true }, orderBy: { username: 'asc' }, }) console.log(`账号总数(未归档): ${users.length}\n`) let wouldActivate = 0 let wouldRoleChange = 0 const plan: string[] = [] for (const u of users) { const personnel = await getAuthoritativePersonnelForUser(u.id) if (!personnel) continue // 无绑定,跳过 const changes: string[] = [] // 激活判定 const shouldActivate = shouldAutoActivate(personnel) const currentStatus = u.status || (u.isActive ? 'active' : 'pending') if (shouldActivate && currentStatus !== 'active') { wouldActivate++ changes.push(`激活: ${currentStatus} -> active`) } // 角色派生 const derived = deriveRoleFromPersonnel(personnel) if (u.role !== 'SYSTEM_ADMIN' && u.role !== 'ADMIN' && u.role !== derived) { wouldRoleChange++ changes.push(`角色: ${u.role} -> ${derived}`) } if (changes.length > 0) { plan.push(`${u.realName ?? u.username} (${u.username}): ${changes.join(', ')}`) if (APPLY) { await prisma.user.update({ where: { id: u.id }, data: { ...(shouldActivate && currentStatus !== 'active' ? { status: 'active', isActive: true, statusChangedAt: new Date(), statusChangedBy: 'auto-花名册在册' } : {}), ...(u.role !== 'SYSTEM_ADMIN' && u.role !== 'ADMIN' && u.role !== derived ? { role: derived } : {}), }, }) } } } console.log(`计划激活: ${wouldActivate} 人`) console.log(`计划角色变更: ${wouldRoleChange} 人`) console.log('\n明细:') for (const line of plan) console.log(` ${line}`) if (APPLY) { console.log(`\n已写入 ${plan.length} 条记录`) } else { console.log('\n(预演结束,未写入任何数据。加 --apply 实际执行)') } await prisma.$disconnect() })().catch((e) => { console.error(e); process.exit(1) })