22-08-18 西安 尚医通(07)挂号流程、就医提醒,预约统计、rabbitmq的使用、定时任务、Echarts

这一天以来真的是有种劫后余生的感觉,体会到了为什么电视剧里那些人在经历一些事情之后,点根烟连打火机都点不着的感觉了,就是还没缓过来!


 挂号流程

大体流程是这样的

1、用户系统选中某一个科室下的某个排班,点击剩余按钮,跳转到一个页面然后选择就诊人,点击确认挂号。

2、现在状态就变为预约成功,未支付状态。我们点击支付,之后就是扫描二维码付款了。


1、确认挂号(创建订单)

rabbitmq的使用

mq在这里充当了异步调用的作用,可以提高下单的响应速度。

1.1 调用医院端 的程序在医院端保存一条订单和在医院端扣减号源。

//使用httpclient发送请求,请求医院接口
//医院端 1.扣减号源 2.保存医院端自己的订单
JSONObject result =
        HttpRequestHelper.sendRequest(paramMap, "http://localhost:9998/order/submitOrder");

1.2 在我们的平台端也保存一条我们自己的订单,之后发送消息到mq,异步处理。

1.3 mq在本项目的异步处理的体现:

 平台端的医院服务更新mongodb中的号源(数据来自医院端的返回)

 平台端医院服务再发送消息到mq,短信服务消费这些消息发送短信通知用户挂号成功。

​OrderMqVo orderMqVo = new OrderMqVo();
//这2个数量都是医院端返给我们平台端的
orderMqVo.setReservedNumber(reservedNumber);//总的号源数量
orderMqVo.setAvailableNumber(availableNumber);//剩余可预约数量
orderMqVo.setScheduleId(scheduleId);//mongondb中排班id

MsmVo msmVo = new MsmVo();
msmVo.setPhone(orderInfo.getPatientPhone());
Map<String,Object> map = new HashMap<String,Object>(){{
    put("message","请于"+orderInfo.getReserveDate()+"到"
            +orderInfo.getHosname()+orderInfo.getDepname()+"就诊");
}};
msmVo.setParam(map);
orderMqVo.setMsmVo(msmVo);
//发送消息到mq,异步处理
rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_ORDER,MqConst.ROUTING_ORDER,orderMqVo);

​

发送短信的话,我们模拟一下,在控制台输出。上一篇我们已经讲过了如何调用阿里云发送短信,在短信服务控制台中输出如下:

2、点击支付(生成二维码)

在线微信支付开发文档:

https://pay.weixin.qq.com/wiki/doc/api/index.html

--------------------------------------

生成二维码

使用Redis判断5分钟内是否生成过二维码

Map m = (Map)redisTemplate.opsForValue().get(orderId.toString());
//防止5分钟之内重复向微信端发请求获取支付链接
if(m!=null){
    return m;
}

1、创建支付记录,处于未支付状态

2、向微信端统一下单 ” 发请求,拿到二维码连接,并把map存储到Redis

paramMap参数的设置就多了去了,,, 

 //2、HTTPClient来根据URL访问第三方接口并且传递参数
 HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/pay/unifiedorder");
 //client设置参数
 client.setXmlParam(WXPayUtil.generateSignedXml(paramMap, ConstantPropertiesUtils.PARTNERKEY));
 client.setHttps(true);
 client.post();
 //3、微信端返回数据xml格式数据
 String xml = client.getContent();
 Map<String, String> result = WXPayUtil.xmlToMap(xml);
 String return_code = result.get("return_code");
 String result_code = result.get("result_code");
 if (return_code.equals("SUCCESS") && result_code.equals("SUCCESS")) {
     Map map = new HashMap();
     map.put("orderId", orderId);
     map.put("totalFee", order.getAmount());
     map.put("resultCode", result.get("result_code"));//返回状态码	 SUCCESS/FAIL
     map.put("codeUrl", result.get("code_url"));//二维码链接
     redisTemplate.opsForValue().set(orderId.toString(),map,5, TimeUnit.MINUTES);
     return map;
 }

----------------------------------------------

查询支付状态

打开二维码后,前端每隔3秒去调用查询支付状态接口

1、查询微信端“查询订单”接口

代码如下,没啥可说的。写法很固定!

代码里面有很多工具类,比如发送请求的、map和xml格式互转的。

    //根据订单号去微信第三方查询支付状态
    @Override
    public Map queryPayStatus(Long orderId) {

        OrderInfo orderInfo = orderService.getById(orderId);
        //1、封装参数
        Map paramMap = new HashMap<>();
        paramMap.put("appid", ConstantPropertiesUtils.APPID);
        paramMap.put("mch_id", ConstantPropertiesUtils.PARTNER);//商户号
        paramMap.put("out_trade_no", orderInfo.getOutTradeNo());//订单的out_trade_no
        paramMap.put("nonce_str", WXPayUtil.generateNonceStr());//随机字符串

        try {
            //2、设置请求,调用微信端“查询订单”接口
            HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/pay/orderquery");
            //微信端都是xml作为参数和返回值
            //generateSignedXml会自动添加签名
            client.setXmlParam(WXPayUtil
                    .generateSignedXml(paramMap, ConstantPropertiesUtils.PARTNERKEY));//商户号签名
            client.setHttps(true); //是否支持指定协议
            client.post();

            //3、获取返回值,转成Map
            String xml = client.getContent();
            Map<String, String> resultMap = WXPayUtil.xmlToMap(xml);

            //4、返回
            return resultMap;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

2、支付成功,需要做的事情有修改订单的状态为已支付,修改或填充支付记录中的4个字段

比较重要的就是 trade_no,这个是微信端返回给我们的支付流水号。另外一个out_trade_no是我们订单表中自己的交易记录号,out_trade_no会伴随着整个支付流程

 paymentInfo.setTradeNo(paramMap.get("transaction_id"))


3、取消预约 (取消订单)

取消预约 有2种情况

(1)未支付取消订单,直接通知医院更新取消预约状态

(2)已支付取消订单,先退款给用户,然后通知医院更新取消预约状态

取消预约需要配置证书

拷贝证书到c盘下:

在配置文件中:

weixin.cert=C:\\apiclient_cert.p12 

1、根据支付记录创建退款记录

2、调用微信端接口“申请退款”

String paramXml = WXPayUtil.generateSignedXml(paramMap,ConstantPropertiesUtils.PARTNERKEY);
//调用微信接口,进行退款
HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/secapi/pay/refund");
client.setXmlParam(paramXml);
client.setHttps(true);
client.setCert(true);
client.setCertPassword(ConstantPropertiesUtils.PARTNER);//商户id
client.post();
//返回第三方的数据
String xml = client.getContent();
Map<String, String> resultMap = WXPayUtil.xmlToMap(xml);
//暂且认为是退款成功,实际要调用退款查询接口
if (null != resultMap && WXPayConstants.SUCCESS.equalsIgnoreCase(resultMap.get("result_code"))) {
    //调用微信端接口 查询退款状态
    refundInfo.setCallbackTime(new Date());
    refundInfo.setTradeNo(resultMap.get("refund_id"));//微信退款单号
    refundInfo.setRefundStatus(RefundStatusEnum.REFUND.getStatus());//已退款
    refundInfo.setCallbackContent(JSONObject.toJSONString(resultMap));
    refundInfoService.updateById(refundInfo);
    return true;
}
return false;

3、查询退款成功则修改第一步创建的退款记录,并把平台端的订单状态也要改为-1

4、mq异步实现

  • 平台端号源数量加1,(相比创建订单少发俩个参数)
  • 通知就诊人退号成功
 //4.向mq发送消息,完成mongondb中号源数量+1,短信通知就诊人
 OrderMqVo orderMqVo = new OrderMqVo();
 orderMqVo.setScheduleId(orderInfo.getScheduleId());
 MsmVo msmVo =new MsmVo();
 msmVo.setPhone(orderInfo.getPatientPhone());
 Map<String,Object> param=new HashMap<>();
 param.put("message","退号成功");
 msmVo.setParam(param);
 orderMqVo.setMsmVo(msmVo);
 rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_ORDER,MqConst.ROUTING_ORDER,msmVo);

就医提醒【定时任务、mq实现】

请夸我灵魂画手,低调低调哈哈

1、在定时任务模块发送消息到task队列

这个消息可以是空的,本来就是起一个提示的作用。

要注意的点就是 @Scheduled(cron = "0/50 * * * * ?") //等步增长

    /**
     * 每天8点执行 提醒就诊
     */
    //@Scheduled(cron = "0 0 8 * * ?")
    @Scheduled(cron = "0/5 * * * * ?") //等步增长
    public void task() {
        System.out.println(new Date().toLocaleString());
        rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_TASK, MqConst.ROUTING_TASK_8, "");
    }

RabbitService是我们自己封装好的一个操作rabbitmq的服务

@Component
public class RabbitService {
    @Autowired
    private RabbitTemplate rabbitTemplate;

    /**
     *  发送消息
     * @param exchange 交换机
     * @param routingKey 路由键
     * @param message 消息
     */
    public boolean sendMessage(String exchange, String routingKey, Object message) {
        rabbitTemplate.convertAndSend(exchange, routingKey, message);
        return true;
    }
}

2、订单服务去消费“task队列”的消息

2.1、去查询当天的就诊人,实际上是查询 就诊日期是当天的订单,

2.2、然后在订单服务遍历当天的这些订单,给“msm队列”里发送消息。

    public void patientTips() {
        //1、查询当天已支付所有的订单
        QueryWrapper<OrderInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("reserve_date", new DateTime().toString("yyyy-MM-dd"));
        queryWrapper.eq("order_status",1);
        List<OrderInfo> orderInfos = baseMapper.selectList(queryWrapper);

        //2、循环遍历发送消息到mq
        for (OrderInfo orderInfo : orderInfos) {
            //短信提示
            MsmVo msmVo = new MsmVo();
            //就诊人手机号
            msmVo.setPhone(orderInfo.getPatientPhone());
            //短信内容
            Map<String,Object> param = new HashMap<String,Object>(){{
                put("message", orderInfo.getPatientName()+"请于今天就诊");
            }};
            msmVo.setParam(param);
            //发送消息到msm队列
            rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_MSM, MqConst.ROUTING_MSM_ITEM, msmVo);
        }
    }

3、短信服务 去消费“msm队列”的消息

    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = MqConst.QUEUE_MSM_ITEM, durable = "true"),
            exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_MSM),
            key = {MqConst.ROUTING_MSM_ITEM}
    ))
    public void send(MsmVo msmVo) {
        Map<String, Object> param = msmVo.getParam();
        System.out.println("[尚医通]: "+param.get("message"));
    }

控制台打印如下:当然你还可以让提示更加丰富,我这里就只取了“就诊人的名字”


预约统计 Echart

在实际的生产环境中,有很多种各式统计,数据来源于各个服务模块,我们得有一个统计模块来专门管理。

ECharts是百度的一个项目,后来百度把Echart捐给apache,用于图表展示,提供了常规的折线图柱状图散点图饼图K线图,用于统计的盒形图,用于地理数据可视化的地图热力图线图,用于关系数据可视化的关系图treemap旭日图,多维数据可视化的平行坐标,还有用于 BI 的漏斗图仪表盘,并且支持图与图之间的混搭。

官方网站:https://echarts.apache.org/zh/index.html

需求:统计每天平台预约数据(即订单数量)

实际上返回给前端的就是横坐标集合和纵坐标集合。横坐标表示日期,纵坐标表示预约数量

项目中安装 echarts组件   
npm install --save echarts@4.1.0
大体流程

我们要做的事,对应到mysql,差不多就是这样

SELECT `reserve_date`,COUNT(0) AS 'count'  FROM `order_info` 
GROUP BY `reserve_date` ORDER BY `reserve_date`

核心代码就是

1、调用mapper接口查询

    <select id="selectOrderCount" resultType="com.atguigu.yygh.vo.order.OrderCountVo">
        select reserve_date as reserveDate, count(reserve_date) as count
        from order_info
        <where>
            <if test="hosname != null and hosname != ''">
                and hosname like CONCAT('%',#{hosname},'%')
            </if>
            <if test="reserveDateBegin != null and reserveDateBegin != ''">
                and reserve_date >= #{reserveDateBegin}
            </if>
            <if test="reserveDateEnd != null and reserveDateEnd != ''">
                and reserve_date &lt;= #{reserveDateEnd}
            </if>
            and is_deleted = 0
        </where>
        group by reserve_date
        order by reserve_date
    </select>

2、把查询的结果封装横坐标集合和纵坐标集合

    //获取订单统计数据
    @Override
    public Map<String, Object> getCountMap(OrderCountQueryVo orderCountQueryVo) {
        List<OrderCountVo> orderCountVos = orderInfoMapper.selectOrderCount(orderCountQueryVo);

        List<String> dateList= orderCountVos.stream()
                .map(OrderCountVo::getReserveDate).collect(Collectors.toList());

        List<Integer> countList= orderCountVos.stream()
                .map(OrderCountVo::getCount).collect(Collectors.toList());
        HashMap<String, Object> map = new HashMap<>();
        //给前端返回横坐标集合(日期)和纵坐标集合(预约数量)
        map.put("dateList",dateList);
        map.put("countList",countList);
        return map;
    }

最后,就可以在页面看到好看的效果了,当然省略了前端的代码


项目总结

1、项目流程图


2、项目功能

医院端

医院设置管理

医院管理

数据字典

用户管理

 统计管理 

  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值