index.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656
  1. <template>
  2. <div class="ele-body">
  3. <el-card shadow="never" v-loading="loading">
  4. <produceOrder-search
  5. @search="reload"
  6. ref="searchRef"
  7. :statusOpt="statusOpt"
  8. :planType="planType"
  9. :activeName="activeName"
  10. >
  11. </produceOrder-search>
  12. <el-tabs v-model="activeName" type="card">
  13. <el-tab-pane label="未完成工单" name="first"></el-tab-pane>
  14. <el-tab-pane label="已完成工单" name="second"></el-tab-pane>
  15. </el-tabs>
  16. <!-- 数据表格 -->
  17. <ele-pro-table
  18. ref="table"
  19. :key="activeName"
  20. :initLoad="false"
  21. :columns="columns"
  22. :datasource="datasource"
  23. row-key="code"
  24. :cache-key="`${activeName}produceOrderTable`"
  25. :selection.sync="selection"
  26. @sort-change="onSortChange"
  27. autoAmendPage
  28. >
  29. <!-- :parse-data="parseData" -->
  30. <template v-slot:toolbar>
  31. <el-button type="success">新建</el-button>
  32. <el-button type="success">暂停</el-button>
  33. <el-button type="success">终止</el-button>
  34. <!-- <el-button type="primary">工单刷新</el-button> -->
  35. <el-button type="success" @click="handlePicking">领料</el-button>
  36. <el-button type="success" @click="toEnd()">批量完结</el-button>
  37. <!-- <el-button type="success" @click="handleCreate">创建工单</el-button> -->
  38. <!-- <el-button type="success">工单操作控制</el-button> -->
  39. <el-button type="success" @click="allPrinting()"
  40. >批量打印二维码</el-button
  41. >
  42. </template>
  43. <template v-slot:code="{ row }">
  44. <el-link type="primary" :underline="false" @click="goDetail(row)">
  45. {{ row.code }}
  46. </el-link>
  47. </template>
  48. <template v-slot:QRcode="{ row }">
  49. <el-link type="primary" :underline="false" @click="handleQRcode(row)"
  50. >生成二维码
  51. </el-link>
  52. </template>
  53. <template v-slot:priority="{ row }">
  54. <el-input
  55. v-model="row.priority"
  56. type="number"
  57. size="mini"
  58. :min="0"
  59. :max="10"
  60. @change="priorityChange(row)"
  61. ></el-input>
  62. <el-popover
  63. placement="right"
  64. width="200"
  65. trigger="hover"
  66. content="数值越大优先级越高(0-3普通, 4-6优先, 7-10紧急)"
  67. >
  68. <div class="sort-wrap" slot="reference">
  69. <i class="el-icon-caret-top" @click="sortTop(row)"></i>
  70. <i class="el-icon-caret-bottom" @click="sortBottom(row)"></i>
  71. </div>
  72. </el-popover>
  73. </template>
  74. <template v-slot:formingNum="{ row }">
  75. <span >
  76. {{ row.formingNum }} {{ row.unit }}
  77. </span>
  78. </template>
  79. <template v-slot:formingWeight="{ row }">
  80. <span >
  81. {{ row.formingNum }} {{ row.weightUnit }}
  82. </span>
  83. </template>
  84. <template v-slot:status="{ row }">
  85. <span :class="{ 'ele-text-danger': row.status == 3 }">
  86. {{ statusFormatter(row.status) }}
  87. </span>
  88. </template>
  89. <!-- 操作列 -->
  90. <template v-slot:action="{ row }">
  91. <template v-if="activeName == 'second'">
  92. <el-link
  93. type="primary"
  94. :underline="false"
  95. icon="el-icon-truck"
  96. v-if="row.status == 6"
  97. @click="toCancel(row)"
  98. >
  99. 取消完结
  100. </el-link></template
  101. >
  102. <template v-if="activeName != 'second'">
  103. <el-link
  104. v-if="row.isSplit == 0"
  105. type="primary"
  106. :underline="false"
  107. icon="el-icon-truck"
  108. @click="handleOrderPublish(1, row)"
  109. >
  110. 报工
  111. </el-link>
  112. <el-link
  113. v-if="row.status == 4 && row.isSplit == 0 && !row.originalCode"
  114. type="primary"
  115. :underline="false"
  116. icon="el-icon-truck"
  117. @click="toUnpack(row)"
  118. >
  119. 拆分
  120. </el-link>
  121. <el-link
  122. v-if="row.isSplit == 0"
  123. type="primary"
  124. :underline="false"
  125. icon="el-icon-edit"
  126. @click="toEnd(row)"
  127. >
  128. 完结
  129. </el-link>
  130. </template>
  131. </template>
  132. </ele-pro-table>
  133. </el-card>
  134. <print ref="printRef"></print>
  135. <printSr ref="printSrRef"></printSr>
  136. <printTg ref="printTgRef"></printTg>
  137. <createDialog ref="createRef" @success="createSuccess" />
  138. <unpackDialog ref="unpackRef" @success="createSuccess" />
  139. <pickingDialog ref="PickingRef" />
  140. </div>
  141. </template>
  142. <script>
  143. import {
  144. getPage,
  145. batchCompletion,
  146. cancelCompletion,
  147. updatePriority
  148. } from '@/api/produceOrder/index.js';
  149. import produceOrderSearch from './components/produceOrder-search.vue';
  150. import createDialog from './components/createDialog.vue';
  151. import unpackDialog from './components/unpackDialog.vue';
  152. import pickingDialog from './components/pickingDialog.vue';
  153. import print from './components/print.vue';
  154. import printSr from './components/printSr';
  155. import printTg from './components/printTg';
  156. import { debounce } from 'lodash';
  157. export default {
  158. components: {
  159. produceOrderSearch,
  160. pickingDialog,
  161. createDialog,
  162. unpackDialog,
  163. print,
  164. printSr,
  165. printTg
  166. },
  167. data() {
  168. return {
  169. activeName: 'first',
  170. // 加载状态
  171. loading: false,
  172. pageType: 'add',
  173. dialogTitle: '',
  174. isBindPlan: false,
  175. statusOpt: {
  176. first: [
  177. { label: '所有状态', value: '5,4' },
  178. { label: '待生产', value: '4' },
  179. { label: '生产中', value: '5' }
  180. // { label: '已延期', value: '7' }
  181. ],
  182. second: [{ label: '已完成', value: '6' }]
  183. },
  184. planType: [
  185. { label: '所有计划类型', value: null },
  186. { label: '内销计划', value: '1' },
  187. { label: '外销计划', value: '2' },
  188. { label: '预制计划', value: '3' }
  189. ],
  190. selection: []
  191. };
  192. },
  193. computed: {
  194. // 表格列配置
  195. columns() {
  196. const opt = {
  197. first: [
  198. // {
  199. // prop: 'deliveryTime',
  200. // label: '预测交货日期',
  201. // align: 'center',
  202. // showOverflowTooltip: true,
  203. // minWidth: 110
  204. // }
  205. ],
  206. second: [
  207. {
  208. prop: 'completeTime',
  209. label: '完成时间',
  210. align: 'center'
  211. },
  212. {
  213. prop: 'cycle',
  214. label: '生产周期',
  215. align: 'center'
  216. }
  217. ]
  218. };
  219. return [
  220. {
  221. width: 45,
  222. type: 'selection',
  223. columnKey: 'selection',
  224. align: 'center',
  225. fixed: 'left'
  226. },
  227. {
  228. slot: 'code',
  229. label: '生产工单号',
  230. align: 'center',
  231. minWidth: 110
  232. },
  233. // {
  234. // prop: 'originalCode',
  235. // label: '原始工单号',
  236. // align: 'center',
  237. // minWidth: 110
  238. // },
  239. {
  240. slot: 'QRcode',
  241. label: '二维码',
  242. align: 'center',
  243. minWidth: 110
  244. },
  245. {
  246. prop: 'productionPlanCode',
  247. label: '计划编号',
  248. align: 'center',
  249. minWidth: 110
  250. },
  251. {
  252. prop: 'planType',
  253. label: '计划类型',
  254. align: 'center',
  255. formatter: (row) => {
  256. const obj = this.planType.find((i) => i.value == row.planType);
  257. return obj && obj.label;
  258. }
  259. },
  260. {
  261. prop: 'produceRoutingName',
  262. label: '工艺路线',
  263. align: 'center'
  264. },
  265. {
  266. prop: 'productCode',
  267. label: '物料编号',
  268. align: 'center'
  269. },
  270. {
  271. prop: 'productName',
  272. label: '产品名称',
  273. align: 'center'
  274. },
  275. {
  276. prop: 'brandNo',
  277. label: '牌号',
  278. align: 'center'
  279. },
  280. {
  281. prop: 'model',
  282. label: '型号',
  283. align: 'center'
  284. },
  285. {
  286. prop: 'batchNo',
  287. label: '批号',
  288. align: 'center',
  289. minWidth: 100,
  290. showOverflowTooltip: true
  291. },
  292. {
  293. prop: 'priority',
  294. label: '优先级',
  295. align: 'center',
  296. minWidth: 120,
  297. slot: 'priority',
  298. sortable: 'custom'
  299. },
  300. {
  301. prop: 'formingNum',
  302. label: '要求生产数量',
  303. align: 'center',
  304. slot: 'formingNum',
  305. showOverflowTooltip: true,
  306. minWidth: 110
  307. },
  308. {
  309. prop: 'formingWeight',
  310. label: '要求生产重量',
  311. slot: 'formingWeight',
  312. align: 'center',
  313. showOverflowTooltip: true,
  314. minWidth: 110
  315. },
  316. {
  317. prop: 'formedNum',
  318. label: '已生产数量',
  319. align: 'center',
  320. showOverflowTooltip: true,
  321. minWidth: 110
  322. },
  323. {
  324. prop: 'formedWeight',
  325. label: '已生产重量',
  326. align: 'center',
  327. showOverflowTooltip: true,
  328. minWidth: 110
  329. },
  330. {
  331. prop: 'planStartTime',
  332. label: '计划开始时间',
  333. align: 'center',
  334. showOverflowTooltip: true,
  335. minWidth: 110
  336. },
  337. {
  338. prop: 'planCompleteTime',
  339. label: '计划结束时间',
  340. align: 'center',
  341. showOverflowTooltip: true,
  342. minWidth: 110
  343. },
  344. {
  345. prop: 'startTime',
  346. label: '实际开始时间',
  347. align: 'center',
  348. showOverflowTooltip: true,
  349. minWidth: 110
  350. },
  351. ...opt[this.activeName],
  352. {
  353. prop: 'createTime',
  354. label: '创建时间',
  355. align: 'center',
  356. showOverflowTooltip: true,
  357. minWidth: 110
  358. },
  359. {
  360. slot: 'status',
  361. label: '状态',
  362. align: 'center',
  363. formatter: (row) => {
  364. const obj = this.statusOpt[this.activeName].find(
  365. (i) => i.value == row.status
  366. );
  367. return obj && obj.label;
  368. }
  369. },
  370. {
  371. prop: 'teamName',
  372. label: '班组',
  373. align: 'center',
  374. showOverflowTooltip: true
  375. },
  376. {
  377. columnKey: 'action',
  378. label: '操作',
  379. width: 250,
  380. align: 'center',
  381. resizable: false,
  382. fixed: 'right',
  383. slot: 'action',
  384. showOverflowTooltip: true
  385. }
  386. ];
  387. },
  388. clientEnvironmentId() {
  389. return this.$store.state.user.info.clientEnvironmentId;
  390. }
  391. },
  392. // created(){
  393. // console.log('positiveIntegerReg',positiveIntegerReg)
  394. // },
  395. methods: {
  396. handlePicking() {
  397. this.$router.push({
  398. path: '/produceOrder/picking'
  399. });
  400. },
  401. statusFormatter(status) {
  402. const obj = this.statusOpt[this.activeName].find(
  403. (i) => i.value == status
  404. );
  405. return obj && obj.label;
  406. },
  407. /* 表格数据源 */
  408. async datasource({ page, limit, where, order }) {
  409. let res = await getPage({
  410. ...where,
  411. ...order,
  412. pageNum: page,
  413. size: limit,
  414. ...this.sort
  415. });
  416. // res['list'] = this.flattenArray(res.list)
  417. return res;
  418. },
  419. onSortChange(e) {
  420. let sort = {
  421. orderBy: e.order,
  422. sortName: e.prop
  423. };
  424. this.sort = sort;
  425. this.reload();
  426. },
  427. flattenArray(arr) {
  428. var result = []; // 存放结果的数组
  429. for (let i = 0; i < arr.length; i++) {
  430. if (Array.isArray(arr[i].subWorkOrder)) {
  431. let _arr = [];
  432. _arr = _arr.concat(arr[i].subWorkOrder);
  433. delete arr[i].subWorkOrder;
  434. result.push(arr[i]);
  435. result.push(..._arr);
  436. } else {
  437. result.push(arr[i]);
  438. }
  439. }
  440. return result;
  441. },
  442. /* 数据转为树形结构 */
  443. parseData(data) {
  444. console.log(99, data);
  445. return this.$util.toTreeData({
  446. data: data.list,
  447. count: data.total,
  448. idField: 'code',
  449. parentIdField: 'originalCode'
  450. });
  451. },
  452. /* 数据转为树形结构 */
  453. createSuccess() {
  454. this.reload();
  455. },
  456. handleCreate() {
  457. this.$refs.createRef.open(0);
  458. },
  459. // 发布工单
  460. handleOrderPublish(type, row) {
  461. this.$router.push({
  462. path: '/produceOrder/report',
  463. query: {
  464. type,
  465. id: row.id
  466. }
  467. });
  468. },
  469. // 完结与批量完结
  470. toEnd(row) {
  471. if (row) {
  472. this.$confirm(`是否要完结工单【${row.code}】?`, '提醒', {
  473. confirmButtonText: '确认',
  474. cancelButtonText: '取消',
  475. type: 'warning'
  476. })
  477. .then(() => {
  478. batchCompletion([row.id]).then((res) => {
  479. this.$message.success('成功');
  480. this.reload();
  481. });
  482. })
  483. .catch(() => {});
  484. } else {
  485. if (!this.selection.length) {
  486. return this.$message.warning('请至少选择一条工单!');
  487. }
  488. const ids = [];
  489. this.selection.map((item) => {
  490. ids.push(item.id);
  491. });
  492. const h = this.$createElement;
  493. this.$msgbox({
  494. title: '提醒',
  495. message: h('p', null, [
  496. h('span', null, '是否要完结 '),
  497. h(
  498. 'span',
  499. { style: 'color: #70B603' },
  500. `${this.selection.length}`
  501. ),
  502. h('span', null, ' 条工单?')
  503. ]),
  504. showCancelButton: true,
  505. confirmButtonText: '确认',
  506. cancelButtonText: '取消',
  507. type: 'warning'
  508. })
  509. .then(() => {
  510. batchCompletion(ids).then((res) => {
  511. this.$message.success('成功');
  512. this.reload();
  513. });
  514. })
  515. .catch(() => {});
  516. }
  517. },
  518. // 取消完结
  519. toCancel(row) {
  520. cancelCompletion([row.id]).then((res) => {
  521. this.$message.success('成功');
  522. this.reload();
  523. });
  524. },
  525. // 拆分
  526. toUnpack(row) {
  527. this.$refs.unpackRef.open(row);
  528. },
  529. handleTabChange() {
  530. this.$refs.searchRef.reset();
  531. },
  532. /* 刷新表格 */
  533. reload(where = {}) {
  534. this.$nextTick(() => {
  535. where.statusList = (
  536. where.status || this.statusOpt[this.activeName][0].value
  537. ).split(',');
  538. this.$refs.table.reload({ page: 1, where });
  539. });
  540. },
  541. goDetail(row) {
  542. this.$router.push({
  543. path: '/produceOrder/detail/' + row.id,
  544. query: {
  545. produceVersionId: row.produceVersionId
  546. }
  547. });
  548. },
  549. handleDelete({ id }) {
  550. this.$confirm('确定删除当前数据?', '提示').then(async () => {
  551. await del(id);
  552. this.$message.success('删除成功!');
  553. this.reload();
  554. });
  555. },
  556. handleQRcode(row) {
  557. if (this.clientEnvironmentId == 2) {
  558. this.$refs.printSrRef.open([row.id]);
  559. } else if (this.clientEnvironmentId == 3) {
  560. this.$refs.printTgRef.open([row.id]);
  561. } else {
  562. this.$refs.printRef.open([row.id]);
  563. }
  564. },
  565. allPrinting() {
  566. let ids = this.findAllIds(this.selection);
  567. if (this.clientEnvironmentId == 2) {
  568. this.$refs.printSrRef.open(ids);
  569. } else if (this.clientEnvironmentId == 3) {
  570. this.$refs.printTgRef.open(ids);
  571. } else {
  572. this.$refs.printRef.open(ids);
  573. }
  574. },
  575. findAllIds(nodes) {
  576. let ids = [];
  577. nodes.forEach((node) => {
  578. ids.push(node.id); // 添加当前节点的id
  579. if (node.children && node.children.length > 0) {
  580. // 递归调用自身来处理子节点
  581. ids = ids.concat(this.findAllIds(node.children));
  582. }
  583. });
  584. return ids;
  585. },
  586. sortTop(row) {
  587. row.priority = Number(row.priority) + 1;
  588. this.priorityChange(row);
  589. },
  590. sortBottom(row) {
  591. if (row.priority <= 1) {
  592. return;
  593. }
  594. row.priority = Number(row.priority) - 1;
  595. this.priorityChange(row);
  596. },
  597. priorityChange(row) {
  598. if (row.priority > 10) {
  599. row.priority = 10; // 如果大于 10,则设置为 10
  600. } else if (row.priority < 0) {
  601. row.priority = 0; // 如果小于 0,则设置为 0
  602. }
  603. this.priorityFn(row);
  604. },
  605. priorityFn: debounce(function (row) {
  606. let params = {
  607. id: row.id,
  608. priority: row.priority
  609. };
  610. updatePriority(params).then((res) => {});
  611. }, 800)
  612. }
  613. };
  614. </script>