76f266645d
含 Phase 1.1 IM seq 排序、断线重连、多端已读同步与微信式语音转文字 UI。 排除 node_modules、构建产物、安装包与 .env 密钥。 Co-authored-by: Cursor <cursoragent@cursor.com>
142 lines
4.7 KiB
TypeScript
142 lines
4.7 KiB
TypeScript
import { PrismaClient } from '@prisma/client';
|
|
import * as fs from 'fs';
|
|
|
|
const prisma = new PrismaClient();
|
|
const DUMP = '/opt/import/prod/oa_hr.json';
|
|
|
|
const ROLES: { code: string; name: string; dataScope: string }[] = [
|
|
{ code: 'rd_director', name: '研发总监', dataScope: 'DEPT' },
|
|
{ code: '3d_director', name: '三维总监', dataScope: 'DEPT' },
|
|
{ code: 'video_director', name: '摄制总监', dataScope: 'DEPT' },
|
|
{ code: 'material_director', name: '物资总监', dataScope: 'DEPT' },
|
|
{ code: 'pm', name: '项目经理', dataScope: 'DEPT' },
|
|
{ code: 'rd_staff', name: '研发技术岗', dataScope: 'SELF' },
|
|
{ code: '3d_staff', name: '三维技术岗', dataScope: 'SELF' },
|
|
{ code: 'video_staff', name: '摄制技术岗', dataScope: 'SELF' },
|
|
{ code: 'material_staff', name: '物资技术岗', dataScope: 'SELF' },
|
|
{ code: 'tech', name: '普通岗位', dataScope: 'SELF' },
|
|
];
|
|
|
|
const POST_ROLE: Record<string, string> = {
|
|
sysadmin: 'admin',
|
|
boss: 'owner',
|
|
business_director: 'biz_director',
|
|
business_staff: 'biz_staff',
|
|
rd_director: 'rd_director',
|
|
'3d_director': '3d_director',
|
|
video_director: 'video_director',
|
|
material_director: 'material_director',
|
|
pm: 'pm',
|
|
tech: 'tech',
|
|
rd_staff: 'rd_staff',
|
|
'3d_staff': '3d_staff',
|
|
video_staff: 'video_staff',
|
|
material_staff: 'material_staff',
|
|
};
|
|
|
|
function pickRole(userName: string, postCodes: string[]) {
|
|
if (userName === 'xibei') return 'employee';
|
|
if (userName === 'administrator' || userName === 'admin') return 'admin';
|
|
const rank: Record<string, number> = {
|
|
employee: 0,
|
|
tech: 1,
|
|
rd_staff: 1,
|
|
'3d_staff': 1,
|
|
video_staff: 1,
|
|
material_staff: 1,
|
|
pm: 2,
|
|
biz_staff: 3,
|
|
rd_director: 4,
|
|
'3d_director': 4,
|
|
video_director: 4,
|
|
material_director: 4,
|
|
tech_director: 4,
|
|
biz_director: 5,
|
|
owner: 6,
|
|
admin: 7,
|
|
};
|
|
let best: string | null = null;
|
|
let bestRank = -1;
|
|
for (const c of postCodes) {
|
|
const role = POST_ROLE[c];
|
|
if (!role) continue;
|
|
const r = rank[role] ?? 1;
|
|
if (r > bestRank) {
|
|
best = role;
|
|
bestRank = r;
|
|
}
|
|
}
|
|
return best || 'employee';
|
|
}
|
|
|
|
async function main() {
|
|
for (const r of ROLES) {
|
|
const existing = await prisma.role.findFirst({ where: { code: r.code } });
|
|
if (existing) {
|
|
await prisma.role.update({ where: { id: existing.id }, data: { name: r.name, dataScope: r.dataScope } });
|
|
} else {
|
|
await prisma.role.create({ data: { name: r.name, code: r.code, dataScope: r.dataScope } });
|
|
}
|
|
}
|
|
await prisma.role.updateMany({ where: { code: 'biz_staff' }, data: { name: '商务专员' } });
|
|
await prisma.role.updateMany({ where: { code: 'biz_director' }, data: { name: '商务总监' } });
|
|
await prisma.role.updateMany({ where: { code: 'owner' }, data: { name: '企业负责人' } });
|
|
|
|
const dump = JSON.parse(fs.readFileSync(DUMP, 'utf8')) as {
|
|
posts: { id: number; code: string; name: string }[];
|
|
users: { id: number; userName: string; nickName: string }[];
|
|
userPosts: { postId: number; userId: number }[];
|
|
};
|
|
const postById = new Map(dump.posts.map((p) => [p.id, p]));
|
|
const postsByUser = new Map<number, { code: string; name: string }[]>();
|
|
for (const up of dump.userPosts) {
|
|
const post = postById.get(up.postId);
|
|
if (!post) continue;
|
|
const list = postsByUser.get(up.userId) || [];
|
|
list.push(post);
|
|
postsByUser.set(up.userId, list);
|
|
}
|
|
|
|
const roles = await prisma.role.findMany();
|
|
const roleByCode = new Map(roles.map((r) => [r.code, r.id]));
|
|
let n = 0;
|
|
for (const u of dump.users) {
|
|
if (u.userName === 'administrator') continue;
|
|
const user = await prisma.user.findFirst({ where: { username: u.userName } });
|
|
if (!user) continue;
|
|
const posts = postsByUser.get(u.id) || [];
|
|
const roleCode = pickRole(u.userName, posts.map((p) => p.code));
|
|
const roleId = roleByCode.get(roleCode);
|
|
if (!roleId) continue;
|
|
await prisma.userRole.deleteMany({ where: { userId: user.id } });
|
|
await prisma.userRole.create({ data: { userId: user.id, roleId } });
|
|
const title = posts.find((p) => POST_ROLE[p.code] === roleCode)?.name || posts[0]?.name;
|
|
if (title && user.employeeId) {
|
|
await prisma.employee.update({ where: { id: user.employeeId }, data: { title } });
|
|
}
|
|
n += 1;
|
|
}
|
|
|
|
const delQual = await prisma.qualification.deleteMany({ where: { code: 'QUAL_P6_OLD' } });
|
|
|
|
const cancelled = await prisma.approvalTask.updateMany({
|
|
where: { bizType: 'EXPENSE_APPROVAL', status: 'PENDING' },
|
|
data: { status: 'CANCELLED' },
|
|
});
|
|
|
|
console.log(
|
|
JSON.stringify({
|
|
reassignedUsers: n,
|
|
deletedTestQuals: delQual.count,
|
|
cancelledExpenseApprovals: cancelled.count,
|
|
}),
|
|
);
|
|
}
|
|
|
|
main()
|
|
.catch((e) => {
|
|
console.error(e);
|
|
process.exit(1);
|
|
})
|
|
.finally(() => prisma.$disconnect());
|