finyx_data_ai/tests/test_ai_analyze.html
2026-01-11 07:48:19 +08:00

781 lines
38 KiB
HTML
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.

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>数据资产智能识别接口测试 - Finyx Data AI</title>
<link rel="stylesheet" href="test_common.css">
<style>
.field-tag {
display: inline-block;
padding: 2px 8px;
border-radius: 4px;
font-size: 11px;
margin-right: 4px;
margin-bottom: 4px;
}
.tag-pii { background-color: #ffebee; color: #d32f2f; }
.tag-important { background-color: #fff3e0; color: #f57c00; }
.confidence-bar {
height: 8px;
background-color: #e0e0e0;
border-radius: 4px;
overflow: hidden;
margin-top: 4px;
}
.confidence-fill {
height: 100%;
border-radius: 4px;
transition: width 0.3s ease;
}
.confidence-high { background-color: #4caf50; }
.confidence-medium { background-color: #ff9800; }
.confidence-low { background-color: #f44336; }
.field-card {
border-left: 3px solid transparent;
padding-left: 12px;
margin-bottom: 12px;
}
.field-card.pii { border-left-color: #f44336; }
.field-card.important { border-left-color: #ff9800; }
.table-accordion {
border: 1px solid var(--border-color);
border-radius: var(--radius);
margin-bottom: 16px;
overflow: hidden;
}
.accordion-header {
background-color: var(--light-color);
padding: 16px;
cursor: pointer;
display: flex;
justify-content: space-between;
align-items: center;
transition: var(--transition);
}
.accordion-header:hover {
background-color: #e9ecef;
}
.accordion-header.active {
background-color: var(--primary-color);
color: var(--white);
}
.accordion-content {
display: none;
padding: 16px;
background-color: var(--white);
}
.accordion-content.active {
display: block;
}
.accordion-icon {
transition: transform 0.3s ease;
}
.accordion-header.active .accordion-icon {
transform: rotate(180deg);
}
</style>
</head>
<body>
<div class="container">
<!-- 页面头部 -->
<header class="page-header">
<h1 class="page-title">🔍 数据资产智能识别接口测试</h1>
<p class="page-subtitle">
使用大模型识别数据资产的中文名称、业务含义、PII敏感信息和重要数据特征
</p>
</header>
<div class="content-grid">
<!-- 左侧:输入表单 -->
<div class="col-4">
<div class="card">
<div class="card-header">
<h3 class="card-title">输入参数</h3>
</div>
<div class="card-body">
<form id="analyzeForm">
<div class="form-group">
<label class="form-label" for="projectId">项目ID *</label>
<input type="text" id="projectId" class="form-control" value="project_001" placeholder="输入项目ID">
</div>
<div class="form-group">
<label class="form-label" for="industry">行业信息</label>
<select id="industry" class="form-control">
<option value="">请选择行业</option>
<option value="retail-fresh" selected>零售生鲜</option>
<option value="retail-general">零售通用</option>
<option value="finance">金融</option>
<option value="healthcare">医疗健康</option>
<option value="logistics">物流</option>
<option value="manufacturing">制造业</option>
</select>
</div>
<div class="form-group">
<label class="form-label" for="context">业务背景信息</label>
<textarea id="context" class="form-control" rows="4" placeholder="描述业务背景、使用场景等">某连锁生鲜零售企业主营水果、蔬菜等生鲜产品拥有200+线下门店和线上电商平台</textarea>
</div>
<div class="form-group">
<label class="form-label">大模型配置</label>
<div class="form-row">
<select id="model" class="form-control">
<option value="qwen-max" selected>通义千问 Max</option>
<option value="gpt-4">GPT-4</option>
</select>
<input type="number" id="temperature" class="form-control" value="0.3" min="0" max="1" step="0.1" title="温度参数">
</div>
</div>
<div class="form-group">
<label class="form-label">选项配置</label>
<div>
<label style="margin-right: 16px;">
<input type="checkbox" id="enablePII" checked> 启用PII识别
</label>
<label>
<input type="checkbox" id="enableImportant" checked> 启用重要数据识别
</label>
</div>
</div>
<div class="form-group">
<label class="form-label">快速使用虚拟数据</label>
<div class="btn-group">
<button type="button" class="btn btn-info btn-sm" onclick="loadMockData('retail')">零售场景</button>
<button type="button" class="btn btn-info btn-sm" onclick="loadMockData('finance')">金融场景</button>
<button type="button" class="btn btn-info btn-sm" onclick="loadMockData('user')">用户中心</button>
</div>
</div>
<div class="btn-group" style="margin-top: 20px;">
<button type="submit" class="btn btn-primary">🚀 开始分析</button>
<button type="button" class="btn btn-outline" onclick="resetForm()">重置</button>
</div>
</form>
</div>
</div>
<!-- API 调用信息 -->
<div class="card">
<div class="card-header">
<h3 class="card-title">API 调用信息</h3>
</div>
<div class="card-body">
<div class="form-group">
<label class="form-label">请求端点</label>
<code style="display: block; padding: 8px; background: var(--light-color); border-radius: var(--radius); font-size: 12px;">
POST /api/v1/inventory/ai-analyze
</code>
</div>
<div id="requestInfo" class="form-group">
<label class="form-label">请求数据</label>
<pre id="requestJson" style="max-height: 200px; overflow: auto; font-size: 11px; background: var(--light-color); padding: 8px; border-radius: var(--radius);">等待提交...</pre>
</div>
<div id="responseInfo" class="form-group" style="display: none;">
<label class="form-label">响应数据</label>
<pre id="responseJson" style="max-height: 300px; overflow: auto; font-size: 11px; background: var(--light-color); padding: 8px; border-radius: var(--radius);"></pre>
</div>
</div>
</div>
</div>
<!-- 右侧:结果展示 -->
<div class="col-8">
<!-- 加载状态 -->
<div id="loadingArea" style="display: none;"></div>
<!-- 结果区域 -->
<div id="resultArea" style="display: none;">
<!-- 统计信息 -->
<div class="stats-grid">
<div class="stat-card">
<div class="stat-label">总表数</div>
<div class="stat-value" id="statTables">0</div>
</div>
<div class="stat-card">
<div class="stat-label">总字段数</div>
<div class="stat-value" id="statFields">0</div>
</div>
<div class="stat-card danger">
<div class="stat-label">PII 字段数</div>
<div class="stat-value" id="statPII">0</div>
</div>
<div class="stat-card warning">
<div class="stat-label">重要数据字段</div>
<div class="stat-value" id="statImportant">0</div>
</div>
<div class="stat-card success">
<div class="stat-label">平均置信度</div>
<div class="stat-value" id="statConfidence">0%</div>
</div>
</div>
<!-- PII 识别统计 -->
<div class="card">
<div class="card-header">
<h3 class="card-title">🔒 PII 敏感信息识别</h3>
</div>
<div class="card-body">
<div id="piiChart"></div>
</div>
</div>
<!-- 表识别结果 -->
<div class="card">
<div class="card-header">
<h3 class="card-title">📊 表识别结果</h3>
</div>
<div class="card-body">
<div id="tableResults"></div>
</div>
</div>
<!-- 重要数据类型 -->
<div class="card">
<div class="card-header">
<h3 class="card-title">⭐ 重要数据类型识别</h3>
</div>
<div class="card-body">
<div id="importantDataChart"></div>
</div>
</div>
<!-- 置信度分布 -->
<div class="card">
<div class="card-header">
<h3 class="card-title">📈 置信度分布</h3>
</div>
<div class="card-body">
<div id="confidenceChart"></div>
</div>
</div>
</div>
<!-- 空状态 -->
<div id="emptyState" class="card" style="text-align: center; padding: 60px 20px;">
<div style="font-size: 48px; margin-bottom: 20px;">🎯</div>
<h3 style="margin-bottom: 12px;">等待分析</h3>
<p style="color: var(--text-muted);">
填写左侧表单参数,或点击"快速使用虚拟数据"按钮<br>
然后点击"开始分析"按钮进行数据资产智能识别
</p>
</div>
</div>
</div>
</div>
<script src="base_test_framework.js"></script>
<script>
// ==================== 虚拟数据 ====================
const mockData = {
retail: {
tables: [
{
raw_name: "t_user_base_01",
fields: [
{ raw_name: "user_id", type: "varchar(64)", comment: "用户唯一标识符" },
{ raw_name: "phone", type: "varchar(11)", comment: "用户手机号码" },
{ raw_name: "email", type: "varchar(100)", comment: "用户电子邮箱" },
{ raw_name: "nickname", type: "varchar(50)", comment: "用户昵称" },
{ raw_name: "register_time", type: "datetime", comment: "注册时间" }
]
},
{
raw_name: "t_order_detail",
fields: [
{ raw_name: "order_id", type: "bigint", comment: "订单ID" },
{ raw_name: "user_id", type: "varchar(64)", comment: "用户ID" },
{ raw_name: "product_name", type: "varchar(200)", comment: "商品名称" },
{ raw_name: "quantity", type: "int", comment: "购买数量" },
{ raw_name: "price", type: "decimal(10,2)", comment: "商品单价" },
{ raw_name: "total_amount", type: "decimal(10,2)", comment: "订单总金额" },
{ raw_name: "pay_time", type: "datetime", comment: "支付时间" }
]
},
{
raw_name: "t_member_info",
fields: [
{ raw_name: "member_id", type: "varchar(64)", comment: "会员ID" },
{ raw_name: "member_level", type: "int", comment: "会员等级" },
{ raw_name: "points", type: "int", comment: "会员积分" },
{ raw_name: "birth_date", type: "date", comment: "出生日期" },
{ raw_name: "id_card", type: "varchar(18)", comment: "身份证号码" }
]
}
]
},
finance: {
tables: [
{
raw_name: "t_account_info",
fields: [
{ raw_name: "account_no", type: "varchar(32)", comment: "账户号码" },
{ raw_name: "customer_name", type: "varchar(100)", comment: "客户姓名" },
{ raw_name: "id_card", type: "varchar(18)", comment: "身份证号码" },
{ raw_name: "phone", type: "varchar(11)", comment: "联系电话" },
{ raw_name: "balance", type: "decimal(18,2)", comment: "账户余额" }
]
},
{
raw_name: "t_transaction_record",
fields: [
{ raw_name: "trans_id", type: "bigint", comment: "交易流水号" },
{ raw_name: "account_no", type: "varchar(32)", comment: "账户号码" },
{ raw_name: "amount", type: "decimal(18,2)", comment: "交易金额" },
{ raw_name: "trans_type", type: "varchar(20)", comment: "交易类型" },
{ raw_name: "trans_time", type: "datetime", comment: "交易时间" },
{ raw_name: "counter_account", type: "varchar(32)", comment: "对方账户" }
]
}
]
},
user: {
tables: [
{
raw_name: "user_profile",
fields: [
{ raw_name: "uid", type: "bigint", comment: "用户ID" },
{ raw_name: "username", type: "varchar(50)", comment: "用户名" },
{ raw_name: "real_name", type: "varchar(50)", comment: "真实姓名" },
{ raw_name: "mobile", type: "varchar(11)", comment: "手机号" },
{ raw_name: "email", type: "varchar(100)", comment: "邮箱" },
{ raw_name: "address", type: "varchar(500)", comment: "家庭地址" },
{ raw_name: "create_time", type: "datetime", comment: "创建时间" }
]
},
{
raw_name: "user_login_log",
fields: [
{ raw_name: "log_id", type: "bigint", comment: "日志ID" },
{ raw_name: "user_id", type: "bigint", comment: "用户ID" },
{ raw_name: "login_ip", type: "varchar(50)", comment: "登录IP" },
{ raw_name: "login_time", type: "datetime", comment: "登录时间" },
{ raw_name: "user_agent", type: "varchar(500)", comment: "用户代理" }
]
},
{
raw_name: "user_payment",
fields: [
{ raw_name: "payment_id", type: "bigint", comment: "支付ID" },
{ raw_name: "user_id", type: "bigint", comment: "用户ID" },
{ raw_name: "card_number", type: "varchar(30)", comment: "银行卡号" },
{ raw_name: "bank_name", type: "varchar(100)", comment: "银行名称" },
{ raw_name: "expiry_date", type: "varchar(10)", comment: "有效期" }
]
}
]
}
};
// ==================== 模拟分析结果 ====================
function generateMockResponse(requestData) {
const tables = requestData.tables || [];
let totalFields = 0;
let piiFields = 0;
let importantFields = 0;
let totalConfidence = 0;
let piiTypes = {};
let importantDataTypes = {};
let confidenceRanges = { high: 0, medium: 0, low: 0 };
const processedTables = tables.map(table => {
const processedFields = table.fields.map(field => {
const hasPII = detectPII(field.raw_name, field.comment);
const isImportant = detectImportantData(field.raw_name, field.comment);
const confidence = calculateConfidence(field);
if (hasPII) {
piiFields++;
const piiType = detectPIIType(field.raw_name);
piiTypes[piiType] = (piiTypes[piiType] || 0) + 1;
}
if (isImportant) {
importantFields++;
const dataType = detectDataType(field.raw_name);
importantDataTypes[dataType] = (importantDataTypes[dataType] || 0) + 1;
}
if (confidence >= 80) confidenceRanges.high++;
else if (confidence >= 60) confidenceRanges.medium++;
else confidenceRanges.low++;
totalConfidence += confidence;
totalFields++;
return {
raw_name: field.raw_name,
ai_name: generateChineseName(field.raw_name),
desc: field.comment || generateDescription(field.raw_name),
type: field.type,
pii: hasPII ? [detectPIIType(field.raw_name)] : [],
pii_type: hasPII ? detectPIIType(field.raw_name) : null,
is_important_data: isImportant,
confidence: confidence
};
});
const tablePII = [];
const tableImportantDataTypes = [];
processedFields.forEach(f => {
if (f.pii.length > 0) tablePII.push(...f.pii);
if (f.is_important_data && f.pii_type) {
if (!tableImportantDataTypes.includes(f.pii_type)) {
tableImportantDataTypes.push(f.pii_type);
}
}
});
return {
raw_name: table.raw_name,
ai_name: generateChineseName(table.raw_name),
desc: generateDescription(table.raw_name),
confidence: Math.round(processedFields.reduce((sum, f) => sum + f.confidence, 0) / processedFields.length),
ai_completed: true,
fields: processedFields,
pii: tablePII,
important: tablePII.length > 0,
important_data_types: tableImportantDataTypes
};
});
const statistics = {
total_tables: tables.length,
total_fields: totalFields,
pii_fields_count: piiFields,
important_data_fields_count: importantFields,
average_confidence: totalFields > 0 ? Math.round(totalConfidence / totalFields) : 0
};
return {
tables: processedTables,
statistics: statistics,
processing_time: (Math.random() * 3 + 1).toFixed(2),
model_used: requestData.options?.model || 'qwen-max',
piiTypes: piiTypes,
importantDataTypes: importantDataTypes,
confidenceRanges: confidenceRanges
};
}
// 辅助函数
function detectPII(fieldName, comment) {
const piiKeywords = ['phone', 'mobile', 'email', 'mail', 'id_card', 'idcard', 'name', 'real_name', 'idcard', 'address', 'card', 'bank', 'birth', 'id'];
const fieldLower = fieldName.toLowerCase();
const commentLower = (comment || '').toLowerCase();
return piiKeywords.some(keyword => fieldLower.includes(keyword) || commentLower.includes(keyword));
}
function detectPIIType(fieldName) {
const fieldLower = fieldName.toLowerCase();
if (fieldLower.includes('phone') || fieldLower.includes('mobile')) return '手机号';
if (fieldLower.includes('email') || fieldLower.includes('mail')) return '邮箱';
if (fieldLower.includes('id_card') || fieldLower.includes('idcard')) return '身份证号';
if (fieldLower.includes('name')) return '姓名';
if (fieldLower.includes('address')) return '地址';
if (fieldLower.includes('card') || fieldLower.includes('bank')) return '银行卡号';
if (fieldLower.includes('birth')) return '出生日期';
return '其他敏感信息';
}
function detectImportantData(fieldName, comment) {
const importantKeywords = ['balance', 'amount', 'price', 'payment', 'transaction', 'trans', 'points', 'score'];
const fieldLower = fieldName.toLowerCase();
const commentLower = (comment || '').toLowerCase();
return importantKeywords.some(keyword => fieldLower.includes(keyword) || commentLower.includes(keyword));
}
function detectDataType(fieldName) {
const fieldLower = fieldName.toLowerCase();
if (fieldLower.includes('balance') || fieldLower.includes('amount') || fieldLower.includes('price')) return '金融数据';
if (fieldLower.includes('transaction') || fieldLower.includes('trans') || fieldLower.includes('payment')) return '交易数据';
if (fieldLower.includes('points') || fieldLower.includes('score')) return '积分数据';
return '其他重要数据';
}
function calculateConfidence(field) {
let baseScore = 70;
if (field.comment && field.comment.length > 0) baseScore += 15;
if (field.type && field.type.length > 0) baseScore += 10;
return Math.min(99, Math.round(baseScore + Math.random() * 5));
}
function generateChineseName(fieldName) {
const translations = {
'user_id': '用户ID',
'uid': '用户唯一标识',
'phone': '手机号',
'mobile': '联系电话',
'email': '电子邮箱',
'nickname': '用户昵称',
'username': '用户名',
'real_name': '真实姓名',
'address': '收货地址',
'register_time': '注册时间',
'create_time': '创建时间',
'login_time': '登录时间',
'order_id': '订单编号',
'product_name': '商品名称',
'quantity': '购买数量',
'price': '商品单价',
'total_amount': '订单总额',
'pay_time': '支付时间',
'member_id': '会员编号',
'member_level': '会员等级',
'points': '会员积分',
'birth_date': '出生日期',
'id_card': '身份证号码',
'account_no': '账户号码',
'customer_name': '客户姓名',
'balance': '账户余额',
'trans_id': '交易流水号',
'amount': '交易金额',
'trans_type': '交易类型',
'trans_time': '交易时间',
'counter_account': '对方账户',
'log_id': '日志编号',
'login_ip': '登录IP地址',
'user_agent': '用户代理',
'payment_id': '支付编号',
'card_number': '银行卡号',
'bank_name': '银行名称',
'expiry_date': '有效期'
};
return translations[fieldName.toLowerCase()] || fieldName;
}
function generateDescription(tableName) {
const descriptions = {
't_user_base_01': '存储用户的基础信息包括用户ID、联系方式等核心身份数据',
'user_profile': '用户个人资料信息,包含用户的真实身份信息',
't_order_detail': '订单详情记录,存储每个订单的商品明细和支付信息',
't_member_info': '会员信息表,记录会员等级、积分等会员权益数据',
't_account_info': '账户信息表,存储客户的银行账户和余额信息',
't_transaction_record': '交易记录表,记录所有账户的交易流水',
'user_login_log': '用户登录日志,记录用户的登录行为和安全信息',
'user_payment': '用户支付信息,存储用户的银行卡等支付方式'
};
return descriptions[tableName] || '存储业务数据的关键数据表';
}
// ==================== 表单处理 ====================
let currentMockData = null;
function loadMockData(type) {
currentMockData = mockData[type];
document.getElementById('context').value = {
'retail': '某连锁生鲜零售企业主营水果、蔬菜等生鲜产品拥有200+线下门店和线上电商平台',
'finance': '某银行机构,提供个人和企业金融服务',
'user': '用户中心系统,负责用户注册、登录、权限管理等核心功能'
}[type];
// 更新行业选择
document.getElementById('industry').value = {
'retail': 'retail-fresh',
'finance': 'finance',
'user': 'retail-fresh'
}[type];
showToast(`已加载${{ 'retail': '零售', 'finance': '金融', 'user': '用户中心' }[type]}场景虚拟数据`);
}
function resetForm() {
document.getElementById('analyzeForm').reset();
currentMockData = null;
document.getElementById('resultArea').style.display = 'none';
document.getElementById('emptyState').style.display = 'block';
document.getElementById('requestInfo').style.display = 'block';
document.getElementById('responseInfo').style.display = 'none';
}
// 表单提交
document.getElementById('analyzeForm').addEventListener('submit', async function(e) {
e.preventDefault();
// 获取表单数据
const requestData = {
project_id: document.getElementById('projectId').value,
industry: document.getElementById('industry').value,
context: document.getElementById('context').value,
options: {
model: document.getElementById('model').value,
temperature: parseFloat(document.getElementById('temperature').value),
enable_pii_detection: document.getElementById('enablePII').checked,
enable_important_data_detection: document.getElementById('enableImportant').checked
}
};
// 使用虚拟数据或空数据
if (currentMockData) {
requestData.tables = currentMockData.tables;
} else {
// 提示用户需要输入表数据
showToast('请使用快速虚拟数据或手动输入表数据');
return;
}
// 显示请求数据
document.getElementById('requestJson').textContent = JSON.stringify(requestData, null, 2);
document.getElementById('responseInfo').style.display = 'none';
// 显示加载状态
document.getElementById('emptyState').style.display = 'none';
document.getElementById('resultArea').style.display = 'none';
showLoading('loadingArea');
try {
// 模拟API调用
await delay(2000);
// 生成模拟响应
const response = generateMockResponse(requestData);
// 显示结果
hideLoading('loadingArea', '');
document.getElementById('resultArea').style.display = 'block';
// 显示响应数据
document.getElementById('responseInfo').style.display = 'block';
document.getElementById('responseJson').textContent = JSON.stringify(response, null, 2);
// 渲染统计信息
renderStatistics(response.statistics);
// 渲染图表
renderCharts(response);
// 渲染表结果
renderTableResults(response.tables);
showSuccess('loadingArea', '✅ 分析完成!');
setTimeout(() => {
document.getElementById('loadingArea').style.display = 'none';
}, 2000);
} catch (error) {
hideLoading('loadingArea', '');
showError('loadingArea', error.message);
}
});
// 渲染统计信息
function renderStatistics(statistics) {
document.getElementById('statTables').textContent = statistics.total_tables;
document.getElementById('statFields').textContent = statistics.total_fields;
document.getElementById('statPII').textContent = statistics.pii_fields_count;
document.getElementById('statImportant').textContent = statistics.important_data_fields_count;
document.getElementById('statConfidence').textContent = statistics.average_confidence + '%';
}
// 渲染图表
function renderCharts(response) {
// PII 类型分布
if (Object.keys(response.piiTypes).length > 0) {
const piiData = Object.entries(response.piiTypes).map(([key, value]) => ({
label: key,
value: value
}));
renderBarChart('piiChart', piiData, 'PII 敏感信息类型分布');
} else {
document.getElementById('piiChart').innerHTML = '<p style="text-align: center; color: var(--text-muted);">未检测到 PII 敏感信息</p>';
}
// 重要数据类型
if (Object.keys(response.importantDataTypes).length > 0) {
const importantData = Object.entries(response.importantDataTypes).map(([key, value]) => ({
label: key,
value: value
}));
renderBarChart('importantDataChart', importantData, '重要数据类型分布');
} else {
document.getElementById('importantDataChart').innerHTML = '<p style="text-align: center; color: var(--text-muted);">未检测到重要数据</p>';
}
// 置信度分布
const confidenceData = [
{ label: '高 (≥80%)', value: response.confidenceRanges.high, color: '#4caf50' },
{ label: '中 (60-79%)', value: response.confidenceRanges.medium, color: '#ff9800' },
{ label: '低 (<60%)', value: response.confidenceRanges.low, color: '#f44336' }
];
renderBarChart('confidenceChart', confidenceData, '识别置信度分布');
}
// 渲染表结果
function renderTableResults(tables) {
const container = document.getElementById('tableResults');
let html = '';
tables.forEach((table, index) => {
html += `
<div class="table-accordion">
<div class="accordion-header" onclick="toggleAccordion(this)">
<div>
<strong style="font-size: 16px;">${table.ai_name}</strong>
<div style="font-size: 12px; color: var(--text-muted); margin-top: 4px;">
原始名称: ${table.raw_name} | 字段数: ${table.fields.length} | 置信度: ${table.confidence}%
</div>
</div>
<div>
${table.important ? '<span class="field-tag tag-important">重要数据</span>' : ''}
${table.pii.length > 0 ? `<span class="field-tag tag-pii">含PII: ${table.pii.join(', ')}</span>` : ''}
<span class="accordion-icon">▼</span>
</div>
</div>
<div class="accordion-content">
<p style="margin-bottom: 12px; color: var(--text-muted);">${table.desc}</p>
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 12px;">
`;
table.fields.forEach(field => {
const hasPII = field.pii.length > 0;
const isImportant = field.is_important_data;
const confidenceClass = field.confidence >= 80 ? 'confidence-high' : (field.confidence >= 60 ? 'confidence-medium' : 'confidence-low');
html += `
<div class="field-card ${hasPII ? 'pii' : ''} ${isImportant ? 'important' : ''}">
<div style="display: flex; justify-content: space-between; align-items: start; margin-bottom: 4px;">
<strong style="font-size: 13px;">${field.ai_name}</strong>
<div style="font-size: 11px;">
${hasPII ? `<span class="field-tag tag-pii">${field.pii_type}</span>` : ''}
${isImportant ? '<span class="field-tag tag-important">重要</span>' : ''}
</div>
</div>
<div style="font-size: 11px; color: var(--text-muted); margin-bottom: 4px;">
${field.raw_name} | ${field.type}
</div>
<div style="font-size: 12px; margin-bottom: 6px;">${field.desc}</div>
<div style="font-size: 11px; display: flex; justify-content: space-between;">
<span>置信度: ${field.confidence}%</span>
</div>
<div class="confidence-bar">
<div class="confidence-fill ${confidenceClass}" style="width: ${field.confidence}%;"></div>
</div>
</div>
`;
});
html += `
</div>
</div>
</div>
`;
});
container.innerHTML = html;
}
// 切换折叠面板
function toggleAccordion(header) {
header.classList.toggle('active');
const content = header.nextElementSibling;
content.classList.toggle('active');
}
</script>
</body>
</html>