first commit
This commit is contained in:
@@ -0,0 +1,216 @@
|
||||
import { request } from '../../utils/request'
|
||||
import { QuotaItem, UserInfo, GoodsItem, QuotaFlowItem, PagedResult, VirtualPayResult, OrderItem } from '../../types/models'
|
||||
import { QUOTA_NAMES, GoodsType, GOODS_TYPE_NAMES } from '../../utils/config'
|
||||
import { fenToYuan, formatDate, formatDateTime } from '../../utils/format'
|
||||
|
||||
const GOODS_ICONS: Record<number, string> = {
|
||||
[GoodsType.MEMBER]: 'icon-crown',
|
||||
[GoodsType.UPLOAD]: 'icon-camera',
|
||||
[GoodsType.AI]: 'icon-sparkles',
|
||||
[GoodsType.CLOSET_SHARE]: 'icon-hanger',
|
||||
[GoodsType.OUTFIT_SHARE]: 'icon-shirt',
|
||||
}
|
||||
|
||||
const GOODS_FILTERS = [
|
||||
{ name: '全部', value: 0 },
|
||||
{ name: '会员包', value: 1 },
|
||||
{ name: '上传包', value: 2 },
|
||||
{ name: 'AI 推荐包', value: 3 },
|
||||
{ name: '衣柜分享包', value: 4 },
|
||||
{ name: '搭配分享包', value: 5 },
|
||||
]
|
||||
|
||||
type PayPlatform = 'android' | 'ios' | 'harmony' | 'windows'
|
||||
|
||||
// 归一化平台:后端仅接受 android/ios/harmony/windows,devtools/mac 等调试环境默认按 android 处理
|
||||
function normalizePlatform(): PayPlatform {
|
||||
let p = 'android'
|
||||
try {
|
||||
p = wx.getSystemInfoSync().platform
|
||||
} catch (e) {
|
||||
// 获取失败时回退 android,避免请求体缺失导致参数校验失败
|
||||
}
|
||||
if (p === 'ios' || p === 'harmony' || p === 'windows') return p
|
||||
return 'android'
|
||||
}
|
||||
|
||||
Page({
|
||||
data: {
|
||||
view: 'mall' as 'mall' | 'flow',
|
||||
userInfo: {} as UserInfo,
|
||||
isVip: false,
|
||||
vipExpireText: '',
|
||||
quotas: [] as QuotaItem[],
|
||||
goodsFilters: GOODS_FILTERS,
|
||||
activeFilter: 0,
|
||||
goods: [] as GoodsItem[],
|
||||
flowList: [] as QuotaFlowItem[],
|
||||
goodsIcons: GOODS_ICONS,
|
||||
orderVisible: false,
|
||||
orderGoods: null as GoodsItem | null,
|
||||
loading: true,
|
||||
},
|
||||
|
||||
onLoad(query: Record<string, string>) {
|
||||
if (query.tab === 'flow') this.setData({ view: 'flow' })
|
||||
},
|
||||
|
||||
onShow() {
|
||||
this.fetchUser()
|
||||
this.fetchQuota()
|
||||
this.fetchGoods()
|
||||
if (this.data.view === 'flow') this.fetchFlow()
|
||||
},
|
||||
|
||||
fetchUser() {
|
||||
request<UserInfo>({ url: '/user/info', showError: false })
|
||||
.then((user) => {
|
||||
const isVip = user.vip_type !== 1
|
||||
this.setData({
|
||||
userInfo: user,
|
||||
isVip,
|
||||
vipExpireText: isVip && user.vip_expire ? `有效期至 ${formatDate(user.vip_expire)}` : '',
|
||||
})
|
||||
})
|
||||
.catch(() => {})
|
||||
},
|
||||
|
||||
fetchQuota() {
|
||||
request<{ quotas: QuotaItem[] }>({ url: '/quota/info', showError: false })
|
||||
.then((res) => {
|
||||
const quotas = res.quotas.map((q) => ({
|
||||
...q,
|
||||
_name: QUOTA_NAMES[q.quota_type] || '额度',
|
||||
_percent: q.total > 0 ? Math.round((q.used / q.total) * 100) : 0,
|
||||
}))
|
||||
this.setData({ quotas })
|
||||
})
|
||||
.catch(() => {})
|
||||
},
|
||||
|
||||
fetchGoods() {
|
||||
const params: Record<string, any> = { page: 1, page_size: 50 }
|
||||
const filter = this.data.activeFilter
|
||||
if (filter > 0) params.goods_type = filter
|
||||
request<PagedResult<GoodsItem>>({ url: '/goods', data: params, auth: false })
|
||||
.then((res) => {
|
||||
const goods = res.list.map((g) => ({
|
||||
...g,
|
||||
_icon: GOODS_ICONS[g.goods_type] || 'icon-crown',
|
||||
_typeName: GOODS_TYPE_NAMES[g.goods_type] || '',
|
||||
_priceText: fenToYuan(g.discount_price),
|
||||
_originText: fenToYuan(g.price),
|
||||
}))
|
||||
this.setData({ goods, loading: false })
|
||||
})
|
||||
.catch(() => this.setData({ loading: false }))
|
||||
},
|
||||
|
||||
fetchFlow() {
|
||||
request<PagedResult<QuotaFlowItem>>({ url: '/quota/flow', data: { page: 1, page_size: 50 } })
|
||||
.then((res) => {
|
||||
const list = res.list.map((it) => ({
|
||||
...it,
|
||||
_time: formatDateTime(it.created_at),
|
||||
_sign: it.change_num > 0 ? `+${it.change_num}` : `${it.change_num}`,
|
||||
_name: QUOTA_NAMES[it.quota_type] || '额度',
|
||||
}))
|
||||
this.setData({ flowList: list })
|
||||
})
|
||||
.catch(() => {})
|
||||
},
|
||||
|
||||
onGoodsFilter(e: WechatMiniprogram.TouchEvent) {
|
||||
const index = Number(e.currentTarget.dataset.index)
|
||||
if (index === this.data.activeFilter) return
|
||||
this.setData({ activeFilter: index, loading: true })
|
||||
this.fetchGoods()
|
||||
},
|
||||
|
||||
onTapMember() {
|
||||
this.setData({ activeFilter: 1, loading: true })
|
||||
this.fetchGoods()
|
||||
},
|
||||
|
||||
onSwitchMall() {
|
||||
this.setData({ view: 'mall' })
|
||||
},
|
||||
onSwitchFlow() {
|
||||
this.setData({ view: 'flow' })
|
||||
this.fetchFlow()
|
||||
},
|
||||
|
||||
onBuy(e: WechatMiniprogram.TouchEvent) {
|
||||
const goods = e.currentTarget.dataset.goods as GoodsItem
|
||||
this.setData({ orderGoods: goods, orderVisible: true })
|
||||
},
|
||||
|
||||
onCloseOrder() {
|
||||
this.setData({ orderVisible: false })
|
||||
},
|
||||
noop() {},
|
||||
|
||||
confirmPay() {
|
||||
if (!this.data.orderGoods) return
|
||||
request<VirtualPayResult>({
|
||||
url: '/order/virtual',
|
||||
method: 'POST',
|
||||
data: {
|
||||
goods_code: this.data.orderGoods.goods_code,
|
||||
platform: normalizePlatform(),
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
this.setData({ orderVisible: false })
|
||||
this.doPayment(res)
|
||||
})
|
||||
.catch(() => {})
|
||||
},
|
||||
|
||||
doPayment(res: VirtualPayResult) {
|
||||
wx.requestVirtualPayment({
|
||||
signData: res.sign_data,
|
||||
paySig: res.pay_sig,
|
||||
signature: res.signature,
|
||||
mode: 'short_series_goods',
|
||||
success: () => {
|
||||
// 拉起成功仅代表进入支付页,最终到账以后端发货推送为准,轮询订单确认
|
||||
this.pollOrder(res.order_no)
|
||||
},
|
||||
fail: () => {},
|
||||
})
|
||||
},
|
||||
|
||||
pollOrder(orderNo: string) {
|
||||
let count = 0
|
||||
const timer = setInterval(() => {
|
||||
count++
|
||||
request<PagedResult<OrderItem>>({ url: '/order', data: { page: 1, page_size: 50 }, showError: false })
|
||||
.then((res) => {
|
||||
const order = res.list.find((it) => it.order_no === orderNo)
|
||||
if (order && order.order_status === 2) {
|
||||
clearInterval(timer)
|
||||
wx.showToast({ title: '支付成功', icon: 'success' })
|
||||
this.fetchQuota()
|
||||
this.fetchUser()
|
||||
} else if (order && (order.order_status === 3 || order.order_status === 4 || order.order_status === 5)) {
|
||||
clearInterval(timer)
|
||||
const msg = order.order_status === 5 ? '订单已退款' : '订单未支付成功'
|
||||
wx.showToast({ title: msg, icon: 'none' })
|
||||
} else if (count >= 10) {
|
||||
this.finishPayTimeout(timer)
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
if (count >= 10) this.finishPayTimeout(timer)
|
||||
})
|
||||
}, 1500)
|
||||
},
|
||||
|
||||
finishPayTimeout(timer: ReturnType<typeof setInterval>) {
|
||||
clearInterval(timer)
|
||||
wx.showToast({ title: '到账可能有延迟,请稍后查看', icon: 'none' })
|
||||
this.fetchQuota()
|
||||
this.fetchUser()
|
||||
},
|
||||
})
|
||||
Reference in New Issue
Block a user