diff --git a/App.vue b/App.vue
index d22b78e..841f8ed 100644
--- a/App.vue
+++ b/App.vue
@@ -1,8 +1,12 @@
-
-
\ No newline at end of file
diff --git a/pages/activity/duiduipeng/index.vue b/pages/activity/duiduipeng/index.vue
index e44d131..a66117f 100644
--- a/pages/activity/duiduipeng/index.vue
+++ b/pages/activity/duiduipeng/index.vue
@@ -5,7 +5,7 @@
diff --git a/pages/activity/wuxianshang.vue b/pages/activity/wuxianshang.vue
deleted file mode 100644
index a65a6c6..0000000
--- a/pages/activity/wuxianshang.vue
+++ /dev/null
@@ -1,65 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/pages/activity/wuxianshang/index.vue b/pages/activity/wuxianshang/index.vue
index 954b074..a81f871 100644
--- a/pages/activity/wuxianshang/index.vue
+++ b/pages/activity/wuxianshang/index.vue
@@ -5,11 +5,11 @@
-
-
+
+
@@ -27,6 +27,13 @@
+
@@ -35,7 +42,8 @@ import { ref, computed, getCurrentInstance } from 'vue'
import ElCard from '../../../components/ElCard.vue'
import FlipGrid from '../../../components/FlipGrid.vue'
import { onLoad } from '@dcloudio/uni-app'
-import { getActivityDetail, getActivityIssues, getActivityIssueRewards, drawActivityIssue } from '../../../api/appUser'
+import PaymentPopup from '../../../components/PaymentPopup.vue'
+import { getActivityDetail, getActivityIssues, getActivityIssueRewards, joinLottery, createWechatOrder, getLotteryResult, getItemCards, getUserCoupons } from '../../../api/appUser'
const detail = ref({})
const statusText = ref('')
@@ -56,6 +64,14 @@ const currentIssueTitle = computed(() => {
const points = ref(0)
const flipRef = ref(null)
const showFlip = ref(false)
+const paymentVisible = ref(false)
+const paymentAmount = ref('0.00')
+const coupons = ref([])
+const propCards = ref([])
+const pendingCount = ref(1)
+const selectedCoupon = ref(null)
+const selectedCard = ref(null)
+const pricePerDrawYuan = computed(() => ((Number(detail.value.price_draw || 0) / 100) || 0))
function statusToText(s) {
if (s === 1) return '进行中'
@@ -220,27 +236,134 @@ function onPreviewBanner() {
if (url) uni.previewImage({ urls: [url], current: url })
}
+function openPayment(count) {
+ const times = Math.max(1, Number(count || 1))
+ pendingCount.value = times
+ paymentAmount.value = (pricePerDrawYuan.value * times).toFixed(2)
+ const token = uni.getStorageSync('token')
+ const phoneBound = !!uni.getStorageSync('phone_bound')
+ if (!token || !phoneBound) {
+ uni.showModal({
+ title: '提示',
+ content: '请先登录并绑定手机号',
+ confirmText: '去登录',
+ success: (res) => { if (res.confirm) uni.navigateTo({ url: '/pages/login/index' }) }
+ })
+ return
+ }
+ paymentVisible.value = true
+ fetchPropCards()
+ fetchCoupons()
+}
-function onMachineDraw(count) {
+async function onPaymentConfirm(data) {
+ selectedCoupon.value = data && data.coupon ? data.coupon : null
+ selectedCard.value = data && data.card ? data.card : null
+ paymentVisible.value = false
+ await onMachineDraw(pendingCount.value)
+}
+
+async function fetchPropCards() {
+ const user_id = uni.getStorageSync('user_id')
+ if (!user_id) return
+ try {
+ const res = await getItemCards(user_id)
+ let list = []
+ if (Array.isArray(res)) list = res
+ else if (res && Array.isArray(res.list)) list = res.list
+ else if (res && Array.isArray(res.data)) list = res.data
+ propCards.value = list.map((i, idx) => ({
+ id: i.id ?? i.card_id ?? String(idx),
+ name: i.name ?? i.title ?? '道具卡'
+ }))
+ } catch (e) {
+ propCards.value = []
+ }
+}
+
+async function fetchCoupons() {
+ const user_id = uni.getStorageSync('user_id')
+ if (!user_id) return
+ try {
+ const res = await getUserCoupons(user_id, 0, 1, 100)
+ let list = []
+ if (Array.isArray(res)) list = res
+ else if (res && Array.isArray(res.list)) list = res.list
+ else if (res && Array.isArray(res.data)) list = res.data
+ coupons.value = list.map((i, idx) => {
+ const amountCents = (i.remaining !== undefined && i.remaining !== null) ? Number(i.remaining) : Number(i.amount ?? i.value ?? 0)
+ const amt = isNaN(amountCents) ? 0 : (amountCents / 100)
+ return {
+ id: i.id ?? i.coupon_id ?? String(idx),
+ name: i.name ?? i.title ?? '优惠券',
+ amount: Number(amt).toFixed(2)
+ }
+ })
+ } catch (e) {
+ coupons.value = []
+ }
+}
+
+async function onMachineDraw(count) {
showFlip.value = true
try { if (flipRef.value && flipRef.value.reset) flipRef.value.reset() } catch (_) {}
const aid = activityId.value || ''
const iid = currentIssueId.value || ''
if (!aid || !iid) { uni.showToast({ title: '期数未选择', icon: 'none' }); return }
+ const token = uni.getStorageSync('token')
+ const phoneBound = !!uni.getStorageSync('phone_bound')
+ if (!token || !phoneBound) {
+ uni.showModal({
+ title: '提示',
+ content: '请先登录并绑定手机号',
+ confirmText: '去登录',
+ success: (res) => { if (res.confirm) uni.navigateTo({ url: '/pages/login/index' }) }
+ })
+ return
+ }
+ const openid = uni.getStorageSync('openid')
+ if (!openid) { uni.showToast({ title: '缺少OpenID,请重新登录', icon: 'none' }); return }
drawLoading.value = true
- const times = Math.max(1, Number(count || 1))
- const calls = Array(times).fill(0).map(() => drawActivityIssue(aid, iid))
- Promise.allSettled(calls).then(list => {
- drawLoading.value = false
- const items = list.map(r => {
- const obj = r.status === 'fulfilled' ? r.value : {}
- const data = obj && (obj.data || obj.result || obj.reward || obj.item || obj)
- const title = String((data && (data.title || data.name || data.product_name)) || '未知奖励')
- const image = String((data && (data.image || data.img || data.pic || data.product_image)) || '')
+ try {
+ const times = Math.max(1, Number(count || 1))
+ const joinRes = await joinLottery({
+ activity_id: Number(aid),
+ issue_id: Number(iid),
+ channel: 'miniapp',
+ count: times,
+ coupon_id: selectedCoupon.value && selectedCoupon.value.id ? Number(selectedCoupon.value.id) : 0,
+ item_card_id: selectedCard.value && selectedCard.value.id ? Number(selectedCard.value.id) : 0
+ })
+ const orderNo = joinRes && (joinRes.order_no || joinRes.data?.order_no || joinRes.result?.order_no)
+ if (!orderNo) throw new Error('未获取到订单号')
+ const payRes = await createWechatOrder({ openid, order_no: orderNo })
+ await new Promise((resolve, reject) => {
+ uni.requestPayment({
+ provider: 'wxpay',
+ timeStamp: payRes.timeStamp || payRes.timestamp,
+ nonceStr: payRes.nonceStr || payRes.noncestr,
+ package: payRes.package,
+ signType: payRes.signType || 'MD5',
+ paySign: payRes.paySign,
+ success: resolve,
+ fail: reject
+ })
+ })
+ const resultRes = await getLotteryResult(orderNo)
+ const raw = resultRes && (resultRes.list || resultRes.items || resultRes.data || resultRes.result || resultRes)
+ const arr = Array.isArray(raw) ? raw : (Array.isArray(resultRes?.data) ? resultRes.data : [raw])
+ const items = arr.filter(Boolean).map(d => {
+ const title = String((d && (d.title || d.name || d.product_name)) || '奖励')
+ const image = String((d && (d.image || d.img || d.pic || d.product_image)) || '')
return { title, image }
})
if (flipRef.value && flipRef.value.revealResults) flipRef.value.revealResults(items)
- }).catch(() => { drawLoading.value = false; if (flipRef.value && flipRef.value.revealResults) flipRef.value.revealResults([{ title: '抽选失败', image: '' }]) })
+ } catch (e) {
+ if (flipRef.value && flipRef.value.revealResults) flipRef.value.revealResults([{ title: e.message || '抽选失败', image: '' }])
+ uni.showToast({ title: e.message || '操作失败', icon: 'none' })
+ } finally {
+ drawLoading.value = false
+ }
}
function onMachineTry() {
diff --git a/pages/activity/yifanshang.vue b/pages/activity/yifanshang.vue
deleted file mode 100644
index 72c6d59..0000000
--- a/pages/activity/yifanshang.vue
+++ /dev/null
@@ -1,66 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/pages/activity/yifanshang/index.vue b/pages/activity/yifanshang/index.vue
index 8da00cd..0f29be7 100644
--- a/pages/activity/yifanshang/index.vue
+++ b/pages/activity/yifanshang/index.vue
@@ -5,13 +5,9 @@
-
-
-
-
+ 抽选价:¥{{ (Number(detail.price_draw || 0) / 100).toFixed(2) }}
+
@@ -19,6 +15,17 @@
+
+
+
+
+
+
@@ -35,7 +42,8 @@ import { ref, computed, getCurrentInstance } from 'vue'
import ElCard from '../../../components/ElCard.vue'
import { onLoad } from '@dcloudio/uni-app'
import FlipGrid from '../../../components/FlipGrid.vue'
-import { getActivityDetail, getActivityIssues, getActivityIssueRewards, drawActivityIssue, getActivityWinRecords } from '../../../api/appUser'
+import YifanSelector from '@/components/YifanSelector.vue'
+import { getActivityDetail, getActivityIssues, getActivityIssueRewards, getActivityWinRecords } from '../../../api/appUser'
const detail = ref({})
const issues = ref([])
@@ -242,34 +250,38 @@ function onPreviewBanner() {
}
-function onMachineDraw(count) {
+function onPaymentSuccess(payload) {
+ console.log('Payment Success:', payload)
+
+ const result = payload.result
+ let wonItems = []
+
+ // 尝试解析返回结果中的奖励列表
+ if (Array.isArray(result)) {
+ wonItems = result
+ } else if (result && Array.isArray(result.list)) {
+ wonItems = result.list
+ } else if (result && Array.isArray(result.data)) {
+ wonItems = result.data
+ } else if (result && Array.isArray(result.rewards)) {
+ wonItems = result.rewards
+ } else {
+ // 兜底:如果是单对象或无法识别,尝试作为单个物品处理
+ wonItems = result ? [result] : []
+ }
+
+ const items = wonItems.map(data => {
+ const title = String((data && (data.title || data.name || data.product_name || data.reward_name)) || '未知奖励')
+ const image = String((data && (data.image || data.img || data.pic || data.product_image || data.reward_image)) || '')
+ return { title, image }
+ })
+
showFlip.value = true
try { if (flipRef.value && flipRef.value.reset) flipRef.value.reset() } catch (_) {}
- const aid = activityId.value || ''
- const iid = currentIssueId.value || ''
- if (!aid || !iid) { uni.showToast({ title: '期数未选择', icon: 'none' }); return }
- drawLoading.value = true
- const times = Math.max(1, Number(count || 1))
- const calls = Array(times).fill(0).map(() => drawActivityIssue(aid, iid))
- Promise.allSettled(calls).then(list => {
- drawLoading.value = false
- const items = list.map(r => {
- const obj = r.status === 'fulfilled' ? r.value : {}
- const data = obj && (obj.data || obj.result || obj.reward || obj.item || obj)
- const title = String((data && (data.title || data.name || data.product_name)) || '未知奖励')
- const image = String((data && (data.image || data.img || data.pic || data.product_image)) || '')
- return { title, image }
- })
+
+ setTimeout(() => {
if (flipRef.value && flipRef.value.revealResults) flipRef.value.revealResults(items)
- }).catch(() => { drawLoading.value = false; if (flipRef.value && flipRef.value.revealResults) flipRef.value.revealResults([{ title: '抽选失败', image: '' }]) })
-}
-
-function onMachineTry() {
- const list = rewardsMap.value[currentIssueId.value] || []
- if (!list.length) { uni.showToast({ title: '暂无奖池', icon: 'none' }); return }
- const idx = Math.floor(Math.random() * list.length)
- const it = list[idx]
- uni.showModal({ title: '试一试', content: it.title || '随机预览', showCancel: false, success: () => { if (it.image) uni.previewImage({ urls: [it.image], current: it.image }) } })
+ }, 100)
}
onLoad((opts) => {
@@ -307,7 +319,19 @@ function closeFlip() { showFlip.value = false }
.issues-title { font-size: 30rpx; font-weight: 600; margin-bottom: 12rpx }
.issues-list { }
.issue-switch { display: flex; align-items: center; justify-content: center; gap: 12rpx; margin: 0 24rpx 24rpx }
-.switch-btn { width: 72rpx; height: 72rpx; border-radius: 999rpx; background: #fff3df; border: 2rpx solid #f0c58a; color: #8a5a2b }
+.switch-btn {
+ width: 72rpx;
+ height: 72rpx;
+ border-radius: 999rpx;
+ background: #fff3df;
+ border: 2rpx solid #f0c58a;
+ color: #8a5a2b;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 0;
+ line-height: 1;
+}
.issue-title { font-size: 28rpx; color: #6b4b1f; background: #ffdfaa; border-radius: 12rpx; padding: 8rpx 16rpx }
.reward { display: flex; align-items: center; margin-bottom: 8rpx }
.reward-img { width: 80rpx; height: 80rpx; border-radius: 8rpx; margin-right: 12rpx; background: #f5f5f5 }
diff --git a/pages/cabinet/index.vue b/pages/cabinet/index.vue
index cfc3ba7..f990f13 100644
--- a/pages/cabinet/index.vue
+++ b/pages/cabinet/index.vue
@@ -1,13 +1,123 @@
- 货柜
+
+
+
+
+ 待处理
+ ({{ aggregatedList.length }})
+
+
+ 已申请发货
+ ({{ shippedList.length }})
+
+
+
+
+
+
+
+
+
+ 全选
+
+
+
+ 加载中...
+ 背包空空如也
+
+
+
+
+
+
+
+
+ {{ item.name || '未命名道具' }}
+ 单价: ¥{{ item.price }}
+
+ x{{ item.count || 1 }}
+
+ -
+ {{ item.selectedCount }}
+ +
+
+
+
+
+
+ 加载更多...
+ 没有更多了
+
+
+
+ 已选 {{ totalSelectedCount }} 件
+
+
+
+
+
+
+
+
+
+
+ 加载中...
+ 暂无已发货记录
+
+
+
+
+
+
+ {{ item.name || '未命名道具' }}
+ x{{ item.count || 1 }}
+ 已申请发货
+ 快递:{{ item.express_code }} {{ item.express_no }}
+ 发货时间:{{ formatDate(item.shipped_at) }}
+ 签收时间:{{ formatDate(item.received_at) }}
+
+
+
+ 加载更多...
+ 没有更多了
+
+
\ No newline at end of file
+.item-status {
+ font-size: 24rpx;
+ color: #007AFF;
+ margin-top: 4rpx;
+}
+.item-meta { font-size: 22rpx; color: #666; margin-top: 4rpx }
+
+.wrap { padding: 30rpx; }
+
+.tabs {
+ display: flex;
+ background: #f5f5f5;
+ border-radius: 16rpx;
+ padding: 8rpx;
+ margin-bottom: 20rpx;
+}
+
+.action-bar {
+ display: flex;
+ align-items: center;
+ margin-bottom: 20rpx;
+ padding: 0 10rpx;
+}
+
+.select-all {
+ display: flex;
+ align-items: center;
+ font-size: 28rpx;
+ color: #333;
+}
+
+.select-all .checkbox {
+ margin-right: 12rpx;
+}
+
+.tab-item {
+ flex: 1;
+ text-align: center;
+ font-size: 28rpx;
+ color: #666;
+ padding: 20rpx 0;
+ border-radius: 12rpx;
+ transition: all 0.3s ease;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ gap: 8rpx;
+}
+
+.tab-item.active {
+ background: #fff;
+ color: #007AFF;
+ font-weight: bold;
+ box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
+}
+
+.tab-text {
+ font-size: 28rpx;
+}
+
+.tab-count {
+ font-size: 24rpx;
+ opacity: 0.8;
+}
+
+.header { font-size: 32rpx; font-weight: bold; margin-bottom: 30rpx; }
+.status-text { text-align: center; color: #999; margin-top: 100rpx; }
+
+.inventory-grid {
+ display: flex;
+ flex-direction: column;
+ gap: 20rpx;
+}
+
+.inventory-item {
+ background: #fff;
+ border-radius: 12rpx;
+ padding: 24rpx;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ box-shadow: 0 2rpx 10rpx rgba(0,0,0,0.05);
+}
+
+.item-image {
+ width: 120rpx;
+ height: 120rpx;
+ margin-right: 24rpx;
+ margin-bottom: 0;
+ border-radius: 8rpx;
+ background-color: #f5f5f5;
+ flex-shrink: 0;
+}
+
+.item-info {
+ flex: 1;
+ text-align: left;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+}
+
+.item-name {
+ font-size: 26rpx;
+ color: #333;
+ display: block;
+ margin-bottom: 4rpx;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.item-count {
+ font-size: 24rpx;
+ color: #999;
+ margin-bottom: 4rpx;
+}
+
+.item-price {
+ font-size: 24rpx;
+ color: #ff4d4f;
+}
+
+.checkbox-area {
+ padding: 10rpx 20rpx 10rpx 0;
+ display: flex;
+ align-items: center;
+}
+
+.checkbox {
+ width: 40rpx;
+ height: 40rpx;
+ border: 2rpx solid #ccc;
+ border-radius: 50%;
+ position: relative;
+}
+
+.checkbox.checked {
+ background-color: #007AFF;
+ border-color: #007AFF;
+}
+
+.checkbox.checked::after {
+ content: '';
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -60%) rotate(45deg);
+ width: 10rpx;
+ height: 20rpx;
+ border-right: 4rpx solid #fff;
+ border-bottom: 4rpx solid #fff;
+}
+
+.item-actions {
+ margin-top: 10rpx;
+ display: flex;
+ align-items: center;
+}
+
+.stepper {
+ display: flex;
+ align-items: center;
+ border: 1px solid #ddd;
+ border-radius: 8rpx;
+ height: 48rpx;
+}
+
+.step-btn {
+ width: 48rpx;
+ height: 100%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background-color: #f8f8f8;
+ font-size: 32rpx;
+ color: #666;
+}
+
+.step-btn.minus { border-right: 1px solid #ddd; }
+.step-btn.plus { border-left: 1px solid #ddd; }
+
+.step-num {
+ width: 60rpx;
+ text-align: center;
+ font-size: 26rpx;
+ color: #333;
+}
+
+.bottom-bar {
+ position: fixed;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ height: 100rpx;
+ background-color: #fff;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 0 30rpx;
+ box-shadow: 0 -2rpx 10rpx rgba(0,0,0,0.05);
+ z-index: 100;
+ padding-bottom: constant(safe-area-inset-bottom);
+ padding-bottom: env(safe-area-inset-bottom);
+}
+
+.selected-info {
+ font-size: 28rpx;
+ color: #333;
+ font-weight: bold;
+}
+
+.btn-group {
+ display: flex;
+ gap: 20rpx;
+}
+
+.action-btn {
+ margin: 0;
+ height: 64rpx;
+ line-height: 64rpx;
+ font-size: 26rpx;
+ border-radius: 32rpx;
+ padding: 0 40rpx;
+}
+
+.btn-ship {
+ background-color: #f0ad4e;
+ color: #fff;
+}
+
+.btn-redeem {
+ background-color: #dd524d;
+ color: #fff;
+}
+
+.bottom-spacer {
+ height: 120rpx;
+ height: calc(120rpx + constant(safe-area-inset-bottom));
+ height: calc(120rpx + env(safe-area-inset-bottom));
+}
+
diff --git a/pages/index/index.vue b/pages/index/index.vue
index bca5b27..bd43b71 100644
--- a/pages/index/index.vue
+++ b/pages/index/index.vue
@@ -173,7 +173,7 @@ export default {
const base = i.subTitle ?? i.sub_title ?? i.subtitle ?? i.desc ?? i.description ?? ''
if (base) return base
const cat = i.category_name ?? i.categoryName ?? ''
- const price = (i.price_draw !== undefined && i.price_draw !== null) ? `¥${i.price_draw}` : ''
+ const price = (i.price_draw !== undefined && i.price_draw !== null) ? `¥${(Number(i.price_draw || 0) / 100).toFixed(2)}` : ''
const parts = [cat, price].filter(Boolean)
return parts.join(' · ')
},
diff --git a/pages/login/index.vue b/pages/login/index.vue
index e720bc7..d71e622 100644
--- a/pages/login/index.vue
+++ b/pages/login/index.vue
@@ -1,9 +1,50 @@
- 微信登录
-
+
+
+
+ 账号:
+
+
+
+
+ 密码:
+
+
+
+
+
+
+ 记住账号密码
+
+
+
+
+
+
+
+ 还没有账号?点击注册
+
+
+
+
+
+
+ 微信登录
+
+
@@ -18,15 +59,39 @@
\ No newline at end of file
+
+/* 积分弹窗样式 */
+.popup-mask {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background-color: rgba(0, 0, 0, 0.6);
+ z-index: 999;
+ display: flex;
+ align-items: flex-end;
+}
+
+.popup-content {
+ width: 100%;
+ height: 70vh;
+ background-color: #fff;
+ border-radius: 24rpx 24rpx 0 0;
+ display: flex;
+ flex-direction: column;
+}
+
+.popup-header {
+ padding: 30rpx;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ border-bottom: 1rpx solid #eee;
+}
+
+.popup-title {
+ font-size: 32rpx;
+ font-weight: bold;
+}
+
+.close-btn {
+ font-size: 40rpx;
+ color: #999;
+ padding: 0 10rpx;
+}
+
+.points-list {
+ flex: 1;
+ overflow-y: auto;
+ padding: 0 30rpx;
+ box-sizing: border-box; /* 确保 padding 不增加宽度 */
+}
+
+.point-item {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 24rpx 0;
+ border-bottom: 1rpx solid #f5f5f5;
+ width: 100%; /* 确保子项占满 */
+}
+
+.point-left {
+ display: flex;
+ flex-direction: column;
+ flex: 1; /* 占据剩余空间 */
+ min-width: 0; /* 关键:允许 flex 子项缩小,防止内容撑开 */
+ margin-right: 20rpx;
+}
+
+.point-desc {
+ font-size: 28rpx;
+ color: #333;
+ margin-bottom: 8rpx;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.point-time {
+ font-size: 24rpx;
+ color: #999;
+}
+
+.point-right {
+ flex-shrink: 0; /* 防止被压缩 */
+ margin-left: auto; /* 靠右对齐 */
+ text-align: right;
+ max-width: 40%; /* 限制最大宽度 */
+}
+
+.point-amount {
+ font-size: 32rpx;
+ font-weight: bold;
+ color: #333;
+ display: block;
+}
+
+.point-amount.positive {
+ color: #ff4d4f;
+}
+
+.point-amount.negative {
+ color: #52c41a;
+}
+
+.status-text {
+ text-align: center;
+ color: #999;
+ margin-top: 60rpx;
+ font-size: 28rpx;
+}
+
+.loading-more, .no-more {
+ text-align: center;
+ color: #999;
+ padding: 20rpx 0;
+ font-size: 24rpx;
+}
+
+/* 优惠券弹窗样式 */
+.popup-tabs {
+ display: flex;
+ border-bottom: 1rpx solid #eee;
+}
+.popup-tab {
+ flex: 1;
+ text-align: center;
+ padding: 24rpx 0;
+ font-size: 28rpx;
+ color: #666;
+ position: relative;
+}
+.popup-tab.active {
+ color: #007AFF;
+ font-weight: bold;
+}
+.popup-tab.active::after {
+ content: '';
+ position: absolute;
+ bottom: 0;
+ left: 50%;
+ transform: translateX(-50%);
+ width: 40rpx;
+ height: 4rpx;
+ background-color: #007AFF;
+ border-radius: 2rpx;
+}
+.redeem-container {
+ padding: 40rpx;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+.redeem-input {
+ width: 100%;
+ height: 80rpx;
+ border: 1rpx solid #ddd;
+ border-radius: 8rpx;
+ padding: 0 20rpx;
+ margin-bottom: 40rpx;
+ font-size: 28rpx;
+ box-sizing: border-box;
+}
+.redeem-btn {
+ width: 100%;
+ height: 80rpx;
+ line-height: 80rpx;
+ background-color: #007AFF;
+ color: #fff;
+ font-size: 32rpx;
+ border-radius: 40rpx;
+}
+.coupon-item {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 24rpx;
+ margin: 20rpx 0;
+ background: #f9f9f9;
+ border-radius: 12rpx;
+ border: 1rpx solid #eee;
+}
+.coupon-left {
+ display: flex;
+ flex-direction: column;
+ flex: 1;
+}
+.coupon-name {
+ font-size: 30rpx;
+ font-weight: bold;
+ color: #333;
+}
+.coupon-desc {
+ font-size: 24rpx;
+ color: #666;
+ margin-top: 8rpx;
+}
+.coupon-time {
+ font-size: 22rpx;
+ color: #999;
+ margin-top: 8rpx;
+}
+.coupon-right {
+ margin-left: 20rpx;
+ display: flex;
+ flex-direction: column;
+ align-items: flex-end;
+}
+.coupon-amount-wrapper {
+ color: #ff4d4f;
+ margin-bottom: 8rpx;
+ display: flex;
+ align-items: baseline;
+}
+.symbol {
+ font-size: 24rpx;
+ font-weight: bold;
+}
+.amount-value {
+ font-size: 40rpx;
+ font-weight: bold;
+ line-height: 1;
+}
+.coupon-status {
+ font-size: 26rpx;
+ color: #999;
+}
+
+.task-item { display: flex; justify-content: space-between; align-items: flex-start; padding: 24rpx; margin: 20rpx 0; background: #f9f9f9; border-radius: 12rpx; border: 1rpx solid #eee }
+.task-left { flex: 1; display: flex; flex-direction: column }
+.task-name { font-size: 30rpx; font-weight: 700; color: #333 }
+.task-desc { margin-top: 6rpx; font-size: 24rpx; color: #666 }
+.task-time { margin-top: 6rpx; font-size: 22rpx; color: #999 }
+.reward-list { margin-top: 10rpx }
+.reward-label, .tier-label { font-size: 24rpx; color: #666 }
+.reward-tags, .tier-tags { margin-top: 8rpx; display: flex; flex-wrap: wrap; gap: 8rpx }
+.reward-item, .tier-item { background: #fff; border: 1rpx solid #eee; border-radius: 999rpx; padding: 8rpx 12rpx; display: flex; align-items: center; gap: 8rpx }
+.reward-type { font-size: 24rpx; color: #333 }
+.reward-qty { font-size: 22rpx; color: #999 }
+.tier-text { font-size: 24rpx; color: #333 }
+.task-right { margin-left: 12rpx; display: flex; align-items: center }
+.task-status { font-size: 26rpx; color: #007AFF }
+
diff --git a/pages/orders/index.vue b/pages/orders/index.vue
index 3b47f0c..f634d9d 100644
--- a/pages/orders/index.vue
+++ b/pages/orders/index.vue
@@ -13,7 +13,7 @@
{{ formatAmount(item.total_amount || item.amount || item.price) }}
- {{ statusText(item.status || item.pay_status || item.state) }}
+ {{ statusText(item) }}
加载中...
@@ -50,13 +50,18 @@ function formatAmount(a) {
if (a === undefined || a === null) return ''
const n = Number(a)
if (Number.isNaN(n)) return String(a)
- return `¥${n.toFixed(2)}`
+ const yuan = n / 100
+ return `¥${yuan.toFixed(2)}`
}
-function statusText(s) {
- const v = String(s || '').toLowerCase()
- if (v.includes('pend')) return '待付款'
- if (v.includes('paid') || v.includes('complete') || v.includes('done')) return '已完成'
+function statusText(item) {
+ const v = item && (item.is_draw ?? item.drawed ?? item.completed)
+ const ok = v === true || v === 1 || String(v) === 'true' || String(v) === '1'
+ if (ok) return '已完成'
+ const s = item && (item.status || item.pay_status || item.state)
+ const t = String(s || '').toLowerCase()
+ if (t.includes('pend')) return '待付款'
+ if (t.includes('paid') || t.includes('complete') || t.includes('done')) return '已完成'
return s || ''
}
@@ -87,15 +92,20 @@ async function fetchOrders(append) {
})
return
}
- if (append) {
+ if (!append) {
+ if (currentTab.value === 'completed') {
+ await fetchAllOrders()
+ return
+ } else {
+ loading.value = true
+ page.value = 1
+ hasMore.value = true
+ orders.value = []
+ }
+ } else {
if (!hasMore.value || loadingMore.value) return
loadingMore.value = true
page.value = page.value + 1
- } else {
- loading.value = true
- page.value = 1
- hasMore.value = true
- orders.value = []
}
error.value = ''
try {
@@ -119,6 +129,29 @@ async function fetchOrders(append) {
}
}
+async function fetchAllOrders() {
+ const user_id = uni.getStorageSync('user_id')
+ loading.value = true
+ page.value = 1
+ hasMore.value = false
+ orders.value = []
+ try {
+ const first = await getOrders(user_id, apiStatus(), 1, pageSize.value)
+ const itemsFirst = Array.isArray(first) ? first : (first && first.items) || (first && first.list) || []
+ const total = (first && first.total) || 0
+ orders.value = itemsFirst
+ const totalPages = Math.max(1, Math.ceil(Number(total) / pageSize.value))
+ for (let p = 2; p <= totalPages; p++) {
+ const res = await getOrders(user_id, apiStatus(), p, pageSize.value)
+ const items = Array.isArray(res) ? res : (res && res.items) || (res && res.list) || []
+ orders.value = orders.value.concat(items)
+ }
+ } catch (e) {
+ error.value = e && (e.message || e.errMsg) || '获取订单失败'
+ } finally {
+ loading.value = false
+ }
+}
onLoad((opts) => {
const s = (opts && opts.status) || ''
if (s === 'completed' || s === 'pending') currentTab.value = s
@@ -146,4 +179,4 @@ onReachBottom(() => {
.error { color: #e43; margin-bottom: 12rpx }
.loading { text-align: center; color: #666; margin: 20rpx 0 }
.end { text-align: center; color: #999; margin: 20rpx 0 }
-
\ No newline at end of file
+
diff --git a/pages/shop/index.vue b/pages/shop/index.vue
index 2e26794..2b9cea9 100644
--- a/pages/shop/index.vue
+++ b/pages/shop/index.vue
@@ -1,15 +1,15 @@
-
-
+
+
提示
由于价格浮动,当前暂不支持自行兑换商品,兑换请联系客服核对价格。
-
+
不再显示
-
+
@@ -151,7 +151,7 @@ function normalizeProducts(list) {
id: i.id ?? i.productId ?? i._id ?? i.sku_id ?? String(idx),
image: cleanUrl(i.main_image ?? i.imageUrl ?? i.image_url ?? i.image ?? i.img ?? i.pic ?? ''),
title: i.title ?? i.name ?? i.product_name ?? i.sku_name ?? '',
- price: i.price_sale ?? i.price ?? i.price_min ?? i.amount ?? null,
+ price: (() => { const raw = i.price_sale ?? i.price ?? i.price_min ?? i.amount ?? null; return raw == null ? null : (Number(raw) / 100) })(),
points: i.points_required ?? i.points ?? i.integral ?? null,
stock: i.stock ?? i.inventory ?? i.quantity ?? null,
link: cleanUrl(i.linkUrl ?? i.link_url ?? i.link ?? i.url ?? '')
@@ -159,12 +159,9 @@ function normalizeProducts(list) {
}
function onProductTap(p) {
- const imgs = (Array.isArray(products.value) ? products.value : []).map(x => x.image).filter(Boolean)
- const current = p && p.image
- if (current) {
- skipReloadOnce.value = true
- try { uni.setStorageSync('shop_skip_reload_once', '1') } catch (_) {}
- uni.previewImage({ urls: imgs.length ? imgs : [current], current })
+ const id = p && p.id
+ if (id !== undefined && id !== null && id !== '') {
+ uni.navigateTo({ url: `/pages/shop/detail?id=${id}` })
return
}
if (p.link && /^\/.+/.test(p.link)) {