




本项目将带领大家从零搭建一个类似截图中的政务 OA 系统首页。前端采用 Vue 3 (Composition API) 结合现代化 UI 布局,后端使用轻量级的 Flask 提供 RESTful API,并利用 ECharts 为统计卡片注入动态数据可视化效果。
一、 需求与 UI 拆解分析
我们将页面拆分为以下几个核心组件:
-
顶部导航栏 (Navbar):深蓝色背景,包含 Logo、菜单、多语言切换及登录/管理后台入口。
-
首屏信息区 (Hero Section):左侧为渐变蓝色的系统介绍区,右侧为系统版本、服务范围等基础信息卡片。
-
数据统计面板 (Stats Cards) :5个带有 Icon 和数字的卡片(内设机构、在职人员、通知公告等)。(此处是我们引入 ECharts 的重点)
-
底部内容区:左侧为"通知公告"列表,右侧为"政务公开"的快捷宫格(机构职能、政策文件等)。
二、 后端搭建:Flask 提供数据接口
首先,我们需要一个简单的后端来提供页面所需的模拟数据。
-
初始化 Flask 项目:
bash
mkdir flask-backend && cd flask-backend python -m venv venv source venv/bin/activate # Windows使用 venv\Scripts\activate pip install Flask flask-cors -
编写
app.py:python
from flask import Flask, jsonify from flask_cors import CORS from datetime import datetime app = Flask(__name__) CORS(app) # 允许跨域请求 @app.route('/api/dashboard', methods=['GET']) def get_dashboard_data(): # 模拟统计数据 (包含用于ECharts的趋势数据) stats = [ {"id": 1, "title": "内设机构", "count": 10, "icon": "org", "color": "#2563eb", "trend": [5, 7, 6, 8, 9, 10, 10]}, {"id": 2, "title": "在职人员", "count": 22, "icon": "user", "color": "#10b981", "trend": [18, 19, 20, 20, 21, 22, 22]}, {"id": 3, "title": "通知公告", "count": 8, "icon": "bell", "color": "#ef4444", "trend": [2, 3, 3, 5, 6, 7, 8]}, {"id": 4, "title": "累计公文", "count": 6, "icon": "doc", "color": "#d97706", "trend": [1, 2, 2, 4, 5, 5, 6]}, {"id": 5, "title": "会议安排", "count": 6, "icon": "calendar", "color": "#8b5cf6", "trend": [0, 1, 3, 3, 4, 6, 6]} ] # 模拟通知公告 notices = [ {"title": "关于做好2026年度政务数字化评估工作的通知", "date": "10-17", "is_top": True}, {"title": "新版公文处理办法(试行)印发", "date": "10-15", "is_top": True}, {"title": "机关食堂冬季供餐时间调整公告", "date": "10-16", "is_top": False}, ] # 模拟政务公开宫格 public_info = [ {"title": "机构职能", "desc": "内设机构与职责"}, {"title": "通知公告", "desc": "通知 / 公告 / 制度"}, {"title": "政策文件", "desc": "规范性文件发布"}, {"title": "人事任免", "desc": "干部任免信息"} ] return jsonify({ "date": datetime.now().strftime("%Y年%m月%d日"), "stats": stats, "notices": notices, "public_info": public_info }) if __name__ == '__main__': app.run(debug=True, port=5000)
三、 前端搭建:Vue3 页面与 ECharts 融合
使用 Vite 快速创建 Vue3 项目,并安装 Axios 和 ECharts。
bash
npm create vite@latest vue-oa-frontend -- --template vue
cd vue-oa-frontend
npm install axios echarts vue-echarts
1. 封装 ECharts 微型图表组件 (StatsCard.vue)
截图中的统计卡片只有数字。为了让 ECharts 发挥作用,我们可以为每个卡片底部添加一个迷你的折线图(Sparkline),展示该指标近7天的发展趋势。
vue
<!-- components/StatsCard.vue -->
<template>
<div class="stats-card">
<div class="card-header">
<div class="icon-box" :style="{ backgroundColor: color + '20', color: color }">
<!-- 此处省略具体图标 SVG,实际开发可用 ElementPlus/Icon 库 -->
<i class="icon">{{ icon }}</i>
</div>
<div class="info">
<h3>{{ count }}</h3>
<p>{{ title }}</p>
</div>
</div>
<!-- ECharts 迷你图表容器 -->
<div class="chart-container" ref="chartRef"></div>
</div>
</template>
<script setup>
import { ref, onMounted, watch } from 'vue'
import * as echarts from 'echarts'
const props = defineProps({
title: String,
count: Number,
icon: String,
color: String,
trend: Array
})
const chartRef = ref(null)
let chartInstance = null
const initChart = () => {
if (!chartRef.value) return
chartInstance = echarts.init(chartRef.value)
const option = {
grid: { top: 5, bottom: 5, left: 0, right: 0 },
xAxis: { type: 'category', show: false, data: ['1','2','3','4','5','6','7'] },
yAxis: { type: 'value', show: false },
series: [{
data: props.trend,
type: 'line',
smooth: true,
symbol: 'none',
lineStyle: { color: props.color, width: 2 },
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: props.color + '80' }, // 渐变色
{ offset: 1, color: props.color + '00' }
])
}
}]
}
chartInstance.setOption(option)
}
onMounted(() => {
initChart()
window.addEventListener('resize', () => chartInstance?.resize())
})
watch(() => props.trend, () => {
if (chartInstance) {
chartInstance.setOption({ series: [{ data: props.trend }] })
}
})
</script>
<style scoped>
.stats-card {
background: #fff;
border-radius: 12px;
padding: 16px;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05);
display: flex;
flex-direction: column;
position: relative;
overflow: hidden;
}
.card-header {
display: flex;
align-items: center;
gap: 12px;
z-index: 2;
}
.icon-box {
width: 40px;
height: 40px;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
font-size: 20px;
font-weight: bold;
}
.info h3 { margin: 0; font-size: 24px; color: #1e293b; }
.info p { margin: 0; font-size: 12px; color: #64748b; }
.chart-container {
height: 30px;
width: 100%;
margin-top: 10px;
z-index: 1;
}
</style>
2. 构建主页面 (App.vue)
参考截图布局,使用 Flex/Grid 进行排版,并请求 Flask 数据。
vue
<template>
<div class="oa-layout">
<!-- 1. 顶部导航 -->
<header class="navbar">
<div class="logo">政务 OA 系统 <span>GOVERNMENT OA SYSTEM</span></div>
<nav>
<a href="#" class="active">首页</a>
<a href="#">政务公开</a>
</nav>
<div class="actions">
<button>中文 / EN</button>
<button>员工门户</button>
<button>管理后台</button>
</div>
</header>
<main class="container">
<!-- 2. 首屏信息 -->
<section class="hero-section">
<div class="hero-left">
<h1>政务 OA 系统</h1>
<p>通知公告 · 公文流转 · 会议管理 · 行政审批 · 日程安排</p>
<p>考勤统计 · 内部消息 · 通讯录 —— 员工门户与管理后台一体化办公</p>
<div class="buttons">
<button class="primary">进入员工门户</button>
<button class="secondary">浏览政务公开</button>
</div>
</div>
<div class="hero-right">
<h2>{{ dashboardData.date }}</h2>
<ul>
<li><span>系统版本</span> <strong>v1.0.0</strong></li>
<li><span>服务范围</span> <strong>全体干部职工</strong></li>
<li><span>运维支持</span> <strong>局办公室 · 信息中心</strong></li>
</ul>
</div>
</section>
<!-- 3. 数据统计卡片 (结合 ECharts) -->
<section class="stats-grid">
<StatsCard
v-for="stat in dashboardData.stats"
:key="stat.id"
v-bind="stat"
/>
</section>
<!-- 4. 底部内容区 -->
<section class="content-grid">
<!-- 通知公告 -->
<div class="panel">
<div class="panel-header">
<h3>通知公告</h3>
<a href="#">更多 →</a>
</div>
<ul class="notice-list">
<li v-for="(notice, index) in dashboardData.notices" :key="index">
<span v-if="notice.is_top" class="tag">置顶</span>
<a href="#">{{ notice.title }}</a>
<span class="date">{{ notice.date }}</span>
</li>
</ul>
</div>
<!-- 政务公开 -->
<div class="panel">
<div class="panel-header">
<h3>政务公开</h3>
<a href="#">进入专栏 →</a>
</div>
<div class="public-grid">
<div class="public-item" v-for="(item, index) in dashboardData.public_info" :key="index">
<h4>{{ item.title }}</h4>
<p>{{ item.desc }}</p>
</div>
</div>
</div>
</section>
</main>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import axios from 'axios'
import StatsCard from './components/StatsCard.vue'
const dashboardData = ref({
date: '',
stats: [],
notices: [],
public_info: []
})
onMounted(async () => {
try {
// 请求 Flask 后端
const res = await axios.get('http://127.0.0.1:5000/api/dashboard')
dashboardData.value = res.data
} catch (error) {
console.error('获取数据失败:', error)
}
})
</script>
<style>
/* 此处仅为关键样式示意,完整样式需配合 UI 设计稿 */
body { background-color: #f1f5f9; margin: 0; font-family: sans-serif; }
.navbar { background: #1e3a8a; color: white; padding: 16px 32px; display: flex; justify-content: space-between; align-items: center; }
.container { max-width: 1200px; margin: 24px auto; padding: 0 16px; }
/* Hero 区域 */
.hero-section { display: grid; grid-template-columns: 2fr 1fr; gap: 24px; margin-bottom: 24px; }
.hero-left { background: linear-gradient(135deg, #1e3a8a, #3b82f6); color: white; padding: 32px; border-radius: 12px; }
.hero-right { background: white; padding: 32px; border-radius: 12px; }
/* ECharts 卡片网格 */
.stats-grid { display: grid; grid-template-columns: repeat(5, 1fr); gap: 16px; margin-bottom: 24px; }
/* 底部面板 */
.content-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; }
.panel { background: white; padding: 24px; border-radius: 12px; }
.public-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.public-item { border: 1px solid #e2e8f0; padding: 16px; border-radius: 8px; }
</style>
四、 项目启动与联调
-
启动后端:进入
flask-backend目录,运行python app.py。 -
启动前端:进入
vue-oa-frontend目录,运行npm run dev。 -
打开浏览器访问 Vite 提供的本地地址,你将看到一个完美复刻截图 UI,并且卡片下方带有 ECharts 动态趋势线的政务 OA 系统门户。
总结
通过 Vue3 的组件化开发,我们快速还原了复杂的政务 OA 首页;Flask 提供了轻量快捷的 API 支撑;而 ECharts 的引入,则让原本静态的数字面板(内设机构、在职人员等)拥有了直观的数据趋势展示能力。这种**"传统政务UI + 微图表"**的设计,不仅保留了庄重感,更增加了数据可视化的现代感。后续您可以继续使用 ECharts 在"管理后台"模块渲染大屏统计饼图和柱状图,进一步完善系统。