资讯详情

资讯详情

基于Flask的医院综合管理系统开发全流程解析

1. 项目全貌这到底是个什么系统如果你拿到的是一个这样的需求一家医院的信息化管理系统要管医生、管患者、管床位、管药品、管挂号、管检查、管费用甚至还要出统计报表——你脑海里第一反应是什么我当时的反应是这不就是把一家医院从门诊到住院再到药房的全流程塞进一个Web系统里吗“python基于flask的安康医院综合管理系统”就是干这个的。它基于Python语言后端用Flask框架标题里也提到了Django这个我后面单独说前端配合Vue整个系统跑在PyCharm这个IDE里开发。说白了这是一个典型的前后端分离的Web信息管理系统业务场景锁定在中小型医院核心目标就是把医院的日常运营数字化。这系统解决的是什么问题说白了三件事纸质病历满天飞、找张处方要翻半小时柜子的问题挂号、收费、药房、检验科各自为政数据对不上账的问题管理者想看看本月门诊量、收入构成只能让手下加班统计的问题。适合谁来学如果你是计算机相关专业正在做毕业设计的学生这题目非常典型覆盖面广、技术栈通用、演示效果好如果你是刚入门Web开发想找一个完整项目练手的开发者它也比那些烂大街的“学生管理系统”高出不少段位甚至如果你是个小诊所/社区医院的IT管理员想给单位搞一套轻量信息化系统这套设计思路也能直接借鉴。标题里有个“功能多”这真不是虚的。一个完整的医院管理系统按我的拆解至少要覆盖六大模块模块核心功能对应角色门诊管理挂号、分诊、门诊病历、处方录入前台、医生住院管理入院登记、床位分配、医嘱执行护士站、住院医生药品管理药品入库、库存预警、出库记录药房管理员检查检验检查单开具、结果录入与查询检验科收费管理门诊收费、住院结算、退费收费员系统管理用户权限、角色分配、操作日志系统管理员这六块做好了医院的核心闭环就串起来了。开发工具我推荐直接用PyCharm Professional它对Flask的支持非常友好——可以一键创建Flask项目、直接配置Run Configuration、自带的数据库插件能可视化看SQLite/MySQL数据调试断点打在视图函数里非常顺手。社区版虽然也能写但体验差不少。2. 技术选型Flask和Django同时出现怎么选标题里同时出现Flask和Django这个词挺有意思。很多初看到这个项目的人会问到底是Flask还是Django我的答案很直接主用FlaskDjango是选型时被对比掉的那个选项。但如果你去搜这个项目的完整源码也有不少版本是Django写的——这其实是个典型的“教程标题合并”现象两个关键词都被塞进去了实际落地时可以任选一套。但这两者怎么选确实值得把逻辑讲透因为这是项目一开始的地基决策。2.1 Flask赢在哪Flask的核心哲学是“微内核可扩展”。它本身只提供路由、请求响应、模板渲染这几样最基础的能力像ORM、表单校验、后台管理这些全靠扩展插件来补——SQLAlchemy管数据库Flask-Login管登录态Flask-Migrate管表结构迁移。这种“需要什么装什么”的模式让一个中小型医院系统完全可以在一个轻量框架上优雅地跑起来。对比来看Django是“全家桶”——自带Admin后台、自带ORM、自带用户认证、自带模板系统开发速度确实快但它有两个问题一是框架太重对中小项目的灵活度限制比较大二是Django的Admin后台确实强大但默认风格一眼就能被看出来是Django生成做演示或交付时“痕迹感”太重。还有一个很实在的原因很多课设、毕设项目的技术栈要求里白纸黑字写着Flask评分的老师看技术选型看到FlaskVue这套主流组合印象分天然高一些。2.2 前端为什么用Vue而不是服务端渲染这个问题我同样被问过无数次。Flask自带的Jinja2模板可以服务端渲染页面一套代码搞定前后端开发量小一半为什么非要用Vue搞前后端分离我的理由有两条都是实操中真实遇到过的。第一是交互复杂度。医院系统的表单不是那种“提交一下就行”的简单表单。挂号时要实时联动医生排班表开处方时要动态增删药品明细行住院结算时费用明细需要实时汇总——这些都是典型的“前端状态管理”场景。你用Jinja2模板写写看每次数据变化都要刷新整个页面患者信息刚填完一刷新床位没了体验非常糟糕。Vue的响应式数据绑定解决的就是这类高频交互问题。第二是分工与扩展性。前后端分离后后端API可以同时服务于Web端和未来的移动端App。医院系统做到后期领导十有八九会问“能不能做个手机端看看数据”要是当初用模板渲染基本等于推倒重来要是后端只有Flask API前端直接用Vue写一套移动端适配页面就行工作量小得多。2.3 PyCharm里的环境搭建这个环节看着基础却是我见过翻车最多的地方。很多同学拿到项目在PyCharm里一跑就报错99%是环境问题。这里给一套稳定不踩坑的流程第一步用虚拟环境别用全局环境。PyCharm新建项目时选择VirtualenvPython解释器选3.8或3.10别用3.12有些Flask老插件兼容性翻车。第二步依赖安装用requirements.txt核心依赖如下flask2.3.3 flask-sqlalchemy3.0.5 flask-cors4.0.0 flask-login0.6.2 flask-migrate4.0.5 pymysql1.1.0 cryptography41.0.7这里有个关键细节flask-sqlalchemy的3.x版本和2.x版本在db.init_app和模型定义方式上完全不同网上很多老教程写的是2.x写法照着抄必报错。所以我强烈建议直接锁定上述版本号别用默认的最新版。第三步在PyCharm里配置Run Configuration将Flask项目的启动入口指向app.py环境变量里设好FLASK_APPapp.py和FLASK_ENVdevelopment这样点一下绿色三角就能跑起来。注意创建Flask项目时PyCharm Professional版自带“Flask”项目模板它会帮你生成app.py和静态目录社区版没有需要手动创建。无论用哪个版本建议统一用“纯Python项目 手动创建Flask结构”的方式因为你后面要前后端分离PyCharm自带的模板里很多用不上。3. 数据库设计医院的业务闭环一张表都不能少坦诚讲数据库设计是这类管理系统的灵魂。你代码写得再花哨表结构设计不合理后面联调阶段就全是泪。医院管理系统的数据库设计核心原则就一句话围绕“人”和“钱”两条线展开。“人”的线是患者从挂号开始 → 看诊 → 开检查 → 取药 → 可能住院 → 出院“钱”的线是挂号费 → 检查费 → 药费 → 住院费 → 结算退费。两线交叉的点就是每一笔业务记录。3.1 核心表结构拆解我这里给出一个实际运行过的最小可用表设计共12张表按模块分组用户与权限侧user主键id、用户名、密码存密码哈希、姓名、角色admin/doctor/nurse/pharmacist/cashier/registrar、创建时间role与permission做RBAC权限控制角色关联菜单权限门诊侧patient患者基本信息姓名、性别、身份证号、手机号、过敏史、既往病史registration挂号记录关联patient_id、doctor_id、挂号类型普通/专家、挂号费、状态待诊/就诊中/已完成、挂号时间medical_record门诊病历关联registration_id、主诉、现病史、诊断结果、处理意见医嘱住院侧bed床位信息床位号、所属科室、状态空闲/占用/维修admission住院登记关联patient_id、床id、入院时间、入院诊断、主治医生、预计出院时间hospitalization_charge住院费用明细关联admission_id、费用项、金额、产生时间药品与检查侧drug药品信息药品名、规格、生产厂家、进价、售价、库存量、预警库存prescription_item处方明细关联medical_record_id、drug_id、数量、用法、用量examination检查项目表项目名、价格、参考范围examination_order检查申请单关联patient_id、examination_id、申请医生、结果值、结果描述、状态这12张表覆盖上面说的六大模块删掉任何一张业务流程都会断。比如你不想做住院管理觉得“这不是重点”那你床位信息就没地方挂而床位使用率往往是医院管理者最关心的数据之一——所以省什么都别省表。3.2 一对多与多对多关系梳理表关系设计的关键点归纳下来就这几条患者与挂号记录是一对多——一个患者可以多次挂号但患者主档案只存一次。所以patient表里不要放任何“最近挂号时间”这种冗余字段通过关联查询去拿。挂号记录与门诊病历是一对一——一次挂号对应一份病历。这里用registration_id做外键并加unique约束。病历与处方明细是一对多——一份病历可以开多行药品所以处方明细是子表外键指向病历表。检查申请与检查项目是一对多——一个申请单可以包含多个检查项目。一个常见误区有人喜欢在一张“处方表”里用逗号分隔存多个药品ID比如drug_ids: 1,3,5,7。这种设计在单体Demo里看似省事但你要做药品库存扣减、费用汇总时就会疯掉——你得先把字符串切开再逐条处理。关系型数据库的正确做法是永远用中间表或明细表一行一条数据别怕“表多”表多不丢人查询方便才是王道。3.3 用SQLAlchemy建模的核心代码Flask里操作数据库默认选择是Flask-SQLAlchemy。以“挂号记录”为例模型定义如下from datetime import datetime from extensions import db class Registration(db.Model): __tablename__ registration id db.Column(db.Integer, primary_keyTrue, autoincrementTrue) patient_id db.Column(db.Integer, db.ForeignKey(patient.id), nullableFalse) doctor_id db.Column(db.Integer, db.ForeignKey(user.id), nullableFalse) reg_type db.Column(db.String(20), nullableFalse, default普通) fee db.Column(db.Numeric(10, 2), nullableFalse, default0.00) status db.Column(db.String(20), nullableFalse, default待诊) reg_time db.Column(db.DateTime, defaultdatetime.now) patient db.relationship(Patient, backrefregistrations) doctor db.relationship(User, backrefreg_records)两处值得多说两句一是fee字段用Numeric(10, 2)而不是Float。原因是Float存小数时有精度误差0.1 0.2可能等于0.30000000000000004。钱的事情精度差一分钱对账时都让人崩溃。二是relationship加backref后你就可以用patient.registrations直接取到某个患者的所有挂号用起来非常顺手。但注意别给同一个模型重复定义指向同一张表的多个relationship而不指定foreign_keysSQLAlchemy会报“could not determine join condition”的错解决方案是显式声明外键。3.4 数据库迁移与初始化数据开发阶段改表结构不要手动去数据库里“改字段”用Flask-Migrate做迁移版本管理flask db init flask db migrate -m init tables flask db upgrade每次改了模型重复后面两步数据库就会自动同步。这比手工执行SQL安全得多也方便你随时回退到上一个版本。初始化数据同样重要——我建议写一个init_data.py脚本一次性插入管理员账号、科室信息、药品目录、床位数据。因为如果每次换个环境部署你都要手动录一层数据来测试效率太低了。脚本形式类似def init_data(): admin User(usernameadmin, passwordgenerate_password_hash(admin123), roleadmin) db.session.add(admin) for i in range(1, 51): bed Bed(bed_nof301-{i}, department内科, status空闲) db.session.add(bed) db.session.commit()4. 后端接口设计用REST风格把业务能力暴露出去Flask后端在这个项目中扮演的角色是纯API服务——不返回HTML页面只返回JSON数据。前端Vue通过axios调用这些接口拿到数据后自己渲染。4.1 接口的命名规范与统一返回格式接口路径设计遵循REST风格资源用名词复数HTTP方法对应操作方法路径功能POST/api/login登录GET/api/patients患者列表分页POST/api/patients新增患者GET/api/patients/3查看id为3的患者详情PUT/api/patients/3更新患者信息DELETE/api/patients/3删除患者GET/api/registrations?doctor_id5按医生查询挂号记录GET/api/stats/outpatient门诊统计报表统一返回格式是前后端联调的关键。我见过最乱的接口就是有人一会儿返回{code:200, data:...}一会儿直接返回数组前端判断逻辑绕来绕去。这里直接抄作业{ code: 200, message: success, data: {} }错误时code换成400/401/403/500message写明原因。前端统一做拦截所有接口的返回结构一致联调时能省一半精力。4.2 蓝图模块化避免把十个模块写成一座大平房Flask新手最容易犯的错是把所有路由写在一个app.py里三千行代码糊一坨后期找改一个功能点翻半天。解决办法是用蓝图Blueprint做模块化拆分。项目结构推荐这样hospital/ ├── app.py # 应用入口注册蓝图 ├── extensions.py # db、cors、login_manager等实例化 ├── config.py # 配置文件 ├── models/ │ ├── __init__.py # 统一导入所有模型 │ ├── user.py │ ├── patient.py │ └── drug.py ├── apis/ │ ├── __init__.py │ ├── auth_api.py # 登录认证接口 │ ├── patient_api.py # 患者管理接口 │ ├── registration_api.py │ ├── drug_api.py │ ├── admission_api.py │ ├── stats_api.py │ └── ... └── utils/ ├── auth_decorator.py # 登录验证装饰器 └── response.py # 统一返回封装对应每个蓝图注册方式from flask import Flask from apis.patient_api import patient_bp def create_app(): app Flask(__name__) app.config.from_object(config.Config) # 初始化扩展 db.init_app(app) CORS(app) # 注册蓝图 app.register_blueprint(patient_bp, url_prefix/api) return app这种结构每新增一个模块只需要在apis目录新建一个文件然后在入口注册不用动任何旧代码加功能就像插积木。4.3 登录验证与权限控制医院系统不能裸奔必须登录。Flask里最常用的是Flask-Login加自封装的角色判断装饰器。先做一个基础登录接口from flask import request, jsonify from werkzeug.security import check_password_hash from flask_login import login_user from models.user import User auth_bp.route(/login, methods[POST]) def login(): data request.get_json() username data.get(username) password data.get(password) user User.query.filter_by(usernameusername).first() if not user or not check_password_hash(user.password_hash, password): return jsonify({code: 401, message: 用户名或密码错误, data: None}) login_user(user) return jsonify({code: 200, message: 登录成功, data: {username: user.username, role: user.role}})但光登录还不够系统里的角色有五种不能让药房管理员去访问患者列表。因此写一个角色校验装饰器from functools import wraps from flask_login import current_user from flask import jsonify def role_required(*roles): def decorator(f): wraps(f) def wrapper(*args, **kwargs): if not current_user.is_authenticated: return jsonify({code: 401, message: 未登录}), 401 if current_user.role not in roles: return jsonify({code: 403, message: 无权限访问}), 403 return f(*args, **kwargs) return wrapper return decorator用的时候一行注解搞定patient_bp.route(/patients, methods[GET]) role_required(admin, doctor, nurse) def list_patients(): # 只有登录且角色匹配的能进来 ...注意Flask-Login的login_user需要配合session启用而且登录态默认存在客户端Cookie里。前后端分离时前端的axios要设置withCredentials: true后端要设置CORS时带上supports_credentialsTrue否则登录后发请求不带Cookie又跳回登录页。这个坑我见过太多人踩了。4.4 CORS跨域问题处理前端Vue跑在localhost:5173后端Flask跑在localhost:5000端口不同就是跨域。不处理的话浏览器会拦截请求页面一片空白控制台刷红。处理方式用Flask-CORS几行代码搞定from flask_cors import CORS CORS(app, supports_credentialsTrue, resources{r/api/*: {origins: *}})一个容易忽略的点origins不要乱用*因为你既然开了supports_credentialsTrue允许携带Cookie两者组合在某些浏览器下会被拦。实际部署时建议把origins设为前端的真实地址http://localhost:5173。5. 前端Vue实现从零搭建页面对接接口后端接口写好了前端Vue的作用是把这些接口的能力变成可交互的界面。这个项目的页面整体分成三块登录页、管理主框架侧边栏顶栏内容区、以及各业务模块的列表/表单页。5.1 前端项目结构与技术栈Vue项目推荐用Vite构建上手简单、编译快。结构如下vue-hospital/ ├── index.html ├── package.json ├── vite.config.js # 配置开发服务器代理 └── src/ ├── main.js # 入口文件创建Vue实例 ├── App.vue # 根组件 ├── router/ │ └── index.js # 路由表 ├── api/ │ ├── request.js # axios封装 │ ├── patient.js # 患者模块接口 │ ├── drug.js # 药品模块接口 │ └── ... ├── stores/ # 状态管理Pinia │ └── user.js ├── views/ │ ├── Login.vue │ ├── Layout.vue │ ├── patient/PatientList.vue │ ├── registration/Registration.vue │ ├── drug/DrugManage.vue │ └── stats/StatsDashboard.vue └── components/ └── Sidebar.vue5.2 axios封装与请求拦截所有接口请求都通过统一封装的axios实例发出这样可以在一个地方处理登录态失效、统一错误提示import axios from axios import { ElMessage } from element-plus import router from /router const request axios.create({ baseURL: /api, // 配合vite代理避免跨域 timeout: 15000, withCredentials: true }) // 响应拦截器统一处理code request.interceptors.response.use( response { const res response.data if (res.code 401) { router.push(/login) ElMessage.error(登录已过期请重新登录) } if (res.code ! 200) { ElMessage.error(res.message) return Promise.reject(new Error(res.message)) } return res }, error { ElMessage.error(网络异常请检查后端服务) return Promise.reject(error) } ) export default requestVite的代理配置也放在这里说开发环境的/api前缀自动转发到后端// vite.config.js export default defineConfig({ server: { port: 5173, proxy: { /api: { target: http://localhost:5000, changeOrigin: true } } } })这样配置后前端请求/api/patients实际转发到http://localhost:5000/api/patients浏览器控制台不会出现跨域报错比后端开CORS再配withCredentials省心得多。5.3 一个核心业务页面挂号和门诊医生工作台挂号的业务逻辑是选择患者 → 选择科室 → 选择医生 → 选择号别 → 提交。这个页面的核心代码思路如下template div el-form :modelregForm label-width80px el-form-item label患者 el-select v-modelregForm.patient_id filterable placeholder输入手机号/姓名搜索 el-option v-forp in patientOptions :keyp.id :label${p.name}(${p.phone}) :valuep.id / /el-select /el-form-item el-form-item label医生 el-select v-modelregForm.doctor_id placeholder选择医生 el-option v-ford in doctorOptions :keyd.id :label${d.name} · ${d.department} :valued.id / /el-select /el-form-item el-button typeprimary clicksubmitReg确认挂号/el-button /el-form /div /template script setup import { reactive, ref, onMounted } from vue import { searchPatients } from /api/patient import { listDoctors } from /api/doctor import { createRegistration } from /api/registration const patientOptions ref([]) const doctorOptions ref([]) const regForm reactive({ patient_id: null, doctor_id: null, reg_type: 普通 }) async function searchPatient(keyword) { const res await searchPatients({ keyword }) patientOptions.value res.data } async function submitReg() { const res await createRegistration(regForm) if (res.code 200) { ElMessage.success(挂号成功) } } onMounted(async () { const res await listDoctors({}) doctorOptions.value res.data }) /script这里有个前端设计的细节患者选择用远程搜索而不是下拉全量加载。因为患者表数据量一上来全量加载会导致页面卡顿。输入手机号或姓名关键词后端接口做模糊查询返回前20条体验好得多。5.4 基于角色的动态菜单不同角色登录后应该看到不同的菜单管理员看到全部模块挂号员只看到挂号和患者查询药房管理员只看到药品管理。实现动态菜单的思路是登录后获取当前用户信息根据角色在前端路由表里做过滤。简单做法是在meta里标记可用角色const routes [ { path: /patient, component: () import(/views/patient/PatientList.vue), meta: { roles: [admin, doctor, nurse, registrar] } }, { path: /drug, component: () import(/views/drug/DrugManage.vue), meta: { roles: [admin, pharmacist] } } ]路由守卫里判断router.beforeEach((to, from, next) { const userStore useUserStore() const role userStore.role if (to.meta.roles !to.meta.roles.includes(role)) { next(/403) } else { next() } })这是最简单的前端权限控制方案。后端接口另有一套role_required做兜底双层保障不会出现“前端藏了菜单但接口裸奔”的问题。6. 核心业务场景的流程实现从挂号到结算的完整链路前几节讲的都是模块怎么搭这一节我选两个最能体现“功能多”的核心链路完整串一遍。一个医院系统能不能用、好不好演示基本就看这两条链路是否打通。6.1 门诊全流程挂号 → 看诊 → 开方 → 取药这条链路覆盖了所有核心业务是最能展示系统完整度的场景。第一步挂号。挂号员在前台登记患者。患者如果第一次来先建档案姓名、身份证、手机号、过敏史之后挂号如果已经来过直接手机号/身份证搜索到患者档案选择科室和医生生成挂号记录。第二步看诊。医生登录后在“待诊列表”里看到分配给自己的患者。点“开始看诊”进入病历填写页主诉、现病史、诊断结果。需要开药时在处方明细里逐行添加药品搜索药品名、填数量、填用法用量药品前端实时计算总金额。第三步结算与取药。患者凭病历去收费处收费员能看到该患者处方明细核对金额后确认收款状态改成“已结算”。此时药房系统里这条处方的状态同步变为“待取药”药剂师进行配药发药点击确认后系统自动扣减库存。这一条链路里处方状态流转是关键。我会在数据库的prescription_item表里加一个status字段取值依次是待收费 → 已收费/待取药 → 已取药 → 已完成前端列表页根据状态值显示不同标签和按钮各项操作紧扣状态流转来限制。这样设计才能在演示时清楚地展示“这单现在在哪个环节”。核心代码扣减库存的原子操作取药确认时要扣库存这一步千万不要写成“先查库存、再更新库存”的两步操作因为并发下会超卖。正确做法是条件更新# 错误写法并发时可能把库存扣成负数 drug Drug.query.get(drug_id) if drug.stock quantity: drug.stock - quantity db.session.commit() # 正确写法SQL层面加条件判断 result Drug.query.filter( Drug.id drug_id, Drug.stock quantity ).update({ Drug.stock: Drug.stock - quantity }) db.session.commit() if result 0: # 库存不足回滚并提示 db.session.rollback() return jsonify({code: 400, message: f药品库存不足{drug.name}})6.2 住院全流程入院登记 → 床位分配 → 费用明细 → 出院结算住院流程比门诊重一点核心环节多两个床位管理和住院费用累计。入院登记。住院收费处确认患者住院后在系统里做入院登记选主治医生、选科室、填写入院诊断。然后分配床位——床位列表只显示当前科室状态为“空闲”的床位选中后床位状态立即改成“占用”。费用记账。住院患者在住院期间的检查费、药费、护理费由各执行科室在系统里记账每一笔都插入hospitalization_charge表关联admission_id。费用实时汇总护士站和患者家属都可以随时查看“截至今天一共欠了多少”。出院结算。医生在系统里开出院医嘱状态改为“待结算”。收费员据此做结算汇总住院期间总费用减去预缴金额多退少补。结算完成后床位状态自动释放回“空闲”完成闭环。这个流程中有一个很实用的小功能预交金管理。患者入院时预缴一笔押金住院期间的费用实时扣除当余额低于预警值比如低于500元时护士站页面弹提醒“该患者余额不足请催缴”。这个小逻辑很简单就是在查询住院患者列表时加一个字段判断但演示效果非常好能体现系统“考虑了真实医院场景”。6.3 数据统计与可视化给管理层看的仪表盘“功能多”的另一个体现是统计报表。医院管理者最关心三个数字今日门诊量、今日收入、床位使用率。这些统计在后端写SQL聚合查询前端用图表库推荐ECharts渲染。后端接口示例stats_bp.route(/stats/dashboard, methods[GET]) role_required(admin) def dashboard_stats(): today datetime.now().date() # 今日门诊量 outpatient_count db.session.query( func.count(Registration.id) ).filter( func.date(Registration.reg_time) today ).scalar() # 今日收入 today_income db.session.query( func.coalesce(func.sum(Registration.fee), 0) ).filter( func.date(Registration.reg_time) today ).scalar() # 床位使用率 total_beds db.session.query(func.count(Bed.id)).scalar() used_beds db.session.query(func.count(Bed.id)).filter( Bed.status 占用 ).scalar() bed_usage_rate round(used_beds / total_beds * 100, 2) if total_beds else 0 return jsonify({code: 200, data: { outpatient_count: outpatient_count, today_income: float(today_income), bed_usage_rate: bed_usage_rate }})还有近7天门诊量趋势、各科室收入占比这类统计思路一样——聚合查询前端图表渲染。我建议项目做到后期至少实现3个以上的统计图因为答辩或汇报时一张图表胜过十页文字说明评委对这个的感知非常明显。7. 常见问题与排查技巧实录这部分我整理的是自己实操这个项目时真实踩过的坑以及帮别人调试时高频见到的问题。按“症状→原因→解法”的格式整理成速查表。问题现象根本原因解决方案启动Flask报ModuleNotFoundError: No module named flask_sqlalchemy没装依赖或装错环境pip install -r requirements.txt确认用的是虚拟环境解释器Vue请求接口报CORS错误后端未配置CORS安装flask-corsCORS(app, resources{r/api/*: {origins: http://localhost:5173}})登录成功后刷新就失效前后端Cookie未携带前端axios加withCredentials: true后端CORS加supports_credentialsTrue表单提交时报400 Bad Request前端传的是JSON但后端没加request.get_json()后端接口里显式调用request.get_json()解析日期字段存进去变成字符串前端传的日期格式不识别统一用YYYY-MM-DD字符串后端用datetime.strptime()转数据库修改字段后一直报错表结构未同步用flask db migrate upgrade同步别手动改表前端页面白屏/控制台报Uncaught SyntaxErrorVue编译时语法错误检查模板中的{{ }}插值和Flask的Jinja2模板语法冲突时改写v-text指令药品搜索接口非常慢未加索引在drug表的name字段加索引测试后发现查询耗时下降90%以上这里面最值得单独说的是第一个坑的变种很多人下载了某个开源项目打开PyCharm直接点运行结果Flask告诉你“No module named flask”然后他就跑去全局环境pip install flask装完还是报错。原因几乎可以肯定是——项目配置了解释器但PyCharm当前选择的解释器不是虚拟环境里的那个。检查位置File → Settings → Project → Python Interpreter确认选中.venv\Scripts\python.exe。第二个值得说的是Vue项目和Flask项目的目录混在一起有没有问题。我的建议是两个项目分开目录但放到一个父文件夹下比如my_hospital/ ├── flask-backend/ # 后端PyCharm打开这个目录 └── vue-frontend/ # 前端用WebStorm或VSCode打开这个目录后端用PyCharm操作前端用VSCode或WebStorm两个IDE各干各的开发时前后端各自热更新效率最高。这算是我踩过“同一个IDE里跑两个项目”的坑之后的经验总结——方便归方便但运行日志混在一起出了问题分不清是前端构建报错还是Python异常排查成本反而翻倍。8. 实操中的几句经验总结项目做到最后有几句话特别想留给做类似系统的人。第一个体会是别一上来就写代码先画一张数据流转图。我就吃过这个亏——一开始觉得“医院系统不就这么几块嘛”撸起袖子直接开写结果做到住院模块发现门诊的数据根本不够用回过头去改了三次表结构。如果一开始先把“挂号单、病历、处方、住院单”之间的流转关系画清楚至少节省一周的返工时间。第二个体会是调试接口别只用浏览器地址栏敲。浏览器只支持GET请求POST和PUT测不了。我建议用接口调试工具比如Postman或Apifox先把所有后端接口调通一遍确认返回结构都对再开始写Vue页面。否则前后端同时排查问题那个酸爽谁试谁知道。第三个体会是密码不要明文存数据库。演示项目也至少用werkzeug的generate_password_hash做哈希加密因为答辩的时候评委看了数据库第一眼就盯着密码。最后分享一个小技巧开发时可以把Flask的debug模式开起来Python代码改动后自动重启。但记住部署演示时一定要关掉debug否则出错页面会弹出面向所有人的完整堆栈信息既不安全也不体面。这套系统我前后带着不下五批同学做过可以说FlaskVue的这套技术栈对医院类管理系统的适配度非常高——Flask的灵活适合按需迭代Vue的交互能力撑起了那些复杂的表单和状态流转SQLAlchemy让12张表的增删改查变得井井有条。只要把上面几层结构理清楚你拿到的就不仅仅是一个能跑的毕业设计而是一个可以投入真实业务的完整解决方案。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →