Xiao_123 9 órája
szülő
commit
9db33219b3

+ 1 - 1
src/components/Dialog/index.vue

@@ -120,7 +120,7 @@ export default {
   data () {
     return {
       isPrint: false,
-      show: false
+      show: this.visible
     }
   },
   watch: {

+ 180 - 0
src/views/dataService/components/PreviewDialog.vue

@@ -0,0 +1,180 @@
+<template>
+  <m-dialog :visible="visible" title="数据预览" widthType="1" :footer="false" max-width="90%" @update:visible="handleVisibleChange">
+    <div v-if="previewData.product" class="mb-4">
+      <v-card outlined>
+        <v-card-text>
+          <div class="d-flex align-center mb-2">
+            <span class="text-h6 mr-3">{{ previewData.product.product_name }}</span>
+            <v-chip small>{{ previewData.total_count }} 条记录</v-chip>
+          </div>
+          <div class="text-body-2">
+            <span class="mr-4">目标表: {{ previewData.product.target_schema }}.{{ previewData.product.target_table }}</span>
+            <span>列数: {{ previewData.product.column_count }}</span>
+          </div>
+        </v-card-text>
+      </v-card>
+      <v-alert v-if="previewData.error" type="warning" dense class="ma-3">{{ previewData.error }}</v-alert>
+    </div>
+    <div v-loading="loading" style="max-height: 600px; overflow-y: auto;">
+      <div v-if="previewData.columns && previewData.columns.length" class="mb-2 d-flex justify-end align-center">
+        <v-autocomplete
+          v-model="selectedColumns"
+          :items="allColumns"
+          hide-details
+          label="选择表头"
+          placeholder="选择表头"
+          height="36"
+          class="mt-2"
+          outlined
+          multiple
+          dense
+          style="max-width: 300px;"
+          @change="handleColumnChange"
+        >
+          <template v-slot:selection="{ item, index }">
+            <v-chip v-if="index === 0" small>
+              <span>{{ item }}</span>
+            </v-chip>
+            <span
+              v-if="index === 1"
+              class="grey--text text-caption"
+            >
+              (+{{ selectedColumns.length - 1 }} others)
+            </span>
+          </template>
+        </v-autocomplete>
+      </div>
+      <v-simple-table v-if="displayColumns && displayColumns.length" fixed-header height="400px">
+        <template v-slot:default>
+          <thead>
+            <tr>
+              <th v-for="col in displayColumns" :key="col.name" class="text-left">
+                <div>
+                  <div>{{ col.name }}</div>
+                </div>
+              </th>
+            </tr>
+          </thead>
+          <tbody>
+            <tr v-for="(row, index) in previewData.data" :key="index">
+              <td v-for="col in displayColumns" :key="col.name">
+                {{ row[col.name] }}
+              </td>
+            </tr>
+          </tbody>
+        </template>
+      </v-simple-table>
+      <div v-else class="text-center pa-10 text--secondary">
+        暂无数据
+      </div>
+      <div class="text-end text--secondary">
+        <span>已加载 {{ previewData.preview_count || 0 }} / {{ previewData.total_count || 0 }} 条</span>
+      </div>
+    </div>
+    <template #footer>
+      <v-divider></v-divider>
+      <v-card-actions>
+        <v-spacer></v-spacer>
+        <v-btn
+          v-if="previewData.preview_count < previewData.total_count && limit < 1000"
+          text
+          color="primary"
+          @click="handleLoadMore"
+        >
+          加载更多
+        </v-btn>
+        <v-btn v-if="previewData.product?.status === 'active'" text color="success" @click="handleDownload">下载Excel</v-btn>
+        <v-btn text @click="handleClose">关闭</v-btn>
+      </v-card-actions>
+    </template>
+  </m-dialog>
+</template>
+
+<script>
+import MDialog from '@/components/Dialog'
+
+export default {
+  name: 'PreviewDialog',
+  components: {
+    MDialog
+  },
+  props: {
+    visible: {
+      type: Boolean,
+      default: false
+    },
+    loading: {
+      type: Boolean,
+      default: false
+    },
+    previewData: {
+      type: Object,
+      default: () => ({
+        product: null,
+        columns: [],
+        data: [],
+        total_count: 0,
+        preview_count: 0,
+        error: null
+      })
+    },
+    limit: {
+      type: Number,
+      default: 200
+    }
+  },
+  data () {
+    return {
+      selectedColumns: []
+    }
+  },
+  computed: {
+    allColumns () {
+      return this.previewData.columns ? this.previewData.columns.map(col => col.name) : []
+    },
+    displayColumns () {
+      if (!this.previewData.columns || !this.previewData.columns.length) {
+        return []
+      }
+      // 返回选中的列,如果没有选中则返回空数组(等待默认选中前10条)
+      if (this.selectedColumns.length === 0) {
+        return []
+      }
+      return this.previewData.columns.filter(col => this.selectedColumns.includes(col.name))
+    }
+  },
+  watch: {
+    visible (val) {
+      if (!val) {
+        // 关闭时重置
+        this.selectedColumns = []
+      }
+    },
+    'previewData.columns' (val) {
+      if (val && val.length && this.visible) {
+        // 当列数据更新时,默认选中前6条
+        const defaultCount = Math.min(6, val.length)
+        this.selectedColumns = val.slice(0, defaultCount).map(col => col.name)
+      }
+    }
+  },
+  methods: {
+    handleColumnChange () {
+      // 列选择变化时的处理
+      this.$emit('column-change', this.selectedColumns)
+    },
+    handleLoadMore () {
+      this.$emit('load-more')
+    },
+    handleDownload () {
+      this.$emit('download')
+    },
+    handleVisibleChange (val) {
+      this.$emit('update:visible', val)
+    },
+    handleClose () {
+      this.$emit('update:visible', false)
+    }
+  }
+}
+</script>

+ 12 - 65
src/views/dataService/index.vue

@@ -35,68 +35,14 @@
     </table-list>
 
     <!-- 预览对话框 -->
-    <m-dialog :visible.sync="previewDialog.show" title="数据预览" :footer="false" max-width="90%">
-      <div v-if="previewDialog.data.product" class="mb-4">
-        <v-card outlined>
-          <v-card-text>
-            <div class="d-flex align-center mb-2">
-              <span class="text-h6 mr-3">{{ previewDialog.data.product.product_name }}</span>
-              <v-chip small>{{ previewDialog.data.total_count }} 条记录</v-chip>
-            </div>
-            <div class="text-body-2">
-              <span class="mr-4">目标表: {{ previewDialog.data.product.target_schema }}.{{ previewDialog.data.product.target_table }}</span>
-              <span>列数: {{ previewDialog.data.product.column_count }}</span>
-            </div>
-          </v-card-text>
-        </v-card>
-        <v-alert v-if="previewDialog.data.error" type="warning" dense class="ma-3">{{ previewDialog.data.error }}</v-alert>
-      </div>
-      <div v-loading="previewDialog.loading" style="max-height: 600px; overflow-y: auto;">
-        <v-simple-table v-if="previewDialog.data.columns && previewDialog.data.columns.length" fixed-header dense>
-          <template v-slot:default>
-            <thead>
-              <tr>
-                <th v-for="col in previewDialog.data.columns" :key="col.name" class="text-left">
-                  <div>
-                    <div>{{ col.name }}</div>
-                    <small style="color: #909399; font-weight: normal;">{{ col.type }}</small>
-                  </div>
-                </th>
-              </tr>
-            </thead>
-            <tbody>
-              <tr v-for="(row, index) in previewDialog.data.data" :key="index">
-                <td v-for="col in previewDialog.data.columns" :key="col.name">
-                  {{ row[col.name] }}
-                </td>
-              </tr>
-            </tbody>
-          </template>
-        </v-simple-table>
-        <div v-else class="text-center pa-10 text--secondary">
-          暂无数据
-        </div>
-        <div class="text-end text--secondary">
-          <span>已加载 {{ previewDialog.data.preview_count || 0 }} / {{ previewDialog.data.total_count || 0 }} 条</span>
-        </div>
-      </div>
-      <template #footer>
-        <v-divider></v-divider>
-        <v-card-actions>
-          <v-spacer></v-spacer>
-          <v-btn
-            v-if="previewDialog.data.preview_count < previewDialog.data.total_count && previewDialog.limit < 1000"
-            text
-            color="primary"
-            @click="handleLoadMore"
-          >
-            加载更多
-          </v-btn>
-          <v-btn v-if="previewDialog.data.product" text color="success" @click="handleDownloadFromPreview">下载Excel</v-btn>
-          <v-btn text @click="previewDialog.show = false">关闭</v-btn>
-        </v-card-actions>
-      </template>
-    </m-dialog>
+    <preview-dialog
+      :visible.sync="previewDialog.show"
+      :loading="previewDialog.loading"
+      :preview-data="previewDialog.data"
+      :limit="previewDialog.limit"
+      @load-more="handleLoadMore"
+      @download="handleDownloadFromPreview"
+    />
 
     <!-- 注册对话框 -->
     <m-dialog :visible.sync="registerDialog.show" :title="registerDialog.isEdit ? '编辑数据产品' : '新增数据产品'" @submit="handleRegisterSubmit">
@@ -110,6 +56,7 @@ import MFilter from '@/components/Filter'
 import TableList from '@/components/List/table'
 import MDialog from '@/components/Dialog'
 import RegisterForm from './components/RegisterForm'
+import PreviewDialog from './components/PreviewDialog'
 import { api } from '@/api/dataService'
 import { formatDate } from '@/utils/date'
 
@@ -119,7 +66,8 @@ export default {
     MFilter,
     TableList,
     MDialog,
-    RegisterForm
+    RegisterForm,
+    PreviewDialog
   },
   data () {
     return {
@@ -274,8 +222,7 @@ export default {
         const response = await api.downloadExcel(item.id, 200)
 
         // 响应拦截器已处理错误情况,这里response格式为 { data: blob, name: filename }
-        const filename = response.name || `${item.product_name_en}_${new Date().toISOString().slice(0, 10).replace(/-/g, '')}.xlsx`
-
+        const filename = `${item.product_name || item.product_name_en}_${new Date().toISOString().slice(0, 10).replace(/-/g, '')}.xlsx`
         // 创建下载链接
         const blob = new Blob([response.data], {
           type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'