积分商城修改

This commit is contained in:
2025-12-11 11:34:06 +08:00
parent 87f2ee8c3d
commit bb2830730d
6 changed files with 372 additions and 170 deletions

View File

@@ -56,3 +56,11 @@ export const recordPage = (data) => {
data: data data: data
}) })
} }
export const recordOne = (data) => {
return request({
url: url + '/user/pointGoods/record/one',
method: 'get',
data: data
})
}

View File

@@ -46,14 +46,17 @@
<view class="title">商品详情</view> <view class="title">商品详情</view>
</view> </view>
<view class="u-m-t-32"> <view class="u-m-t-32">
<image class="w-full" v-for="(item,index) in item.goodsDescription" :key="index" mode="widthFix" :src="item"> <image class="w-full" v-for="(item,index) in item.goodsDescription" :key="index" mode="widthFix"
:src="item">
</image> </image>
</view> </view>
</view> </view>
<view style="height: 100px"></view> <view style="height: 100px"></view>
<view class="fixed-bottom u-flex u-row-center"> <view class="fixed-bottom u-flex u-row-center">
<view class="btn" @click="exchangeClick" :class="isCanExchange">立即兑换</view> <view class="btn" @click="exchangeClick" :class="[isCanExchange?'':'gray']">
{{returnBtmText}}
</view>
</view> </view>
<!-- 兑换确认弹窗start --> <!-- 兑换确认弹窗start -->
@@ -76,27 +79,27 @@
</view> </view>
<view class="goods-info"> <view class="goods-info">
<view class="u-flex"> <view class="u-flex">
<image class="cover"></image> <image class="cover" :src="item.goodsImageUrl"></image>
<view class="u-flex u-flex-1 u-row-between u-p-l-16 u-col-center"> <view class="u-flex u-flex-1 u-row-between u-p-l-16 u-col-center">
<view> <view>
<view class="u-font-32 font-bold">这里是商品名称</view> <view class="u-font-32 font-bold">{{item.goodsName}}</view>
<view class="u-m-t-54 color-666">8000积分+9.99</view> <view class="u-m-t-54 color-666">{{item.requiredPoints}}积分+{{item.extraPrice}}</view>
</view> </view>
<text class="color-666">X1</text> <text class="color-666">X1</text>
</view> </view>
</view> </view>
<view class="u-m-t-20 waring u-flex u-col-center"> <view class="u-m-t-20 waring u-flex u-col-center" v-if="item.goodsCategory=='优惠券'">
<up-icon name="info-circle" size="16" color="#FF9900"></up-icon> <up-icon name="info-circle" size="16" color="#FF9900"></up-icon>
<view class="u-m-l-16">优惠券为虚拟发放一旦兑换不支持退款请悉知</view> <view class="u-m-l-16">优惠券为虚拟发放一旦兑换不支持退款请悉知</view>
</view> </view>
</view> </view>
<view class="bottom font-bold text-right"> <view class="bottom font-bold text-right">
<text>合计 8000积分 + ¥9.99</text> <text>合计 {{item.requiredPoints}}积分 + ¥{{item.extraPrice}}</text>
</view> </view>
<view class="u-m-t-42 u-flex u-row-center"> <view class="u-m-t-42 u-flex u-row-center">
<view class="btn">确认兑换</view> <view class="btn" @click="payExchange">确认兑换</view>
</view> </view>
</view> </view>
</up-popup> </up-popup>
@@ -113,6 +116,9 @@
} from '@/utils/uniapp.js' } from '@/utils/uniapp.js'
import modal from "@/scoreShop/components/modal.vue"; import modal from "@/scoreShop/components/modal.vue";
import * as pointGoodsApi from "@/common/api/order/pointGoods.js"; import * as pointGoodsApi from "@/common/api/order/pointGoods.js";
import {
pay
} from '@/utils/pay.js'
const imgs = { const imgs = {
bg: "https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/2/9fd6a3ad2b384f6cb4e88ed6b77bd334.png", bg: "https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/2/9fd6a3ad2b384f6cb4e88ed6b77bd334.png",
}; };
@@ -125,6 +131,10 @@
}); });
function exchangeClick() { function exchangeClick() {
if (item.extraPrice > 0) {
popupData.show = true
return
}
modalData.show = true; modalData.show = true;
} }
@@ -132,7 +142,45 @@
// modalData.show = false; // modalData.show = false;
exchange() exchange()
} }
async function payExchange() {
uni.showLoading({
title: '兑换中……'
})
const openId = await getOpenId()
uni.hideLoading()
if (openId) {
pointGoodsApi.exchange({
pointsGoodsId: item.id,
shopId: item.shopId,
number: 1,
price: item.extraPrice,
openId
}).then(orderRes => {
popupData.show = false;
pay(orderRes.payInfo).then(res => {
console.log(res)
if (res) {
uni.setStorageSync('exchange_goods_success', orderRes.goodsRecord)
uni.redirectTo({
url: '/scoreShop/success/index'
})
} else {
uni.showToast({
title: '兑换失败',
icon: 'none'
})
}
})
})
} else {
uni.showToast({
title: '鉴权失败,兑换失败',
icon: 'none'
})
}
}
async function exchange() { async function exchange() {
uni.showLoading({ uni.showLoading({
title: '兑换中……' title: '兑换中……'
@@ -148,12 +196,12 @@
openId openId
}).then(res => { }).then(res => {
modalData.show = false; modalData.show = false;
if(res){ if (res) {
uni.setStorageSync('exchange_goods_success',res) uni.setStorageSync('exchange_goods_success', res)
uni.redirectTo({ uni.redirectTo({
url:'/scoreShop/success/index' url: '/scoreShop/success/index'
}) })
}else{ } else {
uni.showToast({ uni.showToast({
title: '兑换失败', title: '兑换失败',
icon: 'none' icon: 'none'
@@ -219,11 +267,27 @@
if (item.quantity <= 0) { if (item.quantity <= 0) {
return false return false
} }
if(item.limitQuota&&item.boughtCount>=item.limitQuota){ if (item.limitQuota && item.boughtCount >= item.limitQuota) {
return false return false
} }
return true return true
}) })
const returnBtmText = computed(() => {
if (isCanExchange.value) {
return '立即兑换'
}
if (pointsUser.pointBalance < item.requiredPoints) {
const num = item.requiredPoints - pointsUser.pointBalance
return `积分不足,还差${num}积分`
}
if (item.quantity <= 0) {
return `库存不足`
}
if (item.limitQuota && item.boughtCount >= item.limitQuota) {
return `单人兑换已达上限`
}
})
onLoad((opt) => { onLoad((opt) => {
const exchange_goods = uni.getStorageSync('exchange_goods') const exchange_goods = uni.getStorageSync('exchange_goods')
if (exchange_goods.goodsDescription) { if (exchange_goods.goodsDescription) {

View File

@@ -25,7 +25,7 @@
</template> </template>
<template v-if="layout === 'block'"> <template v-if="layout === 'block'">
<view class="item"> <view class="item">
<view class="img coupon" v-if="item.goodsCategory=='优惠'&&item.couponInfo"> <view class="img coupon" v-if="item.goodsCategory=='优惠'&&item.couponInfo">
<couponIcon :item="item.couponInfo" typeKey="couponType" /> <couponIcon :item="item.couponInfo" typeKey="couponType" />
</view> </view>
<image class="img" v-else lazy-load :src="item.goodsImageUrl"></image> <image class="img" v-else lazy-load :src="item.goodsImageUrl"></image>
@@ -37,7 +37,7 @@
</view> </view>
<view class="u-flex u-col-center u-m-t-16 u-row-between"> <view class="u-flex u-col-center u-m-t-16 u-row-between">
<view class="limit" v-if="item.limitQuota">限购{{item.limitQuota}}</view> <view class="limit" v-if="item.limitQuota">限购{{item.limitQuota}}</view>
<view class="btn" v-if="canExchange(item)">兑换</view> <view class="btn" v-if="item.quantity>0">兑换</view>
<view class="btn end" v-else>已兑完</view> <view class="btn end" v-else>已兑完</view>
</view> </view>
</view> </view>
@@ -65,7 +65,7 @@
}); });
function toDetail(item) { function toDetail(item) {
if (!canExchange(item)) { if (item.quantity<=0) {
return return
} }
uni.setStorageSync('exchange_goods', item) uni.setStorageSync('exchange_goods', item)

View File

@@ -1,6 +1,6 @@
<template> <template>
<view class="list"> <view class="list">
<view v-for="(item, index) in list" :key="index" class="item"> <view v-for="(item, index) in list" :key="index" class="item" @click="toDetail(item)">
<view class="u-flex u-row-between"> <view class="u-flex u-row-between">
<text class="color-999">{{item.createTime}}</text> <text class="color-999">{{item.createTime}}</text>
<text class="status " :class="[returnStatusClass(item)]">{{item.status}}</text> <text class="status " :class="[returnStatusClass(item)]">{{item.status}}</text>
@@ -16,9 +16,9 @@
</view> </view>
</view> </view>
<view class="u-m-t-28 u-flex u-row-right btns"> <view class="u-m-t-28 u-flex u-row-right btns">
<view class="btn look" @click="lookCode(item)" v-if="item.goodsCategory!='优惠券'">查看券码</view> <view class="btn look" @click.stop="lookCode(item)" v-if="item.goodsCategory!='优惠券'">查看券码</view>
<view class="btn black" @click="tuikuan(item)" v-if="canRefund(item)">申请退款</view> <view class="btn black" @click.stop="refund(item)" v-if="canRefund(item)">申请退款</view>
<view class="btn black" @click="cancelRefund(item)" v-if="item.status=='退款中'" >取消退款</view> <view class="btn black" @click.stop="cancelRefund(item)" v-if="item.status=='退款中'" >取消退款</view>
</view> </view>
</view> </view>
</view> </view>
@@ -39,13 +39,20 @@
emits("lookCode", item); emits("lookCode", item);
}; };
function tuikuan(item) { function refund(item) {
emits("refund", item); emits("refund", item);
} }
function cancelRefund(item) { function cancelRefund(item) {
emits("cancelRefund", item); emits("cancelRefund", item);
} }
function toDetail(item){
uni.setStorageSync('points_order_detail',item)
uni.navigateTo({
url:'/scoreShop/order/detail'
})
}
function returnStatusClass(item) { function returnStatusClass(item) {
if (item.status == '已完成' || item.status == '已退款') { if (item.status == '已完成' || item.status == '已退款') {
return 'gray' return 'gray'

View File

@@ -1,156 +1,279 @@
<template> <template>
<view class="min-page bg-f7 color-333 u-font-28"> <view class="min-page bg-f7 color-333 u-font-28">
<view class="top"> <view class="top">
<view class="u-flex u-col-center"> <view class="u-flex u-col-center">
<up-image width="208rpx" height="208rpx"></up-image> <up-image width="208rpx" height="208rpx" :src="item.goodsImageUrl" v-if="item.goodsCategory!='优惠券'"></up-image>
<view class="u-p-l-28 u-flex-1"> <view class="" style="width: 208rpx;height: 208rpx;">
<view class="font-bold">这里是商品名称</view> <couponIcon :item="item.couponInfo" typeKey="couponType" />
<view class="u-flex u-row-between u-m-t-8"> </view>
<text class="color1 font-bold">8000积分</text> <view class="u-p-l-28 u-flex-1">
<text class="status success">已完成</text> <view class="font-bold">{{item.pointsGoodsName}}</view>
</view> <view class="u-flex u-row-between u-m-t-8">
<view class="u-m-t-8 font-bold color1"> X1 </view> <text class="color1 font-bold">{{item.spendPoints}}积分</text>
</view> <text class="status " :class="[returnStatusClass(item)]">{{item.status}}</text>
</view> </view>
<template v-if="true"> <view class="u-m-t-8 font-bold color1"> X{{item.number}} </view>
<view class="u-m-t-16"> </view>
<view class="u-flex u-row-center"> </view>
<up-qrcode cid="ex1" :size="104" :val="qrcode"></up-qrcode> <template v-if="item.goodsCategory=='其它商品'">
</view> <view class="u-m-t-16">
<view class="u-m-t-22 u-flex u-row-center"> <view class="u-flex u-row-center">
<text>{{ qrcode }}</text> <up-qrcode cid="ex1" :size="104" :val="qrcode"></up-qrcode>
<view @click="copyCode"> </view>
<image <view class="u-m-t-22 u-flex u-row-center">
src="/scoreShop/static/image/copy.png" <text>{{ qrcode }}</text>
class="u-m-l-24 copy" <view @click="copyCode">
></image> <image src="/scoreShop/static/image/copy.png" class="u-m-l-24 copy"></image>
</view> </view>
</view> </view>
</view> </view>
</template> </template>
<view class="u-m-t-16"> <view class="u-m-t-16">
<text class="color-666">领取方式</text> <text class="color-666">领取方式</text>
<text class="u-m-l-20">需前往店铺自行兑换领取</text> <text class="u-m-l-20" v-if="item.goodsCategory=='其它商品'">需前往店铺自行兑换领取</text>
</view> <text class="u-m-l-20" v-else>系统发放</text>
</view> </view>
</view>
<view class="bottom"> <view class="bottom">
<view class="u-flex u-row-between item"> <view class="u-flex u-row-between item">
<text>兑换商品</text> <text>兑换商品</text>
<text class="color-666">这里是商品名称</text> <text class="color-666">{{item.pointsGoodsName}}</text>
</view> </view>
<view class="u-flex u-row-between item"> <view class="u-flex u-row-between item">
<text>兑换数量</text> <text>兑换数量</text>
<text class="color-666">1</text> <text class="color-666">{{item.number}}</text>
</view> </view>
<view class="u-flex u-row-between item"> <view class="u-flex u-row-between item">
<text>消耗积分</text> <text>消耗积分</text>
<text class="color-666">800</text> <text class="color-666">{{item.spendPoints}}</text>
</view> </view>
<view class="u-flex u-row-between item"> <view class="u-flex u-row-between item">
<text>支付金额</text> <text>支付金额</text>
<text class="color-666">9.99</text> <text class="color-666">{{item.extraPaymentAmount}}</text>
</view> </view>
<view class="u-flex u-row-between item"> <view class="u-flex u-row-between item">
<text>下单时间</text> <text>下单时间</text>
<text class="color-666">2025-12-3 17:1932</text> <text class="color-666">{{item.createTime}}</text>
</view> </view>
<view class="u-flex u-row-between item"> <view class="u-flex u-row-between item">
<text>核销时间</text> <text>核销时间</text>
<text class="color-666">2025-12-04 01:13:14</text> <text class="color-666">{{item.checkoutTime||''}}</text>
</view> </view>
<view class="u-flex u-row-between item"> <view class="u-flex u-row-between item">
<text>订单号</text> <text>订单号</text>
<text class="color-666">DH202511300001</text> <text class="color-666">{{item.orderNo}}</text>
</view> </view>
</view> </view>
<view class="btns"> <view class="btns">
<view class="btn cancel">申请退款</view> <view class="btn cancel" @click="refund(item)" v-if="canRefund(item)">申请退款</view>
<view class="btn success ">取消退款</view> <view class="btn success " @click="cancelRefund(item)" v-if="item.status=='退款中'">取消退款</view>
</view> </view>
</view> </view>
</template> </template>
<script setup> <script setup>
const qrcode = ref("251202150055"); import couponIcon from "@/components/coupon-icon/index";
function copyCode() { import * as pointGoodsApi from "@/common/api/order/pointGoods.js";
uni.setClipboardData({ const qrcode = ref();
data: qrcode.value,
success: function () { function copyCode() {
uni.showToast({ uni.setClipboardData({
title: "复制成功", data: qrcode.value,
icon: "none", success: function() {
}); uni.showToast({
}, title: "复制成功",
}); icon: "none",
} });
},
});
}
const item = reactive({
})
function returnStatusClass(item) {
if (item.status == '已完成' || item.status == '已退款') {
return 'gray'
}
if (item.status == '待核销') {
return 'success'
}
if (item.status == '退款中') {
return 'error'
}
}
function canRefund(item) {
if(item.status=='已退款'|| item.status=='退款中'||item.goodsCategory!='其它商品' ){
return false
}
return true
}
function init() {
const data = uni.getStorageSync('points_order_detail')
qrcode.value=data.couponCode
Object.assign(item, data)
}
onLoad(init)
function refund(item) {
uni.showModal({
title: '提示',
content: '是否申请退款',
showCancel: true,
success(res) {
if (res.confirm) {
pointGoodsApi.applyRefund({
orderNo: item.orderNo,
recordId: item.id
}).then(res => {
if (res) {
uni.showToast({
title: '申请退款成功',
icon: 'none'
})
} else {
uni.showToast({
title: '申请退款失败',
icon: 'none'
})
}
setTimeout(() => {
refresh()
}, 1000)
})
}
}
})
}
function refresh(){
pointGoodsApi.recordOne({
id:item.id
}).then(res=>{
Object.assign(item,res)
})
}
function cancelRefund(item) {
uni.showModal({
title: '提示',
content: '是否取消退款',
showCancel: true,
success(res) {
if (res.confirm) {
pointGoodsApi.cancelRefund({
orderNo: item.orderNo,
recordId: item.id
}).then(res => {
if (res) {
uni.showToast({
title: '取消退款成功',
icon: 'none'
})
} else {
uni.showToast({
title: '取消退款失败',
icon: 'none'
})
}
setTimeout(() => {
refresh()
}, 1000)
})
}
}
})
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.min-page { .min-page {
padding: 28rpx; padding: 28rpx;
} }
.top {
padding: 32rpx 24rpx; .top {
background: #fff; padding: 32rpx 24rpx;
.color1 { background: #fff;
color: #9c571f;
} .color1 {
.status { color: #9c571f;
padding: 8rpx 18rpx; }
border-radius: 8rpx;
border: 2rpx solid transparent; .status {
&.success { padding: 8rpx 18rpx;
background: rgba(123, 209, 54, 0.12); border-radius: 8rpx;
border-color: #7bd136; border: 2rpx solid transparent;
color: #7bd136;
} &.success {
&.gray { background: rgba(123, 209, 54, 0.12);
background: #9999991f; border-color: #7bd136;
border-color: #999; color: #7bd136;
color: #999; }
}
&.error { &.gray {
background: #ff1c1c2e; background: #9999991f;
border-color: #ff1c1c; border-color: #999;
color: #ff1c1c; color: #999;
} }
}
} &.error {
.copy { background: #ff1c1c2e;
width: 28rpx; border-color: #ff1c1c;
height: 28rpx; color: #ff1c1c;
} }
.bottom { }
background: #fff; }
border-radius: 32rpx;
padding: 16rpx 28rpx; .copy {
margin-top: 48rpx; width: 28rpx;
.item { height: 28rpx;
padding: 16rpx 0; }
}
} .bottom {
.btns { background: #fff;
margin-top: 66rpx; border-radius: 32rpx;
display: flex; padding: 16rpx 28rpx;
justify-content: center; margin-top: 48rpx;
gap: 48rpx;
.btn { .item {
border: 2rpx solid transparent; padding: 16rpx 0;
border-radius: 100rpx; }
background: #fff; }
padding: 14rpx 76rpx;
font-size: 32rpx; .btns {
&.success { margin-top: 66rpx;
background-color: #e8ad7b; display: flex;
border-color: #e8ad7b; justify-content: center;
color: #fff; gap: 48rpx;
}
&.cancel { .btn {
border-color: #e8ad7b; border: 2rpx solid transparent;
color: #e8ad7b; border-radius: 100rpx;
} background: #fff;
} padding: 14rpx 76rpx;
} font-size: 32rpx;
&.success {
background-color: #e8ad7b;
border-color: #e8ad7b;
color: #fff;
}
&.cancel {
border-color: #e8ad7b;
color: #e8ad7b;
}
}
}
</style> </style>

View File

@@ -171,7 +171,7 @@
function getList() { function getList() {
const status = tabs.list.find(v => v.value == tabs.sel) const status = tabs.list.find(v => v.value == tabs.sel)
pointGoodsApi.recordPage({ pointGoodsApi.recordPage({
...query, ...query,status:tabs.sel?status.name:''
}).then(res => { }).then(res => {
const newList = res.records const newList = res.records
if (query.page == 1) { if (query.page == 1) {