杭州灵隐寺小程序 · 预约门票流程逆向分析

对象: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)

常量值
HOSThttps://www.lotsmall.cn
WAP_HOSThttps://wap.lotsmall.cn(H5 页面 + dubbo 接口)
SAAS_NK_WAP_HOSThttps://nkwap.lotsmall.cn
PUB_WAP_HOST / HOST_PUBhttps://pubswap.zhiyoubao.com / https://pubs.zhiyoubao.com
CDR_HOSThttps://cdr.lotsmall.cn
MERCHANT_INFO_ID22190(dev=14152,支付宝小程序 prod=1001)
PARKSZLY226
X_GRC生产为空(仅 dev 为 xxxxxxxx,且仅 dev 会带 x-grc 头)

merchantInfoId 也可被 wx.getExtConfigSync().merchantInfoId 覆盖(ff51 模块)。

3. 登录与会话(模块 e9cb / 74fc)

  1. wx.login() 拿 code → POST /up/api/login(74fc.wxMiniLogin),业务参数 {code, merchantInfoId, ...},追加 loginFlag: "F", useTemplate: "F"。
  2. 响应 data 含 leaguerId / accessToken / accountId 等。
  3. Cookie 写入(模块 ee16):cookie.login(leaguerId)、cookie.bind("user_key", leaguerId) → 后续所有请求头 Cookie: user_key=<leaguerId>(模块 6dc7 统一拼接)。
  4. GET /up/api/account?token=<accessToken> → 取 {account, nickName},组装并缓存 WxXjscUserInfo = {leaguerId: accountId, token: accessToken, realName, accountId, openId, openid}。
  5. 本地缓存:WxXjscUserInfo、xjsc_merchantInfoId、merchantChannelCode、xjsc_2018_order_url_asds(登录后回跳)。
  6. 未登录跳 /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/timeReserveListPOST可预约时间列表(小程序仅定义常量,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/getContactsListPOST游玩人列表(H5 用)
/leaguer/api/leaguerContacts/saveContactsPOST保存游玩人
/leaguer/api/leaguerContacts/deleteContactsPOST删除游玩人
/leaguer/api/leaguerContacts/selectContactsByIdPOST游玩人详情
/leaguer/api/userLeaguer/manage/leaguerInfoGETcipherText: "2",返回字段 RSA 密文,需私钥解密
/up/api/user/bind/validationGET是否已绑手机
/up/api/user/realNamePUT{cipherText: 0, realName}
/up/api/user/idCardPUT{cipherText: 0, idCard}
/up/api/user/bind/idCardAndFace-身份证+人脸实名认证
/up/api/wechat/applet/decryptDataPOST微信手机号解密 {data, iv}(免弹窗白名单)
/marketing/api/alipay/user/certify/initializePOST支付宝实名认证初始化(f8b7.certifyInitialize)

5.3 提交预约(下单)

接口方法说明
/order/api/saveOrderPOST旧版下单(API 映射 order.saveOrder)
/dubboApi/trade-core/tradeCreateService/createPOST新版下单(host=WAP_HOST,body 原样透传)
/dubboApi/trade-search/orderToCService/queryOrderAsyncResultPOST下单结果轮询:间隔 1000ms,超时 10000ms,{orderCode};返回 {result, orderCode, message, payResult, autoPayment},result=0 未完成继续轮询,result=1 且需自动支付时判断 payResult
/product/api/product/saveDataPOST产品订单保存(免弹窗白名单)

下单完成后未支付跳转:/vue/order/detail?id=<orderId>&m_id=22190&needLogin=1。

5.4 支付

接口方法说明
/order/orderPay/toPayGET{...(orderInfo/orderNo/price/payFrom 组装), payType: 999},返回后 toSuccessPage
/order/api/getUnifiedPayOrderGET{payOrderNo} 统一支付单
/up/api/aLiPay/applet/decryptDataPOST支付宝小程序解密
/vue/pay/result?payOrderNo=...&m_id=22190H5支付结果页

5.5 订单查询 / 核销码

接口方法参数
/order/api/getPayOrdersGET{payOrderNo} → data[0](f8b7.getPayOrderDetail)
/order/api/getPayOrderList-订单列表
/order/api/getOrderPaySumGET{payOrderNo}(免弹窗白名单)
/dubboApi/trade-search/orderCustomPageService/pageQueryPOST自定义分页查询(WAP_HOST)
/dubboApi/trade-core/orderInfoService/publicQueryTicketCodePOST核销码:{orderCode 或 orderDetailId, wayType: "applet", imgWidth: 135, imgHeight: 135},返回 data[].showCheckBOS(chunk_6 取票页/动态刷新码用)
/dubboApi/trade-core/travelPlanRpcService/myTravelPlanPOST行程计划(免弹窗白名单)

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 ×2sha256_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-1024cipherText=2 时 realName/mobile/idcard 等返回密文,前端用内嵌私钥解密(逆向可直接解密)
AES 订单数据AES-128-CBC PKCS7key=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 等9cbb1408518
签名 + RSA 密钥(公/私)847d / 30e21285807 / 598457
SHA-256 实现6eed1199106
稳定按键排序f7271875100 附近
请求封装(增强/签名/重试)ff511893491
HTTP 客户端(get/post/put)1f75307468
统一交易 API(取消/下单/核销码/轮询)f8b71873900
登录e9cb / 74fc1654646 / 1212976
Cookie 绑定ee16 / 6dc7-
webview URL 构造8754-
API 路径映射表-≈680500–681800
AES key/iv 模块7d92pages/member/app-service.js

8. 附录 B:预约链路接口速查表

环节接口host
列表/merchant/api/merchantParkInfo/merchantParkInfoGridlotsmall
详情/merchant/api/merchantParkInfo/merchantParkInfolotsmall
票种/merchant/api/merchantParkTicketGridlotsmall
可预约时间/order/api/timeReserveListlotsmall
余票/product/api/product/getDailyStocklotsmall
游玩人/leaguer/api/leaguerContacts/*lotsmall
实名/up/api/user/{realName,idCard}(PUT)lotsmall
下单/order/api/saveOrder 或 /dubboApi/trade-core/tradeCreateService/createlotsmall / wap
下单轮询/dubboApi/trade-search/orderToCService/queryOrderAsyncResultwap
支付/order/orderPay/toPaylotsmall
订单详情/order/api/getPayOrderslotsmall
核销码/dubboApi/trade-core/orderInfoService/publicQueryTicketCodewap
取消/order/api/cancelOrder 或 /dubboApi/trade-core/orderCancelService/orderCancellotsmall / wap
退款/leaguer/api/order/manage/refundlotsmall

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 }   // ⚠推测字段