|
|
@@ -0,0 +1,256 @@
|
|
|
+<script setup lang="tsx">
|
|
|
+import { nextTick, onMounted, reactive, ref, watch } from 'vue';
|
|
|
+import type { TabsInst } from 'naive-ui';
|
|
|
+import { NImage, NTag } from 'naive-ui';
|
|
|
+import { fetchGetDeliveryOrderList, fetchGetDeliveryStatusNum } from '@/service/api/delivery/normal-orde';
|
|
|
+import { useAppStore } from '@/store/modules/app';
|
|
|
+import { defaultTransform, useNaivePaginatedTable } from '@/hooks/common/table';
|
|
|
+import { $t } from '@/locales';
|
|
|
+import { useForm } from '@/components/zt/Form/hooks/useForm';
|
|
|
+import { SearchForm, orderStatus, refundStatus } from './normal-order';
|
|
|
+const appStore = useAppStore();
|
|
|
+const checkedRowKeys = ref([]);
|
|
|
+const activeTab = ref('all');
|
|
|
+const statusList = ref<{ label: string; value: string; num?: number }[]>([]);
|
|
|
+const wrapperRef = ref<HTMLElement | null>(null);
|
|
|
+const tabsInstRef = ref<TabsInst | null>(null);
|
|
|
+onMounted(() => {
|
|
|
+ nextTick(() => {
|
|
|
+ tabsInstRef.value?.syncBarPosition();
|
|
|
+ console.log(tabsInstRef.value, 'tabsInstRef.value');
|
|
|
+ });
|
|
|
+});
|
|
|
+const [registerSearchForm, { getFieldsValue }] = useForm({
|
|
|
+ schemas: SearchForm,
|
|
|
+ showAdvancedButton: false,
|
|
|
+ labelWidth: 120,
|
|
|
+ layout: 'horizontal',
|
|
|
+ gridProps: {
|
|
|
+ cols: '1 xl:4 s:1 l:3',
|
|
|
+ itemResponsive: true
|
|
|
+ },
|
|
|
+ collapsedRows: 1
|
|
|
+});
|
|
|
+const searchParams = reactive({
|
|
|
+ current: 1,
|
|
|
+ size: 10
|
|
|
+});
|
|
|
+const { columns, data, loading, getData, mobilePagination } = useNaivePaginatedTable({
|
|
|
+ api: () => fetchGetDeliveryOrderList({ ...searchParams, orderStatus: activeTab.value, ...getFieldsValue() }),
|
|
|
+ transform: response => defaultTransform(response),
|
|
|
+ onPaginationParamsChange: params => {
|
|
|
+ searchParams.current = Number(params.page);
|
|
|
+ searchParams.size = Number(params.pageSize);
|
|
|
+ },
|
|
|
+ columns: () => [
|
|
|
+ {
|
|
|
+ key: 'orderItems',
|
|
|
+ title: '商品',
|
|
|
+ align: 'left',
|
|
|
+ width: 200,
|
|
|
+ colSpan: (_rowData, _rowIndex) => 2,
|
|
|
+ render: row => {
|
|
|
+ return (
|
|
|
+ <div>
|
|
|
+ <div class={'mb3 flex items-center'}>
|
|
|
+ <n-tag>
|
|
|
+ 订单编号:{row.orderNumber} 下单时间:{row.createTime} 门店名称 {row.shopName}
|
|
|
+ </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={'w250px'}>
|
|
|
+ <n-ellipsis class={'w250px'}>
|
|
|
+ <span class={'w-full text-left text-15px font-semibold'}>{item.skuName}</span>
|
|
|
+ </n-ellipsis>
|
|
|
+ </div>
|
|
|
+ <div class={'w100px text-left'}>
|
|
|
+ <div class={'text-16px font-semibold'}>¥{item.price} </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class={'w-full flex items-center justify-between'}>
|
|
|
+ <div class={'w250px text-gray'}>规格: </div>
|
|
|
+ <div class={'w100px 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
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: 'seq',
|
|
|
+ title: '买家/收货人',
|
|
|
+ align: 'center',
|
|
|
+ width: 120,
|
|
|
+ render: row => {
|
|
|
+ return (
|
|
|
+ <div class={'mt7'}>
|
|
|
+ <div>{row.receiver}</div>
|
|
|
+ <div>{row.userMobile}</div>
|
|
|
+ </div>
|
|
|
+ );
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: 'status',
|
|
|
+ title: '订单状态',
|
|
|
+ align: 'center',
|
|
|
+ width: 320,
|
|
|
+ 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: 160,
|
|
|
+ render: row => {
|
|
|
+ const statusKey = row.refundStatus as keyof typeof refundStatus;
|
|
|
+ const statusText = refundStatus[statusKey] || '暂无售后';
|
|
|
+ return <NTag class={'mt7'}>{statusText}</NTag>;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: 'operate',
|
|
|
+ title: $t('common.operate'),
|
|
|
+ align: 'center',
|
|
|
+ width: 130,
|
|
|
+ fixed: 'right'
|
|
|
+ }
|
|
|
+ ]
|
|
|
+});
|
|
|
+
|
|
|
+async function getNums() {
|
|
|
+ const { data: keyData } = await fetchGetDeliveryStatusNum();
|
|
|
+ if (!keyData) return;
|
|
|
+ const orderStatusList = [
|
|
|
+ {
|
|
|
+ label: '全部',
|
|
|
+ value: 'all'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: '待支付',
|
|
|
+ value: 'paddingPay'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ 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;
|
|
|
+}
|
|
|
+getNums();
|
|
|
+watch(
|
|
|
+ () => [activeTab.value],
|
|
|
+ () => {
|
|
|
+ getData();
|
|
|
+ }
|
|
|
+);
|
|
|
+</script>
|
|
|
+
|
|
|
+<template>
|
|
|
+ <div ref="wrapperRef" class="flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto">
|
|
|
+ <NCard :bordered="false" size="small">
|
|
|
+ <NCollapse display-directive="show" :default-expanded-names="['dept-search']">
|
|
|
+ <NCollapseItem title="搜索" name="dept-search">
|
|
|
+ <BasicForm @register-form="registerSearchForm" />
|
|
|
+ </NCollapseItem>
|
|
|
+ </NCollapse>
|
|
|
+ </NCard>
|
|
|
+ <NCard title="订单列表" :bordered="false" size="small" class="card-wrapper sm:flex-1-hidden">
|
|
|
+ <NTabs ref="tabsInstRef" v-model:value="activeTab" type="line" animated class="mb-16px h-full">
|
|
|
+ <NTabPane
|
|
|
+ v-for="item in statusList"
|
|
|
+ :key="item.value"
|
|
|
+ display-directive="show"
|
|
|
+ :name="item.value"
|
|
|
+ :tab="`${item.label}(${item.num})`"
|
|
|
+ >
|
|
|
+ <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"
|
|
|
+ />
|
|
|
+ </NTabPane>
|
|
|
+ </NTabs>
|
|
|
+
|
|
|
+ <!-- <BasicModal @register="registerModal" @ok="handleSubmit"></BasicModal> -->
|
|
|
+ </NCard>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+:deep(.n-tabs-pane-wrapper) {
|
|
|
+ height: 100%;
|
|
|
+}
|
|
|
+:deep(.n-tab-pane) {
|
|
|
+ height: 100%;
|
|
|
+}
|
|
|
+</style>
|