项目分为后台管理系统和前台用户系统。
后台管理系统主要有医院设置展示,设置医院编号、名称、联系人、状态等;医院展示,医院列表、详情、科室信息等;数据字典展示,医院等级、地区信息、证件类型等,用户展示,前台登录过的用户、用户添加的就诊人等信息,及预约挂号的统计情况,根据医院名称或者日期展示预约人数。
前台用户系统主要展示医院列表,科室信息,点击科室进行挂号,提交挂号订单,及用户登录等功能。
1.后台系统
1.医院设置
数据库:yygh_hosp 表:hospital_set
模块:service_hosp
接口:HospitalSetController
主要功能:
1.查询医院设置列表
条件分页查询,前端传过来当前页和每页记录数,及条件查询的条件,这里主要是医院编号和医院名称,编号匹配查询,名称模糊查询。返回给前端自定义的Result类型。
//条件查询 分页@PostMapping("findPageHospSet/{current}/{limit}")public Result findPageHospSet(@PathVariable Long current, @PathVariable Long limit, @RequestBody(required = false)HospitalSetQueryVo hospitalSetQueryVo){//创建page对象,传递当前页,每页记录数Page<HospitalSet> page = new Page<>(current,limit);//当前页 每页记录//构建条件QueryWrapper<HospitalSet> wrapper = new QueryWrapper<>();String hosname = hospitalSetQueryVo.getHosname();//医院名称String hoscode = hospitalSetQueryVo.getHoscode();//医院编号if(!StringUtils.isEmpty(hosname)) {wrapper.like("hosname",hospitalSetQueryVo.getHosname());}if(!StringUtils.isEmpty(hoscode)) {wrapper.eq("hoscode",hospitalSetQueryVo.getHoscode());}//调用方法实现分页查询IPage<HospitalSet> pageHospitalSet = hospitalSetService.page(page, wrapper);//返回结果return Result.ok(pageHospitalSet);}
2.逻辑删除医院
增加is_deleted字段,表示数据被删除的状态。同时在实体类相应字段上加@TableLogic注解,即可实现逻辑删除。
//2 逻辑删除医院设置@ApiOperation(value = "逻辑删除医院设置") //为了swagger界面显示中文@DeleteMapping("{id}")public Result removeHospitalSet(@PathVariable Long id){boolean flag = hospitalSetService.removeById(id);if(flag){return Result.ok(flag);}else {return Result.fail();}}
3.医院添加及修改
前端传过来用户输入的信息,封装为HospitalSet对象,后台使用@RequestBody注解进行解析及封装,调用mybaitplus封装好的sava方法进行保存。
//添加医院@PostMapping("saveHospitalSet")public Result saveHospitalSet(@RequestBody HospitalSet hospitalSet){//设置状态 1 使用 0 不能使用hospitalSet.setStatus(1);//签名秘钥Random random = new Random();hospitalSet.setSignKey(MD5.encrypt(System.currentTimeMillis()+""+random.nextInt(1000)));//调用serviceboolean save = hospitalSetService.save(hospitalSet);if(save) {return Result.ok();} else {return Result.fail();}}
4.批量删除医院设置
前端传过来要删除的id的集合,后端使用后台使用@RequestBody注解进行解析及封装,调用mybaitplus封装好的方法进行删除。
//7 批量删除医院设置@DeleteMapping("batchRemove")public Result batchRemoveHospitalSet(@RequestBody List<Long> idList) {hospitalSetService.removeByIds(idList);return Result.ok();}
5.医院设置中用到swagger
1.pom
<!--swagger--><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>2.7.0</version></dependency><!--swagger ui--><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger-ui</artifactId><version>2.7.0</version></dependency>
2.配置类
@Configuration
@EnableSwagger2
public class Swagger2Config {//指定路径显示@Beanpublic Docket webApiConfig(){return new Docket(DocumentationType.SWAGGER_2).groupName("webApi").apiInfo(webApiInfo()).select()//只显示api路径下的页面.paths(Predicates.and(PathSelectors.regex("/api/.*"))).build();}//指定路径显示@Beanpublic Docket adminApiConfig(){return new Docket(DocumentationType.SWAGGER_2).groupName("adminApi").apiInfo(adminApiInfo()).select()//只显示admin路径下的页面.paths(Predicates.and(PathSelectors.regex("/admin/.*"))).build();}//指定显示信息private ApiInfo webApiInfo(){return new ApiInfoBuilder().title("网站-API文档").description("本文档描述了网站微服务接口定义").version("1.0").contact(new Contact("atguigu", "http://atguigu.com", "493211102@qq.com")).build();}指定显示信息private ApiInfo adminApiInfo(){return new ApiInfoBuilder().title("后台管理系统-API文档").description("本文档描述了后台管理系统微服务接口定义").version("1.0").contact(new Contact("atguigu", "http://atguigu.com", "49321112@qq.com")).build();}
}
3.controller添加注解@Api 并且可以指定中文标题
每个接口方法也可以指定为中文标题
5.实体类及字段也可以指定中文
界面可以展示
6.调用
localhost:项目端口/swagger-ui.html
2.数据字典
数据库:yygh_cmn 表:dict
模块:service_cmn
接口:DictController
展示一和三级分类的数据信息。
导入和导出功能,用到easyexcel。
1.pom
<dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>2.1.1</version></dependency>
2.导出用到实体类
@Data
public class DictEeVo {@ExcelProperty(value = "id" ,index = 0)private Long id;@ExcelProperty(value = "上级id" ,index = 1)private Long parentId;@ExcelProperty(value = "名称" ,index = 2)private String name;@ExcelProperty(value = "值" ,index = 3)private String value;@ExcelProperty(value = "编码" ,index = 4)private String dictCode;
}
4.service
//导出@Override@CacheEvict(value = "dict", allEntries=true)public void exportData(HttpServletResponse response) {try {//设置下载的信息response.setContentType("application/vnd.ms-excel");//格式excelresponse.setCharacterEncoding("utf-8");
这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系String fileName = URLEncoder.encode("数据字典", "UTF-8");//Content-disposition:以下载的方式执行此操作response.setHeader("Content-disposition", "attachment;filename="+ fileName + ".xlsx");//查数据库 查出list对象的集合 封装到表头的dicteevo对象的listList<Dict> dictList = baseMapper.selectList(null);List<DictEeVo> dictVoList = new ArrayList<>(dictList.size());for(Dict dict : dictList) {DictEeVo dictVo = new DictEeVo();BeanUtils.copyProperties(dict, dictVo);dictVoList.add(dictVo);}EasyExcel.write(response.getOutputStream(), DictEeVo.class).sheet("数据字典").doWrite(dictVoList);} catch (IOException e) {e.printStackTrace();}}
5.导入
创建监听器,重写invoke方法
public class DictListener extends AnalysisEventListener<DictEeVo> {private DictMapper dictMapper;public DictListener(DictMapper dictMapper) {this.dictMapper = dictMapper;}@Overridepublic void invoke(DictEeVo dictEeVo, AnalysisContext analysisContext) {//调用方法添加数据库Dict dict = new Dict();BeanUtils.copyProperties(dictEeVo,dict);dict.setIsDeleted(0);dictMapper.insert(dict);}@Overridepublic void doAfterAllAnalysed(AnalysisContext analysisContext) {}
}
//导入@Overridepublic void importData(MultipartFile file) {try {EasyExcel.read(file.getInputStream(),DictEeVo.class,new DictListener(baseMapper)).sheet().doRead();} catch (IOException e) {e.printStackTrace();}}
3.医院上传接口
数据库:mongodb
模块:service_hosp
接口:APIController
类:hosptal
通过hospital-manage模块模拟医院模块,调用本地后台接口实现医院信息科室信息排班信息上传。
医院设置 更新数据到表
1.医院添加
manage模块controller:
manage模块service
调用HttpRequestHelper.sendRequest将封装好的数据发送到hospital模块。
@Overridepublic boolean saveHospital(String data) {JSONObject jsonObject = JSONObject.parseObject(data);Map<String, Object> paramMap = new HashMap<>();paramMap.put("hoscode",jsonObject.getString("hoscode"));paramMap.put("hosname",jsonObject.getString("hosname"));paramMap.put("hostype",jsonObject.getString("hostype"));paramMap.put("provinceCode",jsonObject.getString("provinceCode"));paramMap.put("cityCode", jsonObject.getString("cityCode"));paramMap.put("districtCode",jsonObject.getString("districtCode"));paramMap.put("address",jsonObject.getString("address"));paramMap.put("intro",jsonObject.getString("intro"));paramMap.put("route",jsonObject.getString("route"));//图片paramMap.put("logoData", jsonObject.getString("logoData"));JSONObject bookingRule = jsonObject.getJSONObject("bookingRule");paramMap.put("bookingRule",bookingRule.toJSONString());paramMap.put("timestamp", HttpRequestHelper.getTimestamp());// paramMap.put("sign",MD5.encrypt(this.getSignKey()));JSONObject respone = HttpRequestHelper.sendRequest(paramMap,this.getApiUrl()+"/api/hosp/saveHospital");System.out.println(respone.toJSONString());if(null != respone && 200 == respone.getIntValue("code")) {return true;} else {throw new YyghException(respone.getString("message"), 201);}}
hosp接口:
获取传过来的医院信息将数据保存到mongodb
@ApiOperation(value = "上传医院") //把数据传到mongodb中@PostMapping("saveHospital")public Result saveHospital(HttpServletRequest request) {Map<String, String[]> requestMap = request.getParameterMap();//getParameterMap获取的是map集合 value是一个string数组 需要转化为对象!!!!Map<String, Object> paramMap = HttpRequestHelper.switchMap(requestMap);//获取传过来的map中的签名key 带MD5//加密String hospSign = (String)paramMap.get("sign");
// if(StringUtils.isEmpty(hoscode)) {
// throw new YyghException(ResultCodeEnum.PARAM_ERROR);
// }
//签名校验//医院编码String hoscode = (String)paramMap.get("hoscode");//根据编码查询数据库 获取签名//String signKey = hospitalSetService.getSignKey(hoscode);//进行MD5加密//String signKeyMD5 = MD5.encrypt(signKey);// if(!hospSign.equals(signKeyMD5)){// throw new YyghException(ResultCodeEnum.SIGN_ERROR);// }
// //传输过程中“+”转换为了“ ”,因此我们要转换回来 //医院logoString logoData = (String)paramMap.get("logoData");logoData = logoData.replaceAll(" ", "+");paramMap.put("logoData", logoData);hospitalService.save(paramMap);return Result.ok();}
hosp service:
//上传医院信息 保存@Overridepublic void save(Map<String, Object> paramMap) {
// String mappstring =JSONObject.toJSONString(paramMap)//将传过来的paramMap线转化为字符串 再转化为hospital对象!!!!!类中要定义规则Hospital hospital = JSONObject.parseObject(JSONObject.toJSONString(paramMap),Hospital.class);//判断是否存在Hospital targetHospital = hospitalRepository.getHospitalByHoscode(hospital.getHoscode());if(null != targetHospital) {hospital.setStatus(targetHospital.getStatus());hospital.setCreateTime(targetHospital.getCreateTime());hospital.setUpdateTime(new Date());hospital.setIsDeleted(0);hospitalRepository.save(hospital);} else {//0:未上线 1:已上线hospital.setStatus(0);hospital.setCreateTime(new Date());hospital.setUpdateTime(new Date());hospital.setIsDeleted(0);hospitalRepository.save(hospital);}}
科室及排班上传流程相同,需要注意定义为唯一索引的字段不可以重复,否则存入mongodb的时候会报错
4.医院列表
//查询医院列表@Overridepublic Page<Hospital> selectHospPage(Integer page, Integer limit, HospitalQueryVo hospitalQueryVo) {//创建pageable对象Pageable pageable = PageRequest.of(page-1,limit);//创建条件匹配器ExampleMatcher matcher = ExampleMatcher.matching().withStringMatcher(ExampleMatcher.StringMatcher.CONTAINING).withIgnoreCase(true);//hospitalSetQueryVo转换Hospital对象Hospital hospital = new Hospital();BeanUtils.copyProperties(hospitalQueryVo,hospital);//创建对象Example<Hospital> example = Example.of(hospital,matcher);//调用方法实现查询 //查询mongodb中的数据Page<Hospital> pages = hospitalRepository.findAll(example, pageable);//获取查询list集合,遍历进行医院等级封装pages.getContent().stream().forEach(item -> {//调用方法 远程调用cmn中的接口 查询医院等级和位置this.setHospitalHosType(item);});return pages;}
5.查看医院排班
//根据医院编号,查询医院所有科室列表@ApiOperation(value = "查询医院所有科室列表")@GetMapping("getDeptList/{hoscode}")public Result getDeptList(@PathVariable String hoscode){List<DepartmentVo> list = departmentService.findDeptTree(hoscode);return Result.ok(list);}
service
@Override//排班管理会调用 查询所有排班public List<DepartmentVo> findDeptTree(String hoscode) {//创建list集合 封装最后的数据 departmentvo 科室编号,科室名称 下级节点(包含departmentvo对象)List<DepartmentVo> result=new ArrayList<>();//根据医院编号,查询医院所有科室信息Department departmentQuery = new Department();departmentQuery.setHoscode(hoscode);Example example = Example.of(departmentQuery);//springdata查询条件//所有科室列表 departmentList 根据医院编号查询List<Department> departmentList = departmentRepository.findAll(example);//根据大科室编号 bigcode 分组,获取每个大科室里面下级子科室Map<String, List<Department>> deparmentMap =departmentList.stream().collect(Collectors.groupingBy(Department::getBigcode));//遍历map集合 deparmentMap //大科室集合 一共12个for(Map.Entry<String,List<Department>> entry:deparmentMap.entrySet()){//大科室编号String bigcode = entry.getKey();//大科室编号对应的全局数据 每个大科室下边的小科室List<Department> deparment1List = entry.getValue();//封装大科室DepartmentVo departmentVo1 = new DepartmentVo();departmentVo1.setDepcode(bigcode);//get0是因为list中存的bigname都一样 随便取一个就行departmentVo1.setDepname(deparment1List.get(0).getBigname());//封装小科室List<DepartmentVo> children = new ArrayList<>();//遍历这个大科室下的list集合for(Department department: deparment1List) {DepartmentVo departmentVo2 = new DepartmentVo();departmentVo2.setDepcode(department.getDepcode());departmentVo2.setDepname(department.getDepname());//封装到list集合children.add(departmentVo2);}//把小科室list集合放到大科室children里面departmentVo1.setChildren(children);//放到最终result里面result.add(departmentVo1);}//返回return result;}
//根据医院编号 和 科室编号 ,查询排班规则数据@ApiOperation(value ="查询排班规则数据")@GetMapping("getScheduleRule/{page}/{limit}/{hoscode}/{depcode}")public Result getScheduleRule(@PathVariable long page,@PathVariable long limit,@PathVariable String hoscode,@PathVariable String depcode){Map<String,Object> map = scheduleService.getRuleSchedule(page,limit,hoscode,depcode);return Result.ok(map);}
@Override//排班管理调用public Map<String, Object> getRuleSchedule(long page, long limit, String hoscode, String depcode) {//1 根据医院编号 和 科室编号 查询Criteria criteria = Criteria.where("hoscode").is(hoscode).and("depcode").is(depcode);//2 根据工作日workDate期进行分组Aggregation agg = Aggregation.newAggregation(Aggregation.match(criteria),//匹配条件Aggregation.group("workDate")//分组字段.first("workDate").as("workDate")//3 统计号源数量.count().as("docCount").sum("reservedNumber").as("reservedNumber").sum("availableNumber").as("availableNumber"),//排序Aggregation.sort(Sort.Direction.DESC,"workDate"),//4 实现分页Aggregation.skip((page-1)*limit),Aggregation.limit(limit));//调用方法,最终执行AggregationResults<BookingScheduleRuleVo> aggResults =mongoTemplate.aggregate(agg, Schedule.class, BookingScheduleRuleVo.class);List<BookingScheduleRuleVo> bookingScheduleRuleVoList = aggResults.getMappedResults();//分组查询的总记录数Aggregation totalAgg = Aggregation.newAggregation(Aggregation.match(criteria),Aggregation.group("workDate"));AggregationResults<BookingScheduleRuleVo> totalAggResults =mongoTemplate.aggregate(totalAgg, Schedule.class, BookingScheduleRuleVo.class);int total = totalAggResults.getMappedResults().size();//把日期对应星期获取for(BookingScheduleRuleVo bookingScheduleRuleVo:bookingScheduleRuleVoList) {Date workDate = bookingScheduleRuleVo.getWorkDate();String dayOfWeek = this.getDayOfWeek(new DateTime(workDate));bookingScheduleRuleVo.setDayOfWeek(dayOfWeek);}//设置最终数据,进行返回Map<String, Object> result = new HashMap<>();result.put("bookingScheduleRuleList",bookingScheduleRuleVoList);result.put("total",total);//获取医院名称String hosName = hospitalService.getHospName(hoscode);//其他基础数据Map<String, String> baseMap = new HashMap<>();baseMap.put("hosname",hosName);result.put("baseMap",baseMap);return result;}
//根据医院编号 、科室编号和工作日期,查询排班详细信息@ApiOperation(value = "查询排班详细信息")@GetMapping("getScheduleDetail/{hoscode}/{depcode}/{workDate}")public Result getScheduleDetail( @PathVariable String hoscode,@PathVariable String depcode,@PathVariable String workDate) {List<Schedule> list = scheduleService.getDetailSchedule(hoscode,depcode,workDate);return Result.ok(list);}
service
//根据医院编号 、科室编号和工作日期,查询排班详细信息@Override//排班管理调用public List<Schedule> getDetailSchedule(String hoscode, String depcode, String workDate) {//根据参数查询mongodbList<Schedule> scheduleList =scheduleRepository.findScheduleByHoscodeAndDepcodeAndWorkDate(hoscode,depcode,new DateTime(workDate).toDate());//把得到list集合遍历,向设置其他值:医院名称、科室名称、日期对应星期scheduleList.stream().forEach(item->{this.packageSchedule(item);});return scheduleList;}