Preview.vue 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. <template>
  2. <XModal title="预览" v-model="preview.open">
  3. <div class="flex">
  4. <el-card class="w-1/4" :gutter="12" shadow="hover">
  5. <el-scrollbar height="calc(100vh - 88px - 40px - 50px)">
  6. <el-tree
  7. ref="treeRef"
  8. node-key="id"
  9. :data="preview.fileTree"
  10. :expand-on-click-node="false"
  11. highlight-current
  12. @node-click="handleNodeClick"
  13. />
  14. </el-scrollbar>
  15. </el-card>
  16. <el-card class="w-3/4 ml-3" :gutter="12" shadow="hover">
  17. <el-tabs v-model="preview.activeName">
  18. <el-tab-pane
  19. v-for="item in previewCodegen"
  20. :label="item.filePath.substring(item.filePath.lastIndexOf('/') + 1)"
  21. :name="item.filePath"
  22. :key="item.filePath"
  23. >
  24. <XTextButton style="float: right" :title="t('common.copy')" @click="copy(item.code)" />
  25. <pre>{{ item.code }}</pre>
  26. </el-tab-pane>
  27. </el-tabs>
  28. </el-card>
  29. </div>
  30. </XModal>
  31. </template>
  32. <script setup lang="ts">
  33. import { reactive, ref, unref } from 'vue'
  34. import { useClipboard } from '@vueuse/core'
  35. import { ElCard, ElTree, ElTabs, ElTabPane } from 'element-plus'
  36. import { useI18n } from '@/hooks/web/useI18n'
  37. import { useMessage } from '@/hooks/web/useMessage'
  38. import { handleTree2 } from '@/utils/tree'
  39. import { previewCodegenApi } from '@/api/infra/codegen'
  40. import { CodegenTableVO, CodegenPreviewVO } from '@/api/infra/codegen/types'
  41. const { t } = useI18n() // 国际化
  42. const message = useMessage() // 消息弹窗
  43. // ======== 显示页面 ========
  44. const preview = reactive({
  45. open: false,
  46. titel: '代码预览',
  47. fileTree: [],
  48. activeName: ''
  49. })
  50. const previewCodegen = ref<CodegenPreviewVO[]>()
  51. const show = async (row: CodegenTableVO) => {
  52. const res = await previewCodegenApi(row.id)
  53. let file = handleFiles(res)
  54. previewCodegen.value = res
  55. preview.fileTree = handleTree2(file, 'id', 'parentId', 'children', '/')
  56. preview.activeName = res[0].filePath
  57. preview.open = true
  58. }
  59. const handleNodeClick = async (data, node) => {
  60. if (node && !node.isLeaf) {
  61. return false
  62. }
  63. preview.activeName = data.id
  64. }
  65. /** 生成 files 目录 **/
  66. interface filesType {
  67. id: string
  68. label: string
  69. parentId: string
  70. }
  71. const handleFiles = (datas: CodegenPreviewVO[]) => {
  72. let exists = {} // key:file 的 id;value:true
  73. let files: filesType[] = []
  74. // 遍历每个元素
  75. for (const data of datas) {
  76. let paths = data.filePath.split('/')
  77. let fullPath = '' // 从头开始的路径,用于生成 id
  78. // 特殊处理 java 文件
  79. if (paths[paths.length - 1].indexOf('.java') >= 0) {
  80. let newPaths: string[] = []
  81. for (let i = 0; i < paths.length; i++) {
  82. let path = paths[i]
  83. if (path !== 'java') {
  84. newPaths.push(path)
  85. continue
  86. }
  87. newPaths.push(path)
  88. // 特殊处理中间的 package,进行合并
  89. let tmp = ''
  90. while (i < paths.length) {
  91. path = paths[i + 1]
  92. if (
  93. path === 'controller' ||
  94. path === 'convert' ||
  95. path === 'dal' ||
  96. path === 'enums' ||
  97. path === 'service' ||
  98. path === 'vo' || // 下面三个,主要是兜底。可能考虑到有人改了包结构
  99. path === 'mysql' ||
  100. path === 'dataobject'
  101. ) {
  102. break
  103. }
  104. tmp = tmp ? tmp + '.' + path : path
  105. i++
  106. }
  107. if (tmp) {
  108. newPaths.push(tmp)
  109. }
  110. }
  111. paths = newPaths
  112. }
  113. // 遍历每个 path, 拼接成树
  114. for (let i = 0; i < paths.length; i++) {
  115. // 已经添加到 files 中,则跳过
  116. let oldFullPath = fullPath
  117. // 下面的 replaceAll 的原因,是因为上面包处理了,导致和 tabs 不匹配,所以 replaceAll 下
  118. fullPath = fullPath.length === 0 ? paths[i] : fullPath.replaceAll('.', '/') + '/' + paths[i]
  119. if (exists[fullPath]) {
  120. continue
  121. }
  122. // 添加到 files 中
  123. exists[fullPath] = true
  124. files.push({
  125. id: fullPath,
  126. label: paths[i],
  127. parentId: oldFullPath || '/' // "/" 为根节点
  128. })
  129. }
  130. }
  131. return files
  132. }
  133. /** 复制 **/
  134. const copy = async (text: string) => {
  135. const { copy, copied, isSupported } = useClipboard({ source: text })
  136. if (!isSupported) {
  137. message.error(t('common.copyError'))
  138. } else {
  139. await copy()
  140. if (unref(copied)) {
  141. message.success(t('common.copySuccess'))
  142. }
  143. }
  144. }
  145. defineExpose({
  146. show
  147. })
  148. </script>