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,131 @@
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
import * as fs from 'fs';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
const DUMP = '/opt/import/prod/oa_core.json';
|
||||
|
||||
type Row = Record<string, unknown>;
|
||||
|
||||
function str(v: unknown) {
|
||||
if (v == null) return '';
|
||||
return String(v).trim();
|
||||
}
|
||||
|
||||
function officialNo(raw: unknown) {
|
||||
const n = str(raw).replace(/[))]+$/, '').trim();
|
||||
if (!n || n === '无' || n === '-' || n === '—') return '';
|
||||
return n;
|
||||
}
|
||||
|
||||
function mapQual(raw: unknown) {
|
||||
const s = str(raw);
|
||||
if (!s) return '';
|
||||
try {
|
||||
const arr = JSON.parse(s) as { item?: string }[];
|
||||
const item = str(arr?.[0]?.item);
|
||||
if (!item || item === '无') return '无需资质';
|
||||
if (item.includes('军')) return '军二';
|
||||
if (item.includes('涉')) return '涉乙';
|
||||
return item.slice(0, 20);
|
||||
} catch {
|
||||
if (s.includes('军')) return '军二';
|
||||
if (s.includes('涉')) return '涉乙';
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
function mapStatus(row: Row) {
|
||||
const st = str(row.project_status);
|
||||
const win = str(row.winning_status);
|
||||
if (st === '中标' || (st === '' && win.includes('中标'))) return 'WON';
|
||||
if (st === '未中' || (st === '' && win.includes('未中'))) return 'LOST';
|
||||
if (st === '流标') return 'FAILED';
|
||||
if (st === '弃标' || win.includes('弃标')) return 'TERMINATED';
|
||||
return '';
|
||||
}
|
||||
|
||||
function isRealTender(row: Row) {
|
||||
return /^TB-\d/.test(str(row.system_number)) && Boolean(str(row.project_name));
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const raw = JSON.parse(fs.readFileSync(DUMP, 'utf8')) as Record<string, Row[]>;
|
||||
const tenders = (raw.oa_tender || []).filter(isRealTender);
|
||||
const bids = await prisma.bidCase.findMany();
|
||||
const users = await prisma.user.findMany({ select: { id: true, displayName: true } });
|
||||
const userByName = new Map(users.map((u) => [u.displayName, u.id]));
|
||||
userByName.set('张靖妍', userByName.get('张婧妍') || '');
|
||||
|
||||
const testNos = ['SP-TEST-1788068192', 'SP-FIX-1788068273'];
|
||||
const tests = bids.filter((b) => testNos.includes(b.bidNo) || testNos.includes(b.externalNo || ''));
|
||||
const testIds = tests.map((b) => b.id);
|
||||
if (testIds.length) {
|
||||
await prisma.todoTask.deleteMany({ where: { bizId: { in: testIds } } });
|
||||
await prisma.approvalTask.deleteMany({ where: { bizId: { in: testIds } } });
|
||||
await prisma.bidCase.deleteMany({ where: { id: { in: testIds } } });
|
||||
}
|
||||
|
||||
const used = new Set<string>();
|
||||
const remaining = await prisma.bidCase.findMany();
|
||||
let patched = 0;
|
||||
const moves: { name: string; from: string; to: string; no: string }[] = [];
|
||||
|
||||
for (const t of tenders) {
|
||||
const name = str(t.project_name);
|
||||
const sys = str(t.system_number);
|
||||
const official = officialNo(t.project_number);
|
||||
const row =
|
||||
remaining.find((b) => b.name === name) ||
|
||||
remaining.find((b) => b.bidNo === sys || b.externalNo === official || b.externalNo === str(t.project_number));
|
||||
if (!row) continue;
|
||||
|
||||
const status = mapStatus(t) || row.status;
|
||||
const creatorName = str(t.bid_prepare_person) === '张靖妍' ? '张婧妍' : str(t.bid_prepare_person);
|
||||
let bidNo = official || sys;
|
||||
if (used.has(bidNo)) bidNo = `${official || sys}-${sys.slice(-3)}`;
|
||||
used.add(bidNo);
|
||||
|
||||
if (row.status !== status) {
|
||||
moves.push({ name: name.slice(0, 24), from: row.status, to: status, no: official || sys });
|
||||
}
|
||||
|
||||
const qual = mapQual(t.bid_doc_requirement);
|
||||
await prisma.bidCase.update({
|
||||
where: { id: row.id },
|
||||
data: {
|
||||
bidNo: `TMP-${row.id.replace(/-/g, '').slice(0, 18)}`,
|
||||
},
|
||||
});
|
||||
await prisma.bidCase.update({
|
||||
where: { id: row.id },
|
||||
data: {
|
||||
bidNo,
|
||||
externalNo: official || null,
|
||||
status,
|
||||
sourceType: 'FLOW',
|
||||
qualificationNeed: qual || row.qualificationNeed,
|
||||
tenderMethod: str(t.tender_method) || row.tenderMethod,
|
||||
applyMethod: row.applyMethod || (str(t.announcement_file) ? '网上申领' : row.applyMethod),
|
||||
delivererName: str(t.bid_delivery_person) || row.delivererName,
|
||||
createdById: userByName.get(creatorName) || row.createdById,
|
||||
},
|
||||
});
|
||||
patched += 1;
|
||||
}
|
||||
|
||||
const after = await prisma.bidCase.groupBy({ by: ['status'], _count: true });
|
||||
console.log(
|
||||
JSON.stringify(
|
||||
{ deletedTests: testIds.length, patched, moves, counts: after },
|
||||
null,
|
||||
2,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
main()
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
})
|
||||
.finally(() => prisma.$disconnect());
|
||||
Reference in New Issue
Block a user