feat:【mall 商城】门店自提的迁移(ele 80%)
This commit is contained in:
@@ -49,6 +49,7 @@ export namespace MallOrderApi {
|
|||||||
afterSaleStatus?: null | number;
|
afterSaleStatus?: null | number;
|
||||||
/** 属性数组 */
|
/** 属性数组 */
|
||||||
properties?: ProductProperty[];
|
properties?: ProductProperty[];
|
||||||
|
price?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 订单日志 */
|
/** 订单日志 */
|
||||||
@@ -248,7 +249,7 @@ export function getOrderPage(params: PageParam) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** 查询交易订单统计 */
|
/** 查询交易订单统计 */
|
||||||
export function getOrderSummary(params: PageParam) {
|
export function getOrderSummary(params: any) {
|
||||||
return requestClient.get<MallOrderApi.OrderSummary>('/trade/order/summary', {
|
return requestClient.get<MallOrderApi.OrderSummary>('/trade/order/summary', {
|
||||||
params,
|
params,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -4,15 +4,24 @@ import type { MallDeliveryPickUpStoreApi } from '#/api/mall/trade/delivery/pickU
|
|||||||
|
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
|
|
||||||
import { DeliveryTypeEnum, DICT_TYPE } from '@vben/constants';
|
import { DICT_TYPE } from '@vben/constants';
|
||||||
|
import { useUserStore } from '@vben/stores';
|
||||||
|
|
||||||
import { getSimpleDeliveryPickUpStoreList } from '#/api/mall/trade/delivery/pickUpStore';
|
import { getSimpleDeliveryPickUpStoreList } from '#/api/mall/trade/delivery/pickUpStore';
|
||||||
import { getRangePickerDefaultProps } from '#/utils';
|
import { getRangePickerDefaultProps } from '#/utils';
|
||||||
|
|
||||||
|
// TODO @芋艿:统一风格;
|
||||||
|
const userStore = useUserStore();
|
||||||
const pickUpStoreList = ref<MallDeliveryPickUpStoreApi.PickUpStore[]>([]);
|
const pickUpStoreList = ref<MallDeliveryPickUpStoreApi.PickUpStore[]>([]);
|
||||||
|
|
||||||
|
/** 自提门店列表 */
|
||||||
getSimpleDeliveryPickUpStoreList().then((res) => {
|
getSimpleDeliveryPickUpStoreList().then((res) => {
|
||||||
pickUpStoreList.value = res;
|
pickUpStoreList.value = res;
|
||||||
|
// 移除自己无法核销的门店
|
||||||
|
const userId = userStore?.userInfo?.id;
|
||||||
|
pickUpStoreList.value = pickUpStoreList.value.filter((item) =>
|
||||||
|
item.verifyUserIds?.includes(userId),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
/** 列表的搜索表单 */
|
/** 列表的搜索表单 */
|
||||||
@@ -28,18 +37,53 @@ export function useGridFormSchema(): VbenFormSchema[] {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fieldName: 'pickUpStoreId',
|
fieldName: 'pickUpStoreIds',
|
||||||
label: '自提门店',
|
label: '自提门店',
|
||||||
component: 'ApiSelect',
|
component: 'Select',
|
||||||
componentProps: {
|
componentProps: {
|
||||||
api: getSimpleDeliveryPickUpStoreList,
|
options: pickUpStoreList,
|
||||||
labelField: 'name',
|
props: {
|
||||||
valueField: 'id',
|
label: 'name',
|
||||||
|
value: 'id',
|
||||||
},
|
},
|
||||||
dependencies: {
|
placeholder: '请选择自提门店',
|
||||||
triggerFields: ['deliveryType'],
|
},
|
||||||
trigger: (values) =>
|
defaultValue: pickUpStoreList.value[0]?.id,
|
||||||
values.deliveryType === DeliveryTypeEnum.PICK_UP.type,
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'no',
|
||||||
|
label: '订单号',
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请输入订单号',
|
||||||
|
clearable: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'userId',
|
||||||
|
label: '用户 UID',
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请输入用户 UID',
|
||||||
|
clearable: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'userNickname',
|
||||||
|
label: '用户昵称',
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请输入用户昵称',
|
||||||
|
clearable: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'userMobile',
|
||||||
|
label: '用户电话',
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请输入用户电话',
|
||||||
|
clearable: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
@@ -67,17 +111,13 @@ export function useGridColumns(): VxeGridPropTypes.Columns {
|
|||||||
{
|
{
|
||||||
field: 'spuName',
|
field: 'spuName',
|
||||||
title: '商品信息',
|
title: '商品信息',
|
||||||
minWidth: 100,
|
minWidth: 300,
|
||||||
formatter: ({ row }) => {
|
slots: { default: 'spuName' },
|
||||||
if (row.items.length > 1) {
|
|
||||||
return row.items.map((item: any) => item.spuName).join(',');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'payPrice',
|
field: 'payPrice',
|
||||||
title: '实付金额(元)',
|
title: '实付金额(元)',
|
||||||
formatter: 'formatFenToYuanAmount',
|
formatter: 'formatAmount2',
|
||||||
minWidth: 180,
|
minWidth: 180,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -90,9 +130,10 @@ export function useGridColumns(): VxeGridPropTypes.Columns {
|
|||||||
title: '核销门店',
|
title: '核销门店',
|
||||||
minWidth: 160,
|
minWidth: 160,
|
||||||
formatter: ({ row }) => {
|
formatter: ({ row }) => {
|
||||||
return pickUpStoreList.value.find(
|
return (
|
||||||
(item) => item.id === row.pickUpStoreId,
|
pickUpStoreList.value.find((item) => item.id === row.pickUpStoreId)
|
||||||
)?.name;
|
?.name || ''
|
||||||
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,19 +2,27 @@
|
|||||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||||
import type { MallOrderApi } from '#/api/mall/trade/order';
|
import type { MallOrderApi } from '#/api/mall/trade/order';
|
||||||
|
|
||||||
import { h, onMounted, ref } from 'vue';
|
import { h, ref } from 'vue';
|
||||||
|
|
||||||
import { Page, prompt } from '@vben/common-ui';
|
import { Page, prompt } from '@vben/common-ui';
|
||||||
import { DeliveryTypeEnum, TradeOrderStatusEnum } from '@vben/constants';
|
import { DeliveryTypeEnum } from '@vben/constants';
|
||||||
|
import { $t } from '@vben/locales';
|
||||||
import { fenToYuan } from '@vben/utils';
|
import { fenToYuan } from '@vben/utils';
|
||||||
|
|
||||||
import { ElCard, ElInput, ElMessage } from 'element-plus';
|
import {
|
||||||
|
ElCard,
|
||||||
|
ElImage,
|
||||||
|
ElInput,
|
||||||
|
ElLoading,
|
||||||
|
ElMessage,
|
||||||
|
ElTag,
|
||||||
|
} from 'element-plus';
|
||||||
|
|
||||||
import { TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
|
import { TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||||
import {
|
import {
|
||||||
getOrderByPickUpVerifyCode,
|
|
||||||
getOrderPage,
|
getOrderPage,
|
||||||
getOrderSummary,
|
getOrderSummary,
|
||||||
|
pickUpOrderByVerifyCode,
|
||||||
} from '#/api/mall/trade/order';
|
} from '#/api/mall/trade/order';
|
||||||
import { SummaryCard } from '#/components/summary-card';
|
import { SummaryCard } from '#/components/summary-card';
|
||||||
|
|
||||||
@@ -22,15 +30,22 @@ import { useGridColumns, useGridFormSchema } from './data';
|
|||||||
|
|
||||||
const summary = ref<MallOrderApi.OrderSummary>();
|
const summary = ref<MallOrderApi.OrderSummary>();
|
||||||
|
|
||||||
|
/** 刷新表格 */
|
||||||
|
function handleRefresh() {
|
||||||
|
gridApi.query();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 获取订单统计数据 */
|
||||||
async function getOrderSum() {
|
async function getOrderSum() {
|
||||||
const query = await gridApi.formApi.getValues();
|
const query = await gridApi.formApi.getValues();
|
||||||
query.deliveryType = DeliveryTypeEnum.PICK_UP.type;
|
query.deliveryType = DeliveryTypeEnum.PICK_UP.type;
|
||||||
const res = await getOrderSummary(query as any);
|
summary.value = await getOrderSummary(query);
|
||||||
summary.value = res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 核销 */
|
/** 核销订单 */
|
||||||
async function handlePickup(pickUpVerifyCode?: string) {
|
async function handlePickup(pickUpVerifyCode?: string) {
|
||||||
|
// 如果没有传核销码,则弹窗输入
|
||||||
|
// TODO @AI:不太对
|
||||||
if (!pickUpVerifyCode) {
|
if (!pickUpVerifyCode) {
|
||||||
await prompt({
|
await prompt({
|
||||||
component: () => {
|
component: () => {
|
||||||
@@ -48,13 +63,17 @@ async function handlePickup(pickUpVerifyCode?: string) {
|
|||||||
if (!pickUpVerifyCode) {
|
if (!pickUpVerifyCode) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const data = await getOrderByPickUpVerifyCode(pickUpVerifyCode);
|
|
||||||
if (data?.deliveryType !== DeliveryTypeEnum.PICK_UP.type) {
|
// 执行核销
|
||||||
ElMessage.error('未查询到订单');
|
const loadingInstance = ElLoading.service({
|
||||||
return;
|
text: '订单核销中 ...',
|
||||||
}
|
});
|
||||||
if (data?.status !== TradeOrderStatusEnum.UNDELIVERED.status) {
|
try {
|
||||||
ElMessage.error('订单不是待核销状态');
|
await pickUpOrderByVerifyCode(pickUpVerifyCode);
|
||||||
|
ElMessage.success($t('ui.actionMessage.operationSuccess'));
|
||||||
|
handleRefresh();
|
||||||
|
} finally {
|
||||||
|
loadingInstance.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,7 +99,7 @@ async function connectToSerialPort() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取用户之前授予该网站访问权限的所有串口。
|
// 获取用户之前授予该网站访问权限的所有串口
|
||||||
ports.value = await (navigator.serial as any).getPorts();
|
ports.value = await (navigator.serial as any).getPorts();
|
||||||
|
|
||||||
// 等待串口打开
|
// 等待串口打开
|
||||||
@@ -92,7 +111,7 @@ async function connectToSerialPort() {
|
|||||||
|
|
||||||
ElMessage.success('成功连接扫码枪');
|
ElMessage.success('成功连接扫码枪');
|
||||||
serialPort.value = true;
|
serialPort.value = true;
|
||||||
readData();
|
await readData();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// 处理连接串口出错的情况
|
// 处理连接串口出错的情况
|
||||||
console.error('Error connecting to serial port:', error);
|
console.error('Error connecting to serial port:', error);
|
||||||
@@ -120,7 +139,7 @@ async function readData() {
|
|||||||
data = ''; // 清空下次读取不会叠加
|
data = ''; // 清空下次读取不会叠加
|
||||||
console.warn(`二维码数据:${codeData}`);
|
console.warn(`二维码数据:${codeData}`);
|
||||||
// 处理拿到数据逻辑
|
// 处理拿到数据逻辑
|
||||||
handlePickup(codeData);
|
await handlePickup(codeData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -143,12 +162,16 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
|||||||
schema: useGridFormSchema(),
|
schema: useGridFormSchema(),
|
||||||
},
|
},
|
||||||
gridOptions: {
|
gridOptions: {
|
||||||
|
cellConfig: {
|
||||||
|
height: 100,
|
||||||
|
},
|
||||||
columns: useGridColumns(),
|
columns: useGridColumns(),
|
||||||
height: 'auto',
|
height: 'auto',
|
||||||
keepSource: true,
|
keepSource: true,
|
||||||
proxyConfig: {
|
proxyConfig: {
|
||||||
ajax: {
|
ajax: {
|
||||||
query: async ({ page }, formValues) => {
|
query: async ({ page }, formValues) => {
|
||||||
|
await getOrderSum();
|
||||||
return await getOrderPage({
|
return await getOrderPage({
|
||||||
pageNo: page.currentPage,
|
pageNo: page.currentPage,
|
||||||
pageSize: page.pageSize,
|
pageSize: page.pageSize,
|
||||||
@@ -160,6 +183,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
|||||||
},
|
},
|
||||||
rowConfig: {
|
rowConfig: {
|
||||||
keyField: 'id',
|
keyField: 'id',
|
||||||
|
isHover: true,
|
||||||
},
|
},
|
||||||
toolbarConfig: {
|
toolbarConfig: {
|
||||||
refresh: true,
|
refresh: true,
|
||||||
@@ -167,15 +191,11 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
|||||||
},
|
},
|
||||||
} as VxeTableGridOptions<MallOrderApi.Order>,
|
} as VxeTableGridOptions<MallOrderApi.Order>,
|
||||||
});
|
});
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
getOrderSum();
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Page auto-content-height>
|
<Page auto-content-height>
|
||||||
<ElCard class="m-4">
|
<ElCard class="mb-2">
|
||||||
<div class="flex flex-row gap-4">
|
<div class="flex flex-row gap-4">
|
||||||
<SummaryCard
|
<SummaryCard
|
||||||
class="flex flex-1"
|
class="flex flex-1"
|
||||||
@@ -215,8 +235,43 @@ onMounted(() => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</ElCard>
|
</ElCard>
|
||||||
<!-- TODO @霖:核销订单,点出的弹窗,无法输入内容; -->
|
|
||||||
<Grid class="h-4/5" table-title="核销订单">
|
<Grid class="h-4/5" table-title="核销订单">
|
||||||
|
<template #spuName="{ row }">
|
||||||
|
<div class="flex flex-col gap-2">
|
||||||
|
<div
|
||||||
|
v-for="item in row.items"
|
||||||
|
:key="item.id!"
|
||||||
|
class="flex items-start gap-2"
|
||||||
|
>
|
||||||
|
<!-- TODO @AI:长宽不太对 -->
|
||||||
|
<ElImage
|
||||||
|
:src="item.picUrl || ''"
|
||||||
|
:alt="item.spuName || ''"
|
||||||
|
:width="30"
|
||||||
|
:height="30"
|
||||||
|
class="flex-shrink-0"
|
||||||
|
:preview-src-list="item.picUrl ? [item.picUrl] : []"
|
||||||
|
/>
|
||||||
|
<div class="flex flex-1 flex-col gap-1">
|
||||||
|
<span class="text-sm">{{ item.spuName }}</span>
|
||||||
|
<div class="flex flex-wrap gap-1">
|
||||||
|
<ElTag
|
||||||
|
v-for="property in item.properties"
|
||||||
|
:key="property.propertyId!"
|
||||||
|
size="small"
|
||||||
|
type="info"
|
||||||
|
>
|
||||||
|
{{ property.propertyName }}: {{ property.valueName }}
|
||||||
|
</ElTag>
|
||||||
|
</div>
|
||||||
|
<span class="text-xs text-gray-500">
|
||||||
|
{{ fenToYuan(item.price) }} 元 x {{ item.count || 0 }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
<template #toolbar-tools>
|
<template #toolbar-tools>
|
||||||
<TableAction
|
<TableAction
|
||||||
:actions="[
|
:actions="[
|
||||||
@@ -229,9 +284,8 @@ onMounted(() => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: serialPort ? '断开扫描枪' : '连接扫描枪',
|
label: serialPort ? '断开扫描枪' : '连接扫描枪',
|
||||||
type: 'primary',
|
type: serialPort ? 'danger' : 'primary',
|
||||||
icon: serialPort ? 'lucide:circle-x' : 'lucide:circle-play',
|
icon: serialPort ? 'lucide:circle-x' : 'lucide:circle-play',
|
||||||
link: true,
|
|
||||||
onClick: serialPort ? cutPort : connectToSerialPort,
|
onClick: serialPort ? cutPort : connectToSerialPort,
|
||||||
},
|
},
|
||||||
]"
|
]"
|
||||||
|
|||||||
Reference in New Issue
Block a user