|
|
<template>
|
|
|
<div class="dashboard-container">
|
|
|
<!-- 页面头部 -->
|
|
|
<div class="page-header">
|
|
|
<h1 class="page-title">
|
|
|
<el-icon :size="24"><Odometer /></el-icon>
|
|
|
首页
|
|
|
</h1>
|
|
|
<p class="page-subtitle">欢迎回来,这里是您的资金使用概览</p>
|
|
|
</div>
|
|
|
|
|
|
<!-- 统计卡片 -->
|
|
|
<div class="stats-grid">
|
|
|
<el-card
|
|
|
v-for="(stat, index) in stats"
|
|
|
:key="index"
|
|
|
class="stat-card"
|
|
|
shadow="hover"
|
|
|
>
|
|
|
<div class="stat-card-header">
|
|
|
<div class="stat-card-title">{{ stat.title }}</div>
|
|
|
<div class="stat-card-icon" :class="stat.color">
|
|
|
<el-icon :size="24"><component :is="getIcon(stat.icon)" /></el-icon>
|
|
|
</div>
|
|
|
</div>
|
|
|
<div class="stat-card-value">{{ stat.value }}</div>
|
|
|
<div class="stat-card-change" :class="stat.trendType">
|
|
|
<el-icon><ArrowUp v-if="stat.trendType === 'up'" /><ArrowDown v-else /></el-icon>
|
|
|
<span>{{ stat.trend }}</span>
|
|
|
</div>
|
|
|
</el-card>
|
|
|
</div>
|
|
|
|
|
|
<!-- 主要内容区域 -->
|
|
|
<div class="content-grid">
|
|
|
<!-- 待办事项列表 -->
|
|
|
<el-card class="todo-card">
|
|
|
<template #header>
|
|
|
<div class="card-header">
|
|
|
<el-icon><List /></el-icon>
|
|
|
<span>待办事项</span>
|
|
|
</div>
|
|
|
</template>
|
|
|
<el-table :data="todoList" style="width: 100%">
|
|
|
<el-table-column label="申请类型" min-width="200">
|
|
|
<template #default="scope">
|
|
|
<div class="type-cell">
|
|
|
<el-icon :size="16" :color="getTypeColor(scope.row.typeIcon)">
|
|
|
<component :is="getIcon(scope.row.typeIcon)" />
|
|
|
</el-icon>
|
|
|
<span>{{ scope.row.type }}</span>
|
|
|
</div>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
<el-table-column prop="applicant" label="申请人" width="100" />
|
|
|
<el-table-column prop="amount" label="金额" width="120">
|
|
|
<template #default="scope">
|
|
|
<span style="color: #409eff; font-weight: 600;">{{ scope.row.amount }}</span>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
<el-table-column prop="status" label="状态" width="100">
|
|
|
<template #default="scope">
|
|
|
<el-tag :type="getStatusType(scope.row.status)">
|
|
|
{{ scope.row.status }}
|
|
|
</el-tag>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
<el-table-column prop="submitTime" label="提交时间" width="160" />
|
|
|
<el-table-column label="操作" width="100">
|
|
|
<template #default="scope">
|
|
|
<el-button
|
|
|
:type="scope.row.status === '已批准' ? 'success' : 'primary'"
|
|
|
link
|
|
|
size="small"
|
|
|
@click="handleAction(scope.row)"
|
|
|
>
|
|
|
{{ scope.row.status === '已批准' ? '支付' : '查看' }}
|
|
|
</el-button>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
</el-table>
|
|
|
</el-card>
|
|
|
|
|
|
<!-- 快速操作和进度 -->
|
|
|
<div class="right-column">
|
|
|
<!-- 快速操作 -->
|
|
|
<el-card class="quick-actions-card">
|
|
|
<template #header>
|
|
|
<div class="card-header">
|
|
|
<el-icon><Lightning /></el-icon>
|
|
|
<span>快速操作</span>
|
|
|
</div>
|
|
|
</template>
|
|
|
<div class="quick-actions">
|
|
|
<div
|
|
|
v-for="action in actions"
|
|
|
:key="action.id"
|
|
|
class="quick-action-btn"
|
|
|
@click="handleQuickAction(action)"
|
|
|
>
|
|
|
<el-icon :size="32" :color="getActionColor(action.color)">
|
|
|
<component :is="getIcon(action.icon)" />
|
|
|
</el-icon>
|
|
|
<span>{{ action.title }}</span>
|
|
|
</div>
|
|
|
</div>
|
|
|
</el-card>
|
|
|
|
|
|
<!-- 审批进度 -->
|
|
|
<el-card class="progress-card">
|
|
|
<template #header>
|
|
|
<div class="card-header">
|
|
|
<el-icon><TrendCharts /></el-icon>
|
|
|
<span>本月审批进度</span>
|
|
|
</div>
|
|
|
</template>
|
|
|
<div class="progress-list">
|
|
|
<div
|
|
|
v-for="(item, index) in progress"
|
|
|
:key="index"
|
|
|
class="progress-item"
|
|
|
>
|
|
|
<div class="progress-label">
|
|
|
<span>{{ item.category }}</span>
|
|
|
<strong>{{ item.percentage }}%</strong>
|
|
|
</div>
|
|
|
<el-progress
|
|
|
:percentage="item.percentage"
|
|
|
:color="getProgressColor(item.color)"
|
|
|
:stroke-width="8"
|
|
|
/>
|
|
|
</div>
|
|
|
</div>
|
|
|
</el-card>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
|
import { ref, onMounted } from 'vue'
|
|
|
import { useRouter } from 'vue-router'
|
|
|
import { ElMessage } from 'element-plus'
|
|
|
import {
|
|
|
Odometer,
|
|
|
DocumentChecked,
|
|
|
Money,
|
|
|
CircleCheck,
|
|
|
ArrowUp,
|
|
|
ArrowDown,
|
|
|
List,
|
|
|
Lightning,
|
|
|
TrendCharts,
|
|
|
ShoppingBag,
|
|
|
Promotion,
|
|
|
ChatLineRound,
|
|
|
Document,
|
|
|
Tools,
|
|
|
MagicStick
|
|
|
} from '@element-plus/icons-vue'
|
|
|
import {
|
|
|
dashboardStats,
|
|
|
todoTableData,
|
|
|
quickActions,
|
|
|
approvalProgress
|
|
|
} from '@/mock'
|
|
|
|
|
|
const router = useRouter()
|
|
|
|
|
|
const stats = ref([])
|
|
|
const todoList = ref([])
|
|
|
const actions = ref([])
|
|
|
const progress = ref([])
|
|
|
|
|
|
const iconMap = {
|
|
|
DocumentChecked,
|
|
|
Money,
|
|
|
CircleCheck,
|
|
|
ShoppingBag,
|
|
|
Promotion,
|
|
|
ChatLineRound,
|
|
|
Document,
|
|
|
Tools,
|
|
|
MagicStick
|
|
|
}
|
|
|
|
|
|
const getIcon = (iconName) => {
|
|
|
return iconMap[iconName] || Document
|
|
|
}
|
|
|
|
|
|
const getTypeColor = (iconName) => {
|
|
|
const colorMap = {
|
|
|
ShoppingBag: '#409eff',
|
|
|
Promotion: '#909399',
|
|
|
ChatLineRound: '#67c23a',
|
|
|
Document: '#e6a23c',
|
|
|
Tools: '#909399'
|
|
|
}
|
|
|
return colorMap[iconName] || '#409eff'
|
|
|
}
|
|
|
|
|
|
const getStatusType = (status) => {
|
|
|
const statusMap = {
|
|
|
'待审批': 'warning',
|
|
|
'已批准': 'success',
|
|
|
'处理中': 'primary',
|
|
|
'已拒绝': 'danger'
|
|
|
}
|
|
|
return statusMap[status] || ''
|
|
|
}
|
|
|
|
|
|
const getActionColor = (color) => {
|
|
|
const colorMap = {
|
|
|
primary: '#409eff',
|
|
|
success: '#67c23a',
|
|
|
info: '#909399',
|
|
|
warning: '#e6a23c'
|
|
|
}
|
|
|
return colorMap[color] || '#409eff'
|
|
|
}
|
|
|
|
|
|
const getProgressColor = (color) => {
|
|
|
const colorMap = {
|
|
|
primary: '#409eff',
|
|
|
success: '#67c23a',
|
|
|
info: '#909399',
|
|
|
warning: '#e6a23c'
|
|
|
}
|
|
|
return colorMap[color] || '#409eff'
|
|
|
}
|
|
|
|
|
|
const handleAction = (row) => {
|
|
|
if (row.status === '已批准') {
|
|
|
ElMessage.info(`跳转到支付页面: ${row.type}`)
|
|
|
router.push('/payment/direct-payment')
|
|
|
} else {
|
|
|
ElMessage.info(`查看详情: ${row.type}`)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
const handleQuickAction = (action) => {
|
|
|
ElMessage.info(`快速操作: ${action.title}`)
|
|
|
if (action.route) {
|
|
|
router.push(action.route)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
onMounted(async () => {
|
|
|
// 模拟加载数据
|
|
|
await new Promise(resolve => setTimeout(resolve, 300))
|
|
|
stats.value = dashboardStats
|
|
|
todoList.value = todoTableData
|
|
|
actions.value = quickActions
|
|
|
progress.value = approvalProgress
|
|
|
})
|
|
|
</script>
|
|
|
|
|
|
<style scoped>
|
|
|
.dashboard-container {
|
|
|
padding: 20px;
|
|
|
background: #f5f7fa;
|
|
|
min-height: 100%;
|
|
|
}
|
|
|
|
|
|
.page-header {
|
|
|
background: white;
|
|
|
padding: 25px 30px;
|
|
|
border-radius: 10px;
|
|
|
margin-bottom: 20px;
|
|
|
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
|
|
|
}
|
|
|
|
|
|
.page-title {
|
|
|
font-size: 24px;
|
|
|
font-weight: 600;
|
|
|
color: #333;
|
|
|
margin: 0 0 5px 0;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
gap: 10px;
|
|
|
}
|
|
|
|
|
|
.page-subtitle {
|
|
|
color: #666;
|
|
|
font-size: 14px;
|
|
|
margin: 0;
|
|
|
}
|
|
|
|
|
|
.stats-grid {
|
|
|
display: grid;
|
|
|
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
|
|
gap: 20px;
|
|
|
margin-bottom: 20px;
|
|
|
}
|
|
|
|
|
|
.stat-card {
|
|
|
transition: transform 0.3s, box-shadow 0.3s;
|
|
|
}
|
|
|
|
|
|
.stat-card:hover {
|
|
|
transform: translateY(-5px);
|
|
|
box-shadow: 0 5px 20px rgba(0, 0, 0, 0.1);
|
|
|
}
|
|
|
|
|
|
.stat-card-header {
|
|
|
display: flex;
|
|
|
justify-content: space-between;
|
|
|
align-items: center;
|
|
|
margin-bottom: 15px;
|
|
|
}
|
|
|
|
|
|
.stat-card-title {
|
|
|
font-size: 14px;
|
|
|
color: #666;
|
|
|
font-weight: 500;
|
|
|
}
|
|
|
|
|
|
.stat-card-icon {
|
|
|
width: 50px;
|
|
|
height: 50px;
|
|
|
border-radius: 10px;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
color: white;
|
|
|
}
|
|
|
|
|
|
.stat-card-icon.primary {
|
|
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
|
}
|
|
|
|
|
|
.stat-card-icon.success {
|
|
|
background: linear-gradient(135deg, #11998e 0%, #38ef7d 100%);
|
|
|
}
|
|
|
|
|
|
.stat-card-icon.warning {
|
|
|
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
|
|
|
}
|
|
|
|
|
|
.stat-card-icon.info {
|
|
|
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
|
|
|
}
|
|
|
|
|
|
.stat-card-value {
|
|
|
font-size: 32px;
|
|
|
font-weight: 700;
|
|
|
color: #333;
|
|
|
margin-bottom: 5px;
|
|
|
}
|
|
|
|
|
|
.stat-card-change {
|
|
|
font-size: 14px;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
gap: 5px;
|
|
|
}
|
|
|
|
|
|
.stat-card-change.positive {
|
|
|
color: #10b981;
|
|
|
}
|
|
|
|
|
|
.stat-card-change.negative {
|
|
|
color: #ef4444;
|
|
|
}
|
|
|
|
|
|
.content-grid {
|
|
|
display: grid;
|
|
|
grid-template-columns: 2fr 1fr;
|
|
|
gap: 20px;
|
|
|
}
|
|
|
|
|
|
.todo-card {
|
|
|
min-height: 500px;
|
|
|
}
|
|
|
|
|
|
.card-header {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
gap: 8px;
|
|
|
font-weight: 600;
|
|
|
font-size: 16px;
|
|
|
color: #333;
|
|
|
}
|
|
|
|
|
|
.type-cell {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
gap: 8px;
|
|
|
}
|
|
|
|
|
|
.right-column {
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
gap: 20px;
|
|
|
}
|
|
|
|
|
|
.quick-actions-card {
|
|
|
min-height: 200px;
|
|
|
}
|
|
|
|
|
|
.quick-actions {
|
|
|
display: grid;
|
|
|
grid-template-columns: repeat(2, 1fr);
|
|
|
gap: 15px;
|
|
|
}
|
|
|
|
|
|
.quick-action-btn {
|
|
|
padding: 20px;
|
|
|
border: 2px solid #e5e7eb;
|
|
|
border-radius: 10px;
|
|
|
text-align: center;
|
|
|
cursor: pointer;
|
|
|
transition: all 0.3s;
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
align-items: center;
|
|
|
gap: 10px;
|
|
|
}
|
|
|
|
|
|
.quick-action-btn:hover {
|
|
|
border-color: #667eea;
|
|
|
background-color: #f0f0ff;
|
|
|
transform: translateY(-2px);
|
|
|
}
|
|
|
|
|
|
.quick-action-btn span {
|
|
|
font-weight: 500;
|
|
|
font-size: 14px;
|
|
|
color: #333;
|
|
|
}
|
|
|
|
|
|
.progress-card {
|
|
|
min-height: 250px;
|
|
|
}
|
|
|
|
|
|
.progress-list {
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
gap: 20px;
|
|
|
}
|
|
|
|
|
|
.progress-item {
|
|
|
margin-bottom: 0;
|
|
|
}
|
|
|
|
|
|
.progress-label {
|
|
|
display: flex;
|
|
|
justify-content: space-between;
|
|
|
margin-bottom: 8px;
|
|
|
font-size: 14px;
|
|
|
color: #666;
|
|
|
}
|
|
|
|
|
|
.progress-label strong {
|
|
|
color: #333;
|
|
|
}
|
|
|
|
|
|
@media (max-width: 768px) {
|
|
|
.content-grid {
|
|
|
grid-template-columns: 1fr;
|
|
|
}
|
|
|
|
|
|
.stats-grid {
|
|
|
grid-template-columns: 1fr;
|
|
|
}
|
|
|
}
|
|
|
</style>
|