1. 体检预约流程

用户可以通过如下操作流程进行体检预约:

  1. 在移动端首页点击体检预约,页面跳转到套餐列表页面

  2. 在套餐列表页面点击要预约的套餐,页面跳转到套餐详情页面

  3. 在套餐详情页面点击立即预约,页面跳转到预约页面

  4. 在预约页面录入体检人信息,包括手机号,点击发送验证码

  5. 在预约页面录入收到的手机短信验证码,点击提交预约,完成体检预约

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>
//发送验证码
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.itheiheihei.controller;import com.aliyuncs.exceptions.ClientException;
import com.itheiheihei.constant.MessageConstant;
import com.itheiheihei.constant.RedisMessageConstant;
import com.itheiheihei.entity.Result;
import com.itheiheihei.utils.SMSUtils;
import com.itheiheihei.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 嘿嘿嘿1212* @version 1.0* @date 2019/10/21 15:29*/
@RestController
@RequestMapping("/vaildateCode")
public class ValidateCodeController {@Autowiredprivate 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>
<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>
//提交预约
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;}
}

2.2 后台代码

2.2.1 Controller

在health_mobile工程中创建OrderController并提供submitOrder方法

package com.itheiheihei.controller;import com.alibaba.dubbo.config.annotation.Reference;
import com.aliyuncs.exceptions.ClientException;
import com.itheiheihei.constant.MessageConstant;
import com.itheiheihei.constant.RedisMessageConstant;
import com.itheiheihei.entity.Result;
import com.itheiheihei.pojo.Order;
import com.itheiheihei.service.OrderService;
import com.itheiheihei.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 嘿嘿嘿1212* @version 1.0* @date 2019/10/21 16:30*/
@RestController
@RequestMapping("/order")
public class OrderController {@Autowiredprivate JedisPool jedisPool;@Referenceprivate 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.itheiheihei.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产品域名(接口地址固定,无需修改)// 替换成你的AKfinal 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.itheiheihei.service;import com.itheiheihei.entity.Result;
import java.util.Map;/**
*   体检预约服务接口
*/public interface OrderService {//体检预约public Result order(Map map) throws Exception;
}

2.2.3 服务实现类

在health_service_provider工程中创建体检预约服务实现类OrderServiceImpl并实现体检预约方法。

体检预约方法处理逻辑比较复杂,需要进行如下业务处理:

  1. 检查用户所选择的预约日期是否已经提前进行了预约设置,如果没有设置则无法进行预约

  2. 检查用户所选择的预约日期是否已经约满,如果已经约满则无法预约

  3. 检查用户是否重复预约(同一个用户在同一天预约了同一个套餐),如果是重复预约则无法完成再次预约

  4. 检查当前用户是否为会员,如果是会员则直接完成预约,如果不是会员则自动完成注册并进行预约

  5. 预约成功,更新当日的已预约人数

实现代码如下:

package com.itheiheihei.service.impl;import com.alibaba.dubbo.config.annotation.Service;
import com.itheiheihei.constant.MessageConstant;
import com.itheiheihei.dao.MemberDao;
import com.itheiheihei.dao.OrderDao;
import com.itheiheihei.dao.OrderSettingDao;
import com.itheiheihei.entity.Result;
import com.itheiheihei.pojo.Member;
import com.itheiheihei.pojo.Order;
import com.itheiheihei.pojo.OrderSetting;
import com.itheiheihei.service.OrderService;
import com.itheiheihei.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 嘿嘿嘿1212* @version 1.0* @date 2019/10/21 22:28*/
@Service(interfaceClass = OrderService.class)
@Transactional
public class OrderServiceImpl implements OrderService {@Autowiredprivate OrderSettingDao orderSettingDao;@Autowiredprivate MemberDao memberDao;@Autowiredprivate OrderDao orderDao;/*** 体检预约** @param map* @return* @throws Exception*/@Overridepublic 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.itheiheihei.dao;import com.itheiheihei.pojo.OrderSetting;import java.util.Date;
import java.util.List;
import java.util.Map;/*** @author 嘿嘿嘿1212* @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.itheiheihei.dao;import com.github.pagehelper.Page;
import com.itheiheihei.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.itheiheihei.dao;import com.itheiheihei.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.itheiheihei.pojo.OrderSetting">select *from t_ordersettingwhere orderDate = #{orderdate}
</select>
<!--更新已预约人数-->
<update id="editReservationsByOrderDate" parameterType="com.itheiheihei.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.itheiheihei.dao.MemberDao" ><select id="findAll" resultType="com.itheiheihei.pojo.Member">select * from t_member</select><!--根据条件查询--><select id="selectByCondition" parameterType="string" resultType="com.itheiheihei.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.itheiheihei.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.itheiheihei.pojo.Member">select * from t_member where id = #{id}</select><!--根据id查询会员--><select id="findByTelephone" parameterType="string" resultType="com.itheiheihei.pojo.Member">select * from t_member where phoneNumber = #{phoneNumber}</select><!--编辑会员--><update id="edit" parameterType="com.itheiheihei.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 &lt;= #{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 &gt;= #{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.itheiheihei.dao.OrderDao"><resultMap id="baseResultMap" type="com.itheiheihei.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.itheiheihei.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.itheiheihei.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">selectm.name      member,s.name      setmeal,o.orderDate orderDate,o.orderType orderTypefromt_order o,t_member m,t_setmeal swhere 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_orderwhere orderDate = #{value}</select><!--根据日期统计预约数,统计指定日期之后的预约数--><select id="findOrderCountAfterDate" parameterType="string" resultType="int">select count(id)from t_orderwhere orderDate &gt;= #{value}</select><!--根据日期统计到诊数--><select id="findVisitsCountByDate" parameterType="string" resultType="int">select count(id)from t_orderwhere orderDate = #{value} and orderStatus = '已到诊'</select><!--根据日期统计到诊数,统计指定日期之后的到诊数--><select id="findVisitsCountAfterDate" parameterType="string" resultType="int">select count(id)from t_orderwhere orderDate &gt;= #{value} and orderStatus = '已到诊'</select><!--热门套餐,查询前5条--><select id="findHotSetmeal" resultType="map">selects.name,count(o.id)                  setmeal_count,count(o.id) / (select count(id)from t_order) proportionfrom t_order o inner join t_setmeal s on s.id = o.setmeal_idgroup by o.setmeal_idorder by setmeal_count desclimit 0, 4</select><select id="findById" parameterType="int" resultType="com.itheiheihei.pojo.Order">select *from t_orderwhere 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;

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">selectm.name      member,s.name      setmeal,o.orderDate orderDate,o.orderType orderTypefromt_order o,t_member m,t_setmeal swhere o.member_id = m.id and o.setmeal_id = s.id and o.id = #{id}
</select>

XX健康:移动端开发-体检预约验证码30秒倒计时短信验证码获取与验证DatePicker日历展示提交预约复杂流程阿里短信工具类相关推荐

  1. XX健康:移动端开发-体检预约设计和实现微信公众号注册阿里短信服务

    1. 移动端开发 1.1 移动端开发方式 随着移动互联网的兴起和手机的普及,目前移动端应用变得愈发重要,成为了各个商家的必争之地.例如,我们可以使用手机购物.支付.打车.玩游戏.订酒店.购票等,以前只 ...

  2. XX健康:移动端开发手机验证码快速登陆

    1. 需求分析 手机快速登录功能,就是通过短信验证码的方式进行登录.这种方式相对于用户名密码登录方式,用户不需要记忆自己的密码,只需要通过输入手机号并获取验证码就可以完成登录,是目前比较流行的登录方式 ...

  3. Day_06 传智健康项目-移动端开发-体检预约

    第6章 移动端开发-体检预约 1. 移动端开发 1.1 移动端开发方式 随着移动互联网的兴起和手机的普及,目前移动端应用变得愈发重要,成为了各个商家的必争之地.例如,我们可以使用手机购物.支付.打车. ...

  4. 传智健康2.0-6-移动端开发-体检预约

    第6章 移动端开发-体检预约 1. 移动端开发 1.1 移动端开发方式 随着移动互联网的兴起和手机的普及,目前移动端应用变得愈发重要,成为了各个商家的必争之地.例如,我们可以使用手机购物.支付.打车. ...

  5. 健康管理系统第七天(移动端_体检预约(手机号校验、发送验证码之后30秒倒计时效果、生成验证码、向手机发送验证码))

    一.体检预约流程 用户可以通过如下操作流程进行体检预约: 1.在移动端首页点击体检预约,页面跳转到套餐列表页面 2.在套餐列表页面点击要预约的套餐,页面跳转到套餐详情页面 3.在套餐详情页面点击立即预 ...

  6. 移动端开发-体检预约

    移动端开发-体检预约 目录 移动端开发-体检预约 1. 移动端开发 1.1 移动端开发方式 1.2 微信公众号开发 2. 需求分析和环境搭建 2.1 需求分析 2.2 搭建移动端工程 3. 套餐列表页 ...

  7. 移动端开发-体检预约 手机号校验 30秒倒计时 日历展示

    手机验证码 1. 体检预约流程 2.体检预约 2.1页面调整 2.1.1 展示预约的套餐信息 2.1.2 手机号校验 2.1.3 30秒倒计时效果 2.1.4 发送ajax请求 2.1.5 日历展示 ...

  8. 免费获取验证码60秒倒计时

    免费获取验证码60秒倒计时 <!DOCTYPE html> <html> <head> <script src="http://libs.baidu ...

  9. 简单实现vue验证码60秒倒计时功能

    简单实现vue验证码60秒倒计时功能 <span v-if="codeShow" @click="getPhoneCode">点击获取验证码< ...

最新文章

  1. DataGrid连接Access的快速分页法(2)——SQL语句的选用(升序与降序)
  2. Nginx源码分析--字符串处理
  3. CVPR 2021 | 基于稠密场景匹配的相机定位学习
  4. 谷歌启动搜索引擎新功能 网页Flash内容即时预览
  5. oracle 12C(12.2.0.1)安装-plm系统(一)
  6. Python-Jenkins助力传统发布流程
  7. 一个电脑白痴与黑客的对话
  8. 我们可以写100%,但是这样不科学
  9. WslRegisterDistribution failed with error: 0x8007019e The Windows Subsystem for Linux optional compo
  10. php论坛怎么架设,论坛架设有诀窍 phpWind配置技巧三则
  11. cordova+vue 项目打包成Android(apk)应用
  12. vue使用过程中的一些问题
  13. CC2530之定时器T3
  14. linux怎样重启命令,Linux重启命令介绍
  15. 进程的同步与通信,进程与线程同步的区别,进程与线程通信的区别
  16. 基于Zigbee和LabView的无线温度采集系统
  17. zemax---System Explorer(系统选项)
  18. 如何正确使用宝塔配置网站服务器?WEB服务器是什么?
  19. ROS学习笔记---ros的通信机制
  20. mysql----where 1=1是什么意思

热门文章

  1. java找出命题p和q的合取_从键盘输入两个命题变元P和Q的真值-求它们的合取、析取、蕴含和等价的真值.doc...
  2. npm ERR While resolving: vue-admin-template@3.8.0问题的解决方案
  3. 2021 RoboCom 世界机器人开发者大赛-本科组(复赛)
  4. 毕业设计 - 银行柜员业务绩效考核系统的设计与实现【源码+论文】
  5. (一)权限管理系统介绍
  6. 昭通计算机一级b考试试题及答案,2022云南昭通事业单位考试综合应用能力(B类)考试如何备考?...
  7. 关于printf()函数。
  8. vim 删除所有空行
  9. 化妆品标签宣称禁用词、风险词汇总
  10. 大数据产品推荐:星环人工智能平台