import { PrismaClient } from '@prisma/client'; import * as bcrypt from 'bcryptjs'; const prisma = new PrismaClient(); // 五项污染物默认散发参数生成器(占位值;真实数据由实验室检测导入) function ep(y0: number) { return { hcho: { y0, yp: y0 * 1.5, b: 0.01 }, tvoc: { y0: y0 * 0.6, yp: y0 * 0.9, b: 0.01 }, benzene: { y0: y0 * 0.05, yp: y0 * 0.08, b: 0.005 }, toluene: { y0: y0 * 0.1, yp: y0 * 0.15, b: 0.005 }, xylene: { y0: y0 * 0.08, yp: y0 * 0.12, b: 0.005 }, }; } // 取自原系统公共材料库前若干条(散发参数为占位) const MATERIALS = [ { id: 'PM13000003', name: '胶合板', category: '人造板/胶合板', brand: '东营正和', manufacturer: '东营正和', spec: '2.7SE', envGrade: 'E1', y0: 0.06 }, { id: 'PM13000004', name: '胶合板', category: '人造板/胶合板', brand: '东营正和', manufacturer: '东营正和', spec: '3N-3mm', envGrade: 'E0', y0: 0.03 }, { id: 'PM13000005', name: '胶合板', category: '人造板/胶合板', brand: '金秋', manufacturer: '河北金秋木业有限责任公司', spec: '8mm', envGrade: null, y0: 0.05 }, { id: 'PM13000006', name: '胶合板', category: '人造板/胶合板', brand: '金秋', manufacturer: '河北金秋木业有限责任公司', spec: '12mm', envGrade: null, y0: 0.05 }, { id: 'PM13000007', name: '胶合板', category: '人造板/胶合板', brand: '金秋', manufacturer: '河北金秋木业有限责任公司', spec: '15mm', envGrade: null, y0: 0.055 }, { id: 'PM13000008', name: '胶合板', category: '人造板/胶合板', brand: '金秋', manufacturer: '河北金秋木业有限责任公司', spec: '18mm', envGrade: null, y0: 0.06 }, { id: 'PM13000009', name: '阻燃胶合板', category: '人造板/阻燃胶合板', brand: '兔宝宝', manufacturer: '德华兔宝宝装饰新材股份有限公司', spec: null, envGrade: null, y0: 0.045 }, { id: 'PM13000010', name: '阻燃板', category: '人造板/胶合板', brand: '福益安', manufacturer: '北京江夏木业有限公司', spec: null, envGrade: 'E1', y0: 0.05 }, { id: 'PM13000011', name: '阻燃板', category: '人造板/阻燃胶合板', brand: '莫干山', manufacturer: '浙江升华云峰新材股份有限公司', spec: 'E1', envGrade: 'E1', y0: 0.05 }, { id: 'PM13000012', name: '非醛多层基材胶合板', category: '人造板/胶合板', brand: '升达', manufacturer: '四川升达林产业股份有限公司', spec: null, envGrade: null, y0: 0.02 }, ]; async function main() { const passwordHash = await bcrypt.hash('CBMA123456', 10); const org = await prisma.organization.upsert({ where: { username: 'YPJKKJ' }, update: {}, create: { username: 'YPJKKJ', name: '一品健康空间', passwordHash }, }); console.log('组织已就绪:', org.username, org.name); for (let i = 0; i < MATERIALS.length; i++) { const m = MATERIALS[i]; const healthGrade = ['A', 'B', 'C'][i % 3]; // 示例健康等级 const sortOrder = (i + 1) * 10; // 预留竞价排名(越小越靠前) await prisma.material.upsert({ where: { id: m.id }, update: { healthGrade, sortOrder }, // 回填已存在的材料 create: { id: m.id, name: m.name, category: m.category, brand: m.brand, manufacturer: m.manufacturer, spec: m.spec ?? undefined, envGrade: m.envGrade ?? undefined, healthGrade, sortOrder, usageUnit: 'm²', emissionParams: ep(m.y0), isPublic: true, }, }); } console.log(`已导入 ${MATERIALS.length} 条公共材料(散发参数为占位值,待替换真实检测数据)`); // 官方算例 6 种材料(真实 Y0/Yp/B,5 污染物),供 C 端样板间 + 复现算例 const ep5 = ( hcho: number[], tvoc: number[], benzene: number[], toluene: number[], xylene: number[], ) => ({ hcho: { y0: hcho[0], yp: hcho[1], b: hcho[2] }, tvoc: { y0: tvoc[0], yp: tvoc[1], b: tvoc[2] }, benzene: { y0: benzene[0], yp: benzene[1], b: benzene[2] }, toluene: { y0: toluene[0], yp: toluene[1], b: toluene[2] }, xylene: { y0: xylene[0], yp: xylene[1], b: xylene[2] }, }); const REAL_MATERIALS = [ { id: 'PM20000001', name: '多层实木复合地板', category: '木地板/实木地板', brand: '示例', healthGrade: 'B', ep: ep5([0.09, 0.4, 0.47], [0.074, 0.7, 0.205], [0.03, 0.186, 0.265], [0, 0, 0], [0, 0, 0]) }, { id: 'PM20000002', name: '踢脚线', category: '其他', brand: '示例', healthGrade: 'C', ep: ep5([0.38, 2.3, 0.2], [0.25, 1.69, 0.113], [0.053, 0.446, 0.09], [0.05, 0.229, 0.1], [0.009, 0.35, 0.085]) }, { id: 'PM20000003', name: '吸音板', category: '其他', brand: '示例', healthGrade: 'B', ep: ep5([0, 0, 0], [0.24, 1.71, 0.09], [0, 0, 0], [0, 0, 0], [0, 0, 0]) }, { id: 'PM20000004', name: '乳胶漆涂料', category: '涂料/墙面漆', brand: '示例', healthGrade: 'A', ep: ep5([0, 0, 0], [0.04, 0.337, 0.288], [0, 0, 0], [0, 0, 0], [0, 0, 0]) }, { id: 'PM20000005', name: '免漆木门', category: '其他', brand: '示例', healthGrade: 'C', ep: ep5([0, 0, 0], [0.46, 3.05, 0.132], [0.07, 0.53, 0.27], [0.05, 0.41, 0.29], [0.194, 1.24, 0.223]) }, { id: 'PM20000006', name: '人造板家具', category: '家具', brand: '示例', healthGrade: 'C', ep: ep5([0.45, 2.63, 0.446], [0.14, 0.88, 0.36], [0, 0, 0], [0.08, 0.5, 0.39], [0, 0, 0]) }, ]; for (let i = 0; i < REAL_MATERIALS.length; i++) { const m = REAL_MATERIALS[i]; await prisma.material.upsert({ where: { id: m.id }, update: { emissionParams: m.ep, healthGrade: m.healthGrade }, create: { id: m.id, name: m.name, category: m.category, brand: m.brand, healthGrade: m.healthGrade, sortOrder: 1000 + i, usageUnit: 'm²', emissionParams: m.ep, isPublic: true, }, }); } console.log(`已导入 ${REAL_MATERIALS.length} 条官方算例真实材料(PM2000000x)`); // 一条公共项目模板(含 1 个空间 + 2 种材料),供模板库展示 const tplId = 'T13000001'; await prisma.project.upsert({ where: { id: tplId }, update: {}, create: { id: tplId, name: '标准住宅卧室模板', type: '住宅', province: '北京市', city: '北京市', area: 90, isTemplate: true, isPublic: true, ownerOrgId: org.id, status: 'report_generated', rating: 'A', spaces: { create: [ { id: 'TS13000001', name: '主卧', type: '卧室', layout: 'uniform', height: 2.8, area: 15, volume: 42, temperature: 25, humidity: 50, ventilationRate: 0.5, standard: 'GB50325-2020', materials: { create: [ { materialId: 'PM13000004', usageUnit: 'm²', usageAmount: 30 }, { materialId: 'PM13000012', usageUnit: 'm²', usageAmount: 20 }, ], }, }, ], }, }, }); console.log('已导入 1 条公共项目模板'); } main() .catch((e) => { console.error(e); process.exit(1); }) .finally(() => prisma.$disconnect());