小程序后端接口补充与联调实施计划

文档日期:2026-07-28
适用范围:mingdaojingjiang_uniapp 游客小程序、backend 统一后端、frontend 管理后台,以及后续导游端接口。
文档目标:按照游客实际使用流程逐步补齐接口,保证小程序、导游端和管理后台使用同一套业务数据、状态机和权限规则。

1. 最终目标

完成后应满足以下结果:

  1. 小程序 pages.json 注册的 20 个业务页面不再依赖订单、用户、评价、反馈和协议 Mock 数据。
  2. 景区、汇合点、服务套餐、价格、客服和协议均由后台配置,后台修改后小程序按业务规则生效。
  3. 报价、订单金额、订单状态、退款状态、导游信息由后端负责计算和维护,小程序不得自行生成正式结果。
  4. 游客下单、微信支付、派单、导游接单、开始讲解、结束讲解、评价、取消和退款形成完整闭环。
  5. 管理后台能够查询和处理小程序产生的游客、订单、评价、反馈、支付与退款数据。
  6. 所有接口使用统一响应结构:{ code, message, data };分页数据使用 { records, total, page, size }。
  7. 每一阶段均具备可重复的后端测试、小程序联调步骤和后台验证路径。

2. 当前系统盘点

2.1 已有架构边界

客户端 接口前缀 Token 类型 权限
管理后台 /api/admin/** ADMIN ROLE_ADMIN
游客小程序 /api/mini/** MINI ROLE_MINI_USER
导游端 /api/guide/** GUIDE ROLE_GUIDE_USER

三端应继续使用独立 Token,不允许小程序 Token 调用后台或导游端接口。

2.2 后端当前已实现能力

领域 当前能力 结论
小程序认证 用户名密码登录、注册、退出 仅适合本地框架验证,不符合当前微信手机号授权页面
小程序资料 查询、修改昵称/手机号/头像 可复用,需要接入真实 Token 和上传能力
小程序评价 提交已完成订单评价 已有核心校验,但缺少评价查询和图片能力
城市管理 后台新增、查询、启停 已有后台能力,缺少小程序只读接口
景区管理 后台景区、四类价格、汇合点、时间参数配置 已有后台能力,缺少小程序只读接口
订单管理 后台列表、详情、直接退款 只有后台查询和模拟退款,缺少下单及真实状态流转
导游管理 档案、审核、讲解队、景区配置、启停 已有管理能力,缺少在线、位置、接单和服务接口
评价管理 后台查询、删除 已有闭环基础
反馈管理 后台查询、处理 缺少游客提交接口
协议管理 后台查询、编辑 缺少小程序读取接口
平台设置 自动退款时间、派单门槛、客服、结算等 配置已存在,但尚未驱动订单任务和小程序展示

2.3 小程序当前硬编码点

  • constants/scenics.js:景区 Mock。
  • constants/meeting-points.js:汇合点 Mock。
  • constants/services.js:服务套餐和价格 Mock。
  • pages/home/index.vue:当前订单、报价、下单和支付均为前端模拟。
  • pages/order-waiting/index.vue:固定等待约 5 秒后进入待讲解页,并非后端接单结果。
  • pages/orders/index.vue:订单列表为 Mock。
  • 各订单详情页:订单、导游、家庭号、时间和状态均为 Mock。
  • pages/profile/index.vue:资料只保存在本地缓存。
  • pages/feedback/index.vue:提交成功由 setTimeout 模拟。
  • pages/agreement-detail/index.vue:协议内容未读取后台配置。
  • pages/customer-service/index.vue:客服信息未读取平台设置。
  • utils/request.js:未统一附加小程序 Token,也未集中处理 401 登录失效。
  • services/city.js 和 services/scenic.js 当前请求 /api/cities、/api/scenics,与项目 /api/mini/** 的安全边界不一致。

2.4 必须优先解决的领域冲突

服务类型编码不一致

当前存在三套命名:

业务含义 景区价格配置 订单/后台 小程序 Mock
拼团快讲 GROUP_FAST GROUP_QUICK group_quick
拼团精讲 GROUP_PREMIUM GROUP_PREMIUM group_deep
包团快讲 PRIVATE_FAST PRIVATE_QUICK private_quick
包团精讲 PRIVATE_PREMIUM PRIVATE_PREMIUM private_deep

统一后的后端领域编码固定为:

GROUP_QUICK
GROUP_PREMIUM
PRIVATE_QUICK
PRIVATE_PREMIUM

小程序可以保留展示文案,但提交接口时必须使用后端领域编码。历史 operation_scenic_pricing.service_type 中的 GROUP_FAST、PRIVATE_FAST 需要迁移为统一值。

3. 统一业务原则

3.1 单一业务事实来源

  • 城市、景区、汇合点、价格和可售状态以运营后台配置为准。
  • 订单金额以服务端报价和创建订单时的二次计算为准。
  • 订单状态只能由后端领域服务流转,小程序、导游端和后台 Controller 不直接拼装状态。
  • 订单保存景区、汇合点、套餐、游客和导游快照,避免后台配置变化后历史订单内容变化。
  • 评价只能关联本人已完成且未评价的订单。
  • 后台退款、用户取消触发退款、接单超时退款必须调用同一个退款领域服务。

3.2 公共查询与登录权限

游客在未登录时允许浏览城市、景区、套餐、汇合点、协议和客服信息;下单、订单、资料、反馈和评价必须登录。

建议在 SecurityConfig 中只放行:

POST /api/mini/auth/wechat-phone-login
GET  /api/mini/catalog/**
GET  /api/mini/content/**
POST /api/mini/payments/wechat/notify

支付回调必须进行微信签名校验,不能因为免登录而跳过安全验证。

3.3 幂等与并发

  • 创建订单要求 clientRequestId,同一游客重复提交返回同一订单。
  • 微信支付回调、退款回调、导游接单、开始讲解、结束讲解必须幂等。
  • 订单表增加乐观锁版本或使用带当前状态条件的更新语句,避免两名导游同时接单。
  • 后端状态冲突统一返回 409,前端收到后重新拉取订单详情。

4. 统一订单状态机

4.1 主状态

后端状态 小程序页面 后台显示 允许操作
PENDING_PAYMENT 待支付 待支付 用户支付、用户取消、超时关闭
PENDING_ACCEPT 等待接单 待接单 导游接单/拒单、用户取消、超时退款、后台指派
PENDING_MEETING 待讲解 待前往汇合点 导游到达、开始讲解、用户申请取消、后台改派
IN_SERVICE 讲解中 服务中 导游结束讲解;取消仅允许后台按售后规则处理
COMPLETED 待评价或已完成 已完成 用户评价、后台退款
CANCELLED 已取消 已取消 查看取消原因;已支付订单继续关注退款状态
REFUNDED 已取消/已退款 已退款 只读

4.2 评价状态

不新增 PENDING_REVIEW 订单主状态。订单 COMPLETED 后通过是否存在 tour_order_review 判断:

  • hasReview=false:进入小程序待评价页。
  • hasReview=true:进入已完成页和评价详情页。

这样后台订单、财务和评价统计不会因为评价动作改变服务完成状态。

4.3 支付与退款状态

订单主状态不能替代支付流水状态,建议独立维护:

paymentStatus: UNPAID | PAYING | PAID | CLOSED | FAILED
refundStatus: NONE | REFUNDING | REFUNDED | REFUND_FAILED

当前只有 refundStatus=NONE/REFUNDED,接入真实微信退款前必须扩展。

5. 小程序完整业务流程

启动小程序
  -> 加载城市、景区、汇合点、套餐和客服/协议配置
  -> 游客选择景区、汇合点、套餐和人数
  -> 后端报价
  -> 未登录则微信手机号授权登录
  -> 创建待支付订单
  -> 微信支付预下单
  -> wx.requestPayment
  -> 微信支付回调确认成功
  -> 订单进入待接单
  -> 派单服务选择候选导游
  -> 导游接单
  -> 订单进入待讲解
  -> 导游到达并开始讲解
  -> 订单进入讲解中
  -> 导游结束讲解
  -> 订单进入已完成
  -> 游客评价
  -> 后台查看订单、评价和结算数据

取消分支:

待支付取消 -> 关闭订单,不退款
待接单取消/超时 -> 取消订单,已支付则发起退款
待讲解取消 -> 按业务规则退款并记录取消方、原因
讲解中取消 -> 不允许游客直接取消,进入后台售后处理
后台退款 -> 与用户取消共用退款服务和退款流水

6. 分阶段实施步骤

步骤 0:冻结接口契约和领域枚举

实施状态(2026-07-28):已完成。代码、数据库迁移和三端构建验证均已通过。

已落地内容:

  • 后端新增 ServiceType、OrderStatus、PaymentStatus、RefundStatus、CancelParty、CancelReasonCode。
  • 景区价格服务改用统一服务类型,不再写入 GROUP_FAST、PRIVATE_FAST。
  • 订单退款和评价状态判断改用后端领域枚举。
  • 管理后台集中维护订单类型、订单状态、状态样式、状态顺序和可退款状态。
  • 小程序四类套餐使用 GROUP_QUICK、GROUP_PREMIUM、PRIVATE_QUICK、PRIVATE_PREMIUM。
  • 新增迁移脚本 backend/db/migrations/20260728_180000_unify_domain_enums.sql,用于迁移景区价格和历史订单旧编码。
  • 已执行 mvn test、管理后台 npm run build、小程序 npm run build:mp-weixin,均通过。
  • 已在本地 tour_guide 数据库执行迁移,版本 20260728_180000_UNIFY_DOMAIN_ENUMS 已登记;景区价格和订单旧编码残留数量均为 0。

目的: 先消除服务类型、订单状态、支付状态和取消原因的多套命名,避免前后端各自转换后继续产生脏数据。

操作:

  1. 在后端新增统一常量或枚举:ServiceType、OrderStatus、PaymentStatus、RefundStatus、CancelParty、CancelReasonCode。
  2. 将景区价格配置的 GROUP_FAST、PRIVATE_FAST 迁移为 GROUP_QUICK、PRIVATE_QUICK。
  3. 小程序 constants/services.js 改为使用统一领域编码,不再使用 group_deep、private_deep 作为接口值。
  4. 管理后台 orderOptions.js 与后端枚举保持一致。
  5. 建立接口错误码表,至少包含参数错误、未登录、无权限、资源不存在、状态冲突、重复请求、支付失败和退款失败。

影响范围: 景区价格表、订单表、后台景区配置、后台订单筛选、小程序套餐选择和后续所有订单接口。

验证:

  • 查询 operation_scenic_pricing,只能出现四个统一服务类型。
  • 后台保存景区价格后重新打开详情,四类价格正确回显。
  • 小程序提交的服务类型可直接用于查询价格,不需要字符串猜测或多分支兼容。

注意: 数据迁移必须先备份;过渡期后端可临时读取旧值,但写入必须只写新值,兼容代码在数据迁移完成后删除。

步骤 1:完善小程序请求层和环境配置

目的: 后续页面只调用 services/,统一处理地址、Token、响应解包、错误提示和登录失效。

操作:

  1. 将 config/api.js 拆分为开发、测试、生产环境配置,真机不能使用 127.0.0.1。
  2. 在 utils/request.js 自动读取 mini_token 并附加 Authorization: Bearer <token>。
  3. 401 时清理 Token 和用户缓存,并跳转登录页,同时保留原目标页面地址。
  4. 409 状态冲突不直接显示通用错误,订单页面应重新加载最新状态。
  5. 新增 services/auth.js、services/order.js、services/profile.js、services/content.js、services/feedback.js。
  6. 页面中不新增直接 uni.request 调用。

影响范围: 小程序所有接口请求、登录守卫、错误提示和环境切换。

验证:

  • 无 Token 调用受保护接口返回 401,小程序跳转登录页。
  • Token 过期后不会出现多个重复 Toast 和循环跳转。
  • 开发环境、真机测试环境可通过配置切换,不修改业务页面。

注意: 本地开发可关闭微信域名校验,但测试版和正式版必须配置 HTTPS 合法域名。

步骤 2:接入微信手机号授权登录

实施状态(2026-07-29):代码、本地 HTTP 启动验证、后端自动化测试和小程序微信构建均已通过;需要在微信开发者工具或真机使用一次性授权码完成最终微信侧联调。

已落地内容:

  • 新增 POST /api/mini/auth/wechat-phone-login,接收 loginCode 和 phoneCode。
  • 后端调用微信登录凭证校验、AccessToken 和手机号获取接口,并在 Redis 缓存 AccessToken。
  • 首次微信授权按 openid 创建游客,再次授权复用同一游客并同步手机号。
  • 后端签发 clientType=MINI 的 JWT,并写入 Redis 会话。
  • 小程序登录页保留现有 UI,已移除 Mock Token,改为真实 uni.login + getPhoneNumber 调用。
  • 小程序请求层已自动携带 Authorization: Bearer <token>。
  • AppID 和 AppSecret 仅从 WECHAT_APPID、WECHAT_APP_SECRET 环境变量读取。
  • 已执行后端 mvn test,共 6 项测试通过;已执行小程序 npm run build:mp-weixin,构建通过。
  • 已修复后端自定义 Mapper 扫描遗漏,打包后的服务可正常启动,GET /api/health 返回 UP。
  • 已验证未登录调用 POST /api/mini/auth/wechat-phone-login 不会被安全层拦截,空请求按业务校验返回 400。

目的: 让当前登录页的 getPhoneNumber 授权结果换取真实小程序用户和 MINI Token。

操作:

  1. 新增 POST /api/mini/auth/wechat-phone-login。
  2. 小程序先调用 uni.login 获取 loginCode,再将 loginCode 和 getPhoneNumber 返回的 phoneCode 提交后端。
  3. 后端调用微信接口获取 openid 和手机号,以 mini_user.openid 查找或创建用户。
  4. 首次登录创建默认昵称;已有用户更新绑定手机号和最后登录时间。
  5. 签发 clientType=MINI 的 JWT,并写入 Redis 会话。
  6. 保留用户名密码登录仅用于明确的本地测试,不在正式小程序界面暴露。

建议请求:

{
  "loginCode": "wx.login返回值",
  "phoneCode": "getPhoneNumber返回值",
  "agreementCodes": ["USER_AGREEMENT", "PRIVACY_POLICY"]
}

影响范围: MiniAuthController、AuthService、微信配置、mini_user、小程序登录页、后台游客列表。

验证:

  • 首次授权创建一名游客,后台游客列表可以查询。
  • 同一微信再次登录返回同一 mini_user.id,不会重复创建账号。
  • 后台停用游客后,旧 Token 不能继续访问受保护接口。
  • 小程序 Token 无法调用 /api/admin/** 和 /api/guide/**。

注意: 微信密钥只能放在后端环境变量;不得将 session_key、AppSecret 或完整身份证信息返回小程序。

步骤 3:接入城市、景区、汇合点和套餐

目的: 让首页和景区选择页完全由后台运营配置驱动。

操作:

新增只读接口:

GET /api/mini/catalog/cities
GET /api/mini/catalog/scenics?cityId=&keyword=
GET /api/mini/catalog/scenics/{scenicId}
GET /api/mini/catalog/scenics/{scenicId}/meeting-points
GET /api/mini/catalog/scenics/{scenicId}/services
GET /api/mini/catalog/scenics/nearest?longitude=&latitude=

查询规则:

  • 只返回 operation_city.status=1 且未删除的城市。
  • 只返回所属城市启用、景区启用且未删除的景区。
  • 汇合点只返回 status=1,按 sort_order 和 id 排序。
  • 服务套餐只返回四类完整且价格有效的配置。
  • 返回 firstOrderLeadMinutes、visitorNoOrderMinutes、unpaidCancelMinutes,但是否可下单仍由报价接口实时判断。
  • 附近导游数量不能使用固定 Mock;未完成导游位置能力前明确返回 availableGuideCount=null,前端隐藏该文案。

影响范围: 后端运营服务、小程序首页、景区选择页、后台城市和景区管理。

验证:

  • 后台禁用城市后,该城市及其景区不再出现在小程序。
  • 后台修改套餐价格后,小程序重新请求即可看到新价格。
  • 后台禁用汇合点后,首页地图不再展示该点。
  • 接口失败时可以保留“开发环境 Mock 兜底”,测试和生产环境必须关闭兜底并显示可恢复的错误状态。

注意: 小程序当前接口地址 /api/cities、/api/scenics 必须统一改为 /api/mini/catalog/**。

步骤 4:接入协议和客服配置

目的: 登录协议、服务协议和客服页面与后台配置保持一致。

操作:

新增接口:

GET /api/mini/content/agreements
GET /api/mini/content/agreements/{code}
GET /api/mini/content/customer-service

协议接口复用 AgreementSettingService,客服接口复用 PlatformSettingsService;Controller 只负责鉴权边界和响应转换。

影响范围: 登录页、协议列表、协议详情、联系客服页、后台协议设置和平台设置。

验证:

  • 后台修改协议内容后,小程序协议详情显示最新内容和更新时间。
  • 后台修改客服电话、客服微信后,小程序重新进入页面显示新配置。
  • 登录页勾选的协议编码能够随登录请求提交并记录。

注意: 后续如需强制重新同意,应为协议增加版本号和生效时间,不能只依赖 updatedAt。

步骤 5:实现服务端报价

目的: 防止小程序自行计算价格,并在下单前集中校验景区、汇合点、套餐、人数和运营时间。

操作:

新增:

POST /api/mini/orders/quote

请求至少包含:

{
  "scenicId": 1,
  "meetingPointId": 10,
  "serviceType": "GROUP_QUICK",
  "peopleCount": 2
}

后端校验:

  • 城市、景区、汇合点、价格配置均启用。
  • 汇合点属于所选景区。
  • 拼团人数位于 minParticipants 与 maxParticipants 范围内。
  • 包团价格按团计算,拼团价格按人数计算。
  • 根据景区时间参数判断当前是否允许下单。
  • 原价、优惠价、小计、优惠金额和最终金额统一使用 BigDecimal。

影响范围: 景区价格配置、首页服务选择和确认订单弹窗。

验证:

  • 修改后台价格后,新报价使用新价格,历史订单不变化。
  • 篡改前端金额不影响后端报价。
  • 无效人数、禁用景区、跨景区汇合点返回明确业务错误。

注意: 创建订单时必须再次计算并校验,报价响应不能作为后端直接信任的最终金额。

步骤 6:实现订单创建、列表、详情和当前订单

目的: 让首页和全部订单页面由真实订单驱动,并为支付、派单和评价提供主数据。

操作:

新增接口:

POST /api/mini/orders
GET  /api/mini/orders?page=&size=&status=
GET  /api/mini/orders/current
GET  /api/mini/orders/{orderId}

创建订单要求:

  • 从登录用户获取 visitorId,不接受前端传游客 ID。
  • 保存景区 ID、汇合点 ID、服务类型及名称/价格快照。
  • 生成全局唯一订单号和家庭号。
  • 初始状态为 PENDING_PAYMENT,支付状态为 UNPAID。
  • 使用 clientRequestId 防止按钮连点产生重复订单。
  • 记录订单状态日志。

列表状态映射:

pendingPay     -> PENDING_PAYMENT
waiting        -> PENDING_ACCEPT
pendingGuide   -> PENDING_MEETING
serving        -> IN_SERVICE
pendingReview  -> COMPLETED + hasReview=false
completed      -> COMPLETED + hasReview=true
canceled       -> CANCELLED 或 REFUNDED

影响范围: tour_order、订单状态日志、小程序首页当前订单、订单列表和七类订单详情页、后台订单列表与详情。

验证:

  • 小程序创建订单后,后台订单列表立即可见。
  • 游客只能查看本人订单,修改 URL 中 orderId 不能读取他人订单。
  • 重复提交同一 clientRequestId 只产生一条订单。
  • 后台订单详情与小程序订单详情的金额、景区、汇合点和状态一致。

注意: 当前订单表主要保存名称快照,需要增加 scenic_spot_id、meeting_point_id、service_type、payment_status、client_request_id、取消信息和乐观锁字段。

步骤 7:接入微信支付

目的: 替换首页 setTimeout 模拟支付,确保支付结果由微信回调确认。

操作:

新增接口:

POST /api/mini/orders/{orderId}/payment/prepay
POST /api/mini/payments/wechat/notify
GET  /api/mini/orders/{orderId}/payment-status

支付流程:

  1. 小程序请求预支付参数。
  2. 后端再次校验订单属于当前用户且状态为 PENDING_PAYMENT。
  3. 小程序调用 uni.requestPayment。
  4. 前端支付成功只表示客户端流程完成,仍需轮询支付状态。
  5. 后端验证微信回调签名和金额后,将支付状态改为 PAID、订单状态改为 PENDING_ACCEPT。
  6. 写入支付流水和订单状态日志,再触发派单。

影响范围: 小程序确认支付、订单支付状态、后端微信配置、支付流水、后台订单详情和财务数据。

验证:

  • 正常支付后订单进入待接单,后台显示支付流水和支付时间。
  • 重复支付回调不会重复修改订单或重复派单。
  • 回调金额与订单金额不一致时拒绝更新订单并记录异常。
  • 用户关闭支付弹窗后仍停留在待支付状态,可重新发起支付。

注意: 开发环境如需模拟支付,必须由后端测试配置显式开启,不能由小程序直接把订单改成已支付。

步骤 8:实现派单和导游接单

目的: 让等待接单页由真实导游操作驱动,并与后台导游、讲解队和平台派单配置一致。

操作:

后端新增领域能力:

  • 导游在线状态与当前位置。
  • 导游可服务景区和讲解队景区配置匹配。
  • 派单候选记录、推送顺序、接单、拒单、超时和改派记录。
  • 同一订单只能被一名导游成功接单。

导游端接口建议:

PUT  /api/guide/runtime/status
POST /api/guide/runtime/location
GET  /api/guide/orders/pending
POST /api/guide/orders/{orderId}/accept
POST /api/guide/orders/{orderId}/reject
GET  /api/guide/orders

后台接口建议:

GET  /api/admin/orders/{orderId}/dispatch-records
POST /api/admin/orders/{orderId}/assign
POST /api/admin/orders/{orderId}/reassign

派单规则读取后台平台设置,优先级按当前后台文案:评分、接单数、注册先后;具体是否使用距离必须在启用位置上报后统一决定。

影响范围: 导游运行状态、导游景区配置、订单、派单记录、小程序等待接单页、后台订单详情和导游端。

验证:

  • 非启用导游、非服务景区导游、离线导游不能接到订单。
  • 两名导游同时接单只有一人成功,另一人收到 409。
  • 导游接单后订单进入 PENDING_MEETING,小程序轮询后自动进入待讲解页。
  • 后台可以看到候选导游、拒单原因、接单导游和时间。

注意: 小程序 pages/order-waiting/index.vue 的固定 5 秒跳转必须删除;第一阶段可每 2 至 3 秒轮询订单详情,后续再接 WebSocket 或订阅消息。

步骤 9:实现取消、超时关闭和退款

目的: 将小程序取消弹窗、后台退款和平台自动退款统一到真实退款闭环。

操作:

新增接口:

POST /api/mini/orders/{orderId}/cancel
GET  /api/mini/orders/{orderId}/refund-status
POST /api/mini/refunds/wechat/notify

后台现有 PUT /api/admin/orders/{id}/refund 改为调用统一退款服务,不再直接写 REFUNDED。

取消规则:

  • PENDING_PAYMENT:订单改为 CANCELLED,关闭支付单,不发起退款。
  • PENDING_ACCEPT:订单改为 CANCELLED,已支付则创建退款流水。
  • PENDING_MEETING:按后台配置和取消原因决定全额或人工处理。
  • IN_SERVICE:游客端禁止直接取消,提示联系客服。
  • 自动任务扫描超时未支付订单和超时未接单订单。

影响范围: 订单、退款流水、定时任务、小程序取消弹窗、等待接单页、已取消页、后台订单和财务页面。

验证:

  • 未支付取消不会生成退款流水。
  • 已支付取消只发起一次退款,回调后显示退款完成。
  • 后台退款和用户取消生成相同结构的退款记录。
  • 平台修改“未接单自动退款时间”后,定时任务按新配置执行。

注意: 退款请求成功不等于退款完成,必须区分 REFUNDING 和 REFUNDED;退款失败需要后台可重试和查看原因。

步骤 10:实现到达、开始讲解和结束讲解

目的: 让待讲解、讲解中和已完成页面由导游服务动作驱动。

操作:

导游端新增:

POST /api/guide/orders/{orderId}/arrive
POST /api/guide/orders/{orderId}/start
POST /api/guide/orders/{orderId}/complete

状态规则:

  • 只有接单导游可以操作本人订单。
  • arrive 记录 arrivedAt,不改变主状态。
  • start 仅允许从 PENDING_MEETING 进入 IN_SERVICE。
  • complete 仅允许从 IN_SERVICE 进入 COMPLETED。
  • 每次状态变化写入状态日志。

影响范围: 导游端、订单详情、小程序待讲解/讲解中/待评价页面、后台订单时间线。

验证:

  • 非接单导游不能开始或结束讲解。
  • 导游开始讲解后,小程序刷新进入讲解中页面。
  • 导游结束讲解后,小程序进入待评价状态,后台记录完整时间线。

注意: 开始讲解是否要求导游在汇合点围栏内,应在定位精度和现场流程确认后实现;未确认前不要用前端坐标直接阻断业务。

步骤 11:接入评价

目的: 复用现有评价服务,完成游客评价、导游评分和后台评价管理闭环。

操作:

保留并完善:

POST /api/mini/reviews
GET  /api/mini/orders/{orderId}/review

小程序提交 orderId、score、content;后端继续校验本人订单、订单已完成、已关联导游且未评价。提交成功后重新查询订单详情,不由前端自行改状态。

影响范围: 待评价页、已完成页、评价详情页、导游评分、后台评价列表。

验证:

  • 同一订单只能评价一次。
  • 他人订单、未完成订单不能评价。
  • 评价后导游评分和后台评价列表同步更新。
  • 后台隐藏或删除评价不删除订单。

注意: 当前表只支持文字;如产品确认评价图片,需要独立附件表或 JSON 字段,并接入统一文件上传,不要把 Base64 直接存数据库。

步骤 12:接入个人资料、反馈和退出登录

实施状态(2026-07-29):个人资料、退出登录和账号注销已完成;反馈提交仍待后续接入。

个人资料已落地内容:

  • GET /api/mini/profile 回显当前登录用户手机号、昵称、头像、真实姓名和实名状态。
  • PUT /api/mini/profile 修改昵称,手机号仍以微信授权绑定结果为准,不允许在资料页任意修改。
  • POST /api/mini/profile/avatar 上传 JPG、PNG 或 WebP 头像,单文件不超过 5MB。
  • PUT /api/mini/profile/real-name 填写真实姓名;当前业务规则下真实姓名非空即视为已实名。
  • “我的”、个人资料和实名认证页面已移除手机号、昵称、头像及实名状态的本地 Mock。
  • 数据库迁移 20260729_110000_ADD_MINI_USER_REAL_NAME 已执行并登记。
  • 设置页退出登录已调用后端接口,成功后清理本地 Token 并返回首页。
  • 账号注销会先检查未完成订单,再匿名化个人信息、逻辑删除账号并失效当前 Redis 会话。
  • 数据库迁移 20260729_120000_ENABLE_GLOBAL_LOGIC_DELETE 已执行;除迁移元数据表外全部业务表均具备 deleted 标识。

目的: 清理个人中心剩余本地模拟数据,并使后台游客和反馈管理接收到真实数据。

操作:

使用或新增:

GET  /api/mini/profile
PUT  /api/mini/profile
POST /api/mini/profile/avatar
PUT  /api/mini/profile/real-name
POST /api/mini/feedback
POST /api/mini/auth/logout
DELETE /api/mini/auth/account

反馈接口从当前用户获取 userId、昵称和手机号,固定 feedbackType=VISITOR;后端新增创建方法,后台继续使用现有查询和处理接口。

影响范围: 我的页面、个人资料、反馈、设置、后台游客详情和反馈管理。

验证:

  • 修改昵称后重新登录仍能读取,后台游客详情同步显示。
  • 上传头像后“我的”和个人资料页能够回显持久化头像。
  • 填写真实姓名后接口返回 realNameVerified=true,返回个人资料页显示“已实名”。
  • 提交反馈后后台反馈列表立即可查并可处理。
  • 退出登录后 Redis 会话删除,旧 Token 失效。
  • 存在待付款、待接单、待讲解或服务中订单时,账号注销返回业务冲突。
  • 无未完成订单时,账号个人信息被匿名化且 deleted=1,历史订单仍保留。

注意: 当前头像文件保存到后端 AVATAR_STORAGE_DIR 配置目录,适合单机开发和测试;生产环境多实例部署时应切换到对象存储或统一文件服务。

步骤 13:全流程联调和发布门禁

目的: 在关闭 Mock 前验证游客、导游、后台和微信回调共同组成的完整链路。

操作:

准备固定测试数据:

  • 1 个启用城市和 1 个禁用城市。
  • 2 个景区,其中 1 个启用、1 个禁用。
  • 启用景区配置 4 类套餐和至少 2 个汇合点。
  • 2 名可服务该景区的导游和 1 名不可服务该景区的导游。
  • 1 个后台管理员、1 个游客微信账号。

执行场景:

  1. 未登录浏览并切换景区。
  2. 微信手机号授权登录。
  3. 拼团和包团分别报价。
  4. 创建订单并验证重复提交幂等。
  5. 支付成功、支付取消、支付回调重复。
  6. 导游接单竞争、拒单、超时自动退款。
  7. 到达、开始讲解、结束讲解。
  8. 用户取消、后台退款、退款回调失败与重试。
  9. 评价成功和重复评价。
  10. 提交反馈并由后台处理。
  11. 后台禁用景区、导游或游客后验证各端行为。

影响范围: 全系统。

验证: 后端单元/集成测试、小程序开发者工具、真机支付沙箱、导游端测试入口、后台页面和数据库状态日志全部一致。

注意: 只有当测试和生产配置明确关闭前端订单 Mock、模拟支付和固定 5 秒接单后,才能认为联调完成。

7. 小程序页面与接口映射

小程序页面 接口
pages/home/index 城市/景区/汇合点/套餐、当前订单、报价、创建订单、预支付
pages/login/index 微信手机号登录、协议列表/详情
pages/scenic-select/index 城市、景区、附近景区
pages/mine/index 个人资料摘要、订单数量
pages/profile/index 查询和修改个人资料、头像上传
pages/real-name/index 暂不开放;产品确认实名认证方案后单独设计
pages/orders/index 本人订单分页和状态筛选
pages/order-pending-pay/index 订单详情、预支付、取消
pages/order-waiting/index 订单详情轮询、取消、退款状态
pages/order-pending-guide/index 订单详情、导游信息、取消规则
pages/order-serving/index 订单详情、讲解状态
pages/order-pending-review/index 订单详情、提交评价
pages/order-completed/index 订单详情、评价摘要
pages/order-canceled/index 订单详情、取消和退款状态
pages/order-review-detail/index 订单评价详情
pages/agreement-list/index 协议列表
pages/agreement-detail/index 协议详情
pages/settings/index 退出登录;注销账号需另行确认规则
pages/customer-service/index 客服微信和电话
pages/feedback/index 提交游客反馈

8. 后台逻辑一致性要求

8.1 城市和景区

  • 后台启停是小程序可见性和可售性的唯一控制入口。
  • 已有订单引用的景区和汇合点不能物理删除,只能停用或逻辑删除。
  • 价格变更只影响新报价和新订单,历史订单使用快照。

8.2 游客

  • 微信首次登录自动进入后台游客列表。
  • 后台停用游客后,Redis 中已有会话应主动删除或在鉴权时立即拒绝。
  • 后台游客详情中的订单数量不能固定返回 0,应从订单表统计。

8.3 导游和派单

  • 只有启用、审核通过且服务景区匹配的导游可以进入候选池。
  • 讲解队和个人导游的景区配置都应转换为统一查询模型,避免派单服务分别写两套判断。
  • 后台改派必须记录原导游、新导游、操作人、原因和时间。

8.4 订单、支付和退款

  • 后台不能跳过状态机直接修改订单状态。
  • 后台退款与自动退款共用支付渠道退款服务。
  • 后台订单详情必须展示状态日志、支付流水、退款流水、派单记录和关键快照。
  • 财务页面读取流水数据,不从订单状态推算真实到账和退款结果。

8.5 评价和反馈

  • 评价删除/隐藏属于运营动作,不回滚订单完成状态。
  • 反馈处理记录后台处理人和处理时间,小程序第一阶段只需提交,不要求展示处理进度。

9. 建议新增或调整的数据结构

按迁移脚本分批执行,不直接修改已部署数据库:

  1. operation_scenic_pricing:统一服务类型历史值。
  2. tour_order:增加景区 ID、汇合点 ID、服务类型、支付状态、幂等请求号、取消方、取消原因、取消时间和版本号。
  3. tour_order_status_log:记录状态变化前后值、操作者类型、操作者 ID、原因和时间。
  4. payment_transaction:记录微信支付单、预支付 ID、金额、状态、回调报文摘要和时间。
  5. refund_transaction:记录退款单、退款原因、金额、状态、回调和重试信息。
  6. order_dispatch_record:记录候选导游、推送顺序、接单、拒单、超时和改派。
  7. guide_runtime_state:记录导游在线状态、忙碌状态、经纬度和最后上报时间。
  8. mini_user:保留现有 openid,按微信登录需要补充 unionid、最后登录时间;不持久化可直接换取的短期敏感凭据。

10. 每阶段完成定义

一个步骤只有同时满足以下条件才算完成:

  1. 后端接口具备参数校验、权限校验、状态校验和统一错误响应。
  2. 对应后端服务有单元测试或集成测试,至少覆盖成功、无权限、状态冲突和幂等分支。
  3. 小程序页面已移除对应 Mock 和 setTimeout 模拟业务结果。
  4. 后台能够查看或配置该步骤产生的数据,并验证配置对小程序生效。
  5. 数据库迁移脚本可追踪、可验证,不直接依赖手工改表。
  6. 文档记录实际接口字段、测试账号、联调结果和未解决问题。

11. 推荐实施顺序

严格按以下顺序推进,前一步未通过验收时不进入依赖它的下一步:

领域枚举统一
  -> 请求层和环境
  -> 微信登录
  -> 城市/景区/汇合点/套餐
  -> 协议和客服
  -> 报价
  -> 订单创建/查询
  -> 微信支付
  -> 派单/导游接单
  -> 取消/退款
  -> 开始/结束讲解
  -> 评价
  -> 资料/反馈/退出
  -> 全流程联调

第一轮建议只实施到“城市/景区/汇合点/套餐”,先验证后台运营配置能够稳定驱动小程序;第二轮完成报价、订单和支付;第三轮完成派单、导游服务、取消退款与评价闭环。