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>
|
2025-06-17 10:35:33 +08:00
|
|
|
|
<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>
|