区块链医疗系统实战:Vue+Node.js实现病历存证与药品溯源
2026/9/14 5:16:20 网站建设 项目流程

简介:基于区块链的医疗系统设计与实现完整毕业设计资料包,将区块链技术与医疗信息管理场景深度结合,适合软件工程、计科、人工智能等专业学生用于毕业设计、课程设计或项目入门,也可作为区块链应用方向的进阶学习参考。压缩包共67个文件,总大小约5.91MB,核心包括Vue组件页面、JavaScript业务逻辑、JSON配置以及HTML入口页面,另附图片素材、项目说明文档和依赖清单,覆盖前端模块、后端API、路由权限、数据配置等关键结构,目录清晰便于检索和二次扩展。资源内含有详细设计与实现文档,代码经过运行验证,可帮助理解医疗数据上链、共享授权与防篡改等基础机制;借助现有框架还能继续完善电子病历、处方流转等功能,适合快速搭建原型或作为演示项目。目前已有122人学习,对正在准备区块链相关毕设的同学具有不错的参考价值。

1. 为什么医疗系统要上链:区块链项目的真实切入点

医院的电子病历系统最麻烦的不是存储,而是谁在什么时候改过数据。基于区块链的医疗系统把这种“审计需求”变成链上事件日志,让每次处方登记、病历改动都留下不可抵赖的痕迹,这正是毕业设计和课程设计里最容易讲清楚的技术亮点。这个 zip 里的 hospital2-master 是一套完整的 Vue + Node.js 项目,前端覆盖挂号、问诊、药品管理等模块,后端用 server.js 提供业务接口,再通过 Web3 连接本地测试链完成上链操作。无论你是做毕业设计、课程设计,还是刚接触区块链应用开发的工程师,都可以从这套资源里拆出“传统业务系统 + 区块链存证”的完整链路。注意:不要把区块链神话,它解决的是信任和审计,不是性能。

2. 从 hospital2-master 看系统分层:Vue、Node 与链上数据如何协作

2.1 目录结构与一次请求的完整路径

先把压缩包里的核心文件展开看:

hospital2-master/ ├── src/ │ ├── App.vue // 根组件 │ ├── main.js // Vue 入口 │ ├── permision.js // 路由守卫 │ ├── api/ // axios 请求封装 │ ├── utils/ // web3 或工具方法 │ ├── components/ // 表单、表格、药房组件 │ ├── router/ // 前端路由 │ └── store/ // Vuex 状态 ├── server.js // Express 服务 ├── vue.config.js // devServer/代理配置 ├── package.json └── README.md

我一般会先读 README 和 package.json,确认依赖版本。这里能明显看到 Vue CLI 的痕迹,main.js 负责 Vue 实例创建,permision.js 做登录跳转,说明系统包含角色权限控制。前端并不直接调链,而是先请求 server.js 的 REST 接口,再由服务端通过 web3 库访问区块链。这样做的好处是传统业务逻辑保持完整,链只承担存证和授权校验,符合大多数毕业设计的代码组织方式。

一次典型的请求流程是:用户在前端填写病历,点击保存;store 调用 api 里封装的 addRecord 方法,向/api/record发送 POST;server.js 验证 token 后把记录写进 MySQL/MongoDB,同时调用合约的saveHash方法把哈希上链;前端只收到数据库记录 id 和交易 hash。数据库存明文,链上存哈希,两者互相印证。当评委质疑“数据库也能做审计”时,你就回答:数据库记录可以被管理员篡改,而链上事件一旦写入,单条记录很难被静默修改。

2.2 为什么使用本地链而不是公链

不少同学在开题报告里写“基于区块链的医疗系统”,但实际上链路跑在以太坊主网是不现实的:身份信息不能公开,交易费也不是普通学生能承受的。常见做法是使用 Ganache 提供的个人链,或部署到一条以太坊测试网。参数上的差异只有 RPC_URL、chainId 和合约地址。资源包里涉及的服务器大概率是 Node.js,配合 web3.js 或 ethers.js 和一条本地链。用本地链还有一个不需要解释的便利:预置账户自带 100 ETH,答辩现场演示时永远不会因为余额不足而失败。

维度本地链 Ganache公链/测试网
出块速度即时十几秒到几十秒
交易费用0需要 gas
账户预置 10 个账户,可控私钥自己生成并保管私钥
适合场景毕业设计、课程设计、联调发布到应用、跨机构演示

如果题目里加上“低延迟”或“高并发”,要清醒地意识到区块链并不擅长。答辩时被问到性能,通常解释是:业务数据仍在数据库,链上只放关键摘要,所以不会出现大量交易挤压。这样既体现了你对区块链边界有认知,又不会给自己挖坑。

2.3 一个最小病历存证合约

在完整资料里通常附有合约源文件,即使压缩包里没有单独列出 .sol 文件,也需要按下面的最小结构补一个。定义如下:

pragma solidity ^0.8.0; contract MedicalRecord { mapping(address => bytes32[]) private recordHashes; mapping(address => mapping(address => bool)) private granted; event HashSaved(address indexed patient, bytes32 hash, uint256 ts); function saveHash(bytes32 _hash) external { recordHashes[msg.sender].push(_hash); emit HashSaved(msg.sender, _hash, block.timestamp); } function grant(address _doctor) external { granted[msg.sender][_doctor] = true; } function isGranted(address _patient, address _doctor) external view returns (bool) { return granted[_patient][_doctor]; } }

saveHash由患者账号调用,recordHashes按患者地址区分记录;grant实现医生授权,只有被授权的地址才能查看访问入口。把事件HashSaved作为审计索引,后面查“谁在什么时候存过什么”直接用getPastLogs即可。注意合约里没有保存任何明文病历,目的就是规避隐私和存储成本的争议。如果项目里还做了病历分享功能,可以把 ACL 再扩展成角色列表,比如增加revoke方法。实际考试或答辩时,这些细节比页面多一个按钮更有说服力。

3. 本地复现:启动 server.js、配置 MetaMask 并完成第一次上链

3.1 准备依赖:Node、Ganache 和 MetaMask

先检查基础环境:node -vnpm -v。Vue CLI 项目对 Node 版本有一定要求,建议 16 或 18。后端 server.js 如果用了 ESModule,package.json 里会有"type": "module",注意目录下是否已经有package-lock.json,有的话直接npm install会更接近原作者测试过的依赖树。

npm install -g ganache-cli ganache-cli --port 7545 --chainId 1337 --deterministic

--port指定 RPC 端口,前端或后端配置中的http://localhost:7545要与之对应;--chainId 1337是 MetaMask 自定义网络里需要填写的链 ID;--deterministic保证每次启动生成的账户地址一致,这样写死在代码里的测试账号不用反复改。启动成功后终端会列出 10 个账户和私钥,任选一个私钥导入 MetaMask。

MetaMask 中添加自定义网络时,建议在“网络”里新增,参数如下表:

字段
网络名称Localhost 7545
新的 RPC URLhttp://localhost:7545
链 ID1337
货币符号ETH

这里有个常见误会:MetaMask 默认的“Localhost 8545”链 ID 也是 1337,但如果你用 Ganache 默认端口 8545,可以不用改;如果改成 7545,链 ID 仍是 1337。很多同学在自定义 RPC 时填错链 ID,导致Nonce too high或连接不上。

3.2 安装依赖并启动前后端

cd hospital2-master npm install node server.js

另开一个终端:

npm run serve

npm install如果网络原因失败,可以临时切换镜像源,不要反复重试同一个源。server.js启动后通常会监听3000,Vue 开发服务器默认8080。前端请求后端时,vue.config.js需要配置代理避免跨域:

// vue.config.js const { defineConfig } = require('@vue/cli-service') module.exports = defineConfig({ devServer: { port: 8080, proxy: { '/api': { target: 'http://localhost:3000', changeOrigin: true } } } })

这里/api前缀的请求全部转发到3000,如果你的后端接口没有/api前缀,需要改成对应路径。changeOrigin: true是为了让后端收到的请求头 Host 指向目标地址,避免部分框架的防盗链判断。配置完成后,用浏览器访问http://localhost:8080,登录页出现,说明前后端已经通了。

3.3 第一次上链:通过 Web3 发送交易

后端server.js中通常已经写好了合约地址和 ABI。如果是自己接链,需要在项目根目录新增.env文件(注意.gitignore是否忽略),内容类似:

RPC_URL=http://localhost:7545 CONTRACT_ADDRESS=0x... PRIVATE_KEY=0x...

然后用一个脚本验证能否发送交易。常见方式是用 web3.js:

const Web3 = require('web3'); const web3 = new Web3(process.env.RPC_URL); const account = web3.eth.accounts.privateKeyToAccount(process.env.PRIVATE_KEY); web3.eth.accounts.wallet.add(account); web3.eth.defaultAccount = account.address; async function saveHash(hash) { const contract = new web3.eth.Contract(abi, process.env.CONTRACT_ADDRESS); const tx = await contract.methods.saveHash(hash).send({ from: account.address }); console.log('tx hash:', tx.transactionHash); } saveHash(web3.utils.keccak256('first-demo'));

privateKeyToAccount把 Ganache 给的私钥转成账号对象,wallet.add是给交易签名用的;keccak256是合约里bytes32参数的标准转换方式。如果直接把字符串传进去,Solidity 端类型不匹配会报错。tx.transactionHash打印出来后,可以在 MetaMask 的“活动”里看到这笔交易,说明前端、后端、链三层链路已经打通。

3.4 配置参数速查表

参数位置说明
RPC_URLserver.js / .envGanache 端口,常见 7545 或 8545
CONTRACT_ADDRESSserver.js / .env合约部署后的地址,0x 开头
PRIVATE_KEYserver.js / .env测试账户私钥,生产环境绝不放入代码
VUE_APP_API_BASEsrc/api/前端接口基地址,可用代理则留空
CHAIN_IDMetaMask1337,与 ganache-cli 保持一致

如果你拿到的压缩包中没有.env,检查README.md,原作者一般会在文档里写清楚这些值。实在找不到,就全局搜索7545infura,通常能定位到配置代码。

4. 往现有代码里加模块:药品溯源、病历存证与 IPFS

4.1 药品溯源模块的数据组织

压缩包里有shop.jsonmap.json,这是药品销售点或医院分布的数据,可以用来做“附近药店”或“药品流向展示”。如果要把这个模块升级成带区块链的溯源案例,思路是:生产商、经销商、医院各自是链上的一个节点,每个环节把批号、操作人、时间戳写入事件。查询时输入药品批号,合约返回的就是一条不可篡改的流转路径。

struct TraceNode { string location; string operatorName; uint256 time; } mapping(string => TraceNode[]) public traces; function addTrace(string calldata productId, string calldata location, string calldata operatorName) external { traces[productId].push(TraceNode(location, operatorName, block.timestamp)); } function getTrace(string calldata productId) external view returns (TraceNode[] memory) { return traces[productId]; }

productId是药品追溯码,比如电子监管码;TraceNode是每次流通的记录。这里没有做权限控制,实际场景应该限制只有特定角色能调用addTrace。注意mapping的返回值在 web3.js 中拿到的是对象数组,遍历方式与普通 JavaScript 数组一样。如果你需要按时间倒序展示,可以在前端对time字段做sort,不要在前端直接改合约逻辑。

4.2 前端接入查溯源接口

src/api里新建trace.js,然后调用后端接口:

import request from '@/utils/request' export function getProductTrace(productId) { return request({ url: '/api/trace/' + productId, method: 'get' }) }

@/utils/request通常是基于 axios 封装好的实例,已经在拦截器里加过 token。这里的productId是路由参数,后端收到后需要校验格式,避免把非法字符拼进查询语句。在组件里:

const res = await getProductTrace('6901234567890') this.traceList = res.data

如果接口返回的time是 Unix 时间戳(秒),要显示成日期,需要new Date(time * 1000)。Ganache 的block.timestamp是秒,而 JavaScript 的Date构造函数接收毫秒,这是最常见的返工点。展示页面可以加一个时间格式化过滤器,把时间戳转成“年-月-日 时:分:秒”,让评委一眼看到每个环节的时间。

4.3 IPFS 存文件、链上存摘要

病历里包含检查报告、影像文件,体积可能很大。把这些文件塞进合约会让部署成本高到无法接受。常规做法是引入 IPFS:文件上传到本地 IPFS 节点,得到 CID 字符串;合约只需要保存keccak256(CID)或直接保存 CID 的字符串。CID 本身不是机密,配合对称加密后再上传也可以。

import { create } from 'ipfs-http-client' const ipfs = create({ url: 'http://localhost:5001' }) async function uploadReport(fileBuffer) { const { cid } = await ipfs.add(fileBuffer) const hash = web3.utils.keccak256(cid.toString()) await contract.methods.saveHash(hash).send({ from: account.address }) return { cid: cid.toString(), txHash: receipt.transactionHash } }

ipfs-http-client是标准客户端,url指向本地 IPFS 守护进程的 HTTP API。ipfs.add返回的对象在不同版本中略有区别,新版本返回cid,旧版本返回path,如果报错path is not a function,就要看依赖版本。keccak256将 CID 映射成固定长度的bytes32,链上只保存这个值,查询时再把 CID 取出来通过 IPFS 网关拉取原文件。这个方案把“隐私保护”和“内容寻址”两个技术点都覆盖了,答辩时值得单独展开。

存储内容作用
业务数据库病历明文、用户资料快速检索
IPFS原始报告文件文件去重、内容寻址
区块链文件哈希、操作事件防篡改、审计

数据分层之后,数据库被攻破,攻击者拿到的只是散落的文件;链上记录还在,仍然可以用于事后追责。这种设计也是目前区块链医疗项目在论文里最常见的系统架构。

5. 毕业设计答辩前的验证与排错:查链数据、看日志、避坑

5.1 用 getPastLogs 验证上链事件

const events = await contract.getPastEvents('HashSaved', { fromBlock: 0, toBlock: 'latest' }) console.log(events.length, events[0].returnValues)

如果事件数量为 0,说明交易没有真正写到这条链上,可能合约地址错误或链 ID 不匹配。如果长度符合预期,returnValues.hash与数据库中的哈希一致,就完成了整个闭环验证。另外,可以用web3.eth.getBalance(account.address)检查测试账户余额,确保上链操作不会因余额问题中断。

5.2 常见问题排查

现象原因处理方法
MetaMask 一直转圈RPC URL 配置错误或 ganache 未启动检查端口和网络状态
交易返回nonce too low重新启动了 ganache 但 MetaMask 缓存旧 nonce重置账户:设置-高级-清除活动数据
前端白屏代理配置错误或接口返回跨域错误查看浏览器 Network,检查vue.config.js
Cannot find module依赖版本不完整npm install后重启 node server
合约调用超时本地 IPFS 未启动或在公网使用确认 ipfs daemon 运行,或改用本地节点

这三个排错点建议在现场演示前都过一遍,尤其是“清除活动数据”在换链时非常关键。

5.3 现场演示的三个小技巧

在毕业设计展示时,不要只双击浏览器。先打开终端,运行node server.js,再运行npm run serve,然后用ganache-cli --deterministic启动链,并让终端和浏览器同屏。下一个技巧是提前把 MetaMask 的“审批”交互准备好,避免现场让评委等待。最后,把getPastLogs的结果输出到页面上,评委问“数据真的上链了吗”时,直接指着页面上的交易哈希说:这个就是链上证据。这一句比任何介绍都有效。

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

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

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

立即咨询