资讯动态

医院管理系统课程设计:从ER建模到Flask后端的完整实现

发布时间:2026/10/16 19:14:17 来源:尧图企业网站定制
简介本资源是一份面向计算机专业本科生的C语言课程设计实践项目聚焦医院管理系统的完整实现与总结报告适用于软件工程、数据库原理及C语言综合实训等教学场景。项目采用纯C语言开发集成SQL数据库操作如SQLite/MySQL C API与基础GUI界面覆盖患者管理、预约挂号、诊疗记录等核心业务逻辑帮助学习者贯通编程、数据结构、API调用与关系型数据库应用能力。压缩包共16个文件含3个头文件.h定义数据结构与接口、2个C源码.cpp实现主逻辑与对话框、2个目标文件.o及1个可执行程序.exe辅以资源脚本.rc/.res/.ico、文档.docx和工程配置文件.cfp整体体积566KB结构清晰便于编译调试与代码研读。已有1096人学习下载提供从需求分析、系统设计、C语言编码、SQL建表与查询到完整总结报告的全流程交付物特别适合课程设计参考、期末项目复盘及C数据库协同开发入门实践。1. 医院管理系统的课程设计含总结报告一个能跑通、能答辩、能写进简历的完整闭环方案这不是一份“画大饼”的系统架构图也不是只贴几张UI截图就交差的PPT作业。它是一套从需求建模到数据库落地、从前端交互到后端逻辑、从测试用例到总结报告全文可复现的课程设计实战路径。某高校计算机专业连续三年将该选题列为《软件工程》《数据库原理》《Web开发基础》三门课的联合大作业核心诉求很实在学生得在34周内独立完成一个有真实业务约束、有数据流转逻辑、有可演示界面、有文档支撑的轻量级医院管理原型。它不追求替代HIS系统但必须体现挂号、分诊、医生排班、病历录入、药品库存五个关键子域的关联性——比如“患者挂号后分诊台能查到候诊队列医生接诊时能调取该患者历史用药记录开出处方后药房库存自动扣减”。我带过七届学生做这个课题最常翻车的不是代码写不出来而是需求没对齐、ER图和表结构脱节、报告里写不出“为什么选MySQL而不是SQLite”这种细节。本文就带你把这整条链路一节一节拧紧每一步都附可粘贴运行的SQL、可调试的Python/Java片段、可直接套用的报告段落模板。2. 用实体关系建模锁定业务边界从挂号单、处方笺到药房库存的5个核心实体怎么画才不返工课程设计最容易被导师当场叫停的环节就是ER图答辩。很多同学画出的图里“患者”和“医生”之间连着一条粗线旁边标注“就诊”但没人能说清这条线背后是1对1、1对多还是多对多更答不出“如果患者复诊历史病历如何关联新挂号记录”。我们必须先锚定五个不可拆解的核心实体及其约束条件——这是后续所有开发的宪法。2.1 患者与挂号为什么“挂号记录”必须是独立实体而非“患者”属性直觉上“挂号时间”“科室”“医生”似乎可以作为患者表的字段。但业务规则强制要求同一患者可多次挂号复诊、跨科就诊每次挂号生成唯一号源如G20240521001需独立追踪状态已签到/已就诊/已取消挂号费、医保类型、预约渠道窗口/APP/电话等属性仅属于本次挂号行为。因此“挂号记录”必须是独立实体且与“患者”构成一对多关系一个患者对应多条挂号记录。其主键不能是患者ID而应是自增ID或组合键挂号日期序号。常见错误是把挂号ID设为外键指向患者表主键导致无法删除患者时级联误删历史挂号——实际应设为非级联删除保留医疗行为审计线索。-- 正确建模挂号记录表独立存在患者ID仅为外键 CREATE TABLE registration ( reg_id CHAR(12) PRIMARY KEY, -- 格式GYYYYMMDDNNN如G20240521001 patient_id INT NOT NULL, -- 外键指向patient表 dept_id INT NOT NULL, -- 科室ID非空确保挂号必选科室 doctor_id INT, -- 预约医生ID可为空未指定医生时由分诊分配 reg_time DATETIME DEFAULT NOW(), -- 挂号时间精确到秒 status ENUM(pending,checked_in,consulted,cancelled) DEFAULT pending, fee DECIMAL(6,2) NOT NULL, -- 挂号费非空体现收费动作 channel ENUM(window,app,phone) DEFAULT window, FOREIGN KEY (patient_id) REFERENCES patient(patient_id) ON DELETE RESTRICT, FOREIGN KEY (dept_id) REFERENCES department(dept_id) ON DELETE RESTRICT, FOREIGN KEY (doctor_id) REFERENCES doctor(doctor_id) ON DELETE SET NULL );提示ON DELETE RESTRICT是关键。当某患者信息需修正如身份证号录入错误管理员应更新patient表而非删除重建——否则所有历史挂号记录将丢失。ON DELETE SET NULL用于doctor_id因医生离职时其历史挂号记录仍需保留仅将医生字段置空即可。2.2 处方与药品库存如何用“处方明细”桥接开方行为与库存扣减处方不是一张静态纸而是动态触发库存变更的动作。学生常犯的错是在prescription表中直接存药品名称和数量字符串拼接导致无法关联药品库、无法校验库存、无法统计药品消耗忽略“处方审核”环节开方即扣库存违反医疗安全规范。正确做法是引入处方明细prescription_detail作为桥接表它同时关联处方主表和药品主表并承载单次开药的数量、单位、用法。库存扣减必须发生在“处方审核通过”事件之后且需事务保证审核成功则库存原子性减少失败则回滚。-- 处方主表仅存审核状态、开方医生、审核医生、审核时间 CREATE TABLE prescription ( presc_id INT PRIMARY KEY AUTO_INCREMENT, reg_id CHAR(12) NOT NULL, -- 关联挂号记录 doctor_id INT NOT NULL, -- 开方医生 checker_id INT, -- 审核医生可为空待审核状态 check_time DATETIME, -- 审核时间为空表示未审核 status ENUM(draft,checked,rejected) DEFAULT draft, created_at DATETIME DEFAULT NOW(), FOREIGN KEY (reg_id) REFERENCES registration(reg_id) ON DELETE CASCADE, FOREIGN KEY (doctor_id) REFERENCES doctor(doctor_id) ON DELETE RESTRICT, FOREIGN KEY (checker_id) REFERENCES doctor(doctor_id) ON DELETE SET NULL ); -- 处方明细表精准绑定药品与用量支持多药同方 CREATE TABLE prescription_detail ( detail_id INT PRIMARY KEY AUTO_INCREMENT, presc_id INT NOT NULL, drug_id INT NOT NULL, quantity INT NOT NULL CHECK (quantity 0), -- 单次开药数量必须大于0 unit VARCHAR(10) NOT NULL, -- 单位盒、瓶、支、片 usage TEXT, -- 用法口服、外用、每日三次等 FOREIGN KEY (presc_id) REFERENCES prescription(presc_id) ON DELETE CASCADE, FOREIGN KEY (drug_id) REFERENCES drug(drug_id) ON DELETE RESTRICT ); -- 药品库存表实时反映可用数量含预警阈值 CREATE TABLE drug_stock ( stock_id INT PRIMARY KEY AUTO_INCREMENT, drug_id INT NOT NULL, available_quantity INT NOT NULL DEFAULT 0, min_threshold INT NOT NULL DEFAULT 10, -- 低于此值触发库存预警 updated_at DATETIME DEFAULT NOW() ON UPDATE NOW(), FOREIGN KEY (drug_id) REFERENCES drug(drug_id) ON DELETE CASCADE );参数说明available_quantity必须设为NOT NULL DEFAULT 0避免NULL值导致库存计算逻辑崩溃min_threshold不写死数字而是作为可配置字段方便后期扩展预警规则如贵重药品阈值设为5普通药品设为20。2.3 分诊台与候诊队列用状态机模型替代“正在叫号”这种模糊字段分诊逻辑常被简化为“当前叫号张三”但真实场景需支持按科室/医生分流候诊队列患者可签到从“待签到”变“已签到”系统自动排序医生可临时暂停叫号设备故障队列状态需持久化过号患者可重排非删除后重挂。因此“分诊状态”不应是字符串字段而应是状态机驱动的独立表每个挂号记录的状态变迁需留痕。-- 分诊状态表定义合法状态及转换规则 CREATE TABLE triage_status ( status_id TINYINT PRIMARY KEY, status_name VARCHAR(20) NOT NULL UNIQUE, description TEXT ); INSERT INTO triage_status VALUES (1, pending, 已挂号未签到), (2, checked_in, 已签到等待叫号), (3, called, 已叫号前往诊室), (4, consulting, 正在就诊), (5, completed, 就诊完成), (6, overdue, 过号需重排); -- 分诊记录表每次状态变更生成新记录形成审计链 CREATE TABLE triage_log ( log_id BIGINT PRIMARY KEY AUTO_INCREMENT, reg_id CHAR(12) NOT NULL, from_status TINYINT, to_status TINYINT NOT NULL, operator VARCHAR(20) NOT NULL, -- 操作人分诊员工号或系统标识 operated_at DATETIME DEFAULT NOW(), note TEXT, -- 备注如“患者迟到15分钟重排至队尾” FOREIGN KEY (reg_id) REFERENCES registration(reg_id) ON DELETE CASCADE, FOREIGN KEY (to_status) REFERENCES triage_status(status_id), FOREIGN KEY (from_status) REFERENCES triage_status(status_id) );逻辑说明不直接在registration表加status字段是因为状态变更需审计。例如患者签到时插入一条to_status2的日志医生点击“叫号”时再插一条to_status3的日志。这样即使系统崩溃也能通过最新日志还原当前状态而非依赖单字段值——后者在并发操作下极易出错。3. 用Python FlaskMySQL实现最小可行后端挂号、分诊、开方三个接口的事务安全写法前端页面可以简陋Bootstrap表格按钮但后端逻辑必须经得起推敲。课程设计答辩时导师最爱问“如果两个分诊员同时给同一个患者点击‘叫号’会不会重复叫”、“处方审核时库存不足是回滚整个事务还是只提示用户”。本节用Flask实现三个高危接口重点展示事务控制、并发防护、错误回滚的真实写法拒绝try...except pass式玄学容错。3.1 挂号接口防重复提交与号源唯一性双重校验挂号看似简单但存在两个致命并发点用户快速双击“确认挂号”按钮前端未禁用导致同一表单提交两次多个窗口/APP同时挂号生成相同号源如G20240521001。解决方案前端按钮置灰 后端号源生成时加数据库唯一约束 事务内重试机制。# app.py from flask import Flask, request, jsonify from flask_sqlalchemy import SQLAlchemy import datetime import random app Flask(__name__) app.config[SQLALCHEMY_DATABASE_URI] mysqlpymysql://root:passwordlocalhost/hospital db SQLAlchemy(app) class Registration(db.Model): __tablename__ registration reg_id db.Column(db.String(12), primary_keyTrue) patient_id db.Column(db.Integer, nullableFalse) dept_id db.Column(db.Integer, nullableFalse) # ... 其他字段 app.route(/api/register, methods[POST]) def create_registration(): data request.get_json() patient_id data.get(patient_id) dept_id data.get(dept_id) # 1. 生成号源日期3位随机数非自增避免暴露挂号量 today datetime.date.today().strftime(%Y%m%d) for _ in range(10): # 最多重试10次避免死循环 suffix f{random.randint(100, 999)} reg_id fG{today}{suffix} try: # 2. 在事务中插入利用唯一索引捕获重复 with db.session.begin_nested(): # 使用嵌套事务便于回滚 reg Registration( reg_idreg_id, patient_idpatient_id, dept_iddept_id, fee15.00, channelapp ) db.session.add(reg) db.session.flush() # 触发INSERT但不提交 break # 成功则跳出重试 except Exception as e: if Duplicate entry in str(e): continue # 号源重复重新生成 else: raise e # 其他错误抛出 db.session.commit() return jsonify({success: True, reg_id: reg_id})参数说明db.session.begin_nested()创建保存点db.session.flush()强制执行INSERT但不提交此时若违反唯一约束会立即报错continue触发下一轮号源生成。最终db.session.commit()提交整个事务。比在应用层查重再插入更可靠——查重与插入之间仍有时间窗口。3.2 分诊叫号接口乐观锁防止并发覆盖叫号操作本质是更新挂号记录的状态。若无防护A分诊员读取到患者状态为“已签到”B分诊员也读取到同样状态两人同时点击“叫号”都会将状态改为“已叫号”造成逻辑错误患者被叫两次。传统悲观锁SELECT ... FOR UPDATE在Web应用中易引发连接阻塞。我们采用乐观锁 版本号字段# 在registration表中增加version字段 # ALTER TABLE registration ADD COLUMN version INT DEFAULT 1; class Registration(db.Model): # ... 其他字段 version db.Column(db.Integer, default1) app.route(/api/triage/call/reg_id, methods[POST]) def call_patient(reg_id): try: # 1. 带版本号条件更新仅当当前version读取值时才更新 result db.session.execute( text(UPDATE registration SET statuscalled, versionversion1 WHERE reg_id:rid AND version:ver), {rid: reg_id, ver: 1} # 实际应先SELECT获取当前version ) if result.rowcount 0: # 更新失败说明version已变其他人在操作 return jsonify({error: 患者状态已被他人修改请刷新后重试}), 409 db.session.commit() return jsonify({success: True}) except Exception as e: db.session.rollback() return jsonify({error: 系统繁忙请稍后重试}), 500血泪经验初版代码直接SELECT * FROM registration WHERE reg_id?然后UPDATE ... WHERE reg_id? AND version?但SELECT与UPDATE之间仍有并发窗口。正确做法是在UPDATE语句中直接嵌入子查询获取当前version或使用数据库原生的UPDATE ... SET versionversion1 WHERE ... AND version(SELECT version FROM registration WHERE reg_id?)。此处为简化演示实际项目中应封装为原子操作。3.3 处方审核接口库存扣减的事务边界与补偿机制审核处方是典型分布式事务场景需同时更新处方状态、扣减库存、记录日志。任一环节失败必须全部回滚。但MySQL不支持跨库事务若未来药房系统独立部署需预留补偿接口。当前单库方案用with db.session.begin():显式声明事务边界。app.route(/api/prescription/check/presc_id, methods[POST]) def check_prescription(presc_id): try: with db.session.begin(): # 整个块为一个事务 # 1. 查询处方明细获取所有药品ID和数量 details db.session.execute( text(SELECT drug_id, quantity FROM prescription_detail WHERE presc_id:pid), {pid: presc_id} ).fetchall() # 2. 检查每种药品库存是否充足 for drug_id, qty in details: stock db.session.execute( text(SELECT available_quantity FROM drug_stock WHERE drug_id:did FOR UPDATE), {did: drug_id} ).scalar() if stock is None or stock qty: raise ValueError(f药品ID {drug_id} 库存不足当前{stock}需{qty}) # 3. 扣减库存FOR UPDATE已加锁避免并发扣减 for drug_id, qty in details: db.session.execute( text(UPDATE drug_stock SET available_quantity available_quantity - :qty WHERE drug_id :did), {qty: qty, did: drug_id} ) # 4. 更新处方状态为checked db.session.execute( text(UPDATE prescription SET statuschecked, checker_id:uid, check_timeNOW() WHERE presc_id:pid), {uid: 1001, pid: presc_id} # 实际应从session获取当前登录医生ID ) # 5. 记录审核日志可选 db.session.execute( text(INSERT INTO audit_log (action, target_id, operator) VALUES (prescription_check, :pid, :uid)), {pid: presc_id, uid: 1001} ) except ValueError as e: return jsonify({error: str(e)}), 400 except Exception as e: db.session.rollback() # 事务自动回滚 return jsonify({error: 审核失败请重试}), 500 return jsonify({success: True, message: 处方审核通过库存已扣减})关键点FOR UPDATE在库存查询时加行锁确保扣减前库存值未被其他事务修改with db.session.begin():确保所有操作在同一个事务中异常时自动回滚。不要用db.session.commit()分散提交——那是事务失控的开端。4. 前端交互与数据可视化用ECharts画出科室挂号热度图让答辩PPT多一个亮点课程设计答辩时纯文字描述“系统实现了分诊功能”远不如一张动态图表有说服力。某实验室曾要求学生在总结报告中加入“近7天各科室挂号量趋势图”结果80%的学生用Excel截图糊弄。其实用EChartsFlask API20行代码就能生成可交互图表。本节教你如何把数据库里的原始数据变成答辩时能让导师点头的可视化成果。4.1 后端提供挂号量聚合API按科室、按日期分组统计前端图表需要结构化JSON数据而非HTML表格。API设计必须符合ECharts的series.data格式数组每项为[x轴值, y轴值]。注意日期字段需转为字符串避免JavaScript解析错误。app.route(/api/stats/dept_volume) def dept_volume_stats(): # 查询近7天各科室挂号量 seven_days_ago (datetime.date.today() - datetime.timedelta(days6)).strftime(%Y-%m-%d) # 使用原生SQL避免ORM复杂关联提升性能 sql SELECT d.dept_name AS name, DATE(r.reg_time) AS date, COUNT(*) AS count FROM registration r JOIN department d ON r.dept_id d.dept_id WHERE r.reg_time :start_date GROUP BY d.dept_name, DATE(r.reg_time) ORDER BY d.dept_name, date rows db.session.execute(text(sql), {start_date: seven_days_ago}).fetchall() # 转换为ECharts所需格式{dept1: [[date1,count1], [date2,count2]], dept2: [...]} data_dict {} for row in rows: dept_name row.name date_str row.date.strftime(%m/%d) # 格式化为05/21 count int(row.count) if dept_name not in data_dict: data_dict[dept_name] [] data_dict[dept_name].append([date_str, count]) return jsonify(data_dict)参数说明DATE(r.reg_time)提取日期部分忽略时间strftime(%m/%d)生成短日期标签避免X轴拥挤COUNT(*)统计挂号次数非患者数同一患者多科挂号应分别计数。4.2 前端ECharts初始化5行代码渲染科室热度图无需下载ECharts包CDN引入即可。重点在于option配置——课程设计不需炫技清晰传达数据即可。柱状图比折线图更适合科室对比颜色用蓝绿系符合医疗主题。!-- index.html -- div iddeptChart stylewidth: 800px; height: 400px;/div script srchttps://cdn.jsdelivr.net/npm/echarts5.4.3/dist/echarts.min.js/script script const chartDom document.getElementById(deptChart); const myChart echarts.init(chartDom); // 1. 初始化option静态配置 const option { title: { text: 近7天各科室挂号量统计 }, tooltip: { trigger: axis, axisPointer: { type: shadow } }, legend: { data: [] }, // 动态填充 xAxis: { type: category, data: [] }, // X轴日期动态填充 yAxis: { type: value }, series: [], // 图表序列动态填充 grid: { left: 3%, right: 4%, bottom: 3%, containLabel: true } }; // 2. 调用API获取数据并渲染 fetch(/api/stats/dept_volume) .then(res res.json()) .then(data { // 提取所有日期X轴 const allDates new Set(); Object.values(data).forEach(series { series.forEach(item allDates.add(item[0])); }); const dates Array.from(allDates).sort(); // 排序确保日期顺序 // 构建series数组 const series []; Object.entries(data).forEach(([deptName, deptData]) { // 将deptData转换为按dates顺序排列的count数组 const counts dates.map(date { const found deptData.find(d d[0] date); return found ? found[1] : 0; }); series.push({ name: deptName, type: bar, data: counts, stack: total // 堆叠显示直观看出总量 }); }); // 更新option并渲染 option.xAxis.data dates; option.legend.data Object.keys(data); option.series series; myChart.setOption(option); }); /script逻辑说明stack: total使各科室柱形堆叠顶部即为当日总挂号量比并列柱状图更能体现资源占用tooltip.axisPointer.type shadow鼠标悬停时显示垂直阴影线精准定位日期Object.keys(data)动态生成图例避免硬编码科室名。4.3 报告中的图表解读话术三句话讲清数据价值答辩时导师不会盯着图表看10秒。你必须用口语化语言在30秒内点明图表意义。以下是某学生答辩实录已脱敏“这张图展示了系统上线后一周的挂号分布。第一内科和儿科是绝对主力占总挂号量68%印证了我们前期调研中‘常见病集中于这两科’的结论第二周五下午出现小高峰可能与上班族下班后带孩子就诊有关建议在排班模块中增加该时段医生权重第三所有科室周末挂号量低于平日40%以上说明当前系统尚未打通社区预约渠道——这正是我们下一步优化的方向。”提示不要说“图表显示数据波动”要说出谁在波动、为什么波动、对系统意味着什么。数据解读能力比代码本身更能体现工程素养。5. 总结报告撰写避坑指南导师最反感的3类表述以及5处必须写实的细节总结报告不是技术文档的复述而是向非技术背景的评审老师证明“我理解了为什么这么做且能反思局限”。某高校教务处抽查发现72%的课程设计报告存在“假大空”问题——通篇“提高了效率”“增强了安全性”却找不到一句具体数据支撑。本节直击答辩现场高频雷区每条均来自真实翻车案例。5.1 现象用“极大提升”“显著增强”代替量化指标 → 原因缺乏测试验证意识 → 解决补上三组对比数据错误示范“本系统极大提升了挂号效率优化了分诊流程。”翻车现场导师追问“极大是多少比手工挂号快多少秒分诊员每天少点几次鼠标” 学生哑口无言。正确写法必须实测“通过模拟100次挂号操作测试手工登记纸质表Excel录入平均耗时 82±15 秒/人次本系统在线挂号平均耗时 23±4 秒/人次提速72%分诊员处理单个患者状态变更签到→叫号→完成从平均点击6.2次降至2.1次操作步骤减少66%。”实操建议用手机秒表实测记录10次取平均操作次数在系统中埋点统计如console.log(triage_action: checked_in)答辩时打开浏览器开发者工具展示。5.2 现象将技术选型写成“因为简单”“因为学过” → 原因未建立决策依据框架 → 解决用四维对比表锁定MySQL错误示范“选用MySQL数据库因为课程中学过上手快。”翻车现场导师冷笑“那SQLite更简单为什么不用”正确写法附对比表评估维度MySQLSQLite本系统选择理由并发支持支持高并发读写行级锁文件锁写操作全局阻塞分诊、挂号、开方需同时操作必须支持并发事务完整性ACID完备支持SAVEPOINTACID完备但无SAVEPOINT处方审核需多步事务SAVEPOINT便于局部回滚运维成本需独立服务进程配置稍复杂零配置单文件课程设计环境可控运维非重点扩展性支持主从复制、分库分表无集群能力为未来对接LIS/PACS系统预留扩展接口参数说明表中“本系统选择理由”栏必须紧扣业务需求而非技术参数。例如不写“MySQL性能更好”而写“分诊员与挂号员同时操作不会卡顿”。5.3 现象回避系统缺陷用“有待完善”一笔带过 → 原因缺乏工程反思深度 → 解决坦诚三点局限具体改进路径错误示范“系统尚存在一些不足有待在后续版本中完善。”翻车现场导师追问“哪三点不足为什么现在不解决”正确写法示例“当前系统存在三项明确局限已在代码注释及README中标注无患者身份核验挂号仅校验手机号格式未对接公安身份证API。原因课程设计周期内无法申请政务接口。改进预留id_card_verify字段接入第三方SDK只需替换3处函数处方审核无电子签名仅记录医生ID未采集生物特征。原因浏览器端无法安全调用本地证书。改进增加扫码登录环节用企业微信/钉钉OAuth2.0获取可信身份药房库存预警无通知阈值超限仅在后台显示未短信/邮件提醒。原因短信网关需企业资质认证。改进集成免费邮件服务如SendGrid沙箱5行代码即可发送预警邮件。”注意每条“局限”必须包含现象、根因、短期绕过方案、长期改进路径四要素。导师想看到的是你的问题拆解能力而非完美主义幻觉。6. 答辩前最后一小时 checklist3个必验场景、2个防翻车技巧、1个让导师记住你的细节答辩不是代码展示而是信任建立。导师在15分钟内要判断“这学生是否真做过、是否懂原理、是否有工程潜质”。我带过的最惊艳的一次答辩学生没讲一行代码只做了三件事打开系统现场演示“患者张三挂号→分诊员李四叫号→王医生开处方→药房赵五审核→库存自动扣减”全流程当导师问“如果王医生开错药怎么撤回”时他立刻切到数据库执行UPDATE prescription SET statusdraft WHERE presc_id1001并解释“审核后状态不可逆但管理员有紧急回退权限日志全程留痕”最后一页PPT只有一句话“本系统所有SQL语句均通过Explain分析95%查询走索引慢查询日志已归档至report/slow_query.log”。这就是专业感。以下是你答辩前必须亲手验证的清单6.1 三个必验场景每项限时3分钟场景验证方法通过标准并发挂号不重复开两个浏览器窗口同一患者ID、同一科室连续点击“挂号”按钮10次数据库中仅生成1条挂号记录号源不重复库存扣减不超卖查看某药品库存为5开一张处方含该药6片提交审核返回“库存不足”错误数据库库存仍为5处方状态保持draft状态变更可追溯对同一挂号记录依次执行签到→叫号→就诊→完成→过号手动更新状态triage_log表中生成5条记录to_status字段值严格按1→2→3→4→6递进提示这些场景必须在答辩电脑上实操而非“理论上可以”。我见过太多学生说“应该没问题”结果答辩时点一下就报500错误——因为忘了启动MySQL服务或.env文件密码写错。6.2 两个防翻车技巧写在便利贴上贴屏幕边技巧1SQL注入防御自查所有接收用户输入的接口如/api/register检查是否使用?占位符或text()参数化查询。严禁出现fINSERT INTO ... WHERE name{name}。在答辩PPT中放一张截图print(db.session.bind.dialect.statement_compiler(db.session.bind.dialect, stmt))输出的预编译SQL证明参数已转义。技巧2外键约束启用验证登录MySQL命令行执行SHOW CREATE TABLE registration;确认输出中包含FOREIGN KEY (patient_id) REFERENCES patient(patient_id)。若显示CONSTRAINT ... FOREIGN KEY ... REFERENCES ...但无ON DELETE子句说明建表时未启用外键InnoDB引擎需SET FOREIGN_KEY_CHECKS1;。6.3 一个让导师记住你的细节在报告附录放一份“可验证的部署清单”别写“系统部署在本地环境”要写附录A环境可复现性声明操作系统Windows 10 21H2 / Ubuntu 22.04 LTSPython版本3.9.18python --version依赖包pip install -r requirements.txt文件已随代码提交共12个包不含django等冗余框架数据库初始化mysql -u root -p init_db.sql脚本含建库、建表、基础数据INSERT执行耗时8秒启动命令cd src python app.py无Docker、无Nginx纯Python启动默认账号admin/admin123仅用于演示代码中已加盐哈希这份清单的价值在于它告诉导师“你考虑到了别人能否复现你的工作”。工程能力的最高体现不是写出多炫的代码而是让下一个接手的人能在10分钟内跑起来。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑