From 799ec6799ad9e994f7d369f059ca7682962f648f Mon Sep 17 00:00:00 2001
From: zhizhijie <zhizhijie@users.noreply.gitee.com>
Date: 星期三, 02 九月 2026 00:08:30 +0800
Subject: [PATCH] fix: 能耗导入同报表期并发重导互斥锁 + 空车牌(0)过滤 + 前端导入按钮防连点

---
 traffic-audit-web/src/views/DataImport.vue |   86 ++++++++++++++++++++++++++++++++++++------
 1 files changed, 73 insertions(+), 13 deletions(-)

diff --git a/traffic-audit-web/src/views/DataImport.vue b/traffic-audit-web/src/views/DataImport.vue
index e010f1c..12d46de 100644
--- a/traffic-audit-web/src/views/DataImport.vue
+++ b/traffic-audit-web/src/views/DataImport.vue
@@ -51,15 +51,15 @@
                   <el-button size="mini" type="primary" icon="el-icon-upload2" :loading="cityDirLoading"
                              @click="importCityDir(moduleSel[g.key])">浠庣洰褰曟壒閲忓鍏�</el-button>
                 </div>
-                <div v-else-if="moduleSel[g.key]" class="module-file">
-                  <div class="file-name" :title="fileNames[moduleSel[g.key]]">{{ fileNames[moduleSel[g.key]] || '鏈�夋嫨鏂囦欢' }}</div>
+                <div v-else-if="moduleSel[g.key] && !isDirOnlyType(moduleSel[g.key])" class="module-file">
+                  <div class="file-name" :title="fileNamesText(moduleSel[g.key])">{{ fileNamesText(moduleSel[g.key]) || '鏈�夋嫨鏂囦欢' }}</div>
                   <div class="file-btns">
-                    <el-upload action="#" :auto-upload="false" :show-file-list="false" accept=".xlsx,.xls"
+                    <el-upload action="#" :auto-upload="false" :show-file-list="false" multiple accept=".xlsx,.xls,.et"
                                :ref="'up' + g.key" :on-change="f => onFilePicked(g.key, f)" style="display:inline-block">
-                      <el-button size="mini" type="primary" plain icon="el-icon-folder-opened">閫夋嫨鏂囦欢</el-button>
+                      <el-button size="mini" type="primary" plain icon="el-icon-folder-opened" :disabled="importing">閫夋嫨鏂囦欢</el-button>
                     </el-upload>
-                    <el-button size="mini" type="primary" icon="el-icon-upload2" :disabled="!files[moduleSel[g.key]]"
-                               @click="importNow(g.key)">绔嬪嵆瀵煎叆</el-button>
+                    <el-button size="mini" type="primary" icon="el-icon-upload2" :loading="importing" :disabled="importing || !fileCount(moduleSel[g.key])"
+                               @click="importNow(g.key)">{{ fileCount(moduleSel[g.key]) > 1 ? '鎵归噺瀵煎叆 ' + fileCount(moduleSel[g.key]) + ' 涓枃浠�' : '绔嬪嵆瀵煎叆' }}</el-button>
                   </div>
                 </div>
               </div>
@@ -155,6 +155,7 @@
       importType: 'h2032',
       period: (() => { const d = new Date(); return d.getFullYear() + '-' + String(d.getMonth() + 1).padStart(2, '0') })(),
       cityDirLoading: false,
+      importing: false,
       sideOpen: false,
       result: '',
       error: '',
@@ -316,23 +317,35 @@
       return map[t] || ''
     },
     onFilePicked(key, file) {
-      this.$set(this.files, this.moduleSel[key], file.raw)
-      this.$set(this.fileNames, this.moduleSel[key], file.name)
+      const type = this.moduleSel[key]
+      if (!type) return
+      if (this.importing) { this.$message.warning('姝e湪瀵煎叆涓紝璇风◢鍊欏啀閫夋嫨鏂囦欢'); return }
+      const list = (this.files[type] || []).filter(f => f.name !== file.name)
+      list.push(file.raw)
+      this.$set(this.files, type, list)
+      this.$set(this.fileNames, type, list.map(f => f.name))
       const up = this.$refs['up' + key]
       if (up && up.clearFiles) up.clearFiles()
     },
     importNow(key) {
       const type = this.moduleSel[key]
       if (!type) return
-      if (this.isCityDirType(type)) {
+      if (this.isDirOnlyType(type)) {
         this.importCityDir(type)
         this.moduleSel[key] = ''
         this.importType = ''
         return
       }
-      const file = this.files[type]
-      if (!file) { this.$message.warning('璇峰厛涓鸿绫诲瀷閫夋嫨鏂囦欢'); return }
+      const fileList = this.files[type] || []
+      if (!fileList.length) { this.$message.warning('璇峰厛涓鸿绫诲瀷閫夋嫨鏂囦欢'); return }
       if (!this.period) { this.$message.warning('璇峰厛閫夋嫨鎶ヨ〃鏈�'); return }
+      if (this.importing) { this.$message.warning('姝e湪瀵煎叆涓紝璇风◢鍊欌��'); return }
+      this.importing = true
+      if (fileList.length > 1 || type === 'investment' || type === 'investmentLogistics') {
+        this.batchImport(type, key, fileList).finally(() => { this.importing = false })
+        return
+      }
+      const file = fileList[0]
       const g = this.groups.find(x => x.key === key)
       const t = g.types.find(x => x.value === type)
       const row = {
@@ -355,12 +368,59 @@
         this.importType = ''
         this.files[type] = null
         this.$delete(this.fileNames, type)
-      })
+      }).finally(() => { this.importing = false })
+    },
+    fileCount(type) { return (this.files[type] || []).length },
+    fileNamesText(type) {
+      const list = this.fileNames[type] || []
+      return list.length ? '宸查�� ' + list.length + ' 涓枃浠讹細' + list.join('銆�') : ''
+    },
+    batchImport(type, key, fileList) {
+      if (!this.period) { this.$message.warning('璇峰厛閫夋嫨鎶ヨ〃鏈�'); return }
+      const fd = new FormData()
+      fd.append('type', type)
+      fd.append('period', this.period)
+      fileList.forEach(f => fd.append('files', f))
+      const g = this.groups.find(x => x.key === key)
+      const label = g ? g.name : type
+      this.$message({ message: '姝e湪鎵归噺瀵煎叆 ' + fileList.length + ' 涓枃浠垛��', duration: 3000 })
+      return api.post('/import/batch', fd, { timeout: 600000 })
+        .then(res => {
+          const d = (res && res.data) || {}
+          if (!d.files) {
+            this.$message.error((res && res.message) || '鎵归噺瀵煎叆澶辫触')
+            return
+          }
+          const files = d.files || []
+          const errCount = files.filter(f => f.error || f.success === 0).length
+          const html = files.map(f =>
+            '<div style="margin:6px 0;line-height:1.6"><b>' + (f.fileName || '') + '</b>' +
+            (f.city ? '锛�' + f.city + '锛�' : '') + '锛氳В鏋� ' + (f.success || 0) + ' 鏉�' +
+            (f.error ? ' <span style="color:#F56C6C">' + f.error + '</span>' : '') + '</div>'
+          ).join('')
+          this.$alert(html, (label || type) + ' 鎵归噺瀵煎叆瀹屾垚锛氬叡 ' + d.total + ' 涓枃浠�' +
+            (d.fail > 0 ? '锛屽け璐� ' + d.fail + ' 鏉�' : '') + '锛堟垚鍔� ' + d.success + ' 鏉★級', {
+            dangerouslyUseHTMLString: true,
+            type: errCount > 0 ? 'warning' : 'success',
+            confirmButtonText: '鐭ラ亾浜�'
+          })
+          if (type === 'investment' || type === 'investmentLogistics') {
+            this.checkInvest(this.period)
+          }
+          this.afterImport()
+          this.files[type] = null
+          this.$delete(this.fileNames, type)
+        })
+        .catch(e => {
+          if (e && e._toast) return
+          this.$message.error((e.response && e.response.data && e.response.data.message) || '鎵归噺瀵煎叆澶辫触')
+        })
     },
     isCityDirType(t) { return t === 'investCityPassenger' || t === 'investCityLogistics' },
+    isDirOnlyType(t) { return t === 'investCityPassenger' || t === 'investCityLogistics' },
     importCityDir(type) {
       if (!this.period) { this.$message.warning('璇峰厛閫夋嫨鎶ヨ〃鏈�'); return }
-      const category = type === 'investCityPassenger' ? '瀹㈣繍绔欏満' : '鐗╂祦鍥尯'
+      const category = (type === 'investCityPassenger' || type === 'investment') ? '瀹㈣繍绔欏満' : '鐗╂祦鍥尯'
       const fd = new FormData()
       fd.append('period', this.period)
       fd.append('category', category)

--
Gitblit v1.9.1