mirror of
https://github.com/Nezumi-2711/astrbot_plugin_qq_group_daily_analysis.git
synced 2026-09-22 05:31:52 +00:00
[v4.5.0] 添加新的模板主题 retro_futurism, 灵感来源明日方舟 孤星 未来复古主义主题;添加模板调试工具 scripts/debug_render.py,方便用户在不启动 AstrBot 的情况下调试模板效果 (@Saramanda9988)
This commit is contained in:
@@ -108,6 +108,9 @@ simple 模板效果图(用于展示贡献指南)
|
||||
<details>
|
||||
<summary>📋 点击展开查看完整更新日志</summary>
|
||||
|
||||
### v4.5.0
|
||||
- 添加新的模板主题 retro_futurism, 灵感来源明日方舟 孤星 未来复古主义主题;添加模板调试工具 scripts/debug_render.py,方便用户在不启动 AstrBot 的情况下调试模板效果 (@Saramanda9988)
|
||||
|
||||
### v4.4.0
|
||||
- 修复可能的图片生成成功但是发送失败的情况,增加 Fallback 的 BASE64 编码的图片发送方式(@Heximiao)
|
||||
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.6 MiB |
+1
-1
@@ -14,6 +14,6 @@ help: | # 插件的帮助信息
|
||||
命令:
|
||||
/群分析 [天数] - 分析群聊活动
|
||||
/分析设置 [操作] - 管理设置(enable/disable/status/test)
|
||||
version: v4.4.0 # 插件版本号。格式:v1.1.1 或者 v1.1
|
||||
version: v4.5.0 # 插件版本号。格式:v1.1.1 或者 v1.1
|
||||
author: SXP-Simon # 作者
|
||||
repo: https://github.com/SXP-Simon/astrbot-qq-group-daily-analysis # 插件的仓库地址
|
||||
|
||||
@@ -1,562 +0,0 @@
|
||||
<!--
|
||||
@name: 复古未来主义报告
|
||||
@description: 结合复古工业与未来终端风格的统计报告
|
||||
@author: LunaRain_079
|
||||
@version: 1.0.0
|
||||
-->
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>LUNABOX TERMINAL REPORT</title>
|
||||
<!-- Chart.js CDN -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.1/dist/chart.umd.min.js"></script>
|
||||
|
||||
<!-- Fonts - Using system fonts as fallback for export compatibility -->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;700&family=Oswald:wght@400;700&family=Noto+Sans+SC:wght@400;700&display=swap" rel="stylesheet">
|
||||
|
||||
<style>
|
||||
/* Embedded font fallbacks for export */
|
||||
@font-face {
|
||||
font-family: 'Oswald-Fallback';
|
||||
src: local('Impact'), local('Arial Black'), local('Helvetica Neue Bold');
|
||||
font-weight: 400 700;
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'JetBrains-Fallback';
|
||||
src: local('Consolas'), local('Monaco'), local('Courier New');
|
||||
font-weight: 400 700;
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'NotoSans-Fallback';
|
||||
src: local('Microsoft YaHei'), local('PingFang SC'), local('Hiragino Sans GB'), local('SimHei');
|
||||
font-weight: 400 700;
|
||||
}
|
||||
|
||||
:root {
|
||||
/* Palette */
|
||||
--c-bg: #F5EDDC;
|
||||
--c-text: #181818;
|
||||
--c-accent: #B2653B; /* Orange */
|
||||
|
||||
--c-dec-1: #5C7F71; /* Green */
|
||||
--c-dec-2: #802520; /* Red */
|
||||
--c-dec-3: #BA8530; /* Gold */
|
||||
|
||||
--c-grid: rgba(24, 24, 24, 0.1);
|
||||
|
||||
/* Fonts - with system fallbacks for export */
|
||||
--font-display: 'Oswald', 'Oswald-Fallback', Impact, 'Arial Black', sans-serif;
|
||||
--font-mono: 'JetBrains Mono', 'JetBrains-Fallback', Consolas, Monaco, 'Courier New', monospace;
|
||||
--font-body: 'Noto Sans SC', 'NotoSans-Fallback', 'Microsoft YaHei', 'PingFang SC', sans-serif;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background-color: var(--c-bg);
|
||||
color: var(--c-text);
|
||||
font-family: var(--font-body);
|
||||
/* Grid Background */
|
||||
background-image:
|
||||
linear-gradient(var(--c-grid) 1px, transparent 1px),
|
||||
linear-gradient(90deg, var(--c-grid) 1px, transparent 1px);
|
||||
background-size: 40px 40px;
|
||||
min-height: 100vh;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
/* Layout Container */
|
||||
.layout {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 60px 40px;
|
||||
position: relative;
|
||||
border-left: 1px solid var(--c-text);
|
||||
border-right: 1px solid var(--c-text);
|
||||
background:
|
||||
linear-gradient(90deg, transparent 0%, transparent 98%, var(--c-accent) 98%, var(--c-accent) 100%);
|
||||
background-size: 100% 100%;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
/* Decorative Color Bar */
|
||||
.color-bar {
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
left: -20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0;
|
||||
z-index: 10;
|
||||
}
|
||||
.c-block {
|
||||
width: 60px;
|
||||
height: 12px;
|
||||
}
|
||||
.cb-1 { background: var(--c-dec-1); }
|
||||
.cb-2 { background: var(--c-dec-2); }
|
||||
.cb-3 { background: var(--c-dec-3); }
|
||||
|
||||
/* Header */
|
||||
header {
|
||||
margin-bottom: 80px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.header-meta {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.8rem;
|
||||
color: var(--c-text);
|
||||
opacity: 0.7;
|
||||
margin-bottom: 10px;
|
||||
letter-spacing: 1px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-family: var(--font-display);
|
||||
font-size: 5rem;
|
||||
line-height: 0.9;
|
||||
margin: 0;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: -2px;
|
||||
color: var(--c-text);
|
||||
}
|
||||
|
||||
h1 .highlight {
|
||||
color: var(--c-accent);
|
||||
}
|
||||
|
||||
.date-range {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 1.2rem;
|
||||
margin-top: 20px;
|
||||
padding-left: 20px;
|
||||
border-left: 4px solid var(--c-accent);
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
/* Grid System */
|
||||
.grid-container {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(12, 1fr);
|
||||
gap: 20px;
|
||||
margin-bottom: 60px;
|
||||
}
|
||||
|
||||
/* Section Titles */
|
||||
.section-label {
|
||||
grid-column: span 12;
|
||||
font-family: var(--font-display);
|
||||
font-size: 2rem;
|
||||
text-transform: uppercase;
|
||||
border-bottom: 2px solid var(--c-text);
|
||||
padding-bottom: 10px;
|
||||
margin-bottom: 20px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-end;
|
||||
}
|
||||
.section-label span {
|
||||
background: var(--c-text);
|
||||
color: var(--c-bg);
|
||||
padding: 2px 10px;
|
||||
font-size: 1rem;
|
||||
font-family: var(--font-mono);
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
/* Stats Big Number */
|
||||
.stat-box {
|
||||
grid-column: span 4;
|
||||
border: 1px solid var(--c-text);
|
||||
padding: 20px;
|
||||
position: relative;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
.stat-box::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 4px; left: 4px; right: 4px; bottom: 4px;
|
||||
border: 1px solid var(--c-grid);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.9rem;
|
||||
text-transform: uppercase;
|
||||
color: var(--c-dec-1);
|
||||
margin-bottom: 10px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-family: var(--font-display);
|
||||
font-size: 4rem;
|
||||
color: var(--c-accent);
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
/* AI Summary - Terminal Style */
|
||||
.ai-terminal {
|
||||
grid-column: span 8;
|
||||
background: var(--c-text);
|
||||
color: var(--c-bg);
|
||||
padding: 20px;
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.9rem;
|
||||
line-height: 1.6;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.ai-terminal::before {
|
||||
content: "AI_ANALYSIS_MODULE // v.2.0";
|
||||
display: block;
|
||||
border-bottom: 1px solid #444;
|
||||
padding-bottom: 10px;
|
||||
margin-bottom: 15px;
|
||||
color: var(--c-accent);
|
||||
font-size: 0.7rem;
|
||||
}
|
||||
.cursor {
|
||||
display: inline-block;
|
||||
width: 8px;
|
||||
height: 14px;
|
||||
background: var(--c-accent);
|
||||
animation: blink 1s infinite;
|
||||
}
|
||||
@keyframes blink { 0%, 100% { opacity: 1; } 50% { opacity: 0; } }
|
||||
|
||||
/* Charts */
|
||||
.chart-wrapper {
|
||||
grid-column: span 12;
|
||||
border: 1px solid var(--c-text);
|
||||
padding: 20px;
|
||||
background: #fff;
|
||||
position: relative;
|
||||
}
|
||||
.chart-wrapper.half {
|
||||
grid-column: span 6;
|
||||
}
|
||||
.chart-deco {
|
||||
position: absolute;
|
||||
top: -10px;
|
||||
right: 20px;
|
||||
background: var(--c-bg);
|
||||
padding: 0 10px;
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.8rem;
|
||||
border: 1px solid var(--c-text);
|
||||
}
|
||||
|
||||
/* Leaderboard - Asymmetrical List */
|
||||
.game-list {
|
||||
grid-column: span 12;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.game-item {
|
||||
display: grid;
|
||||
grid-template-columns: 60px 80px 1fr 150px;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
border-bottom: 1px solid var(--c-grid);
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.game-cover {
|
||||
width: 80px;
|
||||
height: 106px; /* 3:4 aspect ratio */
|
||||
background: #000;
|
||||
border: 1px solid var(--c-text);
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.game-cover img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
filter: grayscale(100%) contrast(120%); /* Retro B&W look */
|
||||
transition: filter 0.3s;
|
||||
}
|
||||
|
||||
.game-item:hover .game-cover img {
|
||||
filter: grayscale(0%) contrast(100%);
|
||||
}
|
||||
|
||||
.game-rank {
|
||||
font-family: var(--font-display);
|
||||
font-size: 2rem;
|
||||
color: var(--c-text);
|
||||
opacity: 0.3;
|
||||
}
|
||||
.game-item:nth-child(1) .game-rank { color: var(--c-dec-3); opacity: 1; }
|
||||
.game-item:nth-child(2) .game-rank { color: var(--c-dec-1); opacity: 1; }
|
||||
.game-item:nth-child(3) .game-rank { color: var(--c-dec-2); opacity: 1; }
|
||||
|
||||
.game-info h3 {
|
||||
margin: 0;
|
||||
font-family: var(--font-body);
|
||||
font-size: 1.2rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.game-time {
|
||||
font-family: var(--font-mono);
|
||||
text-align: right;
|
||||
color: var(--c-accent);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Footer */
|
||||
footer {
|
||||
margin-top: 80px;
|
||||
border-top: 4px solid var(--c-text);
|
||||
padding-top: 20px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.8rem;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
/* Responsive */
|
||||
@media (max-width: 768px) {
|
||||
.grid-container { display: flex; flex-direction: column; }
|
||||
.chart-wrapper.half { grid-column: span 12; }
|
||||
h1 { font-size: 3rem; }
|
||||
}
|
||||
|
||||
/* CRT Scanline Effect Overlay (Optional, subtle) */
|
||||
.crt-overlay {
|
||||
position: fixed;
|
||||
top: 0; left: 0; width: 100%; height: 100%;
|
||||
background: linear-gradient(rgba(18, 16, 16, 0) 50%, rgba(0, 0, 0, 0.05) 50%);
|
||||
background-size: 100% 4px;
|
||||
pointer-events: none;
|
||||
z-index: 999;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="crt-overlay"></div>
|
||||
|
||||
<div class="layout">
|
||||
<!-- Decorative Bars -->
|
||||
<div class="color-bar">
|
||||
<div class="c-block cb-1"></div>
|
||||
<div class="c-block cb-2"></div>
|
||||
<div class="c-block cb-3"></div>
|
||||
</div>
|
||||
|
||||
<header>
|
||||
<div class="header-meta">System Report // {{.ExportTime}}</div>
|
||||
<h1>Luna<span class="highlight">Box</span><br>Instruction<br>Catalogue</h1>
|
||||
<div class="date-range">
|
||||
PERIOD: {{.StartDate}} >> {{.EndDate}}
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="grid-container">
|
||||
<!-- Stats -->
|
||||
<div class="stat-box" style="grid-column: span 3;">
|
||||
<span class="stat-label">Total Sessions</span>
|
||||
<div class="stat-value">{{.TotalPlayCount}}</div>
|
||||
</div>
|
||||
|
||||
<div class="stat-box" style="grid-column: span 3;">
|
||||
<span class="stat-label">Total Duration</span>
|
||||
<div class="stat-value" style="font-size: 2.5rem; margin-top: 10px;">{{.TotalPlayTimeStr}}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- AI Summary -->
|
||||
{{if .AISummary}}
|
||||
<div class="ai-terminal" style="grid-column: span 6;">
|
||||
{{.AISummary}}<span class="cursor"></span>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
<!-- Charts -->
|
||||
{{if .ChartLabels}}
|
||||
<div class="section-label">
|
||||
Analytics <span>DATA_VISUALIZATION</span>
|
||||
</div>
|
||||
<div class="grid-container">
|
||||
<div class="chart-wrapper">
|
||||
<div class="chart-deco">FIGURE_01: TIME_SERIES</div>
|
||||
<canvas id="trendChart" height="300"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
{{if .GameTrendData}}
|
||||
<div class="grid-container">
|
||||
<div class="chart-wrapper">
|
||||
<div class="chart-deco">FIGURE_02: GAME_TRENDS</div>
|
||||
<canvas id="gameTrendChart" height="300"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
<!-- Leaderboard -->
|
||||
{{if .Leaderboard}}
|
||||
<div class="section-label">
|
||||
Top Records <span>RANKING_MODULE</span>
|
||||
</div>
|
||||
<div class="grid-container">
|
||||
<div class="game-list">
|
||||
{{range $index, $game := .Leaderboard}}
|
||||
<div class="game-item">
|
||||
<div class="game-rank">#{{add $index 1}}</div>
|
||||
<div class="game-cover">
|
||||
{{if $game.CoverBase64}}
|
||||
<img src="{{$game.CoverBase64}}" alt="{{$game.GameName}}">
|
||||
{{else if $game.CoverURL}}
|
||||
<img src="{{$game.CoverURL}}" alt="{{$game.GameName}}">
|
||||
{{else}}
|
||||
<div style="width:100%;height:100%;background:#333;display:flex;align-items:center;justify-content:center;color:#555;font-size:0.8rem;">NO_IMG</div>
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="game-info">
|
||||
<h3>{{$game.GameName}}</h3>
|
||||
</div>
|
||||
<div class="game-time">{{$game.DurationStr}}</div>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
<footer>
|
||||
<div>Generated by {{.AppName}} v{{.AppVersion}}</div>
|
||||
<div>END OF LINE_</div>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
<!-- Data Injection -->
|
||||
<script id="chart-data-config" type="application/json">
|
||||
{
|
||||
"labels": {{ .ChartLabels | safeJS }},
|
||||
"data": {{ .ChartData | safeJS }},
|
||||
"gameTrend": {{ .GameTrendData | safeJS }}
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
// Chart Configuration
|
||||
Chart.defaults.font.family = "'JetBrains Mono', monospace";
|
||||
Chart.defaults.color = '#181818';
|
||||
|
||||
const commonOptions = {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
plugins: {
|
||||
legend: {
|
||||
labels: {
|
||||
usePointStyle: true,
|
||||
boxWidth: 10
|
||||
}
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
x: {
|
||||
grid: {
|
||||
color: 'rgba(24, 24, 24, 0.1)',
|
||||
tickLength: 0
|
||||
}
|
||||
},
|
||||
y: {
|
||||
grid: {
|
||||
color: 'rgba(24, 24, 24, 0.1)',
|
||||
borderDash: [4, 4]
|
||||
},
|
||||
beginAtZero: true
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Load Data
|
||||
let config = {};
|
||||
try {
|
||||
config = JSON.parse(document.getElementById('chart-data-config').textContent);
|
||||
} catch (e) { console.error(e); }
|
||||
|
||||
// Render Trend Chart
|
||||
if (config.labels && config.data) {
|
||||
const ctx = document.getElementById('trendChart');
|
||||
if (ctx) {
|
||||
new Chart(ctx, {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: config.labels,
|
||||
datasets: [{
|
||||
label: 'PLAY_TIME (Hours)',
|
||||
data: config.data,
|
||||
borderColor: '#B2653B',
|
||||
backgroundColor: 'rgba(178, 101, 59, 0.1)',
|
||||
borderWidth: 2,
|
||||
pointBackgroundColor: '#F5EDDC',
|
||||
pointBorderColor: '#B2653B',
|
||||
pointRadius: 4,
|
||||
pointHoverRadius: 6,
|
||||
fill: true,
|
||||
tension: 0 // Sharp lines for retro feel
|
||||
}]
|
||||
},
|
||||
options: commonOptions
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Render Game Distribution
|
||||
if (config.gameTrend) {
|
||||
const ctx2 = document.getElementById('gameTrendChart');
|
||||
if (ctx2) {
|
||||
// Palette for multiple items
|
||||
const palette = ['#B2653B', '#5C7F71', '#802520', '#BA8530', '#181818'];
|
||||
|
||||
// Map data to datasets
|
||||
const datasets = config.gameTrend.map((ds, index) => {
|
||||
const color = palette[index % palette.length];
|
||||
return {
|
||||
label: ds.label, // Game Name
|
||||
data: ds.data, // Array of hours
|
||||
borderColor: color,
|
||||
backgroundColor: color,
|
||||
borderWidth: 2,
|
||||
pointBackgroundColor: '#F5EDDC',
|
||||
pointBorderColor: color,
|
||||
pointRadius: 4,
|
||||
tension: 0 // Sharp lines
|
||||
};
|
||||
});
|
||||
|
||||
new Chart(ctx2, {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: config.labels, // Date labels
|
||||
datasets: datasets
|
||||
},
|
||||
options: commonOptions
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user