文件
jw-beauty/miniprogram/utils/api.js
T
Guoguo 78ea1a03c5 feat: WeChat Pay V3 integration (fill credentials to activate)
Server:
- New lib/wxpay.js: native crypto RSA-SHA256 signing, JSAPI prepay,
  AES-256-GCM notify decryption, order query (no npm deps)
- New dao/payment-order.dao.js: createOrder, markPrepay,
  markPaidAndActivateSubscription (idempotent + transactional)
- New routes/payment.js: GET order status, POST order sync
- New routes/payment-notify.js: WeChat async callback handler with
  signature verification, amount/appid/mchid validation
- Modified subscription/purchase: auto-detects wxpay config, returns
  real payment_params or mock fallback
- Schema: payment_orders table with out_trade_no unique key
- app.js: express.raw() for notify path, payment routes mounted
- config.js: wxpay block with 7 env vars
- .env.example: all WeChat Pay fields documented
- .gitignore: certs/, *.pem, *.p12

Miniprogram:
- subscribe-plans doPurchase: calls real purchase API, falls back to
  mockPurchase only when server returns mock:true
- Added syncAndRedirect for post-payment order confirmation
- api.js: getPaymentOrder, syncPaymentOrder
- Removed "模拟支付"/"测试环境" from UI text
2026-05-18 03:07:59 -07:00

39 行
2.1 KiB
JavaScript

var http = require('./request')
module.exports = {
// Auth
login: function (code) { return http.post('/api/v1/auth/login', { code: code }) },
getPhone: function (code) { return http.post('/api/v1/user/phone', { code: code }) },
// User
getProfile: function () { return http.get('/api/v1/user/profile') },
updateProfile: function (data) { return http.put('/api/v1/user/profile', data) },
// Device
getDevices: function () { return http.get('/api/v1/device/list') },
bindDevice: function (deviceId) { return http.post('/api/v1/device/bind', { device_id: deviceId }) },
confirmBind: function (deviceId, token) { return http.post('/api/v1/device/bind/confirm', { device_id: deviceId, bind_token: token }) },
mockBind: function (deviceId) { return http.post('/api/v1/device/mock-bind', { device_id: deviceId }) },
unbindDevice: function (deviceId) { return http.post('/api/v1/device/unbind', deviceId ? { device_id: deviceId } : {}) },
// Subscription
getPlans: function () { return http.get('/api/v1/subscription/plans') },
getSubscription: function () { return http.get('/api/v1/subscription') },
activateTrial: function () { return http.post('/api/v1/subscription/trial') },
purchase: function (plan) { return http.post('/api/v1/subscription/purchase', { plan: plan }) },
mockPurchase: function (plan) { return http.post('/api/v1/subscription/mock-purchase', { plan: plan }) },
// Payment
getPaymentOrder: function (orderId) { return http.get('/api/v1/payment/orders/' + orderId) },
syncPaymentOrder: function (orderId) { return http.post('/api/v1/payment/orders/' + orderId + '/sync') },
// Treatment
getRecords: function (params) { return http.get('/api/v1/treatment/history', params) },
syncTreatment: function (data) { return http.post('/api/v1/treatment/sync', data) },
getRecordDetail: function (id) { return http.get('/api/v1/treatment/' + id) },
// Device commands
getPendingCommands: function (deviceId) { return http.get('/api/v1/device/command/pending', { device_id: deviceId }) },
reportCommandResult: function (data) { return http.post('/api/v1/device/command/result', data) }
}