index.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478
  1. <template>
  2. <div class="tenant">
  3. <!-- <Banner /> -->
  4. <div class="content">
  5. <byTable :source="sourceList.data" :pagination="sourceList.pagination" :config="config" :loading="loading" highlight-current-row
  6. :selectConfig="selectConfig" :table-events="{
  7. //element talbe事件都能传
  8. select: select,
  9. }" :action-list="[
  10. {
  11. text: '添加工艺',
  12. action: () => openModal('add'),
  13. },
  14. ]" @get-list="getList">
  15. <template #line="{ item }">
  16. <span v-for="(x, i) in item.processRouteNameList" :key="i">
  17. {{ x }}
  18. <span style="margin: 0 3px" v-if="i + 1 < item.processRouteNameList.length"> ,
  19. </span>
  20. </span>
  21. </template>
  22. <template #product="{ item }">
  23. <span v-for="(x, i) in item.applicableProductsNameList" :key="i">
  24. {{ x }}
  25. <span v-if="i + 1 < item.applicableProductsNameList.length">,
  26. </span>
  27. </span>
  28. </template>
  29. </byTable>
  30. </div>
  31. <el-dialog :title="modalType == 'add' ? '添加工艺' : '编辑工艺'" v-model="dialogVisible" width="90%" v-loading="loading" destroy-on-close>
  32. <byForm :formConfig="formConfig" :formOption="formOption" v-model="formData.data" :rules="rules" ref="byform">
  33. <!-- <template #lineSlot>
  34. <el-transfer v-model="selectLine" filterable filter-placeholder="搜索" :data="lineData" :titles="['可选', '已选']" target-order="push">
  35. <template #default="{ option }">
  36. <div class="parent">
  37. <div :draggable="selectLine.includes(option.key)" @dragstart="dragStar($event, option)" @dragover="dragOver($event, option)"
  38. @drop="handleDrop($event)" style="cursor: default" :id="option.key">
  39. {{ option.label }}
  40. </div>
  41. </div>
  42. </template>
  43. </el-transfer>
  44. </template> -->
  45. <template #lineSlot>
  46. <div class="processChart" style="width:100%">
  47. <div class="from">
  48. <div class="commons-title">工序</div>
  49. <!-- <div>
  50. <el-form labelPosition='top'>
  51. <el-form-item label="工序" label-width="80px">
  52. </el-form-item>
  53. </el-form>
  54. </div> -->
  55. </div>
  56. <div class="content">
  57. <div class="commons-title">工艺路线</div>
  58. <div class="chart-warp">
  59. <vueFlow :nodeObject="nodeObject" ref="vueFlowDom"></vueFlow>
  60. </div>
  61. </div>
  62. </div>
  63. </template>
  64. <template #productSlot>
  65. <div>
  66. <el-button type="primary" @click="openProduct = true">
  67. 添加产品
  68. </el-button>
  69. <div style="margin-top: 15px" v-if="productList && productList.length > 0">
  70. <el-tag style="margin-right: 10px" type="info" closable v-for="(product, index) in productList" :key="product.id"
  71. @close="handleRemove(index)">{{ product.name }}({{ product.spec }})</el-tag>
  72. </div>
  73. </div>
  74. </template>
  75. </byForm>
  76. <template #footer>
  77. <el-button @click="dialogVisible = false" size="large">取 消</el-button>
  78. <el-button type="primary" v-no-double-click="submitForm" size="large" :loading="submitLoading">
  79. 确 定
  80. </el-button>
  81. </template>
  82. </el-dialog>
  83. <el-dialog v-model="openProduct" title="选择产品" width="70%" append-to-body>
  84. <SelectProduct @handleSelect="handleSelect" :isTechnology="'0'"></SelectProduct>
  85. <template #footer>
  86. <span class="dialog-footer">
  87. <el-button @click="openProduct = false">取消</el-button>
  88. </span>
  89. </template>
  90. </el-dialog>
  91. </div>
  92. </template>
  93. <script setup>
  94. /* eslint-disable vue/no-unused-components */
  95. import { ElMessage, ElMessageBox } from "element-plus";
  96. import byTable from "@/components/byTable/index";
  97. import byForm from "@/components/byForm/index";
  98. import SelectProduct from "@/components/product/SelectProduct";
  99. import vueFlow from "@/views/JXSK/processConfig/vueFlow.vue";
  100. import { computed, defineComponent, nextTick, ref, toRaw } from "vue";
  101. const loading = ref(false);
  102. const submitLoading = ref(false);
  103. const sourceList = ref({
  104. data: [],
  105. pagination: {
  106. total: 3,
  107. pageNum: 1,
  108. pageSize: 10,
  109. },
  110. });
  111. let lineData = ref([
  112. {
  113. key: "1",
  114. label: "测试1",
  115. disabled: false,
  116. },
  117. {
  118. key: "2",
  119. label: "测试2",
  120. disabled: false,
  121. },
  122. {
  123. key: "3",
  124. label: "测试3",
  125. disabled: false,
  126. },
  127. {
  128. key: "4",
  129. label: "测试4",
  130. disabled: false,
  131. },
  132. ]);
  133. let selectLine = ref([]);
  134. let dialogVisible = ref(false);
  135. let openProduct = ref(false);
  136. let modalType = ref("add");
  137. let rules = ref({
  138. name: [{ required: true, message: "请输入工艺名称", trigger: "blur" }],
  139. });
  140. const { proxy } = getCurrentInstance();
  141. const selectConfig = reactive([
  142. // {
  143. // label: "车间类型",
  144. // prop: "type",
  145. // data: [
  146. // {
  147. // label: "普通车间",
  148. // value: "1",
  149. // },
  150. // {
  151. // label: "半自动化车间",
  152. // value: "2",
  153. // },
  154. // {
  155. // label: "自动化车间",
  156. // value: "3",
  157. // },
  158. // ],
  159. // },
  160. ]);
  161. const config = computed(() => {
  162. return [
  163. {
  164. attrs: {
  165. label: "工艺名称",
  166. prop: "name",
  167. width: 150,
  168. },
  169. },
  170. {
  171. attrs: {
  172. label: "工艺路线",
  173. slot: "line",
  174. },
  175. },
  176. {
  177. attrs: {
  178. label: "适用产品",
  179. slot: "product",
  180. },
  181. },
  182. {
  183. attrs: {
  184. label: "工艺说明",
  185. prop: "remarks",
  186. },
  187. },
  188. {
  189. attrs: {
  190. label: "操作",
  191. width: "200",
  192. align: "right",
  193. },
  194. // 渲染 el-button,一般用在最后一列。
  195. renderHTML(row) {
  196. return [
  197. {
  198. attrs: {
  199. label: "修改",
  200. type: "primary",
  201. text: true,
  202. },
  203. el: "button",
  204. click() {
  205. getDtl(row);
  206. },
  207. },
  208. {
  209. attrs: {
  210. label: "删除",
  211. type: "danger",
  212. text: true,
  213. },
  214. el: "button",
  215. click() {
  216. // 弹窗提示是否删除
  217. ElMessageBox.confirm(
  218. "此操作将永久删除该数据, 是否继续?",
  219. "提示",
  220. {
  221. confirmButtonText: "确定",
  222. cancelButtonText: "取消",
  223. type: "warning",
  224. }
  225. ).then(() => {
  226. // 删除
  227. proxy
  228. .post("/technology/delete", {
  229. id: row.id,
  230. })
  231. .then((res) => {
  232. ElMessage({
  233. message: "删除成功",
  234. type: "success",
  235. });
  236. getList();
  237. });
  238. });
  239. },
  240. },
  241. ];
  242. },
  243. },
  244. ];
  245. });
  246. let formData = reactive({
  247. data: {
  248. name: "",
  249. processRouteList: [],
  250. remarks: "",
  251. productList: [],
  252. },
  253. });
  254. const formOption = reactive({
  255. inline: true,
  256. labelWidth: 100,
  257. itemWidth: 100,
  258. rules: [],
  259. });
  260. const byform = ref(null);
  261. const formConfig = computed(() => {
  262. return [
  263. {
  264. type: "input",
  265. prop: "name",
  266. label: "工艺名称",
  267. required: true,
  268. },
  269. {
  270. type: "slot",
  271. slotName: "lineSlot",
  272. label: "工艺路线",
  273. },
  274. {
  275. type: "slot",
  276. slotName: "productSlot",
  277. label: "适用产品",
  278. },
  279. {
  280. type: "input",
  281. prop: "remarks",
  282. label: "工艺说明",
  283. itemType: "textarea",
  284. },
  285. ];
  286. });
  287. const getList = async (req) => {
  288. sourceList.value.pagination = { ...sourceList.value.pagination, ...req };
  289. loading.value = true;
  290. proxy
  291. .post("/technology/page", sourceList.value.pagination)
  292. .then((message) => {
  293. console.log(message);
  294. sourceList.value.data = message.rows;
  295. sourceList.value.pagination.total = message.total;
  296. setTimeout(() => {
  297. loading.value = false;
  298. }, 200);
  299. });
  300. };
  301. const getProcesses = async () => {
  302. proxy
  303. .post("/productionProcesses/page", { pageNum: 1, pageSize: 9999 })
  304. .then((message) => {
  305. lineData.value = message.rows.map((x) => ({
  306. key: x.id,
  307. label: x.name,
  308. disabled: false,
  309. }));
  310. });
  311. };
  312. const openModal = () => {
  313. dialogVisible.value = true;
  314. nodeObject.value = "";
  315. modalType.value = "add";
  316. formData.data = {};
  317. selectLine.value = [];
  318. productList.value = [];
  319. };
  320. const vueFlowDom = ref(null);
  321. const nodeObject = ref("");
  322. const submitForm = () => {
  323. byform.value.handleSubmit((valid) => {
  324. // if (!selectLine.value.length > 0)
  325. // return ElMessage({
  326. // message: "请添加工艺路线",
  327. // type: "info",
  328. // });
  329. if (!productList.value.length > 0)
  330. return ElMessage({
  331. message: "请添加适用产品",
  332. type: "info",
  333. });
  334. const data = vueFlowDom.value.submitAll();
  335. if (!data) {
  336. return;
  337. }
  338. formData.data.nodeObject = data.nodeObject;
  339. submitLoading.value = true;
  340. // formData.data.processRouteList = selectLine.value; //选择的工序数据
  341. formData.data.productList = productList.value.map((x) => ({
  342. productId: x.id,
  343. })); //选择的产品数据
  344. proxy.post("/technology/" + modalType.value, formData.data).then(
  345. (res) => {
  346. ElMessage({
  347. message: modalType.value == "add" ? "添加成功" : "编辑成功",
  348. type: "success",
  349. });
  350. dialogVisible.value = false;
  351. submitLoading.value = false;
  352. getList();
  353. },
  354. (err) => {
  355. console.log(err, "aswwwww");
  356. submitLoading.value = false;
  357. }
  358. );
  359. });
  360. };
  361. const getDtl = (row) => {
  362. modalType.value = "edit";
  363. proxy.post("/technology/detail", { id: row.id }).then((res) => {
  364. nodeObject.value = res.nodeObject;
  365. productList.value = res.applicableProductsList;
  366. // selectLine.value = res.processRouteList.map((x) => x.id);
  367. formData.data = res;
  368. dialogVisible.value = true;
  369. });
  370. };
  371. const productList = ref([]);
  372. const handleSelect = (row) => {
  373. const flag = productList.value.some((x) => x.id === row.id);
  374. if (flag)
  375. return ElMessage({
  376. message: "该产品已选择",
  377. type: "info",
  378. });
  379. productList.value.push(row);
  380. return ElMessage({
  381. message: "选择成功",
  382. type: "success",
  383. });
  384. };
  385. const handleRemove = (index) => {
  386. productList.value.splice(index, 1);
  387. return ElMessage({
  388. message: "删除成功",
  389. type: "success",
  390. });
  391. };
  392. getList();
  393. getProcesses();
  394. // 以下是实现拖拽排序的处理方法
  395. const dragStar = (e, option) => {
  396. // if (!selectLine.value.includes(e.target.id)) return; //拖拽的数据如不是选择的数据直接return
  397. e.dataTransfer.setData("text/plain", option.key);
  398. e.dataTransfer.effectAllowed = "move";
  399. e.dataTransfer.dropEffect = "move";
  400. };
  401. const dragOver = (e, option) => {
  402. e.preventDefault();
  403. };
  404. const handleDrop = (e) => {
  405. // if (!selectLine.value.includes(e.target.id)) return; //拖拽的数据如不是选择的数据直接return
  406. e.preventDefault();
  407. const sourceKey = e.dataTransfer.getData("text/plain"); //获取拖动元素的key值
  408. const targetKey = e.target.id; //获取被互换元素的id值
  409. swapItems(sourceKey, targetKey);
  410. };
  411. // const findIndex = (target) => {
  412. // while (target && target.parentNode) {
  413. // let targetParent = target.parentNode;
  414. // const index = Array.from(targetParent.children).indexOf(target);
  415. // if (index !== -1) {
  416. // return index;
  417. // }
  418. // }
  419. // return -1;
  420. // };
  421. // 调换数据源位置
  422. const swapItems = (sourceKey, targetKey) => {
  423. const sourceIndex = selectLine.value.findIndex((x) => x === sourceKey);
  424. const targetIndex = selectLine.value.findIndex((x) => x === targetKey);
  425. const temp = selectLine.value[sourceIndex];
  426. selectLine.value[sourceIndex] = selectLine.value[targetIndex];
  427. selectLine.value[targetIndex] = temp;
  428. };
  429. </script>
  430. <style lang="scss" scoped>
  431. .tenant {
  432. padding: 20px;
  433. }
  434. .processChart {
  435. border: 1px solid #ccc;
  436. padding: 20px;
  437. display: flex;
  438. justify-content: space-between;
  439. position: relative;
  440. .from {
  441. width: 400px;
  442. background: #fff;
  443. border-radius: 5px;
  444. padding: 20px;
  445. }
  446. .content {
  447. width: calc(100% - 420px);
  448. border-radius: 5px;
  449. padding: 20px;
  450. background: #fff;
  451. }
  452. }
  453. .chart-warp {
  454. width: 100%;
  455. height: calc(100vh - 280px);
  456. }
  457. </style>