Files
qipai/miniapp/pages/room/detail.js
T

232 lines
6.4 KiB
JavaScript

const {
request,
ensureLogin,
cents,
clientRequestId,
requestWechatPayment,
} = require('../../utils/api.js')
function defaultStartAt() {
const date = new Date(Date.now() + 30 * 60 * 1000)
date.setSeconds(0, 0)
return date
}
function isoMinutesAfter(date, minutes) {
return new Date(date.getTime() + minutes * 60 * 1000).toISOString()
}
Page({
data: {
storeId: '',
roomId: '',
loading: false,
errorMessage: '',
successMessage: '',
durationMinutes: 120,
pricingMode: 'HOURLY',
quote: null,
order: null,
payment: null,
couponGrantId: '',
packageHoldingId: '',
packageMinutes: '',
packageCreditYuan: '',
},
onLoad(options) {
this.setData({
storeId: options.storeId || '',
roomId: options.roomId || '',
})
},
updateBenefitField(event) {
const field = event.currentTarget.dataset.field
if (!field) return
this.setData({
[field]: event.detail.value,
order: null,
payment: null,
successMessage: '',
errorMessage: '',
})
},
setDuration(event) {
this.setData({
durationMinutes: Number(event.currentTarget.dataset.minutes),
quote: null,
order: null,
payment: null,
errorMessage: '',
successMessage: '',
})
},
async quote() {
await this.withRequest(async () => {
const payload = this.pricingPayload()
const response = await request('/pricing/quote', { method: 'POST', data: payload })
this.setData({
quote: {
...response.data,
totalText: cents(response.data.totalCents),
depositText: cents(response.data.depositCents),
},
successMessage: '报价已生成',
})
})
},
async reserve() {
await this.withRequest(async () => {
const payload = this.pricingPayload()
const response = await request('/orders/reserve', { method: 'POST', data: payload })
this.setData({
order: response.data,
successMessage: response.data.benefitReservation
? '时段已预占,权益已冻结,请继续支付'
: '时段已预占,请继续支付',
})
})
},
async createTestPayment() {
if (!this.data.order || !this.data.order.orderId) {
this.setData({ errorMessage: '请先预占订单' })
return
}
await this.withRequest(async () => {
const response = await request('/payments', {
method: 'POST',
data: {
orderId: this.data.order.orderId,
provider: 'TEST',
clientRequestId: clientRequestId('miniapp-pay'),
},
})
this.setData({
payment: {
...response.data,
amountText: cents(response.data.amountCents),
},
successMessage: '测试支付单已创建',
})
})
},
async createWechatPayment() {
if (!this.data.order || !this.data.order.orderId) {
this.setData({ errorMessage: '请先预占订单' })
return
}
await this.withRequest(async () => {
const paymentResponse = await request('/payments', {
method: 'POST',
data: {
orderId: this.data.order.orderId,
provider: 'WECHAT',
clientRequestId: clientRequestId('miniapp-wxpay'),
},
})
const prepayResponse = await request('/pay/wechat/prepay', {
method: 'POST',
data: { paymentId: paymentResponse.data.paymentId },
})
await requestWechatPayment(prepayResponse.data)
this.setData({
payment: {
...paymentResponse.data,
amountText: cents(paymentResponse.data.amountCents),
},
successMessage: '微信支付已提交,请稍后查看订单状态',
})
})
},
async createBalancePayment() {
if (!this.data.order || !this.data.order.orderId) {
this.setData({ errorMessage: '请先预占订单' })
return
}
await this.withRequest(async () => {
const response = await request('/payments', {
method: 'POST',
data: {
orderId: this.data.order.orderId,
provider: 'BALANCE',
clientRequestId: clientRequestId('miniapp-balance'),
},
})
this.setData({
payment: {
...response.data,
amountText: cents(response.data.amountCents),
},
successMessage: '余额支付已完成',
})
})
},
async completeTestPayment() {
if (!this.data.payment || !this.data.payment.paymentId) {
this.setData({ errorMessage: '请先创建测试支付单' })
return
}
await this.withRequest(async () => {
await request(`/payments/${encodeURIComponent(this.data.payment.paymentId)}/test-complete`, {
method: 'POST',
data: {
callbackId: clientRequestId('miniapp-callback'),
amountCents: this.data.payment.amountCents,
},
})
this.setData({ successMessage: '测试支付已完成,生产环境将切换微信支付' })
})
},
openOrder(event) {
const orderId = event.currentTarget.dataset.orderId
if (!orderId) return
wx.navigateTo({ url: `/pages/orders/detail?orderId=${encodeURIComponent(orderId)}` })
},
pricingPayload() {
const start = defaultStartAt()
return {
roomId: this.data.roomId,
startAt: start.toISOString(),
endAt: isoMinutesAfter(start, this.data.durationMinutes),
pricingMode: this.data.pricingMode,
benefits: this.benefitsPayload(),
}
},
benefitsPayload() {
const couponGrantId = String(this.data.couponGrantId || '').trim()
const packageHoldingId = String(this.data.packageHoldingId || '').trim()
if (!couponGrantId && !packageHoldingId) return undefined
const packageMinutes = Number(this.data.packageMinutes || 0)
const packageCreditCents = Math.round(Number(this.data.packageCreditYuan || 0) * 100)
return {
couponGrantId: couponGrantId || null,
packageHoldingId: packageHoldingId || null,
packageMinutes: packageMinutes > 0 ? packageMinutes : 0,
packageCreditCents: packageCreditCents > 0 ? packageCreditCents : 0,
clientRequestId: clientRequestId('miniapp-benefit'),
}
},
async withRequest(work) {
this.setData({ loading: true, errorMessage: '', successMessage: '' })
try {
await ensureLogin()
await work()
} catch (error) {
this.setData({ errorMessage: error.message || '操作失败' })
} finally {
this.setData({ loading: false })
}
},
})