addOrEditDialog.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617
  1. <template>
  2. <ele-modal
  3. custom-class="ele-dialog-form long-dialog-form"
  4. :centered="true"
  5. :visible.sync="addOrEditDialogFlag"
  6. :title="title"
  7. :append-to-body="true"
  8. :close-on-click-modal="false"
  9. width="60%"
  10. :before-close="cancel"
  11. :maxable="true"
  12. :resizable="true"
  13. >
  14. <el-form
  15. ref="form"
  16. :model="form"
  17. :rules="rules"
  18. label-width="120px"
  19. class="el-form-box"
  20. :disabled="title == '详情'"
  21. >
  22. <headerTitle title="产品信息"> </headerTitle>
  23. <el-row>
  24. <el-col :span="12">
  25. <el-form-item label="编码" prop="code">
  26. <el-input
  27. clearable
  28. readonly
  29. v-model="form.code"
  30. @click.native="$refs.produceRef.open()"
  31. placeholder="请选择"
  32. />
  33. </el-form-item>
  34. </el-col>
  35. <el-col :span="12">
  36. <el-form-item label="名称" prop="name">
  37. <el-input clearable disabled v-model="form.name" placeholder=" " />
  38. </el-form-item>
  39. </el-col>
  40. <el-col :span="12">
  41. <el-form-item label="BOM类型" prop="bomCategory">
  42. <el-select
  43. v-model="form.bomCategory"
  44. @change="changeProductType"
  45. style="width: 100%"
  46. clearable
  47. >
  48. <el-option
  49. v-for="item of bomCategoryList"
  50. :key="item.code"
  51. :label="item.name"
  52. :value="item.code"
  53. ></el-option>
  54. </el-select>
  55. </el-form-item>
  56. </el-col>
  57. <el-col :span="12">
  58. <el-form-item label="BOM版本" prop="bomId">
  59. <el-select
  60. v-model="form.bomId"
  61. @change="changeBomId"
  62. style="width: 100%"
  63. clearable
  64. >
  65. <el-option
  66. v-for="item of bomVersionList"
  67. :key="item.id"
  68. :label="item.name + '(V' + item.versions + '.0)'"
  69. :value="item.id"
  70. ></el-option>
  71. </el-select>
  72. </el-form-item>
  73. </el-col>
  74. <el-col :span="12">
  75. <el-form-item label="工艺路线" prop="produceRoutingId">
  76. <el-select
  77. v-model="form.produceRoutingId"
  78. @change="changeRoutingList"
  79. style="width: 100%"
  80. clearable
  81. >
  82. <el-option
  83. v-for="item of routingList"
  84. :key="item.id"
  85. :label="item.name"
  86. :value="item.id"
  87. ></el-option>
  88. </el-select>
  89. </el-form-item>
  90. </el-col>
  91. <el-col :span="12">
  92. <el-form-item label="工厂名称:" prop="factoriesId">
  93. <el-select
  94. style="width: 100%"
  95. clearable
  96. v-model="form.factoriesId"
  97. placeholder="请选择所属工厂"
  98. >
  99. <el-option
  100. v-for="item in factoryList"
  101. :label="item.name"
  102. :value="item.id"
  103. :key="item.id"
  104. @click.native="change_factoryId(item)"
  105. ></el-option>
  106. </el-select>
  107. </el-form-item>
  108. </el-col>
  109. </el-row>
  110. <headerTitle title="工位节拍"> </headerTitle>
  111. <ele-pro-table
  112. :columns="columns"
  113. :datasource="form.list"
  114. ref="table"
  115. height="400px"
  116. full-height="calc(100vh - 116px)"
  117. :needPage="false"
  118. :selection.sync="selection"
  119. >
  120. <template v-slot:toolbar>
  121. <div style="display: flex">
  122. <el-form-item label="工序名称" prop="operationId">
  123. <el-select
  124. v-model="form.operationId"
  125. style="width: 230px"
  126. v-if="form.produceRoutingId"
  127. >
  128. <el-option
  129. v-for="item of taskList"
  130. :key="item.sourceTaskId"
  131. :label="item.name"
  132. :value="item.sourceTaskId"
  133. @click.native="changeOperationId(item)"
  134. ></el-option>
  135. </el-select>
  136. <el-input
  137. v-if="!form.produceRoutingId"
  138. style="width: 230px"
  139. readonly
  140. :value="form.operationName"
  141. placeholder=" "
  142. />
  143. <el-button
  144. v-if="!form.produceRoutingId"
  145. size="small"
  146. type="primary"
  147. style="margin-left: 10px"
  148. @click.native="taskinstanceDialogFlag = true"
  149. >选择
  150. </el-button>
  151. </el-form-item>
  152. <el-form-item label="工序节拍(分)" prop="cycleTime">
  153. <el-input
  154. clearable
  155. style="width: 230px"
  156. disabled
  157. :value="cycleTime"
  158. placeholder=" "
  159. />
  160. </el-form-item>
  161. <el-form-item label-width="0">
  162. <el-button
  163. size="small"
  164. type="primary"
  165. style="margin-left: 10px"
  166. @click.native="$refs.stationBeatDialogRef.open()"
  167. >新增工位
  168. </el-button>
  169. </el-form-item>
  170. </div>
  171. </template>
  172. <template v-slot:stationCycleTime="{ row, $index }">
  173. <el-form-item
  174. label-width="0"
  175. :prop="'list.' + $index + '.stationCycleTime'"
  176. :rules="[{ required: true, message: '请输入', trigger: 'blur' }]"
  177. >
  178. <el-input
  179. clearable
  180. v-model.number="row.stationCycleTime"
  181. placeholder="请输入"
  182. />
  183. </el-form-item>
  184. </template>
  185. <template v-slot:priority="{ row, $index }">
  186. <el-form-item
  187. label-width="0"
  188. :prop="'list.' + $index + '.priority'"
  189. :rules="[{ required: true, message: '请输入', trigger: 'blur' }]"
  190. >
  191. <el-input
  192. clearable
  193. v-model.number="row.priority"
  194. placeholder="请输入"
  195. />
  196. </el-form-item>
  197. </template>
  198. <template v-slot:remark="{ row }">
  199. <el-input clearable v-model="row.remark" placeholder="请输入" />
  200. </template>
  201. <template v-slot:columnRequired="{ column }">
  202. <span class="is-required">{{ column.label }}</span>
  203. </template>
  204. </ele-pro-table>
  205. </el-form>
  206. <div slot="footer">
  207. <el-button
  208. type="primary"
  209. @click="save()"
  210. v-lodading="loading"
  211. v-if="title != '详情'"
  212. >保存</el-button
  213. >
  214. <el-button @click="cancel">返回</el-button>
  215. </div>
  216. <ProductModal
  217. ref="produceRef"
  218. @changeParent="produceConfirm"
  219. ></ProductModal>
  220. <taskinstanceDialog
  221. ref="taskinstanceDialogRef"
  222. v-if="taskinstanceDialogFlag"
  223. @saveTaskInstance="changeOperationId"
  224. :visible.sync="taskinstanceDialogFlag"
  225. ></taskinstanceDialog>
  226. <stationBeatDialog
  227. ref="stationBeatDialogRef"
  228. @save="stationBeatAdd"
  229. :disabledTableList="this.form.list"
  230. ></stationBeatDialog>
  231. </ele-modal>
  232. </template>
  233. <script>
  234. const defForm = {
  235. code: '', //编码
  236. name: '', //名称
  237. productId: '', //物品id
  238. factoriesId: '', //工厂id
  239. factoriesName: '', //工厂名称
  240. bomVersion: '', //bom版本
  241. bomId: '', //bom版本id
  242. bomCategory: '', //bom类型
  243. brandNo: '', //品牌
  244. specification: '', //规格
  245. modelType: '', //型号
  246. produceRoutingId: '', // 工艺路线
  247. produceRoutingName: '', // 工艺路线名称
  248. cycleTime: '', // 工序节拍
  249. operationName: '', // 工序名称
  250. operationId: '', // 工序id
  251. list: [] //表格数据
  252. };
  253. import { getFactoryarea } from '@/api/factoryModel';
  254. import ProductModal from '@/components/productList/product-list.vue';
  255. import taskinstanceDialog from '@/components/procedure/taskinstanceDialog.vue';
  256. import stationBeatDialog from '@/views/factoryModel/station/components/stationBeatDialog.vue';
  257. import {
  258. saveOrUpdate,
  259. getById,
  260. listBomType,
  261. bomListByPlan,
  262. bomRoutingList,
  263. listByRoutingIds,
  264. selectFactoryWorkstation
  265. } from '@/api/productionScheduling/stationBeat';
  266. export default {
  267. components: { ProductModal, taskinstanceDialog, stationBeatDialog },
  268. computed: {},
  269. data() {
  270. return {
  271. lodading: false,
  272. title: '',
  273. addOrEditDialogFlag: false,
  274. taskinstanceDialogFlag: false,
  275. form: { ...defForm },
  276. rules: {
  277. name: [
  278. { required: true, message: '名称不能为空', trigger: 'change' }
  279. ],
  280. // factoriesId: [
  281. // { required: true, message: '请选择工厂', trigger: 'change' }
  282. // ],
  283. // bomId: [
  284. // { required: true, message: '请选择BOM版本', trigger: 'change' }
  285. // ],
  286. // bomCategory: [
  287. // { required: true, message: '请选择BOM类型', trigger: 'change' }
  288. // ],
  289. // produceRoutingId: [
  290. // { required: true, message: '请选择工艺路线', trigger: 'change' }
  291. // ],
  292. code: [{ required: true, message: '编码不能为空', trigger: 'change' }]
  293. },
  294. factoryList: [],
  295. selection: [],
  296. productionLineList: [],
  297. columns: [
  298. {
  299. width: 60,
  300. type: 'index',
  301. columnKey: 'index',
  302. label: '序号',
  303. align: 'center',
  304. fixed: 'left'
  305. },
  306. {
  307. prop: 'workstationName',
  308. label: '工位名称',
  309. align: 'center',
  310. showOverflowTooltip: true,
  311. minWidth: 180
  312. },
  313. {
  314. prop: 'deviceCode',
  315. label: '设备编码',
  316. align: 'center',
  317. showOverflowTooltip: true,
  318. minWidth: 180
  319. },
  320. {
  321. prop: 'deviceName',
  322. label: '设备名称',
  323. align: 'center',
  324. showOverflowTooltip: true,
  325. minWidth: 180
  326. },
  327. {
  328. prop: 'model',
  329. label: '型号',
  330. align: 'center',
  331. showOverflowTooltip: true,
  332. minWidth: 180
  333. },
  334. {
  335. prop: 'deviceType',
  336. label: '设备类型',
  337. align: 'center',
  338. showOverflowTooltip: true,
  339. minWidth: 180
  340. },
  341. {
  342. prop: 'stationCycleTime',
  343. slot: 'stationCycleTime',
  344. headerSlot: 'columnRequired',
  345. label: '工位节拍(分钟)',
  346. align: 'center',
  347. showOverflowTooltip: true,
  348. minWidth: 180
  349. },
  350. {
  351. prop: 'priority',
  352. slot: 'priority',
  353. headerSlot: 'columnRequired',
  354. label: '优先顺序',
  355. align: 'center',
  356. showOverflowTooltip: true,
  357. minWidth: 120
  358. },
  359. {
  360. prop: 'remark',
  361. slot: 'remark',
  362. label: '备注',
  363. align: 'center',
  364. showOverflowTooltip: true,
  365. minWidth: 200
  366. }
  367. ],
  368. loading: false,
  369. bomCategoryList: [],
  370. bomVersionList: [],
  371. routingList: [],
  372. taskList: []
  373. };
  374. },
  375. mounted() {},
  376. created() {
  377. this.getFactoryList();
  378. },
  379. computed: {
  380. cycleTime() {
  381. let cycleTime = this.form.list.reduce((pre, cur) => {
  382. return pre + Number(cur.stationCycleTime);
  383. }, 0);
  384. this.form.cycleTime =
  385. cycleTime / this.form.list.length / this.form.list.length;
  386. return cycleTime / this.form.list.length / this.form.list.length || 0;
  387. }
  388. },
  389. methods: {
  390. //初始化
  391. async open(row = {}, type) {
  392. this.addOrEditDialogFlag = true;
  393. this.title = type == 'add' ? '新增' : type == 'edit' ? '修改' : '详情';
  394. if (type !== 'add') {
  395. this.form = await getById(row.id);
  396. this.form.list.forEach((item, index) => {
  397. item.key = index;
  398. });
  399. this.getBomInfo(this.form.productId);
  400. this.changeProductType('init');
  401. if (this.form.factoriesId) {
  402. this.change_factoryId({ id: this.form.factoriesId });
  403. }
  404. }
  405. },
  406. handParent() {
  407. this.form.list.push({
  408. productionLineName: '',
  409. productionLineId: '',
  410. stationCycleTime: '',
  411. remark: '',
  412. key: this.form.list?.length || 0
  413. });
  414. },
  415. async getFactoryList() {
  416. const { list } = await getFactoryarea({
  417. pageNum: 1,
  418. size: 999,
  419. type: 1,
  420. enable: 1
  421. });
  422. this.factoryList = list || [];
  423. },
  424. async change_factoryId(item) {
  425. const { list } = await getFactoryarea({
  426. pageNum: 1,
  427. size: 999,
  428. type: 4,
  429. factoryId: item.id,
  430. enable: 1
  431. });
  432. this.productionLineList = list || [];
  433. this.form.factoriesName = item.name;
  434. },
  435. change_productionLineId(item, index) {
  436. this.$set(this.form.list[index], 'productionLineName', item.name);
  437. },
  438. produceConfirm(data) {
  439. this.form.name = data[0].name;
  440. this.form.code = data[0].code;
  441. this.form.productId = data[0].id;
  442. this.form.brandNo = data[0].brandNum;
  443. this.form.modelType = data[0].modelType;
  444. this.form.specification = data[0].specification;
  445. this.produceCancel();
  446. this.getBomInfo(data[0].id);
  447. },
  448. produceCancel() {
  449. this.form.bomCategory = '';
  450. this.bomCategoryList = [];
  451. this.form.bomVersion = '';
  452. this.form.bomId = '';
  453. this.bomVersionList = [];
  454. this.routingList = [];
  455. this.form.produceRoutingId = '';
  456. this.form.produceRoutingName = '';
  457. this.produceRoutingList = [];
  458. this.form.operationId = '';
  459. this.form.operationName = '';
  460. this.taskList = [];
  461. this.form.list = [];
  462. },
  463. // 获取bom信息
  464. async getBomInfo(id) {
  465. const res = await listBomType({ categoryId: id });
  466. if (!res || res.length == 0) return;
  467. let bomMap = {
  468. 2: { code: '2', name: 'MBOM' },
  469. 3: { code: '3', name: 'ABOM' }
  470. };
  471. let arr = [];
  472. res.map((item) => {
  473. if (bomMap[item.bomType]) {
  474. arr.push(bomMap[item.bomType]);
  475. }
  476. });
  477. this.bomCategoryList = arr;
  478. },
  479. // 根据bom类型和产品id获取bom版本
  480. async changeProductType(type) {
  481. let data = await bomListByPlan({
  482. bomType: this.form.bomCategory,
  483. categoryId: this.form.productId
  484. });
  485. this.bomVersionList = data;
  486. if (data.length) {
  487. if (type != 'init') {
  488. this.form.bomId = data[0].id;
  489. this.form.bomVersion = data[0].versions;
  490. }
  491. this.changeBomId(type);
  492. }
  493. },
  494. async changeBomId(type) {
  495. const res = await bomRoutingList(this.form.bomId);
  496. let arr = res || [];
  497. this.routingList = arr;
  498. if (type != 'init') {
  499. this.form.bomVersion = this.bomVersionList.find(
  500. (item) => item.id == this.form.bomId
  501. )?.versions;
  502. this.taskList = [];
  503. this.form.produceRoutingId = '';
  504. this.form.produceRoutingName = '';
  505. this.form.operationName = '';
  506. this.form.operationId = '';
  507. this.form.list = [];
  508. }
  509. if (arr.length) {
  510. if (type != 'init') {
  511. this.form.produceRoutingId = arr[0].id;
  512. this.form.produceRoutingName = arr[0].name;
  513. }
  514. this.changeRoutingList(type);
  515. }
  516. },
  517. async changeRoutingList(type) {
  518. const res = await listByRoutingIds([this.form.produceRoutingId]);
  519. let arr = res || [];
  520. this.taskList = arr;
  521. if (type != 'init') {
  522. this.form.operationName = '';
  523. this.form.operationId = '';
  524. this.form.list = [];
  525. }
  526. },
  527. async changeOperationId(item) {
  528. this.form.operationName = item.name;
  529. this.form.operationId = item.sourceTaskId || item.id;
  530. const res = await selectFactoryWorkstation({
  531. taskId: this.form.operationId
  532. });
  533. let arr = res || [];
  534. this.form.list = arr.map((item) => {
  535. return {
  536. deviceId: item.extInfo?.assetId,
  537. deviceName: item.extInfo?.assetName,
  538. deviceCode: item.extInfo?.assetCode,
  539. workstationName: item.name,
  540. workstationId: item.id,
  541. model: item.modelType,
  542. deviceType: item.categoryLevelName,
  543. stationCycleTime: '',
  544. remark: '',
  545. priority: ''
  546. // deviceType: item.extInfo?.assetType,
  547. };
  548. });
  549. },
  550. stationBeatAdd(data) {
  551. data.forEach((item) => {
  552. this.form.list.push({
  553. deviceId: item.extInfo?.assetId,
  554. deviceName: item.extInfo?.assetName,
  555. deviceCode: item.extInfo?.assetCode,
  556. workstationName: item.name,
  557. workstationId: item.id,
  558. model: item.model,
  559. deviceType: item.deviceType,
  560. stationCycleTime: '',
  561. remark: '',
  562. priority: ''
  563. });
  564. });
  565. },
  566. save() {
  567. this.$refs.form.validate((valid) => {
  568. if (!this.form.list?.length) {
  569. this.$message.error('节拍信息不能为空');
  570. return;
  571. }
  572. if (valid) {
  573. let priorityList = this.form.list.map((item) => item.priority);
  574. if (new Set(priorityList).size !== priorityList.length) {
  575. this.$message.error('优先顺序不能重复');
  576. return;
  577. }
  578. this.loading = true;
  579. saveOrUpdate(this.form)
  580. .then((res) => {
  581. this.$message.success('操作成功');
  582. this.cancel();
  583. this.$emit('done');
  584. })
  585. .finally(() => {
  586. this.loading = false;
  587. });
  588. }
  589. });
  590. },
  591. //关闭弹窗
  592. cancel() {
  593. this.addOrEditDialogFlag = false;
  594. this.form = {
  595. ...defForm
  596. };
  597. this.form.list = [];
  598. }
  599. }
  600. };
  601. </script>
  602. <style scoped lang="scss">
  603. // :deep(.el-form-item--medium) {
  604. // display: none;
  605. // }
  606. </style>