stdproject/frontend/src/data-public/Dashboard.vue

364 lines
7.9 KiB
Vue
Raw Normal View History

2025-05-30 13:43:31 +08:00
<template>
<div class="dashboard-container">
<div class="dashboard-header">
<h1>仪表板</h1>
<p>欢迎回来{{ userStore.nickname || userStore.username }}</p>
</div>
<!-- 统计卡片 -->
<div class="stats-grid">
<div class="stat-card">
<div class="stat-icon user-icon">
<el-icon><User /></el-icon>
</div>
<div class="stat-content">
<h3>{{ stats.userCount }}</h3>
<p>用户总数</p>
</div>
</div>
<div class="stat-card">
<div class="stat-icon role-icon">
<el-icon><UserFilled /></el-icon>
</div>
<div class="stat-content">
<h3>{{ stats.roleCount }}</h3>
<p>角色总数</p>
</div>
</div>
<div class="stat-card">
<div class="stat-icon org-icon">
<el-icon><OfficeBuilding /></el-icon>
</div>
<div class="stat-content">
<h3>{{ stats.orgCount }}</h3>
<p>组织总数</p>
</div>
</div>
<div class="stat-card">
<div class="stat-icon dict-icon">
<el-icon><Document /></el-icon>
</div>
<div class="stat-content">
<h3>{{ stats.dictCount }}</h3>
<p>字典总数</p>
</div>
</div>
</div>
<!-- 快捷操作 -->
<div class="quick-actions">
<h2>快捷操作</h2>
<div class="actions-grid">
2025-06-18 11:14:16 +08:00
<el-card class="action-card" @click="routerclick('/Permission')">
2025-05-30 13:43:31 +08:00
<div class="action-content">
<el-icon class="action-icon"><User /></el-icon>
<span>用户管理</span>
</div>
</el-card>
2025-06-19 11:21:06 +08:00
<el-card class="action-card" @click="routerclick('/UserLogin')">
2025-05-30 13:43:31 +08:00
<div class="action-content">
<el-icon class="action-icon"><UserFilled /></el-icon>
<span>角色管理</span>
</div>
</el-card>
2025-06-19 11:21:06 +08:00
<el-card class="action-card" >
2025-05-30 13:43:31 +08:00
<div class="action-content">
<el-icon class="action-icon"><OfficeBuilding /></el-icon>
<span>组织管理</span>
</div>
</el-card>
<el-card class="action-card" @click="$router.push('/dictionaries')">
<div class="action-content">
<el-icon class="action-icon"><Document /></el-icon>
<span>字典管理</span>
</div>
</el-card>
</div>
</div>
2025-05-30 16:20:02 +08:00
<!-- 快捷操作 -->
<div class="quick-actions">
<h2>快捷操作</h2>
<div class="actions-grid">
2025-06-17 15:09:51 +08:00
<el-card class="action-card" @click="$router.push('/FormCreate?appId=1927666485224894465')">
2025-05-30 16:20:02 +08:00
<div class="action-content">
<el-icon class="action-icon"><User /></el-icon>
2025-06-17 15:09:51 +08:00
<span>FormCreat</span>
2025-05-30 16:20:02 +08:00
</div>
</el-card>
<el-card class="action-card" @click="$router.push('/visualization?id=1927640677370306561&busiFlag=dataV')">
<div class="action-content">
<el-icon class="action-icon"><User /></el-icon>
<span>GIS大屏</span>
</div>
</el-card>
<el-card class="action-card" @click="$router.push('/visualization?id=1927658989605187585&busiFlag=dashboard')">
<div class="action-content">
<el-icon class="action-icon"><User /></el-icon>
<span>数据看板</span>
</div>
</el-card>
2025-05-30 16:20:02 +08:00
</div>
</div>
2025-05-30 13:43:31 +08:00
<!-- 最近活动 -->
<div class="recent-activities">
<h2>最近活动</h2>
<el-card>
<el-timeline>
<el-timeline-item
v-for="activity in activities"
:key="activity.id"
:timestamp="activity.time"
:type="activity.type"
>
{{ activity.content }}
</el-timeline-item>
</el-timeline>
</el-card>
</div>
</div>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue'
import { useUserStore } from '@/store/user'
import { User, UserFilled, OfficeBuilding, Document } from '@element-plus/icons-vue'
2025-06-18 11:14:16 +08:00
import { useRouter } from 'vue-router'
2025-05-30 13:43:31 +08:00
const userStore = useUserStore()
2025-06-18 11:14:16 +08:00
const router = useRouter()
2025-05-30 13:43:31 +08:00
// 统计数据
const stats = reactive({
userCount: 0,
roleCount: 0,
orgCount: 0,
dictCount: 0
})
const activities = ref([
{
id: 1,
content: '系统启动成功',
time: '2024-01-01 09:00:00',
type: 'success'
},
{
id: 2,
content: '用户登录系统',
time: '2024-01-01 09:30:00',
type: 'primary'
},
{
id: 3,
content: '创建新用户',
time: '2024-01-01 10:00:00',
type: 'info'
},
{
id: 4,
content: '更新角色权限',
time: '2024-01-01 10:30:00',
type: 'warning'
}
])
// 加载统计数据
const loadStats = async () => {
try {
// 这里应该调用实际的API获取统计数据
// 暂时使用模拟数据
stats.userCount = 156
stats.roleCount = 8
stats.orgCount = 23
stats.dictCount = 45
} catch (error) {
console.error('加载统计数据失败:', error)
}
}
// 组件挂载时加载数据
onMounted(() => {
loadStats()
})
2025-06-18 11:14:16 +08:00
function routerclick(path) {
2025-06-19 11:21:06 +08:00
if(path == '/Permission'){
router.push({
2025-06-18 11:14:16 +08:00
path: path,
query: {
id: '1927554158852841473'
}
})
2025-06-19 11:21:06 +08:00
}else if(path == '/UserLogin'){
const route = router.resolve({
path: path,
query: { id: '1927554158852841473' ,name:'测试项目'}
});
window.open(route.href, '_blank');
}
2025-06-18 11:14:16 +08:00
}
2025-05-30 13:43:31 +08:00
</script>
<style lang="scss" scoped>
.dashboard-container {
padding: 20px;
max-width: 1200px;
margin: 0 auto;
}
.dashboard-header {
margin-bottom: 30px;
h1 {
color: #333;
margin-bottom: 8px;
font-size: 28px;
font-weight: 600;
}
p {
color: #666;
font-size: 16px;
}
}
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
margin-bottom: 40px;
}
.stat-card {
background: white;
border-radius: 10px;
padding: 24px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
display: flex;
align-items: center;
gap: 16px;
transition: transform 0.2s, box-shadow 0.2s;
&:hover {
transform: translateY(-2px);
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
}
}
.stat-icon {
width: 60px;
height: 60px;
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
color: white;
&.user-icon {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
&.role-icon {
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
}
&.org-icon {
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
}
&.dict-icon {
background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);
}
}
.stat-content {
h3 {
font-size: 32px;
font-weight: 700;
color: #333;
margin-bottom: 4px;
}
p {
color: #666;
font-size: 14px;
}
}
.quick-actions {
margin-bottom: 40px;
h2 {
color: #333;
margin-bottom: 20px;
font-size: 20px;
font-weight: 600;
}
}
.actions-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 16px;
}
.action-card {
cursor: pointer;
transition: transform 0.2s, box-shadow 0.2s;
&:hover {
transform: translateY(-2px);
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
}
}
.action-content {
display: flex;
flex-direction: column;
align-items: center;
gap: 12px;
padding: 20px;
.action-icon {
font-size: 32px;
color: #409eff;
}
span {
font-size: 16px;
font-weight: 500;
color: #333;
}
}
.recent-activities {
h2 {
color: #333;
margin-bottom: 20px;
font-size: 20px;
font-weight: 600;
}
.el-card {
padding: 20px;
}
}
@media (max-width: 768px) {
.dashboard-container {
padding: 16px;
}
.stats-grid {
grid-template-columns: 1fr;
}
.actions-grid {
grid-template-columns: repeat(2, 1fr);
}
}
</style>