- Introduced member business tabs for profile and dynamics, improving navigation and user experience. - Implemented image parsing and normalization functions to handle article images effectively. - Updated the UI to display article thumbnails and manage loading states, enhancing visual feedback. - Refactored data synchronization methods to ensure member business tabs reflect current content accurately. This update aims to streamline member profile interactions and improve the overall presentation of member-related content.
305 lines
9.6 KiB
JavaScript
305 lines
9.6 KiB
JavaScript
/**
|
|
* Soul创业派对 - 订单与代付(消费流水 + 我发起的代付,按时间合并)
|
|
*/
|
|
const app = getApp()
|
|
const { cleanSingleLineField } = require('../../utils/contentParser.js')
|
|
|
|
const PAID_STATUSES = new Set(['paid', 'completed', 'success'])
|
|
|
|
function parseOrderTimeMs(o) {
|
|
const raw = o.created_at || o.createdAt || o.pay_time || 0
|
|
const t = new Date(raw).getTime()
|
|
return Number.isFinite(t) ? t : 0
|
|
}
|
|
|
|
function formatShortDate(ms) {
|
|
if (!ms) return '--'
|
|
const d = new Date(ms)
|
|
const m = (d.getMonth() + 1).toString().padStart(2, '0')
|
|
const day = d.getDate().toString().padStart(2, '0')
|
|
return `${m}-${day}`
|
|
}
|
|
|
|
function midForSection(sectionId, bookFlat) {
|
|
const row = bookFlat.find((s) => s.id === sectionId)
|
|
return row?.mid ?? row?.MID ?? 0
|
|
}
|
|
|
|
function giftPayStatusLabel(status) {
|
|
const s = String(status || '').toLowerCase()
|
|
if (s === 'pending' || s === 'pending_pay') return '待支付'
|
|
if (s === 'paid') return '已支付'
|
|
if (s === 'refunded') return '已退款'
|
|
if (s === 'cancelled') return '已取消'
|
|
if (s === 'expired') return '已过期'
|
|
return String(status || '').trim() || '--'
|
|
}
|
|
|
|
function parseIsoMs(iso) {
|
|
const t = new Date(iso || 0).getTime()
|
|
return Number.isFinite(t) ? t : 0
|
|
}
|
|
|
|
function mapGiftPayToRow(item) {
|
|
const requestSn = String(item.requestSn || '').trim()
|
|
if (!requestSn) return null
|
|
const t = parseIsoMs(item.createdAt)
|
|
const amt = Number(item.amount)
|
|
const amountStr = Number.isFinite(amt) ? amt.toFixed(2) : '--'
|
|
const titleRaw = cleanSingleLineField(String(item.description || '').trim())
|
|
const title = titleRaw || '代付'
|
|
const st = String(item.status || '').toLowerCase()
|
|
const stLabel = giftPayStatusLabel(item.status)
|
|
const gpPending = st === 'pending' || st === 'pending_pay'
|
|
const gpPaid = st === 'paid'
|
|
return {
|
|
rowKey: `gp_${requestSn}`,
|
|
kind: 'giftPay',
|
|
requestSn,
|
|
title,
|
|
subLine: `¥${amountStr} · ${stLabel} · ${formatShortDate(t)}`,
|
|
actionLabel: '查看',
|
|
gpPending,
|
|
gpPaid,
|
|
_sortMs: t,
|
|
}
|
|
}
|
|
|
|
function classifyNav(productType, productId, mid) {
|
|
const pt = String(productType || '').toLowerCase()
|
|
if (pt === 'section' && productId) {
|
|
return { kind: 'read', id: productId, mid: mid || 0, label: '阅读' }
|
|
}
|
|
if (pt === 'fullbook') {
|
|
return { kind: 'switchTab', path: '/pages/chapters/chapters', label: '去目录' }
|
|
}
|
|
if (pt === 'vip') {
|
|
return { kind: 'page', path: '/pages/vip/vip', label: '会员中心' }
|
|
}
|
|
if (pt === 'match') {
|
|
return { kind: 'switchTab', path: '/pages/match/match', label: '找伙伴' }
|
|
}
|
|
if (pt === 'balance_recharge') {
|
|
return { kind: 'page', path: '/pages/wallet/wallet', label: '余额' }
|
|
}
|
|
if (pt === 'gift_pay' || pt === 'gift_pay_batch') {
|
|
return { kind: 'page', path: '/pages/purchases/purchases', label: '查看' }
|
|
}
|
|
if (productId && (/^\d+\.\d+/.test(productId) || productId.length > 0)) {
|
|
return { kind: 'read', id: productId, mid: mid || 0, label: '阅读' }
|
|
}
|
|
return { kind: 'none', label: '--' }
|
|
}
|
|
|
|
function mapApiOrderToRow(item, bookFlat) {
|
|
const status = String(item.status || '').toLowerCase()
|
|
if (!PAID_STATUSES.has(status)) return null
|
|
|
|
const pt = String(item.product_type || '').toLowerCase()
|
|
const productId = String(item.product_id || item.section_id || '').trim()
|
|
let mid = Number(item.section_mid ?? item.mid ?? item.MID ?? 0) || 0
|
|
if (pt === 'section' && productId && !mid) mid = midForSection(productId, bookFlat)
|
|
|
|
const titleRaw = cleanSingleLineField(item.product_name || '')
|
|
const title =
|
|
titleRaw ||
|
|
(pt === 'balance_recharge' ? '余额充值' : productId ? `订单 ${productId}` : '消费记录')
|
|
|
|
const amt = Number(item.amount)
|
|
const amountStr = Number.isFinite(amt) ? amt.toFixed(2) : '--'
|
|
const t = parseOrderTimeMs(item)
|
|
const nav = classifyNav(pt, productId, mid)
|
|
|
|
return {
|
|
rowKey: String(item.order_sn || item.id || `o_${t}`),
|
|
kind: 'order',
|
|
title,
|
|
subLine: `¥${amountStr} · ${formatShortDate(t)}`,
|
|
actionLabel: nav.label,
|
|
nav,
|
|
_sortMs: t
|
|
}
|
|
}
|
|
|
|
Page({
|
|
data: {
|
|
statusBarHeight: 44,
|
|
loading: true,
|
|
allRows: [],
|
|
displayRows: [],
|
|
historyExpanded: false
|
|
},
|
|
|
|
onLoad() {
|
|
wx.showShareMenu({ withShareTimeline: true })
|
|
this.setData({ statusBarHeight: app.globalData.statusBarHeight })
|
|
this.loadOrders()
|
|
},
|
|
|
|
onShow() {
|
|
if (!this._purchasesFirstOnShowSkipped) {
|
|
this._purchasesFirstOnShowSkipped = true
|
|
return
|
|
}
|
|
if (app.globalData.isLoggedIn) this.loadOrders()
|
|
},
|
|
|
|
applyDisplay(expanded) {
|
|
const all = this.data.allRows || []
|
|
const display = expanded || all.length <= 5 ? all : all.slice(0, 5)
|
|
this.setData({ displayRows: display, historyExpanded: !!expanded })
|
|
},
|
|
|
|
expandHistory() {
|
|
if (this.data.historyExpanded) return
|
|
this.applyDisplay(true)
|
|
},
|
|
|
|
async loadOrders() {
|
|
this.setData({ loading: true })
|
|
const bookFlat = Array.isArray(app.globalData.bookData) ? app.globalData.bookData : []
|
|
const userId = app.globalData.userInfo?.id
|
|
|
|
try {
|
|
let orderRows = []
|
|
|
|
if (userId) {
|
|
const orderRes = await app.request({
|
|
url: `/api/miniprogram/orders?userId=${encodeURIComponent(userId)}`,
|
|
silent: true,
|
|
}).catch(() => null)
|
|
if (orderRes && orderRes.success && Array.isArray(orderRes.data)) {
|
|
orderRows = orderRes.data.map((item) => mapApiOrderToRow(item, bookFlat)).filter(Boolean)
|
|
}
|
|
}
|
|
|
|
if (!orderRows.length) {
|
|
const ids = [...(app.globalData.purchasedSections || [])].reverse()
|
|
orderRows = ids.map((id, index) => {
|
|
const mid = midForSection(id, bookFlat)
|
|
const row = bookFlat.find((s) => s.id === id)
|
|
const title =
|
|
cleanSingleLineField(
|
|
row?.sectionTitle || row?.section_title || row?.title || row?.chapterTitle || ''
|
|
) || `章节 ${id}`
|
|
const t = Date.now() - index * 86400000
|
|
return {
|
|
rowKey: `p_${id}_${index}`,
|
|
kind: 'order',
|
|
title,
|
|
subLine: `已解锁 · ${formatShortDate(t)}`,
|
|
actionLabel: '阅读',
|
|
nav: { kind: 'read', id, mid, label: '阅读' },
|
|
_sortMs: t,
|
|
}
|
|
})
|
|
}
|
|
|
|
let giftRows = []
|
|
if (userId && !app.globalData.auditMode) {
|
|
const giftRes = await app
|
|
.request(`/api/miniprogram/gift-pay/my-requests?userId=${encodeURIComponent(userId)}`, {
|
|
silent: true,
|
|
})
|
|
.catch(() => null)
|
|
if (giftRes && giftRes.success && Array.isArray(giftRes.list)) {
|
|
giftRows = giftRes.list.map(mapGiftPayToRow).filter(Boolean)
|
|
}
|
|
}
|
|
|
|
const merged = [...orderRows, ...giftRows].sort((a, b) => b._sortMs - a._sortMs)
|
|
const stripped = merged.map(({ _sortMs, ...rest }) => rest)
|
|
this.setData({ allRows: stripped, loading: false })
|
|
this.applyDisplay(false)
|
|
} catch (e) {
|
|
console.error('加载订单失败:', e)
|
|
this.setData({ allRows: [], loading: false })
|
|
this.applyDisplay(false)
|
|
}
|
|
},
|
|
|
|
onUnifiedRowTap(e) {
|
|
const index = e.currentTarget.dataset.index
|
|
const row = (this.data.displayRows || [])[index]
|
|
if (!row) return
|
|
if (row.kind === 'giftPay' && row.requestSn) {
|
|
wx.navigateTo({
|
|
url: `/pages/gift-pay/redemption-detail?requestSn=${encodeURIComponent(String(row.requestSn))}`,
|
|
})
|
|
return
|
|
}
|
|
if (!row.nav) return
|
|
const { nav } = row
|
|
if (nav.kind === 'read' && nav.id) {
|
|
const q = nav.mid ? `mid=${nav.mid}` : `id=${nav.id}`
|
|
wx.navigateTo({ url: `/pages/read/read?${q}` })
|
|
return
|
|
}
|
|
if (nav.kind === 'page' && nav.path) {
|
|
if (app.globalData.auditMode) {
|
|
const block = { '/pages/vip/vip': true, '/pages/wallet/wallet': true }
|
|
if (block[nav.path]) {
|
|
wx.showToast({ title: '当前为体验版,暂无法访问', icon: 'none' })
|
|
return
|
|
}
|
|
}
|
|
wx.navigateTo({ url: nav.path })
|
|
return
|
|
}
|
|
if (nav.kind === 'switchTab' && nav.path) {
|
|
wx.switchTab({ url: nav.path })
|
|
}
|
|
},
|
|
|
|
async onGiftPayCancel(e) {
|
|
if (e && typeof e.stopPropagation === 'function') e.stopPropagation()
|
|
const requestSn = e?.currentTarget?.dataset?.sn
|
|
if (!requestSn) return
|
|
const ok = await new Promise((r) => {
|
|
wx.showModal({ title: '取消代付', content: '确定取消该代付请求?', success: (res) => r(res.confirm) })
|
|
})
|
|
if (!ok) return
|
|
try {
|
|
const res = await app.request({
|
|
url: '/api/miniprogram/gift-pay/cancel',
|
|
method: 'POST',
|
|
data: { requestSn, userId: app.globalData.userInfo?.id },
|
|
})
|
|
if (res && res.success) {
|
|
wx.showToast({ title: '已取消', icon: 'success' })
|
|
this.loadOrders()
|
|
} else {
|
|
wx.showToast({ title: res?.error || '取消失败', icon: 'none' })
|
|
}
|
|
} catch (_) {
|
|
wx.showToast({ title: '取消失败', icon: 'none' })
|
|
}
|
|
},
|
|
|
|
onGiftPayShare(e) {
|
|
if (e && typeof e.stopPropagation === 'function') e.stopPropagation()
|
|
const requestSn = e?.currentTarget?.dataset?.sn
|
|
if (!requestSn) return
|
|
wx.navigateTo({
|
|
url: `/pages/gift-pay/detail?requestSn=${encodeURIComponent(String(requestSn))}`,
|
|
})
|
|
},
|
|
|
|
goBack() {
|
|
getApp().goBackOrToHome()
|
|
},
|
|
|
|
onShareAppMessage() {
|
|
const ref = app.getMyReferralCode()
|
|
return {
|
|
title: '卡若创业派对 - 订单与代付',
|
|
path: ref ? `/pages/purchases/purchases?ref=${ref}` : '/pages/purchases/purchases'
|
|
}
|
|
},
|
|
|
|
onShareTimeline() {
|
|
const ref = app.getMyReferralCode()
|
|
return { title: '卡若创业派对 - 订单与代付', query: ref ? `ref=${ref}` : '' }
|
|
}
|
|
})
|