// 种子数据脚本 — 将 Mock 数据写入 Parse Server import Parse from 'parse/node'; Parse.initialize('prd-test'); Parse.serverURL = 'http://localhost:3000/parse'; Parse.masterKey = 'prd-test-master-key-2026'; const sleep = (ms: number) => new Promise(r => setTimeout(r, ms)); async function seed() { console.log('=== 开始种入数据 ===\n'); // ===== 1. 用户 ===== const users = [ { id: 'u001', name: '张明华', role: 'sales', department: '销售一部', phone: '138-0000-1234', email: 'zhang@furnishing.com', password: '1234' }, { id: 'u002', name: '李晓燕', role: 'sales', department: '销售一部', phone: '139-0001-2345', email: 'li@furnishing.com', password: '2345' }, { id: 'u003', name: '王建国', role: 'reviewer', department: '审单部', phone: '136-0002-3456', email: 'wang@furnishing.com', password: '3456' }, { id: 'u004', name: '陈美丽', role: 'finance', department: '财务部', phone: '135-0003-4567', email: 'chen@furnishing.com', password: '4567' }, { id: 'u005', name: '刘强', role: 'manager', department: '管理层', phone: '137-0004-5678', email: 'liu@furnishing.com', password: '5678' }, { id: 'u006', name: '赵芳', role: 'sales', department: '销售二部', phone: '132-0005-6789', email: 'zhao@furnishing.com', password: '6789' }, { id: 'u007', name: '系统管理员', role: 'admin', department: '系统管理', phone: '138-0000-0000', email: 'admin@furnishing.com', password: 'admin123' }, ]; const userIdMap: Record = {}; for (const u of users) { try { const user = new Parse.User(); user.set('username', u.id); user.set('password', u.password); user.set('name', u.name); user.set('role', u.role); user.set('department', u.department); user.set('phone', u.phone); user.set('email', u.email); const saved = await user.signUp(null); userIdMap[u.id] = saved.id; console.log(` User: ${u.name} (${u.id})`); } catch (e: any) { if (e.message?.includes('already')) { console.log(` User skip: ${u.name} (already exists)`); } else { console.log(` User FAIL: ${u.name} — ${e.message}`); } } await sleep(200); } // ===== 2. 门店 ===== const stores = [ '真北北馆一队:ZB1', '真北北馆二队:ZB2', '真北南馆一队:ZN1', '真北南馆二队:ZN2', '浦东一队:PD1', '浦东二队:PD2', '徐汇一队:XH1', '徐汇二队:XH2', '闵行一队:MH1', '闵行二队:MH2', '杨浦一队:YP1', '杨浦二队:YP2', '长宁一队:CN1', '长宁二队:CN2', '虹口一队:HK1', '虹口二队:HK2', '松江一队:SJ1', '松江二队:SJ2', '家装渠道部:JZ1', ]; for (const s of stores) { const [name, code] = s.split(':'); try { const SC = Parse.Object.extend('StoreConfig'); const obj = new SC(); obj.set('name', name); obj.set('code', code); await obj.save(null, { useMasterKey: true }); } catch (e: any) { console.log(` Store FAIL: ${name} — ${e.message}`); } await sleep(100); } console.log(' Stores: 19 done'); // ===== 3. 产品 ===== const products = [ { name: '定制遮光窗帘', category: '窗帘', subcategory: '遮光帘', baseSpecification: '宽2.5m×高2.8m', unit: '幅', costPrice: 280, salePrice: 580, stock: 48, status: 'active', imageUrl: 'https://images.unsplash.com/photo-1560448204-e02f11c3d0e2?w=400&h=400&fit=crop' }, { name: '北欧风棉麻窗帘', category: '窗帘', subcategory: '棉麻帘', baseSpecification: '宽2m×高2.5m', unit: '幅', costPrice: 180, salePrice: 380, stock: 62, status: 'active', imageUrl: 'https://images.unsplash.com/photo-1513694203232-719a280e022f?w=400&h=400&fit=crop' }, { name: '羊毛混纺地毯', category: '地毯', subcategory: '客厅地毯', baseSpecification: '2m×3m', unit: '张', costPrice: 680, salePrice: 1480, stock: 15, status: 'active', imageUrl: 'https://images.unsplash.com/photo-1600166898405-da9535204843?w=400&h=400&fit=crop' }, { name: '现代简约地毯', category: '地毯', subcategory: '卧室地毯', baseSpecification: '1.5m×2m', unit: '张', costPrice: 320, salePrice: 680, stock: 28, status: 'active', imageUrl: 'https://images.unsplash.com/photo-1555041469-a586c61ea9bc?w=400&h=400&fit=crop' }, { name: '意式真皮沙发', category: '沙发', subcategory: '组合沙发', baseSpecification: '3+2+1人座', unit: '套', costPrice: 8800, salePrice: 18800, stock: 6, status: 'active', imageUrl: 'https://images.unsplash.com/photo-1550254478-ead40cc54513?w=400&h=400&fit=crop' }, { name: '布艺休闲沙发', category: '沙发', subcategory: '单人沙发', baseSpecification: '单人座 85cm', unit: '把', costPrice: 1200, salePrice: 2600, stock: 12, status: 'active', imageUrl: 'https://images.unsplash.com/photo-1540574163026-643ea20ade25?w=400&h=400&fit=crop' }, { name: '四件套床品-云感棉', category: '床品', subcategory: '床上用品', baseSpecification: '1.8m床', unit: '套', costPrice: 380, salePrice: 880, stock: 34, status: 'active', imageUrl: 'https://images.unsplash.com/photo-1522771739844-6a9f6d5f14af?w=400&h=400&fit=crop' }, { name: '法式轻奢台灯', category: '灯具', subcategory: '台灯', baseSpecification: '高45cm', unit: '盏', costPrice: 420, salePrice: 980, stock: 20, status: 'active', imageUrl: 'https://images.unsplash.com/photo-1507473885765-e6ed057f782c?w=400&h=400&fit=crop' }, { name: '欧式花纹壁纸', category: '墙纸', subcategory: '卧室壁纸', baseSpecification: '0.53m×10m/卷', unit: '卷', costPrice: 180, salePrice: 380, stock: 85, status: 'active' }, { name: '抽象装饰画三联', category: '装饰画', subcategory: '挂画', baseSpecification: '60cm×80cm×3幅', unit: '套', costPrice: 280, salePrice: 680, stock: 18, status: 'active' }, { name: '铝合金窗帘轨道', category: '窗帘配件', subcategory: '轨道', baseSpecification: '3m/根', unit: '根', costPrice: 45, salePrice: 120, stock: 120, status: 'active' }, { name: '抱枕套装', category: '配饰', subcategory: '抱枕', baseSpecification: '45cm×45cm 4个', unit: '套', costPrice: 120, salePrice: 280, stock: 45, status: 'active' }, ]; for (const p of products) { try { const Product = Parse.Object.extend('Product'); const obj = new Product(); obj.set('name', p.name); obj.set('category', p.category); obj.set('subcategory', p.subcategory); obj.set('baseSpecification', p.baseSpecification); obj.set('unit', p.unit); obj.set('costPrice', p.costPrice); obj.set('salePrice', p.salePrice); obj.set('stock', p.stock); obj.set('status', p.status); if (p.imageUrl) obj.set('imageUrl', p.imageUrl); await obj.save(null, { useMasterKey: true }); } catch (e: any) { console.log(` Product FAIL: ${p.name} — ${e.message}`); } await sleep(100); } console.log(' Products: 12 done'); // ===== 4. 订单 ===== const orders = [ { orderNo: 'SO2024120001', customerName: '万科·天空之城样板间', customerPhone: '021-88880001', customerAddress: '上海市浦东新区张江路100号', customerType: 'commercial', projectName: '万科天空之城A栋样板间', items: [{ productId: 'p001', productName: '定制遮光窗帘', category: '窗帘', specification: '宽2.5m×高2.8m', quantity: 12, unit: '幅', unitPrice: 580, totalPrice: 6960 }], status: 'pending', totalAmount: 12840, paidAmount: 6420, paymentMethod: '分期付款', isInstallment: true, salesPersonId: 'u001', salesPersonName: '张明华', riskLevel: 'medium', attachments: 3 }, { orderNo: 'SO2024120002', customerName: '林女士', customerPhone: '138-1234-5678', customerAddress: '上海市徐汇区衡山路258号', customerType: 'residential', projectName: '私宅软装全案', items: [{ productId: 'p005', productName: '意式真皮沙发', category: '沙发', specification: '3+2+1人座', quantity: 1, unit: '套', unitPrice: 18800, totalPrice: 18800 }], status: 'approved', totalAmount: 22800, paidAmount: 22800, paymentMethod: '全款', salesPersonId: 'u002', salesPersonName: '李晓燕', reviewHistory: [{ id: 'rh001', action: 'approved', reviewerId: 'u003', reviewerName: '王建国', comment: '客户资质良好,全款支付,通过。', timestamp: '2024-11-30T10:15:00' }], riskLevel: 'low', attachments: 5 }, { orderNo: 'SO2024120003', customerName: '碧桂园·凤凰城', customerPhone: '0755-88880003', customerAddress: '深圳市南山区碧桂园凤凰城', customerType: 'commercial', projectName: '碧桂园凤凰城B区软装', items: [{ productId: 'p002', productName: '北欧风棉麻窗帘', category: '窗帘', specification: '宽2m×高2.5m', quantity: 48, unit: '幅', unitPrice: 380, totalPrice: 18240 }], status: 'rejected', totalAmount: 34560, paidAmount: 0, paymentMethod: '月结', salesPersonId: 'u006', salesPersonName: '赵芳', reviewHistory: [{ id: 'rh002', action: 'rejected', reviewerId: 'u003', reviewerName: '王建国', comment: '月结客户超过授信额度,需要提供担保材料后重新提交。', timestamp: '2024-11-27T16:30:00' }], riskLevel: 'high', attachments: 2, lastRejectedReason: '月结客户超过授信额度' }, { orderNo: 'SO2024120004', customerName: '陈先生', customerPhone: '139-8888-9999', customerAddress: '北京市朝阳区三里屯88号', customerType: 'residential', projectName: '三里屯公寓改造', items: [{ productId: 'p009', productName: '欧式花纹壁纸', category: '墙纸', specification: '0.53m×10m/卷', quantity: 20, unit: '卷', unitPrice: 380, totalPrice: 7600 }], status: 'delivered', totalAmount: 12360, paidAmount: 9270, paymentMethod: '分期付款', isInstallment: true, salesPersonId: 'u001', salesPersonName: '张明华', reviewHistory: [{ id: 'rh003', action: 'approved', reviewerId: 'u003', reviewerName: '王建国', comment: '正常业务,通过。', timestamp: '2024-11-21T09:00:00' }], riskLevel: 'low', attachments: 4 }, { orderNo: 'SO2024120005', customerName: '保利·天汇', customerPhone: '028-88880005', customerAddress: '成都市锦江区保利天汇', customerType: 'commercial', projectName: '保利天汇售楼处软装', items: [{ productId: 'p001', productName: '定制遮光窗帘', category: '窗帘', specification: '宽2.5m×高2.8m', quantity: 20, unit: '幅', unitPrice: 580, totalPrice: 11600 }], status: 'pending', totalAmount: 34600, paidAmount: 0, paymentMethod: '到货付款', salesPersonId: 'u002', salesPersonName: '李晓燕', riskLevel: 'high', attachments: 1 }, { orderNo: 'SO2024120006', customerName: '王女士', customerPhone: '186-6666-7777', customerAddress: '广州市天河区珠江新城168号', customerType: 'residential', projectName: '珠江新城私宅软装', items: [{ productId: 'p005', productName: '意式真皮沙发', category: '沙发', specification: '3+2+1人座', quantity: 1, unit: '套', unitPrice: 18800, totalPrice: 18800 }], status: 'completed', totalAmount: 23440, paidAmount: 23440, paymentMethod: '全款', salesPersonId: 'u001', salesPersonName: '张明华', reviewHistory: [{ id: 'rh004', action: 'approved', reviewerId: 'u003', reviewerName: '王建国', comment: '通过。', timestamp: '2024-11-16T11:00:00' }], riskLevel: 'low', attachments: 6 }, { orderNo: 'SO2024120007', customerName: '龙湖·星悦荟', customerPhone: '023-88880007', customerAddress: '重庆市渝中区龙湖星悦荟', customerType: 'commercial', projectName: '龙湖星悦荟商业空间', items: [{ productId: 'p002', productName: '北欧风棉麻窗帘', category: '窗帘', specification: '宽2m×高2.5m', quantity: 30, unit: '幅', unitPrice: 380, totalPrice: 11400 }], status: 'draft', totalAmount: 16840, paidAmount: 0, paymentMethod: '月结', salesPersonId: 'u001', salesPersonName: '张明华', riskLevel: 'medium', attachments: 0 }, ]; for (const o of orders) { try { const Order = Parse.Object.extend('Order'); const obj = new Order(); obj.set('orderNo', o.orderNo); obj.set('customerName', o.customerName); obj.set('customerPhone', o.customerPhone); obj.set('customerAddress', o.customerAddress); obj.set('customerType', o.customerType); obj.set('projectName', o.projectName); obj.set('items', o.items); obj.set('status', o.status); obj.set('totalAmount', o.totalAmount); obj.set('paidAmount', o.paidAmount); obj.set('paymentMethod', o.paymentMethod); obj.set('salesPersonId', o.salesPersonId); obj.set('salesPersonName', o.salesPersonName); obj.set('riskLevel', o.riskLevel); obj.set('attachments', o.attachments); obj.set('isDeleted', false); if (o.isInstallment) obj.set('isInstallment', true); if (o.reviewHistory) obj.set('reviewHistory', o.reviewHistory); if (o.lastRejectedReason) obj.set('lastRejectedReason', o.lastRejectedReason); await obj.save(null, { useMasterKey: true }); } catch (e: any) { console.log(` Order FAIL: ${o.orderNo} — ${e.message}`); } await sleep(100); } console.log(' Orders: 7 done'); // ===== 5. 财务记录 ===== const finances = [ { orderNo: 'SO2024120002', customerName: '林女士', orderDate: '2024-11-28', dueDate: '2024-11-28', receivable: 22800, received: 22800, difference: 0, status: 'normal', commission: 1368, salesPerson: '李晓燕', verified: true }, { orderNo: 'SO2024120004', customerName: '陈先生', orderDate: '2024-11-20', dueDate: '2024-12-20', receivable: 12360, received: 9270, difference: 3090, status: 'partial', commission: 741.6, salesPerson: '张明华', verified: false }, { orderNo: 'SO2024120006', customerName: '王女士', orderDate: '2024-11-15', dueDate: '2024-11-15', receivable: 23440, received: 23440, difference: 0, status: 'normal', commission: 1406.4, salesPerson: '张明华', verified: true }, { orderNo: 'SO2024110001', customerName: '融创·一号院', orderDate: '2024-11-01', dueDate: '2024-11-30', receivable: 68000, received: 45000, difference: 23000, status: 'overdue', commission: 4080, salesPerson: '赵芳', verified: false }, { orderNo: 'SO2024110002', customerName: '孙先生', orderDate: '2024-11-05', dueDate: '2024-12-05', receivable: 8800, received: 8800, difference: 0, status: 'normal', commission: 528, salesPerson: '李晓燕', verified: true }, ]; for (const f of finances) { try { const FR = Parse.Object.extend('FinanceRecord'); const obj = new FR(); obj.set('orderNo', f.orderNo); obj.set('customerName', f.customerName); obj.set('orderDate', f.orderDate); obj.set('dueDate', f.dueDate); obj.set('receivable', f.receivable); obj.set('received', f.received); obj.set('difference', f.difference); obj.set('status', f.status); obj.set('commission', f.commission); obj.set('salesPerson', f.salesPerson); obj.set('verified', f.verified); await obj.save(null, { useMasterKey: true }); } catch (e: any) { console.log(` Finance FAIL: ${f.orderNo} — ${e.message}`); } await sleep(100); } console.log(' Finance: 5 done'); // ===== 6. 消息 ===== const messages = [ { type: 'approval', title: '订单待您审核', content: '订单 SO2024120001 已提交,请及时审核。', isRead: false, linkPath: '/approval', relatedId: 'o001', recipientId: 'u003' }, { type: 'approval', title: '订单待您审核', content: '订单 SO2024120005 已提交,请及时审核。', isRead: false, linkPath: '/approval', relatedId: 'o005', recipientId: 'u003' }, { type: 'finance', title: '账款逾期提醒', content: '融创·一号院订单逾期未收款 ¥23,000,请跟进。', isRead: false, linkPath: '/finance', relatedId: 'f004', recipientId: 'u004' }, { type: 'order', title: '订单已审核通过', content: '您的订单 SO2024120002 已通过审核。', isRead: true, linkPath: '/orders', relatedId: 'o002', recipientId: 'u002' }, { type: 'order', title: '订单被打回', content: '订单 SO2024120003 被审核打回。', isRead: true, linkPath: '/orders', relatedId: 'o003', recipientId: 'u006' }, { type: 'system', title: '系统维护通知', content: '系统将于12月10日升级维护。', isRead: true, linkPath: null, relatedId: null, recipientId: null }, ]; for (const m of messages) { try { const Msg = Parse.Object.extend('Message'); const obj = new Msg(); obj.set('type', m.type); obj.set('title', m.title); obj.set('content', m.content); obj.set('isRead', m.isRead); if (m.linkPath) obj.set('linkPath', m.linkPath); if (m.relatedId) obj.set('relatedId', m.relatedId); if (m.recipientId) obj.set('recipientId', m.recipientId); await obj.save(null, { useMasterKey: true }); } catch (e: any) { console.log(` Message FAIL: ${m.title} — ${e.message}`); } await sleep(100); } console.log(' Messages: 6 done'); console.log('\n=== 种入完成 ==='); } seed().catch(e => { console.error(e); process.exit(1); });