index.vue 19 KB

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