Parcourir la source

业务域:文件解析接口统一

Xiao_123 il y a 16 heures
Parent
commit
156da7802b

Fichier diff supprimé car celui-ci est trop grand
+ 783 - 199
package-lock.json


+ 2 - 0
package.json

@@ -21,12 +21,14 @@
     "@wangeditor/editor-for-vue": "^1.0.2",
     "axios": "^1.7.2",
     "core-js": "^3.8.3",
+    "docx-preview": "^0.3.7",
     "echarts": "^5.4.3",
     "element-resize-detector": "^1.2.4",
     "exceljs": "^4.4.0",
     "file-saver": "^2.0.1",
     "fs": "0.0.1-security",
     "handsontable": "^14.2.0",
+    "highlight.js": "^11.11.1",
     "html2canvas": "^1.4.1",
     "js-base64": "^3.7.4",
     "lodash": "^4.17.21",

+ 178 - 0
src/components/FileReview/indexCopy.vue

@@ -0,0 +1,178 @@
+<template>
+  <div>
+    <vue-office-excel ref="a" v-if="+type === 0" v-bind="$attrs" :src="src" @error="$emit('error', $event)" @rendered="handleRendered"/>
+  </div>
+</template>
+
+<script>
+import * as Excel from 'exceljs/dist/exceljs'
+// 引入VueOfficeExcel组件
+import VueOfficeExcel from '@vue-office/excel'
+// 引入相关样式
+import '@vue-office/excel/lib/index.css'
+
+const workbook = new Excel.Workbook()
+
+export default {
+  name: 'file-review',
+  components: {
+    VueOfficeExcel
+  },
+  props: {
+    // 预览类型 0: Excel
+    type: {
+      type: [Number, String],
+      default: 0
+    },
+    src: {
+      type: [String, File, ArrayBuffer],
+      default: ''
+    }
+  },
+  data () {
+    return {
+      worksheet: null,
+      rendered: 0
+    }
+  },
+  watch: {
+    src: {
+      async handler (val) {
+        await workbook.xlsx.load(val)
+        this.worksheet = workbook.worksheets[0]
+        this.handleRendered()
+      },
+      deep: true,
+      immediate: true
+    }
+  },
+  mounted () {
+    this.$nextTick(() => {
+      this.setupSheetClickHandler()
+    })
+  },
+  methods: {
+    setupSheetClickHandler () {
+      // 等待组件渲染完成
+      setTimeout(() => {
+        if (!this.$refs.a || !this.$refs.a.rootRef) {
+          return
+        }
+        try {
+          const _bottom = this.$refs.a.rootRef.childNodes[0]?.childNodes[3]
+          if (!_bottom) {
+            return
+          }
+          const _ul = _bottom.childNodes[1]
+          if (!_ul) {
+            return
+          }
+          _ul.addEventListener('click', (evt) => {
+            if (evt.target.localName === 'ul') {
+              return
+            }
+            this.worksheet = workbook.getWorksheet(evt.target.innerText)
+            this.$emit('click:bottom-bar', evt.target.innerText)
+          })
+        } catch (error) {
+          console.error('设置工作表点击事件失败:', error)
+        }
+      }, 500)
+    },
+    switchToFirstSheet () {
+      // 切换到第一个工作表
+      this.$nextTick(() => {
+        // 多次尝试,确保组件完全渲染
+        let attempts = 0
+        const maxAttempts = 10
+        const trySwitch = () => {
+          attempts++
+          if (!this.$refs.a || !this.$refs.a.rootRef) {
+            if (attempts < maxAttempts) {
+              setTimeout(trySwitch, 200)
+            }
+            return
+          }
+          try {
+            const rootNode = this.$refs.a.rootRef.childNodes[0]
+            if (!rootNode) {
+              if (attempts < maxAttempts) {
+                setTimeout(trySwitch, 200)
+              }
+              return
+            }
+            const _bottom = rootNode.childNodes[3]
+            if (!_bottom) {
+              if (attempts < maxAttempts) {
+                setTimeout(trySwitch, 200)
+              }
+              return
+            }
+            const _ul = _bottom.childNodes[1]
+            if (!_ul || !_ul.children || _ul.children.length === 0) {
+              if (attempts < maxAttempts) {
+                setTimeout(trySwitch, 200)
+              }
+              return
+            }
+            // 找到第一个可见的工作表标签
+            const sheetItems = Array.from(_ul.children).filter(li => {
+              return li.style.display !== 'none' && li.textContent && li.textContent.trim()
+            })
+            if (sheetItems.length > 0) {
+              const firstSheetLi = sheetItems[0]
+              // 检查是否已经是激活状态
+              if (!firstSheetLi.classList.contains('active')) {
+                firstSheetLi.click()
+                const sheetName = firstSheetLi.textContent.trim()
+                // 更新 worksheet 引用
+                try {
+                  this.worksheet = workbook.getWorksheet(sheetName)
+                } catch (e) {
+                  console.warn('无法获取工作表:', sheetName)
+                }
+              }
+            }
+          } catch (error) {
+            console.error('切换到第一个工作表失败:', error)
+          }
+        }
+        setTimeout(trySwitch, 500)
+      })
+    },
+    handleRendered () {
+      this.rendered++
+      if (this.rendered >= 2) {
+        // 渲染完成后,切换到第一个工作表
+        this.switchToFirstSheet()
+        this.$emit('rendered')
+        this.rendered = 0
+      }
+    },
+    getRow (index) {
+      const row = this.worksheet.getRow(index + 1)
+      let _merges = 0
+      const text = []
+      row.eachCell((cell, colNumber) => {
+        if (cell._mergeCount) {
+          _merges = cell._mergeCount + colNumber
+        }
+        if (_merges > colNumber) {
+          return
+        }
+        _merges = 0
+        if (typeof cell.value === 'object' && cell.value !== null) {
+          text.push(cell.value.text || cell.value.result || '格式异常')
+          return
+        }
+        text.push(cell.value)
+      })
+      return text
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+
+</style>

+ 314 - 0
src/views/dataGovernance/businessDomain/components/SourceFilePreview.vue

@@ -0,0 +1,314 @@
+<template>
+  <div class="source-file-preview">
+    <div class="d-flex flex-column" style="height: 100%;" elevation="5">
+      <div class="d-flex justify-end mr-3 my-3">
+        <v-btn color="primary" small @click="handleViewParsedData">
+          <v-icon left>mdi-table-eye</v-icon>
+          查看解析数据
+        </v-btn>
+      </div>
+      <div class="preview-content" v-loading="loading">
+        <!-- Excel 预览 -->
+        <ExcelPage
+          v-if="fileType === 'xls' || fileType === 'xlsx'"
+          ref="excelPage"
+          :data-source="fileData"
+          :render-sheet="false"
+        ></ExcelPage>
+
+        <!-- PDF 预览 -->
+        <iframe v-else-if="fileType === 'pdf'" :src="pdfUrl" style="width: 100%; height: 100%; border: none;"></iframe>
+
+        <!-- DOCX 预览 -->
+        <div v-else-if="fileType === 'docx'" ref="docxContainer" class="docx-container"></div>
+
+        <!-- SQL 预览 -->
+        <div v-else-if="fileType === 'sql'" class="sql-preview" v-html="highlightedSql"></div>
+
+        <!-- TXT 预览 -->
+        <div v-else-if="fileType === 'txt'" class="txt-preview">{{ txtContent }}</div>
+
+        <!-- 不支持的文件类型 -->
+        <div v-else class="d-flex align-center justify-center" style="height: 100%;">
+          <div class="text-center">
+            <v-icon size="64" color="grey">mdi-file-question</v-icon>
+            <div class="mt-4 grey--text">不支持的文件类型</div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import ExcelPage from './excel/index.vue'
+import hljs from 'highlight.js'
+import 'highlight.js/styles/monokai.css'
+import { renderAsync } from 'docx-preview'
+import { handleReadFile } from '@/utils/file'
+
+export default {
+  name: 'SourceFilePreview',
+  components: {
+    ExcelPage
+  },
+  props: {
+    file: {
+      type: File,
+      default: null
+    },
+    fileType: {
+      type: String,
+      default: null
+    },
+    fileUrl: {
+      type: String,
+      default: null
+    }
+  },
+  data () {
+    return {
+      loading: false,
+      fileData: null,
+      pdfUrl: null,
+      sqlContent: '',
+      txtContent: '',
+      currentFile: null // 内部文件对象,避免直接修改 prop
+    }
+  },
+  computed: {
+    highlightedSql () {
+      if (!this.sqlContent) {
+        return ''
+      }
+      try {
+        // highlight.js 9.x 版本使用 highlight 方法
+        const result = hljs.highlight('sql', this.sqlContent)
+        return `<pre><code class="hljs sql">${result.value}</code></pre>`
+      } catch (error) {
+        console.error('SQL 高亮错误:', error)
+        // 如果高亮失败,返回转义后的纯文本
+        return `<pre><code>${this.escapeHtml(this.sqlContent)}</code></pre>`
+      }
+    }
+  },
+  watch: {
+    file: {
+      handler (val) {
+        if (val) {
+          this.currentFile = val
+          this.loadFile()
+        }
+      },
+      immediate: true
+    },
+    fileUrl: {
+      handler (val) {
+        if (val && !this.file) {
+          this.loadFileFromUrl()
+        }
+      },
+      immediate: true
+    }
+  },
+  methods: {
+    async loadFile () {
+      const fileToLoad = this.currentFile || this.file
+      if (!fileToLoad) {
+        return
+      }
+
+      this.loading = true
+      try {
+        if (this.fileType === 'xls' || this.fileType === 'xlsx') {
+          // Excel 文件处理
+          if (this.fileType === 'xls') {
+            // xls 文件需要转换为 xlsx
+            handleReadFile(fileToLoad, 'xls', (result) => {
+              // result 是转换后的 File 对象
+              this.fileData = result
+              this.loading = false
+            })
+          } else {
+            // xlsx 文件直接传递 File 对象,@vue-office/excel 支持 File
+            this.fileData = fileToLoad
+            this.loading = false
+          }
+        } else if (this.fileType === 'pdf') {
+          // PDF 文件
+          this.pdfUrl = URL.createObjectURL(fileToLoad)
+          this.loading = false
+        } else if (this.fileType === 'docx') {
+          // DOCX 文件
+          await this.renderDocx(fileToLoad)
+          this.loading = false
+        } else if (this.fileType === 'sql') {
+          // SQL 文件
+          const reader = new FileReader()
+          reader.onload = (e) => {
+            this.sqlContent = e.target.result
+            this.loading = false
+          }
+          reader.onerror = () => {
+            this.$snackbar.error('文件读取失败')
+            this.loading = false
+          }
+          reader.readAsText(fileToLoad, 'UTF-8')
+        } else if (this.fileType === 'txt') {
+          // TXT 文件
+          const reader = new FileReader()
+          reader.onload = (e) => {
+            this.txtContent = e.target.result
+            this.loading = false
+          }
+          reader.onerror = () => {
+            this.$snackbar.error('文件读取失败')
+            this.loading = false
+          }
+          reader.readAsText(fileToLoad, 'UTF-8')
+        }
+      } catch (error) {
+        console.error('文件加载错误:', error)
+        this.$snackbar.error('文件加载失败')
+        this.loading = false
+      }
+    },
+    async loadFileFromUrl () {
+      if (!this.fileUrl) {
+        return
+      }
+
+      this.loading = true
+      try {
+        const { api } = await import('@/api/dataGovernance')
+        const { data } = await api.downloadFile({ url: this.fileUrl })
+
+        // 根据文件类型创建 File 对象
+        const blob = new Blob([data], { type: this.getMimeType(this.fileType) })
+        const file = new File([blob], this.fileUrl.split('/').pop(), { type: blob.type })
+
+        // 使用内部变量存储文件对象,避免直接修改 prop
+        this.currentFile = file
+        await this.loadFile()
+      } catch (error) {
+        console.error('从URL加载文件错误:', error)
+        this.$snackbar.error('文件加载失败')
+        this.loading = false
+      }
+    },
+    async renderDocx (file) {
+      try {
+        const arrayBuffer = await file.arrayBuffer()
+        await renderAsync(arrayBuffer, this.$refs.docxContainer)
+      } catch (error) {
+        console.error('DOCX 渲染错误:', error)
+        this.$snackbar.error('DOCX 文件预览失败')
+      }
+    },
+    getMimeType (fileType) {
+      const mimeTypes = {
+        pdf: 'application/pdf',
+        docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+        xls: 'application/vnd.ms-excel',
+        xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+        sql: 'text/plain',
+        txt: 'text/plain'
+      }
+      return mimeTypes[fileType] || 'application/octet-stream'
+    },
+    handleViewParsedData () {
+      this.$emit('viewParsedData')
+    },
+    escapeHtml (text) {
+      const div = document.createElement('div')
+      div.textContent = text
+      return div.innerHTML
+    }
+  },
+  beforeDestroy () {
+    // 清理 PDF URL
+    if (this.pdfUrl) {
+      URL.revokeObjectURL(this.pdfUrl)
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.source-file-preview {
+  width: 100%;
+  height: 100%;
+}
+
+.preview-content {
+  flex: 1;
+  overflow: hidden;
+  position: relative;
+  min-height: 0;
+
+  // 确保 ExcelPage 有正确的高度
+  > div {
+    height: 100%;
+  }
+}
+
+.docx-container {
+  width: 100%;
+  height: 100%;
+  overflow: auto;
+  padding: 20px;
+}
+
+.sql-preview {
+  width: 100%;
+  height: 100%;
+  overflow: auto;
+  padding: 16px;
+  font-family: 'Courier New', Courier, monospace;
+  font-size: 14px;
+  line-height: 1.5;
+
+  ::v-deep pre {
+    margin: 0;
+    padding: 0;
+    background: transparent;
+    border: none;
+    font-family: inherit;
+    font-size: inherit;
+    line-height: inherit;
+    height: 100%;
+  }
+
+  ::v-deep code {
+    display: block;
+    width: 100%;
+    padding: 0;
+    margin: 0;
+    background: transparent;
+    border: none;
+    font-family: inherit;
+    font-size: inherit;
+    line-height: inherit;
+    white-space: pre;
+    overflow-wrap: normal;
+    overflow-x: auto;
+  }
+}
+
+.txt-preview {
+  width: 100%;
+  height: 100%;
+  overflow: auto;
+  padding: 16px;
+  font-family: 'Courier New', Courier, monospace;
+  font-size: 14px;
+  line-height: 1.5;
+  white-space: pre-wrap;
+  word-wrap: break-word;
+}
+
+.title {
+  color: #1976D2;
+  font-weight: 600;
+}
+</style>

+ 0 - 457
src/views/dataGovernance/businessDomain/components/edit copy.vue

@@ -1,457 +0,0 @@
-<template>
-  <div class="db">
-    <v-card class="db-box d-flex flex-column" elevation="5" v-loading="loadingUpload">
-      <v-banner single-line>
-        <div class="d-flex align-center">
-          <!-- <div class="py-2 title">DDL解析</div> -->
-          <v-tabs v-model="uploadTab" @change="handleTabChange">
-            <v-tab>DDL解析</v-tab>
-            <v-tab>Excel解析</v-tab>
-            <v-tab>文本解析</v-tab>
-          </v-tabs>
-          <v-spacer></v-spacer>
-          <upload-btn
-            text
-            color="primary"
-            @change="handleChangeFile"
-          >
-            <v-icon left>mdi-import</v-icon>
-            {{ uploadBtnText }}
-          </upload-btn>
-        </div>
-      </v-banner>
-      <v-tabs-items v-model="uploadTab">
-        <!-- DDL解析 -->
-        <v-tab-item>
-          <div class="pa-3">
-            <v-text-field
-              v-model="name"
-              label="名称查找"
-              placeholder="请输入名称"
-              dense
-              hide-details
-              outlined
-              clearable
-              append-icon="mdi-magnify"
-              @input="handleSearch"
-              @click:append="handleSearch"
-              @keydown.enter.native="handleSearch"
-            ></v-text-field>
-            <div class="pt-3 pl-3 d-flex justify-end">
-              共 {{ Object.keys(items).length }} 个数据
-            </div>
-          </div>
-          <div class="scrollBox">
-            <v-expansion-panels>
-              <v-expansion-panel
-                v-for="(item, key) in items"
-                :key="key"
-              >
-                <v-expansion-panel-header>
-                  <div class="d-flex justify-space-between align-center">
-                    <div>
-                      <v-chip color="error" small v-if="item.exist">已存在</v-chip>
-                      {{ key }}
-                    </div>
-                    <div>
-                      <v-btn
-                        :disabled="select === key"
-                        text
-                        color="primary"
-                        small
-                        @click.stop="handleSelect(item, key)">使用该资源</v-btn>
-                    </div>
-                  </div>
-                </v-expansion-panel-header>
-                <v-expansion-panel-content>
-                  <v-simple-table
-                    fixed-header
-                    height="400px"
-                  >
-                    <template v-slot:default>
-                      <thead>
-                        <tr>
-                          <th class="text-left">
-                            元数据中文名
-                          </th>
-                          <th class="text-left">
-                            元数据英文名
-                          </th>
-                          <th class="text-left">
-                            元数据类型
-                          </th>
-                        </tr>
-                      </thead>
-                      <tbody>
-                        <tr v-for="val in item.meta" :key="key + val.map.name_zh">
-                          <td>{{ val.map.name_zh }}</td>
-                          <td>{{ val.map.name_en }}</td>
-                          <td>{{ val.map.data_type }}</td>
-                        </tr>
-                      </tbody>
-                    </template>
-                  </v-simple-table>
-                </v-expansion-panel-content>
-              </v-expansion-panel>
-            </v-expansion-panels>
-          </div>
-        </v-tab-item>
-        <!-- EXCEL解析 -->
-        <v-tab-item>
-          <div class="box-resource-content-excel" ref="excelBox">
-            <file-review
-              v-loading="showExcel"
-              v-if="dataSource"
-              ref="excel"
-              :style="`height: ${ExcelHeight}px;`"
-              :src="dataSource"
-              @click:bottom-bar="initMap"
-              @rendered="handleRendered"
-              @error="showExcel = false"
-            ></file-review>
-            <template v-else>
-              <none-page></none-page>
-            </template>
-          </div>
-        </v-tab-item>
-      </v-tabs-items>
-    </v-card>
-
-    <v-card class="db-box d-flex flex-column" elevation="5">
-      <div>
-        <v-tabs v-model="tab">
-          <v-tab>元数据设置</v-tab>
-          <v-tab>基础信息配置</v-tab>
-        </v-tabs>
-      </div>
-      <v-divider></v-divider>
-      <v-tabs-items v-model="tab">
-        <v-tab-item>
-          <!-- <edit-selected
-            style="position: relative;height: 100%;"
-            ref="selected"
-            v-model="selectModel"
-          ></edit-selected> -->
-          <edit-selected
-            style="position: relative;height: 100%;"
-            ref="selected"
-            v-model="headMap"
-            v-loading="loading"
-          >
-            <template #head>
-              <form-list ref="form" :items="formItems">
-                <template #actions>
-                  <div style="width: 100%;" class="d-flex justify-space-between">
-                    <v-btn
-                      v-for="btn in controlBtn"
-                      :key="btn.text"
-                      rounded
-                      class="buttons ml-3"
-                      :color="btn.color"
-                      :disabled="btn.disabled && !multipartFile"
-                      @click="btn.handle(btn)"
-                    >
-                      <v-progress-circular
-                        v-if="btn.loading"
-                        indeterminate
-                        :size="18"
-                        width="2"
-                        color="white"
-                        class="mr-1"
-                      ></v-progress-circular>
-                      <v-icon left v-else>{{ btn.icon }}</v-icon>
-                      {{ btn.text }}
-                    </v-btn>
-                  </div>
-                </template>
-              </form-list>
-            </template>
-          </edit-selected>
-        </v-tab-item>
-        <v-tab-item>
-          <div class="pa-3 d-flex align-center justify-center flex-column">
-            <edit-base ref="base" style="max-width: 500px;" :names="names" :item-data="itemData"></edit-base>
-            <v-btn
-              class="buttons"
-              rounded
-              color="primary"
-              :disabled="loading"
-              @click="handleSubmit"
-            >
-              <v-icon left>mdi-send-variant</v-icon>
-              保存
-            </v-btn>
-          </div>
-        </v-tab-item>
-      </v-tabs-items>
-    </v-card>
-
-    <v-overlay :value="overlay" z-index="9">
-      <div class="d-flex flex-column align-center justify-center" style="width: 300px;">
-        <div class="mb-3">正在提交</div>
-        <v-progress-linear
-          color="primary"
-          indeterminate
-          rounded
-          height="6"
-        ></v-progress-linear>
-      </div>
-    </v-overlay>
-  </div>
-</template>
-
-<script>
-import EditSelected from './editSelected'
-import UploadBtn from '@/components/UploadBtn'
-import FileReview from '@/components/FileReview'
-import NonePage from '@/components/Common/empty.vue'
-import EditBase from './editBase'
-import { api } from '@/api/dataGovernance'
-export default {
-  name: 'database-connect',
-  components: {
-    UploadBtn,
-    EditSelected,
-    EditBase,
-    FileReview,
-    NonePage
-  },
-  props: {
-    itemData: {
-      type: Object,
-      default: () => ({})
-    }
-  },
-  data () {
-    return {
-      name: null,
-      items: {},
-      origin: {},
-      tab: 0,
-      uploadTab: 0,
-      names: {},
-      fileName: undefined,
-      loading: false,
-      loadingUpload: false,
-      controlBtn: [
-        {
-          icon: 'mdi-swap-horizontal',
-          key: 'analysis',
-          color: 'primary',
-          loading: false,
-          disabled: false,
-          text: '解析',
-          handle: this.handleAnalysis
-        }
-      ],
-      select: null,
-      overlay: false,
-      dataSource: null, // excel数据
-      ExcelHeight: 0,
-      ExcelWidth: 0,
-      showExcel: false,
-      selectModel: null,
-      uploadBtnText: '导入DDL',
-      isUpdateMap: true,
-      renderSheet: true // 自动渲染
-    }
-  },
-  mounted () {
-    this.$nextTick(() => {
-      this.ExcelHeight = this.$refs.excelBox.clientHeight
-      this.ExcelWidth = this.$refs.excelBox.clientWidth
-    })
-  },
-  created () {
-    if (!Object.keys(this.itemData).length) {
-      return
-    }
-    this.selectModel = this.itemData.parsed_data.map(e => {
-      return {
-        map: e,
-        text: e.name_zh
-      }
-    })
-    this.select = this.itemData.name_zh
-    this.names = {
-      name_zh: this.itemData.name_zh,
-      name_en: this.itemData.name_en
-    }
-  },
-  methods: {
-    handleRendered () {
-      this.showExcel = false
-      if (!this.renderSheet) {
-        return
-      }
-      // 渲染完毕
-      this.initMap()
-    },
-    async initMap () {
-      if (!this.isUpdateMap || !this.dataSource) {
-        return
-      }
-      const row = this.formItems.options.find(e => e.key === 'headRowNumber').value
-      const mapItems = this.$refs.excel?.getRow(row - 1)
-      if (!mapItems || !mapItems.length) {
-        this.headMap = []
-        return
-      }
-      this.headMap = mapItems.map(_e => {
-        return {
-          map: null,
-          text: _e
-        }
-      })
-    },
-    handleTabChange (tab) {
-      this.uploadTab = tab
-      this.uploadBtnText = tab === 0 ? '导入DDL' : tab === 1 ? '导入Excel' : '导入文本'
-    },
-    async handleChangeFile (file) {
-      this.loadingUpload = true
-      const query = new FormData()
-      query.append('file', file)
-      try {
-        const { data } = await api.parseDDLFile(query)
-        this.items = data.reduce((res, item) => {
-          const { columns, exist, table_info: tableInfo } = item
-          const key = tableInfo.name_zh || tableInfo.name_en
-          res[key] = {
-            exist,
-            table_info: tableInfo,
-            meta: columns.map(e => {
-              return {
-                text: e.name_zh,
-                map: {
-                  ...e,
-                  data_standard: null
-                }
-              }
-            })
-          }
-          return res
-        }, {})
-        this.origin = { ...this.items }
-      } catch (error) {
-        this.$snackbar.error(error)
-      } finally {
-        this.loadingUpload = false
-      }
-    },
-    handleSelect (item, key) {
-      this.select = key
-      this.selectModel = item.meta
-      this.names = {
-        name_zh: item.table_info?.name_zh,
-        name_en: item.table_info?.name_en
-      }
-    },
-    handleSearch () {
-      if (!this.name) {
-        this.items = this.origin
-        return
-      }
-      this.items = Object.keys(this.origin).filter(e => e.includes(this.name)).reduce((res, key) => {
-        res[key] = this.origin[key]
-        return res
-      }, {})
-    },
-
-    async handleSubmit () {
-      if (!this.selectModel || !this.selectModel.length) {
-        this.$snackbar.error('请先选择数据资源')
-        this.tab = 0
-        return
-      }
-      try {
-        const obj = this.$refs.base.getValue()
-        if (!obj) {
-          return
-        }
-
-        const { ...params } = obj
-        // 上传文件
-        if (this.itemData.id) {
-          Object.assign(params, {
-            id: this.itemData.id,
-            parsed_data: this.selectModel.map(e => {
-              const { data_standard: dataStandard, ...obj } = e.map
-              return {
-                data_standard: dataStandard?.id ?? null,
-                ...obj
-              }
-            }),
-            type: 'database',
-            name_en: this.names.name_en
-          })
-        } else {
-          Object.assign(params, {
-            additional_info: {
-              head_data: this.items[this.select].meta.map(e => {
-                const { data_standard: dataStandard, ...obj } = e.map
-                return {
-                  data_standard: dataStandard?.id ?? null,
-                  ...obj
-                }
-              }),
-              data_resource: {
-                name_en: this.names.name_en,
-                name_zh: this.names.name_zh
-              }
-            },
-            type: 'database',
-            url: '' // 文件上传路径
-          })
-        }
-        this.overlay = true
-        const submitApi = this.itemData.id ? api.updateBusinessDomain : api.saveBusinessDomain
-        await submitApi(params)
-        this.$snackbar.success('保存成功')
-        this.$emit('close')
-      } catch (error) {
-        this.$snackbar.error(error)
-      } finally {
-        this.overlay = false
-      }
-    }
-  }
-}
-</script>
-
-<style lang="scss" scoped>
-.db {
-  width: 100%;
-  height: 100%;
-  display: grid;
-  grid-template-columns: repeat(2, 1fr);
-  grid-gap: 15px;
-  &-box {
-    height: 100%;
-    overflow: hidden;
-  }
-}
-.scrollBox {
-  height: 0;
-  flex: 1;
-  overflow: auto;
-}
-.title {
-  color: #1976D2;
-  font-weight: 600;
-}
-::v-deep .v-tabs-items {
-  height: 0;
-  flex: 1;
-  .v-window-item {
-    overflow: auto;
-    height: 100%;
-  }
-  .v-window__container {
-    height: 100%;
-  }
-}
-::v-deep .v-banner--single-line .v-banner__wrapper {
-  padding: 0 8px 0 0;
-}
-</style>

+ 99 - 193
src/views/dataGovernance/businessDomain/components/edit.vue

@@ -3,46 +3,38 @@
     <v-card class="db-box d-flex flex-column" elevation="5" v-loading="loadingUpload">
       <v-banner single-line>
         <div class="d-flex align-center">
-          <!-- <div class="py-2 title">DDL解析</div> -->
-          <v-tabs v-model="uploadTab" @change="handleTabChange">
-            <v-tab>DDL解析</v-tab>
-            <v-tab>Excel解析</v-tab>
-            <v-tab>文本解析</v-tab>
-          </v-tabs>
+          <div class="pa-2 title">文件解析</div>
           <v-spacer></v-spacer>
-          <upload-btn
+          <UploadBtn
             text
             color="primary"
+            accept=".sql,.docx,.xls,.xlsx,.pdf"
             @change="handleChangeFile"
           >
             <v-icon left>mdi-import</v-icon>
-            {{ uploadBtnText }}
-          </upload-btn>
+            导入文件
+          </UploadBtn>
         </div>
       </v-banner>
-      <v-tabs-items v-model="uploadTab">
-        <!-- DDL解析 -->
-        <v-tab-item>
-          <DDLPage
-            :items="items"
-            :origin="origin"
-            :select="select"
-            @select="handleSelect"
-          ></DDLPage>
-        </v-tab-item>
-        <!-- EXCEL解析 -->
-        <v-tab-item>
-          <ExcelPage
-            ref="excelPage"
-            style="position: relative;height: 100%;"
-            :data-source="dataSource"
-            :render-sheet="renderSheet"
-            @rendered="handleRendered"
-            @click:bottom-bar="initMap"
-            @error="handleExcelError"
-          ></ExcelPage>
-        </v-tab-item>
-      </v-tabs-items>
+      <div v-if="fileType" style="height: 100%;">
+        <ParseData
+          v-if="!showSourcePreview"
+          :items="items"
+          :origin="origin"
+          :select="select"
+          @select="handleSelect"
+          @viewSource="handleViewSource"
+        ></ParseData>
+        <!-- 文件预览 -->
+        <SourceFilePreview
+          v-else
+          :file="file"
+          :file-type="fileType"
+          :file-url="itemData?.url"
+          @viewParsedData="handleViewParsedData"
+        ></SourceFilePreview>
+      </div>
+      <NonePage v-else />
     </v-card>
 
     <v-card class="db-box d-flex flex-column" elevation="5">
@@ -61,34 +53,6 @@
             v-model="selectModel"
             v-loading="loading"
           >
-            <template #head v-if="uploadTab === 1">
-              <form-list ref="form" :items="formItems">
-                <template #actions>
-                  <div style="width: 100%;" class="d-flex justify-space-between">
-                    <v-btn
-                      v-for="btn in controlBtn"
-                      :key="btn.text"
-                      rounded
-                      class="buttons ml-3"
-                      :color="btn.color"
-                      :disabled="btn.disabled && !file"
-                      @click="btn.handle(btn)"
-                    >
-                      <v-progress-circular
-                        v-if="btn.loading"
-                        indeterminate
-                        :size="18"
-                        width="2"
-                        color="white"
-                        class="mr-1"
-                      ></v-progress-circular>
-                      <v-icon left v-else>{{ btn.icon }}</v-icon>
-                      {{ btn.text }}
-                    </v-btn>
-                  </div>
-                </template>
-              </form-list>
-            </template>
           </edit-selected>
         </v-tab-item>
         <v-tab-item>
@@ -126,21 +90,21 @@
 <script>
 import EditSelected from './editSelected'
 import UploadBtn from '@/components/UploadBtn'
-import FormList from '@/components/Form/list'
 import EditBase from './editBase'
-import DDLPage from './ddl/index.vue'
-import ExcelPage from './excel/index.vue'
+import ParseData from './parseData.vue'
+import SourceFilePreview from './SourceFilePreview.vue'
+import NonePage from '@/components/Common/empty.vue'
+
 import { api } from '@/api/dataGovernance'
-// import { handleReadFile } from '@/utils/file'
 export default {
   name: 'database-connect',
   components: {
     UploadBtn,
     EditSelected,
     EditBase,
-    FormList,
-    DDLPage,
-    ExcelPage
+    ParseData,
+    SourceFilePreview,
+    NonePage
   },
   props: {
     itemData: {
@@ -153,61 +117,22 @@ export default {
       items: {},
       origin: {},
       tab: 0,
-      uploadTab: 0,
       names: {},
-      fileName: undefined,
+      fileType: null,
       loading: false,
       loadingUpload: false,
-      controlBtn: [
-        {
-          icon: 'mdi-swap-horizontal',
-          key: 'analysis',
-          color: 'primary',
-          loading: false,
-          disabled: false,
-          text: '解析',
-          handle: this.handleAnalysis
-        }
-      ],
       select: null,
       overlay: false,
-      dataSource: null, // excel数据
       selectModel: null,
-      uploadBtnText: '导入DDL',
-      isUpdateMap: true,
-      renderSheet: true, // 自动渲染
       file: null,
-      formItems: {
-        options: [
-          {
-            type: 'number',
-            key: 'headRowNumber',
-            value: 1,
-            col: 4,
-            label: '请输入表头所在行数 *',
-            outlined: true,
-            dense: true,
-            rules: [v => v > 0 || '请输入表头所在行数']
-          },
-          {
-            col: 8,
-            slotName: 'actions'
-          }
-        ]
-      }
-    }
-  },
-  computed: {
-    uploadTabText () {
-      return this.uploadTab === 0 ? '导入DDL' : this.uploadTab === 1 ? '导入Excel' : '导入文本'
+      showSourcePreview: false // 是否显示源文件预览
     }
   },
   created () {
     if (!Object.keys(this.itemData).length) {
       return
     }
-    this.uploadTab = this.itemData.type === 'database' ? 0 : this.itemData.type === 'structure' ? 1 : 2
-    this.uploadBtnText = this.uploadTabText
+    this.fileType = this.itemData.type
     this.selectModel = this.itemData.parsed_data.map(e => {
       return {
         map: e,
@@ -229,100 +154,82 @@ export default {
     async getFile (url) {
       try {
         const { data } = await api.downloadFile({ url })
-        this.file = new File([data], url, { type: data.type || 'text/plain' })
-        // await this.handleChangeFile(file)
+        // 从 URL 中提取文件名
+        const fileName = url.split('/').pop() || 'file'
+        // 根据文件类型设置 MIME 类型
+        const mimeTypes = {
+          pdf: 'application/pdf',
+          docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+          xls: 'application/vnd.ms-excel',
+          xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+          sql: 'text/plain'
+          // txt: 'text/plain'
+        }
+        const mimeType = mimeTypes[this.fileType] || 'application/octet-stream'
+        this.file = new File([data], fileName, { type: mimeType })
+
+        // 编辑需要展示解析数据时调用
+        // await this.handleChangeFile(this.file)
       } catch (error) {
         this.$snackbar.error(error)
       }
     },
-    handleRendered () {
-      this.showExcel = false
-      if (!this.renderSheet) {
-        return
-      }
-      // 渲染完毕
-      this.initMap()
+    handleViewSource () {
+      this.showSourcePreview = true
     },
-    async initMap () {
-      if (!this.isUpdateMap || !this.dataSource) {
+    handleViewParsedData () {
+      this.showSourcePreview = false
+    },
+    // 文件解析处理
+    async handleChangeFile (file) {
+      if (!file) {
         return
       }
-      const row = this.formItems.options.find(e => e.key === 'headRowNumber').value
-      const mapItems = this.$refs.excelPage?.getRow(row - 1)
-      if (!mapItems || !mapItems.length) {
-        this.selectModel = []
+
+      // 获取文件扩展名
+      const fileName = file.name || ''
+      const fileExt = fileName.split('.').pop()?.toLowerCase()
+
+      // 验证文件类型
+      const allowedTypes = ['sql', 'docx', 'xls', 'xlsx', 'pdf']
+      if (!fileExt || !allowedTypes.includes(fileExt)) {
+        this.$snackbar.warning('只支持上传 sql、docx、xls、xlsx、pdf 类型的文件')
         return
       }
-      this.selectModel = mapItems.map(_e => {
-        return {
-          map: null,
-          text: _e
-        }
-      })
-      // 需解析excel内容,解析后接口返回元数据列表
-    },
-    handleTabChange (tab) {
-      this.uploadTab = tab
-      this.uploadBtnText = this.uploadTabText
-    },
-    // EXCEL文件解析
-    async handleAnalysis (item) {
-      item.loading = true
-      await this.initMap()
-      item.loading = false
-    },
-    // 文件解析处理
-    async handleChangeFile (file) {
+
       this.file = file
-      if (this.uploadTab === 0) {
-        // DDL 文件处理
-        this.loadingUpload = true
-        const query = new FormData()
-        query.append('file', file)
-        try {
-          const { data } = await api.parseDDLFile(query)
-          this.items = data.reduce((res, item) => {
-            const { columns, exist, table_info: tableInfo } = item
-            const key = tableInfo.name_zh || tableInfo.name_en
-            res[key] = {
-              exist,
-              table_info: tableInfo,
-              meta: columns.map(e => {
-                return {
-                  text: e.name_zh,
-                  map: {
-                    ...e,
-                    data_standard: null
-                  }
+      this.fileType = fileExt
+
+      this.loadingUpload = true
+      const query = new FormData()
+      query.append('file', file)
+      try {
+        const { data } = await api.parseDDLFile(query)
+        this.items = data.reduce((res, item) => {
+          const { columns, exist, table_info: tableInfo } = item
+          const key = tableInfo.name_zh || tableInfo.name_en
+          res[key] = {
+            exist,
+            table_info: tableInfo,
+            meta: columns.map(e => {
+              return {
+                text: e.name_zh,
+                map: {
+                  ...e,
+                  data_standard: null
                 }
-              })
-            }
-            return res
-          }, {})
-          this.origin = { ...this.items }
-        } catch (error) {
-          this.$snackbar.error(error)
-        } finally {
-          this.loadingUpload = false
-        }
-      } else if (this.uploadTab === 1) {
-        // Excel 文件处理
-        // const type = file.name.split('.').pop()
-        // if (type !== 'xlsx' && type !== 'xls') {
-        //   this.$snackbar.error('请导入Excel文件')
-        //   return
-        // }
-        // this.fileName = file.name
-        // this.renderSheet = true
-        // handleReadFile(file, type, files => {
-        //   // 返回blob
-        //   this.dataSource = files
-        // })
+              }
+            })
+          }
+          return res
+        }, {})
+        this.origin = { ...this.items }
+      } catch (error) {
+        this.$snackbar.error(error)
+      } finally {
+        this.loadingUpload = false
       }
     },
-    handleExcelError () {
-      // Excel 加载错误处理
-    },
     // DDL使用该数据源
     handleSelect (item, key) {
       this.select = key
@@ -335,12 +242,11 @@ export default {
 
     async handleSubmit () {
       // DDL解析需要选择数据资源
-      if (this.uploadTab === 0 && (!this.selectModel || !this.selectModel.length)) {
+      if (this.fileType === 'sql' && (!this.selectModel || !this.selectModel.length)) {
         this.$snackbar.error('请先选择数据资源')
         this.tab = 0
         return
       }
-      const type = this.uploadTab === 0 ? 'database' : this.uploadTab === 1 ? 'structure' : 'unstructured'
       try {
         const obj = this.$refs.base.getValue()
         if (!obj) {
@@ -349,7 +255,7 @@ export default {
 
         const params = {
           ...obj,
-          type
+          type: this.fileType
         }
         // 有id时,更新
         if (this.itemData.id) {

+ 0 - 424
src/views/dataGovernance/businessDomain/components/editCopy1.vue

@@ -1,424 +0,0 @@
-<template>
-  <div class="db">
-    <v-card class="db-box d-flex flex-column" elevation="5" v-loading="loadingUpload">
-      <v-banner single-line>
-        <div class="d-flex align-center">
-          <div class="pa-2 title">文件解析</div>
-          <v-spacer></v-spacer>
-          <upload-btn
-            text
-            color="primary"
-            accept=".sql,.txt,.xls,.xlsx"
-            @change="handleChangeFile"
-          >
-            <v-icon left>mdi-import</v-icon>
-            导入文件
-          </upload-btn>
-        </div>
-      </v-banner>
-      <div v-if="fileType" style="height: 100%;">
-        <DDLPage
-          v-if="fileType === 'sql'"
-          :items="items"
-          :origin="origin"
-          :select="select"
-          @select="handleSelect"
-        ></DDLPage>
-        <ExcelPage
-          v-if="fileType === 'excel'"
-          ref="excelPage"
-          style="position: relative;height: 100%;"
-          :data-source="dataSource"
-          :render-sheet="renderSheet"
-          @rendered="handleRendered"
-          @click:bottom-bar="initMap"
-          @error="handleExcelError"
-        ></ExcelPage>
-        <div v-if="fileType === 'txt'" class="pa-3 d-flex align-center justify-center" style="height: 100%;">
-          <div class="text-center">
-            <v-icon size="64" color="grey lighten-1">mdi-file-document-outline</v-icon>
-            <div class="mt-4 grey--text">文本解析功能开发中</div>
-          </div>
-        </div>
-      </div>
-      <none-page v-else></none-page>
-    </v-card>
-
-    <v-card class="db-box d-flex flex-column" elevation="5">
-      <div>
-        <v-tabs v-model="tab">
-          <v-tab>元数据设置</v-tab>
-          <v-tab>基础信息配置</v-tab>
-        </v-tabs>
-      </div>
-      <v-divider></v-divider>
-      <v-tabs-items v-model="tab">
-        <v-tab-item>
-          <edit-selected
-            style="position: relative;height: 100%;"
-            ref="selected"
-            v-model="selectModel"
-            v-loading="loading"
-          >
-            <template #head v-if="fileType === 'excel'">
-              <form-list ref="form" :items="formItems">
-                <template #actions>
-                  <div style="width: 100%;" class="d-flex justify-space-between">
-                    <v-btn
-                      v-for="btn in controlBtn"
-                      :key="btn.text"
-                      rounded
-                      class="buttons ml-3"
-                      :color="btn.color"
-                      :disabled="btn.disabled && !file"
-                      @click="btn.handle(btn)"
-                    >
-                      <v-progress-circular
-                        v-if="btn.loading"
-                        indeterminate
-                        :size="18"
-                        width="2"
-                        color="white"
-                        class="mr-1"
-                      ></v-progress-circular>
-                      <v-icon left v-else>{{ btn.icon }}</v-icon>
-                      {{ btn.text }}
-                    </v-btn>
-                  </div>
-                </template>
-              </form-list>
-            </template>
-          </edit-selected>
-        </v-tab-item>
-        <v-tab-item>
-          <div class="pa-3 d-flex align-center justify-center flex-column">
-            <edit-base ref="base" style="max-width: 500px;" :names="names" :item-data="itemData"></edit-base>
-            <v-btn
-              class="buttons"
-              rounded
-              color="primary"
-              :disabled="loading"
-              @click="handleSubmit"
-            >
-              <v-icon left>mdi-send-variant</v-icon>
-              保存
-            </v-btn>
-          </div>
-        </v-tab-item>
-      </v-tabs-items>
-    </v-card>
-
-    <v-overlay :value="overlay" z-index="9">
-      <div class="d-flex flex-column align-center justify-center" style="width: 300px;">
-        <div class="mb-3">正在提交</div>
-        <v-progress-linear
-          color="primary"
-          indeterminate
-          rounded
-          height="6"
-        ></v-progress-linear>
-      </div>
-    </v-overlay>
-  </div>
-</template>
-
-<script>
-import EditSelected from './editSelected'
-import UploadBtn from '@/components/UploadBtn'
-import FormList from '@/components/Form/list'
-import EditBase from './editBase'
-import DDLPage from './ddl/index.vue'
-import ExcelPage from './excel/index.vue'
-import NonePage from '@/components/Common/empty.vue'
-
-import { api } from '@/api/dataGovernance'
-// import { handleReadFile } from '@/utils/file'
-export default {
-  name: 'database-connect',
-  components: {
-    UploadBtn,
-    EditSelected,
-    EditBase,
-    FormList,
-    DDLPage,
-    ExcelPage,
-    NonePage
-  },
-  props: {
-    itemData: {
-      type: Object,
-      default: () => ({})
-    }
-  },
-  data () {
-    return {
-      items: {},
-      origin: {},
-      tab: 0,
-      names: {},
-      fileType: null,
-      loading: false,
-      loadingUpload: false,
-      controlBtn: [
-        {
-          icon: 'mdi-swap-horizontal',
-          key: 'analysis',
-          color: 'primary',
-          loading: false,
-          disabled: false,
-          text: '解析',
-          handle: this.handleAnalysis
-        }
-      ],
-      select: null,
-      overlay: false,
-      dataSource: null, // excel数据
-      selectModel: null,
-      isUpdateMap: true,
-      renderSheet: true, // 自动渲染
-      file: null,
-      formItems: {
-        options: [
-          {
-            type: 'number',
-            key: 'headRowNumber',
-            value: 1,
-            col: 4,
-            label: '请输入表头所在行数 *',
-            outlined: true,
-            dense: true,
-            rules: [v => v > 0 || '请输入表头所在行数']
-          },
-          {
-            col: 8,
-            slotName: 'actions'
-          }
-        ]
-      }
-    }
-  },
-  created () {
-    if (!Object.keys(this.itemData).length) {
-      return
-    }
-    this.fileType = this.itemData.type === 'database' ? 'sql' : this.itemData.type === 'structure' ? 'excel' : 'txt'
-    this.selectModel = this.itemData.parsed_data.map(e => {
-      return {
-        map: e,
-        text: e.name_zh
-      }
-    })
-    this.select = this.itemData.name_zh
-    this.names = {
-      name_zh: this.itemData.name_zh,
-      name_en: this.itemData.name_en
-    }
-    // 有url时,下载文件
-    if (this.itemData?.url) {
-      this.getFile(this.itemData.url)
-    }
-  },
-  methods: {
-    // 文件下载,用于编辑时下载文件
-    async getFile (url) {
-      try {
-        const { data } = await api.downloadFile({ url })
-        this.file = new File([data], url, { type: data.type || 'text/plain' })
-        // await this.handleChangeFile(file)
-      } catch (error) {
-        this.$snackbar.error(error)
-      }
-    },
-    handleRendered () {
-      this.showExcel = false
-      if (!this.renderSheet) {
-        return
-      }
-      // 渲染完毕
-      this.initMap()
-    },
-    async initMap () {
-      if (!this.isUpdateMap || !this.dataSource) {
-        return
-      }
-      const row = this.formItems.options.find(e => e.key === 'headRowNumber').value
-      const mapItems = this.$refs.excelPage?.getRow(row - 1)
-      if (!mapItems || !mapItems.length) {
-        this.selectModel = []
-        return
-      }
-      this.selectModel = mapItems.map(_e => {
-        return {
-          map: null,
-          text: _e
-        }
-      })
-      // 需解析excel内容,解析后接口返回元数据列表
-    },
-    // EXCEL文件解析
-    async handleAnalysis (item) {
-      item.loading = true
-      await this.initMap()
-      item.loading = false
-    },
-    // 文件解析处理
-    async handleChangeFile (file) {
-      if (!file) {
-        return
-      }
-
-      // 获取文件扩展名
-      const fileName = file.name || ''
-      const fileExt = fileName.split('.').pop()?.toLowerCase()
-
-      // 验证文件类型
-      const allowedTypes = ['sql', 'txt'] // ['sql', 'txt', 'xls', 'xlsx']
-      if (!fileExt || !allowedTypes.includes(fileExt)) {
-        this.$snackbar.warning('只支持上传 sql、txt 类型的文件')
-        return
-      }
-
-      this.file = file
-
-      if (fileExt === 'sql') {
-        // DDL 文件处理
-        this.fileType = 'sql'
-        this.loadingUpload = true
-        const query = new FormData()
-        query.append('file', file)
-        try {
-          const { data } = await api.parseDDLFile(query)
-          this.items = data.reduce((res, item) => {
-            const { columns, exist, table_info: tableInfo } = item
-            const key = tableInfo.name_zh || tableInfo.name_en
-            res[key] = {
-              exist,
-              table_info: tableInfo,
-              meta: columns.map(e => {
-                return {
-                  text: e.name_zh,
-                  map: {
-                    ...e,
-                    data_standard: null
-                  }
-                }
-              })
-            }
-            return res
-          }, {})
-          this.origin = { ...this.items }
-        } catch (error) {
-          this.$snackbar.error(error)
-        } finally {
-          this.loadingUpload = false
-        }
-      } else if (fileExt === 'xls' || fileExt === 'xlsx') {
-        // this.fileType = 'excel'
-        // this.renderSheet = true
-        // handleReadFile(file, fileExt, files => {
-        //   // 返回blob
-        //   this.dataSource = files
-        // })
-      } else if (fileExt === 'txt') {
-        this.fileType = 'txt'
-        // 文本解析功能待实现
-      }
-    },
-    handleExcelError () {
-      // Excel 加载错误处理
-    },
-    // DDL使用该数据源
-    handleSelect (item, key) {
-      this.select = key
-      this.selectModel = item.meta
-      this.names = {
-        name_zh: item.table_info?.name_zh,
-        name_en: item.table_info?.name_en
-      }
-    },
-
-    async handleSubmit () {
-      // DDL解析需要选择数据资源
-      if (this.fileType === 'sql' && (!this.selectModel || !this.selectModel.length)) {
-        this.$snackbar.error('请先选择数据资源')
-        this.tab = 0
-        return
-      }
-      const type = this.fileType === 'sql' ? 'database' : this.fileType === 'excel' ? 'structure' : 'unstructured'
-      try {
-        const obj = this.$refs.base.getValue()
-        if (!obj) {
-          return
-        }
-
-        const params = {
-          ...obj,
-          type
-        }
-        // 有id时,更新
-        if (this.itemData.id) {
-          params.id = this.itemData.id
-        }
-        // 上传文件
-        if (this.file) {
-          const { data } = await api.uploadFile({ file: this.file })
-          params.url = data.url // 文件上传路径
-        }
-
-        // 如果有解析数据,添加 parsed_data
-        if (this.selectModel && this.selectModel.length) {
-          params.parsed_data = this.selectModel.map(e => {
-            const { data_standard: dataStandard, ...obj } = e.map
-            return {
-              data_standard: dataStandard?.id ?? null,
-              ...obj
-            }
-          })
-        }
-
-        this.overlay = true
-        const submitApi = this.itemData.id ? api.updateBusinessDomain : api.saveBusinessDomain
-        await submitApi(params)
-        this.$snackbar.success('保存成功')
-        this.$emit('close')
-      } catch (error) {
-        this.$snackbar.error(error)
-      } finally {
-        this.overlay = false
-      }
-    }
-  }
-}
-</script>
-
-<style lang="scss" scoped>
-.db {
-  width: 100%;
-  height: 100%;
-  display: grid;
-  grid-template-columns: repeat(2, 1fr);
-  grid-gap: 15px;
-  &-box {
-    height: 100%;
-    overflow: hidden;
-  }
-}
-.title {
-  color: #1976D2;
-  font-weight: 600;
-}
-::v-deep .v-tabs-items {
-  height: 0;
-  flex: 1;
-  .v-window-item {
-    overflow: auto;
-    height: 100%;
-  }
-  .v-window__container {
-    height: 100%;
-  }
-}
-::v-deep .v-banner--single-line .v-banner__wrapper {
-  padding: 0 8px 0 0;
-}
-</style>

+ 8 - 1
src/views/dataGovernance/businessDomain/components/ddl/index.vue → src/views/dataGovernance/businessDomain/components/parseData.vue

@@ -19,6 +19,10 @@
         <span v-if="Object.keys(filteredItems).length === 0 && Object.keys(origin).length > 0" class="ml-2 error--text">
           (数据已加载但未显示,请检查控制台)
         </span>
+        <v-btn color="primary" class="ml-2 mb-3" small @click="handleViewSource">
+          <v-icon left>mdi-table-eye</v-icon>
+          查看源文件
+        </v-btn>
       </div>
     </div>
     <div>
@@ -80,7 +84,7 @@
 
 <script>
 export default {
-  name: 'DDL',
+  name: 'ParseData',
   props: {
     items: {
       type: Object,
@@ -144,6 +148,9 @@ export default {
     },
     handleSelect (item, key) {
       this.$emit('select', item, key)
+    },
+    handleViewSource () {
+      this.$emit('viewSource')
     }
   }
 }

Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff