☰
Django疫情数据可视化系统:从环境配置到ORM聚合与ECharts图表全解析
2026/10/2 2:49:35 网站建设 项目流程

简介:面向计算机专业毕业设计的疫情数据可视化分析系统完整项目包,基于Python与Django框架构建,为需要完成毕设或入门Web开发与数据分析的学习者提供可直接运行与二次开发的范本。资源涵盖完整源码、数据库文件、配置教程及开发说明,系统利用Pandas和NumPy处理疫情数据,借助Django的MVC架构搭建后端服务,并以MySQL作为数据存储方案,清晰呈现了从数据处理到可视化的实现链路。

压缩包共745个文件,大小约15.81MB,主要包含Python后端代码、Vue前端页面、HTML/CSS/JS静态资源、SQL数据库脚本、MD格式开发文档以及一键安装与运行的批处理脚本,结构清晰,便于按模块查阅。开发说明详细梳理了设计思路与功能实现,配置教程可降低上手门槛,数据库文件则提供了关键疫情数据,使分析与可视化能够直接展开。目前已有61人学习下载,对于正在准备毕业设计、希望积累项目经验或提升编程能力的学生而言,是一份兼顾实用性与教学价值的参考资料。

1. 为什么这类毕业设计值得花时间跑通:能让你真正练到 Django 全栈的项目包

答辩现场最怕听到的一句话,不是“你这个功能太简单”,而是“这个页面是你写的还是从某个压缩包解出来的”。基于 Python+Django 的疫情数据可视化分析系统,恰恰是那种“看起来能被一眼看穿”的选题:它同时牵扯后端框架 Django、数据库建模、ORM 聚合查询和 ECharts 数据可视化,任何一个环节答不上来,都会被追问下一句。能跑起来只是及格线,能讲清楚数据怎么进库、接口怎么吐 JSON、图表怎么绑定数据,才是这份源码真正值钱的地方。这篇笔记就沿着这条线拆一遍,适合拿这类项目包交差、但还没把工程真正吃透的人。

2. 把压缩包变成在线系统:两小时落地路线与版本选型

2.1 先看版本,再写代码:Python 和 Django 为什么必须对齐

先说一句实在话。我从别人手里接这类项目包时,第一件事不是打开代码看逻辑,而是看两个地方:README 里标注的 Django 版本,以及 requirements.txt 里的依赖清单。自己机器上装的是 Django 5.1,项目写的是 Django==4.2,直接pip install -r requirements.txt会把版本降回去,降级过程中还可能连带pandas、matplotlib装的版本不兼容,一启动就报ModuleNotFoundError。

这类项目包里最常见的组合是Python 3.10/3.11 + Django 4.2,个别老古董用 Django 2.2,那个版本在 Python 3.8 以上的环境里跑python manage.py runserver会有兼容性小毛病。所以第一步不是急着安装,而是先用虚拟环境把版本隔离出来,别污染你自己平时写代码的 Python 环境。

# 1. 在项目根目录创建虚拟环境,Windows 和 Linux 命令略有区别 cd 项目根目录 python -m venv venv # 2. 激活虚拟环境 source venv/bin/activate # Linux / macOS venv\Scripts\activate # Windows 下用这个 # 3. 安装项目依赖,装之前先看 requirements.txt 里锁了哪些版本 pip install -r requirements.txt # 4. 确认当前环境里 Django 版本和项目要求一致 python -m django --version

参数说明:venv是 Python 内置的虚拟环境工具,不需要额外安装;激活后终端前面会多一个(venv)前缀,看到这个前缀就说明环境切对了。第四条python -m django --version比django-admin --version更可靠,因为它读的是当前虚拟环境里的版本,不会误读到全局安装的 Django。

如果你用 VSCode 写这个项目,记得按Ctrl+Shift+P调出命令面板,选择 Python 解释器,指向venv目录里那个 Python。不然编辑器里import django可能会报红,但终端里又能跑,这种“编辑器红、命令行不红”的割裂状态最容易让人误判环境没问题。

2.2 从源码到跑起来:迁移、超级用户、开发服务器

环境对齐之后,整个项目真正能启动只需要三条命令。别急着去读代码,先按顺序执行,看到页面出来再说。

# 1. 执行数据库迁移,生成 auth_user、session 等 Django 内置表 python manage.py migrate # 2. 创建管理员账号,登录 /admin 后台维护数据时要用 python manage.py createsuperuser # 3. 启动开发服务器,0.0.0.0 表示局域网内别的机器也能访问 python manage.py runserver 0.0.0.0:8000

逻辑说明:migrate是根据项目里已有的migrations目录,把 models 里定义的模型同步到数据库里。新解压的项目没有自己的数据表,第一次运行会生成一堆 Django 内置表,包括用户表、权限表、会话表,这些是后面登录注册功能正常工作的前提。

为什么createsuperuser很重要?多数这类项目的后台管理页面/admin都注册了数据模型,评审老师习惯点进去看有没有数据、能不能编辑,没有管理员账号就进不去。命令执行时会交互式问你用户名、邮箱、密码,密码输入不显示是正常的。runserver 0.0.0.0:8000里的0.0.0.0让服务监听所有网卡地址,这样同一局域网下其他人的浏览器能用你电脑的 IP 加 8000 端口访问,答辩演示时很实用;如果只想本机看,默认的127.0.0.1就够了。

跑完这三步,浏览器访问http://127.0.0.1:8000,看到页面就说明基础环境通了。如果报错,大概率栽在依赖版本上,先回头检查pip freeze和requirements.txt的差异。

2.3 换一台机器后必改的四个配置:数据库、时区、静态文件、ALLOWED_HOSTS

项目在自己电脑上跑通,不代表换到答辩机器上也能跑。配置文件里最常出问题的就是 settings.py,动手改之前先看这几个值。

配置项常见值需要注意什么
DATABASESsqlite3 默认换成 MySQL 要额外装驱动并改引擎
TIME_ZONEUTC / Asia/Shanghai影响时间统计的“今天”边界
USE_TZTrue / False是折线图日期“少一天”的头号原因
STATICFILES_DIRS未配置 / BASE_DIR/static配错则 ECharts 的 JS 加载 404
ALLOWED_HOSTS空列表 / ['*']DEBUG=False 时不配直接报错

这些配置里我一般建议优先检查STATICFILES_DIRS。这个系统的主要图表依赖 ECharts,它是纯前端库,文件放在static/js/目录下面。如果这个配置缺失,模板里{% static 'js/echarts.min.js' %}拼出来的 URL 就是坏链路,页面会白屏,而且后端日志一点报错都没有。

还有一个容易被忽略的点:SECRET_KEY不要动,它是 Django 加密会话、密码哈希的基础;DEBUG如果是False,又没配ALLOWED_HOSTS,浏览器访问时 Django 会直接拒绝请求,这是从源码包切到“生产部署模式”最典型的翻车现场。调试阶段保持DEBUG=True,把ALLOWED_HOSTS配成['*'],能省掉大量排查时间。

3. 数据链路是怎么搭的:疫情数据入库与聚合口径

3.1 数据从哪来:种子 CSV 和同步脚本

可视化系统最重要的不是前端画了几张图,而是数据进库的链路是否可靠。以这类项目最常见的形态来说,数据不会真的让你手动一条条录,包里通常会带一个data目录,里面是整理好的 CSV 文件,字段大致是:日期、省份、城市、累计确诊、疑似、治愈、死亡。

把 CSV 灌进数据库,常见的做法是写一个独立的导入脚本,放到项目根目录,用 Django 的环境入口来执行。下面这个脚本就是最通用的一种形态,你在自己项目里只需要改模型名和字段映射。

# load_csv.py —— 把 data/covid_daily.csv 导入数据库 import csv import os import django # 手动拉起 Django 环境,否则下面的 import models 会报错 os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings") django.setup() from stats.models import DailyReport # 改成你项目里的 app 名和模型名 def run(): path = os.path.join("data", "covid_daily.csv") with open(path, encoding="utf-8-sig") as f: # 注意编码用了 utf-8-sig reader = csv.DictReader(f) objs = [] for row in reader: objs.append(DailyReport( date=row["date"], province=row["province"], city=row["city"], confirmed=int(row["confirmed"]), suspected=int(row["suspected"]), cured=int(row["cured"]), dead=int(row["dead"]), )) DailyReport.objects.bulk_create(objs, batch_size=500) print(f"写入 {len(objs)} 条") if __name__ == "__main__": run()

这段代码有两个细节值得讲。第一是os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings")和django.setup(),这两行是独立脚本连接 Django 项目必备的启动步骤,少了它直接from stats.models import DailyReport会报ImproperlyConfigured。第二是encoding="utf-8-sig",Excel 另存的 CSV 文件通常带 BOM 头,用普通 utf-8 读会导致第一个字段名变成\ufeffdate,后面取row["date"]直接 KeyError。踩过这个坑的人会自然养成写utf-8-sig的习惯。

bulk_create是一次性批量插入,比循环create()快一个数量级,几万条数据也就一两秒。batch_size=500控制每次写入事务的大小,数据量不大时可以不设,但设了能让内存占用更平稳。

3.2 模型要不要做成宽表:一张 DailyReport 还是拆事实表

疫情数据可视化的核心数据无非就是“每天、每个地区有几个数”,这种数据用一张宽表就够了。很多教材会讲维度建模、事实表、维表拆分,但那是针对海量数据的数仓思路,毕业设计这个量级拆成三四张表反而给自己添乱:联表查询变多、聚合 SQL 变复杂、答辩时还要解释为什么这么设计。我见过的绝大多数正常项目,模型都长这样:

# stats/models.py —— 在 startapp 生成的 stats 应用里写模型 from django.db import models class DailyReport(models.Model): date = models.DateField(db_index=True, verbose_name="日期") province = models.CharField(max_length=32, verbose_name="省份") city = models.CharField(max_length=32, verbose_name="城市", blank=True) confirmed = models.IntegerField(default=0, verbose_name="累计确诊") suspected = models.IntegerField(default=0, verbose_name="疑似") cured = models.IntegerField(default=0, verbose_name="治愈") dead = models.IntegerField(default=0, verbose_name="死亡") class Meta: db_table = "daily_report" unique_together = ("date", "province", "city") verbose_name = "疫情日报" def __str__(self): return f"{self.date} {self.province} {self.city}"

字段选择上有几个关键点。日期用DateField而不是DateTimeField,因为疫情统计口径是按“天”来的,不需要时分秒;DateTimeField+USE_TZ=True会引入时区换算问题,后面章节会细说。db_index=True给日期加了索引,因为后续几乎所有聚合查询都按日期范围筛选,这个索引能让查询快不少。

unique_together = ("date", "province", "city")是防重复导入的关键约束。数据更新脚本如果被重复执行,同一天同一个城市会插入两遍,聚合出来的折线图就会在某一天突然冒出一个异常的“山峰”。加了联合唯一约束后,重复插入直接报错,至少让你能发现数据有问题。

3.3 ORM 聚合的正确姿势:一次查询拿到全序列

可视化接口的核心其实是聚合查询。拿“全国累计确诊趋势图”举例,逻辑是按日期分组,把所有省份当天的确诊数累加起来。新手容易犯的错是在 Python 里做循环:先取日期列表,再对每个日期查一次数据库——数据量小的时候看不出问题,数据量上百天、几千条时接口响应速度会肉眼可见地变慢。

正确的方式是让数据库完成聚合,Django ORM 一句就能搞定:

# stats/views.py —— 全国每日累计趋势的 JSON 接口 from django.db.models import Sum from django.http import JsonResponse from .models import DailyReport def national_trend(request): # 先把查询结果取到内存里,避免后面多轮循环触发重复查询 rows = list( DailyReport.objects .values("date") .annotate(confirmed=Sum("confirmed"), cured=Sum("cured"), dead=Sum("dead")) .order_by("date") ) # 数据库返回的是 date 对象,JSON 序列化不了,手动转字符串 data = { "dates": [r["date"].strftime("%Y-%m-%d") for r in rows], "confirmed": [r["confirmed"] for r in rows], "cured": [r["cured"] for r in rows], "dead": [r["dead"] for r in rows], } return JsonResponse(data)

逻辑说明:values("date")表示按日期分组,annotate里的三个Sum是每组内的聚合结果,order_by("date")保证输出按时间排序。这里最容易被忽略的是list(queryset)这一步——Django 的 QuerySet 是惰性的,如果不先转成列表,后面四次循环都会重新执行同一条 SQL,等于一次页面加载把同一个聚合查了四遍。先list()拉回内存,后面无论怎么遍历都只碰一次数据库。

strftime("%Y-%m-%d")是第二个关键点。date对象不能直接进JsonResponse,不转的话接口直接 500,日志报TypeError: Object of type date is not JSON serializable。把日期的格式化放在视图层而不是前端,是为了让接口返回的数据稳定——前端不用关心后端存的是 Date 还是 DateTime。

4. 数据可视化不玄学:从 ORM 聚合到 ECharts 图表的完整链路

4.1 图表方案怎么选:模板直出还是前后端分离

到了可视化这块,最核心的问题不是“用什么库画图”,而是“数据怎么喂给前端”。常见做法有三种:第一种是 Django 模板渲染页面,前端用原生 fetch 请求后端 JSON 接口,再由 ECharts 接管绘图;第二种是前后端完全分离,Vue/React 单独跑一套开发服务器,通过跨域请求拿数据;第三种是直接用 Django 模板的模板变量在页面里输出 JSON。

毕业设计我一般建议选第一种。它在 Django 生态内自洽,不需要跨域配置,不需要 node 环境,答辩时你既能讲后端接口设计,也能讲前端图表配置,中间的数据格式转换还可以当“难点”展开。前后端分离听起来时代感强,但面试时老师更可能追问 CORS、前端路由、打包部署,一个月内补不完这些坑。

三种方式的取舍可以参考下面这张对比:

方案环境依赖可讲性答辩风险
Django 模板 + 原生 JS + ECharts只需要 Python 环境后端和数据可视化都能讲低
Django 模板 + jQuery + ECharts只需要 Python 环境偏陈旧低
前后端分离 + Vue/React需要 node 环境前端能讲很多高,环境问题概率大

结论是别给自己挖坑,环境越少,毕业设计跑通的概率越高。原包里如果已经用了 jQuery 也无所谓,功能上没有任何区别。

4.2 一条折线图的完整链路:模板、静态文件、数据绑定

选定方案后,整条链路分四层:模板层放页面骨架和图表容器,静态文件层放 ECharts 本体,视图层返回聚合 JSON,前端 JS 层把 JSON 映射成图表的 series。先看模板:

<!-- stats/templates/dashboard.html --> {% load static %} <!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="UTF-8"> <title>疫情数据可视化分析</title> <!-- ECharts 必须用 {% static %} 标签引用,不能写死路径 --> <script src="{% static 'js/echarts.min.js' %}"></script> </head> <body> <div id="trendChart" style="width: 100%; height: 480px;"></div> <!-- 页面自己的脚本放在 echarts.min.js 之后,保证先加载库再调用 --> <script src="{% static 'js/dashboard.js' %}"></script> </body> </html>

注意{% load static %}必须写在文件最顶部,否则{% static %}模板标签会报错。图表容器div必须显式设置宽高,ECharts 在初始化时会读取容器尺寸,容器高度为 0 会导致图表渲染出来是空白,控制台还不报错,这是可视化项目里最隐蔽的白屏原因。

真正的数据绑定在dashboard.js里:

// static/js/dashboard.js —— 请求后端接口并完成折线图渲染 fetch("/api/trend/") .then(resp => resp.json()) .then(data => { // 容器 id 必须和模板里 div 的 id 一致 const chart = echarts.init(document.getElementById("trendChart")); chart.setOption({ title: { text: "全国累计确诊趋势" }, tooltip: { trigger: "axis" }, xAxis: { type: "category", data: data.dates }, yAxis: { type: "value" }, series: [{ name: "累计确诊", type: "line", smooth: true, data: data.confirmed }] }); });

fetch("/api/trend/")请求的是第 3 章那个视图对应的 URL,返回的 JSON 结构有三组平行数组:dates、confirmed、cured、dead。ECharts 的xAxis.data接收的就是类别数组,所以后端返回“日期的字符串数组”是配合得最好的格式,不需要前端再做任何转换。

smooth: true让折线变成平滑曲线,视觉上更柔和;trigger: "axis"让鼠标悬浮时按整列显示提示框,多序列对比时更好看。这些参数都是 ECharts 官方配置,改数值就能调效果,比如把line改成bar就是柱状图,同一份数据不用改接口。

4.3 日期序列化和接口设计:三个小细节

做了这么多次数据可视化,我总结出接口设计里最容易出问题的三个细节。

第一个是日期格式。后端返回日期字符串时,保持"%Y-%m-%d"这种纯文本格式,千万别返回时间戳。ECharts 的 x 轴如果收到时间戳,默认按数值轴处理,刻度分布会变得很怪;就算你把它转成时间轴,前端还得自己写格式化函数。

第二个是数据口径。接口返回的字段名要跟前端代码保持绝对一致,比如后端叫confirmed,前端就别写case,前后端各写各的最后对不上,图表上显示出来的数据全是undefined。调试时先打开浏览器开发者工具,看 Network 面板里接口返回的 JSON 字段名,再对照 JS 里的取值逻辑。

第三个是缓存。数据可视化系统里的聚合接口,每次请求都现算一次全表,数据量到几十万条时响应就会慢。开发阶段无所谓,但演示时如果每次都卡几秒,观感很差。常见的做法是在视图上直接加 Django 的缓存装饰器,这个放到最后一章细讲。

5. 避坑清单:六个让系统“跑不起来”的配置与代码问题

5.1 migrate 报 relation already exists

现象:第一次执行python manage.py migrate就报relation "auth_user" already exists,或者迁移执行到一半中断。

原因:项目包里自带了db.sqlite3文件,数据库里已经有一份完整的表和数据。迁移文件检测到表已存在,和迁移记录对不上,就会中断。

解决:备份旧数据后删除db.sqlite3,重新执行migrate。如果不想删数据,就跳过 migrate 直接runserver,但要清楚你现在连的是旧库。最彻底的验证方法是把数据库文件删掉、迁移文件保留,重新走一遍全流程,这样能顺便测试“干净机器上能不能跑通”。

5.2 ECharts 页面白屏,控制台报 404

现象:页面打开后图表区域空白,浏览器开发者工具的 Console 报GET /static/js/echarts.min.js 404,后端日志没有任何异常。

原因:STATICFILES_DIRS没有配置,或者 ECharts 文件没有放在static/js/目录下。Django 开发服务器默认只从每个 app 的 static 目录找静态文件,项目根目录的 static 不算数。

解决:在 settings.py 里显式声明根目录:

import os STATIC_URL = "/static/" STATICFILES_DIRS = [ os.path.join(BASE_DIR, "static"), ]

改完重启runserver,重新加载页面。这个问题的迷惑性在于页面本身能打开,只有图表区域是空的,而且后端日志完全干净,属于典型的“前端问题,后端无感知”。

5.3 CSV 表头第一列变成 \ufeffdate

现象:执行导入脚本报KeyError: 'date',打印字段列表发现第一个键是\ufeffdate。

原因:Excel 另存的 CSV 是 UTF-8 with BOM 编码,BOM 字节被 Python 的 csv 模块读成了字段名的一部分。这个现象在 Windows 上尤其常见,直接打开 CSV 看不出任何问题。

解决:open()时用encoding="utf-8-sig",这个参数会告诉 Python 自动剥离 BOM 头。如果项目里已经用了open(path, encoding="utf-8"),把编码改掉就行。顺带一提,从 Excel 导出的数据最好检查一下“城市”列有没有尾随空格,否则unique_together可能因为"武汉"和"武汉 "被认为是两条不同数据而失效。

5.4 折线图上某天突然出现一座“山峰”

现象:全国趋势图整体平滑,但某一天的数据突然比前后高出一大截,数值恰好是正常值的两倍左右。

原因:数据导入脚本执行了两次,同一天同一个城市的数据被插了两遍,聚合求和时被重复计算。如果数据量是真实的两倍,说明整个表被重复导入;如果只有个别城市异常,往往是脚本中断后重新执行导致的重复插入。

解决:模型层加unique_together只是兜底,真正的修法是把导入逻辑改成“有则更新,无则创建”:

DailyReport.objects.update_or_create( date=row["date"], province=row["province"], city=row["city"], defaults={ "confirmed": int(row["confirmed"]), "suspected": int(row["suspected"]), "cured": int(row["cured"]), "dead": int(row["dead"]), } )

update_or_create的查找条件有三个字段:日期、省份、城市,这三个字段能唯一定位一行数据;defaults里放的是要更新的数值字段。脚本重复执行时,只会更新对应数据,不会新增记录。这是数据同步类脚本的标准写法,比“先 delete 再 create”安全得多。

5.5 日期显示总是“少一天”或“多一天”

现象:折线图横轴最后一天显示的是昨天,或者某个日期的数据跑到了前一天的位置上。

原因:很可能模型用了DateTimeField,同时又开着USE_TZ=True。Django 存数据库时会按 UTC 时间转换,查询出来再转回本地时区,日期的“天”边界就错位了。如果后端返回的是带时区的 ISO 字符串,前端解析时还会再偏移一次,问题叠加后大部分图都对不上。

解决:疫情数据是“按天”的统计口径,模型直接用DateField就能从根上避掉这个问题。接口返回时统一用strftime("%Y-%m-%d")生成纯字符串,前端不做任何时间对象转换,直接给 x 轴用。这条规则适用于所有日期型图表,别让“时间数据”在前后端之间传来传去,谁转换谁出问题。

5.6 自己代码没问题,部署到别的机器上启动报错

现象:项目在自己的电脑上跑得好好的,拷到答辩机器上python manage.py runserver启动失败,报的是 Python 解释器或依赖相关的错误。

原因:目标机器上的 Python 版本和项目开发环境不一致,或者根本没有安装项目依赖。最常见的场景是目标机器装了 Python 3.6,requirements.txt 里要求的 Django 4.2 只支持 Python 3.8 以上,装都装不上。

解决:与其现场折腾,不如直接准备一个可交互的迁移方案。到答辩机器上先python --version确认版本,再依次装依赖。经验之谈是:不要在答辩前最后一晚干这件事,提前至少一天把项目拷到目标机器上完整跑一遍,问题早暴露早解决。这类问题的坑不在技术难度,而在预演不充分。

6. 从“能跑”到“敢答辩”:数据验证与演示彩蛋

页面能打开、图表能显示,这只是项目的一半。真到了答辩,老师最常见的做法是随便指着一个数字问你“这个数怎么算出来的”。所以我把最后一章放在验证方法上,这也是我自己做项目时最容易忽略、后来吃亏最多的地方。

验证思路很简单:准备一组已知的测试数据,插入数据库后手工计算预期值,再和页面显示的数字对比。具体操作分三步。第一步,把数据库重置成干净状态,删掉旧库、重新 migrate、重新导入原始 CSV,保证数据来源可追溯。第二步,抽查最近三天的数据,用数据库查询语句单独算一遍总和,比如执行SELECT date, SUM(confirmed) FROM daily_report GROUP BY date ORDER BY date DESC LIMIT 3;,和页面图表上的值逐一对比。第三步,验证接口返回的 JSON 和数据库聚合结果一致——直接访问/api/trend/,把结果复制到文本编辑器里核对几个关键节点。这一步做到位,“这段数据是不是你自己跑出来的”这种问题就能答得理直气壮。

验证脚本也有一个简单的版本可以放在项目里:

# verify_data.py —— 抽查数据库聚合值与页面数字是否一致 import os import django os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings") django.setup() from django.db.models import Sum from stats.models import DailyReport # 数据库聚合作为“标准答案” total = DailyReport.objects.aggregate(s=Sum("confirmed"))["s"] print(f"数据库累计确诊总数: {total}") # 按日期抽查,找最近三天 latest_three = ( DailyReport.objects.values("date") .annotate(day_total=Sum("confirmed")) .order_by("-date")[:3] ) for row in latest_three: print(row["date"], row["day_total"])

脚本打印出的数字和页面折线图最后一截做对比,吻合就说明数据链路是完整的。这里不需要额外工具,一个print就够了。

进阶一步,给聚合接口加缓存。数据量增长后,每次请求都全表聚合会很浪费,Django 自带的缓存装饰器一行就能解决:

from django.views.decorators.cache import cache_page @cache_page(60 * 5) # 缓存 5 分钟 def national_trend(request): # 视图内部代码不变,依然走 ORM 聚合 pass

cache_page的参数是缓存秒数,60 * 5就是 5 分钟。加了这个之后,5 分钟内的重复请求直接读缓存,不再查询数据库。开发环境默认用的是本地内存缓存,演示场景已经够用,不需要额外配置 Redis。

答辩演示的彩蛋,我的个人习惯是准备三个“对比视角”:全国趋势图、省份累计排行、最近一周环比变化。前面的折线图解决了全国视角,排行可以做成横向柱状图,环比变化可以用 ECharts 的双 Y 轴,三张图共用同一个/api/trend/数据源,只是前端setOption的配置不同。这样给老师展示的不只是“画了几张图”,而是“同一份数据用不同维度展开”。

最后说一句做这类项目的个人习惯:拿到任何一个可视化源码包,我第一步永远是删库、重新导入、重新跑一遍,确认它在一台干净的机器上能活过来。这个过程逼着我把数据的来龙去脉过一遍,心里有数,答辩才能讲得稳。希望这条经验能帮到你,少走点我当时走过的弯路。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询