PageTree.vue 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. <script setup lang="ts">
  2. import {onMounted, ref} from "vue";
  3. import {
  4. deleteById,
  5. fileSave,
  6. folderSave,
  7. getPermissionsByUserCode,
  8. getReportCenterTree,
  9. modifyTheFileName,
  10. move
  11. } from "@/api/base-data/report-center";
  12. import {CyMessageBox} from "@/components/cy/message-box";
  13. import {SaveFile} from "@/api/base-data/type/magic-api";
  14. import {useCompRef} from "@/utils/useCompRef";
  15. import {ElTree} from "element-plus";
  16. import {Document, Folder} from "@element-plus/icons-vue";
  17. import RightClickMenu from "@/components/menu-item/RightClickMenu.vue";
  18. import {ReportForms} from "@/api/reports/report-query-center";
  19. import {createFile, pageHelpV2Mitt, REPORT_FOLDER} from "@/views/data-base/page-editor-help-v2/page-help-v2";
  20. import type Node from 'element-plus/es/components/tree/src/model/node'
  21. import type {DragEvents} from 'element-plus/es/components/tree/src/model/useDragNode'
  22. import type {
  23. NodeDropType,
  24. } from 'element-plus/es/components/tree/src/tree.type'
  25. import CyAutoSize from "@/components/cy/auto-size/cy-auto-size.vue";
  26. import {useElementSize} from "@vueuse/core";
  27. enum FILE_ENUM {
  28. FILE = 0,
  29. FOLDER = 1,
  30. }
  31. interface Props {
  32. nodeClick?: (data: ReportForms) => void,
  33. editor?: boolean
  34. }
  35. //@ts-ignore
  36. const props = withDefaults(defineProps<Props>(), {
  37. editor: false,
  38. })
  39. const treeData = ref([])
  40. const treeRef = useCompRef(ElTree)
  41. const mousePosition = ref()
  42. const inputValue = ref('')
  43. const headerRef = ref()
  44. const {height: headerHeight} = useElementSize(headerRef)
  45. function generateRandomPath() {
  46. const characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
  47. let result = '';
  48. let lastCharTypeIsLowerCase = true; // 用于记录上一个字符是否为小写
  49. // 第一个字符为小写
  50. result += characters.charAt(Math.floor(Math.random() * 26));
  51. for (let i = 1; i < 7; i++) {
  52. let charIndex;
  53. if (lastCharTypeIsLowerCase) {
  54. charIndex = Math.floor(Math.random() * 52);
  55. } else {
  56. charIndex = Math.floor(Math.random() * 26);
  57. }
  58. result += characters.charAt(charIndex);
  59. lastCharTypeIsLowerCase = (charIndex < 26); // 判断当前字符类型
  60. }
  61. return "/" + result;
  62. }
  63. async function createANewReport(flag: FILE_ENUM, parentId: string = REPORT_FOLDER) {
  64. const res = await CyMessageBox.prompt({
  65. message: `输入 ${flag === FILE_ENUM.FILE ? '文件' : '文件夹'} 名称!`,
  66. type: "info"
  67. })
  68. const path = generateRandomPath();
  69. if (flag === FILE_ENUM.FILE) {
  70. const data: SaveFile = {
  71. groupId: parentId,
  72. headers: [],
  73. method: 'POST',
  74. name: res.value,
  75. options: [],
  76. parameters: [],
  77. path: generateRandomPath(),
  78. paths: [],
  79. script: `var data = db.select("""""")
  80. return {
  81. data: data,
  82. columns: []
  83. }`,
  84. pageJson: createFile()
  85. }
  86. await fileSave(data)
  87. } else {
  88. await folderSave({name: res.value, path, parentId, type: 'api'})
  89. }
  90. queryData()
  91. }
  92. const contextmenu = (event: Event, data: ReportForms) => {
  93. if (!props.editor) {
  94. return
  95. }
  96. mousePosition.value = {
  97. event,
  98. data: data,
  99. index: data['$treeNodeId']
  100. }
  101. }
  102. const config = [
  103. {
  104. name: '新增文件夹',
  105. click: (data) => {
  106. createANewReport(FILE_ENUM.FOLDER, data.id)
  107. }
  108. },
  109. {
  110. name: '新增文件',
  111. click: (data) => {
  112. createANewReport(FILE_ENUM.FILE, data.id)
  113. }
  114. },
  115. {
  116. name: '修改文件名',
  117. click: async (data) => {
  118. const box = await CyMessageBox.prompt({
  119. message: `输入新的文件名!`,
  120. type: 'info',
  121. inputDefaultValue: data.name
  122. })
  123. await modifyTheFileName({
  124. id: data.id,
  125. name: box.value,
  126. type: data.type
  127. })
  128. data.name = box.value
  129. }
  130. },
  131. {
  132. name: '删除',
  133. click: async (data) => {
  134. await CyMessageBox.confirm({
  135. message: `确认删除【${data.name}】吗?`
  136. })
  137. await deleteById(data.id)
  138. queryData()
  139. }
  140. }
  141. ]
  142. function nodeClick(data: ReportForms) {
  143. if (data.type === 1) {
  144. return
  145. }
  146. if (props.nodeClick) {
  147. props.nodeClick(data)
  148. } else {
  149. pageHelpV2Mitt.emit('changePageJson', data)
  150. }
  151. }
  152. function handleDragEnd(
  153. draggingNode: Node,
  154. dropNode: Node,
  155. dropType: NodeDropType,
  156. _ev: DragEvents) {
  157. let src = draggingNode.data.id
  158. let groupId = ''
  159. if (dropType === 'inner') {
  160. groupId = dropNode.data.id
  161. } else {
  162. groupId = dropNode.data.parentId || REPORT_FOLDER
  163. }
  164. move(src, groupId)
  165. }
  166. function queryData() {
  167. getReportCenterTree().then(res => {
  168. treeData.value = res
  169. })
  170. }
  171. function handleInputChange(val) {
  172. treeRef.value!.filter(val)
  173. }
  174. function handelFilter(value, data) {
  175. return data.name.includes(value)
  176. }
  177. function rowClick(row) {
  178. getPermissionsByUserCode(row.code).then(res => {
  179. treeRef.value!.setCheckedKeys(res)
  180. })
  181. }
  182. onMounted(() => {
  183. queryData()
  184. pageHelpV2Mitt.on('queryTree', () => {
  185. queryData()
  186. })
  187. })
  188. </script>
  189. <template>
  190. <RightClickMenu v-if="props.editor" :config="config" :mouse-position="mousePosition"/>
  191. <cy-auto-size>
  192. <template #default="{height , width}">
  193. <div ref="headerRef">
  194. <div v-if="props.editor">
  195. <el-button-group>
  196. <el-button @click="createANewReport(FILE_ENUM.FOLDER)"> 文件夹</el-button>
  197. <el-button @click="createANewReport(FILE_ENUM.FILE)">文件</el-button>
  198. </el-button-group>
  199. </div>
  200. <div>
  201. <el-input placeholder="搜索报表" @input="handleInputChange" v-model="inputValue"/>
  202. </div>
  203. </div>
  204. <div :style="{height : height - headerHeight - 10 + 'px' , width: width - 5 + 'px' }" style="overflow: auto">
  205. <el-tree :data="treeData"
  206. ref="treeRef"
  207. :filter-node-method="handelFilter"
  208. @node-click="nodeClick"
  209. @node-contextmenu="contextmenu"
  210. @node-drag-end="handleDragEnd"
  211. highlight-current
  212. :draggable="props.editor"
  213. node-key="id"
  214. default-expand-all>
  215. <template #default="{node,data}">
  216. <el-icon>
  217. <Document v-if="data.type === 0"/>
  218. <Folder v-else/>
  219. </el-icon>
  220. {{ data.name }}
  221. </template>
  222. </el-tree>
  223. </div>
  224. </template>
  225. </cy-auto-size>
  226. </template>
  227. <style scoped lang="scss">
  228. </style>