拓冰建站拓冰建站
首页 / 资讯中心 / 正文

区块链医疗系统实战:Vue+Node.js实现病历存证与药品溯源

简介基于区块链的医疗系统设计与实现完整毕业设计资料包将区块链技术与医疗信息管理场景深度结合适合软件工程、计科、人工智能等专业学生用于毕业设计、课程设计或项目入门也可作为区块链应用方向的进阶学习参考。压缩包共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发送 POSTserver.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 -v和npm -v。Vue CLI 项目对 Node 版本有一定要求建议 16 或 18。后端 server.js 如果用了 ESModulepackage.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 servenpm install如果网络原因失败可以临时切换镜像源不要反复重试同一个源。server.js启动后通常会监听3000Vue 开发服务器默认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_URLhttp://localhost:7545 CONTRACT_ADDRESS0x... PRIVATE_KEY0x...然后用一个脚本验证能否发送交易。常见方式是用 web3.jsconst 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 或 8545CONTRACT_ADDRESSserver.js / .env合约部署后的地址0x 开头PRIVATE_KEYserver.js / .env测试账户私钥生产环境绝不放入代码VUE_APP_API_BASEsrc/api/前端接口基地址可用代理则留空CHAIN_IDMetaMask1337与 ganache-cli 保持一致如果你拿到的压缩包中没有.env检查README.md原作者一般会在文档里写清楚这些值。实在找不到就全局搜索7545或infura通常能定位到配置代码。4. 往现有代码里加模块药品溯源、病历存证与 IPFS4.1 药品溯源模块的数据组织压缩包里有shop.json和map.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.jsCannot find module依赖版本不完整npm install后重启 node server合约调用超时本地 IPFS 未启动或在公网使用确认 ipfs daemon 运行或改用本地节点这三个排错点建议在现场演示前都过一遍尤其是“清除活动数据”在换链时非常关键。5.3 现场演示的三个小技巧在毕业设计展示时不要只双击浏览器。先打开终端运行node server.js再运行npm run serve然后用ganache-cli --deterministic启动链并让终端和浏览器同屏。下一个技巧是提前把 MetaMask 的“审批”交互准备好避免现场让评委等待。最后把getPastLogs的结果输出到页面上评委问“数据真的上链了吗”时直接指着页面上的交易哈希说这个就是链上证据。这一句比任何介绍都有效。本文还有配套的精品资源点击获取
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门