feat: 订单列表+打包
This commit is contained in:
parent
4797a630f3
commit
580cd25221
@ -3,7 +3,8 @@ const order = {
|
|||||||
* 订单管理
|
* 订单管理
|
||||||
*/
|
*/
|
||||||
getOrderList: ['/order/list'], // 获取订单管理
|
getOrderList: ['/order/list'], // 获取订单管理
|
||||||
packOrder: ['/order/pack'], // 打包
|
getOrderDetail: ['/order/detail'], // 获取订单详情
|
||||||
|
packOrder: ['/order/toShipping'], // 打包
|
||||||
unpackOrder: ['/order/unpack'], // 取消打包
|
unpackOrder: ['/order/unpack'], // 取消打包
|
||||||
finishDeliver: ['/order/delivered'] // 妥投
|
finishDeliver: ['/order/delivered'] // 妥投
|
||||||
}
|
}
|
||||||
|
|||||||
788
src/views/order/list/detail/index.vue
Normal file
788
src/views/order/list/detail/index.vue
Normal file
@ -0,0 +1,788 @@
|
|||||||
|
<template>
|
||||||
|
<div class="order-detail-page">
|
||||||
|
<div class="order-detail-main-container">
|
||||||
|
<!-- 左侧:消费者信息和订单详情 -->
|
||||||
|
<div class="left-section">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<!-- 消费者信息 -->
|
||||||
|
<div class="consumer-info flex-1">
|
||||||
|
<h3 class="section-title">消费者信息</h3>
|
||||||
|
<div class="consumer-info-content">
|
||||||
|
<!-- 买家姓名 -->
|
||||||
|
<div class="info-item">
|
||||||
|
<div class="label">买家姓名</div>
|
||||||
|
<div class="value buyer-name">
|
||||||
|
<el-image class="flag-icon" :src="orderDetail.orderInfo.imgUrl" fit="cover">
|
||||||
|
</el-image>
|
||||||
|
<span class="username">{{ orderDetail.orderInfo.buyerName }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 买家ID -->
|
||||||
|
<div class="info-item">
|
||||||
|
<div class="label">买家ID</div>
|
||||||
|
<div class="value">{{ orderDetail.orderInfo.buyerId }}</div>
|
||||||
|
</div>
|
||||||
|
<!-- 付款方式 -->
|
||||||
|
<div class="info-item">
|
||||||
|
<div class="label">付款方式</div>
|
||||||
|
<div class="value">微信支付</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 消费者地址 -->
|
||||||
|
<div class="consumer-info flex-1">
|
||||||
|
<h3 class="section-title">消费者地址</h3>
|
||||||
|
<div class="consumer-info-content">
|
||||||
|
<div class="info-item">
|
||||||
|
<div class="label">收件人姓名</div>
|
||||||
|
<div class="value">{{ orderDetail.orderInfo.buyerName }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="info-item">
|
||||||
|
<div class="label">收件人电话</div>
|
||||||
|
<div class="value">{{ orderDetail.orderInfo.mobile }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="info-item">
|
||||||
|
<div class="label">具体地址</div>
|
||||||
|
<div class="value">{{ orderDetail.orderInfo.buyerDetailAddress }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 订单详情 -->
|
||||||
|
<div class="order-detail-section">
|
||||||
|
<!-- 顶部:订单号和创建时间 -->
|
||||||
|
<div class="order-header">
|
||||||
|
<div class="header-left">
|
||||||
|
<span class="order-number-label">订单号</span>
|
||||||
|
<span class="order-number-value">{{ orderDetail.orderInfo.orderNumber }}</span>
|
||||||
|
<span class="order-number-label ml-5">微信交易订单号</span>
|
||||||
|
<span class="order-number-value">{{ orderDetail.orderInfo.transactionId }}</span>
|
||||||
|
<span class="create-time-label ml-5">创建时间</span>
|
||||||
|
<span class="create-time-value">{{ orderDetail.orderInfo.createTime }}</span>
|
||||||
|
</div>
|
||||||
|
<!-- <div class="header-right">
|
||||||
|
<span class="platform-name">购de着</span>
|
||||||
|
</div> -->
|
||||||
|
</div>
|
||||||
|
<!-- 待处理商品 -->
|
||||||
|
<div class="order-section">
|
||||||
|
<div class="order-table-header">
|
||||||
|
<div class="col goods">商品</div>
|
||||||
|
<div class="col status text-center">状态</div>
|
||||||
|
<div class="col total text-center">总计</div>
|
||||||
|
<div class="col status text-center">退款金额</div>
|
||||||
|
<div class="col status text-center">退款数量</div>
|
||||||
|
<div class="col total text-center">销售价格</div>
|
||||||
|
<div class="col total text-center">成本价</div>
|
||||||
|
<div class="col status text-center">运费</div>
|
||||||
|
<div class="col status text-center">利润</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-for="(packageData, packageIndex) in orderDetail.packageList"
|
||||||
|
:key="packageIndex"
|
||||||
|
class="mt-2"
|
||||||
|
>
|
||||||
|
<div class="order-content">
|
||||||
|
<div class="col goods">
|
||||||
|
<div
|
||||||
|
v-for="item in packageData.vvTradeOrderLineDOList"
|
||||||
|
:key="item.id"
|
||||||
|
class="goods-item"
|
||||||
|
>
|
||||||
|
<el-image class="goods-image" :src="item.productMainImageUrl" fit="cover">
|
||||||
|
</el-image>
|
||||||
|
<div class="goods-info">
|
||||||
|
<div class="title">{{ item.productName }}</div>
|
||||||
|
<div class="sub">
|
||||||
|
<span>{{ item.skuInfo }}</span>
|
||||||
|
<span>skuId:{{ item.skuId }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="goods-price">{{ item.chinesePromotionPrice }} x {{ item.num }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col status">
|
||||||
|
<div class="goods-status-item flex-1 flex justify-center items-center">
|
||||||
|
<div class="status-label">
|
||||||
|
{{ packageData.vvTradeOrderLineDOList[0].status }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col total">
|
||||||
|
<div class="amount">
|
||||||
|
{{
|
||||||
|
packageData.vvTradeOrderLineDOList.reduce((acc: number, it: any) => {
|
||||||
|
return acc + it.promotionPrice * it.num
|
||||||
|
}, 0)
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col status">
|
||||||
|
<div class="goods-status-item flex-1 flex justify-center items-center">
|
||||||
|
<div class="status-label">
|
||||||
|
{{ packageData.vvTradeOrderLineDOList[0].refundAmount }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col status">
|
||||||
|
<div class="goods-status-item flex-1 flex justify-center items-center">
|
||||||
|
<div class="status-label">
|
||||||
|
{{ packageData.vvTradeOrderLineDOList[0].refundCount }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col status">
|
||||||
|
<div class="goods-status-item flex-1 flex justify-center items-center">
|
||||||
|
<div class="status-label">
|
||||||
|
{{ packageData.vvTradeOrderLineDOList[0].salePrice }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col status">
|
||||||
|
<div class="goods-status-item flex-1 flex justify-center items-center">
|
||||||
|
<div class="status-label">
|
||||||
|
{{ packageData.vvTradeOrderLineDOList[0].originPrice }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col status">
|
||||||
|
<div class="goods-status-item flex-1 flex justify-center items-center">
|
||||||
|
<div class="status-label">
|
||||||
|
{{ packageData.vvTradeOrderLineDOList[0].shippingAmount }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col status">
|
||||||
|
<div class="goods-status-item flex-1 flex justify-center items-center">
|
||||||
|
<div class="status-label">
|
||||||
|
{{ packageData.vvTradeOrderLineDOList[0].profitAmount }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 消费者地址 -->
|
||||||
|
<div class="consumer-info">
|
||||||
|
<h3 class="section-title">订单备注</h3>
|
||||||
|
<div class="">
|
||||||
|
<div class="info-item">
|
||||||
|
<div class="label">买家备注</div>
|
||||||
|
<div class="value">{{ orderDetail.orderInfo.buyerName }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="info-item">
|
||||||
|
<div class="label">卖家备注</div>
|
||||||
|
<div class="value">{{ orderDetail.orderInfo.mobile }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 右侧:订单备注和消费者地址 -->
|
||||||
|
<!-- <div class="right-section">
|
||||||
|
<div class="order-notes">
|
||||||
|
<h3 class="section-title">订单备注</h3>
|
||||||
|
<div class="note-item">
|
||||||
|
<div class="label">买家备注</div>
|
||||||
|
<div class="value note-content">暂无</div>
|
||||||
|
</div>
|
||||||
|
<div class="note-item">
|
||||||
|
<div class="label">卖家备注</div>
|
||||||
|
<div class="value">
|
||||||
|
<div class="note-header"></div>
|
||||||
|
<div class="note-content">暂无</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="address-section">
|
||||||
|
<h3 class="section-title">消费者地址</h3>
|
||||||
|
<div class="address-block">
|
||||||
|
<h4 class="address-subtitle">邮寄地址</h4>
|
||||||
|
<div class="address-item">
|
||||||
|
<div class="label">具体地址</div>
|
||||||
|
<div class="value">{{ orderDetail.orderInfo.buyerDetailAddress }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="address-item">
|
||||||
|
<div class="label">收件人姓名</div>
|
||||||
|
<div class="value">{{ orderDetail.orderInfo.buyerName }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="address-item">
|
||||||
|
<div class="label">收件人电话</div>
|
||||||
|
<div class="value">{{ orderDetail.orderInfo.mobile }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div> -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
const route = useRoute()
|
||||||
|
|
||||||
|
interface OrderItem {
|
||||||
|
id: number
|
||||||
|
productName: string
|
||||||
|
// sku: string
|
||||||
|
num: number
|
||||||
|
promotionPrice: string
|
||||||
|
skuInfo: string
|
||||||
|
status: string
|
||||||
|
orderActionList: OrderAction[]
|
||||||
|
productMainImageUrl: string
|
||||||
|
chinesePromotionPrice: string
|
||||||
|
refundAmount: number
|
||||||
|
refundCount: number
|
||||||
|
salePrice: number
|
||||||
|
originPrice: number
|
||||||
|
shippingAmount: number
|
||||||
|
profitAmount: number
|
||||||
|
skuId: number
|
||||||
|
}
|
||||||
|
interface OrderAction {
|
||||||
|
desc: string
|
||||||
|
buttonName: string
|
||||||
|
interfaceUri: string
|
||||||
|
}
|
||||||
|
interface PackageItem {
|
||||||
|
orderActionList: OrderAction[]
|
||||||
|
vvTradeOrderLineDOList: OrderItem[]
|
||||||
|
trackNumber: number
|
||||||
|
}
|
||||||
|
|
||||||
|
interface OrderInfo {
|
||||||
|
orderNumber: string
|
||||||
|
createTime: string
|
||||||
|
num: number
|
||||||
|
allPrice: number
|
||||||
|
buyerId: number
|
||||||
|
mobile: string
|
||||||
|
buyerName: string
|
||||||
|
imgUrl: string
|
||||||
|
buyerDetailAddress: string
|
||||||
|
transactionId: string
|
||||||
|
}
|
||||||
|
|
||||||
|
// 订单详情
|
||||||
|
const orderDetail = reactive<{ packageList: PackageItem[]; orderInfo: OrderInfo }>({
|
||||||
|
orderInfo: {
|
||||||
|
orderNumber: '',
|
||||||
|
createTime: '',
|
||||||
|
num: 0,
|
||||||
|
allPrice: 0,
|
||||||
|
buyerId: 0,
|
||||||
|
mobile: '',
|
||||||
|
buyerName: '',
|
||||||
|
imgUrl: '',
|
||||||
|
buyerDetailAddress: '',
|
||||||
|
transactionId: ''
|
||||||
|
},
|
||||||
|
packageList: []
|
||||||
|
})
|
||||||
|
|
||||||
|
const orderStatusMap = {
|
||||||
|
create: '已创建',
|
||||||
|
wait_pay: '待支付',
|
||||||
|
wait_shipping: '待发货',
|
||||||
|
shipping: '已发货',
|
||||||
|
shipped: '已投递',
|
||||||
|
delivered: '已妥投',
|
||||||
|
apply_cancel: '买家申请取消',
|
||||||
|
cancel: '卖家同意取消',
|
||||||
|
refund: '已退款',
|
||||||
|
close: '买家关闭订单'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析并填充订单数据
|
||||||
|
const parseOrderData = (data: any) => {
|
||||||
|
const order = data.vvTradeOrderResp
|
||||||
|
const buyerInfo = data.vvBuyerEntity
|
||||||
|
|
||||||
|
orderDetail.orderInfo = {
|
||||||
|
imgUrl: buyerInfo.imgUrl,
|
||||||
|
orderNumber: order.id?.toString() || '',
|
||||||
|
createTime: new Date(order.createTimestamp).toLocaleString(),
|
||||||
|
num: order.num,
|
||||||
|
allPrice: order.allPrice,
|
||||||
|
buyerId: buyerInfo.id,
|
||||||
|
buyerName: buyerInfo.buyerName,
|
||||||
|
mobile: order.mobile,
|
||||||
|
buyerDetailAddress:
|
||||||
|
order.contry + order.province + order.city + order.district + order.buyerDetailAddress,
|
||||||
|
transactionId: order.transactionId
|
||||||
|
}
|
||||||
|
orderDetail.packageList = order.packageList.map((packageData: any) => {
|
||||||
|
packageData.vvTradeOrderLineDOList = packageData.vvTradeOrderLineDOList.map((item: any) => {
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
status: orderStatusMap[item.status as keyof typeof orderStatusMap],
|
||||||
|
chinesePromotionPrice: '¥' + item.promotionPrice.toFixed(2),
|
||||||
|
skuInfo: JSON.parse(item.skuInfo)
|
||||||
|
.map((it: any) => `${it.propertyName}:${it.propertyValue}`)
|
||||||
|
.join(',')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return packageData
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取订单详情
|
||||||
|
const fetchOrderDetail = async () => {
|
||||||
|
const orderId = route.query.id || route.params.id
|
||||||
|
if (!orderId) {
|
||||||
|
console.warn('订单ID不存在')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// TODO: 替换为实际的API调用
|
||||||
|
const res = await api.order.getOrderDetail.post!({ tradeOrderId: orderId })
|
||||||
|
parseOrderData(res.data)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取订单详情失败', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 组件挂载时获取数据
|
||||||
|
onMounted(() => {
|
||||||
|
fetchOrderDetail()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.order-detail-page {
|
||||||
|
background-color: #f5f7fa;
|
||||||
|
overflow-x: scroll;
|
||||||
|
|
||||||
|
// 主容器
|
||||||
|
.order-detail-main-container {
|
||||||
|
display: flex;
|
||||||
|
gap: 20px;
|
||||||
|
margin: 0 auto;
|
||||||
|
|
||||||
|
// 左侧:消费者信息和订单详情
|
||||||
|
.left-section {
|
||||||
|
flex: 3;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
|
||||||
|
.consumer-info {
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 12px 12px 4px;
|
||||||
|
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #303133;
|
||||||
|
margin: 0 0 8px 0;
|
||||||
|
padding-bottom: 4px;
|
||||||
|
border-bottom: 1px solid #ebeef5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.consumer-info-content {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-item {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
.label {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #909399;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
.value {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #303133;
|
||||||
|
word-break: break-all;
|
||||||
|
|
||||||
|
&.buyer-name {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
|
.flag-icon {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
border-radius: 2px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-placeholder {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: #f2f3f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-icon {
|
||||||
|
font-size: 18px;
|
||||||
|
color: #909399;
|
||||||
|
}
|
||||||
|
|
||||||
|
.username {
|
||||||
|
font-weight: 500;
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-icon {
|
||||||
|
font-size: 18px;
|
||||||
|
color: #409eff;
|
||||||
|
cursor: pointer;
|
||||||
|
margin-left: 4px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #66b1ff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-detail-section {
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 12px 12px 4px;
|
||||||
|
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
||||||
|
|
||||||
|
.order-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding-top: 4px;
|
||||||
|
padding-bottom: 8px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
border-bottom: 1px solid #ebeef5;
|
||||||
|
|
||||||
|
.header-left {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
font-size: 14px;
|
||||||
|
|
||||||
|
.order-number-label,
|
||||||
|
.create-time-label {
|
||||||
|
color: #909399;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-number-value,
|
||||||
|
.create-time-value {
|
||||||
|
color: #303133;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-icon {
|
||||||
|
color: #909399;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-right {
|
||||||
|
.platform-name {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #303133;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 右侧:订单备注和消费者地址
|
||||||
|
.right-section {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 300px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 20px;
|
||||||
|
|
||||||
|
.order-notes,
|
||||||
|
.address-section {
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 16px;
|
||||||
|
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #303133;
|
||||||
|
margin: 0 0 20px 0;
|
||||||
|
padding-bottom: 12px;
|
||||||
|
border-bottom: 1px solid #ebeef5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-notes {
|
||||||
|
.note-item {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
.label {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #909399;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
.value {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #303133;
|
||||||
|
word-break: break-all;
|
||||||
|
|
||||||
|
.note-header {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
:deep(.el-button) {
|
||||||
|
padding: 0;
|
||||||
|
height: auto;
|
||||||
|
font-size: 13px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.note-content {
|
||||||
|
color: #909399;
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.address-section {
|
||||||
|
.address-block {
|
||||||
|
margin-bottom: 24px;
|
||||||
|
|
||||||
|
&:last-of-type {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.address-subtitle {
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #303133;
|
||||||
|
margin: 0 0 16px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.address-item {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #909399;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.value {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #303133;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.order-table-header {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 80px 60px 60px 60px 60px 60px 30px 30px;
|
||||||
|
padding: 12px 0 12px 0;
|
||||||
|
background: #f9fafc;
|
||||||
|
border-top: 1px solid #ebeef5;
|
||||||
|
border-bottom: 1px solid #ebeef5;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #909399;
|
||||||
|
overflow-x: auto;
|
||||||
|
white-space: nowrap;
|
||||||
|
grid-auto-flow: column;
|
||||||
|
.col:first-child {
|
||||||
|
padding-left: 44px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.order-content {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 80px 60px 60px 60px 60px 60px 30px 30px;
|
||||||
|
padding: 0;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #606266;
|
||||||
|
border: 1px solid #ebeef5;
|
||||||
|
border-radius: 6px;
|
||||||
|
overflow-x: auto;
|
||||||
|
white-space: nowrap;
|
||||||
|
grid-auto-flow: column;
|
||||||
|
|
||||||
|
.goods-item + .goods-item {
|
||||||
|
border-top: 1px solid #f0f2f5;
|
||||||
|
}
|
||||||
|
.goods-status-item {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.goods-status-item + .goods-status-item {
|
||||||
|
border-top: 1px solid #f0f2f5;
|
||||||
|
}
|
||||||
|
.goods {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.goods-item {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
border-right: 1px solid #f0f2f5;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 12px;
|
||||||
|
align-items: center;
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
.goods-image {
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
border-radius: 6px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-fallback {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: #f2f3f5;
|
||||||
|
color: #909399;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.goods-info {
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #303133;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sub {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #909399;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.goods-price {
|
||||||
|
font-weight: 600;
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.total {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
border-left: 1px solid #f0f2f5;
|
||||||
|
|
||||||
|
.amount {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
|
|
||||||
|
.remark {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #909399;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.delivery {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 4px;
|
||||||
|
|
||||||
|
.delivery-type {
|
||||||
|
font-weight: 600;
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delivery-warehouse {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #909399;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.status {
|
||||||
|
border-left: 1px solid #f0f2f5;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
.status-label {
|
||||||
|
font-weight: 600;
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-detail {
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #909399;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.actions {
|
||||||
|
border-left: 1px solid #f0f2f5;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 8px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.order-detail-page {
|
||||||
|
.order-detail-main-container {
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.left-section,
|
||||||
|
.right-section {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-header {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -109,71 +109,78 @@
|
|||||||
<span class="order-meta">创建时间:{{ order.createTimestamp }}</span>
|
<span class="order-meta">创建时间:{{ order.createTimestamp }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="order-content">
|
<div v-for="(packageData, packageIndex) in order.packageList" :key="packageIndex">
|
||||||
<div class="col goods">
|
<div class="order-content">
|
||||||
<div v-for="item in order.vvTradeOrderLineList" :key="item.id" class="goods-item">
|
<div class="col goods">
|
||||||
<el-image class="goods-image" :src="item.productMainImageUrl" fit="cover">
|
<div
|
||||||
</el-image>
|
v-for="item in packageData.vvTradeOrderLineDOList"
|
||||||
<div class="goods-info">
|
:key="item.id"
|
||||||
<div class="title">{{ item.productName }}</div>
|
class="goods-item"
|
||||||
<div class="sub">
|
>
|
||||||
<span>{{ item.skuInfo }}</span>
|
<el-image class="goods-image" :src="item.productMainImageUrl" fit="cover">
|
||||||
<!-- <span>卖家SKU:{{ item.sku }}</span> -->
|
</el-image>
|
||||||
|
<div class="goods-info">
|
||||||
|
<div class="title">{{ item.productName }}</div>
|
||||||
|
<div class="sub">
|
||||||
|
<span>{{ item.skuInfo }}</span>
|
||||||
|
<!-- <span>卖家SKU:{{ item.sku }}</span> -->
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="goods-price">{{ item.chinesePromotionPrice }} x {{ item.num }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="goods-price">{{ item.promotionPrice }} x {{ item.num }}</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="col total">
|
||||||
<div class="col total">
|
<div class="amount">
|
||||||
<div class="amount">{{ order.allPrice }}</div>
|
{{
|
||||||
</div>
|
packageData.vvTradeOrderLineDOList.reduce((acc: number, it: any) => {
|
||||||
<!-- <div class="col delivery">
|
return acc + it.promotionPrice * it.num
|
||||||
<div class="delivery-type">{{ order.delivery.type }}</div>
|
}, 0)
|
||||||
<div class="delivery-warehouse">签收仓库:{{ order.delivery.warehouse }}</div>
|
}}
|
||||||
</div> -->
|
</div>
|
||||||
<div class="col status">
|
|
||||||
<div
|
|
||||||
v-for="item in order.vvTradeOrderLineList"
|
|
||||||
:key="item.id"
|
|
||||||
class="goods-status-item flex-1 flex justify-center items-center"
|
|
||||||
>
|
|
||||||
<div class="status-label">{{ item.status }}</div>
|
|
||||||
</div>
|
</div>
|
||||||
<!-- <ul class="status-detail">
|
<div class="col status">
|
||||||
<li>AWB:{{ order.awb }}</li>
|
<div class="goods-status-item flex-1 flex justify-center items-center">
|
||||||
<li>揽收:{{ order.pickupStatus }}</li>
|
<div class="status-label">{{ packageData.vvTradeOrderLineDOList[0].status }}</div>
|
||||||
<li>装袋:{{ order.bagStatus }}</li>
|
</div>
|
||||||
</ul> -->
|
<!-- <ul class="status-detail">
|
||||||
</div>
|
<li>AWB:{{ order.awb }}</li>
|
||||||
<div class="col actions">
|
<li>揽收:{{ order.pickupStatus }}</li>
|
||||||
<div
|
<li>装袋:{{ order.bagStatus }}</li>
|
||||||
v-for="orderLine in order.vvTradeOrderLineList"
|
</ul> -->
|
||||||
:key="orderLine.id"
|
</div>
|
||||||
class="goods-actions-item flex-1 flex flex-col gap-2 justify-center items-center"
|
<!-- <div class="col delivery">
|
||||||
>
|
<div class="delivery-type">{{ order.delivery.type }}</div>
|
||||||
<el-button
|
<div class="delivery-warehouse">签收仓库:{{ order.delivery.warehouse }}</div>
|
||||||
v-for="item in orderLine.orderActionList.filter(
|
</div> -->
|
||||||
(item) => !item.desc.includes('app')
|
<div class="col actions">
|
||||||
)"
|
<div
|
||||||
:key="item.interfaceUri"
|
v-for="(orderAction, orderActionIndex) in packageData.orderActionList"
|
||||||
class="ml-0!"
|
:key="orderActionIndex"
|
||||||
type="primary"
|
:class="[
|
||||||
size="small"
|
'goods-actions-item flex flex-col gap-2 justify-center items-center',
|
||||||
@click="onButtonClick(item.interfaceUri, orderLine)"
|
orderActionIndex ? '!mt-2' : ''
|
||||||
>{{ item.desc.replace('admin', '').replace('按钮', '') }}</el-button
|
]"
|
||||||
>
|
|
||||||
<el-button
|
|
||||||
v-if="
|
|
||||||
orderLine.orderActionList.every(
|
|
||||||
(item) => item.interfaceUri !== '/mm/order/toShipping'
|
|
||||||
)
|
|
||||||
"
|
|
||||||
type="success"
|
|
||||||
class="!ml-0"
|
|
||||||
size="small"
|
|
||||||
@click="handleViewLogistics(orderLine)"
|
|
||||||
>查看物流信息</el-button
|
|
||||||
>
|
>
|
||||||
|
<el-button
|
||||||
|
class="ml-0!"
|
||||||
|
type="primary"
|
||||||
|
size="small"
|
||||||
|
@click="onButtonClick(orderAction.interfaceUri, packageData)"
|
||||||
|
>{{ orderAction.desc.replace('admin', '').replace('按钮', '') }}</el-button
|
||||||
|
>
|
||||||
|
<el-button
|
||||||
|
v-if="
|
||||||
|
packageData.orderActionList.every(
|
||||||
|
(item) => item.interfaceUri !== '/mm/order/toShipping'
|
||||||
|
)
|
||||||
|
"
|
||||||
|
type="success"
|
||||||
|
class="!ml-0"
|
||||||
|
size="small"
|
||||||
|
@click="handleViewLogistics(packageData)"
|
||||||
|
>查看物流信息</el-button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -196,12 +203,19 @@
|
|||||||
:order-id="currentOrderId"
|
:order-id="currentOrderId"
|
||||||
@close="handleCloseLogisticsDialog"
|
@close="handleCloseLogisticsDialog"
|
||||||
/>
|
/>
|
||||||
|
<!-- 打包 -->
|
||||||
|
<pack-dialog
|
||||||
|
v-model="dialogPackVisible"
|
||||||
|
:orderLineData="currentOrderLineData"
|
||||||
|
@close="dialogPackVisible = false"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { reactive, ref } from 'vue'
|
import { reactive, ref } from 'vue'
|
||||||
import LogisticsDialog from './logistics-dialog.vue'
|
import LogisticsDialog from './logistics-dialog.vue'
|
||||||
|
import PackDialog from './pack-dialog.vue'
|
||||||
|
|
||||||
type SortWay = 'create_desc' | 'create_asc' | 'pickup_desc' | 'pickup_asc'
|
type SortWay = 'create_desc' | 'create_asc' | 'pickup_desc' | 'pickup_asc'
|
||||||
|
|
||||||
@ -215,6 +229,12 @@ interface OrderItem {
|
|||||||
status: string
|
status: string
|
||||||
orderActionList: OrderAction[]
|
orderActionList: OrderAction[]
|
||||||
productMainImageUrl: string
|
productMainImageUrl: string
|
||||||
|
chinesePromotionPrice: string
|
||||||
|
}
|
||||||
|
interface PackageItem {
|
||||||
|
orderActionList: OrderAction[]
|
||||||
|
vvTradeOrderLineDOList: OrderItem[]
|
||||||
|
trackNumber: number
|
||||||
}
|
}
|
||||||
interface OrderAction {
|
interface OrderAction {
|
||||||
desc: string
|
desc: string
|
||||||
@ -240,7 +260,7 @@ interface Order {
|
|||||||
type: string
|
type: string
|
||||||
warehouse: string
|
warehouse: string
|
||||||
} */
|
} */
|
||||||
vvTradeOrderLineList: OrderItem[]
|
packageList: PackageItem[]
|
||||||
checked: boolean
|
checked: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -366,12 +386,14 @@ const onTabClick = () => {
|
|||||||
handleGetOrderList()
|
handleGetOrderList()
|
||||||
}
|
}
|
||||||
|
|
||||||
const onButtonClick = (interfaceUri: string, orderLine: OrderItem) => {
|
const onButtonClick = (interfaceUri: string, packageData: PackageItem) => {
|
||||||
|
console.warn('----- my data is packageData: ', packageData)
|
||||||
if ('/mm/order/toShipping' === interfaceUri) {
|
if ('/mm/order/toShipping' === interfaceUri) {
|
||||||
// 打包
|
// 打包
|
||||||
|
handlePack(packageData.vvTradeOrderLineDOList)
|
||||||
} else if ('/mm/order/testzc' === interfaceUri) {
|
} else if ('/mm/order/testzc' === interfaceUri) {
|
||||||
// testzc 物流的接口
|
// testzc 物流的接口
|
||||||
handleViewLogistics(orderLine)
|
handleViewLogistics(packageData)
|
||||||
} else {
|
} else {
|
||||||
// testzc其他按钮的接口
|
// testzc其他按钮的接口
|
||||||
const apiMap = {
|
const apiMap = {
|
||||||
@ -393,11 +415,19 @@ const logisticsDialogVisible = ref(false)
|
|||||||
const currentOrderId = ref<number>(NaN)
|
const currentOrderId = ref<number>(NaN)
|
||||||
|
|
||||||
// 查看物流
|
// 查看物流
|
||||||
const handleViewLogistics = (orderLine: OrderItem) => {
|
const handleViewLogistics = (packageData: PackageItem) => {
|
||||||
currentOrderId.value = orderLine.id
|
currentOrderId.value = packageData.trackNumber
|
||||||
logisticsDialogVisible.value = true
|
logisticsDialogVisible.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 打包
|
||||||
|
const dialogPackVisible = ref(false)
|
||||||
|
const currentOrderLineData = ref<OrderItem[]>([])
|
||||||
|
const handlePack = (orderLines: OrderItem[]) => {
|
||||||
|
currentOrderLineData.value = orderLines
|
||||||
|
dialogPackVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
// 关闭物流弹窗
|
// 关闭物流弹窗
|
||||||
const handleCloseLogisticsDialog = () => {
|
const handleCloseLogisticsDialog = () => {
|
||||||
logisticsDialogVisible.value = false
|
logisticsDialogVisible.value = false
|
||||||
@ -445,11 +475,109 @@ const handleGetOrderList = async (searchData: any = {}) => {
|
|||||||
pageNum: 1,
|
pageNum: 1,
|
||||||
pageSize: 20
|
pageSize: 20
|
||||||
})
|
})
|
||||||
orders.value = res.data.map((item: any) => {
|
|
||||||
|
/* const res = {
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
id: 202511172456,
|
||||||
|
isDelete: 0,
|
||||||
|
createTime: 1762506683000,
|
||||||
|
modifyTime: 1762506683000,
|
||||||
|
num: 2,
|
||||||
|
allPrice: 0,
|
||||||
|
buyerId: 7,
|
||||||
|
createTimestamp: 1762506683235,
|
||||||
|
modifyTimestamp: 1762506683235,
|
||||||
|
contry: '中国',
|
||||||
|
province: '山西省',
|
||||||
|
city: '阳泉市',
|
||||||
|
district: '城区',
|
||||||
|
buyerDetailAddress: '信息港9期',
|
||||||
|
gmtDownOrder: 1762506683000,
|
||||||
|
packageList: [
|
||||||
|
{
|
||||||
|
vvTradeOrderLineDOList: [
|
||||||
|
{
|
||||||
|
activityAwardCount: 0,
|
||||||
|
batchNum: 2,
|
||||||
|
createTime: 1762506683000,
|
||||||
|
id: 202511172457,
|
||||||
|
isDelete: 0,
|
||||||
|
modifyTime: 1762506683000,
|
||||||
|
num: 2,
|
||||||
|
originPrice: 16,
|
||||||
|
productId: 58,
|
||||||
|
productMainImageUrl:
|
||||||
|
'https://heyuimage.ihzhy.com/prd/202511/9ea39f99ec120fb0.jpg?key=xxxxxxx?key=xxxxxxx?key=xxxxxxx?key=xxxxxxx?key=xxxxxxx?key=xxxxxxx',
|
||||||
|
productName: '32322332',
|
||||||
|
profitAmount: 0,
|
||||||
|
promotionPrice: 20,
|
||||||
|
refundAmount: 0,
|
||||||
|
refundCount: 0,
|
||||||
|
salePrice: 0,
|
||||||
|
shippingAmount: 0,
|
||||||
|
skuId: 346,
|
||||||
|
skuInfo: '[{"propertyName":"长度","propertyValue":"11333"}]',
|
||||||
|
status: 'wait_pay',
|
||||||
|
tradeOrderId: 202511172456,
|
||||||
|
mergeIdList: [202511172457, 202511172456]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
activityAwardCount: 0,
|
||||||
|
batchNum: 2,
|
||||||
|
createTime: 1762506683000,
|
||||||
|
id: 202511172457,
|
||||||
|
isDelete: 0,
|
||||||
|
modifyTime: 1762506683000,
|
||||||
|
num: 2,
|
||||||
|
originPrice: 16,
|
||||||
|
productId: 58,
|
||||||
|
productMainImageUrl:
|
||||||
|
'https://heyuimage.ihzhy.com/prd/202511/9ea39f99ec120fb0.jpg?key=xxxxxxx?key=xxxxxxx?key=xxxxxxx?key=xxxxxxx?key=xxxxxxx?key=xxxxxxx',
|
||||||
|
productName: '32322332',
|
||||||
|
profitAmount: 0,
|
||||||
|
promotionPrice: 20,
|
||||||
|
refundAmount: 0,
|
||||||
|
refundCount: 0,
|
||||||
|
salePrice: 0,
|
||||||
|
shippingAmount: 0,
|
||||||
|
skuId: 346,
|
||||||
|
skuInfo: '[{"propertyName":"长度","propertyValue":"11333"}]',
|
||||||
|
status: 'wait_pay',
|
||||||
|
tradeOrderId: 202511172456,
|
||||||
|
mergeIdList: [202511172457, 202511172456]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
orderActionList: [
|
||||||
|
{
|
||||||
|
buttonName: 'App_Close',
|
||||||
|
desc: 'app关闭订单',
|
||||||
|
interfaceUri: '/app/order/close'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
} */
|
||||||
|
orders.value = res.data.rows.map((item: any) => {
|
||||||
item.platform = '购de着小程序'
|
item.platform = '购de着小程序'
|
||||||
item.allPrice = '¥' + item.allPrice.toFixed(2)
|
item.allPrice = '¥' + item.allPrice
|
||||||
item.tradeOrderId = item.id
|
item.tradeOrderId = item.id
|
||||||
item.vvTradeOrderLineList = item.vvTradeOrderLineDOList.map((childOrder: any) => {
|
item.packageList = item.packageList.map((packageData: any) => {
|
||||||
|
packageData.vvTradeOrderLineDOList = packageData.vvTradeOrderLineDOList.map((item: any) => {
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
status: orderStatusMap[item.status as keyof typeof orderStatusMap],
|
||||||
|
chinesePromotionPrice: '¥' + item.promotionPrice.toFixed(2),
|
||||||
|
skuInfo: JSON.parse(item.skuInfo)
|
||||||
|
.map((it: any) => `${it.propertyName}:${it.propertyValue}`)
|
||||||
|
.join(',')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return packageData
|
||||||
|
})
|
||||||
|
/* item.vvTradeOrderLineList = item.packageList.map((childOrder: any) => {
|
||||||
return {
|
return {
|
||||||
...childOrder,
|
...childOrder,
|
||||||
status: orderStatusMap[childOrder.status as keyof typeof orderStatusMap],
|
status: orderStatusMap[childOrder.status as keyof typeof orderStatusMap],
|
||||||
@ -459,7 +587,7 @@ const handleGetOrderList = async (searchData: any = {}) => {
|
|||||||
.join(','),
|
.join(','),
|
||||||
checked: false
|
checked: false
|
||||||
}
|
}
|
||||||
})
|
}) */
|
||||||
return item
|
return item
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -580,6 +708,7 @@ handleGetOrderList()
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
color: #606266;
|
color: #606266;
|
||||||
|
border-bottom: 1px solid #ebeef5;
|
||||||
|
|
||||||
.goods-item + .goods-item {
|
.goods-item + .goods-item {
|
||||||
border-top: 1px solid #f0f2f5;
|
border-top: 1px solid #f0f2f5;
|
||||||
@ -590,12 +719,6 @@ handleGetOrderList()
|
|||||||
.goods-status-item + .goods-status-item {
|
.goods-status-item + .goods-status-item {
|
||||||
border-top: 1px solid #f0f2f5;
|
border-top: 1px solid #f0f2f5;
|
||||||
}
|
}
|
||||||
.goods-actions-item {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
.goods-actions-item + .goods-actions-item {
|
|
||||||
border-top: 1px solid #f0f2f5;
|
|
||||||
}
|
|
||||||
.goods {
|
.goods {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|||||||
312
src/views/order/list/pack-dialog.vue
Normal file
312
src/views/order/list/pack-dialog.vue
Normal file
@ -0,0 +1,312 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog
|
||||||
|
v-model="dialogVisible"
|
||||||
|
title="打包管理"
|
||||||
|
width="900px"
|
||||||
|
:before-close="() => handleClose()"
|
||||||
|
@close="() => handleClose()"
|
||||||
|
>
|
||||||
|
<div class="pack-dialog">
|
||||||
|
<!-- 表格区域 -->
|
||||||
|
<div class="table-section">
|
||||||
|
<h3
|
||||||
|
class="text-base font-semibold mb-5 flex items-center"
|
||||||
|
style="
|
||||||
|
color: #303133;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
padding-left: 18px;
|
||||||
|
background: linear-gradient(90deg, #f4f8ff 0%, #fff 100%);
|
||||||
|
border-radius: 6px 0 0 6px;
|
||||||
|
height: 36px;
|
||||||
|
align-items: center;
|
||||||
|
"
|
||||||
|
>
|
||||||
|
请选择以下要打包的订单
|
||||||
|
</h3>
|
||||||
|
<el-table
|
||||||
|
ref="tableRef"
|
||||||
|
:data="tableData"
|
||||||
|
style="width: 100%"
|
||||||
|
@selection-change="handleSelectionChange"
|
||||||
|
>
|
||||||
|
<el-table-column type="selection" width="55" />
|
||||||
|
<el-table-column prop="productName" label="商品名称" min-width="150" />
|
||||||
|
<el-table-column prop="skuInfo" label="SKU信息" min-width="120" />
|
||||||
|
<el-table-column prop="num" label="数量" width="80" align="center" />
|
||||||
|
<el-table-column prop="promotionPrice" label="单价" width="100" align="right" />
|
||||||
|
<el-table-column prop="status" label="状态" width="100" align="center" />
|
||||||
|
</el-table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 表单区域 -->
|
||||||
|
<div class="form-section" v-if="selectedRows.length > 0">
|
||||||
|
<h3
|
||||||
|
class="text-base font-semibold mb-5 flex items-center"
|
||||||
|
style="
|
||||||
|
color: #303133;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
padding-left: 18px;
|
||||||
|
background: linear-gradient(90deg, #f4f8ff 0%, #fff 100%);
|
||||||
|
border-radius: 6px 0 0 6px;
|
||||||
|
height: 36px;
|
||||||
|
align-items: center;
|
||||||
|
"
|
||||||
|
>
|
||||||
|
物流信息
|
||||||
|
</h3>
|
||||||
|
<el-form ref="formRef" :model="formData" inline :rules="formRules" label-width="100px">
|
||||||
|
<el-form-item label="物流单号" prop="trackingNumber">
|
||||||
|
<el-input v-model="formData.trackingNumber" placeholder="请输入物流单号" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="物流公司" prop="logisticsCompany">
|
||||||
|
<el-input v-model="formData.logisticsCompany" placeholder="请输入物流公司" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="运费" prop="shippingAmount">
|
||||||
|
<el-input
|
||||||
|
v-model="formData.shippingAmount"
|
||||||
|
placeholder="请输入运费"
|
||||||
|
clearable
|
||||||
|
style="width: 100px"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="上传照片" prop="packageImageUrls">
|
||||||
|
<fileUploadBtn accept="image/*" :multiple="true" @change="handlePhotoChange" />
|
||||||
|
<el-button class="ml-2" @click="onClickChooseResourceBtn('mainImageUrl')"
|
||||||
|
>资源库导入</el-button
|
||||||
|
>
|
||||||
|
</el-form-item>
|
||||||
|
<div v-if="formData.packageImageUrls.length > 0" class="photo-preview ml-24">
|
||||||
|
<div
|
||||||
|
v-for="(photo, index) in formData.packageImageUrls"
|
||||||
|
:key="index"
|
||||||
|
class="photo-item"
|
||||||
|
>
|
||||||
|
<el-image
|
||||||
|
:src="photo"
|
||||||
|
fit="cover"
|
||||||
|
style="width: 70px; height: 70px; border-radius: 4px"
|
||||||
|
:preview-src-list="formData.packageImageUrls"
|
||||||
|
/>
|
||||||
|
<el-button type="danger" size="small" link @click="handleRemovePhoto(index)">
|
||||||
|
删除
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<el-button @click="handleClose()">关闭弹窗</el-button>
|
||||||
|
<el-button type="primary" @click="handleSubmit" :loading="submitting">打包订单</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<FileExplorerDialog
|
||||||
|
v-model="showFileExplorer"
|
||||||
|
v-model:initPathArray="currentPathArray"
|
||||||
|
@select="(files: FileItem[]) => handleChooseResourceFileCallback(files, curFileData)"
|
||||||
|
/>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, computed, watch } from 'vue'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import type { FormInstance, FormRules } from 'element-plus'
|
||||||
|
// @ts-ignore
|
||||||
|
import fileUploadBtn from '@/components/FileUploadBtn/index.vue'
|
||||||
|
import FileExplorerDialog, { FileItem } from '@/components/FileExplorerDialog/index.vue'
|
||||||
|
|
||||||
|
interface TableItem {
|
||||||
|
id: number
|
||||||
|
productName: string
|
||||||
|
skuInfo: string
|
||||||
|
num: number
|
||||||
|
promotionPrice: string
|
||||||
|
status: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface FormData {
|
||||||
|
trackingNumber: string
|
||||||
|
logisticsCompany: string
|
||||||
|
shippingAmount: string
|
||||||
|
packageImageUrls: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
interface OrderItem {
|
||||||
|
orderLineId: number
|
||||||
|
productName: string
|
||||||
|
skuInfo: string
|
||||||
|
num: number
|
||||||
|
promotionPrice: string
|
||||||
|
status: string
|
||||||
|
mergeIdList: number[]
|
||||||
|
}
|
||||||
|
const props = defineProps<{
|
||||||
|
modelValue: boolean
|
||||||
|
orderLineData?: OrderItem[]
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
'update:modelValue': [value: boolean]
|
||||||
|
close: []
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const dialogVisible = computed({
|
||||||
|
get: () => props.modelValue,
|
||||||
|
set: (value) => emit('update:modelValue', value)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 表格相关
|
||||||
|
const tableRef = ref()
|
||||||
|
const tableData = ref<OrderItem[]>([])
|
||||||
|
const selectedRows = ref<OrderItem[]>([])
|
||||||
|
|
||||||
|
// 表单相关
|
||||||
|
const formRef = ref<FormInstance>()
|
||||||
|
const formData = ref<FormData>({
|
||||||
|
trackingNumber: '',
|
||||||
|
logisticsCompany: '',
|
||||||
|
shippingAmount: '',
|
||||||
|
packageImageUrls: []
|
||||||
|
})
|
||||||
|
|
||||||
|
const formRules: FormRules = {
|
||||||
|
trackingNumber: [{ required: true, message: '请输入物流单号', trigger: 'blur' }],
|
||||||
|
logisticsCompany: [{ required: true, message: '请输入物流公司', trigger: 'blur' }],
|
||||||
|
shippingAmount: [{ required: true, message: '请输入运费', trigger: 'blur' }],
|
||||||
|
packageImageUrls: [{ required: true, message: '请上传照片', trigger: 'blur' }]
|
||||||
|
}
|
||||||
|
|
||||||
|
// 状态
|
||||||
|
const submitting = ref(false)
|
||||||
|
|
||||||
|
// 表格选择变化
|
||||||
|
const handleSelectionChange = (selection: TableItem[]) => {
|
||||||
|
selectedRows.value = selection
|
||||||
|
}
|
||||||
|
|
||||||
|
// 照片变化
|
||||||
|
const handlePhotoChange = (
|
||||||
|
files: Array<{ fileName: string; resourceUrl: string; type: 'image' | 'video' }>
|
||||||
|
) => {
|
||||||
|
formData.value.packageImageUrls.push(...files.map((item) => item.resourceUrl))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除照片
|
||||||
|
const handleRemovePhoto = (index: number) => {
|
||||||
|
formData.value.packageImageUrls.splice(index, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提交表单
|
||||||
|
const handleSubmit = async () => {
|
||||||
|
if (!formRef.value) return
|
||||||
|
|
||||||
|
formRef.value.validate(async (valid) => {
|
||||||
|
if (!valid) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedRows.value.length === 0) {
|
||||||
|
ElMessage.warning('请至少选择一项数据进行操作')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
submitting.value = true
|
||||||
|
try {
|
||||||
|
const submitData = {
|
||||||
|
tradeOrderLineIds: selectedRows.value.map((row) => row.orderLineId),
|
||||||
|
...formData.value
|
||||||
|
}
|
||||||
|
await api.order.packOrder.post!(submitData)
|
||||||
|
ElMessage.success('打包成功')
|
||||||
|
handleClose(false)
|
||||||
|
selectedRows.value = []
|
||||||
|
} catch (error) {
|
||||||
|
ElMessage.error('打包失败')
|
||||||
|
} finally {
|
||||||
|
submitting.value = false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentPathArray = ref<{ name: string; id: number }[]>([{ name: '根目录', id: 0 }])
|
||||||
|
const showFileExplorer = ref(false)
|
||||||
|
|
||||||
|
const onClickChooseResourceBtn = () => {
|
||||||
|
showFileExplorer.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleChooseResourceFileCallback = async (files: FileItem[]) => {
|
||||||
|
formData.value.packageImageUrls.push(...files.map((item) => item.resourceUrl!))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭弹窗
|
||||||
|
const handleClose = (isClose = true) => {
|
||||||
|
// 重置数据
|
||||||
|
selectedRows.value = []
|
||||||
|
formData.value = {
|
||||||
|
trackingNumber: '',
|
||||||
|
logisticsCompany: '',
|
||||||
|
shippingAmount: '',
|
||||||
|
packageImageUrls: []
|
||||||
|
}
|
||||||
|
formRef.value?.resetFields()
|
||||||
|
tableRef.value?.clearSelection()
|
||||||
|
isClose && emit('close')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 监听弹窗打开和 id 变化
|
||||||
|
watch(
|
||||||
|
() => dialogVisible.value,
|
||||||
|
(visible) => {
|
||||||
|
if (visible) {
|
||||||
|
tableData.value = []
|
||||||
|
;(props.orderLineData || []).forEach((item: OrderItem) => {
|
||||||
|
tableData.value.push(
|
||||||
|
...item.mergeIdList.map((orderLineId: number) => {
|
||||||
|
return { ...item, orderLineId }
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.pack-dialog {
|
||||||
|
.table-section {
|
||||||
|
margin-bottom: 24px;
|
||||||
|
|
||||||
|
.batch-actions {
|
||||||
|
margin-top: 16px;
|
||||||
|
padding: 12px 0;
|
||||||
|
border-top: 1px solid #ebeef5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-section {
|
||||||
|
.photo-preview {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 12px;
|
||||||
|
margin-top: 0px;
|
||||||
|
|
||||||
|
.photo-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-footer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Loading…
x
Reference in New Issue
Block a user