processComponent.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566
  1. <template>
  2. <div
  3. class="mainContentBox"
  4. style="padding: 0; box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.1)"
  5. >
  6. <div class="header">
  7. <div class="title">绑定工序</div>
  8. <div class="processInfo">
  9. <span>工艺名称:{{ routeInfo?.processRouteName }}</span>
  10. <span>产品名称:{{ routeInfo?.prodtName }}</span>
  11. <span>产品型号: {{ routeInfo?.prodtModel }}</span>
  12. </div>
  13. <el-space>
  14. <el-button :icon="Back" size="small" @click="back">返回</el-button>
  15. <el-button
  16. :type="isChanged ? 'danger' : 'primary'"
  17. :icon="Document"
  18. size="small"
  19. @click="save"
  20. >保存</el-button
  21. >
  22. </el-space>
  23. </div>
  24. <div class="types">
  25. <el-dropdown @command="handleCommand" :hide-on-click="false">
  26. <div class="typeBox addBtn">
  27. <el-icon class="icon"><CirclePlus /></el-icon>
  28. <div class="name">添加组件</div>
  29. </div>
  30. <template #dropdown>
  31. <el-dropdown-menu>
  32. <el-dropdown-item
  33. v-for="(com, index) in comTypes"
  34. :key="index"
  35. :command="com"
  36. >
  37. <div
  38. v-if="
  39. prodtCode != '' ||
  40. (prodtCode == '' && com.compentName != '物料采集')
  41. "
  42. >
  43. {{ com.compentName }}
  44. </div></el-dropdown-item
  45. >
  46. </el-dropdown-menu>
  47. </template>
  48. </el-dropdown>
  49. <VueDraggable
  50. v-model="selectProComs"
  51. :animation="150"
  52. :draggable="false"
  53. ghostClass="ghost"
  54. @update="onUpdate"
  55. style="display: flex"
  56. >
  57. <div
  58. class="typeContainer"
  59. v-for="(item, index) in selectProComs"
  60. :key="index"
  61. @click="clickToolCom(item, index)"
  62. >
  63. <div class="typeBox others" :class="getNameClass(index)">
  64. <svg-icon :icon-class="item.compentType" size="30" />
  65. <div class="name">{{ item.compentName }}</div>
  66. </div>
  67. <Delete class="delete" @click.stop="clickDelete(index)" />
  68. </div>
  69. </VueDraggable>
  70. </div>
  71. <div class="binContainer">
  72. <div v-if="isChanged || selectIndex === -1 || isNoneedEdit">
  73. <el-empty :image-size="200" :description="getTipContent()" />
  74. </div>
  75. <div v-else-if="tipTitle !== '编辑工序表单'">
  76. <div class="tipTitle">{{ tipTitle }}</div>
  77. <el-tabs
  78. v-if="currentCom.compentType === 'wuliaocaiji'"
  79. v-model="materialType"
  80. type="card"
  81. @tab-change="materialTypeChange"
  82. >
  83. <el-tab-pane label="主料" name="1" />
  84. <el-tab-pane label="辅料" name="2" />
  85. </el-tabs>
  86. <el-button
  87. type="primary"
  88. @click="creatNewData"
  89. style="margin-bottom: 15px"
  90. >新增</el-button
  91. >
  92. <el-button
  93. type="primary"
  94. @click="bindCreate"
  95. style="margin-bottom: 15px"
  96. >绑定双规格</el-button
  97. >
  98. <el-button
  99. type="primary"
  100. @click="saveSortData"
  101. style="margin-bottom: 15px"
  102. >保存顺序</el-button
  103. >
  104. <BottomTable ref="bottomTableRef" :tableType="tableType" />
  105. </div>
  106. <div v-else>
  107. <div class="tipTitle">{{ tipTitle }}</div>
  108. <SetExcel />
  109. </div>
  110. </div>
  111. <el-dialog
  112. v-model="dialog.visible"
  113. :title="dialog.title"
  114. width="900px"
  115. @close="dialog.visible = false"
  116. :destroy-on-close="true"
  117. >
  118. <el-container>
  119. <el-aside width="200px" style="overflow: hidden">
  120. <avue-tree
  121. :option="optionTree"
  122. :data="treeData"
  123. v-model="formTree"
  124. @node-click="nodeClick"
  125. @save="saveRow"
  126. @update="updateRow"
  127. @del="delRow"
  128. ></avue-tree>
  129. </el-aside>
  130. <el-main>
  131. <el-button
  132. type="primary"
  133. @click="creatGroupData"
  134. style="margin-bottom: 15px"
  135. >新增</el-button
  136. >
  137. <BottomTable
  138. ref="tableTreeRef"
  139. :tableType="tableType"
  140. :groupId="groupId"
  141. :isTree="'1'"
  142. />
  143. </el-main>
  144. </el-container>
  145. </el-dialog>
  146. </div>
  147. </template>
  148. <script setup>
  149. import { Back, Document, CirclePlus, Delete } from "@element-plus/icons-vue";
  150. import { VueDraggable } from "vue-draggable-plus";
  151. import BottomTable from "@/views/base/craftManagement/route/components/bottomTable.vue";
  152. import SetExcel from "./setExcel/index.vue";
  153. import { comTypes } from "@/views/base/craftManagement/route/components/configs";
  154. import {
  155. saveCompoents,
  156. getCompoentsList,
  157. treeDataList,
  158. treeDataSave,
  159. treeDataDel,
  160. treeDataUpdate,
  161. } from "@/api/craft/process/index";
  162. const formTree = ref(null);
  163. import { useCommonStoreHook, useDictionaryStoreHook } from "@/store";
  164. import {
  165. processesByRouteId,
  166. saveProcessInRoute,
  167. } from "@/api/craft/route/index";
  168. import { opExcelPage } from "@/api/craft/opExcel";
  169. const prodtCode = ref("");
  170. const routerId = ref("");
  171. const router = useRouter();
  172. const route = useRoute();
  173. const dialog = reactive({
  174. title: "绑定双规格",
  175. visible: false,
  176. });
  177. const itemData = ref([]);
  178. //组件是否已经改变,如果改变了需要点击保存,才能展示下面的table
  179. const isChanged = ref(true);
  180. const isNoneedEdit = ref(false); //有些组件是不需要编辑的,所以下面也不展示table
  181. const loadTopList = () => {
  182. getCompoentsList(route.fullPath.split("/")[4]).then((res) => {
  183. selectProComs.value = res.data || [];
  184. selectIndex.value = -1;
  185. isChanged.value = false;
  186. });
  187. };
  188. const bindCreate = () => {
  189. treeDataList(treeParam.value).then((data) => {
  190. if (data.code === "200") {
  191. treeData.value = data.data;
  192. }
  193. });
  194. dialog.visible = true;
  195. };
  196. //查询工艺路线的一些信息
  197. const routeInfo = ref();
  198. const loadRouteInfo = async () => {
  199. const res = await processesByRouteId(route.fullPath.split("/")[6]);
  200. if (res.data) {
  201. routeInfo.value = res.data;
  202. }
  203. };
  204. //弹窗传递分组id
  205. const groupId = ref(null);
  206. const nodeClick = (data) => {
  207. groupId.value = data.id;
  208. };
  209. const treeSave = ref({});
  210. const saveRow = (node, data, done, loading) => {
  211. console.log(data);
  212. treeSave.value.operationId = route.fullPath.split("/")[4];
  213. treeSave.value.label = data.label;
  214. treeSave.value.value = data.label;
  215. treeSave.value.materialType = materialType.value;
  216. treeDataSave(treeSave.value)
  217. .then((res) => {
  218. if (res.code === "200") {
  219. ElMessage.success("操作成功!");
  220. treeDataList(dataDetail.value).then((res) => {
  221. treeData.value = res.data;
  222. });
  223. }
  224. })
  225. .finally(done());
  226. };
  227. const delRow = (data, done) => {
  228. ElMessageBox.confirm("此操作将永久删除此分组, 是否继续?", "提示", {
  229. confirmButtonText: "确定",
  230. cancelButtonText: "取消",
  231. type: "warning",
  232. })
  233. .then(() => {
  234. treeDataDel(data.data).then((resouce) => {
  235. done();
  236. if (resouce.code === "200") {
  237. ElMessage.success("删除成功");
  238. } else {
  239. ElMessage.error(resouce.msg);
  240. treeDataList(dataDetail.value).then((res) => {
  241. treeData.value = res.data;
  242. });
  243. }
  244. });
  245. })
  246. .catch(() => {
  247. ElMessage.info("已取消删除");
  248. });
  249. };
  250. const dataDetail = ref({});
  251. const updateRow = (node, data, done, loading) => {
  252. treeDataUpdate(data).then((resouce) => {
  253. done();
  254. if (resouce.code === "200") {
  255. ElMessage.success("修改成功");
  256. treeDataList(dataDetail.value).then((res) => {
  257. treeData.value = res.data;
  258. });
  259. } else {
  260. ElMessage.error(resouce.msg);
  261. }
  262. });
  263. };
  264. const optionTree = {
  265. formOption: {
  266. labelWidth: 100,
  267. column: [
  268. {
  269. label: "关联名称",
  270. prop: "label",
  271. },
  272. ],
  273. },
  274. props: {
  275. labelText: "标题",
  276. label: "label",
  277. value: "value",
  278. children: "children",
  279. },
  280. };
  281. const treeData = ref(null);
  282. const treeParam = ref({});
  283. treeParam.value.operationId = route.fullPath.split("/")[4];
  284. onMounted(async () => {
  285. prodtCode.value = route.fullPath.split("/")[5];
  286. routerId.value = route.fullPath.split("/")[6];
  287. await loadTopList();
  288. loadRouteInfo();
  289. dataDetail.value.operationId = route.fullPath.split("/")[4];
  290. treeParam.value.materialType = "1";
  291. dataDetail.value.materialType = "1";
  292. });
  293. // 顶部====================
  294. const back = () => {
  295. router.back();
  296. };
  297. const save = async () => {
  298. selectProComs.value.forEach((item1) => {
  299. comTypes.find((item2) => {
  300. if (item2.compentName === item1.compentName) {
  301. item1.index = item2.index;
  302. }
  303. });
  304. });
  305. selectProComs.value = selectProComs.value.sort((a, b) => {
  306. return a.index - b.index;
  307. });
  308. for (let i = 0; i < selectProComs.value.length; i++) {
  309. selectProComs.value[i].operationId = route.fullPath.split("/")[4];
  310. selectProComs.value[i].sortNum = i;
  311. }
  312. let p = {
  313. operationId: route.fullPath.split("/")[4],
  314. dtos: selectProComs.value,
  315. };
  316. let { res, code } = await saveCompoents(p);
  317. if (code == "200") {
  318. ElMessage.success("保存成功");
  319. }
  320. loadTopList();
  321. };
  322. // Tools顶部组件 ==================
  323. // 已经存在的工序组件
  324. const selectProComs = ref([]);
  325. const selectIndex = ref(-1);
  326. const currentCom = ref({});
  327. const handleCommand = (item) => {
  328. let status = true;
  329. for (let i = 0; i < selectProComs.value.length; i++) {
  330. if (selectProComs.value[i].compentName == item.compentName) {
  331. status = false;
  332. }
  333. }
  334. if (status == true) {
  335. selectProComs.value.push(item);
  336. isChanged.value = true;
  337. selectIndex.value = -1;
  338. } else {
  339. ElMessage.error("请勿重复添加");
  340. }
  341. };
  342. // 点击某一个改变下面的table
  343. const clickToolCom = (com, index) => {
  344. // 如果上方组件更改了,提示先保存组件再操作
  345. if (isChanged.value) {
  346. ElMessage.warning("请先保存组件!!!");
  347. return;
  348. }
  349. tipTitle.value = "编辑" + com.compentName;
  350. selectIndex.value = index;
  351. currentCom.value = com;
  352. if (
  353. com.compentType === "jiluxiang" ||
  354. com.compentType === "mingpai" ||
  355. com.compentType === "duomeiticaiji" ||
  356. com.compentType === "tiaoshipipei" ||
  357. com.compentType === "jingu" ||
  358. com.compentType === "ceshishuju" ||
  359. com.compentType === "screwdriver" ||
  360. com.compentType === "gongxuwenjian" ||
  361. com.compentType === "shebeijilu"
  362. ) {
  363. isNoneedEdit.value = true;
  364. } else {
  365. tableType.value = com.compentType;
  366. isNoneedEdit.value = false;
  367. }
  368. };
  369. const onUpdate = () => {
  370. isChanged.value = true;
  371. selectIndex.value = -1;
  372. };
  373. const clickDelete = async (index) => {
  374. if (selectProComs.value[index].compentType === "operationExcel") {
  375. let operationId = route.fullPath.split("/")[4];
  376. let res = await opExcelPage(operationId);
  377. if (res.data.totalCount > 0) {
  378. ElMessage.error("请先删除工序表单数据!");
  379. return;
  380. }
  381. }
  382. selectProComs.value.splice(index, 1);
  383. selectIndex.value = -1;
  384. isChanged.value = true;
  385. };
  386. const getNameClass = (index) => {
  387. return index === selectIndex.value ? "selected" : "normal";
  388. };
  389. // 底部table ===============
  390. let tipTitle = ref({});
  391. const bottomTableRef = ref({});
  392. const tableTreeRef = ref({});
  393. const tableType = ref("MARTERIAL_BOM");
  394. const creatNewData = () => {
  395. bottomTableRef.value && bottomTableRef.value.startCreat();
  396. };
  397. const creatGroupData = () => {
  398. tableTreeRef.value && tableTreeRef.value.groupCreat();
  399. };
  400. const saveSortData = () => {
  401. bottomTableRef.value && bottomTableRef.value.saveSortData();
  402. };
  403. const getTipContent = (itemValue) => {
  404. if (isNoneedEdit.value) {
  405. return "标准组件无需编辑";
  406. }
  407. if (selectIndex.value === -1 && isChanged.value) {
  408. return "请先保存组件,然后再进行操作";
  409. }
  410. return "请先选择组件";
  411. };
  412. // 无聊采集组件 主料和辅料
  413. const materialType = ref("1");
  414. const materialTypeChange = (val) => {
  415. materialType.value = val;
  416. dataDetail.value.materialType = val;
  417. treeParam.value.materialType = val;
  418. if (val === "1") {
  419. tableType.value = "wuliaocaiji";
  420. } else {
  421. tableType.value = "fuliaoCJ";
  422. }
  423. };
  424. </script>
  425. <style lang="scss" scoped>
  426. .header {
  427. height: 50px;
  428. display: flex;
  429. background-color: #f5f7f9;
  430. justify-content: space-between;
  431. align-items: center;
  432. border-bottom: 1px solid rgba(0, 0, 0, 0.1);
  433. }
  434. .types {
  435. width: 100%;
  436. height: 116px;
  437. border-bottom: 1px solid rgba(0, 0, 0, 0.1);
  438. padding: 12px 20px;
  439. display: flex;
  440. .typeContainer {
  441. }
  442. .typeBox {
  443. height: 80px;
  444. width: 80px;
  445. border-radius: 4px 4px 4px 4px;
  446. display: flex;
  447. flex-direction: column;
  448. justify-content: center;
  449. align-items: center;
  450. .icon {
  451. height: 32px;
  452. width: 32px;
  453. }
  454. .name {
  455. width: 56px;
  456. height: 16px;
  457. font-weight: 500;
  458. font-size: 14px;
  459. line-height: 16px;
  460. text-align: center;
  461. font-style: normal;
  462. text-transform: none;
  463. }
  464. }
  465. .addBtn {
  466. border: 1px solid #0a59f7;
  467. color: #0a59f7;
  468. }
  469. .others {
  470. color: rgba(0, 0, 0, 0.9);
  471. border: 1px solid rgba(0, 0, 0, 0.9);
  472. margin-left: 20px;
  473. position: relative;
  474. }
  475. .delete {
  476. //position: absolute;
  477. //bottom: -20px;
  478. //left: 0;
  479. margin-left: 50px;
  480. width: 1em;
  481. height: 1em;
  482. color: red;
  483. visibility: hidden;
  484. }
  485. .typeContainer:hover {
  486. .delete {
  487. visibility: visible;
  488. }
  489. }
  490. .normal {
  491. background: #ffffff;
  492. border: 1px solid rgba(35, 32, 50, 0.1);
  493. }
  494. .selected {
  495. background: rgba(10, 89, 247, 0.2);
  496. border: 1px solid #0a59f7;
  497. }
  498. }
  499. .title,
  500. .processInfo {
  501. line-height: 44px;
  502. color: #6f7991;
  503. font-size: 14px;
  504. font-weight: bold;
  505. text-align: left;
  506. margin-left: 20px;
  507. }
  508. .processInfo span {
  509. margin-left: 100px;
  510. }
  511. .processInfo {
  512. position: absolute;
  513. left: 5%;
  514. }
  515. .binContainer {
  516. height: calc(100vh - 280px);
  517. width: 100%;
  518. background-color: #f5f7f9;
  519. overflow-y: auto;
  520. background-color: white;
  521. //margin-top: 16px;
  522. //margin-left: 20px;
  523. padding: 16px 20px;
  524. }
  525. .tipTitle {
  526. width: 84px;
  527. height: 16px;
  528. font-weight: 500;
  529. font-size: 14px;
  530. color: rgba(0, 0, 0, 0.9);
  531. line-height: 16px;
  532. text-align: left;
  533. font-style: normal;
  534. text-transform: none;
  535. margin-bottom: 16px;
  536. }
  537. .card-header {
  538. display: flex;
  539. justify-content: space-between;
  540. align-items: center;
  541. }
  542. </style>