diff --git a/src/api/mall/trade/delivery/pickUpStore/index.ts b/src/api/mall/trade/delivery/pickUpStore/index.ts index 82ba66c4..c3175021 100644 --- a/src/api/mall/trade/delivery/pickUpStore/index.ts +++ b/src/api/mall/trade/delivery/pickUpStore/index.ts @@ -26,7 +26,7 @@ export const getDeliveryPickUpStore = async (id: number) => { } // 查询自提门店精简列表 -export const getListAllSimple = async () => { +export const getListAllSimple = async (): Promise<DeliveryPickUpStoreVO[]> => { return await request.get({ url: '/trade/delivery/pick-up-store/list-all-simple' }) } diff --git a/src/views/mall/trade/order/components/OrderTableColumn.vue b/src/views/mall/trade/order/components/OrderTableColumn.vue new file mode 100644 index 00000000..89a1ed25 --- /dev/null +++ b/src/views/mall/trade/order/components/OrderTableColumn.vue @@ -0,0 +1,222 @@ +<template> + <el-table-column class-name="order-table-col"> + <template #header> + <!-- TODO @puhui999:小屏幕下,会有偏移,后续看看 --> + <div class="flex items-center" style="width: 100%"> + <div class="ml-100px mr-200px">商品信息</div> + <div class="mr-60px">单价(元)/数量</div> + <div class="mr-60px">售后状态</div> + <div class="mr-60px">实付金额(元)</div> + <div class="mr-60px">买家/收货人</div> + <div class="mr-60px">配送方式</div> + <div class="mr-60px">订单状态</div> + <div class="mr-60px">操作</div> + </div> + </template> + <template #default="scope"> + <el-table + :border="true" + :data="scope.row.items" + :header-cell-style="headerStyle" + :span-method="spanMethod" + style="width: 100%" + > + <el-table-column class-name="table-col-1" min-width="300" prop="spuName"> + <template #header> + <div + class="flex items-center" + style="width: 100%; height: 35px; background-color: #f7f7f7" + > + <span class="mr-20px">订单号:{{ scope.row.no }} </span> + <span class="mr-20px">下单时间:{{ formatDate(scope.row.createTime) }}</span> + <span>订单来源:</span> + <dict-tag :type="DICT_TYPE.TERMINAL" :value="scope.row.terminal" class="mr-20px" /> + <span>支付方式:</span> + <dict-tag + v-if="scope.row.payChannelCode" + :type="DICT_TYPE.PAY_CHANNEL_CODE" + :value="scope.row.payChannelCode" + class="mr-20px" + /> + <span v-else class="mr-20px">未支付</span> + <span v-if="scope.row.payTime" class="mr-20px"> + 支付时间:{{ formatDate(scope.row.payTime) }} + </span> + <span>订单类型:</span> + <dict-tag :type="DICT_TYPE.TRADE_ORDER_TYPE" :value="scope.row.type" /> + </div> + </template> + <template #default="{ row }"> + <div class="flex items-center"> + <el-image + :src="row.picUrl" + class="mr-10px h-30px w-30px" + @click="imagePreview(row.picUrl)" + /> + <span class="mr-10px">{{ row.spuName }}</span> + <el-tag v-for="property in row.properties" :key="property.propertyId" class="mr-10px"> + {{ property.propertyName }}: {{ property.valueName }} + </el-tag> + </div> + </template> + </el-table-column> + <el-table-column class-name="table-col-2" label="商品原价*数量" prop="price" width="150"> + <template #default="{ row }"> + {{ floatToFixed2(row.price) }} 元 / {{ row.count }} + </template> + </el-table-column> + <el-table-column + class-name="table-col-3" + label="售后状态" + prop="afterSaleStatus" + width="120" + > + <template #default="{ row }"> + <dict-tag + :type="DICT_TYPE.TRADE_ORDER_ITEM_AFTER_SALE_STATUS" + :value="row.afterSaleStatus" + /> + </template> + </el-table-column> + <el-table-column + align="center" + class-name="table-col-4" + label="实际支付" + min-width="120" + prop="payPrice" + > + <template #default> + {{ floatToFixed2(scope.row.payPrice) + '元' }} + </template> + </el-table-column> + <el-table-column class-name="table-col-5" label="买家/收货人" min-width="160"> + <template #default> + <!-- 快递发货 --> + <div + v-if="scope.row.deliveryType === DeliveryTypeEnum.EXPRESS.type" + class="flex flex-col" + > + <span>买家:{{ scope.row.user.nickname }}</span> + <span> + 收货人:{{ scope.row.receiverName }} {{ scope.row.receiverMobile }} + {{ scope.row.receiverAreaName }} {{ scope.row.receiverDetailAddress }} + </span> + </div> + <!-- 自提 --> + <div + v-if="scope.row.deliveryType === DeliveryTypeEnum.PICK_UP.type" + class="flex flex-col" + > + <span> + 门店名称: + {{ pickUpStoreList.find((p) => p.id === scope.row.pickUpStoreId)?.name }} + </span> + <span> + 门店手机: + {{ pickUpStoreList.find((p) => p.id === scope.row.pickUpStoreId)?.phone }} + </span> + <span> + 自提门店: + {{ pickUpStoreList.find((p) => p.id === scope.row.pickUpStoreId)?.detailAddress }} + </span> + </div> + </template> + </el-table-column> + <el-table-column align="center" class-name="table-col-6" label="配送方式" width="120"> + <template #default> + <dict-tag :type="DICT_TYPE.TRADE_DELIVERY_TYPE" :value="scope.row.deliveryType" /> + </template> + </el-table-column> + <el-table-column align="center" class-name="table-col-7" label="订单状态" width="120"> + <template #default> + <dict-tag :type="DICT_TYPE.TRADE_ORDER_STATUS" :value="scope.row.status" /> + </template> + </el-table-column> + <el-table-column + align="center" + class-name="table-col-8" + fixed="right" + label="操作" + width="160" + > + <template #default> + <slot :row="scope.row"></slot> + </template> + </el-table-column> + </el-table> + </template> + </el-table-column> +</template> +<script lang="ts" setup> +import { DICT_TYPE } from '@/utils/dict' +import { DeliveryTypeEnum } from '@/utils/constants' +import { formatDate } from '@/utils/formatTime' +import { floatToFixed2 } from '@/utils' +import * as TradeOrderApi from '@/api/mall/trade/order' +import { OrderVO } from '@/api/mall/trade/order' +import { TableColumnCtx } from 'element-plus' +import { createImageViewer } from '@/components/ImageViewer' +import type { DeliveryPickUpStoreVO } from '@/api/mall/trade/delivery/pickUpStore' + +defineOptions({ name: 'OrderTableColumn' }) + +const props = defineProps<{ + list: OrderVO[] + pickUpStoreList: DeliveryPickUpStoreVO[] +}>() + +const headerStyle = ({ row, columnIndex }: any) => { + // 表头第一行第一列占 8 + if (columnIndex === 0) { + row[columnIndex].colSpan = 8 + } else { + // 其余的不要 + row[columnIndex].colSpan = 0 + return { + display: 'none' + } + } +} + +interface SpanMethodProps { + row: TradeOrderApi.OrderItemRespVO + column: TableColumnCtx<TradeOrderApi.OrderItemRespVO> + rowIndex: number + columnIndex: number +} + +type spanMethodResp = number[] | { rowspan: number; colspan: number } | undefined +const spanMethod = ({ row, rowIndex, columnIndex }: SpanMethodProps): spanMethodResp => { + const len = props.list.find( + (order) => order.items?.findIndex((item) => item.id === row.id) !== -1 + )?.items?.length + // 要合并的列,从零开始 + const colIndex = [3, 4, 5, 6, 7] + if (colIndex.includes(columnIndex)) { + // 除了第一行其余的不要 + if (rowIndex !== 0) { + return { + rowspan: 0, + colspan: 0 + } + } + // 动态合并行 + return { + rowspan: len!, + colspan: 1 + } + } +} + +/** 商品图预览 */ +const imagePreview = (imgUrl: string) => { + createImageViewer({ + urlList: [imgUrl] + }) +} +</script> +<style lang="scss" scoped> +:deep(.order-table-col > .cell) { + padding: 0; +} +</style> diff --git a/src/views/mall/trade/order/components/index.ts b/src/views/mall/trade/order/components/index.ts new file mode 100644 index 00000000..9cce9fac --- /dev/null +++ b/src/views/mall/trade/order/components/index.ts @@ -0,0 +1,3 @@ +import OrderTableColumn from './OrderTableColumn.vue' + +export { OrderTableColumn } diff --git a/src/views/mall/trade/order/index.vue b/src/views/mall/trade/order/index.vue index 33d98548..94cd8c17 100644 --- a/src/views/mall/trade/order/index.vue +++ b/src/views/mall/trade/order/index.vue @@ -163,177 +163,42 @@ <!-- 列表 --> <ContentWrap> <el-table v-loading="loading" :data="list"> - <el-table-column class-name="order-table-col"> - <template #header> - <!-- TODO @puhui999:小屏幕下,会有偏移,后续看看 --> - <div class="flex items-center" style="width: 100%"> - <div class="ml-100px mr-200px">商品信息</div> - <div class="mr-60px">单价(元)/数量</div> - <div class="mr-60px">售后状态</div> - <div class="mr-60px">实付金额(元)</div> - <div class="mr-60px">买家/收货人</div> - <div class="mr-60px">配送方式</div> - <div class="mr-60px">订单状态</div> - <div class="mr-60px">操作</div> + <OrderTableColumn :list="list" :pick-up-store-list="pickUpStoreList"> + <template #default="{ row }"> + <!-- TODO 权限后续补齐 --> + <div class="flex items-center justify-center"> + <el-button link type="primary" @click="openDetail(row.id)"> + <Icon icon="ep:notification" /> + 详情 + </el-button> + <el-dropdown @command="(command) => handleCommand(command, row)"> + <el-button link type="primary"> + <Icon icon="ep:d-arrow-right" /> + 更多 + </el-button> + <template #dropdown> + <el-dropdown-menu> + <!-- 如果是【快递】,并且【未发货】,则展示【发货】按钮 --> + <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 command="remark"> + <Icon icon="ep:chat-line-square" /> + 备注 + </el-dropdown-item> + </el-dropdown-menu> + </template> + </el-dropdown> </div> </template> - <template #default="scope"> - <el-table - :border="true" - :data="scope.row.items" - :header-cell-style="headerStyle" - :span-method="spanMethod" - style="width: 100%" - > - <el-table-column min-width="300" prop="spuName"> - <template #header> - <div - class="flex items-center" - style="width: 100%; height: 35px; background-color: #f7f7f7" - > - <span class="mr-20px">订单号:{{ scope.row.no }} </span> - <span class="mr-20px">下单时间:{{ formatDate(scope.row.createTime) }}</span> - <span>订单来源:</span> - <dict-tag - :type="DICT_TYPE.TERMINAL" - :value="scope.row.terminal" - class="mr-20px" - /> - <span>支付方式:</span> - <dict-tag - v-if="scope.row.payChannelCode" - :type="DICT_TYPE.PAY_CHANNEL_CODE" - :value="scope.row.payChannelCode" - class="mr-20px" - /> - <v-else v-else class="mr-20px">未支付</v-else> - <span v-if="scope.row.payTime" class="mr-20px"> - 支付时间:{{ formatDate(scope.row.payTime) }} - </span> - <span>订单类型:</span> - <dict-tag :type="DICT_TYPE.TRADE_ORDER_TYPE" :value="scope.row.type" /> - </div> - </template> - <template #default="{ row }"> - <div class="flex items-center"> - <el-image - :src="row.picUrl" - class="mr-10px h-30px w-30px" - @click="imagePreview(row.picUrl)" - /> - <span class="mr-10px">{{ row.spuName }}</span> - <el-tag - v-for="property in row.properties" - :key="property.propertyId" - class="mr-10px" - > - {{ property.propertyName }}: {{ property.valueName }} - </el-tag> - </div> - </template> - </el-table-column> - <el-table-column label="商品原价*数量" prop="price" width="150"> - <template #default="{ row }"> - {{ floatToFixed2(row.price) }} 元 / {{ row.count }} - </template> - </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" - /> - </template> - </el-table-column> - <el-table-column align="center" label="实际支付" min-width="120" prop="payPrice"> - <template #default> - {{ floatToFixed2(scope.row.payPrice) + '元' }} - </template> - </el-table-column> - <el-table-column label="买家/收货人" min-width="160"> - <template #default> - <!-- 快递发货 --> - <div - v-if="scope.row.deliveryType === DeliveryTypeEnum.EXPRESS.type" - class="flex flex-col" - > - <span>买家:{{ scope.row.user.nickname }}</span> - <span> - 收货人:{{ scope.row.receiverName }} {{ scope.row.receiverMobile }} - {{ scope.row.receiverAreaName }} {{ scope.row.receiverDetailAddress }} - </span> - </div> - <!-- 自提 --> - <div - v-if="scope.row.deliveryType === DeliveryTypeEnum.PICK_UP.type" - class="flex flex-col" - > - <span> - 门店名称: - {{ pickUpStoreList.find((p) => p.id === scope.row.pickUpStoreId)?.name }} - </span> - <span> - 门店手机: - {{ pickUpStoreList.find((p) => p.id === scope.row.pickUpStoreId)?.phone }} - </span> - <span> - 自提门店: - {{ - pickUpStoreList.find((p) => p.id === scope.row.pickUpStoreId)?.detailAddress - }} - </span> - </div> - </template> - </el-table-column> - <el-table-column align="center" label="配送方式" width="120"> - <template #default> - <dict-tag :type="DICT_TYPE.TRADE_DELIVERY_TYPE" :value="scope.row.deliveryType" /> - </template> - </el-table-column> - <el-table-column align="center" label="订单状态" width="120"> - <template #default> - <dict-tag :type="DICT_TYPE.TRADE_ORDER_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column align="center" fixed="right" label="操作" width="160"> - <template #default> - <!-- TODO 权限后续补齐 --> - <div class="flex items-center justify-center"> - <el-button link type="primary" @click="openDetail(scope.row.id)"> - <Icon icon="ep:notification" /> - 详情 - </el-button> - <el-dropdown @command="(command) => handleCommand(command, scope.row)"> - <el-button link type="primary"> - <Icon icon="ep:d-arrow-right" /> - 更多 - </el-button> - <template #dropdown> - <el-dropdown-menu> - <!-- 如果是【快递】,并且【未发货】,则展示【发货】按钮 --> - <el-dropdown-item - v-if=" - scope.row.deliveryType === DeliveryTypeEnum.EXPRESS.type && - scope.row.status === TradeOrderStatusEnum.UNDELIVERED.status - " - command="delivery" - > - <Icon icon="ep:takeaway-box" /> - 发货 - </el-dropdown-item> - <el-dropdown-item command="remark"> - <Icon icon="ep:chat-line-square" /> - 备注 - </el-dropdown-item> - </el-dropdown-menu> - </template> - </el-dropdown> - </div> - </template> - </el-table-column> - </el-table> - </template> - </el-table-column> + </OrderTableColumn> </el-table> <!-- 分页 --> <Pagination @@ -350,22 +215,19 @@ </template> <script lang="ts" setup> -import type { FormInstance, TableColumnCtx } from 'element-plus' +import type { FormInstance } 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' import * as PickUpStoreApi from '@/api/mall/trade/delivery/pickUpStore' import { DICT_TYPE, getIntDictOptions, getStrDictOptions } from '@/utils/dict' -import { formatDate } from '@/utils/formatTime' -import { floatToFixed2 } from '@/utils' -import { createImageViewer } from '@/components/ImageViewer' import * as DeliveryExpressApi from '@/api/mall/trade/delivery/express' import { DeliveryTypeEnum, TradeOrderStatusEnum } from '@/utils/constants' +import { OrderTableColumn } from './components' defineOptions({ name: 'TradeOrder' }) const { currentRoute, push } = useRouter() // 路由跳转 - const loading = ref(true) // 列表的加载中 const total = ref(2) // 列表的总页数 const list = ref<TradeOrderApi.OrderVO[]>([]) // 列表的数据 @@ -374,15 +236,15 @@ const queryFormRef = ref<FormInstance>() // 搜索的表单 const queryParams = ref({ pageNo: 1, // 页数 pageSize: 10, // 每页显示数量 - status: null, // 订单状态 - payChannelCode: null, // 支付方式 - createTime: null, // 创建时间 - terminal: null, // 订单来源 - type: null, // 订单类型 - deliveryType: null, // 配送方式 - logisticsId: null, // 快递公司 - pickUpStoreId: null, // 自提门店 - pickUpVerifyCode: null // 自提核销码 + status: undefined, // 订单状态 + payChannelCode: undefined, // 支付方式 + createTime: undefined, // 创建时间 + terminal: undefined, // 订单来源 + type: undefined, // 订单类型 + deliveryType: undefined, // 配送方式 + logisticsId: undefined, // 快递公司 + pickUpStoreId: undefined, // 自提门店 + pickUpVerifyCode: undefined // 自提核销码 }) const queryType = reactive({ queryParam: '' }) // 订单搜索类型 queryParam @@ -408,48 +270,6 @@ const inputChangeSelect = (val: string) => { }) } -const headerStyle = ({ row, columnIndex }: any) => { - // 表头第一行第一列占 8 - if (columnIndex === 0) { - row[columnIndex].colSpan = 8 - } else { - // 其余的不要 - row[columnIndex].colSpan = 0 - return { - display: 'none' - } - } -} - -interface SpanMethodProps { - row: TradeOrderApi.OrderItemRespVO - column: TableColumnCtx<TradeOrderApi.OrderItemRespVO> - rowIndex: number - columnIndex: number -} - -const spanMethod = ({ row, rowIndex, columnIndex }: SpanMethodProps) => { - const len = list.value.find( - (order) => order.items?.findIndex((item) => item.id === row.id) !== -1 - )?.items?.length - // 要合并的列,从零开始 - const colIndex = [3, 4, 5, 6, 7] - if (colIndex.includes(columnIndex)) { - // 除了第一行其余的不要 - if (rowIndex !== 0) { - return { - rowspan: 0, - colspan: 0 - } - } - // 动态合并行 - return { - rowspan: len, - colspan: 1 - } - } -} - /** 查询列表 */ const getList = async () => { loading.value = true @@ -472,28 +292,21 @@ const handleQuery = async () => { const resetQuery = () => { queryFormRef.value?.resetFields() queryParams.value = { - pickUpVerifyCode: null, // 自提核销码 pageNo: 1, // 页数 pageSize: 10, // 每页显示数量 - status: null, // 订单状态 - payChannelCode: null, // 支付方式 - createTime: null, // 创建时间 - terminal: null, // 订单来源 - type: null, // 订单类型 - deliveryType: null, // 配送方式 - logisticsId: null, // 快递公司 - pickUpStoreId: null // 自提门店 + status: undefined, // 订单状态 + payChannelCode: undefined, // 支付方式 + createTime: undefined, // 创建时间 + terminal: undefined, // 订单来源 + type: undefined, // 订单类型 + deliveryType: undefined, // 配送方式 + logisticsId: undefined, // 快递公司 + pickUpStoreId: undefined, // 自提门店 + pickUpVerifyCode: undefined // 自提核销码 } handleQuery() } -/** 商品图预览 */ -const imagePreview = (imgUrl: string) => { - createImageViewer({ - urlList: [imgUrl] - }) -} - /** 查看订单详情 */ const openDetail = (id: number) => { push({ name: 'TradeOrderDetail', params: { id } }) @@ -521,8 +334,8 @@ watch( } ) -const pickUpStoreList = ref([]) // 自提门店精简列表 -const deliveryExpressList = ref([]) // 物流公司 +const pickUpStoreList = ref<PickUpStoreApi.DeliveryPickUpStoreVO[]>([]) // 自提门店精简列表 +const deliveryExpressList = ref<DeliveryExpressApi.DeliveryExpressVO[]>([]) // 物流公司 /** 初始化 **/ onMounted(async () => { await getList() @@ -530,8 +343,3 @@ onMounted(async () => { deliveryExpressList.value = await DeliveryExpressApi.getSimpleDeliveryExpressList() }) </script> -<style lang="scss" scoped> -:deep(.order-table-col > .cell) { - padding: 0; -} -</style>