diff --git a/pages/activity/duiduipeng/index.vue b/pages/activity/duiduipeng/index.vue
index a825a1e..564caf1 100644
--- a/pages/activity/duiduipeng/index.vue
+++ b/pages/activity/duiduipeng/index.vue
@@ -1133,15 +1133,22 @@ async function fetchPropCards() {
const user_id = uni.getStorageSync('user_id')
if (!user_id) return
try {
- const res = await getItemCards(user_id, 0)
+ // Status 1 = Unused
+ const res = await getItemCards(user_id, 1)
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 ?? i.item_card_id ?? String(idx),
- name: i.name ?? i.title ?? i.card_name ?? '道具卡'
- }))
+ propCards.value = list.map((i, idx) => {
+ const count = i.count ?? i.remaining ?? 1
+ const name = i.name ?? i.title ?? i.card_name ?? '道具卡'
+ return {
+ id: i.id ?? i.card_id ?? i.item_card_id ?? String(idx),
+ name: `${name} (×${count})`,
+ rawName: name,
+ count: count
+ }
+ })
} catch (e) {
propCards.value = []
}
diff --git a/pages/cabinet/index.vue b/pages/cabinet/index.vue
index 335dd06..a61a966 100644
--- a/pages/cabinet/index.vue
+++ b/pages/cabinet/index.vue
@@ -159,6 +159,15 @@ const isAllSelected = computed(() => {
})
onShow(() => {
+ // Check for external tab switch request
+ try {
+ const targetTab = uni.getStorageSync('cabinet_target_tab')
+ if (targetTab !== '' && targetTab !== null && targetTab !== undefined) {
+ currentTab.value = Number(targetTab)
+ uni.removeStorageSync('cabinet_target_tab')
+ }
+ } catch (e) {}
+
const token = uni.getStorageSync('token')
const phoneBound = !!uni.getStorageSync('phone_bound')
console.log('cabinet onShow token:', token, 'isLogin:', !!token, 'phoneBound:', phoneBound)
diff --git a/pages/mine/index.vue b/pages/mine/index.vue
index b2cb6bc..5714cb5 100644
--- a/pages/mine/index.vue
+++ b/pages/mine/index.vue
@@ -93,30 +93,34 @@
全部订单 ›
-
-
-
-
- 盒柜
-
+
待付款
-
+
+
待发货
-
+
+
已发货
+
+
+
+
+
+ 全部订单
+
@@ -254,7 +258,12 @@
-
-
- 使用时间:{{ formatDateTime(item.used_at) }}
@@ -598,6 +604,10 @@ export default {
toOrders(status) {
uni.navigateTo({ url: `/pages/orders/index?status=${status}` })
},
+ toCabinetTab(tabIndex) {
+ uni.setStorageSync('cabinet_target_tab', tabIndex)
+ uni.switchTab({ url: '/pages/cabinet/index' })
+ },
toAddresses() {
uni.navigateTo({ url: '/pages/address/index' })
},
@@ -790,23 +800,27 @@ export default {
this.itemCardsLoading = true
this.itemCardsList = []
try {
- // Mocking used status via local filter if API doesn't support
- // Or assume API supports status param.
- const res = await getItemCards(this.userId)
- // Assuming res is list of cards with counts.
- // For "used", we might need a different API or field.
- // For now, just show all for unused, and empty for used as mock.
- let list = Array.isArray(res) ? res : (res.list || [])
+ // Pass status: 0(tab)=>1(unused), 1(tab)=>2(used)
+ const status = this.itemCardsTab === 0 ? 1 : 2
+ const res = await getItemCards(this.userId, status)
+ // Robustly get the list (support res.list or res.data)
+ let list = Array.isArray(res) ? res : (res.list || res.data || [])
+
+ this.itemCardsList = list.map(item => {
+ return {
+ ...item,
+ // Ensure count exists, default to 1 if undefined
+ count: item.count ?? item.remaining ?? 1
+ }
+ })
+
+ // For unused tab, filter out items with 0 count if any
if (this.itemCardsTab === 0) {
- // Show cards with count > 0
- this.itemCardsList = list.filter(i => (i.count || i.remaining) > 0)
- } else {
- // Mock used history or filter
- this.itemCardsList = []
+ this.itemCardsList = this.itemCardsList.filter(i => i.count > 0)
}
} catch (e) {
- console.error(e)
+ console.error('loadItemCards error:', e)
} finally {
this.itemCardsLoading = false
}
@@ -882,8 +896,24 @@ export default {
},
formatDateTime(ts) {
if (!ts) return ''
- const d = new Date(ts * 1000)
- return `${this.formatDate(ts)} ${String(d.getHours()).padStart(2,'0')}:${String(d.getMinutes()).padStart(2,'0')}`
+ // Convert string timestamp (e.g. "2023-01-01T...") to timestamp if needed
+ let d
+ if (typeof ts === 'string') {
+ // iOS compatibility for ISO strings
+ const safeTs = ts.replace(/-/g, '/')
+ d = new Date(safeTs)
+ if (isNaN(d.getTime())) {
+ // Fallback for non-ISO strings or just numbers as strings
+ const n = Number(ts)
+ if (!isNaN(n)) d = new Date(n * 1000)
+ }
+ } else {
+ d = new Date(ts * 1000)
+ }
+
+ if (!d || isNaN(d.getTime())) return ''
+
+ return `${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,'0')}-${String(d.getDate()).padStart(2,'0')} ${String(d.getHours()).padStart(2,'0')}:${String(d.getMinutes()).padStart(2,'0')}`
}
}
}
@@ -1166,11 +1196,67 @@ export default {
line-height: 1;
padding: 10rpx;
}
+
.status-text, .empty-state {
padding: 60rpx; text-align: center; color: $text-sub; font-size: 26rpx;
}
.empty-icon { font-size: 80rpx; display: block; margin-bottom: 20rpx; }
+.no-more {
+ text-align: center;
+ font-size: 24rpx;
+ color: $text-tertiary;
+ padding: 30rpx 0;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+
+ .text {
+ margin: 0 16rpx;
+ }
+
+ .divider {
+ width: 60rpx;
+ height: 1px;
+ background: #e0e0e0;
+ }
+}
+
+/* 弹窗 Tab 栏 */
+.popup-tabs {
+ display: flex;
+ justify-content: space-around;
+ padding: 0 20rpx;
+ background: #fff;
+ border-bottom: 1rpx solid $border-color-light;
+ margin-bottom: 20rpx;
+}
+.popup-tab {
+ flex: 1;
+ text-align: center;
+ font-size: 28rpx;
+ color: $text-sub;
+ padding: 24rpx 0;
+ position: relative;
+ font-weight: 500;
+ transition: all 0.2s;
+}
+.popup-tab.active {
+ color: $text-main;
+ font-weight: 700;
+}
+.popup-tab.active::after {
+ content: '';
+ position: absolute;
+ bottom: 0;
+ left: 50%;
+ transform: translateX(-50%);
+ width: 40rpx;
+ height: 6rpx;
+ background: $brand-primary;
+ border-radius: 6rpx;
+}
+
/* 列表滚动区 */
.points-list, .coupon-scroll, .item-cards-scroll, .task-list-scroll, .invite-list-scroll {
flex: 1; min-height: 400rpx; background: $bg-grey; padding: 20rpx;
@@ -1197,20 +1283,103 @@ export default {
.coupon-left-v2 {
width: 180rpx; background: linear-gradient(135deg, #FFF5E6, #fff);
display: flex; flex-direction: column; align-items: center; justify-content: center;
- padding: 20rpx; border-right: 2rpx dashed #E0E0E0;
+ padding: 20rpx;
position: relative;
}
.coupon-remaining { color: $brand-primary; font-weight: 900; }
.coupon-symbol { font-size: 24rpx; }
.coupon-amount-num { font-size: 56rpx; line-height: 1; }
.coupon-label { font-size: 20rpx; color: $brand-primary; margin-top: 8rpx; border: 1px solid $brand-primary; padding: 2rpx 8rpx; border-radius: 6rpx; }
-.coupon-right-v2 { flex: 1; padding: 24rpx; display: flex; flex-direction: column; justify-content: space-between; }
-.coupon-name-v2 { font-size: $font-md; font-weight: 700; color: $text-main; margin-bottom: 8rpx; }
+
+/* 优惠券分割线 */
+.coupon-divider-v2 {
+ width: 30rpx;
+ position: relative;
+ background: #fff;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ overflow: hidden;
+}
+.divider-notch {
+ width: 24rpx;
+ height: 24rpx;
+ background: $bg-grey; /* Match scroll container bg */
+ border-radius: 50%;
+ position: absolute;
+ left: 50%;
+ transform: translateX(-50%);
+ z-index: 2;
+}
+.divider-notch.top { top: -12rpx; }
+.divider-notch.bottom { bottom: -12rpx; }
+.divider-dash {
+ width: 0;
+ height: 80%;
+ border-left: 2rpx dashed #eee;
+}
+
+.coupon-right-v2 {
+ flex: 1;
+ padding: 24rpx;
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ overflow: hidden; /* Ensure content stays inside */
+}
+.coupon-name-v2 {
+ font-size: $font-md;
+ font-weight: 700;
+ color: $text-main;
+ margin-bottom: 8rpx;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+.coupon-original { font-size: 20rpx; color: $text-tertiary; text-decoration: line-through; margin-left: 8rpx; display: inline-block; }
.coupon-rules { font-size: $font-xs; color: $text-sub; margin-bottom: 16rpx; }
-.coupon-footer-row { display: flex; justify-content: space-between; align-items: center; margin-top: auto; }
+
+/* 优惠券进度条 */
+.coupon-progress-wrap {
+ margin-bottom: 12rpx;
+}
+.coupon-progress-bar {
+ height: 6rpx;
+ background: $bg-secondary;
+ border-radius: 100rpx;
+ overflow: hidden;
+ margin-bottom: 4rpx;
+}
+.coupon-progress-fill {
+ height: 100%;
+ background: $brand-primary;
+ border-radius: 100rpx;
+}
+.coupon-progress-text {
+ font-size: 18rpx;
+ color: $text-tertiary;
+}
+
+.coupon-footer-row { display: flex; justify-content: space-between; align-items: flex-end; margin-top: auto; }
+.coupon-footer-left { display: flex; flex-direction: column; }
.coupon-expire-v2 { font-size: 20rpx; color: $text-tertiary; }
.use-btn-v2 { background: $brand-primary; color: #fff; font-size: 22rpx; padding: 8rpx 24rpx; border-radius: 100rpx; }
.status-tag { font-size: 22rpx; color: $text-tertiary; background: #F5F5F5; padding: 4rpx 12rpx; border-radius: 6rpx; }
+.coupon-used-time { font-size: 18rpx; color: $text-tertiary; margin-top: 4rpx; text-align: left; }
+
+/* 过期/已使用状态 */
+.coupon-used .coupon-left-v2, .coupon-expired .coupon-left-v2 {
+ background: #f9f9f9;
+}
+.coupon-used .coupon-remaining, .coupon-expired .coupon-remaining,
+.coupon-used .coupon-label, .coupon-expired .coupon-label {
+ color: $text-tertiary;
+ border-color: $text-tertiary;
+}
+.coupon-used .coupon-name-v2, .coupon-expired .coupon-name-v2 {
+ color: $text-sub;
+}
/* 道具卡 */
.item-cards-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 20rpx; }
@@ -1227,6 +1396,41 @@ export default {
.card-count-badge { position: absolute; top: 20rpx; right: 20rpx; background: rgba(0,0,0,0.05); padding: 4rpx 12rpx; border-radius: 100rpx; }
.count-num { font-size: 22rpx; font-weight: 700; color: $text-main; }
+/* 道具卡已使用状态 */
+.item-card.used {
+ background: #fafafa;
+}
+.item-card.used .card-name {
+ color: $text-sub;
+}
+.item-card.used .card-desc {
+ color: $text-tertiary;
+}
+.item-card.used .card-icon-wrap {
+ background: #f0f0f0;
+ opacity: 0.6;
+}
+.card-used-badge {
+ position: absolute;
+ top: 20rpx;
+ right: 20rpx;
+ background: #eee;
+ padding: 4rpx 12rpx;
+ border-radius: 100rpx;
+}
+.used-text {
+ font-size: 22rpx;
+ color: $text-tertiary;
+}
+.card-use-time {
+ font-size: 18rpx;
+ color: $text-tertiary;
+ margin-top: 12rpx;
+ display: block;
+ border-top: 1rpx dashed #eee;
+ padding-top: 8rpx;
+}
+
/* 任务中心弹窗 */
.task-center-popup { background: #F8F9FA; }
.overall-progress {
diff --git a/pages/orders/detail.vue b/pages/orders/detail.vue
index 081e827..a564a6a 100644
--- a/pages/orders/detail.vue
+++ b/pages/orders/detail.vue
@@ -63,8 +63,8 @@
- ¥
- {{ formatPrice(item.price) }}
+ ¥
+ {{ item.price > 0 ? formatPrice(item.price) : '奖品' }}
x{{ item.quantity }}
@@ -87,8 +87,8 @@
- ¥
- {{ formatPrice(order.actual_amount) }}
+ ¥
+ {{ order.actual_amount > 0 ? formatPrice(order.actual_amount) : '奖品' }}
x1
@@ -130,19 +130,39 @@
商品总额
¥{{ formatPrice(order.total_amount) }}
-
- 优惠金额
+
+
+
+ 优惠券
+
+ {{ order.coupon_info.name }}
+ -¥{{ formatPrice(order.coupon_info.value) }}
+
+
+
+
+
+ 道具卡
+
+ {{ order.item_card_info.name }}
+ 双倍奖励
+ 已使用
+
+
+
+
+ 其他优惠
-¥{{ formatPrice(order.discount_amount) }}
- 实付款
-
- ¥
- {{ formatPrice(order.actual_amount) }}
-
+ {{ order.actual_amount > 0 ? '实付款' : '状态' }}
+
+ ¥
+ {{ order.actual_amount > 0 ? formatPrice(order.actual_amount) : '无需支付' }}
+
@@ -656,6 +676,24 @@ function showProofHelp() {
background: $bg-secondary;
}
}
+
+ .tag-small {
+ font-size: 20rpx;
+ padding: 2rpx 8rpx;
+ border-radius: 6rpx;
+
+ &.coupon {
+ color: #FF6B6B;
+ background: rgba(255, 107, 107, 0.1);
+ border: 1rpx solid rgba(255, 107, 107, 0.2);
+ }
+
+ &.card {
+ color: #6C5CE7;
+ background: rgba(108, 92, 231, 0.1);
+ border: 1rpx solid rgba(108, 92, 231, 0.2);
+ }
+ }
}
.divider {
diff --git a/pages/orders/index.vue b/pages/orders/index.vue
index 1370336..d513e82 100644
--- a/pages/orders/index.vue
+++ b/pages/orders/index.vue
@@ -82,6 +82,8 @@
{{ item.activity_name }}
第{{ item.issue_number }}期
+ 券: {{ item.coupon_info.name }}
+ 卡: {{ item.item_card_info.name }}
{{ formatTime(item.created_at) }}
@@ -94,9 +96,9 @@
{{ item.order_no }}
- 实付
- {{ formatAmount(item.actual_amount || item.total_amount) }}
-
+ 实付
+ {{ getAmountText(item) }}
+
@@ -167,6 +169,22 @@ function formatAmount(a) {
return `¥${yuan.toFixed(2)}`
}
+function shouldShowAmountLabel(item) {
+ const amount = item.actual_amount || item.total_amount
+ return amount > 0
+}
+
+function getAmountText(item) {
+ const amount = item.actual_amount || item.total_amount
+ if (amount > 0) return formatAmount(amount)
+
+ // 金额为0的情况
+ if (item.source_type === 3 || item.source_type === 2) {
+ return '奖品'
+ }
+ return '免费'
+}
+
function getOrderTitle(item) {
// 1. 优先使用 items 中的商品名称(通常是实物购买或中奖)
if (item.items && item.items.length > 0 && item.items[0].title) {
@@ -724,6 +742,14 @@ onReachBottom(() => {
background: $bg-secondary;
padding: 4rpx 12rpx;
border-radius: $radius-sm;
+ .coupon-tag {
+ color: #FF6B6B;
+ background: rgba(255, 107, 107, 0.1);
+ }
+ .card-tag {
+ color: #6C5CE7;
+ background: rgba(108, 92, 231, 0.1);
+ }
}
.order-time {
font-size: $font-xs;
diff --git a/pages/shop/detail.vue b/pages/shop/detail.vue
index 84ad784..a27967b 100644
--- a/pages/shop/detail.vue
+++ b/pages/shop/detail.vue
@@ -7,14 +7,25 @@
{{ detail.title || detail.name || '-' }}
- ¥{{ formatPrice(detail.price_sale || detail.price) }}
- {{ detail.points_required }}积分
+
+ {{ detail.points_required }}
+ 积分
+
+ ¥{{ formatPrice(detail.price_sale || detail.price) }}
库存:{{ detail.stock }}
{{ detail.description }}
+
商品不存在
+
+
+
+
+ 立即兑换
+ 立即购买
+
@@ -22,6 +33,7 @@
import { ref } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { getProductDetail } from '../../api/appUser'
+import { redeemProductByPoints } from '../../utils/request.js'
const detail = ref({})
const loading = ref(false)
@@ -43,6 +55,52 @@ async function fetchDetail(id) {
}
}
+function onBuy() {
+ uni.showToast({ title: '暂未开放购买', icon: 'none' })
+}
+
+async function onRedeem() {
+ const p = detail.value
+ if (!p || !p.id) return
+
+ const token = uni.getStorageSync('token')
+ if (!token) {
+ uni.showModal({
+ title: '提示',
+ content: '请先登录',
+ confirmText: '去登录',
+ success: (res) => { if (res.confirm) uni.navigateTo({ url: '/pages/login/index' }) }
+ })
+ return
+ }
+
+ uni.showModal({
+ title: '确认兑换',
+ content: `是否消耗 ${p.points_required} 积分兑换 ${p.title}?`,
+ success: async (res) => {
+ if (res.confirm) {
+ uni.showLoading({ title: '兑换中...' })
+ try {
+ const userId = uni.getStorageSync('user_id')
+ if (!userId) throw new Error('用户ID不存在')
+
+ await redeemProductByPoints(userId, p.id, 1)
+ uni.showToast({ title: '兑换成功', icon: 'success' })
+
+ // Refresh detail
+ setTimeout(() => {
+ fetchDetail(p.id)
+ }, 1500)
+ } catch (e) {
+ uni.showToast({ title: e.message || '兑换失败', icon: 'none' })
+ } finally {
+ uni.hideLoading()
+ }
+ }
+ }
+ })
+}
+
onLoad((opts) => {
const id = opts && opts.id
if (id) fetchDetail(id)
@@ -81,15 +139,14 @@ onLoad((opts) => {
}
.info-card {
- margin: $spacing-lg;
- margin-top: -60rpx;
- background: rgba(255, 255, 255, 0.95);
- backdrop-filter: blur(20rpx);
- border-radius: $radius-xl;
+ background: #fff;
+ border-radius: $radius-xl $radius-xl 0 0;
padding: $spacing-xl;
- box-shadow: $shadow-lg;
+ box-shadow: 0 -4rpx 20rpx rgba(0,0,0,0.05);
position: relative;
z-index: 2;
+ margin-top: -40rpx; /* Slight overlap */
+ min-height: 50vh;
}
.title {
@@ -120,12 +177,19 @@ onLoad((opts) => {
}
}
-.points {
- font-size: $font-sm;
- color: $brand-primary;
- padding: 6rpx $spacing-md;
- background: rgba($brand-primary, 0.1);
- border-radius: 100rpx;
+.points-wrap {
+ display: flex; align-items: baseline;
+}
+.points-val {
+ font-size: 48rpx;
+ font-weight: 900;
+ color: #FF9800;
+ font-family: 'DIN Alternate', sans-serif;
+}
+.points-unit {
+ font-size: 24rpx;
+ color: #FF9800;
+ margin-left: 6rpx;
font-weight: 600;
}
@@ -156,6 +220,33 @@ onLoad((opts) => {
}
}
+.action-bar-placeholder { height: 120rpx; }
+.action-bar {
+ position: fixed;
+ bottom: 0; left: 0; right: 0;
+ padding: 20rpx 40rpx;
+ padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
+ background: rgba(255,255,255,0.9);
+ backdrop-filter: blur(10px);
+ box-shadow: 0 -4rpx 20rpx rgba(0,0,0,0.05);
+ display: flex;
+ justify-content: flex-end;
+ z-index: 10;
+}
+.action-btn {
+ width: 100%;
+ height: 88rpx;
+ border-radius: 44rpx;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 32rpx;
+ font-weight: 700;
+ color: #fff;
+}
+.action-btn.redeem { background: linear-gradient(135deg, #FFB74D, #FF9800); box-shadow: 0 8rpx 20rpx rgba(255, 152, 0, 0.3); }
+.action-btn.buy { background: linear-gradient(135deg, #FF6B6B, #FF3B30); box-shadow: 0 8rpx 20rpx rgba(255, 59, 48, 0.3); }
+
@keyframes fadeInUp {
from { opacity: 0; transform: translateY(40rpx); }
to { opacity: 1; transform: translateY(0); }
diff --git a/pages/shop/index.vue b/pages/shop/index.vue
index a09bf39..a48f0e7 100644
--- a/pages/shop/index.vue
+++ b/pages/shop/index.vue
@@ -37,14 +37,15 @@
{{ p.title }}
-
- ¥
- {{ p.price }}
-
-
+
{{ p.points }}
积分
+
+ ¥
+ {{ p.price }}
+
+ 兑换
@@ -108,6 +109,46 @@ function onProductTap(p) {
}
}
+async function onRedeemTap(p) {
+ const token = uni.getStorageSync('token')
+ if (!token) {
+ uni.showModal({
+ title: '提示',
+ content: '请先登录',
+ confirmText: '去登录',
+ success: (res) => { if (res.confirm) uni.navigateTo({ url: '/pages/login/index' }) }
+ })
+ return
+ }
+
+ uni.showModal({
+ title: '确认兑换',
+ content: `是否消耗 ${p.points} 积分兑换 ${p.title}?`,
+ success: async (res) => {
+ if (res.confirm) {
+ uni.showLoading({ title: '兑换中...' })
+ try {
+ // Get user_id from storage
+ const userId = uni.getStorageSync('user_id')
+ if (!userId) throw new Error('用户ID不存在')
+
+ await redeemProductByPoints(userId, p.id, 1)
+ uni.showToast({ title: '兑换成功', icon: 'success' })
+
+ // Refresh products to update stock/points if needed
+ setTimeout(() => {
+ loadProducts()
+ }, 1500)
+ } catch (e) {
+ uni.showToast({ title: e.message || '兑换失败', icon: 'none' })
+ } finally {
+ uni.hideLoading()
+ }
+ }
+ }
+ })
+}
+
// Filter logic
const allProducts = ref([]) // Store all fetched products for client-side filtering
@@ -473,33 +514,20 @@ onShareTimeline(() => {
gap: 8rpx;
}
.price-row {
- color: $accent-red;
- font-weight: 700;
- display: flex;
- align-items: baseline;
+ display: flex; align-items: baseline;
}
-.price-symbol {
+.points-val { font-size: 36rpx; font-weight: 700; color: #FF9800; }
+.points-unit { font-size: 22rpx; color: #FF9800; margin-left: 4rpx; }
+.price-symbol { font-size: 24rpx; color: #FF3B30; }
+.price-val { font-size: 36rpx; font-weight: 700; color: #FF3B30; }
+
+.redeem-btn {
+ background: #FF9800;
+ color: #fff;
font-size: 24rpx;
-}
-.price-val {
- font-size: 34rpx;
-}
-.points-badge {
- background: rgba($brand-primary, 0.1);
- color: $brand-primary;
- border: 1px solid rgba($brand-primary, 0.2);
- border-radius: 8rpx;
- padding: 2rpx 10rpx;
- display: flex;
- align-items: center;
- gap: 4rpx;
-}
-.points-val {
- font-size: 24rpx;
- font-weight: 700;
-}
-.points-unit {
- font-size: 20rpx;
+ padding: 8rpx 20rpx;
+ border-radius: 30rpx;
+ margin-left: auto;
}
/* Loading & Empty */
diff --git a/utils/request.js b/utils/request.js
index ddcc632..4c67358 100644
--- a/utils/request.js
+++ b/utils/request.js
@@ -66,6 +66,14 @@ export function authRequest(options) {
return request({ ...options, header })
}
+export function redeemProductByPoints(user_id, product_id, count) {
+ return authRequest({
+ url: '/api/app/users/points/redeem-product',
+ method: 'POST',
+ data: { user_id, product_id, count }
+ })
+}
+
function getLanguage() {
try { return (uni.getSystemInfoSync().language || 'zh-CN') } catch (_) { return 'zh-CN' }
}