区块链电子证据存证系统前端源码解析:哈希上链与验证闭环

发布时间:2026/10/3 3:42:57
区块链电子证据存证系统前端源码解析:哈希上链与验证闭环 简介基于区块链的电子证据存证系统前端源码专为计算机专业毕设、课程设计与区块链应用开发者打造。系统借助去中心化存储与不可篡改特性实现电子证据的安全上传、存证及可信验证有效解决传统存证易伪造、难追溯的问题。资源共78个文件以37个JavaScript逻辑脚本和17个Less样式文件为核心辅以页面图片、ESLint/Prettier等工程化配置、环境变量及Markdown说明文档压缩包仅5.13MB轻量且结构清晰。前端采用模块化目录组织涵盖页面、组件、服务、工具、布局等部分便于理解单页应用架构与区块链接口交互流程界面简洁直观交互友好用户无需专业背景即可快速上手。包内附README说明方便快速启动项目。已有60名学习者下载查阅适合作为毕设源码参考或区块链前端开发练手项目。通过研究源码可掌握前端工程化规范、链上数据封装方法、存证业务实现要点及项目部署流程从而快速迁移到实际应用中提升区块链应用开发与Web项目实践能力。1. 区块链电子证据存证系统前端源码毕设季绕不开的一份“完整答案”真正把电子证据存证系统做出来的人都知道难点从来不在页面多好看而在“文件哈希怎么算、上链结果怎么接、验证时怎么比对”。这套基于区块链的电子证据存证系统前端源码把 Vue 页面、哈希计算、与链上交互的接口层都串好了是一个能直接拉起页面、连上本地链演示完整存证闭环的毕设级完整包。对正在做区块链方向毕设的学生它能省下至少两周的接口联调时间对想快速了解存证业务链路的开发者它也是一份现成的结构参考。我的建议很直接先跑通再改业务最后换成你自己的字段和界面去答辩。2. 先搞懂电子存证在链上怎么落哈希、交易与存证编号的设计拿过一套源码先别急着 npm install我习惯先把链路读明白。电子证据存证系统和普通管理系统最大的差别在于它面向的是“事后可验证”而不是“当日可浏览”。一切页面交互最终都在为两个动作服务把证据的指纹写进区块链以及从区块链上把指纹取回来比对。2.1 为什么不是把文件扔上链哈希链路才是核心区块链不是网盘把几 MB 的 PDF、图片、录音直接塞进区块里既慢又贵在 Ganache、Fisco 这类本地链上看不出问题一旦换到真实测试网就会立刻暴露。所以常规做法是文件本体存本地服务器或对象存储只有文件哈希和元数据上链。哈希在这里的角色是“证据指纹”。同一个文件经过 SHA-256 计算后得到一串固定长度的十六进制字符串。文件内容只要有 1 个字节的变化哈希值就完全不一样。上链时记录的是这串哈希验证时重新计算文件的哈希再去链上找对应的那条记录做比对就能判断文件是否被篡改。这里有一个很多人忽略的设计点存证编号和交易哈希是两回事。存证编号是业务层生成的流水号形如EV20250612XXXX用来在前端列表页展示和检索交易哈希是区块链返回的0x开头的字符串用来在区块链浏览器或 Ganache 区块列表里定位真正的上链记录。前端源码里这两个字段是分开存储的答辩时如果你能主动说清这个区别评委一般会认可你对业务的理解。2.2 存证与验证两条流程的时序设计先梳理存证流程通常是五步用户在前端选择文件并填写证据名称、来源等元数据。前端计算文件的 SHA-256 哈希。前端把文件元数据 哈希一起提交给后端业务接口。后端生成存证编号并把哈希、时间戳、操作者信息写入区块链拿到交易哈希。后端把存证编号、交易哈希、上链时间回传前端前端展示存证成功结果页。验证流程则是另外一条链路用户重新上传同一份文件或直接输入存证编号。前端计算文件哈希输入编号的场景则直接使用链上存储的原始哈希。后端根据存证编号从区块链上查询原始记录返回原始哈希与上链时间。前端把两项进行比较一致则显示验证通过不一致则给出篡改告警。需要注意“验证通过”的粒度。很多课设只做到字符串相等的比对这没有错但如果要在答辩时加分可以在此基础上增加“证书生成”环节验证通过后前端用 jsPDF 之类的库生成一张存证证书把文件名、哈希、存证编号、上链时间排版进去作为演示的落地产物。2.3 前端在整条链路里到底负责什么从这套源码的目录结构来看前端职责被分成了四块页面交互、哈希计算、接口封装、路由权限。我拆源码的习惯是先看src/api目录那里藏着整个系统的接口约定。职责模块具体内容对应源码位置典型结构页面交互登录、存证登记、证据列表、证据详情、验证结果src/views/evidence 相关页面哈希计算前端计算文件 SHA-256并做格式校验src/utils/hash.js 或类似工具文件接口封装axios 统一处理请求头、错误码、loading 状态src/api/request.js、src/api/evidence.js路由权限登录态控制不同角色可见菜单不同src/router/index.js 与路由守卫这个分法和大多数 Vue 毕设项目一致但有一点做得比较像真实项目哈希计算单独抽到了utils目录没有和页面组件耦合。这样设计的好处是后续想从“前端算哈希”切换成“后端算哈希”只需要替换这一个工具模块页面代码不用大改。我在帮别人验收存证类毕设时第一眼就会看这个文件是否独立独立了说明作者对模块边界有意识。3. 把前端源码跑起来环境配置与首次启动的完整流程源码在本地跑通是后面一切工作的前提。这套基于 Vue 的前端项目搭建思路很典型但越是典型的项目越容易在环境差异上闹出问题。下面按我自己的操作习惯走一遍每一步都附上配置说明。3.1 环境准备与 npm 依赖还原第一步确认本机 Node 版本。Vue 2 项目配合 Vue CLI 4 左右的环境推荐 Node 14 或 16太新的 Node 20 有时会在编译依赖时触发 OpenSSL 兼容性告警虽然有些项目能靠NODE_OPTIONS--openssl-legacy-provider硬跑但课设场景不值得在这种地方浪费时间。# 建议先用 nvm 锁定版本再进项目目录安装依赖 nvm use 16 npm install如果npm install中途报错优先看是不是 registry 源的问题。国内网络环境下我一般会先设置镜像源再安装npm config set registry https://registry.npmmirror.com npm install依赖装完先不要急着启动看一眼package.json里的 scripts 配置确认启动命令对不对。常见配置是npm run serve端口默认 8080如果 8080 被占用Vue CLI 会自动递增到 8081启动日志里会写明最终地址。3.2 三个必须对齐的配置点API 地址、RPC 地址、路由模式前端跑起来是白屏还是有数据取决于配置环境变量。在这个项目的根目录下通常能看到.env.development文件内容大概是// .env.development VUE_APP_API_BASE_URLhttp://localhost:3000/api VUE_APP_CHAIN_RPC_URLhttp://localhost:7545第一行是后端业务接口的地址第二行是区块链 RPC 的地址。两个地址各管一段链路业务接口负责存证编号生成和元数据管理RPC 地址负责直接读写链上数据。我第一次拿到类似项目时犯过一个低级错误只改了业务接口地址RPC 还指向默认的 7545 端口而本机 Ganache 用的是 8545结果存证提交一直报“链上连接失败”。所以启动前养成交叉检查的习惯后端接口能通、区块链 RPC 能通两个都通页面才完整。如果后端服务允许跨域请求开发环境一般会开 CORS前端就不需要额外配置代理如果后端没开开发环境可以在vue.config.js里加 devServer 转发配置。3.3 打开页面第一步登录、角色与菜单脉络启动完成后浏览器打开页面第一眼通常是登录页。这套存证系统的典型角色分管理员和普通用户两类管理员能查看全部存证记录、管理用户普通用户只能对自己提交的证据进行存证和验证。这里要提醒一点很多毕设源码的登录接口写的是硬编码用户名密码而不是走后端校验。启动后拿 README 或数据库初始化脚本里记录的初始账号登录即可一般在src/api/目录或后端接口注释里能找到。不要一上来就注册新账号很多系统压根没实现注册页只有登录页和忘记密码页是做样子的。登录进去以后按菜单从上到下点一遍存证登记、存证列表、证据验证、存证证书把这四个页面和 2.2 节的流程对应起来源码就算初步读通了。4. 核心页面拆解存证提交与证据验证的完整实现源码跑通以后就该看核心逻辑了。这套系统的灵魂在两个页面里存证提交页和证据验证页。我把关键代码抽出来逐段说明它在整条链路里的作用。4.1 前端文件哈希计算CryptoJS 的 SHA-256 落地写法先看哈希工具文件这是整个存证链路的起点。项目里一般用crypto-js库来计算 SHA-256// src/utils/hash.js import CryptoJS from crypto-js export function sha256File(file) { return new Promise((resolve, reject) { const reader new FileReader() reader.onload (event) { try { const wordArray CryptoJS.lib.WordArray.create(event.target.result) const hash CryptoJS.SHA256(wordArray).toString() resolve(hash) } catch (err) { reject(err) } } reader.onerror reject reader.readAsArrayBuffer(file) }) } export function formatHash(hash) { // 展示用只保留前 16 位和后 16 位中间省略 if (!hash || hash.length 40) return hash return hash.slice(0, 16) ... hash.slice(-16) }逻辑说明FileReader把文件读成ArrayBuffer再转换成 crypto-js 的 WordArray 数据结构然后执行 SHA-256 计算。同步的CryptoJS.SHA256在文件较大时会把主线程堵死所以外层包了一层 Promise让页面至少有机会展示 loading 状态。参数说明formatHash是纯粹的展示函数不影响链上存储的原始哈希值。列表页展示完整 64 位哈希会撑破表格布局截取首尾各 16 位是最常见的做法但注意比对时一定要用完整哈希不能拿截断后的字符串上链。4.2 存证提交从表单校验到存证编号回显存证提交页的逻辑集中在一个保存函数里大致骨架如下// src/views/evidence/submit.vue关键片段 async handleSubmit() { this.submitLoading true try { // 第一步校验表单 if (!this.file || !this.evidenceName) { this.$message.warning(请完善证据信息和文件) return } if (this.file.size 20 * 1024 * 1024) { this.$message.error(演示环境建议上传 20MB 以内的文件) return } // 第二步计算哈希 this.hashValue await sha256File(this.file) // 第三步组装数据提交给后端 const payload { evidenceName: this.evidenceName, evidenceType: this.evidenceType, fileHash: this.hashValue, fileSize: this.file.size, fileName: this.file.name } const res await submitEvidence(payload) // 第四步处理回显 this.evidenceNo res.data.evidenceNo this.txHash res.data.txHash this.$message.success(存证成功已写入区块链) } catch (error) { this.$message.error(存证失败 error.message) } finally { this.submitLoading false } }逻辑说明第一步过滤掉空表单和超大文件第二步在浏览器本地完成哈希计算第三步把文件属性连同哈希交给后端第四步拿到两个关键返回值——evidenceNo和txHash。这里有个容易被忽略的细节前端上传的不是文件本身而是文件信息文件本体是单独走上传接口传到存储区的。参数说明20 * 1024 * 1024这个限制是演示场景的经验值。Ganache 本地链对数据量不敏感但过大的文件会让 FileReader 和 SHA-256 计算变慢严重时浏览器会弹出“页面无响应”。如果你要演示大文件存证建议改用分片哈希计算。4.3 证据验证本地哈希与链上哈希的比对逻辑验证页和提交页是相反的操作。用户重新上传文件或者输入存证编号前端拿到链上原始哈希后和本地计算结果比对// src/views/evidence/verify.vue关键片段 async handleVerify() { this.verifyLoading true try { // 场景 A传文件 → 先算哈希 let localHash if (this.file) { localHash await sha256File(this.file) } // 场景 B调接口查链上记录 const res await getEvidenceByNo(this.evidenceNo) const chainData res.data // 核心比对本地哈希 vs 链上哈希 const isMatch !this.file ? true : (localHash chainData.fileHash) this.verifyResult { isMatch, evidenceNo: chainData.evidenceNo, txHash: chainData.txHash, onChainTime: chainData.onChainTime, localHash: localHash || 未上传文件跳过比对, chainHash: chainData.fileHash } this.resultVisible true } catch (error) { this.$message.error(验证失败 error.message) } finally { this.verifyLoading false } }逻辑说明代码里分了两种场景。只输入存证编号时前端没有本地文件isMatch直接置为true这种验证其实只证明“链上存在这条记录”不证明文件没被篡改很多课设没区分这两种场景答辩时容易被打疑问。如果上传了文件本地哈希和链上哈希必须逐字符相等才算通过。参数说明getEvidenceByNo的入参是存证编号而不是交易哈希因为用户拿到的凭证是业务层的编号不是区块链概念。后端会根据编号反查交易所对应的日志或事件数据。5. 避坑指南本地上链调试里最常翻车的 5 个真坑本地折腾这套系统的时候下面五个问题几乎每次帮别人验收都能碰上。每一条我都按现象、原因、解决的顺序写清楚照着排查能少走很多弯路。5.1 上传大文件时浏览器卡死现象选择 50MB 以上的视频或压缩包后页面直接白屏点击无响应过几分钟才恢复或者直接被系统提示“无响应”。原因FileReader一次性把整个文件读进内存再交给 crypto-js 做 SHA-256 计算。这个过程中主线程被完全占用UI 无法渲染超过一定阈值浏览器就会判定页面崩溃。解决演示场景最省事的办法是把文件大小限制在 20MB 以内在代码里if (file.size 20 * 1024 * 1024)直接拦截。如果一定要展示大文件改用分片哈希每片 2MB 左右依次读入并更新摘要同时对sha256File加上进度回调。从那以后我只要在页面上看到文件选择框第一反应就是看它有没有做大小限制。5.2 提示存证成功但链上查不到记录现象前端弹窗显示“存证成功”存证编号也回显了但去 Ganache 或区块链浏览器里查交易哈希什么都查不到。原因后端接口把上链动作包在try...catch里链上写入失败时 catch 了异常却没有回滚业务数据反而返回了成功状态码。前端只判断 HTTP 状态码是 200 就当作成功没校验txHash是否真实存在。解决前端拿到响应后必须增加一道校验res.data.txHash存在且以0x开头才显示成功。更稳的做法是上链后立即向后端轮询一次交易收据确认区块确认数大于 0。验收代码时我用一句话作为标准成功弹窗的触发条件必须是evidenceNo txHash缺一不可。5.3 验证时时间显示和本机差 8 小时现象存证列表里显示的上链时间是2025-06-12 04:30:00但本机北京时间是2025-06-12 12:30:00刚好差 8 个小时。原因Ganache 生成的区块时间戳是 UTC 时间后端接口直接透传了 ISO 字符串前端页面没有做时区转换new Date()之后的格式化逻辑又写错了时区参数。解决统一在展示层做一次转换用 dayjs 或原生toLocaleString处理不要直接渲染后端返回的原始字符串。我在代码里习惯写死一个格式化函数dayjs(chainData.onChainTime).format(YYYY-MM-DD HH:mm:ss)这个写法的结果是本地时区。检查时只看一点同一时间字段在提交页和验证页显示必须一致。5.4 换机器后 npm install 和启动报错现象拿到源码的新电脑上执行npm install依赖装完了但npm run serve报模块找不到或者编译时报语法错误还有人直接遇到digital envelope routines::unsupported。原因Node 版本和项目依赖不匹配。Vue 2 旧版 webpack 的项目在 Node 17 以上会出现 OpenSSL 算法变化导致的编译失败Node 版本过低又会缺语法支持。解决项目根目录如果没有.nvmrc文件自己手动指定版本。我一般直接用 Node 16装完依赖后跑一次npm run serve。如果还是报错删掉node_modules和package-lock.json重装一遍这一步能解决八成环境问题。5.5 Ganache 重启后之前存的证据全不见了现象第一天辛苦存了十条测试证据第二天打开项目重新启动页面列表空了链上也查不到任何记录。原因Ganache 默认以内存模式运行数据只存在进程生命周期里。进程一停所有区块、交易、账户余额全部清空。很多人把 Ganache 当成数据库这是概念上的误解。解决启动 Ganache 时加上持久化参数指定数据目录ganache -d --db ./chain-data --networkId 5777-d表示确定性模式每次启动账户地址和私钥都一样--db指定链数据保存目录重启后不会丢数据--networkId固定网络 ID避免前端 RPC 配置里的 chainId 与 Ganache 不一致导致连接失败。从那以后我每次启动链都把这条命令存成一个start-chain.sh脚本再也不用手敲参数。6. 答辩演示前的一小时把存证系统调到“不用解释”的状态源码跑通、坑也排完了最后一步是准备演示。我见过太多人当场翻车现场算大文件哈希等了半分钟、Ganache 没启动页面白屏、演示完存证但忘记演示验证。说白了演示环节不是展示你写了多少代码而是展示“这个系统能用”。提前一小时做下面四件事。第一准备一份固定的小文件。我习惯用一份 1MB 左右的合同 PDF命名为《存证测试合同.pdf》放在桌面。文件小是为了哈希计算够快命名为中文是为了演示时更有说服力。第二把项目、后端服务、Ganache 依次启动并且确认页面能正常登录。启动顺序别乱先把链跑起来再启动后端最后启动前端因为后端启动时要连接区块链。第三提前执行一遍完整的存证和验证流程把生成的存证编号和交易哈希截个图万一现场演示时出了岔子还能用截图兜底。第四验证证书导出功能提前打开证书预览确认 PDF 可以正常生成字体、排版没有乱掉。再补一个多媒体细节如果要在投影仪上演示浏览器窗口建议用无痕模式打开避免账号登录态过期或者浏览器插件干扰页面样式。字体调大一点控制台不要开着这些细节直接影响评委的第一观感。从那以后我每次做存证类项目演示都强制自己先完整跑一遍存证、验证、导出证书三件套再坐下来准备讲解词。这套代码本身不复杂但它把区块链存证的业务闭环做完整了你把它跑通、理解透、再换成自己的业务字段就是一次合格的毕设交付。希望帮到你。本文还有配套的精品资源点击获取