feat: 订单列表+打包
This commit is contained in:
parent
4797a630f3
commit
580cd25221
@ -3,7 +3,8 @@ const order = {
|
||||
* 订单管理
|
||||
*/
|
||||
getOrderList: ['/order/list'], // 获取订单管理
|
||||
packOrder: ['/order/pack'], // 打包
|
||||
getOrderDetail: ['/order/detail'], // 获取订单详情
|
||||
packOrder: ['/order/toShipping'], // 打包
|
||||
unpackOrder: ['/order/unpack'], // 取消打包
|
||||
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>
|
||||
</div>
|
||||
</div>
|
||||
<div class="order-content">
|
||||
<div class="col goods">
|
||||
<div v-for="item in order.vvTradeOrderLineList" :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>卖家SKU:{{ item.sku }}</span> -->
|
||||
<div v-for="(packageData, packageIndex) in order.packageList" :key="packageIndex">
|
||||
<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>卖家SKU:{{ item.sku }}</span> -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="goods-price">{{ item.chinesePromotionPrice }} x {{ item.num }}</div>
|
||||
</div>
|
||||
<div class="goods-price">{{ item.promotionPrice }} x {{ item.num }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col total">
|
||||
<div class="amount">{{ order.allPrice }}</div>
|
||||
</div>
|
||||
<!-- <div class="col delivery">
|
||||
<div class="delivery-type">{{ order.delivery.type }}</div>
|
||||
<div class="delivery-warehouse">签收仓库:{{ order.delivery.warehouse }}</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 class="col total">
|
||||
<div class="amount">
|
||||
{{
|
||||
packageData.vvTradeOrderLineDOList.reduce((acc: number, it: any) => {
|
||||
return acc + it.promotionPrice * it.num
|
||||
}, 0)
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
<!-- <ul class="status-detail">
|
||||
<li>AWB:{{ order.awb }}</li>
|
||||
<li>揽收:{{ order.pickupStatus }}</li>
|
||||
<li>装袋:{{ order.bagStatus }}</li>
|
||||
</ul> -->
|
||||
</div>
|
||||
<div class="col actions">
|
||||
<div
|
||||
v-for="orderLine in order.vvTradeOrderLineList"
|
||||
:key="orderLine.id"
|
||||
class="goods-actions-item flex-1 flex flex-col gap-2 justify-center items-center"
|
||||
>
|
||||
<el-button
|
||||
v-for="item in orderLine.orderActionList.filter(
|
||||
(item) => !item.desc.includes('app')
|
||||
)"
|
||||
:key="item.interfaceUri"
|
||||
class="ml-0!"
|
||||
type="primary"
|
||||
size="small"
|
||||
@click="onButtonClick(item.interfaceUri, orderLine)"
|
||||
>{{ 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
|
||||
<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>
|
||||
<!-- <ul class="status-detail">
|
||||
<li>AWB:{{ order.awb }}</li>
|
||||
<li>揽收:{{ order.pickupStatus }}</li>
|
||||
<li>装袋:{{ order.bagStatus }}</li>
|
||||
</ul> -->
|
||||
</div>
|
||||
<!-- <div class="col delivery">
|
||||
<div class="delivery-type">{{ order.delivery.type }}</div>
|
||||
<div class="delivery-warehouse">签收仓库:{{ order.delivery.warehouse }}</div>
|
||||
</div> -->
|
||||
<div class="col actions">
|
||||
<div
|
||||
v-for="(orderAction, orderActionIndex) in packageData.orderActionList"
|
||||
:key="orderActionIndex"
|
||||
:class="[
|
||||
'goods-actions-item flex flex-col gap-2 justify-center items-center',
|
||||
orderActionIndex ? '!mt-2' : ''
|
||||
]"
|
||||
>
|
||||
<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>
|
||||
@ -196,12 +203,19 @@
|
||||
:order-id="currentOrderId"
|
||||
@close="handleCloseLogisticsDialog"
|
||||
/>
|
||||
<!-- 打包 -->
|
||||
<pack-dialog
|
||||
v-model="dialogPackVisible"
|
||||
:orderLineData="currentOrderLineData"
|
||||
@close="dialogPackVisible = false"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref } from 'vue'
|
||||
import LogisticsDialog from './logistics-dialog.vue'
|
||||
import PackDialog from './pack-dialog.vue'
|
||||
|
||||
type SortWay = 'create_desc' | 'create_asc' | 'pickup_desc' | 'pickup_asc'
|
||||
|
||||
@ -215,6 +229,12 @@ interface OrderItem {
|
||||
status: string
|
||||
orderActionList: OrderAction[]
|
||||
productMainImageUrl: string
|
||||
chinesePromotionPrice: string
|
||||
}
|
||||
interface PackageItem {
|
||||
orderActionList: OrderAction[]
|
||||
vvTradeOrderLineDOList: OrderItem[]
|
||||
trackNumber: number
|
||||
}
|
||||
interface OrderAction {
|
||||
desc: string
|
||||
@ -240,7 +260,7 @@ interface Order {
|
||||
type: string
|
||||
warehouse: string
|
||||
} */
|
||||
vvTradeOrderLineList: OrderItem[]
|
||||
packageList: PackageItem[]
|
||||
checked: boolean
|
||||
}
|
||||
|
||||
@ -256,7 +276,7 @@ const tabs = reactive([
|
||||
{ name: 'delete', label: '已删除' },
|
||||
{ name: 'refund', label: '已退款' }
|
||||
])
|
||||
/*
|
||||
/*
|
||||
const statusShortcuts = reactive([
|
||||
{ label: '待打包', count: 3544 },
|
||||
{ label: '待安排物流', count: 492 },
|
||||
@ -366,12 +386,14 @@ const onTabClick = () => {
|
||||
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) {
|
||||
// 打包
|
||||
handlePack(packageData.vvTradeOrderLineDOList)
|
||||
} else if ('/mm/order/testzc' === interfaceUri) {
|
||||
// testzc 物流的接口
|
||||
handleViewLogistics(orderLine)
|
||||
handleViewLogistics(packageData)
|
||||
} else {
|
||||
// testzc其他按钮的接口
|
||||
const apiMap = {
|
||||
@ -393,11 +415,19 @@ const logisticsDialogVisible = ref(false)
|
||||
const currentOrderId = ref<number>(NaN)
|
||||
|
||||
// 查看物流
|
||||
const handleViewLogistics = (orderLine: OrderItem) => {
|
||||
currentOrderId.value = orderLine.id
|
||||
const handleViewLogistics = (packageData: PackageItem) => {
|
||||
currentOrderId.value = packageData.trackNumber
|
||||
logisticsDialogVisible.value = true
|
||||
}
|
||||
|
||||
// 打包
|
||||
const dialogPackVisible = ref(false)
|
||||
const currentOrderLineData = ref<OrderItem[]>([])
|
||||
const handlePack = (orderLines: OrderItem[]) => {
|
||||
currentOrderLineData.value = orderLines
|
||||
dialogPackVisible.value = true
|
||||
}
|
||||
|
||||
// 关闭物流弹窗
|
||||
const handleCloseLogisticsDialog = () => {
|
||||
logisticsDialogVisible.value = false
|
||||
@ -445,11 +475,109 @@ const handleGetOrderList = async (searchData: any = {}) => {
|
||||
pageNum: 1,
|
||||
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.allPrice = '¥' + item.allPrice.toFixed(2)
|
||||
item.allPrice = '¥' + item.allPrice
|
||||
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 {
|
||||
...childOrder,
|
||||
status: orderStatusMap[childOrder.status as keyof typeof orderStatusMap],
|
||||
@ -459,7 +587,7 @@ const handleGetOrderList = async (searchData: any = {}) => {
|
||||
.join(','),
|
||||
checked: false
|
||||
}
|
||||
})
|
||||
}) */
|
||||
return item
|
||||
})
|
||||
}
|
||||
@ -580,6 +708,7 @@ handleGetOrderList()
|
||||
padding: 0;
|
||||
font-size: 13px;
|
||||
color: #606266;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
|
||||
.goods-item + .goods-item {
|
||||
border-top: 1px solid #f0f2f5;
|
||||
@ -590,12 +719,6 @@ handleGetOrderList()
|
||||
.goods-status-item + .goods-status-item {
|
||||
border-top: 1px solid #f0f2f5;
|
||||
}
|
||||
.goods-actions-item {
|
||||
width: 100%;
|
||||
}
|
||||
.goods-actions-item + .goods-actions-item {
|
||||
border-top: 1px solid #f0f2f5;
|
||||
}
|
||||
.goods {
|
||||
display: flex;
|
||||
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