基于SpringBoot+VUE的宠物医院后台管理系统【源码开源】【建议收藏】
今天给大家开源一个基于SpringBoot+VUE的宠物医院后台管理系统,系统基于脚手架工程,花了大概1周时间做出来的。
该系统完全开源。
系统完美运行,无任何的bug,技术较多,可以当做
面试的项目或者作为毕设的项目。
通过本项目你可以学到:
- 项目是怎样前后端分离的
- vue 是如何用于后台管理的
- 如何用MyBaitsPlus 代码生成器生成代码的
- 单表增删改查(包括分页模糊查询)
- 批量删除
- 基于RBAC的权限管理是如何设计的
- 菜单管理又是如何实现的
- 文件上传的实现
- 导入导出
- 主从表的数据是如何在前端呈现的
- …
** 获取源码的方式见文章底部。**
为防止刷着刷着找不到,大家点赞、收藏文章。
具体的介绍如下所示。
1.技术介绍
核心技术:SpringBoot+MyBatis-Plus;
前端:vue+elementui;
开发工具:Idea,VS Code, Git;
数据库:mysql5.7;
2.系统设计
本系统考虑的应用场景是在宠物店或宠物医院里, 主要有预约管理、药品管理、订单管理、充值管理等功能。
主要分了用户、医生和管理员三个角色。每个角色登录系统会有不同的菜单功能呈现,页面中不同的角色有不同的权限。各角色可访问的菜单都由管理员进行配置。
2.1系统功能设计

2.2预约流程

2.3就诊流程

2.4商品流程

2.5充值流程

3.功能介绍
3.1登录或注册

没有账号可以注册账号,当前只开放 普通用户的注册。对于医生和管理员的注册,由系统管理员在管理段注册。(默认管理员的账号和密码都是 admin)
登录之后,后台会菜单和权限的配置生成相应数据告知前端,前端进入相应的模块。
4.用户端
4.1就诊预约
用户可以查看所有医生信息,并根据宠物病情选择预约对应的医生预约排队(即添加预约信息)。
4.2预约管理
用户查看自己的预约信息,查看预约审核状态;并实现预约信息的添加,修改,删除,查询功能。
4.3药品管理
用户可以查询治疗宠物需要用到的所有药品或食品,针对自己宠物需要用到的商品可以进行订购(不能对商品实现添加,修改,删除功能)。
4.4订单管理
用户可以查看自己的所有商品订单,并实现修改,删除,查询功能,针未支付的订单可以进行支付,收到商品以后进行确认收货。

4.5充值中心
用户针对自己的账户进行余额充值。每笔充值记录及消费记录都可查询到。
4.6个人中心
用户可以查看自己的个人信息,并实现修改功能(例如:修改账号,密码等)。

5.医生端
医生的注册目前只能由管理员在管理员端进行注册,暂不开放自己注册。
5.1预约管理
医生可以查询预约了自己的所有预约信息,实现预约信息的添加,修改,删除,查询功能。
5.2诊断管理
针对每一个自己诊断的宠物进行记录,方便下次诊断时查询,实现就诊记录的添加,修改,删除,查询功能。

5.3.个人中心
医生可以查看自己的个人信息,并实现修改功能(例如:修改账号,密码等)。
(截图可参见前面用户端的)
6.管理员端
6.1.用户管理
查询所有普通用户信息,实现普通用户的添加,修改,删除,查询功能。
6.2.医生管理
查询所有医生信息,实现医生的添加,修改,删除,查询功能。
6.3.药品管理
查询所有治疗宠物的药品或食品信息,实现商品的添加,修改,删除,查询功能。
6.4.订单管理
查询用户的所有订单,针对已经付款的订单进行发货处理,针对已经完成的订单,以及未支付的订单可以进行删除处理,不能修改用户订单。
6.5.科室管理
查询科室信息,实现科室的添加,修改,删除,查询功能。
6.6.宠物种类管理
查询宠物种类信息,实现科室的添加,修改,删除,查询功能。
6.7.个人中心
管理员查询自己的个人信息,并可以实现修改功能(例如:修改账号,密码等)。
(截图可参见前面用户端的)
7.核心代码
/**
* <p>
* 订单管理控制器
* </p>
*
* @author
* @since 2023-04-24
*/@RestController@RequestMapping("/order")publicclassOrderController{@ResourceprivateIOrderBaseService orderBaseService;@ResourceprivateIOrderItemService orderItemService;@ResourceprivateIDrugService drugService;@ResourceprivateIUserService userService;privatefinalString now =DateUtil.now();// 新增或者更新@PostMappingpublicResultsave(@RequestBodyOrderDTO orderDTO){if(orderDTO.getItems()==null|| orderDTO.getItems().size()<1){returnResult.error(Constants.CODE_400,"参数错误.订单缺少项目信息");}if(StringUtils.isEmpty(orderDTO.getReceiverPhone())){returnResult.error(Constants.CODE_400,"参数错误.请提供收货人电话");}if(StringUtils.isEmpty(orderDTO.getReceiverAddress())){returnResult.error(Constants.CODE_400,"参数错误.请提供收货人地址");}//判断用户是否存在QueryWrapper<User> queryWrapperCustom =newQueryWrapper<>();
queryWrapperCustom.eq("username", orderDTO.getUserName());
queryWrapperCustom.eq("role",RoleEnum.ROLE_USER.toString());User findUser = userService.getOne(queryWrapperCustom);if(null== findUser){returnResult.error(Constants.CODE_404,"用户不存在");}if(orderDTO.getRemark()==null){
orderDTO.setRemark("");}BigDecimal totalAmount =newBigDecimal(0);OrderBase orderBase =newOrderBase();
orderBase.setStatus(OrderBase.OrderStatus.UN_PAY);
orderBase.setPayMode(OrderBase.PayMode.UNKNOWN);
orderBase.setPayVoucherNo("");
orderBase.setUserId(findUser.getId());
orderBase.setUserName(findUser.getUsername());
orderBase.setReceiverPhone(orderDTO.getReceiverPhone());
orderBase.setReceiverAddress(orderDTO.getReceiverAddress());
orderBase.setRemark(orderDTO.getRemark());long oid =0;if(orderDTO.getId()==null){//添加操作OrderIdGenerator orderIdGenerator =newOrderIdGenerator();
oid = orderIdGenerator.nextId(this);
orderDTO.setId(oid);User currentUser =TokenUtils.getCurrentUser();
orderBase.setCreateName(currentUser.getUsername());
orderBase.setCreateBy(String.valueOf(currentUser.getId()));
orderBase.setCreateRole(currentUser.getRole());
orderBase.setCreateTime(newDate());}else{//更新操作
oid = orderDTO.getId();//找出原订单信息OrderBase oldOrder = orderBaseService.getById(oid);if(null== oldOrder){returnResult.error(Constants.CODE_404,"订单记录不存在.id="+ oid);}//只有待支付状态的订单才 可以 修改if(oldOrder.getStatus()!=OrderBase.OrderStatus.UN_PAY){returnResult.error(Constants.CODE_600,"只有待支付状态的订单才可以修改 .id="+ oid);}
orderBase.setCreateName(oldOrder.getCreateName());
orderBase.setCreateBy(oldOrder.getCreateBy());
orderBase.setCreateRole(oldOrder.getCreateRole());
orderBase.setCreateTime(oldOrder.getCreateTime());//删除原来项目 表的内容
orderItemService.delByOrderId(oid);}//先保存项目表int seq =0;String orderOverview ="";// 订单项目简要for(OrderItem orderItem: orderDTO.getItems()){
orderItem.setOrderId(oid);//处理 序号
seq++;
orderItem.setSeq(seq);if(orderItem.getItemId()==null){returnResult.error(Constants.CODE_400,"参数错误. 订单项目id为Null");};if(orderItem.getQty()==null){returnResult.error(Constants.CODE_400,"参数错误. 订单项目数量为Null");}if(orderItem.getQty()<=0){returnResult.error(Constants.CODE_400,"参数错误. 订单项目数量必须大于0");}//数据库中查找商品是否存在Drug drug = drugService.getById(orderItem.getItemId());if(null== drug){returnResult.error(Constants.CODE_400,"参数错误. 商品不存在. 项目id="+ orderItem.getItemId());}
orderItem.setPrice(drug.getRetailPrice());
orderItem.setName(drug.getName()+" "+ drug.getProductName());
orderItem.setUnit(drug.getUnit());
orderOverview +="|";
orderOverview += orderItem.getName();//计算合计
totalAmount = totalAmount.add(orderItem.getPrice().multiply(newBigDecimal(orderItem.getQty())));if(!orderItemService.save(orderItem)){returnResult.error(Constants.CODE_600,"业务异常.无法保存某订单的项目.项目id="+ orderItem.getItemId());};}
orderOverview +="|";if(orderOverview.length()>128){
orderOverview = orderOverview.substring(0,127);}
orderBase.setId(oid);
orderBase.setOverview(orderOverview);
orderBase.setAmount(totalAmount);//再保存主表的if(orderBaseService.saveOrUpdate(orderBase)){returnResult.success();}else{returnResult.error(Constants.CODE_600,"业务异常.保存订单主表失败");}}@DeleteMapping("/{id}")publicResultdelete(@PathVariableLong id){OrderBase orderBase = orderBaseService.getById(id);if(null== orderBase ){returnResult.error(Constants.CODE_404,"订单不存在. 订单id="+ id );}//只能删除未支付或已签收的订单if(orderBase.getStatus()==OrderBase.OrderStatus.UN_PAY ||
orderBase.getStatus()==OrderBase.OrderStatus.SIGN ){;}else{returnResult.error(Constants.CODE_600,"无效订单状态.只能删除未支付或已签收的订单");}//先删除项目表的记录
orderItemService.delByOrderId(id);
orderBaseService.removeById(id);returnResult.success();}@PostMapping("/del/batch")publicResultdeleteBatch(@RequestBodyList<Long> ids){//先删除项目表的记录for(Long id: ids){
orderItemService.delByOrderId(id);}
orderBaseService.removeByIds(ids);returnResult.success();}@GetMappingpublicResultfindAll(){returnResult.success(orderBaseService.list());}@GetMapping("/{id}")publicResultfindOne(@PathVariableLong id){returnResult.success(orderBaseService.getById(id));}@GetMapping("/page")publicResultfindPage(@RequestParam(defaultValue ="")String userName,@RequestParamInteger pageNum,@RequestParamInteger pageSize){QueryWrapper<OrderBase> queryWrapper =newQueryWrapper<>();
queryWrapper.orderByDesc("create_time");if(!"".equals(userName)){
queryWrapper.like("user_name", userName);}User currentUser =TokenUtils.getCurrentUser();if(currentUser.getRole().equals(RoleEnum.ROLE_USER.toString())){//普通用户只能查看自己的预约记录
queryWrapper.eq("user_id", currentUser.getId());}Object object = orderBaseService.page(newPage<>(pageNum, pageSize), queryWrapper);returnResult.success(object);//return Result.success(orderBaseService.page(new Page<>(pageNum, pageSize), queryWrapper));}@GetMapping("/items/{id}")publicResultfindOrderItems(@PathVariableLong id){//查找订单项目列表QueryWrapper<OrderItem> queryWrapper =newQueryWrapper<>();
queryWrapper.orderByDesc("seq");
queryWrapper.eq("order_id", id);returnResult.success(orderItemService.list(queryWrapper));}/**
* 导出接口
*/@GetMapping("/export")publicvoidexport(HttpServletResponse response)throwsException{// 从数据库查询出所有的数据List<OrderBase> list = orderBaseService.list();// 在内存操作,写出到浏览器ExcelWriter writer =ExcelUtil.getWriter(true);// 一次性写出list内的对象到excel,使用默认样式,强制输出标题
writer.write(list,true);// 设置浏览器响应的格式
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");String fileName =URLEncoder.encode("OrderBase信息表","UTF-8");
response.setHeader("Content-Disposition","attachment;filename="+ fileName +".xlsx");ServletOutputStream out = response.getOutputStream();
writer.flush(out,true);
out.close();
writer.close();}/**
* excel 导入
* @param file
* @throws Exception
*/@PostMapping("/import")publicResultimp(MultipartFile file)throwsException{InputStream inputStream = file.getInputStream();ExcelReader reader =ExcelUtil.getReader(inputStream);// 通过 javabean的方式读取Excel内的对象,但是要求表头必须是英文,跟javabean的属性要对应起来List<OrderBase> list = reader.readAll(OrderBase.class);
orderBaseService.saveBatch(list);returnResult.success();}@PostMapping("/delivery/{id}")publicResultdelivery(@PathVariableLong id){//发货//判断订单是否存在OrderBase orderBase = orderBaseService.getById(id);if(null== orderBase){returnResult.error(Constants.CODE_404,"订单不存在.订单id="+ id);}//判断订单是否已经支付if(orderBase.getStatus()==OrderBase.OrderStatus.PAYED){}else{returnResult.error(Constants.CODE_600,"订单不是已支付状态, 不允许发货.");}if(orderBaseService.updateDeliveryInfo(id,OrderBase.OrderStatus.DELIVERED,newDate())>0){returnResult.success(orderBaseService.getById(id));}else{returnResult.error(Constants.CODE_600,"业务异常.更新订单发货信息失败");}}@PostMapping("/sign/{id}")publicResultsign(@PathVariableLong id){//签收,//判断订单是否存在OrderBase orderBase = orderBaseService.getById(id);if(null== orderBase){returnResult.error(Constants.CODE_404,"订单不存在.订单id="+ id);}//判断订单是否已经支付if(orderBase.getStatus()==OrderBase.OrderStatus.DELIVERED){;}else{returnResult.error(Constants.CODE_600,"订单不是已发货状态, 不允许签收.");}if(orderBaseService.updateSignInfo(id,OrderBase.OrderStatus.SIGN,newDate())>0){returnResult.success(orderBaseService.getById(id));}else{returnResult.error(Constants.CODE_600,"业务异常.更新订单签收信息失败");}}privateUsergetUser(){returnTokenUtils.getCurrentUser();}}
/**
* <p>
* 预约管理控制器
* </p>
*
* @author
* @since 2023-04-23
*/@RestController@RequestMapping("/appointment")publicclassAppointmentController{@ResourceprivateIAppointmentService appointmentService;@ResourceprivateIUserService userService;@ResourceprivateIDoctorService doctorService;privatefinalString now =DateUtil.now();// 新增或者更新@PostMappingpublicResultsave(@RequestBodyAppointment appointment){if(appointment.getAppointmentTime()==null){returnResult.error(Constants.CODE_400,"参数错误:请提供预约时间");}//查找顾客信息QueryWrapper<User> queryWrapperCustom =newQueryWrapper<>();
queryWrapperCustom.eq("username", appointment.getCustomName());
queryWrapperCustom.eq("role",RoleEnum.ROLE_USER.toString());User findCustom = userService.getOne(queryWrapperCustom);if(null== findCustom){returnResult.error(Constants.CODE_404,"顾客不存在");}
appointment.setCustomId(findCustom.getId());
appointment.setCustomName(findCustom.getUsername());
appointment.setCustomPhone(findCustom.getPhone());//查找医生信息QueryWrapper<User> queryWrapperDoctor =newQueryWrapper<>();
queryWrapperDoctor.eq("username", appointment.getDoctorName());
queryWrapperDoctor.eq("role",RoleEnum.ROLE_DOCTOR.toString());User findDoctor = userService.getOne(queryWrapperDoctor);if(null== findDoctor){returnResult.error(Constants.CODE_404,"医生不存在");}
appointment.setDoctorId(findDoctor.getId());
appointment.setDoctorName(findDoctor.getUsername());
appointment.setDoctorPhone(findDoctor.getPhone());if(appointment.getRemark()==null){
appointment.setRemark("");}if(appointment.getId()==null){//添加操作
appointment.setStatus(Appointment.AppointmentStatus.WAIT_AUDIT);User currentUser =TokenUtils.getCurrentUser();
appointment.setCreateName(currentUser.getUsername());
appointment.setCreateBy(String.valueOf(currentUser.getId()));
appointment.setCreateRole(currentUser.getRole());
appointment.setCreateTime(newDate());}else{//更新操作if(appointment.getStatus()==null){returnResult.error(Constants.CODE_400,"参数错误:请提供预约状态");}//不更新原 创建人信息Appointment oldAppointment = appointmentService.getById(appointment.getId());if(null==oldAppointment){returnResult.error(Constants.CODE_404,"预约记录不存在");}
appointment.setCreateName(oldAppointment.getCreateName());
appointment.setCreateBy(oldAppointment.getCreateBy());
appointment.setCreateRole(oldAppointment.getCreateRole());
appointment.setCreateTime(oldAppointment.getCreateTime());}
appointmentService.saveOrUpdate(appointment);returnResult.success();}@DeleteMapping("/{id}")publicResultdelete(@PathVariableLong id){
appointmentService.removeById(id);returnResult.success();}@PostMapping("/del/batch")publicResultdeleteBatch(@RequestBodyList<Long> ids){
appointmentService.removeByIds(ids);returnResult.success();}// @GetMapping// public Result findAll() {// return Result.success(appointmentService.list());// }@GetMapping("/{id}")publicResultfindOne(@PathVariableLong id){returnResult.success(appointmentService.getById(id));}@GetMapping("/page")publicResultfindPage(@RequestParamInteger pageNum,@RequestParamInteger pageSize,@RequestParam(defaultValue ="")String customName,@RequestParam(defaultValue ="")String doctorName){QueryWrapper<Appointment> queryWrapper =newQueryWrapper<>();
queryWrapper.orderByDesc("id");if(!"".equals(customName)){
queryWrapper.like("custom_name", customName);}if(!"".equals(doctorName)){
queryWrapper.like("doctor_name", doctorName);}User currentUser =TokenUtils.getCurrentUser();if(currentUser.getRole().equals(RoleEnum.ROLE_USER.toString())){//普通用户只能查看自己的预约记录
queryWrapper.eq("create_by", currentUser.getId());}elseif(currentUser.getRole().equals(RoleEnum.ROLE_DOCTOR.toString())){//医生可以查看自己的记录和 别人约自己的
queryWrapper.eq("create_by", currentUser.getId()).or().eq("doctor_id", currentUser.getId());}returnResult.success(appointmentService.page(newPage<>(pageNum, pageSize), queryWrapper));}/**
* 导出接口
*/@GetMapping("/export")publicvoidexport(HttpServletResponse response)throwsException{// 从数据库查询出所有的数据List<Appointment> list = appointmentService.list();// 在内存操作,写出到浏览器ExcelWriter writer =ExcelUtil.getWriter(true);// 一次性写出list内的对象到excel,使用默认样式,强制输出标题
writer.write(list,true);// 设置浏览器响应的格式
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");String fileName =URLEncoder.encode("Appointment信息表","UTF-8");
response.setHeader("Content-Disposition","attachment;filename="+ fileName +".xlsx");ServletOutputStream out = response.getOutputStream();
writer.flush(out,true);
out.close();
writer.close();}/**
* excel 导入
* @param file
* @throws Exception
*/@PostMapping("/import")publicResultimp(MultipartFile file)throwsException{InputStream inputStream = file.getInputStream();ExcelReader reader =ExcelUtil.getReader(inputStream);// 通过 javabean的方式读取Excel内的对象,但是要求表头必须是英文,跟javabean的属性要对应起来List<Appointment> list = reader.readAll(Appointment.class);
appointmentService.saveBatch(list);returnResult.success();}privateUsergetUser(){returnTokenUtils.getCurrentUser();}}
8.设计文档
提供需求说明和关键的业务数据库表字典,很难得喔。

9.源码获取
如果你喜欢这个项目的话, 给个一键三连,点赞越多,往后提高更多的开源项目, 谢谢大家,gitee链接附上。
后端:https://gitee.com/madifu/petHis-backend
前端:https://gitee.com/madifu/petHis-fontend-admin
10.后记
在开发这个系统时,遇到过几个坑,包括 VUE的,还有js 的,它们是怎么绕过去的,将另行文章做相关介绍。
版权归原作者 码递夫 所有, 如有侵权,请联系我们删除。