杭州灵隐寺小程序 · 预约门票流程逆向分析
对象:
wx8e29145b9c569926(乐程商城 SaaS 版小程序,商户 22190,生产环境)说明:
wx4d2deeab3aed6e5a仅为企微“联系我”插件(contactPlugin 1.0.8),与预约流程无关。
1. 总体架构
- 技术栈:uni-app (Vue2) + webpack 打包,主包
app-service.js+ 分包pages/member/*。 - 关键结论:
pages/scenic/*(门票列表/详情/下单页)未打进小程序包。门票浏览 → 预约 → 提交订单均在 H5 webview 内完成(/pages/webView/index?src=<encodeURIComponent(URL)>),小程序只承担:登录/会话、支付、订单查询与取消、游玩人管理入口。 - 门票预约 H5 入口 URL(首页点击门票时构造,
app-service.js约 986397 行):
/vue/order/ticket?merchantInfoId=22190&scenicId=<merchantParkInfoId>&ticketId=<merchantParkTicketId>
- 首页点击逻辑:先请求商品详情,若商品支持买(
buyFlag/addActivityFlag/buyNewFlag/pageType)→ 跳/vue/souvenir/*,否则跳上述/vue/order/ticket。 - 订单详情 H5:
/vue/order/detail?id=<orderId>&m_id=22190&needLogin=1(host = WAP_HOST);支付结果页:/vue/pay/result?payOrderNo=...&m_id=22190&needLogin=1。
2. 环境常量(模块 9cbb,生产 prod)
| 常量 | 值 |
|---|---|
| HOST | https://www.lotsmall.cn |
| WAP_HOST | https://wap.lotsmall.cn(H5 页面 + dubbo 接口) |
| SAAS_NK_WAP_HOST | https://nkwap.lotsmall.cn |
| PUB_WAP_HOST / HOST_PUB | https://pubswap.zhiyoubao.com / https://pubs.zhiyoubao.com |
| CDR_HOST | https://cdr.lotsmall.cn |
| MERCHANT_INFO_ID | 22190(dev=14152,支付宝小程序 prod=1001) |
| PARKSZLY | 226 |
| X_GRC | 生产为空(仅 dev 为 xxxxxxxx,且仅 dev 会带 x-grc 头) |
merchantInfoId 也可被 wx.getExtConfigSync().merchantInfoId 覆盖(ff51 模块)。
3. 登录与会话(模块 e9cb / 74fc)
wx.login()拿 code → POST/up/api/login(74fc.wxMiniLogin),业务参数{code, merchantInfoId, ...},追加loginFlag: "F", useTemplate: "F"。- 响应
data含leaguerId / accessToken / accountId等。 - Cookie 写入(模块
ee16):cookie.login(leaguerId)、cookie.bind("user_key", leaguerId)→ 后续所有请求头Cookie: user_key=<leaguerId>(模块6dc7统一拼接)。 - GET
/up/api/account?token=<accessToken>→ 取{account, nickName},组装并缓存WxXjscUserInfo = {leaguerId: accountId, token: accessToken, realName, accountId, openId, openid}。 - 本地缓存:
WxXjscUserInfo、xjsc_merchantInfoId、merchantChannelCode、xjsc_2018_order_url_asds(登录后回跳)。 - 未登录跳
/pages/authorization/index?redirectUrl=...;需手机号跳/pages/authorization/getPhone。
4. 请求封装与加密(模块 ff51 → 1f75)
4.1 统一请求入口 ff51.H()
每次请求前自动增强请求体并强制签名:
Y = { merchantInfoId: 22190, ...body, merchantId: 22190 }
Y.channelType = "wxPayMini"
// 仅 "/up/api/aLiPay/applet/decryptData" 会 delete Y.merchantInfoId
J = setSign(Y, jsonFlag) // 签名覆盖增强后的完整 body
请求头(1f75.request 最终以 HOST + path 发起):
access-token: <WxXjscUserInfo.token 或 body.token>
content-type: application/json | application/x-www-form-urlencoded
sk: RSA 加密后的随机串(encodeURIComponent 后)
sign: SHA-256 双重哈希
sessionId / traceId / browserId: 埋点模块(vuex point)注入
Cookie: user_key=<leaguerId>
merLang: 语言(默认 "CN")
状态码处理:200 → 返回 data;400 / Unauthorized(code=1005003041) → 重新登录后重试一次;410 → 跳授权页;429 → 限流弹窗;402 → 弹后端 message。
4.2 签名算法(模块 847d/30e2,两者内容相同)★
setSign(body, jsonFlag) {
const random15 = this.random(15); // ①
const str = this.signInitData(body, jsonFlag); // ②
const sign = this.signData(str, random15); // ③
const sk = this.setRSA(random15); // ④
return { sk, sign };
}
random(15): // ① 大写字母+数字的随机 15 位串
for (var e = ""; e.length < 15; e += Math.random().toString(36).substr(2).toUpperCase());
return e.substr(0, 15);
signInitData(body, jsonFlag): // ② 序列化
if (jsonFlag) return JSON.stringify(sortObjectKeys(body)); // f727 稳定按键名升序排序
else return Object.keys(body).sort()
.filter(k => typeof body[k] === "boolean" || body[k] || body[k] === 0)
.map(k => k + "=" + body[k]).join("&");
signData(str, random15): // ③ 双重 SHA-256(hex 小写),模块 6eed = sha256
return sha256_hex(sha256_hex(str) + random15);
setRSA(random15): // ④ RSA 公钥加密(PKCS1 v1.5,jsencrypt 系模块 df3a)
return encodeURIComponent(rsaEncrypt(pubsKey, random15));
验证方式:服务器用私钥解 sk 得 random15,再按相同规则重算 sign 比对。公钥/私钥均内嵌在前端包中(完整文本见 6.5)。
解密场景:GET /leaguer/api/userLeaguer/manage/leaguerInfo?cipherText=2 返回的 realName/mobile/idcard/linkmanName/linkmanMobile/linkmanCertNo 均为 RSA 密文,前端用内嵌私钥 getRSA()(先 decodeURIComponent 再解密)还原。
4.3 白名单说明(修正)
ff51 中 x 数组(/lotsapi/marketing/api/log/save、/up/api/aLiPay/applet/decryptData、/order/api/getOrderPaySum、/product/api/product/saveData 等 15 条)仅用于抑制错误弹窗(O(D) || showModal(...)),不跳过签名——除 onlyDataFlag=true 的参数外,所有请求都会签名。
4.4 BFF 代理
启动时 GET https://front-static.lotsmall.cn/frontStatic/prodBffProxyUrlConfig.json,命中 bffUrlList(scoped=all 或包含本商户)的路径会改走 WAP_HOST 且路径前加 /bff;命中 merLangUrl 的请求带 merLang 头。
4.5 AES(模块 7d92,member 分包)
- AES-128-CBC / PKCS7;key =
050NqbfpHJdOPXHW,iv =fljWOTW4SXKG0TBA(均按 UTF-8 解析)。 - 用于订单数据加密/解密(订单详情与 H5 bridge 场景),
Decrypt()结果 JSON.parse。
5. 预约门票流程链路
首页(chunk_0) ──点击门票──▶ webview: /vue/order/ticket?merchantInfoId=22190&scenicId&ticketId
│(H5 在 wap.lotsmall.cn 内完成以下步骤,调用同一套签名接口)
├─ 1 选择日期 → 可预约时段(含余票)
├─ 2 选择游玩人/填写信息(联系人或实名)
├─ 3 提交预约(下单)
├─ 4 支付(wx.requestPayment)
└─ 5 订单生成 → 核销码
小程序侧:订单列表/详情 ──▶ 取消预约(cancelOrder / orderCancel)
5.1 可预约时间列表
| 接口 | 方法 | 说明 |
|---|---|---|
/order/api/timeReserveList | POST | 可预约时间列表(小程序仅定义常量,H5 调用) |
/product/api/product/getDailyStock | - | 每日库存/余票 |
/product/api/product/getData | - | 产品数据 |
/product/api/product/ruleBuy | - | 购买规则 |
/product/api/product/getLevelAreas | - | 分级区域 |
/product/api/product/virtualTicket/getVirtualTicketDetail | - | 虚拟票详情 |
/merchant/api/merchantParkTicketGrid | - | 票种列表 |
/merchant/api/getSaleStatusByModelCode | - | 售卖状态 |
注:这些是 API 映射表中的路径(app-service.js ≈680500–681800),参数结构由 H5 端构造,包内无调用点。
5.2 游玩人 / 联系人 / 实名
| 接口 | 方法 | 参数 |
|---|---|---|
/leaguer/api/leaguerContacts/getContactsList | POST | 游玩人列表(H5 用) |
/leaguer/api/leaguerContacts/saveContacts | POST | 保存游玩人 |
/leaguer/api/leaguerContacts/deleteContacts | POST | 删除游玩人 |
/leaguer/api/leaguerContacts/selectContactsById | POST | 游玩人详情 |
/leaguer/api/userLeaguer/manage/leaguerInfo | GET | cipherText: "2",返回字段 RSA 密文,需私钥解密 |
/up/api/user/bind/validation | GET | 是否已绑手机 |
/up/api/user/realName | PUT | {cipherText: 0, realName} |
/up/api/user/idCard | PUT | {cipherText: 0, idCard} |
/up/api/user/bind/idCardAndFace | - | 身份证+人脸实名认证 |
/up/api/wechat/applet/decryptData | POST | 微信手机号解密 {data, iv}(免弹窗白名单) |
/marketing/api/alipay/user/certify/initialize | POST | 支付宝实名认证初始化(f8b7.certifyInitialize) |
5.3 提交预约(下单)
| 接口 | 方法 | 说明 |
|---|---|---|
/order/api/saveOrder | POST | 旧版下单(API 映射 order.saveOrder) |
/dubboApi/trade-core/tradeCreateService/create | POST | 新版下单(host=WAP_HOST,body 原样透传) |
/dubboApi/trade-search/orderToCService/queryOrderAsyncResult | POST | 下单结果轮询:间隔 1000ms,超时 10000ms,{orderCode};返回 {result, orderCode, message, payResult, autoPayment},result=0 未完成继续轮询,result=1 且需自动支付时判断 payResult |
/product/api/product/saveData | POST | 产品订单保存(免弹窗白名单) |
下单完成后未支付跳转:/vue/order/detail?id=<orderId>&m_id=22190&needLogin=1。
5.4 支付
| 接口 | 方法 | 说明 |
|---|---|---|
/order/orderPay/toPay | GET | {...(orderInfo/orderNo/price/payFrom 组装), payType: 999},返回后 toSuccessPage |
/order/api/getUnifiedPayOrder | GET | {payOrderNo} 统一支付单 |
/up/api/aLiPay/applet/decryptData | POST | 支付宝小程序解密 |
/vue/pay/result?payOrderNo=...&m_id=22190 | H5 | 支付结果页 |
5.5 订单查询 / 核销码
| 接口 | 方法 | 参数 |
|---|---|---|
/order/api/getPayOrders | GET | {payOrderNo} → data[0](f8b7.getPayOrderDetail) |
/order/api/getPayOrderList | - | 订单列表 |
/order/api/getOrderPaySum | GET | {payOrderNo}(免弹窗白名单) |
/dubboApi/trade-search/orderCustomPageService/pageQuery | POST | 自定义分页查询(WAP_HOST) |
/dubboApi/trade-core/orderInfoService/publicQueryTicketCode | POST | 核销码:{orderCode 或 orderDetailId, wayType: "applet", imgWidth: 135, imgHeight: 135},返回 data[].showCheckBOS(chunk_6 取票页/动态刷新码用) |
/dubboApi/trade-core/travelPlanRpcService/myTravelPlan | POST | 行程计划(免弹窗白名单) |
5.6 取消预约(订单)——两条链路 ★
链路 A(旧,小程序原生页调用) — pages/member/chunk_1.appservice.js(≈105718) 与 chunk_8.appservice.js(≈93332):
postData("/order/api/cancelOrder", {
payOrderNo: <payOrderNo>,
forceCancel: <可选>,
leaguerId: getStorageSync("WxXjscUserInfo").leaguerId
})
链路 B(新,dubbo 接口,host=WAP_HOST=wap.lotsmall.cn) — f8b7.tradeCancelOrder:
postData("/dubboApi/trade-core/orderCancelService/orderCancel",
{ orderCode: <orderCode>, forceCancel: true, requestFrom: "C" },
true, true, WAP_HOST) // jsonFlag=true, flag=true, host=WAP_HOST
取消后建议用
/order/api/getPayOrders {payOrderNo}刷新状态。
5.7 退款(member 分包 chunk_9 退款页)
postData("/leaguer/api/order/manage/refund", {
refundAmount, orderId, orderDetailId, refundType,
wayType: 33, reason, ...
})
// 酒店类走 /pmsorder/api/order/pmsRefund
5.8 排队预约授权页(灵隐寺排队场景)
pages/member/queueAppointAuthorization/index(member 分包 chunk_11):校验 headImg/nickName/phone 后 jumpQueueAppoint 跳 H5 排队预约页,本身无业务接口。
6. 加密参数专项说明
| 参数/字段 | 算法 | 说明 |
|---|---|---|
sign(请求头) | SHA-256 ×2 | sha256_hex(sha256_hex(sortedBody) + random15);sortedBody 为按键名升序的 JSON 或 k=v& 串 |
sk(请求头) | RSA-1024 PKCS1 v1.5 | 公钥加密 random15,encodeURIComponent;服务端私钥解出 random15 验签 |
Cookie: user_key | 明文 | = leaguerId(登录后绑定) |
access-token | 明文 | = accessToken(WxXjscUserInfo.token) |
merchantInfoId/merchantId/channelType | 明文 | 自动注入 22190 / 22190 / "wxPayMini" |
| leaguerInfo 密文字段 | RSA-1024 | cipherText=2 时 realName/mobile/idcard 等返回密文,前端用内嵌私钥解密(逆向可直接解密) |
| AES 订单数据 | AES-128-CBC PKCS7 | key=050NqbfpHJdOPXHW,iv=fljWOTW4SXKG0TBA |
| 微信手机号 | 服务端解密 | /up/api/wechat/applet/decryptData {data, iv}(无需签名的白名单) |
6.5 RSA 密钥(完整文本,内嵌于模块 847d/30e2)
公钥(pubsKey,用于签名 sk 加密):
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDI5kmdW9rmxQlTraZ6Wx+C7kYR
DjL332N53dsqFsqqT+PX6mosaM5hW4MS4vUbQNtUblhmQgzmUD0KBJFH9YZMmSPL
dCC+G4r7d2PPFBrCy+9dFUMUNaT4PenyaVQJyAp3bhUJ7n93bRJT9jtxsdDwJ/Zl
12A/kO93fr7+waaepwIDAQAB
-----END PUBLIC KEY-----
私钥(privateKey,用于 leaguerInfo 等密文字段解密 getRSA()):
-----BEGIN PRIVATE KEY-----
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAIvTT4CNu+WPelfl9h8MqvA4Bl0ir++U15pcC2MLK2NdRojD1dPsao515rBL0Oa8H5p/re6iDuF575ev7I/I04kGjrINuwpXnORhv62Opb160OXN6wfVV+cYhyY9yHkseKueRqkfzLJf7BDUuqqMjG39Ffb43d0TYvSIosq0lSpTAgMBAAECgYADV98bxMfMWlzjgyUaYvQnYD+OtIieYuGw2CiRiq/T5WQNWxlewtVdaKZGatmo2rCqwgjHnupaK881wkgWvAeKwyMI+k0C1+qAqvxEMlPkP9ed4SUd3kpWFmLt7KB5fcDVXFl9Ak9mV2nO2Kctho5swAnSvr0n5Ig3+p3+mdZVCQJBAMpByAdTOkLiXxFhYemVFJIl96XSM4Ne6GJYAoJt/AscyuzmT9SpDiIrpROz6mQMpr3YWGBDeAcFxC1iABPf3FUCQQCw+rh4HM16nVh4kWaA8i3FkKxbjxtRxp2NVsmf15xL8f7i5ugcgxs0akhkEK/dW3XQOBmvU+EYwwxHU4sawZQHAkEAofn+fMdNgGUUJ7IqnMtUlxqq8vSdZpcqWiALmnMEh82+QezMgA4HkJwNbvMGQqvTGXTaifVeeZlHm+TBFSmRpQJAaVg0KbrrTIsQOGREIYkGWc0t6yoZ1ulkqtb4GR8cN9CKKcHMc/xOWzrQcE/GfvqL/C8IiuZg3H5tdp9x87E6TQJBAK+cY731g+eKWXd5gNDBBJPPMwgchubKvXb4ITrZqwhb0mUPRn4Gmjm35D/KErClsbBSaNcxz/Tn1JmurPX6Bao=
-----END PRIVATE KEY-----
用途:
sk头 =encodeURIComponent(RSA_encrypt_pub(随机15位串));leaguerInfo(cipherText=2)返回字段 =RSA_decrypt_priv(decodeURIComponent(密文))。私钥随包分发即意味着密文可被完全还原。
安全提示:RSA 私钥、AES 密钥均明文内嵌包内;
sign可离线完全复现,仅凭 HTTPS 传输保护,无动态 token/时间戳参与。
7. 附录 A:模块定位(app-service.js 偏移)
| 内容 | 模块 | 偏移 |
|---|---|---|
| 常量 HOST/MERCHANT_INFO_ID 等 | 9cbb | 1408518 |
| 签名 + RSA 密钥(公/私) | 847d / 30e2 | 1285807 / 598457 |
| SHA-256 实现 | 6eed | 1199106 |
| 稳定按键排序 | f727 | 1875100 附近 |
| 请求封装(增强/签名/重试) | ff51 | 1893491 |
| HTTP 客户端(get/post/put) | 1f75 | 307468 |
| 统一交易 API(取消/下单/核销码/轮询) | f8b7 | 1873900 |
| 登录 | e9cb / 74fc | 1654646 / 1212976 |
| Cookie 绑定 | ee16 / 6dc7 | - |
| webview URL 构造 | 8754 | - |
| API 路径映射表 | - | ≈680500–681800 |
| AES key/iv 模块 | 7d92 | pages/member/app-service.js |
8. 附录 B:预约链路接口速查表
| 环节 | 接口 | host |
|---|---|---|
| 列表 | /merchant/api/merchantParkInfo/merchantParkInfoGrid | lotsmall |
| 详情 | /merchant/api/merchantParkInfo/merchantParkInfo | lotsmall |
| 票种 | /merchant/api/merchantParkTicketGrid | lotsmall |
| 可预约时间 | /order/api/timeReserveList | lotsmall |
| 余票 | /product/api/product/getDailyStock | lotsmall |
| 游玩人 | /leaguer/api/leaguerContacts/* | lotsmall |
| 实名 | /up/api/user/{realName,idCard}(PUT) | lotsmall |
| 下单 | /order/api/saveOrder 或 /dubboApi/trade-core/tradeCreateService/create | lotsmall / wap |
| 下单轮询 | /dubboApi/trade-search/orderToCService/queryOrderAsyncResult | wap |
| 支付 | /order/orderPay/toPay | lotsmall |
| 订单详情 | /order/api/getPayOrders | lotsmall |
| 核销码 | /dubboApi/trade-core/orderInfoService/publicQueryTicketCode | wap |
| 取消 | /order/api/cancelOrder 或 /dubboApi/trade-core/orderCancelService/orderCancel | lotsmall / wap |
| 退款 | /leaguer/api/order/manage/refund | lotsmall |
9. 附录 C:各接口请求/响应示例
通用约定:
- 除特别注明外,请求 body 会被自动增强为
{merchantInfoId: 22190, ...body, merchantId: 22190, channelType: "wxPayMini"}后再签名;-
sign/sk用增强后的完整 body 计算(计算过程见 C.2);- 响应统一格式:
{code: 200, message, data},code=200即成功(ff51直接返回data);- 标注 ⚠推测 的参数为 H5 端构造、小程序包内无调用点,依据乐程商城同源接口约定推断,实际值以抓包为准。
C.1 通用请求头(所有接口一致)
POST /order/api/cancelOrder HTTP/1.1
Host: www.lotsmall.cn
content-type: application/json
access-token: <accessToken> # WxXjscUserInfo.token
sk: <RSA加密后的随机15位串, 已encodeURIComponent>
sign: <sha256_hex(sha256_hex(sortedBody)+random15)>
Cookie: user_key=<leaguerId>
sessionId: <埋点sessionId>
traceId: <埋点traceId>
browserId: <埋点browserId>
merLang: CN
C.2 签名计算示例(以取消订单 body 为例)
// 1) 增强后的最终 body
body = {
merchantInfoId: 22190,
payOrderNo: "2026080312000012345",
forceCancel: true,
leaguerId: 123456789,
merchantId: 22190,
channelType: "wxPayMini"
}
// 2) signInitData(jsonFlag=true):按键名升序后 JSON.stringify
sorted = JSON.stringify({
channelType: "wxPayMini", forceCancel: true, leaguerId: 123456789,
merchantId: 22190, merchantInfoId: 22190, payOrderNo: "2026080312000012345"
})
// 3) 随机15位串(大写字母+数字)
random15 = "K3FX9MAB2VQZ4RT"
// 4) sign = SHA-256(SHA-256(sorted) + random15),hex 小写
h1 = sha256hex(sorted) // 64位hex
sign = sha256hex(h1 + random15) // 64位hex
// 5) sk = encodeURIComponent(RSA_encrypt(publicKey, random15))
sk = encodeURIComponent(rsaEncrypt(pub, random15)) // PKCS1 v1.5, 128字节密文
C.3 登录
POST https://www.lotsmall.cn/up/api/login
Cookie: <无或为空>
Body: { code: "wx登录code", merchantInfoId: 22190, loginFlag: "F", useTemplate: "F" }
200 → data: {
leaguerId: 123456789,
accessToken: "9d3f7a...",
accountId: 123456789,
...
}
// 客户端随后: cookie.login(leaguerId); cookie.bind("user_key", leaguerId)
GET https://www.lotsmall.cn/up/api/account?token=<accessToken>
200 → data: { account: "<openid>", nickName: "游客_xxxx" }
C.4 用户信息(RSA 密文返回,需私钥解密)
GET https://www.lotsmall.cn/leaguer/api/userLeaguer/manage/leaguerInfo?cipherText=2
200 → data: {
leaguerCode: "LEAGUER001",
realName: "MIGf...b2B2B2B2", // RSA密文 → getRSA()解密 → "张三"
mobile: "AbC...cXcXcXcX", // RSA密文 → 解密 → "138****1234"
idcard: "dEf...dYdYdYdY", // RSA密文 → 解密 → "3301**19900101****"
linkmanName: "..." , linkmanMobile: "...", linkmanCertNo: "..."
}
C.5 游玩人列表 / 保存 / 删除(H5 调用 ⚠参数推测)
POST https://www.lotsmall.cn/leaguer/api/leaguerContacts/getContactsList
Body: { merchantInfoId: 22190 } // ⚠推测
200 → data: [{ id: 1001, name: "张三", mobile: "13800001234", idCard: "", certType: 1 }]
POST https://www.lotsmall.cn/leaguer/api/leaguerContacts/saveContacts
Body: { name: "张三", mobile: "13800001234", idCard: "", certType: 1 } // ⚠推测
POST https://www.lotsmall.cn/leaguer/api/leaguerContacts/deleteContacts
Body: { id: 1001 } // ⚠推测
C.6 可预约时间列表(H5 调用 ⚠参数推测)
POST https://www.lotsmall.cn/order/api/timeReserveList
Body: { merchantInfoId: 22190, scenicId: 226, productCode: "TICKET_XXX", date: "2026-08-05" } // ⚠推测
200 → data: [ // ⚠推测
{ timeSlotId: "TS001", startTime: "08:00", endTime: "09:00", stock: 300, sold: 120, remain: 180, status: 1 },
{ timeSlotId: "TS002", startTime: "09:00", endTime: "10:00", stock: 300, sold: 260, remain: 40, status: 1 }
]
C.7 提交预约(下单)
POST https://www.lotsmall.cn/order/api/saveOrder
Body: { // ⚠推测(H5 构造)
merchantInfoId: 22190,
productCode: "TICKET_XXX",
ticketNum: 2,
reserveDate: "2026-08-05",
timeSlotId: "TS001",
travelers: [ { name: "张三", mobile: "13800001234", idCard: "" } ],
contactName: "张三",
contactMobile: "13800001234"
}
200 → data: { payOrderNo: "2026080512000012345", orderId: 987654321 }
// 或新版(同步下单 + 轮询):
POST https://wap.lotsmall.cn/dubboApi/trade-core/tradeCreateService/create
Body: { ...下单参数原样透传... } // jsonFlag=true, host=WAP_HOST
200 → data: { orderCode: "2026080512000012345", result: 1, message: "成功", payResult: 0, autoPayment: true }
POST https://wap.lotsmall.cn/dubboApi/trade-search/orderToCService/queryOrderAsyncResult
Body: { orderCode: "2026080512000012345" } // 1s 轮询一次,最长 10s
200 → data: { result: 1, orderCode: "2026080512000012345", message: "成功", payResult: 1, autoPayment: true }
C.8 支付
GET https://www.lotsmall.cn/order/orderPay/toPay
Query: payOrderNo=2026080512000012345&orderNo=2026080512000012345&price=80&payFrom=wxMiniapp&payType=999&merchantInfoId=22190&merchantId=22190&channelType=wxPayMini
200 → data: { timeStamp, nonceStr, package: "prepay_id=wx...", signType: "RSA", paySign } // ⚠推测字段
// 前端拿到后 wx.requestPayment(...),成功跳 /vue/pay/result?payOrderNo=...&m_id=22190&needLogin=1
GET https://www.lotsmall.cn/order/api/getUnifiedPayOrder?payOrderNo=2026080512000012345
200 → data: { payOrderNo, status: 2, amount: 80, ... } // ⚠推测字段
C.9 订单详情 / 订单列表
GET https://www.lotsmall.cn/order/api/getPayOrders?payOrderNo=2026080512000012345
200 → data: [ {
payOrderNo: "2026080512000012345", orderStatus: 2,
orderDetails: [ { orderDetailNo, ticketName: "飞来峰门票", parkName: "灵隐寺", reserveDate: "2026-08-05", timeSlot: "08:00-09:00", num: 2, price: 40 } ]
} ] // data[0] 即详情
POST https://wap.lotsmall.cn/dubboApi/trade-search/orderCustomPageService/pageQuery
Body: { pageNo: 1, pageSize: 10, orderType: "ticket" } // ⚠推测
200 → data: { pageList: [...], total: 1 }
C.10 取消预约(两条链路)
// 链路 A(小程序原生页)
POST https://www.lotsmall.cn/order/api/cancelOrder
Body: { payOrderNo: "2026080512000012345", forceCancel: true, leaguerId: 123456789 }
200 → data: { cancelSuccess: true } // ⚠推测字段
// 链路 B(dubbo)
POST https://wap.lotsmall.cn/dubboApi/trade-core/orderCancelService/orderCancel
Body: { orderCode: "2026080512000012345", forceCancel: true, requestFrom: "C" }
200 → data: { result: 1, message: "取消成功" } // ⚠推测字段
C.11 核销码
POST https://wap.lotsmall.cn/dubboApi/trade-core/orderInfoService/publicQueryTicketCode
Body: { orderCode: "2026080512000012345", wayType: "applet", imgWidth: 135, imgHeight: 135 }
// 或 { orderDetailId: 555, wayType: "applet", imgWidth: 135, imgHeight: 135 }(单票刷新)
200 → data: [ {
orderDetailNo: "DET20260805001", checkNo: "KT20260805123456", parkName: "灵隐寺",
ticketName: "飞来峰门票", reserveDate: "2026-08-05",
showCheckBOS: [ { orderDetailId: 555, orderDetailNo: "DET20260805001", code: "http://..." } ]
} ]
C.12 实名绑定 / 手机号解密
PUT https://www.lotsmall.cn/up/api/user/realName
Body: { cipherText: 0, realName: "张三" }
PUT https://www.lotsmall.cn/up/api/user/idCard
Body: { cipherText: 0, idCard: "3301***********1234" }
POST https://www.lotsmall.cn/up/api/wechat/applet/decryptData // 免弹窗白名单,仍签名
Body: { data: "<wx.getPhoneNumber 返回的 encryptedData>", iv: "<iv>" }
200 → data: { phoneNumber: "13800001234" } // ⚠推测字段
C.13 退款
POST https://www.lotsmall.cn/leaguer/api/order/manage/refund
Body: {
refundAmount: 80, orderId: 987654321, orderDetailId: 555,
refundType: "full", wayType: 33, reason: "行程变更"
} // 部分字段为 chunk_9 实参,业务枚举 ⚠推测
200 → data: { refundOrderNo: "R20260805001", status: 1 } // ⚠推测字段