order-page-all.vue 23 KB

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