index.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  1. <script setup lang="tsx">
  2. import { nextTick, onMounted, ref, watch } from 'vue';
  3. import { useRoute, useRouter } from 'vue-router';
  4. import { NTag, useDialog } from 'naive-ui';
  5. import type { InternalRowData } from 'naive-ui/es/data-table/src/interface';
  6. import {
  7. // fetchAudit,
  8. fetchBreakDownload,
  9. fetchExportList,
  10. fetchExportOrderList,
  11. fetchGetDeliveryOrderList,
  12. fetchGetDeliveryStatusNum
  13. } from '@/service/api/order-manage/normal-order';
  14. // import { fetchGetLoginUserList } from '@/service/api/common';
  15. // import { useAuth } from '@/hooks/business/auth';
  16. // import { copyTextToClipboard } from '@/utils/zt';
  17. // import { commonExport } from '@/utils/common';
  18. import { useModal } from '@/components/zt/Modal/hooks/useModal';
  19. import { useTable } from '@/components/zt/Table/hooks/useTable';
  20. // import { type } from '../../../../packages/axios/src/index';
  21. import { DJKOrderStatus, businessType, getSearchForm, orderStatus } from './normal-order';
  22. const router = useRouter();
  23. const route = useRoute();
  24. const activeTab = ref('all');
  25. const statusList = ref<{ label: string; value: string; num?: number }[]>([]);
  26. // const ShipmentModal = useTemplateRef('Shipment');
  27. const channelIdList = ref([]);
  28. const orderNumber = route.query.orderNumber;
  29. const options = [
  30. {
  31. label: '导出商品数据',
  32. key: 'goods'
  33. },
  34. {
  35. label: '导出订单数据',
  36. key: 'order'
  37. }
  38. ];
  39. const columns: NaiveUI.TableColumn<Api.delivery.deliveryOrder>[] = [
  40. {
  41. key: 'orderNumber',
  42. title: '订单编号',
  43. align: 'center',
  44. width: 220
  45. },
  46. {
  47. key: 'consigneeAddress',
  48. title: '业务类型',
  49. align: 'center',
  50. width: 120,
  51. render: row => {
  52. return <NTag>{businessType[row.businessType as keyof typeof businessType] || row.businessType}</NTag>;
  53. }
  54. },
  55. {
  56. key: 'shopName',
  57. title: '门店名称',
  58. align: 'center',
  59. width: 120
  60. },
  61. {
  62. key: 'channelName',
  63. title: '所属企业',
  64. align: 'center',
  65. width: 120
  66. },
  67. {
  68. key: 'accessName',
  69. title: '渠道',
  70. align: 'center',
  71. width: 120
  72. },
  73. {
  74. key: 'info',
  75. title: '客户信息',
  76. align: 'center',
  77. width: 220,
  78. render: row => {
  79. return (
  80. <div>
  81. <div>
  82. {row.consigneeName}
  83. {row.consigneeMobile}
  84. </div>
  85. {row.dvyType == 2 ? <div>自提</div> : <div>{row.consigneeAddress}</div>}
  86. </div>
  87. );
  88. }
  89. },
  90. {
  91. key: 'orderMoney',
  92. title: '订单金额(元)',
  93. align: 'center',
  94. width: 120
  95. },
  96. {
  97. key: 'status',
  98. title: '业务状态',
  99. align: 'center',
  100. width: 120,
  101. render: row => {
  102. const statusKey = row.hbOrderStatus as keyof typeof orderStatus;
  103. let statusText;
  104. if (row.businessType == 'XNSP') {
  105. if (row.hbOrderStatus == 60 || row.hbOrderStatus == 50 || row.hbOrderStatus == 0) {
  106. statusText = '订单取消';
  107. } else {
  108. statusText = '订单完成';
  109. }
  110. } else if (row.businessType == 'DJK') {
  111. statusText = DJKOrderStatus[statusKey as keyof typeof DJKOrderStatus] || '未知状态';
  112. } else {
  113. statusText = orderStatus[statusKey] || '未知状态';
  114. }
  115. return <NTag>{statusText}</NTag>;
  116. }
  117. },
  118. {
  119. key: 'createTime',
  120. title: '下单时间',
  121. align: 'center',
  122. width: 180,
  123. render: row => {
  124. return <div>{row.createTime?.replace('T', ' ')}</div>;
  125. }
  126. }
  127. ];
  128. const [registerTable, { refresh, getSeachForm, getTableData, setFieldsValue }] = useTable({
  129. searchFormConfig: {
  130. schemas: [...getSearchForm()]
  131. },
  132. tableConfig: {
  133. keyField: 'id',
  134. title: '',
  135. showAddButton: false,
  136. showTableHeaderAction: true,
  137. fieldMapToTime: [['createTime', ['startTime', 'endTime']]]
  138. }
  139. });
  140. const [registerLogTable, { refresh: refresh1, setTableLoading }] = useTable({
  141. tableConfig: {
  142. keyField: 'id',
  143. title: '',
  144. showAddButton: false,
  145. showTableHeaderAction: true,
  146. showSearch: false,
  147. minHeight: 400
  148. }
  149. });
  150. const exportColumns: NaiveUI.TableColumn<InternalRowData>[] = [
  151. {
  152. key: 'index',
  153. title: '序号',
  154. align: 'center',
  155. width: 100,
  156. render(_, rowIndex) {
  157. return rowIndex + 1;
  158. }
  159. },
  160. {
  161. key: 'taskName',
  162. title: '任务名称',
  163. align: 'center',
  164. minWidth: 100
  165. },
  166. {
  167. key: 'createTime',
  168. title: '时间',
  169. align: 'center'
  170. },
  171. {
  172. key: 'operatorAccount',
  173. title: '操作人',
  174. align: 'center',
  175. minWidth: 100
  176. },
  177. {
  178. key: 'status',
  179. title: '状态',
  180. align: 'center',
  181. minWidth: 100,
  182. render: row => {
  183. if (row.status == 0) {
  184. return (
  185. <div>
  186. 请耐心等待,正在导出中...
  187. <n-button text type="info" onClick={() => handleBreak(row.id as string)}>
  188. 中断
  189. </n-button>
  190. </div>
  191. );
  192. } else if (!row.fileUrl) {
  193. return <div>导出失败</div>;
  194. } else if (row.status == 1) {
  195. return (
  196. <div>
  197. 完成 {row.fileSize}
  198. <n-button text type="info" onClick={() => handleDownload(row.fileUrl as string)}>
  199. 下载
  200. </n-button>
  201. </div>
  202. );
  203. }
  204. // else if (row.exportStatus == 2) {
  205. // return <div class={'text-gray-500'}>生成文件失败</div>;
  206. // } else if (row.exportStatus == 3) {
  207. // return (
  208. // <div>
  209. // 已下载&nbsp;
  210. // <n-button text type="info" onClick={() => handleDownload(row.id as string)}>
  211. // 下载
  212. // </n-button>
  213. // </div>
  214. // );
  215. // }
  216. return <div>进行中</div>;
  217. }
  218. }
  219. ];
  220. async function handleDownload(fileUrl: string) {
  221. // setTableLoading(true);
  222. window.open(fileUrl);
  223. // await commonExport('/platform/exportTask/download', { fileId: id }, '正常订单列表.xlsx');
  224. refresh1();
  225. }
  226. async function handleBreak(id: string) {
  227. setTableLoading(true);
  228. await fetchBreakDownload(id);
  229. refresh1();
  230. }
  231. const [registerModalPrice, { openModal }] = useModal({
  232. title: '导出记录',
  233. width: 1200,
  234. height: 600,
  235. showFooter: false
  236. });
  237. const dialog = useDialog();
  238. // async function handleDeivery(row: Api.delivery.deliveryOrder) {
  239. // if (!row.orderNumber) {
  240. // window.$message?.error('订单异常');
  241. // return;
  242. // }
  243. // ShipmentModal.value?.handleOpenOrder(row.orderNumber);
  244. // }
  245. function handleOrderDetail(row: Api.delivery.deliveryOrder) {
  246. if (!row.orderNumber) {
  247. window.$message?.error('订单异常');
  248. }
  249. router.push({
  250. path: '/order-manage/order-detail',
  251. query: {
  252. orderNumber: row.orderNumber
  253. }
  254. });
  255. // orderMoadl.value?.open(String(row.orderNumber));
  256. }
  257. function handleSaleOrder(row: Api.delivery.deliveryOrder) {
  258. if (!row.orderNumber) {
  259. window.$message?.error('订单异常');
  260. }
  261. router.push({
  262. path: '/order-manage/after-sales-order',
  263. query: {
  264. orderNumber: row.orderNumber
  265. }
  266. });
  267. }
  268. // async function handleAudit(row: any) {
  269. // window.$dialog?.info({
  270. // title: '提示',
  271. // content: `此操作将核销该订单,且无法撤销,确定要核销吗?`,
  272. // positiveText: '确定',
  273. // negativeText: '取消',
  274. // onPositiveClick: async () => {
  275. // const { error } = await fetchAudit({ orderNumber: row.orderNumber });
  276. // if (!error) {
  277. // refresh();
  278. // }
  279. // }
  280. // });
  281. // }
  282. async function getNums() {
  283. const form = getSeachForm();
  284. const params = {
  285. ...form,
  286. channelIdList: channelIdList.value,
  287. startTime: form?.createTime && form.createTime[0],
  288. endTime: form?.createTime && form.createTime[1],
  289. createTime: null
  290. };
  291. const { data: keyData } = await fetchGetDeliveryStatusNum(params);
  292. if (!keyData) return;
  293. const orderStatusList = [
  294. {
  295. label: '全部',
  296. value: 'all'
  297. },
  298. {
  299. label: '待支付',
  300. value: 'paddingPay'
  301. },
  302. {
  303. label: '进行中',
  304. value: 'ing'
  305. },
  306. {
  307. label: '已完成',
  308. value: 'completed'
  309. },
  310. {
  311. label: '已取消',
  312. value: 'cancel'
  313. }
  314. ];
  315. const updatedOrderStatusList = orderStatusList.map(item => {
  316. const key = item.value as keyof typeof keyData;
  317. if (Object.hasOwn(keyData, key)) {
  318. return {
  319. ...item,
  320. num: keyData[key]
  321. };
  322. }
  323. return item;
  324. });
  325. // console.log(updatedOrderStatusList, 'updatedOrderStatusList');
  326. statusList.value = updatedOrderStatusList;
  327. }
  328. getNums();
  329. // async function handleCopy(row: Api.delivery.deliveryOrder, key: string) {
  330. // if (!row[key]) {
  331. // window.$message?.error('订单编号不存在');
  332. // return;
  333. // }
  334. // await copyTextToClipboard(row[key]);
  335. // }
  336. async function handleExport(exportType: any) {
  337. setTableLoading(true);
  338. try {
  339. // await commonExport(
  340. // '/platform/order/export',
  341. // { ...getFieldsValue(), orderStatus: activeTab.value },
  342. // '正常订单列表.xlsx'
  343. // );
  344. await fetchExportOrderList({ exportType, ...getSeachForm(), orderStatus: activeTab.value });
  345. dialog.success({
  346. title: '提示',
  347. content: () => {
  348. return (
  349. <div>
  350. <p>导出操作进行中......</p>
  351. <p>是否进入导出记录</p>
  352. </div>
  353. );
  354. },
  355. positiveText: '确定',
  356. negativeText: '取消',
  357. onPositiveClick: () => {
  358. openModal();
  359. },
  360. onNegativeClick: () => {}
  361. });
  362. } finally {
  363. setTableLoading(false);
  364. }
  365. }
  366. async function handleExportLog() {
  367. setTableLoading(true);
  368. try {
  369. openModal();
  370. } finally {
  371. setTableLoading(false);
  372. }
  373. }
  374. watch(
  375. () => [activeTab.value],
  376. () => {
  377. nextTick(() => {
  378. refresh();
  379. });
  380. }
  381. );
  382. onMounted(async () => {
  383. await setFieldsValue({ orderNumber });
  384. refresh();
  385. });
  386. function getData() {
  387. return getTableData() || [];
  388. }
  389. function handleSelect(key: string) {
  390. console.log(key);
  391. if (key === 'goods') {
  392. handleExport('PRODUCT');
  393. } else if (key === 'order') {
  394. handleExport('ORDER');
  395. }
  396. }
  397. function handleship(row: Api.delivery.deliveryOrder) {
  398. if (!row.orderNumber) {
  399. window.$message?.error('订单异常');
  400. }
  401. router.push({
  402. path: '/order-manage/order-detail',
  403. query: {
  404. orderNumber: row.orderNumber,
  405. type: 'ship'
  406. }
  407. });
  408. }
  409. </script>
  410. <template>
  411. <LayoutTable>
  412. <ZTable
  413. :columns="columns"
  414. :api="fetchGetDeliveryOrderList"
  415. :immediate="false"
  416. :default-params="{ orderStatus: activeTab }"
  417. @register="registerTable"
  418. @search="getNums"
  419. >
  420. <template #op="{ row }">
  421. <div>
  422. <NButton size="small" type="primary" ghost @click="handleOrderDetail(row)">订单详情</NButton>
  423. <NButton
  424. v-if="row.backendOrderRefundButton"
  425. class="mt-10px"
  426. size="small"
  427. type="primary"
  428. ghost
  429. @click="handleSaleOrder(row)"
  430. >
  431. 售后订单
  432. </NButton>
  433. <NButton
  434. v-if="row.dvyType === 10 && row.hbOrderStatus === 40 && !row.dvyNo"
  435. class="mt-10px"
  436. size="small"
  437. type="primary"
  438. ghost
  439. @click="handleship(row)"
  440. >
  441. 发货
  442. </NButton>
  443. <NButton
  444. v-if="row.dvyType === 10 && (row.hbOrderStatus === 40 || row.hbOrderStatus === 70) && row.dvyNo"
  445. class="mt-10px"
  446. size="small"
  447. type="primary"
  448. ghost
  449. @click="handleship(row)"
  450. >
  451. 修改发货信息
  452. </NButton>
  453. </div>
  454. <!--
  455. <NButton
  456. v-if="row.businessType === 'DJK' && row.isWriteOff == 1 && row.hbOrderStatus != 80"
  457. size="small"
  458. type="primary"
  459. ghost
  460. @click="handleAudit(row)"
  461. >
  462. 核销
  463. </NButton>
  464. -->
  465. </template>
  466. <template #header>
  467. <div class="flex items-center">
  468. <NScrollbar x-scrollable>
  469. <div class="flex items-center">
  470. <div class="max-w-800px">
  471. <NTabs v-model:value="activeTab" type="line" animated display-directive="show">
  472. <NTab
  473. v-for="item in statusList"
  474. :key="item.value"
  475. :name="item.value"
  476. :tab="`${item.label}(${item.num})`"
  477. ></NTab>
  478. </NTabs>
  479. </div>
  480. </div>
  481. </NScrollbar>
  482. </div>
  483. </template>
  484. <template #prefix="{ loading }">
  485. <div class="flex items-center">
  486. <NDropdown trigger="click" :options="options" @select="handleSelect">
  487. <NButton size="small" type="primary" ghost :loading="loading" :disabled="getData().length === 0">
  488. <template #icon>
  489. <SvgIcon icon="mingcute:file-export-line"></SvgIcon>
  490. </template>
  491. 导出
  492. </NButton>
  493. </NDropdown>
  494. <NButton size="small" type="primary" class="ml10px" ghost :loading="loading" @click="handleExportLog">
  495. 导出记录
  496. </NButton>
  497. </div>
  498. </template>
  499. </ZTable>
  500. <BasicModal @register="registerModalPrice" @after-leave="refresh">
  501. <LayoutTable>
  502. <ZTable
  503. :show-table-action="false"
  504. :columns="exportColumns"
  505. :api="fetchExportList"
  506. @register="registerLogTable"
  507. ></ZTable>
  508. </LayoutTable>
  509. </BasicModal>
  510. </LayoutTable>
  511. </template>
  512. <style scoped></style>