秦佳浩 2 months ago
commit 676eeaf5ff

@ -1,10 +1,22 @@
/*
.container #fff
*/
.container {
background: #fff;
}
/*
.input-box 50rpx#fff 20rpx
.section
*/
.input-box {
margin-bottom: 50rpx;
background: #fff;
padding: 0 20rpx;
/*
.section display: flex使便align-items: center100%box-sizing 2rpx #e5e5e5
textinputpicker.pca.arrow
*/
.section {
display: flex;
align-items: center;
@ -15,26 +27,42 @@
height: 100%;
box-sizing: border-box;
border-bottom: 2rpx solid #e5e5e5;
/*
text 20%#333
*/
text {
width: 20%;
color: #333;
}
/*
input 70% 20rpx#333
*/
input {
width: 70%;
padding: 0 20rpx;
color: #333;
}
/*
picker 70% 30rpx
*/
picker {
width: 70%;
padding: 0 30rpx;
}
/*
.pca 70% 20rpx
*/
.pca {
width: 70%;
padding: 0 20rpx;
}
/*
.arrow 28rpximage100%vertical-align: top
*/
.arrow {
width: 28rpx;
height: 28rpx;
image {
width: 100%;
height: 100%;
@ -43,14 +71,23 @@
}
}
}
/*
.btn-box 5px 10px100% margin: auto 使
.clear.btn.keep
*/
.btn-box {
padding: 5px 10px;
width: 100%;
text-align: center;
margin: auto;
text {
font-size: 30rpx;
}
/*
.clear.btn 60% 80rpx line-height 使margin: auto#eb2444#f8f0f1b6
*/
.clear.btn {
width: 60%;
height: 80rpx;
@ -64,11 +101,18 @@
color: #eb2444;
background-color: #f8f0f1b6;
}
/*
.keep #fff#eb2444.keep.btn 使
*/
.keep {
color: #fff;
background-color: #eb2444;
}
}
/*
.keep.btn .keep 60% 80rpx line-height 使margin: auto使便
*/
.keep.btn {
width: 60%;
height: 80rpx;
@ -79,12 +123,20 @@
border-radius: 50rpx;
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05), 0 1px 0 rgba(255, 255, 255, 0.3);
}
/*
.infoText 20rpx100%justify-content: center使 flex HTML
*/
.infoText {
margin-top: 20rpx;
text-align: center;
width: 100%;
justify-content: center;
}
/*
picker-view whitepadding: 0100% 380rpxposition: fixed使bottom: 0text#999inline-flex
*/
picker-view {
background-color: white;
padding: 0;
@ -92,6 +144,7 @@ picker-view {
height: 380rpx;
bottom: 0;
position: fixed;
text {
color: #999;
display: inline-flex;
@ -104,6 +157,10 @@ picker-view {
font-family: Arial, Helvetica, sans-serif;
}
}
/*
picker-view-column view vertical-align: middle100%使便display: flexalign-items: centerjustify-content: center
*/
picker-view-column {
view {
vertical-align: middle;
@ -115,6 +172,10 @@ picker-view-column {
justify-content: center;
}
}
/*
.animation-element-wrapper display: flexposition: fixed使left: 0top: 0width: 100%height: 100%rgba(0, 0, 0, 0.6)z-index 999
*/
.animation-element-wrapper {
display: flex;
position: fixed;
@ -125,6 +186,10 @@ picker-view-column {
background-color: rgba(0, 0, 0, 0.6);
z-index: 999;
}
/*
.animation-element 100% 470rpx使bottom: 0#fff JavaScript
*/
.animation-element {
display: flex;
position: fixed;
@ -133,21 +198,37 @@ picker-view-column {
bottom: 0;
background-color: rgba(255, 255, 255, 1);
}
/*
.animation-button 20rpx 290rpx 100rpxalign-items: center.left-bt.right-bt
*/
.animation-button {
top: 20rpx;
width: 290rpx;
height: 100rpx;
align-items: center;
}
/*
.left-bt left 30rpx使.animation-element
*/
.left-bt {
left: 30rpx;
}
/*
.right-bt right 20rpx top 20rpx使position: absolute 80rpx!important
*/
.right-bt {
right: 20rpx;
top: 20rpx;
position: absolute;
width: 80rpx !important;
}
/*
.line 线display: block使 89rpx 2rpx100%#eee
*/
.line {
display: block;
position: fixed;

@ -1,82 +1,77 @@
<template>
<!-- 页面的最外层容器用于包裹整个页面内容 -->
<view class="container">
<!--input列表 -->
<!-- input列表区域用于展示多个输入项相关的视图 -->
<view class="input-box">
<!-- 每个输入项的整体视图容器这里用于展示收货人相关的输入项 -->
<view class="section">
<!-- 输入项的文本标签显示 字样用于提示用户此处应输入的内容 -->
<text> </text>
<input
placeholder="姓名"
type="text"
maxlength="15"
:value="receiver"
@input="onReceiverInput"
>
<!-- 文本输入框用于用户输入收货人姓名设置了占位符提示placeholder姓名输入类型为文本type="text"最大输入长度为15个字符maxlength="15"通过 :value 绑定了名为 receiver 的响应式变量来显示和更新输入框中的值并且绑定了 @input 事件onReceiverInput当用户输入内容时会触发该事件进行相应处理 -->
<input placeholder="姓名"
type="text"
maxlength="15"
:value="receiver"
@input="onReceiverInput">
</view>
<!-- 用于展示手机号码相关的输入项的视图容器 -->
<view class="section">
<!-- 输入项的文本标签显示手机号码字样提示用户此处应输入手机号码 -->
<text>手机号码</text>
<input
placeholder="11位手机号码"
type="number"
maxlength="11"
:value="mobile"
@input="onMobileInput"
>
<!-- 文本输入框用于用户输入手机号码设置了占位符提示为11位手机号码输入类型为数字type="number"最大输入长度为11位对应手机号码的长度要求通过 :value 绑定了名为 mobile 的响应式变量来显示和更新输入框中的值同时绑定了 @input 事件onMobileInput用于在输入时进行相关逻辑处理 -->
<input placeholder="11位手机号码"
type="number"
maxlength="11"
:value="mobile"
@input="onMobileInput">
</view>
<view
class="section"
@tap="translate"
>
<!-- 用于展示所在地区相关的输入项及操作的视图容器绑定了点击事件 translate点击可触发地区选择相关的操作如弹出地区选择器等 -->
<view class="section"
@tap="translate">
<!-- 输入项的文本标签显示所在地区字样提示用户此处应选择所在地区信息 -->
<text>所在地区</text>
<!-- 用于展示已选择的地区信息省份城市区县的视图元素通过双括号插值表达式绑定对应的响应式变量provincecityarea来显示具体的地区名称 -->
<view class="pca">
{{ province }} {{ city }} {{ area }}
</view>
<view
class="animation-element-wrapper"
:animation="animation"
:style="'visibility:' + (show ? 'visible':'hidden')"
@tap.stop="hiddenFloatView"
>
<view
class="animation-element"
@tap.stop="nono"
>
<text
class="right-bt"
@tap.stop="hiddenFloatView"
>
<!-- 这是一个用于实现地区选择器弹出效果的外层包装元素通过绑定 :animation 属性值为 animation 响应式变量来应用相关动画效果通过 :style 动态控制其可见性根据 show 响应式变量的值显示或隐藏并且绑定了 @tap.stop 事件hiddenFloatView点击该区域除了内部特定元素外可触发隐藏地区选择器浮层的操作阻止事件冒泡 -->
<view class="animation-element-wrapper"
:animation="animation"
:style="'visibility:' + (show? 'visible':'hidden')"
@tap.stop="hiddenFloatView">
<!-- 地区选择器浮层的主体元素设置了 @tap.stop 事件nono可能用于阻止一些默认的点击行为具体功能要结合代码逻辑看内部包含确定按钮分割线以及 picker-view 组件用于实际的地区选择操作 -->
<view class="animation-element"
@tap.stop="nono">
<!-- 右侧的确定按钮设置了类名为 right-bt绑定了 @tap.stop 事件hiddenFloatView点击可触发隐藏地区选择器浮层的操作显示确定字样用于用户完成地区选择后确认操作 -->
<text class="right-bt"
@tap.stop="hiddenFloatView">
确定
</text>
<!-- 水平分割线元素用于在视觉上区分不同区域可能是按钮与选择器部分的区分等 -->
<view class="line" />
<picker-view
indicator-style="height: 50rpx;"
:value="valArr"
@change="bindChange"
@tap.stop="nono"
>
<!---->
<!-- picker-view 组件用于实现多级联动的地区选择功能设置了指示器的样式indicator-style通过 :value 绑定 valArr 响应式变量来记录当前选择的值绑定了 @change 事件bindChange当选择的值发生变化时会触发该事件进行相应的数据更新等操作同时绑定了 @tap.stop 事件nono阻止一些默认点击行为 -->
<picker-view indicator-style="height: 50rpx;"
:value="valArr"
@change="bindChange"
@tap.stop="nono">
<!-- 省选择列的视图容器内部通过 v-for 指令循环遍历 provArray 数组该数组存储省份相关数据每个元素对应一个省份选项展示省份名称 -->
<picker-view-column>
<view
v-for="(item, indexs) in provArray"
:key="indexs"
>
<view v-for="(item, indexs) in provArray"
:key="indexs">
{{ item.areaName }}
</view>
</picker-view-column>
<!--地级市-->
<!-- 地级市选择列的视图容器类似省选择列通过 v-for 指令循环遍历 cityArray 数组存储地级市相关数据展示地级市名称 -->
<picker-view-column>
<view
v-for="(item, indexss) in cityArray"
:key="indexss"
>
<view v-for="(item, indexss) in cityArray"
:key="indexss">
{{ item.areaName }}
</view>
</picker-view-column>
<!--区县-->
<!-- 区县选择列的视图容器通过 v-for 指令循环遍历 areaArray 数组存储区县相关数据展示区县名称 -->
<picker-view-column>
<view
v-for="(item, indexsss) in areaArray"
:key="indexsss"
>
<view v-for="(item, indexsss) in areaArray"
:key="indexsss">
{{ item.areaName }}
</view>
</picker-view-column>
@ -84,350 +79,343 @@
</view>
</view>
<!-- 箭头图标元素用于提示用户可点击展开地区选择器等操作内部通过指定的路径引入图片资源一般是一个向右的箭头图标 -->
<view class="arrow">
<image src="@/static/images/icon/more.png" />
</view>
</view>
<!-- 用于展示详细地址相关的输入项的视图容器 -->
<view class="section">
<!-- 输入项的文本标签显示详细地址字样提示用户此处应输入详细的收货地址信息 -->
<text>详细地址</text>
<input
placeholder="如楼号/单元/门牌号"
type="text"
:value="addr"
@input="onAddrInput"
>
<!-- 文本输入框用于用户输入详细地址设置了占位符提示为如楼号/单元/门牌号通过 :value 绑定了名为 addr 的响应式变量来显示和更新输入框中的值并且绑定了 @input 事件onAddrInput用于在输入时进行相关逻辑处理 -->
<input placeholder="如楼号/单元/门牌号"
type="text"
:value="addr"
@input="onAddrInput">
</view>
</view>
<!-- end input列表 -->
<!-- 功能按钮 -->
<!-- input列表区域结束 -->
<!-- 功能按钮区域包含保存地址删除地址等功能按钮 -->
<view class="btn-box">
<view
class="keep btn"
@tap="onSaveAddr"
>
<!-- 保存收货地址按钮设置了类名为 keep btn绑定了点击事件 onSaveAddr点击可触发保存当前输入的收货地址信息的操作 -->
<view class="keep btn"
@tap="onSaveAddr">
<text>保存收货地址</text>
</view>
<view
v-if="addrId!=0"
class="clear btn"
@tap="onDeleteAddr"
>
<!-- 条件渲染的删除收货地址按钮只有当 addrId 不等于0时才显示可能表示当前是在编辑已有地址的场景下才显示删除按钮设置了类名为 clear btn绑定了点击事件 onDeleteAddr点击可触发删除当前收货地址的操作 -->
<view v-if="addrId!=0"
class="clear btn"
@tap="onDeleteAddr">
<text>删除收货地址</text>
</view>
</view>
<!-- end 功能按钮 -->
<!-- 功能按钮区域结束 -->
</view>
</template>
<script setup>
const addrId = ref(0)
const city = ref('')
const area = ref('')
const provinceId = ref(0)
const cityId = ref(0)
const areaId = ref(0)
const receiver = ref('')
const mobile = ref('')
const addr = ref('')
const province = ref('')
onLoad((options) => {
if (options.addrId) {
uni.showLoading()
//
const addrId = ref(0)
const city = ref('')
const area = ref('')
const provinceId = ref(0)
const cityId = ref(0)
const areaId = ref(0)
const receiver = ref('')
const mobile = ref('')
const addr = ref('')
const province = ref('')
//
onLoad((options) => {
if (options.addrId) { // ID
uni.showLoading() //
http.request({
url: '/p/address/addrInfo/' + options.addrId,
method: 'GET'
})
.then(({ data }) => {
//
province.value = data.province
city.value = data.city
area.value = data.area
provinceId.value = data.provinceId
cityId.value = data.cityId
areaId.value = data.areaId
receiver.value = data.receiver
mobile.value = data.mobile
addr.value = data.addr
addrId.value = options.addrId
initCityData(data.provinceId, data.cityId, data.areaId) //
uni.hideLoading() //
})
} else {
initCityData(provinceId.value, cityId.value, areaId.value) //
}
})
//
const provArray = ref([])
const valArr = ref([0, 0, 0])
//
const initCityData = (provinceId, cityId, areaId) => {
uni.showLoading()
http.request({
url: '/p/address/addrInfo/' + options.addrId,
method: 'GET'
url: '/p/area/listByPid',
method: 'GET',
data: {
pid: 0 //
}
})
.then(({ data }) => {
province.value = data.province
city.value = data.city
area.value = data.area
provinceId.value = data.provinceId
cityId.value = data.cityId
areaId.value = data.areaId
receiver.value = data.receiver
mobile.value = data.mobile
addr.value = data.addr
addrId.value = options.addrId
initCityData(data.provinceId, data.cityId, data.areaId)
provArray.value = data //
if (provinceId) {
for (const index in data) {
if (data[index].areaId === provinceId) {
valArr.value = [parseInt(index), valArr.value[1], valArr.value[2]] //
}
}
}
getCityArray(provinceId || data[0].areaId, cityId, areaId) // ID
uni.hideLoading()
})
} else {
initCityData(provinceId.value, cityId.value, areaId.value)
}
})
const provArray = ref([])
const valArr = ref([0, 0, 0])
const initCityData = (provinceId, cityId, areaId) => {
uni.showLoading()
http.request({
url: '/p/area/listByPid',
method: 'GET',
data: {
pid: 0
//
let indexArr = [18, 0, 0]
const areaArray = ref([])
const cityArray = ref([])
//
const bindChange = (e) => {
const val = e.detail.value //
if (indexArr[0] != val[0]) { //
val[1] = 0
val[2] = 0 //
getCityArray(provArray.value[val[0]].areaId) //
} else if (indexArr[1] != val[1]) { //
val[2] = 0 //
getAreaArray(cityArray.value[val[1]].areaId) //
}
})
.then(({ data }) => {
provArray.value = data
if (provinceId) {
for (const index in data) {
if (data[index].areaId === provinceId) {
valArr.value = [parseInt(index), valArr.value[1], valArr.value[2]]
}
}
}
getCityArray(provinceId || data[0].areaId, cityId, areaId)
uni.hideLoading()
})
}
indexArr = val
valArr.value = [val[0], val[1], val[2]]
// ID
province.value = provArray.value[valArr.value[0]].areaName
city.value = cityArray.value[valArr.value[1]].areaName
area.value = areaArray.value[valArr.value[2]].areaName
provinceId.value = provArray.value[valArr.value[0]].areaId
cityId.value = cityArray.value[valArr.value[1]].areaId
areaId.value = areaArray.value[valArr.value[2]].areaId
}
// /
let t = 0
let moveY = 200
const show = ref('')
let indexArr = [18, 0, 0]
const areaArray = ref([])
const cityArray = ref([])
/**
* 滑动事件
*/
const bindChange = (e) => {
// column
const val = e.detail.value
// column
if (indexArr[0] != val[0]) {
val[1] = 0
val[2] = 0 //
//
getCityArray(provArray.value[val[0]].areaId)
} else {
// column
if (indexArr[1] != val[1]) {
val[2] = 0 //
getAreaArray(cityArray.value[val[1]].areaId) //
const translate = () => {
if (t == 0) {
moveY = 0
show.value = true
t = 1
} else {
moveY = 200
show.value = false
t = 0
}
animationEvents(moveY, show.value)
}
indexArr = val
valArr.value = [val[0], val[1], val[2]]
province.value = provArray.value[valArr.value[0]].areaName
city.value = cityArray.value[valArr.value[1]].areaName
area.value = areaArray.value[valArr.value[2]].areaName
provinceId.value = provArray.value[valArr.value[0]].areaId
cityId.value = cityArray.value[valArr.value[1]].areaId
areaId.value = areaArray.value[valArr.value[2]].areaId
}
let t = 0
let moveY = 200
const show = ref('')
/**
* 移动按钮点击事件
*/
const translate = () => {
if (t == 0) {
moveY = 0
show.value = true
t = 1
} else {
//
const hiddenFloatView = () => {
moveY = 200
show.value = false
t = 0
animationEvents(moveY, show.value)
}
animationEvents(moveY, show.value)
}
/**
* 隐藏弹窗浮层
*/
const hiddenFloatView = () => {
moveY = 200
show.value = false
t = 0
animationEvents(moveY, show.value)
}
const animation = ref('')
const animation = ref('')
/**
* 动画事件
*/
const animationEvents = (moveY, showParam) => {
animation.value = uni.createAnimation({
transformOrigin: '50% 50%',
duration: 400,
timingFunction: 'ease',
delay: 0
})
animation.value.translateY(moveY + 'vh').step()
animation.value = animation.value.export()
show.value = showParam
}
//
const animationEvents = (moveY, showParam) => {
animation.value = uni.createAnimation({
transformOrigin: '50% 50%',
duration: 400,
timingFunction: 'ease',
delay: 0
})
animation.value.translateY(moveY + 'vh').step()
animation.value = animation.value.export()
show.value = showParam
}
/**
* 根据省份ID获取 城市数据
*/
const getCityArray = (provinceId, cityId, areaId) => {
http.request({
url: '/p/area/listByPid',
method: 'GET',
data: {
pid: provinceId
}
})
.then(({ data }) => {
cityArray.value = data
if (cityId) {
for (const index in data) {
if (data[index].areaId == cityId) {
valArr.value = [valArr.value[0], parseInt(index), valArr.value[2]]
}
}
// ID
const getCityArray = (provinceId, cityId, areaId) => {
http.request({
url: '/p/area/listByPid',
method: 'GET',
data: {
pid: provinceId // IDID
}
getAreaArray(cityId || data[0].areaId, areaId)
uni.hideLoading()
})
}
.then(({ data }) => {
cityArray.value = data //
if (cityId) {
for (const index in data) {
if (data[index].areaId == cityId) {
valArr.value = [valArr.value[0], parseInt(index), valArr.value[2]] //
}
}
}
getAreaArray(cityId || data[0].areaId, areaId) // ID
uni.hideLoading()
})
}
/**
* 根据城市ID获取 区数据
*/
const getAreaArray = (cityId, areaId) => {
http.request({
url: '/p/area/listByPid',
method: 'GET',
data: {
pid: cityId
}
}).then(({ data }) => {
areaArray.value = data
if (areaId) {
for (const _index in data) {
if (data[_index].areaId == areaId) {
valArr.value = [valArr.value[0], valArr.value[1], parseInt(_index)]
// ID
const getAreaArray = (cityId, areaId) => {
http.request({
url: '/p/area/listByPid',
method: 'GET',
data: {
pid: cityId // IDID
}
}).then(({ data }) => {
areaArray.value = data //
if (areaId) {
for (const _index in data) {
if (data[_index].areaId == areaId) {
valArr.value = [valArr.value[0], valArr.value[1], parseInt(_index)] //
}
}
indexArr = valArr.value
} else {
// ID
province.value = provArray.value[valArr.value[0]].areaName
city.value = cityArray.value[valArr.value[1]].areaName
area.value = areaArray.value[valArr.value[2]].areaName
provinceId.value = provArray.value[valArr.value[0]].areaId
cityId.value = cityArray.value[valArr.value[1]].areaId
areaId.value = areaArray.value[valArr.value[2]].areaId
}
indexArr = valArr.value
} else {
province.value = provArray.value[valArr.value[0]].areaName
city.value = cityArray.value[valArr.value[1]].areaName
area.value = areaArray.value[valArr.value[2]].areaName
provinceId.value = provArray.value[valArr.value[0]].areaId
cityId.value = cityArray.value[valArr.value[1]].areaId
areaId.value = areaArray.value[valArr.value[2]].areaId
}
uni.hideLoading()
})
}
/**
* 保存地址
*/
const onSaveAddr = () => {
const receiverParam = receiver.value
const mobileParam = mobile.value
const addrParam = addr.value
if (!receiverParam.trim()) {
receiver.value = ''
uni.showToast({
title: '请输入收货人姓名',
icon: 'none'
uni.hideLoading()
})
return
}
if (!mobileParam) {
uni.showToast({
title: '请输入手机号码',
icon: 'none'
})
return
}
//
const onSaveAddr = () => {
const receiverParam = receiver.value
const mobileParam = mobile.value
const addrParam = addr.value
if (mobileParam.length != 11) {
uni.showToast({
title: '请输入正确的手机号码',
icon: 'none'
})
return
}
//
if (!receiverParam.trim()) {
receiver.value = ''
uni.showToast({
title: '请输入收货人姓名',
icon: 'none'
})
return
}
if (!addrParam.trim()) {
receiver.value = ''
uni.showToast({
title: '请输入详细地址',
icon: 'none'
})
return
}
if (!mobileParam) {
uni.showToast({
title: '请输入手机号码',
icon: 'none'
})
return
}
if (mobileParam.length != 11) {
uni.showToast({
title: '请输入正确的手机号码',
icon: 'none'
})
return
}
uni.showLoading()
let url = '/p/address/addAddr'
let method = 'POST'
if (!addrParam.trim()) {
receiver.value = ''
uni.showToast({
title: '请输入详细地址',
icon: 'none'
})
return
}
if (addrId.value != 0) {
url = '/p/address/updateAddr'
method = 'PUT'
} //
uni.showLoading()
let url = '/p/address/addAddr'
let method = 'POST'
http.request({
url,
method,
data: {
receiver: receiver.value,
mobile: mobile.value,
addr: addr.value,
province: province.value,
provinceId: provinceId.value,
city: city.value,
cityId: cityId.value,
areaId: areaId.value,
area: area.value,
userType: 0,
addrId: addrId.value
if (addrId.value != 0) { // ID
url = '/p/address/updateAddr'
method = 'PUT'
}
})
.then(() => {
uni.hideLoading()
uni.navigateBack({
delta: 1
})
http.request({
url,
method,
data: {
receiver: receiver.value,
mobile: mobile.value,
addr: addr.value,
province: province.value,
provinceId: provinceId.value,
city: city.value,
cityId: cityId.value,
areaId: areaId.value,
area: area.value,
userType: 0,
addrId: addrId.value
}
})
}
const onReceiverInput = (e) => {
receiver.value = e.detail.value
}
const onMobileInput = (e) => {
mobile.value = e.detail.value
}
const onAddrInput = (e) => {
addr.value = e.detail.value
}
.then(() => {
uni.hideLoading()
uni.navigateBack({
delta: 1 //
})
})
}
//
const onReceiverInput = (e) => {
receiver.value = e.detail.value
}
const onMobileInput = (e) => {
mobile.value = e.detail.value
}
const onAddrInput = (e) => {
addr.value = e.detail.value
}
/**
* 删除配送地址
*/
const onDeleteAddr = () => {
uni.showModal({
title: '',
content: '确定要删除此收货地址吗?',
confirmColor: '#eb2444',
//
const onDeleteAddr = () => {
uni.showModal({
title: '',
content: '确定要删除此收货地址吗?',
confirmColor: '#eb2444',
success (res) {
if (res.confirm) {
const addrIdParam = addrId.value
uni.showLoading()
http.request({
url: '/p/address/deleteAddr/' + addrIdParam,
method: 'DELETE'
})
.then(() => {
uni.hideLoading()
uni.navigateBack({
delta: 1
})
success(res) {
if (res.confirm) {
const addrIdParam = addrId.value
uni.showLoading()
http.request({
url: '/p/address/deleteAddr/' + addrIdParam,
method: 'DELETE'
})
.then(() => {
uni.hideLoading()
uni.navigateBack({
delta: 1 //
})
})
}
}
}
})
}
})
}
</script>
<style scoped lang="scss">

@ -1,50 +1,67 @@
/* 设置页面背景颜色 */
page {
background: #f7f8fa;
}
/* 容器高度设置为100%,确保容器占据整个页面的高度 */
.container {
height: 100%;
}
/* 设置顶部内边距,以适应可能存在的导航栏或其他顶部组件 */
.padding20 {
padding-top: 88rpx;
padding-top: 88rpx; /* rpx 是相对于屏幕宽度的单位,适用于移动设备 */
}
/* 左浮动样式 */
.f-fl {
float: left;
}
/* 右浮动样式 */
.f-fr {
float: right;
}
/* 导航栏包裹器,固定在页面顶部 */
.navWrap {
position: fixed;
top: 0;
left: 0;
z-index: 1;
z-index: 1; /* 确保导航栏位于其他内容之上 */
overflow: hidden;
background-color: #fafafa;
border-bottom: 2rpx solid #f4f4f4;
height: 92rpx;
}
/* 导航栏内部布局 */
.nav {
display: flex;
flex-flow: row nowrap;
flex-flow: row nowrap; /* 水平排列,不换行 */
}
/* 导航栏底部滑动指示器 */
.nav-slider {
left: 0;
bottom: 0;
height: 4rpx;
background-color: #b4282d;
transition: transform 0.3s;
transition: transform 0.3s, -webkit-transform 0.3s;
transition: transform 0.3s, -webkit-transform 0.3s; /* 平滑过渡效果 */
box-sizing: border-box;
}
/* 单个导航项 */
.nav-item {
display: flex;
align-items: center;
justify-content: center;
flex: 1;
flex: 1; /* 均分空间 */
float: left;
height: 88rpx;
padding: 0 16rpx;
font-size: 28rpx;
text {
box-sizing: border-box;
color: #333;
@ -52,14 +69,20 @@ page {
line-height: 34rpx;
}
}
/* 当前选中的导航项 */
.nav-item.active {
text {
color: #b4282d;
color: #b4282d; /* 改变文字颜色 */
}
}
/* 图标对齐方式 */
.u-icon {
vertical-align: middle;
}
/* 物流信息展示区域 */
.deliveryInfo {
height: 198rpx;
width: 100%;
@ -69,24 +92,23 @@ page {
display: table;
position: relative;
box-sizing: border-box;
.companyname {
.companyname, .expno { /* 快递公司名称和快递单号 */
line-height: 1;
margin-left: 136rpx;
font-size: 28rpx;
.key {
.key { /* 标签部分的颜色 */
color: #666;
}
}
.expno {
line-height: 1;
margin-left: 136rpx;
font-size: 28rpx;
.expno { /* 快递单号样式 */
margin-top: 16rpx;
.key {
color: #666;
}
}
}
/* 物流图标 */
.icon-express {
width: 104rpx;
height: 104rpx;
@ -95,22 +117,30 @@ page {
top: 48rpx;
left: 30rpx;
}
/* 物流信息内的文本对齐 */
.infoWarp {
display: table-cell;
vertical-align: middle;
}
/* 物流详情部分 */
.deliveryDetail {
margin-top: 20rpx;
padding-top: 40rpx;
background-color: #fff;
min-height: 670rpx;
}
/* 物流进度条项 */
.detailItem {
border-left: 1px dashed #f4f4f4;
border-left: 1px dashed #f4f4f4; /* 左侧虚线 */
margin-left: 42rpx;
position: relative;
margin-bottom: 2rpx;
}
/* 进度点 */
.dot {
image {
width: 35rpx;
@ -121,29 +151,37 @@ page {
left: -18rpx;
}
}
/* 最新的物流信息 */
.lastest {
.dot {
image {
top: -2rpx;
top: -2rpx; /* 调整最新点的位置 */
}
}
.detail {
.desc {
color: #105c3e;
color: #105c3e; /* 文字颜色 */
margin-top: 0;
}
.time {
color: #105c3e;
color: #105c3e; /* 时间颜色 */
}
border-top: 0;
border-top: 0; /* 移除上边框 */
}
}
/* 物流详情描述 */
.detail {
.desc {
font-size: 24rpx;
line-height: 30rpx;
margin-top: 40rpx;
}
.time {
font-size: 24rpx;
line-height: 30rpx;
@ -151,11 +189,14 @@ page {
margin-top: 15rpx;
margin-bottom: 39rpx;
}
border-top: 1px solid #f4f4f4;
margin-left: 28rpx;
overflow: hidden;
padding-right: 30rpx;
}
/* 提示信息 */
.deliveryTip {
height: 80rpx;
background-color: #fff8d8;
@ -165,6 +206,8 @@ page {
line-height: 80rpx;
margin-bottom: 20rpx;
}
/* 空白占位符 */
.empty-space {
margin-top: 20rpx;
background: #fff;

@ -1,16 +1,21 @@
<template>
<!-- 物流信息 -->
<view class="container">
<!-- 主要内容包裹器 -->
<view class="wrapper">
<!-- 物流信息头部 -->
<view
class="deliveryInfo"
style="background:url(http://jiales.gz-yami.com/delivery-bg.png) center center no-repeat #fff;"
>
<!-- 物流图标 -->
<view
class="icon-express"
style="background:url(http://jiales.gz-yami.com/delivery-car.png) no-repeat;background-size:100% 100%;"
/>
<!-- 物流信息文本 -->
<view class="infoWarp">
<!-- 快递公司名称 -->
<view class="companyname">
<text class="key">
物流公司
@ -19,6 +24,7 @@
{{ companyName }}
</text>
</view>
<!-- 运单编号 -->
<view class="expno">
<text class="key">
运单编号
@ -29,30 +35,39 @@
</view>
</view>
</view>
<!-- 如果有物流数据则显示物流详情 -->
<view
v-if="dvyData.length"
class="deliveryDetail"
>
<!-- 使用v-for循环渲染每个物流详情项 -->
<block
v-for="(item, index) in dvyData"
:key="index"
>
<!-- 每个物流详情项如果是最新的一条记录则添加lastest类 -->
<view :class="'detailItem ' + (index==0?'lastest':'')">
<!-- 物流进度点 -->
<view class="dot">
<!-- 根据条件加载不同的点图标 -->
<image src="@/static/images/icon/delive-dot.png" />
<image src="@/static/images/icon/dot.png" />
</view>
<!-- 物流详情描述 -->
<view class="detail">
<view class="desc">
{{ item.context }}
{{ item.context }} <!-- 描述文字 -->
</view>
<view class="time">
{{ item.time }}
{{ item.time }} <!-- 时间戳 -->
</view>
</view>
</view>
</block>
</view>
<!-- 如果没有物流数据则显示暂无配送信息 -->
<view
v-else
class="empty-space"
@ -64,30 +79,39 @@
</template>
<script setup>
const companyName = ref('')
const dvyFlowId = ref('')
const dvyData = ref([])
//
const companyName = ref('') //
const dvyFlowId = ref('') //
const dvyData = ref([]) //
/**
* 生命周期函数--监听页面加载
*/
onLoad((options) => {
//
uni.showLoading()
//
http.request({
url: '/delivery/check',
method: 'GET',
url: '/delivery/check', // URL
method: 'GET', // HTTP
data: {
orderNumber: options.orderNum
orderNumber: options.orderNum //
}
})
.then(({ data }) => {
//
companyName.value = data.companyName
dvyFlowId.value = data.dvyFlowId
dvyData.value = data.data
//
uni.hideLoading()
})
})
</script>
<style scoped lang="scss">
/* 引入本地的SCSS文件用于定义样式 */
@use './express-delivery.scss';
</style>

Loading…
Cancel
Save