ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

SpringBoot+Vue美发门店管理系统毕设实战:选题、设计与答辩全指南

SpringBoot+Vue美发门店管理系统毕设实战:选题、设计与答辩全指南 做毕设选管理系统类题目最怕的就是两种情况要么东西太简单答辩时三句话就讲完老师问几句就露馅要么业务逻辑太绕做完前面模块后面根本收不了尾。美发门店管理系统恰好卡在两者之间——它本质上是一个典型的人、货、场、单四要素管理系统但和图书管理、宿舍管理这类烂大街的题目相比又多了预约排班、会员卡扣费、员工提成这些真正有嚼头的业务点。我见过太多人选了商城项目最后被购物车和订单状态机折磨到怀疑人生也见过选图书管理然后被老师一句你这和课设作业有什么区别问得哑口无言。如果你正在纠结SpringBootVue方向的项目我可以很直接地告诉你美发门店管理系统大概是当前最适合拿来当毕设或者课设的题目之一。技术栈上它一套组合拳覆盖了主流前后端分离开发的所有环节业务上它有足够多的细节让你在答辩时有话可说工作量上单人完成大约四到六周时间正好卡在本科毕业设计的合理区间。下面我把自己做这类项目的完整思路、建表逻辑、核心代码要点以及那些在踩坑中总结出来的经验全部摊开来讲。1. 为什么美发门店管理是毕设黄金题目选型背后的真实考量先别急着写代码选型这件事搞明白你后面一个月都会过得舒服很多。很多同学一上来就想着越复杂越好实际上评审老师看重的从来不是功能数量而是你有没有把一个垂直场景做透。1.1 与常见毕设题目的横向对比我做过一个简单的对比把最近几年学生在管理系统选题上常用的方向拆开看你就明白差距在哪了题目方向业务复杂度技术亮点空间数据演示效果答辩提问风险图书管理极低几乎没有差纯增删改查高风险容易被问难点在哪宿舍管理低低一般中风险功能一眼望穿商城系统很高较高好高风险购物车/支付/订单状态机容易失控课堂考勤中中一般中风险场景较单薄美发门店管理中高高很好低风险业务细节丰富美发门店的妙处在于它同时占了三样东西预约时间片、会员卡储值、员工服务提成。这三个点任何一个展开都能做出一篇像样的设计说明而且它们之间有天然的联动——比如会员用卡结算一次染发服务系统需要同时扣减卡内余额、生成订单明细、记录员工提成、更新发型师排班状态。这种跨实体的数据一致性操作才是答辩时能够拿出台面的内容。1.2 技术栈定位SpringBootVue为什么是最稳组合SpringBoot负责后端接口Vue负责前端页面MySQL存数据这套组合在毕设场景里几乎是标准答案级别的存在。原因很朴素网上资料极度丰富任何报错都能搜到解决方案这对毕设周期来说就是保命前后端分离的模式贴合目前公司里真实项目的开发方式答辩时可以说通过该项目掌握了前后端分离开发的基本流程SpringBoot的自动配置大大降低了环境搭建成本你不需要像SSM时代那样折腾一堆XML配置Vue的组件化和Element UI这套成熟UI库搭配起来页面实现速度非常快我自己做这个项目的时候最开始也纠结过要不要上Redis做缓存要不要引入消息队列。后来想明白了毕设项目的评分核心是技术选型合理并且能说清楚为什么场景里面要用。美发门店这种数据量级别的系统Redis确实用得上但没那么必要硬上反而显得堆砌。倒是可以预留一两个可扩展的技术点比如首页统计报表的缓存、短信提醒预约成功等把扩展思路写在论文里能显著提升项目的层次感。2. 从理发店的实际业务拆解核心模块与数据库建表设计很多人的第一反应是打开Navicat就开始建表建着建着发现表之间的关系理不清。我的习惯是先画业务流程图从顾客进门到离店整个流程里面涉及到哪些角色、哪些单据、哪些状态转换。把流程吃透了表结构自然就出来了。2.1 门店真实业务流程梳理一家正常营业的美发门店最简单的服务流程是这样的顾客到店或者线上预约系统记录预约时间、服务项目、指定发型师前台开单选择服务项目和套餐录入顾客信息发型师执行服务服务完成后确认订单完成收银台结算顾客可以选择现金支付、微信/支付宝或者使用会员卡余额如果是会员卡支付系统扣减卡内余额/次数并记录本次消费积分后端生成消费记录更新员工业绩和提成报表这个流程里已经包含了五个核心实体顾客会员、员工发型师、服务项目、预约单、订单。还没算套餐卡、折扣规则、门店信息这些支撑型数据。做管理系统最忌讳的就是把表建得又碎又多最后关联查询写到想哭。我的建议是控制在8到12张核心表之间既能覆盖业务又不至于把自己绕晕。2.2 核心表结构与关键字段设计我先把我认为最核心的几张表的建表SQL列出来你参考一下重点看状态字段和关联字段的设计思路-- 顾客表也是会员表非会员顾客注册后自动成为普通等级会员 CREATE TABLE customer ( id INT PRIMARY KEY AUTO_INCREMENT COMMENT 顾客ID, phone VARCHAR(20) NOT NULL UNIQUE COMMENT 手机号登录账号, password VARCHAR(100) NOT NULL COMMENT 登录密码BCrypt加密, name VARCHAR(50) NOT NULL COMMENT 姓名, gender TINYINT DEFAULT 0 COMMENT 性别 0未知 1男 2女, level TINYINT DEFAULT 0 COMMENT 会员等级 0普通 1银卡 2金卡 3钻石, balance DECIMAL(10,2) DEFAULT 0 COMMENT 卡内储值余额, total_points INT DEFAULT 0 COMMENT 累计积分, create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 注册时间, status TINYINT DEFAULT 1 COMMENT 状态 1正常 0冻结 ) COMMENT 顾客会员表; -- 服务项目表 CREATE TABLE service_item ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50) NOT NULL COMMENT 服务名称如精剪、染发、烫发, category VARCHAR(30) COMMENT 分类剪发/烫染/护理/造型, duration INT NOT NULL COMMENT 预计耗时分钟, price DECIMAL(10,2) NOT NULL COMMENT 门市价, member_price DECIMAL(10,2) COMMENT 会员价, status TINYINT DEFAULT 1 COMMENT 1上架 0下架 ) COMMENT 服务项目表; -- 预约表 CREATE TABLE appointment ( id INT PRIMARY KEY AUTO_INCREMENT, customer_id INT NOT NULL COMMENT 顾客ID, staff_id INT NOT NULL COMMENT 指定发型师ID, service_item_id INT NOT NULL COMMENT 服务项目ID, appointment_date DATE NOT NULL COMMENT 预约日期, start_time TIME NOT NULL COMMENT 预约开始时间, end_time TIME NOT NULL COMMENT 预计结束时间, status TINYINT DEFAULT 0 COMMENT 0待确认 1已确认 2已完成 3已取消, remark VARCHAR(255) COMMENT 顾客备注, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY uk_staff_time (staff_id, appointment_date, start_time) ) COMMENT 预约表;上面这个预约表里有个小细节我加了一个联合唯一索引uk_staff_time。这个索引的作用很关键它从数据库层面锁死了同一个发型师在同一个日期同一个开始时间只能有一条预约记录这比在Java代码里先查再插要靠谱得多后面讲并发问题时会详细说。订单表我就不贴完整SQL了但字段一定要包含订单号、顾客ID、员工ID、服务项目ID、订单金额、会员支付金额、现金支付金额、卡号流水、优惠金额、订单状态待支付/服务中/已完成/已取消/已退款、创建时间、完成时间。特别注意订单号不要用自增ID建议用日期随机数方式生成这样既方便查询又不会泄露业务量。2.3 套餐卡与充值记录把会员体系做成加分项会员卡是这个项目的灵魂之一也是很多同学容易做砸的地方。一套完整的会员体系至少要包含三张表会员卡表卡号、持卡人ID、卡类型、余额、有效期、状态、充值记录表充值单号、顾客ID、充值金额、赠送金额、充值时间、操作员、消费记录表关联订单号、卡号、消费金额、消费时间。这里有个业务细节要提前想清楚会员卡支付时余额不足怎么办是允许部分扣款然后补差额还是直接拒绝整单只能换支付方式我当时的做法是检查余额是否够支付会员价折扣后的金额够就整单从卡里扣不够就提示余额不足请选择其他支付方式避免出现订单拆分后对账困难的局面。这个规则虽然朴素但在答辩时能解释清楚还能反衬出你对边界情况的考虑。充值赠金的规则也值得设计一下比如充1000送200这种常见的营销策略。我的方案是充值金额和赠送金额分开存储这样后续报表统计实收充值和赠送成本时不用对着明细绞尽脑汁直接SUM两个字段就行。3. 后端核心实现权限、预约冲突与订单状态机的三种硬骨头建表只是地基真正让这个项目有价值的是后端接口设计里那几块硬骨头。我把它们单独拎出来讲每一块都是你在答辩时可以展开说的技术点。3.1 JWT登录认证与接口权限控制SpringBoot做登录认证方案其实就那么几个Session、Token、JWT。我在系统里用的是JWTSpringMVC拦截器的方式理由也不复杂前后端分离架构下前端可能部署在Nginx上、后端跑在独立端口Session跨域处理比较麻烦JWT天然无状态请求头里带token就能识别身份JWT的payload部分可以携带用户ID、角色等非敏感信息后端不用每次查数据库确认这个用户是谁配合拦截器做白名单控制安全性可控代码量也不大核心逻辑分三步。第一步登录接口校验手机号和密码密码用BCrypt加密存储千万别明文存校验通过后生成token返回前端。第二步写一个拦截器配置放行路径比如/api/auth/login、/api/auth/register、静态资源路径其余接口一律校验请求头中的token。第三步写一个自定义注解RequireRole在需要权限控制的管理员接口上标注拦截器里对token中携带的角色进行二次校验。// 拦截器核心代码片段 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 放行预检请求 if (OPTIONS.equalsIgnoreCase(request.getMethod())) { return true; } String token request.getHeader(Authorization); if (token null || token.isEmpty()) { // 返回401前端根据状态码跳转登录页 response.setStatus(401); return false; } try { Claims claims JwtUtil.parseToken(token); request.setAttribute(userId, claims.get(userId)); request.setAttribute(userRole, claims.get(role)); // 检查是否有RequireRole注解 if (handler instanceof HandlerMethod) { HandlerMethod handlerMethod (HandlerMethod) handler; RequireRole requireRole handlerMethod.getMethodAnnotation(RequireRole.class); if (requireRole ! null) { String requiredRole requireRole.value(); if (!requiredRole.equals(claims.get(role))) { response.setStatus(403); return false; } } } return true; } catch (Exception e) { response.setStatus(401); return false; } }这个方案我在多个项目里反复用过稳定性没问题。要注意的坑是JWT的密钥不要硬编码在代码里放到application.yml配置项里key的复杂度尽量高一点否则存在被暴力解密的隐患。3.2 预约冲突的数据库级与业务级双重校验预约功能最核心的问题不是增删改查而是时间片冲突。一个发型师一天10个小时、每个项目耗时30到90分钟不等怎么保证同一个时间段不被重复预约我的方案是双重校验。第一重在写预约接口前先用SQL查询判断SELECT COUNT(*) FROM appointment WHERE staff_id #{staffId} AND appointment_date #{date} AND status IN (0, 1) AND ( (start_time #{endTime} AND end_time #{startTime}) )这个时间段重叠判断是精髓新预约的开始时间必须晚于已有预约的结束时间或者新预约的结束时间必须早于已有预约的开始时间否则就认为存在重叠。第二重就是前面建表时提到的联合唯一索引当极端情况下两个人同时提交预约请求数据库层的约束也能兜底。这里要特别说明为什么要查status IN (0, 1)已取消的预约不应该占用时间片已完成的预约不应该影响未来排班这两个状态得排除在外。不少新手会漏掉这个条件最后排班逻辑一团乱麻。3.3 订单状态机与会员卡扣费的并发处理订单状态看起来简单做起来非常容易翻车。我画状态流转的时候反复确认了一个原则订单的状态只能按固定方向流动不能跳转。待支付 - 已支付 - 服务中 - 已完成 待支付 - 已取消 已支付 - 已退款比如一笔待支付订单你可以取消但一笔已完成订单你想把它改回待支付这在逻辑上就是不允许的。我在Service层做状态更新时会在SQL里加上当前状态的WHERE条件UPDATE order SET status 1 WHERE id #{id} AND status 0这条语句的返回值如果是0说明当前订单状态不是待支付可能是被人改了也可能是重复提交此时就抛出业务异常提示订单状态已变更请刷新后重试。这个机制比先查询再判断要安全得多能防止并发情况下状态被覆盖。会员卡扣费属于资金类操作尤其要注意并发场景两个订单同时用一张卡结算如果查余额和扣余额之间存在时间窗口就可能出现余额扣成负数的情况。最稳妥的办法是用带条件更新的SQLUPDATE customer SET balance balance - #{amount} WHERE id #{customerId} AND balance #{amount}返回受影响行数为0就说明余额不足。这种原子操作方式虽然只是单行SQL却是并发正确性的重要保障答辩时完全可以展开讲。4. 前端Vue落地路由权限、axios封装与前后端联调那些事后端接口写得再漂亮前端页面拉胯一样白搭。美发门店管理系统的前端我用的是Vue2 Element UI Axios的组合选Vue2而不是Vue3的原因纯粹是生态稳定、坑少毕设项目求稳为主。4.1 前端项目结构与角色菜单渲染前端项目结构我习惯这样组织src/ |-- api/ // 存放所有接口请求方法按模块拆分 |-- assets/ // 静态资源 |-- components/ // 公共组件 |-- router/ // 路由配置 |-- store/ // Vuex状态管理 |-- utils/ // 封装的工具类axios实例等 |-- views/ // 页面组件 |-- admin/ // 管理员端 |-- staff/ // 员工端 |-- customer/ // 顾客端H5端或桌面端前端里最值得讲的是路由守卫和动态菜单。管理员、发型师、顾客三种角色登录后能看到的菜单和能访问的页面应该不一样。我采取的方式是登录成功后后端返回一个角色标识前端在路由守卫里根据角色调用后端接口获取当前角色允许访问的菜单列表动态挂载路由。// 路由守卫核心代码 router.beforeEach((to, from, next) { const token localStorage.getItem(token); if (to.path /login) { next(); return; } if (!token) { next(/login); return; } const role localStorage.getItem(role); // 检查当前路由是否在该角色允许访问的meta.roles数组中 if (to.meta.roles to.meta.roles.indexOf(role) -1) { next(/403); return; } next(); });这里有个小技巧路由的meta字段里直接声明roles: [admin, staff]表示这个页面允许哪些角色访问。原理虽然简单但把权限控制从隐藏菜单升级到了路由跳转拦截安全性提升了一个档次老师问到的时候你也能讲出东西来。4.2 axios统一封装与带token的请求处理联调阶段最烦的就是一堆请求各自处理token和错误提示代码写得到处重复。我的做法是封装一个统一axios实例// utils/request.js 核心封装 import axios from axios; const service axios.create({ baseURL: /api, timeout: 10000 }); // 请求拦截器自动携带token service.interceptors.request.use(config { const token localStorage.getItem(token); if (token) { config.headers[Authorization] token; } return config; }, error Promise.reject(error)); // 响应拦截器统一处理业务码和异常 service.interceptors.response.use(response { const res response.data; // 后端返回格式约定{ code: 200, message: 成功, data: {...} } if (res.code ! 200) { // 业务错误统一弹提示 Message.error(res.message || 请求失败); return Promise.reject(new Error(res.message)); } return res.data; }, error { if (error.response error.response.status 401) { // 登录过期清除本地信息并跳转登录页 localStorage.clear(); router.push(/login); } else { Message.error(error.message || 网络异常); } return Promise.reject(error); });封装好了以后每个页面里的接口调用只管业务逻辑不用再关心token和错误处理这些通用逻辑。联调时如果遇到明明登录了但接口还是401先看浏览器控制台里请求头有没有带Authorization再确认拦截器有没有被正确引入八成问题都出在这两个地方。前后端联调另一个高频坑就是跨域。在Vue的vue.config.js里配置代理是最省事的方案前后端都在本地开发时前端开发服务器把/api开头的请求代理到后端的8080端口即可后端就不需要额外加CrossOrigin注解了。等到部署阶段再用Nginx统一处理开发体验和线上架构都能兼顾。4.3 日期的处理方式前端组件与后端格式对不齐做预约功能时有个埋点特别深、但是几乎人人都会踩的坑时间格式。前端Element UI的el-date-picker组件返回的日期是YYYY-MM-DD但如果用了自动带时间的typedatetime返回值会变成YYYY-MM-DD HH:mm:ss。如果你直接把字符串往MySQL的DATE或TIME字段里塞很容易出现看起来存进去了查出来发现时间不对的诡异问题。我的建议是前端传日期时分两个字段传日期用YYYY-MM-DD时间用HH:mm后端实体类用字符串接收在Service层统一用LocalDate和LocalTime接收并校验格式。千万别在Java实体里用Date去接前端的字符串时区转换和格式解析会让你怀疑人生。5. 打包部署与启动排错环境变量、端口占用、数据库连接项目跑通了接下来就是打包部署。很多同学写完代码以为万事大吉结果在本地能跑服务器跑不起来这个环节卡了两三天。我把我踩过的坑集中说一下。5.1 前端打包与后端发布的正确姿势后端发布非常简单Maven项目执行mvn clean package -DskipTests然后拿生成的jar包直接java -jar启动。前端先用npm run build打包生成一个dist目录里面全是静态文件。生产环境的部署架构分两种。第一种是前后端完全分开dist里的静态文件交给Nginx托管Nginx把/api开头的请求反向代理到后端Java服务这样可以省掉跨域配置。第二种是图省事把前端打包结果放进SpringBoot的src/main/resources/static目录这样只启动一个Java进程就能同时访问页面和接口适合课设答辩前的演示环境。我建议至少了解第一种方式因为Nginx反向代理是真实项目中必然要掌握的内容。5.2 最常见的三类启动报错与排查思路数据库连接报错这个排到第一名当之无愧。常见错误信息有Communications link failure、Access denied for user前者是IP、端口、防火墙问题后者是账号密码和权限问题。还有MySQL 8.x的驱动加载问题记得在pom里用mysql-connector-j8.0.33或更新版本并在JDBC URL后面加上useSSLfalseserverTimezoneAsia/ShanghaicharacterEncodingutf8。端口被占用后端的8080被其他进程占用了启动直接报Port already in use。Linux下用netstat -tlnp | grep 8080找到进程IDdebug排查之前如果有多个测试进程残留逐个清理掉。Windows下用netstat -ano | findstr 8080然后到任务管理器里结束对应PID的进程。前端页面打开了但接口404通常是因为Nginx里没有配好location /api的反向代理或者代理指向的后端端口不对。先用curl直接请求后端接口确认后端本身能通再排查Nginx配置。# Nginx配置示例 location / { root /usr/share/nginx/html; index index.html; try_files $uri $uri/ /index.html; # 解决Vue路由刷新404 } location /api/ { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; }try_files $uri $uri/ /index.html;这行是前端路由history模式部署的必备配置漏掉的情况下直接访问某个子页面比如/admin/order会因为找不到对应物理文件返回404。这个坑我帮人排查过不止一次九成的人第一次部署都会踩到提前写进配置里能省去一大段麻烦。5.3 两个隐藏较深的运行时风险一个是控制台打印的PDF字体报错如果项目里有导出报表或PDF的功能Linux服务器上没装字体就会出现中文乱码或者报错需要安装fontconfig和中文字体包。另一个是MySQL的时区问题。serverTimezoneAsia/Shanghai只是让驱动正确读取数据库时区但你在Java代码里生成时间字段时最好统一用LocalDateTime.now()而不是new Date()否则会出现服务器存的时间比实际慢8小时的问题。6. 从能跑到高分提前准备的答辩加分项项目做完只是第一步答辩的表现往往决定了最终成绩的走向。我给自己学员的建议是留出三天时间专门把技术细节整理成答辩话术。6.1 三个可以展开讲的技术亮点第一个是数据库层面的并发安全控制。不要只说我用了事务要把事务和具体的业务场景绑在一起会员卡扣费时用带余额条件更新的SQL确保余额不会被扣成负数订单状态更新时用带当前状态的WHERE条件防止状态跳转。这种挑战—方案—验证的叙述结构评审老师是最爱听的。第二个是预约排班的时间片校验。从时间段重叠的SQL判断讲到联合唯一索引兜底展示的是你对并发场景的思考深度。如果能再补一句把已取消和已完成的预约排除在冲突检测之外老师马上会觉得你仔细推敲过业务边界。第三个是权限控制的层次性。JWT无状态认证 拦截器统一鉴权 路由守卫前端兜底 动态菜单渲染四个层级每个都有清晰的职责这是一个完整的权限设计方案。答辩时用前端是方便用户、后端是保障安全来概括整个思路逻辑非常清晰。为了验证这些设计是否站得住脚我在开发完成后用JMeter做了一轮简单的压力测试模拟50个并发用户同时发起预约请求结果没有出现超卖或状态错乱的问题数据库层的唯一索引成功拦截了冲突写入。这个测试数据写进论文的结果分析部分比单纯的测试通过四个字有说服力得多。6.2 扩展方向技术上留出的想象空间如果你的时间充裕下面这几个方向可以挑选一两个做出来立刻让项目从课设级别跳到优秀毕设级别首页数据看板接入ECharts把当日营收、预约量、会员消费占比、员工业绩排行用图表展示出来。数据看板是最直观的成果展示道具演示时一眼就能看出工作量。项目导入导出的Excel报表用EasyExcel生成月度营业报表一键导出。这个功能业务价值高、实现成本低属于性价比最高的扩展。预约成功后的短信/邮件提醒接入阿里云短信或者用QQ邮箱的SMTP服务预约成功后自动发送提醒。这个小功能能体现系统闭环的思路。微信公众号端适配让顾客在手机端完成自助预约和充值。工作量稍大但做出来之后整个项目的完整度和演示冲击力完全不一样。我在做的时候实际选了前两个。ECharts看板大概花了一天半就完成了效果却非常惊艳答辩时老师盯着大屏数据看了好一会儿EasyExcel导出功能用了半天写了一个通用的导出工具类后面所有表格都能复用。这两个功能是投入产出比最高的。6.3 答辩时最可能被问到的问题清单提前把这些问题过一遍答辩时不至于被问懵为什么选择JWT而不是Session——因为前后端分离架构需要无状态认证JWT跨域友好服务端不用维护会话状态。预约冲突是怎么解决的——时间段重叠查询加数据库唯一索引双重保障。会员卡扣费时如果两个人同时消费怎么办——使用原子化的条件UPDATE余额不足则更新失败不会出现超扣。前端页面刷新后为什么会404——history路由模式刷新触发服务端404需要Nginx配置try_files回退到index.html。用户密码是怎么存的——BCrypt加盐哈希数据库不存明文登录时用BCrypt校验。项目有哪些可以改进的地方——可以引入Redis缓存热点数据增加消息队列处理预约通知服务拆分成微服务等。注意这里不要给自己挖坑说出方向并且说明理由即可。这些问题我全部模拟过每一条都能在一分钟内讲清楚核心逻辑。如果全部背下来有困难至少要把第1、2、3条练熟它们是区分照着教程做完和真正理解项目的分水岭。写在最后做这个项目我最有共鸣的两点体会一个是先理业务、再写代码的节奏感。我第一次做类似的管理系统时着急忙慌地建了20张表改来改去浪费了大量时间。后来养成习惯花一整天把业务流程和状态流转图画清楚表面上耽误了时间实际后面几周的开发效率翻了一倍。美发门店这个场景特别适合练这一关因为流程不复杂但细节多画清楚了你就会对数据建模这件事有自己的理解。另一个是卡壳超过一小时就停手的原则。开发过程中遇到MySQL8小时连接断连、Vue打包路径错误这种问题搜索引擎上翻来翻去可能一晚上就没了。不如起身倒杯水把问题按环境/代码/数据三个维度拆分逐个排查。经验值慢慢累积之后你会发现大部分报错的解决思路其实就是看日志、查配置、搜报错原文这三板斧。如果你正准备拿这个题目开工我的建议很简单先把数据表和接口文档定下来再碰前端页面先跑通核心流程预约—开单—结算—办卡再补报表和权限这类锦上添花的东西。这个顺序做下来你大概率会在某个深夜突然意识到——原来从零做一个能上线的管理系统真的没有想象中那么难。
返回列表