order-page-all.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682
  1. <template>
  2. <ele-page flex-table>
  3. <!-- 搜索表单 -->
  4. <order-search @search="reload" />
  5. <ele-card :body-style="{ paddingTop: '8px' }" flex-table>
  6. <!-- 表格 -->
  7. <ele-pro-table
  8. ref="tableRef"
  9. row-key="orderId"
  10. :columns="columns"
  11. :datasource="datasource"
  12. :show-overflow-tooltip="true"
  13. v-model:selections="selections"
  14. highlight-current-row
  15. :export-config="{ fileName: pageConfig.fileName }"
  16. :cache-key="pageConfig.cacheKey"
  17. >
  18. <template #toolbar>
  19. <slot name="toolbar"></slot>
  20. </template>
  21. <template #status="{ row }">
  22. <el-tag type="danger" v-if="row.cancelStatus == 1">已取消</el-tag>
  23. <dict-data
  24. v-else
  25. code="order_status"
  26. type="tag"
  27. :model-value="row.status"
  28. />
  29. </template>
  30. <template #orderNumber="{ row }">
  31. <order-number :row="row"></order-number>
  32. </template>
  33. <template #customer="{ row }">
  34. <order-customer :row="row"></order-customer>
  35. </template>
  36. <template #amount="{ row }">
  37. <order-amount :row="row"></order-amount>
  38. </template>
  39. <template #time="{ row }">
  40. <order-time :row="row"></order-time>
  41. </template>
  42. <template #remarks="{ row }">
  43. <el-popover
  44. trigger="hover"
  45. width="240px"
  46. @show="handleShowPopover(row)"
  47. @hide="showOrderId = ''"
  48. >
  49. <template #reference>
  50. <el-icon
  51. style="cursor: pointer"
  52. :size="24"
  53. :color="row.remarkLabel || '#777777'"
  54. @click="handleRemarks(row)"
  55. >
  56. <Flag />
  57. </el-icon>
  58. </template>
  59. <orderTimeline
  60. :orderId="showOrderId"
  61. title="备注历史记录"
  62. ></orderTimeline>
  63. </el-popover>
  64. </template>
  65. <template #action="{ row }">
  66. <div>
  67. <el-button
  68. type="success"
  69. link
  70. v-permission="usePermission('detail')"
  71. @click="toOrderDetail(row)"
  72. >
  73. [订单详情]
  74. </el-button>
  75. <el-button
  76. type="warning"
  77. link
  78. v-permission="usePermission('log')"
  79. @click="openOrderLog(row)"
  80. >
  81. [订单日志]
  82. </el-button>
  83. <el-button
  84. type="danger"
  85. link
  86. v-if="row.status == 2"
  87. v-permission="usePermission('audit')"
  88. @click="handleFirstCheck(row)"
  89. >
  90. [初步审核]
  91. </el-button>
  92. <!-- 3 已初审-带上门取件 5已揽件-待签收 6已签收-待确认到货 -->
  93. <el-button
  94. type="danger"
  95. link
  96. v-if="['3', '5', '6'].includes(row.status)"
  97. v-permission="usePermission('cancel')"
  98. @click="handleCancelOrder(row)"
  99. >
  100. [取消订单]
  101. </el-button>
  102. <!-- 3 已初审-带上门取件 5已揽件-待签收 6已签收-待确认到货 8待回收审核 9审核未提交 10待付款 -->
  103. <el-button
  104. type="primary"
  105. link
  106. v-if="['3', '5', '6', '8', '9', '10'].includes(row.status)"
  107. v-permission="usePermission('fallback')"
  108. @click="fallbackOrder(row)"
  109. >
  110. [回退状态]
  111. </el-button>
  112. <el-button
  113. type="success"
  114. link
  115. v-if="row.status == 3"
  116. v-permission="usePermission('materialPickup')"
  117. @click="materialPickup(row)"
  118. >
  119. [物流揽件]
  120. </el-button>
  121. <el-button
  122. type="success"
  123. link
  124. v-if="row.status == 5"
  125. v-permission="usePermission('receive')"
  126. @click="handleLogisticsSigning(row)"
  127. >
  128. [物流签收]
  129. </el-button>
  130. <el-button
  131. type="success"
  132. link
  133. v-if="row.status == 5 || row.status == 7"
  134. v-permission="usePermission('signDelivery')"
  135. @click="handleSignDelivery(row)"
  136. >
  137. [快递签收]
  138. </el-button>
  139. <el-button
  140. type="success"
  141. link
  142. v-if="row.status == 6"
  143. v-permission="usePermission('confirmReceipt')"
  144. @click="handleConfirmReceipt(row)"
  145. >
  146. [确认收货]
  147. </el-button>
  148. <el-button
  149. type="success"
  150. link
  151. v-if="['8', '9'].includes(row.status)"
  152. v-permission="usePermission('arrivalAudit')"
  153. @click="toOrderDetail(row)"
  154. >
  155. [到货审核]
  156. </el-button>
  157. <el-button
  158. type="danger"
  159. link
  160. v-if="['8', '9', '10', '11'].includes(row.status)"
  161. v-permission="usePermission('auditScreenshot')"
  162. @click="handleAuditScreenshot(row)"
  163. >
  164. [审核截图]
  165. </el-button>
  166. <el-button
  167. type="danger"
  168. link
  169. v-if="row.status == 10"
  170. v-permission="usePermission('payment')"
  171. @click="handleBatchPayment(row)"
  172. >
  173. [支付书款]
  174. </el-button>
  175. <el-button
  176. type="danger"
  177. link
  178. v-if="row.status == 11"
  179. v-permission="usePermission('afterSalesPayment')"
  180. @click="handleAfterSalesPayment(row)"
  181. >
  182. [售后补款]
  183. </el-button>
  184. <el-button
  185. type="warning"
  186. link
  187. v-permission="usePermission('userTag')"
  188. @click="openEditUserTag(row)"
  189. >
  190. [用户标签]
  191. </el-button>
  192. <el-button
  193. type="success"
  194. link
  195. v-if="row.status == 2"
  196. v-permission="usePermission('modifyAddress')"
  197. @click="handleModifyAddress(row)"
  198. >
  199. [修改地址]
  200. </el-button>
  201. <el-button
  202. type="success"
  203. link
  204. v-if="['8', '9', '10', '11'].includes(row.status)"
  205. v-permission="usePermission('sendSMS')"
  206. @click="handleSendSMS(row)"
  207. >
  208. [推送短信]
  209. </el-button>
  210. <el-button
  211. type="info"
  212. link
  213. v-if="['8', '9', '10'].includes(row.status)"
  214. v-permission="usePermission('smsLog')"
  215. @click="handleSmsLog(row)"
  216. >
  217. [短信记录]
  218. </el-button>
  219. <el-button
  220. color="#7728f5"
  221. link
  222. plain
  223. v-if="row.status == 11"
  224. v-permission="usePermission('applyForOrderClaim')"
  225. @click="handleApplyForOrderClaim(row)"
  226. >
  227. [申请订单理赔]
  228. </el-button>
  229. <el-button
  230. color="#7728f5"
  231. link
  232. plain
  233. v-if="row.cancelStatus == 1"
  234. v-permission="usePermission('applyForOrderRestore')"
  235. @click="handleApplyForOrderRestore(row)"
  236. >
  237. [申请恢复订单]
  238. </el-button>
  239. <template v-if="row.interceptStatus == 0">
  240. <el-button
  241. type="danger"
  242. link
  243. v-if="['5', '6'].includes(row.status)"
  244. v-permission="usePermission('interception')"
  245. @click="applyForInterception(row)"
  246. >
  247. [申请拦截退回]
  248. </el-button>
  249. </template>
  250. <template v-else>
  251. <el-button
  252. type="info"
  253. link
  254. v-if="['5', '6'].includes(row.status)"
  255. v-permission="usePermission('cancelInterception')"
  256. @click="cancelInterception(row)"
  257. >
  258. [取消拦截退回]
  259. </el-button>
  260. </template>
  261. </div>
  262. </template>
  263. </ele-pro-table>
  264. </ele-card>
  265. <slot></slot>
  266. <!-- 备注 -->
  267. <orderRemarks ref="remarksRef" />
  268. <!-- 初审 -->
  269. <firstCheckModal ref="firstCheckRef" @success="reload()" />
  270. <!-- 修改地址 -->
  271. <modifyAddress ref="modifyAddressRef" />
  272. <!-- 订单日志 -->
  273. <orderLog ref="orderLogRef" />
  274. <!-- 用户标签 -->
  275. <userBindTag ref="userTagRef" @success="reload()" />
  276. <!-- 订单详情 -->
  277. <orderDetail ref="orderDetailRef" @refresh="reload()" />
  278. <!-- 审核截图 -->
  279. <auditScreenshot ref="auditScreenshotRef" />
  280. <!-- 申请订单理赔 -->
  281. <applyForOrderClaim ref="applyForOrderClaimRef" />
  282. <!-- 售后补款 -->
  283. <afterSalesPayment ref="afterSalesPaymentRef" />
  284. </ele-page>
  285. </template>
  286. <script setup>
  287. import { ref, getCurrentInstance } from 'vue';
  288. import { ElMessageBox } from 'element-plus/es';
  289. import { EleMessage } from 'ele-admin-plus/es';
  290. import { DownloadOutlined } from '@/components/icons';
  291. import { Flag, ChatDotSquare } from '@element-plus/icons-vue';
  292. import OrderSearch from '../components/order-search.vue';
  293. import OrderNumber from '@/views/recycleOrder/components/order-number.vue';
  294. import OrderCustomer from '@/views/recycleOrder/components/order-customer.vue';
  295. import OrderAmount from '@/views/recycleOrder/components/order-amount.vue';
  296. import OrderTime from '@/views/recycleOrder/components/order-time.vue';
  297. import { useDictData } from '@/utils/use-dict-data';
  298. import { download, toFormData, checkDownloadRes } from '@/utils/common';
  299. import orderRemarks from '@/views/recycleOrder/components/order-remarks.vue';
  300. import orderTimeline from '@/views/recycleOrder/components/order-timeline.vue';
  301. import firstCheckModal from '@/views/recycleOrder/components/first-check-modal.vue';
  302. import modifyAddress from '@/views/recycleOrder/components/modify-address.vue';
  303. import applyForOrderClaim from '@/views/recycleOrder/components/applyfor-order-claim.vue';
  304. import afterSalesPayment from '@/views/recycleOrder/components/after-sales-payment.vue';
  305. //订单日志
  306. import orderLog from '@/views/recycleOrder/components/order-log.vue';
  307. //用户标签
  308. import userBindTag from '@/views/recycleOrder/components/user-bind-tag.vue';
  309. //订单详情
  310. import orderDetail from '@/views/recycleOrder/components/order-detail.vue';
  311. //审核截图
  312. import auditScreenshot from '@/views/recycleOrder/components/audit-screenshot.vue';
  313. let props = defineProps({
  314. pageConfig: {
  315. type: Object,
  316. default: () => ({
  317. cacheKey: 'recycleOrderTable',
  318. pageUrl: '/order/orderInfo/pageList',
  319. fileName: '回收订单查询',
  320. exportUrl: '/order/orderInfo/export',
  321. where: {}
  322. })
  323. },
  324. exportUrl: { type: String, default: '/system/post/export' },
  325. permissionKey: { type: String, default: 'search' }
  326. });
  327. const usePermission = computed(() => (opts) => {
  328. return `recycleOrder:${props.permissionKey}:${opts}`;
  329. });
  330. let { proxy } = getCurrentInstance();
  331. /** 字典数据 */
  332. const [statusDicts] = useDictData(['order_status']);
  333. /** 表格实例 */
  334. const tableRef = ref(null);
  335. /** 表格列配置 */
  336. const columns = ref([
  337. {
  338. type: 'selection',
  339. columnKey: 'selection',
  340. width: 50,
  341. align: 'center',
  342. fixed: 'left'
  343. },
  344. { label: '单号', prop: 'orderNumber', slot: 'orderNumber', minWidth: 230 },
  345. { label: '客户', prop: 'customer', slot: 'customer', minWidth: 360 },
  346. { label: '金额', prop: 'amount', slot: 'amount', minWidth: 160 },
  347. {
  348. label: '状态',
  349. prop: 'status',
  350. slot: 'status',
  351. width: '140'
  352. },
  353. { label: '时间', prop: 'time', slot: 'time', minWidth: 210 },
  354. { label: '备注', prop: 'remarks', slot: 'remarks' },
  355. {
  356. columnKey: 'action',
  357. label: '操作',
  358. width: 176,
  359. align: 'center',
  360. slot: 'action',
  361. hideInPrint: true,
  362. hideInExport: true,
  363. fixed: 'right'
  364. }
  365. ]);
  366. /** 表格选中数据 */
  367. const selections = ref([]);
  368. /** 当前编辑数据 */
  369. const current = ref(null);
  370. /** 是否显示编辑弹窗 */
  371. const showEdit = ref(false);
  372. async function queryPage(params) {
  373. if (!props.pageConfig.pageUrl) return EleMessage.error('未配置页面请求URL');
  374. const res = await proxy.$http.get(props.pageConfig.pageUrl, { params });
  375. if (res.data.code === 200) {
  376. return res.data;
  377. }
  378. return Promise.reject(new Error(res.data.msg));
  379. }
  380. /** 表格数据源 */
  381. const datasource = ({ pages, where, orders }) => {
  382. let initParams = props.pageConfig?.where || {};
  383. return queryPage({
  384. ...where,
  385. ...orders,
  386. ...pages,
  387. ...initParams
  388. });
  389. };
  390. /** 搜索 */
  391. const reload = (where) => {
  392. tableRef.value?.reload?.({ page: 1, where });
  393. };
  394. /** 批量操作 */
  395. const operatBatch = ({ row, url, title }) => {
  396. const rows = row == null ? selections.value : [row];
  397. if (!rows.length) {
  398. EleMessage.error('请至少选择一条数据');
  399. return;
  400. }
  401. title = title || '是否确认当前操作?';
  402. ElMessageBox.confirm(title, '提示', {
  403. type: 'warning',
  404. draggable: true
  405. })
  406. .then(() => {
  407. const loading = EleMessage.loading({
  408. message: '请求中..',
  409. plain: true
  410. });
  411. proxy.$http
  412. .delete(url)
  413. .then(() => {
  414. loading.close();
  415. EleMessage.success('操作成功');
  416. reload();
  417. })
  418. .catch((e) => {
  419. loading.close();
  420. EleMessage.error(e.message);
  421. });
  422. })
  423. .catch(() => {});
  424. };
  425. /// 导出数据
  426. async function exportPage(params, name) {
  427. if (!props.pageConfig.exportUrl)
  428. return EleMessage.error('未配置导出的URL!');
  429. const res = await proxy.$http({
  430. url: props.pageConfig.exportUrl,
  431. method: 'POST',
  432. data: toFormData(params),
  433. responseType: 'blob'
  434. });
  435. await checkDownloadRes(res);
  436. download(
  437. res.data,
  438. name ? `${name}_${Date.now()}.xlsx` : `post_${Date.now()}.xlsx`
  439. );
  440. }
  441. //导出数据 进导出记录
  442. function exportRecord(params, name) {
  443. if (!props.pageConfig.exportUrl)
  444. return EleMessage.error('未配置导出的URL!');
  445. return proxy.$http({
  446. url: props.pageConfig.exportUrl,
  447. method: 'POST',
  448. data: params
  449. }); // 导出记录
  450. }
  451. /** 导出数据 */
  452. const exportData = (name) => {
  453. const loading = EleMessage.loading({
  454. message: '请求中..',
  455. plain: true
  456. });
  457. tableRef.value?.fetch?.(({ where, orders }) => {
  458. exportRecord({ ...where, ...orders }, name)
  459. .then((res) => {
  460. if (res.data.code === 200) {
  461. EleMessage.success('操作成功,请前往导出记录下载');
  462. }
  463. loading.close();
  464. })
  465. .catch((e) => {
  466. loading.close();
  467. EleMessage.error(e.message);
  468. });
  469. });
  470. };
  471. //修改备注
  472. const remarksRef = ref(null);
  473. function handleRemarks(row) {
  474. remarksRef.value?.handleOpen(row);
  475. }
  476. //备注弹窗显示
  477. const showOrderId = ref();
  478. function handleShowPopover(row) {
  479. showOrderId.value = row.orderId;
  480. }
  481. //弹窗确认操作
  482. function messageBoxConfirm({ message, fetch }) {
  483. ElMessageBox.confirm(message, '提示', {
  484. confirmButtonText: '确定',
  485. cancelButtonText: '关闭',
  486. type: 'warning'
  487. }).then(() => {
  488. fetch().then((res) => {
  489. if (res.data.code === 200) {
  490. EleMessage.success('操作成功');
  491. reload();
  492. } else {
  493. EleMessage.error(res.data.msg);
  494. }
  495. });
  496. });
  497. }
  498. //取消订单
  499. function handleCancelOrder(row) {
  500. const rows = row == null ? selections.value : [row];
  501. if (!rows.length) {
  502. EleMessage.error('请至少选择一条数据');
  503. return;
  504. }
  505. messageBoxConfirm({
  506. message: '是否确认取消订单?',
  507. fetch: () =>
  508. proxy.$http.post('/order/orderInfo/adminCancel', {
  509. orderIds: rows.map((item) => item.orderId)
  510. })
  511. });
  512. }
  513. //申请拦截退出
  514. function applyForInterception(row) {
  515. messageBoxConfirm({
  516. message: '确认拦截?',
  517. fetch: () => proxy.$http.post(`/order/orderInfo/intercept/${row.orderId}`)
  518. });
  519. }
  520. //取消拦截退出
  521. function cancelInterception(row) {
  522. messageBoxConfirm({
  523. message: '确认取消拦截?',
  524. fetch: () =>
  525. proxy.$http.post(`/order/orderInfo/interceptBack/${row.orderId}`)
  526. });
  527. }
  528. //物流签收
  529. function handleLogisticsSigning(row) {
  530. messageBoxConfirm({
  531. message: '确认签收?',
  532. fetch: () =>
  533. proxy.$http.post('/order/orderInfo/adminSigned', {
  534. orderIds: [row.orderId]
  535. })
  536. });
  537. }
  538. //快递签收
  539. function handleSignDelivery(row) {
  540. messageBoxConfirm({
  541. message: '确认快递签收?',
  542. fetch: () =>
  543. proxy.$http.post('/order/orderInfo/adminDeliverySigned', {
  544. orderId: row.orderId
  545. })
  546. });
  547. }
  548. //物流揽件
  549. function materialPickup(row) {
  550. messageBoxConfirm({
  551. message: '确认物流揽件?',
  552. fetch: () =>
  553. proxy.$http.post('/order/orderInfo/adminPickup', {
  554. orderIds: [row.orderId]
  555. })
  556. });
  557. }
  558. //申请订单理赔
  559. const applyForOrderClaimRef = ref(null);
  560. function handleApplyForOrderClaim(row) {
  561. applyForOrderClaimRef.value?.handleOpen(row);
  562. }
  563. //售后补款
  564. const afterSalesPaymentRef = ref(null);
  565. function handleAfterSalesPayment(row) {
  566. afterSalesPaymentRef.value?.handleOpen(row);
  567. }
  568. //确认收货
  569. function handleConfirmReceipt(row) {
  570. const rows = row == null ? selections.value : [row];
  571. if (!rows.length) {
  572. EleMessage.error('请至少选择一条数据');
  573. return;
  574. }
  575. messageBoxConfirm({
  576. message: '确认收货?',
  577. fetch: () =>
  578. proxy.$http.post('/order/orderInfo/adminConfirm', {
  579. orderIds: rows.map((item) => item.orderId)
  580. })
  581. });
  582. }
  583. //订单详情
  584. const orderDetailRef = ref(null);
  585. function toOrderDetail(row) {
  586. orderDetailRef.value?.handleOpen(row);
  587. }
  588. //初审
  589. const firstCheckRef = ref(null);
  590. function handleFirstCheck(row) {
  591. const rows = row == null ? selections.value : [row];
  592. if (!rows.length) {
  593. EleMessage.error('请至少选择一条数据');
  594. return;
  595. }
  596. let orderIds = rows.map((item) => item.orderId).join(',');
  597. firstCheckRef.value?.handleOpen(orderIds);
  598. }
  599. //修改地址
  600. const modifyAddressRef = ref(null);
  601. function handleModifyAddress(row) {
  602. modifyAddressRef.value?.handleOpen(row);
  603. }
  604. //订单日志
  605. const orderLogRef = ref(null);
  606. function openOrderLog(row) {
  607. orderLogRef.value?.handleOpen(row.orderId);
  608. }
  609. //用户标签
  610. const userTagRef = ref(null);
  611. function openEditUserTag(row) {
  612. userTagRef.value?.handleOpen(row);
  613. }
  614. function handleBatchPayment(row) {
  615. const rows = row == null ? selections.value : [row];
  616. console.log(row, rows, 'xxxx');
  617. if (!rows.length) {
  618. EleMessage.error('请至少选择一条数据');
  619. return;
  620. }
  621. messageBoxConfirm({
  622. message: '确认支付书款?',
  623. fetch: () =>
  624. proxy.$http.post('/order/orderInfo/payout', {
  625. orderIds: rows.map((item) => item.orderId)
  626. })
  627. });
  628. }
  629. //回退状态
  630. function fallbackOrder(row) {
  631. messageBoxConfirm({
  632. message: '确认回退?',
  633. fetch: () =>
  634. proxy.$http.post(`/order/orderInfo/statusBack/${row.orderId}`)
  635. });
  636. }
  637. //审核截图
  638. const auditScreenshotRef = ref(null);
  639. function handleAuditScreenshot(row) {
  640. auditScreenshotRef.value?.handleOpen(row);
  641. }
  642. defineExpose({
  643. selections,
  644. reload,
  645. exportData,
  646. operatBatch,
  647. handleFirstCheck,
  648. handleConfirmReceipt,
  649. handleCancelOrder,
  650. handleBatchPayment
  651. });
  652. </script>