ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Flask+Vue+SQLite家电维修系统实战:前后端分离设计与避坑指南

2026/9/26 5:14:56 拓冰建站 浏览量
Flask+Vue+SQLite家电维修系统实战:前后端分离设计与避坑指南 先说一个实话看到“基于 flask 与 django”这种标题组合我第一反应是——这兄弟俩一起出现大概率是课程设计或者毕业设计的需求描述写标题的人想表达“我用 Python 做后端、用 Vue 做前端、用 PyCharm 当开发工具”至于 Flask 和 Django可能自己也没完全想清楚到底要用哪个。这篇博客我就按一个真实项目的落地思路来写用 Flask 做后端服务Vue 做前端页面PyCharm 做开发调试数据库用轻量级的 SQLite最终交付一个可以本地直接跑起来的家电维修服务系统。这套系统要解决的场景很清晰用户家里电器坏了在线提交报修单维修工接单、上门、维修、提交结果管理员负责派单和整体调度用户最后可以对维修服务做评价。听起来简单但真正实现的时候会踩不少坑比如前后端联调时跨域、报修单状态流转设计、角色权限控制、中文数据编码、图片上传返回相对路径等等。这篇博客会把整个设计和实现过程拆开来讲包括数据模型怎么设计、API 怎么规划、Vue 页面怎么写、Flask 路由怎么组织、联调时遇到的坑和应对办法。不管你是刚开始做 Flask 项目的新手还是想给自己的毕设找个完整参考这篇文章都值得花十分钟看完。1. 技术选型与方案取舍1.1 为什么选 Flask 而不选 Django先说结论不是 Django 不好而是对于这种“业务逻辑以自定义 API 为主、前端完全交给 Vue 处理”的项目Flask 更轻、更直接。Django 的优势是全家桶自带 Admin 后台、内置 ORM、有完整的用户认证体系但代价是框架本身比较重很多约定需要遵守学习曲线也更陡。Flask 相反它只提供路由、请求响应、模板渲染这些最基础的能力其他的自己配或者不配都行自由度非常高。我在实际开发里的感受是Flask 的路由和视图函数之间的关系非常直白。你在app.py里写一个路由浏览器访问这个地址就执行对应的函数返回 JSON 或者 HTML 页面。这种“一翻代码就能看懂全局”的感觉对于课程设计来说特别友好。而 Django 的 MTV 分层对新手来说容易搞不清数据到底是怎么从 Model 流到 Template 再到 View 的。项目标题里同时出现 Flask 和 Django我自己在实现时会明确选择 FlaskDjango 仅作为对照思考如果换用 Django管理后台和用户认证能省不少事但自定义 API 的需求会让 Django 的序列化和跨域配置反而更繁琐。对比维度FlaskDjango上手难度低一个文件能跑通较高工程结构固定内置功能少而精需自配全而重开箱即用API 开发体验简洁灵活需要 DRF 扩展Admin 后台无可自写自带强大后台适合场景轻量服务、API、小中型系统内容管理、大型应用1.2 前后端分离还是服务端渲染这也是一个很关键的取舍点。Flask 本身支持 Jinja2 模板渲染你完全可以像传统 Web 开发那样在后端拼 HTML 页面返回给浏览器。但我强烈推荐在当前这个项目里选择前后端分离后端只提供 JSON 接口前端用 Vue 负责所有页面的渲染和交互。原因很简单——家电维修系统有大量动态交互场景比如报修单列表的筛选、状态标签的切换、派单弹窗、评价表单用 Vue 的响应式数据驱动比后端拼模板舒服太多。前后端分离还带来一个额外的好处调试成本低。后端接口用 Postman 或者浏览器直接测前端页面用npm run dev启动两边各自开发互不干扰。我见过很多同学把代码写成一堆render_template()最后改个按钮样式都要翻后端代码真的很痛苦。1.3 开发工具与运行环境准备开发工具建议用 PyCharm原因不需要太复杂虚拟环境管理、数据库插件、断点调试、Flask 运行配置都是开箱即用。在 PyCharm 里新建一个项目选择虚拟环境然后安装依赖是最稳妥的流程。依赖清单不多核心的就这几个pip install flask flask-cors flask-sqlalchemy pip install jieba # 用于智能派单的关键词分词Vue 前端的话用 Vite 和 Vue3 的组合。Node 环境装好之后执行npm create vitelatest repair_front -- --template vue cd repair_front npm install npm install element-plus axios2. 系统设计与数据模型2.1 用户角色与业务流程梳理家电维修服务系统的核心不是“写代码”而是把业务流程理清楚。我把它拆成三个角色、四条核心流程。三个角色分别是普通用户、维修工、管理员。用户从小程序或者网页端发起报修填写家电类型、故障描述、期望上门时间、联系电话管理员在后台看到新报修单按照故障类型指派维修工维修工收到派单后先电话联系用户确认时间后上门维修维修完成在系统里填写维修结果和费用用户对维修过程进行评价整个工单流程才算闭环。这四条流程里最关键的是“报修单状态”的设计。如果状态设计得不好后面所有页面都会跟着乱。2.2 数据表设计与状态流转数据库用 SQLite 就够了不需要单独安装 MySQL。SQLite 是轻量级文件型数据库对于毕业设计这种量级的系统完全够用而且复制整个项目目录就可以迁移数据非常香。核心数据表我设计了四张用户表、维修工表、报修单表、评价表。用户表和维修工表本质上都是“人员表”我这里做成分开的两张表是因为维修工有技能标签、接单量这些额外字段混在一起会让模型变臃肿。报修单表是核心状态字段用数字表示在代码里用常量维护。核心的表结构大致是这样表名关键字段说明userid, username, password_hash, phone, address普通用户workerid, name, phone, skills, workload维修工skills 存技能标签repair_orderid, user_id, worker_id, category, description, address, status, create_time, finish_time报修单主表commentid, order_id, user_id, rating, content, create_time评价表报修单的status我用 0 到 4 五个数字表示0 待派单、1 已派单、2 维修中、3 已完成、4 已评价。这里要特别注意一点状态只能单向流转不要允许任意跳转。我在后端的业务逻辑里强制判断比如只有已派单状态才能改为维修中已完成不能重新改回待派单。这是我实际开发中踩过大坑之后才加上的约束没有状态校验的时候前端误操作或者接口被调用很容易把数据改成一团乱麻。2.3 智能派单的关键词匹配逻辑智能派单是这个系统里最有技术含量的部分。实现思想不算复杂用户提交故障描述时用jieba分词提取关键词维修工注册时填写的skills字段也按同样的方式分词然后计算两者的相似度相似度最高的维修工作为推荐派单对象在管理员的派单页面按照分数从高到低排序。from jieba import lcut def calc_similarity(desc, skills): desc_words set(lcut(desc)) skill_words set(lcut(skills)) if not desc_words or not skill_words: return 0.0 return len(desc_words skill_words) / len(desc_words | skill_words)这段代码用 Jaccard 相似度思路是“交集越大、并集越小相似度越高”。比如用户描述“冰箱不制冷冷冻室温度偏高”分词后是{冰箱, 不, 制冷, 冷冻, 室, 温度, 偏高}而某个维修工的技能标签是{冰箱, 维修, 制冷}交集有“冰箱”“制冷”两个词并集总共有八个词相似度就是 0.25。实际可以再加权重或者同义词映射表比如“不制冷”和“制冷故障”归一为同一类。效果虽然不是 AI 级别的智能但在本地部署的轻量化系统里足够用而且解释性好。3. 后端 Flask 核心实现3.1 工程结构与配置管理Flask 项目不要把所有代码都堆在app.py里即使课程设计也建议把工程划分清楚。我的目录结构长这样repair_system/ ├── app.py # 入口文件注册蓝图 ├── config.py # 配置项 ├── models.py # 数据模型 ├── api/ │ ├── auth.py # 登录注册 │ ├── order.py # 报修单 │ ├── worker.py # 维修工 │ └── admin.py # 管理员派单 ├── utils/ │ └── match.py # 相似度算法配置项放在独立文件里好处是改端口、数据库路径、密钥时不需要翻主文件。我习惯在config.py里放一个基类未来如果需要跑在服务器上可以再维护生产配置当然当前只是本地部署一个文件足矣。class Config: SECRET_KEY your-secret-key SQLALCHEMY_DATABASE_URI sqlite:///repair.db SQLALCHEMY_TRACK_MODIFICATIONS False3.2 核心 API 设计与实现API 设计遵循一个原则按资源划分按动作定义。报修单资源的核心接口是这样规划的方法路径功能角色POST/api/register用户注册匿名POST/api/login登录获取 token匿名POST/api/orders创建报修单用户GET/api/orders/my我提交的报修单用户GET/api/orders/pending待派单列表管理员POST/api/orders/assign指派维修工管理员POST/api/orders/progress开始维修维修工POST/api/orders/complete完成维修维修工POST/api/orders/comment评价工单用户创建报修单的核心代码并不复杂但要注意几个点一是状态初始值必须是 0二是从登录用户的 token 里解析 user_id不要相信前端传过来的用户 ID三是创建成功后返回完整对象省去前端再查一次。app_api.route(/api/orders, methods[POST]) def create_order(): data request.get_json() user_id g.user_id order RepairOrder( user_iduser_id, worker_idNone, categorydata.get(category), descriptiondata.get(description), addressdata.get(address), status0 ) db.session.add(order) db.session.commit() return jsonify(order.to_dict()), 2013.3 登录鉴权与权限控制登录这块我不用flask-login而是用最简单的itsdangerous生成 token。itsdangerous是 Flask 自带的依赖不需要额外安装它的URLSafeTimedSerializer能把用户 ID 加密成一段字符串客户端保存这个字符串每次请求放进请求头Authorization后端解析出来就知道是谁。def generate_token(user_id): s URLSafeTimedSerializer(app.config[SECRET_KEY]) return s.dumps({user_id: user_id}) def parse_token(token): s URLSafeTimedSerializer(app.config[SECRET_KEY]) data s.loads(token, max_age86400) return data[user_id]权限控制我在before_request钩子里统一处理。比如/api/orders/assign必须先校验登录用户的角色是管理员否则一律返回 403。这个思路和 Django 的 RBAC 是类似的只是没必要为此引入一套完整的权限框架用装饰器加一个角色判断就足够。4. 前端 Vue 页面与交互4.1 Vue3 工程搭建与目录组织Vite 创建出来的 Vue3 项目默认结构很干净我在此基础上做了简单的模块划分src/api放 axios 请求封装src/router放路由配置src/views按角色分目录。这里给新手一个建议尽量把所有 axios 调用都集中到api/目录里不要在组件里直接写axios.get。集中管理的好处是后端接口地址变了只需要改一个文件登录 token 也可以统一在拦截器里挂载。4.2 页面结构与核心组件拆解系统需要的主要页面如下可以使用一个侧边栏布局来承载登录/注册页用户端提交报修单、我的报修单列表、评价弹窗维修工端我的工单、维修进度更新管理员端待派单列表、派单弹窗、数据分析面板这里我详细讲讲“提交报修单”页面的实现。表单字段有家电类型下拉选择、故障描述文本域、联系地址和联系电话。Element Plus 的el-form自带校验可以在前端先挡掉一批不合格数据比如电话格式不对、描述少于十个字不要等提交到后端再返回错误。故障描述这块我还做了个交互小优化用户输入描述后前端自动调用后端的/api/match/worker接口实时显示“可匹配的维修工技能标签”虽然对用户没什么用但对管理员派单时有参考价值。这其实就是把后端那个相似度算法暴露成一个接口前端调一次就能拿到匹配建议。4.3 前后端联调与跨域问题前后端联调第一个遇到的就是跨域。Flask 默认只允许同源请求Vue 开发服务器的地址是http://localhost:5173Flask 是http://localhost:5000两个端口不同浏览器就会拦截响应。解决办法很简单后端安装flask-cors然后注册到应用上from flask_cors import CORS CORS(app, resources{r/api/*: {origins: *}})开发阶段把origins设成*没问题生产环境要收紧成具体域名。这个配置我踩过坑有段时间前端一直报 CORS 错误怎么调都不行最后发现是请求头里带了自定义的Authorization需要在 CORS 配置里加allow_headers[Authorization, Content-Type]。4.4 Vue 课程中经常被问到的几个细节很多人学 Vue 的时候会被“组件间传值”搞晕。在这个项目里我的经验法则是能用props就尽量用props子组件要修改父组件数据时通过$emit触发事件。那种“通过全局事件总线实现任意组件通信”的做法项目小的时候用着爽项目一复杂就容易不知道数据从哪来、改到哪去。另外如果用了 Vue Router页面跳转前需要判断用户角色就在路由守卫里写逻辑不要在每一个页面重复判断这样维护起来最省心。5. 联调、部署与高频问题排查5.1 PyCharm 里的运行与调试配置Flask 项目在 PyCharm 里运行方式很简单但我建议不要直接右键运行app.py而是专门配一个 Flask 运行配置。具体操作点击右上角下拉框选择 Edit Configurations新增一个 Flask Server 配置Target Type 选 Script path指向app.pyEnvironment variables 里加FLASK_ENVdevelopment和FLASK_DEBUG1。调试的时候断点可以打在 API 函数里用 Postman 发请求触发然后在 PyCharm 里按 F8 单步看变量。PyCharm 的调试器对 Flask 支持得很好数据库 Session 里的对象也能直接展开看字段排查数据问题非常方便。5.2 本地网络的手机访问测试系统实现完如果要给老师演示或者自己拿手机测需要让 Flask 监听非本机地址。运行参数改成flask run --host0.0.0.0 --port5000这样同一局域网内的手机可以通过电脑的局域网 IP 访问后端接口。对应地Vue 前端开发服务器也可以配置server.host: true允许局域网访问。有一点要注意手机访问的时候localhost不能直接用axios 的 baseURL 必须写成http://电脑的局域网IP:5000。5.3 高频问题与避坑清单我整理了一份实际操作中遇到过的高频问题速查表这些坑基本属于“教程里不写但十有八九会碰见”的类型。问题现象原因分析解决办法前端请求返回 404路由路径写错或者少了/api前缀检查 Flask 路由装饰器和 axios 的 url 是否一致返回的日期时间格式奇怪SQLite 日期字段被序列化成字符串在to_dict()中手动format_datetime中文乱码前后端编码不一致Flaskapp.config[JSON_AS_ASCII] False数据库锁错误多线程同时操作 SQLiteSQLite 连接加check_same_threadFalse或改用 WAL 模式Vue 页面刷新后 404前端路由为 history 模式改成 createWebHashHistory 或后端兜底图片上传后路径加载不出来静态目录配置不对使用app.send_static_file或配置static_folder这里重点说说 Vue 路由刷新 404 的问题。开发的时候没问题但如果把前端打包后的文件挂到 Flask 下托管刷新子路由就会找不到页面。因为 Flask 并不知道前端内部的路由规则刷新/user/orders时 Flask 会去找这个路径对应的视图函数找不到就 404。最简单的解法是把 Vue 路由改成 Hash 模式也就是createWebHashHistoryURL 变成/#/user/orders这就不会影响后端路由。要省事就别去折腾 history 模式的重写规则本地跑通最重要。另一个容易被忽略的坑是render_template和 API 返回的响应类型不一致。我见过有些代码在同一个路由函数里根据条件有时候返回 JSON、有时候返回render_template结果前端拿到的是 HTML解析 JSON 时报错。统一策略是凡是/api/开头的路由只返回 JSON页面渲染走 Vue后端永远不要混用。还有一个关于 PyCharm 的小技巧。很多同学会遇到“为什么我改了代码页面没有变化”的问题原因大概率是 Flask 没开 Debug 模式或者 PyCharm 运行配置里没有勾选FLASK_DEBUG1。Flask 的自动重载依赖 watchdog在虚拟环境里偶尔会失效这时候手动重启 Flask 是最快的不要浪费时间在找自动重载的配置上。5.4 安全与规范层面的几个注意点虽然这是课程设计级别的系统但用户密码不能明文存储。我直接用werkzeug.security提供的generate_password_hash和check_password_hash这是 Flask 自带的工具没必要自己写哈希算法。另外由于前端和后端分离后端的接口无法通过 CSRF 中间件自动保护但好在我们用了 token 鉴权只要 token 不过期、不泄露安全性基本可控。关于用户输入这块Jinja2 模板引擎有自动转义但我们用的是前后端分离Vue 默认也会转义插值所以 XSS 风险相对低。但如果后端接口里把用户输入原样返回并且前端用v-html渲染就要小心了。我的建议是所有用户输入的文本前端一律用{{ }}插值展示不要用v-html这个地方其实也是之前看搜索词里提到 flask ssti 时特意留了注意力别让自己的接口变成模板注入的入口能省掉很多麻烦。5.5 数据看板与系统演示的小建议如果期末答辩需要演示我强烈建议管理员端加一个最基础的数据看板页面用 Element Plus 的el-statistic或echarts展示报修单总数、待派单数量、各故障类型占比。实现起来并不复杂后端加一个聚合查询接口app_api.route(/api/admin/stats, methods[GET]) def admin_stats(): total RepairOrder.query.count() pending RepairOrder.query.filter_by(status0).count() return jsonify({total: total, pending: pending})演示效果会明显好很多因为评审最关心的是系统的实际使用情况和数据闭环。看板不需要复杂能说明系统跑得通、有数据流转就够了。我个人在做这套系统时最大的体会是这一类“设计与实现”项目的难度不在某一个单独的技术点而在于把所有模块串起来的时候交界面上的问题最多。Flask 到 Vue 的跨域、Vue 到后端的字段约定、SQLite 到序列化的类型转换每一条都是一层“胶水”胶水打好了系统运行很顺胶水出了岔子前面再好的设计都会变成一段段孤单的代码。如果你也在做类似的系统建议先按角色把页面和数据模型画下来再动手写后端接口最后接前端这条路是最省时间的。最后再分享一个小技巧接口字段命名前后端要事先对齐比如统一用order_id还是orderId强烈建议统一用下划线风格因为 Python 这边处理下划线字段天然方便前端对象转接时只需写一个transform函数集中转换别在几十个组件里到处替字段改名这是我栽过跟头之后养成的习惯。