tree.vue 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. <template>
  2. <div class="tree-wrapper card-shadow">
  3. <el-input
  4. v-model="filterText"
  5. placeholder="输入关键字过滤"
  6. @input="funfilterChange"
  7. />
  8. <el-tree
  9. class="treeRef"
  10. ref="treeRef"
  11. :data="props.data"
  12. :show-checkbox="props.showCheckbox"
  13. default-expand-all
  14. node-key="id"
  15. highlight-current
  16. :props="defaultProps"
  17. :current-node-key="''"
  18. @check="funCheckChange"
  19. :expand-on-click-node="false"
  20. @node-click="funCurrentChange"
  21. :filter-node-method="funTreeFilter"
  22. >
  23. <template #default="{ node, data }">
  24. <p v-if="node.level === 1" class="dashboard-tree-title">
  25. <span>{{ node.label }}</span>
  26. <el-icon
  27. class="refresh"
  28. size="14"
  29. title="刷新"
  30. @click.stop="emits('refresh')"
  31. >
  32. <RefreshRight />
  33. </el-icon>
  34. </p>
  35. <el-dropdown
  36. ref="dropdown1"
  37. v-else
  38. size="small"
  39. trigger="contextmenu"
  40. @command="funCommand"
  41. style="color: #b3bdc0"
  42. >
  43. <span class="el-dropdown-link">
  44. <el-icon>
  45. <Folder
  46. v-if="!node.expanded || (node.isLeaf && !node.isCurrent)"
  47. />
  48. <FolderOpened v-else />
  49. </el-icon>
  50. {{ node.label }}
  51. </span>
  52. <template #dropdown>
  53. <el-dropdown-menu>
  54. <el-dropdown-item
  55. v-if="props.dropdownMenu.includes('save')"
  56. :command="{ type: 'save', data, node }"
  57. >保存</el-dropdown-item
  58. >
  59. <el-dropdown-item
  60. v-if="
  61. data.childs &&
  62. data.childs.length &&
  63. props.dropdownMenu.includes('export')
  64. "
  65. :command="{ type: 'export', data, node }"
  66. >导出
  67. </el-dropdown-item>
  68. <el-dropdown-item
  69. v-if="props.dropdownMenu.includes('delete')"
  70. :command="{ type: 'delete', data, node }"
  71. >删除</el-dropdown-item
  72. >
  73. </el-dropdown-menu>
  74. </template>
  75. </el-dropdown>
  76. </template>
  77. </el-tree>
  78. </div>
  79. </template>
  80. <script setup name="search">
  81. import { ref, defineExpose, defineEmits, defineProps } from "vue";
  82. import {
  83. fittingCurveSave,
  84. dataOptionDel,
  85. filesDel,
  86. } from "@/api/powerGenerating/index.js";
  87. import { ElMessage, ElMessageBox } from "element-plus";
  88. const baseURL = process.env.VUE_APP_TEST;
  89. const socketURL = process.env.WS_APP_TEST;
  90. const emits = defineEmits(["currentChange", "checkChange", "refresh"]);
  91. const props = defineProps({
  92. data: {
  93. type: Array,
  94. default: () => {},
  95. },
  96. showCheckbox: {
  97. type: Boolean,
  98. default: false,
  99. },
  100. type: {
  101. type: String,
  102. default: "wind",
  103. },
  104. dropdownMenu: {
  105. type: Array,
  106. default: () => ["export", "delete"],
  107. },
  108. });
  109. const treeRef = ref();
  110. const filterText = ref("");
  111. /**输入框过滤 */
  112. const funfilterChange = () => {
  113. treeRef.value.filter(filterText.value);
  114. };
  115. const funTreeFilter = (value, data) => {
  116. if (!value) return true;
  117. return data.label.includes(value);
  118. };
  119. /**选中节点变化 */
  120. const funCurrentChange = (current, currentNode) => {
  121. emits("currentChange", { current, currentNode });
  122. };
  123. /**复选框选中变化 */
  124. const funCheckChange = (
  125. current,
  126. { checkedNodes, checkedKeys, halfCheckedNodes, halfCheckedKeys }
  127. ) => {
  128. emits("checkChange", {
  129. current,
  130. checkedNodes,
  131. checkedKeys,
  132. halfCheckedNodes,
  133. halfCheckedKeys,
  134. });
  135. };
  136. //右键时, command菜单
  137. const funCommand = async ({ type, data, node }) => {
  138. switch (type) {
  139. case "save":
  140. /**该保存功能目前暂用于风电场, combine页 */
  141. if (props.type !== "wind") {
  142. return false;
  143. }
  144. ElMessageBox.confirm("确认保存当前节点的拟合功率?", "保存", {
  145. confirmButtonText: "确认",
  146. cancelButtonText: "取消",
  147. type: "warning",
  148. }).then(async () => {
  149. let saveArr = [];
  150. const repeatArr = (arr, saveArr) => {
  151. for (const unit of arr) {
  152. if (unit.childs?.length) {
  153. saveArr.push(...unit.childs.map((o) => o.id));
  154. } else if (unit.children?.length) {
  155. repeatArr(unit.children, saveArr);
  156. }
  157. }
  158. };
  159. if (data.childs?.length) {
  160. saveArr = data.childs.map((o) => o.id);
  161. } else if (data.children?.length) {
  162. repeatArr(data.children, saveArr);
  163. }
  164. let res = { code: 500 };
  165. res = await fittingCurveSave({ ids: saveArr.join(",") }); //删除当前节点
  166. if (res.code === 200) {
  167. ElMessage.success(res.msg);
  168. }
  169. });
  170. break;
  171. case "export":
  172. ElMessageBox.confirm("确认导出当前节点的所有数据?", "导出", {
  173. confirmButtonText: "确认",
  174. cancelButtonText: "取消",
  175. type: "warning",
  176. }).then(() => {
  177. const a = document.createElement("a");
  178. let childs = [];
  179. childs =
  180. props.type === "wind"
  181. ? data.childs.map((o) => o.id)
  182. : data.childs.map((o) => o.path);
  183. const url =
  184. props.type === "wind"
  185. ? "/data/option/download?ids="
  186. : "/export/files?filename=";
  187. a.href = baseURL + url + childs.join(",");
  188. a.download = "";
  189. a.target = "_blank";
  190. a.click();
  191. });
  192. break;
  193. case "delete":
  194. ElMessageBox.confirm("确认删除当前节点的所有数据?", "删除", {
  195. confirmButtonText: "确认",
  196. cancelButtonText: "取消",
  197. type: "warning",
  198. }).then(async () => {
  199. let deleteArr = [];
  200. const repeatArr = (arr, deleteArr) => {
  201. for (const unit of arr) {
  202. if (unit.childs?.length) {
  203. deleteArr.push(
  204. ...unit.childs.map((o) =>
  205. props.type === "wind" ? o.id : o.path
  206. )
  207. );
  208. } else if (unit.children?.length) {
  209. repeatArr(unit.children, deleteArr);
  210. }
  211. }
  212. };
  213. if (data.childs?.length) {
  214. deleteArr = data.childs.map((o) =>
  215. props.type === "wind" ? o.id : o.path
  216. );
  217. } else if (data.children?.length) {
  218. repeatArr(data.children, deleteArr);
  219. }
  220. let res = { code: 500 };
  221. if (props.type === "wind") {
  222. res = await dataOptionDel({ ids: deleteArr.join(",") }); //删除当前节点
  223. } else {
  224. res = await filesDel({ filename: deleteArr.join(",") }); //删除当前节点
  225. }
  226. if (res.code === 200) {
  227. ElMessage.success(res.msg);
  228. emits("refresh");
  229. }
  230. });
  231. break;
  232. }
  233. };
  234. const getCheckedNodes = () => {
  235. // // console.log(treeRef.value!.getCheckedNodes(false, false));
  236. };
  237. const getCheckedKeys = () => {
  238. // // console.log(treeRef.value!.getCheckedKeys(false));
  239. };
  240. const setCheckedNodes = () => {
  241. treeRef.value.setCheckedNodes(
  242. [
  243. {
  244. id: 5,
  245. label: "Level two 2-1",
  246. },
  247. {
  248. id: 9,
  249. label: "Level three 1-1-1",
  250. },
  251. ],
  252. false
  253. );
  254. };
  255. const setCheckedKeys = (keyArr) => {
  256. treeRef.value.setCheckedKeys(keyArr, false);
  257. };
  258. const resetChecked = () => {
  259. treeRef.value.setCheckedKeys([], false);
  260. };
  261. const defaultProps = {
  262. children: "children",
  263. label: "label",
  264. };
  265. defineExpose({ setCheckedKeys });
  266. </script>
  267. <style lang="less" scoped>
  268. .tree-wrapper {
  269. height: 100%;
  270. ;
  271. padding: 20px;
  272. .treeRef {
  273. height: calc(100% - 30px - 20px);
  274. width: 100%;
  275. margin-top: 10px;
  276. padding: 10px 0;
  277. overflow: auto;
  278. .dashboard-tree-title {
  279. display: flex;
  280. justify-content: space-between;
  281. width: 100%;
  282. }
  283. .refresh {
  284. margin-right: 15px;
  285. }
  286. }
  287. }
  288. .el-tree::v-deep {
  289. .el-tree-node__content:hover,
  290. .el-tree-node__content:active {
  291. background: rgba(97, 97, 90, 25%);
  292. }
  293. &.el-tree--highlight-current
  294. .el-tree-node.is-current
  295. > .el-tree-node__content {
  296. background: rgba(97, 97, 90, 25%);
  297. }
  298. }
  299. </style>