1.15提交
This commit is contained in:
@@ -16,13 +16,13 @@
|
||||
</view>
|
||||
<view class="divider-line"></view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-item" v-if="type==2">
|
||||
<view class="label">邮箱</view>
|
||||
<input class="input" v-model="email" type="text" placeholder="用于接收电子卡等信息(可选)" />
|
||||
</view>
|
||||
<view class="divider-line"></view>
|
||||
|
||||
|
||||
<view class="form-item select-item" @click="openAreaPicker">
|
||||
<view class="form-item select-item" @click="openAreaPicker" v-if="type==1">
|
||||
<view class="label">地址</view>
|
||||
<view class="input placeholder" v-if="!regionText">请选择地址</view>
|
||||
<view class="input" v-else>{{ regionText }}</view>
|
||||
@@ -30,14 +30,15 @@
|
||||
</view>
|
||||
<view class="divider-line"></view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-item" v-if="type==1">
|
||||
<view class="label">详细地址</view>
|
||||
<input class="input" v-model="detail" placeholder="请输入街道、门牌等详细地址信息" />
|
||||
</view>
|
||||
<view class="divider-line"></view>
|
||||
</scroll-view>
|
||||
|
||||
<view class="footer-bar" @click="submit">
|
||||
<view class="confirm-btn" >确定</view>
|
||||
<view class="confirm-btn" >确定兑换</view>
|
||||
</view>
|
||||
|
||||
<!-- 省市区选择器 -->
|
||||
@@ -62,20 +63,80 @@
|
||||
<view v-else class="picker-empty">地区数据加载中...</view>
|
||||
</view>
|
||||
</view>
|
||||
<unidialog
|
||||
:title="'确认收货信息'"
|
||||
:visible="freeVisible"
|
||||
:content="freeContent"
|
||||
@close="freeClose"
|
||||
@confirm="freeConfirm"
|
||||
>
|
||||
<template #content>
|
||||
<view>
|
||||
<view class="row">
|
||||
<view class="left">收件人:</view>
|
||||
<view class="right">{{ receiver }}</view>
|
||||
</view>
|
||||
<view class="row">
|
||||
<view class="left">手机号:</view>
|
||||
<view class="right">{{ mobile }}</view>
|
||||
</view>
|
||||
<view class="row" >
|
||||
<view class="left">地址:</view>
|
||||
<view class="right">{{ regionText+detail }}</view>
|
||||
</view>
|
||||
<view class="row">
|
||||
<view class="left">兑换积分:</view>
|
||||
<view class="right"><text class="price">{{ points }}积分</text>(包邮)</view>
|
||||
</view>
|
||||
<view class="row">请确认此次兑换,物品不退不换</view>
|
||||
</view>
|
||||
</template>
|
||||
</unidialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import areaList from '@/utils/areaList.js'
|
||||
|
||||
import api from '@/api/api.js'
|
||||
import navTo from '@/utils/navTo';
|
||||
import goods_api from '@/api/goods_api';
|
||||
import unidialog from '@/components/dialog/dialog.vue';
|
||||
const freeVisible = ref(false)
|
||||
const freeContent = ref('')
|
||||
const goods_order_id = ref('')
|
||||
const points = ref(0)
|
||||
const freeClose = () => {
|
||||
freeVisible.value = false
|
||||
}
|
||||
const freeConfirm = () => {
|
||||
freeVisible.value = false;
|
||||
goods_api.payGoodsOrder({
|
||||
goods_order_uuid: goods_order_id.value,
|
||||
}).then(res => {
|
||||
if(res.code == 1 || res.code == 200){
|
||||
uni.showToast({
|
||||
title: '兑换成功',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
setTimeout(() => {
|
||||
uni.navigateBack({
|
||||
delta: 2
|
||||
})
|
||||
}, 2000)
|
||||
}
|
||||
})
|
||||
}
|
||||
const receiver = ref('')
|
||||
const mobile = ref('')
|
||||
const regionText = ref('')
|
||||
const detail = ref('')
|
||||
const email = ref('')
|
||||
const editingId = ref(null)
|
||||
|
||||
const goodsUuid = ref('')
|
||||
const type = ref(1)
|
||||
const goodsNum = ref(1)
|
||||
const goBack = () => uni.navigateBack()
|
||||
|
||||
// 省市区数据(适配树形数组:[{code,label,value,children:[...] }...])
|
||||
@@ -142,69 +203,42 @@ const confirmArea = () => {
|
||||
}
|
||||
|
||||
onLoad((opts) => {
|
||||
if (opts && opts.id) {
|
||||
// 回填编辑
|
||||
editingId.value = Number(opts.id)
|
||||
try {
|
||||
const list = uni.getStorageSync('goods_addresses') || []
|
||||
const target = Array.isArray(list) ? list.find(a => a.id === editingId.value) : null
|
||||
if (target) {
|
||||
receiver.value = target.receiver || ''
|
||||
mobile.value = target.mobile || ''
|
||||
regionText.value = target.region || ''
|
||||
detail.value = target.detail || ''
|
||||
email.value = target.email || ''
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
console.log(22);
|
||||
console.log(opts);
|
||||
goodsUuid.value = opts.goodsUuid
|
||||
goodsNum.value = opts.goodsNum;
|
||||
type.value = opts.type;
|
||||
})
|
||||
|
||||
const submit = () => {
|
||||
if (!receiver.value) return uni.showToast({ title: '请输入收件人', icon: 'none' })
|
||||
if (!/^1\d{10}$/.test(mobile.value)) return uni.showToast({ title: '请输入正确手机号', icon: 'none' })
|
||||
if (!regionText.value) return uni.showToast({ title: '请选择地址', icon: 'none' })
|
||||
if (!detail.value) return uni.showToast({ title: '请输入详细地址', icon: 'none' })
|
||||
if (email.value && !/^([a-zA-Z0-9_\.-]+)@([a-zA-Z0-9\.-]+)\.([a-zA-Z]{2,})$/.test(email.value)) return uni.showToast({ title: '邮箱格式不正确', icon: 'none' })
|
||||
|
||||
const STORAGE_KEY = 'goods_addresses'
|
||||
let list = []
|
||||
try {
|
||||
const cached = uni.getStorageSync(STORAGE_KEY)
|
||||
list = Array.isArray(cached) ? cached : []
|
||||
} catch (e) { list = [] }
|
||||
|
||||
if (editingId.value) {
|
||||
// 更新
|
||||
list = list.map(a => a.id === editingId.value ? {
|
||||
...a,
|
||||
receiver: receiver.value,
|
||||
mobile: mobile.value,
|
||||
region: regionText.value,
|
||||
detail: detail.value,
|
||||
fullAddress: `${regionText.value} ${detail.value}`,
|
||||
email: email.value
|
||||
} : a)
|
||||
} else {
|
||||
// 新增
|
||||
const address = {
|
||||
id: Date.now(),
|
||||
receiver: receiver.value,
|
||||
mobile: mobile.value,
|
||||
region: regionText.value,
|
||||
detail: detail.value,
|
||||
fullAddress: `${regionText.value} ${detail.value}`,
|
||||
email: email.value,
|
||||
createdAt: Date.now()
|
||||
}
|
||||
list.unshift(address)
|
||||
if(type.value == 1){
|
||||
if (!regionText.value) return uni.showToast({ title: '请选择地址', icon: 'none' })
|
||||
if (!detail.value) return uni.showToast({ title: '请输入详细地址', icon: 'none' })
|
||||
}else{
|
||||
if (email.value && !/^([a-zA-Z0-9_\.-]+)@([a-zA-Z0-9\.-]+)\.([a-zA-Z]{2,})$/.test(email.value)) return uni.showToast({ title: '邮箱格式不正确', icon: 'none' })
|
||||
}
|
||||
uni.setStorageSync(STORAGE_KEY, list)
|
||||
uni.showToast({ title: '提交成功', icon: 'none' })
|
||||
setTimeout(() => { uni.navigateBack() }, 500)
|
||||
goods_api.createGoodsOrder({
|
||||
goodsUuid: goodsUuid.value,
|
||||
goodsNum: goodsNum.value,
|
||||
user_name: receiver.value,
|
||||
mobile: mobile.value,
|
||||
email:email.value,
|
||||
address: regionText.value+detail.value
|
||||
}).then(res => {
|
||||
if(res.code == 1 || res.code == 200){
|
||||
points.value = res.data.pionts*res.data.goods_num;
|
||||
freeVisible.value = true
|
||||
goods_order_id.value = res.data.goods_order_id
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
<style scoped lang="scss">
|
||||
.address-page { min-height: 100vh; background: #fff; }
|
||||
.content { position: absolute; top: calc(var(--status-bar-height) + 44px); bottom: 120rpx; left: 0; right: 0; background: #fff; }
|
||||
.form-item { display: flex; align-items: center; padding: 24rpx; }
|
||||
@@ -227,5 +261,25 @@ const submit = () => {
|
||||
.picker-view { height: 480rpx; }
|
||||
.picker-item { height: 80rpx; line-height: 80rpx; text-align: center; color: #333; }
|
||||
.picker-empty { padding: 40rpx; text-align: center; color: #999; }
|
||||
.row{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 28rpx;
|
||||
padding: 12rpx 0;
|
||||
|
||||
max-width: 800rpx;
|
||||
margin-left: -100rpx;
|
||||
.left{
|
||||
text-align: left;
|
||||
max-width: 125rpx;
|
||||
width:auto!important;
|
||||
}
|
||||
.price{
|
||||
color: #FF4D4F;
|
||||
}
|
||||
}
|
||||
.left{
|
||||
width: 160rpx;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
<scroll-view scroll-y class="content">
|
||||
<!-- 收货地址 -->
|
||||
<view class="addr-card" @click="changeAddress">
|
||||
<!-- <view class="addr-card" @click="changeAddress">
|
||||
<view class="addr-header">
|
||||
<text class="addr-title">收货信息</text>
|
||||
<text class="addr-change">{{ selectedAddress ? '更换' : '添加' }}</text>
|
||||
@@ -15,7 +15,7 @@
|
||||
<text class="addr-row small">{{ selectedAddress.fullAddress || (selectedAddress.region + ' ' + selectedAddress.detail) }}</text>
|
||||
</view>
|
||||
<view v-else class="addr-empty">请添加收货地址</view>
|
||||
</view>
|
||||
</view> -->
|
||||
|
||||
<view class="goods-title">{{ title }}</view>
|
||||
<view class="price">{{ price }}积分</view>
|
||||
@@ -37,16 +37,38 @@
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<view class="footer-bar">
|
||||
<view class="confirm-btn" @click="goAddress">我要兑换</view>
|
||||
<view class="footer-bar" @click="goAddress">
|
||||
<view class="confirm-btn" >我要兑换</view>
|
||||
</view>
|
||||
</view>
|
||||
<unidialog
|
||||
:title="'确认收货信息'"
|
||||
:visible="freeVisible"
|
||||
:content="freeContent"
|
||||
@close="freeClose"
|
||||
@confirm="freeConfirm"
|
||||
>
|
||||
|
||||
</unidialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { onLoad, onShow } from '@dcloudio/uni-app'
|
||||
import goods_api from '@/api/goods_api'
|
||||
import unidialog from '@/components/dialog/dialog.vue';
|
||||
const freeVisible = ref(false)
|
||||
import navTo from '@/utils/navTo';
|
||||
const freeContent = ref('您的积分不足,是否购买积分?')
|
||||
const freeClose = () => {
|
||||
freeVisible.value = false
|
||||
}
|
||||
const freeConfirm = () => {
|
||||
freeVisible.value = false;
|
||||
navTo({
|
||||
url: '/pages_app/buyPoint/buyPoint'
|
||||
})
|
||||
}
|
||||
const title = ref('')
|
||||
const price = ref(0)
|
||||
const qty = ref(1)
|
||||
@@ -54,6 +76,7 @@ const needPoints = ref(0)
|
||||
const totalPoints = ref(0)
|
||||
const selectedAddress = ref(null)
|
||||
const id = ref('')
|
||||
const type = ref(null)
|
||||
|
||||
const goBack = () => uni.navigateBack()
|
||||
|
||||
@@ -63,10 +86,12 @@ const setQty = (n) => {
|
||||
}
|
||||
|
||||
onLoad((opts) => {
|
||||
console.log(opts);
|
||||
if (opts) {
|
||||
title.value = decodeURIComponent(opts.title || '')
|
||||
price.value = Number(opts.price || 0)
|
||||
id.value = opts.id || ''
|
||||
type.value = opts.type
|
||||
setQty(1)
|
||||
getTotalPoints()
|
||||
}
|
||||
@@ -110,24 +135,14 @@ const changeAddress = () => {
|
||||
}
|
||||
|
||||
const goAddress = () => {
|
||||
if (needPoints.value > totalPoints.value) {
|
||||
uni.showToast({ title: '积分不足', icon: 'none' })
|
||||
return
|
||||
if(Number(needPoints.value) > Number(totalPoints.value)){
|
||||
freeVisible.value = true
|
||||
}else{
|
||||
uni.navigateTo({
|
||||
url: '/pages_goods/exchange/address?goodsUuid='+id.value+'&type='+type.value+'&goodsNum='+qty.value
|
||||
})
|
||||
}
|
||||
if (!selectedAddress.value) {
|
||||
changeAddress()
|
||||
return
|
||||
}
|
||||
|
||||
const data = {
|
||||
goodsUuid: id.value,
|
||||
address: selectedAddress.value.fullAddress,
|
||||
user_name: selectedAddress.value.receiver,
|
||||
mobile: selectedAddress.value.mobile,
|
||||
goodsNum: qty.value,
|
||||
email: selectedAddress.value.email
|
||||
}
|
||||
console.log(data)
|
||||
|
||||
|
||||
|
||||
//{"goodsUuid":"e6ca84edc8e64242a379dd0b895ea812",
|
||||
@@ -137,26 +152,26 @@ const goAddress = () => {
|
||||
// "goodsNum":"1",
|
||||
// "email":""}
|
||||
// 模拟下单:此处可调用后端接口完成兑换
|
||||
uni.showModal({
|
||||
title: '确认兑换',
|
||||
content: `兑换“${title.value}”x${qty.value},共需 ${needPoints.value} 积分`,
|
||||
success: (r) => {
|
||||
if (r.confirm) {
|
||||
// 扣减本地积分(演示)
|
||||
totalPoints.value = Math.max(0, totalPoints.value - needPoints.value)
|
||||
uni.removeStorageSync(SELECTED_KEY)
|
||||
goods_api.createGoodsOrder(data).then(res => {
|
||||
console.log(res)
|
||||
if (res.code == 200) {
|
||||
uni.showToast({ title: '兑换成功', icon: 'none' })
|
||||
uni.navigateBack()
|
||||
} else {
|
||||
uni.showToast({ title: res.msg, icon: 'none' })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
// uni.showModal({
|
||||
// title: '确认兑换',
|
||||
// content: `兑换“${title.value}”x${qty.value},共需 ${needPoints.value} 积分`,
|
||||
// success: (r) => {
|
||||
// if (r.confirm) {
|
||||
// // 扣减本地积分(演示)
|
||||
// totalPoints.value = Math.max(0, totalPoints.value - needPoints.value)
|
||||
// uni.removeStorageSync(SELECTED_KEY)
|
||||
// goods_api.createGoodsOrder(data).then(res => {
|
||||
// console.log(res)
|
||||
// if (res.code == 200) {
|
||||
// uni.showToast({ title: '兑换成功', icon: 'none' })
|
||||
// uni.navigateBack()
|
||||
// } else {
|
||||
// uni.showToast({ title: res.msg, icon: 'none' })
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
// })
|
||||
}
|
||||
const getTotalPoints = () => {
|
||||
goods_api.getTotalPoints && goods_api.getTotalPoints().then(res => {
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
>
|
||||
<template v-slot:right>
|
||||
<view class="nav-actions">
|
||||
<view class="btn" @click="goToSearch">搜索</view>
|
||||
<view class="btn" @click="goSearch">搜索</view>
|
||||
</view>
|
||||
</template>
|
||||
</uni-nav-bar>
|
||||
@@ -148,11 +148,14 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 商品网格(上拉加载) -->
|
||||
<!-- 商品网格(上拉加载 + 下拉刷新) -->
|
||||
<scroll-view
|
||||
class="product-grid"
|
||||
scroll-y
|
||||
refresher-enabled="true"
|
||||
:refresher-triggered="refresherTriggered"
|
||||
@scrolltolower="getGoodsList"
|
||||
@refresherrefresh="onRefresherRefresh"
|
||||
:lower-threshold="100"
|
||||
>
|
||||
<view class="grid-wrap">
|
||||
@@ -160,6 +163,7 @@
|
||||
class="product-item"
|
||||
v-for="(product, index) in products"
|
||||
:key="product.uuid || index"
|
||||
|
||||
@click="goToProductDetail(product)"
|
||||
>
|
||||
<view class="product-image-container">
|
||||
@@ -219,6 +223,7 @@ const page = ref(1);
|
||||
const pageSize = ref(10);
|
||||
const isLoadingMore = ref(false);
|
||||
const noMore = ref(false);
|
||||
const refresherTriggered = ref(false);
|
||||
const onSwiperChange = (e) => {
|
||||
currentBannerIndex.value = e.detail.current;
|
||||
};
|
||||
@@ -288,7 +293,17 @@ const goToProductDetail = (product) => {
|
||||
url: `/pages_goods/productDetail/productDetail?id=${id}`,
|
||||
});
|
||||
};
|
||||
|
||||
const goSearch = () => {
|
||||
uni.sendNativeEvent(
|
||||
"goHomeSearch",
|
||||
{
|
||||
msg: "pointMall",
|
||||
},
|
||||
(ret) => {
|
||||
console.log(ret);
|
||||
}
|
||||
);
|
||||
}
|
||||
const goToMyRedemption = () => {
|
||||
uni.navigateTo({
|
||||
url: "/pages_goods/myRedemption/myRedemption",
|
||||
@@ -305,7 +320,7 @@ const goToBannerDetail = (banner) => {
|
||||
// 跳转到轮播图详情页面
|
||||
uni.navigateTo({
|
||||
url: `/pages_app/webview/webview?url=${encodeURIComponent(
|
||||
banner.path
|
||||
docUrl+banner.path
|
||||
)}&title=${banner.title}`,
|
||||
});
|
||||
};
|
||||
@@ -393,6 +408,31 @@ const getGoodsTagList = () => {
|
||||
});
|
||||
};
|
||||
|
||||
// 下拉刷新处理
|
||||
const onRefresherRefresh = async () => {
|
||||
if (refresherTriggered.value) return;
|
||||
refresherTriggered.value = true;
|
||||
try {
|
||||
// 重置分页和列表
|
||||
page.value = 1;
|
||||
noMore.value = false;
|
||||
isLoadingMore.value = false;
|
||||
products.value = [];
|
||||
// 重新加载所有数据
|
||||
getGoodsNewsList();
|
||||
getGoodsTagList();
|
||||
await getGoodsList();
|
||||
} catch (error) {
|
||||
console.error("刷新数据失败:", error);
|
||||
uni.showToast({
|
||||
title: "刷新失败,请重试",
|
||||
icon: "none",
|
||||
});
|
||||
} finally {
|
||||
refresherTriggered.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getGoodsNewsList();
|
||||
// 初始化分页并加载第一页
|
||||
@@ -613,7 +653,7 @@ onMounted(() => {
|
||||
right: 0;
|
||||
z-index: 1;
|
||||
height: calc(
|
||||
100vh - var(--status-bar-height) - 44px - 88rpx
|
||||
100vh - var(--status-bar-height) - 44px - 575rpx
|
||||
); /* 预留顶部导航/筛选及底部栏 */
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<scroll-view scroll-y class="detail-scroll">
|
||||
<!-- 商品主图轮播 -->
|
||||
<view class="swiper-box">
|
||||
<swiper class="detail-swiper" :indicator-dots="true" :autoplay="false" :interval="3000" :duration="400" indicator-color="#ccc" indicator-active-color="#8B2316">
|
||||
<swiper class="detail-swiper" :indicator-dots="true" :autoplay="true" :interval="5000" :duration="400" indicator-color="#ccc" indicator-active-color="#8B2316">
|
||||
<swiper-item v-for="(img, idx) in images" :key="idx">
|
||||
<image class="swiper-image" :src="img" mode="aspectFit"></image>
|
||||
</swiper-item>
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
<!-- 标题与价格、销量 -->
|
||||
<view class="summary">
|
||||
<view class="title">{{ product.title }}</view>
|
||||
<view class="title">[包邮]{{ product.title }}</view>
|
||||
<view class="price-row">
|
||||
<text class="price">{{ product.price }}积分</text>
|
||||
<text class="exchanged">已兑换{{ product.times }}件</text>
|
||||
@@ -51,8 +51,8 @@
|
||||
</scroll-view>
|
||||
|
||||
<!-- 底部兑换按钮 -->
|
||||
<view class="bottom-bar">
|
||||
<view class="redeem-btn" @click="goExchange">在线兑换</view>
|
||||
<view class="bottom-bar" @click="goExchange">
|
||||
<view class="redeem-btn" >在线兑换</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
@@ -76,6 +76,7 @@ const fetchDetail = async (id) => {
|
||||
if ((res.code === 200 || res.code === '200') && res.data) {
|
||||
product.value = {
|
||||
id,
|
||||
type: res.data.type,
|
||||
title: res.data.name || '',
|
||||
price: res.data.bonuspoints || 0,
|
||||
times: res.data.times || 0,
|
||||
@@ -103,7 +104,7 @@ onLoad((opts) => {
|
||||
|
||||
const goExchange = () => {
|
||||
uni.navigateTo({
|
||||
url: `/pages_goods/exchange/index?id=${product.value.id}&title=${encodeURIComponent(product.value.title)}&price=${product.value.price}`
|
||||
url: `/pages_goods/exchange/index?id=${product.value.id}&title=${encodeURIComponent(product.value.title)}&price=${product.value.price}&type=${product.value.type}`
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user