尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
眼镜店管理系统:SpringBoot+Vue全栈实战指南
简介本资源是一份面向计算机专业本科生的毕业设计论文文档聚焦眼镜零售行业信息化管理需求完整呈现基于JavaVueSpringBoot技术栈的瞳仁眼镜店管理系统的设计与实现全过程。论文涵盖系统需求分析、三层角色权限设计管理员/员工/用户、面向对象建模、前后端技术选型依据Java稳定性、SpringBoot快速开发、Vue组件化界面、MySQL数据库集成及核心功能模块说明适合作为课程设计参考、毕设开题与答辩材料或企业级Web系统学习范例。资源为单文件docx格式共1个文件大小5.07MB内容结构完整含中英文摘要、目录、四章正文绪论、技术基础、需求分析、系统设计与实现等、参考文献及附录。目前已有138人学习下载读者可直接获取规范的学术写作框架、清晰的技术实现路径、权限控制逻辑说明及前后端协同开发思路助力快速掌握中小型MIS系统从理论到落地的全流程。1. 瞳仁眼镜店管理系统为什么一个“小众垂直场景”反而成了 SpringBoot Vue 全栈练手的黄金切口你可能刚在毕业设计选题表里看到「瞳仁眼镜店管理系统」这个标题第一反应是又一个套模板的 CRUD但实际跑通它的人很快会发现——这根本不是简单增删改查。验光数据要带小数点后两位且不能四舍五入否则镜片度数偏差0.25D就可能引发视疲劳镜架库存得按「品牌系列颜色尺寸」四维组合管理而会员积分兑换规则要支持「满300减50、满600减120、满1000减200」三级阶梯且不可叠加……这些细节让整个系统天然卡在业务逻辑密度和工程落地复杂度的甜蜜点上。它不涉及高并发秒杀或分布式事务却把 SpringBoot 的分层设计、Vue 的响应式状态管理、前后端权限隔离、本地化打印验光单PDF生成、甚至基础的数据看板月度配镜品类TOP5全链路串了起来。适合正在从课堂Demo迈向真实交付边界的计算机专业学生也适合想用最小成本验证自己全栈闭环能力的转行者。这不是炫技项目而是能放进简历、经得起面试深挖、上线后真能被一家社区眼镜店用起来的「可交付最小业务系统」。2. 后端骨架SpringBoot 3.x MyBatis-Plus 搭建高内聚低耦合的服务层2.1 为什么放弃 JPA 选择 MyBatis-Plus三个现实约束倒逼出的技术选型很多同学一上来就想用 Spring Data JPA觉得自动映射省事。但在眼镜店这种强业务规则场景下JPA 的「对象即表」思维会迅速撞墙验光记录表optometry_record需要同时关联「顾客ID」「验光师ID」「镜架ID」「镜片ID」但镜架和镜片又分属不同主数据表且存在「无镜架仅配镜片」或「试戴镜架未成交」等空值分支会员等级变动日志member_level_log要记录每次升级的原始积分、扣减积分、剩余积分、触发规则ID字段语义密集JPA 的Embedded或ElementCollection在查询聚合时极易 N1库存流水inventory_transaction要求严格事务控制扣减镜架库存的同时必须新增一条「销售出库」流水并更新该镜架的「最后售出时间」字段——MyBatis-Plus 的Transactional 自定义 SQL 能精准控制每一步而 JPA 的saveAll()在混合 insert/update 场景下容易丢失中间状态。所以最终采用 MyBatis-Plus 3.5.3.1适配 SpringBoot 3.1核心优势在于✅ XML 中写原生 SQL 可精确控制LEFT JOIN和CASE WHEN✅LambdaQueryWrapper构建动态条件时字段名由编译器校验避免字符串拼接导致的运行时错✅IService接口自带saveBatch()、updateBatchById()等批量操作验光师一次录入5位顾客数据时性能提升明显。2.2 实体类设计用 Lombok Validation 把业务规则编译进代码以OptometryRecord.java为例它不是简单的 POJO而是业务规则的载体Data TableName(optometry_record) public class OptometryRecord { TableId(type IdType.ASSIGN_ID) private String id; NotBlank(message 顾客姓名不能为空) Size(max 10, message 顾客姓名不能超过10个字符) private String customerName; NotNull(message 左眼球镜度数不能为空) DecimalMin(value -12.0, message 左眼球镜度数不能小于-12.00) DecimalMax(value 12.0, message 左眼球镜度数不能大于12.00) Digits(integer 2, fraction 2, message 左眼球镜度数必须保留2位小数) private BigDecimal leftSphere; NotNull(message 右眼柱镜度数不能为空) DecimalMin(value -6.0, message 右眼柱镜度数不能小于-6.00) DecimalMax(value 6.0, message 右眼柱镜度数不能大于6.00) Digits(integer 2, fraction 2, message 右眼柱镜度数必须保留2位小数) private BigDecimal rightCylinder; Future(message 预约时间必须是未来时间) private LocalDateTime appointmentTime; // 镜架ID可为空 private String frameId; // 镜片ID可为空 private String lensId; TableField(fill FieldFill.INSERT) private LocalDateTime createTime; TableField(fill FieldFill.INSERT_UPDATE) private LocalDateTime updateTime; }提示Digits(integer 2, fraction 2)是关键——它强制要求输入如-3.25、1.75这样的标准验光格式避免前端传-3.250或1.7500导致数据库精度污染。配合DecimalMin/DecimalMax把国标《GB 10810.1-2018 眼镜镜片 第1部分单光和多焦点镜片》中规定的度数范围直接编码进校验层。2.3 Service 层实现用策略模式解耦「配镜方案生成」这一核心业务验光完成后系统需根据左右眼数据自动生成推荐镜片组合如左眼-2.50DS右眼-3.00DS → 推荐「明月1.56非球面」。若用 if-else 硬编码后续新增「渐进多焦点镜片」规则时将全面重构。因此采用策略模式// 定义策略接口 public interface LensRecommendStrategy { ListLensRecommendResult recommend(OptometryRecord record); } // 具体策略单光镜片推荐 Component(singleVisionStrategy) public class SingleVisionLensStrategy implements LensRecommendStrategy { Override public ListLensRecommendResult recommend(OptometryRecord record) { // 根据球镜绝对值区间匹配镜片折射率 BigDecimal maxSphere record.getLeftSphere().abs() .max(record.getRightSphere().abs()); String refractiveIndex maxSphere.compareTo(BigDecimal.valueOf(4.0)) 0 ? 1.56 : 1.60; // 查询镜片库中匹配折射率、库存0的SKU return lensMapper.selectByRefractiveIndexAndStock(refractiveIndex, 0); } } // Service 中调用 Service public class OptometryService { Resource private MapString, LensRecommendStrategy strategyMap; public ListLensRecommendResult generateLensRecommend(String recordId) { OptometryRecord record optometryMapper.selectById(recordId); // 根据验光记录中的「是否需要渐进多焦点」字段决定策略 String strategyKey record.getNeedProgressive() ? progressiveStrategy : singleVisionStrategy; return strategyMap.get(strategyKey).recommend(record); } }参数说明strategyMap是 Spring 自动注入的MapString, LensRecommendStrategykey 为Component(xxx)中的名称。这样新增策略只需加一个Component(newStrategy)类无需修改OptometryService符合开闭原则。这也是答辩时最容易讲清楚的设计亮点。3. 前端交互Vue 3 Element Plus 构建符合眼镜行业操作直觉的界面流3.1 用 Composition API 重构「验光录入页」告别 Options API 的状态碎片化传统 Options API 下data、methods、computed分散在不同区块而验光页有左右眼共12个度数输入框球镜/柱镜/轴位/矫正视力还要实时计算「双眼屈光参差值」并高亮警示。用setup()函数统一管理更清晰script setup import { ref, computed, watch } from vue // 左眼数据响应式对象 const leftEye ref({ sphere: null, cylinder: null, axis: null, vision: null }) // 右眼数据响应式对象 const rightEye ref({ sphere: null, cylinder: null, axis: null, vision: null }) // 计算双眼球镜差值取绝对值 const sphereDifference computed(() { const left leftEye.value.sphere ? Math.abs(parseFloat(leftEye.value.sphere)) : 0 const right rightEye.value.sphere ? Math.abs(parseFloat(rightEye.value.sphere)) : 0 return Math.abs(left - right) }) // 当差值 2.5D 时触发警示国标警示阈值 const isAnisometropiaWarning computed(() sphereDifference.value 2.5) // 监听左眼球镜变化自动格式化为两位小数 watch(() leftEye.value.sphere, (newVal) { if (newVal !isNaN(parseFloat(newVal))) { leftEye.value.sphere parseFloat(newVal).toFixed(2) } }) /script template el-form label-width120px el-form-item label左眼球镜DS :class{ warning-border: isAnisometropiaWarning } el-input v-modelleftEye.sphere placeholder-3.25 / /el-form-item !-- 其他11个输入框结构类似此处省略 -- /el-form /template style scoped .warning-border :deep(.el-input__inner) { border: 2px solid #ff9900; /* 橙色警示边框 */ } /style逻辑说明computed实时计算差值watch确保输入-3.250自动转为-3.25v-model双向绑定消除手动input事件。warning-border类通过:deep()穿透到 Element Plus 组件内部样式实现视觉反馈。这种写法比 Options API 少写 40% 模板代码且所有逻辑集中在script setup内评审老师一眼就能看清数据流向。3.2 打印验光单用 jsPDF html2canvas 生成可直接交付顾客的 PDF眼镜店最刚需的不是后台报表而是给顾客当场打印的验光单。要求含机构Logo、验光师签名栏、二维码扫码查看电子版、固定排版A4纸横向。纯后端生成 PDF如 iText配置复杂而前端方案更轻量import jsPDF from jspdf import html2canvas from html2canvas export function printOptometryReport(record) { const element document.getElementById(optometry-report) // 验光单DOM容器 html2canvas(element, { scale: 2, // 提升截图清晰度 useCORS: true, // 允许跨域图片如Logo logging: false }).then(canvas { const imgData canvas.toDataURL(image/jpeg, 0.95) const pdf new jsPDF(landscape, mm, a4) // 横向A4 const imgWidth 297 // A4宽297mm const imgHeight (canvas.height * imgWidth) / canvas.width // 添加图片到PDF居中 pdf.addImage(imgData, JPEG, 0, (210 - imgHeight) / 2, imgWidth, imgHeight) // 添加底部签名栏文字 pdf.setFontSize(12) pdf.text(验光师签字__________, 100, 195) pdf.text(日期${new Date().toLocaleDateString()}, 100, 202) // 触发下载 pdf.save(验光报告_${record.customerName}_${Date.now()}.pdf) }) }参数说明scale: 2解决高清屏截图模糊问题useCORS: true是加载本地Logo图片的关键addImage的坐标(100, 195)是反复调试出的签名栏位置确保打印时不会被裁切。实测在 Chrome 115 下生成 PDF 清晰度完全满足门店打印需求比后端生成快 3 倍无网络传输耗时。3.3 权限控制基于角色的按钮级细粒度拦截而非页面级粗放跳转眼镜店角色只有三类管理员全权限、店长可审核采购单、验光师仅能录验光、查会员。但「采购入库」按钮对验光师必须彻底隐藏而非点击后弹窗提示「无权限」——后者会暴露后台接口路径。Element Plus 的v-if结合 Vuex 状态实现!-- store/modules/user.js -- const state { userInfo: { role: optometrist, // admin | manager | optometrist permissions: [optometry:read, optometry:write, inventory:read] } } !-- 页面中按钮 -- el-button v-ifuserStore.userInfo.permissions.includes(inventory:write) clickopenPurchaseDialog 新建采购单 /el-button el-button v-ifuserStore.userInfo.permissions.includes(optometry:write) clickstartOptometry 开始验光 /el-button注意权限数组permissions在登录成功后由后端返回非前端硬编码每次路由切换时重新校验。这样即使用户手动修改 localStorage也无法绕过按钮渲染逻辑——因为按钮不存在连点击事件都注册不上。4. 数据流转与集成打通验光→配镜→库存→财务的业务闭环4.1 验光记录与配镜订单的强一致性用「乐观锁 事务回滚」保障数据不漂移当验光师提交验光记录后系统需自动生成一条待确认的配镜订单含推荐镜片、预估价格。但此时镜片库存可能被其他订单占用必须保证「验光成功」和「订单创建」原子性。MyBatis-Plus 的乐观锁在此场景比数据库行锁更轻量// 验光记录表增加 version 字段 TableField(fill FieldFill.INSERT) private Integer version; // 配镜订单实体 Data TableName(prescription_order) public class PrescriptionOrder { TableId(type IdType.ASSIGN_ID) private String id; private String optometryRecordId; // 关联验光记录ID TableField(fill FieldFill.INSERT) private Integer version; // 乐观锁版本号 } // Service 中的创建逻辑 Transactional(rollbackFor Exception.class) public void createOrderFromOptometry(String recordId) { // 1. 查询验光记录带 version OptometryRecord record optometryMapper.selectById(recordId); // 2. 检查镜片库存假设推荐镜片ID为 lensId LensInventory inventory inventoryMapper.selectById(record.getLensId()); if (inventory.getStock() 1) { throw new BusinessException(推荐镜片库存不足请更换); } // 3. 创建订单version 初始为 0 PrescriptionOrder order new PrescriptionOrder(); order.setOptometryRecordId(recordId); order.setVersion(0); orderMapper.insert(order); // 4. 更新验光记录的 version1同时校验原 version 未变 LambdaUpdateWrapperOptometryRecord updateWrapper new LambdaUpdateWrapper(); updateWrapper.eq(OptometryRecord::getId, recordId) .eq(OptometryRecord::getVersion, record.getVersion()) .set(OptometryRecord::getVersion, record.getVersion() 1); int updated optometryMapper.update(null, updateWrapper); if (updated 0) { throw new BusinessException(验光记录已被其他操作修改请刷新后重试); } }原理说明updateWrapper.eq(...).set(...)生成的 SQL 是UPDATE optometry_record SET version1 WHERE idxxx AND version0。若并发时另一线程已将 version 改为 1则此 SQL 影响行数为 0updated0触发回滚。相比SELECT FOR UPDATE锁表乐观锁在低冲突场景下性能更高且避免死锁风险。4.2 库存变动双记账业务表 流水表为财务对账留审计线索眼镜店老板最怕「账实不符」。单纯在frame_inventory表中stock stock - 1不够必须记录每一笔变动原因字段示例值说明idtx_20240520_001流水号日期序号business_typeSALE_OUT业务类型SALE_OUT销售出库、PURCHASE_IN采购入库、ADJUST盘盈盘亏related_idord_abc123关联业务单号如订单IDframe_idf_001镜架IDchange_amount-1变动数量负数为出库before_stock15变动前库存快照after_stock14变动后库存快照operator张验光师操作人// 库存服务中扣减方法 public void deductFrameStock(String frameId, Integer amount, String businessType, String relatedId, String operator) { FrameInventory inventory inventoryMapper.selectById(frameId); Integer beforeStock inventory.getStock(); Integer afterStock beforeStock - amount; if (afterStock 0) { throw new BusinessException(镜架库存不足当前库存 beforeStock); } // 1. 更新库存主表 inventory.setStock(afterStock); inventory.setLastSaleTime(LocalDateTime.now()); inventoryMapper.updateById(inventory); // 2. 插入流水记录 InventoryTransaction transaction new InventoryTransaction(); transaction.setId(tx_ LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE) _ getSequence()); transaction.setBusinessType(businessType); transaction.setRelatedId(relatedId); transaction.setFrameId(frameId); transaction.setChangeAmount(-amount); // 出库为负 transaction.setBeforeStock(beforeStock); transaction.setAfterStock(afterStock); transaction.setOperator(operator); transaction.setCreateTime(LocalDateTime.now()); transactionMapper.insert(transaction); }价值点财务月底对账时只需比对inventory_transaction表中business_typeSALE_OUT的SUM(change_amount)与prescription_order表中COUNT(*)是否一致再抽查几条related_id对应的订单详情即可。这种设计让「谁、何时、因何事、动了多少货」全部可追溯远超课程设计要求。5. 避坑指南那些让答辩老师皱眉、让系统上线即崩的5个血泪经验5.1 现象Vue 页面首次加载时验光单上的「左眼视力」显示为null但控制台无报错原因OptometryRecord实体类中leftVision字段类型为BigDecimal而 MySQL 对应列为DECIMAL(3,2)。当数据库存NULL时MyBatis-Plus 默认将null映射为BigDecimal.ZERO即0.00但前端v-model绑定null时会显示空字符串而0.00会显示为0造成视觉不一致。解决在OptometryRecord的leftVision字段上添加TableField(select false)改用String类型接收并在Select注解中用IFNULL(left_vision, )显式返回空字符串。5.2 现象导出 Excel 会员列表时手机号列显示为科学计数法如1.38E10原因Excel 默认将长数字识别为数值类型并自动转科学计数法。而poi-tl模板引擎未显式设置单元格格式。解决在 Apache POI 导出逻辑中为手机号列设置CellStyleCellStyle phoneStyle workbook.createCellStyle(); DataFormat format workbook.createDataFormat(); phoneStyle.setDataFormat(format.getFormat()); // 强制文本格式 cell.setCellStyle(phoneStyle); cell.setCellValue(member.getPhone());5.3 现象SpringBoot 启动时报错Failed to configure a DataSource但application.yml中已配置数据库原因使用了 HikariCP 连接池但spring.datasource.url中 JDBC URL 缺少serverTimezoneGMT%2B8参数MySQL 8.0 默认时区为 UTC导致连接认证失败。解决修正 URL 为jdbc:mysql://localhost:3306/eyeglass?useUnicodetruecharacterEncodingUTF-8serverTimezoneGMT%2B8allowPublicKeyRetrievaltrueuseSSLfalse。5.4 现象Vue 打包后部署到 Nginx访问/login路由返回 404原因Vue Router 使用history模式Nginx 未配置try_files规则导致/login请求直接被当作静态文件查找。解决在 Nginx 配置中添加location / { try_files $uri $uri/ /index.html; }5.5 现象验光师在平板电脑上录入验光数据点击「提交」后页面卡住Network 面板显示preflight请求 403原因SpringBoot 后端未正确配置 CORS浏览器对Content-Type: application/json的 POST 请求发起 OPTIONS 预检而CrossOrigin注解未覆盖 OPTIONS 方法。解决在 Controller 类上添加全局 CORS 配置CrossOrigin(origins *, methods {RequestMethod.GET, RequestMethod.POST, RequestMethod.PUT, RequestMethod.DELETE, RequestMethod.OPTIONS}) RestController RequestMapping(/api/optometry) public class OptometryController { ... }6. 毕业答辩加分项用「可验证的业务指标」替代「技术功能罗列」答辩时老师最想听的不是「我用了 Vue3」而是「这个系统如何帮眼镜店解决问题」。我建议你在 PPT 最后一页放一张真实的「业务价值对照表」用你本地测试数据说话业务环节传统方式耗时系统支持后耗时效率提升验证方式顾客验光数据录入平均 8 分钟/人手写→录入Excel→核对平均 2.3 分钟/人表单直填自动校验71%录制 10 位顾客操作视频统计平均时长镜片库存查询电话问仓库/翻纸质台账平均 5 分钟输入镜片型号0.8 秒返回库存位置99.7%Postman 调用/api/inventory/search?skuMY156计时月度销售分析财务手工汇总各门店日报耗时 2 天后台「数据看板」自动更新 TOP5 镜片销量100%截图看板页面标注「最后更新2024-05-20 08:30」会员积分兑换人工查积分手写兑换记录易出错扫码识别会员勾选商品10 秒完成95%拍摄扫码兑换全流程 GIF这张表背后是你真正跑通了「数据采集→存储→计算→展示」全链路。它不吹技术多炫只说「省了多少时间、减少多少错误、老板能立刻看到什么」。我在某高校指导学生答辩时有位同学凭这张表让三位老师当场追问细节最后以 96 分全场最高分通过——因为大家突然意识到这不是作业这是能落地的小型 SaaS。最后分享一个习惯每次写完一个功能我都会用「老板视角」问自己一句——如果现在把系统装进店里那台 Win10 旧电脑让店员阿姨点开就用她会不会迷路会不会输错会不会找不到昨天的单子答案永远指向最朴素的交互按钮位置是否符合右手操作习惯错误提示是否用「请检查镜片库存」而不是「ConstraintViolationException」打印预览是否默认 A4 横向这些细节不写在论文里但决定了你的系统是玩具还是工具。希望帮到你。本文还有配套的精品资源点击获取
RELATED

相关推荐

Java实现图片分块下载与断点续传:朋友圈九宫格场景优化实战

Java实现图片分块下载与断点续传:朋友圈九宫格场景优化实战

总有一些场景,做出来之后回头看特别简单,但踩坑的过程能让人想砸电脑。我这次要分享的,是一个在自研App里模拟朋友圈九宫格图集场景时,用Java实现的一套图片下载优化组件。核心就两件事:分块请求(HTTP Rang…

📅 2026/10/11 14:41:36
动态网格步长:用ATR+订单簿+价格位置自动调参

动态网格步长:用ATR+订单簿+价格位置自动调参

简介:本资源是一份面向量化投资初学者与Python编程实践者的网格交易策略优化方案,聚焦解决传统网格交易中因固定网格导致的过早满仓或空仓问题。作者提出基于市场波动性(收盘价、最高价、最低价标准差)与趋势判断(RSV指…

📅 2026/10/11 14:41:36
企业微信API Java SDK封装:Token管理、错误码处理与可测试性设计

企业微信API Java SDK封装:Token管理、错误码处理与可测试性设计

前阵子因为一个群机器人需求,我把企业微信API接口的Java SDK封装重新梳理了一遍。现在回头看,这次梳理最大的收获不是代码写得多花哨,而是确认了一个判断:所谓可复用、可测试,不是贴一大堆设计模式标签,而是…

📅 2026/10/11 14:41:36
MORE NEWS

更多资讯

📰

H5 Canvas粒子爆炸动画:轻量级60fps视觉特效实现

简介:这是一份面向前端开发者与HTML5动画学习者的Canvas粒子特效实战资源,聚焦于用原生JavaScript实现炫酷的文字背景爆炸动画,适用于网页动态视觉设计、交互式Banner开发及Canvas进阶练习。压缩包共6个文件,含3个JS脚本&#xff…

📰

Vibe-coding时代,Git就是你的刹车系统:基础操作与实战策略

开头先说个现象。最近不管是在技术群里还是线下交流里,到处都在讨论 Vibe-coding,就是你对着 AI 编辑器描述需求,让大模型一口气把功能代码写出来,你负责审、负责跑、负责修。很多人上手一玩,发现确实爽——一个周末能…

📰

Linux命令与终端快捷键:从入门到高效排查实战

搞 Linux 的朋友都有过这种经历:刚接触那会儿,命令抄了满满几页纸,一到真要干活的时候脑子一片空白;快捷键更是只用 CtrlC 和 CtrlV,连中断程序用的 CtrlC 都是在网上搜“怎么终止卡死的命令”才学会的。我用 Linux 当…

📰

OWASP Top 10 2021「Next Steps」全解读:代码质量、拒绝服务与内存管理三大风险域

应用安全 【免费下载链接】Top10 Official OWASP Top 10 Document Repository 项目地址: https://gitcode.com/gh_mirrors/top/Top10 点击查看 免费下载 本文基于 OWASP Top 10 2021 官方文档仓库中的 A11:2021 – Next Steps(印尼语版) 及其…

📰

Vitest Test API 完全指南:test/it 定义、修饰符、参数化与 Fixtures 实战

AI 技能人工智能 【免费下载链接】skills Anthony Fus curated collection of agent skills. 项目地址: https://gitcode.com/gh_mirrors/skills11/skills 点击查看 免费下载 导读 本文以 Vitest 5.x 为核心,系统讲解 test / it 测试定义函数及其全部修…

📰

PyTorch强化学习实现六轴机械臂实时轨迹规划:从仿真到部署

简介:《机器人运动控制新突破:PyTorch强化学习模型在六轴机械臂中的实时轨迹规划》是一份面向机器人控制与强化学习研究者的技术资料,旨在解决六轴机械臂实时轨迹规划中深度强化学习模型的设计与训练问题。内容覆盖机械臂运动学与动力学模型、…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬