Preview.vue 4.8 KB

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