feat: overhaul UI styling, improve templates, enhance services and tests
This commit is contained in:
+145
-150
@@ -1,8 +1,5 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}{{ page_title }} — HF Daily Papers{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% extends "base.html" %} {% block title %}{{ page_title }} — HF Daily Papers{%
|
||||
endblock %} {% block content %}
|
||||
<section class="trends-page">
|
||||
<h1>趋势看板</h1>
|
||||
|
||||
@@ -32,154 +29,152 @@
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
{% endblock %} {% block scripts %}
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.7/dist/chart.umd.min.js"></script>
|
||||
<script>
|
||||
// 颜色配置(kami 风格墨蓝色系)
|
||||
const COLORS = {
|
||||
primary: '#2d5f8a',
|
||||
primaryLight: 'rgba(45, 95, 138, 0.2)',
|
||||
accent: '#5a9bc7',
|
||||
success: '#388e3c',
|
||||
warning: '#f57f17',
|
||||
danger: '#c62828',
|
||||
muted: '#4a4a6a',
|
||||
palette: [
|
||||
'#2d5f8a', '#5a9bc7', '#388e3c', '#f57f17', '#c62828',
|
||||
'#7b1fa2', '#00838f', '#ef6c00', '#455a64', '#827717',
|
||||
'#1565c0', '#ad1457', '#00695c', '#e65100', '#283593',
|
||||
'#9e9d24', '#6a1b9a', '#00838f', '#4e342e', '#37474f',
|
||||
],
|
||||
};
|
||||
|
||||
const statsData = {{ stats | tojson }};
|
||||
|
||||
// 每日论文数量折线图
|
||||
(function() {
|
||||
const ctx = document.getElementById('dailyChart').getContext('2d');
|
||||
const labels = statsData.daily_counts.map(d => d.date);
|
||||
const data = statsData.daily_counts.map(d => d.count);
|
||||
new Chart(ctx, {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: labels,
|
||||
datasets: [{
|
||||
label: '论文数',
|
||||
data: data,
|
||||
borderColor: COLORS.primary,
|
||||
backgroundColor: COLORS.primaryLight,
|
||||
fill: true,
|
||||
tension: 0.3,
|
||||
pointRadius: 3,
|
||||
pointHoverRadius: 6,
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
plugins: { legend: { display: false } },
|
||||
scales: {
|
||||
x: { ticks: { maxTicksLimit: 10, font: { size: 11 } } },
|
||||
y: { beginAtZero: true, ticks: { stepSize: 1 } },
|
||||
}
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
// 热门标签柱状图
|
||||
(function() {
|
||||
const ctx = document.getElementById('tagsChart').getContext('2d');
|
||||
const labels = statsData.top_tags.map(d => d.tag);
|
||||
const data = statsData.top_tags.map(d => d.count);
|
||||
new Chart(ctx, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: labels,
|
||||
datasets: [{
|
||||
label: '论文数',
|
||||
data: data,
|
||||
backgroundColor: COLORS.palette.slice(0, data.length),
|
||||
borderRadius: 4,
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
indexAxis: 'y',
|
||||
plugins: { legend: { display: false } },
|
||||
scales: {
|
||||
x: { beginAtZero: true, ticks: { stepSize: 1 } },
|
||||
}
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
// Upvotes 分布
|
||||
(function() {
|
||||
const ctx = document.getElementById('upvotesChart').getContext('2d');
|
||||
const labels = statsData.upvotes_dist.map(d => d.range);
|
||||
const data = statsData.upvotes_dist.map(d => d.count);
|
||||
new Chart(ctx, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: labels,
|
||||
datasets: [{
|
||||
label: '论文数',
|
||||
data: data,
|
||||
backgroundColor: COLORS.accent,
|
||||
borderRadius: 4,
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
plugins: { legend: { display: false } },
|
||||
scales: {
|
||||
y: { beginAtZero: true, ticks: { stepSize: 1 } },
|
||||
}
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
// 总结完成率环形图
|
||||
(function() {
|
||||
const ctx = document.getElementById('summaryChart').getContext('2d');
|
||||
const statusLabels = {
|
||||
'done': '已完成',
|
||||
'pending': '待总结',
|
||||
'processing': '总结中',
|
||||
'failed': '失败',
|
||||
'permanent_failure': '永久失败',
|
||||
'none': '未开始',
|
||||
// 颜色配置(kami 风格墨蓝色系)
|
||||
const COLORS = {
|
||||
primary: '#2d5f8a',
|
||||
primaryLight: 'rgba(45, 95, 138, 0.2)',
|
||||
accent: '#5a9bc7',
|
||||
success: '#388e3c',
|
||||
warning: '#f57f17',
|
||||
danger: '#c62828',
|
||||
muted: '#4a4a6a',
|
||||
palette: [
|
||||
'#2d5f8a', '#5a9bc7', '#388e3c', '#f57f17', '#c62828',
|
||||
'#7b1fa2', '#00838f', '#ef6c00', '#455a64', '#827717',
|
||||
'#1565c0', '#ad1457', '#00695c', '#e65100', '#283593',
|
||||
'#9e9d24', '#6a1b9a', '#00838f', '#4e342e', '#37474f',
|
||||
],
|
||||
};
|
||||
const statusColors = {
|
||||
'done': COLORS.success,
|
||||
'pending': COLORS.warning,
|
||||
'processing': COLORS.primary,
|
||||
'failed': COLORS.danger,
|
||||
'permanent_failure': '#b71c1c',
|
||||
'none': '#bdbdbd',
|
||||
};
|
||||
const labels = statsData.summary_completion.map(d => statusLabels[d.status] || d.status);
|
||||
const data = statsData.summary_completion.map(d => d.count);
|
||||
const colors = statsData.summary_completion.map(d => statusColors[d.status] || COLORS.muted);
|
||||
new Chart(ctx, {
|
||||
type: 'doughnut',
|
||||
data: {
|
||||
labels: labels,
|
||||
datasets: [{
|
||||
data: data,
|
||||
backgroundColor: colors,
|
||||
borderWidth: 2,
|
||||
borderColor: '#fff',
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
plugins: {
|
||||
legend: { position: 'bottom', labels: { padding: 12 } },
|
||||
|
||||
const statsData = {{ stats | tojson }};
|
||||
|
||||
// 每日论文数量折线图
|
||||
(function() {
|
||||
const ctx = document.getElementById('dailyChart').getContext('2d');
|
||||
const labels = statsData.daily_counts.map(d => d.date);
|
||||
const data = statsData.daily_counts.map(d => d.count);
|
||||
new Chart(ctx, {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: labels,
|
||||
datasets: [{
|
||||
label: '论文数',
|
||||
data: data,
|
||||
borderColor: COLORS.primary,
|
||||
backgroundColor: COLORS.primaryLight,
|
||||
fill: true,
|
||||
tension: 0.3,
|
||||
pointRadius: 3,
|
||||
pointHoverRadius: 6,
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
plugins: { legend: { display: false } },
|
||||
scales: {
|
||||
x: { ticks: { maxTicksLimit: 10, font: { size: 11 } } },
|
||||
y: { beginAtZero: true, ticks: { stepSize: 1 } },
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
})();
|
||||
});
|
||||
})();
|
||||
|
||||
// 热门标签柱状图
|
||||
(function() {
|
||||
const ctx = document.getElementById('tagsChart').getContext('2d');
|
||||
const labels = statsData.top_tags.map(d => d.tag);
|
||||
const data = statsData.top_tags.map(d => d.count);
|
||||
new Chart(ctx, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: labels,
|
||||
datasets: [{
|
||||
label: '论文数',
|
||||
data: data,
|
||||
backgroundColor: COLORS.palette.slice(0, data.length),
|
||||
borderRadius: 4,
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
indexAxis: 'y',
|
||||
plugins: { legend: { display: false } },
|
||||
scales: {
|
||||
x: { beginAtZero: true, ticks: { stepSize: 1 } },
|
||||
}
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
// Upvotes 分布
|
||||
(function() {
|
||||
const ctx = document.getElementById('upvotesChart').getContext('2d');
|
||||
const labels = statsData.upvotes_dist.map(d => d.range);
|
||||
const data = statsData.upvotes_dist.map(d => d.count);
|
||||
new Chart(ctx, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: labels,
|
||||
datasets: [{
|
||||
label: '论文数',
|
||||
data: data,
|
||||
backgroundColor: COLORS.accent,
|
||||
borderRadius: 4,
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
plugins: { legend: { display: false } },
|
||||
scales: {
|
||||
y: { beginAtZero: true, ticks: { stepSize: 1 } },
|
||||
}
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
// 总结完成率环形图
|
||||
(function() {
|
||||
const ctx = document.getElementById('summaryChart').getContext('2d');
|
||||
const statusLabels = {
|
||||
'done': '已完成',
|
||||
'pending': '待总结',
|
||||
'processing': '总结中',
|
||||
'failed': '失败',
|
||||
'permanent_failure': '永久失败',
|
||||
'none': '未开始',
|
||||
};
|
||||
const statusColors = {
|
||||
'done': COLORS.success,
|
||||
'pending': COLORS.warning,
|
||||
'processing': COLORS.primary,
|
||||
'failed': COLORS.danger,
|
||||
'permanent_failure': '#b71c1c',
|
||||
'none': '#bdbdbd',
|
||||
};
|
||||
const labels = statsData.summary_completion.map(d => statusLabels[d.status] || d.status);
|
||||
const data = statsData.summary_completion.map(d => d.count);
|
||||
const colors = statsData.summary_completion.map(d => statusColors[d.status] || COLORS.muted);
|
||||
new Chart(ctx, {
|
||||
type: 'doughnut',
|
||||
data: {
|
||||
labels: labels,
|
||||
datasets: [{
|
||||
data: data,
|
||||
backgroundColor: colors,
|
||||
borderWidth: 2,
|
||||
borderColor: '#fff',
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
plugins: {
|
||||
legend: { position: 'bottom', labels: { padding: 12 } },
|
||||
}
|
||||
}
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
Reference in New Issue
Block a user