前言
在内容安全监管、情报分析等专业领域,敏感词的智能检索与可视化分析是核心需求。本文详细解析一个集成了树形组织架构过滤 、多维度智能检索 和实时数据交互的敏感词分析系统前端实现,展示如何构建高效、直观的数据分析界面。
一、组件概览
1.1 功能特性亮点
组织架构树形过滤:支持按组织单位逐级筛选
多维检索条件:敏感词类型、时间范围、聊天类型等
实时数据交互:点击查看对话详情
分页懒加载:大数据量下的性能优化
自适应布局:响应式设计适应不同屏幕
1.2 技术栈
XML
Vue 2 + Element UI + Axios + Vue Router
┌────────────────────────────────────────────┐
│ 敏感词检索分析系统 │
├────────────────────────────────────────────┤
│ 左侧:组织架构树 │ 右侧:数据表格 + 筛选面板 │
├────────────────────────────────────────────┤
│ 智能检索引擎 │
│ - 树形过滤 │ - 关键词搜索 │ - 时间筛选 │
├────────────────────────────────────────────┤
│ 数据可视化层 │
│ - 表格展示 │ - 详情弹窗 │ - 导出功能 │
└────────────────────────────────────────────┘
二、核心组件设计
2.1 双栏布局设计
html
<template>
<div class="extractSwBox">
<el-card class="box-card" shadow="never">
<!-- 筛选面板(可折叠) -->
<div slot="header" class="clearfix">
<div class="sensitive_body" v-show="closs">
<!-- 多维筛选表单 -->
</div>
</div>
<div class="text item" ref="text">
<el-container class="main_content">
<!-- 左侧树形菜单 -->
<el-aside width="200px" class="list_aside">
<div class="sideTreeBox">
<el-tree
:data="data"
@node-click="handleNodeClick"
ref="tree"
></el-tree>
</div>
</el-aside>
<!-- 右侧数据表格 -->
<el-main class="list_main">
<el-table class="list_table" :data="tableList">
<!-- 表格列定义 -->
</el-table>
<!-- 分页组件 -->
<aby-pagination
@page_num="page"
@page_size="page_sizes"
:message="parentMsg"
></aby-pagination>
</el-main>
</el-container>
</div>
</el-card>
</div>
</template>
2.2 响应式高度计算
javascript
resize() {
// 动态计算内容区域高度
this.contentT =
document.getElementsByClassName("main_content")[0].offsetTop;
},
mounted() {
this.resize();
// 初始数据加载
this.selectAllSensitiveWord();
this.page(1);
await this.get_tree(); // 获取组织树
}

三、树形组织架构实现
3.1 树形数据结构管理
javascript
data() {
return {
// 树形图相关参数
expandedKeys: [], // 默认展开的节点
data: [{ label: "", id: "" }], // 树形数据
defaultProps: {
children: "children",
label: "label", // 节点显示字段映射
},
node_children: [], // 当前选中节点的子节点
orgNo: "", // 选中节点的单位编码
curTreeNode: "", // 当前点击的树形图节点
};
}

3.2 树形数据加载与渲染
javascript
// 获取组织架构树
async get_tree() {
try {
const res = await getWAOrgTree();
if (res.data.code == 1) {
this.data = []; // 清空初始占位数据
const treeData = res.data.data;
this.orgNo = treeData.orgNo;
this.node_children = treeData.children;
this.curTreeNode = treeData.label;
// 构建树形数据
this.data.push(treeData);
// 设置默认展开的节点
this.expandedKeys = [];
for (let item of this.data) {
this.expandedKeys.push(item.orgNo);
}
}
} catch (error) {
console.error('获取组织树失败:', error);
this.$message.error('组织架构加载失败');
}
}
3.3 节点点击事件处理
javascript
// 树节点点击事件
handleNodeClick(val) {
// 更新当前选中状态
this.curTreeNode = val.label;
this.orgNo = val.orgNo;
this.node_children = val.children;
// 重新加载表格数据
this.page(1);
}
四、智能检索设计
4.1 多维度筛选条件
javascript
data() {
return {
// 检索条件
searchVal: "", // 敏感词/账号/群号搜索
caseName: "", // 案件名称搜索
searchType: "", // 敏感词类型
searchTypeList: [], // 敏感词类型选项
searchTime: [], // 时间范围 [开始时间, 结束时间]
chatType: "", // 聊天类型:1-私聊,2-群聊
};
}
4.2 动态筛选面板
html
<el-form :inline="true">
<!-- 敏感词类型筛选 -->
<el-form-item label="敏感词类型">
<el-select v-model="searchType" placeholder="敏感词类型">
<el-option
v-for="item in searchTypeList"
:key="item.id"
:label="item.keyWord"
:value="item.keyWord"
></el-option>
</el-select>
</el-form-item>
<!-- 关键词搜索 -->
<el-form-item label="搜索敏感词">
<el-input
v-model.trim="searchVal"
placeholder="搜索敏感词/个人账号/群号"
></el-input>
</el-form-item>
<!-- 时间范围选择 -->
<el-form-item label="选择时间:" class="block">
<el-date-picker
v-model="searchTime"
type="datetimerange"
value-format="yyyy-MM-dd HH:mm:ss"
range-separator="至"
start-placeholder="发送时间"
end-placeholder="发送时间"
></el-date-picker>
</el-form-item>
<!-- 案件名称搜索 -->
<el-form-item label="搜索案件">
<el-input v-model.trim="caseName" placeholder="搜索案件"></el-input>
</el-form-item>
<!-- 聊天类型筛选 -->
<el-form-item label="聊天类型:">
<el-select v-model="chatType" clearable placeholder="请选择聊天类型">
<el-option label="全部" value=""></el-option>
<el-option label="私聊" :value="1"></el-option>
<el-option label="群聊" :value="2"></el-option>
</el-select>
</el-form-item>
</el-form>
4.3 数据请求参数构建
javascript
buildRequestParams(page_data) {
return {
page: page_data,
pageSize: this.page_size,
searchContent: this.searchVal,
caseName: this.caseName,
sensitiveWordsType: this.searchType,
startTime: this.searchTime[0] || "",
endTime: this.searchTime[1] || "",
chatType: this.chatType,
orgNo: this.orgNo, // 组织单位编码
childrenList: this.node_children // 子单位列表
};
}
page(page_data) {
this.loadingInstance = this.openLoading("加载中...");
// 重置分页计数
if (page_data == 1) this.reset_pagenum++;
// 构建请求参数
const requestData = this.buildRequestParams(page_data);
// 发起请求
getApi.getSensitiveWordsPageList(requestData).then((res) => {
if (res.data.code == 1 && res.data.data) {
this.tableList = res.data.data;
this.parentMsg = res.data.count;
} else {
this.tableList = [];
this.parentMsg = 0;
}
this.loadingInstance.close();
});
}
4.4 复杂列渲染设计
html
<el-table class="list_table" :data="tableList" stripe height="100%">
<!-- 敏感词列 -->
<el-table-column
label="敏感词"
prop="sensitiveContent"
show-overflow-tooltip
></el-table-column>
<!-- 聊天内容列 - 使用自定义组件 -->
<el-table-column label="聊天内容">
<template slot-scope="scope">
<tool-tip
:content="scope.row.message"
:max-lines="3"
></tool-tip>
</template>
</el-table-column>
<!-- 发送账号列 - 复杂模板 -->
<el-table-column label="发送账号(昵称)" show-overflow-tooltip>
<template slot-scope="scope">
<el-row>{{scope.row.account1Number}}</el-row>
<el-row v-if="scope.row.account1Nick">
({{scope.row.account1Nick}})
</el-row>
</template>
</el-table-column>
<!-- 接收账号列 - 条件渲染 -->
<el-table-column label="接收账号(昵称)" show-overflow-tooltip>
<template slot-scope="scope">
<el-row v-if="scope.row.chatType == 1">
<el-row>{{scope.row.account2Number}}</el-row>
<el-row v-if="scope.row.account2Nick">
({{scope.row.account2Nick}})
</el-row>
</el-row>
<el-row v-else>
<el-row>{{scope.row.groupId}}</el-row>
<el-row v-if="scope.row.groupName">
({{scope.row.groupName}})
</el-row>
</el-row>
</template>
</el-table-column>
<!-- 操作列 - 详情跳转 -->
<el-table-column label="操作" width="150">
<template slot-scope="scope">
<el-button
type="primary"
size="mini"
@click="toReport(scope.row)"
>
详情
</el-button>
</template>
</el-table-column>
</el-table>
4.5 自定义ToolTip组件
html
<!-- ToolTip组件 - 用于长文本截断显示 -->
<template>
<div class="tooltip-container">
<span
class="text-content"
:title="content"
@mouseenter="showTooltip = true"
@mouseleave="showTooltip = false"
>
{{ truncatedText }}
</span>
<el-tooltip
v-if="showTooltip && isOverflow"
effect="dark"
:content="content"
placement="top"
>
</el-tooltip>
</div>
</template>
<script>
export default {
props: {
content: String,
maxLines: {
type: Number,
default: 3
}
},
computed: {
truncatedText() {
if (!this.content) return '';
const lines = this.content.split('\n');
if (lines.length > this.maxLines) {
return lines.slice(0, this.maxLines).join('\n') + '...';
}
return this.content;
},
isOverflow() {
return this.content.split('\n').length > this.maxLines;
}
}
};
</script>
五、详情跳转与数据传递
5.1 路由跳转参数构建
javascript
toReport(row) {
// 构建查询参数对象
const queryParams = {
id: row.chatId, // 聊天记录ID
phoneId: row.phoneId, // 手机/设备ID
fromPage: 4, // 来源页面标识(敏感词页)
reportId: row.reportId, // 报告ID
type: row.reportType, // 报告类型
accountType: row.accountType, // 账号类型
isDelete: row.deleteFlag, // 是否删除标志
chatType: row.chatType, // 聊天类型:1私聊/2群聊
name: row.dataSources, // 数据来源/报告名称
sendAccount: row.account1Number, // 发送账号
acceptAccount: row.chatType == 1 ?
row.account2Number : row.groupId, // 接收账号或群号
groupInvolvedAccount: row.groupInvolvedAccount, // 群内涉及账号
sendTime: row.sendTime, // 发送时间
};
// 新窗口打开(推荐方式)
openWin({
name: "evidences.report",
query: queryParams,
});
// 原窗口打开(备选方案)
// this.$router.push({
// name: "evidences.report",
// query: queryParams
// });
}
5.2 工具函数封装
javascript
// utils/tools.js - openWin函数实现
export const openWin = ({ name, path, query = {} }) => {
// 构建URL
const routeUrl = this.$router.resolve({
name: name || '',
path: path || '',
query: query
});
// 新窗口打开
window.open(routeUrl.href, '_blank');
// 或者使用更复杂的方式处理浏览器限制
const newWindow = window.open('', '_blank');
if (newWindow) {
newWindow.location.href = routeUrl.href;
} else {
// 处理浏览器拦截
this.$message.warning('请允许弹出窗口');
}
};
5.3 树形数据缓存
javascript
// 树形数据缓存策略
const treeCache = new Map();
async get_tree(forceRefresh = false) {
const cacheKey = 'org_tree_data';
// 检查缓存
if (!forceRefresh && treeCache.has(cacheKey)) {
const cachedData = treeCache.get(cacheKey);
this.processTreeData(cachedData);
return;
}
try {
const res = await getWAOrgTree();
if (res.data.code == 1) {
// 缓存数据
treeCache.set(cacheKey, res.data.data);
this.processTreeData(res.data.data);
}
} catch (error) {
console.error('获取组织树失败:', error);
}
}
processTreeData(treeData) {
this.data = [];
this.orgNo = treeData.orgNo;
this.node_children = treeData.children;
this.curTreeNode = treeData.label;
this.data.push(treeData);
// 设置展开节点
this.expandedKeys = this.data.map(item => item.orgNo);
}
总结
这个敏感词智能检索组件前端实现展示了如何将复杂的业务需求转化为直观、高效的用户界面。关键设计亮点包括:
组织架构树形过滤:实现数据的分级权限管理
多维智能检索:支持多条件组合查询
响应式布局:适应不同屏幕和设备
性能优化:分页、缓存、防抖等多重优化
用户体验:平滑动画、空状态、加载提示等细节处理
系统具有良好的扩展性,可以通过配置化方式添加新的筛选维度,支持插件化开发模式,能够快速适应业务需求的变化。