index.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597
  1. <template>
  2. <el-card class="box-card">
  3. <byTable
  4. :source="sourceList.data"
  5. :pagination="sourceList.pagination"
  6. :config="config"
  7. :loading="loading"
  8. :searchConfig="searchConfig"
  9. highlight-current-row
  10. @get-list="getList"
  11. @clickReset="clickReset">
  12. <template #code="{ item }">
  13. <div>
  14. <a style="color: #409eff; cursor: pointer; word-break: break-all" @click="clickCode(item)">{{ item.code }}</a>
  15. </div>
  16. </template>
  17. <template #address="{ item }">
  18. <div>{{ item.province }}, {{ item.city }}, {{ item.county }}, {{ item.detailedAddress }}</div>
  19. </template>
  20. </byTable>
  21. <el-dialog title="售后类型" v-if="openAfterSale" v-model="openAfterSale" width="300px" style="margin-top: 20vh !important">
  22. <template #footer>
  23. <el-button type="primary" @click="applyForAfterSale(1)" size="large" v-preReClick>退 货</el-button>
  24. <el-button @click="applyForAfterSale(2)" size="large" v-preReClick>换 货</el-button>
  25. </template>
  26. </el-dialog>
  27. <el-dialog title="送货单" v-if="openDeliveryNote" v-model="openDeliveryNote" width="1000px">
  28. <DeliveryNote :rowData="rowData" @clickCancel="clickCancel"></DeliveryNote>
  29. </el-dialog>
  30. <el-dialog title="产品包装配置" v-if="openShippingPackage" v-model="openShippingPackage" width="80%" :close-on-press-escape="false" :show-close="false">
  31. <div style="height: calc(100vh - 184px); overflow-y: auto; overflow-x: hidden" v-loading="loadingPackage">
  32. <el-form :model="formData.data" :rules="rulesShippingPackage" ref="shippingPackage">
  33. <div style="font-weight: 700; margin: 20px 0 10px 0">发货包装</div>
  34. <div style="margin-bottom: 10px">
  35. <el-button type="primary" size="small" @click="clickExpressPacking()">选择包材</el-button>
  36. </div>
  37. <el-table :data="formData.data.orderPackageBomList" :row-style="{ height: '35px' }" header-row-class-name="tableHeader">
  38. <el-table-column label="品号" prop="code" width="160" />
  39. <el-table-column label="品名" prop="name" min-width="220" />
  40. <el-table-column label="销售单价" prop="internalSellingPrice" width="100" />
  41. <el-table-column label="数量" width="120">
  42. <template #default="{ row, $index }">
  43. <div class="shippingPackage">
  44. <el-form-item
  45. :prop="'orderPackageBomList.' + $index + '.quantity'"
  46. :rules="rulesShippingPackage.quantity"
  47. :inline-message="true"
  48. style="width: 100%">
  49. <el-input-number
  50. onmousewheel="return false;"
  51. v-model="row.quantity"
  52. placeholder="修正数量"
  53. style="width: 100%"
  54. :controls="false"
  55. :min="0"
  56. :precision="0" />
  57. </el-form-item>
  58. </div>
  59. </template>
  60. </el-table-column>
  61. <el-table-column label="销售小计" width="120">
  62. <template #default="{ row }">
  63. {{ moneyFormat(computePackagingMoney(row, "internalSellingPrice"), 2) }}
  64. </template>
  65. </el-table-column>
  66. <el-table-column label="操作" align="center" fixed="right" width="80">
  67. <template #default="{ $index }">
  68. <el-button type="danger" @click="clickPackagingDelete($index)" text>删除</el-button>
  69. </template>
  70. </el-table-column>
  71. </el-table>
  72. <div style="font-weight: 700; margin: 20px 0 10px 0">外箱不干胶图稿</div>
  73. <div style="display: flex; width: 100%">
  74. <div style="width: 80px; line-height: 32px">不干胶图片:</div>
  75. <div style="width: calc(100% - 80px)">
  76. <el-image
  77. fit="scale-down"
  78. style="width: 148px; height: 148px; margin-right: 10px; cursor: pointer"
  79. v-if="formData.data.outerBoxSelfAdhesiveStickerFile && formData.data.outerBoxSelfAdhesiveStickerFile.fileUrl"
  80. :src="formData.data.outerBoxSelfAdhesiveStickerFile.fileUrl"
  81. @click="openFile(formData.data.outerBoxSelfAdhesiveStickerFile.fileUrl)" />
  82. <div style="display: flex">
  83. <el-upload
  84. :show-file-list="false"
  85. action="https://winfaster.obs.cn-south-1.myhuaweicloud.com"
  86. :data="uploadAdhesiveData"
  87. :before-upload="uploadAdhesiveFile"
  88. :on-success="
  89. (response, uploadFile) => {
  90. return handleAdhesivePackagingSuccess(uploadFile);
  91. }
  92. "
  93. style="width: 100%">
  94. <el-button type="primary" text>上传文件</el-button>
  95. </el-upload>
  96. </div>
  97. </div>
  98. </div>
  99. </el-form>
  100. </div>
  101. <template #footer>
  102. <el-button @click="openShippingPackage = false" v-preReClick>取 消</el-button>
  103. <el-button type="primary" @click="clickSaveShippingPackage" v-preReClick>提 交</el-button>
  104. </template>
  105. </el-dialog>
  106. <el-dialog title="选择快递包装" v-if="openExpressPacking" v-model="openExpressPacking" width="90%">
  107. <SelectBOM :selectStatus="true" :bomClassifyIdList="[2, 3]" @selectBOM="selectExpressPacking"></SelectBOM>
  108. <template #footer>
  109. <el-button @click="openExpressPacking = false">关 闭</el-button>
  110. </template>
  111. </el-dialog>
  112. </el-card>
  113. </template>
  114. <script setup>
  115. import byTable from "/src/components/byTable/index";
  116. import DeliveryNote from "/src/components/order/deliveryNote/index";
  117. import SelectBOM from "/src/views/group/BOM/management/index";
  118. import { ElMessage, ElMessageBox } from "element-plus";
  119. const { proxy } = getCurrentInstance();
  120. const departmentList = ref([{ dictKey: "0", dictValue: "胜德体育" }]);
  121. const sourceList = ref({
  122. data: [],
  123. pagination: {
  124. total: 0,
  125. pageNum: 1,
  126. pageSize: 10,
  127. departmentId: "",
  128. code: "",
  129. wlnCode: "",
  130. status: "",
  131. settlementStatus: "",
  132. exception: "0",
  133. },
  134. });
  135. const loading = ref(false);
  136. const searchConfig = computed(() => {
  137. return [
  138. {
  139. type: "input",
  140. prop: "code",
  141. label: "订单号",
  142. },
  143. {
  144. type: "input",
  145. prop: "wlnCode",
  146. label: "E10单号",
  147. },
  148. {
  149. type: "select",
  150. prop: "departmentId",
  151. data: departmentList.value,
  152. label: "事业部",
  153. },
  154. {
  155. type: "select",
  156. prop: "status",
  157. dictKey: "order_status",
  158. label: "订单状态",
  159. },
  160. ];
  161. });
  162. const config = computed(() => {
  163. return [
  164. {
  165. attrs: {
  166. label: "事业部",
  167. prop: "departmentName",
  168. width: 120,
  169. },
  170. },
  171. {
  172. attrs: {
  173. label: "订单号",
  174. slot: "code",
  175. "min-width": 200,
  176. },
  177. },
  178. {
  179. attrs: {
  180. label: "E10单号",
  181. prop: "wlnCode",
  182. "min-width": 180,
  183. },
  184. },
  185. {
  186. attrs: {
  187. label: "快递单号",
  188. prop: "expressDeliveryCode",
  189. "min-width": 160,
  190. },
  191. },
  192. {
  193. attrs: {
  194. label: "订单状态",
  195. prop: "status",
  196. width: 120,
  197. },
  198. render(val) {
  199. return proxy.dictKeyValue(val, proxy.useUserStore().allDict["order_status"]);
  200. },
  201. },
  202. {
  203. attrs: {
  204. label: "交期",
  205. prop: "deliveryTime",
  206. width: 160,
  207. align: "center",
  208. },
  209. },
  210. {
  211. attrs: {
  212. label: "发货时间",
  213. prop: "shippingTime",
  214. width: 160,
  215. align: "center",
  216. },
  217. },
  218. {
  219. attrs: {
  220. label: "收货人",
  221. prop: "consignee",
  222. width: 140,
  223. },
  224. },
  225. {
  226. attrs: {
  227. label: "收货人电话",
  228. prop: "consigneeNumber",
  229. width: 140,
  230. },
  231. },
  232. {
  233. attrs: {
  234. label: "收货人地址",
  235. slot: "address",
  236. "min-width": 220,
  237. },
  238. },
  239. {
  240. attrs: {
  241. label: "操作",
  242. width: 220,
  243. align: "center",
  244. fixed: "right",
  245. },
  246. renderHTML(row) {
  247. return [
  248. judgeRoles()
  249. ? {
  250. attrs: {
  251. label: "修改包装配置",
  252. type: "primary",
  253. text: true,
  254. },
  255. el: "button",
  256. click() {
  257. clickChangePackaging(row);
  258. },
  259. }
  260. : {},
  261. [40, 50].includes(row.status)
  262. ? {
  263. attrs: {
  264. label: "售后",
  265. type: "primary",
  266. text: true,
  267. },
  268. el: "button",
  269. click() {
  270. clickAfterSale(row);
  271. },
  272. }
  273. : {},
  274. row.type === 1 && row.status == 40
  275. ? {
  276. attrs: {
  277. label: "送货单",
  278. type: "primary",
  279. text: true,
  280. },
  281. el: "button",
  282. click() {
  283. clickDeliveryNote(row);
  284. },
  285. }
  286. : {},
  287. row.status == 20
  288. ? {
  289. attrs: {
  290. label: "挂起",
  291. type: "primary",
  292. text: true,
  293. },
  294. el: "button",
  295. click() {
  296. clickHangUp(row);
  297. },
  298. }
  299. : {},
  300. row.status == 60
  301. ? {
  302. attrs: {
  303. label: "取消挂起",
  304. type: "primary",
  305. text: true,
  306. },
  307. el: "button",
  308. click() {
  309. clickCancelHangUp(row);
  310. },
  311. }
  312. : {},
  313. ];
  314. },
  315. },
  316. ];
  317. });
  318. const getDemandData = () => {
  319. proxy.post("/department/page", { pageNum: 1, pageSize: 999 }).then((res) => {
  320. if (res.rows && res.rows.length > 0) {
  321. departmentList.value = departmentList.value.concat(
  322. res.rows.map((item) => {
  323. return {
  324. dictKey: item.id,
  325. dictValue: item.name,
  326. };
  327. })
  328. );
  329. }
  330. });
  331. };
  332. getDemandData();
  333. const getList = async (req, status) => {
  334. if (status) {
  335. sourceList.value.pagination = {
  336. pageNum: sourceList.value.pagination.pageNum,
  337. pageSize: sourceList.value.pagination.pageSize,
  338. exception: "0",
  339. };
  340. } else {
  341. sourceList.value.pagination = { ...sourceList.value.pagination, ...req };
  342. }
  343. loading.value = true;
  344. proxy.post("/orderInfo/page", sourceList.value.pagination).then((res) => {
  345. sourceList.value.data = res.rows;
  346. sourceList.value.pagination.total = res.total;
  347. setTimeout(() => {
  348. loading.value = false;
  349. }, 200);
  350. });
  351. };
  352. getList();
  353. const clickReset = () => {
  354. getList("", true);
  355. };
  356. const clickCode = (row) => {
  357. proxy.$router.replace({
  358. path: "/addOrder",
  359. query: {
  360. detailId: row.id,
  361. text: "订单详情",
  362. random: proxy.random(),
  363. orderInquiry: true,
  364. },
  365. });
  366. };
  367. const openAfterSale = ref(false);
  368. const rowData = ref({});
  369. const clickAfterSale = (row) => {
  370. rowData.value = row;
  371. openAfterSale.value = true;
  372. };
  373. const applyForAfterSale = (type) => {
  374. openAfterSale.value = false;
  375. proxy.$router.replace({
  376. path: "/order/after-sale/initiate",
  377. query: {
  378. orderInfoId: rowData.value.id,
  379. type: type,
  380. random: proxy.random(),
  381. },
  382. });
  383. };
  384. const openDeliveryNote = ref(false);
  385. const clickDeliveryNote = (row) => {
  386. rowData.value = row;
  387. openDeliveryNote.value = true;
  388. };
  389. const clickCancel = (status) => {
  390. openDeliveryNote.value = false;
  391. if (status) {
  392. getList();
  393. }
  394. };
  395. const clickHangUp = (row) => {
  396. ElMessageBox.confirm("你是否确认此操作", "提示", {
  397. confirmButtonText: "确定",
  398. cancelButtonText: "取消",
  399. type: "warning",
  400. })
  401. .then(() => {
  402. proxy.post("/orderInfo/suspendOrder", { id: row.id }).then(() => {
  403. ElMessage({ message: "操作成功", type: "success" });
  404. getList();
  405. });
  406. })
  407. .catch(() => {});
  408. };
  409. const clickCancelHangUp = (row) => {
  410. ElMessageBox.confirm("你是否确认此操作", "提示", {
  411. confirmButtonText: "确定",
  412. cancelButtonText: "取消",
  413. type: "warning",
  414. })
  415. .then(() => {
  416. proxy.post("/orderInfo/cancelSuspendOrder", { id: row.id }).then(() => {
  417. ElMessage({ message: "操作成功", type: "success" });
  418. getList();
  419. });
  420. })
  421. .catch(() => {});
  422. };
  423. const formData = reactive({
  424. data: {
  425. orderPackageBomList: [],
  426. outerBoxSelfAdhesiveStickerFile: {},
  427. },
  428. });
  429. const rulesShippingPackage = ref({
  430. quantity: [{ required: true, message: "请输入数量", trigger: "blur" }],
  431. });
  432. const openShippingPackage = ref(false);
  433. const loadingPackage = ref(false);
  434. const clickChangePackaging = (row) => {
  435. loadingPackage.value = true;
  436. openShippingPackage.value = true;
  437. proxy.post("/orderInfo/detail", { id: row.id }).then(
  438. (res) => {
  439. formData.data = res;
  440. proxy.post("/fileInfo/getList", { businessIdList: [formData.data.id] }).then((fileObj) => {
  441. if (fileObj[formData.data.id] && fileObj[formData.data.id].length > 0) {
  442. let outerBoxSelfAdhesiveStickerFile = fileObj[formData.data.id].filter((item) => item.businessType == "1");
  443. if (outerBoxSelfAdhesiveStickerFile && outerBoxSelfAdhesiveStickerFile.length > 0) {
  444. formData.data.outerBoxSelfAdhesiveStickerFile = outerBoxSelfAdhesiveStickerFile[0];
  445. } else {
  446. formData.data.outerBoxSelfAdhesiveStickerFile = {};
  447. }
  448. }
  449. });
  450. loadingPackage.value = false;
  451. },
  452. (err) => {
  453. console.log(err);
  454. loadingPackage.value = false;
  455. }
  456. );
  457. };
  458. const computePackagingMoney = (item, label) => {
  459. let money = 0;
  460. if (item.quantity && item[label]) {
  461. money = Number(Math.round(item.quantity * item[label] * 100) / 100);
  462. }
  463. return money;
  464. };
  465. const clickPackagingDelete = (index) => {
  466. formData.data.orderPackageBomList.splice(index, 1);
  467. };
  468. const openFile = (path) => {
  469. window.open(path);
  470. };
  471. const uploadAdhesiveData = ref({});
  472. const uploadAdhesiveFile = async (file) => {
  473. const res = await proxy.post("/fileInfo/getSing", { fileName: file.name });
  474. uploadAdhesiveData.value = res.uploadBody;
  475. file.id = res.id;
  476. file.fileName = res.fileName;
  477. file.fileUrl = res.fileUrl;
  478. return true;
  479. };
  480. const handleAdhesivePackagingSuccess = (UploadFile) => {
  481. formData.data.outerBoxSelfAdhesiveStickerFile = {
  482. id: UploadFile.raw.id,
  483. fileName: UploadFile.raw.fileName,
  484. fileUrl: UploadFile.raw.fileUrl,
  485. };
  486. };
  487. const clickSaveShippingPackage = () => {
  488. proxy.$refs.shippingPackage.validate((valid) => {
  489. if (valid) {
  490. loadingPackage.value = true;
  491. if (formData.data.orderPackageBomList && formData.data.orderPackageBomList.length > 0) {
  492. proxy
  493. .post("/orderInfo/editOrderPackageBom", {
  494. id: formData.data.id,
  495. orderPackageBomList: formData.data.orderPackageBomList,
  496. outerBoxSelfAdhesiveStickerFile: formData.data.outerBoxSelfAdhesiveStickerFile,
  497. })
  498. .then(
  499. () => {
  500. ElMessage({ message: "提交成功", type: "success" });
  501. openShippingPackage.value = false;
  502. getList();
  503. },
  504. (err) => {
  505. console.log(err);
  506. loadingPackage.value = false;
  507. }
  508. );
  509. } else {
  510. ElMessageBox.confirm("是否确认无产品发货包装", "提示", {
  511. confirmButtonText: "确定",
  512. cancelButtonText: "取消",
  513. type: "warning",
  514. })
  515. .then(() => {
  516. proxy
  517. .post("/orderInfo/editOrderPackageBom", {
  518. id: formData.data.id,
  519. orderPackageBomList: formData.data.orderPackageBomList,
  520. outerBoxSelfAdhesiveStickerFile: formData.data.outerBoxSelfAdhesiveStickerFile,
  521. })
  522. .then(
  523. () => {
  524. ElMessage({ message: "提交成功", type: "success" });
  525. openShippingPackage.value = false;
  526. getList();
  527. },
  528. (err) => {
  529. console.log(err);
  530. loadingPackage.value = false;
  531. }
  532. );
  533. })
  534. .catch(() => {});
  535. }
  536. }
  537. });
  538. };
  539. const openExpressPacking = ref(false);
  540. const clickExpressPacking = () => {
  541. openExpressPacking.value = true;
  542. };
  543. const selectExpressPacking = (data) => {
  544. if (formData.data.orderPackageBomList && formData.data.orderPackageBomList.length > 0) {
  545. let list = formData.data.orderPackageBomList.filter((item) => item.bomSpecId === data.id);
  546. if (list && list.length > 0) {
  547. return ElMessage("快递物流包材已添加");
  548. }
  549. formData.data.orderPackageBomList.push({
  550. bomSpecId: data.id,
  551. code: data.code,
  552. name: data.name,
  553. internalSellingPrice: data.internalSellingPrice,
  554. quantity: undefined,
  555. });
  556. } else {
  557. formData.data.orderPackageBomList = [
  558. {
  559. bomSpecId: data.id,
  560. code: data.code,
  561. name: data.name,
  562. internalSellingPrice: data.internalSellingPrice,
  563. quantity: undefined,
  564. },
  565. ];
  566. }
  567. ElMessage({ message: "添加成功", type: "success" });
  568. };
  569. const judgeRoles = () => {
  570. let status = true;
  571. if (proxy.useUserStore().user.roles && proxy.useUserStore().user.roles.length > 0) {
  572. let list = proxy.useUserStore().user.roles.filter((item) => ["factoryAdmin", "factoryLaser", "factoryPacker", "factoryZxy"].includes(item.roleKey));
  573. if (list && list.length > 0) {
  574. status = false;
  575. }
  576. }
  577. return status;
  578. };
  579. </script>
  580. <style lang="scss" scoped>
  581. :deep(.el-dialog) {
  582. margin-top: 10px !important;
  583. margin-bottom: 10px !important;
  584. }
  585. .shippingPackage {
  586. .el-form-item {
  587. margin-bottom: 0;
  588. }
  589. }
  590. </style>