智慧教务系统
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

342 lines
11 KiB

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{$pageTitle}</title>
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.0/dist/echarts.min.js"></script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background-color: #181A20;
color: #fff;
padding: 0;
line-height: 1.6;
}
.container {
padding: 20px;
max-width: 100%;
}
.page-title {
text-align: center;
font-size: 24px;
font-weight: bold;
margin-bottom: 30px;
color: #29d3b4;
}
.stats-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 15px;
margin-bottom: 30px;
}
.stat-card {
background: linear-gradient(135deg, #29d3b4 0%, #1a9b7c 100%);
border-radius: 12px;
padding: 20px;
text-align: center;
position: relative;
overflow: hidden;
}
.stat-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(255, 255, 255, 0.1);
border-radius: 12px;
pointer-events: none;
}
.stat-label {
font-size: 12px;
color: rgba(255, 255, 255, 0.8);
margin-bottom: 8px;
}
.stat-value {
font-size: 20px;
font-weight: bold;
color: #fff;
margin-bottom: 5px;
}
.stat-unit {
font-size: 12px;
font-weight: normal;
margin-left: 2px;
}
.stat-trend {
font-size: 12px;
font-weight: bold;
}
.chart-container {
background-color: #292929;
border-radius: 12px;
padding: 20px;
margin-bottom: 20px;
}
.chart-title {
font-size: 16px;
font-weight: bold;
margin-bottom: 15px;
color: #fff;
}
.chart {
height: 300px;
width: 100%;
}
.refresh-btn {
position: fixed;
bottom: 30px;
right: 30px;
width: 56px;
height: 56px;
background: linear-gradient(135deg, #29d3b4 0%, #1a9b7c 100%);
border-radius: 50%;
border: none;
color: #fff;
font-size: 24px;
cursor: pointer;
box-shadow: 0 4px 12px rgba(41, 211, 180, 0.3);
z-index: 1000;
}
.refresh-btn:active {
transform: scale(0.95);
}
.loading {
text-align: center;
padding: 40px;
color: #29d3b4;
}
@media (max-width: 480px) {
.stats-grid {
grid-template-columns: 1fr;
}
.stat-value {
font-size: 18px;
}
.chart {
height: 250px;
}
}
</style>
</head>
<body>
<div class="container">
<h1 class="page-title">{$pageTitle}</h1>
<div class="stats-grid">
{volist name="pageData.stats" id="stat"}
<div class="stat-card">
<div class="stat-label">{$stat.label}</div>
<div class="stat-value">{$stat.value}<span class="stat-unit">{$stat.unit}</span></div>
<div class="stat-trend" style="color: {php}echo strpos($stat['trend'], '+') !== false ? '#4CAF50' : '#FF5722'{/php}">{$stat.trend}</div>
</div>
{/volist}
</div>
<div id="charts-container"></div>
</div>
<button class="refresh-btn" onclick="refreshData()"></button>
<script>
// 页面数据
const pageData = {$pageData|json_encode|raw};
// 图表渲染函数
function renderChart(chartId, title, data) {
const container = document.getElementById('charts-container');
const chartDiv = document.createElement('div');
chartDiv.className = 'chart-container';
chartDiv.innerHTML = `
<div class='chart-title'>${title}</div>
<div class='chart' id='${chartId}'></div>
`;
container.appendChild(chartDiv);
const chart = echarts.init(document.getElementById(chartId));
let option;
if (Array.isArray(data) && data[0] && typeof data[0] === 'object' && 'name' in data[0]) {
// 饼图或柱状图
if (chartId.includes('source') || chartId.includes('distribution')) {
// 饼图
option = {
backgroundColor: 'transparent',
textStyle: { color: '#fff' },
tooltip: {
trigger: 'item',
backgroundColor: 'rgba(0,0,0,0.8)',
textStyle: { color: '#fff' }
},
legend: {
orient: 'horizontal',
bottom: '0%',
textStyle: { color: '#fff' }
},
series: [{
type: 'pie',
radius: '60%',
center: ['50%', '45%'],
data: data,
itemStyle: {
borderRadius: 5,
borderColor: '#181A20',
borderWidth: 2
},
label: {
color: '#fff'
}
}]
};
} else {
// 柱状图
option = {
backgroundColor: 'transparent',
textStyle: { color: '#fff' },
tooltip: {
trigger: 'axis',
backgroundColor: 'rgba(0,0,0,0.8)',
textStyle: { color: '#fff' }
},
xAxis: {
type: 'category',
data: data.map(item => item.name),
axisLabel: { color: '#fff' },
axisLine: { lineStyle: { color: '#666' } }
},
yAxis: {
type: 'value',
axisLabel: { color: '#fff' },
axisLine: { lineStyle: { color: '#666' } },
splitLine: { lineStyle: { color: '#333' } }
},
series: [{
type: 'bar',
data: data.map(item => item.value),
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{offset: 0, color: '#29d3b4'},
{offset: 1, color: '#1a9b7c'}
]),
borderRadius: [4, 4, 0, 0]
}
}]
};
}
} else {
// 折线图
option = {
backgroundColor: 'transparent',
textStyle: { color: '#fff' },
tooltip: {
trigger: 'axis',
backgroundColor: 'rgba(0,0,0,0.8)',
textStyle: { color: '#fff' }
},
xAxis: {
type: 'category',
data: ['1月', '2月', '3月', '4月', '5月', '6月'],
axisLabel: { color: '#fff' },
axisLine: { lineStyle: { color: '#666' } }
},
yAxis: {
type: 'value',
axisLabel: { color: '#fff' },
axisLine: { lineStyle: { color: '#666' } },
splitLine: { lineStyle: { color: '#333' } }
},
series: [{
type: 'line',
data: data,
smooth: true,
itemStyle: { color: '#29d3b4' },
lineStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
{offset: 0, color: '#29d3b4'},
{offset: 1, color: '#1a9b7c'}
]),
width: 3
},
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{offset: 0, color: 'rgba(41, 211, 180, 0.3)'},
{offset: 1, color: 'rgba(41, 211, 180, 0.05)'}
])
}
}]
};
}
chart.setOption(option);
// 响应式
window.addEventListener('resize', () => {
chart.resize();
});
}
// 渲染所有图表
if (pageData.charts) {
Object.keys(pageData.charts).forEach(chartId => {
const chart = pageData.charts[chartId];
renderChart(chartId, chart.title, chart.data);
});
}
// 刷新数据
function refreshData() {
// 发送消息给UniApp
if (typeof uni !== 'undefined' && uni.postMessage) {
uni.postMessage({
data: {
type: 'refresh'
}
});
} else {
// 页面刷新
location.reload();
}
}
// 页面加载完成后的处理
document.addEventListener('DOMContentLoaded', function() {
console.log('Dashboard页面加载完成');
// 通知UniApp页面加载完成
if (typeof uni !== 'undefined' && uni.postMessage) {
uni.postMessage({
data: {
type: 'loaded'
}
});
}
});
</script>
</body>
</html>