// 种子数据:服务分类、客户、订单、公告 // 说明:仅用于初始化演示数据,真实环境可替换为数据库迁移/导入 // 服务列表对象结构: key(唯一标识)、name(显示名)、base(基础价,元)、desc(描述) // svg(svg 字符串)、enabled(是否上架),排序 index const serviceCatalog = [ { key: 'express', name: '代拿快递', base: 4, desc: '菜鸟驿站/快递点代取', svg: ``, enabled: true, sort: 0 }, { key: 'food', name: '代取外卖', base: 4, desc: '食堂/外卖柜代拿', svg: ``, enabled: true, sort: 1 }, { key: 'buy', name: '帮我买', base: 5, desc: '超市便利店代购', svg: ``, enabled: true, sort: 2 }, { key: 'send', name: '帮我送', base: 5, desc: '文件物品代送', svg: ``, enabled: true, sort: 3 }, { key: 'print', name: '打印文印', base: 3, desc: '论文资料打印', svg: ``, enabled: true, sort: 4 }, { key: 'queue', name: '排队代办', base: 6, desc: '代排队/代办事', svg: ``, enabled: true, sort: 5 }, { key: 'more', name: '全部服务', base: 0, desc: '查看更多服务', svg: null, enabled: false, sort: 99 } // “全部服务”是占位入口,非真正下单项 ] const notices = [ '新学期上线:跨校区配送,最快 15 分钟送达', '邀请好友注册,双方各得 5 元无门槛券' ] // 将服务目录映射为完整的服务对象(与 store.createService 输出结构一致) // 字段:id / key / name / icon(图标 key) / base / sort / status / desc / createdAt function buildServices() { return serviceCatalog.map((s, i) => ({ id: 'S' + String(1001 + i), key: s.key, name: s.name, icon: s.key === 'more' ? 'service' : s.key, // 前端图标库以 key 命名,与服务 key 一致 base: s.base, sort: s.sort !== undefined ? s.sort : i, status: s.enabled === false ? 'inactive' : 'active', desc: s.desc || '', createdAt: daysAgoISO(45, 8, 0) })) } const rawCustomers = [ { name: '张伟', phone: '13800010001', campus: '东校区' }, { name: '李娜', phone: '13800010002', campus: '东校区' }, { name: '王芳', phone: '13800010003', campus: '西校区' }, { name: '刘洋', phone: '13800010004', campus: '南校区' }, { name: '陈静', phone: '13800010005', campus: '东校区' }, { name: '杨帆', phone: '13800010006', campus: '西校区' }, { name: '赵磊', phone: '13800010007', campus: '南校区' }, { name: '周敏', phone: '13800010008', campus: '东校区' }, { name: '吴强', phone: '13800010009', campus: '西校区' }, { name: '徐丽', phone: '13800010010', campus: '东校区' }, { name: '孙浩', phone: '13800010011', campus: '南校区' }, { name: '马超', phone: '13800010012', campus: '西校区' } ] const fromPool = ['菜鸟驿站(东门)', '南门外卖取餐柜', '全家便利店', '图文快印中心', '食堂二楼', '京东快递点'] const toPool = ['3 号宿舍楼 512', '图书馆 2 楼自习区', '教学楼 B305', '行政楼 208', '5 号宿舍楼 208', '实验楼 A101'] const notePool = ['两个包裹,帮忙拿一下', '瑞幸咖啡一杯,尽快', '矿泉水两瓶 + 纸巾一包', '双面黑白 20 页', '送到寝室楼下即可', '轻拿轻放,谢谢'] const riders = ['骑手·小林', '骑手·阿强', '骑手·大鹏', '骑手·阿杰'] const goodsPool = ['文件资料', '食品饮料', '生活用品', '数码产品', '其他'] // 状态分布(尽量贴近真实:待接单/配送中/已完成/已取消) const statusPattern = [ 'done', 'done', 'done', 'running', 'waiting', 'done', 'canceled', 'done', 'running', 'done', 'waiting', 'done' ] const rewardPool = [0, 2, 2, 3, 3, 5, 8] function daysAgoISO(days, hour = 10, minute = 0) { const d = new Date() d.setDate(d.getDate() - days) d.setHours(hour, minute, 0, 0) return d.toISOString() } function makeOrderId(iso, seq) { const d = new Date(iso) const y = d.getFullYear() const m = String(d.getMonth() + 1).padStart(2, '0') const day = String(d.getDate()).padStart(2, '0') return `PT${y}${m}${day}${String(seq).padStart(3, '0')}` } // 表白墙种子数据(status: pending 待审核 / approved 已通过 / rejected 已驳回) export function buildConfessions() { const now = Date.now() const min = 60 * 1000 const hr = 60 * min const day = 24 * hr const iso = (ms) => new Date(now - ms).toISOString() return [ { id: 'CF1001', to: '图书馆三楼靠窗的女孩', content: '每天下午都能看见你在那里自习,阳光落在你侧脸的样子真好看。今天终于鼓起勇气写下这段话,希望有机会认识你。', author: '匿名', anonymous: true, theme: 0, likes: 128, status: 'approved', comments: [ { id: 'CM1001', name: '路人甲', content: '好浪漫,加油冲!', createdAt: iso(10 * min) }, { id: 'CM1002', name: '同楼层', content: '我好像知道是谁~', createdAt: iso(6 * min) } ], createdAt: iso(12 * min), updatedAt: iso(6 * min) }, { id: 'CF1002', to: '', content: '大学四年很快,谢谢一路陪我熬夜赶due、一起吃食堂二楼麻辣烫的室友们。毕业不散,我们江湖再见!', author: '阿泽', anonymous: false, theme: 2, likes: 76, status: 'approved', comments: [], createdAt: iso(3 * hr), updatedAt: iso(3 * hr) }, { id: 'CF1003', to: '篮球场穿7号球衣的男生', content: '你投三分的样子超帅,可惜我只敢在场边偷偷看。如果你也注意到了那个总来看球的女生,记得对我笑一下。', author: '匿名', anonymous: true, theme: 1, likes: 203, status: 'approved', comments: [ { id: 'CM1003', name: '球队经理', content: '7号已阅(划掉)', createdAt: iso(20 * hr) } ], createdAt: iso(1 * day), updatedAt: iso(20 * hr) }, { id: 'CF1004', to: '高数课代表', content: '谢谢你每次都耐心给我讲题,其实我很多时候是故意问的……喜欢你,希望期末我们都能拿高分。', author: '同班的你', anonymous: false, theme: 3, likes: 54, status: 'approved', comments: [], createdAt: iso(2 * day), updatedAt: iso(2 * day) }, { id: 'CF1005', to: '三食堂打饭的阿姨', content: '谢谢您每次都给我多打一勺菜,大学最温暖的瞬间之一。(这条留给管理员审核演示)', author: '匿名', anonymous: true, theme: 4, likes: 0, status: 'pending', comments: [], createdAt: iso(5 * min), updatedAt: iso(5 * min) } ] } export function buildSeed() { const services = buildServices() // 仅用上架中的服务参与派单(排除 more 占位入口) const activeServices = services.filter((s) => s.status === 'active') const customers = rawCustomers.map((c, i) => ({ id: 'U' + String(1001 + i), name: c.name, phone: c.phone, campus: c.campus, balance: Number((50 + i * 13.5).toFixed(2)), coupons: (i % 4) + 1, points: 120 + i * 65, status: i % 7 === 0 ? 'disabled' : 'active', orderCount: 0, totalSpend: 0, createdAt: daysAgoISO(40 - i, 9, (i * 7) % 60) })) const orders = [] let seq = 1 for (let i = 0; i < 30; i++) { const cust = customers[i % customers.length] const svc = activeServices[i % activeServices.length] const status = statusPattern[i % statusPattern.length] const reward = rewardPool[i % rewardPool.length] const dayOffset = Math.floor(i / 3) const iso = daysAgoISO(dayOffset, 9 + (i % 10), (i * 11) % 60) const total = Number((svc.base + reward).toFixed(2)) orders.push({ id: makeOrderId(iso, seq++), customerId: cust.id, customerName: cust.name, customerPhone: cust.phone, campus: cust.campus, serviceKey: svc.key, type: svc.name, status, from: fromPool[i % fromPool.length], to: toPool[i % toPool.length], goods: goodsPool[i % goodsPool.length], note: notePool[i % notePool.length], baseFee: svc.base, reward, total, riderName: status === 'waiting' ? null : riders[i % riders.length], createdAt: iso, updatedAt: iso }) } // 回填客户的下单数与消费额(仅统计已完成的有效消费) for (const o of orders) { const c = customers.find((x) => x.id === o.customerId) if (!c) continue c.orderCount += 1 if (o.status === 'done') c.totalSpend = Number((c.totalSpend + o.total).toFixed(2)) } return { services, notices, customers, orders, confessions: buildConfessions(), seqCounter: seq } }