|
|
@@ -0,0 +1,509 @@
|
|
|
+<script setup lang="tsx">
|
|
|
+import { onMounted, reactive, ref, unref, useTemplateRef, watch } from 'vue';
|
|
|
+import { useRouter } from 'vue-router';
|
|
|
+import { NTag, useDialog } from 'naive-ui';
|
|
|
+import type { InternalRowData } from 'naive-ui/es/data-table/src/interface';
|
|
|
+import {
|
|
|
+ fetchBreakDownload,
|
|
|
+ fetchExportList,
|
|
|
+ fetchExportOrderList,
|
|
|
+ fetchGetDeliveryOrderList,
|
|
|
+ fetchGetDeliveryStatusNum
|
|
|
+} from '@/service/api/order-manage/normal-order';
|
|
|
+// import { fetchGetLoginUserList } from '@/service/api/common';
|
|
|
+import { useAppStore } from '@/store/modules/app';
|
|
|
+import { defaultTransform, useNaivePaginatedTable } from '@/hooks/common/table';
|
|
|
+import { useAuth } from '@/hooks/business/auth';
|
|
|
+// import { copyTextToClipboard } from '@/utils/zt';
|
|
|
+import { commonExport } from '@/utils/common';
|
|
|
+import { $t } from '@/locales';
|
|
|
+import { useForm } from '@/components/zt/Form/hooks/useForm';
|
|
|
+import { useModal } from '@/components/zt/Modal/hooks/useModal';
|
|
|
+import { useTable } from '@/components/zt/Table/hooks/useTable';
|
|
|
+// import { type } from '../../../../packages/axios/src/index';
|
|
|
+import { SearchForm, orderStatus } from './normal-order';
|
|
|
+import DeliveryModal from './component/delivery-modal.vue';
|
|
|
+import NormalMoadl from './component/normal-modal.vue';
|
|
|
+const router = useRouter();
|
|
|
+const appStore = useAppStore();
|
|
|
+const checkedRowKeys = ref([]);
|
|
|
+const activeTab = ref('all');
|
|
|
+const statusList = ref<{ label: string; value: string; num?: number }[]>([]);
|
|
|
+const orderMoadl = useTemplateRef('orderMoadl');
|
|
|
+// const ShipmentModal = useTemplateRef('Shipment');
|
|
|
+const channelIdList = ref([]);
|
|
|
+const searchForm = ref();
|
|
|
+const searchParams = reactive({
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 10
|
|
|
+});
|
|
|
+const [registerSearchForm, { getFieldsValue, setFieldsValue }] = useForm({
|
|
|
+ schemas: [
|
|
|
+ // {
|
|
|
+ // field: 'channelIdList',
|
|
|
+ // label: '所属企业',
|
|
|
+ // component: 'ApiSelect',
|
|
|
+ // componentProps: {
|
|
|
+ // api: () => fetchGetLoginUserList(),
|
|
|
+ // labelFeild: 'channelName',
|
|
|
+ // valueFeild: 'id',
|
|
|
+ // multiple: true,
|
|
|
+ // onUpdateValue: () => {
|
|
|
+ // nextTick(() => {
|
|
|
+ // handleSearch();
|
|
|
+ // });
|
|
|
+ // },
|
|
|
+ // getOptions: async (options: any) => {
|
|
|
+ // await setFieldsValue({ channelIdList: [options[0].id] });
|
|
|
+ // handleSearch();
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+ // },
|
|
|
+ ...SearchForm
|
|
|
+ ],
|
|
|
+ showAdvancedButton: false,
|
|
|
+ labelWidth: 120,
|
|
|
+ layout: 'horizontal',
|
|
|
+ size: 'small',
|
|
|
+ gridProps: {
|
|
|
+ cols: '1 xl:4 s:1 l:3',
|
|
|
+ itemResponsive: true
|
|
|
+ },
|
|
|
+ collapsedRows: 1
|
|
|
+});
|
|
|
+const { columns, data, loading, getData, mobilePagination } = useNaivePaginatedTable({
|
|
|
+ api: () => fetchGetDeliveryOrderList({ ...searchParams, orderStatus: activeTab.value, ...unref(searchForm) }),
|
|
|
+ transform: response => defaultTransform(response),
|
|
|
+ immediate: false,
|
|
|
+ paginationProps: {
|
|
|
+ pageSizes: import.meta.env.VITE_PAGE_SIZE.split(',').map(Number)
|
|
|
+ },
|
|
|
+ onPaginationParamsChange: params => {
|
|
|
+ searchParams.pageNum = Number(params.page);
|
|
|
+ searchParams.pageSize = Number(params.pageSize);
|
|
|
+ },
|
|
|
+ columns: () => [
|
|
|
+ {
|
|
|
+ key: 'orderNumber',
|
|
|
+ title: '订单编号',
|
|
|
+ align: 'center',
|
|
|
+ width: 220
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: 'consigneeAddress',
|
|
|
+ title: '业务类型',
|
|
|
+ align: 'center',
|
|
|
+ width: 120,
|
|
|
+ render: row => {
|
|
|
+ return <NTag class={'mt7'}>{row.businessType}</NTag>;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: 'info',
|
|
|
+ title: '客户信息',
|
|
|
+ align: 'center',
|
|
|
+ width: 220,
|
|
|
+ render: row => {
|
|
|
+ return (
|
|
|
+ <div class={'mt7'}>
|
|
|
+ <div>
|
|
|
+ {row.consigneeName}
|
|
|
+ {row.consigneeMobile}
|
|
|
+ </div>
|
|
|
+ <div>{row.consigneeAddress}</div>
|
|
|
+ </div>
|
|
|
+ );
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: 'status',
|
|
|
+ title: '订单状态',
|
|
|
+ align: 'center',
|
|
|
+ width: 120,
|
|
|
+ render: row => {
|
|
|
+ const statusKey = row.hbOrderStatus as keyof typeof orderStatus;
|
|
|
+ const statusText = orderStatus[statusKey] || '未知状态';
|
|
|
+ return <NTag class={'mt7'}>{statusText}</NTag>;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: 'createTime',
|
|
|
+ title: '下单时间',
|
|
|
+ align: 'center',
|
|
|
+ width: 180,
|
|
|
+ render: row => {
|
|
|
+ return <div>{row.createTime?.replace('T', ' ')}</div>;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: 'operate',
|
|
|
+ title: $t('common.operate'),
|
|
|
+ align: 'center',
|
|
|
+ width: 150,
|
|
|
+ fixed: 'right',
|
|
|
+ render: row => {
|
|
|
+ return (
|
|
|
+ <div class={'mt7'}>
|
|
|
+ <n-button size="small" type="primary" ghost onClick={() => handleOrderDetail(row)}>
|
|
|
+ 订单详情
|
|
|
+ </n-button>
|
|
|
+ </div>
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ]
|
|
|
+});
|
|
|
+
|
|
|
+const [registerTable, { refresh, setTableLoading }] = useTable({
|
|
|
+ tableConfig: {
|
|
|
+ keyField: 'id',
|
|
|
+ title: '',
|
|
|
+ showAddButton: false,
|
|
|
+ showTableHeaderAction: false,
|
|
|
+ showSearch: false,
|
|
|
+ minHeight: 400
|
|
|
+ }
|
|
|
+});
|
|
|
+
|
|
|
+const exportColumns: NaiveUI.TableColumn<InternalRowData>[] = [
|
|
|
+ {
|
|
|
+ key: 'index',
|
|
|
+ title: '序号',
|
|
|
+ align: 'center',
|
|
|
+ width: 100,
|
|
|
+ render(_, rowIndex) {
|
|
|
+ return rowIndex + 1;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: 'taskName',
|
|
|
+ title: '任务名称',
|
|
|
+ align: 'center',
|
|
|
+ minWidth: 100
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: 'updateTime',
|
|
|
+ title: '时间',
|
|
|
+ align: 'center',
|
|
|
+ minWidth: 100,
|
|
|
+ render: row => {
|
|
|
+ return (
|
|
|
+ <div>
|
|
|
+ <div>创建时间:{row.createTime}</div>
|
|
|
+ <div>完成时间:{row.updateTime}</div>
|
|
|
+ </div>
|
|
|
+ );
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: 'operator',
|
|
|
+ title: '操作人',
|
|
|
+ align: 'center',
|
|
|
+ minWidth: 100
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: 'exportStatus',
|
|
|
+ title: '状态',
|
|
|
+ align: 'center',
|
|
|
+ minWidth: 100,
|
|
|
+ render: row => {
|
|
|
+ if (row.exportStatus == 0) {
|
|
|
+ return (
|
|
|
+ <div>
|
|
|
+ 请耐心等待,正在导出中...
|
|
|
+ <n-button text type="info" onClick={() => handleBreak(row.id as string)}>
|
|
|
+ 中断
|
|
|
+ </n-button>
|
|
|
+ </div>
|
|
|
+ );
|
|
|
+ } else if (row.exportStatus == 1) {
|
|
|
+ return (
|
|
|
+ <div>
|
|
|
+ 未下载
|
|
|
+ <n-button text type="info" onClick={() => handleDownload(row.id as string)}>
|
|
|
+ 下载
|
|
|
+ </n-button>
|
|
|
+ </div>
|
|
|
+ );
|
|
|
+ } else if (row.exportStatus == 2) {
|
|
|
+ return <div class={'text-gray-500'}>生成文件失败</div>;
|
|
|
+ } else if (row.exportStatus == 3) {
|
|
|
+ return (
|
|
|
+ <div>
|
|
|
+ 已下载
|
|
|
+ <n-button text type="info" onClick={() => handleDownload(row.id as string)}>
|
|
|
+ 下载
|
|
|
+ </n-button>
|
|
|
+ </div>
|
|
|
+ );
|
|
|
+ } else if (row.exportStatus == 4) {
|
|
|
+ return <div>导出失败</div>;
|
|
|
+ }
|
|
|
+ return <div>进行中</div>;
|
|
|
+ }
|
|
|
+ }
|
|
|
+];
|
|
|
+
|
|
|
+async function handleDownload(id: string) {
|
|
|
+ setTableLoading(true);
|
|
|
+ await commonExport('/platform/exportTask/download', { fileId: id }, '正常订单列表.xlsx');
|
|
|
+ refresh();
|
|
|
+}
|
|
|
+async function handleBreak(id: string) {
|
|
|
+ setTableLoading(true);
|
|
|
+ await fetchBreakDownload(id);
|
|
|
+ refresh();
|
|
|
+}
|
|
|
+
|
|
|
+const [registerModalPrice, { openModal }] = useModal({
|
|
|
+ title: '导出记录',
|
|
|
+ width: 1200,
|
|
|
+ height: 600,
|
|
|
+ showFooter: false
|
|
|
+});
|
|
|
+
|
|
|
+const dialog = useDialog();
|
|
|
+
|
|
|
+// async function handleDeivery(row: Api.delivery.deliveryOrder) {
|
|
|
+// if (!row.orderNumber) {
|
|
|
+// window.$message?.error('订单异常');
|
|
|
+// return;
|
|
|
+// }
|
|
|
+// ShipmentModal.value?.handleOpenOrder(row.orderNumber);
|
|
|
+// }
|
|
|
+
|
|
|
+function handleOrderDetail(row: Api.delivery.deliveryOrder) {
|
|
|
+ if (!row.orderNumber) {
|
|
|
+ window.$message?.error('订单异常');
|
|
|
+ }
|
|
|
+ router.push({
|
|
|
+ path: '/order-manage/order-detail',
|
|
|
+ query: {
|
|
|
+ orderNumber: row.orderNumber
|
|
|
+ }
|
|
|
+ });
|
|
|
+ // orderMoadl.value?.open(String(row.orderNumber));
|
|
|
+}
|
|
|
+async function getNums() {
|
|
|
+ const form = getFieldsValue();
|
|
|
+ const params = {
|
|
|
+ ...form,
|
|
|
+ channelIdList: channelIdList.value,
|
|
|
+ startTime: form.createTime ? form.createTime[0] : null,
|
|
|
+ endTime: form.createTime ? form.createTime[1] : null,
|
|
|
+ createTime: null
|
|
|
+ };
|
|
|
+ const { data: keyData } = await fetchGetDeliveryStatusNum(params);
|
|
|
+ if (!keyData) return;
|
|
|
+ const orderStatusList = [
|
|
|
+ {
|
|
|
+ label: '全部',
|
|
|
+ value: 'all'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: '待支付',
|
|
|
+ value: 'paddingPay'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: '进行中',
|
|
|
+ value: 'ing'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: '已完成',
|
|
|
+ value: 'completed'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: '已取消',
|
|
|
+ value: 'cancel'
|
|
|
+ }
|
|
|
+ ];
|
|
|
+ const updatedOrderStatusList = orderStatusList.map(item => {
|
|
|
+ const key = item.value as keyof typeof keyData;
|
|
|
+ if (Object.hasOwn(keyData, key)) {
|
|
|
+ return {
|
|
|
+ ...item,
|
|
|
+ num: keyData[key]
|
|
|
+ };
|
|
|
+ }
|
|
|
+ return item;
|
|
|
+ });
|
|
|
+ // console.log(updatedOrderStatusList, 'updatedOrderStatusList');
|
|
|
+ statusList.value = updatedOrderStatusList;
|
|
|
+}
|
|
|
+
|
|
|
+watch(
|
|
|
+ () => [activeTab.value],
|
|
|
+ () => {
|
|
|
+ searchParams.pageNum = 1;
|
|
|
+ getData();
|
|
|
+ }
|
|
|
+);
|
|
|
+function handleSearch() {
|
|
|
+ const form = getFieldsValue();
|
|
|
+ if (form.createTime) {
|
|
|
+ form.startTime = form.createTime[0];
|
|
|
+ form.endTime = form.createTime[1];
|
|
|
+ delete form.createTime;
|
|
|
+ }
|
|
|
+ channelIdList.value = form.channelIdList;
|
|
|
+ searchForm.value = form;
|
|
|
+ getData();
|
|
|
+ getNums();
|
|
|
+}
|
|
|
+onMounted(() => {
|
|
|
+ getData();
|
|
|
+ getNums();
|
|
|
+});
|
|
|
+
|
|
|
+function handleReset() {
|
|
|
+ searchForm.value = getFieldsValue();
|
|
|
+ searchForm.value.channelIdList = channelIdList.value;
|
|
|
+ setFieldsValue({ channelIdList: channelIdList.value });
|
|
|
+ getData();
|
|
|
+ getNums();
|
|
|
+}
|
|
|
+// async function handleCopy(row: Api.delivery.deliveryOrder, key: string) {
|
|
|
+// if (!row[key]) {
|
|
|
+// window.$message?.error('订单编号不存在');
|
|
|
+// return;
|
|
|
+// }
|
|
|
+// await copyTextToClipboard(row[key]);
|
|
|
+// }
|
|
|
+function handleRefsh() {
|
|
|
+ getData();
|
|
|
+ getNums();
|
|
|
+}
|
|
|
+async function handleExport() {
|
|
|
+ loading.value = true;
|
|
|
+ try {
|
|
|
+ // await commonExport(
|
|
|
+ // '/platform/order/export',
|
|
|
+ // { ...getFieldsValue(), orderStatus: activeTab.value },
|
|
|
+ // '正常订单列表.xlsx'
|
|
|
+ // );
|
|
|
+ const newParams = getFieldsValue();
|
|
|
+ if (newParams.createTime) {
|
|
|
+ newParams.startTime = newParams.createTime[0];
|
|
|
+ newParams.endTime = newParams.createTime[1];
|
|
|
+ delete newParams.createTime;
|
|
|
+ }
|
|
|
+ await fetchExportOrderList({ ...newParams, orderStatus: activeTab.value });
|
|
|
+ dialog.success({
|
|
|
+ title: '提示',
|
|
|
+ content: () => {
|
|
|
+ return (
|
|
|
+ <div>
|
|
|
+ <p>导出操作进行中......</p>
|
|
|
+ <p>是否进入导出记录</p>
|
|
|
+ </div>
|
|
|
+ );
|
|
|
+ },
|
|
|
+ positiveText: '确定',
|
|
|
+ negativeText: '取消',
|
|
|
+ onPositiveClick: () => {
|
|
|
+ openModal();
|
|
|
+ },
|
|
|
+ onNegativeClick: () => {}
|
|
|
+ });
|
|
|
+ } finally {
|
|
|
+ loading.value = false;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+async function handleExportLog() {
|
|
|
+ loading.value = true;
|
|
|
+ try {
|
|
|
+ openModal();
|
|
|
+ } finally {
|
|
|
+ loading.value = false;
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<template>
|
|
|
+ <div class="flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto">
|
|
|
+ <NCard :bordered="false" size="small">
|
|
|
+ <NCollapse display-directive="show" default-expanded-names="search">
|
|
|
+ <NCollapseItem title="搜索" name="search">
|
|
|
+ <BasicForm @register-form="registerSearchForm" @submit="handleSearch" @reset="handleReset" />
|
|
|
+ </NCollapseItem>
|
|
|
+ </NCollapse>
|
|
|
+ </NCard>
|
|
|
+ <NCard :bordered="false" size="small" class="card-wrapper sm:flex-1-hidden">
|
|
|
+ <template #header>
|
|
|
+ <div class="mr3">订单列表</div>
|
|
|
+ <NScrollbar x-scrollable>
|
|
|
+ <div class="flex items-center">
|
|
|
+ <div class="max-w-800px">
|
|
|
+ <NTabs v-model:value="activeTab" type="line" animated display-directive="show">
|
|
|
+ <NTab
|
|
|
+ v-for="item in statusList"
|
|
|
+ :key="item.value"
|
|
|
+ :name="item.value"
|
|
|
+ :tab="`${item.label}(${item.num})`"
|
|
|
+ ></NTab>
|
|
|
+ </NTabs>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </NScrollbar>
|
|
|
+ </template>
|
|
|
+ <template #header-extra>
|
|
|
+ <NButton
|
|
|
+ v-if="useAuth().hasAuth('order:user:export')"
|
|
|
+ size="small"
|
|
|
+ type="primary"
|
|
|
+ class="ml20px mt30px"
|
|
|
+ ghost
|
|
|
+ :loading="loading"
|
|
|
+ :disabled="data.length == 0"
|
|
|
+ @click="handleExport"
|
|
|
+ >
|
|
|
+ <template #icon>
|
|
|
+ <SvgIcon icon="mingcute:file-export-line"></SvgIcon>
|
|
|
+ </template>
|
|
|
+ 导出
|
|
|
+ </NButton>
|
|
|
+ <NButton
|
|
|
+ v-if="useAuth().hasAuth('order:user:export')"
|
|
|
+ size="small"
|
|
|
+ type="primary"
|
|
|
+ class="ml20px mt30px"
|
|
|
+ ghost
|
|
|
+ :loading="loading"
|
|
|
+ @click="handleExportLog"
|
|
|
+ >
|
|
|
+ 导出记录
|
|
|
+ </NButton>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <NDataTable
|
|
|
+ v-model:checked-row-keys="checkedRowKeys"
|
|
|
+ :columns="columns"
|
|
|
+ :data="data"
|
|
|
+ size="small"
|
|
|
+ :flex-height="!appStore.isMobile"
|
|
|
+ :scroll-x="1800"
|
|
|
+ :loading="loading"
|
|
|
+ :row-key="row => row.orderId"
|
|
|
+ remote
|
|
|
+ class="sm:h-full"
|
|
|
+ :pagination="mobilePagination"
|
|
|
+ />
|
|
|
+ <NormalMoadl ref="orderMoadl" @finish="handleRefsh"></NormalMoadl>
|
|
|
+ <DeliveryModal ref="Shipment" @finish="handleRefsh"></DeliveryModal>
|
|
|
+ </NCard>
|
|
|
+ <BasicModal @register="registerModalPrice" @after-leave="refresh">
|
|
|
+ <LayoutTable>
|
|
|
+ <ZTable
|
|
|
+ :show-table-action="false"
|
|
|
+ :columns="exportColumns"
|
|
|
+ :api="fetchExportList"
|
|
|
+ :default-params="{ exportType: 1 }"
|
|
|
+ @register="registerTable"
|
|
|
+ ></ZTable>
|
|
|
+ </LayoutTable>
|
|
|
+ </BasicModal>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<style scoped></style>
|