mall_client/zyhs3_uniapp/pages/order/index.vue

641 lines
21 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view>
<v-tabs
ref="tabs"
v-if="isDone"
v-model="current"
:tabs="tabs"
field="name"
height="90rpx"
fontSize="30rpx"
:fixed="true"
topOffset="var(--window-top)"
:scroll="true"
@change="changeTab">
</v-tabs>
<view class="list">
<view class="list-item" v-for="(item, i) in list" :key="i" @tap="goDetails(item)">
<view class="flex flex-between store">
<view class="flex flex-align-center">
<image :src="filterImg(item.storeInfo.logoImage)" mode="" class="logo"></image>
<text class="font34 color-b3">{{item.storeInfo.name}}</text>
<!-- <text class="iconfont color-b9 font36">&#xe770;</text> -->
</view>
<text class="color-purple font28" v-if="item.status === 1">待付款</text>
<text class="color-purple font28" v-if="item.status === 2">未支付完成</text>
<text class="color-purple font28" v-if="item.status === 3">{{deliveryStatus(item)}}</text>
<text class="color-purple font28" v-if="item.status === 4">待评价</text>
<text class="color-b9 font28" v-if="item.status === 5">已完成</text>
<text class="color-b9 font28" v-if="item.status === 10">已退款</text>
<text class="color-b9 font28" v-if="item.status === 11">已关闭</text>
</view>
<view class="goods flex">
<view class="goods-img">
<image :src="filterImg(item.skuImage || item.goodsImage)" mode="" class="img"></image>
<text class="tips">{{item.orderType | filterType}}</text>
</view>
<view class="flex flex-column" style="width: 100%;">
<block v-if="item.combOrderType === 1">
<text class="line font28 color-b3">{{item.goodsName + ' - ' + item.periodNo + '期'}}</text>
<text class="spec">{{item.skuName}}</text>
<view class="flex flex-between" style="width: 100%;"></view>
</block>
<block v-else>
<text class="line font28 color-b3">{{item.goodsName}}</text>
<text class="spec">{{item.skuName}}</text>
<view class="flex flex-between" style="width: 100%;">
<view class="flex">
<text class="color-red font30">¥{{item.unitPrice}}</text>
<text class="color-red font30" v-if="item.payIntegralAmount">,绿色积分{{item.payIntegralAmount}}</text>
</view>
<text class="color-b9 font26">x{{item.number}}</text>
</view>
</block>
</view>
</view>
<!-- 子订单渲染(父订单为待发货和已收货时展示) -->
<view
class="child-orders"
v-if="isShipTab() && item.combOrderType === 2 && item.childOrderList && item.childOrderList.length"
@tap.stop>
<view class="child-orders__title" @tap.stop="toggleChildOpen(item)">
<view>
<text class="font30 color-b3">分期子订单</text>
<text class="font24 color-b9">(共{{ item.childOrderList.length }}期)</text>
</view>
<text class="font26 color-b9 toggle">{{ isChildOpen(item) ? '收起' : '展开' }}</text>
</view>
<scroll-view scroll-y class="child-orders__scroller" v-if="isChildOpen(item)">
<view class="child-orders__content">
<block v-if="item.combOrderType === 2 && item.status === 4 && item.deliveryLogisticsStatus === 3"></block>
<block v-else>
<view class="child-orders__steps">
<u-steps direction="column" :activeColor="'#e5e5e5'" :inactiveColor="'#e5e5e5'">
<u-steps-item v-for="(sub, subIndex) in item.childOrderList" :key="sub.id || subIndex">
<template #icon>
<view class="custom-step-icon">
<u-icon :name="childStepIcon(sub)" :color="childStepColor(sub)" size="18"></u-icon>
</view>
</template>
</u-steps-item>
</u-steps>
</view>
</block>
<view class="child-orders__list">
<view
class="child-card"
v-for="(sub, subIndex) in item.childOrderList"
:key="sub.id || subIndex">
<block v-if="sub.status === 3 && sub.deliveryMethod === 1 && sub.deliveryLogisticsStatus === 1">
<view class="flex child-card__header">
<text class="badge">第{{ sub.periodNo }}期</text>
<view class="flex flex-align-center">
<text class="font26 color-b9" style="margin-left: 10rpx;margin-right: 10rpx;">预计发货:</text>
<!-- <text class="font24 color-b3">{{ expectedShipRange(item, sub) }}</text> -->
<text class="font24 color-b3">{{ sub.expectedDeliveryTime | formatYearMonth }}</text>
</view>
</view>
<view class="flex child-card__body">
<text class="font26 color-b9">收货人信息:</text>
<text class="font26 consignee" @tap.stop="openSenderForm(sub)">查看</text>
<text class="font26 consignee" @tap.stop="openAddressEdit(item, sub)">修改</text>
<!-- <text class="font24" :class="(sub.senderName||sub.senderMobile||sub.senderAddress)?'color-b3':'color-b9'">{{ (sub.senderName||sub.senderMobile||sub.senderAddress) ? '已设置' : '未设置' }}</text> -->
</view>
</block>
<block v-if="sub.status === 3 && sub.deliveryMethod === 1 && sub.deliveryLogisticsStatus === 2">
<view class="flex flex-between child-card__header">
<view class="flex flex-align-center">
<text class="badge">第{{ sub.periodNo }}期</text>
<text class="font26 color-b3 f-b">已发货</text>
</view>
<view class="flex flex-align-center" @tap.stop="goDetails(sub)">
<text class="font26 color-b9">订单详情</text>
<text class="iconfont color-b9 font36">&#xe770;</text>
</view>
</view>
<view class="child-card__body">
<text class="font26 color-b9" style="margin-left: 10rpx;margin-right: 10rpx;">发货时间:</text>
<text class="font26 color-b3">{{ sub.deliveryLogisticsDeliverTime }}</text>
</view>
</block>
<block v-if="sub.status === 4">
<view class="flex flex-between child-card__header">
<view class="flex flex-align-center">
<text class="badge">第{{ sub.periodNo }}期</text>
<text class="font26 color-b3 f-b">已收货</text>
</view>
<view class="flex flex-align-center" @tap.stop="goDetails(sub)">
<text class="font26 color-b9">订单详情</text>
<text class="iconfont color-b9 font36">&#xe770;</text>
</view>
</view>
<view class="child-card__body">
<text class="font26 color-b9" style="margin-left: 10rpx;margin-right: 10rpx;">收货时间:</text>
<text class="font26 color-b3">{{ sub.confirmReceiptTime }}</text>
</view>
</block>
</view>
</view>
</view>
</scroll-view>
</view>
<block v-if="item.combOrderType === 1">
</block>
<block v-else>
<view class="flex flex-align-end flex-space-end total font30">
<text class="color-b9 font28">总价¥{{item.totalPrice}}</text>
<text class="color-b9" v-if="item.couponStatus === 2">优惠¥{{item.couponAmount}},</text>
<text class="color-b3">
<text v-if="item.payIntegralAmount">,绿色积分{{item.payIntegralAmount}}</text>
</text>
</view>
</block>
<view class="btns">
<text class="btn base" v-if="item.status === 1 || item.status === 2" @tap.stop="payOrder(item)">立即支付</text>
<text class="btn base" v-if="item.status === 4" @tap.stop="toEvaluate(item.id)">立即评价</text>
<text class="btn base" v-if="item.deliveryLogisticsOrderNumber" @tap.stop="handlerExpress(item)">查看物流</text>
<text class="btn base" v-if="item.status === 3 && judgeReceiv(item)" @tap.stop="confimDelivery(item.id, 'getStatusNum')">确认收货</text>
<text class="btn base" v-if="item.status === 12 && judgeReceiv(item)" @tap.stop="confimUse(item.id, 'getStatusNum')">确认使用</text>
<text class="btn base" v-if="item.status === 5 && item.qvyu == 5 && item.status != 11" @tap.stop="handlerSign(item.id)">签署合同</text>
<!-- <block v-if="item.orderType !== 3 && item.status === 3 && judgeRefund(item)">
<block v-if="item.orderType !== 3 && item.status === 3 && judgeRefund(item)">
<text class="btn base" @tap.stop="onRefund(item)">申请退款</text>
</block> -->
<!-- <text class="btn base" v-if="item.status === 1 || item.status === 5 || item.status === 10 || item.status === 11" @tap.stop="delOrder(item.id, false)">删除订单</text> -->
<text class="btn base" v-if="item.status === 1 || item.status === 11" @tap.stop="delOrder(item.id, false)">删除订单</text>
</view>
</view>
</view>
<uni-load-more :status="loadingType"></uni-load-more>
<!-- 收货人信息查看弹层u-popup + 表单样式) -->
<u-popup :show="senderPopupShow" mode="bottom" @close="senderPopupShow = false" :round="15">
<view class="sender-popup">
<view class="flex flex-center">
<text class="font32 color-b3">收货人信息</text>
</view>
<view class="sp-form">
<view class="sp-row">
<view class="sp-label">联系人</view>
<view class="sp-value">{{ senderForm.fullName || '—' }}</view>
</view>
<view class="sp-row">
<view class="sp-label">手机号</view>
<view class="sp-value">{{ senderForm.mobile || '—' }}</view>
</view>
<view class="sp-row">
<view class="sp-label">地区</view>
<view class="sp-value">{{ senderForm.areaText || '—' }}</view>
</view>
<view class="sp-row">
<view class="sp-label">详细地址</view>
<view class="sp-value">{{ senderForm.addressDetails || '—' }}</view>
</view>
</view>
</view>
</u-popup>
</view>
</template>
<script>
import url from "@/common/http/url.js"
import mix from "./mix.js"
import vTabs from "@/components/v-tabs/v-tabs.vue"
import uniLoadMore from '@/components/uni-load-more/uni-load-more.vue';
import { handlerSign } from '@/utils/common.js';
import publics from "@/common/utils/public.js"
export default{
components: { vTabs, uniLoadMore },
mixins: [mix],
data(){
return {
isDone: false,
loadingType: "loading",
current: 0,
tabs: [
{name: "全部", status: 1},
{name: "待付款", status: 2},
{name: "待发货", status: 3},
{name: "待收货", status: 4},
{name: "待使用", status: 6},
{name: "待评价", status: 5},
// {name: "退款", status: 6}
],
list: [],
childOpenMap: {}, // 记录每个父订单的折叠状态
// 收货人信息查看
senderForm:{
fullName: "",
mobile: "",
areaText: "",
addressDetails: ""
},
senderPopupShow: false,
reShow: true
}
},
filters: {
filterType(val){
switch(val){
case 1:
return "普通";
case 2:
return "精品";
case 3:
return "进货";
case 11:
return "新人";
case 12:
return "秒杀";
case 13:
return "特价";
case 14:
return "拼团";
case 15:
return "积分";
default:
return "其他";
}
},
formatYearMonth(val){
try{
if(!val) return ''
let source = val
if (typeof source === 'string'){
// 提取日期部分并兼容 iOS 解析
source = source.split('T')[0].replace(/-/g, '/')
}
const d = new Date(source)
if (isNaN(d.getTime())) return ''
const y = d.getFullYear()
const m = d.getMonth() + 1
return `${y}${m}`
}catch(e){
return ''
}
}
},
onPullDownRefresh() {
this.getStatusNum()
},
onReachBottom(){
this.loadData();
},
onLoad(option) {
let status = option.status || 1
if (option.status) {
this.tabs.map((v, i) =>{
if (parseInt(option.status) === v.status) {
this.current = i
}
})
}
},
onShow() {
// 详情页操作后返回触发全量刷新(含数量与列表)
try{
const need = uni.getStorageSync('ORDER_LIST_NEED_REFRESH')
if (need) {
uni.removeStorageSync('ORDER_LIST_NEED_REFRESH')
this.getStatusNum()
return
}
}catch(e){}
if (this.reShow) {
this.getStatusNum()
}
this.reShow = false;
},
methods:{
// 子订单步骤条:根据状态返回图标
childStepIcon(sub){
const s = Number(sub.status)
if(s === 4) return 'checkmark'
if(s === 3 && sub.deliveryMethod === 1 && sub.deliveryLogisticsStatus === 2) return 'car'
return 'clock'
},
// 子订单步骤条:根据状态返回颜色
childStepColor(sub){
const s = Number(sub.status)
if(s === 4) return '#5ac725'
if(s === 3 && sub.deliveryMethod === 1 && sub.deliveryLogisticsStatus === 2) return '#3c3cff'
return '#F8D247'
},
isShipTab(){
return this.tabs[this.current] && (this.tabs[this.current].status === 3 || this.tabs[this.current].status === 5)
},
handlerSign (id) {
handlerSign(id)
},
handlerExpress (item) {
this.$navigateTo(`/pages/order/express/express?com=${item.deliveryLogisticsCompanyCode}&num=${item.deliveryLogisticsOrderNumber}&name=${item.deliveryLogisticsCompanyName}&phone=${item.userMobile}`)
},
loadData(){
this.loadingType = "loading"
let params = {
pageNum: this.list.length,
type: this.tabs[this.current].status
}
this.$http("GET", url.order.orderList, params).then(res =>{
this.list = this.list.concat(res.data)
this.loadingType = res.data < 12 ? 'nomore' : 'more';
uni.stopPullDownRefresh();
})
},
getStatusNum(){
this.tabs = [
{name: "全部", status: 1},
{name: "待付款", status: 2},
{name: "待发货", status: 3},
{name: "待收货", status: 4},
{name: "待使用", status: 7},
{name: "待评价", status: 5},
// {name: "退款", status: 6}
];
this.$http("GET", url.order.getOrderAmount).then(res =>{
if (res.data.whole) {
this.tabs[0].name = `全部(${res.data.whole})`
}
if (res.data.unpaid){
this.tabs[1].name = `待付款(${res.data.unpaid})`
}
if (res.data.ongoing){
this.tabs[2].name = `待发货(${res.data.ongoing})`
}
if (res.data.waitReceived){
this.tabs[3].name = `待收货(${res.data.waitReceived})`
}
if (res.data.notUsed){
this.tabs[4].name = `待使用(${res.data.notUsed})`
}
if (res.data.evaluated){
this.tabs[5].name = `待评价(${res.data.evaluated})`
}
this.isDone = true
this.$nextTick(() => {
this.$refs.tabs && this.$refs.tabs.getTabItemWidth && this.$refs.tabs.getTabItemWidth()
this.list = []
this.loadData();
})
})
},
// 取消订单
cancelOrder(){
let _this = this;
this.$showModal("是否确定取消该笔订单?", null, res=>{
if (res.confirm) {
_this.$http("POST", url.order.closeOrder, {orderId: item.id}).then(res =>{
_this.$msg(res.data)
_this.list = []
_this.loadData()
})
}
})
},
// 订单详情
goDetails(item){
this.$navigateTo('details?id=' + item.id)
},
changeTab(i) {
this.current = i
this.list = []
this.loadData()
},
// 折叠/展开子订单
toggleChildOpen(parent){
const key = parent.id || `${parent.storeInfo && parent.storeInfo.id || 'store'}-${parent.createTime}`
this.$set(this.childOpenMap, key, !this.childOpenMap[key])
},
isChildOpen(parent){
const key = parent.id || `${parent.storeInfo && parent.storeInfo.id || 'store'}-${parent.createTime}`
return !!this.childOpenMap[key]
},
// 预计发货时间范围([付款+(n-1)月, 付款+n月]
expectedShipRange(parentItem, childItem){
try{
let base = parentItem.rmbPayTime || parentItem.payTime || parentItem.createTime
if(!base) return '时间未知'
let payDate = this.parseDate(base)
let start = this.addMonths(new Date(payDate), (childItem.periodNo || 1) - 1)
let end = this.addMonths(new Date(payDate), (childItem.periodNo || 1))
return `${this.formatDate(start)} ~ ${this.formatDate(end)}`
}catch(e){
return '时间未知'
}
},
addMonths(date, months){
let d = new Date(date)
let day = d.getDate()
d.setMonth(d.getMonth() + months)
if (d.getDate() !== day){
// 处理月底溢出
d.setDate(0)
}
return d
},
parseDate(str){
// 兼容 iOS将 YYYY-MM-DD 替换为 YYYY/MM/DD
if(typeof str === 'string'){
return str.replace(/-/g, '/').slice(0, 19)
}
return str
},
formatDate(d){
const pad = n => n < 10 ? '0'+n : ''+n
return `${d.getFullYear()}-${pad(d.getMonth()+1)}-${pad(d.getDate())}`
},
openSenderForm(childItem){
this.$http("GET", url.order.getOrderInfoById, {orderId: childItem.id}).then(({code, data}) =>{
if (code == 200) {
this.senderForm.fullName = data.userFullName || ''
this.senderForm.mobile = data.userMobile || ''
// 地区名称拼接,参考地址编辑页地区选择
let areaText = ''
try{
if (data.userThreeAdcode) {
const arr = publics.getLngAndLatByCode(data.userThreeAdcode) || []
arr.forEach(v => { areaText = areaText + (v.name || '') })
}
}catch(e){ areaText = '' }
this.senderForm.areaText = areaText
this.senderForm.addressDetails = data.userAddressDetails || ''
this.senderPopupShow = true
}
})
},
// 修改收货人信息:跳转至地址列表,逻辑与订单详情一致
openAddressEdit(parentItem, childItem){
if(!childItem || !childItem.id){
return
}
this.$navigateTo(`/pages/user/address/index?orderId=${childItem.id}&&editAddr=true`)
this.reShow = false;
}
}
}
</script>
<style scoped lang="scss">
.list{
margin: 20rpx;
&-item{
border-radius: 20rpx;
margin-bottom: 20rpx;
padding: 20rpx;
background-color: white;
.store{
.logo{
width: 50rpx;
height: 50rpx;
display: block;
margin-right: 20rpx;
border-radius: 8rpx;
}
}
.goods{
margin-top: 20rpx;
&-img{
position: relative;
margin-right: 20rpx;
width: 140upx;
height: 140upx;
overflow: hidden;
border-radius: 10upx;
.img{
flex-shrink: 0;
display: block;
width: 140upx;
height: 140upx;
}
.tips{
color: #CA0400;
background-color: white;
font-size: 24rpx;
position: absolute;
right: -32rpx;
top: -16rpx;
width: 100rpx;
text-align: center;
height: 60rpx;
line-height: 80rpx;
transform: rotate(45deg);
}
}
.spec{
background-color: #F8F8F8;
color: #bcbbbd;
font-size: 24rpx;
padding: 10rpx;
margin-top: 4rpx;
border-radius: 8rpx;
align-self: flex-start;
}
}
.child-orders{
margin-top: 16rpx;
padding: 16rpx;
background: #FAFAFA;
border-radius: 12rpx;
&__title{
display: flex;
align-items: baseline;
justify-content: space-between;
margin-bottom: 12rpx;
}
&__scroller{
max-height: 375rpx;
overflow: hidden;
}
&__content{
display: flex;
flex-direction: row;
}
&__steps{
width: 56rpx;
padding-right: 10rpx;
display: flex;
justify-content: flex-start;
}
&__list{
flex: 1;
.child-card{
background: #FFFFFF;
border-radius: 10rpx;
padding: 16rpx;
margin-bottom: 12rpx;
&__header{ display: flex; align-items: center;}
&__body{ margin-top: 10rpx; }
.badge{
background: #F8D247;
color: #3a2397;
border-radius: 8rpx;
padding: 4rpx 10rpx;
font-size: 22rpx;
margin-right: 10rpx;
}
.consignee {
color: #333333;
border: 1rpx solid #999999;
padding: 0 24rpx;
border-radius: 20rpx;
margin-right: 15rpx;
}
}
}
.btn.mini{
margin-left: 10rpx;
width: auto;
padding: 0 20rpx;
}
}
::v-deep .u-steps-item__wrapper {
background-color: #FAFAFA;
}
.total{
margin: 20rpx 0;
}
.btns{
display: flex;
justify-content: flex-end;
.btn{
margin-left: 10rpx;
width: 160rpx;
height: 60rpx;
text-align: center;
line-height: 60rpx;
display: inline-block;
border-radius: 50rpx;
color: #666666;
border: 2rpx solid #e9eae9;
font-size: 26rpx;
}
.base{
color: #F8D247;
border: 2rpx solid #F8D247;
}
}
}
}
.sender-popup{
padding: 20rpx;
}
.sender-actions{
margin-top: 20rpx;
display: flex;
justify-content: flex-end;
}
.sp-form{ margin-top: 20rpx; }
.sp-row{ height: 80rpx; display: flex; align-items: center; border-bottom: 1upx solid #EEEEEE; }
.sp-label{ width: 25%; display: flex; align-items: center; font-size: 32rpx; color: #676769; }
.sp-value{ flex: 1; font-size: 30rpx; color: #676769; }
</style>