gongxiangp2/scripts/backfill-auto-personnel.ts

88 lines
3.0 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 一次性校正脚本:按花名册自动激活 + 同步角色(全量)
*
* 规则(与 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) })