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>
//发送验证码
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 {
@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>
<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 {
@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.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产品域名(接口地址固定,无需修改)
// 替换成你的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.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并实现体检预约方法。
体检预约方法处理逻辑比较复杂,需要进行如下业务处理:
-
检查用户所选择的预约日期是否已经提前进行了预约设置,如果没有设置则无法进行预约
-
检查用户所选择的预约日期是否已经约满,如果已经约满则无法预约
-
检查用户是否重复预约(同一个用户在同一天预约了同一个套餐),如果是重复预约则无法完成再次预约
-
检查当前用户是否为会员,如果是会员则直接完成预约,如果不是会员则自动完成注册并进行预约
-
预约成功,更新当日的已预约人数
实现代码如下:
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 {
@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.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_ordersetting
where 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 <= #{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.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">
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.itheiheihei.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;
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>