traffic-audit-web/src/views/DataImport.vue
@@ -26,7 +26,7 @@
          <el-card shadow="hover" class="import-card" style="margin-bottom:15px">
            <div class="card-head">本月导入进度({{ period || '未选择报表期' }})
              <el-button type="text" icon="el-icon-refresh" style="float:right" @click="loadOverview">刷新</el-button>
              <el-button type="text" icon="el-icon-refresh" style="float:right" @click="loadData">刷新</el-button>
            </div>
            <div v-if="!period" class="tip">请先在上方选择报表期</div>
            <div v-else class="overview-grid">
@@ -43,8 +43,12 @@
            <div class="card-head">选择类型并挂载文件
              <span class="tip" style="float:right;line-height:24px">各模块互不影响:先选类型、挂载文件,可「立即导入」或「加入队列」统一执行;也可在下方粘贴目录路径点「导入该目录」,文件夹里多个月的 Excel 会按文件名自动识别月份、分别导入对应报表期</span>
            </div>
            <el-tabs v-model="activeModule" class="module-tabs">
              <el-tab-pane v-for="g in groups" :key="g.key" :label="g.name" :name="g.key">
            <div class="module-tabs-head">
                <el-radio-group v-model="activeModule" size="small">
                  <el-radio-button v-for="g in groups" :key="g.key" :label="g.key">{{ g.name }}</el-radio-button>
                </el-radio-group>
              </div>
              <div v-for="g in groups" :key="g.key" v-show="activeModule === g.key" class="module-tab-pane">
                <div class="module-sel">
                  <el-select v-model="moduleSel[g.key]" placeholder="选择导入类型" style="width:260px"
                             @change="onModuleChange(g.key)" clearable>
@@ -88,8 +92,7 @@
                    </div>
                  </div>
                </div>
              </el-tab-pane>
            </el-tabs>
              </div>
            <div v-if="importType" class="type-info">
              <div>模板:{{ templateName }}
                <el-link v-if="templateUrl" type="primary" icon="el-icon-download" :underline="false"
@@ -170,7 +173,7 @@
          <el-card shadow="never" style="margin-top:15px" class="batch-card">
            <div slot="header" class="card-head">
              导入记录({{ period || '全部报表期' }})
              <el-button type="text" icon="el-icon-refresh" style="float:right" @click="loadBatches">刷新</el-button>
              <el-button type="text" icon="el-icon-refresh" style="float:right" @click="loadData">刷新</el-button>
            </div>
            <el-table :data="batches" border size="small" v-loading="batchLoading" style="width:100%">
              <el-table-column prop="importType" label="导入类型" width="150">
@@ -394,7 +397,7 @@
      this.importType = this.moduleSel[key] || ''
      this.dirPath = (this.importType && localStorage.getItem('dirLast_' + this.importType)) || ''
    },
    onPeriodChange() { this.loadOverview(); this.loadBatches() },
    onPeriodChange() { this.loadData() },
    endpoint(t) {
      const map = {
        h2032: '/import/h2032',
@@ -437,7 +440,7 @@
          this.dirFiles = d.files || []
          this.dirFilesTruncated = !!d.filesTruncated
        })
        .catch(e => { this.$message.error((e.response && e.response.data && e.response.data.message) || '目录加载失败') })
        .catch(e => { if (e && e._toast) return; this.$message.error((e.response && e.response.data && e.response.data.message) || '目录加载失败') })
        .finally(() => { this.dirLoading = false })
    },
    goDirParent() { if (this.dirParent) this.loadDirs(this.dirParent) },
@@ -505,6 +508,7 @@
        })
        .catch(e => {
          this.dirImporting = false
          if (e && e._toast) return
          this.$message.error((e.response && e.response.data && e.response.data.message) || '目录不存在或无法访问:' + dir)
        })
    },
@@ -585,6 +589,7 @@
          this.afterImport()
        })
        .catch(e => {
          if (e && e._toast) return
          this.$message.error((e.response && e.response.data && e.response.data.message) || '批量导入失败')
        })
        .finally(() => { this.cityDirLoading = false })
@@ -655,13 +660,17 @@
        run(0)
      })
    },
    afterImport() { this.loadOverview(); this.loadBatches() },
    loadOverview() {
      if (!this.period) return
      api.get('/import/batches', { params: { period: this.period, limit: 200 } })
    afterImport() { this.loadData() },
    loadData() {
      if (this.batchLoading) return
      this.batchLoading = true
      const params = { limit: 200 }
      if (this.period) params.period = this.period
      api.get('/import/batches', { params })
        .then(res => {
          const map = {}
          const records = (res.data && res.data.records) || []
          this.batches = records.slice(0, 50)
          const map = {}
          records.forEach(r => {
            const key = this.batchKeyToType(r.importType)
            if (!key) return
@@ -672,7 +681,8 @@
          })
          this.overview = map
        })
        .catch(() => {})
        .catch(e => { if (!e || !e._toast) this.$message.error('导入记录加载失败,请刷新重试') })
        .finally(() => { this.batchLoading = false })
    },
    batchKeyToType(k) {
      if (BATCH_TYPE_MAP[k]) return BATCH_TYPE_MAP[k]
@@ -724,8 +734,7 @@
    }
  },
  mounted() {
    this.loadBatches()
    this.loadOverview()
    this.loadData()
  }
}
</script>
@@ -769,4 +778,6 @@
.dir-empty { padding: 14px; font-size: 12px; color: #909399; text-align: center; }
.dir-files { margin-top: 8px; }
.module-tabs-head { margin-bottom: 10px; }
.module-tab-pane { min-height: 120px; }
</style>