feat:打印面单功能

This commit is contained in:
yangmf_0726 committed 2025-09-25 10:38:56 +08:00
1 parent fdc1f7e3eb
commit 461dc7f28b
5 files changed
+113 -221

No files matched your search

+1
View File
@@ -34,6 +34,7 @@ export interface OrderVO {
deliveryTemplateId?: number | null // 配送模板编号
logisticsId?: number | null // 发货物流公司编号
logisticsNo?: string // 发货物流单号
logisticsLabel?: string //发货物流面单短链
deliveryTime?: Date | null // 发货时间
receiveTime?: Date | null // 收货时间
receiverName?: string // 收件人名称
@@ -3,27 +3,16 @@
<el-form ref="formRef" :model="formData" :rules="rules" label-width="120px" :disabled="isDetail">
<el-form-item label="配送方式" prop="deliveryTypes">
<el-checkbox-group v-model="formData.deliveryTypes" class="w-80">
<el-checkbox
v-for="dict in getIntDictOptions(DICT_TYPE.TRADE_DELIVERY_TYPE)"
:key="dict.value"
:value="dict.value"
>
<el-checkbox v-for="dict in getIntDictOptions(DICT_TYPE.TRADE_DELIVERY_TYPE)" :key="dict.value"
:value="dict.value">
{{ dict.label }}
</el-checkbox>
</el-checkbox-group>
</el-form-item>
<el-form-item
label="运费模板"
prop="deliveryTemplateId"
v-if="formData.deliveryTypes?.includes(DeliveryTypeEnum.EXPRESS.type)"
>
<el-form-item label="运费模板" prop="deliveryTemplateId"
v-if="formData.deliveryTypes?.includes(DeliveryTypeEnum.EXPRESS.type)">
<el-select placeholder="请选择运费模板" v-model="formData.deliveryTemplateId" class="w-80">
<el-option
v-for="item in deliveryTemplateList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
<el-option v-for="item in deliveryTemplateList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
</el-form>
@@ -44,7 +33,7 @@ const message = useMessage() // 消息弹窗
const props = defineProps({
propFormData: {
type: Object as PropType<Spu>,
default: () => {}
default: () => { }
},
isDetail: propTypes.bool.def(false) // 是否作为详情组件
})
+27 -54
View File
@@ -27,37 +27,23 @@
<dict-tag :type="DICT_TYPE.TRADE_ORDER_STATUS" :value="formData.status!" />
</el-descriptions-item>
<el-descriptions-item v-hasPermi="['trade:order:update']" label-class-name="no-colon">
<el-button
v-if="formData.status! === TradeOrderStatusEnum.UNPAID.status"
type="primary"
@click="updatePrice"
>
<el-button v-if="formData.status! === TradeOrderStatusEnum.UNPAID.status" type="primary" @click="updatePrice">
调整价格
</el-button>
<el-button type="primary" @click="remark">备注</el-button>
<!-- 待发货 -->
<template v-if="formData.status! === TradeOrderStatusEnum.UNDELIVERED.status">
<!-- 快递发货 -->
<el-button
v-if="formData.deliveryType === DeliveryTypeEnum.EXPRESS.type"
type="primary"
@click="delivery"
>
<el-button v-if="formData.deliveryType === DeliveryTypeEnum.EXPRESS.type" type="primary" @click="delivery">
发货
</el-button>
<el-button
v-if="formData.deliveryType === DeliveryTypeEnum.EXPRESS.type"
type="primary"
@click="updateAddress"
>
<el-button v-if="formData.deliveryType === DeliveryTypeEnum.EXPRESS.type" type="primary"
@click="updateAddress">
修改地址
</el-button>
<!-- 到店自提 -->
<el-button
v-if="formData.deliveryType === DeliveryTypeEnum.PICK_UP.type && showPickUp"
type="primary"
@click="handlePickUp"
>
<el-button v-if="formData.deliveryType === DeliveryTypeEnum.PICK_UP.type && showPickUp" type="primary"
@click="handlePickUp">
核销
</el-button>
</template>
@@ -93,10 +79,7 @@
</el-table-column>
<el-table-column label="售后状态" prop="afterSaleStatus" width="120">
<template #default="{ row }">
<dict-tag
:type="DICT_TYPE.TRADE_ORDER_ITEM_AFTER_SALE_STATUS"
:value="row.afterSaleStatus"
/>
<dict-tag :type="DICT_TYPE.TRADE_ORDER_ITEM_AFTER_SALE_STATUS" :value="row.afterSaleStatus" />
</template>
</el-table-column>
</el-table>
@@ -152,30 +135,23 @@
<div v-if="formData.deliveryType === DeliveryTypeEnum.EXPRESS.type">
<el-descriptions-item v-if="formData.receiverDetailAddress" label="收货地址: ">
{{ formData.receiverAreaName }} {{ formData.receiverDetailAddress }}
<el-link
v-clipboard:copy="formData.receiverAreaName + ' ' + formData.receiverDetailAddress"
v-clipboard:success="clipboardSuccess"
icon="ep:document-copy"
type="primary"
/>
<el-link v-clipboard:copy="formData.receiverAreaName + ' ' + formData.receiverDetailAddress"
v-clipboard:success="clipboardSuccess" icon="ep:document-copy" type="primary" />
</el-descriptions-item>
<el-descriptions-item v-if="formData.logisticsId" label="物流公司: ">
{{ deliveryExpressList.find((item) => item.id === formData.logisticsId)?.name }}
{{deliveryExpressList.find((item) => item.id === formData.logisticsId)?.name}}
</el-descriptions-item>
<el-descriptions-item v-if="formData.logisticsId" label="运单号: ">
{{ formData.logisticsNo }}
</el-descriptions-item>
<el-descriptions-item v-if="formatDate.deliveryTime" label="发货时间: ">
</el-descriptions-item>
<el-descriptions-item escriptions-item v-if="formatDate.deliveryTime" label="发货时间: ">
{{ formatDate(formData.deliveryTime) }}
</el-descriptions-item>
<el-descriptions-item v-for="item in 2" :key="item" label-class-name="no-colon" />
<el-descriptions-item v-if="expressTrackList.length > 0" label="物流详情: ">
<el-timeline>
<el-timeline-item
v-for="(express, index) in expressTrackList"
:key="index"
:timestamp="formatDate(express.time)"
>
<el-timeline-item v-for="(express, index) in expressTrackList" :key="index"
:timestamp="formatDate(express.time)">
{{ express.content }}
</el-timeline-item>
</el-timeline>
@@ -193,20 +169,13 @@
<el-descriptions title="订单操作日志">
<el-descriptions-item labelClassName="no-colon">
<el-timeline>
<el-timeline-item
v-for="(log, index) in formData.logs"
:key="index"
:timestamp="formatDate(log.createTime!)"
placement="top"
>
<el-timeline-item v-for="(log, index) in formData.logs" :key="index" :timestamp="formatDate(log.createTime!)"
placement="top">
<div class="el-timeline-right-content">
{{ log.content }}
</div>
<template #dot>
<span
:style="{ backgroundColor: getUserTypeColor(log.userType!) }"
class="dot-node-style"
>
<span :style="{ backgroundColor: getUserTypeColor(log.userType!) }" class="dot-node-style">
{{ getDictLabel(DICT_TYPE.USER_TYPE, log.userType)[0] }}
</span>
</template>
@@ -258,7 +227,7 @@ const getUserTypeColor = (type: number) => {
}
// 订单详情
const formData = ref<TradeOrderApi.OrderVO>({
const formData = ref < TradeOrderApi.OrderVO > ({
logs: []
})
@@ -290,7 +259,7 @@ const handlePickUp = async () => {
message.success('核销成功')
// 刷新列表
await getDetail()
} catch {}
} catch { }
}
/** 获得详情 */
@@ -403,11 +372,15 @@ onMounted(async () => {
&::before {
position: absolute;
top: 10px;
left: 13px; /* 将伪元素水平居中 */
border-color: transparent var(--app-content-bg-color) transparent transparent; /* 尖角颜色,左侧朝向 */
left: 13px;
/* 将伪元素水平居中 */
border-color: transparent var(--app-content-bg-color) transparent transparent;
/* 尖角颜色,左侧朝向 */
border-style: solid;
border-width: 8px; /* 调整尖角大小 */
content: ''; /* 必须设置 content 属性 */
border-width: 8px;
/* 调整尖角大小 */
content: '';
/* 必须设置 content 属性 */
}
}
@@ -7,6 +7,16 @@
<el-radio border value="none">无需发货</el-radio>
</el-radio-group>
</el-form-item>
<template v-if="expressType === 'express'">
<el-form-item label="物流公司">
<el-select v-model="formData.logisticsId" placeholder="请选择" style="width: 100%">
<el-option v-for="item in deliveryExpressList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
<!-- <el-form-item label="物流单号">
<el-input v-model="formData.logisticsNo" />
</el-form-item> -->
</template>
</el-form>
<template #footer>
<el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
@@ -15,9 +25,9 @@
</Dialog>
</template>
<script lang="ts" setup>
// import * as DeliveryExpressApi from '@/api/mall/trade/delivery/express'
import * as DeliveryExpressApi from '@/api/mall/trade/delivery/express'
import * as TradeOrderApi from '@/api/mall/trade/order'
// import { copyValueToTarget } from '@/utils'
import { copyValueToTarget } from '@/utils'
defineOptions({ name: 'OrderDeliveryForm' })
@@ -27,17 +37,20 @@ const message = useMessage() // 消息弹窗
const dialogVisible = ref(false) // 弹窗的是否展示
const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
const expressType = ref('express') // 如果值是 express,则是快递;none 则是无;未来做同城配送;
const formData = ref({
const formData = ref<TradeOrderApi.DeliveryVO>({
id: undefined, // 订单编号
logisticsId: 1, // 物流公司编号
})
const formRef = ref() // 表单 Ref
/** 打开弹窗 */
const open = async (orderId: number) => {
const open = async (row: TradeOrderApi.OrderVO) => {
resetForm()
// 设置订单ID
formData.value = { ...formData.value, id: orderId }
// 设置数据
copyValueToTarget(formData.value, row)
if (row.logisticsId === 0) {
expressType.value = 'none'
}
dialogVisible.value = true
}
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
@@ -49,7 +62,6 @@ const submitForm = async () => {
formLoading.value = true
try {
const data = unref(formData)
if (expressType.value === 'express' && data.id) {
// 选择快递物流时调用快递100接口
await TradeOrderApi.deliveryOrder100({ id: data.id })
@@ -71,13 +83,13 @@ const submitForm = async () => {
const resetForm = () => {
formData.value = {
id: undefined, // 订单编号
// logisticsId: null, // 物流公司编号
// logisticsNo: '' // 物流编号
logisticsId: null, // 物流公司编号
logisticsNo: '' // 物流编号
}
formRef.value?.resetFields()
}
// const deliveryExpressList = ref([])
const deliveryExpressList = ref([])
onMounted(async () => {
// deliveryExpressList.value = await DeliveryExpressApi.getSimpleDeliveryExpressList()
deliveryExpressList.value = await DeliveryExpressApi.getSimpleDeliveryExpressList()
})
</script>
+55 -138
View File
@@ -4,149 +4,64 @@
<!-- 搜索 -->
<ContentWrap>
<el-form
ref="queryFormRef"
:inline="true"
:model="queryParams"
class="-mb-15px"
label-width="68px"
>
<el-form ref="queryFormRef" :inline="true" :model="queryParams" class="-mb-15px" label-width="68px">
<el-form-item label="订单状态" prop="status">
<el-select v-model="queryParams.status" class="!w-280px" clearable placeholder="全部">
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.TRADE_ORDER_STATUS)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
<el-option v-for="dict in getIntDictOptions(DICT_TYPE.TRADE_ORDER_STATUS)" :key="dict.value"
:label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="支付方式" prop="payChannelCode">
<el-select
v-model="queryParams.payChannelCode"
class="!w-280px"
clearable
placeholder="全部"
>
<el-option
v-for="dict in getStrDictOptions(DICT_TYPE.PAY_CHANNEL_CODE)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
<el-select v-model="queryParams.payChannelCode" class="!w-280px" clearable placeholder="全部">
<el-option v-for="dict in getStrDictOptions(DICT_TYPE.PAY_CHANNEL_CODE)" :key="dict.value" :label="dict.label"
:value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="创建时间" prop="createTime">
<el-date-picker
v-model="queryParams.createTime"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
class="!w-280px"
end-placeholder="自定义时间"
start-placeholder="自定义时间"
type="daterange"
value-format="YYYY-MM-DD HH:mm:ss"
/>
<el-date-picker v-model="queryParams.createTime"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" class="!w-280px" end-placeholder="自定义时间"
start-placeholder="自定义时间" type="daterange" value-format="YYYY-MM-DD HH:mm:ss" />
</el-form-item>
<el-form-item label="订单来源" prop="terminal">
<el-select v-model="queryParams.terminal" class="!w-280px" clearable placeholder="全部">
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.TERMINAL)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
<el-option v-for="dict in getIntDictOptions(DICT_TYPE.TERMINAL)" :key="dict.value" :label="dict.label"
:value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="订单类型" prop="type">
<el-select v-model="queryParams.type" class="!w-280px" clearable placeholder="全部">
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.TRADE_ORDER_TYPE)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
<el-option v-for="dict in getIntDictOptions(DICT_TYPE.TRADE_ORDER_TYPE)" :key="dict.value" :label="dict.label"
:value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="配送方式" prop="deliveryType">
<el-select v-model="queryParams.deliveryType" class="!w-280px" clearable placeholder="全部">
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.TRADE_DELIVERY_TYPE)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
<el-option v-for="dict in getIntDictOptions(DICT_TYPE.TRADE_DELIVERY_TYPE)" :key="dict.value"
:label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item
v-if="queryParams.deliveryType === DeliveryTypeEnum.EXPRESS.type"
label="快递公司"
prop="logisticsId"
>
<el-form-item v-if="queryParams.deliveryType === DeliveryTypeEnum.EXPRESS.type" label="快递公司" prop="logisticsId">
<el-select v-model="queryParams.logisticsId" class="!w-280px" clearable placeholder="全部">
<el-option
v-for="item in deliveryExpressList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
<el-option v-for="item in deliveryExpressList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item
v-if="queryParams.deliveryType === DeliveryTypeEnum.PICK_UP.type"
label="自提门店"
prop="pickUpStoreId"
>
<el-select
v-model="queryParams.pickUpStoreId"
class="!w-280px"
clearable
multiple
placeholder="全部"
>
<el-option
v-for="item in pickUpStoreList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
<el-form-item v-if="queryParams.deliveryType === DeliveryTypeEnum.PICK_UP.type" label="自提门店" prop="pickUpStoreId">
<el-select v-model="queryParams.pickUpStoreId" class="!w-280px" clearable multiple placeholder="全部">
<el-option v-for="item in pickUpStoreList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item
v-if="queryParams.deliveryType === DeliveryTypeEnum.PICK_UP.type"
label="核销码"
prop="pickUpVerifyCode"
>
<el-input
v-model="queryParams.pickUpVerifyCode"
class="!w-280px"
clearable
placeholder="请输入自提核销码"
@keyup.enter="handleQuery"
/>
<el-form-item v-if="queryParams.deliveryType === DeliveryTypeEnum.PICK_UP.type" label="核销码"
prop="pickUpVerifyCode">
<el-input v-model="queryParams.pickUpVerifyCode" class="!w-280px" clearable placeholder="请输入自提核销码"
@keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="聚合搜索">
<el-input
v-show="true"
v-model="queryParams[queryType.queryParam]"
:type="queryType.queryParam === 'userId' ? 'number' : 'text'"
class="!w-280px"
clearable
placeholder="请输入"
>
<el-input v-show="true" v-model="queryParams[queryType.queryParam]"
:type="queryType.queryParam === 'userId' ? 'number' : 'text'" class="!w-280px" clearable placeholder="请输入">
<template #prepend>
<el-select
v-model="queryType.queryParam"
class="!w-110px"
clearable
placeholder="全部"
@change="inputChangeSelect"
>
<el-option
v-for="dict in dynamicSearchList"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
<el-select v-model="queryType.queryParam" class="!w-110px" clearable placeholder="全部"
@change="inputChangeSelect">
<el-option v-for="dict in dynamicSearchList" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</template>
</el-input>
@@ -171,19 +86,11 @@
<OrderTableColumn :list="list" :pick-up-store-list="pickUpStoreList">
<template #default="{ row }">
<div class="flex items-center justify-center">
<el-button
v-hasPermi="['trade:order:query']"
link
type="primary"
@click="openDetail(row.id)"
>
<el-button v-hasPermi="['trade:order:query']" link type="primary" @click="openDetail(row.id)">
<Icon icon="ep:notification" />
详情
</el-button>
<el-dropdown
v-hasPermi="['trade:order:update']"
@command="(command) => handleCommand(command, row)"
>
<el-dropdown v-hasPermi="['trade:order:update']" @command="(command) => handleCommand(command, row)">
<el-button link type="primary">
<Icon icon="ep:d-arrow-right" />
更多
@@ -191,20 +98,25 @@
<template #dropdown>
<el-dropdown-menu>
<!-- 如果是【快递】,并且【未发货】,则展示【发货】按钮 -->
<el-dropdown-item
v-if="
row.deliveryType === DeliveryTypeEnum.EXPRESS.type &&
row.status === TradeOrderStatusEnum.UNDELIVERED.status
"
command="delivery"
>
<el-dropdown-item v-if="
row.deliveryType === DeliveryTypeEnum.EXPRESS.type &&
row.status === TradeOrderStatusEnum.UNDELIVERED.status
" command="delivery">
<Icon icon="ep:takeaway-box" />
发货
</el-dropdown-item>
<el-dropdown-item
v-if="row.deliveryType === DeliveryTypeEnum.EXPRESS.type &&
(row.status === TradeOrderStatusEnum.DELIVERED.status || row.status === TradeOrderStatusEnum.COMPLETED.status)"
command="print">
<Icon icon="ep:printer" />
打印
</el-dropdown-item>
<el-dropdown-item command="remark">
<Icon icon="ep:chat-line-square" />
备注
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
@@ -213,12 +125,8 @@
</OrderTableColumn>
</el-table>
<!-- 分页 -->
<Pagination
v-model:limit="queryParams.pageSize"
v-model:page="queryParams.pageNo"
:total="total"
@pagination="getList"
/>
<Pagination v-model:limit="queryParams.pageSize" v-model:page="queryParams.pageNo" :total="total"
@pagination="getList" />
</ContentWrap>
<!-- 各种操作的弹窗 -->
@@ -228,6 +136,7 @@
<script lang="ts" setup>
import type { FormInstance } from 'element-plus'
import { ElMessage } from 'element-plus'
import OrderDeliveryForm from '@/views/mall/trade/order/form/OrderDeliveryForm.vue'
import OrderUpdateRemarkForm from '@/views/mall/trade/order/form/OrderUpdateRemarkForm.vue'
import * as TradeOrderApi from '@/api/mall/trade/order'
@@ -248,7 +157,7 @@ const queryFormRef = ref<FormInstance>() // 搜索的表单
const queryParams = ref({
pageNo: 1, // 页数
pageSize: 10, // 每页显示数量
id:undefined, // 订单ID
id: undefined, // 订单ID
status: undefined, // 订单状态
payChannelCode: undefined, // 支付方式
createTime: undefined, // 创建时间
@@ -338,6 +247,14 @@ const handleCommand = (command: string, row: TradeOrderApi.OrderVO) => {
case 'delivery':
deliveryFormRef.value?.open(row.id) // 直接传递id而不是整个row对象
break
case 'print':
// 打印功能:在新窗口打开物流面单链接
if (row.logisticsLabel) {
window.open(row.logisticsLabel, '_blank')
} else {
ElMessage.warning('该订单暂无物流面单信息')
}
break
}
}