180 lines
5.5 KiB
TypeScript
180 lines
5.5 KiB
TypeScript
import { request } from '../../utils/request'
|
|
import { PagedResult, OrderItem } from '../../types/models'
|
|
import { fenToYuan, formatDateTime, formatCountdown } from '../../utils/format'
|
|
import { normalizePaged, mergePaged, hasMorePaged } from '../../utils/paged'
|
|
|
|
const STATUS_FILTERS = [
|
|
{ name: '全部', value: 0 },
|
|
{ name: '待支付', value: 1 },
|
|
{ name: '已支付', value: 2 },
|
|
{ name: '已取消', value: 3 },
|
|
{ name: '已过期', value: 4 },
|
|
{ name: '已退款', value: 5 },
|
|
]
|
|
|
|
const STATUS_TEXT: Record<number, string> = { 1: '待支付', 2: '已支付', 3: '已取消', 4: '已过期', 5: '已退款' }
|
|
const STATUS_TYPE: Record<number, string> = { 1: 'orange', 2: 'green', 3: 'gray', 4: 'gray', 5: 'blue' }
|
|
|
|
Page({
|
|
data: {
|
|
filters: STATUS_FILTERS,
|
|
activeFilter: 0,
|
|
list: [] as OrderItem[],
|
|
loading: true,
|
|
loadingMore: false,
|
|
page: 1,
|
|
pageSize: 20,
|
|
hasMore: true,
|
|
},
|
|
|
|
onShow() {
|
|
this.refresh()
|
|
this.startCountdown()
|
|
},
|
|
|
|
onHide() {
|
|
this.stopCountdown()
|
|
},
|
|
|
|
onUnload() {
|
|
this.stopCountdown()
|
|
},
|
|
|
|
refresh() {
|
|
this.setData({ page: 1, hasMore: true, loading: this.data.list.length === 0 })
|
|
this.fetchList(1)
|
|
},
|
|
|
|
onReachBottom() {
|
|
if (!this.data.hasMore || this.data.loading || this.data.loadingMore) return
|
|
this.fetchList(this.data.page + 1)
|
|
},
|
|
|
|
// 待支付倒计时需要每秒走动,仅在有倒计时项时才 setData
|
|
startCountdown() {
|
|
this.stopCountdown()
|
|
;(this as any).tickTimer = setInterval(() => this.tickCountdown(), 1000)
|
|
},
|
|
|
|
stopCountdown() {
|
|
const timer = (this as any).tickTimer
|
|
if (timer) {
|
|
clearInterval(timer)
|
|
;(this as any).tickTimer = null
|
|
}
|
|
},
|
|
|
|
tickCountdown() {
|
|
const list = this.data.list
|
|
if (!list.length) return
|
|
const now = Math.floor(Date.now() / 1000)
|
|
let changed = false
|
|
const next = list.map((it: any) => {
|
|
if (it.order_status !== 1 || !it.expire_time) return it
|
|
const left = it.expire_time - now
|
|
const text = left > 0 ? formatCountdown(left) : ''
|
|
if (text === it._countdown) return it
|
|
changed = true
|
|
return { ...it, _countdown: text }
|
|
})
|
|
if (changed) this.setData({ list: next })
|
|
},
|
|
|
|
fetchList(page: number) {
|
|
const params: Record<string, any> = { page, page_size: this.data.pageSize }
|
|
const filter = this.data.activeFilter
|
|
if (filter > 0) params.status = filter
|
|
|
|
// 请求序号:切换筛选时旧响应可能后到,序号不匹配直接丢弃
|
|
const seq = ((this as any).reqSeq || 0) + 1
|
|
;(this as any).reqSeq = seq
|
|
if (page > 1) this.setData({ loadingMore: true })
|
|
|
|
request<PagedResult<OrderItem>>({ url: '/order', data: params })
|
|
.then((res) => {
|
|
if ((this as any).reqSeq !== seq) return
|
|
const { list: raw, total } = normalizePaged<OrderItem>(res)
|
|
const now = Math.floor(Date.now() / 1000)
|
|
const list = raw.map((it) => ({
|
|
...it,
|
|
_statusText: STATUS_TEXT[it.order_status] || '',
|
|
_statusType: STATUS_TYPE[it.order_status] || 'gray',
|
|
_amount: fenToYuan(it.pay_amount),
|
|
_time: formatDateTime(it.created_at),
|
|
_orderTail: `…${it.order_no.slice(-4)}`,
|
|
_countdown: it.order_status === 1 && it.expire_time > now ? formatCountdown(it.expire_time - now) : '',
|
|
_benefit: it.member_days > 0 ? `${it.member_days} 天会员` : '',
|
|
_canCancel: it.order_status === 1 && it.pay_channel !== 2,
|
|
_payChannelText: it.pay_channel === 2 ? '虚拟支付' : '',
|
|
}))
|
|
const merged = mergePaged(this.data.list, list, page === 1)
|
|
this.setData({
|
|
list: merged,
|
|
hasMore: hasMorePaged(merged, total, this.data.pageSize),
|
|
loading: false,
|
|
loadingMore: false,
|
|
page,
|
|
})
|
|
})
|
|
.catch(() => {
|
|
if ((this as any).reqSeq !== seq) return
|
|
this.setData({ loading: false, loadingMore: false })
|
|
})
|
|
},
|
|
|
|
onFilterTap(e: WechatMiniprogram.TouchEvent) {
|
|
const index = Number(e.currentTarget.dataset.index)
|
|
if (index === this.data.activeFilter) return
|
|
this.setData({ activeFilter: index, list: [], loading: true })
|
|
this.refresh()
|
|
},
|
|
|
|
onCancel(e: WechatMiniprogram.TouchEvent) {
|
|
const orderNo = e.currentTarget.dataset.no as string
|
|
wx.showModal({
|
|
title: '取消订单',
|
|
content: '确认取消该订单?',
|
|
success: (res) => {
|
|
if (!res.confirm) return
|
|
request({ url: `/order/${orderNo}/cancel`, method: 'POST' })
|
|
.then(() => {
|
|
wx.showToast({ title: '已取消', icon: 'success' })
|
|
this.refresh()
|
|
})
|
|
.catch(() => {})
|
|
},
|
|
})
|
|
},
|
|
|
|
onPay() {
|
|
wx.showToast({ title: '请返回商城重新下单支付', icon: 'none' })
|
|
},
|
|
|
|
onRefund(e: WechatMiniprogram.TouchEvent) {
|
|
const orderNo = e.currentTarget.dataset.no as string
|
|
wx.showModal({
|
|
title: '申请退款',
|
|
editable: true,
|
|
placeholderText: '请填写退款原因',
|
|
success: (res) => {
|
|
if (!res.confirm) return
|
|
const reason = (res.content || '').trim()
|
|
if (!reason) {
|
|
wx.showToast({ title: '请填写退款原因', icon: 'none' })
|
|
return
|
|
}
|
|
request({ url: '/order/refund', method: 'POST', data: { order_no: orderNo, reason } })
|
|
.then(() => {
|
|
wx.showToast({ title: '退款申请已提交,等待审核', icon: 'none' })
|
|
this.refresh()
|
|
})
|
|
.catch(() => {})
|
|
},
|
|
})
|
|
},
|
|
|
|
onGoMall() {
|
|
wx.navigateTo({ url: '/pages/mall/mall' })
|
|
},
|
|
})
|