1. 体检预约流程
用户可以通过如下操作流程进行体检预约:
- 在移动端首页点击体检预约,页面跳转到套餐列表页面
- 在套餐列表页面点击要预约的套餐,页面跳转到套餐详情页面
- 在套餐详情页面点击立即预约,页面跳转到预约页面
- 在预约页面录入体检人信息,包括手机号,点击发送验证码
- 在预约页面录入收到的手机短信验证码,点击提交预约,完成体检预约
2.体检预约
2.1 页面调整
在预约页面(/pages/orderInfo.html)进行调整
2.1.1 展示预约的套餐信息
第一步:从请求路径中获取当前套餐的id
<script> var id = getUrlParam("id");//套餐id </script>
第二步:定义模型数据setmeal,用于套餐数据展示
var vue = new Vue({ el: '#app', data: { setmeal: {},//套餐信息 orderInfo: { setmealId: id, sex: '1' }//预约信息 } }); <div class="card"> <div class=""> <img :src="'http://pqjroc654.bkt.clouddn.com/'+setmeal.img" width="100%" height="100%"/> </div> <div class="project-text"> <h4 class="tit">{{setmeal.name}}</h4> <p class="subtit">{{setmeal.remark}}</p> <p class="keywords"> <span>{{setmeal.sex == '0' ? '性别不限' : setmeal.sex == '1' ? '男':'女'}}</span> <span>{{setmeal.age}}</span> </p> </div> <div class="project-know"> <a href="orderNotice.html" class="link-page"> <i class="icon-ask-circle"><span class="path1"></span><span class="path2"></span></i> <span class="word">预约须知</span> <span class="arrow"><i class="icon-rit-arrow"></i></span> </a> </div> </div>
第三步:在VUE的钩子函数中发送ajax请求,根据id查询套餐信息
mounted(){ //发送ajax请求,获取套餐信息 axios.post("/setmeal/findById.do?id=" + id).then((resp) => { if (resp.data.flag) { this.setmeal = resp.data.data; } else { this.$message.error(resp.data.message) } }) }
2.1.2 手机号校验
第一步:在页面导入的healthmobile.js文件中已经定义了校验手机号的方法
/** * 手机号校验 1‐‐以1为开头; 2‐‐第二位可为3,4,5,7,8,中的任意一位; 3‐‐最后以0‐9的9个整数结尾。 */ function checkTelephone(telephone) { var reg=/^[1][3,4,5,7,8][0‐9]{9}$/; if (!reg.test(telephone)) { return false; } else { return true; } }
第二步:为发送验证码按钮绑定事件sendValidateCode
<div class="input‐row"> <label>手机号</label> <input v‐model="orderInfo.telephone" type="text" class="input‐clear" placeholder="请输入手机号"> <input style="font‐size: x‐small;" id="validateCodeButton" @click="sendValidateCode()" type="button" value="发送验证码"> </div> 12345 //发送验证码 sendValidateCode(){ //获取用户输入的手机号 var telephone = this.orderInfo.telephone; //校验手机号输入是否正确 if (!checkTelephone(telephone)) { this.$message.error('请输入正确的手机号'); return false; } }
2.1.3 30秒倒计时效果
前面在sendValidateCode方法中进行了手机号校验,如果校验通过,需要显示30秒倒计时效果
//发送验证码 sendValidateCode(){ //获取用户输入的手机号 var telephone = this.orderInfo.telephone; //校验手机号输入是否正确 if (!checkTelephone(telephone)) { this.$message.error('请输入正确的手机号'); return false; } validateCodeButton = $("#validateCodeButton")[0]; clock = window.setInterval(doLoop, 1000); //一秒执行一次 }
其中,validateCodeButton和clock是在healthmobile.js文件中定义的变量,doLoop是在healthmobile.js文件中定义的方法
var clock = '';//定时器对象,用于页面30秒倒计时效果 var nums = 30; var validateCodeButton; //基于定时器实现30秒倒计时效果 function doLoop() { validateCodeButton.disabled = true;//将按钮置为不可点击 nums‐‐; if (nums > 0) { validateCodeButton.value = nums + '秒后重新获取'; } else { clearInterval(clock); //清除js定时器 validateCodeButton.disabled = false; validateCodeButton.value = '重新获取验证码'; nums = 30; //重置时间 } }
2.1.4 发送ajax请求
在按钮上显示30秒倒计时效果的同时,需要发送ajax请求,在后台给用户发送手机验证码
//发送验证码 sendValidateCode(){ //获取用户输入的手机号 var telephone = this.orderInfo.telephone; //校验手机号输入是否正确 if (!checkTelephone(telephone)) { this.$message.error('请输入正确的手机号'); return false; } validateCodeButton = $("#validateCodeButton")[0]; clock = window.setInterval(doLoop, 1000); //一秒执行一次 axios.post("/validateCode/send4Order.do?telephone=" +telephone).then((response) => { if(!response.data.flag){ //验证码发送失败 this.$message.error('验证码发送失败,请检查手机号输入是否正确'); } }); }
创建ValidateCodeController,提供方法发送短信验证码,并将验证码保存到redis
package com.oldlu.controller; import com.aliyuncs.exceptions.ClientException; import com.oldlu.constant.MessageConstant; import com.oldlu.constant.RedisMessageConstant; import com.oldlu.entity.Result; import com.oldlu.utils.SMSUtils; import com.oldlu.utils.ValidateCodeUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import redis.clients.jedis.JedisPool; /** * 验证码管理 * * @author oldlu * @version 1.0 * @date 2019/10/21 15:29 */ @RestController @RequestMapping("/vaildateCode") public class ValidateCodeController { @Autowired private JedisPool jedisPool; /** * 用户提交预约发送验证码 * * @param telephone * @return */ @RequestMapping("/send4Order") public Result send4Order(String telephone) { try { //给用户是否验证码 //获取随机4位验证码 Integer code = ValidateCodeUtils.generateValidateCode(4); //发送短信 SMSUtils.sendShortMessage(SMSUtils.VALIDATE_CODE, telephone, code.toString()); //将验证码保存到redis(5分钟 ) jedisPool.getResource().setex(telephone + RedisMessageConstant.SENDTYPE_ORDER, 500, code.toString()); return new Result(true, MessageConstant.SEND_VALIDATECODE_SUCCESS); } catch (ClientException e) { e.printStackTrace(); return new Result(false, MessageConstant.SEND_VALIDATECODE_FAIL); } } }
2.1.5 日历展示
页面中使用DatePicker控件来展示日历。根据需求,最多可以提前一个月进行体检预约,所以日历控件只展示未来一个月的日期
<div class="date"> <label>体检日期</label> <i class="icon‐date" class="picktime"></i> <input v‐model="orderInfo.orderDate" type="text" class="picktime" readonly> </div> 12345 <script> //日期控件 var calendar = new datePicker(); calendar.init({ 'trigger': '.picktime',/*按钮选择器,用于触发弹出插件*/ 'type': 'date',/*模式:date日期;datetime日期时间;time时间;ym年月;*/ 'minDate': getSpecifiedDate(new Date(),1),/*最小日期*/ 'maxDate': getSpecifiedDate(new Date(),30),/*最大日期*/ 'onSubmit': function() { /*确认时触发事件*/}, 'onClose': function() { /*取消时触发事件*/ } }); </script>
其中getSpecifiedDate
方法定义在healthmobile.js
文件中
//获得指定日期后指定天数的日期 function getSpecifiedDate(date,days) { date.setDate(date.getDate() + days);//获取指定天之后的日期 var year = date.getFullYear(); var month = date.getMonth() + 1; var day = date.getDate(); return (year + "‐" + month + "‐" + day); }
2.1.6 提交预约请求
为提交预约按钮绑定事件
<div class="box‐button"> <button @click="submitOrder()" type="button" class="btn order‐btn">提交预约</button> </div> 123 //提交预约 submitOrder(){ //校验身份证号格式 if(!checkIdCard(this.orderInfo.idCard)){ this.$message.error('身份证号码输入错误,请重新输入'); return ; } axios.post("/order/submit.do",this.orderInfo).then((response) => { if(response.data.flag){ //预约成功,跳转到预约成功页面 window.location.href="orderSuccess.html?orderId=" + response.data.data; }else{ //预约失败,提示预约失败信息 this.$message.error(response.data.message); } }); }
其中checkIdCard方法是在healthmobile.js文件中定义的
/** * 身份证号码校验 * 身份证号码为15位或者18位,15位时全为数字,18位前17位为数字,最后一位是校验位,可能为数字或字符X */ function checkIdCard(idCard){ var reg = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/; if(reg.test(idCard)){ return true; }else{ return false; } } 1234567891011
2.2 后台代码
2.2.1 Controller
在health_mobile工程中创建OrderController并提供submitOrder方法
package com.oldlu.controller; import com.alibaba.dubbo.config.annotation.Reference; import com.aliyuncs.exceptions.ClientException; import com.oldlu.constant.MessageConstant; import com.oldlu.constant.RedisMessageConstant; import com.oldlu.entity.Result; import com.oldlu.pojo.Order; import com.oldlu.service.OrderService; import com.oldlu.utils.SMSUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import java.util.Map; /** * 体检预约处理 * * @author oldlu * @version 1.0 * @date 2019/10/21 16:30 */ @RestController @RequestMapping("/order") public class OrderController { @Autowired private JedisPool jedisPool; @Reference private OrderService orderService; @RequestMapping("submit") public Result submit(@RequestBody Map map) { String telephone = (String) map.get("telephone"); String validateCode = (String) map.get("validateCode"); if (telephone == null || validateCode == null) { return new Result(false, MessageConstant.TELEPHONE_VALIDATECODE_NOTNULL); } //Redis中获取保存的验证码 String validateCodeInRedis = jedisPool.getResource().get(telephone + RedisMessageConstant.SENDTYPE_ORDER); //将用户输入的验证码和Redis中保存的验证码进行比对 if (validateCodeInRedis != null && validateCodeInRedis.equals(validateCode)) { //如果对比成功,调用服务完成预约业务处理 Result result = null; try { map.put("orderType", Order.ORDERTYPE_WEIXIN); result = orderService.order(map); } catch (Exception e) { e.printStackTrace(); return result; } if (result.isFlag()) { //预约成功短信通知 String orderDate = (String) map.get("orderDate"); try { SMSUtils.sendShortMessage(SMSUtils.ORDER_NOTICE, telephone, orderDate); } catch (ClientException e) { e.printStackTrace(); } } return result; } else { //如果比对不成功,返回结果给页面 return new Result(false, MessageConstant.VALIDATECODE_ERROR); } } }
- SMSUtils
package com.oldlu.utils; import com.aliyuncs.DefaultAcsClient; import com.aliyuncs.IAcsClient; import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest; import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse; import com.aliyuncs.exceptions.ClientException; import com.aliyuncs.http.MethodType; import com.aliyuncs.profile.DefaultProfile; import com.aliyuncs.profile.IClientProfile; /** * 短信发送工具类 */ public class SMSUtils { public static final String VALIDATE_CODE = "SMS_175532946";//发送短信验证码 public static final String ORDER_NOTICE = "SMS_175582890";//体检预约成功通知 /** * 发送短信 * * @param phoneNumbers * @param param * @throws ClientException */ public static void sendShortMessage(String templateCode, String phoneNumbers, String param) throws ClientException { // 设置超时时间-可自行调整 System.setProperty("sun.net.client.defaultConnectTimeout", "10000"); System.setProperty("sun.net.client.defaultReadTimeout", "10000"); // 初始化ascClient需要的几个参数 final String product = "Dysmsapi";// 短信API产品名称(短信产品名固定,无需修改) final String domain = "dysmsapi.aliyuncs.com";// 短信API产品域名(接口地址固定,无需修改) // 替换成你的AK final String accessKeyId = "";// 你的accessKeyId, final String accessKeySecret = "";// 你的accessKeySecret, // 初始化ascClient,暂时不支持多region(请勿修改) IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, accessKeySecret); DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product, domain); IAcsClient acsClient = new DefaultAcsClient(profile); // 组装请求对象 SendSmsRequest request = new SendSmsRequest(); // 使用post提交 request.setMethod(MethodType.POST); // 必填:待发送手机号。支持以逗号分隔的形式进行批量调用,批量上限为1000个手机号码,批量调用相对于单条调用及时性稍有延迟,验证码类型的短信推荐使用单条调用的方式 request.setPhoneNumbers(phoneNumbers); // 必填:短信签名-可在短信控制台中找到 request.setSignName("XX健康"); // 必填:短信模板-可在短信控制台中找到 request.setTemplateCode(templateCode); // 可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为 // 友情提示:如果JSON中需要带换行符,请参照标准的JSON协议对换行符的要求,比如短信内容中包含\r\n的情况在JSON中需要表示成\\r\\n,否则会导致JSON在服务端解析失败 request.setTemplateParam("{\"code\":\"" + param + "\"}"); // 可选-上行短信扩展码(扩展码字段控制在7位或以下,无特殊需求用户请忽略此字段) // request.setSmsUpExtendCode("90997"); // 可选:outId为提供给业务方扩展字段,最终在短信回执消息中将此值带回给调用者 // request.setOutId("yourOutId"); // 请求失败这里会抛ClientException异常 SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request); if (sendSmsResponse.getCode() != null && sendSmsResponse.getCode().equals("OK")) { // 请求成功 System.out.println("请求成功"); } } }
2.2.2 服务接口
在health_interface工程中创建体检预约服务接口OrderService并提供预约方法
package com.oldlu.service; import com.oldlu.entity.Result; import java.util.Map; /** * 体检预约服务接口 */ public interface OrderService { //体检预约 public Result order(Map map) throws Exception; }
2.2.3 服务实现类
在health_service_provider工程中创建体检预约服务实现类OrderServiceImpl并实现体检预约方法。
体检预约方法处理逻辑比较复杂,需要进行如下业务处理:
- 检查用户所选择的预约日期是否已经提前进行了预约设置,如果没有设置则无法进行预约
- 检查用户所选择的预约日期是否已经约满,如果已经约满则无法预约
- 检查用户是否重复预约(同一个用户在同一天预约了同一个套餐),如果是重复预约则无法完成再次预约
- 检查当前用户是否为会员,如果是会员则直接完成预约,如果不是会员则自动完成注册并进行预约
- 预约成功,更新当日的已预约人数
实现代码如下:
package com.oldlu.service.impl; import com.alibaba.dubbo.config.annotation.Service; import com.oldlu.constant.MessageConstant; import com.oldlu.dao.MemberDao; import com.oldlu.dao.OrderDao; import com.oldlu.dao.OrderSettingDao; import com.oldlu.entity.Result; import com.oldlu.pojo.Member; import com.oldlu.pojo.Order; import com.oldlu.pojo.OrderSetting; import com.oldlu.service.OrderService; import com.oldlu.utils.DateUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import java.util.Date; import java.util.List; import java.util.Map; /** * 体检预约服务 * * @author oldlu * @version 1.0 * @date 2019/10/21 22:28 */ @Service(interfaceClass = OrderService.class) @Transactional public class OrderServiceImpl implements OrderService { @Autowired private OrderSettingDao orderSettingDao; @Autowired private MemberDao memberDao; @Autowired private OrderDao orderDao; /** * 体检预约 * * @param map * @return * @throws Exception */ @Override public Result order(Map map) throws Exception { //1. 检查用户所选择的预约日期是否已经提前进行了预约设置,如果没有设置则无法进行预约 String orderDate = (String) map.get("orderDate"); Date orderTime = DateUtils.parseString2Date(orderDate); OrderSetting orderSetting = orderSettingDao.findByOrderDate(orderTime); if (orderSetting == null) { //指定日期没有进行预约设置,无法完成体检预约 return new Result(false, MessageConstant.SELECTED_DATE_CANNOT_ORDER); } //2. 检查用户所选择的预约日期是否已经约满,如果已经约满则无法预约 int number = orderSetting.getNumber(); int reservations = orderSetting.getReservations(); if (reservations > number) { //已经约满,无法预约 return new Result(false, MessageConstant.ORDER_FULL); } //3. 检查用户是否重复预约(同一个用户在同一天预约了同一个套餐),如果是重复预约则无法完成再次预约 //获取用户输入的手机号 String telephone = (String) map.get("telephone"); Member member = memberDao.findByTelephone(telephone); if (member != null) { //判断是否重复预约 Integer id = member.getId(); Integer setmealId = (Integer) map.get("setmealId"); Order order = new Order(setmealId, orderTime, setmealId); //根据条件进行查询 List<Order> orderList = orderDao.findByCondition(order); if (orderList != null && orderList.size() > 0) { //说明用户在重复预约,无法完成再次预约 return new Result(false, MessageConstant.HAS_ORDERED); } } else { //4. 检查当前用户是否为会员,如果是会员则直接完成预约,如果不是会员则自动完成注册并进行预约 member = new Member(); member.setName((String) map.get("name")); member.setPhoneNumber(telephone); member.setIdCard((String) map.get("idCard")); member.setSex((String) map.get("sex")); member.setRegTime(new Date()); //自动完成会员注册 memberDao.add(member); } //5. 预约成功,更新当日的已预约人数 Order order = new Order(); order.setMemberId(member.getId()); order.setOrderDate(orderTime); order.setOrderType((String) map.get("orderType")); order.setSetmealId(Integer.parseInt((String) map.get("setmealId"))); orderDao.add(order); //更新当日的已预约人数 orderSetting.setReservations(orderSetting.getReservations()+1); orderSettingDao.editReservationsByOrderDate(orderSetting); return new Result(true,MessageConstant.ORDER_SUCCESS,order.getId()); } }
2.2.4 Dao接口
package com.oldlu.dao; import com.oldlu.pojo.OrderSetting; import java.util.Date; import java.util.List; import java.util.Map; /** * @author oldlu * @version 1.0 * @date 2019/10/18 20:17 */ public interface OrderSettingDao { /** * 根据预约时间查询是否存在预约 * @param orderDate * @return */ public long findCountByOrderDate(Date orderDate); /** * 添加预约 * @param orderSetting */ public void add(OrderSetting orderSetting); /** * 根据预约时间修改预约人数 * @param orderSetting */ public void editNumberByOrderDate(OrderSetting orderSetting); /** * 根据月份查询对应的预约设置数据 * @param map * @return */ public List<OrderSetting> getOrderSettingByMonth(Map<String, String> map); /** * 根据时间查询预约设置信息 * @param date * @return */ public OrderSetting findByOrderDate(Date date); /** * 更新已预约人数 * @param orderSetting */ public void editReservationsByOrderDate(OrderSetting orderSetting); } package com.oldlu.dao; import com.github.pagehelper.Page; import com.oldlu.pojo.Member; import java.util.List; public interface MemberDao { public List<Member> findAll(); public Page<Member> selectByCondition(String queryString); public void add(Member member); public void deleteById(Integer id); public Member findById(Integer id); public Member findByTelephone(String telephone); public void edit(Member member); public Integer findMemberCountBeforeDate(String date); public Integer findMemberCountByDate(String date); public Integer findMemberCountAfterDate(String date); public Integer findMemberTotalCount(); } package com.oldlu.dao; import com.oldlu.pojo.Order; import java.util.List; import java.util.Map; public interface OrderDao { public List<Order> findByCondition(Order order); }
2.2.5 Mapper映射文件
OrderSettingDao.xml
<!--根据日期查询预约设置信息--> <select id="findByOrderDate" parameterType="date" resultType="com.oldlu.pojo.OrderSetting"> select * from t_ordersetting where orderDate = #{orderdate} </select> <!--更新已预约人数--> <update id="editReservationsByOrderDate" parameterType="com.oldlu.pojo.OrderSetting"> update t_ordersetting set reservations = #{reservations} where orderDate = #{orderDate} </update>
MemberDao.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace="com.oldlu.dao.MemberDao" > <select id="findAll" resultType="com.oldlu.pojo.Member"> select * from t_member </select> <!--根据条件查询--> <select id="selectByCondition" parameterType="string" resultType="com.oldlu.pojo.Member"> select * from t_member <if test="value != null and value.length > 0"> where fileNumber = #{value} or phoneNumber = #{value} or name = #{value} </if> </select> <!--新增会员--> <insert id="add" parameterType="com.oldlu.pojo.Member"> <selectKey resultType="java.lang.Integer" order="AFTER" keyProperty="id"> SELECT LAST_INSERT_ID() </selectKey> insert into t_member(fileNumber,name,sex,idCard,phoneNumber,regTime,password,email,birthday,remark) values (#{fileNumber},#{name},#{sex},#{idCard},#{phoneNumber},#{regTime},#{password},#{email},#{birthday},#{remark}) </insert> <!--删除会员--> <delete id="deleteById" parameterType="int"> delete from t_member where id = #{id} </delete> <!--根据id查询会员--> <select id="findById" parameterType="int" resultType="com.oldlu.pojo.Member"> select * from t_member where id = #{id} </select> <!--根据id查询会员--> <select id="findByTelephone" parameterType="string" resultType="com.oldlu.pojo.Member"> select * from t_member where phoneNumber = #{phoneNumber} </select> <!--编辑会员--> <update id="edit" parameterType="com.oldlu.pojo.Member"> update t_member <set> <if test="fileNumber != null"> fileNumber = #{fileNumber}, </if> <if test="name != null"> name = #{name}, </if> <if test="sex != null"> sex = #{sex}, </if> <if test="idCard != null"> idCard = #{idCard}, </if> <if test="phoneNumber != null"> phoneNumber = #{phoneNumber}, </if> <if test="regTime != null"> regTime = #{regTime}, </if> <if test="password != null"> password = #{password}, </if> <if test="email != null"> email = #{email}, </if> <if test="birthday != null"> birthday = #{birthday}, </if> <if test="remark != null"> remark = #{remark}, </if> </set> where id = #{id} </update> <!--根据日期统计会员数,统计指定日期之前的会员数--> <select id="findMemberCountBeforeDate" parameterType="string" resultType="int"> select count(id) from t_member where regTime <= #{value} </select> <!--根据日期统计会员数--> <select id="findMemberCountByDate" parameterType="string" resultType="int"> select count(id) from t_member where regTime = #{value} </select> <!--根据日期统计会员数,统计指定日期之后的会员数--> <select id="findMemberCountAfterDate" parameterType="string" resultType="int"> select count(id) from t_member where regTime >= #{value} </select> <!--总会员数--> <select id="findMemberTotalCount" resultType="int"> select count(id) from t_member </select> </mapper>
OrderDao.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace="com.oldlu.dao.OrderDao"> <resultMap id="baseResultMap" type="com.oldlu.pojo.Order"> <id column="id" property="id"/> <result column="member_id" property="memberId"/> <result column="orderDate" property="orderDate"/> <result column="orderType" property="orderType"/> <result column="orderStatus" property="orderStatus"/> <result column="setmeal_id" property="setmealId"/> </resultMap> <!--新增--> <insert id="add" parameterType="com.oldlu.pojo.Order"> <selectKey resultType="java.lang.Integer" order="AFTER" keyProperty="id"> SELECT LAST_INSERT_ID() </selectKey> insert into t_order(member_id,orderDate,orderType,orderStatus,setmeal_id) values (#{memberId},#{orderDate},#{orderType},#{orderStatus},#{setmealId}) </insert> <!--动态条件查询--> <select id="findByCondition" parameterType="com.oldlu.pojo.Order" resultMap="baseResultMap"> select * from t_order <where> <if test="id != null"> and id = #{id} </if> <if test="memberId != null"> and member_id = #{memberId} </if> <if test="orderDate != null"> and orderDate = #{orderDate} </if> <if test="orderType != null"> and orderType = #{orderType} </if> <if test="orderStatus != null"> and orderStatus = #{orderStatus} </if> <if test="setmealId != null"> and setmeal_id = #{setmealId} </if> </where> </select> <!--根据预约id查询预约信息,包括体检人信息、套餐信息--> <select id="findById4Detail" parameterType="int" resultType="map"> select m.name member, s.name setmeal, o.orderDate orderDate, o.orderType orderType from t_order o, t_member m, t_setmeal s where o.member_id = m.id and o.setmeal_id = s.id and o.id = #{id} </select> <!--根据日期统计预约数--> <select id="findOrderCountByDate" parameterType="string" resultType="int"> select count(id) from t_order where orderDate = #{value} </select> <!--根据日期统计预约数,统计指定日期之后的预约数--> <select id="findOrderCountAfterDate" parameterType="string" resultType="int"> select count(id) from t_order where orderDate >= #{value} </select> <!--根据日期统计到诊数--> <select id="findVisitsCountByDate" parameterType="string" resultType="int"> select count(id) from t_order where orderDate = #{value} and orderStatus = '已到诊' </select> <!--根据日期统计到诊数,统计指定日期之后的到诊数--> <select id="findVisitsCountAfterDate" parameterType="string" resultType="int"> select count(id) from t_order where orderDate >= #{value} and orderStatus = '已到诊' </select> <!--热门套餐,查询前5条--> <select id="findHotSetmeal" resultType="map"> select s.name, count(o.id) setmeal_count, count(o.id) / (select count(id) from t_order) proportion from t_order o inner join t_setmeal s on s.id = o.setmeal_id group by o.setmeal_id order by setmeal_count desc limit 0, 4 </select> <select id="findById" parameterType="int" resultType="com.oldlu.pojo.Order"> select * from t_order where id = #{id} </select> </mapper>
3. 预约成功页面展示
前面已经完成了体检预约,预约成功后页面会跳转到成功提示页面
(orderSuccess.html
)并展示预约的相关信息(体检人、体检套餐、体检时间等)。
3.1 页面调整
提供orderSuccess.html页面,展示预约成功后相关信息
<div class="info-title"> <span class="name">体检预约成功</span> </div> <div class="notice-item"> <div class="item-title">预约信息</div> <div class="item-content"> <p>体检人:{{orderInfo.member}}</p> <p>体检套餐:{{orderInfo.setmeal}}</p> <p>体检日期:{{orderInfo.orderDate}}</p> <p>预约类型:{{orderInfo.orderType}}</p> </div> </div> <script> var vue = new Vue({ el: '#app', data: { orderInfo: {} }, mounted() { //发送ajax请求,根据预约ID查询相关信息,用于页面显示 axios.post("/order/findById.do?id=" + id).then((response) => { if (response.data.flag) { this.orderInfo = response.data.data; } else { this.$message.error(response.data.message) } }); } }); </script>
3.2 后台代码
3.2.1 Controller
在OrderController中提供findById方法,根据预约id查询预约相关信息
/** * 根据id查询预约详细信息,包括套餐信息和会员信息 * @param id * @return */ @RequestMapping("/findById") public Result findById(Integer id) { try { Map map = orderService.findById(id); return new Result(true, MessageConstant.QUERY_ORDER_SUCCESS, map); } catch (Exception e) { e.printStackTrace(); return new Result(false, MessageConstant.QUERY_ORDER_FAIL); } }
3.2.2 服务接口
在OrderService服务接口中扩展findById方法
//根据id查询预约信息,包括体检人信息、套餐信息 public Map findById(Integer id) throws Exception; 123
3.2.3 服务实现类
在OrderServiceImpl服务实现类中实现findById方法
/** * 根据预约ID查询预约详细信息,包括体检人信息、套餐信息 * * @param id * @return * @throws Exception */ @Override public Map findById(Integer id) throws Exception { Map map = orderDao.findById4Detail(id); //处理日期格式 if (map != null) { Date orderDate = (Date) map.get("orderDate"); map.put("orderDate", DateUtils.parseDate2String(orderDate)); } return map; }
3.2.4 Dao接口
在OrderDao接口中扩展findById4Detail方法
public Map findById4Detail(Integer id);
3.2.5 Mapper映射文件
在OrderDao.xml映射文件中提供SQL语句
<!‐‐根据预约id查询预约信息,包括体检人信息、套餐信息‐‐> <!--根据预约id查询预约信息,包括体检人信息、套餐信息--> <select id="findById4Detail" parameterType="int" resultType="map"> select m.name member, s.name setmeal, o.orderDate orderDate, o.orderType orderType from t_order o, t_member m, t_setmeal s where o.member_id = m.id and o.setmeal_id = s.id and o.id = #{id} </select>