index.vue 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. <script setup lang="tsx">
  2. import { nextTick, ref, watch } from 'vue';
  3. import { 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. fetchBreakDownload,
  8. fetchExportList,
  9. fetchExportOrderList,
  10. fetchGetDeliveryOrderList,
  11. fetchGetDeliveryStatusNum
  12. } from '@/service/api/order-manage/normal-order';
  13. // import { fetchGetLoginUserList } from '@/service/api/common';
  14. import { useAuth } from '@/hooks/business/auth';
  15. // import { copyTextToClipboard } from '@/utils/zt';
  16. import { commonExport } from '@/utils/common';
  17. import { useModal } from '@/components/zt/Modal/hooks/useModal';
  18. import { useTable } from '@/components/zt/Table/hooks/useTable';
  19. // import { type } from '../../../../packages/axios/src/index';
  20. import { SearchForm, orderStatus } from './normal-order';
  21. const router = useRouter();
  22. const activeTab = ref('all');
  23. const statusList = ref<{ label: string; value: string; num?: number }[]>([]);
  24. // const ShipmentModal = useTemplateRef('Shipment');
  25. const channelIdList = ref([]);
  26. const columns: NaiveUI.TableColumn<Api.delivery.deliveryOrder>[] = [
  27. {
  28. key: 'orderNumber',
  29. title: '订单编号',
  30. align: 'center',
  31. width: 220
  32. },
  33. {
  34. key: 'consigneeAddress',
  35. title: '业务类型',
  36. align: 'center',
  37. width: 120,
  38. render: row => {
  39. return <NTag class={'mt7'}>{row.businessType}</NTag>;
  40. }
  41. },
  42. {
  43. key: 'info',
  44. title: '客户信息',
  45. align: 'center',
  46. width: 220,
  47. render: row => {
  48. return (
  49. <div class={'mt7'}>
  50. <div>
  51. {row.consigneeName}
  52. {row.consigneeMobile}
  53. </div>
  54. <div>{row.consigneeAddress}</div>
  55. </div>
  56. );
  57. }
  58. },
  59. {
  60. key: 'status',
  61. title: '订单状态',
  62. align: 'center',
  63. width: 120,
  64. render: row => {
  65. const statusKey = row.hbOrderStatus as keyof typeof orderStatus;
  66. const statusText = orderStatus[statusKey] || '未知状态';
  67. return <NTag class={'mt7'}>{statusText}</NTag>;
  68. }
  69. },
  70. {
  71. key: 'createTime',
  72. title: '下单时间',
  73. align: 'center',
  74. width: 180,
  75. render: row => {
  76. return <div>{row.createTime?.replace('T', ' ')}</div>;
  77. }
  78. }
  79. ];
  80. const [registerTable, { refresh, setTableLoading, getSeachForm, getTableData }] = useTable({
  81. searchFormConfig: {
  82. schemas: [...SearchForm]
  83. },
  84. tableConfig: {
  85. keyField: 'id',
  86. title: '',
  87. showAddButton: false,
  88. showTableHeaderAction: true,
  89. fieldMapToTime: [['createTime', ['startTime', 'endTime']]]
  90. }
  91. });
  92. const exportColumns: NaiveUI.TableColumn<InternalRowData>[] = [
  93. {
  94. key: 'index',
  95. title: '序号',
  96. align: 'center',
  97. width: 100,
  98. render(_, rowIndex) {
  99. return rowIndex + 1;
  100. }
  101. },
  102. {
  103. key: 'taskName',
  104. title: '任务名称',
  105. align: 'center',
  106. minWidth: 100
  107. },
  108. {
  109. key: 'updateTime',
  110. title: '时间',
  111. align: 'center',
  112. minWidth: 100,
  113. render: row => {
  114. return (
  115. <div>
  116. <div>创建时间:{row.createTime}</div>
  117. <div>完成时间:{row.updateTime}</div>
  118. </div>
  119. );
  120. }
  121. },
  122. {
  123. key: 'operator',
  124. title: '操作人',
  125. align: 'center',
  126. minWidth: 100
  127. },
  128. {
  129. key: 'exportStatus',
  130. title: '状态',
  131. align: 'center',
  132. minWidth: 100,
  133. render: row => {
  134. if (row.exportStatus == 0) {
  135. return (
  136. <div>
  137. 请耐心等待,正在导出中...
  138. <n-button text type="info" onClick={() => handleBreak(row.id as string)}>
  139. 中断
  140. </n-button>
  141. </div>
  142. );
  143. } else if (row.exportStatus == 1) {
  144. return (
  145. <div>
  146. 未下载
  147. <n-button text type="info" onClick={() => handleDownload(row.id as string)}>
  148. 下载
  149. </n-button>
  150. </div>
  151. );
  152. } else if (row.exportStatus == 2) {
  153. return <div class={'text-gray-500'}>生成文件失败</div>;
  154. } else if (row.exportStatus == 3) {
  155. return (
  156. <div>
  157. 已下载&nbsp;
  158. <n-button text type="info" onClick={() => handleDownload(row.id as string)}>
  159. 下载
  160. </n-button>
  161. </div>
  162. );
  163. } else if (row.exportStatus == 4) {
  164. return <div>导出失败</div>;
  165. }
  166. return <div>进行中</div>;
  167. }
  168. }
  169. ];
  170. async function handleDownload(id: string) {
  171. setTableLoading(true);
  172. await commonExport('/platform/exportTask/download', { fileId: id }, '正常订单列表.xlsx');
  173. refresh();
  174. }
  175. async function handleBreak(id: string) {
  176. setTableLoading(true);
  177. await fetchBreakDownload(id);
  178. refresh();
  179. }
  180. const [registerModalPrice, { openModal }] = useModal({
  181. title: '导出记录',
  182. width: 1200,
  183. height: 600,
  184. showFooter: false
  185. });
  186. const dialog = useDialog();
  187. // async function handleDeivery(row: Api.delivery.deliveryOrder) {
  188. // if (!row.orderNumber) {
  189. // window.$message?.error('订单异常');
  190. // return;
  191. // }
  192. // ShipmentModal.value?.handleOpenOrder(row.orderNumber);
  193. // }
  194. function handleOrderDetail(row: Api.delivery.deliveryOrder) {
  195. if (!row.orderNumber) {
  196. window.$message?.error('订单异常');
  197. }
  198. router.push({
  199. path: '/order-manage/order-detail',
  200. query: {
  201. orderNumber: row.orderNumber
  202. }
  203. });
  204. // orderMoadl.value?.open(String(row.orderNumber));
  205. }
  206. async function getNums() {
  207. const form = getSeachForm();
  208. const params = {
  209. ...form,
  210. channelIdList: channelIdList.value,
  211. startTime: form?.createTime && form.createTime[0],
  212. endTime: form?.createTime && form.createTime[1],
  213. createTime: null
  214. };
  215. const { data: keyData } = await fetchGetDeliveryStatusNum(params);
  216. if (!keyData) return;
  217. const orderStatusList = [
  218. {
  219. label: '全部',
  220. value: 'all'
  221. },
  222. {
  223. label: '待支付',
  224. value: 'paddingPay'
  225. },
  226. {
  227. label: '进行中',
  228. value: 'ing'
  229. },
  230. {
  231. label: '已完成',
  232. value: 'completed'
  233. },
  234. {
  235. label: '已取消',
  236. value: 'cancel'
  237. }
  238. ];
  239. const updatedOrderStatusList = orderStatusList.map(item => {
  240. const key = item.value as keyof typeof keyData;
  241. if (Object.hasOwn(keyData, key)) {
  242. return {
  243. ...item,
  244. num: keyData[key]
  245. };
  246. }
  247. return item;
  248. });
  249. // console.log(updatedOrderStatusList, 'updatedOrderStatusList');
  250. statusList.value = updatedOrderStatusList;
  251. }
  252. getNums();
  253. // async function handleCopy(row: Api.delivery.deliveryOrder, key: string) {
  254. // if (!row[key]) {
  255. // window.$message?.error('订单编号不存在');
  256. // return;
  257. // }
  258. // await copyTextToClipboard(row[key]);
  259. // }
  260. async function handleExport() {
  261. setTableLoading(true);
  262. try {
  263. // await commonExport(
  264. // '/platform/order/export',
  265. // { ...getFieldsValue(), orderStatus: activeTab.value },
  266. // '正常订单列表.xlsx'
  267. // );
  268. await fetchExportOrderList({ ...getSeachForm(), orderStatus: activeTab.value });
  269. dialog.success({
  270. title: '提示',
  271. content: () => {
  272. return (
  273. <div>
  274. <p>导出操作进行中......</p>
  275. <p>是否进入导出记录</p>
  276. </div>
  277. );
  278. },
  279. positiveText: '确定',
  280. negativeText: '取消',
  281. onPositiveClick: () => {
  282. openModal();
  283. },
  284. onNegativeClick: () => {}
  285. });
  286. } finally {
  287. setTableLoading(false);
  288. }
  289. }
  290. async function handleExportLog() {
  291. setTableLoading(true);
  292. try {
  293. openModal();
  294. } finally {
  295. setTableLoading(false);
  296. }
  297. }
  298. watch(
  299. () => [activeTab.value],
  300. () => {
  301. nextTick(() => {
  302. refresh();
  303. });
  304. }
  305. );
  306. </script>
  307. <template>
  308. <LayoutTable>
  309. <ZTable
  310. :columns="columns"
  311. :api="fetchGetDeliveryOrderList"
  312. :default-params="{ orderStatus: activeTab }"
  313. @register="registerTable"
  314. >
  315. <template #op="{ row }">
  316. <NButton size="small" type="primary" ghost @click="handleOrderDetail(row)">订单详情</NButton>
  317. </template>
  318. <template #header>
  319. <div class="flex items-center">
  320. <NScrollbar x-scrollable>
  321. <div class="flex items-center">
  322. <div class="max-w-800px">
  323. <NTabs v-model:value="activeTab" type="line" animated display-directive="show">
  324. <NTab
  325. v-for="item in statusList"
  326. :key="item.value"
  327. :name="item.value"
  328. :tab="`${item.label}(${item.num})`"
  329. ></NTab>
  330. </NTabs>
  331. </div>
  332. </div>
  333. </NScrollbar>
  334. </div>
  335. </template>
  336. <template #prefix="{ loading }">
  337. <div class="flex items-center">
  338. <NButton
  339. v-if="useAuth().hasAuth('order:user:export')"
  340. size="small"
  341. type="primary"
  342. class="ml20px mt30px"
  343. ghost
  344. :loading="loading"
  345. :disabled="getTableData().length == 0"
  346. @click="handleExport"
  347. >
  348. <template #icon>
  349. <SvgIcon icon="mingcute:file-export-line"></SvgIcon>
  350. </template>
  351. 导出
  352. </NButton>
  353. <NButton
  354. v-if="useAuth().hasAuth('order:user:export')"
  355. size="small"
  356. type="primary"
  357. class="ml20px mt30px"
  358. ghost
  359. :loading="loading"
  360. @click="handleExportLog"
  361. >
  362. 导出记录
  363. </NButton>
  364. </div>
  365. </template>
  366. </ZTable>
  367. <BasicModal @register="registerModalPrice" @after-leave="refresh">
  368. <LayoutTable>
  369. <ZTable
  370. :show-table-action="false"
  371. :columns="exportColumns"
  372. :api="fetchExportList"
  373. :default-params="{ exportType: 1 }"
  374. @register="registerTable"
  375. ></ZTable>
  376. </LayoutTable>
  377. </BasicModal>
  378. </LayoutTable>
  379. </template>
  380. <style scoped></style>