guanghulab/modules/m-channel/channel-stats.js
Guanghu Domestic Migration d1e47f4565
Some checks are pending
自动更新代码和重启 / update-and-restart (push) Waiting to run
CI检查 + 自动部署 / check (push) Waiting to run
CI检查 + 自动部署 / deploy (push) Blocked by required conditions
重启聊天服务 / restart (push) Waiting to run
chore: import sanitized domestic snapshot for REPO-002
Source snapshot: ca48d3ddf926d79aa138306164169baf764bb829
2026-07-17 15:54:41 +08:00

299 lines
9.4 KiB
JavaScript

// 频道使用统计管理
window.ChannelStats = {
// 初始化
init: function() {
console.log('[stats] 初始化');
this.bindEvents();
},
// 绑定事件
bindEvents: function() {
if (!window.EventBus) return;
// 监听模块加载,开始计时
EventBus.on('module:loaded', (data) => {
if (data && data.module) {
this.recordView(data.module);
}
});
// 监听模块卸载,结束计时
EventBus.on('module:unloaded', (data) => {
if (data && data.module) {
if (window.ChannelPreferences) {
ChannelPreferences.stopTiming(data.module);
}
}
});
// 监听页面关闭,停止所有计时
window.addEventListener('beforeunload', () => {
if (window.ChannelPreferences && window.ChannelPreferences.timing) {
Object.keys(ChannelPreferences.timing).forEach(moduleId => {
ChannelPreferences.stopTiming(moduleId);
});
}
});
},
// 记录模块访问
recordView: function(moduleId) {
if (!window.ChannelPreferences) return;
// 记录使用次数和开始计时
ChannelPreferences.recordUsage(moduleId);
// 发送事件
if (window.EventBus) {
EventBus.emit('stats:recorded', {
module: moduleId,
time: Date.now()
});
}
},
// 获取统计报告
getStatsReport: function() {
if (!window.ChannelPreferences) return {};
const stats = ChannelPreferences.getStats();
const modules = window.ModuleRegistry ? ModuleRegistry.list() : [];
// 格式化统计数据
const report = {
totalViews: 0,
mostUsed: null,
lastUsed: null,
moduleDetails: {}
};
let maxCount = 0;
let lastTime = 0;
modules.forEach(moduleId => {
const moduleStats = stats[moduleId] || { count: 0, lastUsed: null, totalTime: 0 };
report.moduleDetails[moduleId] = {
count: moduleStats.count,
lastUsed: moduleStats.lastUsed ? new Date(moduleStats.lastUsed).toLocaleString() : '从未使用',
totalTime: moduleStats.totalTime ? this.formatTime(moduleStats.totalTime) : '0秒'
};
report.totalViews += moduleStats.count;
if (moduleStats.count > maxCount) {
maxCount = moduleStats.count;
report.mostUsed = moduleId;
}
if (moduleStats.lastUsed && moduleStats.lastUsed > lastTime) {
lastTime = moduleStats.lastUsed;
report.lastUsed = moduleId;
}
});
return report;
},
// 格式化时间(秒 -> 可读格式)
formatTime: function(seconds) {
if (seconds < 60) return `${Math.round(seconds)}`;
if (seconds < 3600) {
const minutes = Math.floor(seconds / 60);
const secs = Math.round(seconds % 60);
return `${minutes}${secs}`;
}
const hours = Math.floor(seconds / 3600);
const minutes = Math.floor((seconds % 3600) / 60);
return `${hours}小时${minutes}`;
},
// 渲染统计面板
renderStatsPanel: function(container) {
if (!container) return;
const report = this.getStatsReport();
const modules = window.ModuleRegistry ? ModuleRegistry.list() : [];
let html = `
<div class="stats-panel">
<h3>📊 使用统计</h3>
<div class="stats-summary">
<div class="stat-item">
<span class="stat-label">总访问次数:</span>
<span class="stat-value">${report.totalViews}</span>
</div>
${report.mostUsed ? `
<div class="stat-item">
<span class="stat-label">最常用模块:</span>
<span class="stat-value">${this.getModuleName(report.mostUsed)} (${report.moduleDetails[report.mostUsed]?.count || 0}次)</span>
</div>
` : ''}
${report.lastUsed ? `
<div class="stat-item">
<span class="stat-label">最近使用:</span>
<span class="stat-value">${this.getModuleName(report.lastUsed)}</span>
</div>
` : ''}
</div>
<h4>模块详情</h4>
<table class="stats-table">
<thead>
<tr>
<th>模块</th>
<th>访问次数</th>
<th>累计使用时长</th>
<th>最后使用</th>
</tr>
</thead>
<tbody>
`;
modules.forEach(moduleId => {
const detail = report.moduleDetails[moduleId] || { count: 0, totalTime: '0秒', lastUsed: '从未使用' };
html += `
<tr>
<td>${this.getModuleName(moduleId)}</td>
<td>${detail.count}</td>
<td>${detail.totalTime}</td>
<td>${detail.lastUsed}</td>
</tr>
`;
});
html += `
</tbody>
</table>
<div class="stats-actions">
<button id="reset-stats-btn" class="stats-reset-btn">重置统计数据</button>
</div>
</div>
`;
container.innerHTML = html;
// 绑定重置按钮
const resetBtn = document.getElementById('reset-stats-btn');
if (resetBtn) {
resetBtn.addEventListener('click', () => {
if (confirm('确定要重置所有统计数据吗?')) {
this.resetStats();
}
});
}
},
// 获取模块显示名称
getModuleName: function(moduleId) {
const names = {
'm06': '工单管理',
'm08': '数据统计',
'm11': '组件库',
'home': '首页',
'debug': '调试面板'
};
return names[moduleId] || moduleId;
},
// 重置统计
resetStats: function() {
if (!window.ChannelPreferences) return;
const config = ChannelPreferences.config;
if (config) {
config.stats = {};
ChannelPreferences.save();
if (window.EventBus) {
EventBus.emit('stats:reset');
}
alert('统计数据已重置');
// 重新渲染统计面板
const container = document.querySelector('.stats-panel-container');
if (container) {
this.renderStatsPanel(container);
}
}
},
// 注入样式
injectStyles: function() {
const style = document.createElement('style');
style.textContent = `
.stats-panel {
padding: 20px;
background: white;
border-radius: 12px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.stats-summary {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 16px;
margin: 20px 0;
padding: 16px;
background: #f8fafc;
border-radius: 8px;
}
.stat-item {
font-size: 14px;
}
.stat-label {
color: #64748b;
}
.stat-value {
font-weight: 600;
color: #0f172a;
margin-left: 8px;
}
.stats-table {
width: 100%;
border-collapse: collapse;
margin: 20px 0;
}
.stats-table th,
.stats-table td {
padding: 12px;
text-align: left;
border-bottom: 1px solid #e2e8f0;
}
.stats-table th {
background: #f1f5f9;
font-weight: 600;
color: #334155;
}
.stats-table tr:hover {
background: #f8fafc;
}
.stats-actions {
text-align: right;
margin-top: 20px;
}
.stats-reset-btn {
padding: 8px 16px;
background: #ef4444;
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 14px;
}
.stats-reset-btn:hover {
background: #dc2626;
}
`;
document.head.appendChild(style);
}
};
// 自动注入样式
setTimeout(() => {
if (window.ChannelStats) {
ChannelStats.injectStyles();
}
}, 100);
console.log('[stats] 已加载');