index.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599
  1. <template>
  2. <div class="ele-body">
  3. <el-card shadow="never" v-loading="loading">
  4. <productionPlan-search
  5. @search="reload"
  6. ref="searchRef"
  7. :statusOpt="statusOpt"
  8. :planType="planType"
  9. :activeName="activeName"
  10. >
  11. </productionPlan-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-tab-pane label="已变更" name="change"></el-tab-pane>
  16. </el-tabs>
  17. <!-- 数据表格 -->
  18. <ele-pro-table
  19. ref="table"
  20. :key="activeName"
  21. :initLoad="false"
  22. :columns="newColumns"
  23. :datasource="datasource"
  24. height="calc(100vh - 335px)"
  25. :cache-key="`${activeName}ProductionPlanTable`"
  26. @sort-change="onSortChange"
  27. >
  28. <template v-slot:code="{ row }">
  29. <el-link type="primary" :underline="false" @click="goDetail(row)">
  30. {{ row.code }}
  31. </el-link>
  32. </template>
  33. <template v-slot:priority="{ row }">
  34. <el-input
  35. v-model="row.priority"
  36. type="number"
  37. size="mini"
  38. :min="0"
  39. :max="10"
  40. @change="priorityChange(row)"
  41. ></el-input>
  42. <el-popover
  43. placement="right"
  44. width="200"
  45. trigger="hover"
  46. content="数值越大优先级越高(0-3普通, 4-6优先, 7-10紧急)"
  47. >
  48. <div class="sort-wrap" slot="reference">
  49. <i class="el-icon-caret-top" @click="sortTop(row)"></i>
  50. <i class="el-icon-caret-bottom" @click="sortBottom(row)"></i>
  51. </div>
  52. </el-popover>
  53. </template>
  54. <template v-slot:productWeight="{ row }">
  55. {{ row.productWeight }} {{ row.weightUnit }}
  56. </template>
  57. <template v-slot:newSumOrderWeight="{ row }">
  58. {{ row.newSumOrderWeight }} {{ row.newWeightUnit }}
  59. </template>
  60. <template v-slot:status="{ row }">
  61. <span :class="{ 'ele-text-danger': row.status == 3 }">
  62. {{ statusFormatter(row.status) }}
  63. </span>
  64. </template>
  65. <!-- 操作列 -->
  66. <template v-slot:action="{ row }">
  67. <el-link
  68. type="primary"
  69. :underline="false"
  70. icon="el-icon-truck"
  71. v-if="row.status == 2"
  72. @click="handleOrderPublish(1, row)"
  73. >
  74. 发布工单
  75. </el-link>
  76. <el-link
  77. type="primary"
  78. v-if="row.status == 3"
  79. :underline="false"
  80. icon="el-icon-truck"
  81. @click="handleOrderPublish(2, row)"
  82. >
  83. 重新发布
  84. </el-link>
  85. <el-link
  86. type="primary"
  87. :underline="false"
  88. icon="el-icon-edit"
  89. @click="planEdit(row)"
  90. >
  91. 修改计划
  92. </el-link>
  93. <el-link
  94. type="primary"
  95. :underline="false"
  96. @click="toUnpack(row)"
  97. >
  98. 拆批
  99. </el-link>
  100. <el-link
  101. type="danger"
  102. :underline="false"
  103. @click="handleDelete(row)"
  104. icon="el-icon-delete"
  105. >
  106. 删除
  107. </el-link>
  108. </template>
  109. </ele-pro-table>
  110. </el-card>
  111. <unpackDialog ref="unpackRef" @success="reload" />
  112. </div>
  113. </template>
  114. <script>
  115. import { getList, del, updatePriority } from '@/api/productionPlan/index.js';
  116. import productionPlanSearch from './components/productionPlan-search.vue';
  117. import unpackDialog from './components/unpackDialog.vue';
  118. import { release } from '@/api/productionPlan/order.js';
  119. import { getCode } from '@/api/codeManagement';
  120. import { fieldModel } from '@/api/saleOrder';
  121. import { debounce } from 'lodash';
  122. export default {
  123. components: {
  124. productionPlanSearch,
  125. unpackDialog
  126. },
  127. data() {
  128. return {
  129. activeName: 'first',
  130. // 加载状态
  131. loading: false,
  132. pageType: 'add',
  133. dialogTitle: '',
  134. isBindPlan: false,
  135. statusOpt: {
  136. first: [
  137. { label: '所有状态', value: '3,2' },
  138. { label: '待发布', value: '2' },
  139. { label: '发布失败', value: '3' }
  140. ],
  141. second: [
  142. { label: '所有状态', value: '7,4,5,6' },
  143. { label: '待生产', value: '4' },
  144. { label: '生产中', value: '5' },
  145. { label: '已完成', value: '6' },
  146. { label: '已延期', value: '7' }
  147. ], change: [
  148. { label: '已变更', value: '9' },
  149. ]
  150. },
  151. planType: [
  152. { label: '所有计划类型', value: null },
  153. { label: '内销计划', value: '1' },
  154. { label: '外销计划', value: '2' },
  155. { label: '预制计划', value: '3' }
  156. ], newColumns: []
  157. };
  158. },
  159. computed: {
  160. clientEnvironmentId() {
  161. return this.$store.state.user.info.clientEnvironmentId;
  162. },
  163. // 表格列配置
  164. columns() {
  165. const opt = {
  166. first: [
  167. // {
  168. // prop: 'deliveryTime',
  169. // label: '预测交货日期',
  170. // align: 'center',
  171. // showOverflowTooltip: true,
  172. // minWidth: 110
  173. // }
  174. ],
  175. second: [
  176. // {
  177. // prop: 'formingTime',
  178. // label: '实际生产日期',
  179. // align: 'center',
  180. // showOverflowTooltip: true,
  181. // minWidth: 110
  182. // },
  183. {
  184. prop: 'releaseTime',
  185. label: '工单发布日期',
  186. align: 'center',
  187. showOverflowTooltip: true,
  188. minWidth: 110
  189. },
  190. {
  191. prop: 'planFormingTime',
  192. label: '预测生产日期',
  193. align: 'center',
  194. showOverflowTooltip: true,
  195. minWidth: 110
  196. },
  197. {
  198. prop: 'deliveryTime',
  199. label: '预测交货日期',
  200. align: 'center',
  201. showOverflowTooltip: true,
  202. minWidth: 110
  203. },
  204. {
  205. prop: 'formingTime',
  206. label: '实际交货日期',
  207. align: 'center',
  208. showOverflowTooltip: true,
  209. minWidth: 110
  210. }
  211. ],
  212. change:[]
  213. };
  214. return [
  215. {
  216. columnKey: 'index',
  217. label: '序号',
  218. type: 'index',
  219. width: 55,
  220. align: 'center',
  221. showOverflowTooltip: true,
  222. fixed: 'left'
  223. },
  224. {
  225. slot: 'code',
  226. prop: 'code',
  227. action: 'code',
  228. label: '计划编号',
  229. align: 'center',
  230. showOverflowTooltip: true,
  231. minWidth: 180
  232. },
  233. {
  234. prop: 'productCode',
  235. label: '产品编码',
  236. align: 'center',
  237. showOverflowTooltip: true,
  238. minWidth: 140
  239. },
  240. {
  241. prop: 'productName',
  242. label: '产品名称',
  243. align: 'center',
  244. showOverflowTooltip: true,
  245. minWidth: 140
  246. },
  247. {
  248. prop: 'brandNo',
  249. label: '牌号',
  250. align: 'center',
  251. showOverflowTooltip: true
  252. },
  253. {
  254. prop: 'batchNo',
  255. label: '批号',
  256. align: 'center',
  257. minWidth: 100,
  258. showOverflowTooltip: true
  259. },
  260. {
  261. prop: 'specification',
  262. label: '规格',
  263. align: 'center',
  264. minWidth: 150,
  265. showOverflowTooltip: true
  266. },
  267. {
  268. prop: 'model',
  269. label: '型号',
  270. align: 'center',
  271. showOverflowTooltip: true
  272. },
  273. {
  274. prop: 'priority',
  275. label: '优先级',
  276. align: 'center',
  277. minWidth: 120,
  278. slot: 'priority',
  279. sortable: 'custom'
  280. },
  281. {
  282. prop: 'produceRoutingName',
  283. label: '工艺路线',
  284. align: 'center',
  285. minWidth: 120
  286. },
  287. {
  288. prop: 'productNum',
  289. label: '计划数量' + (this.clientEnvironmentId == '4' ? '(方)' : ''),
  290. align: 'center',
  291. showOverflowTooltip: true
  292. },
  293. {
  294. prop: 'productWeight',
  295. label: '计划重量',
  296. align: 'center',
  297. showOverflowTooltip: true,
  298. slot: 'productWeight'
  299. },
  300. {
  301. prop: 'requiredFormingNum',
  302. label:
  303. '要求生产数量' + (this.clientEnvironmentId == '4' ? '(方)' : ''),
  304. align: 'center',
  305. showOverflowTooltip: true
  306. },
  307. {
  308. prop: 'newSumOrderWeight',
  309. label: '要求生产重量',
  310. align: 'center',
  311. showOverflowTooltip: true,
  312. slot: 'newSumOrderWeight'
  313. },
  314. {
  315. prop: 'moCount',
  316. label: '模数',
  317. align: 'center',
  318. show: this.clientEnvironmentId == '4'
  319. },
  320. {
  321. prop: 'blockCount',
  322. label: '块数',
  323. align: 'center',
  324. show: this.clientEnvironmentId == '4'
  325. },
  326. {
  327. prop: 'noWordCount',
  328. label: '未排程块数',
  329. align: 'center',
  330. showOverflowTooltip: true,
  331. show: this.clientEnvironmentId == '4',
  332. minWidth: 110
  333. },
  334. {
  335. prop: 'reqMoldTime',
  336. label: '要求生产日期',
  337. align: 'center',
  338. showOverflowTooltip: true,
  339. minWidth: 110
  340. },
  341. ...opt[this.activeName],
  342. {
  343. prop: 'orderType',
  344. label: '计划类型',
  345. align: 'center',
  346. showOverflowTooltip: true,
  347. formatter: (row) => {
  348. const obj = this.planType.find((i) => i.value == row.planType);
  349. return obj && obj.label;
  350. }
  351. },{
  352. prop: 'version',
  353. label: '版本',
  354. align: 'center',
  355. showOverflowTooltip: true,
  356. minWidth: 80
  357. },
  358. {
  359. prop: 'createTime',
  360. label: '创建时间',
  361. align: 'center',
  362. showOverflowTooltip: true,
  363. minWidth: 110
  364. },
  365. {
  366. columnKey: 'status',
  367. slot: 'status',
  368. label: '状态',
  369. align: 'center',
  370. formatter: (row) => {
  371. const obj = this.statusOpt[this.activeName].find(
  372. (i) => i.value == row.status
  373. );
  374. return obj && obj.label;
  375. }
  376. },
  377. // ...(this.activeName === 'second'
  378. // ? [
  379. // {
  380. // prop: 'releaseTime',
  381. // label: '发布时间',
  382. // align: 'center',
  383. // showOverflowTooltip: true,
  384. // minWidth: 110
  385. // }
  386. // ]
  387. // : []),
  388. ];
  389. }
  390. },
  391. created() {
  392. this.getFieldModel();
  393. },
  394. methods: {
  395. statusFormatter(status) {
  396. const obj = this.statusOpt[this.activeName].find(
  397. (i) => i.value == status
  398. );
  399. return obj && obj.label;
  400. },
  401. /* 表格数据源 */
  402. datasource({ page, limit, where }) {
  403. return getList({
  404. pageNum: page,
  405. size: limit,
  406. ...where,
  407. ...this.sort
  408. });
  409. },
  410. // 发布工单
  411. handleOrderPublish(type, row) {
  412. if (!row.produceRoutingName) {
  413. return this.$message.error('请先选择工艺路线!');
  414. }
  415. this.$confirm('发布工单后不可撤回,确定发布吗?', '发布确认')
  416. .then(async () => {
  417. const loading = this.$loading({
  418. lock: true,
  419. fullscreen: true,
  420. text: '工单发布中...'
  421. });
  422. try {
  423. let code = row.workOrderCode;
  424. if (!code) {
  425. code = await getCode('product_order_code');
  426. }
  427. // 反显对象会报错 status
  428. const data = await release([row.id]);
  429. if (data || data === 0) {
  430. this.$message.success('发布成功!');
  431. } else {
  432. this.$message.error('发布失败,请重新发布!');
  433. }
  434. this.reload();
  435. } catch (error) {
  436. console.error(error);
  437. }
  438. loading.close();
  439. })
  440. .catch((err) => {
  441. console.error(err);
  442. });
  443. // this.$router.push({
  444. // path: '/productionPlan/workOrderPublish',
  445. // query: {
  446. // type,
  447. // id: row.id
  448. // }
  449. // });
  450. },
  451. // 修改计划
  452. planEdit({ id }) {
  453. this.$router.push({
  454. path: '/saleOrder/salesToProduction',
  455. query: {
  456. type: 'edit',
  457. id
  458. }
  459. });
  460. },
  461. getFieldModel() {
  462. fieldModel({ fieldModel: 't_main_category' }).then((res) => {
  463. const privateColumn = [];
  464. if (this.activeName == 'first') {
  465. privateColumn.push({
  466. columnKey: 'action',
  467. label: '操作',
  468. width: 250,
  469. align: 'center',
  470. resizable: false,
  471. fixed: 'right',
  472. slot: 'action',
  473. });
  474. } else {
  475. privateColumn = [];
  476. }
  477. let newRes = res.map((m) => {
  478. return {
  479. prop: 'extField.' + m.prop,
  480. label: m.label,
  481. align: 'center',
  482. showOverflowTooltip: true
  483. };
  484. });
  485. this.newColumns = [...this.columns, ...newRes, ...privateColumn];
  486. this.$forceUpdate();
  487. });
  488. },
  489. handleTabChange() {
  490. this.$refs.searchRef.reset();
  491. },
  492. /* 刷新表格 */
  493. reload(where) {
  494. this.$nextTick(() => {
  495. this.$refs.table.reload({ page: 1, where });
  496. });
  497. },
  498. goDetail({ id }) {
  499. this.$router.push({
  500. path: '/productionPlan/detail/' + id
  501. });
  502. },
  503. // 拆批
  504. toUnpack(row) {
  505. this.$refs.unpackRef.open(row);
  506. },
  507. handleDelete({ id }) {
  508. this.$confirm('确定删除当前数据?', '提示')
  509. .then(async () => {
  510. await del(id);
  511. this.$message.success('删除成功!');
  512. this.reload();
  513. })
  514. .catch((err) => {
  515. console.error(err);
  516. });
  517. },
  518. onSortChange(e) {
  519. let sort = {
  520. orderBy: e.order,
  521. sortName: e.prop
  522. };
  523. this.sort = sort;
  524. this.reload();
  525. },
  526. sortTop(row) {
  527. row.priority = Number(row.priority) + 1;
  528. this.priorityChange(row);
  529. },
  530. sortBottom(row) {
  531. if (row.priority <= 1) {
  532. return;
  533. }
  534. row.priority = Number(row.priority) - 1;
  535. this.priorityChange(row);
  536. },
  537. priorityChange(row) {
  538. if (row.priority > 10) {
  539. row.priority = 10; // 如果大于 10,则设置为 10
  540. } else if (row.priority < 0) {
  541. row.priority = 0; // 如果小于 0,则设置为 0
  542. }
  543. this.priorityFn(row);
  544. },
  545. priorityFn: debounce(function (row) {
  546. let params = {
  547. id: row.id,
  548. priority: row.priority
  549. };
  550. updatePriority(params).then((res) => {});
  551. }, 800)
  552. }
  553. };
  554. </script>
  555. <style lang="scss" scoped></style>