1.14提交
This commit is contained in:
@@ -0,0 +1,268 @@
|
||||
<template>
|
||||
<view class="address-page">
|
||||
<navBar :title="'收货地址'" />
|
||||
<!-- <uni-nav-bar left-icon="left" title="收货地址" fixed color="#8B2316" height="180rpx" :border="false" backgroundColor="#ffffff" @clickLeft="goBack" /> -->
|
||||
|
||||
<scroll-view scroll-y class="content">
|
||||
<view class="form-item">
|
||||
<view class="label">收件人</view>
|
||||
<input class="input" v-model="receiver" placeholder="请输入收货人名字" />
|
||||
</view>
|
||||
<view class="divider-line"></view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="label">手机号</view>
|
||||
<input class="input" v-model="mobile" type="number" placeholder="收货人的电话,方便联系" />
|
||||
</view>
|
||||
<view class="divider-line"></view>
|
||||
|
||||
<!-- <view class="form-item">
|
||||
<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="label">地址</view>
|
||||
<view class="input placeholder" v-if="!regionText">请选择地址</view>
|
||||
<view class="input" v-else>{{ regionText }}</view>
|
||||
<text class="arrow">›</text>
|
||||
</view>
|
||||
<view class="divider-line"></view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="label">详细地址</view>
|
||||
<input class="input" v-model="detail" placeholder="请输入街道、门牌等详细地址信息" />
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<view class="footer-bar" @click="submit">
|
||||
<view class="confirm-btn" >确定兑换</view>
|
||||
</view>
|
||||
|
||||
<!-- 省市区选择器 -->
|
||||
<view v-if="showAreaPicker" class="picker-mask" @click="closeAreaPicker"></view>
|
||||
<view v-if="showAreaPicker" class="picker-panel">
|
||||
<view class="picker-header">
|
||||
<text class="picker-btn" @click="closeAreaPicker">取消</text>
|
||||
<text class="picker-title">选择地区</text>
|
||||
<text class="picker-btn ok" @click="confirmArea">确定</text>
|
||||
</view>
|
||||
<picker-view v-if="provinces.length && cities.length && areas.length" class="picker-view" :indicator-style="indicatorStyle" :value="pickerIndex" @change="onAreaChange">
|
||||
<picker-view-column>
|
||||
<view v-for="(p,pi) in provinces" :key="pi" class="picker-item">{{ p.name }}</view>
|
||||
</picker-view-column>
|
||||
<picker-view-column>
|
||||
<view v-for="(c,ci) in cities" :key="ci" class="picker-item">{{ c.name }}</view>
|
||||
</picker-view-column>
|
||||
<picker-view-column>
|
||||
<view v-for="(a,ai) in areas" :key="ai" class="picker-item">{{ a.name }}</view>
|
||||
</picker-view-column>
|
||||
</picker-view>
|
||||
<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">0积分</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 unidialog from '@/components/dialog/dialog.vue';
|
||||
const freeVisible = ref(false)
|
||||
const freeContent = ref('')
|
||||
const goods_order_id = ref('')
|
||||
const freeClose = () => {
|
||||
freeVisible.value = false
|
||||
}
|
||||
const freeConfirm = () => {
|
||||
freeVisible.value = false;
|
||||
api.useWelfareNum({
|
||||
other_uuid: goods_order_id.value,
|
||||
type: 5
|
||||
}).then(res => {
|
||||
if(res.code == 1 || res.code == 200){
|
||||
uni.sendNativeEvent('goTabbarPage', {
|
||||
msg: 'mine'
|
||||
},ret => {
|
||||
console.log(ret);
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
const receiver = ref('')
|
||||
const mobile = ref('')
|
||||
const regionText = ref('')
|
||||
const detail = ref('')
|
||||
const email = ref('')
|
||||
const editingId = ref(null)
|
||||
const goodsUuid = ref('')
|
||||
const goodsNum = ref(0)
|
||||
const goBack = () => uni.navigateBack()
|
||||
|
||||
// 省市区数据(适配树形数组:[{code,label,value,children:[...] }...])
|
||||
const provinces = ref([])
|
||||
const cities = ref([])
|
||||
const areas = ref([])
|
||||
const pickerIndex = ref([0,0,0])
|
||||
const showAreaPicker = ref(false)
|
||||
const indicatorStyle = `height: 80rpx;`
|
||||
|
||||
const normalizeNode = (node) => ({
|
||||
code: node?.code || '',
|
||||
name: node?.label || node?.value || node?.name || '',
|
||||
children: Array.isArray(node?.children) ? node.children : []
|
||||
})
|
||||
|
||||
const getAreaTree = () => {
|
||||
const raw = areaList && (areaList.default || areaList)
|
||||
return Array.isArray(raw) ? raw.map(normalizeNode) : []
|
||||
}
|
||||
|
||||
const buildData = () => {
|
||||
const tree = getAreaTree()
|
||||
provinces.value = tree.length ? tree : [{ code: '', name: '', children: [] }]
|
||||
const pIdx = Math.min(pickerIndex.value[0], Math.max(provinces.value.length - 1, 0))
|
||||
const pNode = provinces.value[pIdx]
|
||||
cities.value = (pNode?.children || []).map(normalizeNode)
|
||||
if (!cities.value.length) cities.value = [{ code: '', name: '', children: [] }]
|
||||
const cIdx = Math.min(pickerIndex.value[1], Math.max(cities.value.length - 1, 0))
|
||||
const cNode = cities.value[cIdx]
|
||||
areas.value = (cNode?.children || []).map(normalizeNode)
|
||||
if (!areas.value.length) areas.value = [{ code: '', name: '' }]
|
||||
}
|
||||
|
||||
const openAreaPicker = () => {
|
||||
showAreaPicker.value = true
|
||||
pickerIndex.value = [0,0,0]
|
||||
buildData()
|
||||
}
|
||||
const closeAreaPicker = () => { showAreaPicker.value = false }
|
||||
|
||||
const onAreaChange = (e) => {
|
||||
const val = (e && e.detail && e.detail.value) ? e.detail.value : [0,0,0]
|
||||
const [pi, ci, ai] = val
|
||||
if (pi !== pickerIndex.value[0]) {
|
||||
pickerIndex.value = [pi, 0, 0]
|
||||
buildData()
|
||||
return
|
||||
}
|
||||
if (ci !== pickerIndex.value[1]) {
|
||||
pickerIndex.value = [pi, ci, 0]
|
||||
buildData()
|
||||
return
|
||||
}
|
||||
pickerIndex.value = [pi, ci, ai]
|
||||
}
|
||||
|
||||
const confirmArea = () => {
|
||||
const p = provinces.value[pickerIndex.value[0]]
|
||||
const c = cities.value[pickerIndex.value[1]]
|
||||
const a = areas.value[pickerIndex.value[2]]
|
||||
regionText.value = [p?.name, c?.name, a?.name].filter(Boolean).join(' ')
|
||||
closeAreaPicker()
|
||||
}
|
||||
|
||||
onLoad((opts) => {
|
||||
console.log(22);
|
||||
console.log(opts);
|
||||
goodsUuid.value = opts.goodsUuid
|
||||
goodsNum.value = opts.goodsNum
|
||||
})
|
||||
|
||||
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' })
|
||||
api.createGoodsOrder({
|
||||
goodsUuid: goodsUuid.value,
|
||||
goodsNum: goodsNum.value,
|
||||
user_name: receiver.value,
|
||||
mobile: mobile.value,
|
||||
email:'',
|
||||
address: regionText.value+detail.value
|
||||
}).then(res => {
|
||||
if(res.code == 1 || res.code == 200){
|
||||
freeVisible.value = true
|
||||
goods_order_id.value = res.data.goods_order_id
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<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; }
|
||||
.label { width: 160rpx; color: #333; font-size: 30rpx; }
|
||||
.input { flex: 1; color: #333; font-size: 30rpx; }
|
||||
.placeholder { color: #bbb; }
|
||||
.divider-line { height: 2rpx; background: #eee; margin: 0 24rpx; }
|
||||
.select-item { position: relative; }
|
||||
.arrow { position: absolute; right: 24rpx; color: #999; font-size: 48rpx; }
|
||||
.footer-bar { position: fixed; left: 0; right: 0; bottom: 0; height: 120rpx; background: #27c5b8; display: flex; align-items: center; justify-content: center; }
|
||||
.confirm-btn { color: #fff; font-size: 34rpx; font-weight: 700; }
|
||||
|
||||
/* 地区选择器 */
|
||||
.picker-mask { position: fixed; left: 0; right: 0; top: 0; bottom: 0; background: rgba(0,0,0,0.4); }
|
||||
.picker-panel { position: fixed; left: 0; right: 0; bottom: 0; background: #fff; }
|
||||
.picker-header { display: flex; align-items: center; justify-content: space-between; padding: 20rpx 24rpx; border-bottom: 1rpx solid #eee; }
|
||||
.picker-title { font-size: 30rpx; color: #333; }
|
||||
.picker-btn { color: #666; font-size: 28rpx; }
|
||||
.picker-btn.ok { color: #38c1b1; }
|
||||
.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;
|
||||
}
|
||||
.price{
|
||||
color: #FF4D4F;
|
||||
}
|
||||
}
|
||||
.left{
|
||||
width: 160rpx;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,291 @@
|
||||
<template>
|
||||
<navBar :title="'U盘在线兑换'" />
|
||||
|
||||
<view class="buy-upan-page">
|
||||
<!-- 主要内容区域 -->
|
||||
<view class="main-content">
|
||||
<!-- 商品信息卡片 -->
|
||||
<view class="product-card">
|
||||
<!-- 商品描述 -->
|
||||
<view class="product-title">超实用~肝胆相照知识U盘(2026年版)</view>
|
||||
|
||||
<!-- 兑换信息 -->
|
||||
<view class="exchange-info">
|
||||
<text class="info-left">免费兑换剩余{{ remainingCount }}个</text>
|
||||
<text class="info-right">已兑换{{ exchangedCount }}件</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 兑换数量选择器 -->
|
||||
<view class="quantity-section">
|
||||
<text class="quantity-label">兑换数量</text>
|
||||
<view class="quantity-selector">
|
||||
<view
|
||||
class="quantity-btn minus-btn"
|
||||
:class="{ disabled: quantity <= 1 }"
|
||||
@click="decreaseQuantity"
|
||||
>
|
||||
<text class="btn-text">—</text>
|
||||
</view>
|
||||
<view class="quantity-display">
|
||||
<text class="quantity-value">{{ quantity }}</text>
|
||||
</view>
|
||||
<view
|
||||
class="quantity-btn plus-btn"
|
||||
:class="{ disabled: quantity >= remainingCount }"
|
||||
@click="increaseQuantity"
|
||||
>
|
||||
<text class="btn-text">+</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部兑换按钮 -->
|
||||
<view class="bottom-actions">
|
||||
<view class="exchange-btn" @click="handleExchange">
|
||||
<text class="btn-text">我要兑换</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { onLoad } from '@dcloudio/uni-app';
|
||||
import navBar from '@/components/navBar/navBar.vue';
|
||||
import api from '@/api/api';
|
||||
import navTo from '@/utils/navTo';
|
||||
const goodsUuid = ref('');
|
||||
|
||||
|
||||
// 商品信息
|
||||
const remainingCount = ref(2); // 剩余数量
|
||||
const exchangedCount = ref(1129); // 已兑换数量
|
||||
const quantity = ref(1); // 当前选择的数量
|
||||
const goodsInfo = ref({});
|
||||
|
||||
// 增加数量
|
||||
const increaseQuantity = () => {
|
||||
if (quantity.value < remainingCount.value) {
|
||||
quantity.value += 1;
|
||||
}
|
||||
};
|
||||
|
||||
// 减少数量
|
||||
const decreaseQuantity = () => {
|
||||
if (quantity.value > 1) {
|
||||
quantity.value -= 1;
|
||||
}
|
||||
};
|
||||
|
||||
// 处理兑换
|
||||
const handleExchange = () => {
|
||||
if (quantity.value <= 0) {
|
||||
uni.showToast({
|
||||
title: '请选择兑换数量',
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (quantity.value > remainingCount.value) {
|
||||
uni.showToast({
|
||||
title: '兑换数量不能超过剩余数量',
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: 调用兑换接口
|
||||
navTo({
|
||||
url:'/pages_app/buyUpan/address?goodsUuid='+goodsUuid.value+'&goodsNum='+quantity.value
|
||||
})
|
||||
};
|
||||
|
||||
// 获取U盘福利剩余数量
|
||||
const getUpanWelfareCount = () => {
|
||||
api.getUGoods().then(res => {
|
||||
console.log(res);
|
||||
if (res.code == 1 || res.code == 200) {
|
||||
// 根据实际接口返回的数据结构更新
|
||||
console.log(33);
|
||||
console.log(res.data);
|
||||
if (res.data) {
|
||||
//remainingCount.value = res.data.remainingCount;
|
||||
exchangedCount.value = res.data.times;
|
||||
goodsUuid.value = res.data.uuid;
|
||||
}
|
||||
}
|
||||
}).catch(err => {
|
||||
console.error('获取U盘福利数量失败:', err);
|
||||
});
|
||||
};
|
||||
|
||||
onLoad((options) => {
|
||||
remainingCount.value = options.restNum;
|
||||
// 可选:获取实时剩余数量
|
||||
getUpanWelfareCount();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
// 变量定义
|
||||
$bg-color: #ffffff;
|
||||
$text-primary: #333333;
|
||||
$text-secondary: #666666;
|
||||
$text-light: #999999;
|
||||
$border-color: #e5e5e5;
|
||||
$white: #ffffff;
|
||||
$teal-color: #00cbc0;
|
||||
$light-teal: #e6f7f6;
|
||||
$page-bg: #f5f6f7;
|
||||
|
||||
// 混合器
|
||||
@mixin flex-center {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
@mixin flex-between {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.buy-upan-page {
|
||||
|
||||
overflow: hidden;
|
||||
background-color: $page-bg;
|
||||
margin-top: calc(var(--status-bar-height) + 44px);
|
||||
// 为底部按钮留出空间
|
||||
}
|
||||
|
||||
.main-content {
|
||||
padding: 40rpx 30rpx;
|
||||
}
|
||||
|
||||
// 商品信息卡片
|
||||
.product-card {
|
||||
background-color: $white;
|
||||
border-radius: 16rpx;
|
||||
padding: 40rpx 30rpx;
|
||||
margin-bottom: 40rpx;
|
||||
|
||||
.product-title {
|
||||
font-size: 32rpx;
|
||||
color: $text-primary;
|
||||
font-weight: 500;
|
||||
margin-bottom: 30rpx;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.exchange-info {
|
||||
@include flex-between;
|
||||
font-size: 28rpx;
|
||||
|
||||
.info-left {
|
||||
color: $text-secondary;
|
||||
}
|
||||
|
||||
.info-right {
|
||||
color: $text-secondary;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 数量选择器区域
|
||||
.quantity-section {
|
||||
background-color: $white;
|
||||
border-radius: 16rpx;
|
||||
padding: 40rpx 30rpx;
|
||||
|
||||
.quantity-label {
|
||||
font-size: 32rpx;
|
||||
color: $text-primary;
|
||||
margin-bottom: 30rpx;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.quantity-selector {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
gap: 20rpx;
|
||||
|
||||
.quantity-btn {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
border: 2rpx solid $teal-color;
|
||||
border-radius: 8rpx;
|
||||
@include flex-center;
|
||||
background-color: $white;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
.btn-text {
|
||||
font-size: 36rpx;
|
||||
color: $teal-color;
|
||||
font-weight: 500;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
opacity: 0.5;
|
||||
border-color: $border-color;
|
||||
cursor: not-allowed;
|
||||
|
||||
.btn-text {
|
||||
color: $text-light;
|
||||
}
|
||||
}
|
||||
|
||||
&:not(.disabled):active {
|
||||
background-color: $light-teal;
|
||||
}
|
||||
}
|
||||
|
||||
.quantity-display {
|
||||
min-width: 120rpx;
|
||||
height: 80rpx;
|
||||
background-color: $teal-color;
|
||||
border-radius: 8rpx;
|
||||
@include flex-center;
|
||||
margin: 0 10rpx;
|
||||
|
||||
.quantity-value {
|
||||
font-size: 40rpx;
|
||||
color: $white;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 底部操作按钮
|
||||
.bottom-actions {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
|
||||
.exchange-btn {
|
||||
background-color: $teal-color;
|
||||
height: 88rpx;
|
||||
@include flex-center;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:active {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.btn-text {
|
||||
color: $white;
|
||||
font-size: 32rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user