| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553 |
- <script setup lang="tsx">
- import { nextTick, reactive, ref, unref, useTemplateRef, watch } from 'vue';
- import { NImage, NTag, useDialog } from 'naive-ui';
- import type { InternalRowData } from 'naive-ui/es/data-table/src/interface';
- import {
- fetchBreakDownload,
- fetchExportList,
- fetchExportOrderList,
- fetchGetDeliveryOrderList
- } from '@/service/api/delivery/normal-orde';
- 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, dvyStatus } from './split-order';
- import NormalMoadl from './component/normal-modal.vue';
- const appStore = useAppStore();
- const checkedRowKeys = ref([]);
- const activeTab = ref('all');
- const orderMoadl = useTemplateRef('orderMoadl');
- const channelIdList = ref([]);
- const searchForm = ref();
- const searchParams = reactive({
- current: 1,
- size: 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,
- orderLevel: 0,
- splitStatus: 4,
- 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.current = Number(params.page);
- searchParams.size = Number(params.pageSize);
- },
- columns: () => [
- {
- key: 'orderItems',
- title: '商品',
- align: 'left',
- width: 260,
- colSpan: (_rowData, _rowIndex) => 2,
- render: row => {
- return (
- <div>
- <div class={'mb3 flex items-center'}>
- <n-tag>
- <div class={'flex items-center'}>
- {row.parentOrderNumber && <div class={''}>父订单编号:{row.parentOrderNumber}</div>}
- <div onClick={() => handleCopy(row, 'parentOrderNumber')}>
- <svgIcon icon={'bxs:copy'} class={'mx-3 cursor-pointer text-[#f97316]'}></svgIcon>
- </div>
- {row.orderLevel === 0 ? '订单编号' : '子订单编号'}:{row.orderNumber}
- <div onClick={() => handleCopy(row, 'orderNumber')}>
- <svgIcon icon={'bxs:copy'} class={'mx-3 cursor-pointer text-[#f97316]'}></svgIcon>
- </div>
- 下单时间:
- {row.createTime} 门店名称 {row.shopName}
- </div>
- </n-tag>
- </div>
- {row.orderItems?.map(item => {
- return (
- <div class={'mb-3 h-80px flex items-center'}>
- <NImage src={item.pic} class="h-[80px] min-w-80px w-[80px]" lazy />
- <div class={'ml12px flex-1'}>
- <div class={'w-full flex items-center justify-between'}>
- <div class={'w200px'}>
- <n-ellipsis class={'w200px'}>
- <span class={'w-full text-left text-15px font-semibold'}>{item.skuName}</span>
- </n-ellipsis>
- </div>
- <div class={'w150px pl30px text-left'}>
- <div class={'text-16px font-semibold'}>¥{item.price} </div>
- </div>
- </div>
- <div class={'w-full flex items-center justify-between'}>
- <div class={'w200px text-gray'}>规格: {item.spec}</div>
- <div class={'w150px pl30px text-left text-gray'}>x{item.prodCount} </div>
- </div>
- </div>
- </div>
- );
- })}
- </div>
- );
- }
- },
- {
- key: 'deptName',
- title: '单价(元)/数量',
- align: 'center',
- width: 100
- },
- {
- key: 'actualTotal',
- title: '实付金额(元)',
- align: 'center',
- width: 120,
- render: row => {
- return (
- <div class={'mt7'}>
- <div class={'text-16px text-#ff0000 font-semibold'}>{row.actualTotal} 元</div>
- <div>共 {row.goodsTotalCount} 件</div>
- </div>
- );
- }
- },
- {
- key: 'payType',
- title: '支付方式',
- align: 'center',
- width: 120,
- render: row => {
- return (
- <NTag class={'mt7'} type="success">
- {row.payType == 0 || row.payType == 1 ? '微信' : '未支付'}
- </NTag>
- );
- }
- },
- {
- key: 'seq',
- title: '买家/收货人',
- align: 'center',
- width: 120,
- render: row => {
- return (
- <div class={'mt7'}>
- <div>{row.receiver}</div>
- <div>{row.userMobile}</div>
- </div>
- );
- }
- },
- {
- key: 'dvyType',
- title: '订单类型',
- align: 'center',
- width: 120,
- render: row => {
- return <NTag class={'mt7'}>{dvyStatus[row.dvyType as keyof typeof dvyStatus] || '未知类型'}</NTag>;
- }
- },
- {
- key: 'status',
- title: '拆单方式',
- align: 'center',
- width: 320,
- render: row => {
- return (
- <div class={'mt7'}>
- <div>{row.autoSplit == 1 ? '自动拆单' : '手动拆单'}</div>
- {row.autoSplit === 0 && <div>{row.splitUserName}</div>}
- </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={() => handleOpenMoadl(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();
- function handleOpenMoadl(row: Api.delivery.deliveryOrder) {
- if (!row.orderNumber) {
- window.$message?.error('订单异常');
- return;
- }
- 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: 'split'
- // },
- // {
- // label: '待发货',
- // value: 'paddingShipped'
- // },
- // {
- // label: '待收货',
- // value: 'paddingReceived'
- // },
- // {
- // 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.current = 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();
- }
- 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-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>
- </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>
|