mirror of
https://gitee.com/beijing_hongye_huicheng/lilishop-uniapp.git
synced 2026-11-13 04:18:53 +08:00
feat: 更新预约功能与礼品卡支持
- 新增礼品卡页面,支持礼品卡的选择与使用。 - 调整预约下单流程,增强预约信息展示与用户交互。 - 更新支付成功页面的导航逻辑,确保用户体验流畅。 - 优化搜索页面的历史关键词加载逻辑,提升性能。
This commit is contained in:
@@ -17,7 +17,7 @@
|
||||
</view>
|
||||
<view>
|
||||
<template v-for="(item,index) in sku.orderItems" :key="index">
|
||||
<view class="goods-item-view" v-if="item.sn == sn"
|
||||
<view class="goods-item-view" v-if="item && item.sn == sn"
|
||||
@click="gotoGoodsDetail(sku.goodsId || sku.goods_id)">
|
||||
<view class="goods-img">
|
||||
<u-image
|
||||
@@ -32,7 +32,7 @@
|
||||
<view class="goods-title">{{ getGoodsName(item) }}</view>
|
||||
<view class="goods-price">
|
||||
<text>¥{{ unitPrice(displayRefundPrice) }}</text>
|
||||
<text class="num">购买数量: {{ item.num }}</text>
|
||||
<text class="num">购买数量: {{ item.num || 0 }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -41,10 +41,10 @@
|
||||
<view class="after-num">
|
||||
<text class="after-num-label">申请数量</text>
|
||||
<u-number-box
|
||||
:value="parseInt(form.num)"
|
||||
:value="applyNum"
|
||||
disabled-input
|
||||
:min="1"
|
||||
:max="parseInt(sku.num)"
|
||||
:max="maxApplyNum"
|
||||
bg-color="#fff"
|
||||
@change="valChange"
|
||||
></u-number-box>
|
||||
@@ -164,7 +164,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, computed, getCurrentInstance, watch } from 'vue'
|
||||
import { ref, reactive, computed, getCurrentInstance } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { useStore } from '@/store'
|
||||
import { unitPrice, parseGoodsImageUrl } from '@/utils/filters.js'
|
||||
@@ -189,22 +189,6 @@ const applyInfo = ref<any>({})
|
||||
const uToast = ref<any>(null)
|
||||
const isAppointmentAfterSale = ref(false)
|
||||
|
||||
const displayRefundPrice = computed(() => {
|
||||
if (!isAppointmentAfterSale.value) return applyInfo.value?.applyRefundPrice
|
||||
return computePartialRefundPrice(applyInfo.value, form.num)
|
||||
})
|
||||
|
||||
watch(
|
||||
() => form.num,
|
||||
() => {
|
||||
if (!isAppointmentAfterSale.value) return
|
||||
applyInfo.value = {
|
||||
...applyInfo.value,
|
||||
displayRefundPrice: displayRefundPrice.value,
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const form = reactive({
|
||||
orderItemSn: '',
|
||||
skuId: '',
|
||||
@@ -222,6 +206,21 @@ const form = reactive({
|
||||
bankAccountNumber: '',
|
||||
})
|
||||
|
||||
const displayRefundPrice = computed(() => {
|
||||
if (!isAppointmentAfterSale.value) return applyInfo.value?.applyRefundPrice
|
||||
return computePartialRefundPrice(applyInfo.value, form.num)
|
||||
})
|
||||
|
||||
const maxApplyNum = computed(() => {
|
||||
const value = Number(sku.value?.num)
|
||||
return value > 0 ? value : 1
|
||||
})
|
||||
|
||||
const applyNum = computed(() => {
|
||||
const value = Number(form.num)
|
||||
return value > 0 ? value : 1
|
||||
})
|
||||
|
||||
onLoad((options) => {
|
||||
let navTitle = '申请售后'
|
||||
form.serviceType = 'RETURN_GOODS'
|
||||
@@ -239,12 +238,14 @@ onLoad((options) => {
|
||||
}
|
||||
uni.setNavigationBarTitle({ title: navTitle })
|
||||
sn.value = options?.sn || ''
|
||||
sku.value = storage.getAfterSaleData()
|
||||
const cached = storage.getAfterSaleData()
|
||||
sku.value = cached && typeof cached === 'object' ? cached : { orderItems: [] }
|
||||
if (!Array.isArray(sku.value.orderItems)) sku.value.orderItems = []
|
||||
isAppointmentAfterSale.value = isAppointmentOrder(sku.value?.orderType)
|
||||
form.orderItemSn = options?.sn || ''
|
||||
form.skuId = sku.value.skuId
|
||||
form.num = sku.value.num
|
||||
form.goodsId = sku.value.goodsId
|
||||
form.skuId = sku.value.skuId || ''
|
||||
form.num = Number(sku.value.num) > 0 ? Number(sku.value.num) : 1
|
||||
form.goodsId = sku.value.goodsId || ''
|
||||
fetchReasonActions(form.serviceType)
|
||||
init(options?.sn || '')
|
||||
})
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
</view>
|
||||
<view>
|
||||
<template v-for="(item,index) in sku.orderItems" :key="index">
|
||||
<view class="goods-item-view" v-if="item.sn == sn" @click="navigateToGoodsDetail(sku.skuId)">
|
||||
<view class="goods-item-view" v-if="item && item.sn == sn" @click="navigateToGoodsDetail(sku.skuId)">
|
||||
<view class="goods-img">
|
||||
<u-image
|
||||
border-radius="6"
|
||||
@@ -23,8 +23,8 @@
|
||||
<view class="goods-info">
|
||||
<view class="goods-title">{{ getGoodsName(item) }}</view>
|
||||
<view class="goods-price">
|
||||
<text v-if="sku.orderItems.length <= 1">¥{{ unitPrice(sku.flowPrice) }}</text>
|
||||
<text class="num">购买数量: {{ item.num }}</text>
|
||||
<text v-if="!sku.orderItems || sku.orderItems.length <= 1">¥{{ unitPrice(sku.flowPrice) }}</text>
|
||||
<text class="num">购买数量: {{ item.num || 0 }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -72,7 +72,9 @@ const applyInfo = ref<any>({})
|
||||
|
||||
onLoad((options) => {
|
||||
sn.value = options?.sn || ''
|
||||
sku.value = storage.getAfterSaleData()
|
||||
const cached = storage.getAfterSaleData()
|
||||
sku.value = cached && typeof cached === 'object' ? cached : { orderItems: [] }
|
||||
if (!Array.isArray(sku.value.orderItems)) sku.value.orderItems = []
|
||||
if (isECouponOrder(sku.value?.orderType)) {
|
||||
uni.showToast({
|
||||
title: '电子卡券订单不支持售后',
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,234 +0,0 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view class="section current">
|
||||
<view class="section-title">当前预约</view>
|
||||
<text class="current-text">{{ currentSlotText }}</text>
|
||||
</view>
|
||||
|
||||
<view class="section">
|
||||
<view class="section-title">新预约日期</view>
|
||||
<picker mode="date" :value="slotDate" :start="minDate" :end="maxDate" @change="onDateChange">
|
||||
<view class="picker-row">
|
||||
<text>{{ slotDate || '请选择日期' }}</text>
|
||||
<u-icon name="arrow-right" color="#ccc" size="16" />
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
|
||||
<view class="section">
|
||||
<view class="section-title">新预约时段</view>
|
||||
<view v-if="loadingSlots" class="tip">加载时段中...</view>
|
||||
<view v-else-if="!slots.length" class="tip">该日期暂无可预约时段</view>
|
||||
<view v-else class="slot-list">
|
||||
<view
|
||||
v-for="slot in slots"
|
||||
:key="slot.id"
|
||||
class="slot-item"
|
||||
:class="{ active: selectedSlot && selectedSlot.id === slot.id }"
|
||||
@click="selectSlot(slot)"
|
||||
>
|
||||
{{ slot.slotStartTime }}-{{ slot.slotEndTime }}
|
||||
<text v-if="slot.showRemainingQty && slot.availableQty != null" class="slot-qty">
|
||||
余{{ slot.availableQty }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="section">
|
||||
<view class="section-title">改期说明(选填)</view>
|
||||
<u-input v-model="remark" type="textarea" placeholder="如有需要请填写改期原因" border="surround" height="100" />
|
||||
</view>
|
||||
|
||||
<view class="footer">
|
||||
<u-button type="primary" shape="circle" :loading="submitting" @click="submit">提交改期</u-button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, watch, onMounted } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { listSlots, getAppointmentOrderDetail, requestReschedule, getGoodsExt } from '@/api/appointment.js'
|
||||
import { buildBookableDates, formatDate } from '@/utils/appointmentGoods.js'
|
||||
|
||||
const orderSn = ref('')
|
||||
const skuId = ref('')
|
||||
const goodsId = ref('')
|
||||
const quantity = ref(1)
|
||||
const currentDetail = ref<any>({})
|
||||
const goodsExt = ref<any>(null)
|
||||
const slotDate = ref('')
|
||||
const slots = ref<any[]>([])
|
||||
const selectedSlot = ref<any>(null)
|
||||
const remark = ref('')
|
||||
const loadingSlots = ref(false)
|
||||
const submitting = ref(false)
|
||||
const bookableDates = ref<string[]>([])
|
||||
|
||||
const minDate = computed(() => bookableDates.value[0] || formatDate(new Date()))
|
||||
const maxDate = computed(() => {
|
||||
const list = bookableDates.value
|
||||
return list.length ? list[list.length - 1] : minDate.value
|
||||
})
|
||||
const currentSlotText = computed(() => {
|
||||
const d = currentDetail.value
|
||||
if (!d?.slotDate) return '加载中...'
|
||||
return `${d.slotDate} ${d.slotStartTime || ''}-${d.slotEndTime || ''}`
|
||||
})
|
||||
|
||||
onLoad((options) => {
|
||||
orderSn.value = options?.orderSn || ''
|
||||
})
|
||||
|
||||
onMounted(async () => {
|
||||
if (!orderSn.value) return
|
||||
try {
|
||||
const res = await getAppointmentOrderDetail(orderSn.value)
|
||||
currentDetail.value = res.data?.result || {}
|
||||
skuId.value = currentDetail.value.skuId || ''
|
||||
goodsId.value = currentDetail.value.goodsId || ''
|
||||
quantity.value = currentDetail.value.quantity || 1
|
||||
if (goodsId.value) {
|
||||
const extRes = await getGoodsExt(goodsId.value)
|
||||
goodsExt.value = extRes.data?.result || null
|
||||
bookableDates.value = buildBookableDates(goodsExt.value)
|
||||
} else {
|
||||
bookableDates.value = buildBookableDates(null)
|
||||
}
|
||||
slotDate.value = bookableDates.value[0] || formatDate(new Date())
|
||||
await loadSlots()
|
||||
} catch {
|
||||
uni.showToast({ title: '加载预约信息失败', icon: 'none' })
|
||||
}
|
||||
})
|
||||
|
||||
watch(slotDate, () => {
|
||||
selectedSlot.value = null
|
||||
loadSlots()
|
||||
})
|
||||
|
||||
async function loadSlots() {
|
||||
if (!skuId.value || !slotDate.value) return
|
||||
loadingSlots.value = true
|
||||
try {
|
||||
const res = await listSlots(skuId.value, slotDate.value)
|
||||
slots.value = res.data?.result || []
|
||||
} catch {
|
||||
slots.value = []
|
||||
} finally {
|
||||
loadingSlots.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function onDateChange(e: any) {
|
||||
slotDate.value = e.detail?.value || ''
|
||||
}
|
||||
|
||||
function selectSlot(slot: any) {
|
||||
const need = quantity.value || 1
|
||||
if (slot?.availableQty != null && slot.availableQty < need) {
|
||||
uni.showToast({ title: '该时段可约数量不足', icon: 'none' })
|
||||
return
|
||||
}
|
||||
selectedSlot.value = slot
|
||||
}
|
||||
|
||||
async function submit() {
|
||||
if (!selectedSlot.value) {
|
||||
uni.showToast({ title: '请选择新时段', icon: 'none' })
|
||||
return
|
||||
}
|
||||
submitting.value = true
|
||||
try {
|
||||
const slot = selectedSlot.value
|
||||
const res = await requestReschedule(orderSn.value, {
|
||||
slotStockId: slot.id,
|
||||
slotDate: slotDate.value,
|
||||
slotStartTime: slot.slotStartTime,
|
||||
slotEndTime: slot.slotEndTime,
|
||||
remark: remark.value.trim(),
|
||||
})
|
||||
const action = res.data?.result?.action
|
||||
uni.showToast({
|
||||
title: action === 'APPLY' ? '改期申请已提交,等待审核' : '改期成功',
|
||||
icon: 'none',
|
||||
})
|
||||
setTimeout(() => {
|
||||
uni.navigateBack()
|
||||
}, 1200)
|
||||
} catch (e: any) {
|
||||
uni.showToast({
|
||||
title: e?.data?.message || e?.message || '改期失败',
|
||||
icon: 'none',
|
||||
})
|
||||
} finally {
|
||||
submitting.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.page {
|
||||
min-height: 100vh;
|
||||
background: #f5f5f5;
|
||||
padding: 24rpx 24rpx 160rpx;
|
||||
}
|
||||
.section {
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 24rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
.section-title {
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
.current-text {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
}
|
||||
.picker-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
}
|
||||
.tip {
|
||||
color: #999;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
.slot-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 16rpx;
|
||||
}
|
||||
.slot-item {
|
||||
padding: 16rpx 28rpx;
|
||||
background: #f2f2f2;
|
||||
border-radius: 30rpx;
|
||||
font-size: 24rpx;
|
||||
color: #333;
|
||||
border: 2rpx solid transparent;
|
||||
}
|
||||
.slot-item.active {
|
||||
background: #fff5f5;
|
||||
border-color: #f2270c;
|
||||
color: #f2270c;
|
||||
}
|
||||
.slot-qty {
|
||||
margin-left: 8rpx;
|
||||
color: #999;
|
||||
}
|
||||
.footer {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
padding: 20rpx 32rpx calc(20rpx + env(safe-area-inset-bottom));
|
||||
background: #fff;
|
||||
box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
</style>
|
||||
44
pages/order/components/verificationCodes.vue
Normal file
44
pages/order/components/verificationCodes.vue
Normal file
@@ -0,0 +1,44 @@
|
||||
<template>
|
||||
<view v-if="items.length" class="verify-codes">
|
||||
<view v-for="(item, index) in items" :key="item.key" class="verify-code">
|
||||
<text class="verify-code__label">{{ index === 0 ? '核销码' : '' }}</text>
|
||||
<text class="verify-code__text" :class="{ 'is-struck': item.struck }">{{ item.code }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
defineProps({
|
||||
items: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.verify-code {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 26rpx;
|
||||
margin-bottom: 12rpx;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.verify-code__label {
|
||||
color: #999;
|
||||
width: 140rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.verify-code__text {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
font-weight: bold;
|
||||
letter-spacing: 2rpx;
|
||||
color: #333;
|
||||
}
|
||||
.verify-code__text.is-struck {
|
||||
color: #999;
|
||||
font-weight: normal;
|
||||
text-decoration: line-through;
|
||||
}
|
||||
</style>
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="wrapper">
|
||||
<div class="wrapper" :style="themeStyle">
|
||||
<!-- 选择地址 -->
|
||||
<div
|
||||
class="address-box"
|
||||
@@ -68,9 +68,24 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<view class="address-box appointment-summary" v-if="isAppointmentCheckout && appointmentCheckoutSummary">
|
||||
<view class="appointment-summary__title">预约信息</view>
|
||||
<view class="appointment-summary__text">{{ appointmentCheckoutSummary }}</view>
|
||||
<view class="appointment-card" v-if="isAppointmentCheckout && appointmentCheckoutView">
|
||||
<view class="appointment-card__title">预约信息</view>
|
||||
<view class="appointment-hero">
|
||||
<view class="appointment-hero__time">{{ appointmentCheckoutView.time }}</view>
|
||||
<view class="appointment-hero__meta">
|
||||
<text>{{ appointmentCheckoutView.dateText }} {{ appointmentCheckoutView.week }}</text>
|
||||
<text v-if="appointmentCheckoutView.mode" class="appointment-tag">{{ appointmentCheckoutView.mode }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="appointment-form" v-if="appointmentCheckoutView.formRows.length">
|
||||
<template v-for="(row, index) in appointmentCheckoutView.formRows" :key="index">
|
||||
<view v-if="row.type === 'group'" class="appointment-group">{{ row.label }}</view>
|
||||
<view v-else class="appointment-row">
|
||||
<text class="appointment-row__label">{{ row.label }}</text>
|
||||
<text class="appointment-row__value">{{ row.value }}</text>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 开团信息 -->
|
||||
@@ -341,54 +356,24 @@
|
||||
</u-col>
|
||||
</u-row>
|
||||
</div>
|
||||
<div class="gift-card-module">
|
||||
<u-row>
|
||||
<u-col :span="6">
|
||||
<view class="gift-card-title-row">
|
||||
<text>使用礼品卡</text>
|
||||
<text class="gift-card-help" @click.stop="showGiftCardNotice">使用说明</text>
|
||||
</view>
|
||||
</u-col>
|
||||
<u-col :span="6" class="tr tipsColor" textAlign="right">
|
||||
<span v-if="giftCardDeductAmount > 0" class="main-color"
|
||||
>已抵扣 -¥{{ unitPrice(giftCardDeductAmount) }}</span
|
||||
>
|
||||
<span v-else>{{ giftCardList.length }} 张可用</span>
|
||||
</u-col>
|
||||
</u-row>
|
||||
<view v-if="!giftCardList.length" class="gift-card-empty">暂无可用礼品卡</view>
|
||||
<view v-else class="gift-card-list">
|
||||
<view
|
||||
class="gift-card-item"
|
||||
:class="{ 'gift-card-item--selected': isGiftCardSelected(item) }"
|
||||
v-for="item in giftCardList"
|
||||
:key="item.id"
|
||||
@click="toggleGiftCard(item)"
|
||||
>
|
||||
<view class="gift-card-item__header">
|
||||
<view class="gift-card-item__pattern" />
|
||||
<view class="gift-card-item__inner">
|
||||
<view>
|
||||
<view class="gift-card-item__name">{{ item.giftCardName || '礼品卡' }}</view>
|
||||
<view class="gift-card-item__face">面值{{ item.faceText }}元</view>
|
||||
</view>
|
||||
<view class="gift-card-item__right">
|
||||
<view class="gift-card-item__type">现金卡</view>
|
||||
<view class="gift-card-item__expire">{{ item.expireText }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="gift-card-item__body">
|
||||
<view class="gift-card-item__balance">
|
||||
<text class="gift-card-item__amt">¥{{ unitPrice(item.balance) }}</text>
|
||||
<text>余额</text>
|
||||
</view>
|
||||
<view class="gift-card-item__no">{{ item.cardNo }}</view>
|
||||
</view>
|
||||
<view v-if="isGiftCardSelected(item)" class="gift-card-item__check">已选</view>
|
||||
<u-row>
|
||||
<u-col :span="8" @click="openGiftCards()">使用礼品卡</u-col>
|
||||
<u-col
|
||||
:span="4"
|
||||
textAlign="right"
|
||||
class="coupon-col"
|
||||
@click="openGiftCards()"
|
||||
>
|
||||
<view class="coupon-col__content" v-if="giftCardDeductAmount > 0">
|
||||
<text class="main-color">-¥{{ unitPrice(giftCardDeductAmount) }}</text>
|
||||
<u-icon name="arrow-right" size="14" color="#909399"></u-icon>
|
||||
</view>
|
||||
</view>
|
||||
</div>
|
||||
<view class="coupon-col__content" v-else>
|
||||
<text>{{ giftCardList.length }} 张可用</text>
|
||||
<u-icon name="arrow-right" size="14" color="#909399"></u-icon>
|
||||
</view>
|
||||
</u-col>
|
||||
</u-row>
|
||||
</div>
|
||||
|
||||
<!-- 配送地区没有提示 -->
|
||||
@@ -441,11 +426,11 @@
|
||||
import { ref, computed, watch, getCurrentInstance } from 'vue'
|
||||
import { onLoad, onShow, onBackPress } from '@dcloudio/uni-app'
|
||||
import { useStore } from '@/store'
|
||||
import { getThemeStyle } from '@/utils/theme'
|
||||
import * as API_Address from '@/api/address'
|
||||
import * as API_Order from '@/api/order'
|
||||
import * as API_Trade from '@/api/trade'
|
||||
import configs from '@/config/config'
|
||||
import LiLiWXPay from '@/js_sdk/lili-pay/wx-pay.js'
|
||||
import invoices from '@/pages/order/invoice/setInvoice'
|
||||
import {
|
||||
unitPrice,
|
||||
@@ -456,9 +441,9 @@ import {
|
||||
import { hasECouponInCheckout, hasAppointmentInCheckout } from '@/utils/goodsType.js'
|
||||
import { SERVICE_MODE_LABEL, formatDate } from '@/utils/appointmentGoods.js'
|
||||
import { bindCheckout } from '@/api/appointment.js'
|
||||
import { decorateGiftCard, GIFT_CARD_PAY_NOTICE } from '@/utils/giftCard.js'
|
||||
|
||||
const store = useStore()
|
||||
const themeStyle = computed(() => getThemeStyle(store.state.theme))
|
||||
const { proxy } = getCurrentInstance()!
|
||||
const lightColor = computed(() => store.getters.lightColor)
|
||||
const mainColor = computed(() => store.getters.mainColor)
|
||||
@@ -509,25 +494,66 @@ const hidePhysicalCheckout = computed(
|
||||
)
|
||||
const appointmentCheckoutContext = ref<any>(null)
|
||||
|
||||
const appointmentCheckoutSummary = computed(() => {
|
||||
const APPOINTMENT_WEEK_LABELS = ['周日', '周一', '周二', '周三', '周四', '周五', '周六']
|
||||
|
||||
function presentAppointmentFormRows(rows: any[]) {
|
||||
const result: any[] = []
|
||||
let lastGroup = ''
|
||||
rows.forEach((row) => {
|
||||
if (row?.type === 'group') {
|
||||
result.push(row)
|
||||
lastGroup = row.label || ''
|
||||
return
|
||||
}
|
||||
const matched = String(row?.label || '').match(/^(.*?)(?:\s*[((](\d+)[))])$/)
|
||||
if (!matched) {
|
||||
result.push(row)
|
||||
return
|
||||
}
|
||||
const group = `第${matched[2]}位`
|
||||
if (group !== lastGroup) {
|
||||
result.push({ type: 'group', label: group })
|
||||
lastGroup = group
|
||||
}
|
||||
result.push({ label: matched[1], value: row.value })
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
||||
const appointmentCheckoutView = computed(() => {
|
||||
const ctx =
|
||||
appointmentCheckoutContext.value ||
|
||||
orderMessage.value?.appointmentCheckout ||
|
||||
orderMessage.value?.appointmentContext
|
||||
if (!ctx) return ''
|
||||
if (!ctx) return null
|
||||
const date = formatDate(ctx.slotDate)
|
||||
let dateText = ''
|
||||
let week = ''
|
||||
if (date) {
|
||||
const [year, month, day] = date.split('-').map(Number)
|
||||
const current = new Date(year, month - 1, day)
|
||||
dateText = `${month}月${day}日`
|
||||
week = APPOINTMENT_WEEK_LABELS[current.getDay()] || ''
|
||||
}
|
||||
const time =
|
||||
ctx.slotStartTime && ctx.slotEndTime ? `${ctx.slotStartTime} - ${ctx.slotEndTime}` : dateText
|
||||
const mode = SERVICE_MODE_LABEL[ctx.serviceMode] || ctx.serviceMode || ''
|
||||
const slot = ctx.slotStartTime && ctx.slotEndTime ? `${ctx.slotStartTime}-${ctx.slotEndTime}` : ''
|
||||
const contact = ctx.contactName ? `${ctx.contactName} ${ctx.contactPhone || ''}` : ''
|
||||
return [date, slot, mode, contact].filter(Boolean).join(' · ')
|
||||
const formRows = []
|
||||
if (ctx.serviceAddressSnapshot) {
|
||||
formRows.push({ label: '服务地址', value: ctx.serviceAddressSnapshot })
|
||||
}
|
||||
const savedRows = Array.isArray(ctx.formRows) ? ctx.formRows : []
|
||||
if (savedRows.length) {
|
||||
formRows.push(...presentAppointmentFormRows(savedRows))
|
||||
} else {
|
||||
if (ctx.contactName) formRows.push({ label: '联系人', value: ctx.contactName })
|
||||
if (ctx.contactPhone) formRows.push({ label: '联系方式', value: ctx.contactPhone })
|
||||
}
|
||||
if (!time && !formRows.length) return null
|
||||
return { dateText, week, time, mode, formRows }
|
||||
})
|
||||
|
||||
const selectedGiftCardIds = computed(() => orderMessage.value?.selectedGiftCardIds || [])
|
||||
const giftCardList = computed(() =>
|
||||
(orderMessage.value?.canUseGiftCards || []).map((item: any) =>
|
||||
decorateGiftCard(item, selectedGiftCardIds.value)
|
||||
)
|
||||
)
|
||||
const giftCardList = computed(() => orderMessage.value?.canUseGiftCards || [])
|
||||
const giftCardDeductAmount = computed(() => {
|
||||
const dto = orderMessage.value?.priceDetailDTO
|
||||
if (!dto) return 0
|
||||
@@ -652,36 +678,10 @@ function invoice() {
|
||||
invoiceFlag.value = true
|
||||
}
|
||||
|
||||
function showGiftCardNotice() {
|
||||
uni.showModal({
|
||||
title: '礼品卡使用说明',
|
||||
content: GIFT_CARD_PAY_NOTICE,
|
||||
showCancel: false,
|
||||
confirmText: '我知道了',
|
||||
})
|
||||
}
|
||||
|
||||
function isGiftCardSelected(item: any) {
|
||||
if (!item?.id) return false
|
||||
return (selectedGiftCardIds.value || []).map(String).includes(String(item.id))
|
||||
}
|
||||
|
||||
function toggleGiftCard(item: any) {
|
||||
if (!item?.id) return
|
||||
API_Trade.selectGiftCard({
|
||||
way: routerVal.value.way,
|
||||
credentialId: String(item.id),
|
||||
used: !isGiftCardSelected(item),
|
||||
}).then((res) => {
|
||||
if (res.data.success) {
|
||||
getOrderList()
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: res.data.message || '礼品卡选择失败',
|
||||
icon: 'none',
|
||||
})
|
||||
}
|
||||
})
|
||||
function openGiftCards() {
|
||||
;(store.state as any).canUseGiftCards = giftCardList.value
|
||||
;(store.state as any).selectedGiftCardIds = orderMessage.value?.selectedGiftCardIds || []
|
||||
navigateTo(`/pages/cart/gift-card/index?way=${routerVal.value.way}`)
|
||||
}
|
||||
|
||||
function GET_Discount() {
|
||||
@@ -787,15 +787,9 @@ function createTradeFun() {
|
||||
url: '/pages/order/myOrder?status=0',
|
||||
})
|
||||
} else {
|
||||
// #ifdef MP-WEIXIN
|
||||
pay(res.data.result.sn)
|
||||
// #endif
|
||||
|
||||
// #ifndef MP-WEIXIN
|
||||
navigateTo(
|
||||
`/pages/cart/payment/payOrder?trade_sn=${res.data.result.sn}`
|
||||
)
|
||||
// #endif
|
||||
}
|
||||
} else {
|
||||
uni.showToast({
|
||||
@@ -832,13 +826,6 @@ function createTradeFun() {
|
||||
}, 3000)
|
||||
}
|
||||
|
||||
async function pay(sn: string) {
|
||||
new LiLiWXPay({
|
||||
sn,
|
||||
price: orderMessage.value.priceDetailDTO.billPrice,
|
||||
}).pay()
|
||||
}
|
||||
|
||||
function getUserAddress() {
|
||||
API_Address.getAddressDefault().then((res) => {
|
||||
if (res.data.result) {
|
||||
@@ -942,6 +929,8 @@ function getOrderList() {
|
||||
orderMessage.value = res.data.result
|
||||
;(store.state as any).canUseCoupons = res.data.result.canUseCoupons
|
||||
;(store.state as any).cantUseCoupons = res.data.result.cantUseCoupons
|
||||
;(store.state as any).canUseGiftCards = res.data.result.canUseGiftCards || []
|
||||
;(store.state as any).selectedGiftCardIds = res.data.result.selectedGiftCardIds || []
|
||||
|
||||
// E_COUPON / 预约商品免地址,不自动回填 memberAddress
|
||||
if (!hasECouponInCheckout(res.data.result) && !hasAppointmentInCheckout(res.data.result)) {
|
||||
@@ -976,20 +965,87 @@ page {
|
||||
}
|
||||
</style>
|
||||
<style scoped lang="scss">
|
||||
.appointment-summary {
|
||||
padding: 24rpx 32rpx;
|
||||
background: #fff;
|
||||
.appointment-card {
|
||||
margin-bottom: 20rpx;
|
||||
padding: 28rpx 32rpx 12rpx;
|
||||
background: #fff;
|
||||
border-radius: 40rpx;
|
||||
}
|
||||
.appointment-summary__title {
|
||||
font-size: 28rpx;
|
||||
.appointment-card__title {
|
||||
font-size: 26rpx;
|
||||
color: #999;
|
||||
line-height: 1.4;
|
||||
}
|
||||
.appointment-hero {
|
||||
margin-top: 12rpx;
|
||||
}
|
||||
.appointment-hero__time {
|
||||
font-size: 44rpx;
|
||||
font-weight: 600;
|
||||
margin-bottom: 12rpx;
|
||||
color: #222;
|
||||
line-height: 1.2;
|
||||
letter-spacing: 1rpx;
|
||||
}
|
||||
.appointment-summary__text {
|
||||
font-size: 24rpx;
|
||||
.appointment-hero__meta {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 12rpx;
|
||||
margin-top: 14rpx;
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
line-height: 1.4;
|
||||
}
|
||||
.appointment-tag {
|
||||
padding: 2rpx 14rpx;
|
||||
border-radius: 8rpx;
|
||||
background: var(--theme-primary-10, rgba(255, 60, 42, 0.1));
|
||||
color: var(--theme-primary, #ff3c2a);
|
||||
font-size: 22rpx;
|
||||
line-height: 1.6;
|
||||
}
|
||||
.appointment-form {
|
||||
margin-top: 20rpx;
|
||||
border-top: 1rpx solid #f2f2f2;
|
||||
}
|
||||
.appointment-group {
|
||||
padding-top: 20rpx;
|
||||
font-size: 24rpx;
|
||||
color: var(--theme-primary, #ff3c2a);
|
||||
line-height: 1.4;
|
||||
}
|
||||
.appointment-row + .appointment-group {
|
||||
margin-top: 8rpx;
|
||||
border-top: 1rpx solid #f5f5f5;
|
||||
}
|
||||
.appointment-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 24rpx;
|
||||
padding: 22rpx 0;
|
||||
}
|
||||
.appointment-row + .appointment-row {
|
||||
border-top: 1rpx solid #f5f5f5;
|
||||
}
|
||||
.appointment-group + .appointment-row {
|
||||
padding-top: 12rpx;
|
||||
}
|
||||
.appointment-row__label {
|
||||
flex: none;
|
||||
font-size: 26rpx;
|
||||
color: #999;
|
||||
line-height: 1.5;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.appointment-row__value {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
text-align: right;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
line-height: 1.5;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.flex-8 {
|
||||
@@ -1159,6 +1215,7 @@ page {
|
||||
|
||||
.box6 {
|
||||
position: fixed;
|
||||
z-index: 20;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
@@ -1170,6 +1227,7 @@ page {
|
||||
color: #333;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
box-shadow: 0 -4rpx 16rpx rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.tabbar-right {
|
||||
@@ -1260,7 +1318,8 @@ page {
|
||||
.wrapper {
|
||||
height: auto;
|
||||
background: #f7f7f7;
|
||||
padding-bottom: 200rpx;
|
||||
padding-bottom: calc(240rpx + constant(safe-area-inset-bottom));
|
||||
padding-bottom: calc(240rpx + env(safe-area-inset-bottom));
|
||||
overflow: auto !important;
|
||||
}
|
||||
|
||||
@@ -1348,129 +1407,4 @@ page {
|
||||
margin: 20rpx 0;
|
||||
}
|
||||
|
||||
.gift-card-module {
|
||||
margin-top: 8rpx;
|
||||
}
|
||||
|
||||
.gift-card-title-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12rpx;
|
||||
}
|
||||
|
||||
.gift-card-help {
|
||||
font-size: 22rpx;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.gift-card-empty {
|
||||
margin-top: 16rpx;
|
||||
padding: 24rpx;
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
text-align: center;
|
||||
background: #fafafa;
|
||||
border-radius: 12rpx;
|
||||
}
|
||||
|
||||
.gift-card-list {
|
||||
margin-top: 16rpx;
|
||||
}
|
||||
|
||||
.gift-card-item {
|
||||
position: relative;
|
||||
border-radius: 16rpx;
|
||||
overflow: hidden;
|
||||
margin-bottom: 16rpx;
|
||||
border: 2rpx solid transparent;
|
||||
background: #fff;
|
||||
|
||||
&--selected {
|
||||
border-color: $main-color;
|
||||
}
|
||||
}
|
||||
|
||||
.gift-card-item__header {
|
||||
position: relative;
|
||||
background: linear-gradient(125deg, #ff9a4a 0%, #ff7729 42%, #ff8f3d 100%);
|
||||
}
|
||||
|
||||
.gift-card-item__pattern {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
opacity: 0.22;
|
||||
pointer-events: none;
|
||||
background-image: repeating-linear-gradient(
|
||||
-36deg,
|
||||
transparent,
|
||||
transparent 10rpx,
|
||||
rgba(255, 255, 255, 0.45) 10rpx,
|
||||
rgba(255, 255, 255, 0.45) 12rpx
|
||||
);
|
||||
}
|
||||
|
||||
.gift-card-item__inner {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 20rpx 24rpx 16rpx;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.gift-card-item__name {
|
||||
font-size: 28rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.gift-card-item__face,
|
||||
.gift-card-item__expire {
|
||||
margin-top: 8rpx;
|
||||
font-size: 22rpx;
|
||||
opacity: 0.92;
|
||||
}
|
||||
|
||||
.gift-card-item__right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.gift-card-item__type {
|
||||
font-size: 28rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.gift-card-item__body {
|
||||
padding: 16rpx 24rpx 20rpx;
|
||||
}
|
||||
|
||||
.gift-card-item__balance {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 8rpx;
|
||||
font-size: 22rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.gift-card-item__amt {
|
||||
font-size: 32rpx;
|
||||
font-weight: 700;
|
||||
color: #ff6b22;
|
||||
}
|
||||
|
||||
.gift-card-item__no {
|
||||
margin-top: 8rpx;
|
||||
font-size: 22rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.gift-card-item__check {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
padding: 4rpx 14rpx;
|
||||
font-size: 20rpx;
|
||||
color: #fff;
|
||||
background: $main-color;
|
||||
border-top-left-radius: 12rpx;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,17 +1,48 @@
|
||||
<template>
|
||||
<view class="content">
|
||||
<view class="navbar">
|
||||
<view v-for="(item, index) in navList" :key="index" class="nav-item"
|
||||
:class="{ current: tabCurrentIndex === index }" @click="tabClick(index)">{{ item.text }}</view>
|
||||
</view>
|
||||
<scroll-view class="navbar" scroll-x :show-scrollbar="false">
|
||||
<view class="navbar-inner">
|
||||
<view v-for="(item, index) in navList" :key="index" class="nav-item"
|
||||
:class="{ current: tabCurrentIndex === index }" @click="tabClick(index)">{{ item.text }}</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<swiper :current="tabCurrentIndex" class="swiper-box" duration="300" @change="changeTab">
|
||||
<swiper-item class="tab-content" v-for="(tabItem, tabIndex) in navList" :key="tabIndex">
|
||||
<scroll-view class="list-scroll-content" scroll-y @scrolltolower="loadData(tabIndex)">
|
||||
<!-- 空白页 -->
|
||||
<u-empty text="暂无订单" mode="list"
|
||||
<u-empty :text="tabItem.kind === 'afterSale' ? '暂无售后记录' : '暂无订单'" mode="list"
|
||||
v-if="tabItem.loaded === true && tabItem.orderList.length === 0"></u-empty>
|
||||
<!-- 订单列表 -->
|
||||
<view class="seller-view" :key="orderIndex" v-for="(order, orderIndex) in tabItem.orderList">
|
||||
<template v-if="order.isAfterSale">
|
||||
<view class="seller-info u-flex u-row-between">
|
||||
<view class="seller-name wes">
|
||||
<view class="name">{{ order.storeName }}</view>
|
||||
</view>
|
||||
<view class="order-sn">{{ orderCardStatus(order) }}</view>
|
||||
</view>
|
||||
<view class="after-sale-sn">售后单号:{{ order.serviceSn }}</view>
|
||||
<view class="goods-item-view" @click="openOrder(order)">
|
||||
<view class="goods-img">
|
||||
<u-image border-radius="6" width="131rpx" height="131rpx" mode="aspectFill"
|
||||
:src="getOrderItemImage(order.orderItems[0], order, 0)"></u-image>
|
||||
</view>
|
||||
<view class="goods-info">
|
||||
<view class="goods-title u-line-2">{{ order.groupName }}</view>
|
||||
<view class="goods-price">申请退款 ¥{{ unitPrice(order.applyRefundPrice) }}</view>
|
||||
</view>
|
||||
<view class="goods-num">
|
||||
<view>x{{ order.groupNum }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="btn-view u-flex u-row-between">
|
||||
<view class="description">{{ afterSaleTypeText(order.serviceType) }}</view>
|
||||
<view class="goods-btn flex flex-a-c">
|
||||
<view class="pay-btn" @click="openOrder(order)">售后详情</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<!-- 店铺名称 -->
|
||||
<view class="seller-info u-flex u-row-between">
|
||||
<view class="seller-name wes" @click="navigateToStore(order)">
|
||||
@@ -26,12 +57,11 @@
|
||||
</view>
|
||||
|
||||
</view>
|
||||
<view class="order-sn">{{orderStatusList(order.orderStatus)
|
||||
}}</view>
|
||||
<view class="order-sn">{{ orderCardStatus(order) }}</view>
|
||||
</view>
|
||||
<view>
|
||||
<view>
|
||||
<view class="goods-item-view" @click="navigateToOrderDetail(order.sn)">
|
||||
<view class="goods-item-view" @click="openOrder(order)">
|
||||
<view class="goods-img" v-for="(goods, goodsIndex) in order.orderItems"
|
||||
:key="goodsIndex">
|
||||
<u-image border-radius="6" width="131rpx" height="131rpx" mode="aspectFill"
|
||||
@@ -70,16 +100,12 @@
|
||||
v-if="order.allowOperationVO.rog && !isECouponOrder(order.orderType)" @click="onRog(order.sn)">
|
||||
确认收货
|
||||
</view>
|
||||
<view ripple shape="circle" class="cancel-btn" size="mini"
|
||||
v-if="showOrderAfterSale(order)"
|
||||
@click="applyService(order)">
|
||||
退款/售后
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
<uni-load-more :status="tabItem.loadStatus"></uni-load-more>
|
||||
<uni-load-more v-if="tabItem.orderList.length > 0" :status="tabItem.loadStatus"></uni-load-more>
|
||||
</scroll-view>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
@@ -114,7 +140,7 @@ import { onLoad, onShow, onPullDownRefresh, onBackPress } from '@dcloudio/uni-ap
|
||||
import { useStore } from '@/store'
|
||||
import uniLoadMore from '@/components/uni-load-more/uni-load-more.vue'
|
||||
import { getOrderList, cancelOrder, confirmReceipt } from '@/api/order.js'
|
||||
import { getClearReason } from '@/api/after-sale.js'
|
||||
import { getClearReason, getAfterSaleList } from '@/api/after-sale.js'
|
||||
import LiLiWXPay from '@/js_sdk/lili-pay/wx-pay.js'
|
||||
import {
|
||||
unitPrice,
|
||||
@@ -124,7 +150,7 @@ import {
|
||||
} from '@/utils/filters.js'
|
||||
// E_COUPON 订单不展示确认收货、退款/售后(FR-B-04)
|
||||
import { isECouponOrder, isAppointmentOrder } from '@/utils/goodsType.js'
|
||||
import { getAppointmentAllowOperation } from '@/utils/appointmentGoods.js'
|
||||
import { appointmentOrderStatusText, getAppointmentAllowOperation } from '@/utils/appointmentGoods.js'
|
||||
|
||||
const store = useStore()
|
||||
const { proxy } = getCurrentInstance()!
|
||||
@@ -134,6 +160,9 @@ const mainColor = computed(() => store.getters.mainColor)
|
||||
interface NavTabItem {
|
||||
state: number
|
||||
text: string
|
||||
tag: string
|
||||
commentStatus?: string
|
||||
kind?: 'order' | 'afterSale'
|
||||
loadStatus: string
|
||||
orderList: any[]
|
||||
pageNumber: number
|
||||
@@ -142,30 +171,27 @@ interface NavTabItem {
|
||||
|
||||
const tabCurrentIndex = ref(0)
|
||||
const navList = reactive<NavTabItem[]>([
|
||||
{ state: 0, text: '全部', loadStatus: 'more', orderList: [], pageNumber: 1 },
|
||||
{ state: 1, text: '待付款', loadStatus: 'more', orderList: [], pageNumber: 1 },
|
||||
{ state: 2, text: '待发货', loadStatus: 'more', orderList: [], pageNumber: 1 },
|
||||
{ state: 3, text: '待收货', loadStatus: 'more', orderList: [], pageNumber: 1 },
|
||||
{ state: 4, text: '已完成', loadStatus: 'more', orderList: [], pageNumber: 1 },
|
||||
{ state: 5, text: '已取消', loadStatus: 'more', orderList: [], pageNumber: 1 },
|
||||
{ state: 0, text: '全部', tag: 'ALL', loadStatus: 'more', orderList: [], pageNumber: 1 },
|
||||
{ state: 1, text: '待支付', tag: 'WAIT_PAY', loadStatus: 'more', orderList: [], pageNumber: 1 },
|
||||
{ state: 2, text: '待发货', tag: 'WAIT_SHIP', loadStatus: 'more', orderList: [], pageNumber: 1 },
|
||||
{ state: 3, text: '待收货/使用', tag: 'WAIT_USE', loadStatus: 'more', orderList: [], pageNumber: 1 },
|
||||
{ state: 4, text: '评价', tag: 'ALL', commentStatus: 'UNFINISHED', loadStatus: 'more', orderList: [], pageNumber: 1 },
|
||||
{ state: 5, text: '售后', tag: 'ALL', kind: 'afterSale', loadStatus: 'more', orderList: [], pageNumber: 1 },
|
||||
])
|
||||
|
||||
const status = ref<number>(0)
|
||||
const params = reactive({
|
||||
pageNumber: 1,
|
||||
pageSize: 10,
|
||||
tag: 'ALL',
|
||||
})
|
||||
|
||||
const orderStatus = [
|
||||
{ orderStatus: 'ALL' },
|
||||
{ orderStatus: 'WAIT_PAY' },
|
||||
{ orderStatus: 'WAIT_SHIP' },
|
||||
{ orderStatus: 'WAIT_ROG' },
|
||||
{ orderStatus: 'COMPLETE' },
|
||||
{ orderStatus: 'CANCELLED' },
|
||||
{ orderStatus: 'STAY_PICKED_UP' },
|
||||
]
|
||||
const afterSaleStatusText: Record<string, string> = {
|
||||
APPLY: '申请中',
|
||||
PASS: '已通过',
|
||||
REFUSE: '已拒绝',
|
||||
BUYER_RETURN: '待卖家收货',
|
||||
SELLER_CONFIRM: '卖家确认收货',
|
||||
SELLER_TERMINATION: '卖家终止售后',
|
||||
BUYER_CANCEL: '买家取消售后',
|
||||
WAIT_REFUND: '等待平台退款',
|
||||
COMPLETE: '完成',
|
||||
}
|
||||
|
||||
const cancelShow = ref(false)
|
||||
const orderSn = ref('')
|
||||
@@ -208,21 +234,15 @@ onLoad((options) => {
|
||||
})
|
||||
|
||||
watch(tabCurrentIndex, (val) => {
|
||||
params.tag = orderStatus[val].orderStatus
|
||||
navList.forEach((res) => {
|
||||
res.pageNumber = 1
|
||||
res.loadStatus = 'more'
|
||||
res.orderList = []
|
||||
res.loaded = false
|
||||
})
|
||||
loadData(val)
|
||||
})
|
||||
|
||||
function applyService(order: any) {
|
||||
uni.navigateTo({
|
||||
url: `/pages/order/afterSales/afterSales?orderSn=${order.sn}`,
|
||||
})
|
||||
}
|
||||
|
||||
function navigateToStore(val: any) {
|
||||
uni.navigateTo({
|
||||
url: '/pages/product/shopPage?id=' + val.storeId,
|
||||
@@ -286,6 +306,7 @@ function initData(index: number) {
|
||||
navList[index].pageNumber = 1
|
||||
navList[index].loadStatus = 'more'
|
||||
navList[index].orderList = []
|
||||
navList[index].loaded = false
|
||||
loadData(index)
|
||||
}
|
||||
|
||||
@@ -302,26 +323,99 @@ function pay(val: any) {
|
||||
}
|
||||
|
||||
function loadData(index: number) {
|
||||
params.pageNumber = navList[index].pageNumber
|
||||
getOrderList(params).then((res) => {
|
||||
const tab = navList[index]
|
||||
if (!tab || tab.loadStatus === 'noMore') {
|
||||
return
|
||||
}
|
||||
const pageNumber = tab.pageNumber
|
||||
const request = tab.kind === 'afterSale'
|
||||
? getAfterSaleList({
|
||||
pageNumber,
|
||||
pageSize: 10,
|
||||
sort: 'createTime',
|
||||
order: 'desc',
|
||||
})
|
||||
: getOrderList({
|
||||
pageNumber,
|
||||
pageSize: 10,
|
||||
tag: tab.tag,
|
||||
...(tab.commentStatus ? { commentStatus: tab.commentStatus } : {}),
|
||||
})
|
||||
request.then((res) => {
|
||||
uni.stopPullDownRefresh()
|
||||
tab.loaded = true
|
||||
if (!res.data.success) {
|
||||
navList[index].loadStatus = 'noMore'
|
||||
tab.loadStatus = 'noMore'
|
||||
return false
|
||||
}
|
||||
const records = res.data.result.records
|
||||
if (records.length == 0) {
|
||||
navList[index].loadStatus = 'noMore'
|
||||
} else if (records.length < 10) {
|
||||
navList[index].loadStatus = 'noMore'
|
||||
let records = res.data.result.records || []
|
||||
if (tab.kind === 'afterSale') {
|
||||
records = records.map(mapAfterSaleOrder)
|
||||
}
|
||||
if (records.length < 10) {
|
||||
tab.loadStatus = 'noMore'
|
||||
}
|
||||
if (records.length > 0) {
|
||||
navList[index].orderList = navList[index].orderList.concat(records)
|
||||
navList[index].pageNumber += 1
|
||||
tab.orderList = tab.orderList.concat(records)
|
||||
tab.pageNumber += 1
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const afterSaleTypeTextMap: Record<string, string> = {
|
||||
RETURN_MONEY: '仅退款',
|
||||
RETURN_GOODS: '退货退款',
|
||||
EXCHANGE_GOODS: '换货',
|
||||
SUPPLY_AGAIN_GOODS: '补发商品',
|
||||
CANCEL: '取消订单',
|
||||
}
|
||||
|
||||
function afterSaleTypeText(type: string) {
|
||||
return afterSaleTypeTextMap[type] || '售后'
|
||||
}
|
||||
|
||||
function mapAfterSaleOrder(item: any) {
|
||||
return {
|
||||
...item,
|
||||
isAfterSale: true,
|
||||
serviceSn: item.sn,
|
||||
sn: item.orderSn,
|
||||
orderStatus: item.serviceStatus,
|
||||
groupName: item.goodsName,
|
||||
groupNum: item.num,
|
||||
groupImages: item.goodsImage,
|
||||
applyRefundPrice: item.applyRefundPrice,
|
||||
orderItems: [
|
||||
{
|
||||
image: item.goodsImage,
|
||||
name: item.goodsName,
|
||||
num: item.num,
|
||||
},
|
||||
],
|
||||
allowOperationVO: {},
|
||||
}
|
||||
}
|
||||
|
||||
function orderCardStatus(order: any) {
|
||||
if (order?.isAfterSale) {
|
||||
return afterSaleStatusText[order.serviceStatus] || '售后'
|
||||
}
|
||||
if (isAppointmentOrder(order?.orderType)) {
|
||||
return appointmentOrderStatusText(order.orderStatus)
|
||||
}
|
||||
return orderStatusList(order.orderStatus)
|
||||
}
|
||||
|
||||
function openOrder(order: any) {
|
||||
if (order?.isAfterSale) {
|
||||
uni.navigateTo({
|
||||
url: './afterSales/applyDetail?sn=' + order.serviceSn,
|
||||
})
|
||||
return
|
||||
}
|
||||
navigateToOrderDetail(order.sn)
|
||||
}
|
||||
|
||||
function changeTab(e: any) {
|
||||
tabCurrentIndex.value = e.target.current
|
||||
}
|
||||
@@ -379,16 +473,6 @@ function showOrderCancel(order: any) {
|
||||
return !!order?.allowOperationVO?.cancel
|
||||
}
|
||||
|
||||
function showOrderAfterSale(order: any) {
|
||||
if (isECouponOrder(order?.orderType)) return false
|
||||
if (isAppointmentOrder(order?.orderType)) {
|
||||
const allow = getAppointmentAllowOperation(order)
|
||||
if (!allow?.afterSale) return false
|
||||
}
|
||||
const status = order?.groupAfterSaleStatus
|
||||
return status && (status.includes('NOT_APPLIED') || status.includes('PART_AFTER_SALE'))
|
||||
}
|
||||
|
||||
function navigateToOrderDetail(sn: string) {
|
||||
uni.navigateTo({
|
||||
url: './orderDetail?sn=' + sn,
|
||||
@@ -474,23 +558,31 @@ function reBuy(order: any) {
|
||||
}
|
||||
|
||||
.navbar {
|
||||
display: flex;
|
||||
height: 40px;
|
||||
padding: 0 5px;
|
||||
background: #fff;
|
||||
box-shadow: 0 1px 5px rgba(0, 0, 0, 0.06);
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
white-space: nowrap;
|
||||
|
||||
.navbar-inner {
|
||||
display: inline-flex;
|
||||
align-items: stretch;
|
||||
height: 40px;
|
||||
min-width: 100%;
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex: none;
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
padding: 0 24rpx;
|
||||
font-size: 26rpx;
|
||||
color: $font-color-light;
|
||||
position: relative;
|
||||
white-space: nowrap;
|
||||
|
||||
&.current {
|
||||
color: $main-color;
|
||||
@@ -543,6 +635,12 @@ function reBuy(order: any) {
|
||||
}
|
||||
}
|
||||
|
||||
.after-sale-sn {
|
||||
padding: 0 32rpx 8rpx;
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.goods-item-view {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<view>
|
||||
<view :style="themeStyle">
|
||||
<!-- 订单状态 -->
|
||||
<div class="info-view order-view">
|
||||
<div class="order-status" v-if="orderStatusMap[order.orderStatus]">
|
||||
<view class="order-status-title">{{ orderStatusMap[order.orderStatus].title }}</view>
|
||||
<view class="order-status-desc">{{ orderStatusMap[order.orderStatus].value }}</view>
|
||||
<div class="order-status" v-if="displayOrderStatus">
|
||||
<view class="order-status-title">{{ displayOrderStatus.title }}</view>
|
||||
<view class="order-status-desc" v-if="displayOrderStatus.value">{{ displayOrderStatus.value }}</view>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -14,50 +14,24 @@
|
||||
<view v-if="isAppointmentOrderFlag" class="appointment-entry">
|
||||
<view class="appointment-entry__row">
|
||||
<text class="label">预约时间</text>
|
||||
<text>{{ appointmentSlotText }}</text>
|
||||
<text class="value">{{ appointmentSlotText }}</text>
|
||||
</view>
|
||||
<view class="appointment-entry__row" v-if="appointmentDetail.serviceMode">
|
||||
<text class="label">服务方式</text>
|
||||
<text>{{ serviceModeLabel }}</text>
|
||||
</view>
|
||||
<view class="appointment-entry__row" v-if="appointmentDetail.contactName">
|
||||
<text class="label">联系人</text>
|
||||
<text>{{ appointmentDetail.contactName }} {{ appointmentDetail.contactPhone }}</text>
|
||||
<text class="value">{{ serviceModeLabel }}</text>
|
||||
</view>
|
||||
<view class="appointment-entry__row" v-if="appointmentDetail.serviceAddressSnapshot">
|
||||
<text class="label">服务地址</text>
|
||||
<text>{{ appointmentDetail.serviceAddressSnapshot }}</text>
|
||||
<text class="value">{{ appointmentDetail.serviceAddressSnapshot }}</text>
|
||||
</view>
|
||||
<view
|
||||
v-for="(rows, gi) in appointmentFormGroups"
|
||||
:key="gi"
|
||||
class="appointment-entry__row appointment-form-block"
|
||||
>
|
||||
<text class="label">{{ appointmentFormGroups.length > 1 ? `补充信息${gi + 1}` : '补充信息' }}</text>
|
||||
<view class="form-answers">
|
||||
<view v-for="row in rows" :key="row.fieldKey" class="form-answer-row">
|
||||
{{ row.fieldLabel }}:{{ row.value }}
|
||||
</view>
|
||||
<template v-for="(row, index) in appointmentFormRows" :key="index">
|
||||
<view v-if="row.type === 'group'" class="appointment-group">{{ row.label }}</view>
|
||||
<view v-else class="appointment-entry__row">
|
||||
<text class="label">{{ row.label }}</text>
|
||||
<text class="value">{{ row.value }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="appointmentCodes.length" class="appointment-codes">
|
||||
<view class="appointment-codes__title">核销码({{ appointmentCodes.length }})</view>
|
||||
<view
|
||||
v-for="code in appointmentCodes"
|
||||
:key="code.id || code.code"
|
||||
class="verificationCode appointment-code-item"
|
||||
>
|
||||
{{ code.seqNo ? '#' + code.seqNo + ' ' : '' }}{{ code.code }}
|
||||
<text class="code-status">({{ verificationStatusText(code.status) }})</text>
|
||||
</view>
|
||||
</view>
|
||||
<view
|
||||
v-if="appointmentAllow.reschedule"
|
||||
class="card-key-entry__btn reschedule-stub"
|
||||
@click="onRescheduleStub"
|
||||
>
|
||||
申请改期
|
||||
</view>
|
||||
</template>
|
||||
<verification-codes :items="verificationCodeItems" />
|
||||
</view>
|
||||
<view v-else-if="isECouponOrder" class="card-key-entry">
|
||||
<view v-if="ecouponCardKeyDelivered" class="card-key-entry__btn" @click="goCardKeyDetail">
|
||||
@@ -70,9 +44,7 @@
|
||||
{{ ecouponPendingMessage || '卡密尚未发放,请稍后刷新' }}
|
||||
</view>
|
||||
</view>
|
||||
<view class="verificationCode" v-else-if="order.verificationCode">
|
||||
券码: {{ order.orderStatus == 'CANCELLED' ? '已失效' : order.verificationCode }}
|
||||
</view>
|
||||
<verification-codes v-else-if="verificationCodeItems.length" :items="verificationCodeItems" />
|
||||
<view
|
||||
v-else-if="allowOperation.showLogistics"
|
||||
@click="handleClickDeliver()"
|
||||
@@ -124,8 +96,7 @@
|
||||
<view class="seller-info u-flex u-row-between">
|
||||
<view class="seller-name" @click="goToShopPage(order)">
|
||||
<view class="name">{{ order.storeName }}</view>
|
||||
<view class="status" v-if="orderStatusMap[order.orderStatus]"> {{ orderStatusMap[order.orderStatus].title
|
||||
}}</view>
|
||||
<view class="status" v-if="displayOrderStatus"> {{ displayOrderStatus.title }}</view>
|
||||
</view>
|
||||
<view class="order-sn"></view>
|
||||
</view>
|
||||
@@ -135,18 +106,23 @@
|
||||
<view class="goods-img" @click="gotoGoodsDetail(sku)">
|
||||
<u-image border-radius="6" width="131rpx" height="131rpx" :src="sku.image"></u-image>
|
||||
</view>
|
||||
<view class="goods-info" @click="gotoGoodsDetail(sku)">
|
||||
<view class="goods-title u-line-2">{{ sku.goodsName }}</view>
|
||||
<view class="goods-price">
|
||||
¥{{unitPrice(sku.goodsPrice) }}
|
||||
<!-- <span v-if="sku.point">+{{ sku.point }}积分</span> -->
|
||||
<span style="font-size: 24rpx;margin-left: 14rpx;color: #ff9900;" v-if="!isECouponOrder && !isAppointmentOrderFlag && sku.isRefund && sku.isRefund !== 'NO_REFUND'">
|
||||
{{refundPriceList(sku.isRefund)}} ({{unitPrice(sku.refundPrice, "¥") }})
|
||||
</span>
|
||||
<view class="goods-body">
|
||||
<view class="goods-info" @click="gotoGoodsDetail(sku)">
|
||||
<view class="goods-title u-line-2">{{ sku.goodsName }}</view>
|
||||
<view class="goods-price">
|
||||
¥{{unitPrice(sku.goodsPrice) }}
|
||||
<!-- <span v-if="sku.point">+{{ sku.point }}积分</span> -->
|
||||
<span style="font-size: 24rpx;margin-left: 14rpx;color: #ff9900;" v-if="!isECouponOrder && !isAppointmentOrderFlag && sku.isRefund && sku.isRefund !== 'NO_REFUND'">
|
||||
{{refundPriceList(sku.isRefund)}} ({{unitPrice(sku.refundPrice, "¥") }})
|
||||
</span>
|
||||
</view>
|
||||
</view>
|
||||
<view class="goods-side" :class="{ 'has-action': canShowSkuAfterSale(sku) }">
|
||||
<view class="goods-num">
|
||||
<view>x{{ sku.num }}</view>
|
||||
</view>
|
||||
<view class="after-sale-btn" v-if="canShowSkuAfterSale(sku)" @click.stop="onSkuAfterSale(sku)">退款/售后</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="goods-num">
|
||||
<view>x{{ sku.num }}</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -206,8 +182,8 @@
|
||||
<view class="title">订单编号:</view>
|
||||
<view class="value order-sn-value">
|
||||
<text class="order-sn-text">{{ order.sn }}</text>
|
||||
<view class="copy" @click.stop="onCopy(order.sn)">
|
||||
<u-tag text="复制" type="info" plain size="mini" />
|
||||
<view class="copy" @tap.stop="onCopy(order.sn)">
|
||||
<view class="copy-icon"></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -312,10 +288,12 @@
|
||||
import { ref, computed } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { useStore } from '@/store'
|
||||
import { getThemeStyle } from '@/utils/theme'
|
||||
import { getExpress, getPackage } from '@/api/trade.js'
|
||||
import { cancelOrder, confirmReceipt, getOrderDetail } from '@/api/order.js'
|
||||
import shares from '@/components/m-share/index'
|
||||
import { getClearReason } from '@/api/after-sale.js'
|
||||
import storage from '@/utils/storage'
|
||||
import {
|
||||
unitPrice,
|
||||
secrecyMobile,
|
||||
@@ -338,15 +316,18 @@ import {
|
||||
CARD_KEY_FULFILL_STATUS,
|
||||
} from '@/utils/goodsType.js'
|
||||
import { getAppointmentOrderDetail } from '@/api/appointment.js'
|
||||
import VerificationCodes from './components/verificationCodes.vue'
|
||||
import {
|
||||
SERVICE_MODE_LABEL,
|
||||
VERIFICATION_CODE_STATUS_TEXT,
|
||||
appointmentOrderStatusText,
|
||||
getAppointmentAllowOperation,
|
||||
formatDate,
|
||||
parseFormAnswerGroups,
|
||||
formatFormAnswerValue,
|
||||
} from '@/utils/appointmentGoods.js'
|
||||
|
||||
const store = useStore()
|
||||
const themeStyle = computed(() => getThemeStyle(store.state.theme))
|
||||
const lightColor = computed(() => store.getters.lightColor)
|
||||
const mainColor = computed(() => store.getters.mainColor)
|
||||
|
||||
@@ -375,12 +356,27 @@ const reason = ref('')
|
||||
const orderPackage = ref<any[]>([])
|
||||
const legacyTraces = ref<any>(null)
|
||||
|
||||
const displayOrderStatus = computed(() => {
|
||||
if (isAppointmentOrderFlag.value) {
|
||||
const status = order.value?.orderStatus
|
||||
const title = appointmentOrderStatusText(status)
|
||||
if (status === 'UNPAID') return { title, value: '请尽快完成支付' }
|
||||
if (status === 'CANCELLED') return { title, value: '订单已取消' }
|
||||
if (status === 'COMPLETED' || status === 'COMPLETE') return { title, value: '服务已完成' }
|
||||
const onSite = appointmentDetail.value?.serviceMode === 'ON_SITE'
|
||||
return {
|
||||
title,
|
||||
value: onSite ? '请等待上门服务' : '请按时到店使用',
|
||||
}
|
||||
}
|
||||
return orderStatusMap[order.value?.orderStatus]
|
||||
})
|
||||
const isECouponOrder = computed(() => checkECouponOrder(order.value?.orderType))
|
||||
const isAppointmentOrderFlag = computed(() => checkAppointmentOrder(order.value?.orderType))
|
||||
const isNonPhysicalOrder = computed(() => checkNonPhysicalOrder(order.value?.orderType))
|
||||
const appointmentDetail = ref<Record<string, any>>({})
|
||||
const appointmentAllow = computed(() =>
|
||||
getAppointmentAllowOperation(order.value) || { cancel: false, afterSale: false, reschedule: false }
|
||||
getAppointmentAllowOperation(order.value) || { cancel: false, afterSale: false }
|
||||
)
|
||||
const showCancelBtn = computed(() => {
|
||||
if (isAppointmentOrderFlag.value) return appointmentAllow.value.cancel
|
||||
@@ -400,6 +396,30 @@ const appointmentSlotText = computed(() => {
|
||||
const appointmentFormGroups = computed(() =>
|
||||
parseFormAnswerGroups(appointmentDetail.value?.formAnswerJson)
|
||||
)
|
||||
const appointmentFormRows = computed(() => {
|
||||
const groups = appointmentFormGroups.value
|
||||
const rows = []
|
||||
if (groups.length) {
|
||||
groups.forEach((group, index) => {
|
||||
if (groups.length > 1) {
|
||||
rows.push({ type: 'group', label: `第${index + 1}位` })
|
||||
}
|
||||
group.forEach((field) => {
|
||||
const value = formatFormAnswerValue(field.value)
|
||||
if (!value) return
|
||||
rows.push({ label: field.fieldLabel || '补充信息', value })
|
||||
})
|
||||
})
|
||||
return rows
|
||||
}
|
||||
if (appointmentDetail.value?.contactName) {
|
||||
rows.push({ label: '联系人', value: appointmentDetail.value.contactName })
|
||||
}
|
||||
if (appointmentDetail.value?.contactPhone) {
|
||||
rows.push({ label: '联系方式', value: appointmentDetail.value.contactPhone })
|
||||
}
|
||||
return rows
|
||||
})
|
||||
const ecouponCardKeyDelivered = computed(() =>
|
||||
orderHasCardKeyContent(orderGoodsList.value)
|
||||
)
|
||||
@@ -417,13 +437,43 @@ const allowOperation = computed(() =>
|
||||
const showDeliveryInfoBlock = computed(() => {
|
||||
if (isAppointmentOrderFlag.value) return true
|
||||
if (isECouponOrder.value) return true
|
||||
if (order.value.verificationCode) return true
|
||||
if (order.value.orderType === 'VIRTUAL') return false
|
||||
if (order.value.deliveryMethod === 'SELF_PICK_UP') return false
|
||||
if (order.value.verificationCode) return true
|
||||
if (order.value.deliveryMethod === 'LOGISTICS') return true
|
||||
return false
|
||||
})
|
||||
|
||||
const verificationCodeItems = computed(() => {
|
||||
if (isAppointmentOrderFlag.value) {
|
||||
const cancelled = order.value.orderStatus === 'CANCELLED'
|
||||
let qrAssigned = false
|
||||
return appointmentCodes.value.map((code, index) => {
|
||||
const pending = !cancelled && code.status === 'UNUSED'
|
||||
const showQr = pending && !qrAssigned
|
||||
if (showQr) qrAssigned = true
|
||||
return {
|
||||
key: code.id || code.code || String(index),
|
||||
canvasId: `verify-code-${index}`,
|
||||
code: code.code,
|
||||
struck: !pending,
|
||||
showQr,
|
||||
}
|
||||
})
|
||||
}
|
||||
const code = order.value.verificationCode
|
||||
if (!code || isECouponOrder.value) return []
|
||||
const status = order.value.orderStatus
|
||||
const pending = status !== 'CANCELLED' && status !== 'COMPLETED'
|
||||
return [{
|
||||
key: code,
|
||||
canvasId: 'verify-code-0',
|
||||
code,
|
||||
struck: !pending,
|
||||
showQr: pending,
|
||||
}]
|
||||
})
|
||||
|
||||
const deliveryEntryText = computed(() =>
|
||||
getDeliveryEntryText(
|
||||
orderPackage.value,
|
||||
@@ -525,10 +575,6 @@ function ByUserMessage(orderItem: any) {
|
||||
})
|
||||
}
|
||||
|
||||
function verificationStatusText(status: string) {
|
||||
return VERIFICATION_CODE_STATUS_TEXT[status] || status || '—'
|
||||
}
|
||||
|
||||
async function loadAppointmentDetail(orderSnParam: string) {
|
||||
if (!checkAppointmentOrder(order.value?.orderType)) {
|
||||
appointmentDetail.value = {}
|
||||
@@ -542,12 +588,6 @@ async function loadAppointmentDetail(orderSnParam: string) {
|
||||
}
|
||||
}
|
||||
|
||||
function onRescheduleStub() {
|
||||
uni.navigateTo({
|
||||
url: `/pages/order/appointment/appointmentReschedule?orderSn=${order.value.sn}`,
|
||||
})
|
||||
}
|
||||
|
||||
function loadData(orderSnParam: string) {
|
||||
uni.showLoading({ title: '加载中' })
|
||||
getOrderDetail(orderSnParam).then(async (res) => {
|
||||
@@ -584,6 +624,35 @@ function onCopy(orderSnText: string) {
|
||||
setClipboard(String(orderSnText))
|
||||
}
|
||||
|
||||
function canApplySkuAfterSale(sku: any) {
|
||||
const status = String(sku?.afterSaleStatus || '')
|
||||
if (status.includes('NOT_APPLIED') || status.includes('PART_AFTER_SALE')) return true
|
||||
if (isAppointmentOrderFlag.value && (!status || status === 'NEW')) return true
|
||||
return false
|
||||
}
|
||||
|
||||
function canShowSkuAfterSale(sku: any) {
|
||||
if (isECouponOrder.value) return false
|
||||
if (!order.value?.sn || Number(order.value.flowPrice) === 0) return false
|
||||
if (isAppointmentOrderFlag.value && !appointmentAllow.value.afterSale) return false
|
||||
return canApplySkuAfterSale(sku)
|
||||
}
|
||||
|
||||
function onSkuAfterSale(sku: any) {
|
||||
if (!canShowSkuAfterSale(sku)) return
|
||||
storage.setAfterSaleData({
|
||||
...order.value,
|
||||
...sku,
|
||||
orderItems: orderGoodsList.value || [],
|
||||
storeName: order.value.storeName,
|
||||
flowPrice: order.value.flowPrice,
|
||||
orderType: order.value.orderType,
|
||||
})
|
||||
uni.navigateTo({
|
||||
url: `./afterSales/afterSalesSelect?sn=${sku.sn}`,
|
||||
})
|
||||
}
|
||||
|
||||
function onAfterSales(orderSnText: string, sku: any) {
|
||||
uni.navigateTo({
|
||||
url: `./afterSales/afterSalesSelect?sn=${orderSnText}&sku=${encodeURIComponent(
|
||||
@@ -676,13 +745,56 @@ function reBuy(orderItem: any) {
|
||||
<style lang="scss">
|
||||
@import "./goods.scss";
|
||||
|
||||
.goods-item-view {
|
||||
.seller-view .goods-item-view {
|
||||
align-items: flex-start;
|
||||
|
||||
.goods-body {
|
||||
flex: 4;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.goods-info {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
|
||||
.goods-title {
|
||||
font-size: 24rpx;
|
||||
line-height: 1.4;
|
||||
}
|
||||
}
|
||||
|
||||
.goods-side {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-end;
|
||||
justify-content: center;
|
||||
align-self: stretch;
|
||||
min-height: 131rpx;
|
||||
margin-left: 12rpx;
|
||||
}
|
||||
|
||||
.goods-side.has-action {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.goods-num {
|
||||
flex: none;
|
||||
width: auto;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
.after-sale-btn {
|
||||
height: 44rpx;
|
||||
line-height: 44rpx;
|
||||
padding: 0 16rpx;
|
||||
font-size: 22rpx;
|
||||
color: #666;
|
||||
background: #f5f5f5;
|
||||
border-radius: 22rpx;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.empty {
|
||||
@@ -857,6 +969,38 @@ page,
|
||||
.copy {
|
||||
margin-left: 16rpx;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
}
|
||||
|
||||
.copy-icon {
|
||||
position: relative;
|
||||
width: 28rpx;
|
||||
height: 28rpx;
|
||||
}
|
||||
|
||||
.copy-icon::before,
|
||||
.copy-icon::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 16rpx;
|
||||
height: 16rpx;
|
||||
border: 2rpx solid #666;
|
||||
border-radius: 4rpx;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.copy-icon::before {
|
||||
left: 0;
|
||||
top: 8rpx;
|
||||
}
|
||||
|
||||
.copy-icon::after {
|
||||
right: 0;
|
||||
top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -881,8 +1025,9 @@ page,
|
||||
|
||||
.appointment-entry__row {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
font-size: 26rpx;
|
||||
margin-bottom: 12rpx;
|
||||
margin-bottom: 16rpx;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.appointment-entry__row .label {
|
||||
@@ -890,26 +1035,17 @@ page,
|
||||
width: 140rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.form-answers {
|
||||
.appointment-entry__row .value {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
color: #333;
|
||||
word-break: break-all;
|
||||
}
|
||||
.form-answer-row {
|
||||
margin-bottom: 4rpx;
|
||||
}
|
||||
.appointment-codes__title {
|
||||
font-size: 26rpx;
|
||||
font-weight: 600;
|
||||
margin: 16rpx 0 8rpx;
|
||||
}
|
||||
.appointment-code-item {
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
.code-status {
|
||||
color: #999;
|
||||
font-size: 22rpx;
|
||||
}
|
||||
.reschedule-stub {
|
||||
margin-top: 16rpx;
|
||||
.appointment-group {
|
||||
margin: 8rpx 0 12rpx;
|
||||
font-size: 24rpx;
|
||||
color: var(--theme-primary, #ff3c2a);
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.verificationCode {
|
||||
|
||||
Reference in New Issue
Block a user