From 95a1f46104dadf824586498aa139a1acaf5fc77c Mon Sep 17 00:00:00 2001
From: zhizhijie <zhizhijie@users.noreply.gitee.com>
Date: 星期四, 10 九月 2026 08:58:55 +0800
Subject: [PATCH] feat: 数据导入页清空增强——支持按数据类型清空(后端 types 参数 + 弹窗多选),清空按钮移出“刷新”行改独立危险操作区防误触(含功能测试报告与工作日结)

---
 traffic-audit-web/src/views/DataImport.vue |  100 +++++++++++++++++++++++++++++++++++++------------
 1 files changed, 75 insertions(+), 25 deletions(-)

diff --git a/traffic-audit-web/src/views/DataImport.vue b/traffic-audit-web/src/views/DataImport.vue
index e496ed4..7ed598b 100644
--- a/traffic-audit-web/src/views/DataImport.vue
+++ b/traffic-audit-web/src/views/DataImport.vue
@@ -103,11 +103,12 @@
               <div v-show="sideOpen" class="side-content">
                 <div class="side-head">
                   <span>鏈湀瀵煎叆杩涘害锛坽{ period || '鏈�夋嫨鎶ヨ〃鏈�' }}锛�</span>
-                  <span class="side-head-btns">
-                    <el-button type="text" icon="el-icon-refresh" @click="loadData">鍒锋柊</el-button>
-                    <el-button type="text" icon="el-icon-delete" style="color:#F56C6C" :loading="clearing"
-                               :disabled="!period || clearing || importing" @click="clearPeriodData">娓呯┖</el-button>
-                  </span>
+                  <el-button type="text" icon="el-icon-refresh" @click="loadData">鍒锋柊</el-button>
+                </div>
+                <div v-if="period" class="side-danger">
+                  <el-button size="mini" type="danger" plain icon="el-icon-delete"
+                             :disabled="clearing || importing" @click="openClearDialog">娓呯┖鏁版嵁鈥�</el-button>
+                  <span class="side-danger-tip">鎸夋姤琛ㄦ湡娓呭簱锛岀敤浜庢暣鏈堥噸瀵�</span>
                 </div>
                 <div v-if="!period" class="tip">璇峰厛鍦ㄤ笂鏂归�夋嫨鎶ヨ〃鏈�</div>
                 <div v-else class="overview-grid">
@@ -123,6 +124,32 @@
             </div>
           </div>
         </div>
+        <el-dialog title="娓呯┖鏁版嵁" :visible.sync="clearDialog" width="560px" append-to-body :close-on-click-modal="false">
+          <div class="clear-dlg">
+            <div class="clear-period">鎶ヨ〃鏈燂細<b>{{ period }}</b></div>
+            <el-radio-group v-model="clearScope">
+              <el-radio label="all">娓呯┖璇ユ姤琛ㄦ湡鍏ㄩ儴宸插鍏ユ暟鎹�</el-radio>
+              <el-radio label="types">鍙竻绌烘寚瀹氱被鍨�</el-radio>
+            </el-radio-group>
+            <div v-if="clearScope === 'types'" class="clear-types">
+              <el-select v-model="clearTypes" multiple filterable collapse-tags placeholder="閫夋嫨瑕佹竻绌虹殑鏁版嵁绫诲瀷" style="width:100%">
+                <el-option-group v-for="g in clearableGroups()" :key="g.key" :label="g.name">
+                  <el-option v-for="t in g.types" :key="t.value" :value="t.value"
+                             :label="t.label + '锛�' + overviewState(t.value).text + '锛�'"></el-option>
+                </el-option-group>
+              </el-select>
+              <div class="tip" style="margin-top:6px">鍙閫夛紱鏈鍏ョ殑绫诲瀷娌℃湁鏁版嵁鍙垹銆�</div>
+            </div>
+            <div class="clear-warn">
+              灏嗗垹闄ゆ墍閫夎寖鍥村唴璇ユ姤琛ㄦ湡鐨勬暟鎹簱鏁版嵁锛屽苟鍚屾鍒犻櫎瀵瑰簲瀹℃牳缁撴灉銆佸凡瀹℃牳鏍囪涓庡鍏ユ壒娆¤褰曪紙鎶曡祫椤圭洰涓绘。淇濈暀锛夈�傛鎿嶄綔涓嶅彲鎾ら攢锛岃纭宸叉湁澶囦唤鎴栧噯澶囬噸鏂板鍏ャ��
+            </div>
+          </div>
+          <span slot="footer">
+            <el-button @click="clearDialog = false">鍙栨秷</el-button>
+            <el-button type="danger" :loading="clearing"
+                       :disabled="clearScope === 'types' && !clearTypes.length" @click="confirmClear">纭娓呯┖</el-button>
+          </span>
+        </el-dialog>
       </el-main>
     </el-container>
   </el-container>
@@ -163,6 +190,9 @@
       cityDirLoading: false,
       importing: false,
       clearing: false,
+      clearDialog: false,
+      clearScope: 'all',
+      clearTypes: [],
       sideOpen: false,
       result: '',
       error: '',
@@ -525,27 +555,43 @@
         .catch(e => { if (!e || !e._toast) this.$message.error('瀵煎叆璁板綍鍔犺浇澶辫触锛岃鍒锋柊閲嶈瘯') })
         .finally(() => { this.batchLoading = false })
     },
-    clearPeriodData() {
+    openClearDialog() {
       if (!this.period) { this.$message.warning('璇峰厛閫夋嫨鎶ヨ〃鏈�'); return }
       if (this.importing) { this.$message.warning('姝e湪瀵煎叆鏁版嵁锛岃绛夊緟瀵煎叆瀹屾垚鍚庡啀娓呯┖'); return }
+      this.clearScope = 'all'
+      this.clearTypes = []
+      this.clearDialog = true
+    },
+    clearableGroups() {
+      return this.groups.filter(g => !g.hidden)
+    },
+    confirmClear() {
+      if (!this.period) { this.$message.warning('璇峰厛閫夋嫨鎶ヨ〃鏈�'); return }
       if (this.clearing) return
-      this.$confirm(
-        '灏嗘竻绌� ' + this.period + ' 鎶ヨ〃鏈熷湪鏁版嵁搴撲腑鐨勫叏閮ㄥ凡瀵煎叆鏁版嵁锛屽悓鏃跺垹闄よ鎶ヨ〃鏈熺殑瀹℃牳缁撴灉涓庡鍏ユ壒娆¤褰曪紙渚夸簬鏁存湀閲嶆柊瀵煎叆锛夈�俓n姝ゆ搷浣滀笉鍙挙閿�锛屾槸鍚︾户缁紵',
-        '娓呯┖ ' + this.period + ' 鏁版嵁',
-        { type: 'warning', confirmButtonText: '纭娓呯┖', cancelButtonText: '鍙栨秷' }
-      ).then(() => {
-        this.clearing = true
-        api.post('/import/clear', null, { params: { period: this.period }, timeout: 600000 })
-          .then(() => {
-            this.$message.success('宸叉竻绌� ' + this.period + ' 鎶ヨ〃鏈熺殑鏁版嵁锛屽彲浠ラ噸鏂板鍏�')
-            this.loadData()
-          })
-          .catch(e => {
-            if (e && e._toast) return
-            this.$message.error((e.response && e.response.data && e.response.data.message) || '娓呯┖澶辫触锛岃绋嶅悗閲嶈瘯')
-          })
-          .finally(() => { this.clearing = false })
-      }).catch(() => {})
+      if (this.clearScope === 'types' && !this.clearTypes.length) { this.$message.warning('璇烽�夋嫨瑕佹竻绌虹殑鏁版嵁绫诲瀷'); return }
+      const scopeText = this.clearScope === 'all'
+        ? '璇ユ姤琛ㄦ湡鍏ㄩ儴宸插鍏ユ暟鎹�'
+        : '浠ヤ笅 ' + this.clearTypes.length + ' 涓被鍨嬶細' + this.clearTypes.map(t => this.typeLabel(t)).join('銆�')
+      this.$confirm('灏嗘竻绌� ' + this.period + ' 鐨�' + scopeText + '锛屽苟鍚屾鍒犻櫎瀵瑰簲瀹℃牳缁撴灉銆佸凡瀹℃牳鏍囪涓庡鍏ユ壒娆¤褰曘�傛鎿嶄綔涓嶅彲鎾ら攢锛屾槸鍚︾户缁紵',
+        '娓呯┖纭', { type: 'warning', confirmButtonText: '纭娓呯┖', cancelButtonText: '鍙栨秷' })
+        .then(() => {
+          this.clearing = true
+          const params = { period: this.period }
+          if (this.clearScope === 'types') params.types = this.clearTypes.join(',')
+          return api.post('/import/clear', null, { params, timeout: 600000 })
+            .then(res => {
+              const d = (res && res.data) || {}
+              this.$message.success('宸叉竻绌� ' + this.period + ' 鏁版嵁锛氫笟鍔℃暟鎹� ' + (d.dataRows || 0) +
+                ' 琛屻�佸鏍哥粨鏋� ' + (d.auditRows || 0) + ' 琛屻�佸鍏ユ壒娆� ' + (d.batchRows || 0) + ' 鏉★紝鍙互閲嶆柊瀵煎叆')
+              this.clearDialog = false
+              this.loadData()
+            })
+            .catch(e => {
+              if (e && e._toast) return
+              this.$message.error((e.response && e.response.data && e.response.data.message) || '娓呯┖澶辫触锛岃绋嶅悗閲嶈瘯')
+            })
+            .finally(() => { this.clearing = false })
+        }).catch(() => {})
     },
     batchKeyToType(k) {
       if (BATCH_TYPE_MAP[k]) return BATCH_TYPE_MAP[k]
@@ -618,8 +664,12 @@
 .import-side.side-open .side-toggle-text { writing-mode: horizontal-tb; letter-spacing: normal; margin-top: 0; }
 .side-content { padding: 8px 12px 12px; max-height: calc(100vh - 220px); overflow-y: auto; overscroll-behavior: contain; }
 .side-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; font-weight: 600; margin-bottom: 6px; }
-.side-head-btns { display: flex; align-items: center; gap: 2px; flex-shrink: 0; }
-.side-head-btns .el-button + .el-button { margin-left: 0; }
+.side-danger { display: flex; align-items: center; gap: 8px; margin: 4px 0 10px; padding: 6px 8px; background: #FEF0F0; border: 1px solid #FDE2E2; border-radius: 4px; }
+.side-danger-tip { font-size: 12px; color: #F56C6C; line-height: 1.3; }
+.clear-dlg { line-height: 1.7; }
+.clear-period { margin-bottom: 6px; }
+.clear-types { margin-top: 10px; }
+.clear-warn { margin-top: 12px; padding: 8px 10px; background: #FEF0F0; border: 1px solid #FDE2E2; border-radius: 4px; color: #F56C6C; font-size: 12px; line-height: 1.6; }
 .import-side .overview-grid { display: block; }
 .import-side .ov-row { display: block; margin-bottom: 6px; }
 .import-side .ov-group { width: auto; }

--
Gitblit v1.9.1