feat: 在AI查询页面添加统计功能

- 添加AI查询统计卡片,显示总查询次数、成功率、平均响应时间等
- 按场景统计:文章摘要、垃圾评论检测、批量检测、关键词提取
- 按服务商统计:OpenAI、Anthropic、DeepSeek、小米Mimo等
- 使用AJAX动态加载统计数据
- 仅对管理员可见
- 统计数据来自wp_argon_ai_query_log表
This commit is contained in:
2026-01-26 13:00:08 +08:00
parent 31e55648cb
commit 33d2b23408

View File

@@ -1064,6 +1064,220 @@ if (current_user_can('manage_options')):
<?php <?php
endif; // !empty($all_records) endif; // !empty($all_records)
// ==========================================================================
// AI 查询统计
// ==========================================================================
?>
<article class="post card shadow-sm bg-white border-0 ai-verify-card" style="margin-top: 16px;">
<h3 class="ai-verify-section-title">
<i class="fa fa-bar-chart"></i><?php _e('AI 查询统计', 'argon'); ?>
</h3>
<div class="ai-alert ai-alert-info" style="margin-bottom: 20px;">
<span class="ai-alert-icon"></span>
<div>
<strong><?php _e('管理员专属', 'argon'); ?></strong><br>
<?php _e('显示 AI 查询的统计信息,包括总查询次数、成功率、平均响应时间等', 'argon'); ?>
</div>
</div>
<div id="aiStatsContainer">
<div style="text-align: center; padding: 40px; color: var(--color-text-muted);">
<i class="fa fa-spinner fa-spin" style="font-size: 24px; margin-bottom: 12px;"></i>
<p><?php _e('加载统计数据中...', 'argon'); ?></p>
</div>
</div>
<style>
.ai-stats-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 16px; margin-bottom: 28px; }
.ai-stat-card { background: linear-gradient(135deg, rgba(var(--themecolor-rgbstr), 0.08) 0%, rgba(var(--themecolor-rgbstr), 0.03) 100%); border: 1px solid rgba(var(--themecolor-rgbstr), 0.15); border-radius: var(--card-radius); padding: 20px; text-align: center; transition: all var(--animation-fast) var(--ease-standard); }
.ai-stat-card:hover { transform: translateY(-2px); box-shadow: 0 4px 12px rgba(var(--themecolor-rgbstr), 0.15); }
.ai-stat-value { font-size: 32px; font-weight: 700; color: var(--themecolor); margin-bottom: 8px; font-family: 'Consolas', 'Monaco', monospace; }
.ai-stat-label { font-size: 13px; color: var(--color-text-muted); font-weight: 500; text-transform: uppercase; letter-spacing: 0.5px; }
.ai-stats-table { width: 100%; border-collapse: separate; border-spacing: 0; margin-top: 20px; }
.ai-stats-table th { background: linear-gradient(135deg, rgba(var(--themecolor-rgbstr), 0.08) 0%, rgba(var(--themecolor-rgbstr), 0.04) 100%); padding: 12px 16px; text-align: left; font-size: 13px; font-weight: 600; color: var(--color-text-deeper); }
.ai-stats-table td { padding: 12px 16px; font-size: 14px; color: var(--color-text); border-bottom: 1px solid var(--color-border-on-foreground); }
.ai-stats-table tbody tr:last-child td { border-bottom: none; }
.ai-stats-table tbody tr:hover { background: rgba(var(--themecolor-rgbstr), 0.05); }
@media (max-width: 768px) {
.ai-stats-grid { grid-template-columns: repeat(2, 1fr); }
.ai-stat-value { font-size: 24px; }
}
</style>
<script data-pjax>
(function() {
// 加载统计数据
fetch('<?php echo admin_url('admin-ajax.php'); ?>', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
action: 'argon_get_ai_query_stats',
nonce: '<?php echo wp_create_nonce('argon_ai_query_stats'); ?>'
})
})
.then(response => response.json())
.then(data => {
if (data.success) {
renderStats(data.data);
} else {
showError(data.data || '<?php _e('加载失败', 'argon'); ?>');
}
})
.catch(error => {
console.error('Error loading stats:', error);
showError('<?php _e('网络错误', 'argon'); ?>');
});
function renderStats(stats) {
const container = document.getElementById('aiStatsContainer');
let html = `
<div class="ai-stats-grid">
<div class="ai-stat-card">
<div class="ai-stat-value">${stats.total_queries || 0}</div>
<div class="ai-stat-label"><?php _e('总查询次数', 'argon'); ?></div>
</div>
<div class="ai-stat-card">
<div class="ai-stat-value">${stats.success_queries || 0}</div>
<div class="ai-stat-label"><?php _e('成功次数', 'argon'); ?></div>
</div>
<div class="ai-stat-card">
<div class="ai-stat-value">${stats.error_queries || 0}</div>
<div class="ai-stat-label"><?php _e('失败次数', 'argon'); ?></div>
</div>
<div class="ai-stat-card">
<div class="ai-stat-value">${stats.success_rate || 0}%</div>
<div class="ai-stat-label"><?php _e('成功率', 'argon'); ?></div>
</div>
<div class="ai-stat-card">
<div class="ai-stat-value">${stats.avg_response_time || 0}ms</div>
<div class="ai-stat-label"><?php _e('平均响应时间', 'argon'); ?></div>
</div>
</div>
`;
// 按场景统计
if (stats.by_scenario && stats.by_scenario.length > 0) {
html += `
<h4 class="ai-section-subtitle"><?php _e('按场景统计', 'argon'); ?></h4>
<div style="overflow-x: auto;">
<table class="ai-stats-table">
<thead>
<tr>
<th><?php _e('场景', 'argon'); ?></th>
<th><?php _e('查询次数', 'argon'); ?></th>
<th><?php _e('平均响应时间', 'argon'); ?></th>
</tr>
</thead>
<tbody>
`;
const scenarioNames = {
'summary': '<?php _e('文章摘要', 'argon'); ?>',
'spam_detection': '<?php _e('垃圾评论检测', 'argon'); ?>',
'spam_detection_batch': '<?php _e('批量评论检测', 'argon'); ?>',
'keyword_extraction': '<?php _e('关键词提取', 'argon'); ?>'
};
stats.by_scenario.forEach(item => {
const scenarioName = scenarioNames[item.scenario] || item.scenario;
html += `
<tr>
<td><strong>${escapeHtml(scenarioName)}</strong></td>
<td>${item.count || 0}</td>
<td>${Math.round(item.avg_time || 0)}ms</td>
</tr>
`;
});
html += `
</tbody>
</table>
</div>
`;
}
// 按服务商统计
if (stats.by_provider && stats.by_provider.length > 0) {
html += `
<h4 class="ai-section-subtitle" style="margin-top: 28px;"><?php _e('按服务商统计', 'argon'); ?></h4>
<div style="overflow-x: auto;">
<table class="ai-stats-table">
<thead>
<tr>
<th><?php _e('服务商', 'argon'); ?></th>
<th><?php _e('查询次数', 'argon'); ?></th>
<th><?php _e('平均响应时间', 'argon'); ?></th>
</tr>
</thead>
<tbody>
`;
const providerNames = {
'openai': 'OpenAI',
'anthropic': 'Anthropic',
'deepseek': 'DeepSeek',
'xiaomi': '小米 Mimo',
'qianwen': '通义千问',
'wenxin': '文心一言',
'doubao': '豆包',
'kimi': 'Kimi',
'zhipu': '智谱',
'siliconflow': 'SiliconFlow'
};
stats.by_provider.forEach(item => {
const providerName = providerNames[item.provider] || item.provider;
html += `
<tr>
<td><strong>${escapeHtml(providerName)}</strong></td>
<td>${item.count || 0}</td>
<td>${Math.round(item.avg_time || 0)}ms</td>
</tr>
`;
});
html += `
</tbody>
</table>
</div>
`;
}
container.innerHTML = html;
}
function showError(message) {
const container = document.getElementById('aiStatsContainer');
container.innerHTML = `
<div class="ai-alert ai-alert-warning">
<span class="ai-alert-icon">⚠</span>
<div>
<strong><?php _e('加载失败', 'argon'); ?></strong><br>
${escapeHtml(message)}
</div>
</div>
`;
}
function escapeHtml(text) {
if (!text) return '';
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
})();
</script>
</article>
<?php
endif; // current_user_can('manage_options') endif; // current_user_can('manage_options')
?> ?>