本地 RAG 知识库
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

41 lines
3.2 KiB

<template>
<t-card title="📋 内容审计日志" :bordered="false">
<p class="desc-text">记录所有敏感词命中事件,包含输入/输出方向、违规内容、命中词及处理方式。</p>
<BaseTable :data="logs" :columns="columns" row-key="id" :loading="loading" :sort="sortInfo"
:pagination="{current:page,total:total,pageSize:pageSize,showJumper:true}" @page-change="onPageChange" @sort-change="onSortChange">
<template #direction="{row}"><span :style="{color:row.direction==='INPUT'?'var(--color-primary)':'var(--color-success)'}">{{ row.direction==='INPUT'?'输入':'输出' }}</span></template>
<template #originalText="{row}"><span :title="row.originalText" class="ellipsis-td">{{ row.originalText }}</span></template>
<template #actionTaken="{row}"><span :style="{color:row.actionTaken==='BLOCK'?'var(--color-error)':row.actionTaken==='MASK'?'var(--color-warning)':'var(--color-success)'}">{{ row.actionTaken==='BLOCK'?'拦截':row.actionTaken==='MASK'?'脱敏':'通过' }}</span></template>
<template #hitWords="{row}"><span class="hit-words">{{ formatHitWords(row.hitWords) }}</span></template>
</BaseTable>
</t-card>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { listAuditLogs } from '@/api/sensitive-word'
import { toast } from '@/utils/toast'
import { formatDate } from '@/utils/format'
const logs=ref<any[]>([]);const loading=ref(false);const page=ref(1);const pageSize=ref(30);const total=ref(0)
const columns=[{colKey:'createTime',title:'时间',width:160,sorter:true,cell:(_:any,{row}:any)=>formatDate(row.createTime)},{colKey:'direction',title:'方向',width:60,sorter:true},{colKey:'originalText',title:'违规内容',width:260},{colKey:'hitWords',title:'命中词',width:180},{colKey:'actionTaken',title:'处理方式',width:80,sorter:true}]
const sortInfo = ref<{ sortBy: string; descending: boolean } | null>(null)
onMounted(()=>loadLogs())
async function loadLogs(){loading.value=true
try{const r=await listAuditLogs(page.value,pageSize.value,undefined,sortInfo.value?.sortBy||undefined,sortInfo.value?(sortInfo.value.descending?'desc':'asc'):undefined);if(r.success){logs.value=r.data?.records||r.data||[];total.value=r.data?.total||r.total||0}else toast('加载失败:'+(r.message||''),'error')}catch(e:any){toast('加载失败:'+e.message,'error')}finally{loading.value=false}}
function onPageChange(i:{current:number;pageSize:number}){page.value=i.current;pageSize.value=i.pageSize;loadLogs()}
function onSortChange(s:any){sortInfo.value=s&&s.sortBy?{sortBy:s.sortBy,descending:!!s.descending}:null;loadLogs()}
function formatHitWords(hw:any):string{
if(!hw)return'';if(hw.type==='jsonb'&&hw.value){try{hw=JSON.parse(hw.value)}catch{return hw.value}}
if(typeof hw==='string'){try{hw=JSON.parse(hw)}catch{return hw}}
if(hw?.hits&&Array.isArray(hw.hits))return hw.hits.map((h:any)=>`${h.word||''}(${h.category||''})`).join('、')
if(Array.isArray(hw))return hw.map((h:any)=>typeof h==='string'?h:h.word||'').join('、')
return String(hw)
}
</script>
<style scoped>.ellipsis-td{max-width:260px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:block;}.hit-words{font-size:12px;}</style>