Files
prop-data-guard/frontend/src/views/unstructured/Unstructured.vue
T
hiderfong 6d70520e79 feat: 全量功能模块开发与集成测试修复
- 新增后端模块:Alert、APIAsset、Compliance、Lineage、Masking、Risk、SchemaChange、Unstructured、Watermark
- 新增前端模块页面与API接口
- 新增Alembic迁移脚本(002-014)覆盖全量业务表
- 新增测试数据生成脚本与集成测试脚本
- 修复metadata模型JSON类型导入缺失导致启动失败的问题
- 修复前端Alert/APIAsset页面request模块路径错误
- 更新docker-compose与开发计划文档
2026-04-25 08:51:38 +08:00

144 lines
5.1 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="page-container">
<h2 class="page-title">非结构化文件识别</h2>
<div class="upload-area card-shadow" style="padding: 24px; margin-bottom: 16px;">
<el-upload
drag
action="#"
:auto-upload="false"
:on-change="handleFileChange"
accept=".docx,.xlsx,.pdf,.txt"
:limit="1"
>
<el-icon class="el-icon--upload"><upload-icon /></el-icon>
<div class="el-upload__text">拖拽文件到此处或 <em>点击上传</em></div>
<template #tip>
<div class="el-upload__tip">支持 WordExcelPDFTXT 格式</div>
</template>
</el-upload>
<el-button type="primary" :loading="uploadLoading" @click="handleUpload" style="margin-top: 12px;">开始识别</el-button>
</div>
<div class="table-card card-shadow">
<el-table :data="fileList" v-loading="listLoading" stripe size="default" border>
<el-table-column prop="original_name" label="文件名" min-width="180" />
<el-table-column prop="file_type" label="类型" width="80" />
<el-table-column prop="status" label="状态" width="100">
<template #default="{ row }">
<el-tag :type="row.status === 'processed' ? 'success' : row.status === 'error' ? 'danger' : 'warning'">
{{ ({ pending: '待处理', processed: '已处理', error: '失败' } as Record<string, string>)[row.status as string] || row.status }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="敏感信息" min-width="200">
<template #default="{ row }">
<div v-if="row.analysis_result?.matches?.length">
<el-tag v-for="(m, idx) in row.analysis_result.matches.slice(0, 3)" :key="idx" size="small" type="danger" style="margin-right: 4px;">
{{ m.rule_name }}
</el-tag>
<span v-if="row.analysis_result.matches.length > 3" class="more-tag">+{{ row.analysis_result.matches.length - 3 }}</span>
</div>
<span v-else class="empty-text">未检测到</span>
</template>
</el-table-column>
<el-table-column label="操作" width="140" fixed="right">
<template #default="{ row }">
<el-button type="primary" link size="small" @click="handleView(row)">查看详情</el-button>
<el-button type="primary" link size="small" @click="handleReprocess(row)">重新识别</el-button>
</template>
</el-table-column>
</el-table>
</div>
<el-dialog v-model="detailVisible" title="识别详情" width="640px" destroy-on-close>
<div v-if="currentFile?.analysis_result?.matches?.length">
<div style="margin-bottom: 12px;">共发现 {{ currentFile.analysis_result.matches.length }} 处敏感信息</div>
<el-timeline>
<el-timeline-item v-for="(m, idx) in currentFile.analysis_result.matches" :key="idx" :type="m.level_code === 'L4' || m.level_code === 'L5' ? 'danger' : 'warning'">
<div style="font-weight: 600;">{{ m.rule_name }} ({{ m.level_code }})</div>
<div style="color: #909399; font-size: 13px; margin-top: 4px;">片段{{ m.snippet }}</div>
</el-timeline-item>
</el-timeline>
</div>
<el-empty v-else description="未检测到敏感信息" />
</el-dialog>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { ElMessage } from 'element-plus'
import { Upload as UploadIcon } from '@element-plus/icons-vue'
import { uploadUnstructuredFile, getUnstructuredFiles, reprocessUnstructuredFile } from '@/api/unstructured'
const uploadLoading = ref(false)
const listLoading = ref(false)
const fileList = ref<any[]>([])
const selectedFile = ref<File | null>(null)
const detailVisible = ref(false)
const currentFile = ref<any>(null)
function handleFileChange(file: any) {
selectedFile.value = file.raw
}
async function handleUpload() {
if (!selectedFile.value) {
ElMessage.warning('请选择文件')
return
}
uploadLoading.value = true
try {
const res: any = await uploadUnstructuredFile(selectedFile.value)
ElMessage.success('上传并识别成功')
selectedFile.value = null
fetchList()
} catch (e: any) {
ElMessage.error(e?.message || '上传失败')
} finally {
uploadLoading.value = false
}
}
async function fetchList() {
listLoading.value = true
try {
const res: any = await getUnstructuredFiles()
fileList.value = res.data || []
} catch (e: any) {
ElMessage.error(e?.message || '加载失败')
} finally {
listLoading.value = false
}
}
function handleView(row: any) {
currentFile.value = row
detailVisible.value = true
}
async function handleReprocess(row: any) {
try {
const res: any = await reprocessUnstructuredFile(row.id)
ElMessage.success('重新识别完成')
fetchList()
} catch (e: any) {
ElMessage.error(e?.message || '识别失败')
}
}
onMounted(() => {
fetchList()
})
</script>
<style scoped lang="scss">
.empty-text {
color: #c0c4cc;
}
.more-tag {
font-size: 12px;
color: #909399;
}
</style>