xyc
1 天以前 079d872fabfe488abf485d8898c40ff1fd746472
traffic-audit-web/src/views/ReportExport.vue
@@ -1,6 +1,6 @@
<template>
  <el-container>
    <el-header>交通统计报表审核系统 - 报表生成</el-header>
  <el-container direction="vertical">
    <app-header title="交通统计报表审核系统 - 报表生成"></app-header>
    <el-container>
      <el-aside width="200px">
        <el-menu router :default-active="activeMenu">
@@ -12,7 +12,6 @@
          <el-menu-item index="/report">报表生成</el-menu-item>
          <el-menu-item index="/rules">规则管理</el-menu-item>
          <el-menu-item index="/users">用户管理</el-menu-item>
          <el-menu-item index="/login" @click="logout">退出登录</el-menu-item>
        </el-menu>
      </el-aside>
      <el-main>
@@ -26,12 +25,12 @@
            </div>
          </div>
          <!-- 第二行:报表类型 Tab(货运 / 旅客 / 投资 / 能耗 / 城市客运) -->
          <el-tabs v-model="activeKey" class="module-tabs">
            <el-tab-pane v-for="m in modules" :key="m.key" :name="m.key">
              <span slot="label">{{ m.title }}<el-tag v-if="m.tag" size="mini" :type="m.tagType || 'info'" style="margin-left:6px">{{ m.tag }}</el-tag></span>
            </el-tab-pane>
          </el-tabs>
          <!-- 第二行:报表类型切换(货运 / 旅客 / 投资 / 能耗 / 城市客运);el-radio-group 替代 el-tabs,规避 el-tabs 布局无限循环(与 /import 修复一致) -->
          <el-radio-group v-model="activeKey" class="module-tabs">
            <el-radio-button v-for="m in modules" :key="m.key" :label="m.key">
              {{ m.title }}<el-tag v-if="m.tag" size="mini" :type="m.tagType || 'info'" style="margin-left:6px">{{ m.tag }}</el-tag>
            </el-radio-button>
          </el-radio-group>
          <!-- 第三行:查询条件区(周期 + 月份 + 查询) -->
          <section class="query-panel">
@@ -146,9 +145,11 @@
</template>
<script>
import AppHeader from '@/components/AppHeader.vue'
import api from '@/api'
export default {
  components: { AppHeader },
  name: 'ReportExport',
  data() {
    return {
@@ -210,10 +211,10 @@
    }
  },
  computed: {
    username() { return localStorage.getItem('username') || '' },
    realName() { return localStorage.getItem('realName') || '' },
    username() { return sessionStorage.getItem('username') || '' },
    realName() { return sessionStorage.getItem('realName') || '' },
    myModules() {
      const s = localStorage.getItem('modules')
      const s = sessionStorage.getItem('modules')
      if (!s) return []
      return s.split(',').filter(Boolean)
    },
@@ -263,7 +264,7 @@
      return m ? m.title : key
    },
    logout() {
      localStorage.removeItem('token'); localStorage.removeItem('username'); localStorage.removeItem('realName'); localStorage.removeItem('modules')
      sessionStorage.removeItem('token'); sessionStorage.removeItem('username'); sessionStorage.removeItem('realName'); sessionStorage.removeItem('modules')
      this.$router.push('/login')
    },
    // ==================== 查询条件与状态刷新 ====================
@@ -303,7 +304,7 @@
      const m = this.curModule
      if (!m || !this.period) return
      const params = Object.assign(this.buildParams(), { types: m.items.map(i => i.key).join(',') })
      api.get('/report/ready', { params })
      api.get('/report/ready', { params, timeout: 60000 })
        .then(res => {
          const list = (res && res.data && res.data.items) || []
          list.forEach(r => {
@@ -348,7 +349,7 @@
      if (!items.length) { this.$message.warning('请选择要预览的报表'); return }
      this.loading = 'preview-' + m.key
      const params = Object.assign(this.buildParams(), { types: items.map(i => i.key).join(',') })
      api.get('/report/preview', { params })
      api.get('/report/preview', { params, timeout: 60000 })
        .then(res => {
          const list = (res && res.data && res.data.items) || []
          this.previewItems = list.map(it => {
@@ -386,18 +387,18 @@
      const params = this.buildParams()
      const doExport = () => {
        if (items.length === 1) {
          api.get('/report/export/' + items[0].key, { params, responseType: 'blob' })
          api.get('/report/export/' + items[0].key, { params, responseType: 'blob', timeout: 120000 })
            .then(res => { this.downloadBlob(res, items[0].fileName); this.$message.success('报表导出成功'); this.loading = '' })
            .catch(err => this.failWith(err))
          return
        }
        const zipParams = Object.assign({}, params, { types: items.map(i => i.key).join(',') })
        api.get('/report/export/selected', { params: zipParams, responseType: 'blob' })
        api.get('/report/export/selected', { params: zipParams, responseType: 'blob', timeout: 120000 })
          .then(res => { this.downloadBlob(res, '生成_所选报表_' + this.period + '.zip'); this.$message.success('已导出 ' + items.length + ' 张报表(zip)'); this.loading = '' })
          .catch(err => this.failWith(err))
      }
      const readyParams = Object.assign({}, params, { types: items.map(i => i.key).join(',') })
      api.get('/report/ready', { params: readyParams })
      api.get('/report/ready', { params: readyParams, timeout: 60000 })
        .then(rd => {
          const list = (rd && rd.data && rd.data.items) || []
          const missing = list.filter(i => !i.ready)
@@ -419,6 +420,7 @@
        .catch(() => doExport())
    },
    failWith(err) {
      if (err && err._toast) { this.loading = ''; return }
      let msg = ''
      const d = err && err.response && err.response.data
      if (d && typeof d === 'object' && d.message) msg = d.message