You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

1257 lines
41 KiB

<template>
<!-- 商家订单详情 -->
<view class="page1">
<view class="title">
<view class="title-sreach">
<view class="back-btn" @tap="back" :style="{'top': menuButtonInfo.top +'px'}">
<uni-icons type="left" size="28"></uni-icons>
</view>
<view class="title-name" :style="{'padding-top': menuButtonInfo.top +'px'}">
订单详情
</view>
</view>
</view>
<view class="title-holder"></view>
<view class="content">
<view class="box1 order-header">
<view class="order-header-info">
<text v-if="data.numberCode" class="order-number">{{'#'+data.numberCode}}</text>
<view class="order-time">
<text class="order-time-label">{{getHeaderTimeLabel(data)}}</text>
<text class="order-time-text">{{getHeaderTimeText(data)}}</text>
</view>
</view>
<text class="order-status">
{{data.status == 0?'待支付':data.status == 2?'待配送员接单':(data.status == 3 && data.deliveryType == 1 && data.shopMakeTime == null) || (data.status == 3 && data.deliveryType == 2 && data.userRequireMake == 1)?'待出餐':(data.status == 3 && data.deliveryType == 1 && data.shopMakeTime != null)?'待取货':(data.status == 3 && data.deliveryType == 2)?'待消费':data.status == 4?'待送达':data.status == 5?'已完成':data.status == 7?'待同意退款':data.status == 8?'已退款':data.status == 6?'已取消':data.status == 11?'售后中':data.status == 12?'已售后':""}}
</text>
</view>
<view class="box1" style="display: flex;height: 100rpx;line-height: 100rpx;padding: 0 20rpx;">
<view style="border: 1px solid #48D1CC;height: 50rpx;line-height: 50rpx;padding: 0 20rpx;border-radius: 20rpx;margin-top: auto;margin-bottom: auto;color: #48D1CC;font-weight: 700;">
{{(data.deliveryType == 1 && data.orderType != 3)?'普通配送单':(data.deliveryType == 1 && data.orderType == 3)?'面对面配送单':(data.isPack == 1 && data.otherOrder == null)?'自取-打包':(data.isPack == 0 && data.otherOrder == null)?'自取-堂食':'到店消费'}}
</view>
<view v-if="data.deliveryType == 1" style="display: flex;flex: 1;padding-left: 20rpx;">
<text style="flex: 1;">{{data.shopDelivery == 1 ? '商家配送员' : '配送员'}}:{{getWorkerName(data)}}</text>
<view class="" v-if="data.deliveryInfo && data.deliveryInfo.workerPhone">
<img @tap="makeCall(data.deliveryInfo.workerPhone)" src="https://jewel-shop.oss-cn-beijing.aliyuncs.com/869a7af6a1c24bf3a0d523c4a18b55c6.png" alt="" style="width: 60rpx;height: 60rpx;margin-top: 20rpx;" />
</view>
</view>
</view>
<view class="box1 delivery-card" v-if="data.deliveryType == 1 && data.deliveryInfo" style="display: flex;">
<view style="flex: 1;">
<view style="font-weight: 700;height: 50rpx;">
收货人:{{data.deliveryInfo.receiverName}}
</view>
<view style="color: #777;line-height: 36rpx;">
{{data.deliveryInfo.receiverAddress}}
</view>
<view class="delivery-time" v-if="data.deliveryInfo.mustFinishTime">
预计{{data.deliveryInfo.mustFinishTime | formatHourMinute}}送达
</view>
</view>
<view class="" v-if="data.deliveryInfo.receiverPhone">
<img @tap="makeCall(data.deliveryInfo.receiverPhone)" src="https://jewel-shop.oss-cn-beijing.aliyuncs.com/869a7af6a1c24bf3a0d523c4a18b55c6.png" alt="" style="width: 60rpx;height: 60rpx;margin-top: 28rpx;" />
</view>
</view>
<view class="box1 remark-box" v-if="data.remark">
<view class="remark-label">用户备注</view>
<view class="remark-text">{{data.remark}}</view>
</view>
<view class="box1">
<view style="border-bottom: 1px solid #eee;padding-bottom: 20rpx;">
<view style="font-size: 32rpx;height: 60rpx;">
商品 <text style="font-size: 28rpx;color: #777;">共{{data.goodsNum}}件</text>
</view>
<view v-for="(item,index) in data.goodsList" :key="index" style="display: flex;min-height: 48rpx;line-height: 40rpx;">
<view style="flex: 1;">
<view>{{item.productName}}</view>
<view class="goods-spec" v-if="item.specs">{{item.specs | delNode}}</view>
</view>
<view style="width: 60rpx;">
{{'x'+ item.quantity}}
</view>
<view style="width: 100rpx;text-align: right;">
¥{{formatAmount(item.price)}}
</view>
</view>
</view>
<view class="">
<view style="display: flex;height: 60rpx;line-height: 60rpx;">
<view style="flex: 1;">
商品金额
</view>
<view class="">
¥{{formatAmount(data.goodsAmount)}}
</view>
</view>
<view style="display: flex;height: 60rpx;line-height: 60rpx;" v-if="data.packageFee != null && data.packageFee > 0">
<view style="flex: 1;">
打包/餐盒费
</view>
<view class="">
¥{{formatAmount(data.packageFee)}}
</view>
</view>
<view style="display: flex;height: 60rpx;line-height: 60rpx;" v-if="data.deliveryFee > 0">
<view style="flex: 1;">
配送费
</view>
<view class="">
¥{{formatAmount(data.deliveryFee)}}
</view>
</view>
<view style="display: flex;height: 60rpx;line-height: 60rpx;" v-if="data.freeAmount != null && data.freeAmount > 0">
<view style="flex: 1;color: #ff6f2c;font-weight: 700;">
锦鲤免单
</view>
<view style="color: #ff6f2c;font-weight: 700;">
¥{{formatAmount(data.freeAmount)}}
</view>
</view>
<view style="display: flex;height: 60rpx;line-height: 60rpx;" v-if="data.userCouponNum != null && data.userCouponNum > 0">
<view style="flex: 1;">
优惠券
</view>
<view class="">
-¥{{formatAmount(data.userCouponNum)}}
</view>
</view>
<view style="display: flex;height: 60rpx;line-height: 60rpx;">
<view style="flex: 1;">
客户实际支付
</view>
<view class="">
¥{{formatAmount(data.totalAmount)}}
</view>
</view>
<view v-if="Ptype != 'work'" style="display: flex;height: 60rpx;line-height: 60rpx;">
<view style="flex: 1;">
平台服务费
</view>
<view class="">
¥{{data.chouyong ?data.chouyong:0}}
</view>
</view>
</view>
</view>
<view class="box1 refund-box" v-if="data.mallRefundRecord != null && data.mallRefundRecord.length > 0">
<view class="refund-title">
<text style="flex: 1;">退款/售后</text>
<view class="refund-service-btn" @tap="callPlatformService">
平台介入
</view>
</view>
<view class="refund-card" v-for="(item,index) in data.mallRefundRecord" :key="index">
<view class="refund-row">
<view class="refund-label">申请时间</view>
<view class="refund-value">{{item.createTime | formatISOTime}}</view>
</view>
<view class="refund-row">
<view class="refund-label">金额</view>
<view class="refund-value refund-amount">¥{{formatMoney(getMerchantRefundDisplayAmount(item))}}</view>
</view>
<view class="refund-goods-card" v-for="(goods,goodsIndex) in item.items" :key="goodsIndex"
v-if="item.items != null && item.items.length > 0">
<view class="refund-goods-img">
<img :src="goods.productPicture" alt="">
</view>
<view class="refund-goods-content">
<view class="refund-goods-name">{{goods.productName}}</view>
<view class="refund-goods-spec">{{goods.specs | delNode}}</view>
<view class="refund-goods-bottom">
<text>X{{goods.quantity}}</text>
<text>¥{{formatAmount(goods.price)}}</text>
</view>
<view class="refund-goods-bottom" v-if="goods.packageFee != undefined && goods.packageFee > 0 && data.packageFee > 0">
<text>餐盒费</text>
<text>¥{{formatAmount(goods.packageFee)}}</text>
</view>
</view>
</view>
<view class="refund-info-row">
<view class="refund-info-label">原因</view>
<view class="refund-info-value">{{item.reason != null ? item.reason : ''}}</view>
</view>
<view class="refund-info-row" v-if="getPictureList(item.pictures).length > 0">
<view class="refund-info-label">图片</view>
<view class="refund-info-value refund-image-list">
<image class="refund-image" v-for="(picture,pictureIndex) in getPictureList(item.pictures)"
:key="pictureIndex" :src="picture" mode="aspectFill"
@tap="previewRefundImage(item.pictures,pictureIndex)"></image>
</view>
</view>
<view class="refund-info-row">
<view class="refund-info-label">退款/售后类型</view>
<view class="refund-info-value">{{getRefundTypeText(item)}}<text v-if="item.refundTypeStatus != null"> | {{getRefundReasonTypeText(item)}}</text></view>
</view>
<view class="refund-info-row">
<view class="refund-info-label">退款/售后状态</view>
<view class="refund-info-value">{{getRefundStatusText(item)}}</view>
</view>
<view class="refund-info-row" v-if="(item.status == 2 || item.status == 5) && item.rejectReason">
<view class="refund-info-label">拒绝原因</view>
<view class="refund-info-value">{{item.rejectReason}}</view>
</view>
<view class="auto-refund-tip" v-if="isRefundPending(item)">
{{getAutoRefundTime(item.createTime)}} 之前对方未处理系统会自动退款
</view>
<view class="refund-info-row" v-if="item.successTime != null">
<view class="refund-info-label">处理退款/售后时间</view>
<view class="refund-info-value">{{item.successTime | formatISOTime}}</view>
</view>
</view>
</view>
<view class="box1 income-card" v-if="data.incomeSummary && data.incomeSummary.show && Ptype !='work'">
<view class="income-title">
<text>商家预计收入</text>
<text class="income-total">¥{{formatMoney(data.incomeSummary.expectedIncome)}}</text>
</view>
<view class="income-subtitle">{{data.incomeSummary.remark}}</view>
<view class="income-row">
<text>结算基数</text>
<text>¥{{formatMoney(data.incomeSummary.baseAmount)}}</text>
</view>
<view class="income-formula">商品金额 ¥{{formatMoney(data.goodsAmount)}} + 餐盒/打包费 ¥{{formatMoney(data.packageFee)}}</view>
<view class="income-row">
<text>抽佣比例</text>
<text>{{formatMoney(data.incomeSummary.commissionRate)}}%</text>
</view>
<view class="income-row">
<text>正常结算</text>
<text>¥{{formatMoney(data.incomeSummary.normalSettlementAmount)}}</text>
</view>
<view class="income-formula">
¥{{formatMoney(data.incomeSummary.normalBaseAmount)}} - 平台服务费 ¥{{formatMoney(data.incomeSummary.normalCommissionAmount)}}
</view>
<view class="income-row" v-if="data.incomeSummary.deductionBaseAmount > 0">
<text>退款/售后责任扣款</text>
<text class="income-negative">-¥{{formatMoney(data.incomeSummary.deductionSettlementAmount)}}</text>
</view>
<view class="income-formula" v-if="data.incomeSummary.deductionBaseAmount > 0">
责任金额 ¥{{formatMoney(data.incomeSummary.deductionBaseAmount)}} - 返还服务费 ¥{{formatMoney(data.incomeSummary.deductionCommissionAmount)}}
</view>
<view class="income-row income-result">
<text>预计收入</text>
<text>¥{{formatMoney(data.incomeSummary.expectedIncome)}}</text>
</view>
<view class="income-formula">正常结算 - 退款/售后责任扣款</view>
<view class="income-line-list" v-if="data.incomeSummary.lines && data.incomeSummary.lines.length > 0">
<view class="income-line" v-for="(line,lineIndex) in data.incomeSummary.lines" :key="lineIndex">
<text>{{line.name}}</text>
<text :class="{'income-negative': line.amount < 0}">{{line.amount < 0 ? '-' : ''}}{{formatMoney(absAmount(line.amount))}}</text>
</view>
</view>
</view>
<view class="box1">
<view class="">
<view style="display: flex;height: 60rpx;line-height: 60rpx;">
<view style="width: 140rpx;">
订单编号
</view>
<view style="flex: 1;text-align: right;">
{{data.id}}
</view>
</view>
<view style="display: flex;height: 60rpx;line-height: 60rpx;">
<view style="width: 140rpx;">
下单时间
</view>
<view style="flex: 1;text-align: right;">
{{data.createTime | formatISOTime}}
</view>
</view>
<view v-if="data.payTime" style="display: flex;height: 60rpx;line-height: 60rpx;">
<view style="width: 140rpx;">
支付时间
</view>
<view style="flex: 1;text-align: right;">
{{data.payTime | formatISOTime}}
</view>
</view>
<view v-if="data.groupInfo && data.groupInfo.successTime" style="display: flex;height: 60rpx;line-height: 60rpx;">
<view style="width: 140rpx;">
成团时间
</view>
<view style="flex: 1;text-align: right;">
{{data.groupInfo.successTime | formatISOTime}}
</view>
</view>
<view v-if="data.deliveryType == 2 && data.shopMakeTime" style="display: flex;height: 60rpx;line-height: 60rpx;">
<view style="width: 140rpx;">
核销时间
</view>
<view style="flex: 1;text-align: right;">
{{data.shopMakeTime | formatISOTime}}
</view>
</view>
<view v-if="data.deliveryInfo && data.deliveryType == 1 && data.deliveryInfo.acceptTime" style="display: flex;height: 60rpx;line-height: 60rpx;">
<view style="width: 180rpx;">
接单时间
</view>
<view style="flex: 1;text-align: right;">
{{data.deliveryInfo.acceptTime | formatISOTime}}
</view>
</view>
<view v-if="data.deliveryType == 1 && data.shopMakeTime" style="display: flex;height: 60rpx;line-height: 60rpx;">
<view style="width: 180rpx;">
商家出餐时间
</view>
<view style="flex: 1;text-align: right;">
{{data.shopMakeTime | formatISOTime}}
</view>
</view>
<view v-if="data.deliveryInfo && data.deliveryType == 1 && data.deliveryInfo.arriveTime" style="display: flex;height: 60rpx;line-height: 60rpx;">
<view style="width: 180rpx;">
到店时间
</view>
<view style="flex: 1;text-align: right;">
{{data.deliveryInfo.arriveTime | formatISOTime}}
</view>
</view>
<view v-if="data.deliveryInfo && data.deliveryType == 1 && data.deliveryInfo.getTime" style="display: flex;height: 60rpx;line-height: 60rpx;">
<view style="width: 180rpx;">
取货时间
</view>
<view style="flex: 1;text-align: right;">
{{data.deliveryInfo.getTime | formatISOTime}}
</view>
</view>
<view v-if="data.deliveryInfo && data.deliveryType == 1" style="display: flex;height: 60rpx;line-height: 60rpx;">
<view style="width: 180rpx;">
{{data.deliveryInfo.finishTime ? '送达时间' : '预计送达'}}
</view>
<view style="flex: 1;text-align: right;">
{{(data.deliveryInfo.finishTime || data.deliveryInfo.mustFinishTime || '尽快送达') | formatISOTime}}
</view>
</view>
<view v-if="data.deliveryInfo && data.deliveryInfo.transferDelivery == 1" style="display: flex;height: 60rpx;line-height: 60rpx;">
<view style="width: 180rpx;">
中转配送
</view>
<view style="flex: 1;text-align: right;color: #ff6f2c;font-weight: 700;">
{{data.deliveryInfo.transferAddressName || data.transferAddressName || '是'}}
</view>
</view>
<view v-if="data.deliveryInfo && data.deliveryInfo.transferDelivery == 1" style="display: flex;height: 60rpx;line-height: 60rpx;">
<view style="width: 180rpx;">
送达中转点
</view>
<view style="flex: 1;text-align: right;">
{{data.deliveryInfo.transferArriveTime ? formatTimeText(data.deliveryInfo.transferArriveTime) : '未送达'}}
</view>
</view>
<!-- <view v-if="data.receiverPhone" style="display: flex;height: 60rpx;line-height: 60rpx;">
<view style="width: 140rpx;">
用户账号
</view>
<view style="flex: 1;text-align: right;">
{{data.receiverPhone}}
</view>
</view> -->
<view v-if="data.orderType != 1 && data.groupInfo != null" style="display: flex;height: 60rpx;line-height: 60rpx;">
<view style="width: 140rpx;">
团购信息
</view>
<view @tap="checkGroup" style="flex: 1;text-align: right;">
查看 >
</view>
</view>
</view>
</view>
</view>
<view class="bottom">
<view v-if="data.status != 6 && data.status != 8 && Ptype != 'work'" style="height: 66rpx;line-height: 66rpx;display: flex;border-bottom: 1px solid #eee;font-size: 33rpx;">
<view style="flex: 1;">
预计收入
</view>
<view style="color: red;font-weight: 700;">
¥{{data.incomeSummary ? formatMoney(data.incomeSummary.expectedIncome) : (data.yujishouru?data.yujishouru:0)}}
</view>
</view>
<view style="margin-top: 20rpx;">
<view @tap="mealServing(data)" v-if="(data.status == 3 && data.deliveryType == 1 && data.shopMakeTime == null) || (data.status == 3 && data.deliveryType == 2 && data.userRequireMake == 1)" class="btn" style="background: rgba(0, 35, 28, 1);color: rgba(166, 255, 234, 1);">
已出餐
</view>
</view>
</view>
<!-- 拼团信息弹出层 -->
<uni-popup ref="groupPopup" background-color="#fff">
<view class="group-content" v-if="data.groupInfo">
<view style="height: 100rpx;text-align: center;line-height: 100rpx;font-size: 36rpx;font-weight: 700;">
<text>{{data.groupInfo.targetMembers}}人团/</text><text>已拼{{data.groupInfo.currentMembers}}人</text>
</view>
<view class="kaituan2">
<view class="kaituan22" style="display: flex;" v-if="data.groupInfo.groupIdList">
<view class="" @tap="goDetail(item)" v-for="(item,index) in data.groupInfo.groupIdList" :key="index" style="width: 90rpx;height: 90rpx;margin: 0 auto;position: relative;">
<view style="z-index: 99;position: absolute;top:0;width: 90rpx;height: 90rpx;border-radius: 90rpx;border:4rpx solid #48D1CC"></view>
<view style="">
<img src="/static/images/img/songshu.png" alt="" style="width: 90rpx;height: 90rpx;border-radius: 90rpx;display: block;" />
</view>
<view style="background: #fff;position: absolute;bottom: 6rpx;width: 100%;height: 24rpx;font-size: 20rpx;line-height: 24rpx;text-align: center;">
{{item | lastFour}}
</view>
</view>
</view>
<view v-if="(data.groupInfo.targetMembers - data.groupInfo.currentMembers) > 0" class="kaituan22">
<view class="weipincheng">
+
</view>
</view>
</view>
<view style="height: 100rpx;line-height: 100rpx;text-align: center;font-weight: 700;">
点击头像可查看拼团订单详情
</view>
</view>
</uni-popup>
</view>
</template>
<script>
export default {
data() {
return {
Ptype:'',
menuButtonInfo: {},
data:{},
mealServingLoading: false
}
},
filters:{
formatHourMinute(value) {
if (!value) return '';
if (value == '尽快送达') return '尽快送达';
const date = new Date(value);
if (isNaN(date.getTime())) return value;
const hour = String(date.getHours()).padStart(2, '0');
const minute = String(date.getMinutes()).padStart(2, '0');
return `${hour}:${minute}`;
},
formatISOTime(isoString) {
if (!isoString) return '';
if (isoString == '尽快送达') return '尽快送达';
const date = new Date(isoString);
if (isNaN(date.getTime())) return isoString;
const year = date.getFullYear();
const month = (date.getMonth() + 1).toString().padStart(2, '0');
const day = date.getDate().toString().padStart(2, '0');
const hours = date.getHours().toString().padStart(2, '0');
const minutes = date.getMinutes().toString().padStart(2, '0');
const seconds = date.getSeconds().toString().padStart(2, '0');
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
},
delNode(data) {
if (data == null || data === '') return '';
let str = '';
if (typeof data === 'object') {
str = JSON.stringify(data);
} else {
str = String(data);
}
return str.replace(/[{}"]/g, '');
},
lastFour(str){
if (str == null) return '';
return String(str).slice(-4);
}
},
onShow() {
this.menuButtonInfo = uni.getMenuButtonBoundingClientRect()
},
onLoad(option) {
this.Ptype = option.type
this.shopId = option.id
this.getDetail()
},
methods: {
formatTimeText(value) {
return this.$options.filters.formatISOTime(value);
},
formatAmount(value) {
if (value === undefined || value === null || value === '') return '0';
return value;
},
formatMoney(value) {
let num = this.toAmount(value);
return num.toFixed(2);
},
toAmount(value) {
let num = Number(value);
return isNaN(num) ? 0 : num;
},
roundAmount(value) {
return Number(this.toAmount(value).toFixed(2));
},
absAmount(value) {
return Math.abs(this.toAmount(value));
},
isRunnerOrder(order) {
return order && order.otherOrder == 1;
},
isMerchantDeliveryOrder(order) {
return order && order.deliveryType == 1;
},
isWorkerRefundRecord(record) {
return !!(record && record.linkId && String(record.linkId).toUpperCase().indexOf('W') == 0);
},
isApprovedRefundRecord(record) {
return record && (record.status == 1 || record.status == 4);
},
isMerchantResponsibilityRecord(record) {
if (!record || this.isWorkerRefundRecord(record)) return false;
return record.refundTypeStatus == 1 || record.refundTypeStatus == 3;
},
isMerchantAfterSaleDeductionRecord(record) {
if (!record || record.status != 4) return false;
if (!this.isMerchantResponsibilityRecord(record)) return false;
return record.refundType != 2;
},
getMerchantRefundDisplayAmount(item) {
if (!item) return 0;
return item.settlementAmount != null ? item.settlementAmount : item.refundAmount;
},
getCommissionRate(order) {
let shopTakeaway = uni.getStorageSync('shopTakeaway') || {};
if (order && order.orderType == 1) {
return this.toAmount(shopTakeaway.commissionRateOne);
}
return this.toAmount(shopTakeaway.commissionRateMore);
},
getSettlementNet(baseAmount, commissionBaseAmount, commissionRate) {
let commission = this.roundAmount(this.toAmount(commissionBaseAmount) * this.toAmount(commissionRate) / 100);
let settlement = this.roundAmount(this.toAmount(baseAmount) - commission);
return {
commission,
settlement
};
},
buildMerchantIncomeSummary(order) {
if (!order || this.isRunnerOrder(order)) {
return {
show: false,
expectedIncome: 0
};
}
let baseAmount = this.roundAmount(this.toAmount(order.goodsAmount) + this.toAmount(order.packageFee));
let deliveryFee = this.toAmount(order.deliveryFee);
let commissionRate = this.getCommissionRate(order);
let refundRecords = Array.isArray(order.mallRefundRecord) ? order.mallRefundRecord : [];
let approvedRefundRecords = refundRecords.filter(item => this.isApprovedRefundRecord(item));
let hasWorkerReasonRefund = approvedRefundRecords.some(item => item.status == 1 && item.refundTypeStatus == 2 && this.isWorkerRefundRecord(item));
let hasMerchantReasonRefund = approvedRefundRecords.some(item => item.status == 1 && item.refundTypeStatus == 1 && this.isMerchantResponsibilityRecord(item));
let hasBothReasonRefund = approvedRefundRecords.some(item => item.status == 1 && item.refundTypeStatus == 3);
let normalBaseAmount = (order.status == 6 || order.status == 8) ? 0 : baseAmount;
if (order.status == 8 && hasWorkerReasonRefund) {
normalBaseAmount = baseAmount;
}
if (order.status == 8 && (hasMerchantReasonRefund || hasBothReasonRefund)) {
normalBaseAmount = 0;
}
let normalNet = this.getSettlementNet(normalBaseAmount, normalBaseAmount, commissionRate);
let deductionBaseAmount = 0;
let deductionCommissionAmount = 0;
let deductionSettlementAmount = 0;
let lines = [];
if (normalBaseAmount > 0) {
lines.push({
name: '正常订单结算',
amount: normalNet.settlement
});
}
if (order.status == 8 && hasMerchantReasonRefund && this.isMerchantDeliveryOrder(order)) {
let deliveryDeduction = this.roundAmount(deliveryFee);
deductionBaseAmount = this.roundAmount(deductionBaseAmount + deliveryFee);
deductionSettlementAmount = this.roundAmount(deductionSettlementAmount + deliveryDeduction);
lines.push({
name: '商家原因退款承担配送费',
amount: -deliveryDeduction
});
}
approvedRefundRecords.forEach(item => {
if (!this.isMerchantAfterSaleDeductionRecord(item)) return;
let responsibilityAmount = this.toAmount(this.getMerchantRefundDisplayAmount(item));
if (responsibilityAmount <= 0) return;
let includesDeliveryFee = item.refundType == 3 && item.refundTypeStatus == 1 && this.isMerchantDeliveryOrder(order);
let commissionBase = includesDeliveryFee ? Math.max(0, responsibilityAmount - deliveryFee) : responsibilityAmount;
let deductionNet = this.getSettlementNet(responsibilityAmount, commissionBase, commissionRate);
deductionBaseAmount = this.roundAmount(deductionBaseAmount + responsibilityAmount);
deductionCommissionAmount = this.roundAmount(deductionCommissionAmount + deductionNet.commission);
deductionSettlementAmount = this.roundAmount(deductionSettlementAmount + deductionNet.settlement);
lines.push({
name: '商家原因售后扣款',
amount: -deductionNet.settlement
});
});
let expectedIncome = this.roundAmount(normalNet.settlement - deductionSettlementAmount);
let remark = '按后台结算口径估算,最终以平台结算账单为准';
if (order.status == 8 && hasWorkerReasonRefund) {
remark = '配送员原因全额退款,商家餐费仍按正常订单结算';
} else if (order.status == 8 && hasMerchantReasonRefund) {
remark = this.isMerchantDeliveryOrder(order) ? '商家原因全额退款,商家不结餐费并承担配送费' : '商家原因全额退款,商家不产生收入';
} else if (order.status == 8 && hasBothReasonRefund) {
remark = '商家/配送员都有原因全额退款,商家不产生收入';
}
return {
show: true,
baseAmount,
commissionRate,
normalBaseAmount,
normalCommissionAmount: normalNet.commission,
normalSettlementAmount: normalNet.settlement,
deductionBaseAmount,
deductionCommissionAmount,
deductionSettlementAmount,
expectedIncome,
lines,
remark
};
},
getSettlementAmount(item) {
if (!item) return 0;
let price = this.toAmount(item.goodsAmount) + this.toAmount(item.packageFee);
if (item.status == 8 || this.hasMerchantFullRefund(item.mallRefundRecord)) {
return 0;
}
price -= this.getMerchantGoodsRefundAmount(item.mallRefundRecord);
return Math.max(0, Number(price.toFixed(2)));
},
isRefundAgreed(item) {
return item && (item.status == 1 || item.status == 4);
},
hasMerchantFullRefund(list) {
if (!Array.isArray(list)) return false;
for (let i = 0; i < list.length; i++) {
let item = list[i];
if (this.isRefundAgreed(item) && item.refundType == 3 && (item.refundTypeStatus == 1 || item.refundTypeStatus == 3)) {
return true;
}
}
return false;
},
getMerchantGoodsRefundAmount(list) {
if (!Array.isArray(list)) return 0;
let amount = 0;
for (let i = 0; i < list.length; i++) {
let item = list[i];
if (this.isRefundAgreed(item) && item.refundType == 1) {
amount += this.getRefundGoodsAmount(item);
}
}
return Number(amount.toFixed(2));
},
getRefundGoodsAmount(item) {
if (!item || !Array.isArray(item.items) || item.items.length == 0) {
return this.toAmount(item && item.refundAmount);
}
let amount = 0;
for (let i = 0; i < item.items.length; i++) {
let goods = item.items[i];
let quantity = this.toAmount(goods.quantity);
quantity = quantity > 0 ? quantity : 1;
amount += (this.toAmount(goods.price) + this.toAmount(goods.packageFee)) * quantity;
}
return Number(amount.toFixed(2));
},
getPictureList(pictures) {
if (pictures == null || pictures === '') return [];
if (Array.isArray(pictures)) {
return pictures.filter(item => item != null && item !== '');
}
return String(pictures).split(',').map(item => item.trim()).filter(item => item !== '');
},
previewRefundImage(pictures, index) {
const urls = this.getPictureList(pictures);
if (urls.length === 0) return;
uni.previewImage({
urls,
current: urls[index]
});
},
getRefundTypeText(item) {
if (!item) return '';
if (item.refundType == 1) return '退商品';
if (item.refundType == 2) return '退配送费';
return '全额退款';
},
getRefundReasonTypeText(item) {
if (!item) return '';
if (item.refundTypeStatus == 1) return '商家原因';
if (item.refundTypeStatus == 2) return '配送员原因';
if (item.refundTypeStatus == 3) {
return item.linkId && String(item.linkId).indexOf('W') != -1 ? '配送员原因' : '商家原因';
}
return '平台退款';
},
getRefundStatusText(item) {
if (!item) return '';
if (item.status == 0) return '处理退款中';
if (item.status == 1) return '同意退款';
if (item.status == 2) return '拒绝退款';
if (item.status == 3) return '处理售后中';
if (item.status == 4) return '同意售后';
return '拒绝售后';
},
isRefundPending(item) {
return item && (item.status == 0 || item.status == 3);
},
getAutoRefundTime(value) {
if (!value) return '';
const date = new Date(value);
if (isNaN(date.getTime())) return '';
date.setHours(date.getHours() + 1);
return this.$options.filters.formatISOTime(date);
},
getHeaderTimeLabel(item) {
if (item && item.deliveryType == 1) return item.deliveryInfo && item.deliveryInfo.finishTime ? '送达时间' : '预计送达'
if (item && item.payTime) return '支付时间'
return '下单时间'
},
getHeaderTimeText(item) {
if (!item) return ''
if (item.deliveryType == 1 && item.deliveryInfo) {
return this.$options.filters.formatHourMinute(item.deliveryInfo.finishTime || item.deliveryInfo.mustFinishTime || '尽快送达')
}
return this.$options.filters.formatISOTime(item.payTime || item.createTime)
},
getWorkerName(item) {
if (!item || !item.deliveryInfo) return '未指定等待接单中'
const name = item.deliveryInfo.workerName
if (!name || name == 'null') return '未指定等待接单中'
return name
},
getDetail(){
let that = this
that.tui.request("/mall/order/detail/"+ this.shopId, "get", {}, false, false).then((res) => {
if (res.code == 200) {
that.data = res.result
//商家预计收入的计算
that.data.incomeSummary = that.buildMerchantIncomeSummary(that.data)
that.data.chouyong = that.data.incomeSummary ? that.formatMoney(that.data.incomeSummary.normalCommissionAmount) : 0
that.data.yujishouru = that.data.incomeSummary ? that.formatMoney(that.data.incomeSummary.expectedIncome) : 0
if(that.data.groupInfo != null && that.data.groupInfo != undefined && that.data.groupInfo.groupOrderIds){
that.data.groupInfo.groupIdList = that.data.groupInfo.groupOrderIds.split(',');
}
that.data.goodsNum = 0
if (!that.data.goodsList) {
that.data.goodsList = []
}
for(let m=0;m<that.data.goodsList.length;m++){
that.data.goodsNum += that.data.goodsList[m].quantity
}
that.$forceUpdate()
} else {
that.tui.toast(res.message);
return;
}
uni.hideLoading();
}).catch((res) => {});
},
goDetail(id){
this.shopId = id
this.getDetail()
this.$refs.groupPopup.close()
},
checkGroup(){
this.$refs.groupPopup.open()
},
mealServing(item){
let that = this
if (that.mealServingLoading) return
that.mealServingLoading = true
uni.showModal({
title: '提示',
content: '确定要出餐吗?',
success: function (res) {
if (res.confirm) {
let data = {}
let url = ''
if(item.deliveryType == 2){ //自取单
url = '/mall/order/complete'
}else if(item.deliveryType == 1){ //外卖单
url = '/mall/order/shopMakeTime'
}
that.tui.request(url, "post", {
orderId:item.id
}, false, true).then((res) => {
if (res.code == 200) {
uni.setStorageSync('refreshShopOrderList', true)
that.back()
} else {
that.tui.toast(res.message);
that.mealServingLoading = false
return;
}
uni.hideLoading();
}).catch((res) => {
that.mealServingLoading = false
});
} else {
that.mealServingLoading = false
}
},
fail: function () {
that.mealServingLoading = false
}
});
},
makeCall(phone){
uni.makePhoneCall({
phoneNumber: phone
});
},
callPlatformService() {
let regionId = this.getCurrentRegionId();
if (!regionId) {
this.tui.toast("请选择校区");
return;
}
let that = this;
that.tui.request("/mall/admin/seckillGroup/customerPhone/get", "GET", {
regionId: regionId
}, false, true).then((res) => {
if (res.code == 200) {
that.makeCall(res.result);
} else {
that.tui.toast(res.message || "获取客服电话失败");
}
}).catch(() => {
that.tui.toast("获取客服电话失败");
});
},
getCurrentRegionId() {
let area = uni.getStorageSync('area');
if (!area) return '';
if (typeof area === 'object') {
return area.id || '';
}
try {
return JSON.parse(area).id || '';
} catch (e) {
return '';
}
},
back() {
uni.navigateBack()
},
}
}
</script>
<style>
page {
width: 100%;
height: 100%;
font-size: 24rpx;
background: #F5F8F5;
color: #00231C;
}
.page1 {
width: 100%;
height: 100%;
font-size: 24rpx;
position: relative;
}
.title {
background-color: #fff;
background-image: url('https://jewel-shop.oss-cn-beijing.aliyuncs.com/8bc15960c2dc40268e295d6dd23aecce.png');
background-repeat: no-repeat;
width: 100%;
height: 200rpx;
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 1000;
background-size: 100% 100%;
}
.title-holder {
height: 200rpx;
}
.title-sreach {
width: 100%;
display: flex;
height: 200rpx;
position: relative;
}
.back-btn {
position: absolute;
bottom: 0;
left: 0;
}
.title-name {
padding-top: 110rpx;
font-size: 36rpx;
font-weight: 700;
flex: 1;
text-align: center;
}
.content{
margin: 0 auto;
padding-bottom: 190rpx;
}
.box1 {
width: 95%;
margin: 20rpx auto;
background: #fff;
border-radius: 20rpx;
padding: 20rpx;
}
.order-header {
display: flex;
align-items: center;
font-size: 28rpx;
font-weight: 700;
}
.order-header-info {
display: flex;
align-items: center;
flex-wrap: wrap;
flex: 1;
min-width: 0;
}
.order-number {
margin-right: 20rpx;
flex-shrink: 0;
white-space: nowrap;
}
.order-time {
display: flex;
flex-shrink: 0;
white-space: nowrap;
}
.order-time-label {
flex-shrink: 0;
margin-right: 20rpx;
}
.order-time-text {
flex-shrink: 0;
}
.order-status {
flex-shrink: 0;
margin-left: 16rpx;
color: red;
text-align: right;
white-space: nowrap;
}
.bottom{
position: fixed;
bottom: 0;
height: 170rpx;
width: 100%;
background: #fff;
padding: 0 20rpx;
}
.btn{
height: 50rpx;
width: 130rpx;
line-height: 50rpx;
background: linear-gradient(90deg, #e3ff96, #a6ffea);
text-align: center;
border-radius: 14rpx;
font-weight: 700;
float: right;
margin-left: 20rpx;
}
.delivery-card {
align-items: center;
}
.delivery-time {
display: inline-block;
margin-top: 12rpx;
padding: 6rpx 14rpx;
border-radius: 999rpx;
background: rgba(255, 107, 53, 0.1);
color: #ff6b35;
font-weight: 700;
}
.remark-box {
display: flex;
border: 1px solid rgba(255, 107, 53, 0.22);
background: linear-gradient(90deg, #fff6eb, #fffbf3);
}
.remark-label {
flex-shrink: 0;
height: 40rpx;
line-height: 40rpx;
margin-right: 14rpx;
padding: 0 12rpx;
border-radius: 10rpx;
background: #ff6b35;
color: #fff;
font-weight: 700;
}
.remark-text {
flex: 1;
color: #9a3d00;
font-size: 28rpx;
font-weight: 700;
line-height: 40rpx;
word-break: break-all;
}
.goods-spec {
margin-top: 4rpx;
color: #777;
font-size: 22rpx;
line-height: 30rpx;
}
.refund-title {
width: 100%;
height: 60rpx;
line-height: 60rpx;
font-size: 32rpx;
font-weight: 700;
display: flex;
align-items: center;
}
.refund-service-btn {
width: 136rpx;
height: 54rpx;
text-align: center;
line-height: 54rpx;
border-radius: 999rpx;
background: rgba(255, 255, 255, 0.72);
border: 1px solid rgba(0, 35, 28, 0.1);
color: #60706c;
font-size: 20rpx;
font-weight: 800;
box-shadow: 0 8rpx 18rpx rgba(0, 35, 28, 0.05);
}
.refund-card {
margin-top: 12rpx;
padding: 20rpx;
background: rgba(247, 248, 248, 0.8);
border-radius: 20rpx;
}
.refund-row {
display: flex;
height: 70rpx;
line-height: 70rpx;
}
.refund-label {
flex: 1;
color: #777;
font-weight: 700;
}
.refund-value {
color: #00231C;
font-weight: 700;
text-align: right;
}
.refund-amount {
color: red;
font-size: 30rpx;
}
.refund-goods-card {
display: flex;
padding: 18rpx;
margin: 12rpx 0;
background: #fff;
border-radius: 18rpx;
box-sizing: border-box;
}
.refund-goods-img {
width: 132rpx;
height: 132rpx;
flex-shrink: 0;
border-radius: 18rpx;
overflow: hidden;
background: #f0f5f3;
}
.refund-goods-img img {
width: 100%;
height: 100%;
border-radius: 18rpx;
}
.refund-goods-content {
flex: 1;
min-width: 0;
padding-left: 18rpx;
}
.refund-goods-name {
color: #00231C;
font-size: 28rpx;
font-weight: 700;
line-height: 38rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.refund-goods-spec {
margin-top: 8rpx;
color: #777;
font-size: 22rpx;
line-height: 32rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.refund-goods-bottom {
display: flex;
justify-content: space-between;
margin-top: 12rpx;
color: #00231C;
font-size: 24rpx;
font-weight: 700;
line-height: 34rpx;
}
.refund-info-row {
display: flex;
align-items: flex-start;
padding: 16rpx 0;
border-bottom: 1px solid #eee;
}
.refund-info-label {
width: 180rpx;
flex-shrink: 0;
color: #777;
font-weight: 700;
line-height: 38rpx;
}
.refund-info-value {
flex: 1;
min-width: 0;
color: #00231C;
font-weight: 700;
line-height: 38rpx;
text-align: right;
word-break: break-all;
}
.refund-image-list {
display: flex;
justify-content: flex-end;
flex-wrap: wrap;
gap: 12rpx;
}
.refund-image {
width: 160rpx;
height: 160rpx;
border-radius: 16rpx;
background: #f0f5f3;
}
.income-card {
border: 1rpx solid rgba(0, 35, 28, 0.08);
background: linear-gradient(180deg, #ffffff 0%, #f8fffc 100%);
}
.income-title {
display: flex;
align-items: center;
padding-bottom: 14rpx;
border-bottom: 1px solid #eef2ef;
color: #00231C;
font-size: 32rpx;
font-weight: 900;
}
.income-title text:first-child {
flex: 1;
}
.income-total {
color: red;
font-size: 34rpx;
}
.income-subtitle {
margin-top: 14rpx;
padding: 14rpx 18rpx;
border-radius: 16rpx;
background: rgba(166, 255, 234, 0.28);
color: #37645b;
font-size: 24rpx;
font-weight: 700;
line-height: 34rpx;
}
.income-row {
display: flex;
align-items: center;
min-height: 58rpx;
color: #00231C;
font-size: 27rpx;
font-weight: 800;
}
.income-row text:first-child {
flex: 1;
color: #66736f;
}
.income-formula {
margin-bottom: 8rpx;
color: #8a9692;
font-size: 23rpx;
line-height: 32rpx;
}
.income-result {
margin-top: 8rpx;
padding-top: 10rpx;
border-top: 1px dashed #dce7e2;
font-size: 30rpx;
}
.income-result text:last-child {
color: red;
font-size: 34rpx;
}
.income-negative {
color: #f04438;
}
.income-line-list {
margin-top: 14rpx;
padding: 14rpx 18rpx;
border-radius: 16rpx;
background: rgba(247, 248, 248, 0.9);
}
.income-line {
display: flex;
min-height: 42rpx;
line-height: 42rpx;
color: #66736f;
font-size: 24rpx;
font-weight: 700;
}
.income-line text:first-child {
flex: 1;
}
.auto-refund-tip {
margin: 8rpx 0 12rpx;
padding: 16rpx 18rpx;
border-radius: 16rpx;
background: rgba(255, 244, 232, 0.9);
border: 1rpx solid rgba(255, 180, 118, 0.48);
color: #b4572d;
font-size: 24rpx;
font-weight: 700;
line-height: 34rpx;
}
.group-content{
background: #fff;
width: 300px;
height: auto;
border-radius: 20rpx;
}
.weipincheng {
width: 90rpx;
height: 90rpx;
background: #a6ffea;
border-radius: 90rpx;
text-align: center;
font-size: 60rpx;
font-weight: 700;
margin-left: -6rpx;
z-index: 97;
color: #02fbdd;
border: 1px solid #a6ffea;
line-height: 80rpx;
margin: 0 auto;
}
.kaituan2{
display: flex;
width: 90%;
margin: 40rpx auto;
}
.kaituan22{
flex: 1;
}
</style>