itemChooseTree.vue 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597
  1. <template>
  2. <div>
  3. <!-- 数据项选择树 -->
  4. <el-dialog :title="title" width="80%" top="5vh" custom-class="dialog-max" class="cy-custom-dialog" center
  5. :before-close="dialogClose" :visible.sync="visible" @open="handleOpen" @close="handleClose">
  6. <el-form label-width="100px">
  7. <el-row>
  8. <el-col :span="6">
  9. <el-form-item label="数据源:" style="margin-bottom: 20px; width: 300px">
  10. <el-select v-model="dataSourceId" disabled>
  11. <el-option v-for="dict in dataSourceList" :key="dict.id" :label="dict.dataSourceName"
  12. :value="dict.id"></el-option>
  13. </el-select>
  14. </el-form-item>
  15. <!-- <el-form-item label="所选路径" style="margin-bottom: 20px; width: 300px">
  16. <el-input style="margin-top: -10px; width: 400px" disabled
  17. v-model="queryParams.chooseItemStr"></el-input>
  18. </el-form-item> -->
  19. </el-col>
  20. <template>
  21. <el-select v-model="queryParams.needItemStr" multiple collapse-tags placeholder="请选择">
  22. <el-option v-for="item in DriverItemData" :key="item.id" :label="item.itemName"
  23. :value="item.itemName">
  24. </el-option>
  25. </el-select>
  26. <el-button type="primary" size="mini" style="margin-left: 15px;"
  27. @click="getCompositeScreen">复合筛选</el-button>
  28. </template>
  29. </el-row>
  30. </el-form>
  31. <!-- <div style="display: flex; height: calc(100% - 36px); overflow: auto"> -->
  32. <div style="display: flex; height: calc(100% - 36px);">
  33. <!-- 数据项 -->
  34. <div class="cy-transform-data">
  35. <el-divider content-position="left">数据项</el-divider>
  36. <div class="cy-line" style="padding-bottom: 10px">
  37. <div style="height: 35px">
  38. <el-input placeholder="输入关键字进行过滤" v-model="filterLabelText" size="mini"
  39. prefix-icon="el-icon-search"></el-input>
  40. </div>
  41. <div style="height: calc(100% - 50px); overflow: auto">
  42. <!-- 树节点 -->
  43. <div style="height: 20vh;overflow: auto;">
  44. <virtual-tree class="cy-group-tree" ref="itemTree" :data="treeData" :indent="10"
  45. node-key="id" :filter-node-method="filterLabelEvent" @node-click="handleLabelNodeClick"
  46. :check-on-click-node="false" :show-checkbox="true" :highlight-current="true"
  47. :default-expand-all="true">
  48. <span class="custom-tree-node" slot-scope="{ node, data }">
  49. <i v-if="data.isLeaf" class="el-icon-document"
  50. style="color: #e69a0f; margin-right: 5px;" />
  51. <i v-else-if="node.expanded" class="el-icon-folder-opened"
  52. style="color: #e69a0f; margin-right: 5px;" />
  53. <i v-else class="el-icon-folder" style="color: #e69a0f; margin-right: 5px;" />
  54. <!-- <svg-icon v-if="data.isLeaf" icon-class="file-bg" />
  55. <svg-icon v-else-if="node.expanded" icon-class="folder-open" style="width: 1.2em" />
  56. <svg-icon v-else icon-class="folder" /> -->
  57. <span :title="node.label || '-'" style="margin-left: 2px">{{
  58. node.label
  59. }}</span>
  60. </span>
  61. </virtual-tree>
  62. </div>
  63. <!-- 树节点对应的叶节点 -->
  64. <div style="height: 30vh; overflow: auto">
  65. <el-divider content-position="left" style="margin-bottom: 15px !important">
  66. <i></i>
  67. <span>(共{{ leavesList.length }}项)</span>
  68. </el-divider>
  69. <el-input placeholder="输入关键字进行过滤" style="margin-top: -10px; width: calc(100% - 60px)"
  70. size="mini" @input="filterLeavesEvent" v-model="filterLeavesText"></el-input>
  71. <el-checkbox v-model="isSelectAllLeaves" @change="handleCheckAllLeavesChange"
  72. style="margin-left: 5px">全选</el-checkbox>
  73. <div class="cy-leaves-div">
  74. <p-virtual-check ref="pvc" :data-sources="leavesList"
  75. @check-change-all="checkChangeAllLeaves"
  76. @check-change="checkChangeLeaves"></p-virtual-check>
  77. </div>
  78. </div>
  79. </div>
  80. </div>
  81. </div>
  82. <!-- 操作按钮 -->
  83. <div class="cy-transform-btn">
  84. <el-row>
  85. <el-button size="mini" @click="addCheckNodesBtnEvent">添加&nbsp;&gt;&gt;</el-button>
  86. </el-row>
  87. <el-row>
  88. <el-button size="mini" @click="removeCheckNodesBtnEvent">&lt;&lt;&nbsp;移除</el-button>
  89. </el-row>
  90. <el-row>
  91. <el-button size="mini" @click="removeAllCheckNodesBtnEvent">全部移除</el-button>
  92. </el-row>
  93. </div>
  94. <!-- 已选择数据项 -->
  95. <div class="cy-transform-data">
  96. <el-divider content-position="left">已选择数据项({{ chooseItemDataListByTree.length }})</el-divider>
  97. <div class="cy-line">
  98. <el-checkbox v-model="isSelectAllItem" @change="selectAllItem"
  99. style="margin-left: 10px">全选</el-checkbox>
  100. <div style="height: 60vh; overflow: auto">
  101. <p-virtual-check ref="pvcChoose" :data-sources="chooseItemDataListByTree"
  102. @check-change-all="checkChangeAllChoose"
  103. @check-change="checkChangeChoose"></p-virtual-check>
  104. </div>
  105. </div>
  106. </div>
  107. </div>
  108. <span slot="footer">
  109. <el-button type="primary" @click="gotoItemConfig">下一步</el-button>
  110. <el-button @click="dialogClose">取消</el-button>
  111. </span>
  112. </el-dialog>
  113. <!-- 数据项表达式配置 -->
  114. <ItemConfigModel ref="itemConfigModel" @dialogClose="dialogClose" @saveItemChoose="saveItemChoose">
  115. </ItemConfigModel>
  116. </div>
  117. </template>
  118. <script>
  119. import { showLoading } from '@/utils/cqcy'
  120. import { extractDataItemValues, getNodeAllPath } from '@/utils/cqcy'
  121. import PVirtualCheck from "@/components/PVirtualCheck/index.vue";
  122. import { getNextAllItem, getDriverItemBySouceId, getCompositeScreen } from '@/api/source/itemGroup';
  123. import { getAllDataModel } from '@/api/source/dataModel';
  124. import ItemConfigModel from './itemConfigModel.vue'
  125. export default {
  126. components: {
  127. 'p-virtual-check': PVirtualCheck,
  128. ItemConfigModel
  129. },
  130. watch: {
  131. filterLabelText(val) {
  132. this.$refs.itemTree.filter(val);
  133. },
  134. },
  135. created() {
  136. this.getAllDataModel()
  137. },
  138. data() {
  139. return {
  140. visible: false,
  141. title: '选择数据项',
  142. dataSourceId: null,
  143. treeItemName: null,
  144. //树数据
  145. treeData: [],
  146. //所有数据源信息
  147. dataSourceList: [],
  148. //所有数据模型
  149. dataModelList: [],
  150. //原来数据组中包含的数据项信息
  151. itemList: [],
  152. //过滤树节点的输入文本
  153. filterLabelText: null,
  154. //左侧展示的叶节点
  155. leavesList: [],
  156. leavesListF: [],
  157. //左侧选中的叶节点
  158. leavesChooseList: [],
  159. //过滤叶节点的输入文本
  160. filterLeavesText: null,
  161. //是否全选所有叶节点
  162. isSelectAllLeaves: false,
  163. //右侧展示的,已选择的数据项
  164. chooseItemDataListByTree: [],
  165. //右侧,是否选择所有数据项
  166. isSelectAllItem: false,
  167. queryParams: {
  168. id: null,
  169. chooseItemStr: "",
  170. nextItemStr: "",
  171. needItemStr: [],
  172. },
  173. DriverItemData: []
  174. }
  175. },
  176. methods: {
  177. /** 关闭弹出层 */
  178. dialogClose() {
  179. this.visible = false
  180. },
  181. /** 弹窗打开事件 */
  182. handleOpen() {
  183. const loading = showLoading(this, "加载中,请稍候···")
  184. this.isSelectAllItem = false
  185. this.getNextAllItem(this.dataSourceId, this.treeItemName, (data) => {
  186. //加载树
  187. this.treeData = data.children
  188. //加载虚拟列表,叶节点
  189. let leaves = data.leaves
  190. this.leavesList = leaves
  191. this.leavesListF = leaves
  192. let arr = [];
  193. //将原来的数据项加载到,右侧作为已选择的
  194. for (let i = 0; i < this.itemList.length; i++) {
  195. let temp = {
  196. nodeIdentifier: null,
  197. dataType: null,
  198. label: this.itemList[i].itemName,
  199. nodeIndex: this.itemList[i].nodeIndex,
  200. itemName: this.itemList[i].itemName,
  201. itemReadName: this.itemList[i].itemReadName,
  202. dataModelId: this.itemList[i].dataModelId,
  203. value: this.itemList[i].itemReadName,
  204. checked: false,
  205. };
  206. arr.push(temp)
  207. }
  208. this.chooseItemDataListByTree = arr
  209. //获取数据源的驱动数据项信息
  210. this.getDriverItemBySouceId(this.dataSourceId)
  211. loading.close()
  212. })
  213. },
  214. /** 弹窗关闭事件 */
  215. handleClose() {
  216. this.dataSourceId = null
  217. this.treeItemName = []
  218. this.treeData = []
  219. this.leavesList = []
  220. this.chooseItemDataListByTree = []
  221. this.filterLabelText = null
  222. this.filterLeavesText = null
  223. },
  224. /** 查询改数据源下的驱动数据项信息 */
  225. getDriverItemBySouceId(id) {
  226. this.queryParams.id = id;
  227. getDriverItemBySouceId(id).then((res) => {``
  228. if (res.code === 200) {
  229. this.DriverItemData = res.data;
  230. }
  231. });
  232. },
  233. /** 跳转到配置数据项表达式 */
  234. gotoItemConfig() {
  235. if (this.chooseItemDataListByTree.length == 0) {
  236. this.$message({
  237. message: '请选择数据项!',
  238. type: 'warning'
  239. });
  240. return;
  241. }
  242. this.$refs.itemConfigModel.title = '数据项表达式配置'
  243. this.$refs.itemConfigModel.visible = true
  244. this.$refs.itemConfigModel.leavesChooseList = this.chooseItemDataListByTree
  245. this.$refs.itemConfigModel.tableTotal = this.chooseItemDataListByTree.length
  246. let arr = [];
  247. for (let i = 0; i < this.chooseItemDataListByTree.length; i++) {
  248. let temp = this.chooseItemDataListByTree[i];
  249. let dataModelId = this.chooseItemDataListByTree[i].dataModelId
  250. for (let j = 0; j < this.dataModelList.length; j++) {
  251. if (this.dataModelList[j].id == dataModelId) {
  252. temp.remark = this.dataModelList[j].remark
  253. break
  254. }
  255. }
  256. arr.push(temp)
  257. }
  258. this.$refs.itemConfigModel.tableData = arr
  259. this.$refs.itemConfigModel.dataModelList = this.dataModelList
  260. },
  261. /** 将数据项选择的信息,传递给父组件 */
  262. saveItemChoose(datas) {
  263. this.$emit('saveItemChoose', datas)
  264. },
  265. /** 获取树节点的下级信息 */
  266. getNextAllItem(dataSourceId, itemName, callback) {
  267. getNextAllItem(dataSourceId, itemName).then((res) => {
  268. let data = {}
  269. this.filterLeavesText = "";
  270. let datas = res.data.label;
  271. let leaves = res.data.leaves;
  272. // 模拟数据
  273. let dataList = [];
  274. if (datas && datas.length > 0) {
  275. datas.forEach((t) => {
  276. dataList.push({
  277. dataSourceId: dataSourceId,
  278. label: t.itemName,
  279. leaf: false,
  280. children: [],
  281. });
  282. });
  283. }
  284. let leavesList = [];
  285. if (leaves && leaves.length > 0) {
  286. leaves.forEach((t) => {
  287. t.label = t.itemName;
  288. t.value = t.itemReadName;
  289. t.checked = false;
  290. leavesList.push(t);
  291. });
  292. }
  293. data.children = dataList
  294. data.leaves = leavesList
  295. callback(data);
  296. })
  297. },
  298. /** 过滤树节点事件 */
  299. filterLabelEvent(value, data) {
  300. if (!value) return true;
  301. return data.label.indexOf(value) !== -1;
  302. },
  303. /** 数据项点击事件 */
  304. handleLabelNodeClick(d, n, t) {
  305. let itemNames = [];
  306. extractDataItemValues(n, itemNames);
  307. let itemName = itemNames.reverse().join("!@");
  308. this.queryParams.chooseItemStr = itemName;
  309. const loading = showLoading(this, "加载中,请稍候···");
  310. if ((!d.children || d.children.length == 0) && (!d.leaves || d.leaves.length == 0)) {
  311. this.getNextAllItem(this.dataSourceId, itemName, (data) => {
  312. //加载树
  313. d.children = data.children
  314. let leaves = data.leaves
  315. d.leaves = leaves
  316. //加载虚拟列表,叶节点
  317. this.leavesList = leaves
  318. this.leavesListF = leaves
  319. loading.close();
  320. })
  321. } else {
  322. if (d.leaves) {
  323. let leaves = d.leaves
  324. this.leavesList = leaves
  325. this.leavesListF = leaves
  326. }
  327. loading.close();
  328. }
  329. },
  330. /** 过滤叶节点事件 */
  331. filterLeavesEvent(value) {
  332. let arr = JSON.parse(JSON.stringify(this.leavesListF));
  333. if (!value || !value.trim()) {
  334. this.leavesList = arr;
  335. return;
  336. }
  337. let filterList = arr.filter((v) => {
  338. return v.itemName.indexOf(value) !== -1;
  339. });
  340. this.leavesList = filterList;
  341. },
  342. /** 全选叶节点事件 */
  343. handleCheckAllLeavesChange(flag) {
  344. this.$refs.pvc.checkedAll(flag);
  345. },
  346. /** 是否全部选中 */
  347. checkChangeAllLeaves(flag) {
  348. this.isSelectAllLeaves = flag;
  349. },
  350. /** 查看选中的所有叶节点状态,并将checked为true的填入到选中的叶节点中 */
  351. checkChangeLeaves(datas) {
  352. this.leavesChooseList = [];
  353. if (!datas || datas.length == 0) {
  354. return;
  355. }
  356. datas.forEach((data) => {
  357. if (data.checked) {
  358. this.leavesChooseList.push(data);
  359. }
  360. });
  361. },
  362. /** 将选择的叶节点添加到右边,成为数据项 */
  363. addCheckNodesBtnEvent() {
  364. // 根据当前选择节点拼接为:XXXX.XXXX.XXX
  365. let chooseChannelNameList = [];
  366. if (this.leavesChooseList.length == 0) {
  367. this.$message({
  368. message: '请选择数据项!',
  369. type: 'warning'
  370. });
  371. return;
  372. }
  373. for (let i = 0; i < this.leavesChooseList.length; i++) {
  374. let temp = {
  375. nodeIdentifier: null,
  376. dataType: this.leavesChooseList[i].dataType,
  377. label: this.leavesChooseList[i].fullPath,
  378. nodeIndex: this.leavesChooseList[i].nodeIndex,
  379. itemName: this.leavesChooseList[i].fullPath,
  380. // itemName: this.leavesChooseList[i].itemName,
  381. itemReadName: this.leavesChooseList[i].itemReadName,
  382. value: this.leavesChooseList[i].itemReadName,
  383. checked: false,
  384. };
  385. chooseChannelNameList.push(temp);
  386. }
  387. // 去重
  388. let arr = JSON.parse(JSON.stringify(this.chooseItemDataListByTree));
  389. if (arr.length == 0) {
  390. arr = chooseChannelNameList;
  391. } else {
  392. let status = false;
  393. for (let i in chooseChannelNameList) {
  394. let flag = false;
  395. for (let j in arr) {
  396. let tName = arr[j].label ? arr[j].label : arr[j].itemName;
  397. if (chooseChannelNameList[i].label == tName) {
  398. flag = true;
  399. if (!status) {
  400. status = true;
  401. }
  402. break;
  403. }
  404. }
  405. if (!flag) {
  406. arr.push(chooseChannelNameList[i]);
  407. }
  408. }
  409. if (status) {
  410. this.$message({
  411. message: '请注意,选择的数据项中含有重复的项',
  412. type: 'warning'
  413. });
  414. }
  415. }
  416. this.handleCheckAllLeavesChange(false);
  417. this.$nextTick(() => {
  418. this.chooseItemDataListByTree = arr;
  419. this.isSelectAllItem = false;
  420. this.isSelectAllLeaves = false;
  421. this.leavesChooseList = [];
  422. this.$refs.itemTree.setCheckedKeys([]);
  423. });
  424. },
  425. /** 将右边选择的数据项移除 */
  426. removeCheckNodesBtnEvent() {
  427. let _temp = this.chooseItemDataListByTree;
  428. if (!_temp || _temp.length == 0) {
  429. return;
  430. }
  431. for (let i = _temp.length - 1; i >= 0; i--) {
  432. if (_temp[i].checked) {
  433. this.chooseItemDataListByTree.splice(i, 1);
  434. }
  435. }
  436. // 重置选择
  437. this.isSelectAllItem = false;
  438. this.$refs.itemTree.setCheckedKeys([]);
  439. this.selectAllItem(false);
  440. },
  441. /** 将右边所有的数据项移除 */
  442. removeAllCheckNodesBtnEvent() {
  443. if (this.chooseItemDataListByTree.length == 0) {
  444. return;
  445. }
  446. this.isSelectAllItem = false;
  447. this.chooseItemDataListByTree = [];
  448. },
  449. /** 数据项全选事件 */
  450. selectAllItem(val) {
  451. this.$refs.pvcChoose.checkedAll(val);
  452. },
  453. /** 是否全部选中监听器 */
  454. checkChangeAllChoose(flag) {
  455. this.isSelectAllItem = flag;
  456. },
  457. /** 选中的数据项信息 */
  458. checkChangeChoose(datas) {
  459. this.chooseItemDataListByTree = datas;
  460. },
  461. /** 复合筛选 */
  462. getCompositeScreen() {
  463. let params = {};
  464. params.id = this.queryParams.id
  465. params.chooseItemStr = this.queryParams.chooseItemStr
  466. params.needItemStr = JSON.stringify(this.queryParams.needItemStr)
  467. //得到选择的所有节点
  468. const treeArr = this.$refs.itemTree.getCheckedNodes();
  469. const treeQ = document.getElementsByClassName('el-tree cy-group-tree el-tree--highlight-current')[0]
  470. .getElementsByClassName('el-tree-node__content');
  471. let seTreeArr = []
  472. //赛选出需要的节点
  473. if (treeArr.length > 0) {
  474. for (let i = 0; i < treeQ.length; i++) {
  475. const parentClass = treeQ[i].parentElement.classList;
  476. if (parentClass.contains('is-current') && !parentClass.contains('is-hidden')) {
  477. // 选择的层级
  478. let treechild = treeQ[i].nextElementSibling.getElementsByClassName('el-tree-node__content');
  479. for (let j = 0; j < treechild.length; j++) {
  480. const clz = treechild[j].parentElement.classList;
  481. if (clz.contains('is-checked') && !clz.contains('is-hidden')) {
  482. seTreeArr.push(treechild[j].textContent)
  483. }
  484. }
  485. break;
  486. }
  487. }
  488. }
  489. params.nextItemStr = JSON.stringify(seTreeArr)
  490. if (!seTreeArr || seTreeArr.length == 0) {
  491. this.$message({
  492. message: '节点选择为空',
  493. type: 'warning'
  494. });
  495. return
  496. }
  497. if (!this.queryParams.needItemStr || this.queryParams.needItemStr.length == 0) {
  498. this.$message({
  499. message: '复合筛选属性不能为空',
  500. type: 'warning'
  501. });
  502. return
  503. }
  504. const loading = showLoading(this, "筛选中,请稍候···");
  505. getCompositeScreen(params).then((res) => {
  506. if (res.code === 200) {
  507. let treeData = this.chooseItemDataListByTree ? this.chooseItemDataListByTree : [];
  508. if (res.data && res.data.length > 0) {
  509. let lodArr = [];
  510. for (let j = 0; j < res.data.length; j++) {
  511. lodArr.push(res.data[j].label ? res.data[j].label : res.data[j].itemName);
  512. }
  513. let status = false;
  514. let idArr = {}
  515. for (let i = 0; i < treeData.length; i++) {
  516. if (lodArr.indexOf(treeData[i].label) !== -1) {
  517. idArr[lodArr.indexOf(treeData[i].label)] = '1'
  518. }
  519. }
  520. for (let j = 0; j < res.data.length; j++) {
  521. if (!idArr[j]) {
  522. treeData.push(res.data[j])
  523. } else {
  524. status = true;
  525. }
  526. }
  527. if (status) {
  528. this.$message({
  529. message: '请注意,选择的数据项中含有重复的项',
  530. type: 'warning'
  531. });
  532. }
  533. }
  534. this.checkChangeAllLeaves(false);
  535. this.$nextTick(() => {
  536. this.chooseItemDataListByTree = treeData;
  537. this.isSelectAllItem = false;
  538. this.isSelectAllLeaves = false;
  539. this.leavesChooseList = [];
  540. this.$refs.itemTree.setCheckedKeys([]);
  541. this.$refs.itemTree.setCheckedNodes([]);
  542. });
  543. if (!res.data || res.data.length === 0) {
  544. this.$message({
  545. message: '没有筛选出符合条件的数据项,请重新筛选',
  546. type: 'warning'
  547. });
  548. }
  549. loading.close()
  550. }
  551. }).catch((e) => {
  552. this.$message({
  553. message: e,
  554. type: 'warning'
  555. });
  556. loading.close()
  557. });
  558. },
  559. /** 查询所有模型数据 */
  560. getAllDataModel() {
  561. let queryParams = {
  562. page: 1,
  563. limit: 9999,
  564. operationRule: null
  565. }
  566. getAllDataModel(queryParams).then(res => {
  567. if (!res || !res.data) {
  568. this.$message({
  569. message: '数据查询失败!',
  570. type: 'warning'
  571. })
  572. return
  573. }
  574. this.dataModelList = res.data.dataModelList
  575. })
  576. }
  577. }
  578. }
  579. </script>
  580. <style rel="stylesheet/scss" lang="scss" scoped>
  581. @import './itemChooseTree.css';
  582. .dialog-max {
  583. height: 85vh;
  584. .el-dialog__body {
  585. height: 72vh;
  586. overflow: hidden;
  587. }
  588. }
  589. </style>