From e45e74e5ae207f7642be9a88ed99b593de89fb3b Mon Sep 17 00:00:00 2001
From: longz <longzhaoz@qq.com>
Date: 星期三, 24 六月 2026 16:54:46 +0800
Subject: [PATCH] 1.0

---
 frontend-admin/src/views/SensitiveWordsView.vue |   75 +++++++++++++++++++++++++++++++++++++
 1 files changed, 74 insertions(+), 1 deletions(-)

diff --git a/frontend-admin/src/views/SensitiveWordsView.vue b/frontend-admin/src/views/SensitiveWordsView.vue
index d3860a5..215f03b 100644
--- a/frontend-admin/src/views/SensitiveWordsView.vue
+++ b/frontend-admin/src/views/SensitiveWordsView.vue
@@ -2,7 +2,20 @@
   <div class="page">
     <div class="header">
       <h3 class="section-title">敏感词库</h3>
-      <el-button v-permission="'config:sensitive-words:create'" type="primary" @click="openCreate">新增</el-button>
+      <div class="header-actions">
+        <el-button v-permission="'config:sensitive-words:import'" type="primary" plain @click="downloadTemplate">
+          下载模板
+        </el-button>
+        <el-upload
+          v-permission="'config:sensitive-words:import'"
+          :show-file-list="false"
+          accept=".xls,.xlsx"
+          :http-request="importSensitiveWords"
+        >
+          <el-button type="primary" :loading="importing">导入</el-button>
+        </el-upload>
+        <el-button v-permission="'config:sensitive-words:create'" type="primary" @click="openCreate">新增</el-button>
+      </div>
     </div>
 
     <el-form class="filters" :inline="true" :model="filters" @submit.prevent>
@@ -89,6 +102,7 @@
 <script setup lang="ts">
 import { onMounted, reactive, ref } from "vue";
 import { ElMessage, ElMessageBox } from "element-plus";
+import type { UploadRequestOptions } from "element-plus";
 import http from "../api/http";
 
 type Row = {
@@ -101,6 +115,7 @@
 
 const loading = ref(false);
 const saving = ref(false);
+const importing = ref(false);
 const rows = ref<Row[]>([]);
 const page = ref(1);
 const size = ref(10);
@@ -213,6 +228,59 @@
   }
 }
 
+async function importSensitiveWords(opt: UploadRequestOptions) {
+  const file = opt.file as File;
+  if (!file) return;
+  if (!/\.(xls|xlsx)$/i.test(file.name)) {
+    ElMessage.warning("请上传 xls 或 xlsx 文件");
+    return;
+  }
+  const fd = new FormData();
+  fd.append("file", file);
+  importing.value = true;
+  try {
+    const { data } = await http.post("/config/sensitive-words/manage/import", fd, {
+      headers: { "Content-Type": "multipart/form-data" },
+    });
+    const result = data.result || {};
+    const success = Number(result.successCount) || 0;
+    const duplicate = Number(result.duplicateCount) || 0;
+    const invalid = Number(result.invalidCount) || 0;
+    const errors = Array.isArray(result.errorMessages) ? result.errorMessages : [];
+    const message = `导入完成:成功${success}条,重复跳过${duplicate}条,无效${invalid}条`;
+    if (errors.length) {
+      ElMessageBox.alert(`${message}\n${errors.join("\n")}`, "导入结果", {
+        confirmButtonText: "知道了",
+      });
+    } else {
+      ElMessage.success(message);
+    }
+    page.value = 1;
+    load();
+  } catch (e: unknown) {
+    ElMessage.error(e instanceof Error ? e.message : "导入失败");
+  } finally {
+    importing.value = false;
+  }
+}
+
+async function downloadTemplate() {
+  try {
+    const res = await http.get("/config/sensitive-words/manage/import-template", { responseType: "blob" });
+    const blob = new Blob([res.data], {
+      type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
+    });
+    const url = window.URL.createObjectURL(blob);
+    const a = document.createElement("a");
+    a.href = url;
+    a.download = "sensitive-word-import-template.xlsx";
+    a.click();
+    window.URL.revokeObjectURL(url);
+  } catch (e: unknown) {
+    ElMessage.error(e instanceof Error ? e.message : "下载模板失败");
+  }
+}
+
 function toggleEnabled(row: Row) {
   const nextEnabled = row.enabled === 1 ? 0 : 1;
   const actionText = nextEnabled === 1 ? "启用" : "禁用";
@@ -269,6 +337,11 @@
   margin-bottom: 12px;
   flex: none;
 }
+.header-actions {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+}
 .section-title {
   font-size: 16px;
   font-weight: 600;

--
Gitblit v1.7.1