/** * 种子数据脚本:写入上海16区 → 门店 → 小区 完整层级数据 * 用法: npx tsx scripts/seed-data.ts */ import 'dotenv/config'; import Parse from '../src/db/parse-client.js'; /* ======================== 上海16个行政区 ======================== */ const SHANGHAI_DISTRICTS = [ '浦东新区', '黄浦区', '徐汇区', '长宁区', '静安区', '普陀区', '虹口区', '杨浦区', '闵行区', '宝山区', '嘉定区', '金山区', '松江区', '青浦区', '奉贤区', '崇明区', ]; /* ======================== 门店数据(按区分布,共30个) ======================== */ interface StoreSeed { code: string; name: string; district: string; communities: CommunitySeed[]; } interface CommunitySeed { name: string; address: string; totalHouseholds: number; avgPrice: number; deliveryDate: string; } const STORE_SEEDS: StoreSeed[] = [ // ── 浦东新区 (3门店) ── { code: 'SH-PD-001', name: '陆家嘴旗舰店', district: '浦东新区', communities: [ { name: '汤臣一品', address: '浦东新区花园石桥路28号', totalHouseholds: 400, avgPrice: 250000, deliveryDate: '2025-03-15' }, { name: '中粮海景壹号', address: '浦东新区银城中路600号', totalHouseholds: 500, avgPrice: 220000, deliveryDate: '2025-09-01' }, { name: '仁恒滨江园', address: '浦东新区浦明路99号', totalHouseholds: 1200, avgPrice: 160000, deliveryDate: '2024-12-31' }, { name: '世茂滨江花园', address: '浦东新区潍坊西路1号', totalHouseholds: 800, avgPrice: 145000, deliveryDate: '2025-06-30' }, ], }, { code: 'SH-PD-002', name: '金桥国际店', district: '浦东新区', communities: [ { name: '碧云国际社区', address: '浦东新区碧云路299号', totalHouseholds: 600, avgPrice: 120000, deliveryDate: '2025-01-15' }, { name: '联洋年华', address: '浦东新区丁香路1088号', totalHouseholds: 900, avgPrice: 98000, deliveryDate: '2024-09-01' }, { name: '金桥瑞仕花园', address: '浦东新区金桥路1500号', totalHouseholds: 700, avgPrice: 105000, deliveryDate: '2025-11-30' }, ], }, { code: 'SH-PD-003', name: '张江科技店', district: '浦东新区', communities: [ { name: '张江汤臣豪园', address: '浦东新区科苑路399号', totalHouseholds: 500, avgPrice: 85000, deliveryDate: '2025-04-01' }, { name: '万科翡翠公园', address: '浦东新区张江路1088号', totalHouseholds: 1100, avgPrice: 78000, deliveryDate: '2025-08-15' }, { name: '中建朗阅', address: '浦东新区盛夏路299号', totalHouseholds: 400, avgPrice: 92000, deliveryDate: '2026-02-28' }, { name: '张江科技花园', address: '浦东新区祖冲之路399号', totalHouseholds: 300, avgPrice: 88000, deliveryDate: '2025-12-31' }, ], }, // ── 黄浦区 (2门店) ── { code: 'SH-HP-001', name: '外滩精品店', district: '黄浦区', communities: [ { name: '翠湖天地', address: '黄浦区济南路260号', totalHouseholds: 1800, avgPrice: 185000, deliveryDate: '2024-06-30' }, { name: '复兴珑御', address: '黄浦区复兴东路1188号', totalHouseholds: 400, avgPrice: 175000, deliveryDate: '2025-03-01' }, { name: '华府天地', address: '黄浦区马当路222号', totalHouseholds: 350, avgPrice: 200000, deliveryDate: '2025-09-15' }, { name: '老西门新苑', address: '黄浦区西藏南路688号', totalHouseholds: 600, avgPrice: 155000, deliveryDate: '2024-11-01' }, ], }, { code: 'SH-HP-002', name: '新天地体验店', district: '黄浦区', communities: [ { name: '淮海晶华苑', address: '黄浦区淮海中路158号', totalHouseholds: 450, avgPrice: 165000, deliveryDate: '2025-07-01' }, { name: '永业公寓', address: '黄浦区建国东路88号', totalHouseholds: 520, avgPrice: 140000, deliveryDate: '2024-08-15' }, { name: '海珀日晖', address: '黄浦区瑞金南路1号', totalHouseholds: 380, avgPrice: 180000, deliveryDate: '2025-12-01' }, ], }, // ── 徐汇区 (2门店) ── { code: 'SH-XH-001', name: '徐汇滨江店', district: '徐汇区', communities: [ { name: '尚海湾豪庭', address: '徐汇区凯滨路18号', totalHouseholds: 550, avgPrice: 170000, deliveryDate: '2025-05-01' }, { name: '云锦东方', address: '徐汇区龙兰路399号', totalHouseholds: 400, avgPrice: 190000, deliveryDate: '2025-10-15' }, { name: '百汇园', address: '徐汇区宛平南路1518号', totalHouseholds: 680, avgPrice: 145000, deliveryDate: '2024-10-01' }, { name: '中信君廷', address: '徐汇区斜土路2088号', totalHouseholds: 320, avgPrice: 155000, deliveryDate: '2025-08-01' }, ], }, { code: 'SH-XH-002', name: '衡山路精品店', district: '徐汇区', communities: [ { name: '嘉御庭', address: '徐汇区建国西路228号', totalHouseholds: 280, avgPrice: 200000, deliveryDate: '2025-06-15' }, { name: '太原邸', address: '徐汇区太原路289号', totalHouseholds: 200, avgPrice: 210000, deliveryDate: '2025-11-01' }, { name: '上方花园', address: '徐汇区淮海中路1285号', totalHouseholds: 350, avgPrice: 175000, deliveryDate: '2024-12-15' }, ], }, // ── 长宁区 (2门店) ── { code: 'SH-CN-001', name: '古北国际店', district: '长宁区', communities: [ { name: '古北壹号', address: '长宁区古北路1398号', totalHouseholds: 420, avgPrice: 160000, deliveryDate: '2025-04-01' }, { name: '西郊紫郡', address: '长宁区剑河路688号', totalHouseholds: 500, avgPrice: 135000, deliveryDate: '2024-11-01' }, { name: '仁恒河滨花园', address: '长宁区芙蓉江路388号', totalHouseholds: 700, avgPrice: 125000, deliveryDate: '2024-08-15' }, ], }, { code: 'SH-CN-002', name: '中山公园店', district: '长宁区', communities: [ { name: '长宁八八', address: '长宁区长宁路88号', totalHouseholds: 380, avgPrice: 140000, deliveryDate: '2025-09-01' }, { name: '虹桥豪苑', address: '长宁区虹桥路996号', totalHouseholds: 310, avgPrice: 150000, deliveryDate: '2025-03-15' }, { name: '兆丰花园', address: '长宁区中山西路879号', totalHouseholds: 450, avgPrice: 115000, deliveryDate: '2025-01-01' }, { name: '圣约翰名邸', address: '长宁区金钟路68号', totalHouseholds: 550, avgPrice: 108000, deliveryDate: '2025-07-01' }, ], }, // ── 静安区 (2门店) ── { code: 'SH-JA-001', name: '静安寺旗舰店', district: '静安区', communities: [ { name: '中凯城市之光', address: '静安区威海路333号', totalHouseholds: 480, avgPrice: 180000, deliveryDate: '2024-09-01' }, { name: '静安枫景苑', address: '静安区常德路500号', totalHouseholds: 350, avgPrice: 170000, deliveryDate: '2025-02-15' }, { name: '远中风华园', address: '静安区昌平路888号', totalHouseholds: 420, avgPrice: 155000, deliveryDate: '2025-07-15' }, { name: '静安豪景苑', address: '静安区西康路699号', totalHouseholds: 380, avgPrice: 165000, deliveryDate: '2025-11-30' }, ], }, { code: 'SH-JA-002', name: '大宁国际店', district: '静安区', communities: [ { name: '大宁金茂府', address: '静安区彭江路399号', totalHouseholds: 600, avgPrice: 125000, deliveryDate: '2025-04-01' }, { name: '静安府', address: '静安区汶水路658号', totalHouseholds: 800, avgPrice: 115000, deliveryDate: '2025-09-01' }, { name: '明园森林都市', address: '静安区共和新路2999号', totalHouseholds: 500, avgPrice: 98000, deliveryDate: '2024-12-01' }, ], }, // ── 普陀区 (2门店) ── { code: 'SH-PT-001', name: '长风公园店', district: '普陀区', communities: [ { name: '长风瑞仕璟庭', address: '普陀区丹巴路368号', totalHouseholds: 450, avgPrice: 105000, deliveryDate: '2025-06-01' }, { name: '高尚领域', address: '普陀区礼尚路222号', totalHouseholds: 320, avgPrice: 98000, deliveryDate: '2025-10-01' }, { name: '品尊国际', address: '普陀区铜川路58号', totalHouseholds: 550, avgPrice: 110000, deliveryDate: '2024-11-15' }, ], }, { code: 'SH-PT-002', name: '长寿路店', district: '普陀区', communities: [ { name: '中远两湾城', address: '普陀区中潭路99号', totalHouseholds: 1500, avgPrice: 85000, deliveryDate: '2024-07-01' }, { name: '华府樟园', address: '普陀区凯旋北路1555号', totalHouseholds: 380, avgPrice: 102000, deliveryDate: '2025-03-01' }, { name: '苏堤春晓名苑', address: '普陀区光复西路1185号', totalHouseholds: 420, avgPrice: 95000, deliveryDate: '2025-08-01' }, ], }, // ── 虹口区 (2门店) ── { code: 'SH-HK-001', name: '北外滩体验店', district: '虹口区', communities: [ { name: '瑞虹新城', address: '虹口区瑞虹路368号', totalHouseholds: 800, avgPrice: 120000, deliveryDate: '2025-02-01' }, { name: '白金湾府邸', address: '虹口区海平路18号', totalHouseholds: 300, avgPrice: 150000, deliveryDate: '2025-07-01' }, { name: '馥敦坊', address: '虹口区东余杭路588号', totalHouseholds: 350, avgPrice: 109000, deliveryDate: '2025-12-31' }, ], }, { code: 'SH-HK-002', name: '虹口足球场店', district: '虹口区', communities: [ { name: '建邦16区', address: '虹口区天宝路466号', totalHouseholds: 500, avgPrice: 105000, deliveryDate: '2025-05-01' }, { name: '虹叶茗园', address: '虹口区虹口路128号', totalHouseholds: 280, avgPrice: 115000, deliveryDate: '2024-10-01' }, { name: '金轩大邸', address: '虹口区四平路758号', totalHouseholds: 420, avgPrice: 98000, deliveryDate: '2025-09-15' }, { name: '溧阳华府', address: '虹口区宝安路138号', totalHouseholds: 360, avgPrice: 102000, deliveryDate: '2025-04-15' }, ], }, // ── 杨浦区 (2门店) ── { code: 'SH-YP-001', name: '五角场店', district: '杨浦区', communities: [ { name: '新江湾城', address: '杨浦区殷行路1280号', totalHouseholds: 650, avgPrice: 95000, deliveryDate: '2025-05-15' }, { name: '翡丽甲第', address: '杨浦区平凉路2788号', totalHouseholds: 380, avgPrice: 110000, deliveryDate: '2025-08-01' }, { name: '圣骊河滨苑', address: '杨浦区龙江路388号', totalHouseholds: 420, avgPrice: 92000, deliveryDate: '2024-12-01' }, ], }, { code: 'SH-YP-002', name: '大学路社区店', district: '杨浦区', communities: [ { name: '创智天地', address: '杨浦区淞沪路290号', totalHouseholds: 480, avgPrice: 88000, deliveryDate: '2025-06-01' }, { name: '同济欣苑', address: '杨浦区四平路1239号', totalHouseholds: 320, avgPrice: 82000, deliveryDate: '2025-01-15' }, { name: '文化佳园', address: '杨浦区国定路777号', totalHouseholds: 350, avgPrice: 90000, deliveryDate: '2025-10-01' }, ], }, // ── 闵行区 (2门店) ── { code: 'SH-MH-001', name: '莘庄旗舰店', district: '闵行区', communities: [ { name: '万科假日风景', address: '闵行区畹町路99号', totalHouseholds: 900, avgPrice: 75000, deliveryDate: '2025-03-01' }, { name: '春申景城', address: '闵行区莲花南路1111号', totalHouseholds: 700, avgPrice: 72000, deliveryDate: '2024-09-15' }, { name: '上海星河湾', address: '闵行区都会路3899号', totalHouseholds: 450, avgPrice: 95000, deliveryDate: '2025-07-01' }, { name: '中环名品公馆', address: '闵行区古美路1458号', totalHouseholds: 380, avgPrice: 88000, deliveryDate: '2025-11-01' }, ], }, { code: 'SH-MH-002', name: '虹桥天地店', district: '闵行区', communities: [ { name: '万科时一区', address: '闵行区申郑路18号', totalHouseholds: 520, avgPrice: 85000, deliveryDate: '2025-04-01' }, { name: '尚品华庭', address: '闵行区申滨路1058号', totalHouseholds: 400, avgPrice: 78000, deliveryDate: '2025-09-01' }, { name: '爱博新村', address: '闵行区宁虹路1101号', totalHouseholds: 350, avgPrice: 65000, deliveryDate: '2024-08-01' }, ], }, // ── 宝山区 (2门店) ── { code: 'SH-BS-001', name: '宝山万达店', district: '宝山区', communities: [ { name: '大华锦绣华城', address: '宝山区真华路999号', totalHouseholds: 600, avgPrice: 68000, deliveryDate: '2025-02-01' }, { name: '经纬城市绿洲', address: '宝山区纬地路358号', totalHouseholds: 500, avgPrice: 62000, deliveryDate: '2025-07-15' }, { name: '上大聚丰园', address: '宝山区上大路1288号', totalHouseholds: 420, avgPrice: 58000, deliveryDate: '2024-11-01' }, { name: '丰翔新城', address: '宝山区丰翔路258号', totalHouseholds: 350, avgPrice: 65000, deliveryDate: '2025-12-31' }, ], }, { code: 'SH-BS-002', name: '顾村公园店', district: '宝山区', communities: [ { name: '顾村大家园', address: '宝山区顾北路568号', totalHouseholds: 450, avgPrice: 55000, deliveryDate: '2025-05-01' }, { name: '美兰湖花园', address: '宝山区美兰湖路339号', totalHouseholds: 300, avgPrice: 72000, deliveryDate: '2025-10-01' }, { name: '保利叶上海', address: '宝山区菊太路1198号', totalHouseholds: 520, avgPrice: 60000, deliveryDate: '2024-12-15' }, ], }, // ── 嘉定区 (2门店) ── { code: 'SH-JD-001', name: '嘉定新城店', district: '嘉定区', communities: [ { name: '金地格林世界', address: '嘉定区芳林路951号', totalHouseholds: 550, avgPrice: 52000, deliveryDate: '2025-06-01' }, { name: '龙湖郦城', address: '嘉定区双单路999号', totalHouseholds: 480, avgPrice: 55000, deliveryDate: '2025-03-01' }, { name: '嘉宝梦之湾', address: '嘉定区平城路2055号', totalHouseholds: 380, avgPrice: 58000, deliveryDate: '2025-09-01' }, ], }, { code: 'SH-JD-002', name: '安亭汽车城店', district: '嘉定区', communities: [ { name: '安亭新镇', address: '嘉定区安礼路258号', totalHouseholds: 600, avgPrice: 48000, deliveryDate: '2025-04-01' }, { name: '绿地海域苏河源', address: '嘉定区安亭镇泽普路588号', totalHouseholds: 420, avgPrice: 45000, deliveryDate: '2024-10-01' }, { name: '万科安亭新镇', address: '嘉定区安亭镇安诚路318号', totalHouseholds: 350, avgPrice: 50000, deliveryDate: '2025-08-01' }, ], }, // ── 金山区 (1门店) ── { code: 'SH-JS-001', name: '金山新城店', district: '金山区', communities: [ { name: '金山豪庭', address: '金山区卫清西路399号', totalHouseholds: 400, avgPrice: 35000, deliveryDate: '2025-07-01' }, { name: '海上明珠', address: '金山区龙胜路828号', totalHouseholds: 350, avgPrice: 32000, deliveryDate: '2025-01-15' }, { name: '枫丹白露', address: '金山区朱泾镇人民路360号', totalHouseholds: 280, avgPrice: 38000, deliveryDate: '2025-12-01' }, ], }, // ── 松江区 (2门店) ── { code: 'SH-SJ-001', name: '松江大学城店', district: '松江区', communities: [ { name: '松江新城', address: '松江区新松江路1188号', totalHouseholds: 500, avgPrice: 48000, deliveryDate: '2025-05-01' }, { name: '保利西子湾', address: '松江区广富林路1518号', totalHouseholds: 380, avgPrice: 52000, deliveryDate: '2025-09-01' }, { name: '绿地蔷薇九里', address: '松江区广富林路600号', totalHouseholds: 420, avgPrice: 50000, deliveryDate: '2024-11-15' }, { name: '佘山一品', address: '松江区佘山镇外青松公路666号', totalHouseholds: 300, avgPrice: 62000, deliveryDate: '2025-06-15' }, ], }, { code: 'SH-SJ-002', name: '九亭社区店', district: '松江区', communities: [ { name: '九亭明珠苑', address: '松江区九亭镇沪亭南路88号', totalHouseholds: 450, avgPrice: 45000, deliveryDate: '2025-03-01' }, { name: '中大九里德', address: '松江区九亭镇涞坊路1018号', totalHouseholds: 350, avgPrice: 43000, deliveryDate: '2024-08-01' }, { name: '奥林匹克花园', address: '松江区九亭镇涞亭北路99号', totalHouseholds: 550, avgPrice: 47000, deliveryDate: '2025-11-01' }, ], }, // ── 青浦区 (1门店) ── { code: 'SH-QP-001', name: '青浦吾悦店', district: '青浦区', communities: [ { name: '仁恒西郊花园', address: '青浦区徐泾镇盈港东路1188号', totalHouseholds: 450, avgPrice: 55000, deliveryDate: '2025-04-01' }, { name: '万科天空之城', address: '青浦区徐泾镇诸光路66号', totalHouseholds: 550, avgPrice: 60000, deliveryDate: '2025-10-01' }, { name: '金地天境', address: '青浦区赵巷镇嘉松中路6888号', totalHouseholds: 320, avgPrice: 52000, deliveryDate: '2025-08-01' }, ], }, // ── 奉贤区 (1门店) ── { code: 'SH-FX-001', name: '南桥百联店', district: '奉贤区', communities: [ { name: '南桥老街', address: '奉贤区南桥镇解放西路128号', totalHouseholds: 400, avgPrice: 35000, deliveryDate: '2025-02-01' }, { name: '奉贤海湾', address: '奉贤区海湾路188号', totalHouseholds: 350, avgPrice: 38000, deliveryDate: '2025-06-01' }, { name: '阳光四季', address: '奉贤区南桥镇环城东路558号', totalHouseholds: 300, avgPrice: 36000, deliveryDate: '2025-12-01' }, ], }, // ── 崇明区 (1门店) ── { code: 'SH-CM-001', name: '崇明生态店', district: '崇明区', communities: [ { name: '崇明绿地长岛', address: '崇明区长兴岛凤凰公路888号', totalHouseholds: 500, avgPrice: 28000, deliveryDate: '2025-05-01' }, { name: '崇明新城', address: '崇明区城桥镇翠竹路128号', totalHouseholds: 380, avgPrice: 30000, deliveryDate: '2025-09-01' }, { name: '东滩花园', address: '崇明区陈家镇揽海路1号', totalHouseholds: 280, avgPrice: 35000, deliveryDate: '2025-03-15' }, ], }, ]; /* ======================== 执行脚本 ======================== */ async function seed() { console.log('[Seed] 开始写入上海16区层级数据...\n'); let districtsCreated = 0; let districtsSkipped = 0; let storesCreated = 0; let storesSkipped = 0; let communitiesCreated = 0; let communitiesSkipped = 0; // 1. 写入行政区 const districtIdMap = new Map(); // name → objectId for (let i = 0; i < SHANGHAI_DISTRICTS.length; i++) { const name = SHANGHAI_DISTRICTS[i]; const q = new Parse.Query('District'); q.equalTo('name', name); const existing = await q.first({ useMasterKey: true }); if (existing) { districtIdMap.set(name, existing.id); districtsSkipped++; console.log(` [跳过] 行政区已存在: ${name}`); } else { const obj = new Parse.Object('District'); obj.set('name', name); obj.set('sortOrder', i + 1); const saved = await obj.save(null, { useMasterKey: true }); districtIdMap.set(name, saved.id); districtsCreated++; console.log(` [创建] 行政区: ${name} (排序: ${i + 1})`); } } console.log(`\n[Seed] 行政区: +${districtsCreated} (跳过${districtsSkipped})\n`); // 2. 写入门店和小区 for (const s of STORE_SEEDS) { const districtId = districtIdMap.get(s.district); if (!districtId) { console.warn(` [警告] 行政区 ${s.district} 未找到,跳过门店 ${s.name}`); continue; } // Store const sq = new Parse.Query('Store'); sq.equalTo('code', s.code); const existingStore = await sq.first({ useMasterKey: true }); let storeId: string; if (existingStore) { storeId = existingStore.id; storesSkipped++; console.log(` [跳过] 门店已存在: ${s.name} (${s.code})`); } else { const obj = new Parse.Object('Store'); obj.set('code', s.code); obj.set('name', s.name); const districtPtr = new Parse.Object('District'); districtPtr.id = districtId; obj.set('district', districtPtr); const saved = await obj.save(null, { useMasterKey: true }); storeId = saved.id; storesCreated++; console.log(` [创建] 门店: ${s.name} (${s.code}) — ${s.district}`); } // Communities for (const c of s.communities) { const storePtr = new Parse.Object('Store'); storePtr.id = storeId; const cq = new Parse.Query('Community'); cq.equalTo('name', c.name); cq.equalTo('store', storePtr); const cExist = await cq.first({ useMasterKey: true }); if (cExist) { communitiesSkipped++; console.log(` [跳过] 小区已存在: ${c.name}`); } else { const obj = new Parse.Object('Community'); obj.set('name', c.name); obj.set('address', c.address); obj.set('totalHouseholds', c.totalHouseholds); obj.set('avgPrice', c.avgPrice); obj.set('deliveryDate', c.deliveryDate); obj.set('store', storePtr); await obj.save(null, { useMasterKey: true }); communitiesCreated++; console.log(` [创建] 小区: ${c.name} → ${s.name}`); } } } console.log(`\n[Seed] 完成:`); console.log(` 行政区: +${districtsCreated} (跳过${districtsSkipped})`); console.log(` 门店: +${storesCreated} (跳过${storesSkipped})`); console.log(` 小区: +${communitiesCreated} (跳过${communitiesSkipped})`); } seed() .then(() => process.exit(0)) .catch((err) => { console.error('[Seed] 失败:', err); process.exit(1); });