/** * 串档排查脚本(只读): * 找出"无花名(外部/离职人员)却带有 M 级等级/负责人标志"的可疑档案。 * * 规则(用户确认):有花名 = 正式员工;无花名 = 外部人员/离职人员。 * 正式员工才应有 M/P 等级;无花名的档案若带等级,极可能是花名册同名串档。 * * 用法:npx tsx --env-file=.env scripts/audit-flower-mismatch.ts */ import { PrismaClient } from '@prisma/client' const prisma = new PrismaClient() ;(async () => { console.log('=== 花名与等级一致性审计(只读)===\n') // 有绑定且带等级但无花名的档案(疑似串档) const suspicious = await prisma.performanceSurveyEmployeeProfile.findMany({ where: { positionLevel: { not: null }, OR: [{ flowerName: null }, { flowerName: '' }], }, select: { id: true, displayName: true, realName: true, flowerName: true, jobNumber: true, dingtalkUserId: true, departmentPath: true, positionLevel: true, levelType: true, isLeadership: true, employmentState: true, }, orderBy: { departmentPath: 'asc' }, }) // 过滤:只看有素材库绑定的人(无绑定的花名册人员即使无花名带等级也不是我们关注的) const boundIds = new Set( (await prisma.userEmployeeBinding.findMany({ where: { status: 'ACTIVE' }, select: { employeeProfileId: true }, })).map((b) => b.employeeProfileId), ) const relevant = suspicious.filter((p) => boundIds.has(p.id)) console.log(`无花名但带等级 + 有绑定的档案: ${relevant.length} 条\n`) for (const p of relevant) { console.log(`【${p.displayName}】真名=${p.realName ?? '?'} 花名=${p.flowerName ?? '(无)'} 工号=${p.jobNumber ?? '?'}`) console.log(` 部门=${p.departmentPath ?? '?'}`) console.log(` 等级=${p.positionLevel}(${p.levelType ?? '?'}) 负责人=${p.isLeadership} 在职=${p.employmentState}`) console.log(` 钉钉ID=${p.dingtalkUserId ?? '(无)'} 档案ID=${p.id}\n`) } console.log('=== 审计结束(未写入任何数据)===') await prisma.$disconnect() })().catch((e) => { console.error(e); process.exit(1) })