目录
- 一、预约挂号详情
- 1、需求
- 2、预约挂号详情接口
- 3、预约挂号详情前端
- 二、预约确认
- 1、需求
- 2、预约确认接口
- 3、预约确认前端
一、预约挂号详情
1、需求
接口分析
(1)根据预约周期,展示可预约日期数据,按分页展示
(2)选择日期展示当天可预约列表(该接口后台已经实现过)
页面展示分析
(1)分页展示可预约日期,根据有号、无号、约满等状态展示不同颜色,以示区分
(2)可预约最后一个日期为即将放号日期,根据放号时间页面展示倒计时
2、预约挂号详情接口
(1)在ScheduleService添加方法
/*** 获取排班可预约日期数据* @param page* @param limit* @param hoscode* @param depcode*/Map<String, Object> getSchedulePageByCondition(String hoscode, String depcode, Integer pageNum, Integer pageSize);
(2)在ScheduleServiceImpl实现方法
public Map<String, Object> getSchedulePageByCondition(String hoscode, String depcode, Integer pageNum, Integer pageSize) {Hospital hospital = hospitalService.getHospitalByHoscode(hoscode);if(hospital == null){throw new YyghException(20001,"该医院信息不存在");}BookingRule bookingRule = hospital.getBookingRule();//获取可预约日期分页数据IPage<Date> page = this.getListDate(pageNum, pageSize, bookingRule);List<Date> records = page.getRecords();Criteria criteria=Criteria.where("hoscode").is(hoscode).and("depcode").is(depcode).and("workDate").in(records);Aggregation aggregation=Aggregation.newAggregation(Aggregation.match(criteria),Aggregation.group("workDate").first("workDate").as("workDate").count().as("docCount").sum("reservedNumber").as("reservedNumber").sum("availableNumber").as("availableNumber"),Aggregation.sort(Sort.Direction.ASC,"workDate"));AggregationResults<BookingScheduleRuleVo> aggregate = mongoTemplate.aggregate(aggregation, Schedule.class, BookingScheduleRuleVo.class);List<BookingScheduleRuleVo> mappedResults = aggregate.getMappedResults();Map<Date, BookingScheduleRuleVo> collect = mappedResults.stream().collect(Collectors.toMap(BookingScheduleRuleVo::getWorkDate, BookingScheduleRuleVo -> BookingScheduleRuleVo));int size = records.size();List<BookingScheduleRuleVo> bookingScheduleRuleVoList=new ArrayList<BookingScheduleRuleVo>();for(int i=0;i<size;i++){Date date = records.get(i);BookingScheduleRuleVo bookingScheduleRuleVo = collect.get(date);if(bookingScheduleRuleVo == null){bookingScheduleRuleVo=new BookingScheduleRuleVo();bookingScheduleRuleVo.setWorkDate(date);//bookingScheduleRuleVo.setWorkDateMd(date);bookingScheduleRuleVo.setDocCount(0);bookingScheduleRuleVo.setReservedNumber(0);bookingScheduleRuleVo.setAvailableNumber(-1);//当天所有医生的总的剩余可预约数//bookingScheduleRuleVo.setStatus(0);}bookingScheduleRuleVo.setWorkDateMd(date);bookingScheduleRuleVo.setDayOfWeek(this.getDayOfWeek(new DateTime(date)));bookingScheduleRuleVo.setStatus(0); ////第一页第一条做特殊判断处理if(i==0 && pageNum == 1){DateTime dateTime = this.getDateTime(new Date(), bookingRule.getStopTime());//如果医院规定的当前的挂号截止时间在此时此刻之前,说明:此时此刻已经过了当天的挂号截止时间了if(dateTime.isBeforeNow()){bookingScheduleRuleVo.setStatus(-1);}}//最后一页的最后一条做特殊判断处理if(pageNum==page.getPages() && i== (size-1) ){bookingScheduleRuleVo.setStatus(1);}bookingScheduleRuleVoList.add(bookingScheduleRuleVo);}Map<String,Object> map = new HashMap<String,Object>();map.put("total",page.getTotal());map.put("list",bookingScheduleRuleVoList);Map<String,Object> baseMap = new HashMap<String,Object>();//医院名称baseMap.put("hosname", hospitalService.getHospitalByHoscode(hoscode).getHosname());//科室Department department=departmentService.getDepartment(hoscode,depcode);//大科室名称baseMap.put("bigname", department.getBigname());//科室名称baseMap.put("depname", department.getDepname());//月baseMap.put("workDateString", new DateTime().toString("yyyy年MM月"));//放号时间baseMap.put("releaseTime", bookingRule.getReleaseTime());//停号时间baseMap.put("stopTime", bookingRule.getStopTime());map.put("baseMap",baseMap);return map;}
(3)添加获取可预约日期分页数据方法
private IPage getListDate(Integer pageNum, Integer pageSize, BookingRule bookingRule) {Integer cycle = bookingRule.getCycle();//此时此刻是否已经超过了医院规定的当天的挂号起始时间,如果此时此刻已经超过了:cycle+1String releaseTime = bookingRule.getReleaseTime();//今天医院规定的挂号的起始时间:2022-06-07 08:30DateTime dateTime = this.getDateTime(new Date(), releaseTime);if(dateTime.isBeforeNow()){cycle=cycle+1;}//预约周期内所有的时间列表(10天|11天)List<Date> list = new ArrayList<Date>();for(int i=0;i<cycle;i++){list.add(new DateTime( new DateTime().plusDays(i).toString("yyyy-MM-dd")).toDate());}int start = (pageNum-1)*pageSize;int end = start+pageSize;if(end>list.size()){end=list.size();}List<Date> currentPageDateList=new ArrayList<Date>();for(int j=start;j<end;j++){Date date = list.get(j);currentPageDateList.add(date);}com.baomidou.mybatisplus.extension.plugins.pagination.Page<Date> page = new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(pageNum, pageSize, list.size());page.setRecords(currentPageDateList);return page;}
(4)将Date日期(yyyy-MM-dd HH:mm)转换为DateTime
/*** 将Date日期(yyyy-MM-dd HH:mm)转换为DateTime*/private DateTime getDateTime(Date date, String timeString) {String dateTimeString = new DateTime(date).toString("yyyy-MM-dd") + " "+ timeString;DateTime dateTime = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm").parseDateTime(dateTimeString);return dateTime;}
(5)在DepartmentService类添加方法和实现
/*** 根据医院编号 和 科室编号获取科室数据*/Department getDepartment(String hoscode, String depcode);//实现方法:根据医院编号 和 科室编号获取科室数据@Overridepublic Department getDepartment(String hoscode, String depcode) {return departmentRepository.getDepartmentByHoscodeAndDepcode(hoscode,depcode);}
(6)在HospitalApiController添加方法
@RestController
@RequestMapping("/user/hosp/schedule")
public class UserScheduleController {@Autowiredprivate ScheduleService scheduleService;@GetMapping("/{hoscode}/{depcode}/{pageNum}/{pageSize}")public R getSchedulePage(@PathVariable String hoscode,@PathVariable String depcode,@PathVariable Integer pageNum,@PathVariable Integer pageSize){Map<String,Object> map=scheduleService.getSchedulePageByCondition(hoscode,depcode,pageNum,pageSize);return R.ok().data(map);}@GetMapping("/{hoscode}/{depcode}/{workdate}")public R getScheduleDetail(@PathVariable String hoscode,@PathVariable String depcode,@PathVariable String workdate){List<Schedule> details = scheduleService.detail(hoscode, depcode, workdate);return R.ok().data("details",details);}
}
3、预约挂号详情前端
(1)在/api/schedule.js添加方法
import request from '@/utils/request'const api_name = `/user/hosp/schedule`export default {getSchedulePage(hoscode,depcode,pageNum,pageSize) {return request({url: `${api_name}/${hoscode}/${depcode}/${pageNum}/${pageSize}`,method: `get`})},getScheduleDetail(hoscode,depcode,workdate) {return request({url: `${api_name}/${hoscode}/${depcode}/${workdate}`,method: `get`})},
}
(2)页面显示
创建/pages/hospital/schedule.vue组件
<template><!-- header --><div class="nav-container page-component"><!--左侧导航 #start --><div class="nav left-nav"><div class="nav-item selected"><span class="v-link selected dark" :onclick="'javascript:window.location=\'/hosp/'+hoscode+'\''">预约挂号 </span></div><div class="nav-item "><span class="v-link clickable dark" :onclick="'javascript:window.location=\'/hosp/detail/'+hoscode+'\''"> 医院详情 </span></div><div class="nav-item"><span class="v-link clickable dark" :onclick="'javascript:window.location=\'/hosp/notice/'+hoscode+'\''"> 预约须知 </span></div><div class="nav-item "><spanclass="v-link clickable dark"> 停诊信息 </span></div><div class="nav-item "><spanclass="v-link clickable dark"> 查询/取消 </span></div></div><!-- 左侧导航 #end --><!-- 右侧内容 #start --><div class="page-container"><div class="hospital-source-list"><div class="header-wrapper" style="justify-content:normal"><span class="v-link clickable" @click="show()">{{ baseMap.hosname}}</span><div class="split"></div><div>{{ baseMap.bigname }}</div></div><div class="title mt20"> {{ baseMap.depname }}</div><!-- 号源列表 #start --><div class="mt60"><div class="title-wrapper">{{ baseMap.workDateString }}</div><div class="calendar-list-wrapper"><!-- item.depNumber == -1 ? 'gray space' : item.depNumber == 0 ? 'gray' : 'small small-space'--><!-- selected , index == activeIndex ? 'selected' : ''--><div :class="'calendar-item '+item.curClass" style="width: 124px;"v-for="(item, index) in bookingScheduleList" :key="item.id"@click="selectDate(item, index)"><div class="date-wrapper"><span>{{ item.workDate }}</span><span class="week">{{ item.dayOfWeek }}</span></div><div class="status-wrapper" v-if="item.status == 0">{{ item.availableNumber == -1 ? '无号' : item.availableNumber == 0 ? '约满' : '有号' }}</div><div class="status-wrapper" v-if="item.status == 1">即将放号</div><div class="status-wrapper" v-if="item.status == -1">停止挂号</div></div></div><!-- 分页 --><el-paginationclass="pagination"layout="prev, pager, next":current-page="page":total="total":page-size="limit"@current-change="getPage"></el-pagination></div><!-- 即将放号 #start--><div class="countdown-wrapper mt60" v-if="!tabShow"><div class="countdonw-title"> {{ time }}<span class="v-link selected">{{ baseMap.releaseTime }} </span>放号</div><div class="countdown-text"> 倒 计 时<div><span class="number">{{ timeString }}</span></div></div></div><!-- 即将放号 #end--><!-- 号源列表 #end --><!-- 上午号源 #start --><div class="mt60" v-if="tabShow"><div class=""><div class="list-title"><div class="block"></div>上午号源</div><div v-for="item in scheduleList" :key="item.id" ><div class="list-item" v-if="item.workTime == 0"><div class="item-wrapper"><div class="title-wrapper"><div class="title">{{ item.title }}</div><div class="split"></div><div class="name"> {{ item.docname }}</div></div><div class="special-wrapper">{{ item.skill }}</div></div><div class="right-wrapper"><div class="fee"> ¥{{ item.amount }}</div><div class="button-wrapper"><div class="v-button" @click="booking(item.id, item.availableNumber)" :style="item.availableNumber == 0 || pageFirstStatus == -1 ? 'background-color: #7f828b;' : ''"><span>剩余<span class="number">{{ item.availableNumber }}</span></span></div></div></div></div></div></div></div><!-- 上午号源 #end --><!-- 下午号源 #start --><div class="mt60" v-if="tabShow"><div class=""><div class="list-title"><div class="block"></div>下午号源</div><div v-for="item in scheduleList" :key="item.id"><div class="list-item" v-if="item.workTime == 1"><div class="item-wrapper"><div class="title-wrapper"><div class="title">{{ item.title }}</div><div class="split"></div><div class="name"> {{ item.docname }}</div></div><div class="special-wrapper">{{ item.skill }}</div></div><div class="right-wrapper"><div class="fee"> ¥{{ item.amount }}</div><div class="button-wrapper"><div class="v-button" @click="booking(item.id, item.availableNumber)" :style="item.availableNumber == 0 || pageFirstStatus == -1 ? 'background-color: #7f828b;' : ''"><span>剩余<span class="number">{{ item.availableNumber }}</span></span></div></div></div></div></div></div></div><!-- 下午号源 #end --></div></div><!-- 右侧内容 #end --></div><!-- footer --></template><script>import '~/assets/css/hospital_personal.css'import '~/assets/css/hospital.css'import scheduleApi from '@/api/schedule'export default {data() {return {hoscode: null,depcode: null,workDate: null,bookingScheduleList: [],scheduleList : [],baseMap : {},nextWorkDate: null, // 下一页第一个日期preWorkDate: null, // 上一页第一个日期tabShow: true, //挂号列表与即将挂号切换activeIndex: 0,page: 1, // 当前页limit: 7, // 每页个数total: 1, // 总页码timeString: null,time: '今天',timer: null,pageFirstStatus: 0 // 第一页第一条数据状态}},created() {this.hoscode = this.$route.query.hoscodethis.depcode = this.$route.query.depcodethis.workDate = this.getCurDate()this.getBookingScheduleRule()},methods: {getPage(page = 1) {this.page = pagethis.workDate = nullthis.activeIndex = 0this.getBookingScheduleRule()},getBookingScheduleRule() {scheduleApi.getSchedulePage( this.hoscode, this.depcode,this.page, this.limit).then(response => {this.bookingScheduleList = response.data.listthis.total = response.data.totalthis.baseMap = response.data.baseMapconsole.log(this.total)this.dealClass()// 分页后workDate=null,默认选中第一个if (this.workDate == null) {this.workDate = this.bookingScheduleList[0].workDate}//判断当天是否停止预约 status == -1 停止预约if(this.workDate == this.getCurDate()) {this.pageFirstStatus = this.bookingScheduleList[0].status} else {this.pageFirstStatus = 0}this.findScheduleList()})},findScheduleList() {scheduleApi.getScheduleDetail(this.hoscode, this.depcode, this.workDate).then(response => {this.scheduleList = response.data.details})},selectDate(item, index) {this.workDate = item.workDatethis.activeIndex = index//清理定时if(this.timer != null) clearInterval(this.timer)// 是否即将放号if(item.status == 1) {this.tabShow = false// 放号时间let releaseTime = new Date(this.getCurDate() + ' ' + this.baseMap.releaseTime).getTime()let nowTime = new Date().getTime();this.countDown(releaseTime, nowTime)this.dealClass();} else {this.tabShow = truethis.getBookingScheduleRule()}},dealClass() {//处理样式for (let i = 0; i < this.bookingScheduleList.length; i++) {// depNumber -1:无号 0:约满 >0:有号let curClass = this.bookingScheduleList[i].availableNumber == -1 ? 'gray space' : this.bookingScheduleList[i].availableNumber == 0 ? 'gray' : 'small small-space'curClass += i == this.activeIndex ? ' selected' : ''this.bookingScheduleList[i].curClass = curClass}},getCurDate() {let datetime = new Date()let year = datetime.getFullYear()let month = datetime.getMonth() + 1 < 10 ? '0' + (datetime.getMonth() + 1) : datetime.getMonth() + 1let date = datetime.getDate() < 10 ? '0' + datetime.getDate() : datetime.getDate()return year + '-' + month + '-' + date},countDown(releaseTime, nowTime) {//计算倒计时时长let secondes = 0;if(releaseTime > nowTime) {this.time = '今天'//当前时间到放号时间的时长secondes = Math.floor((releaseTime - nowTime) / 1000);} else {this.time = '明天'//计算明天放号时间let releaseDate = new Date(releaseTime)releaseTime = new Date(releaseDate.setDate(releaseDate.getDate() + 1)).getTime()//当前时间到明天放号时间的时长secondes = Math.floor((releaseTime - nowTime) / 1000);}//定时任务this.timer = setInterval(() => {secondes = secondes - 1if(secondes <= 0) {clearInterval(timer);this.init()}this.timeString = this.convertTimeString(secondes)}, 1000);// 通过$once来监听定时器,在beforeDestroy钩子可以被清除。this.$once('hook:beforeDestroy', () => {clearInterval(timer);})},convertTimeString(allseconds) {if(allseconds <= 0) return '00:00:00'// 计算天数let days = Math.floor(allseconds / (60 * 60 * 24));// 小时let hours = Math.floor((allseconds - (days * 60 * 60 * 24)) / (60 * 60));// 分钟let minutes = Math.floor((allseconds - (days * 60 * 60 * 24) - (hours * 60 * 60)) / 60);// 秒let seconds = allseconds - (days * 60 * 60 * 24) - (hours * 60 * 60) - (minutes * 60);//拼接时间let timString = "";if (days > 0) {timString = days + "天:";}return timString += hours + " 时 " + minutes + " 分 " + seconds + " 秒 ";},show() {window.location.href = '/hospital/' + this.hoscode},booking(scheduleId, availableNumber) {if(availableNumber == 0 || this.pageFirstStatus == -1) {this.$message.error('不能预约')} else {window.location.href = '/hospital/booking?scheduleId=' + scheduleId}}}}</script>
这里还有个问题都是无号,我们需要重新导入数据到mongodb,使得日期跟今天对应上
改成自己当前的月份
登陆第三方管理医院系统
二、预约确认
1、需求
2、预约确认接口
(1)在ScheduleService添加方法和实现
/*** 根据id获取排班* @param id*/Schedule getScheduleList(String id);//实现方法:根据id获取排班@Overridepublic Schedule getScheduleList(String id) {Schedule schedule = scheduleRepository.findById(id).get();this.packageSchedule(schedule);return schedule;}
(2)在HospitalApiController添加方法
@ApiOperation(value = "获取排班详情")@GetMapping("getSchedule/{id}")public R getScheduleList(@PathVariable String id) {Schedule schedule = scheduleService.getScheduleList(id);return R.ok().data("schedule",schedule);}
3、预约确认前端
(1)在/api/schedule.js添加方法
getSchedule(id) {return request({url: `${api_name}/getSchedule/${id}`,method: 'get'})}
(2)页面显示
创建/pages/hospital/booking.vue组件
<template><!-- header --><div class="nav-container page-component"><!--左侧导航 #start --><div class="nav left-nav"><div class="nav-item selected"><span class="v-link selected dark" :onclick="'javascript:window.location=\'/hospital/'+schedule.hoscode+'\''">预约挂号 </span></div><div class="nav-item "><span class="v-link clickable dark" :onclick="'javascript:window.location=\'/hospital/detail/'+schedule.hoscode+'\''"> 医院详情 </span></div><div class="nav-item"><span class="v-link clickable dark" :onclick="'javascript:window.location=\'/hospital/notice/'+schedule.hoscode+'\''"> 预约须知 </span></div><div class="nav-item "><spanclass="v-link clickable dark"> 停诊信息 </span></div><div class="nav-item "><spanclass="v-link clickable dark"> 查询/取消 </span></div></div><!-- 左侧导航 #end --><!-- 右侧内容 #start --><div class="page-container"><div class="hospital-order"><div class="header-wrapper"><div class="title mt20"> 确认挂号信息</div><div><div class="sub-title"><div class="block"></div>选择就诊人:</div><div class="patient-wrapper"><div ><div class="v-card clickable item "><div class="inline" v-for="(item,index) in patientList" :key="item.id"@click="selectPatient(index)" style="margin-right: 10px;"><!-- 选中 selected 未选中去掉selected--><div :class="activeIndex == index ? 'item-wrapper selected' : 'item-wrapper'"><div><div class="item-title">{{ item.name }}</div><div>{{ item.param.certificatesTypeString }}</div><div>{{ item.certificatesNo }}</div></div><img src="//img.114yygh.com/static/web/checked.png" class="checked"></div></div></div></div><div class="item space add-patient v-card clickable"><div class=""><div class="item-add-wrapper" @click="addPatient()"> +添加就诊人</div></div></div><div class="el-loading-mask" style="display: none;"><div class="el-loading-spinner"><svg viewBox="25 25 50 50" class="circular"><circle cx="50" cy="50" r="20" fill="none" class="path"></circle></svg></div></div></div><!-- 就诊人,选中显示 --><div class="sub-title" v-if="patientList.length > 0"><div class="block"></div>选择就诊卡: <span class="card-tips"><spanclass="iconfont"></span> 如您持社保卡就诊,请务必选择医保预约挂号,以保证正常医保报销</span></div><el-card class="patient-card" shadow="always" v-if="patientList.length > 0"><div slot="header" class="clearfix"><div><span class="name"> {{ patient.name }} {{ patient.certificatesNo }} 居民身份证</span></div></div><div class="card SELF_PAY_CARD"><div class="info"><span class="type">{{ patient.isInsure == 0 ? '自费' : '医保'}}</span><span class="card-no">{{ patient.certificatesNo }}</span><spanclass="card-view">居民身份证</span></div><span class="operate"></span></div><div class="card"><div class="text bind-card"></div></div></el-card><div class="sub-title"><div class="block"></div>挂号信息</div><div class="content-wrapper"><el-form ref="form"><el-form-item label="就诊日期:"><div class="content"><span>{{ schedule.workDate }} {{ schedule.param.dayOfWeek }} {{ schedule.workTime == 0 ? '上午' : '下午' }}</span></div></el-form-item><el-form-item label="就诊医院:"><div class="content"><span>{{ schedule.param.hosname }} </span></div></el-form-item><el-form-item label="就诊科室:"><div class="content"><span>{{ schedule.param.depname }} </span></div></el-form-item><el-form-item label="医生姓名:"><div class="content"><span>{{ schedule.docname }} </span></div></el-form-item><el-form-item label="医生职称:"><div class="content"><span>{{ schedule.title }} </span></div></el-form-item><el-form-item label="医生专长:"><div class="content"><span>{{ schedule.skill }}</span></div></el-form-item><el-form-item label="医事服务费:"><div class="content"><div class="fee">{{ schedule.amount }}元</div></div></el-form-item></el-form></div><!-- 用户信息 #start--><div><div class="sub-title"><div class="block"></div>用户信息</div><div class="content-wrapper"><el-form ref="form" :model="form"><el-form-item class="form-item" label="就诊人手机号:">{{ patient.phone }}</el-form-item></el-form></div></div><!-- 用户信息 #end --><div class="bottom-wrapper"><div class="button-wrapper"><div class="v-button" @click="submitOrder()">{{ submitBnt }}</div></div></div></div></div></div></div><!-- 右侧内容 #end --></div><!-- footer --></template><script>import '~/assets/css/hospital_personal.css'import '~/assets/css/hospital.css'import scheduleApi from '@/api/schedule'import patientApi from '@/api/patient'export default {data() {return {scheduleId: null,schedule: {param: {}},patientList: [],patient: {},activeIndex: 0,submitBnt: '确认挂号'}},created() {this.scheduleId = this.$route.query.scheduleIdthis.init()},methods: {init() {this.getSchedule()this.findPatientList()},getSchedule() {scheduleApi.getSchedule(this.scheduleId).then(response => {this.schedule = response.data.schedule})},findPatientList() {patientApi.findList().then(response => {this.patientList = response.data.listif(this.patientList.length > 0) {this.patient = this.patientList[0]}})},selectPatient(index) {this.activeIndex = index;this.patient = this.patientList[index]},submitOrder() {},addPatient() {window.location.href = '/patient/add'}}}</script><style>.hospital-order .header-wrapper {display: -webkit-box;display: -ms-flexbox;display: block !important;-webkit-box-align: center;-ms-flex-align: center;align-items: center;}.hospital-order .sub-title {letter-spacing: 1px;color: #999;margin-top: 60px;display: -webkit-box;display: -ms-flexbox;display: flex;-webkit-box-align: center;-ms-flex-align: center;align-items: center;}.hospital-order .content-wrapper .content {color: #333;}.el-form-item {margin-bottom: 5px;}.hospital-order .content-wrapper {margin-left: 140px;margin-top: 20px;}</style>