Preview.vue 4.5 KB

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