Initial commit: 风影 OA 全栈源码(API/Web/Flutter/IM)
含 Phase 1.1 IM seq 排序、断线重连、多端已读同步与微信式语音转文字 UI。 排除 node_modules、构建产物、安装包与 .env 密钥。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,587 @@
|
||||
// @ts-nocheck
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
import * as argon2 from 'argon2';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
const DUMP = path.resolve('/opt/import/prod/oa_hr.json');
|
||||
const DEFAULT_PASSWORD = '123456';
|
||||
|
||||
const DEMO_USERS = [
|
||||
'owner',
|
||||
'bizdir',
|
||||
'bizstaff',
|
||||
'dirsoft',
|
||||
'dir3d',
|
||||
'dirfilm',
|
||||
'dirmaterial',
|
||||
'finance',
|
||||
'hr',
|
||||
'employee',
|
||||
'softpm',
|
||||
'batchdemo1',
|
||||
];
|
||||
|
||||
const DEPT_META: Record<number, { deptType: string; categoryCode?: string }> = {
|
||||
1: { deptType: 'ADMIN' },
|
||||
2: { deptType: 'ADMIN' },
|
||||
4: { deptType: 'BUSINESS' },
|
||||
7: { deptType: 'ADMIN' },
|
||||
8: { deptType: 'ADMIN' },
|
||||
9: { deptType: 'TECH', categoryCode: 'CAT_SOFTWARE' },
|
||||
10: { deptType: 'TECH', categoryCode: 'CAT_SOFTWARE' },
|
||||
19: { deptType: 'TECH', categoryCode: 'CAT_FILM' },
|
||||
23: { deptType: 'TECH', categoryCode: 'CAT_3D' },
|
||||
210: { deptType: 'TECH', categoryCode: 'CAT_SOFTWARE' },
|
||||
211: { deptType: 'TECH', categoryCode: 'CAT_3D' },
|
||||
212: { deptType: 'TECH', categoryCode: 'CAT_FILM' },
|
||||
213: { deptType: 'TECH', categoryCode: 'CAT_MATERIAL' },
|
||||
214: { deptType: 'TECH', categoryCode: 'CAT_SOFTWARE' },
|
||||
};
|
||||
|
||||
const OLD_DEPT_TO_OA: Record<string, string> = {
|
||||
ROOT: 'OA_1',
|
||||
BIZ: 'OA_4',
|
||||
TECH_SOFTWARE: 'OA_9',
|
||||
TECH_3D: 'OA_211',
|
||||
TECH_FILM: 'OA_212',
|
||||
TECH_MATERIAL: 'OA_213',
|
||||
FIN: 'OA_2',
|
||||
HR: 'OA_2',
|
||||
};
|
||||
|
||||
const DEPT_MANAGER_OA: Record<number, number> = {
|
||||
1: 101,
|
||||
2: 101,
|
||||
4: 107,
|
||||
7: 101,
|
||||
8: 101,
|
||||
9: 131,
|
||||
10: 131,
|
||||
19: 102,
|
||||
23: 105,
|
||||
210: 131,
|
||||
211: 105,
|
||||
212: 102,
|
||||
213: 104,
|
||||
214: 131,
|
||||
};
|
||||
|
||||
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',
|
||||
};
|
||||
|
||||
const ROLE_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,
|
||||
tech_director: 4,
|
||||
rd_director: 4,
|
||||
'3d_director': 4,
|
||||
video_director: 4,
|
||||
material_director: 4,
|
||||
biz_director: 5,
|
||||
owner: 6,
|
||||
admin: 7,
|
||||
};
|
||||
|
||||
type Dump = {
|
||||
depts: { id: number; name: string; parentId: number; orderNum: number; delFlag: string }[];
|
||||
posts: { id: number; code: string; name: string }[];
|
||||
users: {
|
||||
id: number;
|
||||
sex: string;
|
||||
email: string;
|
||||
phone: string;
|
||||
deptId: number;
|
||||
remark: string | null;
|
||||
status: string;
|
||||
nickName: string;
|
||||
userName: string;
|
||||
entryDate: string | null;
|
||||
leaveDate: string | null;
|
||||
employmentStatus: string;
|
||||
}[];
|
||||
userPosts: { postId: number; userId: number }[];
|
||||
};
|
||||
|
||||
function empNo(oaId: number) {
|
||||
return `E${String(oaId).padStart(4, '0')}`;
|
||||
}
|
||||
|
||||
function gender(sex: string) {
|
||||
if (sex === '0') return 'MALE';
|
||||
if (sex === '1') return 'FEMALE';
|
||||
return null;
|
||||
}
|
||||
|
||||
function empStatus(code: string) {
|
||||
if (code === '1') return 'INTERN';
|
||||
if (code === '2') return 'PROBATION';
|
||||
if (code === '4') return 'LEFT';
|
||||
return 'REGULAR';
|
||||
}
|
||||
|
||||
function when(v: string | null) {
|
||||
if (!v || v.startsWith('0000')) return null;
|
||||
const d = new Date(v.includes('T') ? v : `${v}T00:00:00`);
|
||||
return Number.isNaN(d.getTime()) ? null : d;
|
||||
}
|
||||
|
||||
function addMonths(d: Date, n: number) {
|
||||
const x = new Date(d);
|
||||
x.setMonth(x.getMonth() + n);
|
||||
return x;
|
||||
}
|
||||
|
||||
function pickRole(userName: string, postCodes: string[]) {
|
||||
if (userName === 'xibei') return 'employee';
|
||||
let best: string | null = null;
|
||||
let bestRank = -1;
|
||||
for (const c of postCodes) {
|
||||
const role = POST_ROLE[c];
|
||||
if (!role) continue;
|
||||
const r = ROLE_RANK[role] ?? 1;
|
||||
if (r > bestRank) {
|
||||
best = role;
|
||||
bestRank = r;
|
||||
}
|
||||
}
|
||||
return best || 'employee';
|
||||
}
|
||||
|
||||
async function remumber<T extends { id: string; createdAt: Date }>(
|
||||
rows: T[],
|
||||
prefix: string,
|
||||
update: (id: string, no: string) => Promise<unknown>,
|
||||
) {
|
||||
for (const r of rows) await update(r.id, `TMP-${r.id.replace(/-/g, '').slice(0, 20)}`);
|
||||
const groups = new Map<number, T[]>();
|
||||
const sorted = [...rows].sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime() || a.id.localeCompare(b.id));
|
||||
for (const r of sorted) {
|
||||
const y = r.createdAt.getFullYear();
|
||||
const list = groups.get(y) || [];
|
||||
list.push(r);
|
||||
groups.set(y, list);
|
||||
}
|
||||
for (const [year, list] of [...groups.entries()].sort((a, b) => a[0] - b[0])) {
|
||||
let i = 1;
|
||||
for (const r of list) {
|
||||
await update(r.id, `${prefix}-${year}-${String(i).padStart(5, '0')}`);
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function remapDeptFks(codeToId: Map<string, string>) {
|
||||
const old = await prisma.department.findMany({ where: { tenantId: '1' } });
|
||||
const oldByCode = new Map(old.map((d) => [d.code, d.id]));
|
||||
const mapping = new Map<string, string>();
|
||||
for (const d of old) {
|
||||
const targetCode = OLD_DEPT_TO_OA[d.code] || (d.code.startsWith('OA_') ? d.code : 'OA_2');
|
||||
const nid = codeToId.get(targetCode);
|
||||
if (nid && nid !== d.id) mapping.set(d.id, nid);
|
||||
}
|
||||
for (const [from, to] of mapping) {
|
||||
await prisma.projectTask.updateMany({ where: { departmentId: from }, data: { departmentId: to } });
|
||||
await prisma.employmentEvent.updateMany({ where: { fromDeptId: from }, data: { fromDeptId: to } });
|
||||
await prisma.employmentEvent.updateMany({ where: { toDeptId: from }, data: { toDeptId: to } });
|
||||
}
|
||||
return { oldByCode, mapping };
|
||||
}
|
||||
|
||||
async function reassignDemoUsers(demoIds: string[], adminId: string) {
|
||||
if (!demoIds.length) return;
|
||||
await prisma.bidReviewer.deleteMany({ where: { userId: { in: demoIds } } });
|
||||
await prisma.bidAssignee.deleteMany({ where: { userId: { in: demoIds } } });
|
||||
await prisma.contractReviewer.deleteMany({ where: { userId: { in: demoIds } } });
|
||||
await prisma.todoTask.deleteMany({ where: { assigneeId: { in: demoIds } } });
|
||||
await prisma.approvalTask.deleteMany({ where: { assigneeId: { in: demoIds } } });
|
||||
await prisma.workReport.deleteMany({ where: { OR: [{ authorId: { in: demoIds } }, { toUserId: { in: demoIds } }, { ccUserId: { in: demoIds } }] } });
|
||||
await prisma.refreshToken.deleteMany({ where: { userId: { in: demoIds } } });
|
||||
await prisma.userRole.deleteMany({ where: { userId: { in: demoIds } } });
|
||||
|
||||
const patch = async (model: string, field: string) => {
|
||||
const delegate = (prisma as unknown as Record<string, { updateMany: (a: unknown) => Promise<unknown> }>)[model];
|
||||
if (!delegate?.updateMany) return;
|
||||
try {
|
||||
await delegate.updateMany({
|
||||
where: { [field]: { in: demoIds } },
|
||||
data: { [field]: adminId },
|
||||
});
|
||||
} catch (e) {
|
||||
console.warn(`skip ${model}.${field}`, (e as Error).message);
|
||||
}
|
||||
};
|
||||
|
||||
await patch('bidCase', 'createdById');
|
||||
await patch('bidActionLog', 'actorId');
|
||||
await patch('bidDocVersion', 'submittedById');
|
||||
await patch('contract', 'createdById');
|
||||
await patch('contractActionLog', 'actorId');
|
||||
await patch('expenseClaim', 'applicantId');
|
||||
await patch('expenseClaim', 'decidedById');
|
||||
await patch('loanRecord', 'applicantId');
|
||||
await patch('loanRecord', 'decidedById');
|
||||
await patch('sealRequest', 'applicantId');
|
||||
await patch('sealRequest', 'decidedById');
|
||||
await patch('timesheet', 'userId');
|
||||
await patch('projectTask', 'assigneeId');
|
||||
await patch('projectAcceptance', 'actorId');
|
||||
await patch('employmentEvent', 'actorId');
|
||||
await patch('attendanceMonth', 'importedById');
|
||||
await patch('payrollRun', 'createdById');
|
||||
await patch('purchaseRequest', 'applicantId');
|
||||
await patch('purchaseRequest', 'decidedById');
|
||||
await patch('paymentRecord', 'createdById');
|
||||
await patch('projectChange', 'actorId');
|
||||
await patch('assetOccupancy', 'holderId');
|
||||
await patch('invoiceRecord', 'createdById');
|
||||
await patch('operationLog', 'userId');
|
||||
await patch('credentialBorrow', 'borrowerId');
|
||||
|
||||
await prisma.user.deleteMany({ where: { id: { in: demoIds } } });
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const dump = JSON.parse(fs.readFileSync(DUMP, 'utf8')) as Dump;
|
||||
const hash = await argon2.hash(DEFAULT_PASSWORD);
|
||||
const posts = new Map(dump.posts.map((p) => [p.id, p]));
|
||||
const postsByUser = new Map<number, string[]>();
|
||||
const postNamesByUser = new Map<number, string[]>();
|
||||
for (const up of dump.userPosts) {
|
||||
const p = posts.get(up.postId);
|
||||
if (!p) continue;
|
||||
postsByUser.set(up.userId, [...(postsByUser.get(up.userId) || []), p.code]);
|
||||
postNamesByUser.set(up.userId, [...(postNamesByUser.get(up.userId) || []), p.name]);
|
||||
}
|
||||
|
||||
await prisma.role.updateMany({ where: { code: { in: ['admin', 'owner', 'finance', 'hr'] } }, data: { dataScope: 'ALL' } });
|
||||
await prisma.role.updateMany({ where: { code: { in: ['biz_director', 'tech_director'] } }, data: { dataScope: 'DEPT' } });
|
||||
await prisma.role.updateMany({ where: { code: { in: ['biz_staff', 'employee'] } }, data: { dataScope: 'SELF' } });
|
||||
|
||||
const numberRules = [
|
||||
{ code: 'BID', name: '投标编号', prefix: 'BID', padLength: 5 },
|
||||
{ code: 'HT', name: '合同编号', prefix: 'HT', padLength: 5 },
|
||||
{ code: 'PRJ', name: '项目编号', prefix: 'PRJ', padLength: 5 },
|
||||
{ code: 'BX', name: '报销编号', prefix: 'BX', padLength: 5 },
|
||||
{ code: 'JK', name: '借款编号', prefix: 'JK', padLength: 5 },
|
||||
{ code: 'BZ', name: '保证金编号', prefix: 'BZ', padLength: 5 },
|
||||
];
|
||||
for (const r of numberRules) {
|
||||
await prisma.numberRule.upsert({
|
||||
where: { tenantId_code: { tenantId: '1', code: r.code } },
|
||||
update: { prefix: r.prefix, padLength: r.padLength, name: r.name },
|
||||
create: { ...r, tenantId: '1' },
|
||||
});
|
||||
}
|
||||
|
||||
const roles = await prisma.role.findMany();
|
||||
const roleByCode = new Map(roles.map((r) => [r.code, r.id]));
|
||||
|
||||
const codeToId = new Map<string, string>();
|
||||
const sortedDepts = [...dump.depts].sort((a, b) => a.parentId - b.parentId || a.orderNum - b.orderNum);
|
||||
for (const d of sortedDepts) {
|
||||
const code = `OA_${d.id}`;
|
||||
const meta = DEPT_META[d.id] || { deptType: 'ADMIN' };
|
||||
const parentCode = d.parentId ? `OA_${d.parentId}` : null;
|
||||
const parentId = parentCode ? codeToId.get(parentCode) || null : null;
|
||||
const existing = await prisma.department.findFirst({ where: { tenantId: '1', code } });
|
||||
const row = existing
|
||||
? await prisma.department.update({
|
||||
where: { id: existing.id },
|
||||
data: {
|
||||
name: d.name,
|
||||
deptType: meta.deptType,
|
||||
categoryCode: meta.categoryCode || null,
|
||||
sortNo: d.orderNum,
|
||||
parentId,
|
||||
},
|
||||
})
|
||||
: await prisma.department.create({
|
||||
data: {
|
||||
name: d.name,
|
||||
code,
|
||||
deptType: meta.deptType,
|
||||
categoryCode: meta.categoryCode || null,
|
||||
sortNo: d.orderNum,
|
||||
parentId,
|
||||
},
|
||||
});
|
||||
codeToId.set(code, row.id);
|
||||
}
|
||||
|
||||
await remapDeptFks(codeToId);
|
||||
|
||||
const officeId = codeToId.get('OA_2')!;
|
||||
const empByOa = new Map<number, string>();
|
||||
const empByName = new Map<string, string>();
|
||||
|
||||
const adminUser = await prisma.user.findFirst({ where: { username: 'admin' } });
|
||||
if (!adminUser) throw new Error('本地必须先有 admin 账号');
|
||||
|
||||
const adminEmpId =
|
||||
adminUser.employeeId ||
|
||||
(
|
||||
await prisma.employee.create({
|
||||
data: {
|
||||
name: '系统管理员',
|
||||
employeeNo: 'E0000',
|
||||
departmentId: officeId,
|
||||
title: '系统管理员',
|
||||
employmentStatus: 'REGULAR',
|
||||
},
|
||||
})
|
||||
).id;
|
||||
|
||||
const adminOa = dump.users.find((u) => u.userName === 'administrator');
|
||||
await prisma.employee.update({
|
||||
where: { id: adminEmpId },
|
||||
data: {
|
||||
name: adminOa?.nickName || '系统管理员',
|
||||
employeeNo: 'E0000',
|
||||
departmentId: officeId,
|
||||
title: '系统管理员',
|
||||
employmentStatus: 'REGULAR',
|
||||
hiredAt: when(adminOa?.entryDate || '2026-06-04'),
|
||||
gender: gender(adminOa?.sex || '2'),
|
||||
email: adminOa?.email || null,
|
||||
mobile: adminOa?.phone || null,
|
||||
remark: adminOa?.remark || '超级管理员',
|
||||
managerId: null,
|
||||
},
|
||||
});
|
||||
empByOa.set(1, adminEmpId);
|
||||
empByName.set('系统管理员', adminEmpId);
|
||||
|
||||
for (const u of dump.users) {
|
||||
if (u.userName === 'administrator') continue;
|
||||
const deptId = codeToId.get(`OA_${u.deptId}`) || officeId;
|
||||
const status = empStatus(u.employmentStatus);
|
||||
const hiredAt = when(u.entryDate);
|
||||
const titles = postNamesByUser.get(u.id) || [];
|
||||
const title = titles[0] || u.remark || '员工';
|
||||
const no = empNo(u.id);
|
||||
const data = {
|
||||
name: u.nickName,
|
||||
departmentId: deptId,
|
||||
title,
|
||||
restSchedule: DEPT_META[u.deptId]?.categoryCode === 'CAT_SOFTWARE' ? 'DOUBLE' : 'SINGLE',
|
||||
employmentStatus: status,
|
||||
hiredAt,
|
||||
internStartAt: status === 'INTERN' ? hiredAt : null,
|
||||
probationEndAt: status === 'PROBATION' && hiredAt ? addMonths(hiredAt, 3) : null,
|
||||
leftAt: when(u.leaveDate),
|
||||
gender: gender(u.sex),
|
||||
email: u.email || null,
|
||||
mobile: u.phone || null,
|
||||
remark: u.remark,
|
||||
};
|
||||
const existing = await prisma.employee.findFirst({ where: { tenantId: '1', employeeNo: no } });
|
||||
const row = existing
|
||||
? await prisma.employee.update({ where: { id: existing.id }, data })
|
||||
: await prisma.employee.create({ data: { ...data, employeeNo: no } });
|
||||
empByOa.set(u.id, row.id);
|
||||
empByName.set(u.nickName, row.id);
|
||||
}
|
||||
|
||||
for (const u of dump.users) {
|
||||
if (u.userName === 'administrator') continue;
|
||||
const mgrOa = DEPT_MANAGER_OA[u.deptId];
|
||||
if (!mgrOa || mgrOa === u.id) continue;
|
||||
const managerId = empByOa.get(mgrOa);
|
||||
const id = empByOa.get(u.id);
|
||||
if (managerId && id) await prisma.employee.update({ where: { id }, data: { managerId } });
|
||||
}
|
||||
|
||||
await prisma.user.update({
|
||||
where: { id: adminUser.id },
|
||||
data: {
|
||||
passwordHash: hash,
|
||||
displayName: '系统管理员',
|
||||
employeeId: adminEmpId,
|
||||
status: 'ACTIVE',
|
||||
},
|
||||
});
|
||||
|
||||
for (const u of dump.users) {
|
||||
if (u.userName === 'administrator') continue;
|
||||
const employeeId = empByOa.get(u.id)!;
|
||||
const roleCode = pickRole(u.userName, postsByUser.get(u.id) || []);
|
||||
const roleId = roleByCode.get(roleCode);
|
||||
if (!roleId) throw new Error(`缺少角色 ${roleCode}`);
|
||||
const disabled = u.status === '1' || u.employmentStatus === '4';
|
||||
const existing = await prisma.user.findFirst({ where: { tenantId: '1', username: u.userName } });
|
||||
const row = existing
|
||||
? await prisma.user.update({
|
||||
where: { id: existing.id },
|
||||
data: {
|
||||
passwordHash: hash,
|
||||
displayName: u.nickName,
|
||||
employeeId,
|
||||
status: disabled ? 'DISABLED' : 'ACTIVE',
|
||||
},
|
||||
})
|
||||
: await prisma.user.create({
|
||||
data: {
|
||||
username: u.userName,
|
||||
passwordHash: hash,
|
||||
displayName: u.nickName,
|
||||
employeeId,
|
||||
status: disabled ? 'DISABLED' : 'ACTIVE',
|
||||
},
|
||||
});
|
||||
await prisma.userRole.deleteMany({ where: { userId: row.id } });
|
||||
await prisma.userRole.create({ data: { userId: row.id, roleId } });
|
||||
}
|
||||
|
||||
const users = await prisma.user.findMany({ include: { employee: true } });
|
||||
const userByName = new Map(users.map((u) => [u.displayName, u.id]));
|
||||
userByName.set('系统管理员', adminUser.id);
|
||||
|
||||
const rematchByText = async (
|
||||
model: 'expenseClaim' | 'loanRecord' | 'sealRequest',
|
||||
field: 'remark' | 'reason',
|
||||
) => {
|
||||
const rows = await prisma[model].findMany({ select: { id: true, [field]: true } as never });
|
||||
let n = 0;
|
||||
for (const r of rows as { id: string; remark?: string; reason?: string }[]) {
|
||||
const name = ((r.remark || r.reason || '') as string).split(' / ')[0]?.trim();
|
||||
if (!name) continue;
|
||||
const uid = userByName.get(name);
|
||||
if (!uid) continue;
|
||||
await prisma[model].update({ where: { id: r.id }, data: { applicantId: uid } });
|
||||
n += 1;
|
||||
}
|
||||
console.log(`matched ${model}`, n);
|
||||
};
|
||||
await rematchByText('expenseClaim', 'remark');
|
||||
await rematchByText('loanRecord', 'remark');
|
||||
await rematchByText('sealRequest', 'reason');
|
||||
|
||||
const keepUsernames = new Set(['admin', ...dump.users.filter((u) => u.userName !== 'administrator').map((u) => u.userName)]);
|
||||
const demo = await prisma.user.findMany({
|
||||
where: { OR: [{ username: { in: DEMO_USERS } }, { username: { notIn: [...keepUsernames] } }] },
|
||||
});
|
||||
const demoIds = demo.filter((u) => u.username !== 'admin').map((u) => u.id);
|
||||
console.log(
|
||||
'delete demo users',
|
||||
demo.filter((u) => u.username !== 'admin').map((u) => u.username),
|
||||
);
|
||||
await reassignDemoUsers(demoIds, adminUser.id);
|
||||
|
||||
const keepEmp = new Set([adminEmpId, ...empByOa.values()]);
|
||||
const leftoverEmp = await prisma.employee.findMany({ where: { id: { notIn: [...keepEmp] } } });
|
||||
const leftoverIds = leftoverEmp.map((e) => e.id);
|
||||
if (leftoverIds.length) {
|
||||
await prisma.payrollItem.deleteMany({ where: { employeeId: { in: leftoverIds } } });
|
||||
await prisma.attendanceMonth.deleteMany({ where: { employeeId: { in: leftoverIds } } });
|
||||
await prisma.employmentEvent.deleteMany({ where: { employeeId: { in: leftoverIds } } });
|
||||
await prisma.user.updateMany({ where: { employeeId: { in: leftoverIds } }, data: { employeeId: null } });
|
||||
await prisma.employee.updateMany({ where: { managerId: { in: leftoverIds } }, data: { managerId: null } });
|
||||
await prisma.employee.deleteMany({ where: { id: { in: leftoverIds } } });
|
||||
}
|
||||
console.log(
|
||||
'deleted demo employees',
|
||||
leftoverEmp.map((e) => e.name),
|
||||
);
|
||||
|
||||
const keepDept = new Set(codeToId.values());
|
||||
const leftoverDept = await prisma.department.findMany({ where: { id: { notIn: [...keepDept] } } });
|
||||
if (leftoverDept.length) {
|
||||
const leftoverDeptIds = leftoverDept.map((d) => d.id);
|
||||
await prisma.employee.updateMany({
|
||||
where: { departmentId: { in: leftoverDeptIds } },
|
||||
data: { departmentId: officeId },
|
||||
});
|
||||
await prisma.projectTask.updateMany({
|
||||
where: { departmentId: { in: leftoverDeptIds } },
|
||||
data: { departmentId: officeId },
|
||||
});
|
||||
await prisma.department.updateMany({ where: { id: { in: leftoverDeptIds } }, data: { parentId: null } });
|
||||
await prisma.department.deleteMany({ where: { id: { in: leftoverDeptIds } } });
|
||||
}
|
||||
console.log(
|
||||
'deleted demo depts',
|
||||
leftoverDept.map((d) => `${d.code}:${d.name}`),
|
||||
);
|
||||
|
||||
const demoBid = await prisma.bidCase.findMany({ where: { name: '某市展厅数字化升级' } });
|
||||
for (const b of demoBid) {
|
||||
const used =
|
||||
(await prisma.expenseClaim.count({ where: { bidCaseId: b.id } })) +
|
||||
(await prisma.contract.count({ where: { bidCaseId: b.id } }));
|
||||
if (used) continue;
|
||||
await prisma.bidReviewer.deleteMany({ where: { bidCaseId: b.id } });
|
||||
await prisma.bidAssignee.deleteMany({ where: { bidCaseId: b.id } });
|
||||
await prisma.bidActionLog.deleteMany({ where: { bidCaseId: b.id } });
|
||||
await prisma.bidDocVersion.deleteMany({ where: { bidCaseId: b.id } });
|
||||
await prisma.bondRecord.deleteMany({ where: { bidCaseId: b.id } });
|
||||
await prisma.sealRequest.deleteMany({ where: { bidCaseId: b.id } });
|
||||
await prisma.bidCase.delete({ where: { id: b.id } });
|
||||
console.log('deleted demo bid', b.bidNo);
|
||||
}
|
||||
|
||||
await remumber(
|
||||
await prisma.bidCase.findMany({ select: { id: true, createdAt: true }, orderBy: { createdAt: 'asc' } }),
|
||||
'BID',
|
||||
(id, bidNo) => prisma.bidCase.update({ where: { id }, data: { bidNo } }),
|
||||
);
|
||||
await remumber(
|
||||
await prisma.contract.findMany({ select: { id: true, createdAt: true }, orderBy: { createdAt: 'asc' } }),
|
||||
'HT',
|
||||
(id, contractNo) => prisma.contract.update({ where: { id }, data: { contractNo } }),
|
||||
);
|
||||
await remumber(
|
||||
await prisma.project.findMany({ select: { id: true, createdAt: true }, orderBy: { createdAt: 'asc' } }),
|
||||
'PRJ',
|
||||
(id, projectNo) => prisma.project.update({ where: { id }, data: { projectNo } }),
|
||||
);
|
||||
await remumber(
|
||||
await prisma.expenseClaim.findMany({ select: { id: true, createdAt: true }, orderBy: { createdAt: 'asc' } }),
|
||||
'BX',
|
||||
(id, claimNo) => prisma.expenseClaim.update({ where: { id }, data: { claimNo } }),
|
||||
);
|
||||
await remumber(
|
||||
await prisma.loanRecord.findMany({ select: { id: true, createdAt: true }, orderBy: { createdAt: 'asc' } }),
|
||||
'JK',
|
||||
(id, loanNo) => prisma.loanRecord.update({ where: { id }, data: { loanNo } }),
|
||||
);
|
||||
await remumber(
|
||||
await prisma.bondRecord.findMany({ select: { id: true, createdAt: true }, orderBy: { createdAt: 'asc' } }),
|
||||
'BZ',
|
||||
(id, bondNo) => prisma.bondRecord.update({ where: { id }, data: { bondNo } }),
|
||||
);
|
||||
|
||||
const empCount = await prisma.employee.count();
|
||||
const userCount = await prisma.user.count();
|
||||
const deptCount = await prisma.department.count();
|
||||
const sample = await prisma.expenseClaim.findMany({ take: 3, include: { applicant: true }, orderBy: { createdAt: 'desc' } });
|
||||
console.log({ empCount, userCount, deptCount, sampleNos: sample.map((s) => `${s.claimNo}:${s.applicant.displayName}`) });
|
||||
}
|
||||
|
||||
main()
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
})
|
||||
.finally(() => prisma.$disconnect());
|
||||
Reference in New Issue
Block a user