mirror of https://github.com/veypi/OneAuth.git
feat: change auth check
parent
96acf05fb6
commit
ada216cfd5
@ -1,696 +1,9 @@
|
||||
<!doctype html>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>项目与用户管理 Dashboard</title>
|
||||
<script src="/assets/libs/echarts.min.js"></script>
|
||||
</head>
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background-color: #f5f7fa;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.dashboard {
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 28px;
|
||||
color: #2c3e50;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.header .date {
|
||||
color: #7f8c8d;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.stats-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 20px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
background: white;
|
||||
border-radius: 10px;
|
||||
padding: 20px;
|
||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
|
||||
transition: transform 0.3s, box-shadow 0.3s;
|
||||
}
|
||||
|
||||
.stat-card:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.stat-card .icon {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 15px;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.stat-card .value {
|
||||
font-size: 28px;
|
||||
font-weight: 700;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.stat-card .label {
|
||||
color: #7f8c8d;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.stat-card .trend {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 10px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.trend.up {
|
||||
color: #2ecc71;
|
||||
}
|
||||
|
||||
.trend.down {
|
||||
color: #e74c3c;
|
||||
}
|
||||
|
||||
.charts-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 20px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.chart-container {
|
||||
background: white;
|
||||
border-radius: 10px;
|
||||
padding: 20px;
|
||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.chart-container h2 {
|
||||
margin-top: 0;
|
||||
font-size: 18px;
|
||||
color: #2c3e50;
|
||||
}
|
||||
|
||||
.chart {
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.recent-activities {
|
||||
background: white;
|
||||
border-radius: 10px;
|
||||
padding: 20px;
|
||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.recent-activities h2 {
|
||||
margin-top: 0;
|
||||
font-size: 18px;
|
||||
color: #2c3e50;
|
||||
}
|
||||
|
||||
.activity-item {
|
||||
display: flex;
|
||||
padding: 15px 0;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.activity-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.activity-icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
background: #f1f5f9;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 15px;
|
||||
color: #3b82f6;
|
||||
}
|
||||
|
||||
.activity-content {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.activity-title {
|
||||
font-weight: 600;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.activity-time {
|
||||
color: #7f8c8d;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.badge {
|
||||
display: inline-block;
|
||||
padding: 3px 8px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.badge-primary {
|
||||
background: #e3f2fd;
|
||||
color: #1976d2;
|
||||
}
|
||||
|
||||
.badge-success {
|
||||
background: #e8f5e9;
|
||||
color: #388e3c;
|
||||
}
|
||||
|
||||
.badge-warning {
|
||||
background: #fff8e1;
|
||||
color: #ffa000;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body>
|
||||
<div class="dashboard">
|
||||
<div class="header">
|
||||
<h1>项目与用户管理 Dashboard</h1>
|
||||
<div class="date">{{ currentDate }}</div>
|
||||
</div>
|
||||
|
||||
<div class="stats-grid">
|
||||
<div class="stat-card">
|
||||
<div class="icon" style="background: #e3f2fd; color: #1976d2;">
|
||||
<i class="bi bi-people"></i>
|
||||
</div>
|
||||
<div class="value">{{ totalUsers }}</div>
|
||||
<div class="label">总用户数</div>
|
||||
<div class="trend up">
|
||||
<i class="bi bi-arrow-up"></i> {{ userGrowthRate }}% 较上月
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="stat-card">
|
||||
<div class="icon" style="background: #e8f5e9; color: #388e3c;">
|
||||
<i class="bi bi-folder"></i>
|
||||
</div>
|
||||
<div class="value">{{ activeProjects }}</div>
|
||||
<div class="label">活跃项目</div>
|
||||
<div class="trend up">
|
||||
<i class="bi bi-arrow-up"></i> {{ projectGrowthRate }}% 较上月
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="stat-card">
|
||||
<div class="icon" style="background: #fff8e1; color: #ffa000;">
|
||||
<i class="bi bi-clock-history"></i>
|
||||
</div>
|
||||
<div class="value">{{ pendingTasks }}</div>
|
||||
<div class="label">待处理任务</div>
|
||||
<div class="trend down">
|
||||
<i class="bi bi-arrow-down"></i> {{ taskChangeRate }}% 较上周
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="stat-card">
|
||||
<div class="icon" style="background: #f3e5f5; color: #8e24aa;">
|
||||
<i class="bi bi-graph-up"></i>
|
||||
</div>
|
||||
<div class="value">{{ completionRate }}%</div>
|
||||
<div class="label">项目完成率</div>
|
||||
<div class="trend up">
|
||||
<i class="bi bi-arrow-up"></i> {{ completionRateChange }}% 较上月
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="charts-grid">
|
||||
<div class="chart-container">
|
||||
<h2>用户增长趋势</h2>
|
||||
<div id="userGrowthChart" class="chart"></div>
|
||||
</div>
|
||||
|
||||
<div class="chart-container">
|
||||
<h2>项目状态分布</h2>
|
||||
<div id="projectStatusChart" class="chart"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="charts-grid">
|
||||
<div class="chart-container">
|
||||
<h2>用户活跃度</h2>
|
||||
<div id="userActivityChart" class="chart"></div>
|
||||
</div>
|
||||
|
||||
<div class="chart-container">
|
||||
<h2>任务完成情况</h2>
|
||||
<div id="taskCompletionChart" class="chart"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="recent-activities">
|
||||
<h2>最近活动</h2>
|
||||
<div v-for="activity in recentActivities" class="activity-item">
|
||||
<div class="activity-icon">
|
||||
<i :class="'bi bi-' + activity.icon"></i>
|
||||
</div>
|
||||
<div class="activity-content">
|
||||
<div class="activity-title">
|
||||
{{ activity.title }}
|
||||
<span v-if="activity.type" :class="'badge badge-' + activity.type">{{ activity.typeLabel }}</span>
|
||||
</div>
|
||||
<div class="activity-time">{{ activity.time }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script setup>
|
||||
// 统计数据
|
||||
totalUsers = 1248;
|
||||
activeProjects = 86;
|
||||
pendingTasks = 342;
|
||||
completionRate = 78;
|
||||
|
||||
// 增长率
|
||||
userGrowthRate = 12.5;
|
||||
projectGrowthRate = 8.3;
|
||||
taskChangeRate = 5.2;
|
||||
completionRateChange = 3.7;
|
||||
|
||||
// 当前日期
|
||||
currentDate = new Date().toLocaleDateString('zh-CN', {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
weekday: 'long'
|
||||
});
|
||||
|
||||
// 最近活动数据
|
||||
recentActivities = [
|
||||
{
|
||||
icon: 'plus-circle',
|
||||
title: '新用户 "张小明" 注册',
|
||||
type: 'primary',
|
||||
typeLabel: '用户',
|
||||
time: '10分钟前'
|
||||
},
|
||||
{
|
||||
icon: 'folder-plus',
|
||||
title: '新项目 "电商平台重构" 创建',
|
||||
type: 'success',
|
||||
typeLabel: '项目',
|
||||
time: '35分钟前'
|
||||
},
|
||||
{
|
||||
icon: 'check-circle',
|
||||
title: '项目 "CRM系统升级" 完成',
|
||||
type: 'success',
|
||||
typeLabel: '项目',
|
||||
time: '2小时前'
|
||||
},
|
||||
{
|
||||
icon: 'exclamation-triangle',
|
||||
title: '任务 "用户权限模块" 逾期',
|
||||
type: 'warning',
|
||||
typeLabel: '任务',
|
||||
time: '5小时前'
|
||||
},
|
||||
{
|
||||
icon: 'person-plus',
|
||||
title: '团队成员 "李华" 加入项目',
|
||||
type: 'primary',
|
||||
typeLabel: '团队',
|
||||
time: '昨天'
|
||||
}
|
||||
];
|
||||
|
||||
// 图表数据
|
||||
userGrowthData = {
|
||||
months: ['1月', '2月', '3月', '4月', '5月', '6月', '7月'],
|
||||
values: [820, 890, 920, 950, 1020, 1120, 1248]
|
||||
};
|
||||
|
||||
projectStatusData = [
|
||||
{value: 32, name: '进行中'},
|
||||
{value: 24, name: '已完成'},
|
||||
{value: 18, name: '规划中'},
|
||||
{value: 12, name: '已暂停'}
|
||||
];
|
||||
|
||||
userActivityData = {
|
||||
days: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
|
||||
activeUsers: [420, 532, 601, 534, 630, 410, 320],
|
||||
newUsers: [120, 132, 101, 134, 90, 60, 40]
|
||||
};
|
||||
|
||||
taskCompletionData = {
|
||||
weeks: ['第1周', '第2周', '第3周', '第4周'],
|
||||
completed: [120, 132, 101, 134],
|
||||
pending: [80, 60, 90, 70]
|
||||
};
|
||||
</script>
|
||||
|
||||
<script>
|
||||
// 初始化图表
|
||||
function initCharts() {
|
||||
// 用户增长趋势图
|
||||
const userGrowthChart = echarts.init(document.getElementById('userGrowthChart'));
|
||||
userGrowthChart.setOption({
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'shadow'
|
||||
}
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: $data.userGrowthData.months,
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#9ca3af'
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#6b7280'
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#9ca3af'
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#6b7280'
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: '#e5e7eb'
|
||||
}
|
||||
}
|
||||
},
|
||||
series: [{
|
||||
data: $data.userGrowthData.values,
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
lineStyle: {
|
||||
width: 4,
|
||||
color: '#3b82f6'
|
||||
},
|
||||
itemStyle: {
|
||||
color: '#3b82f6',
|
||||
borderWidth: 2
|
||||
},
|
||||
areaStyle: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{
|
||||
offset: 0,
|
||||
color: 'rgba(59, 130, 246, 0.5)'
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: 'rgba(59, 130, 246, 0.1)'
|
||||
}
|
||||
])
|
||||
}
|
||||
}]
|
||||
});
|
||||
|
||||
// 项目状态分布图
|
||||
const projectStatusChart = echarts.init(document.getElementById('projectStatusChart'));
|
||||
projectStatusChart.setOption({
|
||||
tooltip: {
|
||||
trigger: 'item'
|
||||
},
|
||||
legend: {
|
||||
orient: 'vertical',
|
||||
right: 10,
|
||||
top: 'center',
|
||||
textStyle: {
|
||||
color: '#6b7280'
|
||||
}
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '项目状态',
|
||||
type: 'pie',
|
||||
radius: ['40%', '70%'],
|
||||
avoidLabelOverlap: false,
|
||||
itemStyle: {
|
||||
borderRadius: 10,
|
||||
borderColor: '#fff',
|
||||
borderWidth: 2
|
||||
},
|
||||
label: {
|
||||
show: false,
|
||||
position: 'center'
|
||||
},
|
||||
emphasis: {
|
||||
label: {
|
||||
show: true,
|
||||
fontSize: '18',
|
||||
fontWeight: 'bold'
|
||||
}
|
||||
},
|
||||
labelLine: {
|
||||
show: false
|
||||
},
|
||||
data: $data.projectStatusData.map((item, index) => ({
|
||||
value: item.value,
|
||||
name: item.name,
|
||||
itemStyle: {
|
||||
color: ['#3b82f6', '#10b981', '#f59e0b', '#8b5cf6'][index]
|
||||
}
|
||||
}))
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
// 用户活跃度图
|
||||
const userActivityChart = echarts.init(document.getElementById('userActivityChart'));
|
||||
userActivityChart.setOption({
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'cross',
|
||||
label: {
|
||||
backgroundColor: '#6a7985'
|
||||
}
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
data: ['活跃用户', '新增用户'],
|
||||
textStyle: {
|
||||
color: '#6b7280'
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '4%',
|
||||
bottom: '3%',
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: $data.userActivityData.days,
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#9ca3af'
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#6b7280'
|
||||
}
|
||||
}
|
||||
],
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#9ca3af'
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#6b7280'
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: '#e5e7eb'
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: '活跃用户',
|
||||
type: 'line',
|
||||
stack: 'Total',
|
||||
smooth: true,
|
||||
lineStyle: {
|
||||
width: 0
|
||||
},
|
||||
showSymbol: false,
|
||||
areaStyle: {
|
||||
opacity: 0.8,
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{
|
||||
offset: 0,
|
||||
color: 'rgba(59, 130, 246, 0.8)'
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: 'rgba(59, 130, 246, 0.1)'
|
||||
}
|
||||
])
|
||||
},
|
||||
emphasis: {
|
||||
focus: 'series'
|
||||
},
|
||||
data: $data.userActivityData.activeUsers
|
||||
},
|
||||
{
|
||||
name: '新增用户',
|
||||
type: 'line',
|
||||
stack: 'Total',
|
||||
smooth: true,
|
||||
lineStyle: {
|
||||
width: 0
|
||||
},
|
||||
showSymbol: false,
|
||||
areaStyle: {
|
||||
opacity: 0.8,
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{
|
||||
offset: 0,
|
||||
color: 'rgba(16, 185, 129, 0.8)'
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: 'rgba(16, 185, 129, 0.1)'
|
||||
}
|
||||
])
|
||||
},
|
||||
emphasis: {
|
||||
focus: 'series'
|
||||
},
|
||||
data: $data.userActivityData.newUsers
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
// 任务完成情况图
|
||||
const taskCompletionChart = echarts.init(document.getElementById('taskCompletionChart'));
|
||||
taskCompletionChart.setOption({
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'shadow'
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
data: ['已完成', '待处理'],
|
||||
textStyle: {
|
||||
color: '#6b7280'
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '4%',
|
||||
bottom: '3%',
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: $data.taskCompletionData.weeks,
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#9ca3af'
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#6b7280'
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#9ca3af'
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#6b7280'
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: '#e5e7eb'
|
||||
}
|
||||
}
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '已完成',
|
||||
type: 'bar',
|
||||
stack: 'total',
|
||||
emphasis: {
|
||||
focus: 'series'
|
||||
},
|
||||
data: $data.taskCompletionData.completed,
|
||||
itemStyle: {
|
||||
color: '#10b981'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '待处理',
|
||||
type: 'bar',
|
||||
stack: 'total',
|
||||
emphasis: {
|
||||
focus: 'series'
|
||||
},
|
||||
data: $data.taskCompletionData.pending,
|
||||
itemStyle: {
|
||||
color: '#f59e0b'
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
// 窗口大小变化时重新调整图表大小
|
||||
window.addEventListener('resize', function () {
|
||||
userGrowthChart.resize();
|
||||
projectStatusChart.resize();
|
||||
userActivityChart.resize();
|
||||
taskCompletionChart.resize();
|
||||
});
|
||||
}
|
||||
hello
|
||||
</body>
|
||||
|
||||
// 页面加载完成后初始化图表
|
||||
initCharts()
|
||||
</script>
|
||||
</html>
|
||||
|
||||
@ -0,0 +1,696 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>项目与用户管理 Dashboard</title>
|
||||
<script src="/assets/libs/echarts.min.js"></script>
|
||||
</head>
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background-color: #f5f7fa;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.dashboard {
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 28px;
|
||||
color: #2c3e50;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.header .date {
|
||||
color: #7f8c8d;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.stats-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 20px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
background: white;
|
||||
border-radius: 10px;
|
||||
padding: 20px;
|
||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
|
||||
transition: transform 0.3s, box-shadow 0.3s;
|
||||
}
|
||||
|
||||
.stat-card:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.stat-card .icon {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 15px;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.stat-card .value {
|
||||
font-size: 28px;
|
||||
font-weight: 700;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.stat-card .label {
|
||||
color: #7f8c8d;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.stat-card .trend {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 10px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.trend.up {
|
||||
color: #2ecc71;
|
||||
}
|
||||
|
||||
.trend.down {
|
||||
color: #e74c3c;
|
||||
}
|
||||
|
||||
.charts-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 20px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.chart-container {
|
||||
background: white;
|
||||
border-radius: 10px;
|
||||
padding: 20px;
|
||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.chart-container h2 {
|
||||
margin-top: 0;
|
||||
font-size: 18px;
|
||||
color: #2c3e50;
|
||||
}
|
||||
|
||||
.chart {
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.recent-activities {
|
||||
background: white;
|
||||
border-radius: 10px;
|
||||
padding: 20px;
|
||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.recent-activities h2 {
|
||||
margin-top: 0;
|
||||
font-size: 18px;
|
||||
color: #2c3e50;
|
||||
}
|
||||
|
||||
.activity-item {
|
||||
display: flex;
|
||||
padding: 15px 0;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.activity-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.activity-icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
background: #f1f5f9;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 15px;
|
||||
color: #3b82f6;
|
||||
}
|
||||
|
||||
.activity-content {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.activity-title {
|
||||
font-weight: 600;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.activity-time {
|
||||
color: #7f8c8d;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.badge {
|
||||
display: inline-block;
|
||||
padding: 3px 8px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.badge-primary {
|
||||
background: #e3f2fd;
|
||||
color: #1976d2;
|
||||
}
|
||||
|
||||
.badge-success {
|
||||
background: #e8f5e9;
|
||||
color: #388e3c;
|
||||
}
|
||||
|
||||
.badge-warning {
|
||||
background: #fff8e1;
|
||||
color: #ffa000;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body>
|
||||
<div class="dashboard">
|
||||
<div class="header">
|
||||
<h1>项目与用户管理 Dashboard</h1>
|
||||
<div class="date">{{ currentDate }}</div>
|
||||
</div>
|
||||
|
||||
<div class="stats-grid">
|
||||
<div class="stat-card">
|
||||
<div class="icon" style="background: #e3f2fd; color: #1976d2;">
|
||||
<i class="bi bi-people"></i>
|
||||
</div>
|
||||
<div class="value">{{ totalUsers }}</div>
|
||||
<div class="label">总用户数</div>
|
||||
<div class="trend up">
|
||||
<i class="bi bi-arrow-up"></i> {{ userGrowthRate }}% 较上月
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="stat-card">
|
||||
<div class="icon" style="background: #e8f5e9; color: #388e3c;">
|
||||
<i class="bi bi-folder"></i>
|
||||
</div>
|
||||
<div class="value">{{ activeProjects }}</div>
|
||||
<div class="label">活跃项目</div>
|
||||
<div class="trend up">
|
||||
<i class="bi bi-arrow-up"></i> {{ projectGrowthRate }}% 较上月
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="stat-card">
|
||||
<div class="icon" style="background: #fff8e1; color: #ffa000;">
|
||||
<i class="bi bi-clock-history"></i>
|
||||
</div>
|
||||
<div class="value">{{ pendingTasks }}</div>
|
||||
<div class="label">待处理任务</div>
|
||||
<div class="trend down">
|
||||
<i class="bi bi-arrow-down"></i> {{ taskChangeRate }}% 较上周
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="stat-card">
|
||||
<div class="icon" style="background: #f3e5f5; color: #8e24aa;">
|
||||
<i class="bi bi-graph-up"></i>
|
||||
</div>
|
||||
<div class="value">{{ completionRate }}%</div>
|
||||
<div class="label">项目完成率</div>
|
||||
<div class="trend up">
|
||||
<i class="bi bi-arrow-up"></i> {{ completionRateChange }}% 较上月
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="charts-grid">
|
||||
<div class="chart-container">
|
||||
<h2>用户增长趋势</h2>
|
||||
<div id="userGrowthChart" class="chart"></div>
|
||||
</div>
|
||||
|
||||
<div class="chart-container">
|
||||
<h2>项目状态分布</h2>
|
||||
<div id="projectStatusChart" class="chart"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="charts-grid">
|
||||
<div class="chart-container">
|
||||
<h2>用户活跃度</h2>
|
||||
<div id="userActivityChart" class="chart"></div>
|
||||
</div>
|
||||
|
||||
<div class="chart-container">
|
||||
<h2>任务完成情况</h2>
|
||||
<div id="taskCompletionChart" class="chart"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="recent-activities">
|
||||
<h2>最近活动</h2>
|
||||
<div v-for="activity in recentActivities" class="activity-item">
|
||||
<div class="activity-icon">
|
||||
<i :class="'bi bi-' + activity.icon"></i>
|
||||
</div>
|
||||
<div class="activity-content">
|
||||
<div class="activity-title">
|
||||
{{ activity.title }}
|
||||
<span v-if="activity.type" :class="'badge badge-' + activity.type">{{ activity.typeLabel }}</span>
|
||||
</div>
|
||||
<div class="activity-time">{{ activity.time }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script setup>
|
||||
// 统计数据
|
||||
totalUsers = 1248;
|
||||
activeProjects = 86;
|
||||
pendingTasks = 342;
|
||||
completionRate = 78;
|
||||
|
||||
// 增长率
|
||||
userGrowthRate = 12.5;
|
||||
projectGrowthRate = 8.3;
|
||||
taskChangeRate = 5.2;
|
||||
completionRateChange = 3.7;
|
||||
|
||||
// 当前日期
|
||||
currentDate = new Date().toLocaleDateString('zh-CN', {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
weekday: 'long'
|
||||
});
|
||||
|
||||
// 最近活动数据
|
||||
recentActivities = [
|
||||
{
|
||||
icon: 'plus-circle',
|
||||
title: '新用户 "张小明" 注册',
|
||||
type: 'primary',
|
||||
typeLabel: '用户',
|
||||
time: '10分钟前'
|
||||
},
|
||||
{
|
||||
icon: 'folder-plus',
|
||||
title: '新项目 "电商平台重构" 创建',
|
||||
type: 'success',
|
||||
typeLabel: '项目',
|
||||
time: '35分钟前'
|
||||
},
|
||||
{
|
||||
icon: 'check-circle',
|
||||
title: '项目 "CRM系统升级" 完成',
|
||||
type: 'success',
|
||||
typeLabel: '项目',
|
||||
time: '2小时前'
|
||||
},
|
||||
{
|
||||
icon: 'exclamation-triangle',
|
||||
title: '任务 "用户权限模块" 逾期',
|
||||
type: 'warning',
|
||||
typeLabel: '任务',
|
||||
time: '5小时前'
|
||||
},
|
||||
{
|
||||
icon: 'person-plus',
|
||||
title: '团队成员 "李华" 加入项目',
|
||||
type: 'primary',
|
||||
typeLabel: '团队',
|
||||
time: '昨天'
|
||||
}
|
||||
];
|
||||
|
||||
// 图表数据
|
||||
userGrowthData = {
|
||||
months: ['1月', '2月', '3月', '4月', '5月', '6月', '7月'],
|
||||
values: [820, 890, 920, 950, 1020, 1120, 1248]
|
||||
};
|
||||
|
||||
projectStatusData = [
|
||||
{value: 32, name: '进行中'},
|
||||
{value: 24, name: '已完成'},
|
||||
{value: 18, name: '规划中'},
|
||||
{value: 12, name: '已暂停'}
|
||||
];
|
||||
|
||||
userActivityData = {
|
||||
days: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
|
||||
activeUsers: [420, 532, 601, 534, 630, 410, 320],
|
||||
newUsers: [120, 132, 101, 134, 90, 60, 40]
|
||||
};
|
||||
|
||||
taskCompletionData = {
|
||||
weeks: ['第1周', '第2周', '第3周', '第4周'],
|
||||
completed: [120, 132, 101, 134],
|
||||
pending: [80, 60, 90, 70]
|
||||
};
|
||||
</script>
|
||||
|
||||
<script>
|
||||
// 初始化图表
|
||||
function initCharts() {
|
||||
// 用户增长趋势图
|
||||
const userGrowthChart = echarts.init(document.getElementById('userGrowthChart'));
|
||||
userGrowthChart.setOption({
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'shadow'
|
||||
}
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: $data.userGrowthData.months,
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#9ca3af'
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#6b7280'
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#9ca3af'
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#6b7280'
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: '#e5e7eb'
|
||||
}
|
||||
}
|
||||
},
|
||||
series: [{
|
||||
data: $data.userGrowthData.values,
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
lineStyle: {
|
||||
width: 4,
|
||||
color: '#3b82f6'
|
||||
},
|
||||
itemStyle: {
|
||||
color: '#3b82f6',
|
||||
borderWidth: 2
|
||||
},
|
||||
areaStyle: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{
|
||||
offset: 0,
|
||||
color: 'rgba(59, 130, 246, 0.5)'
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: 'rgba(59, 130, 246, 0.1)'
|
||||
}
|
||||
])
|
||||
}
|
||||
}]
|
||||
});
|
||||
|
||||
// 项目状态分布图
|
||||
const projectStatusChart = echarts.init(document.getElementById('projectStatusChart'));
|
||||
projectStatusChart.setOption({
|
||||
tooltip: {
|
||||
trigger: 'item'
|
||||
},
|
||||
legend: {
|
||||
orient: 'vertical',
|
||||
right: 10,
|
||||
top: 'center',
|
||||
textStyle: {
|
||||
color: '#6b7280'
|
||||
}
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '项目状态',
|
||||
type: 'pie',
|
||||
radius: ['40%', '70%'],
|
||||
avoidLabelOverlap: false,
|
||||
itemStyle: {
|
||||
borderRadius: 10,
|
||||
borderColor: '#fff',
|
||||
borderWidth: 2
|
||||
},
|
||||
label: {
|
||||
show: false,
|
||||
position: 'center'
|
||||
},
|
||||
emphasis: {
|
||||
label: {
|
||||
show: true,
|
||||
fontSize: '18',
|
||||
fontWeight: 'bold'
|
||||
}
|
||||
},
|
||||
labelLine: {
|
||||
show: false
|
||||
},
|
||||
data: $data.projectStatusData.map((item, index) => ({
|
||||
value: item.value,
|
||||
name: item.name,
|
||||
itemStyle: {
|
||||
color: ['#3b82f6', '#10b981', '#f59e0b', '#8b5cf6'][index]
|
||||
}
|
||||
}))
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
// 用户活跃度图
|
||||
const userActivityChart = echarts.init(document.getElementById('userActivityChart'));
|
||||
userActivityChart.setOption({
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'cross',
|
||||
label: {
|
||||
backgroundColor: '#6a7985'
|
||||
}
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
data: ['活跃用户', '新增用户'],
|
||||
textStyle: {
|
||||
color: '#6b7280'
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '4%',
|
||||
bottom: '3%',
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: $data.userActivityData.days,
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#9ca3af'
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#6b7280'
|
||||
}
|
||||
}
|
||||
],
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#9ca3af'
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#6b7280'
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: '#e5e7eb'
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: '活跃用户',
|
||||
type: 'line',
|
||||
stack: 'Total',
|
||||
smooth: true,
|
||||
lineStyle: {
|
||||
width: 0
|
||||
},
|
||||
showSymbol: false,
|
||||
areaStyle: {
|
||||
opacity: 0.8,
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{
|
||||
offset: 0,
|
||||
color: 'rgba(59, 130, 246, 0.8)'
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: 'rgba(59, 130, 246, 0.1)'
|
||||
}
|
||||
])
|
||||
},
|
||||
emphasis: {
|
||||
focus: 'series'
|
||||
},
|
||||
data: $data.userActivityData.activeUsers
|
||||
},
|
||||
{
|
||||
name: '新增用户',
|
||||
type: 'line',
|
||||
stack: 'Total',
|
||||
smooth: true,
|
||||
lineStyle: {
|
||||
width: 0
|
||||
},
|
||||
showSymbol: false,
|
||||
areaStyle: {
|
||||
opacity: 0.8,
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{
|
||||
offset: 0,
|
||||
color: 'rgba(16, 185, 129, 0.8)'
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: 'rgba(16, 185, 129, 0.1)'
|
||||
}
|
||||
])
|
||||
},
|
||||
emphasis: {
|
||||
focus: 'series'
|
||||
},
|
||||
data: $data.userActivityData.newUsers
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
// 任务完成情况图
|
||||
const taskCompletionChart = echarts.init(document.getElementById('taskCompletionChart'));
|
||||
taskCompletionChart.setOption({
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'shadow'
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
data: ['已完成', '待处理'],
|
||||
textStyle: {
|
||||
color: '#6b7280'
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '4%',
|
||||
bottom: '3%',
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: $data.taskCompletionData.weeks,
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#9ca3af'
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#6b7280'
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#9ca3af'
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#6b7280'
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: '#e5e7eb'
|
||||
}
|
||||
}
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '已完成',
|
||||
type: 'bar',
|
||||
stack: 'total',
|
||||
emphasis: {
|
||||
focus: 'series'
|
||||
},
|
||||
data: $data.taskCompletionData.completed,
|
||||
itemStyle: {
|
||||
color: '#10b981'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '待处理',
|
||||
type: 'bar',
|
||||
stack: 'total',
|
||||
emphasis: {
|
||||
focus: 'series'
|
||||
},
|
||||
data: $data.taskCompletionData.pending,
|
||||
itemStyle: {
|
||||
color: '#f59e0b'
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
// 窗口大小变化时重新调整图表大小
|
||||
window.addEventListener('resize', function () {
|
||||
userGrowthChart.resize();
|
||||
projectStatusChart.resize();
|
||||
userActivityChart.resize();
|
||||
taskCompletionChart.resize();
|
||||
});
|
||||
}
|
||||
|
||||
// 页面加载完成后初始化图表
|
||||
initCharts()
|
||||
</script>
|
||||
Loading…
Reference in New Issue