一、最终项目结构(强烈推荐)
bigscreen/
├── backend/ # Flask 后端
│ ├── app/
│ │ ├── __init__.py
│ │ ├── models.py
│ │ ├── routes.py
│ │ └── extensions.py
│ ├── config.py
│ ├── run.py
│ └── requirements.txt
│
├── frontend/ # Vue 3 前端
│ ├── src/
│ │ ├── api/
│ │ │ └── index.js
│ │ ├── components/
│ │ │ └── ChartPanel.vue
│ │ ├── views/
│ │ │ └── Home.vue
│ │ ├── App.vue
│ │ └── main.js
│ ├── package.json
│ └── vite.config.js
│
└── README.md
二、后端:Flask(生产级结构)
1️⃣ 安装依赖
cd backend
python -m venv .venv
.venv\Scripts\activate
pip install flask flask_sqlalchemy flask_cors pymysql
requirements.txt
flask
flask_sqlalchemy
flask_cors
pymysql
2️⃣ 配置(config.py)
class Config:
SQLALCHEMY_DATABASE_URI = (
"mysql+pymysql://root:你的密码@localhost/bigscreen?charset=utf8mb4"
)
SQLALCHEMY_TRACK_MODIFICATIONS = False
SECRET_KEY = "dev-secret"
3️⃣ 扩展(app/extensions.py)
from flask_sqlalchemy import SQLAlchemy
from flask_cors import CORS
db = SQLAlchemy()
cors = CORS()
4️⃣ 数据模型(app/models.py)
from .extensions import db
class Sales(db.Model):
__tablename__ = "sales"
id = db.Column(db.Integer, primary_key=True)
category = db.Column(db.String(50))
amount = db.Column(db.Numeric(10,2))
date = db.Column(db.Date)
5️⃣ 路由(app/routes.py)
from flask import Blueprint, jsonify
from .extensions import db
from .models import Sales
bp = Blueprint("api", __name__, url_prefix="/api")
@bp.route("/sales")
def sales():
data = Sales.query.all()
return jsonify([
{
"category": s.category,
"amount": float(s.amount),
"date": s.date.strftime("%Y-%m-%d")
}
for s in data
])
@bp.route("/sales/summary")
def summary():
sql = """
SELECT category, SUM(amount) AS total
FROM sales GROUP BY category
"""
result = db.session.execute(sql).fetchall()
return jsonify([
{"name": r[0], "value": float(r[1])}
for r in result
])
6️⃣ 应用工厂(app/init.py)
from flask import Flask
from .extensions import db, cors
from .routes import bp
def create_app():
app = Flask(__name__)
app.config.from_object("config.Config")
db.init_app(app)
cors.init_app(app)
app.register_blueprint(bp)
return app
7️⃣ 启动入口(run.py)
from app import create_app
app = create_app()
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000, debug=True)
启动:
python run.py
✅ 接口:
三、前端:Vue 3 + ECharts(完整脚手架)
1️⃣ 创建项目
npm create vite@latest frontend -- --template vue
cd frontend
npm install
npm install echarts
2️⃣ 统一 API(src/api/index.js)
import axios from 'axios'
const service = axios.create({
baseURL: 'http://localhost:5000',
timeout: 10000
})
export const getSales = () => service.get('/api/sales')
export const getSalesSummary = () => service.get('/api/sales/summary')
3️⃣ 通用图表组件(src/components/ChartPanel.vue)
<template>
<div ref="chartRef" class="chart"></div>
</template>
<script setup>
import { ref, onMounted, onBeforeUnmount, watch } from 'vue'
import * as echarts from 'echarts'
const props = defineProps({
option: Object
})
const chartRef = ref(null)
let chart = null
const initChart = () => {
chart = echarts.init(chartRef.value)
chart.setOption(props.option)
}
watch(() => props.option, (opt) => {
chart?.setOption(opt)
})
onMounted(() => {
initChart()
const ro = new ResizeObserver(() => chart?.resize())
ro.observe(chartRef.value)
onBeforeUnmount(() => {
ro.disconnect()
chart?.dispose()
})
})
</script>
<style scoped>
.chart {
width: 100%;
height: 100%;
}
</style>
✅ 这个组件 = 所有大屏图表的基础
4️⃣ 首页(src/views/Home.vue)
<template>
<div class="screen">
<ChartPanel :option="pieOption" />
<ChartPanel :option="barOption" />
<ChartPanel :option="lineOption" />
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { getSales, getSalesSummary } from '../api'
import ChartPanel from '../components/ChartPanel.vue'
const pieOption = ref({})
const barOption = ref({})
const lineOption = ref({})
onMounted(async () => {
const summary = await getSalesSummary()
pieOption.value = {
title: { text: '销售占比', left: 'center', textStyle: { fontSize: '1.5vh' } },
tooltip: { trigger: 'item' },
legend: { bottom: '2%' },
series: [{
type: 'pie',
radius: ['45%', '70%'],
center: ['50%', '55%'],
data: summary.data
}]
}
const sales = await getSales()
barOption.value = {
title: { text: '销售趋势', left: 'center', textStyle: { fontSize: '1.5vh' } },
tooltip: {},
xAxis: { type: 'category', data: [...new Set(sales.data.map(i => i.date))] },
yAxis: { type: 'value' },
series: [{
type: 'bar',
data: sales.data.map(i => i.amount)
}]
}
})
</script>
<style scoped>
.screen {
width: 100vw;
height: 100vh;
display: flex;
}
</style>
5️⃣ 入口(src/main.js)
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')
6️⃣ App.vue
<template>
<Home />
</template>
<script setup>
import Home from './views/Home.vue'
</script>
四、启动顺序(非常重要)
# 1️⃣ 启动后端
cd backend
.venv\Scripts\activate
python run.py
# 2️⃣ 启动前端
cd frontend
npm run dev