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,125 @@
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
import * as fs from 'fs';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
const DUMP = '/opt/import/prod/oa_clean.json';
|
||||
|
||||
type Row = Record<string, unknown>;
|
||||
|
||||
function str(v: unknown) {
|
||||
if (v == null) return '';
|
||||
return String(v).trim();
|
||||
}
|
||||
|
||||
function when(v: unknown) {
|
||||
const s = str(v);
|
||||
if (!s || s.startsWith('0000')) return null;
|
||||
const d = new Date(s.includes('T') ? s : s.replace(' ', 'T'));
|
||||
return Number.isNaN(d.getTime()) ? null : d;
|
||||
}
|
||||
|
||||
function entityKey(raw: unknown) {
|
||||
const s = str(raw);
|
||||
if (!s) return '';
|
||||
if (s.includes('鲁兵')) return '山东鲁兵';
|
||||
if (s.includes('隆创')) return '隆创';
|
||||
if (s.includes('风影')) return '江苏风影随行科技有限公司';
|
||||
return s;
|
||||
}
|
||||
|
||||
const ENTITIES: { key: string; name: string; shortName: string }[] = [
|
||||
{ key: '江苏风影随行科技有限公司', name: '江苏风影随行科技有限公司', shortName: '江苏风影' },
|
||||
{ key: '山东鲁兵', name: '山东鲁兵', shortName: '山东鲁兵' },
|
||||
{ key: '隆创', name: '隆创', shortName: '隆创' },
|
||||
];
|
||||
|
||||
async function main() {
|
||||
const raw = JSON.parse(fs.readFileSync(DUMP, 'utf8')) as Record<string, Row[]>;
|
||||
const tenders = raw.oa_tender || [];
|
||||
const entityIds = new Map<string, string>();
|
||||
for (const e of ENTITIES) {
|
||||
const existing = await prisma.legalEntity.findFirst({
|
||||
where: { tenantId: '1', OR: [{ name: e.name }, { shortName: e.shortName }] },
|
||||
});
|
||||
if (existing) {
|
||||
await prisma.legalEntity.update({ where: { id: existing.id }, data: { name: e.name, shortName: e.shortName } });
|
||||
entityIds.set(e.key, existing.id);
|
||||
} else {
|
||||
const created = await prisma.legalEntity.create({
|
||||
data: { name: e.name, shortName: e.shortName, isDefault: e.shortName === '江苏风影' },
|
||||
});
|
||||
entityIds.set(e.key, created.id);
|
||||
}
|
||||
}
|
||||
await prisma.legalEntity.updateMany({
|
||||
where: { name: { not: '江苏风影随行科技有限公司' } },
|
||||
data: { isDefault: false },
|
||||
});
|
||||
await prisma.legalEntity.updateMany({
|
||||
where: { name: '江苏风影随行科技有限公司' },
|
||||
data: { isDefault: true },
|
||||
});
|
||||
|
||||
const users = await prisma.user.findMany();
|
||||
const userByName = new Map(users.map((u) => [u.displayName, u]));
|
||||
const bids = await prisma.bidCase.findMany();
|
||||
const usedNos = new Set<string>();
|
||||
const matched: { rowId: string; t: Row }[] = [];
|
||||
for (const t of tenders) {
|
||||
const name = str(t.project_name);
|
||||
const sys = str(t.system_number);
|
||||
const official = str(t.project_number);
|
||||
const row = bids.find((b) => b.name === name) || bids.find((b) => b.bidNo === sys || b.externalNo === official);
|
||||
if (!row) continue;
|
||||
matched.push({ rowId: row.id, t });
|
||||
}
|
||||
for (const m of matched) {
|
||||
await prisma.bidCase.update({
|
||||
where: { id: m.rowId },
|
||||
data: { bidNo: `TMP-${m.rowId.replace(/-/g, '').slice(0, 20)}` },
|
||||
});
|
||||
}
|
||||
|
||||
for (const { rowId, t } of matched) {
|
||||
const row = bids.find((b) => b.id === rowId)!;
|
||||
const official = str(t.project_number);
|
||||
const key = entityKey(t.participating_unit);
|
||||
let bidNo = official || row.externalNo || row.bidNo;
|
||||
if (usedNos.has(bidNo)) bidNo = `${bidNo}-${row.id.slice(0, 4)}`;
|
||||
usedNos.add(bidNo);
|
||||
const preparer = str(t.bid_prepare_person);
|
||||
const creator = userByName.get(preparer === '张靖妍' ? '张婧妍' : preparer);
|
||||
await prisma.bidCase.update({
|
||||
where: { id: row.id },
|
||||
data: {
|
||||
bidNo,
|
||||
externalNo: official || row.externalNo,
|
||||
legalEntityId: key ? entityIds.get(key) || null : null,
|
||||
openAt: when(t.bid_open_date) || row.openAt,
|
||||
applyEndAt: when(t.file_apply_deadline) || row.applyEndAt,
|
||||
applyStartAt: when(t.create_time) || row.applyStartAt,
|
||||
createdById: creator?.id || row.createdById,
|
||||
createdAt: when(t.create_time) || row.createdAt,
|
||||
},
|
||||
});
|
||||
}
|
||||
const patched = matched.length;
|
||||
|
||||
const loan = await prisma.loanRecord.findFirst({ where: { purpose: { contains: '重庆投标' } } });
|
||||
const chongqing = await prisma.bidCase.findFirst({ where: { name: { contains: '门诊特病' } } });
|
||||
if (loan && chongqing) {
|
||||
await prisma.loanRecord.update({
|
||||
where: { id: loan.id },
|
||||
data: { bidCaseId: chongqing.id, costType: 'BID' },
|
||||
});
|
||||
}
|
||||
|
||||
console.log(JSON.stringify({ patchedBids: patched, entities: ENTITIES.map((e) => e.shortName), linkedChongqingLoan: Boolean(loan && chongqing) }));
|
||||
}
|
||||
|
||||
main()
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
})
|
||||
.finally(() => prisma.$disconnect());
|
||||
Reference in New Issue
Block a user