📱 MVP-WX 启动辅助工具

微信小程序版 · 云开发配置 / 数据库初始化 / 云函数模板 / 4 周冲刺 / 审核清单 | → MVP-FS 飞书版

🧭 快速导航(4 周冲刺路线图)

TL 1 人 4 周完成开发+审核+上线,详见 MVP-WX 实施方案 §7

Week 1

需求确认 + UI 原型
云环境搭建
数据库初始化
框架搭建

Week 2

客户端核心功能
下单/报价/支付
验收/NPS
L1→L8 跑通

Week 3

师傅端打卡拍照
管理端派单看板
异常监控
L6 全流程

Week 4

AI 云函数
全流程联调
提交审核
上线首单

☁️ §1 云开发环境配置(Day 3)

微信云开发 CloudBase:零运维、免域名、免 SSL

1.1 前置条件

  1. 注册微信小程序(企业主体)

    mp.weixin.qq.com → 注册 → 服务号/小程序 → 企业认证(¥300/年)→ 获取 AppID

  2. 开通云开发

    微信开发者工具 → 打开小程序项目 → 云开发 → 创建环境 weavely-mvp

  3. 选择套餐

    基础版(免费额度,日均<30单够用)或 专业版(¥40/月,额度更高)

1.2 项目目录结构

weavely-mvp/
├── miniprogram/          # 小程序前端代码
│   ├── pages/
│   │   ├── customer/     # 客户端页面(8页)
│   │   ├── worker/       # 师傅端页面(6页)
│   │   └── admin/        # 管理端页面(10页)
│   ├── components/       # 公共组件
│   ├── utils/            # 工具函数
│   └── app.js            # 入口(角色切换逻辑)
├── cloudfunctions/       # 云函数
│   ├── createOrder/      # L1 创建订单
│   ├── generateQuote/    # L3 生成报价
│   ├── assignWorker/     # L4 派单
│   ├── workerCheckin/    # L6 打卡
│   ├── uploadPhotos/     # L6 照片上传
│   ├── acceptOrder/      # L7 验收
│   ├── npsSurvey/        # L8 NPS推送
│   └── weeklyReport/     # 周报生成
└── project.config.json   # 项目配置

1.3 app.js 角色切换核心代码

// app.js - 三端角色切换
App({
  globalData: {
    role: null,  // 'customer' | 'worker' | 'admin'
    openid: null,
    userInfo: null
  },
  onLaunch() {
    // 微信登录获取 openid
    wx.cloud.callFunction({ name: 'login' }).then(res => {
      this.globalData.openid = res.result.openid
      // 根据openid查询用户角色(首次进入选择角色)
      this.checkRole()
    })
  },
  checkRole() {
    const db = wx.cloud.database()
    db.collection('users').where({ openid: this.globalData.openid }).get().then(res => {
      if (res.data.length > 0) {
        this.globalData.role = res.data[0].role
        this.gotoHome()
      } else {
        // 首次进入,跳转角色选择页
        wx.redirectTo({ url: '/pages/role-select/role-select' })
      }
    })
  }
})

🗄️ §2 数据库初始化(Day 4)

6 个集合,字段与 MVP-FS 完全一致(snake_case),可互导互迁

2.1 集合清单

集合名对应 FS 表字段数主键说明
ordersCPT-Lite40order_id订单跟踪(8阶段状态机)
quotesQSV-Lite15quote_id报价记录
workersWPL-Lite8worker_id师傅台账
customersCPL-Lite10customer_id客户台账
servicesSCL-Lite7category_id品类费率
buildingsBPL-Lite8building_id楼宇系数

2.2 种子数据初始化脚本(云函数)

// cloudfunctions/initSeed/index.js - 种子数据初始化
const cloud = require('wx-server-sdk')
cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV })
const db = cloud.database()

exports.main = async (event, context) => {
  // 师傅种子数据(≥3)
  const workers = [
    { worker_id: 'WK-001', name: '陈师傅', contact: '+852-91234567', level: 'L2',
      skill_categories: ['衣柜','橱柜'], total_orders: 0, avg_rating: 5.0, status: '在职' },
    { worker_id: 'WK-002', name: '李师傅', contact: '+852-98765432', level: 'L3',
      skill_categories: ['床','餐桌','书柜'], total_orders: 0, avg_rating: 5.0, status: '在职' },
    { worker_id: 'WK-003', name: '王师傅', contact: '+852-95558888', level: 'L1',
      skill_categories: ['衣柜','床'], total_orders: 0, avg_rating: 5.0, status: '在职' }
  ]

  // 品类费率(≥5)
  const services = [
    { category_id: 'CAT-01', name: '衣柜', sub_category: 'PAX/定制', base_fee: 600,
      base_work_hours: 3.0, cap_price: 3000, skill_required: 'L1+' },
    { category_id: 'CAT-02', name: '橱柜', sub_category: '整体/定制', base_fee: 800,
      base_work_hours: 4.0, cap_price: 5000, skill_required: 'L2+' },
    { category_id: 'CAT-03', name: '床', sub_category: '框架/储物', base_fee: 400,
      base_work_hours: 1.5, cap_price: 1500, skill_required: 'L1+' },
    { category_id: 'CAT-04', name: '餐桌', sub_category: '标准/伸缩', base_fee: 300,
      base_work_hours: 1.0, cap_price: 1000, skill_required: 'L1+' },
    { category_id: 'CAT-05', name: '书柜', sub_category: '墙挂/落地', base_fee: 500,
      base_work_hours: 2.5, cap_price: 2000, skill_required: 'L2+' }
  ]

  // 楼宇系数(≥5)
  const buildings = [
    { building_id: 'BLD-001', estate_name: '沙田第一城', address: '沙田', building_type: '私人住宅',
      floor_factor: 1.0, has_elevator: true, parking_note: '有访客车位', access_note: '' },
    { building_id: 'BLD-002', estate_name: '太古城', address: '鲗鱼涌', building_type: '私人屋苑',
      floor_factor: 1.2, has_elevator: true, parking_note: '需预约', access_note: '大件走货梯' },
    { building_id: 'BLD-003', estate_name: '公屋-彩虹邨', address: '黄大仙', building_type: '公屋',
      floor_factor: 1.5, has_elevator: true, parking_note: '无车位', access_note: '走后楼梯' },
    { building_id: 'BLD-004', estate_name: '海怡半岛', address: '鸭脷洲', building_type: '私人屋苑',
      floor_factor: 1.1, has_elevator: true, parking_note: '有访客车位', access_note: '' },
    { building_id: 'BLD-005', estate_name: '村屋-锦田', address: '元朗', building_type: '村屋',
      floor_factor: 0.9, has_elevator: false, parking_note: '门口停车', access_note: '楼梯搬运' }
  ]

  // 批量插入
  for (const w of workers) await db.collection('workers').add({ data: w })
  for (const s of services) await db.collection('services').add({ data: s })
  for (const b of buildings) await db.collection('buildings').add({ data: b })

  return { success: true, workers: workers.length, services: services.length, buildings: buildings.length }
}
📋 在微信开发者工具中右键 cloudfunctions/initSeed → 上传并部署 → 在云开发控制台调用即可完成种子数据初始化。

📱 §3 三端页面清单(Week 2-3)

MVP 阶段三端合一(一个小程序+角色切换),共 ~24 页

客户端8 页

页面阶段
首页/扫码入口L1
下单表单L1→L2
报价查看L3→L4
支付页L4
订单进度L4→L7
验收签字L7
NPS评价L8
历史订单

师傅端6 页

页面阶段
接单列表L4
订单详情L4→L6
打卡页(3按钮)L6
拍照页L6
工时记录L6
异常上报L6

管理端10 页

工作台 / 需求确认(L2) / 报价审核(L3) / 派单管理(L4) / 配送协调(L5) / 异常监控 / 回访管理(L8) / 数据看板 / 师傅管理 / 客户管理

⚡ §4 核心云函数模板(Week 2-4)

8 个云函数,复制即可部署

4.1 createOrder(L1 创建订单 + AI 提炼需求)

// cloudfunctions/createOrder/index.js
const cloud = require('wx-server-sdk')
cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV })
const db = cloud.database()

exports.main = async (event, context) => {
  const { OPENID } = cloud.getWXContext()
  const today = new Date().toISOString().slice(0,10).replace(/-/g,'')
  
  // 生成订单编号 ORD-YYYYMMDD-NNN
  const count = await db.collection('orders').count()
  const seq = String(count.total + 1).padStart(3, '0')
  const order_id = `ORD-${today}-${seq}`

  // AI 提炼需求(如有自由文本)
  let lead_demand = event.lead_demand || ''
  if (event.raw_text && event.raw_text.length > 20) {
    try {
      const ai = await cloud.callFunction({ name: 'aiExtract', data: { text: event.raw_text } })
      lead_demand = ai.result.extracted || lead_demand
    } catch (e) { console.log('AI降级,使用原始文本') }
  }

  const order = {
    order_id,
    current_stage: 'L1',
    order_status: '进行中',
    created_at: db.serverDate(),
    updated_at: db.serverDate(),
    lead_source: event.lead_source || 'SCENE01线上',
    customer_name: event.customer_name,
    customer_contact: event.customer_contact,
    lead_demand,
    lead_time: db.serverDate(),
    _openid: OPENID,
    _ai_generated: lead_demand !== event.lead_demand
  }

  const res = await db.collection('orders').add({ data: order })
  
  // 发送订阅消息通知 OL
  await cloud.callFunction({ name: 'notifyAdmin', data: { order_id, type: 'new_order' } })
  
  return { success: true, order_id, _id: res._id }
}

4.2 generateQuote(L3 报价生成 + AI 建议)

// cloudfunctions/generateQuote/index.js
const cloud = require('wx-server-sdk')
cloud.init()
const db = cloud.database()

exports.main = async (event, context) => {
  const { order_id } = event
  const order = (await db.collection('orders').where({ order_id }).get()).data[0]
  
  // 查主数据
  const service = (await db.collection('services').where({ name: order.category }).get()).data[0]
  const building = order.building_id 
    ? (await db.collection('buildings').where({ building_id: order.building_id }).get()).data[0]
    : { floor_factor: 1.0 }
  const worker = order.assigned_worker_id
    ? (await db.collection('workers').where({ worker_id: order.assigned_worker_id }).get()).data[0]
    : { level: 'L1' }

  // 系数映射
  const levelFactor = { 'L1': 1.0, 'L2': 1.2, 'L3': 1.4 }[worker.level] || 1.0
  
  // QSV-Lite 报价公式
  const base_fee = service.base_fee
  const complexity_factor = event.complexity_factor || 1.0
  const building_factor = building.floor_factor
  const worker_level_factor = levelFactor
  const extra_work_fee = event.extra_work_fee || 0
  const discount = event.discount || 0
  const cap_price = service.cap_price

  const subtotal = base_fee * complexity_factor * building_factor * worker_level_factor + extra_work_fee
  const before_cap = subtotal - discount
  const final_amount = Math.min(before_cap, cap_price)
  const cap_triggered = before_cap > cap_price

  // AI 报价建议(可选)
  let ai_suggestion = null
  try {
    const ai = await cloud.callFunction({
      name: 'aiQuoteAdvice',
      data: { order_id, final_amount, category: order.category, history: true }
    })
    ai_suggestion = ai.result
  } catch (e) { console.log('AI报价建议降级') }

  // 生成报价编号
  const today = new Date().toISOString().slice(0,10).replace(/-/g,'')
  const count = await db.collection('quotes').count()
  const seq = String(count.total + 1).padStart(3, '0')
  const quote_id = `QTE-${today}-${seq}`

  const quote = {
    quote_id, order_id, category: order.category,
    base_fee, complexity_factor, building_factor, worker_level_factor,
    extra_work_fee, subtotal, discount, cap_price, final_amount,
    quote_detail_json: JSON.stringify({ cap_triggered, ai_suggestion }),
    quote_time: db.serverDate(),
    quote_status: '待确认'
  }

  await db.collection('quotes').add({ data: quote })
  
  // 更新订单阶段
  await db.collection('orders').where({ order_id }).update({
    data: { current_stage: 'L3', quote_id, quote_amount: final_amount, updated_at: db.serverDate() }
  })

  return { success: true, quote_id, final_amount, cap_triggered, ai_suggestion }
}

4.3 workerCheckin(L6 打卡 + GPS + 自动工时)

// cloudfunctions/workerCheckin/index.js
const cloud = require('wx-server-sdk')
cloud.init()
const db = cloud.database()

exports.main = async (event, context) => {
  const { order_id, action, gps } = event
  // action: 'depart' | 'arrive' | 'complete'
  
  const fieldMap = {
    depart: 'worker_depart_time',
    arrive: 'worker_arrive_time',
    complete: 'work_complete_time'
  }
  
  const update = {
    updated_at: db.serverDate(),
    [fieldMap[action]]: db.serverDate()
  }
  
  if (gps) update.gps_location = gps
  
  // 完工时自动计算工时
  if (action === 'complete') {
    const order = (await db.collection('orders').where({ order_id }).get()).data[0]
    if (order.worker_arrive_time) {
      const arrive = new Date(order.worker_arrive_time)
      const complete = new Date()
      update.actual_work_hours = Math.round((complete - arrive) / 3600000 * 10) / 10  // 1位小数
    }
  }
  
  await db.collection('orders').where({ order_id }).update({ data: update })
  
  // 推送通知给客户
  await cloud.callFunction({ name: 'notifyCustomer', data: { order_id, action } })
  
  return { success: true, action, work_hours: update.actual_work_hours }
}
📋 其余 5 个云函数(uploadPhotos / acceptOrder / npsSurvey / weeklyReport / assignWorker)结构类似,详见 MVP-WX §2.5

💳 §5 微信支付对接要点(Week 2)

⚠ 前置条件:小程序已认证(企业主体)+ 开通微信支付 + 绑定商户号。审核约 1-3 天。

支付流程

// 客户端调起支付
wx.cloud.callFunction({
  name: 'createPayment',
  data: { order_id, amount: final_amount }
}).then(res => {
  const payment = res.result.payment
  wx.requestPayment({
    ...payment,
    success: () => {
      // 支付成功,云函数已收到回调,更新 payment_status
      wx.showToast({ title: '支付成功' })
      wx.navigateTo({ url: '/pages/customer/progress?order_id=' + order_id })
    },
    fail: (err) => {
      console.log('支付失败', err)
    }
  })
})
// cloudfunctions/createPayment/index.js - 云函数创建支付订单
const cloud = require('wx-server-sdk')
cloud.init()
const db = cloud.database()

exports.main = async (event, context) => {
  const { order_id, amount } = event
  const res = await cloud.cloudPay.unifiedOrder({
    body: `WEAVELY安装服务-${order_id}`,
    outTradeNo: order_id,
    spbillCreateIp: '127.0.0.1',
    subMchId: '你的子商户号',
    totalFee: Math.round(amount * 100),  // 分
    envId: cloud.DYNAMIC_CURRENT_ENV,
    functionName: 'paymentCallback'  // 支付回调云函数
  })
  
  // 记录支付订单号
  await db.collection('orders').where({ order_id }).update({
    data: { payment_transaction_id: res.payment.outTradeNo }
  })
  
  return { payment: res.payment }
}

🔄 §6 与 MVP-FS 数据互导

数据模型完全一致,字段名 snake_case 直接映射,零成本互导

FS → WX(飞书导入云数据库)

// cloudfunctions/importFromCSV/index.js
// 接收飞书导出的CSV JSON,批量导入
const cloud = require('wx-server-sdk')
cloud.init()
const db = cloud.database()

exports.main = async (event, context) => {
  const { collection, rows } = event
  // collection: 'orders' | 'workers' | ...
  // rows: [{ order_id: '...', current_stage: '...', ... }, ...]
  
  let success = 0, fail = 0
  for (const row of rows) {
    try {
      await db.collection(collection).add({ data: row })
      success++
    } catch (e) { fail++ }
  }
  return { success, fail, total: rows.length }
}

WX → FS(云数据库导出CSV)

// cloudfunctions/exportToCSV/index.js
const cloud = require('wx-server-sdk')
cloud.init()
const db = cloud.database()

exports.main = async (event, context) => {
  const { collection } = event
  const res = await db.collection(collection).limit(1000).get()
  
  // 转CSV
  const headers = Object.keys(res.data[0] || {})
  const csv = [
    headers.join(','),
    ...res.data.map(row => 
      headers.map(h => JSON.stringify(row[h] ?? '')).join(',')
    )
  ].join('\n')
  
  return { csv, count: res.data.length }
}
📋 导出 CSV 后可直接用 scripts/mvp-data-checker.py 校验数据质量,脚本对 FS 和 WX 通用(字段定义一致)。

🚀 §7 上线审核 Checklist(Week 4 D19)

提交微信审核前逐项确认,避免被拒延误上线

7.1 资质与配置

必须

企业认证

  • 小程序已通过企业认证
  • 主体类型:企业/个体工商户
  • 营业执照已上传
必须

服务类目

  • 选择「家政服务」或「上门服务」
  • 类目资质已上传(如有)
  • 服务范围已填写
如需支付

微信支付

  • 已开通微信支付
  • 已绑定商户号
  • 支付回调云函数已部署
必须

隐私合规

  • 隐私协议页面已上线
  • 用户信息收集声明
  • 位置信息授权说明

7.2 功能验证

  1. 模拟 3 单走通 L1→L8

    客户下单 → OL 确认 → 报价 → 支付 → 派单 → 配送 → 师傅打卡拍照 → 验收签字 → NPS

  2. 异常分支验证

    需求超能力转介 / 配送延误 PAUSE / 验收整改回退 L6 / NPS≤6 低分跟进

  3. AI 云函数验证

    需求提炼 / 报价建议 / 师傅推荐 / 周报生成,AI 不可用时降级正常

  4. 支付流程验证

    沙箱环境支付成功 → 回调更新 payment_status → 订单阶段自动流转 L4

  5. 订阅消息验证

    新订单通知 OL / 阶段变更通知客户 / NPS 推送 / 超时预警

7.3 审核注意事项

❌ 常见被拒原因:① 服务类目不匹配 ② 隐私协议缺失 ③ 测试账号未提供 ④ 支付流程不完整 ⑤ 页面空白或功能未完成
💡 建议:审核期间小程序设置为「体验版」,提供测试账号给审核员;首次审核通常 1-3 天,被拒后修改可重新提交。

🤝 §8 协作规范(MVP-WX 特有补充)

通用协作规范见 MVP-FS §4,以下为 WX 特有

场景WX 做法责任人
Bug 反馈小程序 → 截图 → 飞书群 @TL,30min 内响应发现者/TL
云函数部署TL 独占,禁止 OL 直接改云函数TL
数据库变更加字段 TL 确认即可;删字段/改字段需 PO 确认TL/PO
小程序版本发布体验版 → 审核 → 正式版,版本号 V1.0.xTL
AI 提示词调整DT 维护提示词库,版本管理DT/TL
数据备份每周五导出 CSV → 飞书多维表同步(双备份)TL/OL