删除冗余代码
This commit is contained in:
parent
fe61729cb4
commit
860ce21b52
@ -1,219 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import { getOrderEvaluateListApi, getOrderEvaluateTabsApi } from '@/api/order'
|
|
||||||
import { ref } from 'vue'
|
|
||||||
// 必须导入需要用到的页面生命周期(即使在当前页面上没有直接使用到)
|
|
||||||
import { onPageScroll, onReachBottom } from '@dcloudio/uni-app'
|
|
||||||
import useZPaging from '@/uni_modules/z-paging/components/z-paging/js/hooks/useZPaging.js'
|
|
||||||
import type { orderEvaluateListResult } from '@/types/order'
|
|
||||||
import type { TabItem } from '@/types/global'
|
|
||||||
import { fullUrl, onShowRefreshData, previewImg } from '@/utils/common'
|
|
||||||
|
|
||||||
const props = defineProps<{
|
|
||||||
goods_id: string
|
|
||||||
}>()
|
|
||||||
|
|
||||||
const paging = ref()
|
|
||||||
// 类似mixins,如果是页面滚动务必要写这一行,并传入当前ref绑定的paging,注意此处是paging,而非paging.value
|
|
||||||
useZPaging(paging)
|
|
||||||
|
|
||||||
const tabList = ref<TabItem[]>([])
|
|
||||||
const tabIndex = ref(0)
|
|
||||||
const tabsChange = (index: number) => {
|
|
||||||
tabIndex.value = index
|
|
||||||
paging.value.reload()
|
|
||||||
}
|
|
||||||
|
|
||||||
const dataList = ref<orderEvaluateListResult[]>([])
|
|
||||||
const queryList = async (page: number, page_size: number) => {
|
|
||||||
const res = await getOrderEvaluateListApi({
|
|
||||||
page,
|
|
||||||
page_size,
|
|
||||||
goods_id: props.goods_id,
|
|
||||||
type: tabList.value[tabIndex.value]?.value ?? '',
|
|
||||||
})
|
|
||||||
paging.value.complete(res.result.data)
|
|
||||||
}
|
|
||||||
|
|
||||||
const getTabList = async () => {
|
|
||||||
const res = await getOrderEvaluateTabsApi({
|
|
||||||
goods_id: props.goods_id,
|
|
||||||
})
|
|
||||||
tabList.value = res.result.map((item) => ({
|
|
||||||
...item,
|
|
||||||
disabled: false,
|
|
||||||
badge: { count: item.count },
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
const groupedImages = (imageList: string[]) => {
|
|
||||||
if (imageList.length <= 0) return []
|
|
||||||
|
|
||||||
const groups = []
|
|
||||||
const images = imageList.map((item) => fullUrl(item))
|
|
||||||
|
|
||||||
for (let i = 0; i < images.length; i += 3) {
|
|
||||||
groups.push(images.slice(i, i + 3))
|
|
||||||
}
|
|
||||||
|
|
||||||
return groups
|
|
||||||
}
|
|
||||||
|
|
||||||
onShowRefreshData(() => {
|
|
||||||
getTabList()
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<z-paging ref="paging" v-model="dataList" @query="queryList" :safe-area-inset-bottom="true">
|
|
||||||
<template #top>
|
|
||||||
<z-tabs
|
|
||||||
:list="tabList"
|
|
||||||
@change="tabsChange"
|
|
||||||
:current="tabIndex"
|
|
||||||
:badge-style="{ backgroundColor: '#c3c3c3' }"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
<view class="evaluate panel" v-for="(item, index) in dataList" :key="index">
|
|
||||||
<view class="top">
|
|
||||||
<shop-user-avatar class="portrait" :url="item.user_avatar" width="70" />
|
|
||||||
<text class="name">{{ item.user_name }}</text>
|
|
||||||
<text class="time">{{ item.create_time }}</text>
|
|
||||||
</view>
|
|
||||||
<view class="rate">
|
|
||||||
<uni-rate :value="item.score" :size="18" readonly />
|
|
||||||
<text class="spec">{{ item.goods_spec }}</text>
|
|
||||||
</view>
|
|
||||||
<text class="content">{{ item.content }}</text>
|
|
||||||
<view class="content-img">
|
|
||||||
<view class="image-group" v-for="(group, index) in groupedImages(item.images)" :key="index">
|
|
||||||
<image
|
|
||||||
v-for="(img, imgIndex) in group"
|
|
||||||
:key="imgIndex"
|
|
||||||
:src="img"
|
|
||||||
mode="aspectFill"
|
|
||||||
@click="previewImg(img, item.images)"
|
|
||||||
:class="{
|
|
||||||
'first-image': imgIndex === 0 && group.length > 1,
|
|
||||||
'last-image': imgIndex === group.length - 1 && group.length > 1,
|
|
||||||
'single-image': group.length === 1,
|
|
||||||
'middle-image': imgIndex !== 0 && imgIndex !== group.length - 1,
|
|
||||||
}"
|
|
||||||
/>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="bot"> </view>
|
|
||||||
</view>
|
|
||||||
</z-paging>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
page {
|
|
||||||
height: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
background-color: #f4f4f4;
|
|
||||||
}
|
|
||||||
|
|
||||||
.panel {
|
|
||||||
margin-top: 10rpx;
|
|
||||||
background-color: #fff;
|
|
||||||
padding: 20rpx;
|
|
||||||
margin: 20rpx;
|
|
||||||
border-radius: 20rpx;
|
|
||||||
|
|
||||||
.top {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
margin-bottom: 10rpx;
|
|
||||||
|
|
||||||
.portrait {
|
|
||||||
width: 70rpx;
|
|
||||||
height: 70rpx;
|
|
||||||
border-radius: 50%;
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.name {
|
|
||||||
flex: 1;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
font-size: 28rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.time {
|
|
||||||
font-size: 24rpx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.rate {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
margin-bottom: 10rpx;
|
|
||||||
|
|
||||||
.spec {
|
|
||||||
::before {
|
|
||||||
content: '|';
|
|
||||||
margin: 0 10rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
color: #666;
|
|
||||||
font-size: 20rpx;
|
|
||||||
overflow: hidden;
|
|
||||||
display: -webkit-box;
|
|
||||||
-webkit-line-clamp: 1;
|
|
||||||
-webkit-box-orient: vertical;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
|
||||||
display: flex;
|
|
||||||
padding-left: 7rpx;
|
|
||||||
font-size: 26rpx;
|
|
||||||
margin: 20rpx 0rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content-img {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
margin-top: 10rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.image-group {
|
|
||||||
display: flex;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.image-group image {
|
|
||||||
height: 200rpx;
|
|
||||||
width: 33%;
|
|
||||||
margin-right: 1.5%;
|
|
||||||
margin-bottom: 10rpx;
|
|
||||||
object-fit: cover;
|
|
||||||
border-radius: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.image-group image.single-image {
|
|
||||||
border-radius: 20rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.image-group image.first-image {
|
|
||||||
border-top-left-radius: 20rpx;
|
|
||||||
border-bottom-left-radius: 20rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.image-group image.last-image {
|
|
||||||
border-top-right-radius: 20rpx;
|
|
||||||
border-bottom-right-radius: 20rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.image-group image.middle-image {
|
|
||||||
border-radius: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.image-group image:last-child {
|
|
||||||
margin-right: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,162 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import { useAddressStore } from '@/stores/modules/address'
|
|
||||||
import type { addressItem } from '@/types/address'
|
|
||||||
import { pageUrl } from '@/utils/constants'
|
|
||||||
|
|
||||||
const emit = defineEmits<{
|
|
||||||
(event: 'close'): void
|
|
||||||
}>()
|
|
||||||
|
|
||||||
//获取地址信息
|
|
||||||
const props = defineProps<{
|
|
||||||
list?: addressItem[]
|
|
||||||
}>()
|
|
||||||
|
|
||||||
const addressStore = useAddressStore()
|
|
||||||
|
|
||||||
//选择收货地址
|
|
||||||
const onSelectAddress = (item: addressItem) => {
|
|
||||||
addressStore.changeSelectedAddress(item)
|
|
||||||
emit('close')
|
|
||||||
}
|
|
||||||
|
|
||||||
const toAddressList = () => {
|
|
||||||
uni.navigateTo({
|
|
||||||
url: `${pageUrl['address-form']}`,
|
|
||||||
})
|
|
||||||
|
|
||||||
emit('close')
|
|
||||||
}
|
|
||||||
|
|
||||||
useAddressStore().changeScene('order')
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<view class="address-panel">
|
|
||||||
<text class="close icon-close" @tap="emit('close')"></text>
|
|
||||||
<view class="title">配送至</view>
|
|
||||||
<view class="content">
|
|
||||||
<view v-if="props.list!.length > 0">
|
|
||||||
<view class="item" v-for="item in props.list" :key="item.id" @tap="onSelectAddress(item)">
|
|
||||||
<view class="user">{{ item.name }} {{ item.phone }}</view>
|
|
||||||
<view class="address">{{ item.full_location }} {{ item.address }}</view>
|
|
||||||
<text
|
|
||||||
class="icon"
|
|
||||||
:class="item.id === addressStore.selectedAddress?.id ? 'icon-checked' : 'icon-check'"
|
|
||||||
></text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view v-else>
|
|
||||||
<z-paging-empty-view
|
|
||||||
empty-view-text="暂无收货地址"
|
|
||||||
:empty-view-style="{
|
|
||||||
top: '50rpx',
|
|
||||||
}"
|
|
||||||
/>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="footer">
|
|
||||||
<view class="button primary">
|
|
||||||
<view open-type="navigate" hover-class="navigator-hover" @tap="toAddressList">
|
|
||||||
新增收货地址
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
.address-panel {
|
|
||||||
padding: 0 30rpx;
|
|
||||||
border-radius: 10rpx 10rpx 0 0;
|
|
||||||
position: relative;
|
|
||||||
background-color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title {
|
|
||||||
line-height: 1;
|
|
||||||
padding: 40rpx 0;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 32rpx;
|
|
||||||
font-weight: normal;
|
|
||||||
border-bottom: 1rpx solid #ddd;
|
|
||||||
color: #444;
|
|
||||||
}
|
|
||||||
|
|
||||||
.close {
|
|
||||||
position: absolute;
|
|
||||||
right: 24rpx;
|
|
||||||
top: 24rpx;
|
|
||||||
font-size: 40rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
|
||||||
min-height: 300rpx;
|
|
||||||
max-height: 540rpx;
|
|
||||||
overflow: auto;
|
|
||||||
padding: 20rpx;
|
|
||||||
|
|
||||||
.item {
|
|
||||||
padding: 30rpx 50rpx 30rpx 60rpx;
|
|
||||||
background-size: 40rpx;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-position: 0 center;
|
|
||||||
background-image: url('~@/static/images/locate.png');
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
.icon {
|
|
||||||
color: #999;
|
|
||||||
font-size: 40rpx;
|
|
||||||
transform: translateY(-50%);
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
right: 0;
|
|
||||||
}
|
|
||||||
.icon-checked {
|
|
||||||
color: #ff5f3c;
|
|
||||||
}
|
|
||||||
.icon-ring {
|
|
||||||
color: #444;
|
|
||||||
}
|
|
||||||
.user {
|
|
||||||
font-size: 28rpx;
|
|
||||||
color: #444;
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
.address {
|
|
||||||
font-size: 26rpx;
|
|
||||||
color: #666;
|
|
||||||
}
|
|
||||||
.empty-text {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.footer {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
padding: 20rpx 0 40rpx;
|
|
||||||
font-size: 28rpx;
|
|
||||||
color: #444;
|
|
||||||
|
|
||||||
.button {
|
|
||||||
flex: 1;
|
|
||||||
height: 72rpx;
|
|
||||||
text-align: center;
|
|
||||||
line-height: 72rpx;
|
|
||||||
margin: 0 20rpx;
|
|
||||||
color: #fff;
|
|
||||||
border-radius: 72rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.primary {
|
|
||||||
color: #fff;
|
|
||||||
background-color: #ff5f3c;
|
|
||||||
}
|
|
||||||
|
|
||||||
.secondary {
|
|
||||||
background-color: #ffa868;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,87 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import type { goodsServiceItem } from '@/types/goods'
|
|
||||||
|
|
||||||
const emit = defineEmits<{
|
|
||||||
(event: 'close'): void
|
|
||||||
}>()
|
|
||||||
|
|
||||||
//获取服务与承诺信息
|
|
||||||
const props = defineProps<{
|
|
||||||
list?: goodsServiceItem[]
|
|
||||||
}>()
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<view class="service-panel">
|
|
||||||
<text class="close icon-close" @tap="emit('close')"></text>
|
|
||||||
<view class="title">服务说明</view>
|
|
||||||
<view class="content">
|
|
||||||
<view class="item" v-for="item in props.list" :key="item.id">
|
|
||||||
<view class="dt">{{ item.name }}</view>
|
|
||||||
<view class="dd">
|
|
||||||
{{ item.content }}
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
.service-panel {
|
|
||||||
padding: 0 30rpx;
|
|
||||||
border-radius: 10rpx 10rpx 0 0;
|
|
||||||
position: relative;
|
|
||||||
background-color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title {
|
|
||||||
line-height: 1;
|
|
||||||
padding: 40rpx 0;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 32rpx;
|
|
||||||
font-weight: normal;
|
|
||||||
border-bottom: 1rpx solid #ddd;
|
|
||||||
color: #444;
|
|
||||||
}
|
|
||||||
|
|
||||||
.close {
|
|
||||||
position: absolute;
|
|
||||||
right: 24rpx;
|
|
||||||
top: 24rpx;
|
|
||||||
font-size: 40rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
|
||||||
padding: 20rpx 20rpx 150rpx 20rpx;
|
|
||||||
|
|
||||||
.item {
|
|
||||||
margin-top: 20rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dt {
|
|
||||||
margin-bottom: 10rpx;
|
|
||||||
font-size: 28rpx;
|
|
||||||
color: #333;
|
|
||||||
font-weight: 500;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
content: '';
|
|
||||||
width: 10rpx;
|
|
||||||
height: 10rpx;
|
|
||||||
border-radius: 50%;
|
|
||||||
background-color: #eaeaea;
|
|
||||||
transform: translateY(-50%);
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
left: -20rpx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.dd {
|
|
||||||
line-height: 1.6;
|
|
||||||
font-size: 26rpx;
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,153 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import type { goodsListItem } from '@/types/goods'
|
|
||||||
import { getShareUrl } from './sharePoster'
|
|
||||||
|
|
||||||
const emits = defineEmits<{
|
|
||||||
(event: 'close'): void
|
|
||||||
(event: 'showPoster'): void
|
|
||||||
}>()
|
|
||||||
|
|
||||||
const props = defineProps<{
|
|
||||||
goods: goodsListItem
|
|
||||||
}>()
|
|
||||||
|
|
||||||
const onCpoyLink = () => {
|
|
||||||
const shareUrl = getShareUrl(props.goods.id)
|
|
||||||
|
|
||||||
uni.setClipboardData({
|
|
||||||
data: shareUrl,
|
|
||||||
success: function () {
|
|
||||||
uni.showToast({
|
|
||||||
title: '复制成功',
|
|
||||||
icon: 'none',
|
|
||||||
})
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
emits('close')
|
|
||||||
}
|
|
||||||
const onShowSharePoster = () => {
|
|
||||||
emits('close')
|
|
||||||
emits('showPoster')
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template v-if="path == ''">
|
|
||||||
<view class="panel">
|
|
||||||
<view class="content">
|
|
||||||
<!-- #ifdef MP-WEIXIN -->
|
|
||||||
<button class="content-item" open-type="share">
|
|
||||||
<image class="icon" src="/static/icons/wechat.svg" />
|
|
||||||
<view class="text">微信好友</view>
|
|
||||||
</button>
|
|
||||||
<!-- #endif -->
|
|
||||||
<button class="content-item" @tap="onShowSharePoster">
|
|
||||||
<image class="icon" src="/static/icons/poster.svg" />
|
|
||||||
<view class="text">生成海报</view>
|
|
||||||
</button>
|
|
||||||
<button class="content-item" @tap="onCpoyLink">
|
|
||||||
<image class="icon" src="/static/icons/link.svg" />
|
|
||||||
<view class="text">复制链接</view>
|
|
||||||
</button>
|
|
||||||
</view>
|
|
||||||
<view class="footer">
|
|
||||||
<view class="button" @tap="emits('close')"> 取消分享 </view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
.panel {
|
|
||||||
padding: 0 30rpx;
|
|
||||||
border-radius: 10rpx 10rpx 0 0;
|
|
||||||
position: relative;
|
|
||||||
background-color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title {
|
|
||||||
line-height: 1;
|
|
||||||
padding: 40rpx 0;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 32rpx;
|
|
||||||
font-weight: normal;
|
|
||||||
border-bottom: 1rpx solid #ddd;
|
|
||||||
color: #444;
|
|
||||||
}
|
|
||||||
|
|
||||||
.close {
|
|
||||||
position: absolute;
|
|
||||||
right: 24rpx;
|
|
||||||
top: 24rpx;
|
|
||||||
font-size: 40rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
|
||||||
display: flex;
|
|
||||||
justify-content: cneter;
|
|
||||||
|
|
||||||
.content-item {
|
|
||||||
margin-top: 20rpx;
|
|
||||||
background-color: transparent;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
::after {
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
width: 80rpx;
|
|
||||||
height: 80rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.text {
|
|
||||||
font-size: 30rpx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.footer {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
padding: 20rpx 0 20px;
|
|
||||||
font-size: 28rpx;
|
|
||||||
color: #444;
|
|
||||||
|
|
||||||
.button {
|
|
||||||
flex: 1;
|
|
||||||
height: 72rpx;
|
|
||||||
text-align: center;
|
|
||||||
line-height: 72rpx;
|
|
||||||
margin: 0 20rpx;
|
|
||||||
border-radius: 72rpx;
|
|
||||||
color: #fff;
|
|
||||||
background-color: #ff5f3c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.action {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
padding: 20rpx;
|
|
||||||
background: #f5f5f5;
|
|
||||||
|
|
||||||
.button {
|
|
||||||
padding: 16rpx 32rpx;
|
|
||||||
margin: 0 10rpx;
|
|
||||||
|
|
||||||
background: #ff784d;
|
|
||||||
color: #ffffff;
|
|
||||||
|
|
||||||
border-radius: 40rpx;
|
|
||||||
|
|
||||||
&:active {
|
|
||||||
opacity: 0.8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.cancel {
|
|
||||||
background: #b3b3b3;
|
|
||||||
color: #ffffff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,9 +0,0 @@
|
|||||||
import { useMemberStore, useSettingStore } from '@/stores'
|
|
||||||
import { pageUrl } from '@/utils/constants'
|
|
||||||
|
|
||||||
export const getShareUrl = (goodsId: number | string) => {
|
|
||||||
const settingData = useSettingStore().data
|
|
||||||
const profileData = useMemberStore().profile
|
|
||||||
|
|
||||||
return `${settingData.h5_domain}${pageUrl['goods-detail']}?id=${goodsId}&sharer=${profileData?.id}`
|
|
||||||
}
|
|
@ -1,231 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import { useMemberStore } from '@/stores'
|
|
||||||
import type { goodsListItem } from '@/types/goods'
|
|
||||||
import { ref, reactive } from 'vue'
|
|
||||||
import { fullUrl, checkImage, getUserDefaultAvatar } from '@/utils/common'
|
|
||||||
import { getShareInfoApi } from '@/api/goods'
|
|
||||||
import { getShareUrl } from './sharePoster'
|
|
||||||
import { usePopupStore } from '@/stores'
|
|
||||||
|
|
||||||
const props = defineProps<{
|
|
||||||
goods: goodsListItem
|
|
||||||
currentPrice: string
|
|
||||||
currentOriginPrice: string
|
|
||||||
goodsImage: string
|
|
||||||
}>()
|
|
||||||
|
|
||||||
const sharePosterRef = ref()
|
|
||||||
const painter = ref()
|
|
||||||
|
|
||||||
const state = reactive({
|
|
||||||
posterImgPath: '',
|
|
||||||
showPoster: false,
|
|
||||||
userAvatarImg: useMemberStore().profile!.avatar,
|
|
||||||
qrcodeUrl: '',
|
|
||||||
})
|
|
||||||
|
|
||||||
const userImage = ref('')
|
|
||||||
const open = async () => {
|
|
||||||
userImage.value = fullUrl(state.userAvatarImg)
|
|
||||||
await checkImage(userImage.value)
|
|
||||||
.then((url) => {
|
|
||||||
userImage.value = url
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
userImage.value = getUserDefaultAvatar()
|
|
||||||
})
|
|
||||||
|
|
||||||
// #ifdef MP-WEIXIN
|
|
||||||
const shareInfo = await getShareInfoApi(props.goods.id)
|
|
||||||
state.qrcodeUrl = shareInfo.result.qrcode_url
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
await sharePosterRef.value?.open()
|
|
||||||
state.showPoster = true
|
|
||||||
state.posterImgPath = ''
|
|
||||||
await uni.showLoading({
|
|
||||||
title: '海报生成中…',
|
|
||||||
mask: true,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const close = () => {
|
|
||||||
sharePosterRef.value.close()
|
|
||||||
|
|
||||||
state.showPoster = false
|
|
||||||
}
|
|
||||||
|
|
||||||
const onDone = () => {}
|
|
||||||
|
|
||||||
const onSuccess = (imgPath: string) => {
|
|
||||||
state.posterImgPath = imgPath
|
|
||||||
uni.hideLoading()
|
|
||||||
}
|
|
||||||
|
|
||||||
const onSave = () => {
|
|
||||||
// #ifdef MP-WEIXIN
|
|
||||||
painter.value.canvasToTempFilePathSync({
|
|
||||||
fileType: 'jpg',
|
|
||||||
pathType: 'url',
|
|
||||||
quality: 1,
|
|
||||||
success: (res: any) => {
|
|
||||||
console.log(res.tempFilePath)
|
|
||||||
uni.saveImageToPhotosAlbum({
|
|
||||||
filePath: res.tempFilePath,
|
|
||||||
success: () => {
|
|
||||||
uni.showToast({
|
|
||||||
title: '保存成功',
|
|
||||||
icon: 'none',
|
|
||||||
})
|
|
||||||
},
|
|
||||||
fail: (err) => {
|
|
||||||
console.log(err)
|
|
||||||
if (err.errMsg == 'saveImageToPhotosAlbum:fail cancel') {
|
|
||||||
return uni.showToast({
|
|
||||||
title: '取消保存',
|
|
||||||
icon: 'none',
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
uni.showToast({
|
|
||||||
title: '保存失败',
|
|
||||||
icon: 'none',
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
complete: () => {
|
|
||||||
close()
|
|
||||||
},
|
|
||||||
})
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
// #endif
|
|
||||||
}
|
|
||||||
|
|
||||||
defineExpose({ sharePosterRef, open, close })
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<uni-popup
|
|
||||||
ref="sharePosterRef"
|
|
||||||
type="center"
|
|
||||||
:animation="false"
|
|
||||||
:mask-click="false"
|
|
||||||
@change="usePopupStore().onChangePopupProps"
|
|
||||||
>
|
|
||||||
<image :src="state.posterImgPath" mode="widthFix" style="width: 600rpx" />
|
|
||||||
<view>
|
|
||||||
<view class="poster">
|
|
||||||
<l-painter
|
|
||||||
ref="painter"
|
|
||||||
isCanvasToTempFilePath
|
|
||||||
@success="onSuccess"
|
|
||||||
css="width: 750rpx; padding-bottom: 40rpx; background: #edca88; object-fit: contain;"
|
|
||||||
hidden
|
|
||||||
@done="onDone"
|
|
||||||
:after-delay="500"
|
|
||||||
>
|
|
||||||
<l-painter-image
|
|
||||||
:src="userImage"
|
|
||||||
css="margin-left: 40rpx; margin-top: 40rpx; width: 100rpx; height: 100rpx; border-radius: 50%;"
|
|
||||||
/>
|
|
||||||
<l-painter-view css="margin-top: 40rpx; padding-left: 20rpx; display: inline-block">
|
|
||||||
<l-painter-text
|
|
||||||
:text="useMemberStore().profile?.nickname || ''"
|
|
||||||
css="display: block; padding-bottom: 20rpx; color: #000; font-size: 32rpx; fontWeight: bold"
|
|
||||||
/>
|
|
||||||
<l-painter-text text="推荐了一个好物给您" css="color: #000; font-size: 24rpx" />
|
|
||||||
</l-painter-view>
|
|
||||||
<l-painter-view
|
|
||||||
css="margin-left: 40rpx; margin-top: 30rpx; padding: 32rpx; box-sizing: border-box; background: #fff; border-radius: 16rpx; width: 670rpx; box-shadow: 0 20rpx 58rpx rgba(0,0,0,.15)"
|
|
||||||
>
|
|
||||||
<l-painter-image
|
|
||||||
:src="fullUrl(props.goodsImage)"
|
|
||||||
css="object-fit: fill; width: 600rpx; max-height: 550rpx; border-radius: 12rpx;"
|
|
||||||
/>
|
|
||||||
<l-painter-view
|
|
||||||
css="margin-top: 32rpx; color: #FF0000; font-weight: bold; font-size: 28rpx; line-height: 1em;"
|
|
||||||
>
|
|
||||||
<l-painter-text text="¥" css="vertical-align: bottom" />
|
|
||||||
<l-painter-text
|
|
||||||
:text="`${props.currentPrice.split('.')[0]}`"
|
|
||||||
css="vertical-align: bottom; font-size: 58rpx"
|
|
||||||
/>
|
|
||||||
<l-painter-text
|
|
||||||
:text="`.${props.currentPrice.split('.')[1]}`"
|
|
||||||
css="vertical-align: bottom"
|
|
||||||
/>
|
|
||||||
<l-painter-text
|
|
||||||
:text="`¥${props.currentOriginPrice}`"
|
|
||||||
css="vertical-align: bottom; padding-left: 10rpx; font-weight: normal; text-decoration: line-through; color: #999999"
|
|
||||||
/>
|
|
||||||
</l-painter-view>
|
|
||||||
<l-painter-view css="margin-top: 30rpx">
|
|
||||||
<l-painter-text
|
|
||||||
:text="props.goods.name"
|
|
||||||
css="line-clamp: 2; color: #333333; line-height: 1.5em; width: 620rpx; font-size: 30rpx; padding-right:32rpx; box-sizing: border-box"
|
|
||||||
></l-painter-text>
|
|
||||||
</l-painter-view>
|
|
||||||
<l-painter-view css="margin-top: 30rpx; display: flex; flex-wrap: nowrap;">
|
|
||||||
<l-painter-text
|
|
||||||
text="长按或扫一扫识别二维码"
|
|
||||||
css="float: left; padding-bottom: 10rpx; color: #999999; font-size: 26rpx; margin-top: 60rpx; margin-right: 160rpx"
|
|
||||||
/>
|
|
||||||
<!-- #ifdef MP-WEIXIN -->
|
|
||||||
<l-painter-image
|
|
||||||
v-if="state.qrcodeUrl"
|
|
||||||
:src="state.qrcodeUrl"
|
|
||||||
css="float: right; width: 150rpx; height: 150rpx;"
|
|
||||||
/>
|
|
||||||
<!-- #endif -->
|
|
||||||
<!-- #ifdef WEB -->
|
|
||||||
<l-painter-qrcode
|
|
||||||
:text="getShareUrl(props.goods.id)"
|
|
||||||
css="float: right; width: 150rpx; height: 150rpx;"
|
|
||||||
/>
|
|
||||||
<!-- #endif -->
|
|
||||||
</l-painter-view>
|
|
||||||
</l-painter-view>
|
|
||||||
</l-painter>
|
|
||||||
</view>
|
|
||||||
<view class="action" v-if="state.posterImgPath">
|
|
||||||
<view class="button cancel" @tap="close()">取消分享</view>
|
|
||||||
<!-- #ifdef WEB -->
|
|
||||||
<view>长按图片进行保存</view>
|
|
||||||
<!-- #endif -->
|
|
||||||
<!-- #ifdef MP-WEIXIN -->
|
|
||||||
<view class="button" @tap="onSave()">保存图片</view>
|
|
||||||
<!-- #endif -->
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</uni-popup>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.action {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
padding: 20rpx;
|
|
||||||
background: #f5f5f5;
|
|
||||||
|
|
||||||
.button {
|
|
||||||
padding: 16rpx 32rpx;
|
|
||||||
margin: 0 10rpx;
|
|
||||||
|
|
||||||
background: #ff784d;
|
|
||||||
color: #ffffff;
|
|
||||||
|
|
||||||
border-radius: 40rpx;
|
|
||||||
|
|
||||||
&:active {
|
|
||||||
opacity: 0.8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.cancel {
|
|
||||||
background: #b3b3b3;
|
|
||||||
color: #ffffff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,864 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import { getGoodsByIdApi } from '@/api/goods'
|
|
||||||
import { onLoad } from '@dcloudio/uni-app'
|
|
||||||
import { ref, watchEffect, reactive, computed } from 'vue'
|
|
||||||
import type { goodsResult, goodsServiceItem, skuItem } from '@/types/goods'
|
|
||||||
import type {
|
|
||||||
SkuPopupEvent,
|
|
||||||
SkuPopupInstance,
|
|
||||||
SkuPopupLocaldata,
|
|
||||||
} from '@/components/vk-data-goods-sku-popup/vk-data-goods-sku-popup'
|
|
||||||
import { addCartApi } from '@/api/cart'
|
|
||||||
import { useAddressStore } from '@/stores/modules/address'
|
|
||||||
import { previewImg, fullUrl, arrayFullUrl, onShowRefreshData } from '@/utils/common'
|
|
||||||
import { pageUrl, safeBottom, pageMateStyle, isIOSWithHomeIndicator } from '@/utils/constants'
|
|
||||||
import { useCartStore } from '@/stores'
|
|
||||||
import { postAddFavoriteApi, postCancelFavoriteApi } from '@/api/favorite'
|
|
||||||
import _, { debounce } from 'lodash'
|
|
||||||
import { onShareAppMessage } from '@dcloudio/uni-app'
|
|
||||||
import { useMemberStore } from '@/stores'
|
|
||||||
import { getAddressApi } from '@/api/address'
|
|
||||||
import type { addressItem } from '@/types/address'
|
|
||||||
import { computeConversion } from '@/utils/common'
|
|
||||||
import servicePanel from '@/pagesGoods/pages/goods/components/servicePanel.vue'
|
|
||||||
import addressPanel from '@/pagesGoods/pages/goods/components//addressPanel.vue'
|
|
||||||
import sharePanel from '@/pagesGoods/pages/goods/components/sharePanel.vue'
|
|
||||||
import sharePoster from '@/pagesGoods/pages/goods/components/sharePoster.vue'
|
|
||||||
import { usePopupStore } from '@/stores'
|
|
||||||
|
|
||||||
const props = defineProps<{
|
|
||||||
id: string | number
|
|
||||||
scene?: string
|
|
||||||
}>()
|
|
||||||
|
|
||||||
//接收参数
|
|
||||||
const query = reactive({
|
|
||||||
id: props.id,
|
|
||||||
scene: props.scene,
|
|
||||||
})
|
|
||||||
|
|
||||||
const cartStore = useCartStore()
|
|
||||||
|
|
||||||
//商品sku弹窗
|
|
||||||
const isShowSku = ref(false)
|
|
||||||
//商品sku数据
|
|
||||||
const skuData = ref({} as SkuPopupLocaldata)
|
|
||||||
//sku按钮模式
|
|
||||||
enum skuskuModeType {
|
|
||||||
both = 1,
|
|
||||||
cart = 2,
|
|
||||||
buy = 3,
|
|
||||||
}
|
|
||||||
const skuMode = ref<skuskuModeType>(skuskuModeType.both)
|
|
||||||
//sku弹窗ref实例
|
|
||||||
const skuPopupRef = ref<SkuPopupInstance>()
|
|
||||||
//sku中被选中的值
|
|
||||||
const selectAttrText = computed(() => {
|
|
||||||
return skuPopupRef.value?.selectArr?.join(' ').trim() || '请选择商品规格'
|
|
||||||
})
|
|
||||||
// 计算当前显示的价格
|
|
||||||
const selectedPrice = ref(0)
|
|
||||||
const currentPrice = computed(() => selectedPrice.value || goods.value?.min_price || 0)
|
|
||||||
// 计算当前显示的划线价
|
|
||||||
const selectedOriginPrice = ref(0)
|
|
||||||
const currentOriginPrice = computed(
|
|
||||||
() => selectedOriginPrice.value || goods.value?.max_origin_price || 0,
|
|
||||||
)
|
|
||||||
|
|
||||||
//打开sku弹窗
|
|
||||||
const openSkuPopup = (mode: skuskuModeType) => {
|
|
||||||
isShowSku.value = true
|
|
||||||
skuMode.value = mode
|
|
||||||
}
|
|
||||||
|
|
||||||
const goodsServiceList = ref<goodsServiceItem[]>([])
|
|
||||||
const goodsServiceText = ref('')
|
|
||||||
//商品详情
|
|
||||||
const goods = ref<goodsResult>()
|
|
||||||
const getGoodsDataById = async () => {
|
|
||||||
const res = await getGoodsByIdApi(Number(query.id))
|
|
||||||
goods.value = res.result
|
|
||||||
|
|
||||||
//设置sku组件所需数据
|
|
||||||
skuData.value = {
|
|
||||||
_id: res.result.id.toString(),
|
|
||||||
name: res.result.name,
|
|
||||||
goods_thumb: fullUrl(res.result.images[0]),
|
|
||||||
spec_list: res.result.spec_list.map((spec) => {
|
|
||||||
return {
|
|
||||||
name: spec.name,
|
|
||||||
list: spec.value,
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
sku_list: res.result.sku_list.map((sku) => {
|
|
||||||
return {
|
|
||||||
_id: sku.id.toString(),
|
|
||||||
goods_id: res.result.id.toString(),
|
|
||||||
goods_name: res.result.name,
|
|
||||||
image: fullUrl(sku.image),
|
|
||||||
price: sku.price,
|
|
||||||
origin_price: sku.origin_price,
|
|
||||||
sku_name_arr: sku.spec?.map((sku_name) => sku_name.value),
|
|
||||||
stock: sku.stock,
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
|
|
||||||
//服务与承诺
|
|
||||||
goodsServiceList.value = goods.value.goods_service
|
|
||||||
goodsServiceText.value = goods.value.goods_service.map((item) => item.name).join(' ')
|
|
||||||
}
|
|
||||||
|
|
||||||
//更新轮播图下标
|
|
||||||
const currentIndex = ref(0)
|
|
||||||
const updateIndex: UniHelper.SwiperOnChange = (event) => {
|
|
||||||
currentIndex.value = event.detail.current
|
|
||||||
}
|
|
||||||
//弹出层ref
|
|
||||||
const popup = ref<{
|
|
||||||
open: (type?: UniHelper.UniPopupType) => void
|
|
||||||
close: () => void
|
|
||||||
}>()
|
|
||||||
//调用弹出层
|
|
||||||
const popupName = ref<'address' | 'service' | 'share' | 'sharePoster'>()
|
|
||||||
const openPopup = (name: typeof popupName.value) => {
|
|
||||||
popupName.value = name
|
|
||||||
popup.value?.open()
|
|
||||||
}
|
|
||||||
|
|
||||||
//添加购物车
|
|
||||||
const onAddCart = (event: SkuPopupEvent) => {
|
|
||||||
addCartApi({
|
|
||||||
sku_id: event._id,
|
|
||||||
num: event.buy_num,
|
|
||||||
}).then((res) => {
|
|
||||||
cartStore.setCartTotalNum(res.result.total_num)
|
|
||||||
cartInfo.value = res.result.total_num
|
|
||||||
isShowSku.value = false
|
|
||||||
uni.showToast({
|
|
||||||
title: '加入购物车成功',
|
|
||||||
icon: 'success',
|
|
||||||
mask: true,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
//跳转下单页
|
|
||||||
const onBuyNow = (event: SkuPopupEvent) => {
|
|
||||||
console.log(event)
|
|
||||||
isShowSku.value = false
|
|
||||||
uni.navigateTo({
|
|
||||||
url: `${pageUrl['order-create']}?sku_id=${event._id}&count=${event.buy_num}`,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
//规格选择后处理
|
|
||||||
const onSpecSelected = (skuData: skuItem) => {
|
|
||||||
selectedPrice.value = skuData.price
|
|
||||||
selectedOriginPrice.value = skuData.origin_price
|
|
||||||
}
|
|
||||||
|
|
||||||
// 收货地址
|
|
||||||
const addressStore = useAddressStore()
|
|
||||||
const selectAddressText = computed(() => {
|
|
||||||
return addressStore.selectedAddress
|
|
||||||
? addressStore.selectedAddress.full_location
|
|
||||||
: '请选择收货地址'
|
|
||||||
})
|
|
||||||
|
|
||||||
const addressList = ref<addressItem[]>([])
|
|
||||||
const openAddressPopup = () => {
|
|
||||||
getAddressApi().then((res) => {
|
|
||||||
addressList.value = res.result.data
|
|
||||||
openPopup('address')
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const getMoreEvaluate = () => {
|
|
||||||
uni.navigateTo({
|
|
||||||
url: `${pageUrl['goods-evaluate']}?goods_id=${query.id}`,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const cartInfo = ref(0)
|
|
||||||
const menuButtons = computed<UniHelper.UniGoodsNavOption[]>(() => [
|
|
||||||
{
|
|
||||||
icon: 'shop',
|
|
||||||
text: '首页',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: 'cart',
|
|
||||||
text: '购物车',
|
|
||||||
info: cartInfo.value,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: 'redo',
|
|
||||||
text: '分享',
|
|
||||||
},
|
|
||||||
])
|
|
||||||
const menuClick = (event: UniHelper.UniGoodsNavOnClickEvent) => {
|
|
||||||
switch (event.index) {
|
|
||||||
case 0:
|
|
||||||
uni.switchTab({
|
|
||||||
url: `${pageUrl['index']}`,
|
|
||||||
})
|
|
||||||
break
|
|
||||||
case 1:
|
|
||||||
uni.switchTab({
|
|
||||||
url: `${pageUrl['cart']}`,
|
|
||||||
})
|
|
||||||
break
|
|
||||||
case 2:
|
|
||||||
showSharePopup()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const operateButtons: UniHelper.UniGoodsNavButton[] = [
|
|
||||||
{
|
|
||||||
text: '加入购物车',
|
|
||||||
backgroundColor: '#ffa200',
|
|
||||||
color: '#fff',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: '立即购买',
|
|
||||||
backgroundColor: '#ff0000',
|
|
||||||
color: '#fff',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
const buttonClick = (event: UniHelper.UniGoodsNavOnButtonClickEvent) => {
|
|
||||||
switch (event.index) {
|
|
||||||
case 0:
|
|
||||||
openSkuPopup(skuskuModeType.cart)
|
|
||||||
break
|
|
||||||
case 1:
|
|
||||||
openSkuPopup(skuskuModeType.buy)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const changeFavoriteStatus = debounce((goods) => {
|
|
||||||
if (goods.favorite === true) {
|
|
||||||
postCancelFavoriteApi({
|
|
||||||
goods_id: goods.id,
|
|
||||||
}).then((res) => {
|
|
||||||
if (res.result) {
|
|
||||||
goods.favorite = false
|
|
||||||
uni.showToast({
|
|
||||||
title: '商品取消收藏',
|
|
||||||
icon: 'none',
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
postAddFavoriteApi({
|
|
||||||
goods_id: goods.id,
|
|
||||||
})
|
|
||||||
.then((res) => {
|
|
||||||
if (res.result) {
|
|
||||||
goods.favorite = true
|
|
||||||
uni.showToast({
|
|
||||||
title: '商品收藏成功',
|
|
||||||
icon: 'none',
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
console.log(err)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}, 500)
|
|
||||||
|
|
||||||
watchEffect(() => {
|
|
||||||
cartInfo.value = useCartStore().cartTotalNum
|
|
||||||
})
|
|
||||||
|
|
||||||
const sharePopupRef = ref()
|
|
||||||
// 分享弹窗
|
|
||||||
const showSharePopup = () => {
|
|
||||||
if (!useMemberStore().profile?.id) {
|
|
||||||
return uni.showModal({
|
|
||||||
title: '温馨提示',
|
|
||||||
content: '登录解锁更多精彩,是否继续?',
|
|
||||||
confirmText: '去登录',
|
|
||||||
cancelText: '再看看',
|
|
||||||
success: function (res) {
|
|
||||||
if (res.confirm) {
|
|
||||||
uni.navigateTo({ url: pageUrl['login'] })
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
openPopup('share')
|
|
||||||
}
|
|
||||||
|
|
||||||
const sharePosterRef = ref()
|
|
||||||
const goodsImage = ref('')
|
|
||||||
const onShowPoster = () => {
|
|
||||||
sharePosterRef.value.open()
|
|
||||||
goodsImage.value = goods.value!.images[currentIndex.value] || goods.value!.images[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
onShareAppMessage(() => {
|
|
||||||
sharePopupRef.value.close()
|
|
||||||
|
|
||||||
const sharePath = `${pageUrl['goods-detail']}?id=${goods.value?.id}&sharer=${
|
|
||||||
useMemberStore().profile?.id
|
|
||||||
}`
|
|
||||||
console.log(sharePath)
|
|
||||||
|
|
||||||
return {
|
|
||||||
title: goods.value?.name,
|
|
||||||
path: sharePath,
|
|
||||||
imageUrl: fullUrl(goods.value!.images[0]),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
onShowRefreshData(() => {
|
|
||||||
if (props.scene) {
|
|
||||||
const params = decodeURIComponent(props.scene)
|
|
||||||
.split('&')
|
|
||||||
.reduce((acc: { [key: string]: any }, curr) => {
|
|
||||||
const [key, value] = curr.split('=')
|
|
||||||
acc[key] = value
|
|
||||||
return acc
|
|
||||||
}, {})
|
|
||||||
console.log('解析scene', params)
|
|
||||||
if (params.id) {
|
|
||||||
query.id = params.id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getGoodsDataById()
|
|
||||||
})
|
|
||||||
|
|
||||||
onLoad(() => {
|
|
||||||
// #ifdef WEB
|
|
||||||
// 兼容带有底部导航的IOS设备
|
|
||||||
if (isIOSWithHomeIndicator()) {
|
|
||||||
document.documentElement.classList.add('ios-device')
|
|
||||||
}
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
// #ifdef MP-WEIXIN
|
|
||||||
uni.showShareMenu({
|
|
||||||
withShareTicket: true,
|
|
||||||
menus: ['shareAppMessage'],
|
|
||||||
})
|
|
||||||
// #endif
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<!-- #ifdef MP-WEIXIN -->
|
|
||||||
<page-meta :page-style="pageMateStyle">
|
|
||||||
<!-- #endif -->
|
|
||||||
<scroll-view scroll-y class="viewport" :style="safeBottom" v-if="goods">
|
|
||||||
<!-- 基本信息 -->
|
|
||||||
<view class="goods">
|
|
||||||
<!-- 商品主图 -->
|
|
||||||
<view class="preview">
|
|
||||||
<swiper circular @change="updateIndex" autoplay>
|
|
||||||
<swiper-item v-for="item in goods?.images" :key="item">
|
|
||||||
<image
|
|
||||||
class="image"
|
|
||||||
:src="fullUrl(item)"
|
|
||||||
@tap="previewImg(item, arrayFullUrl(goods!.images))"
|
|
||||||
/>
|
|
||||||
</swiper-item>
|
|
||||||
</swiper>
|
|
||||||
<view class="indicator">
|
|
||||||
<text class="current">{{ currentIndex + 1 }}</text>
|
|
||||||
<text class="split">/</text>
|
|
||||||
<text class="total">{{ goods?.images.length }}</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="panel">
|
|
||||||
<view class="meta">
|
|
||||||
<view class="meta-top">
|
|
||||||
<view class="price">
|
|
||||||
<view class="origin">¥{{ currentOriginPrice }} </view>
|
|
||||||
<view class="current">
|
|
||||||
<text class="symbol">¥</text>
|
|
||||||
<text class="number">{{ currentPrice }}</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="operate">
|
|
||||||
<view class="operate-item" @tap="changeFavoriteStatus(goods!)" v-if="goods.favorite">
|
|
||||||
<button class="operate-item-btn">
|
|
||||||
<text class="icon icon-favorite-checked" />
|
|
||||||
</button>
|
|
||||||
<text class="icon-text">已收藏</text>
|
|
||||||
</view>
|
|
||||||
<view class="operate-item" @tap="changeFavoriteStatus(goods!)" v-else>
|
|
||||||
<button class="operate-item-btn">
|
|
||||||
<text class="icon icon-favorite-default" />
|
|
||||||
</button>
|
|
||||||
<text class="icon-text">收藏</text>
|
|
||||||
</view>
|
|
||||||
<!-- #ifdef MP-WEIXIN -->
|
|
||||||
<view class="operate-item">
|
|
||||||
<button open-type="contact" class="operate-item-btn">
|
|
||||||
<text class="icon-handset"></text>
|
|
||||||
</button>
|
|
||||||
<view class="icon-text">
|
|
||||||
<text>客服</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<!-- #endif -->
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="name-box">
|
|
||||||
<view class="name ellipsis">{{ goods?.name }} </view>
|
|
||||||
<view class="sales">
|
|
||||||
已售{{ computeConversion(goods.sales_init + goods.sales_real) }}</view
|
|
||||||
>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="panel">
|
|
||||||
<view class="action">
|
|
||||||
<view class="item arrow" @tap="openSkuPopup(skuskuModeType.both)">
|
|
||||||
<text class="label">已选</text>
|
|
||||||
<text class="text ellipsis">{{ selectAttrText }}</text>
|
|
||||||
</view>
|
|
||||||
<view class="item arrow" @tap="openAddressPopup">
|
|
||||||
<text class="label">送至</text>
|
|
||||||
<text class="text ellipsis">{{ selectAddressText }}</text>
|
|
||||||
</view>
|
|
||||||
<view class="item arrow" @tap="openPopup('service')">
|
|
||||||
<text class="label">服务</text>
|
|
||||||
<text class="text ellipsis">{{ goodsServiceText }}</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<!-- 弹出层 -->
|
|
||||||
<uni-popup
|
|
||||||
ref="popup"
|
|
||||||
type="bottom"
|
|
||||||
background-color="#fff"
|
|
||||||
@change="usePopupStore().onChangePopupProps"
|
|
||||||
>
|
|
||||||
<address-panel
|
|
||||||
v-if="popupName === 'address'"
|
|
||||||
@close="popup?.close()"
|
|
||||||
:list="addressList"
|
|
||||||
/>
|
|
||||||
<service-panel
|
|
||||||
v-if="popupName === 'service'"
|
|
||||||
:list="goodsServiceList"
|
|
||||||
@close="popup?.close()"
|
|
||||||
/>
|
|
||||||
<share-panel
|
|
||||||
v-if="popupName === 'share'"
|
|
||||||
@close="popup?.close()"
|
|
||||||
@showPoster="onShowPoster"
|
|
||||||
:goods="goods"
|
|
||||||
/>
|
|
||||||
</uni-popup>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 商品评价 -->
|
|
||||||
<view class="panel">
|
|
||||||
<view v-if="goods?.evaluate_count > 0" @click="getMoreEvaluate">
|
|
||||||
<uni-section :title="`评价 (${computeConversion(goods?.evaluate_count)})`" type="line">
|
|
||||||
<template #right>
|
|
||||||
<view class="tip">
|
|
||||||
<text> 好评率 {{ goods?.positive_rate }}%</text>
|
|
||||||
<uni-icons type="forward" size="14" color="#909399" class="icon"></uni-icons>
|
|
||||||
</view>
|
|
||||||
</template>
|
|
||||||
<view class="eva-box" v-for="(evaluate, index) in goods?.evaluate" :key="index">
|
|
||||||
<view class="top">
|
|
||||||
<shop-user-avatar
|
|
||||||
:url="evaluate.user_avatar"
|
|
||||||
width="50"
|
|
||||||
style="padding-right: 10rpx"
|
|
||||||
/>
|
|
||||||
<text class="name">{{ evaluate.user_name }}</text>
|
|
||||||
<view class="rate">
|
|
||||||
<uni-rate :value="evaluate.score" :size="20" readonly />
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<text class="content">{{ evaluate.content }}</text>
|
|
||||||
<scroll-view class="scroll-view-container" :scroll-x="true">
|
|
||||||
<image
|
|
||||||
class="content-img"
|
|
||||||
mode="aspectFill"
|
|
||||||
v-for="(item, index) in arrayFullUrl(evaluate.images)"
|
|
||||||
:key="index"
|
|
||||||
:src="item"
|
|
||||||
@click.stop="previewImg(item, evaluate.images)"
|
|
||||||
/>
|
|
||||||
</scroll-view>
|
|
||||||
<view class="bot"> </view>
|
|
||||||
</view>
|
|
||||||
</uni-section>
|
|
||||||
</view>
|
|
||||||
<view v-else>
|
|
||||||
<uni-section title="评价 (0)" type="line">
|
|
||||||
<z-paging-empty-view empty-view-text="期待您的评价" :empty-view-fixed="false" />
|
|
||||||
</uni-section>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="panel">
|
|
||||||
<uni-section title="详情" type="line">
|
|
||||||
<view class="properties">
|
|
||||||
<view class="item" v-for="item in goods?.params" :key="item.key">
|
|
||||||
<text class="label">{{ item.key }}</text>
|
|
||||||
<text class="value">{{ item.value }}</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</uni-section>
|
|
||||||
<view v-if="goods.detail_images.length > 0">
|
|
||||||
<shop-image :src="goods?.detail_images" />
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view :style="{ paddingBottom: '5rpx' }"> </view>
|
|
||||||
|
|
||||||
<!-- sku弹窗 -->
|
|
||||||
<vk-data-goods-sku-popup
|
|
||||||
v-model="isShowSku"
|
|
||||||
:localdata="skuData"
|
|
||||||
:mode="skuMode"
|
|
||||||
buy-now-background-color="#ff0000"
|
|
||||||
add-cart-background-color="#ffa200"
|
|
||||||
:amountType="0"
|
|
||||||
ref="skuPopupRef"
|
|
||||||
:actived-style="{
|
|
||||||
color: '#ff0000',
|
|
||||||
backgroundColor: '#fee8e6',
|
|
||||||
borderColor: '#ff0000',
|
|
||||||
}"
|
|
||||||
@add-cart="onAddCart"
|
|
||||||
@buy-now="onBuyNow"
|
|
||||||
@spec-selected="onSpecSelected"
|
|
||||||
class="sku-popup"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<!-- 海报弹窗 -->
|
|
||||||
<sharePoster
|
|
||||||
ref="sharePosterRef"
|
|
||||||
:goods="goods"
|
|
||||||
:currentPrice="currentPrice"
|
|
||||||
:currentOriginPrice="currentOriginPrice"
|
|
||||||
:goodsImage="goodsImage"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<!-- 用户操作 -->
|
|
||||||
<view class="goods-nav" :style="safeBottom" v-show="goods">
|
|
||||||
<uni-goods-nav
|
|
||||||
:fill="true"
|
|
||||||
:options="menuButtons"
|
|
||||||
:buttonGroup="operateButtons"
|
|
||||||
@click="menuClick"
|
|
||||||
@buttonClick="buttonClick"
|
|
||||||
/>
|
|
||||||
</view>
|
|
||||||
</scroll-view>
|
|
||||||
<!-- #ifdef MP-WEIXIN -->
|
|
||||||
</page-meta>
|
|
||||||
<!-- #endif -->
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
swiper {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
page {
|
|
||||||
height: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.viewport {
|
|
||||||
background-color: #f4f4f4;
|
|
||||||
z-index: 999;
|
|
||||||
margin-bottom: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.panel {
|
|
||||||
background-color: #fff;
|
|
||||||
border-radius: 10rpx;
|
|
||||||
margin: 15rpx 15rpx 20rpx;
|
|
||||||
padding: 10rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.arrow {
|
|
||||||
&::after {
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
right: 30rpx;
|
|
||||||
content: '\e6c2';
|
|
||||||
color: #ccc;
|
|
||||||
font-family: 'iconfont' !important;
|
|
||||||
font-size: 32rpx;
|
|
||||||
transform: translateY(-50%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 商品信息 */
|
|
||||||
.goods {
|
|
||||||
background-color: #fff;
|
|
||||||
margin: 15rpx 15rpx 20rpx;
|
|
||||||
|
|
||||||
.preview {
|
|
||||||
height: 750rpx;
|
|
||||||
position: relative;
|
|
||||||
.image {
|
|
||||||
width: 750rpx;
|
|
||||||
height: 750rpx;
|
|
||||||
}
|
|
||||||
.indicator {
|
|
||||||
height: 40rpx;
|
|
||||||
padding: 0 24rpx;
|
|
||||||
line-height: 40rpx;
|
|
||||||
border-radius: 30rpx;
|
|
||||||
color: #fff;
|
|
||||||
font-family: Arial, Helvetica, sans-serif;
|
|
||||||
background-color: rgba(0, 0, 0, 0.3);
|
|
||||||
position: absolute;
|
|
||||||
bottom: 30rpx;
|
|
||||||
right: 30rpx;
|
|
||||||
.current {
|
|
||||||
font-size: 26rpx;
|
|
||||||
}
|
|
||||||
.split {
|
|
||||||
font-size: 24rpx;
|
|
||||||
margin: 0 1rpx 0 2rpx;
|
|
||||||
}
|
|
||||||
.total {
|
|
||||||
font-size: 24rpx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.meta {
|
|
||||||
.meta-top {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
|
|
||||||
.operate {
|
|
||||||
display: flex;
|
|
||||||
|
|
||||||
.operate-item {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
.operate-item-btn {
|
|
||||||
width: 80rpx;
|
|
||||||
height: 80rpx;
|
|
||||||
background-color: transparent;
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon-text {
|
|
||||||
font-size: 20rpx;
|
|
||||||
color: #9a9a9a;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon-favorite-checked {
|
|
||||||
color: red;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.price {
|
|
||||||
height: 130rpx;
|
|
||||||
padding: 0rpx 20rpx;
|
|
||||||
color: red;
|
|
||||||
font-size: 34rpx;
|
|
||||||
box-sizing: border-box;
|
|
||||||
background-color: #fff;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
.origin {
|
|
||||||
margin-top: 15rpx;
|
|
||||||
color: #888;
|
|
||||||
text-decoration: line-through;
|
|
||||||
|
|
||||||
::after {
|
|
||||||
content: ¥;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.number {
|
|
||||||
font-size: 50rpx;
|
|
||||||
}
|
|
||||||
.brand {
|
|
||||||
width: 160rpx;
|
|
||||||
height: 80rpx;
|
|
||||||
overflow: hidden;
|
|
||||||
position: absolute;
|
|
||||||
top: 26rpx;
|
|
||||||
right: 30rpx;
|
|
||||||
}
|
|
||||||
.name {
|
|
||||||
max-height: 88rpx;
|
|
||||||
line-height: 1.4;
|
|
||||||
margin: 20rpx;
|
|
||||||
font-size: 32rpx;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
.desc {
|
|
||||||
line-height: 1;
|
|
||||||
padding: 0 20rpx 30rpx;
|
|
||||||
font-size: 24rpx;
|
|
||||||
color: #cf4444;
|
|
||||||
}
|
|
||||||
.sales {
|
|
||||||
margin: 20rpx;
|
|
||||||
font-size: 24rpx;
|
|
||||||
color: #888;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.action {
|
|
||||||
padding-left: 10rpx;
|
|
||||||
background: #fff;
|
|
||||||
|
|
||||||
.item {
|
|
||||||
height: 90rpx;
|
|
||||||
padding-right: 60rpx;
|
|
||||||
border-bottom: 1rpx solid #eaeaea;
|
|
||||||
font-size: 26rpx;
|
|
||||||
color: #333;
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
&:last-child {
|
|
||||||
border-bottom: 0 none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.label {
|
|
||||||
width: 60rpx;
|
|
||||||
color: #898b94;
|
|
||||||
margin: 0 16rpx 0 10rpx;
|
|
||||||
}
|
|
||||||
.text {
|
|
||||||
flex: 1;
|
|
||||||
-webkit-line-clamp: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.tip {
|
|
||||||
font-size: 24rpx;
|
|
||||||
color: #9a9a9a;
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
padding-left: 10rpx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.eva-box {
|
|
||||||
padding: 10rpx;
|
|
||||||
|
|
||||||
.top {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
padding-bottom: 20rpx;
|
|
||||||
|
|
||||||
.name {
|
|
||||||
flex: 1;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
font-size: 26rpx;
|
|
||||||
padding-bottom: 10rpx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.rate {
|
|
||||||
margin-right: 10rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
|
||||||
margin: 0rpx 10rpx 10rpx;
|
|
||||||
max-height: 100rpx;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
display: -webkit-box;
|
|
||||||
-webkit-line-clamp: 2;
|
|
||||||
-webkit-box-orient: vertical;
|
|
||||||
font-size: 24rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.scroll-view-container {
|
|
||||||
width: 100%;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow-x: scroll;
|
|
||||||
-webkit-overflow-scrolling: touch;
|
|
||||||
|
|
||||||
.content-img {
|
|
||||||
margin-left: 10rpx;
|
|
||||||
height: 150rpx;
|
|
||||||
width: 150rpx;
|
|
||||||
margin-bottom: 10rpx;
|
|
||||||
margin-right: 10rpx;
|
|
||||||
border-radius: 10rpx;
|
|
||||||
margin-top: 10rpx;
|
|
||||||
scroll-snap-align: start;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.properties {
|
|
||||||
padding: 0 20rpx;
|
|
||||||
|
|
||||||
.item {
|
|
||||||
display: flex;
|
|
||||||
line-height: 2;
|
|
||||||
padding: 10rpx;
|
|
||||||
font-size: 26rpx;
|
|
||||||
color: #333;
|
|
||||||
border-bottom: 1rpx dashed #ccc;
|
|
||||||
}
|
|
||||||
.label {
|
|
||||||
width: 200rpx;
|
|
||||||
}
|
|
||||||
.value {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 底部工具栏 */
|
|
||||||
.goods-nav {
|
|
||||||
position: fixed;
|
|
||||||
bottom: 0;
|
|
||||||
width: 100%;
|
|
||||||
background-color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* #ifdef WEB */
|
|
||||||
// 当根元素有 ios-device 类时,兼容底部样式
|
|
||||||
.ios-device {
|
|
||||||
.viewport {
|
|
||||||
padding-bottom: 34px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.goods-nav {
|
|
||||||
padding-bottom: 34px !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* #endif */
|
|
||||||
</style>
|
|
@ -1,107 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import { reactive, ref } from 'vue'
|
|
||||||
import type { shopGoodsListInsatnce } from '@/types/component'
|
|
||||||
|
|
||||||
//接收参数
|
|
||||||
const props = withDefaults(
|
|
||||||
defineProps<{
|
|
||||||
classify_id?: string
|
|
||||||
name?: string
|
|
||||||
coupon_id?: string
|
|
||||||
empty_text?: string
|
|
||||||
}>(),
|
|
||||||
{
|
|
||||||
classify_id: '',
|
|
||||||
name: '',
|
|
||||||
coupon_id: '',
|
|
||||||
empty_text: '暂无商品数据',
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
const query = reactive({
|
|
||||||
classify_id: props.classify_id,
|
|
||||||
name: props.name,
|
|
||||||
coupon_id: props.coupon_id,
|
|
||||||
sort_field: '',
|
|
||||||
sort_by: '',
|
|
||||||
})
|
|
||||||
|
|
||||||
const shopGoodsListRef = ref<shopGoodsListInsatnce>()
|
|
||||||
|
|
||||||
const queryOptions = ref([
|
|
||||||
{ title: '综合排序', value: 'all', type: 'click' },
|
|
||||||
{ title: '销量优先', value: 'sales', type: 'click' },
|
|
||||||
{
|
|
||||||
title: '价格排序',
|
|
||||||
value: '',
|
|
||||||
type: 'sort',
|
|
||||||
options: [{ value: 'asc' }, { value: 'desc' }],
|
|
||||||
},
|
|
||||||
])
|
|
||||||
|
|
||||||
const onChange = (data: any, index: number) => {
|
|
||||||
console.log(data, index)
|
|
||||||
}
|
|
||||||
const onConfirm = (data: any) => {
|
|
||||||
const { value, type } = data
|
|
||||||
if (value === 'all') {
|
|
||||||
Object.assign(query, { sort_field: data.value })
|
|
||||||
} else if (value === 'sales') {
|
|
||||||
Object.assign(query, { sort_field: data.value, sort_by: 'desc' })
|
|
||||||
} else if (type === 'sort') {
|
|
||||||
Object.assign(query, { sort_field: 'price', sort_by: value })
|
|
||||||
}
|
|
||||||
|
|
||||||
shopGoodsListRef.value?.reload()
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<shop-goods-list
|
|
||||||
:query="query"
|
|
||||||
:safe-area-inset-bottom="true"
|
|
||||||
ref="shopGoodsListRef"
|
|
||||||
:options="{
|
|
||||||
emptyViewText: empty_text,
|
|
||||||
backGroundColor: '#fff',
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
<template #top>
|
|
||||||
<view v-if="query">
|
|
||||||
<le-dropdown
|
|
||||||
v-model:menuList="queryOptions"
|
|
||||||
themeColor="#3185FF"
|
|
||||||
:duration="300"
|
|
||||||
:isCeiling="false"
|
|
||||||
@onConfirm="onConfirm"
|
|
||||||
@onChange="onChange"
|
|
||||||
></le-dropdown>
|
|
||||||
</view>
|
|
||||||
</template>
|
|
||||||
</shop-goods-list>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
page {
|
|
||||||
background-color: #ececec;
|
|
||||||
}
|
|
||||||
.toolbar {
|
|
||||||
position: fixed;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
z-index: 1;
|
|
||||||
background-color: #fff;
|
|
||||||
height: 100rpx;
|
|
||||||
padding: 0 20rpx var(--window-bottom);
|
|
||||||
border-top: 1rpx solid #eaeaea;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
box-sizing: content-box;
|
|
||||||
}
|
|
||||||
// 底部占位空盒子
|
|
||||||
.toolbar-height {
|
|
||||||
height: 190rpx;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,147 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import { pageUrl } from '@/utils/constants'
|
|
||||||
import { ref } from 'vue'
|
|
||||||
|
|
||||||
let name = ref('')
|
|
||||||
|
|
||||||
const history = ref<string[]>(uni.getStorageSync('search') || [])
|
|
||||||
|
|
||||||
const storeHistroy = () => {
|
|
||||||
name.value = name.value.trim()
|
|
||||||
if (name.value == '') return
|
|
||||||
// 缓存搜索关键词
|
|
||||||
const index = history.value.findIndex((item) => item === name.value)
|
|
||||||
if (index !== -1) {
|
|
||||||
history.value.splice(index, 1)
|
|
||||||
}
|
|
||||||
history.value.unshift(name.value)
|
|
||||||
uni.setStorageSync('search', history.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
const search = async () => {
|
|
||||||
await uni.navigateTo({
|
|
||||||
url: `${pageUrl['goods-list']}?name=${name.value}`,
|
|
||||||
})
|
|
||||||
storeHistroy()
|
|
||||||
}
|
|
||||||
|
|
||||||
const onTapHistory = async (keyword: string) => {
|
|
||||||
await uni.navigateTo({
|
|
||||||
url: `${pageUrl['goods-list']}?name=${keyword}`,
|
|
||||||
})
|
|
||||||
name.value = keyword
|
|
||||||
storeHistroy()
|
|
||||||
}
|
|
||||||
|
|
||||||
const onCancel = () => {
|
|
||||||
uni.navigateBack()
|
|
||||||
}
|
|
||||||
|
|
||||||
const onClearHistory = () => {
|
|
||||||
uni.showModal({
|
|
||||||
title: '',
|
|
||||||
content: '确定要清空历史搜索吗',
|
|
||||||
showCancel: true,
|
|
||||||
success: ({ confirm, cancel }) => {
|
|
||||||
if (confirm) {
|
|
||||||
uni.removeStorageSync('search')
|
|
||||||
history.value = []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const onDeleteHistory = (name: string) => {
|
|
||||||
uni.showModal({
|
|
||||||
title: '',
|
|
||||||
content: '确定要删除该条历史搜索吗',
|
|
||||||
showCancel: true,
|
|
||||||
success: ({ confirm, cancel }) => {
|
|
||||||
if (confirm) {
|
|
||||||
const index = history.value.findIndex((item) => item === name)
|
|
||||||
if (index !== -1) {
|
|
||||||
history.value.splice(index, 1)
|
|
||||||
uni.setStorageSync('search', history.value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<view class="search">
|
|
||||||
<uni-search-bar
|
|
||||||
@confirm="search"
|
|
||||||
:focus="true"
|
|
||||||
v-model="name"
|
|
||||||
radius="100"
|
|
||||||
@cancel="onCancel"
|
|
||||||
/>
|
|
||||||
</view>
|
|
||||||
<view class="search-history">
|
|
||||||
<text>历史搜索</text>
|
|
||||||
<view class="trash">
|
|
||||||
<uni-icons type="trash" color="" size="24" @tap="onClearHistory" />
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="keyword">
|
|
||||||
<button
|
|
||||||
v-for="(item, index) in history"
|
|
||||||
:key="index"
|
|
||||||
@tap="onTapHistory(item)"
|
|
||||||
class="keyword-button"
|
|
||||||
aria-readonly
|
|
||||||
@longtap="onDeleteHistory(item)"
|
|
||||||
>
|
|
||||||
{{ item }}
|
|
||||||
</button>
|
|
||||||
</view>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
page {
|
|
||||||
padding-left: 20rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search {
|
|
||||||
padding-right: 20rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-history {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
margin-top: 10px;
|
|
||||||
font-size: 14px;
|
|
||||||
|
|
||||||
.trash {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
margin-right: 50rpx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.keyword {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
margin-top: 20px;
|
|
||||||
float: left;
|
|
||||||
|
|
||||||
button {
|
|
||||||
background-color: #f2f2f2;
|
|
||||||
border-radius: 25rpx;
|
|
||||||
color: #333333;
|
|
||||||
font-size: 24rpx;
|
|
||||||
align-items: center;
|
|
||||||
margin: 0 10rpx 15rpx 15rpx;
|
|
||||||
justify-content: flex-start;
|
|
||||||
// padding-left: 10px;
|
|
||||||
display: flex;
|
|
||||||
|
|
||||||
.delete-icon {
|
|
||||||
margin-left: 5px;
|
|
||||||
margin-right: -10rpx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,40 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import { pageUrl } from '@/utils/constants'
|
|
||||||
|
|
||||||
const pageList = [
|
|
||||||
{
|
|
||||||
title: '商城订单',
|
|
||||||
icon: 'icon-shop-order',
|
|
||||||
to: `${pageUrl['order-list']}`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '充值订单',
|
|
||||||
icon: 'icon-recharge-order',
|
|
||||||
to: `${pageUrl['recharge-order-list']}`,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
</script>
|
|
||||||
<template>
|
|
||||||
<uni-list class="list">
|
|
||||||
<uni-list-item
|
|
||||||
class="item"
|
|
||||||
v-for="(item, index) in pageList"
|
|
||||||
:key="index"
|
|
||||||
showArrow
|
|
||||||
:title="item.title"
|
|
||||||
:to="item.to"
|
|
||||||
>
|
|
||||||
<template #header>
|
|
||||||
<text class="icon" :class="item.icon"></text>
|
|
||||||
</template>
|
|
||||||
</uni-list-item>
|
|
||||||
</uni-list>
|
|
||||||
</template>
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.item {
|
|
||||||
line-height: 2em;
|
|
||||||
}
|
|
||||||
.icon {
|
|
||||||
margin-right: 20rpx;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,612 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import { fullUrl } from '@/utils/common'
|
|
||||||
import { orderType, pageUrl, safeBottom, pageMateStyle } from '@/utils/constants'
|
|
||||||
import {
|
|
||||||
getCartOrderPreApi,
|
|
||||||
getOrderPreApi,
|
|
||||||
getRepurchaseOrderPreByOrderIdApi,
|
|
||||||
postOrderApi,
|
|
||||||
} from '@/api/order'
|
|
||||||
import { useAddressStore } from '@/stores/modules/address'
|
|
||||||
import type { orderPreResult } from '@/types/order'
|
|
||||||
import { onShow } from '@dcloudio/uni-app'
|
|
||||||
import { computed, ref } from 'vue'
|
|
||||||
import shopCoupon from '@/components/shop-coupon/shop-coupon.vue'
|
|
||||||
import type { couponListItem } from '@/types/coupon'
|
|
||||||
import { debounce } from 'lodash'
|
|
||||||
import { usePopupStore } from '@/stores/modules/popup'
|
|
||||||
import type { InputNumberBoxEvent } from '@/components/vk-data-input-number-box/vk-data-input-number-box'
|
|
||||||
|
|
||||||
//获取地址store
|
|
||||||
const addressStore = useAddressStore()
|
|
||||||
addressStore.changeScene('order')
|
|
||||||
|
|
||||||
// 订单备注
|
|
||||||
const buyerMessage = ref('')
|
|
||||||
|
|
||||||
const disabledSubmit = ref(false)
|
|
||||||
|
|
||||||
if (!addressStore.selectedAddress?.id) {
|
|
||||||
disabledSubmit.value = true
|
|
||||||
}
|
|
||||||
|
|
||||||
const selectCouponId = ref<string | number>('')
|
|
||||||
const couponText = ref('')
|
|
||||||
|
|
||||||
//获取页面参数
|
|
||||||
const query = defineProps<{
|
|
||||||
sku_id?: string
|
|
||||||
count?: string
|
|
||||||
orderId?: string
|
|
||||||
}>()
|
|
||||||
|
|
||||||
//获取下单前信息
|
|
||||||
const orderPreData = ref<orderPreResult>()
|
|
||||||
const orderPreParams = ref<{
|
|
||||||
id: string
|
|
||||||
sku_id: string
|
|
||||||
num: string | number
|
|
||||||
address_id: string | number
|
|
||||||
coupon_id: string | number
|
|
||||||
}>({
|
|
||||||
id: query.orderId ?? '0',
|
|
||||||
sku_id: query.sku_id ?? '0',
|
|
||||||
num: query.count ?? 0,
|
|
||||||
address_id: addressStore.selectedAddress?.id ?? '0',
|
|
||||||
coupon_id: selectCouponId.value ?? '0',
|
|
||||||
})
|
|
||||||
|
|
||||||
const getOrderPreData = async () => {
|
|
||||||
orderPreParams.value = {
|
|
||||||
...orderPreParams.value,
|
|
||||||
coupon_id: selectCouponId.value ?? '0',
|
|
||||||
}
|
|
||||||
|
|
||||||
let res: any = []
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (query.sku_id && query.count) {
|
|
||||||
//直接下单
|
|
||||||
res = await getOrderPreApi({
|
|
||||||
sku_id: orderPreParams.value.sku_id,
|
|
||||||
num: Number(orderPreParams.value.num),
|
|
||||||
address_id: orderPreParams.value.address_id,
|
|
||||||
coupon_id: orderPreParams.value.coupon_id,
|
|
||||||
})
|
|
||||||
} else if (query.orderId) {
|
|
||||||
//再次购买下单
|
|
||||||
res = await getRepurchaseOrderPreByOrderIdApi({
|
|
||||||
id: orderPreParams.value.id,
|
|
||||||
address_id: orderPreParams.value.address_id,
|
|
||||||
coupon_id: orderPreParams.value.coupon_id,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
//购物车下单
|
|
||||||
res = await getCartOrderPreApi({
|
|
||||||
address_id: orderPreParams.value.address_id,
|
|
||||||
coupon_id: orderPreParams.value.coupon_id,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
disabledSubmit.value = false
|
|
||||||
} catch (error: any) {
|
|
||||||
uni.showModal({
|
|
||||||
title: '提示',
|
|
||||||
content: error.data.msg,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
orderPreData.value = res.result
|
|
||||||
|
|
||||||
if (res.result.error) {
|
|
||||||
uni.showModal({
|
|
||||||
title: '提示',
|
|
||||||
content: res.result.error,
|
|
||||||
})
|
|
||||||
disabledSubmit.value = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//下单页收货地址
|
|
||||||
const addressData = computed(() => {
|
|
||||||
return addressStore.selectedAddress
|
|
||||||
})
|
|
||||||
|
|
||||||
// 提交订单
|
|
||||||
const onOrderSubmit = async () => {
|
|
||||||
await checkOrder()
|
|
||||||
}
|
|
||||||
// 订单提交前校验
|
|
||||||
const checkOrder = () => {
|
|
||||||
if (!addressStore.selectedAddress?.id) {
|
|
||||||
return uni.showToast({
|
|
||||||
title: '请选择收货地址',
|
|
||||||
icon: 'none',
|
|
||||||
mask: true,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
debouncedSubmitOrder()
|
|
||||||
}
|
|
||||||
// 提交订单函数
|
|
||||||
const debouncedSubmitOrder = debounce(async () => {
|
|
||||||
const res = await postOrderApi({
|
|
||||||
address_id: addressStore.selectedAddress!.id,
|
|
||||||
remark: buyerMessage.value,
|
|
||||||
goods: orderPreData.value!.goods.map((item) => ({
|
|
||||||
sku_id: item.id,
|
|
||||||
num: item.num,
|
|
||||||
})),
|
|
||||||
type: orderType.default,
|
|
||||||
coupon_id: selectCouponId.value,
|
|
||||||
})
|
|
||||||
|
|
||||||
if (!res.result.id) {
|
|
||||||
return uni.showToast({
|
|
||||||
icon: 'error',
|
|
||||||
title: '订单提交失败',
|
|
||||||
})
|
|
||||||
}
|
|
||||||
// 跳转详情
|
|
||||||
uni.redirectTo({ url: `${pageUrl['order-detail']}?id=${res.result.id}` })
|
|
||||||
}, 1000)
|
|
||||||
|
|
||||||
const couponPopup = ref<{
|
|
||||||
open: (type?: UniHelper.UniPopupType) => void
|
|
||||||
close: () => void
|
|
||||||
}>()
|
|
||||||
const openCouponPopup = () => {
|
|
||||||
couponPopup.value?.open()
|
|
||||||
}
|
|
||||||
const closeCouponPopup = () => {
|
|
||||||
couponPopup.value?.close()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 选中优惠券
|
|
||||||
const selectCoupon = (item: couponListItem) => {
|
|
||||||
selectCouponId.value = item.id
|
|
||||||
getOrderPreData().then(() => {
|
|
||||||
couponText.value = orderPreData.value!.summary.coupon_discount
|
|
||||||
couponPopup.value?.close()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
// 清空已选择的优惠券
|
|
||||||
const clearSelectCoupon = () => {
|
|
||||||
selectCouponId.value = ''
|
|
||||||
getOrderPreData().then(() => {
|
|
||||||
couponPopup.value?.close()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const onChangeNum = debounce((event: InputNumberBoxEvent) => {
|
|
||||||
orderPreParams.value.num = event.value
|
|
||||||
selectCouponId.value = ''
|
|
||||||
getOrderPreData()
|
|
||||||
}, 500)
|
|
||||||
|
|
||||||
onShow(() => {
|
|
||||||
getOrderPreData().then(() => {
|
|
||||||
if (!orderPreData.value?.user_address) {
|
|
||||||
addressStore.clearSelectedAddress()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<!-- #ifdef MP-WEIXIN -->
|
|
||||||
<page-meta :page-style="pageMateStyle">
|
|
||||||
<!-- #endif -->
|
|
||||||
<view v-if="orderPreData">
|
|
||||||
<scroll-view scroll-y class="viewport">
|
|
||||||
<!-- 收货地址 -->
|
|
||||||
<navigator
|
|
||||||
v-if="addressData"
|
|
||||||
class="shipment"
|
|
||||||
hover-class="none"
|
|
||||||
:url="`${pageUrl['address']}?from=order`"
|
|
||||||
>
|
|
||||||
<view class="user"> {{ addressData.name }} {{ addressData.phone }} </view>
|
|
||||||
<view class="address"> {{ addressData.full_location }} {{ addressData.address }} </view>
|
|
||||||
<text class="icon icon-right"></text>
|
|
||||||
</navigator>
|
|
||||||
<navigator
|
|
||||||
v-else
|
|
||||||
class="shipment"
|
|
||||||
hover-class="none"
|
|
||||||
:url="`${pageUrl['address']}?from=order`"
|
|
||||||
>
|
|
||||||
<view class="address"> 请选择收货地址 </view>
|
|
||||||
<text class="icon icon-right"></text>
|
|
||||||
</navigator>
|
|
||||||
|
|
||||||
<!-- 商品信息 -->
|
|
||||||
<view class="goods" v-if="orderPreData">
|
|
||||||
<view v-for="item in orderPreData?.goods" :key="item.sku_id" class="item">
|
|
||||||
<navigator :url="`${pageUrl['goods-detail']}?id=${item.goods_id}`" hover-class="none">
|
|
||||||
<image class="picture" :src="fullUrl(item.image)" />
|
|
||||||
</navigator>
|
|
||||||
<view class="meta">
|
|
||||||
<view class="name ellipsis"> {{ item.goods.name }} </view>
|
|
||||||
<view class="attrs">{{ item.spec_text }}</view>
|
|
||||||
<view class="prices">
|
|
||||||
<view class="pay-price symbol">{{ item.price }}</view>
|
|
||||||
<view class="price symbol">{{ item.origin_price }}</view>
|
|
||||||
</view>
|
|
||||||
<view class="count">
|
|
||||||
<vk-data-input-number-box
|
|
||||||
v-if="query.sku_id && query.count"
|
|
||||||
:style="{ position: 'absolute', right: '0', bottom: '-10rpx' }"
|
|
||||||
v-model="item.num"
|
|
||||||
:index="item.id"
|
|
||||||
:min="1"
|
|
||||||
@plus="onChangeNum($event)"
|
|
||||||
@minus="onChangeNum($event)"
|
|
||||||
@blur="onChangeNum($event)"
|
|
||||||
/>
|
|
||||||
<view else="orderPreData?.goods.length > 1">x {{ item.num }}</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="related">
|
|
||||||
<view class="item">
|
|
||||||
<text class="text">订单备注</text>
|
|
||||||
<input
|
|
||||||
class="input"
|
|
||||||
:cursor-spacing="30"
|
|
||||||
placeholder="建议留言前先与商家沟通确认"
|
|
||||||
v-model="buyerMessage"
|
|
||||||
/>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 支付金额 -->
|
|
||||||
<view class="settlement">
|
|
||||||
<view class="item">
|
|
||||||
<text class="text">商品总价: </text>
|
|
||||||
<text class="number symbol">{{ orderPreData?.summary.total_price }}</text>
|
|
||||||
</view>
|
|
||||||
<view class="item">
|
|
||||||
<text class="text">优惠券: </text>
|
|
||||||
<text class="coupon" @tap="openCouponPopup" v-if="orderPreData.coupon_list.length > 0">
|
|
||||||
<text v-if="selectCouponId" class="danger">-¥{{ couponText }}</text>
|
|
||||||
<text v-else>
|
|
||||||
<text class="danger">{{ orderPreData.coupon_list.length }}</text> 张优惠券可用
|
|
||||||
</text>
|
|
||||||
</text>
|
|
||||||
<text v-else>无优惠券可用</text>
|
|
||||||
</view>
|
|
||||||
<view class="item">
|
|
||||||
<text class="text">运费: </text>
|
|
||||||
<text class="number symbol">{{ orderPreData?.summary.freight }}</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</scroll-view>
|
|
||||||
|
|
||||||
<!-- 优惠券弹出层 -->
|
|
||||||
<uni-popup
|
|
||||||
ref="couponPopup"
|
|
||||||
type="share"
|
|
||||||
background-color="#fff"
|
|
||||||
class="coupon-popup"
|
|
||||||
@change="usePopupStore().onChangePopupProps"
|
|
||||||
>
|
|
||||||
<view class="coupon-panel">
|
|
||||||
<text class="close icon-close" @tap="closeCouponPopup"></text>
|
|
||||||
<view class="title">选择优惠券</view>
|
|
||||||
<view class="content">
|
|
||||||
<shop-coupon
|
|
||||||
:couponList="orderPreData.coupon_list"
|
|
||||||
mode="user"
|
|
||||||
buttonTitle="选择使用"
|
|
||||||
@buttonClicked="selectCoupon"
|
|
||||||
class="user-coupon-popup"
|
|
||||||
/>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="coupon-panel-footer">
|
|
||||||
<view class="button primary" @tap="clearSelectCoupon"> 不使用优惠券</view>
|
|
||||||
</view>
|
|
||||||
</uni-popup>
|
|
||||||
|
|
||||||
<!-- 底部占位空盒子 -->
|
|
||||||
<view class="toolbar-height"></view>
|
|
||||||
|
|
||||||
<!-- 吸底工具栏 -->
|
|
||||||
<view class="toolbar" :style="safeBottom">
|
|
||||||
<view class="total-pay symbol">
|
|
||||||
<text class="number">{{ orderPreData?.summary.pay_price }}</text>
|
|
||||||
</view>
|
|
||||||
<view class="button" :class="{ disabled: disabledSubmit }" @tap="onOrderSubmit">
|
|
||||||
<button class="button" :disabled="disabledSubmit">提交订单</button>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<!-- #ifdef MP-WEIXIN -->
|
|
||||||
</page-meta>
|
|
||||||
<!-- #endif -->
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
page {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
background-color: #f4f4f4;
|
|
||||||
}
|
|
||||||
|
|
||||||
.symbol::before {
|
|
||||||
content: '¥';
|
|
||||||
font-size: 80%;
|
|
||||||
margin-right: 5rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.shipment {
|
|
||||||
margin: 20rpx;
|
|
||||||
padding: 30rpx 30rpx 30rpx 84rpx;
|
|
||||||
font-size: 26rpx;
|
|
||||||
border-radius: 10rpx;
|
|
||||||
background: url('~@/static/images/locate.png') 20rpx center / 50rpx no-repeat #fff;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
font-size: 36rpx;
|
|
||||||
color: #333;
|
|
||||||
transform: translateY(-50%);
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
right: 20rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.user {
|
|
||||||
color: #333;
|
|
||||||
margin-bottom: 5rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.address {
|
|
||||||
color: #666;
|
|
||||||
width: 94%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.goods {
|
|
||||||
margin: 20rpx;
|
|
||||||
padding: 0 20rpx;
|
|
||||||
border-radius: 10rpx;
|
|
||||||
background-color: #fff;
|
|
||||||
|
|
||||||
.item {
|
|
||||||
display: flex;
|
|
||||||
padding: 30rpx 0;
|
|
||||||
border-top: 1rpx solid #eee;
|
|
||||||
|
|
||||||
&:first-child {
|
|
||||||
border-top: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.picture {
|
|
||||||
width: 170rpx;
|
|
||||||
height: 170rpx;
|
|
||||||
border-radius: 10rpx;
|
|
||||||
margin-right: 20rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.meta {
|
|
||||||
flex: 1;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: space-around;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.name {
|
|
||||||
font-size: 26rpx;
|
|
||||||
color: #444;
|
|
||||||
}
|
|
||||||
|
|
||||||
.attrs {
|
|
||||||
line-height: 1.8;
|
|
||||||
padding: 0 15rpx;
|
|
||||||
margin-top: 6rpx;
|
|
||||||
margin-bottom: 10rpx;
|
|
||||||
font-size: 24rpx;
|
|
||||||
align-self: flex-start;
|
|
||||||
border-radius: 4rpx;
|
|
||||||
color: #888;
|
|
||||||
background-color: #f7f7f8;
|
|
||||||
max-width: 90%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.prices {
|
|
||||||
display: flex;
|
|
||||||
align-items: baseline;
|
|
||||||
margin-top: 6rpx;
|
|
||||||
font-size: 28rpx;
|
|
||||||
width: 50%;
|
|
||||||
flex-flow: wrap;
|
|
||||||
|
|
||||||
.pay-price {
|
|
||||||
margin-right: 10rpx;
|
|
||||||
color: #cf4444;
|
|
||||||
}
|
|
||||||
|
|
||||||
.price {
|
|
||||||
font-size: 24rpx;
|
|
||||||
color: #999;
|
|
||||||
text-decoration: line-through;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.count {
|
|
||||||
position: absolute;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.related {
|
|
||||||
margin: 20rpx;
|
|
||||||
padding: 0 20rpx;
|
|
||||||
border-radius: 10rpx;
|
|
||||||
background-color: #fff;
|
|
||||||
|
|
||||||
.item {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
min-height: 80rpx;
|
|
||||||
font-size: 26rpx;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
.input {
|
|
||||||
flex: 1;
|
|
||||||
text-align: right;
|
|
||||||
margin: 20rpx 0;
|
|
||||||
padding-right: 20rpx;
|
|
||||||
font-size: 26rpx;
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
|
|
||||||
.item .text {
|
|
||||||
width: 125rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.picker {
|
|
||||||
color: #666;
|
|
||||||
}
|
|
||||||
|
|
||||||
.picker::after {
|
|
||||||
content: '\e6c2';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 结算清单 */
|
|
||||||
.settlement {
|
|
||||||
margin: 20rpx;
|
|
||||||
padding: 0 20rpx;
|
|
||||||
border-radius: 10rpx;
|
|
||||||
background-color: #fff;
|
|
||||||
// padding-bottom: 200rpx;
|
|
||||||
|
|
||||||
.item {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
height: 80rpx;
|
|
||||||
font-size: 26rpx;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
.coupon {
|
|
||||||
&::after {
|
|
||||||
font-family: 'iconfont' !important;
|
|
||||||
content: '\e6c2';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.danger {
|
|
||||||
color: #cf4444;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.coupon-panel {
|
|
||||||
.title {
|
|
||||||
line-height: 1;
|
|
||||||
padding: 40rpx 0;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 32rpx;
|
|
||||||
font-weight: normal;
|
|
||||||
border-bottom: 1rpx solid #ddd;
|
|
||||||
color: #444;
|
|
||||||
}
|
|
||||||
|
|
||||||
.close {
|
|
||||||
position: absolute;
|
|
||||||
right: 24rpx;
|
|
||||||
top: 24rpx;
|
|
||||||
font-size: 40rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
|
||||||
min-height: 400rpx;
|
|
||||||
max-height: 650rpx;
|
|
||||||
overflow: auto;
|
|
||||||
-webkit-overflow-scrolling: touch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.coupon-panel-footer {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
padding: 20rpx 0 40rpx;
|
|
||||||
font-size: 28rpx;
|
|
||||||
color: #444;
|
|
||||||
|
|
||||||
.button {
|
|
||||||
flex: 1;
|
|
||||||
height: 72rpx;
|
|
||||||
text-align: center;
|
|
||||||
line-height: 72rpx;
|
|
||||||
margin: 0 20rpx;
|
|
||||||
color: #fff;
|
|
||||||
border-radius: 72rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.primary {
|
|
||||||
color: #fff;
|
|
||||||
background-color: #ff5f3c;
|
|
||||||
}
|
|
||||||
|
|
||||||
.secondary {
|
|
||||||
background-color: #ffa868;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 吸底工具栏 */
|
|
||||||
.toolbar {
|
|
||||||
position: fixed;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: calc(var(--window-bottom));
|
|
||||||
z-index: 1;
|
|
||||||
|
|
||||||
background-color: #fff;
|
|
||||||
height: 100rpx;
|
|
||||||
padding: 0 20rpx;
|
|
||||||
border-top: 1rpx solid #eaeaea;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
box-sizing: content-box;
|
|
||||||
|
|
||||||
.total-pay {
|
|
||||||
font-size: 40rpx;
|
|
||||||
color: #cf4444;
|
|
||||||
|
|
||||||
.decimal {
|
|
||||||
font-size: 75%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.button {
|
|
||||||
width: 220rpx;
|
|
||||||
text-align: center;
|
|
||||||
line-height: 72rpx;
|
|
||||||
font-size: 26rpx;
|
|
||||||
color: #fff;
|
|
||||||
border-radius: 72rpx;
|
|
||||||
background-color: #ff5f3c;
|
|
||||||
}
|
|
||||||
|
|
||||||
.disabled {
|
|
||||||
opacity: 0.6;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 底部占位空盒子
|
|
||||||
.toolbar-height {
|
|
||||||
height: 190rpx;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,261 +0,0 @@
|
|||||||
<template>
|
|
||||||
<view v-if="deliveryList.length > 0">
|
|
||||||
<z-tabs
|
|
||||||
:list="deliveryList"
|
|
||||||
@change="onChangeTabs"
|
|
||||||
class="tabs"
|
|
||||||
v-if="deliveryInfo.length > 1"
|
|
||||||
:scroll-count="1"
|
|
||||||
/>
|
|
||||||
<view class="body">
|
|
||||||
<!-- 商品详情 -->
|
|
||||||
<view class="delivery">
|
|
||||||
<view class="delivery-goods-list">
|
|
||||||
<view class="goods-item" v-for="(goods, idx) in deliveryInfo[tabIndex].detail" :key="idx">
|
|
||||||
<image class="goods-img" :src="fullUrl(goods.order_detail.image)" alt="商品图片" />
|
|
||||||
<view class="title">共{{ goods.delivery_num }}件</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<!-- 物流信息 -->
|
|
||||||
<view class="delivery-info">
|
|
||||||
<view v-if="deliveryInfo[tabIndex].delivery_company">
|
|
||||||
<view class="info-item">
|
|
||||||
<view class="item-label">物流公司: </view>
|
|
||||||
<view class="item-content">{{ deliveryInfo[tabIndex].delivery_company.name }}</view>
|
|
||||||
</view>
|
|
||||||
<view class="info-item">
|
|
||||||
<view class="item-label">物流单号: </view>
|
|
||||||
<view class="item-content">{{ deliveryInfo[tabIndex].delivery_no }}</view>
|
|
||||||
<view class="item-content">
|
|
||||||
<button class="copy-button" @tap="onCopy(deliveryInfo[tabIndex].delivery_no)">
|
|
||||||
复制
|
|
||||||
</button>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="info-item">
|
|
||||||
<view class="item-label address">收货地址: </view>
|
|
||||||
<view class="item-content">
|
|
||||||
{{ deliveryInfo[tabIndex].order_address.full_address }}
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view v-else>
|
|
||||||
<view class="info-item">
|
|
||||||
<view>无需物流</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<!-- 物流轨迹 -->
|
|
||||||
<view class="delivery-tracks" v-if="deliveryList[tabIndex].value.length > 0">
|
|
||||||
<view
|
|
||||||
v-for="(item, index) in deliveryList[tabIndex].value"
|
|
||||||
:key="index"
|
|
||||||
class="track-item"
|
|
||||||
:class="{ start: index === 0, end: index === deliveryList[tabIndex].value.length - 1 }"
|
|
||||||
>
|
|
||||||
<view class="track-item-content">
|
|
||||||
<view class="item-content">
|
|
||||||
<text>{{ item.context }}</text>
|
|
||||||
</view>
|
|
||||||
<view class="item-time">
|
|
||||||
<text>{{ item.time }}</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view v-else>
|
|
||||||
<z-paging-empty-view :empty-view-fixed="false" empty-view-text="暂无物流轨迹信息" />
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view :style="safeBottom" class="bottom"></view>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { safeBottom } from '@/utils/constants'
|
|
||||||
import { getOrderDeliveryByIdApi } from '@/api/order'
|
|
||||||
import type { orderDeliveryResult } from '@/types/order'
|
|
||||||
import { ref } from 'vue'
|
|
||||||
import { fullUrl, onShowRefreshData } from '@/utils/common'
|
|
||||||
|
|
||||||
const props = defineProps<{
|
|
||||||
order_id: string
|
|
||||||
}>()
|
|
||||||
|
|
||||||
let deliveryInfo: orderDeliveryResult[] = []
|
|
||||||
const deliveryList = ref<any[]>([])
|
|
||||||
const tabIndex = ref(0)
|
|
||||||
|
|
||||||
const onChangeTabs = (index: number) => {
|
|
||||||
tabIndex.value = index
|
|
||||||
}
|
|
||||||
|
|
||||||
const onCopy = (deliveryNo: string) => {
|
|
||||||
uni.setClipboardData({ data: deliveryNo })
|
|
||||||
}
|
|
||||||
|
|
||||||
onShowRefreshData(async () => {
|
|
||||||
const res = await getOrderDeliveryByIdApi(props.order_id)
|
|
||||||
deliveryInfo = res.result
|
|
||||||
for (let i = 1; i <= deliveryInfo.length; i++) {
|
|
||||||
deliveryList.value.push({
|
|
||||||
name: '包裹' + i,
|
|
||||||
value: deliveryInfo[i - 1].delivery_tracks,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
page {
|
|
||||||
background-color: #f6f6f6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.body {
|
|
||||||
padding-top: 20rpx;
|
|
||||||
padding-bottom: 20rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.delivery {
|
|
||||||
padding: 10rpx;
|
|
||||||
background-color: #fff;
|
|
||||||
|
|
||||||
.delivery-goods-list {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
margin-top: 20rpx;
|
|
||||||
margin-bottom: -30rpx;
|
|
||||||
|
|
||||||
.goods-item {
|
|
||||||
position: relative;
|
|
||||||
border-radius: 8rpx;
|
|
||||||
overflow: hidden;
|
|
||||||
width: 130rpx;
|
|
||||||
height: 130rpx;
|
|
||||||
margin-bottom: 30rpx;
|
|
||||||
margin-left: 18rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.goods-img {
|
|
||||||
display: block;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 0;
|
|
||||||
width: 100%;
|
|
||||||
text-align: center;
|
|
||||||
background: rgba(0, 0, 0, 0.6);
|
|
||||||
color: #fff;
|
|
||||||
padding: 4rpx 0;
|
|
||||||
font-size: 24rpx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.delivery-info {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
line-height: 1.6;
|
|
||||||
padding: 20rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.info-item {
|
|
||||||
display: flex;
|
|
||||||
font-size: 24rpx;
|
|
||||||
|
|
||||||
.copy-button {
|
|
||||||
display: flex;
|
|
||||||
height: 34rpx;
|
|
||||||
font-size: 24rpx;
|
|
||||||
align-items: center;
|
|
||||||
margin-left: 20rpx;
|
|
||||||
border-radius: 50rpx;
|
|
||||||
border: 1rpx solid #c1c1c1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.item-label {
|
|
||||||
color: #9d9d9d;
|
|
||||||
margin-right: 20rpx;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.item-content {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
flex-direction: column;
|
|
||||||
font-size: 26rpx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.track {
|
|
||||||
font-size: 40rrpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.delivery-tracks {
|
|
||||||
padding: 30rpx;
|
|
||||||
background-color: #fff;
|
|
||||||
border-radius: 25rpx;
|
|
||||||
|
|
||||||
.track-item {
|
|
||||||
position: relative;
|
|
||||||
padding-left: 20rpx;
|
|
||||||
padding-bottom: 25rpx;
|
|
||||||
border-left: 4rpx solid #ccc;
|
|
||||||
|
|
||||||
&.start {
|
|
||||||
border-left: 5rpx solid red;
|
|
||||||
&:after {
|
|
||||||
background-color: red;
|
|
||||||
top: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.end {
|
|
||||||
padding-bottom: 0rpx;
|
|
||||||
border-left: none;
|
|
||||||
&::after {
|
|
||||||
left: -13rpx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:after {
|
|
||||||
content: ' ';
|
|
||||||
display: inline-block;
|
|
||||||
position: absolute;
|
|
||||||
left: -9px;
|
|
||||||
top: 0rpx;
|
|
||||||
width: 24rpx;
|
|
||||||
height: 24rpx;
|
|
||||||
border-radius: 40rpx;
|
|
||||||
background: #bdbdbd;
|
|
||||||
border: 2rpx solid #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.track-item-content {
|
|
||||||
position: relative;
|
|
||||||
padding: 20rpx 20rpx;
|
|
||||||
background-color: #f4f4f4;
|
|
||||||
border-radius: 20rpx;
|
|
||||||
|
|
||||||
.item-content {
|
|
||||||
font-size: 27rpx;
|
|
||||||
padding-bottom: 12rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.item-time {
|
|
||||||
font-size: 24rpx;
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.bottom {
|
|
||||||
height: 50rpx;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,788 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import { orderState, orderStateActions, orderStateList, pageUrl } from '@/utils/constants'
|
|
||||||
import { deleteOrderApi, getOrderDetailByIdApi, putOrderCancelByIdApi } from '@/api/order'
|
|
||||||
import type { orderResult } from '@/types/order'
|
|
||||||
import { ref, computed } from 'vue'
|
|
||||||
import { fullUrl, getPayPageUrl, formatPrice, onShowRefreshData } from '@/utils/common'
|
|
||||||
import receiveButton from '@/pagesOrder/components/receiveButton.vue'
|
|
||||||
import cancelButton from '@/pagesOrder/components/cancelButton.vue'
|
|
||||||
import { safeBottom } from '@/utils/constants'
|
|
||||||
|
|
||||||
//订单详情
|
|
||||||
const detailData = ref<orderResult>()
|
|
||||||
const getDetailData = async () => {
|
|
||||||
const res = await getOrderDetailByIdApi(orderId)
|
|
||||||
detailData.value = res.result
|
|
||||||
}
|
|
||||||
|
|
||||||
// 复制内容
|
|
||||||
const onCopy = () => {
|
|
||||||
// 设置系统剪贴板的内容
|
|
||||||
uni.setClipboardData({ data: detailData.value!.order_no })
|
|
||||||
}
|
|
||||||
// 获取页面参数
|
|
||||||
const query = defineProps<{
|
|
||||||
id: string
|
|
||||||
}>()
|
|
||||||
|
|
||||||
//订单ID
|
|
||||||
const orderId = Number(query.id)
|
|
||||||
|
|
||||||
//倒计时结束事件
|
|
||||||
const onTimeUp = () => {
|
|
||||||
if (detailData.value?.status != orderState.canceled) {
|
|
||||||
putOrderCancelByIdApi({
|
|
||||||
id: detailData.value!.id,
|
|
||||||
time_out: true,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
detailData.value!.status = orderState.canceled
|
|
||||||
}
|
|
||||||
|
|
||||||
//删除订单
|
|
||||||
const onDeleteOrder = () => {
|
|
||||||
uni.showModal({
|
|
||||||
title: '提示',
|
|
||||||
content: '确定要删除订单吗',
|
|
||||||
showCancel: true,
|
|
||||||
success: async ({ confirm, cancel }) => {
|
|
||||||
if (confirm) {
|
|
||||||
await deleteOrderApi({
|
|
||||||
id: [orderId],
|
|
||||||
})
|
|
||||||
uni.showToast({
|
|
||||||
title: '删除成功',
|
|
||||||
icon: 'success',
|
|
||||||
mask: true,
|
|
||||||
})
|
|
||||||
setTimeout(() => {
|
|
||||||
uni.redirectTo({ url: `${pageUrl['order-list']}` })
|
|
||||||
}, 500)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
onShowRefreshData(() => {
|
|
||||||
getDetailData()
|
|
||||||
}, true)
|
|
||||||
|
|
||||||
const showDelivery = computed(() => {
|
|
||||||
return (
|
|
||||||
[orderState.toReceived, orderState.toEvaluate, orderState.completed].includes(
|
|
||||||
detailData.value!.status,
|
|
||||||
) && detailData.value!.delivery.length > 0
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
const onCancel = () => {
|
|
||||||
if (detailData.value?.pay_time) {
|
|
||||||
detailData.value!.status = orderState.applyCancel
|
|
||||||
} else {
|
|
||||||
detailData.value!.status = orderState.canceled
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<scroll-view scroll-y class="viewport" id="scroller">
|
|
||||||
<template v-if="detailData">
|
|
||||||
<!-- 订单状态 -->
|
|
||||||
<view class="overview" :style="{ paddingTop: '30rpx' }">
|
|
||||||
<!-- 待付款状态:展示去支付按钮和倒计时 -->
|
|
||||||
<template v-if="detailData.status === orderState.toPay">
|
|
||||||
<view class="status icon-clock">{{ orderStateList[detailData.status].text }}</view>
|
|
||||||
<view class="tips">
|
|
||||||
<view class="time">
|
|
||||||
<view>还剩</view>
|
|
||||||
<uni-countdown
|
|
||||||
:second="detailData.countdown"
|
|
||||||
@timeup.once="onTimeUp"
|
|
||||||
color="#fff"
|
|
||||||
splitor-color="#fff"
|
|
||||||
:show-day="false"
|
|
||||||
:show-colon="false"
|
|
||||||
/>
|
|
||||||
<view>自动取消</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<navigator
|
|
||||||
class="button primary"
|
|
||||||
:url="getPayPageUrl(orderId, detailData.pay_price)"
|
|
||||||
hover-class="none"
|
|
||||||
>
|
|
||||||
去支付
|
|
||||||
</navigator>
|
|
||||||
</template>
|
|
||||||
<!-- 其他订单状态:展示再次购买按钮 -->
|
|
||||||
<template v-else>
|
|
||||||
<!-- 订单状态文字 -->
|
|
||||||
<view class="status"> {{ orderStateList[detailData.status].text }} </view>
|
|
||||||
</template>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="shipment" v-show="detailData.address">
|
|
||||||
<view class="locate">
|
|
||||||
<view class="user"> {{ detailData.address.name }} {{ detailData.address.phone }} </view>
|
|
||||||
<view class="address">{{ detailData.address.full_address }} </view>
|
|
||||||
</view>
|
|
||||||
<!-- 配送状态 -->
|
|
||||||
<view class="item" v-if="showDelivery">
|
|
||||||
<view class="delivery-card">
|
|
||||||
<template v-if="detailData.delivery.length > 1">
|
|
||||||
<navigator
|
|
||||||
class="delivery"
|
|
||||||
:url="`${pageUrl['order-delivery']}?order_id=${orderId}`"
|
|
||||||
hover-class="none"
|
|
||||||
>
|
|
||||||
<view v-if="detailData.status == orderState.toReceived" class="delivery-tip">
|
|
||||||
<text>订单拆分为 {{ detailData.delivery.length }} 个包裹发货</text>
|
|
||||||
</view>
|
|
||||||
<view v-else class="delivery-tip">
|
|
||||||
<text>订单拆分为多个包裹发货</text>
|
|
||||||
<text>已发货 {{ detailData.delivery.length }} 个包裹</text>
|
|
||||||
</view>
|
|
||||||
<view class="more">
|
|
||||||
<text class="icon-right"></text>
|
|
||||||
</view>
|
|
||||||
</navigator>
|
|
||||||
</template>
|
|
||||||
<template v-else>
|
|
||||||
<navigator
|
|
||||||
class="delivery"
|
|
||||||
:url="`${pageUrl['order-delivery']}?order_id=${orderId}`"
|
|
||||||
hover-class="none"
|
|
||||||
v-for="(item, idx) in detailData.delivery"
|
|
||||||
:key="idx"
|
|
||||||
>
|
|
||||||
<view class="delivery-info">
|
|
||||||
<view class="info-item">
|
|
||||||
<view class="item-label">物流公司</view>
|
|
||||||
<view class="item-content">
|
|
||||||
{{ item.delivery_company?.name || '无需物流' }}
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="info-item">
|
|
||||||
<view class="item-label">物流单号</view>
|
|
||||||
<view class="item-content">{{ item.delivery_no || '' }}</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="more">
|
|
||||||
<text class="icon-right"></text>
|
|
||||||
</view>
|
|
||||||
</navigator>
|
|
||||||
</template>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 商品信息 -->
|
|
||||||
<view class="goods" v-if="detailData.detail.length > 0">
|
|
||||||
<view class="item" v-for="detail in detailData.detail" :key="detail.id">
|
|
||||||
<navigator
|
|
||||||
class="navigator"
|
|
||||||
:url="`${pageUrl['goods-detail']}?id=${detail.goods_id}`"
|
|
||||||
hover-class="none"
|
|
||||||
>
|
|
||||||
<view> <image class="cover" :src="fullUrl(detail.image)"></image> </view>
|
|
||||||
<view class="meta">
|
|
||||||
<view class="name ellipsis">{{ detail.goods_name }}</view>
|
|
||||||
<view class="type">{{ detail.spec_text }}</view>
|
|
||||||
<view class="price">
|
|
||||||
<view class="actual">
|
|
||||||
<text class="symbol">¥</text>
|
|
||||||
<text>{{ detail.price }}</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="quantity">x{{ detail.num }}</view>
|
|
||||||
</view>
|
|
||||||
</navigator>
|
|
||||||
|
|
||||||
<view class="operate">
|
|
||||||
<view
|
|
||||||
v-if="
|
|
||||||
orderStateActions.evaluatable.includes(detailData.status) &&
|
|
||||||
detail.evaluate_time <= 0
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<navigator
|
|
||||||
:url="`${pageUrl['order-evaluate']}?detail_id=${detail.id}`"
|
|
||||||
open-type="navigate"
|
|
||||||
hover-class="navigator-hover"
|
|
||||||
class="button"
|
|
||||||
>
|
|
||||||
去评价
|
|
||||||
</navigator>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view v-if="detail.apply_refund">
|
|
||||||
<navigator
|
|
||||||
:url="`${pageUrl['order-refund']}?order_id=${
|
|
||||||
detailData.id
|
|
||||||
}&detail_data=${JSON.stringify(detail)}`"
|
|
||||||
open-type="navigate"
|
|
||||||
hover-class="navigator-hover"
|
|
||||||
class="button"
|
|
||||||
>
|
|
||||||
申请售后
|
|
||||||
</navigator>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="goods">
|
|
||||||
<view class="total">
|
|
||||||
<view class="row">
|
|
||||||
<view class="text">商品总价</view>
|
|
||||||
<view class="symbol">{{ formatPrice(detailData.total_price) }}</view>
|
|
||||||
</view>
|
|
||||||
<view class="row">
|
|
||||||
<view class="text">商品运费</view>
|
|
||||||
<view class="symbol">{{ formatPrice(detailData.freight) }}</view>
|
|
||||||
</view>
|
|
||||||
<view class="row">
|
|
||||||
<view class="text">优惠折扣</view>
|
|
||||||
<view class="symbol discount">
|
|
||||||
{{ formatPrice(detailData.discount_data.coupon_discount) }}
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="row">
|
|
||||||
<view class="text">应付金额</view>
|
|
||||||
<view class="symbol">{{ formatPrice(detailData.pay_price) }}</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 订单信息 -->
|
|
||||||
<view class="detail">
|
|
||||||
<view class="row">
|
|
||||||
<view class="item">
|
|
||||||
<view class="item-title"> 订单编号</view>
|
|
||||||
<view>
|
|
||||||
{{ detailData.order_no }}
|
|
||||||
<text class="copy" @tap="onCopy">复制</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="item">
|
|
||||||
<view class="item-title">下单时间</view>
|
|
||||||
<view>{{ detailData.create_time }}</view>
|
|
||||||
</view>
|
|
||||||
<view class="item" v-if="detailData.pay_time">
|
|
||||||
<view class="item-title">支付时间</view>
|
|
||||||
<view> {{ detailData.pay_time }}</view>
|
|
||||||
</view>
|
|
||||||
<view class="item">
|
|
||||||
<view class="item-title">买家留言</view>
|
|
||||||
<view style="width: 80%">{{ detailData.remark || '--' }}</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 底部操作栏 -->
|
|
||||||
<view class="toolbar-height" :style="safeBottom"></view>
|
|
||||||
<view class="toolbar" :style="safeBottom">
|
|
||||||
<!-- 待付款状态:展示支付按钮 -->
|
|
||||||
<template v-if="detailData.status === orderState.toPay">
|
|
||||||
<cancelButton
|
|
||||||
:status="detailData.status"
|
|
||||||
:id="detailData.id"
|
|
||||||
className="button secondary"
|
|
||||||
@cancel="onCancel"
|
|
||||||
/>
|
|
||||||
<navigator
|
|
||||||
class="button primary"
|
|
||||||
:url="getPayPageUrl(detailData.id, detailData.pay_price)"
|
|
||||||
hover-class="none"
|
|
||||||
>
|
|
||||||
去支付
|
|
||||||
</navigator>
|
|
||||||
</template>
|
|
||||||
<!-- 其他订单状态:按需展示按钮 -->
|
|
||||||
<template v-else>
|
|
||||||
<view v-if="orderStateActions.deletable.includes(detailData.status)">
|
|
||||||
<view class="button secondary" @tap="onDeleteOrder"> 删除订单 </view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<cancelButton
|
|
||||||
:status="detailData.status"
|
|
||||||
:id="detailData.id"
|
|
||||||
className="button secondary"
|
|
||||||
@cancel="onCancel"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<receiveButton
|
|
||||||
:status="detailData.status"
|
|
||||||
:id="detailData.id"
|
|
||||||
:payment-trade-info="detailData.payment_trade"
|
|
||||||
className="button secondary"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<view v-if="orderStateActions.evaluatable.includes(detailData.status)">
|
|
||||||
<navigator
|
|
||||||
:url="`${pageUrl['order-evaluate']}?order_id=${orderId}`"
|
|
||||||
class="button secondary"
|
|
||||||
hover-class="none"
|
|
||||||
>
|
|
||||||
一键评价
|
|
||||||
</navigator>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<navigator
|
|
||||||
class="button primary"
|
|
||||||
:url="`${pageUrl['order-create']}?orderId=${orderId}`"
|
|
||||||
hover-class="none"
|
|
||||||
>
|
|
||||||
再次购买
|
|
||||||
</navigator>
|
|
||||||
</template>
|
|
||||||
</view>
|
|
||||||
</template>
|
|
||||||
</scroll-view>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
page {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
height: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
line-height: 1.6;
|
|
||||||
padding: 20rpx;
|
|
||||||
margin: 20rpx;
|
|
||||||
border-radius: 30rpx;
|
|
||||||
background-color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.navbar {
|
|
||||||
width: 750rpx;
|
|
||||||
color: #000;
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
z-index: 9;
|
|
||||||
/* background-color: #f8f8f8; */
|
|
||||||
background-color: transparent;
|
|
||||||
|
|
||||||
.wrap {
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
.title {
|
|
||||||
height: 44px;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
font-size: 32rpx;
|
|
||||||
/* color: #000; */
|
|
||||||
color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.back {
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
height: 44px;
|
|
||||||
width: 44px;
|
|
||||||
font-size: 44rpx;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
/* color: #000; */
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.viewport {
|
|
||||||
background-color: #f7f7f8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.overview {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
padding-bottom: 35rpx;
|
|
||||||
color: #fff;
|
|
||||||
background-image: url('~@/static/images/bg.png');
|
|
||||||
background-size: cover;
|
|
||||||
|
|
||||||
.status {
|
|
||||||
font-size: 36rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status::before {
|
|
||||||
margin-right: 6rpx;
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tips {
|
|
||||||
margin: 30rpx 0;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
font-size: 14px;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
.money {
|
|
||||||
margin-right: 30rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.time {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
gap: 10rpx;
|
|
||||||
padding-top: 10rpx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.button-group {
|
|
||||||
margin-top: 30rpx;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button {
|
|
||||||
width: 260rpx;
|
|
||||||
height: 64rpx;
|
|
||||||
margin: 0 10rpx;
|
|
||||||
text-align: center;
|
|
||||||
line-height: 64rpx;
|
|
||||||
font-size: 28rpx;
|
|
||||||
color: #ff5f3c;
|
|
||||||
border-radius: 68rpx;
|
|
||||||
background-color: #fff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.shipment {
|
|
||||||
line-height: 1.4;
|
|
||||||
padding: 0 20rpx;
|
|
||||||
margin: 20rpx 20rpx 20rpx;
|
|
||||||
border-radius: 30rpx;
|
|
||||||
background-color: #fff;
|
|
||||||
|
|
||||||
.locate,
|
|
||||||
.item {
|
|
||||||
// min-height: 120rpx;
|
|
||||||
padding: 30rpx 30rpx 25rpx 75rpx;
|
|
||||||
background-size: 50rpx;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-position: 6rpx center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.locate {
|
|
||||||
background-image: url('~@/static/images/locate.png');
|
|
||||||
border-bottom: 1rpx solid #eee;
|
|
||||||
|
|
||||||
.user {
|
|
||||||
font-size: 26rpx;
|
|
||||||
color: #444;
|
|
||||||
}
|
|
||||||
|
|
||||||
.address {
|
|
||||||
font-size: 24rpx;
|
|
||||||
color: #666;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.item {
|
|
||||||
background-image: url('~@/static/images/car.png');
|
|
||||||
border-bottom: 1rpx solid #eee;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
.message {
|
|
||||||
font-size: 26rpx;
|
|
||||||
color: #444;
|
|
||||||
}
|
|
||||||
|
|
||||||
.date {
|
|
||||||
font-size: 24rpx;
|
|
||||||
color: #666;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.delivery {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
.delivery-tip {
|
|
||||||
font-size: 24rpx;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.info-item {
|
|
||||||
display: flex;
|
|
||||||
font-size: 24rpx;
|
|
||||||
padding-bottom: 10rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.item-label {
|
|
||||||
color: #999999;
|
|
||||||
margin-right: 20rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.item-content {
|
|
||||||
font-size: 26rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.more {
|
|
||||||
margin-left: auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.goods {
|
|
||||||
margin: 20rpx;
|
|
||||||
padding: 0 20rpx;
|
|
||||||
border-radius: 30rpx;
|
|
||||||
background-color: #fff;
|
|
||||||
|
|
||||||
.item {
|
|
||||||
padding: 30rpx 0;
|
|
||||||
border-bottom: 1rpx solid #eee;
|
|
||||||
|
|
||||||
.navigator {
|
|
||||||
display: flex;
|
|
||||||
// margin: 20rpx 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cover {
|
|
||||||
width: 170rpx;
|
|
||||||
height: 170rpx;
|
|
||||||
border-radius: 10rpx;
|
|
||||||
margin-right: 20rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.meta {
|
|
||||||
flex: 1;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: space-around;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.name {
|
|
||||||
font-size: 26rpx;
|
|
||||||
color: #444;
|
|
||||||
}
|
|
||||||
|
|
||||||
.type {
|
|
||||||
line-height: 1.8;
|
|
||||||
padding: 0 15rpx;
|
|
||||||
margin-top: 6rpx;
|
|
||||||
font-size: 24rpx;
|
|
||||||
align-self: flex-start;
|
|
||||||
border-radius: 4rpx;
|
|
||||||
color: #888;
|
|
||||||
background-color: #f7f7f8;
|
|
||||||
max-width: 91%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.price {
|
|
||||||
display: flex;
|
|
||||||
margin-top: 6rpx;
|
|
||||||
font-size: 24rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.symbol {
|
|
||||||
font-size: 20rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.original {
|
|
||||||
color: #999;
|
|
||||||
text-decoration: line-through;
|
|
||||||
}
|
|
||||||
|
|
||||||
.actual {
|
|
||||||
margin-left: 10rpx;
|
|
||||||
color: #444;
|
|
||||||
}
|
|
||||||
|
|
||||||
.text {
|
|
||||||
font-size: 22rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.operate {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
flex-direction: row-reverse;
|
|
||||||
|
|
||||||
.button {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
border-radius: 60rpx;
|
|
||||||
height: 50rpx;
|
|
||||||
width: 150rpx;
|
|
||||||
align-items: center;
|
|
||||||
border: 1rpx solid #ccc;
|
|
||||||
color: #444;
|
|
||||||
font-size: 20rpx;
|
|
||||||
margin-left: 20rpx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.quantity {
|
|
||||||
position: absolute;
|
|
||||||
right: 0;
|
|
||||||
font-size: 24rpx;
|
|
||||||
color: #444;
|
|
||||||
}
|
|
||||||
|
|
||||||
.action {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row-reverse;
|
|
||||||
justify-content: flex-start;
|
|
||||||
padding: 30rpx 0 0;
|
|
||||||
|
|
||||||
.button {
|
|
||||||
width: 200rpx;
|
|
||||||
height: 60rpx;
|
|
||||||
text-align: center;
|
|
||||||
justify-content: center;
|
|
||||||
line-height: 60rpx;
|
|
||||||
margin-left: 20rpx;
|
|
||||||
border-radius: 60rpx;
|
|
||||||
border: 1rpx solid #ccc;
|
|
||||||
font-size: 26rpx;
|
|
||||||
color: #444;
|
|
||||||
}
|
|
||||||
|
|
||||||
.primary {
|
|
||||||
color: #ff5f3c;
|
|
||||||
border-color: #ff5f3c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.total {
|
|
||||||
line-height: 1.4;
|
|
||||||
font-size: 26rpx;
|
|
||||||
padding: 20rpx 0;
|
|
||||||
color: #666;
|
|
||||||
|
|
||||||
.row {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
padding: 10rpx 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.symbol::before {
|
|
||||||
content: '¥';
|
|
||||||
font-size: 80%;
|
|
||||||
margin-right: 3rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.discount::before {
|
|
||||||
content: '- ¥';
|
|
||||||
font-size: 80%;
|
|
||||||
margin-right: 3rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.primary {
|
|
||||||
color: #cf4444;
|
|
||||||
font-size: 36rpx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.detail {
|
|
||||||
line-height: 1.4;
|
|
||||||
padding: 20rpx;
|
|
||||||
margin: 20rpx;
|
|
||||||
font-size: 26rpx;
|
|
||||||
color: #666;
|
|
||||||
border-radius: 30rpx;
|
|
||||||
background-color: #fff;
|
|
||||||
|
|
||||||
.title {
|
|
||||||
font-size: 30rpx;
|
|
||||||
color: #444;
|
|
||||||
}
|
|
||||||
|
|
||||||
.row {
|
|
||||||
padding: 20rpx 0;
|
|
||||||
|
|
||||||
.item {
|
|
||||||
padding: 10rpx 0;
|
|
||||||
display: flex;
|
|
||||||
|
|
||||||
.item-title {
|
|
||||||
margin-right: 30rpx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.copy {
|
|
||||||
border-radius: 20rpx;
|
|
||||||
font-size: 20rpx;
|
|
||||||
border: 1px solid #ccc;
|
|
||||||
padding: 5rpx 20rpx;
|
|
||||||
margin-left: 10rpx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.toolbar-height {
|
|
||||||
height: 100rpx;
|
|
||||||
box-sizing: content-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
.toolbar {
|
|
||||||
position: fixed;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: calc(var(--window-bottom));
|
|
||||||
z-index: 1;
|
|
||||||
|
|
||||||
height: 100rpx;
|
|
||||||
padding: 0 20rpx;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: flex-end;
|
|
||||||
border-top: 1rpx solid #ededed;
|
|
||||||
border-bottom: 1rpx solid #ededed;
|
|
||||||
background-color: #fff;
|
|
||||||
box-sizing: content-box;
|
|
||||||
|
|
||||||
.button {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
width: 150rpx;
|
|
||||||
height: 60rpx;
|
|
||||||
margin-left: 15rpx;
|
|
||||||
font-size: 26rpx;
|
|
||||||
border-radius: 72rpx;
|
|
||||||
border: 1rpx solid #ccc;
|
|
||||||
color: #444;
|
|
||||||
}
|
|
||||||
|
|
||||||
.delete {
|
|
||||||
order: 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button {
|
|
||||||
order: 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
.secondary {
|
|
||||||
order: 2;
|
|
||||||
color: #ff5f3c;
|
|
||||||
border-color: #ff5f3c;
|
|
||||||
}
|
|
||||||
|
|
||||||
.primary {
|
|
||||||
order: 1;
|
|
||||||
color: #fff;
|
|
||||||
background-color: #ff5f3c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,221 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import { cleanContent } from '@/utils/common'
|
|
||||||
import { postOrderEvaluateApi } from '@/api/order'
|
|
||||||
import { ref } from 'vue'
|
|
||||||
import { uploadApi } from '@/api/common'
|
|
||||||
|
|
||||||
const props = defineProps<{
|
|
||||||
detail_id?: string
|
|
||||||
order_id?: string
|
|
||||||
}>()
|
|
||||||
|
|
||||||
const content = ref('')
|
|
||||||
const images = ref([])
|
|
||||||
|
|
||||||
const score = ref(5)
|
|
||||||
const rateArr = ['非常差', '差', '一般', '好', '非常好']
|
|
||||||
const rateStr = ref(rateArr[score.value - 1])
|
|
||||||
const onChange = (event: UniHelper.UniRateOnChangeEvent) => {
|
|
||||||
rateStr.value = rateArr[event.value - 1]
|
|
||||||
}
|
|
||||||
|
|
||||||
const tmpPathArr = ref<string[]>([])
|
|
||||||
const imagePathArr = ref<string[]>([])
|
|
||||||
const onSelect = (e: UniHelper.UniFilePickerOnSelectEvent) => {
|
|
||||||
tmpPathArr.value = tmpPathArr.value.concat(e.tempFilePaths)
|
|
||||||
}
|
|
||||||
|
|
||||||
const onDelete = (e: UniHelper.UniFilePickerOnDeleteEvent) => {
|
|
||||||
// 移除图片
|
|
||||||
const index = tmpPathArr.value.findIndex((item) => item === e.tempFilePath)
|
|
||||||
tmpPathArr.value.splice(index, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
const onSubmit = async () => {
|
|
||||||
const uploadPromises = tmpPathArr.value.map((item) => {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
uploadApi(item).then((res) => {
|
|
||||||
// console.log(res)
|
|
||||||
imagePathArr.value.push(res.result.url)
|
|
||||||
resolve(res)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
try {
|
|
||||||
uni.showLoading({
|
|
||||||
title: '数据提交中...',
|
|
||||||
})
|
|
||||||
await Promise.all(uploadPromises)
|
|
||||||
const res = await postOrderEvaluateApi({
|
|
||||||
detail_id: props.detail_id ?? '',
|
|
||||||
order_id: props.order_id ?? '',
|
|
||||||
score: score.value,
|
|
||||||
content: cleanContent(content.value),
|
|
||||||
images: imagePathArr.value.join(','),
|
|
||||||
})
|
|
||||||
if (res.msg) {
|
|
||||||
uni.showToast({
|
|
||||||
title: res.msg,
|
|
||||||
icon: 'error',
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
uni.showToast({
|
|
||||||
title: '评价成功',
|
|
||||||
icon: 'success',
|
|
||||||
})
|
|
||||||
setTimeout(() => {
|
|
||||||
uni.navigateBack({
|
|
||||||
delta: 1,
|
|
||||||
})
|
|
||||||
}, 1500)
|
|
||||||
} catch (err) {
|
|
||||||
// 处理错误
|
|
||||||
console.log(err)
|
|
||||||
uni.showToast({
|
|
||||||
title: '评价失败,请刷新重试',
|
|
||||||
icon: 'none',
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<view class="body">
|
|
||||||
<view class="top">
|
|
||||||
<text class="text">商品评价</text>
|
|
||||||
<view class="rate">
|
|
||||||
<uni-rate v-model="score" @change="onChange" />
|
|
||||||
</view>
|
|
||||||
<text class="rate-text">{{ rateStr }}</text>
|
|
||||||
</view>
|
|
||||||
<view class="content">
|
|
||||||
<uni-easyinput
|
|
||||||
type="textarea"
|
|
||||||
autoHeight
|
|
||||||
v-model="content"
|
|
||||||
placeholder="请输入评价内容"
|
|
||||||
:inputBorder="false"
|
|
||||||
></uni-easyinput>
|
|
||||||
</view>
|
|
||||||
<view class="image">
|
|
||||||
<uni-file-picker
|
|
||||||
v-model="images"
|
|
||||||
file-mediatype="image"
|
|
||||||
mode="grid"
|
|
||||||
file-extname="png,jpg"
|
|
||||||
:limit="9"
|
|
||||||
return-type="array"
|
|
||||||
@select="onSelect"
|
|
||||||
@delete="onDelete"
|
|
||||||
:auto-upload="false"
|
|
||||||
>
|
|
||||||
<view class="upload">
|
|
||||||
<uni-icons type="camera" color="#ff0000" size="30"></uni-icons>
|
|
||||||
<text class="text">添加图片</text>
|
|
||||||
</view>
|
|
||||||
</uni-file-picker>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<shop-submit-button @tap="onSubmit">提交评价</shop-submit-button>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
page {
|
|
||||||
height: 100%;
|
|
||||||
overflow: auto;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
background-color: #f4f4f4;
|
|
||||||
}
|
|
||||||
|
|
||||||
.body {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
border-radius: 10rpx;
|
|
||||||
overflow: hidden;
|
|
||||||
border: 1rpx solid #ccc;
|
|
||||||
|
|
||||||
.top {
|
|
||||||
padding: 20rpx 15rpx 20rpx;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
background-color: #fff;
|
|
||||||
|
|
||||||
.rate {
|
|
||||||
margin: 0 20rpx 0 0rpx;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.text {
|
|
||||||
font-size: 24rpx;
|
|
||||||
color: #333;
|
|
||||||
margin-right: 20rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.rate-text {
|
|
||||||
font-size: 20rpx;
|
|
||||||
color: #666;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
|
||||||
display: flex;
|
|
||||||
background-color: #fff;
|
|
||||||
margin-top: 10rpx;
|
|
||||||
padding: 15rpx;
|
|
||||||
|
|
||||||
.uni-easyinput {
|
|
||||||
width: 100%;
|
|
||||||
font-size: 24rpx;
|
|
||||||
line-height: 1.5;
|
|
||||||
color: #666;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.image {
|
|
||||||
display: flex;
|
|
||||||
background-color: #fff;
|
|
||||||
margin-top: 10rpx;
|
|
||||||
padding: 0;
|
|
||||||
align-items: flex-start;
|
|
||||||
|
|
||||||
.upload {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 24rpx;
|
|
||||||
|
|
||||||
.text {
|
|
||||||
color: #666;
|
|
||||||
font-size: 27rpx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.sub-button {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
position: absolute;
|
|
||||||
bottom: 0;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
.button-container {
|
|
||||||
background-color: white;
|
|
||||||
padding: 10rpx;
|
|
||||||
border-radius: 20rpx;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
width: 100%;
|
|
||||||
background-color: #ff5f3c;
|
|
||||||
color: white;
|
|
||||||
border-radius: 20rpx;
|
|
||||||
text-align: center;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,438 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import { deleteOrderApi, getOrderListApi } from '@/api/order'
|
|
||||||
import type { orderListResult } from '@/types/order'
|
|
||||||
import { ref, watch } from 'vue'
|
|
||||||
import {
|
|
||||||
orderState,
|
|
||||||
orderStateList,
|
|
||||||
orderType,
|
|
||||||
orderStateActions,
|
|
||||||
refundStateList,
|
|
||||||
pageUrl,
|
|
||||||
} from '@/utils/constants'
|
|
||||||
import { fullUrl, getPayPageUrl } from '@/utils/common'
|
|
||||||
import { onShow } from '@dcloudio/uni-app'
|
|
||||||
import cancelButton from '@/pagesOrder/components/cancelButton.vue'
|
|
||||||
import { usePopupStore } from '@/stores'
|
|
||||||
import ReceiveButton from '@/pagesOrder/components/receiveButton.vue'
|
|
||||||
|
|
||||||
// eslint-disable-next-line no-undef
|
|
||||||
const paging = ref<ZPagingInstance>()
|
|
||||||
const dataList = ref<orderListResult[]>([])
|
|
||||||
// 当前组件是否已经加载过了
|
|
||||||
const firstLoaded = ref(false)
|
|
||||||
// 是否滚动到当前页
|
|
||||||
const isCurrentPage = ref(false)
|
|
||||||
|
|
||||||
const props = withDefaults(
|
|
||||||
defineProps<{
|
|
||||||
tabIndex: number
|
|
||||||
currentIndex: number
|
|
||||||
status: string
|
|
||||||
}>(),
|
|
||||||
{
|
|
||||||
tableIndex: 0,
|
|
||||||
currentIndex: 0,
|
|
||||||
status: '',
|
|
||||||
},
|
|
||||||
)
|
|
||||||
const queryList = (page: number, page_size: number) => {
|
|
||||||
const params = {
|
|
||||||
page,
|
|
||||||
page_size,
|
|
||||||
type: orderType.default,
|
|
||||||
status: props.status,
|
|
||||||
}
|
|
||||||
getOrderListApi(params).then((res) => {
|
|
||||||
res.result.data.map((item) => {
|
|
||||||
if (item.status == orderState.toPay && item.countdown < 0) {
|
|
||||||
item.status = orderState.canceled
|
|
||||||
}
|
|
||||||
})
|
|
||||||
paging.value?.complete(res.result.data)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 删除订单
|
|
||||||
const onDeleteOrder = (id: number) => {
|
|
||||||
uni.showModal({
|
|
||||||
content: '确定要删除订单吗?',
|
|
||||||
cancelText: '取消',
|
|
||||||
confirmText: '确定',
|
|
||||||
success: (res) => {
|
|
||||||
if (res.confirm) {
|
|
||||||
deleteOrderApi({
|
|
||||||
id: [id],
|
|
||||||
}).then(() => {
|
|
||||||
uni.showToast({
|
|
||||||
title: '删除成功',
|
|
||||||
icon: 'success',
|
|
||||||
})
|
|
||||||
setTimeout(() => {
|
|
||||||
paging.value?.refresh()
|
|
||||||
}, 1000)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const onCancel = (event: { orderId: number; reason: string }) => {
|
|
||||||
const index = dataList.value.findIndex((v) => v.id == event.orderId)
|
|
||||||
if (index > -1) {
|
|
||||||
dataList.value.splice(index, 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => props.currentIndex,
|
|
||||||
(newVal) => {
|
|
||||||
if (newVal === props.tabIndex) {
|
|
||||||
// 懒加载,当滑动到当前的item时,才去加载
|
|
||||||
if (!firstLoaded.value) {
|
|
||||||
// 这里需要延迟渲染z-paging的原因是为了避免在一些平台上立即渲染可能引发的底层报错问题
|
|
||||||
setTimeout(() => {
|
|
||||||
isCurrentPage.value = true
|
|
||||||
}, 100)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
immediate: true,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
onShow(() => {
|
|
||||||
if (props.currentIndex === props.tabIndex) {
|
|
||||||
paging.value?.refresh()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const backToTop = ref(true)
|
|
||||||
watch(
|
|
||||||
() => usePopupStore().show,
|
|
||||||
(newVal) => {
|
|
||||||
backToTop.value = !newVal
|
|
||||||
},
|
|
||||||
{ immediate: true },
|
|
||||||
)
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- 在这个文件对每个tab对应的列表进行渲染 -->
|
|
||||||
<template>
|
|
||||||
<view class="content">
|
|
||||||
<!-- 如果当前页已经加载过数据或者当前切换到的tab是当前页,才展示当前页数据(懒加载) -->
|
|
||||||
<z-paging
|
|
||||||
:enable-back-to-top="currentIndex === tabIndex"
|
|
||||||
v-if="firstLoaded || isCurrentPage"
|
|
||||||
ref="paging"
|
|
||||||
v-model="dataList"
|
|
||||||
@query="queryList"
|
|
||||||
:fixed="false"
|
|
||||||
:auto-show-back-to-top="backToTop"
|
|
||||||
:back-to-top-style="{
|
|
||||||
display: backToTop ? '' : 'none',
|
|
||||||
}"
|
|
||||||
bg-color="#f6f6f6"
|
|
||||||
>
|
|
||||||
<view class="orders" v-for="(item, index) in dataList" :key="index">
|
|
||||||
<view class="card">
|
|
||||||
<view class="status">
|
|
||||||
<text class="date">{{ item.create_time }}</text>
|
|
||||||
<text v-if="item.status === orderState.applyCancel">
|
|
||||||
{{ refundStateList.find((v) => v.id == item.refund_status)?.text ?? '' }}
|
|
||||||
</text>
|
|
||||||
<text v-else>{{ orderStateList[item.status].text ?? '' }}</text>
|
|
||||||
<text
|
|
||||||
class="icon-delete"
|
|
||||||
v-show="orderStateActions.deletable.includes(item.status)"
|
|
||||||
@tap="onDeleteOrder(item.id)"
|
|
||||||
/>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<navigator
|
|
||||||
v-for="sku in item.detail"
|
|
||||||
:key="sku.id"
|
|
||||||
class="goods"
|
|
||||||
:url="`${pageUrl['order-detail']}?id=${item.id}`"
|
|
||||||
hover-class="none"
|
|
||||||
>
|
|
||||||
<image class="cover" :src="fullUrl(sku.image)"></image>
|
|
||||||
|
|
||||||
<view class="meta">
|
|
||||||
<view class="name ellipsis">{{ sku.goods_name }}</view>
|
|
||||||
<view class="name meta-spec">{{ sku.spec }}</view>
|
|
||||||
<view class="meta-quantity">x{{ sku.num }}</view>
|
|
||||||
</view>
|
|
||||||
</navigator>
|
|
||||||
|
|
||||||
<view class="payment">
|
|
||||||
<text class="quantity">共{{ item.total_num }}件商品</text>
|
|
||||||
<text v-if="orderStateActions.normalTransaction.includes(item.status)">实付</text>
|
|
||||||
<text v-else>应付</text>
|
|
||||||
<text class="amount"> <text class="symbol">¥</text>{{ item.pay_price }}</text>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="action">
|
|
||||||
<template v-if="item.status === orderState.toPay && item.countdown > 0">
|
|
||||||
<text class="pay-time">支付剩余</text>
|
|
||||||
<countdown-timer :time="item.countdown * 1000" :autoStart="true">
|
|
||||||
<template v-slot="{ day, hour, minute, second }">
|
|
||||||
<view v-if="item.countdown > 86400">{{ day }}天{{ hour }}时{{ minute }}分</view>
|
|
||||||
<view v-else-if="item.countdown < 60">{{ second }}秒</view>
|
|
||||||
<view v-else>{{ hour }}时{{ minute }}分</view>
|
|
||||||
</template>
|
|
||||||
</countdown-timer>
|
|
||||||
<cancelButton
|
|
||||||
:status="item.status"
|
|
||||||
:id="item.id"
|
|
||||||
className="button secondary"
|
|
||||||
@cancel="onCancel"
|
|
||||||
/>
|
|
||||||
<navigator
|
|
||||||
class="button primary"
|
|
||||||
:url="getPayPageUrl(item.id, item.pay_price)"
|
|
||||||
hover-class="none"
|
|
||||||
>
|
|
||||||
去支付
|
|
||||||
</navigator>
|
|
||||||
</template>
|
|
||||||
<template v-else>
|
|
||||||
<cancelButton
|
|
||||||
:status="item.status"
|
|
||||||
:id="item.id"
|
|
||||||
className="button secondary"
|
|
||||||
@cancel="onCancel"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<ReceiveButton
|
|
||||||
:status="item.status"
|
|
||||||
:id="item.id"
|
|
||||||
:paymentTradeInfo="item.payment_trade"
|
|
||||||
className="button secondary"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<view v-if="orderStateActions.evaluatable.includes(item.status)">
|
|
||||||
<navigator
|
|
||||||
:url="`${pageUrl['order-evaluate']}?order_id=${item.id}`"
|
|
||||||
class="button secondary"
|
|
||||||
hover-class="none"
|
|
||||||
>
|
|
||||||
一键评价
|
|
||||||
</navigator>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<navigator
|
|
||||||
class="button primary"
|
|
||||||
:url="`${pageUrl['order-create']}?orderId=${item.id}`"
|
|
||||||
hover-class="none"
|
|
||||||
>
|
|
||||||
再次购买
|
|
||||||
</navigator>
|
|
||||||
</template>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</z-paging>
|
|
||||||
</view>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
/* 注意:父节点需要固定高度,z-paging的height:100%才会生效 */
|
|
||||||
.content {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
page {
|
|
||||||
background-color: #f6f6f6;
|
|
||||||
}
|
|
||||||
.orders {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
background-color: #f6f6f6;
|
|
||||||
|
|
||||||
.card {
|
|
||||||
min-height: 100rpx;
|
|
||||||
padding: 20rpx;
|
|
||||||
margin: 20rpx;
|
|
||||||
border-radius: 10rpx;
|
|
||||||
background-color: #fff;
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
padding-bottom: 40rpx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.status {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
font-size: 28rpx;
|
|
||||||
color: #999;
|
|
||||||
margin-bottom: 15rpx;
|
|
||||||
|
|
||||||
.date {
|
|
||||||
color: #666;
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.primary {
|
|
||||||
color: #ff9240;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon-delete {
|
|
||||||
line-height: 1;
|
|
||||||
margin-left: 10rpx;
|
|
||||||
padding-left: 10rpx;
|
|
||||||
border-left: 1rpx solid #e3e3e3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.goods {
|
|
||||||
display: flex;
|
|
||||||
margin-bottom: 20rpx;
|
|
||||||
|
|
||||||
.cover {
|
|
||||||
width: 170rpx;
|
|
||||||
height: 170rpx;
|
|
||||||
margin-right: 20rpx;
|
|
||||||
border-radius: 10rpx;
|
|
||||||
overflow: hidden;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.quantity {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 0;
|
|
||||||
right: 0;
|
|
||||||
line-height: 1;
|
|
||||||
padding: 6rpx 4rpx 6rpx 8rpx;
|
|
||||||
font-size: 24rpx;
|
|
||||||
color: #fff;
|
|
||||||
border-radius: 10rpx 0 0 0;
|
|
||||||
background-color: rgba(0, 0, 0, 0.6);
|
|
||||||
}
|
|
||||||
|
|
||||||
.name {
|
|
||||||
font-size: 26rpx;
|
|
||||||
color: #444;
|
|
||||||
max-width: 90%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.meta {
|
|
||||||
flex: 1;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: space-evenly;
|
|
||||||
|
|
||||||
.meta-spec {
|
|
||||||
font-size: 24rpx;
|
|
||||||
color: #999;
|
|
||||||
margin-top: 10rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-quantity {
|
|
||||||
position: absolute;
|
|
||||||
right: 20px;
|
|
||||||
font-size: 24rpx;
|
|
||||||
color: #9e9c9c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.type {
|
|
||||||
line-height: 1.8;
|
|
||||||
padding: 0 15rpx;
|
|
||||||
margin-top: 10rpx;
|
|
||||||
font-size: 24rpx;
|
|
||||||
align-self: flex-start;
|
|
||||||
border-radius: 4rpx;
|
|
||||||
color: #888;
|
|
||||||
background-color: #f7f7f8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.more {
|
|
||||||
flex: 1;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
font-size: 22rpx;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.payment {
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
align-items: center;
|
|
||||||
line-height: 1;
|
|
||||||
padding: 20rpx 0;
|
|
||||||
text-align: right;
|
|
||||||
color: #999;
|
|
||||||
font-size: 28rpx;
|
|
||||||
border-bottom: 1rpx solid #eee;
|
|
||||||
|
|
||||||
.quantity {
|
|
||||||
font-size: 24rpx;
|
|
||||||
margin-right: 16rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.amount {
|
|
||||||
color: #444;
|
|
||||||
margin-left: 6rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.symbol {
|
|
||||||
font-size: 20rpx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.action {
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
align-items: center;
|
|
||||||
padding-top: 20rpx;
|
|
||||||
|
|
||||||
.pay-time {
|
|
||||||
font-size: 24rpx;
|
|
||||||
color: #999;
|
|
||||||
margin-right: 20rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.countdown {
|
|
||||||
font-size: 24rpx;
|
|
||||||
color: #999;
|
|
||||||
margin-left: auto;
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button {
|
|
||||||
width: 150rpx;
|
|
||||||
height: 60rpx;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
margin-left: 20rpx;
|
|
||||||
border-radius: 60rpx;
|
|
||||||
border: 1rpx solid #ccc;
|
|
||||||
font-size: 26rpx;
|
|
||||||
color: #444;
|
|
||||||
}
|
|
||||||
|
|
||||||
.secondary {
|
|
||||||
color: #ff5f3c;
|
|
||||||
border-color: #ff5f3c;
|
|
||||||
}
|
|
||||||
|
|
||||||
.primary {
|
|
||||||
color: #fff;
|
|
||||||
background-color: #ff5f3c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.loading-text {
|
|
||||||
text-align: center;
|
|
||||||
font-size: 28rpx;
|
|
||||||
color: #666;
|
|
||||||
padding: 20rpx 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,119 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import { ref, watch } from 'vue'
|
|
||||||
import orderListItem from '@/pagesOrder/pages/list/components/order-list-item.vue'
|
|
||||||
import { usePopupStore } from '@/stores'
|
|
||||||
import { pageMateStyle } from '@/utils/constants'
|
|
||||||
|
|
||||||
//页面传参
|
|
||||||
const query = withDefaults(
|
|
||||||
defineProps<{
|
|
||||||
status?: string
|
|
||||||
}>(),
|
|
||||||
{
|
|
||||||
status: '',
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
const tabs = ref()
|
|
||||||
const tabList = ref([
|
|
||||||
{
|
|
||||||
name: '全部',
|
|
||||||
value: '',
|
|
||||||
disabled: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '待付款',
|
|
||||||
value: '1',
|
|
||||||
disabled: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '待发货',
|
|
||||||
value: '2',
|
|
||||||
disabled: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '待收货',
|
|
||||||
value: '3',
|
|
||||||
disabled: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '待评价',
|
|
||||||
value: '4',
|
|
||||||
disabled: false,
|
|
||||||
},
|
|
||||||
])
|
|
||||||
|
|
||||||
// 当前tab下标
|
|
||||||
const sub = tabList.value.findIndex((item) => item.value == query.status)
|
|
||||||
const current = ref(sub == -1 ? 0 : sub)
|
|
||||||
// tabs通知swiper切换
|
|
||||||
const tabsChange = (index: number) => {
|
|
||||||
current.value = index
|
|
||||||
}
|
|
||||||
|
|
||||||
// swiper滑动中
|
|
||||||
const swiperTransition = (e: UniHelper.SwiperOnTransitionEvent) => {
|
|
||||||
if (!current.value) {
|
|
||||||
tabs.value.setDx(e.detail.dx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// swiper滑动结束
|
|
||||||
const swiperAnimationfinish = (e: UniHelper.SwiperOnAnimationfinishEvent) => {
|
|
||||||
current.value = e.detail.current
|
|
||||||
if (current.value) {
|
|
||||||
tabs.value.unlockDx()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => usePopupStore().show,
|
|
||||||
(newVal) => {
|
|
||||||
tabList.value.forEach((item) => (item.disabled = newVal))
|
|
||||||
},
|
|
||||||
{ immediate: true },
|
|
||||||
)
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<!-- #ifdef MP-WEIXIN-->
|
|
||||||
<page-mate :pageStyle="pageMateStyle">
|
|
||||||
<!-- #endif -->
|
|
||||||
<z-paging-swiper>
|
|
||||||
<template #top>
|
|
||||||
<z-tabs
|
|
||||||
ref="tabs"
|
|
||||||
:list="tabList"
|
|
||||||
:current="current"
|
|
||||||
@change="tabsChange"
|
|
||||||
bg-color="#f6f6f6"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
<swiper
|
|
||||||
class="swiper"
|
|
||||||
:current="current"
|
|
||||||
@transition="swiperTransition"
|
|
||||||
@animationfinish="swiperAnimationfinish"
|
|
||||||
>
|
|
||||||
<swiper-item class="swiper-item" v-for="(item, index) in tabList" :key="index">
|
|
||||||
<order-list-item
|
|
||||||
:tabIndex="index"
|
|
||||||
:currentIndex="current"
|
|
||||||
:status="tabList[current].value"
|
|
||||||
></order-list-item>
|
|
||||||
</swiper-item>
|
|
||||||
</swiper>
|
|
||||||
</z-paging-swiper>
|
|
||||||
<!-- #ifdef MP-WEIXIN -->
|
|
||||||
</page-mate>
|
|
||||||
<!-- #endif -->
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
page {
|
|
||||||
background-color: #f6f6f6;
|
|
||||||
}
|
|
||||||
.swiper {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,244 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import { pageUrl } from '@/utils/constants'
|
|
||||||
import { getMemberProfileApi } from '@/api/member'
|
|
||||||
import { payOrderApi } from '@/api/pay'
|
|
||||||
import _ from 'lodash'
|
|
||||||
import { computed, reactive, ref } from 'vue'
|
|
||||||
import { onShowRefreshData } from '@/utils/common'
|
|
||||||
|
|
||||||
// 获取页面参数
|
|
||||||
const props = defineProps<{
|
|
||||||
orderId: string
|
|
||||||
payPrice: string
|
|
||||||
}>()
|
|
||||||
|
|
||||||
const state = reactive({
|
|
||||||
orderId: Number(props.orderId),
|
|
||||||
balance: '0.00',
|
|
||||||
})
|
|
||||||
|
|
||||||
const getBalance = async () => {
|
|
||||||
const res = await getMemberProfileApi()
|
|
||||||
state.balance = res.result.money || '0.00'
|
|
||||||
}
|
|
||||||
|
|
||||||
const payMethods = computed(() => {
|
|
||||||
return [
|
|
||||||
// #ifdef WEB
|
|
||||||
{
|
|
||||||
name: '支付宝支付',
|
|
||||||
value: 'alipay',
|
|
||||||
icon: '/static/icons/alipay.svg',
|
|
||||||
},
|
|
||||||
// #endif
|
|
||||||
{
|
|
||||||
name: '微信支付',
|
|
||||||
value: 'wxpay',
|
|
||||||
icon: '/static/icons/wechat-pay.svg',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: `余额支付(可用¥${state.balance})`,
|
|
||||||
value: 'balance',
|
|
||||||
icon: '/static/icons/balance.svg',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
})
|
|
||||||
|
|
||||||
const current = ref()
|
|
||||||
const payWay = ref('')
|
|
||||||
|
|
||||||
const radioChange = (event: UniHelper.RadioGroupOnChangeEvent) => {
|
|
||||||
payWay.value = event.detail.value
|
|
||||||
}
|
|
||||||
|
|
||||||
const onPayment = async () => {
|
|
||||||
if (!payWay.value) {
|
|
||||||
return uni.showToast({
|
|
||||||
title: '请选择支付方式',
|
|
||||||
icon: 'none',
|
|
||||||
mask: true,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if (payWay.value === 'balance' && parseFloat(props.payPrice) > parseFloat(state.balance)) {
|
|
||||||
return uni.showToast({
|
|
||||||
title: '很抱歉,您的余额不足',
|
|
||||||
icon: 'none',
|
|
||||||
mask: true,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
const res = await payOrderApi({
|
|
||||||
id: state.orderId,
|
|
||||||
pay_way: payWay.value,
|
|
||||||
})
|
|
||||||
switch (payWay.value) {
|
|
||||||
case 'wxpay':
|
|
||||||
if (uni.getSystemInfoSync().uniPlatform === 'web') {
|
|
||||||
doH5Wxpay(res)
|
|
||||||
} else {
|
|
||||||
doWxPay(res.result)
|
|
||||||
}
|
|
||||||
break
|
|
||||||
case 'alipay':
|
|
||||||
doAlipay(res)
|
|
||||||
break
|
|
||||||
case 'balance':
|
|
||||||
successHandle()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
} catch (err: any) {
|
|
||||||
console.log(err)
|
|
||||||
// 捕获异常并处理
|
|
||||||
uni.showModal({
|
|
||||||
title: '提示',
|
|
||||||
content: err.data.msg || '支付失败',
|
|
||||||
showCancel: false,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const doWxPay = async (result: WechatMiniprogram.RequestPaymentOption) => {
|
|
||||||
wx.requestPayment({
|
|
||||||
...result,
|
|
||||||
success: () => {
|
|
||||||
successHandle()
|
|
||||||
},
|
|
||||||
fail: (fail) => {
|
|
||||||
failHandle(fail)
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const doH5Wxpay = (res: any) => {
|
|
||||||
wx.showLoading({
|
|
||||||
title: '正在支付…',
|
|
||||||
mask: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
location.href = res.result.h5_url
|
|
||||||
}
|
|
||||||
|
|
||||||
const doAlipay = (res: any) => {
|
|
||||||
wx.showLoading({
|
|
||||||
title: '正在支付…',
|
|
||||||
mask: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
location.href = res.result.url
|
|
||||||
}
|
|
||||||
|
|
||||||
const successHandle = () => {
|
|
||||||
setTimeout(() => {
|
|
||||||
uni.redirectTo({
|
|
||||||
url: `${pageUrl['order-payment']}?id=${state.orderId}&pay_way=${payWay.value}`,
|
|
||||||
})
|
|
||||||
}, 500)
|
|
||||||
}
|
|
||||||
const failHandle = (err: any) => {
|
|
||||||
console.warn('支付异常:')
|
|
||||||
console.warn(err)
|
|
||||||
if (err.errMsg == 'requestPayment:fail cancel') {
|
|
||||||
uni.showToast({
|
|
||||||
title: '订单取消支付~',
|
|
||||||
icon: 'none',
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
uni.showToast({
|
|
||||||
title: err.data.msg ? err.data.msg : '支付未完成',
|
|
||||||
icon: 'none',
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onShowRefreshData(() => {
|
|
||||||
getBalance()
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<view class="overview">
|
|
||||||
<view class="money">
|
|
||||||
<span class="currency">¥</span>
|
|
||||||
<span class="integer">{{ props.payPrice.split('.')[0] }}.</span>
|
|
||||||
<span class="decimal">{{ props.payPrice.split('.')[1] }}</span>
|
|
||||||
</view>
|
|
||||||
<view class="payment">
|
|
||||||
<radio-group @change="radioChange" class="card">
|
|
||||||
<label class="item" v-for="(item, index) in payMethods" :key="item.value">
|
|
||||||
<view class="method">
|
|
||||||
<span><image :src="item.icon" class="icon" /></span>
|
|
||||||
{{ item.name }}
|
|
||||||
</view>
|
|
||||||
<view>
|
|
||||||
<radio :value="item.value" :checked="current === index" />
|
|
||||||
</view>
|
|
||||||
</label>
|
|
||||||
</radio-group>
|
|
||||||
</view>
|
|
||||||
<shop-submit-button title="确认支付" @tap="onPayment"></shop-submit-button>
|
|
||||||
</view>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
page {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
height: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
background: #f0f0f0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.overview {
|
|
||||||
background-color: #f0f0f0;
|
|
||||||
|
|
||||||
.money {
|
|
||||||
padding: 5%;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
position: relative;
|
|
||||||
color: red;
|
|
||||||
font-size: 50rpx;
|
|
||||||
|
|
||||||
.currency {
|
|
||||||
font-size: 35rpx;
|
|
||||||
vertical-align: sub;
|
|
||||||
align-self: flex-end;
|
|
||||||
}
|
|
||||||
|
|
||||||
.integer {
|
|
||||||
font-size: 60rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.decimal {
|
|
||||||
font-size: 50rpx;
|
|
||||||
align-self: flex-end;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.payment {
|
|
||||||
margin: 20rpx 20rpx 0;
|
|
||||||
padding: auto;
|
|
||||||
border-radius: 10rpx;
|
|
||||||
background-color: #fff;
|
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
||||||
|
|
||||||
.item {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
padding: 5%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.method {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
width: 40rpx;
|
|
||||||
height: 40rpx;
|
|
||||||
margin-right: 20rpx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,133 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import { pageUrl } from '@/utils/constants'
|
|
||||||
import { onShow } from '@dcloudio/uni-app'
|
|
||||||
import { postPayNotifyApi } from '@/api/pay'
|
|
||||||
import { ref } from 'vue'
|
|
||||||
|
|
||||||
// 获取页面参数
|
|
||||||
const query = defineProps<{
|
|
||||||
id: number | string
|
|
||||||
pay_way: string
|
|
||||||
}>()
|
|
||||||
|
|
||||||
const isPay = ref(false)
|
|
||||||
|
|
||||||
const checkPay = () => {
|
|
||||||
if (query.pay_way === 'balance') {
|
|
||||||
isPay.value = true
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
postPayNotifyApi({
|
|
||||||
id: Number(query.id),
|
|
||||||
pay_way: query.pay_way,
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
isPay.value = true
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
console.warn(err)
|
|
||||||
if (err.errMsg == 'requestPayment:fail cancel') {
|
|
||||||
uni.showToast({
|
|
||||||
title: '订单取消支付~',
|
|
||||||
icon: 'none',
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
uni.showToast({
|
|
||||||
title: err.data.msg ? err.data.msg : '支付未完成',
|
|
||||||
icon: 'none',
|
|
||||||
})
|
|
||||||
}
|
|
||||||
setTimeout(() => {
|
|
||||||
uni.redirectTo({
|
|
||||||
url: `${pageUrl['order-list']}`,
|
|
||||||
})
|
|
||||||
}, 500)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
onShow(() => {
|
|
||||||
checkPay()
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<scroll-view enable-back-to-top class="viewport" scroll-y>
|
|
||||||
<!-- 订单状态 -->
|
|
||||||
<view class="overview" v-if="isPay">
|
|
||||||
<view class="status icon-checked">支付成功</view>
|
|
||||||
<view class="buttons">
|
|
||||||
<navigator
|
|
||||||
hover-class="none"
|
|
||||||
class="button navigator"
|
|
||||||
:url="`${pageUrl['index']}`"
|
|
||||||
open-type="switchTab"
|
|
||||||
>
|
|
||||||
返回首页
|
|
||||||
</navigator>
|
|
||||||
<navigator
|
|
||||||
hover-class="none"
|
|
||||||
class="button navigator"
|
|
||||||
:url="`${pageUrl['order-detail']}?id=${query.id}`"
|
|
||||||
open-type="redirect"
|
|
||||||
>
|
|
||||||
查看订单
|
|
||||||
</navigator>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</scroll-view>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
page {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
height: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.viewport {
|
|
||||||
background-color: #f7f7f8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.overview {
|
|
||||||
line-height: 1;
|
|
||||||
padding: 50rpx 0;
|
|
||||||
color: #fff;
|
|
||||||
background-color: #ff7c22;
|
|
||||||
|
|
||||||
.status {
|
|
||||||
font-size: 36rpx;
|
|
||||||
font-weight: 500;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status::before {
|
|
||||||
display: block;
|
|
||||||
font-size: 110rpx;
|
|
||||||
margin-bottom: 20rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.buttons {
|
|
||||||
height: 60rpx;
|
|
||||||
line-height: 60rpx;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
margin-top: 60rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button {
|
|
||||||
text-align: center;
|
|
||||||
margin: 0 10rpx;
|
|
||||||
font-size: 28rpx;
|
|
||||||
color: #fff;
|
|
||||||
|
|
||||||
&:first-child {
|
|
||||||
width: 200rpx;
|
|
||||||
border-radius: 64rpx;
|
|
||||||
border: 1rpx solid #fff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,89 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import { ref } from 'vue'
|
|
||||||
import { pageUrl } from '@/utils/constants'
|
|
||||||
|
|
||||||
// 获取页面参数
|
|
||||||
const query = defineProps<{
|
|
||||||
id: number
|
|
||||||
}>()
|
|
||||||
|
|
||||||
const back = () => {
|
|
||||||
uni.navigateBack({ delta: 1 })
|
|
||||||
}
|
|
||||||
|
|
||||||
const orderId = ref(query.id)
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<scroll-view enable-back-to-top class="viewport" scroll-y>
|
|
||||||
<!-- 订单状态 -->
|
|
||||||
<view class="overview">
|
|
||||||
<view class="status icon-checked">收货成功</view>
|
|
||||||
<view class="buttons">
|
|
||||||
<view class="button navigator" @tap="back"> 返回 </view>
|
|
||||||
<navigator
|
|
||||||
hover-class="none"
|
|
||||||
class="button navigator"
|
|
||||||
:url="`${pageUrl['order-evaluate']}?order_id=${orderId}`"
|
|
||||||
open-type="redirect"
|
|
||||||
>
|
|
||||||
去评价
|
|
||||||
</navigator>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</scroll-view>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
page {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
height: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.viewport {
|
|
||||||
background-color: #f7f7f8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.overview {
|
|
||||||
line-height: 1;
|
|
||||||
padding: 50rpx 0;
|
|
||||||
color: #fff;
|
|
||||||
background-color: #ff7c22;
|
|
||||||
|
|
||||||
.status {
|
|
||||||
font-size: 36rpx;
|
|
||||||
font-weight: 500;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status::before {
|
|
||||||
display: block;
|
|
||||||
font-size: 110rpx;
|
|
||||||
margin-bottom: 20rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.buttons {
|
|
||||||
height: 60rpx;
|
|
||||||
line-height: 60rpx;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
margin-top: 60rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button {
|
|
||||||
text-align: center;
|
|
||||||
margin: 0 10rpx;
|
|
||||||
font-size: 28rpx;
|
|
||||||
color: #fff;
|
|
||||||
|
|
||||||
&:first-child {
|
|
||||||
width: 200rpx;
|
|
||||||
border-radius: 64rpx;
|
|
||||||
border: 1rpx solid #fff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,77 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import { getRechargeOrderListApi } from '@/api/recharge'
|
|
||||||
import { onShowRefreshData } from '@/utils/common'
|
|
||||||
import type { rechargeOrderListItem } from '@/types/member'
|
|
||||||
import { ref } from 'vue'
|
|
||||||
|
|
||||||
// eslint-disable-next-line no-undef
|
|
||||||
const paging = ref<ZPagingInstance>()
|
|
||||||
const dataList = ref<rechargeOrderListItem[]>([])
|
|
||||||
const queryList = (page: number, page_size: number) => {
|
|
||||||
getRechargeOrderListApi({
|
|
||||||
page,
|
|
||||||
page_size,
|
|
||||||
}).then((res) => {
|
|
||||||
paging.value?.complete(res.result.data)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const getRechargeDesc = (item: rechargeOrderListItem) => {
|
|
||||||
let str = ''
|
|
||||||
if (parseFloat(item.gift_money) > 0) {
|
|
||||||
str += `充值${item.money}元,赠送${item.gift_money}元`
|
|
||||||
} else {
|
|
||||||
str += `充值${item.money}元`
|
|
||||||
}
|
|
||||||
if (item.pay_status == 1) {
|
|
||||||
str += '(充值中)'
|
|
||||||
} else if (item.pay_status == 2) {
|
|
||||||
str += '(已到账)'
|
|
||||||
}
|
|
||||||
|
|
||||||
return str
|
|
||||||
}
|
|
||||||
|
|
||||||
onShowRefreshData(() => {
|
|
||||||
paging.value?.refresh()
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
<template>
|
|
||||||
<shop-paginate-list ref="paging" v-model="dataList" @query="queryList">
|
|
||||||
<uni-list class="list">
|
|
||||||
<uni-list-item
|
|
||||||
v-for="(item, index) in dataList"
|
|
||||||
:key="index"
|
|
||||||
class="item"
|
|
||||||
:title="item.order_no"
|
|
||||||
:note="getRechargeDesc(item)"
|
|
||||||
>
|
|
||||||
<template #footer>
|
|
||||||
<view class="right">
|
|
||||||
<text class="time">{{ item.create_time }}</text>
|
|
||||||
<text class="money"> +{{ item.actual_money }}元 </text>
|
|
||||||
</view>
|
|
||||||
</template>
|
|
||||||
</uni-list-item>
|
|
||||||
</uni-list>
|
|
||||||
</shop-paginate-list>
|
|
||||||
</template>
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.item {
|
|
||||||
line-height: 1.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.right {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: flex-end;
|
|
||||||
}
|
|
||||||
|
|
||||||
.time {
|
|
||||||
font-size: 24rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.money {
|
|
||||||
color: red;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,545 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import { fullUrl, previewImg } from '@/utils/common'
|
|
||||||
import { getDeliveryCompanyApi } from '@/api/delivery'
|
|
||||||
import { getOrderRefundDetailApi, postOrderRefundReturnApi } from '@/api/order'
|
|
||||||
import type { deliveryCompanyItem } from '@/types/delivery'
|
|
||||||
import type { orderRefundDetailResult } from '@/types/order'
|
|
||||||
import { onLoad } from '@dcloudio/uni-app'
|
|
||||||
import { computed } from 'vue'
|
|
||||||
import { ref } from 'vue'
|
|
||||||
import { pageUrl } from '@/utils/constants'
|
|
||||||
|
|
||||||
const props = defineProps<{
|
|
||||||
data: string
|
|
||||||
id: number
|
|
||||||
}>()
|
|
||||||
|
|
||||||
const orderData = ref<orderRefundDetailResult>()
|
|
||||||
|
|
||||||
const getOrderData = async () => {
|
|
||||||
const res = await getOrderRefundDetailApi({ id: props.id })
|
|
||||||
orderData.value = res.result
|
|
||||||
}
|
|
||||||
|
|
||||||
// 审核状态
|
|
||||||
enum auditStatusEnum {
|
|
||||||
wait_audit = 1,
|
|
||||||
agree = 2,
|
|
||||||
refuse = 3,
|
|
||||||
cancel = 4,
|
|
||||||
}
|
|
||||||
|
|
||||||
// 显示协商历史
|
|
||||||
const showHistory = computed(() => {
|
|
||||||
return orderData.value?.audit_status == auditStatusEnum.refuse
|
|
||||||
})
|
|
||||||
// 显示退货地址
|
|
||||||
const showDelivery = computed(() => {
|
|
||||||
return orderData.value?.audit_status == auditStatusEnum.agree && orderData.value.refund_address
|
|
||||||
})
|
|
||||||
// 复制地址
|
|
||||||
const copyAddress = () => {
|
|
||||||
const fullAddress = `收货人:${orderData.value?.refund_address.name}联系电话:${orderData.value?.refund_address.phone}详细地址:${orderData.value?.refund_address.full_address}`
|
|
||||||
|
|
||||||
uni.setClipboardData({
|
|
||||||
data: fullAddress,
|
|
||||||
success: () => {
|
|
||||||
uni.showToast({
|
|
||||||
title: '复制成功',
|
|
||||||
icon: 'none',
|
|
||||||
})
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const deliveryCompanyOptions = ref<deliveryCompanyItem[]>([])
|
|
||||||
const companyIndex = ref(0)
|
|
||||||
|
|
||||||
const getDeliveryCompanyData = async () => {
|
|
||||||
// 有物流信息时不请求
|
|
||||||
if (deliverForm.value.delivery_company && deliverForm.value.delivery_no) return
|
|
||||||
|
|
||||||
const res = await getDeliveryCompanyApi()
|
|
||||||
res.result.unshift({ id: 0, name: '请选择物流公司', code: '' })
|
|
||||||
deliveryCompanyOptions.value = res.result
|
|
||||||
}
|
|
||||||
|
|
||||||
const deliverForm = ref({
|
|
||||||
delivery_company_id: 0,
|
|
||||||
delivery_company: '',
|
|
||||||
delivery_no: '',
|
|
||||||
})
|
|
||||||
const deliverFormRules = ref({
|
|
||||||
delivery_no: {
|
|
||||||
rules: [{ required: true, errorMessage: '请输入物流单号' }],
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const onChnageCompanyIndex = (event: UniHelper.SelectorPickerOnChangeEvent) => {
|
|
||||||
companyIndex.value = event.detail.value
|
|
||||||
const deliveryCompany = deliveryCompanyOptions.value.find((item) => item.id == companyIndex.value)
|
|
||||||
|
|
||||||
deliverForm.value.delivery_company_id = deliveryCompany!.id
|
|
||||||
deliverForm.value.delivery_company = deliveryCompany!.name
|
|
||||||
}
|
|
||||||
|
|
||||||
const formRef = ref()
|
|
||||||
const onSubmit = async () => {
|
|
||||||
if (!deliverForm.value.delivery_company_id) {
|
|
||||||
uni.showToast({
|
|
||||||
title: '请选择物流公司',
|
|
||||||
icon: 'none',
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
await formRef.value.validate()
|
|
||||||
const params = {
|
|
||||||
id: props.id,
|
|
||||||
...deliverForm.value,
|
|
||||||
}
|
|
||||||
const res = await postOrderRefundReturnApi(params)
|
|
||||||
uni.showToast({
|
|
||||||
title: res.msg,
|
|
||||||
icon: 'none',
|
|
||||||
})
|
|
||||||
setTimeout(() => {
|
|
||||||
uni.navigateBack()
|
|
||||||
}, 1500)
|
|
||||||
}
|
|
||||||
|
|
||||||
const refundTypeText = computed(() => {
|
|
||||||
switch (orderData.value?.refund_type) {
|
|
||||||
case 1:
|
|
||||||
return '退货退款'
|
|
||||||
case 2:
|
|
||||||
return '换货'
|
|
||||||
default:
|
|
||||||
return ''
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
onLoad(async () => {
|
|
||||||
await getOrderData()
|
|
||||||
await getDeliveryCompanyData()
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<view class="detail" v-if="orderData">
|
|
||||||
<view class="status">
|
|
||||||
<image class="image" src="/static/images/bg.png" />
|
|
||||||
<text>{{ orderData.status_text }}</text>
|
|
||||||
</view>
|
|
||||||
<view class="order">
|
|
||||||
<view class="card">
|
|
||||||
<text class="title">售后商品</text>
|
|
||||||
<navigator
|
|
||||||
class="goods"
|
|
||||||
:url="`${pageUrl['goods-detail']}?id=${orderData.detail.goods_id}`"
|
|
||||||
hover-class="none"
|
|
||||||
>
|
|
||||||
<image class="cover" :src="fullUrl(orderData.detail.image)"></image>
|
|
||||||
<view class="meta">
|
|
||||||
<view class="name ellipsis">{{ orderData.detail.goods_name }}</view>
|
|
||||||
<view class="meta-spec">{{ orderData.detail.spec }}</view>
|
|
||||||
<view class="meta-quantity">x{{ orderData!.refund_num }}</view>
|
|
||||||
</view>
|
|
||||||
</navigator>
|
|
||||||
<view class="detail">
|
|
||||||
<view class="detail-item" v-if="parseFloat(orderData.apply_money) > 0">
|
|
||||||
<text>申请金额</text>
|
|
||||||
<text class="amount">¥{{ orderData.apply_money }}</text>
|
|
||||||
</view>
|
|
||||||
<view class="detail-item" v-if="parseFloat(orderData.refund_money) > 0">
|
|
||||||
<text>退款金额</text>
|
|
||||||
<text class="amount">¥{{ orderData.refund_money }}</text>
|
|
||||||
</view>
|
|
||||||
<view class="detail-item" v-if="parseFloat(orderData.refund_freight) > 0">
|
|
||||||
<text>退款运费</text>
|
|
||||||
<text>¥{{ orderData.refund_freight }}</text>
|
|
||||||
</view>
|
|
||||||
<view class="detail-item">
|
|
||||||
<text>申请时间</text>
|
|
||||||
<text>{{ orderData.create_time }}</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="block" v-if="showHistory">
|
|
||||||
<view class="history">
|
|
||||||
<view class="header">
|
|
||||||
<text class="title">协商历史</text>
|
|
||||||
</view>
|
|
||||||
<view class="history-item">
|
|
||||||
<text>售后类型:{{ refundTypeText }}</text>
|
|
||||||
</view>
|
|
||||||
<view class="history-item">
|
|
||||||
<text>申请原因:{{ orderData.remark }}</text>
|
|
||||||
</view>
|
|
||||||
<view class="history-item" v-if="orderData.remark_images">
|
|
||||||
<text>申请凭证:</text>
|
|
||||||
<view class="images-container">
|
|
||||||
<image
|
|
||||||
v-for="(item, index) in orderData.remark_images"
|
|
||||||
:key="index"
|
|
||||||
:src="item"
|
|
||||||
mode="aspectFit"
|
|
||||||
@tap="previewImg(item, orderData!.remark_images)"
|
|
||||||
/>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="history-item" v-if="orderData.refuse_reason">
|
|
||||||
<text>商家回复:{{ orderData.refuse_reason }}</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="block" v-if="showDelivery">
|
|
||||||
<view class="address">
|
|
||||||
<view class="header">
|
|
||||||
<text class="title">退货地址</text>
|
|
||||||
<button class="copy-button" @tap="copyAddress">复制</button>
|
|
||||||
</view>
|
|
||||||
<view>
|
|
||||||
<text>收货人:{{ orderData.refund_address.name }}</text>
|
|
||||||
</view>
|
|
||||||
<view>
|
|
||||||
<text>联系电话:{{ orderData.refund_address.phone }}</text>
|
|
||||||
</view>
|
|
||||||
<view>
|
|
||||||
<text>详细地址:{{ orderData.refund_address.full_address }}</text>
|
|
||||||
</view>
|
|
||||||
<view class="remark">
|
|
||||||
<text>未与商家协商一致情况下,请勿使用平邮或到付邮寄方式</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="block" v-if="showDelivery">
|
|
||||||
<view class="delivery">
|
|
||||||
<view class="header">
|
|
||||||
<text class="title">退货物流</text>
|
|
||||||
</view>
|
|
||||||
<uni-list v-if="orderData.user_ship_delivery">
|
|
||||||
<uni-list-item
|
|
||||||
title="物流公司"
|
|
||||||
:rightText="orderData.user_ship_delivery.delivery_company"
|
|
||||||
>
|
|
||||||
</uni-list-item>
|
|
||||||
<uni-list-item title="物流单号" :rightText="orderData.user_ship_delivery.delivery_no">
|
|
||||||
</uni-list-item>
|
|
||||||
</uni-list>
|
|
||||||
<view v-else>
|
|
||||||
<uni-forms
|
|
||||||
ref="formRef"
|
|
||||||
label-width="100"
|
|
||||||
validate-trigger="blur"
|
|
||||||
:rules="deliverFormRules"
|
|
||||||
:model="deliverForm"
|
|
||||||
>
|
|
||||||
<uni-forms-item required label="物流公司" name="delivery_company">
|
|
||||||
<view style="display: flex; align-items: center; height: 35px">
|
|
||||||
<picker
|
|
||||||
mode="selector"
|
|
||||||
:range="deliveryCompanyOptions"
|
|
||||||
range-key="name"
|
|
||||||
:value="companyIndex"
|
|
||||||
@change="onChnageCompanyIndex"
|
|
||||||
>
|
|
||||||
<text>{{ deliveryCompanyOptions[companyIndex]?.name }}</text>
|
|
||||||
</picker>
|
|
||||||
</view>
|
|
||||||
</uni-forms-item>
|
|
||||||
<uni-forms-item required label="物流单号" name="delivery_no">
|
|
||||||
<uni-easyinput
|
|
||||||
v-model="deliverForm.delivery_no"
|
|
||||||
placeholder="请输入物流单号"
|
|
||||||
:disabled="Boolean(orderData.user_ship_status)"
|
|
||||||
/>
|
|
||||||
</uni-forms-item>
|
|
||||||
</uni-forms>
|
|
||||||
<button class="sub-button" @tap="onSubmit" v-if="!Boolean(orderData.user_ship_status)">
|
|
||||||
录入物流信息
|
|
||||||
</button>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="block" v-if="orderData.exchange_delivery">
|
|
||||||
<view class="delivery">
|
|
||||||
<view class="header">
|
|
||||||
<text class="title">换货物流</text>
|
|
||||||
</view>
|
|
||||||
<uni-list>
|
|
||||||
<uni-list-item title="物流公司" :rightText="orderData.exchange_delivery.delivery_company">
|
|
||||||
</uni-list-item>
|
|
||||||
<uni-list-item title="物流单号" :rightText="orderData.exchange_delivery.delivery_no">
|
|
||||||
</uni-list-item>
|
|
||||||
</uni-list>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view :style="{ paddingBottom: '100rpx' }"></view>
|
|
||||||
</view>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
page {
|
|
||||||
background-color: #f6f6f6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
position: relative;
|
|
||||||
height: 150rpx;
|
|
||||||
|
|
||||||
/* 图片样式 */
|
|
||||||
.image {
|
|
||||||
width: 100%;
|
|
||||||
height: 150rpx;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 文本样式 */
|
|
||||||
text {
|
|
||||||
z-index: 1;
|
|
||||||
font-size: 36rpx;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.order {
|
|
||||||
height: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
background-color: #f6f6f6;
|
|
||||||
|
|
||||||
.card {
|
|
||||||
min-height: 100rpx;
|
|
||||||
padding: 20rpx;
|
|
||||||
margin: 20rpx 20rpx 0;
|
|
||||||
border-radius: 10rpx;
|
|
||||||
background-color: #fff;
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
padding-bottom: 40rpx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.status {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
font-size: 28rpx;
|
|
||||||
color: #999;
|
|
||||||
margin-bottom: 15rpx;
|
|
||||||
|
|
||||||
.date {
|
|
||||||
color: #666;
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.text {
|
|
||||||
color: red;
|
|
||||||
}
|
|
||||||
|
|
||||||
.primary {
|
|
||||||
color: #ff9240;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon-delete {
|
|
||||||
line-height: 1;
|
|
||||||
margin-left: 10rpx;
|
|
||||||
padding-left: 10rpx;
|
|
||||||
border-left: 1rpx solid #e3e3e3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.goods {
|
|
||||||
display: flex;
|
|
||||||
padding-top: 20rpx;
|
|
||||||
padding-bottom: 20rpx;
|
|
||||||
|
|
||||||
.cover {
|
|
||||||
width: 170rpx;
|
|
||||||
height: 170rpx;
|
|
||||||
margin-right: 20rpx;
|
|
||||||
border-radius: 10rpx;
|
|
||||||
overflow: hidden;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.quantity {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 0;
|
|
||||||
right: 0;
|
|
||||||
line-height: 1;
|
|
||||||
padding: 6rpx 4rpx 6rpx 8rpx;
|
|
||||||
font-size: 24rpx;
|
|
||||||
color: #fff;
|
|
||||||
border-radius: 10rpx 0 0 0;
|
|
||||||
background-color: rgba(0, 0, 0, 0.6);
|
|
||||||
}
|
|
||||||
|
|
||||||
.meta {
|
|
||||||
flex: 1;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: space-around;
|
|
||||||
|
|
||||||
&-spec {
|
|
||||||
font-size: 24rpx;
|
|
||||||
color: #999;
|
|
||||||
margin-top: 10rpx;
|
|
||||||
max-width: 90%;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-quantity {
|
|
||||||
position: absolute;
|
|
||||||
right: 20px;
|
|
||||||
font-size: 24rpx;
|
|
||||||
color: #9e9c9c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.name {
|
|
||||||
font-size: 26rpx;
|
|
||||||
color: #444;
|
|
||||||
max-width: 90%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.detail {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
color: #999;
|
|
||||||
font-size: 28rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.detail-item {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
padding: 5rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.amount {
|
|
||||||
color: red;
|
|
||||||
}
|
|
||||||
|
|
||||||
.action {
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
align-items: center;
|
|
||||||
padding-top: 20rpx;
|
|
||||||
|
|
||||||
.pay-time {
|
|
||||||
font-size: 24rpx;
|
|
||||||
color: #999;
|
|
||||||
margin-right: 20rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.countdown {
|
|
||||||
font-size: 24rpx;
|
|
||||||
color: #999;
|
|
||||||
margin-left: auto;
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button {
|
|
||||||
width: 130rpx;
|
|
||||||
height: 60rpx;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
margin-left: 20rpx;
|
|
||||||
border-radius: 60rpx;
|
|
||||||
font-size: 26rpx;
|
|
||||||
color: #444;
|
|
||||||
}
|
|
||||||
|
|
||||||
.secondary {
|
|
||||||
color: #ff5f3c;
|
|
||||||
border-color: #ff5f3c;
|
|
||||||
}
|
|
||||||
|
|
||||||
.primary {
|
|
||||||
color: #fff;
|
|
||||||
background-color: #ff5f3c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.loading-text {
|
|
||||||
text-align: center;
|
|
||||||
font-size: 28rpx;
|
|
||||||
color: #666;
|
|
||||||
padding: 20rpx 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.block {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
padding: 20rpx;
|
|
||||||
margin: 20rpx 20rpx 0;
|
|
||||||
border-radius: 10rpx;
|
|
||||||
background-color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.address view {
|
|
||||||
margin-bottom: 20rpx;
|
|
||||||
font-size: 24rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.history view {
|
|
||||||
margin-bottom: 20rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.images-container {
|
|
||||||
display: flex;
|
|
||||||
|
|
||||||
image {
|
|
||||||
width: 150rpx;
|
|
||||||
height: 120rpx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.header {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
padding-bottom: 20rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title {
|
|
||||||
font-size: 35rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.copy-button {
|
|
||||||
display: flex;
|
|
||||||
height: 50rpx;
|
|
||||||
font-size: 24rpx;
|
|
||||||
margin-right: initial;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.remark {
|
|
||||||
padding: 10rpx 0 10rpx 0;
|
|
||||||
font-size: 24rpx;
|
|
||||||
color: #999;
|
|
||||||
line-height: 1.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sub-button {
|
|
||||||
background-color: #ff5f3c;
|
|
||||||
color: white;
|
|
||||||
border-radius: 20rpx;
|
|
||||||
text-align: center;
|
|
||||||
cursor: pointer;
|
|
||||||
margin: 20rpx;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,293 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import { onLoad, onPageScroll, onReachBottom, onShow } from '@dcloudio/uni-app'
|
|
||||||
import useZPaging from '@/uni_modules/z-paging/components/z-paging/js/hooks/useZPaging.js'
|
|
||||||
import { nextTick, ref } from 'vue'
|
|
||||||
import type { TabItem } from '@/types/global'
|
|
||||||
import { getOrderRefundListApi } from '@/api/order'
|
|
||||||
import { fullUrl } from '@/utils/common'
|
|
||||||
import type { orderRefundListResult } from '@/types/order'
|
|
||||||
import { pageUrl } from '@/utils/constants'
|
|
||||||
|
|
||||||
const paging = ref()
|
|
||||||
useZPaging(paging)
|
|
||||||
|
|
||||||
const props = defineProps<{
|
|
||||||
status: string
|
|
||||||
}>()
|
|
||||||
|
|
||||||
const tabList = ref<TabItem[]>([
|
|
||||||
{ name: '全部', value: '' },
|
|
||||||
{ name: '待处理', value: 1 },
|
|
||||||
])
|
|
||||||
|
|
||||||
const dataList = ref<orderRefundListResult[]>([])
|
|
||||||
|
|
||||||
const queryList = (page: number, page_size: number) => {
|
|
||||||
const params = {
|
|
||||||
page,
|
|
||||||
page_size,
|
|
||||||
status: tabList.value[tabIndex.value].value,
|
|
||||||
}
|
|
||||||
getOrderRefundListApi(params).then((res) => {
|
|
||||||
paging.value.complete(res.result.data)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const tabIndex = ref(Number(props.status) || 0)
|
|
||||||
const tabsChange = (index: number) => {
|
|
||||||
tabIndex.value = index
|
|
||||||
paging.value.refresh()
|
|
||||||
}
|
|
||||||
|
|
||||||
onShow(() => {
|
|
||||||
nextTick(() => {
|
|
||||||
paging.value.refresh()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<view class="list">
|
|
||||||
<z-paging
|
|
||||||
ref="paging"
|
|
||||||
v-model="dataList"
|
|
||||||
use-page-scroll
|
|
||||||
@query="queryList"
|
|
||||||
:safe-area-inset-bottom="true"
|
|
||||||
:auto-show-back-to-top="true"
|
|
||||||
:auto="false"
|
|
||||||
>
|
|
||||||
<template #top>
|
|
||||||
<z-tabs
|
|
||||||
:list="tabList"
|
|
||||||
@change="tabsChange"
|
|
||||||
:current="tabIndex"
|
|
||||||
:badge-style="{ 'background-color': '#c3c3c3' }"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
<view class="order">
|
|
||||||
<view class="card" v-for="(item, index) in dataList" :key="index">
|
|
||||||
<view class="status">
|
|
||||||
<text class="date">{{ item.create_time }}</text>
|
|
||||||
<text class="text">{{ item.status_text }}</text>
|
|
||||||
</view>
|
|
||||||
<navigator
|
|
||||||
class="goods"
|
|
||||||
hover-class="none"
|
|
||||||
:url="`${pageUrl['order-refund-detail']}?id=${item.id}&data=${JSON.stringify(item)}`"
|
|
||||||
>
|
|
||||||
<image class="cover" :src="fullUrl(item.detail.image)"></image>
|
|
||||||
<view class="meta">
|
|
||||||
<view class="name ellipsis">{{ item.detail.goods_name }}</view>
|
|
||||||
<view class="meta-spec">{{ item.detail.spec }}</view>
|
|
||||||
<view class="meta-quantity">x{{ item.refund_num }}</view>
|
|
||||||
</view>
|
|
||||||
</navigator>
|
|
||||||
</view>
|
|
||||||
<!-- 占位符 -->
|
|
||||||
<view style="padding-bottom: 10rpx"></view>
|
|
||||||
</view>
|
|
||||||
</z-paging>
|
|
||||||
</view>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
.list {
|
|
||||||
background-color: #f6f6f6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.order {
|
|
||||||
height: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
background-color: #f6f6f6;
|
|
||||||
|
|
||||||
.card {
|
|
||||||
min-height: 100rpx;
|
|
||||||
padding: 20rpx;
|
|
||||||
margin: 20rpx 20rpx 0;
|
|
||||||
border-radius: 10rpx;
|
|
||||||
background-color: #fff;
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
padding-bottom: 40rpx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.status {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
font-size: 28rpx;
|
|
||||||
color: #999;
|
|
||||||
margin-bottom: 15rpx;
|
|
||||||
|
|
||||||
.date {
|
|
||||||
color: #666;
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.text {
|
|
||||||
color: red;
|
|
||||||
}
|
|
||||||
|
|
||||||
.primary {
|
|
||||||
color: #ff9240;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon-delete {
|
|
||||||
line-height: 1;
|
|
||||||
margin-left: 10rpx;
|
|
||||||
padding-left: 10rpx;
|
|
||||||
border-left: 1rpx solid #e3e3e3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.goods {
|
|
||||||
display: flex;
|
|
||||||
margin-bottom: 20rpx;
|
|
||||||
|
|
||||||
.cover {
|
|
||||||
width: 170rpx;
|
|
||||||
height: 170rpx;
|
|
||||||
margin-right: 20rpx;
|
|
||||||
border-radius: 10rpx;
|
|
||||||
overflow: hidden;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.quantity {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 0;
|
|
||||||
right: 0;
|
|
||||||
line-height: 1;
|
|
||||||
padding: 6rpx 4rpx 6rpx 8rpx;
|
|
||||||
font-size: 24rpx;
|
|
||||||
color: #fff;
|
|
||||||
border-radius: 10rpx 0 0 0;
|
|
||||||
background-color: rgba(0, 0, 0, 0.6);
|
|
||||||
}
|
|
||||||
|
|
||||||
.meta {
|
|
||||||
flex: 1;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: space-around;
|
|
||||||
|
|
||||||
&-spec {
|
|
||||||
font-size: 24rpx;
|
|
||||||
color: #999;
|
|
||||||
margin-top: 10rpx;
|
|
||||||
max-width: 90%;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-quantity {
|
|
||||||
position: absolute;
|
|
||||||
right: 20px;
|
|
||||||
font-size: 24rpx;
|
|
||||||
color: #9e9c9c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.name {
|
|
||||||
font-size: 26rpx;
|
|
||||||
color: #444;
|
|
||||||
max-width: 90%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.type {
|
|
||||||
line-height: 1.8;
|
|
||||||
padding: 0 15rpx;
|
|
||||||
margin-top: 10rpx;
|
|
||||||
font-size: 24rpx;
|
|
||||||
align-self: flex-start;
|
|
||||||
border-radius: 4rpx;
|
|
||||||
color: #888;
|
|
||||||
background-color: #f7f7f8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.more {
|
|
||||||
flex: 1;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
font-size: 22rpx;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.payment {
|
|
||||||
display: flex;
|
|
||||||
// justify-content: flex-end;
|
|
||||||
align-items: center;
|
|
||||||
line-height: 1;
|
|
||||||
padding: 20rpx 0;
|
|
||||||
text-align: right;
|
|
||||||
color: #999;
|
|
||||||
font-size: 28rpx;
|
|
||||||
|
|
||||||
.quantity {
|
|
||||||
font-size: 24rpx;
|
|
||||||
margin-right: 16rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.amount {
|
|
||||||
color: #444;
|
|
||||||
margin-left: 6rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.symbol {
|
|
||||||
font-size: 20rpx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.action {
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
align-items: center;
|
|
||||||
padding-top: 20rpx;
|
|
||||||
|
|
||||||
.pay-time {
|
|
||||||
font-size: 24rpx;
|
|
||||||
color: #999;
|
|
||||||
margin-right: 20rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.countdown {
|
|
||||||
font-size: 24rpx;
|
|
||||||
color: #999;
|
|
||||||
margin-left: auto;
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button {
|
|
||||||
width: 130rpx;
|
|
||||||
height: 60rpx;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
margin-left: 20rpx;
|
|
||||||
border-radius: 60rpx;
|
|
||||||
font-size: 26rpx;
|
|
||||||
color: #444;
|
|
||||||
}
|
|
||||||
|
|
||||||
.secondary {
|
|
||||||
color: #ff5f3c;
|
|
||||||
border-color: #ff5f3c;
|
|
||||||
}
|
|
||||||
|
|
||||||
.primary {
|
|
||||||
color: #fff;
|
|
||||||
background-color: #ff5f3c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.loading-text {
|
|
||||||
text-align: center;
|
|
||||||
font-size: 28rpx;
|
|
||||||
color: #666;
|
|
||||||
padding: 20rpx 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,362 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import { fullUrl } from '@/utils/common'
|
|
||||||
import { safeBottom } from '@/utils/constants'
|
|
||||||
import { postOrderRefundApi } from '@/api/order'
|
|
||||||
import { computed, reactive } from 'vue'
|
|
||||||
import { ref } from 'vue'
|
|
||||||
import { pageUrl } from '@/utils/constants'
|
|
||||||
import { uploadApi } from '@/api/common'
|
|
||||||
|
|
||||||
const props = defineProps<{
|
|
||||||
order_id: number
|
|
||||||
detail_data?: string
|
|
||||||
}>()
|
|
||||||
|
|
||||||
const detailData = JSON.parse(props.detail_data ?? '{}')
|
|
||||||
const refundTypeArr = [
|
|
||||||
{ value: 1, text: '退货退款' },
|
|
||||||
{ value: 2, text: '换货' },
|
|
||||||
]
|
|
||||||
const tmpPathArr = ref<string[]>([])
|
|
||||||
const imagePathArr = ref<string[]>([])
|
|
||||||
const onSelect = (e: UniHelper.UniFilePickerOnSelectEvent) => {
|
|
||||||
tmpPathArr.value = tmpPathArr.value.concat(e.tempFilePaths)
|
|
||||||
}
|
|
||||||
const onDelete = (e: UniHelper.UniFilePickerOnDeleteEvent) => {
|
|
||||||
// 移除图片
|
|
||||||
const index = tmpPathArr.value.findIndex((item) => item === e.tempFilePath)
|
|
||||||
tmpPathArr.value.splice(index, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
const applyForm = reactive({
|
|
||||||
refund_type: 1,
|
|
||||||
refund_num: 1,
|
|
||||||
apply_money: detailData.pay_price,
|
|
||||||
remark: '',
|
|
||||||
remark_images: [],
|
|
||||||
})
|
|
||||||
|
|
||||||
const maxApplyNum = computed(() => {
|
|
||||||
return parseFloat(detailData.num)
|
|
||||||
})
|
|
||||||
const maxApplyAmount = computed(() => {
|
|
||||||
return parseFloat(detailData.pay_price)
|
|
||||||
})
|
|
||||||
|
|
||||||
// 提交申请
|
|
||||||
const onSubmit = async () => {
|
|
||||||
if (!applyForm.remark) {
|
|
||||||
uni.showToast({
|
|
||||||
title: '请填写申请说明',
|
|
||||||
icon: 'none',
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const uploadPromises = tmpPathArr.value.map((item) => {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
uploadApi(item).then((res) => {
|
|
||||||
imagePathArr.value.push(res.result.url)
|
|
||||||
resolve(res)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
try {
|
|
||||||
await Promise.all(uploadPromises)
|
|
||||||
|
|
||||||
// 退款
|
|
||||||
const res = await postOrderRefundApi({
|
|
||||||
id: props.order_id,
|
|
||||||
detail_id: detailData.id,
|
|
||||||
refund_type: applyForm.refund_type,
|
|
||||||
refund_num: applyForm.refund_num,
|
|
||||||
remark: applyForm.remark,
|
|
||||||
apply_money: applyForm.apply_money,
|
|
||||||
remark_images: imagePathArr.value.join(','),
|
|
||||||
})
|
|
||||||
|
|
||||||
if (res.result) {
|
|
||||||
uni.showToast({
|
|
||||||
title: '申请成功,请等待商家处理',
|
|
||||||
icon: 'none',
|
|
||||||
mask: true,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
uni.navigateBack()
|
|
||||||
}, 1500)
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<view class="panel goods">
|
|
||||||
<view class="item">
|
|
||||||
<navigator
|
|
||||||
class="navigator"
|
|
||||||
:url="`${pageUrl['goods-detail']}?id=${detailData.goods_id}`"
|
|
||||||
hover-class="none"
|
|
||||||
>
|
|
||||||
<image class="cover" :src="fullUrl(detailData.image)"></image>
|
|
||||||
<view class="meta">
|
|
||||||
<view class="name ellipsis">{{ detailData.goods_name }}</view>
|
|
||||||
<view class="type">{{ detailData.spec_text }}</view>
|
|
||||||
<view class="price">
|
|
||||||
<view class="actual">
|
|
||||||
<text class="symbol">¥</text>
|
|
||||||
<text>{{ detailData.price }}</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="quantity">x{{ detailData.num }}</view>
|
|
||||||
</view>
|
|
||||||
</navigator>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="panel">
|
|
||||||
<view class="panel-item">
|
|
||||||
<view class="item-title">
|
|
||||||
<text>售后类型:</text>
|
|
||||||
</view>
|
|
||||||
<view class="content">
|
|
||||||
<uni-data-checkbox mode="tag" v-model="applyForm.refund_type" :localdata="refundTypeArr" />
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="panel-item">
|
|
||||||
<view class="item-title">
|
|
||||||
<text>售后数量:</text>
|
|
||||||
</view>
|
|
||||||
<view class="content">
|
|
||||||
<uni-number-box v-model="applyForm.refund_num" :min="1" :max="maxApplyNum" />
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="panel-item" v-if="applyForm.refund_type == 1">
|
|
||||||
<view class="item-title">
|
|
||||||
<text>申请金额:</text>
|
|
||||||
</view>
|
|
||||||
<view class="content">
|
|
||||||
<uni-number-box v-model="applyForm.apply_money" :min="0.01" :max="maxApplyAmount" />
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="panel">
|
|
||||||
<view class="panel-item2">
|
|
||||||
<view class="item-title">申请说明</view>
|
|
||||||
<view class="content">
|
|
||||||
<uni-easyinput
|
|
||||||
type="textarea"
|
|
||||||
v-model="applyForm.remark"
|
|
||||||
placeholder="描述清晰有助于商家快速处理售后问题"
|
|
||||||
/>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="panel-item2">
|
|
||||||
<view class="item-title">上传凭证(最多6张)</view>
|
|
||||||
<view class="content">
|
|
||||||
<uni-file-picker
|
|
||||||
class="image"
|
|
||||||
v-model="applyForm.remark_images"
|
|
||||||
file-mediatype="image"
|
|
||||||
mode="grid"
|
|
||||||
file-extname="png,jpg"
|
|
||||||
:limit="6"
|
|
||||||
return-type="array"
|
|
||||||
:auto-upload="false"
|
|
||||||
@select="onSelect"
|
|
||||||
@delete="onDelete"
|
|
||||||
/>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="sub-button" :style="safeBottom">
|
|
||||||
<button @tap="onSubmit">提交申请</button>
|
|
||||||
</view>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
page {
|
|
||||||
background-color: #f7f7f8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.panel {
|
|
||||||
margin: 20rpx 20rpx;
|
|
||||||
padding: 10rpx 20rpx;
|
|
||||||
border-radius: 20rpx;
|
|
||||||
background-color: #fff;
|
|
||||||
|
|
||||||
.panel-item {
|
|
||||||
display: flex; // 使用flex布局
|
|
||||||
align-items: center; // 垂直居中
|
|
||||||
justify-content: space-between; // 水平方向上的空间分布
|
|
||||||
padding: 10rpx 0;
|
|
||||||
margin-bottom: 20rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.item-title {
|
|
||||||
font-size: 26rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
|
||||||
margin-bottom: 10rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.price-value {
|
|
||||||
color: red;
|
|
||||||
}
|
|
||||||
|
|
||||||
.panel-item2 {
|
|
||||||
.item-title {
|
|
||||||
padding: 10rpx 0 30rpx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.image {
|
|
||||||
padding: 10rpx 0 10rpx 0;
|
|
||||||
.uni-file-picker {
|
|
||||||
margin-top: 20rpx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.goods {
|
|
||||||
.item {
|
|
||||||
.navigator {
|
|
||||||
display: flex;
|
|
||||||
margin: 20rpx 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cover {
|
|
||||||
width: 170rpx;
|
|
||||||
height: 170rpx;
|
|
||||||
border-radius: 10rpx;
|
|
||||||
margin-right: 20rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.meta {
|
|
||||||
flex: 1;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: space-around;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.name {
|
|
||||||
font-size: 26rpx;
|
|
||||||
color: #444;
|
|
||||||
}
|
|
||||||
|
|
||||||
.type {
|
|
||||||
line-height: 1.8;
|
|
||||||
padding: 0 15rpx;
|
|
||||||
margin-top: 6rpx;
|
|
||||||
font-size: 24rpx;
|
|
||||||
align-self: flex-start;
|
|
||||||
border-radius: 4rpx;
|
|
||||||
color: #888;
|
|
||||||
background-color: #f7f7f8;
|
|
||||||
max-width: 90%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.price {
|
|
||||||
display: flex;
|
|
||||||
margin-top: 6rpx;
|
|
||||||
font-size: 24rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.symbol {
|
|
||||||
font-size: 20rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.original {
|
|
||||||
color: #999;
|
|
||||||
text-decoration: line-through;
|
|
||||||
}
|
|
||||||
|
|
||||||
.actual {
|
|
||||||
margin-left: 10rpx;
|
|
||||||
color: #444;
|
|
||||||
}
|
|
||||||
|
|
||||||
.text {
|
|
||||||
font-size: 22rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.evaluate {
|
|
||||||
position: absolute;
|
|
||||||
right: 0;
|
|
||||||
font-size: 24rpx;
|
|
||||||
bottom: 50rpx;
|
|
||||||
|
|
||||||
.button {
|
|
||||||
width: 80rpx;
|
|
||||||
text-align: center;
|
|
||||||
justify-content: center;
|
|
||||||
margin-left: 20rpx;
|
|
||||||
border-radius: 60rpx;
|
|
||||||
border: 1rpx solid #ccc;
|
|
||||||
color: #444;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.quantity {
|
|
||||||
position: absolute;
|
|
||||||
right: 0;
|
|
||||||
font-size: 24rpx;
|
|
||||||
color: #444;
|
|
||||||
}
|
|
||||||
|
|
||||||
.action {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row-reverse;
|
|
||||||
justify-content: flex-start;
|
|
||||||
padding: 30rpx 0 0;
|
|
||||||
|
|
||||||
.button {
|
|
||||||
width: 200rpx;
|
|
||||||
height: 60rpx;
|
|
||||||
text-align: center;
|
|
||||||
justify-content: center;
|
|
||||||
line-height: 60rpx;
|
|
||||||
margin-left: 20rpx;
|
|
||||||
border-radius: 60rpx;
|
|
||||||
border: 1rpx solid #ccc;
|
|
||||||
font-size: 26rpx;
|
|
||||||
color: #444;
|
|
||||||
}
|
|
||||||
|
|
||||||
.primary {
|
|
||||||
color: #ff5f3c;
|
|
||||||
border-color: #ff5f3c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.sub-button {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
position: absolute;
|
|
||||||
bottom: 0;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
.button-container {
|
|
||||||
background-color: white;
|
|
||||||
padding: 10rpx;
|
|
||||||
border-radius: 30rpx;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
width: 100%;
|
|
||||||
background-color: #ff5f3c;
|
|
||||||
color: white;
|
|
||||||
border-radius: 20rpx;
|
|
||||||
text-align: center;
|
|
||||||
cursor: pointer;
|
|
||||||
margin: 20rpx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
Loading…
Reference in New Issue
Block a user