10.java项目
前端代码:.git
后端代码:.git
1.用户订单管理
1.1 订单详情
1.1.1 api接口
操作模块:service_order
1.添加service接口及实现类
在OrderService类添加接口
//根据订单id查询订单详情
OrderInfo getOrder(String orderId);
在OrderServiceImpl类添加接口实现
@Override
public OrderInfo getOrder(String orderId) {OrderInfo orderInfo = baseMapper.selectById(orderId);return this.packOrderInfo(orderInfo);
}
private OrderInfo packOrderInfo(OrderInfo orderInfo){orderInfo.getParam().put("orderStatusString",OrderStatusEnum.getStatusNameByStatus(orderInfo.getOrderStatus()));return orderInfo;
}
2.添加controller
在OrderApiController类添加方法
//根据订单id查询订单详情
@GetMapping("auth/getOrders/{orderId}")
public Result getOrder(@PathVariable String orderId){OrderInfo orderInfo = orderService.getOrder(orderId);return Result.ok(orderInfo);
}
1.1.2 前端
操作:yygh-site
1.封装api请求
在/api/orderInfo.js添加方法
//订单详情
getOrders(orderId){return request({url: `${api_name}/auth/getOrders/${orderId}`,method: 'get'})
}
2.页面展示
创建/pages/order/show.vue组件
<template><!-- header --><div class="nav-container page-component"><!--左侧导航 #start --><div class="nav left-nav"><div class="nav-item "><span class="v-link clickable dark" οnclick="javascript:window.location='/user'">实名认证 </span></div><div class="nav-item selected"><span class="v-link selected dark" οnclick="javascript:window.location='/order'"> 挂号订单 </span></div><div class="nav-item "><span class="v-link clickable dark" οnclick="javascript:window.location='/patient'"> 就诊人管理 </span></div><div class="nav-item "><span class="v-link clickable dark"> 修改账号信息 </span></div><div class="nav-item "><span class="v-link clickable dark"> 意见反馈 </span></div></div><!-- 左侧导航 #end --><!-- 右侧内容 #start --><div class="page-container"><div class="order-detail"><div class="title"> 挂号详情</div><div class="status-bar"><div class="left-wrapper"><div class="status-wrapper BOOKING_SUCCESS"><span class="iconfont"></span> {{ orderInfo.param.orderStatusString }}</div></div><div class="right-wrapper"><img src="//img.114yygh.com/static/web/code_order_detail.png" class="code-img"><div class="content-wrapper"><div> 微信<span class="iconfont"></span>关注“北京114预约挂号”</div><div class="watch-wrapper"> 快速挂号,轻松就医</div></div></div></div><div class="info-wrapper"><div class="title-wrapper"><div class="block"></div><div>挂号信息</div></div><div class="info-form"><el-form ref="form" :model="form"><el-form-item label="就诊人信息:"><div class="content"><span>{{ orderInfo.patientName }}</span></div></el-form-item><el-form-item label="就诊日期:"><div class="content"><span>{{ orderInfo.reserveDate }} {{ orderInfo.reserveTime == 0 ? '上午' : '下午' }}</span></div></el-form-item><el-form-item label="就诊医院:"><div class="content"><span>{{ orderInfo.hosname }} </span></div></el-form-item><el-form-item label="就诊科室:"><div class="content"><span>{{ orderInfo.depname }} </span></div></el-form-item><el-form-item label="医生职称:"><div class="content"><span>{{ orderInfo.title }} </span></div></el-form-item><el-form-item label="医事服务费:"><div class="content"><div class="fee">{{ orderInfo.amount }}元</div></div></el-form-item><el-form-item label="挂号单号:"><div class="content"><span>{{ orderInfo.outTradeNo }} </span></div></el-form-item><el-form-item label="挂号时间:"><div class="content"><span>{{ orderInfo.createTime }}</span></div></el-form-item></el-form></div></div><div class="rule-wrapper mt40"><div class="rule-title"> 注意事项</div><div>1、请确认就诊人信息是否准确,若填写错误将无法取号就诊,损失由本人承担;<br><span style="color:red">2、【取号】就诊当天需在{{ orderInfo.fetchTime }}在医院取号,未取号视为爽约,该号不退不换;</span><br>3、【退号】在{{ orderInfo.quitTime }}前可在线退号 ,逾期将不可办理退号退费;<br>4、北京114预约挂号支持自费患者使用身份证预约,同时支持北京市医保患者使用北京社保卡在平台预约挂号。请于就诊当日,携带预约挂号所使用的有效身份证件到院取号;<br>5、请注意北京市医保患者在住院期间不能使用社保卡在门诊取号。</div></div><div class="bottom-wrapper mt60" v-if="orderInfo.orderStatus == 0 || orderInfo.orderStatus == 1"><div class="button-wrapper"><div class="v-button white" @click="cancelOrder()">取消预约</div></div><div class="button-wrapper ml20" v-if="orderInfo.orderStatus == 0"><div class="v-button" @click="pay()">支付</div></div></div></div></div><!-- 右侧内容 #end --><!-- 微信支付弹出框 --><el-dialog :visible.sync="dialogPayVisible" style="text-align: left" :append-to-body="true" width="500px" @close="closeDialog"><div class="container"><div class="operate-view" style="height: 350px;"><div class="wrapper wechat"><div><img src="images/weixin.jpg" alt=""><div style="text-align: center;line-height: 25px;margin-bottom: 40px;">请使用微信扫一扫<br/>扫描二维码支付</div></div></div></div></div></el-dialog></div><!-- footer -->
</template>
<script>
import '~/assets/css/hospital_personal.css'
import '~/assets/css/hospital.css'
import orderInfoApi from '@/api/orderInfo'
export default {data() {return {orderId: null,orderInfo: {param: {}},dialogPayVisible: false,payObj: {},timer: null // 定时器名称}},created() {this.orderId = this.$route.query.orderIdthis.init()},methods: {init() {orderInfoApi.getOrders(this.orderId).then(response => {console.log(response.data);this.orderInfo = response.data})}}
}
</script>
<style>
.info-wrapper {padding-left: 0;padding-top: 0;
}
.content-wrapper {color: #333;font-size: 14px;padding-bottom: 0;
}
.bottom-wrapper {width: 100%;
}
.button-wrapper {margin: 0;
}
.el-form-item {margin-bottom: 5px;
}
.bottom-wrapper .button-wrapper {margin-top: 0;
}
</style>
1.2 订单列表
操作模块:service_order
1.2.1 api接口
1.添加service接口及实现类
在OrderService类添加接口
//订单列表(条件查询带分页)
IPage<OrderInfo> selectPage(Page<OrderInfo> pageParam, OrderQueryVo orderQueryVo);
在OrderServiceImpl类添加接口实现
//订单列表(条件查询带分页)
@Override
public IPage<OrderInfo> selectPage(Page<OrderInfo> pageParam, OrderQueryVo orderQueryVo) {//orderQueryVo获取条件String name = orderQueryVo.getKeyword(); //医院名称Long patientId = orderQueryVo.getPatientId(); //就诊人idString orderStatus = orderQueryVo.getOrderStatus(); //订单状态String reserveDate = orderQueryVo.getReserveDate();//安排时间String createTimeBegin = orderQueryVo.getCreateTimeBegin();String createTimeEnd = orderQueryVo.getCreateTimeEnd();//对条件值进行非空判断QueryWrapper<OrderInfo> wrapper = new QueryWrapper<>();wrapper.eq("user_id",orderQueryVo.getUserId());if(!StringUtils.isEmpty(name)) {wrapper.like("hosname",name);}if(!StringUtils.isEmpty(patientId)) {wrapper.eq("patient_id",patientId);}if(!StringUtils.isEmpty(orderStatus)) {wrapper.eq("order_status",orderStatus);}if(!StringUtils.isEmpty(reserveDate)) {wrapper.le("reserve_date",reserveDate);}if(!StringUtils.isEmpty(createTimeBegin)) {wrapper.ge("create_time",createTimeBegin);}if(!StringUtils.isEmpty(createTimeEnd)) {wrapper.le("create_time",createTimeEnd);}//调用mapper的方法Page<OrderInfo> pages = baseMapper.selectPage(pageParam, wrapper);//编号变成对应封装pages.getRecords().stream().forEach(item -> {this.packOrderInfo(item);});return pages;
}
2.添加controller
在OrderApiController类添加方法
//订单列表(条件查询带分页)
@GetMapping("auth/{page}/{limit}")
public Result list(@PathVariable Long page,@PathVariable Long limit,OrderQueryVo orderQueryVo,HttpServletRequest request){//设置当前用户idorderQueryVo.setUserId(AuthContextHolder.getUserId(request));Page<OrderInfo> pageParam = new Page<>(page,limit);IPage<OrderInfo> pageModel = orderService.selectPage(pageParam,orderQueryVo);return Result.ok(pageModel);
}@ApiOperation(value = "获取订单状态")
@GetMapping("auth/getStatusList")
public Result getStatusList() {return Result.ok(OrderStatusEnum.getStatusList());
}
1.2.2 前端
1.封装api请求
在/api/orderInfo.js添加方法
//订单列表
getPageList(page,limit,searchObj){return request({url: `${api_name}/auth/${page}/${limit}`,method: 'get',params: searchObj})
},
//查询订单状态
getStatusList() {return request({url: `${api_name}/auth/getStatusList`,method: 'get'})
}
2.页面展示
创建/pages/order/index.vue组件
<template><!-- header --><div class="nav-container page-component"><!--左侧导航 #start --><div class="nav left-nav"><div class="nav-item "><span class="v-link clickable dark" onclick="javascript:window.location='/user'">实名认证 </span></div><div class="nav-item selected"><span class="v-link selected dark" onclick="javascript:window.location='/order'"> 挂号订单 </span></div><div class="nav-item "><span class="v-link clickable dark" onclick="javascript:window.location='/patient'"> 就诊人管理 </span></div><div class="nav-item "><span class="v-link clickable dark"> 修改账号信息 </span></div><div class="nav-item "><span class="v-link clickable dark"> 意见反馈 </span></div></div><!-- 左侧导航 #end --><!-- 右侧内容 #start --><div class="page-container"><div class="personal-order"><div class="title"> 挂号订单</div><el-form :inline="true"><el-form-item label="就诊人:"><el-select v-model="searchObj.patientId" placeholder="请选择就诊人" class="v-select patient-select"><el-optionv-for="item in patientList":key="item.id":label="item.name + '【' + item.certificatesNo + '】'":value="item.id"></el-option></el-select></el-form-item><el-form-item label="订单状态:" style="margin-left: 80px"><el-select v-model="searchObj.orderStatus" placeholder="全部" class="v-select patient-select" style="width: 200px;"><el-optionv-for="item in statusList":key="item.status":label="item.comment":value="item.status"></el-option></el-select></el-form-item><el-form-item><el-button type="text" class="search-button v-link highlight clickable selected" @click="fetchData()">查询</el-button></el-form-item></el-form><div class="table-wrapper table"><el-table:data="list"stripestyle="width: 100%"><el-table-columnlabel="就诊时间"width="120"><template slot-scope="scope">{{ scope.row.reserveDate }} {{ scope.row.reserveTime === 0 ? '上午' : '下午' }}</template></el-table-column><el-table-columnprop="hosname"label="医院"width="100"></el-table-column><el-table-columnprop="depname"label="科室"></el-table-column><el-table-columnprop="title"label="医生"></el-table-column><el-table-columnprop="amount"label="医事服务费"></el-table-column><el-table-columnprop="patientName"label="就诊人"></el-table-column><el-table-columnprop="param.orderStatusString"label="订单状态"></el-table-column><el-table-column label="操作"><template slot-scope="scope"><el-button type="text" class="v-link highlight clickable selected" @click="show(scope.row.id)">详情</el-button></template></el-table-column></el-table></div><!-- 分页 --><el-paginationclass="pagination"layout="prev, pager, next":current-page="page":total="total":page-size="limit"@current-change="fetchData"></el-pagination></div></div><!-- 右侧内容 #end --></div><!-- footer -->
</template>
<script>
import '~/assets/css/hospital_personal.css'
import '~/assets/css/hospital.css'
import orderInfoApi from '@/api/orderInfo'
import patientApi from '@/api/patient'
export default {data() {return {list: [], // banner列表total: 0, // 数据库中的总记录数page: 1, // 默认页码limit: 10, // 每页记录数searchObj: {}, // 查询表单对象patientList: [],statusList: []}},created() {this.orderId = this.$route.query.orderIdthis.fetchData()this.findPatientList()this.getStatusList()},methods: {fetchData(page = 1) {this.page = pageorderInfoApi.getPageList(this.page, this.limit, this.searchObj).then(response => {console.log(response.data);this.list = response.data.recordsthis.total = response.data.total})},findPatientList() {patientApi.findList().then(response => {this.patientList = response.data})},getStatusList() {orderInfoApi.getStatusList().then(response => {this.statusList = response.data})},changeSize(size) {console.log(size)this.limit = sizethis.fetchData(1)},show(id) {window.location.href = '/order/show?orderId=' + id}}
}
</script>
注:平台订单管理和用户订单管理接口基本一样,因此不再操作
2.微信支付
2.1 微信支付简介
微信扫码支付申请
微信扫码支付是商户系统按微信支付协议生成支付二维码,用户再用微信“扫一扫”完成支付的模式。该模式适用于PC网站支付、实体店单品或订单支付、媒体广告支付等场景。
申请步骤:(了解)
第一步:注册公众号(类型须为:服务号)
请根据营业执照类型选择以下主体注册:个体工商户| 企业/公司| 政府| 媒体| 其他类型。
第二步:认证公众号
公众号认证后才可申请微信支付,认证费:300元/年。
第三步:提交资料申请微信支付
登录公众平台,点击左侧菜单【微信支付】,开始填写资料等待审核,审核时间为1-5个工作日内。
第四步:开户成功,登录商户平台进行验证
资料审核通过后,请登录联系人邮箱查收商户号和密码,并登录商户平台填写财付通备付金打的小额资金数额,完成账户验证。
第五步:在线签署协议
本协议为线上电子协议,签署后方可进行交易及资金结算,签署完立即生效。
开发文档
微信支付接口调用的整体思路:
按API要求组装参数,以XML方式发送(POST)给微信支付接口(URL),微信支付接口也是以XML方式给予响应。程序根据返回的结果(其中包括支付URL)生成二维码或判断订单状态。
在线微信支付开发文档:
.html
- appid:微信公众账号或开放平台APP的唯一标识
- mch_id:商户号 (配置文件中的partner)
- partnerkey:商户密钥
- sign:数字签名, 根据微信官方提供的密钥和一套算法生成的一个加密信息, 就是为了保证交易的安全性
2.2 微信支付开发
2.2.1 api接口
场景:用户扫描商户展示在各种场景的二维码进行支付
使用案例:
线下:家乐福超市、7-11便利店、上品折扣线下店等
线上:大众点评网站、携程网站、唯品会、美丽说网站等
开发模式:
模式一:商户在后台给你生成二维码,用户打开扫一扫
模式二:商户后台系统调用微信支付【统一下单API】生成预付交易,将接口返回的链接生成二维码,用户扫码后输入密码完成支付交易。注意:该模式的预付单有效期为2小时,过期后无法支付。
微信支付:生成xml发送请求
操作模块:service-order
1.引入依赖
<dependency><groupId>com.github.wxpay</groupId><artifactId>wxpay-sdk</artifactId><version>0.0.3</version>
</dependency>
2.添加配置
在application.yml中添加商户信息
spring:redis:timeout: 1800000lettuce:pool:max-active: 20max-wait: -1max-idle: 5min-idle: 0
weixin:appid: wx74862e0dfcf69954partner: 1558950191partnerkey: T6m9iK73b0kn9g5v426MKfHQH7X8rKwb
3.引入工具类
com.myproject.yygh.order.utils.ConstantPropertiesUtils
package com.myproject.yygh.order.utils;import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;@Component
public class ConstantPropertiesUtils implements InitializingBean {@Value("${weixin.appid}")private String appid;@Value("${weixin.partner}")private String partner;@Value("${weixin.partnerkey}")private String partnerkey;public static String APPID;public static String PARTNER;public static String PARTNERKEY;@Overridepublic void afterPropertiesSet() throws Exception {APPID = appid;PARTNER = partner;PARTNERKEY = partnerkey;}
}
com.myproject.yygh.order.utils.HttpClient
package com.myproject.yygh.order.utils;import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;import javax.net.ssl.SSLContext;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.KeyStore;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.text.ParseException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;/*** http请求客户端*/
public class HttpClient {private String url;private Map<String, String> param;private int statusCode;private String content;private String xmlParam;private boolean isHttps;private boolean isCert = false;//证书密码 微信商户号(mch_id)private String certPassword;public boolean isHttps() {return isHttps;}public void setHttps(boolean isHttps) {this.isHttps = isHttps;}public boolean isCert() {return isCert;}public void setCert(boolean cert) {isCert = cert;}public String getXmlParam() {return xmlParam;}public void setXmlParam(String xmlParam) {this.xmlParam = xmlParam;}public HttpClient(String url, Map<String, String> param) {this.url = url;this.param = param;}public HttpClient(String url) {this.url = url;}public String getCertPassword() {return certPassword;}public void setCertPassword(String certPassword) {this.certPassword = certPassword;}public void setParameter(Map<String, String> map) {param = map;}public void addParameter(String key, String value) {if (param == null)param = new HashMap<String, String>();param.put(key, value);}public void post() throws ClientProtocolException, IOException {HttpPost http = new HttpPost(url);setEntity(http);execute(http);}public void put() throws ClientProtocolException, IOException {HttpPut http = new HttpPut(url);setEntity(http);execute(http);}public void get() throws ClientProtocolException, IOException {if (param != null) {StringBuilder url = new StringBuilder(this.url);boolean isFirst = true;for (String key : param.keySet()) {if (isFirst)url.append("?");elseurl.append("&");url.append(key).append("=").append(param.get(key));}this.url = url.toString();}HttpGet http = new HttpGet(url);execute(http);}/*** set http post,put param*/private void setEntity(HttpEntityEnclosingRequestBase http) {if (param != null) {List<NameValuePair> nvps = new LinkedList<NameValuePair>();for (String key : param.keySet())nvps.add(new BasicNameValuePair(key, param.get(key))); // 参数http.setEntity(new UrlEncodedFormEntity(nvps, Consts.UTF_8)); // 设置参数}if (xmlParam != null) {http.setEntity(new StringEntity(xmlParam, Consts.UTF_8));}}private void execute(HttpUriRequest http) throws ClientProtocolException,IOException {CloseableHttpClient httpClient = null;try {if (isHttps) {if(isCert) {//TODO 需要完善FileInputStream inputStream = new FileInputStream(new File(""));KeyStore keystore = KeyStore.getInstance("PKCS12");char[] partnerId2charArray = certPassword.toCharArray();keystore.load(inputStream, partnerId2charArray);SSLContext sslContext = SSLContexts.custom().loadKeyMaterial(keystore, partnerId2charArray).build();SSLConnectionSocketFactory sslsf =new SSLConnectionSocketFactory(sslContext,new String[] { "TLSv1" },null,SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();} else {SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {// 信任所有public boolean isTrusted(X509Certificate[] chain,String authType)throws CertificateException {return true;}}).build();SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext);httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();}} else {httpClient = HttpClients.createDefault();}CloseableHttpResponse response = httpClient.execute(http);try {if (response != null) {if (response.getStatusLine() != null)statusCode = response.getStatusLine().getStatusCode();HttpEntity entity = response.getEntity();// 响应内容content = EntityUtils.toString(entity, Consts.UTF_8);}} finally {response.close();}} catch (Exception e) {e.printStackTrace();} finally {httpClient.close();}}public int getStatusCode() {return statusCode;}public String getContent() throws ParseException, IOException {return content;}
}
2.2.2 添加交易记录接口
1.添加Mapper
com.myproject.yygh.order.mapper.PaymentMapper
package com.myproject.yygh.order.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.myproject.yygh.model.order.PaymentInfo;
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface PaymentMapper extends BaseMapper<PaymentInfo> {
}
2.添加service接口与实现
com.myproject.yygh.order.service.PaymentService
package com.myproject.yygh.order.service;import com.baomidou.mybatisplus.extension.service.IService;
import com.myproject.yygh.model.order.OrderInfo;
import com.myproject.yygh.model.order.PaymentInfo;public interface PaymentService extends IService<PaymentInfo> {//向支付记录表添加信息void savePaymentInfo(OrderInfo orderInfo, Integer status);
}
com.myproject.yygh.order.service.impl.PaymentServiceImpl
package com.myproject.yygh.order.service.impl;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.myproject.yygh.enums.PaymentStatusEnum;
import com.myproject.yygh.model.order.OrderInfo;
import com.myproject.yygh.model.order.PaymentInfo;
import com.myproject.yygh.order.mapper.PaymentMapper;
import com.myproject.yygh.order.service.PaymentService;
import org.joda.time.DateTime;
import org.springframework.stereotype.Service;import java.util.Date;@Service
public class PaymentServiceImpl extends ServiceImpl<PaymentMapper, PaymentInfo> implements PaymentService {//向支付记录表添加信息@Overridepublic void savePaymentInfo(OrderInfo orderInfo, Integer paymentType) {//根据订单id和支付类型,查询支付记录表是否存在相同订单QueryWrapper<PaymentInfo> wrapper = new QueryWrapper<>();wrapper.eq("order_id",orderInfo.getId());wrapper.eq("payment_type",paymentType);Long count = baseMapper.selectCount(wrapper);if(count > 0){return;}//添加记录PaymentInfo paymentInfo = new PaymentInfo();paymentInfo.setCreateTime(new Date());paymentInfo.setOrderId(orderInfo.getId());paymentInfo.setPaymentType(paymentType);paymentInfo.setOutTradeNo(orderInfo.getOutTradeNo());paymentInfo.setPaymentStatus(PaymentStatusEnum.UNPAID.getStatus());String subject = new DateTime(orderInfo.getReserveDate()).toString("yyyy-MM-dd")+"|"+orderInfo.getHosname()+"|"+orderInfo.getDepname()+"|"+orderInfo.getTitle();paymentInfo.setSubject(subject);paymentInfo.setTotalAmount(orderInfo.getAmount());baseMapper.insert(paymentInfo);}
}
*3.添加支付service接口与实现
com.myproject.yygh.order.service.WeixinService
package com.myproject.yygh.order.service;import java.util.Map;public interface WeixinService {//生成微信支付扫描的二维码Map createNative(Long orderId);
}
com.myproject.yygh.order.service.impl.WeixinServiceImpl
package com.myproject.yygh.order.service.impl;import com.github.wxpay.sdk.WXPayUtil;
import com.myproject.yygh.enums.PaymentTypeEnum;
import com.myproject.yygh.model.order.OrderInfo;
import com.myproject.yygh.order.service.OrderService;
import com.myproject.yygh.order.service.PaymentService;
import com.myproject.yygh.order.service.WeixinService;
import com.myproject.yygh.order.utils.ConstantPropertiesUtils;
import com.myproject.yygh.order.utils.HttpClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;@Service
public class WeixinServiceImpl implements WeixinService {@Autowiredprivate OrderService orderService;@Autowiredprivate PaymentService paymentService;@Autowiredprivate RedisTemplate redisTemplate;//生成微信支付扫描的二维码@Overridepublic Map createNative(Long orderId) {try {//从redis获取数据Map payMap = (Map) redisTemplate.opsForValue().get(orderId.toString());if(payMap != null){return payMap;}//1.根据orderId获取订单信息OrderInfo orderInfo = orderService.getById(orderId);//2.向支付记录表添加信息paymentService.savePaymentInfo(orderInfo, PaymentTypeEnum.WEIXIN.getStatus());//3.设置参数//吧参数转换xml格式,使用商户key进行加密Map paramMap = new HashMap<>();paramMap.put("appid", ConstantPropertiesUtils.APPID);paramMap.put("mch_id", ConstantPropertiesUtils.PARTNER);paramMap.put("nonce_str", WXPayUtil.generateNonceStr());String body = orderInfo.getReserveDate() + "就诊"+ orderInfo.getDepname();paramMap.put("body", body);paramMap.put("out_trade_no", orderInfo.getOutTradeNo());//paramMap.put("total_fee", order.getAmount().multiply(new BigDecimal("100")).longValue()+"");paramMap.put("total_fee", "1");//为了测试,统一携程这个值paramMap.put("spbill_create_ip", "127.0.0.1");paramMap.put("notify_url", "/api/order/weixinPay/weixinNotify");paramMap.put("trade_type", "NATIVE");//4.调用微信生成二维码接口,httpclient调用HttpClient client = new HttpClient("");//设置map参数client.setXmlParam(WXPayUtil.generateSignedXml(paramMap,ConstantPropertiesUtils.PARTNERKEY));client.setHttps(true);client.post();//6.返回相关数据String xml = client.getContent();//转换成map集合Map<String,String> resultMap = WXPayUtil.xmlToMap(xml);System.out.println("resultMap:" + resultMap);//4、封装返回结果集Map map = new HashMap<>();map.put("orderId", orderId);map.put("totalFee", orderInfo.getAmount());map.put("resultCode", resultMap.get("result_code"));map.put("codeUrl", resultMap.get("code_url"));//二维码地址//微信支付二维码2小时过期,可采取2小时未支付取消订单if(resultMap.get("resultCode") != null){redisTemplate.opsForValue().set(orderId.toString(),map,120, TimeUnit.MINUTES);}return map;} catch (Exception e) {throw new RuntimeException(e);}}
}
4.添加controller方法
com.myproject.yygh.order.api.WeiXinController
package com.myproject.yygh.order.api;import com.myproject.yygh.common.result.Result;
import com.myproject.yygh.order.service.WeixinService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.Map;@RestController
@RequestMapping("/api/order/weixin")
public class WeiXinController {@Autowiredprivate WeixinService weixinService;//生成微信支付扫描的二维码@GetMapping("createNative/{orderId}")public Result createNative(@PathVariable Long orderId){Map map = weixinService.createNative(orderId);return Result.ok(map);}
}
2.2 前端
2.2.1 封装api请求
添加/api/weixin.js文件
//生成微信支付的二维码
createNative(orderId) {return request({url: `/api/order/weixin/createNative/${orderId}`,method: 'get'})
},
//查询支付状态的接口
queryPayStatus(orderId) {return request({url: `/api/order/weixin/queryPayStatus/${orderId}`,method: 'get'})
}
2.2.2 引入vue-qriously生成二维码
安装vue-qriously
npm install vue-qriously
引入
在/plugins/myPlugin.js文件添加引入
import VueQriously from 'vue-qriously'
Vue.use(VueQriously)
2.2.3 页面展示
修改/pages/order/show.vue组件
1.将104行的微信图片改为显示二维码
<qriously :value="payObj.codeUrl" :size="220"/>
2.在script中引入api接口
import weixinApi from '@/api/weixin'
3.添加方法
//生成支付二维码
pay(){//支付二维码弹框显示this.dialogPayVisible = trueweixinApi.createNative(this.orderId).then(response => {this.payObj = response.dataif(this.payObj.codeUrl == ''){//生成失败this.dialogPayVisible = falsethis.$message.error('支付错误')}else{//每个3秒调用查询支付状态接口this.timer = setInterval(() => {this.queryPayStatus(this.orderId)},3000);}})
},
//查询支付状态的方法
queryPayStatus(orderId) {weixinApi.queryPayStatus(orderId).then(response => {if(response.message == '支付中'){return;}//清除定时器clearInterval(this.timer)window.location.reload()})
},
closeDialog(){if(this.timer){clearInterval(this.timer);}
}
说明:我们只有轮询查看支付状态,接下来我们处理支付查询接口
测试功能,查看订单点击“支付”后是否显示二维码
2.3 处理支付结果
操作模块:yygh_order
2.3.1 支付查询
1.添加service接口与实现
在WeixinService类添加接口
//调用微信接口实现支付状态查询
Map<String, String> queryPayStatus(Long orderId);
在WeixinServiceImpl类添加实现
//调用微信接口实现支付状态查询
@Override
public Map<String, String> queryPayStatus(Long orderId) {try{//1.根据orderId获取订单信息OrderInfo orderInfo = orderService.getById(orderId);//2.封装提交参数Map paramMap = new HashMap<>();paramMap.put("appid", ConstantPropertiesUtils.APPID);paramMap.put("mch_id", ConstantPropertiesUtils.PARTNER);paramMap.put("out_trade_no", orderInfo.getOutTradeNo());paramMap.put("nonce_str", WXPayUtil.generateNonceStr());//3.设置请求内容HttpClient client = new HttpClient("");client.setXmlParam(WXPayUtil.generateSignedXml(paramMap, ConstantPropertiesUtils.PARTNERKEY));client.setHttps(true);client.post();//4.得到微信接口返回数据String xml = client.getContent();Map<String, String> resultMap = WXPayUtil.xmlToMap(xml);System.out.println("支付状态resultMap:" + resultMap);//5.把接口数据返回return resultMap;}catch (Exception e){return null;}
}
2.3.2 处理支付成功逻辑
1.添加service接口与实现
在PaymentService类添加接口
//更新订单状态
void paySuccess(String out_trade_no, Map<String, String> resultMap);
在PaymentServiceImpl类添加实现
@Autowired
private OrderService orderService;@Autowired
private HospitalFeignClient hospitalFeignClient;//更新订单状态
@Override
public void paySuccess(String out_trade_no, Map<String, String> resultMap) {//1.根据订单编号得到支付记录QueryWrapper<PaymentInfo> wrapper = new QueryWrapper<>();wrapper.eq("out_trade_no", out_trade_no);wrapper.eq("payment_type", PaymentTypeEnum.WEIXIN.getStatus());PaymentInfo paymentInfo = baseMapper.selectOne(wrapper);//2.更新支付记录信息paymentInfo.setPaymentStatus(PaymentStatusEnum.PAID.getStatus());paymentInfo.setTradeNo(resultMap.get("transaction_id"));paymentInfo.setCallbackTime(new Date());paymentInfo.setCallbackContent(resultMap.toString());baseMapper.updateById(paymentInfo);//3.根据订单号得到订单信息//4.更新订单信息OrderInfo orderInfo = orderService.getById(paymentInfo.getOrderId());orderInfo.setOrderStatus(OrderStatusEnum.PAID.getStatus());orderService.updateById(orderInfo);//5.调用医院接口,更新订单信息SignInfoVo signInfoVo = hospitalFeignClient.getSignInfoVo(orderInfo.getHoscode());Map<String,Object> reqMap = new HashMap<>();reqMap.put("hoscode",orderInfo.getHoscode());reqMap.put("hosRecordId",orderInfo.getHosRecordId());reqMap.put("timestamp", HttpRequestHelper.getTimestamp());String sign = HttpRequestHelper.getSign(reqMap, signInfoVo.getSignKey());reqMap.put("sign", sign);JSONObject result = HttpRequestHelper.sendRequest(reqMap, signInfoVo.getApiUrl() + "/order/updatePayStatus");
}
2.3.3 添加controller方法
在WeixinController类添加方法
@Autowired
private PaymentService paymentService;//查询支付状态
@GetMapping("queryPayStatus/{orderId}")
public Result queryPayStatus(@PathVariable Long orderId){//调用微信接口实现支付状态查询Map<String,String> resultMap = weixinService.queryPayStatus(orderId);if(resultMap == null){return Result.fail().message("支付出错");}if("SUCCESS".equals(resultMap.get("trade_state"))){//支付成功//更新订单状态String out_trade_no = resultMap.get("out_trade_no");//订单编号paymentService.paySuccess(out_trade_no,resultMap);return Result.ok().message("支付成功");}return Result.ok().message("支付中");
}
3.取消预约
需求分析
取消订单分两种情况:
1、未支付取消订单,直接通知医院更新取消预约状态
2、已支付取消订单,先退款给用户,然后通知医院更新取消预约状态
3.1 开发微信退款接口
参考文档:.php?chapter=9_4
该接口需要使用证书,详情参考文档并下载证书
3.1.1 配置证书
请下载的证书放在service-order模块/resources/cert文件夹下
(链接: 提取码:odj8)
1.在application.yml文件配置证书路径
weixin:cert: service/service_order/src/main/java/com/myproject/yygh/order/cert/apiclient_cert.p12
2.修改ConstantPropertiesUtils工具类
package com.myproject.yygh.order.utils;import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;@Component
public class ConstantPropertiesUtils implements InitializingBean {@Value("${weixin.appid}")private String appid;@Value("${weixin.partner}")private String partner;@Value("${weixin.partnerkey}")private String partnerkey;@Value("${weixin.cert}")private String cert;public static String APPID;public static String PARTNER;public static String PARTNERKEY;public static String CERT;@Overridepublic void afterPropertiesSet() throws Exception {APPID = appid;PARTNER = partner;PARTNERKEY = partnerkey;CERT = cert;}
}
3.修改HttpClient工具类
修改第131行
FileInputStream inputStream = new FileInputStream(new File(ConstantPropertiesUtils.CERT));
3.1.2 添加获取支付记录接口
退款我们是根据支付记录发起退款的
1.在PaymentService类添加接口
//获取支付记录
PaymentInfo getPaymentInfo(Long orderId, Integer paymentType);
2.在PaymentServiceImpl类添加实现
//获取支付记录
@Override
public PaymentInfo getPaymentInfo(Long orderId, Integer paymentType) {QueryWrapper<PaymentInfo> wrapper = new QueryWrapper<>();wrapper.eq("order_id",orderId);wrapper.eq("payment_type",paymentType);PaymentInfo paymentInfo = baseMapper.selectOne(wrapper);return paymentInfo;
}
3.1.3 添加退款记录
1.添加mapper
com.myproject.yygh.order.mapper.RefundInfoMapper
package com.myproject.yygh.order.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.myproject.yygh.model.order.RefundInfo;
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface RefundInfoMapper extends BaseMapper<RefundInfo> {
}
2.添加service接口与实现
添加service接口
com.myproject.yygh.order.service.RefundInfoService
package com.myproject.yygh.order.service;import com.baomidou.mybatisplus.extension.service.IService;
import com.myproject.yygh.model.order.PaymentInfo;
import com.myproject.yygh.model.order.RefundInfo;public interface RefundInfoService extends IService<RefundInfo> {//保存退款记录RefundInfo saveRefundInfo(PaymentInfo paymentInfo);
}
添加service接口实现
com.myproject.yygh.order.service.impl.RefundInfoServiceImpl
package com.myproject.yygh.order.service.impl;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.myproject.yygh.enums.RefundStatusEnum;
import com.myproject.yygh.model.order.PaymentInfo;
import com.myproject.yygh.model.order.RefundInfo;
import com.myproject.yygh.order.mapper.RefundInfoMapper;
import com.myproject.yygh.order.service.RefundInfoService;
import org.springframework.stereotype.Service;import java.util.Date;@Service
public class RefundInfoServiceImpl extends ServiceImpl<RefundInfoMapper, RefundInfo> implements RefundInfoService {//保存退款记录@Overridepublic RefundInfo saveRefundInfo(PaymentInfo paymentInfo) {//判断是否有重复数据添加QueryWrapper<RefundInfo> wrapper = new QueryWrapper<>();wrapper.eq("order_id", paymentInfo.getOrderId());wrapper.eq("payment_type", paymentInfo.getPaymentType());RefundInfo refundInfo = baseMapper.selectOne(wrapper);if(refundInfo != null){return refundInfo;}//添加记录refundInfo = new RefundInfo();refundInfo.setCreateTime(new Date());refundInfo.setOrderId(paymentInfo.getOrderId());refundInfo.setPaymentType(paymentInfo.getPaymentType());refundInfo.setOutTradeNo(paymentInfo.getOutTradeNo());refundInfo.setRefundStatus(RefundStatusEnum.UNREFUND.getStatus());refundInfo.setSubject(paymentInfo.getSubject());//paymentInfo.setSubject("test");refundInfo.setTotalAmount(paymentInfo.getTotalAmount());baseMapper.insert(refundInfo);return refundInfo;}
}
3.1.4 添加微信退款接口
在WeixinService添加接口
//退款
Boolean refund(Long orderId);
在WeixinServiceImpl添加实现
@Autowired
private RefundInfoService refundInfoService;//微信退款
@Override
public Boolean refund(Long orderId) {try {//获取支付记录信息PaymentInfo paymentInfo = paymentService.getPaymentInfo(orderId, PaymentTypeEnum.WEIXIN.getStatus());//添加信息到退款记录表RefundInfo refundInfo = refundInfoService.saveRefundInfo(paymentInfo);//判断当前订单数据是否已经退款if(refundInfo.getRefundStatus().intValue() == RefundStatusEnum.REFUND.getStatus().intValue()) {return true;}//调用微信接口实现退款//封装需要参数Map<String,String> paramMap = new HashMap<>(8);paramMap.put("appid",ConstantPropertiesUtils.APPID); //公众账号IDparamMap.put("mch_id",ConstantPropertiesUtils.PARTNER); //商户编号paramMap.put("nonce_str",WXPayUtil.generateNonceStr());paramMap.put("transaction_id",paymentInfo.getTradeNo()); //微信订单号paramMap.put("out_trade_no",paymentInfo.getOutTradeNo()); //商户订单编号paramMap.put("out_refund_no","tk"+paymentInfo.getOutTradeNo()); //商户退款单号
// paramMap.put("total_fee",paymentInfoQuery.getTotalAmount().multiply(new BigDecimal("100")).longValue()+"");
// paramMap.put("refund_fee",paymentInfoQuery.getTotalAmount().multiply(new BigDecimal("100")).longValue()+"");paramMap.put("total_fee","1");paramMap.put("refund_fee","1");String paramXml = WXPayUtil.generateSignedXml(paramMap,ConstantPropertiesUtils.PARTNERKEY);//设置调用接口内容HttpClient client = new HttpClient("");client.setXmlParam(paramXml);client.setHttps(true);//设置整数信息client.setCert(true);client.setCertPassword(ConstantPropertiesUtils.PARTNER);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;}} catch (Exception e) {throw new RuntimeException(e);}return null;
}
3.2 完成取消预约
参考《尚医通API接口文档.docx》业务接口5.3.取消预约
3.2.1 添加service接口与实现
在OrderService添加接口
//取消预约
Boolean cancelOrder(Long orderId);
在OrderServiceImpl添加实现
@Autowired
private WeixinService weixinService;//取消预约
@Override
public Boolean cancelOrder(Long orderId) {//获取订单信息OrderInfo orderInfo = baseMapper.selectById(orderId);//判断是否取消DateTime quitTime = new DateTime(orderInfo.getQuitTime());if(quitTime.isBeforeNow()){throw new YyghException(ResultCodeEnum.CANCEL_ORDER_NO);}//调用医院接口实现预约取消SignInfoVo signInfoVo = hospitalFeignClient.getSignInfoVo(orderInfo.getHoscode());if(null == signInfoVo) {throw new YyghException(ResultCodeEnum.PARAM_ERROR);}Map<String, Object> reqMap = new HashMap<>();reqMap.put("hoscode",orderInfo.getHoscode());reqMap.put("hosRecordId",orderInfo.getHosRecordId());reqMap.put("timestamp", HttpRequestHelper.getTimestamp());String sign = HttpRequestHelper.getSign(reqMap, signInfoVo.getSignKey());reqMap.put("sign", sign);JSONObject result = HttpRequestHelper.sendRequest(reqMap, signInfoVo.getApiUrl()+"/order/updateCancelStatus");//根据医院接口返回数据if(result.getInteger("code") != 200){throw new YyghException(result.getString("message"), ResultCodeEnum.FAIL.getCode());}else {//判断当前订单是否可以取消if(orderInfo.getOrderStatus().intValue() == OrderStatusEnum.PAID.getStatus().intValue()) {//已支付 退款boolean isRefund = weixinService.refund(orderId);if(!isRefund) {throw new YyghException(ResultCodeEnum.CANCEL_ORDER_FAIL);}//更新订单状态orderInfo.setOrderStatus(OrderStatusEnum.CANCLE.getStatus());baseMapper.updateById(orderInfo);//发送mq更新预约数量OrderMqVo orderMqVo = new OrderMqVo();orderMqVo.setScheduleId(orderInfo.getScheduleId());//短信提示MsmVo msmVo = new MsmVo();msmVo.setPhone(orderInfo.getPatientPhone());String reserveDate = new DateTime(orderInfo.getReserveDate()).toString("yyyy-MM-dd") + (orderInfo.getReserveTime()==0 ? "上午": "下午");Map<String,Object> param = new HashMap<String,Object>(){{put("title", orderInfo.getHosname()+"|"+orderInfo.getDepname()+"|"+orderInfo.getTitle());put("reserveDate", reserveDate);put("name", orderInfo.getPatientName());}};msmVo.setParam(param);orderMqVo.setMsmVo(msmVo);rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_ORDER, MqConst.ROUTING_ORDER, orderMqVo);return true;}}return false;
}
3.2.2 添加controller方法
在OrderApiController添加方法
//取消预约
@GetMapping("auth/cancelOrder/{orderId}")
public Result cancelOrder(@PathVariable Long orderId){Boolean isOrder = orderService.cancelOrder(orderId);return Result.ok(isOrder);
}
3.2.3 修改监听
操作:service-hosp模块
修改HospitalReceiver 类
@RabbitListener(bindings = @QueueBinding(value = @Queue(value = MqConst.QUEUE_ORDER, durable = "true"),exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_ORDER),key = {MqConst.ROUTING_ORDER}
))
public void receiver(OrderMqVo orderMqVo, Message message, Channel channel) throws IOException {if(orderMqVo.getAvailableNumber() != null){//下单成功更新预约数Schedule schedule = scheduleService.getScheduleById(orderMqVo.getScheduleId());schedule.setReservedNumber(orderMqVo.getReservedNumber());schedule.setAvailableNumber(orderMqVo.getAvailableNumber());scheduleService.update(schedule);}else {Schedule schedule = scheduleService.getScheduleById(orderMqVo.getScheduleId());int availableNumber = schedule.getAvailableNumber().intValue() + 1;schedule.setAvailableNumber(availableNumber);scheduleService.update(schedule);}//发送短信MsmVo msmVo = orderMqVo.getMsmVo();if(null != msmVo) {rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_MSM, MqConst.ROUTING_MSM_ITEM, msmVo);}
}
3.3 前端
3.3.1 封装api请求
添加/api/orderInfo.js文件
//取消订单
cancelOrder(orderId) {return request({url: `${api_name}/auth/cancelOrder/${orderId}`,method: 'get'})
}
3.3.2 页面展示
修改/pages/order/show.vue组件
//取消预约
cancelOrder() {this.$confirm('确定取消预约吗?', '提示', {confirmButtonText: '确定',cancelButtonText: '取消',type: 'warning'}).then(() => { // promise// 点击确定,远程调用return orderInfoApi.cancelOrder(this.orderId)}).then((response) => {this.$message.success('取消成功')this.init()}).catch(() => {this.$message.info('已取消取消预约')})
}
4.就医提醒功能
我们通过定时任务,每天8点执行,提醒就诊
4.1 搭建定时任务模块service-task
在service模块中创建service-task子模块
1.修改配置pom.xml
<dependencies><dependency><groupId>com.myproject</groupId><artifactId>rabbit_util</artifactId><version>1.0</version></dependency>
</dependencies>
2.添加配置文件
application.yml
server:port: 8207spring:application:name: service-taskprofiles:active: devcloud:nacos:server-addr: 127.0.0.1:8848rabbitmq:host: 192.168.50.224port: 5672username: adminpassword: admin
3. 添加启动类
package com.myproject.yygh.task;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.annotation.ComponentScan;@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)//取消数据源自动配置
@EnableDiscoveryClient
@ComponentScan(basePackages = {"com.myproject"})
public class ServiceTaskApplication {public static void main(String[] args) {SpringApplication.run(ServiceTaskApplication.class, args);}
}
4.添加常量配置
在rabbit-util模块com.myproject.common.rabbit.constant.MqConst类添加
public static final String EXCHANGE_DIRECT_TASK = "exchange.direct.task";
public static final String ROUTING_TASK_8 = "task.8";
//队列
public static final String QUEUE_TASK_8 = "queue.task.8";
5.添加定时任务
com.myproject.yygh.task.scheduled.ScheduledTask
package com.myproject.yygh.task.scheduled;import com.myproject.common.rabbit.constant.MqConst;
import com.myproject.common.rabbit.service.RabbitService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;@Component
@EnableScheduling
public class ScheduledTask {@Autowiredprivate RabbitService rabbitService;//每天8点执行方法,提醒就医//cron表达式,执行时间间隔//每天8点:0 0 8 * * ?@Scheduled(cron = "0/30 * * * * ?")public void taskPatient(){rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_TASK,MqConst.ROUTING_TASK_8,"");}
}
4.2 添加就医提醒处理
操作:service_order
1.添加service接口和接口实现
在OrderService类添加接口
//就诊人通知
void patientTips();
在OrderServiceImpl类添加接口实现
//就诊人通知
@Override
public void patientTips() {QueryWrapper<OrderInfo> wrapper = new QueryWrapper<>();wrapper.eq("reserve_date",new DateTime().toString("yyy-MM-dd"));wrapper.ne("order_status",OrderStatusEnum.CANCLE.getStatus());List<OrderInfo> orderInfoList = baseMapper.selectList(wrapper);for (OrderInfo orderInfo : orderInfoList) {//短信提示MsmVo msmVo = new MsmVo();msmVo.setPhone(orderInfo.getPatientPhone());String reserveDate = new DateTime(orderInfo.getReserveDate()).toString("yyyy-MM-dd") + (orderInfo.getReserveTime()==0 ? "上午": "下午");Map<String,Object> param = new HashMap<String,Object>(){{put("title", orderInfo.getHosname()+"|"+orderInfo.getDepname()+"|"+orderInfo.getTitle());put("reserveDate", reserveDate);put("name", orderInfo.getPatientName());}};msmVo.setParam(param);rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_MSM, MqConst.ROUTING_MSM_ITEM, msmVo);}
}
2.添加mq监听
com.myproject.yygh.order.receiver.OrderReceiver
package com.myproject.yygh.order.receiver;import com.myproject.common.rabbit.constant.MqConst;
import com.myproject.yygh.order.service.OrderService;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import java.io.IOException;@Component
public class OrderReceiver {@Autowiredprivate OrderService orderService;@RabbitListener(bindings = @QueueBinding(value = @Queue(value = MqConst.QUEUE_TASK_8, durable = "true"),exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_TASK),key = {MqConst.ROUTING_TASK_8}))public void patientTips(Message message, Channel channel) throws IOException {orderService.patientTips();}
}
5.预约统计
我们统计医院每天的预约情况,通过图表的形式展示,统计的数据都来自订单模块,因此我们在该模块封装好数据,在统计模块通过feign的形式获取数据。
我们为什么需要一个统计模块呢,因为在实际的生成环境中,有很多种各式统计,数据来源于各个服务模块,我们得有一个统计模块来专门管理
5.1 ECharts
简介
ECharts是百度的一个项目,后来百度把Echart捐给apache,用于图表展示,提供了常规的折线图、柱状图、散点图、饼图、K线图,用于统计的盒形图,用于地理数据可视化的地图、热力图、线图,用于关系数据可视化的关系图、treemap、旭日图,多维数据可视化的平行坐标,还有用于 BI 的漏斗图,仪表盘,并且支持图与图之间的混搭。
官方网站:.html
5.1.1 基本使用
echarts.min.js(链接: 提取码:pyrg)
1.引入ECharts
<!--引入 EChars 文件-->
<script src="../js/echarts.min.js"></script>
2.定义图表区域
<!-- 为ECharts准备一个具备大小(宽高)的Dom -->
<div id="main" style="width: 600px;height:400px;"></div>
3.渲染图表(折线图)
<script>var myChart = echarts.init(document.getElementById('main'));var option = {//x轴是类目轴(离散数据),必须通过data设置类目数据xAxis: {type: 'category',data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']},//y轴是数据轴(连续数据)yAxis: {type: 'value'},//系列列表。每个系列通过 type 决定自己的图表类型series: [{//系列中的数据内容数组data: [820, 932, 901, 934, 1290, 1330, 1320],//折线图type: 'line'}]};myChart.setOption(option);
</script>
4.渲染图表(柱状图)
<script>// 基于准备好的dom,初始化echarts实例var myChart = echarts.init(document.getElementById('main'));// 指定图表的配置项和数据var option = {title: {text: 'ECharts 入门示例'},tooltip: {},legend: {data:['销量']},xAxis: {data: ["衬衫","羊毛衫","雪纺衫","裤子","高跟鞋","袜子"]},yAxis: {},series: [{name: '销量',type: 'bar',data: [5, 20, 36, 10, 10, 20]}]};// 使用刚指定的配置项和数据显示图表。myChart.setOption(option);
</script>
4.项目中集成ECharts
在yygh-page中安装
npm install --save echarts@4.1.0
5.2 获取医院每天平台预约数据接口
操作模块:service-order
5.2.1 添加Mapper接口
1.在OrderMapper类添加接口
//查询预约统计数据的方法
List<OrderCountVo> selectOrderCount(@Param("vo") OrderCountQueryVo orderCountQueryVo);
2.在OrderMapper.xml文件添加方法
com/myproject/yygh/order/mapper/xml/OrderMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"".dtd">
<mapper namespace="com.myproject.yygh.order.mapper.OrderMapper"><select id="selectOrderCount" resultType="com.myproject.yygh.vo.order.OrderCountVo">select reserve_date as reserveDate, count(reserve_date) as countfrom order_info<where><if test="vo.hosname != null and vo.hosname != ''">and hosname like CONCAT('%',#{vo.hosname},'%')</if><if test="vo.reserveDateBegin != null and vo.reserveDateBegin != ''">and reserve_date >= #{vo.reserveDateBegin}</if><if test="vo.reserveDateEnd != null and vo.reserveDateEnd != ''">and reserve_date <= #{vo.reserveDateEnd}</if>and is_deleted = 0</where>group by reserve_dateorder by reserve_date</select>
</mapper>
3.添加application.yml配置
mybatis-plus:mapper-locations: classpath:com/myproject/yygh/order/mapper/xml/*.xml
4.在yygh_parent的pom.xml中添加
<!--项目打包时会将java目录中的*.xml文件也进行打包-->
<build><resources><resource><directory>src/main/java</directory><includes><include>**/*.xml</include></includes><filtering>false</filtering></resource></resources>
</build>
5.2.2 添加service接口和接口实现
在OrderService类添加接口
//预约统计
Map<String,Object> getCountMap(OrderCountQueryVo orderCountQueryVo);
在OrderServiceImpl类添加实现
//预约统计
@Override
public Map<String, Object> getCountMap(OrderCountQueryVo orderCountQueryVo) {//调用mapper方法得到数据List<OrderCountVo> orderCountVoList = baseMapper.selectOrderCount(orderCountQueryVo);//获取x需要数据,日期数据 list集合List<String> dateList = orderCountVoList.stream().map(OrderCountVo::getReserveDate).collect(Collectors.toList());//获取y需要数据,具体数量 list集合List<Integer> countList = orderCountVoList.stream().map(OrderCountVo::getCount).collect(Collectors.toList());Map<String, Object> map = new HashMap<>();map.put("dateList", dateList);map.put("countList", countList);return map;
}
5.2.3 添加controller方法
在OrderApiController类添加方法
//获取订单统计数据
@PostMapping("inner/getCountMap")
public Map<String, Object> getCountMap(@RequestBody OrderCountQueryVo orderCountQueryVo) {return orderService.getCountMap(orderCountQueryVo);
}
5.2.4 添加feign方法
创建模块:service-order-client
1.添加依赖
<dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-openfeign-core</artifactId></dependency><dependency><groupId>com.myproject</groupId><artifactId>model</artifactId><version>1.0</version><scope>compile</scope></dependency>
</dependencies>
2.添加feign接口
com.myproject.yygh.order.client.OrderFeignClient
package com.myproject.yygh.order.client;import com.myproject.yygh.vo.order.OrderCountQueryVo;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Repository;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;import java.util.Map;@FeignClient(value = "service-order")
@Repository
public interface OrderFeignClient {/*** 获取订单统计数据*/@PostMapping("/api/order/orderInfo/inner/getCountMap")Map<String, Object> getCountMap(@RequestBody OrderCountQueryVo orderCountQueryVo);
}
5.3 搭建service-statistics
创建service_statistics子模块
1.修改配置pom.xml
<dependencies><dependency><groupId>com.myproject</groupId><artifactId>service_order_client</artifactId><version>1.0</version></dependency>
</dependencies>
2.添加配置文件
application.yml
server:port: 8208
spring:application:name: service-statisticsprofiles:active: devcloud:nacos:server-addr: 127.0.0.1:8848
3.添加启动类
com.myproject.yygh.sta.ServiceStatisticsApplication
package com.myproject.yygh.sta;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.ComponentScan;@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)//取消数据源自动配置
@EnableDiscoveryClient
@EnableFeignClients(basePackages = {"com.myproject"})
@ComponentScan(basePackages = {"com.myproject"})
public class ServiceStatisticsApplication {public static void main(String[] args) {SpringApplication.run(ServiceStatisticsApplication.class, args);}
}
4.添加controller方法
com.myproject.yygh.sta.controller.StatisticsController
package com.myproject.yygh.sta.controller;import com.myproject.yygh.common.result.Result;
import com.myproject.yygh.order.client.OrderFeignClient;
import com.myproject.yygh.vo.order.OrderCountQueryVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.Map;@Api(tags = "统计管理接口")
@RestController
@RequestMapping("/admin/statistics")
public class StatisticsController {@Autowiredprivate OrderFeignClient orderFeignClient;//获取预约统计数据@GetMapping("getCountMap")public Result getCountMap(OrderCountQueryVo orderCountQueryVo) {Map<String,Object> countMap = orderFeignClient.getCountMap(orderCountQueryVo);return Result.ok(countMap);}
}
5.添加网关
- id: service-statisticsuri: lb://service-statisticspredicates:- name: Pathargs:- /*/statistics/**
5.4 前端展示
操作:yygh_page
1.添加路由
在 src/router/index.js 文件添加路由
{path: '/statistics',component: Layout,redirect: '/statistics/order/index',name: 'BasesInfo',meta: { title: '统计管理', icon: 'table' },alwaysShow: true,children: [{path: 'order/index',name: '预约统计',component: () =>import('@/views/statistics/order/index'),meta: { title: '预约统计' }}]
},
2.封装api请求
创建/api/sta.js
import request from '@/utils/request'const api_name = '/admin/statistics'export default {getCountMap(searchObj) {return request({url: `${api_name}/getCountMap`,method: 'get',params: searchObj})}
}
3.添加组件
创建/views/statistics/order/index.vue组件
<template><div class="app-container"><!--表单--><el-form :inline="true" class="demo-form-inline"><el-form-item><el-input v-model="searchObj.hosname" placeholder="点击输入医院名称"/></el-form-item><el-form-item><el-date-pickerv-model="searchObj.reserveDateBegin"type="date"placeholder="选择开始日期"value-format="yyyy-MM-dd"/></el-form-item><el-form-item><el-date-pickerv-model="searchObj.reserveDateEnd"type="date"placeholder="选择截止日期"value-format="yyyy-MM-dd"/></el-form-item><el-button:disabled="btnDisabled"type="primary"icon="el-icon-search"@click="showChart()">查询</el-button></el-form><div class="chart-container"><div id="chart" ref="chart"class="chart" style="height:500px;width:100%"/></div></div>
</template><script>
import echarts from 'echarts'
import statisticsApi from '@/api/sta'export default {data() {return {searchObj: {hosname: '',reserveDateBegin: '',reserveDateEnd: ''},btnDisabled: false,chart: null,title: '',xData: [], // x轴数据yData: [] // y轴数据}},methods: {// 初始化图表数据showChart() {statisticsApi.getCountMap(this.searchObj).then(response => {this.yData = response.data.countListthis.xData = response.data.dateListthis.setChartData()})},setChartData() {// 基于准备好的dom,初始化echarts实例var myChart = echarts.init(document.getElementById('chart'))// 指定图表的配置项和数据var option = {title: {text: this.title + '挂号量统计'},tooltip: {},legend: {data: [this.title]},xAxis: {data: this.xData},yAxis: {minInterval: 1},series: [{name: this.title,type: 'line',data: this.yData}]}// 使用刚指定的配置项和数据显示图表。myChart.setOption(option)},}
}
</script>
10.java项目
前端代码:.git
后端代码:.git
1.用户订单管理
1.1 订单详情
1.1.1 api接口
操作模块:service_order
1.添加service接口及实现类
在OrderService类添加接口
//根据订单id查询订单详情
OrderInfo getOrder(String orderId);
在OrderServiceImpl类添加接口实现
@Override
public OrderInfo getOrder(String orderId) {OrderInfo orderInfo = baseMapper.selectById(orderId);return this.packOrderInfo(orderInfo);
}
private OrderInfo packOrderInfo(OrderInfo orderInfo){orderInfo.getParam().put("orderStatusString",OrderStatusEnum.getStatusNameByStatus(orderInfo.getOrderStatus()));return orderInfo;
}
2.添加controller
在OrderApiController类添加方法
//根据订单id查询订单详情
@GetMapping("auth/getOrders/{orderId}")
public Result getOrder(@PathVariable String orderId){OrderInfo orderInfo = orderService.getOrder(orderId);return Result.ok(orderInfo);
}
1.1.2 前端
操作:yygh-site
1.封装api请求
在/api/orderInfo.js添加方法
//订单详情
getOrders(orderId){return request({url: `${api_name}/auth/getOrders/${orderId}`,method: 'get'})
}
2.页面展示
创建/pages/order/show.vue组件
<template><!-- header --><div class="nav-container page-component"><!--左侧导航 #start --><div class="nav left-nav"><div class="nav-item "><span class="v-link clickable dark" οnclick="javascript:window.location='/user'">实名认证 </span></div><div class="nav-item selected"><span class="v-link selected dark" οnclick="javascript:window.location='/order'"> 挂号订单 </span></div><div class="nav-item "><span class="v-link clickable dark" οnclick="javascript:window.location='/patient'"> 就诊人管理 </span></div><div class="nav-item "><span class="v-link clickable dark"> 修改账号信息 </span></div><div class="nav-item "><span class="v-link clickable dark"> 意见反馈 </span></div></div><!-- 左侧导航 #end --><!-- 右侧内容 #start --><div class="page-container"><div class="order-detail"><div class="title"> 挂号详情</div><div class="status-bar"><div class="left-wrapper"><div class="status-wrapper BOOKING_SUCCESS"><span class="iconfont"></span> {{ orderInfo.param.orderStatusString }}</div></div><div class="right-wrapper"><img src="//img.114yygh.com/static/web/code_order_detail.png" class="code-img"><div class="content-wrapper"><div> 微信<span class="iconfont"></span>关注“北京114预约挂号”</div><div class="watch-wrapper"> 快速挂号,轻松就医</div></div></div></div><div class="info-wrapper"><div class="title-wrapper"><div class="block"></div><div>挂号信息</div></div><div class="info-form"><el-form ref="form" :model="form"><el-form-item label="就诊人信息:"><div class="content"><span>{{ orderInfo.patientName }}</span></div></el-form-item><el-form-item label="就诊日期:"><div class="content"><span>{{ orderInfo.reserveDate }} {{ orderInfo.reserveTime == 0 ? '上午' : '下午' }}</span></div></el-form-item><el-form-item label="就诊医院:"><div class="content"><span>{{ orderInfo.hosname }} </span></div></el-form-item><el-form-item label="就诊科室:"><div class="content"><span>{{ orderInfo.depname }} </span></div></el-form-item><el-form-item label="医生职称:"><div class="content"><span>{{ orderInfo.title }} </span></div></el-form-item><el-form-item label="医事服务费:"><div class="content"><div class="fee">{{ orderInfo.amount }}元</div></div></el-form-item><el-form-item label="挂号单号:"><div class="content"><span>{{ orderInfo.outTradeNo }} </span></div></el-form-item><el-form-item label="挂号时间:"><div class="content"><span>{{ orderInfo.createTime }}</span></div></el-form-item></el-form></div></div><div class="rule-wrapper mt40"><div class="rule-title"> 注意事项</div><div>1、请确认就诊人信息是否准确,若填写错误将无法取号就诊,损失由本人承担;<br><span style="color:red">2、【取号】就诊当天需在{{ orderInfo.fetchTime }}在医院取号,未取号视为爽约,该号不退不换;</span><br>3、【退号】在{{ orderInfo.quitTime }}前可在线退号 ,逾期将不可办理退号退费;<br>4、北京114预约挂号支持自费患者使用身份证预约,同时支持北京市医保患者使用北京社保卡在平台预约挂号。请于就诊当日,携带预约挂号所使用的有效身份证件到院取号;<br>5、请注意北京市医保患者在住院期间不能使用社保卡在门诊取号。</div></div><div class="bottom-wrapper mt60" v-if="orderInfo.orderStatus == 0 || orderInfo.orderStatus == 1"><div class="button-wrapper"><div class="v-button white" @click="cancelOrder()">取消预约</div></div><div class="button-wrapper ml20" v-if="orderInfo.orderStatus == 0"><div class="v-button" @click="pay()">支付</div></div></div></div></div><!-- 右侧内容 #end --><!-- 微信支付弹出框 --><el-dialog :visible.sync="dialogPayVisible" style="text-align: left" :append-to-body="true" width="500px" @close="closeDialog"><div class="container"><div class="operate-view" style="height: 350px;"><div class="wrapper wechat"><div><img src="images/weixin.jpg" alt=""><div style="text-align: center;line-height: 25px;margin-bottom: 40px;">请使用微信扫一扫<br/>扫描二维码支付</div></div></div></div></div></el-dialog></div><!-- footer -->
</template>
<script>
import '~/assets/css/hospital_personal.css'
import '~/assets/css/hospital.css'
import orderInfoApi from '@/api/orderInfo'
export default {data() {return {orderId: null,orderInfo: {param: {}},dialogPayVisible: false,payObj: {},timer: null // 定时器名称}},created() {this.orderId = this.$route.query.orderIdthis.init()},methods: {init() {orderInfoApi.getOrders(this.orderId).then(response => {console.log(response.data);this.orderInfo = response.data})}}
}
</script>
<style>
.info-wrapper {padding-left: 0;padding-top: 0;
}
.content-wrapper {color: #333;font-size: 14px;padding-bottom: 0;
}
.bottom-wrapper {width: 100%;
}
.button-wrapper {margin: 0;
}
.el-form-item {margin-bottom: 5px;
}
.bottom-wrapper .button-wrapper {margin-top: 0;
}
</style>
1.2 订单列表
操作模块:service_order
1.2.1 api接口
1.添加service接口及实现类
在OrderService类添加接口
//订单列表(条件查询带分页)
IPage<OrderInfo> selectPage(Page<OrderInfo> pageParam, OrderQueryVo orderQueryVo);
在OrderServiceImpl类添加接口实现
//订单列表(条件查询带分页)
@Override
public IPage<OrderInfo> selectPage(Page<OrderInfo> pageParam, OrderQueryVo orderQueryVo) {//orderQueryVo获取条件String name = orderQueryVo.getKeyword(); //医院名称Long patientId = orderQueryVo.getPatientId(); //就诊人idString orderStatus = orderQueryVo.getOrderStatus(); //订单状态String reserveDate = orderQueryVo.getReserveDate();//安排时间String createTimeBegin = orderQueryVo.getCreateTimeBegin();String createTimeEnd = orderQueryVo.getCreateTimeEnd();//对条件值进行非空判断QueryWrapper<OrderInfo> wrapper = new QueryWrapper<>();wrapper.eq("user_id",orderQueryVo.getUserId());if(!StringUtils.isEmpty(name)) {wrapper.like("hosname",name);}if(!StringUtils.isEmpty(patientId)) {wrapper.eq("patient_id",patientId);}if(!StringUtils.isEmpty(orderStatus)) {wrapper.eq("order_status",orderStatus);}if(!StringUtils.isEmpty(reserveDate)) {wrapper.le("reserve_date",reserveDate);}if(!StringUtils.isEmpty(createTimeBegin)) {wrapper.ge("create_time",createTimeBegin);}if(!StringUtils.isEmpty(createTimeEnd)) {wrapper.le("create_time",createTimeEnd);}//调用mapper的方法Page<OrderInfo> pages = baseMapper.selectPage(pageParam, wrapper);//编号变成对应封装pages.getRecords().stream().forEach(item -> {this.packOrderInfo(item);});return pages;
}
2.添加controller
在OrderApiController类添加方法
//订单列表(条件查询带分页)
@GetMapping("auth/{page}/{limit}")
public Result list(@PathVariable Long page,@PathVariable Long limit,OrderQueryVo orderQueryVo,HttpServletRequest request){//设置当前用户idorderQueryVo.setUserId(AuthContextHolder.getUserId(request));Page<OrderInfo> pageParam = new Page<>(page,limit);IPage<OrderInfo> pageModel = orderService.selectPage(pageParam,orderQueryVo);return Result.ok(pageModel);
}@ApiOperation(value = "获取订单状态")
@GetMapping("auth/getStatusList")
public Result getStatusList() {return Result.ok(OrderStatusEnum.getStatusList());
}
1.2.2 前端
1.封装api请求
在/api/orderInfo.js添加方法
//订单列表
getPageList(page,limit,searchObj){return request({url: `${api_name}/auth/${page}/${limit}`,method: 'get',params: searchObj})
},
//查询订单状态
getStatusList() {return request({url: `${api_name}/auth/getStatusList`,method: 'get'})
}
2.页面展示
创建/pages/order/index.vue组件
<template><!-- header --><div class="nav-container page-component"><!--左侧导航 #start --><div class="nav left-nav"><div class="nav-item "><span class="v-link clickable dark" onclick="javascript:window.location='/user'">实名认证 </span></div><div class="nav-item selected"><span class="v-link selected dark" onclick="javascript:window.location='/order'"> 挂号订单 </span></div><div class="nav-item "><span class="v-link clickable dark" onclick="javascript:window.location='/patient'"> 就诊人管理 </span></div><div class="nav-item "><span class="v-link clickable dark"> 修改账号信息 </span></div><div class="nav-item "><span class="v-link clickable dark"> 意见反馈 </span></div></div><!-- 左侧导航 #end --><!-- 右侧内容 #start --><div class="page-container"><div class="personal-order"><div class="title"> 挂号订单</div><el-form :inline="true"><el-form-item label="就诊人:"><el-select v-model="searchObj.patientId" placeholder="请选择就诊人" class="v-select patient-select"><el-optionv-for="item in patientList":key="item.id":label="item.name + '【' + item.certificatesNo + '】'":value="item.id"></el-option></el-select></el-form-item><el-form-item label="订单状态:" style="margin-left: 80px"><el-select v-model="searchObj.orderStatus" placeholder="全部" class="v-select patient-select" style="width: 200px;"><el-optionv-for="item in statusList":key="item.status":label="item.comment":value="item.status"></el-option></el-select></el-form-item><el-form-item><el-button type="text" class="search-button v-link highlight clickable selected" @click="fetchData()">查询</el-button></el-form-item></el-form><div class="table-wrapper table"><el-table:data="list"stripestyle="width: 100%"><el-table-columnlabel="就诊时间"width="120"><template slot-scope="scope">{{ scope.row.reserveDate }} {{ scope.row.reserveTime === 0 ? '上午' : '下午' }}</template></el-table-column><el-table-columnprop="hosname"label="医院"width="100"></el-table-column><el-table-columnprop="depname"label="科室"></el-table-column><el-table-columnprop="title"label="医生"></el-table-column><el-table-columnprop="amount"label="医事服务费"></el-table-column><el-table-columnprop="patientName"label="就诊人"></el-table-column><el-table-columnprop="param.orderStatusString"label="订单状态"></el-table-column><el-table-column label="操作"><template slot-scope="scope"><el-button type="text" class="v-link highlight clickable selected" @click="show(scope.row.id)">详情</el-button></template></el-table-column></el-table></div><!-- 分页 --><el-paginationclass="pagination"layout="prev, pager, next":current-page="page":total="total":page-size="limit"@current-change="fetchData"></el-pagination></div></div><!-- 右侧内容 #end --></div><!-- footer -->
</template>
<script>
import '~/assets/css/hospital_personal.css'
import '~/assets/css/hospital.css'
import orderInfoApi from '@/api/orderInfo'
import patientApi from '@/api/patient'
export default {data() {return {list: [], // banner列表total: 0, // 数据库中的总记录数page: 1, // 默认页码limit: 10, // 每页记录数searchObj: {}, // 查询表单对象patientList: [],statusList: []}},created() {this.orderId = this.$route.query.orderIdthis.fetchData()this.findPatientList()this.getStatusList()},methods: {fetchData(page = 1) {this.page = pageorderInfoApi.getPageList(this.page, this.limit, this.searchObj).then(response => {console.log(response.data);this.list = response.data.recordsthis.total = response.data.total})},findPatientList() {patientApi.findList().then(response => {this.patientList = response.data})},getStatusList() {orderInfoApi.getStatusList().then(response => {this.statusList = response.data})},changeSize(size) {console.log(size)this.limit = sizethis.fetchData(1)},show(id) {window.location.href = '/order/show?orderId=' + id}}
}
</script>
注:平台订单管理和用户订单管理接口基本一样,因此不再操作
2.微信支付
2.1 微信支付简介
微信扫码支付申请
微信扫码支付是商户系统按微信支付协议生成支付二维码,用户再用微信“扫一扫”完成支付的模式。该模式适用于PC网站支付、实体店单品或订单支付、媒体广告支付等场景。
申请步骤:(了解)
第一步:注册公众号(类型须为:服务号)
请根据营业执照类型选择以下主体注册:个体工商户| 企业/公司| 政府| 媒体| 其他类型。
第二步:认证公众号
公众号认证后才可申请微信支付,认证费:300元/年。
第三步:提交资料申请微信支付
登录公众平台,点击左侧菜单【微信支付】,开始填写资料等待审核,审核时间为1-5个工作日内。
第四步:开户成功,登录商户平台进行验证
资料审核通过后,请登录联系人邮箱查收商户号和密码,并登录商户平台填写财付通备付金打的小额资金数额,完成账户验证。
第五步:在线签署协议
本协议为线上电子协议,签署后方可进行交易及资金结算,签署完立即生效。
开发文档
微信支付接口调用的整体思路:
按API要求组装参数,以XML方式发送(POST)给微信支付接口(URL),微信支付接口也是以XML方式给予响应。程序根据返回的结果(其中包括支付URL)生成二维码或判断订单状态。
在线微信支付开发文档:
.html
- appid:微信公众账号或开放平台APP的唯一标识
- mch_id:商户号 (配置文件中的partner)
- partnerkey:商户密钥
- sign:数字签名, 根据微信官方提供的密钥和一套算法生成的一个加密信息, 就是为了保证交易的安全性
2.2 微信支付开发
2.2.1 api接口
场景:用户扫描商户展示在各种场景的二维码进行支付
使用案例:
线下:家乐福超市、7-11便利店、上品折扣线下店等
线上:大众点评网站、携程网站、唯品会、美丽说网站等
开发模式:
模式一:商户在后台给你生成二维码,用户打开扫一扫
模式二:商户后台系统调用微信支付【统一下单API】生成预付交易,将接口返回的链接生成二维码,用户扫码后输入密码完成支付交易。注意:该模式的预付单有效期为2小时,过期后无法支付。
微信支付:生成xml发送请求
操作模块:service-order
1.引入依赖
<dependency><groupId>com.github.wxpay</groupId><artifactId>wxpay-sdk</artifactId><version>0.0.3</version>
</dependency>
2.添加配置
在application.yml中添加商户信息
spring:redis:timeout: 1800000lettuce:pool:max-active: 20max-wait: -1max-idle: 5min-idle: 0
weixin:appid: wx74862e0dfcf69954partner: 1558950191partnerkey: T6m9iK73b0kn9g5v426MKfHQH7X8rKwb
3.引入工具类
com.myproject.yygh.order.utils.ConstantPropertiesUtils
package com.myproject.yygh.order.utils;import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;@Component
public class ConstantPropertiesUtils implements InitializingBean {@Value("${weixin.appid}")private String appid;@Value("${weixin.partner}")private String partner;@Value("${weixin.partnerkey}")private String partnerkey;public static String APPID;public static String PARTNER;public static String PARTNERKEY;@Overridepublic void afterPropertiesSet() throws Exception {APPID = appid;PARTNER = partner;PARTNERKEY = partnerkey;}
}
com.myproject.yygh.order.utils.HttpClient
package com.myproject.yygh.order.utils;import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;import javax.net.ssl.SSLContext;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.KeyStore;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.text.ParseException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;/*** http请求客户端*/
public class HttpClient {private String url;private Map<String, String> param;private int statusCode;private String content;private String xmlParam;private boolean isHttps;private boolean isCert = false;//证书密码 微信商户号(mch_id)private String certPassword;public boolean isHttps() {return isHttps;}public void setHttps(boolean isHttps) {this.isHttps = isHttps;}public boolean isCert() {return isCert;}public void setCert(boolean cert) {isCert = cert;}public String getXmlParam() {return xmlParam;}public void setXmlParam(String xmlParam) {this.xmlParam = xmlParam;}public HttpClient(String url, Map<String, String> param) {this.url = url;this.param = param;}public HttpClient(String url) {this.url = url;}public String getCertPassword() {return certPassword;}public void setCertPassword(String certPassword) {this.certPassword = certPassword;}public void setParameter(Map<String, String> map) {param = map;}public void addParameter(String key, String value) {if (param == null)param = new HashMap<String, String>();param.put(key, value);}public void post() throws ClientProtocolException, IOException {HttpPost http = new HttpPost(url);setEntity(http);execute(http);}public void put() throws ClientProtocolException, IOException {HttpPut http = new HttpPut(url);setEntity(http);execute(http);}public void get() throws ClientProtocolException, IOException {if (param != null) {StringBuilder url = new StringBuilder(this.url);boolean isFirst = true;for (String key : param.keySet()) {if (isFirst)url.append("?");elseurl.append("&");url.append(key).append("=").append(param.get(key));}this.url = url.toString();}HttpGet http = new HttpGet(url);execute(http);}/*** set http post,put param*/private void setEntity(HttpEntityEnclosingRequestBase http) {if (param != null) {List<NameValuePair> nvps = new LinkedList<NameValuePair>();for (String key : param.keySet())nvps.add(new BasicNameValuePair(key, param.get(key))); // 参数http.setEntity(new UrlEncodedFormEntity(nvps, Consts.UTF_8)); // 设置参数}if (xmlParam != null) {http.setEntity(new StringEntity(xmlParam, Consts.UTF_8));}}private void execute(HttpUriRequest http) throws ClientProtocolException,IOException {CloseableHttpClient httpClient = null;try {if (isHttps) {if(isCert) {//TODO 需要完善FileInputStream inputStream = new FileInputStream(new File(""));KeyStore keystore = KeyStore.getInstance("PKCS12");char[] partnerId2charArray = certPassword.toCharArray();keystore.load(inputStream, partnerId2charArray);SSLContext sslContext = SSLContexts.custom().loadKeyMaterial(keystore, partnerId2charArray).build();SSLConnectionSocketFactory sslsf =new SSLConnectionSocketFactory(sslContext,new String[] { "TLSv1" },null,SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();} else {SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {// 信任所有public boolean isTrusted(X509Certificate[] chain,String authType)throws CertificateException {return true;}}).build();SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext);httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();}} else {httpClient = HttpClients.createDefault();}CloseableHttpResponse response = httpClient.execute(http);try {if (response != null) {if (response.getStatusLine() != null)statusCode = response.getStatusLine().getStatusCode();HttpEntity entity = response.getEntity();// 响应内容content = EntityUtils.toString(entity, Consts.UTF_8);}} finally {response.close();}} catch (Exception e) {e.printStackTrace();} finally {httpClient.close();}}public int getStatusCode() {return statusCode;}public String getContent() throws ParseException, IOException {return content;}
}
2.2.2 添加交易记录接口
1.添加Mapper
com.myproject.yygh.order.mapper.PaymentMapper
package com.myproject.yygh.order.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.myproject.yygh.model.order.PaymentInfo;
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface PaymentMapper extends BaseMapper<PaymentInfo> {
}
2.添加service接口与实现
com.myproject.yygh.order.service.PaymentService
package com.myproject.yygh.order.service;import com.baomidou.mybatisplus.extension.service.IService;
import com.myproject.yygh.model.order.OrderInfo;
import com.myproject.yygh.model.order.PaymentInfo;public interface PaymentService extends IService<PaymentInfo> {//向支付记录表添加信息void savePaymentInfo(OrderInfo orderInfo, Integer status);
}
com.myproject.yygh.order.service.impl.PaymentServiceImpl
package com.myproject.yygh.order.service.impl;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.myproject.yygh.enums.PaymentStatusEnum;
import com.myproject.yygh.model.order.OrderInfo;
import com.myproject.yygh.model.order.PaymentInfo;
import com.myproject.yygh.order.mapper.PaymentMapper;
import com.myproject.yygh.order.service.PaymentService;
import org.joda.time.DateTime;
import org.springframework.stereotype.Service;import java.util.Date;@Service
public class PaymentServiceImpl extends ServiceImpl<PaymentMapper, PaymentInfo> implements PaymentService {//向支付记录表添加信息@Overridepublic void savePaymentInfo(OrderInfo orderInfo, Integer paymentType) {//根据订单id和支付类型,查询支付记录表是否存在相同订单QueryWrapper<PaymentInfo> wrapper = new QueryWrapper<>();wrapper.eq("order_id",orderInfo.getId());wrapper.eq("payment_type",paymentType);Long count = baseMapper.selectCount(wrapper);if(count > 0){return;}//添加记录PaymentInfo paymentInfo = new PaymentInfo();paymentInfo.setCreateTime(new Date());paymentInfo.setOrderId(orderInfo.getId());paymentInfo.setPaymentType(paymentType);paymentInfo.setOutTradeNo(orderInfo.getOutTradeNo());paymentInfo.setPaymentStatus(PaymentStatusEnum.UNPAID.getStatus());String subject = new DateTime(orderInfo.getReserveDate()).toString("yyyy-MM-dd")+"|"+orderInfo.getHosname()+"|"+orderInfo.getDepname()+"|"+orderInfo.getTitle();paymentInfo.setSubject(subject);paymentInfo.setTotalAmount(orderInfo.getAmount());baseMapper.insert(paymentInfo);}
}
*3.添加支付service接口与实现
com.myproject.yygh.order.service.WeixinService
package com.myproject.yygh.order.service;import java.util.Map;public interface WeixinService {//生成微信支付扫描的二维码Map createNative(Long orderId);
}
com.myproject.yygh.order.service.impl.WeixinServiceImpl
package com.myproject.yygh.order.service.impl;import com.github.wxpay.sdk.WXPayUtil;
import com.myproject.yygh.enums.PaymentTypeEnum;
import com.myproject.yygh.model.order.OrderInfo;
import com.myproject.yygh.order.service.OrderService;
import com.myproject.yygh.order.service.PaymentService;
import com.myproject.yygh.order.service.WeixinService;
import com.myproject.yygh.order.utils.ConstantPropertiesUtils;
import com.myproject.yygh.order.utils.HttpClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;@Service
public class WeixinServiceImpl implements WeixinService {@Autowiredprivate OrderService orderService;@Autowiredprivate PaymentService paymentService;@Autowiredprivate RedisTemplate redisTemplate;//生成微信支付扫描的二维码@Overridepublic Map createNative(Long orderId) {try {//从redis获取数据Map payMap = (Map) redisTemplate.opsForValue().get(orderId.toString());if(payMap != null){return payMap;}//1.根据orderId获取订单信息OrderInfo orderInfo = orderService.getById(orderId);//2.向支付记录表添加信息paymentService.savePaymentInfo(orderInfo, PaymentTypeEnum.WEIXIN.getStatus());//3.设置参数//吧参数转换xml格式,使用商户key进行加密Map paramMap = new HashMap<>();paramMap.put("appid", ConstantPropertiesUtils.APPID);paramMap.put("mch_id", ConstantPropertiesUtils.PARTNER);paramMap.put("nonce_str", WXPayUtil.generateNonceStr());String body = orderInfo.getReserveDate() + "就诊"+ orderInfo.getDepname();paramMap.put("body", body);paramMap.put("out_trade_no", orderInfo.getOutTradeNo());//paramMap.put("total_fee", order.getAmount().multiply(new BigDecimal("100")).longValue()+"");paramMap.put("total_fee", "1");//为了测试,统一携程这个值paramMap.put("spbill_create_ip", "127.0.0.1");paramMap.put("notify_url", "/api/order/weixinPay/weixinNotify");paramMap.put("trade_type", "NATIVE");//4.调用微信生成二维码接口,httpclient调用HttpClient client = new HttpClient("");//设置map参数client.setXmlParam(WXPayUtil.generateSignedXml(paramMap,ConstantPropertiesUtils.PARTNERKEY));client.setHttps(true);client.post();//6.返回相关数据String xml = client.getContent();//转换成map集合Map<String,String> resultMap = WXPayUtil.xmlToMap(xml);System.out.println("resultMap:" + resultMap);//4、封装返回结果集Map map = new HashMap<>();map.put("orderId", orderId);map.put("totalFee", orderInfo.getAmount());map.put("resultCode", resultMap.get("result_code"));map.put("codeUrl", resultMap.get("code_url"));//二维码地址//微信支付二维码2小时过期,可采取2小时未支付取消订单if(resultMap.get("resultCode") != null){redisTemplate.opsForValue().set(orderId.toString(),map,120, TimeUnit.MINUTES);}return map;} catch (Exception e) {throw new RuntimeException(e);}}
}
4.添加controller方法
com.myproject.yygh.order.api.WeiXinController
package com.myproject.yygh.order.api;import com.myproject.yygh.common.result.Result;
import com.myproject.yygh.order.service.WeixinService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.Map;@RestController
@RequestMapping("/api/order/weixin")
public class WeiXinController {@Autowiredprivate WeixinService weixinService;//生成微信支付扫描的二维码@GetMapping("createNative/{orderId}")public Result createNative(@PathVariable Long orderId){Map map = weixinService.createNative(orderId);return Result.ok(map);}
}
2.2 前端
2.2.1 封装api请求
添加/api/weixin.js文件
//生成微信支付的二维码
createNative(orderId) {return request({url: `/api/order/weixin/createNative/${orderId}`,method: 'get'})
},
//查询支付状态的接口
queryPayStatus(orderId) {return request({url: `/api/order/weixin/queryPayStatus/${orderId}`,method: 'get'})
}
2.2.2 引入vue-qriously生成二维码
安装vue-qriously
npm install vue-qriously
引入
在/plugins/myPlugin.js文件添加引入
import VueQriously from 'vue-qriously'
Vue.use(VueQriously)
2.2.3 页面展示
修改/pages/order/show.vue组件
1.将104行的微信图片改为显示二维码
<qriously :value="payObj.codeUrl" :size="220"/>
2.在script中引入api接口
import weixinApi from '@/api/weixin'
3.添加方法
//生成支付二维码
pay(){//支付二维码弹框显示this.dialogPayVisible = trueweixinApi.createNative(this.orderId).then(response => {this.payObj = response.dataif(this.payObj.codeUrl == ''){//生成失败this.dialogPayVisible = falsethis.$message.error('支付错误')}else{//每个3秒调用查询支付状态接口this.timer = setInterval(() => {this.queryPayStatus(this.orderId)},3000);}})
},
//查询支付状态的方法
queryPayStatus(orderId) {weixinApi.queryPayStatus(orderId).then(response => {if(response.message == '支付中'){return;}//清除定时器clearInterval(this.timer)window.location.reload()})
},
closeDialog(){if(this.timer){clearInterval(this.timer);}
}
说明:我们只有轮询查看支付状态,接下来我们处理支付查询接口
测试功能,查看订单点击“支付”后是否显示二维码
2.3 处理支付结果
操作模块:yygh_order
2.3.1 支付查询
1.添加service接口与实现
在WeixinService类添加接口
//调用微信接口实现支付状态查询
Map<String, String> queryPayStatus(Long orderId);
在WeixinServiceImpl类添加实现
//调用微信接口实现支付状态查询
@Override
public Map<String, String> queryPayStatus(Long orderId) {try{//1.根据orderId获取订单信息OrderInfo orderInfo = orderService.getById(orderId);//2.封装提交参数Map paramMap = new HashMap<>();paramMap.put("appid", ConstantPropertiesUtils.APPID);paramMap.put("mch_id", ConstantPropertiesUtils.PARTNER);paramMap.put("out_trade_no", orderInfo.getOutTradeNo());paramMap.put("nonce_str", WXPayUtil.generateNonceStr());//3.设置请求内容HttpClient client = new HttpClient("");client.setXmlParam(WXPayUtil.generateSignedXml(paramMap, ConstantPropertiesUtils.PARTNERKEY));client.setHttps(true);client.post();//4.得到微信接口返回数据String xml = client.getContent();Map<String, String> resultMap = WXPayUtil.xmlToMap(xml);System.out.println("支付状态resultMap:" + resultMap);//5.把接口数据返回return resultMap;}catch (Exception e){return null;}
}
2.3.2 处理支付成功逻辑
1.添加service接口与实现
在PaymentService类添加接口
//更新订单状态
void paySuccess(String out_trade_no, Map<String, String> resultMap);
在PaymentServiceImpl类添加实现
@Autowired
private OrderService orderService;@Autowired
private HospitalFeignClient hospitalFeignClient;//更新订单状态
@Override
public void paySuccess(String out_trade_no, Map<String, String> resultMap) {//1.根据订单编号得到支付记录QueryWrapper<PaymentInfo> wrapper = new QueryWrapper<>();wrapper.eq("out_trade_no", out_trade_no);wrapper.eq("payment_type", PaymentTypeEnum.WEIXIN.getStatus());PaymentInfo paymentInfo = baseMapper.selectOne(wrapper);//2.更新支付记录信息paymentInfo.setPaymentStatus(PaymentStatusEnum.PAID.getStatus());paymentInfo.setTradeNo(resultMap.get("transaction_id"));paymentInfo.setCallbackTime(new Date());paymentInfo.setCallbackContent(resultMap.toString());baseMapper.updateById(paymentInfo);//3.根据订单号得到订单信息//4.更新订单信息OrderInfo orderInfo = orderService.getById(paymentInfo.getOrderId());orderInfo.setOrderStatus(OrderStatusEnum.PAID.getStatus());orderService.updateById(orderInfo);//5.调用医院接口,更新订单信息SignInfoVo signInfoVo = hospitalFeignClient.getSignInfoVo(orderInfo.getHoscode());Map<String,Object> reqMap = new HashMap<>();reqMap.put("hoscode",orderInfo.getHoscode());reqMap.put("hosRecordId",orderInfo.getHosRecordId());reqMap.put("timestamp", HttpRequestHelper.getTimestamp());String sign = HttpRequestHelper.getSign(reqMap, signInfoVo.getSignKey());reqMap.put("sign", sign);JSONObject result = HttpRequestHelper.sendRequest(reqMap, signInfoVo.getApiUrl() + "/order/updatePayStatus");
}
2.3.3 添加controller方法
在WeixinController类添加方法
@Autowired
private PaymentService paymentService;//查询支付状态
@GetMapping("queryPayStatus/{orderId}")
public Result queryPayStatus(@PathVariable Long orderId){//调用微信接口实现支付状态查询Map<String,String> resultMap = weixinService.queryPayStatus(orderId);if(resultMap == null){return Result.fail().message("支付出错");}if("SUCCESS".equals(resultMap.get("trade_state"))){//支付成功//更新订单状态String out_trade_no = resultMap.get("out_trade_no");//订单编号paymentService.paySuccess(out_trade_no,resultMap);return Result.ok().message("支付成功");}return Result.ok().message("支付中");
}
3.取消预约
需求分析
取消订单分两种情况:
1、未支付取消订单,直接通知医院更新取消预约状态
2、已支付取消订单,先退款给用户,然后通知医院更新取消预约状态
3.1 开发微信退款接口
参考文档:.php?chapter=9_4
该接口需要使用证书,详情参考文档并下载证书
3.1.1 配置证书
请下载的证书放在service-order模块/resources/cert文件夹下
(链接: 提取码:odj8)
1.在application.yml文件配置证书路径
weixin:cert: service/service_order/src/main/java/com/myproject/yygh/order/cert/apiclient_cert.p12
2.修改ConstantPropertiesUtils工具类
package com.myproject.yygh.order.utils;import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;@Component
public class ConstantPropertiesUtils implements InitializingBean {@Value("${weixin.appid}")private String appid;@Value("${weixin.partner}")private String partner;@Value("${weixin.partnerkey}")private String partnerkey;@Value("${weixin.cert}")private String cert;public static String APPID;public static String PARTNER;public static String PARTNERKEY;public static String CERT;@Overridepublic void afterPropertiesSet() throws Exception {APPID = appid;PARTNER = partner;PARTNERKEY = partnerkey;CERT = cert;}
}
3.修改HttpClient工具类
修改第131行
FileInputStream inputStream = new FileInputStream(new File(ConstantPropertiesUtils.CERT));
3.1.2 添加获取支付记录接口
退款我们是根据支付记录发起退款的
1.在PaymentService类添加接口
//获取支付记录
PaymentInfo getPaymentInfo(Long orderId, Integer paymentType);
2.在PaymentServiceImpl类添加实现
//获取支付记录
@Override
public PaymentInfo getPaymentInfo(Long orderId, Integer paymentType) {QueryWrapper<PaymentInfo> wrapper = new QueryWrapper<>();wrapper.eq("order_id",orderId);wrapper.eq("payment_type",paymentType);PaymentInfo paymentInfo = baseMapper.selectOne(wrapper);return paymentInfo;
}
3.1.3 添加退款记录
1.添加mapper
com.myproject.yygh.order.mapper.RefundInfoMapper
package com.myproject.yygh.order.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.myproject.yygh.model.order.RefundInfo;
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface RefundInfoMapper extends BaseMapper<RefundInfo> {
}
2.添加service接口与实现
添加service接口
com.myproject.yygh.order.service.RefundInfoService
package com.myproject.yygh.order.service;import com.baomidou.mybatisplus.extension.service.IService;
import com.myproject.yygh.model.order.PaymentInfo;
import com.myproject.yygh.model.order.RefundInfo;public interface RefundInfoService extends IService<RefundInfo> {//保存退款记录RefundInfo saveRefundInfo(PaymentInfo paymentInfo);
}
添加service接口实现
com.myproject.yygh.order.service.impl.RefundInfoServiceImpl
package com.myproject.yygh.order.service.impl;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.myproject.yygh.enums.RefundStatusEnum;
import com.myproject.yygh.model.order.PaymentInfo;
import com.myproject.yygh.model.order.RefundInfo;
import com.myproject.yygh.order.mapper.RefundInfoMapper;
import com.myproject.yygh.order.service.RefundInfoService;
import org.springframework.stereotype.Service;import java.util.Date;@Service
public class RefundInfoServiceImpl extends ServiceImpl<RefundInfoMapper, RefundInfo> implements RefundInfoService {//保存退款记录@Overridepublic RefundInfo saveRefundInfo(PaymentInfo paymentInfo) {//判断是否有重复数据添加QueryWrapper<RefundInfo> wrapper = new QueryWrapper<>();wrapper.eq("order_id", paymentInfo.getOrderId());wrapper.eq("payment_type", paymentInfo.getPaymentType());RefundInfo refundInfo = baseMapper.selectOne(wrapper);if(refundInfo != null){return refundInfo;}//添加记录refundInfo = new RefundInfo();refundInfo.setCreateTime(new Date());refundInfo.setOrderId(paymentInfo.getOrderId());refundInfo.setPaymentType(paymentInfo.getPaymentType());refundInfo.setOutTradeNo(paymentInfo.getOutTradeNo());refundInfo.setRefundStatus(RefundStatusEnum.UNREFUND.getStatus());refundInfo.setSubject(paymentInfo.getSubject());//paymentInfo.setSubject("test");refundInfo.setTotalAmount(paymentInfo.getTotalAmount());baseMapper.insert(refundInfo);return refundInfo;}
}
3.1.4 添加微信退款接口
在WeixinService添加接口
//退款
Boolean refund(Long orderId);
在WeixinServiceImpl添加实现
@Autowired
private RefundInfoService refundInfoService;//微信退款
@Override
public Boolean refund(Long orderId) {try {//获取支付记录信息PaymentInfo paymentInfo = paymentService.getPaymentInfo(orderId, PaymentTypeEnum.WEIXIN.getStatus());//添加信息到退款记录表RefundInfo refundInfo = refundInfoService.saveRefundInfo(paymentInfo);//判断当前订单数据是否已经退款if(refundInfo.getRefundStatus().intValue() == RefundStatusEnum.REFUND.getStatus().intValue()) {return true;}//调用微信接口实现退款//封装需要参数Map<String,String> paramMap = new HashMap<>(8);paramMap.put("appid",ConstantPropertiesUtils.APPID); //公众账号IDparamMap.put("mch_id",ConstantPropertiesUtils.PARTNER); //商户编号paramMap.put("nonce_str",WXPayUtil.generateNonceStr());paramMap.put("transaction_id",paymentInfo.getTradeNo()); //微信订单号paramMap.put("out_trade_no",paymentInfo.getOutTradeNo()); //商户订单编号paramMap.put("out_refund_no","tk"+paymentInfo.getOutTradeNo()); //商户退款单号
// paramMap.put("total_fee",paymentInfoQuery.getTotalAmount().multiply(new BigDecimal("100")).longValue()+"");
// paramMap.put("refund_fee",paymentInfoQuery.getTotalAmount().multiply(new BigDecimal("100")).longValue()+"");paramMap.put("total_fee","1");paramMap.put("refund_fee","1");String paramXml = WXPayUtil.generateSignedXml(paramMap,ConstantPropertiesUtils.PARTNERKEY);//设置调用接口内容HttpClient client = new HttpClient("");client.setXmlParam(paramXml);client.setHttps(true);//设置整数信息client.setCert(true);client.setCertPassword(ConstantPropertiesUtils.PARTNER);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;}} catch (Exception e) {throw new RuntimeException(e);}return null;
}
3.2 完成取消预约
参考《尚医通API接口文档.docx》业务接口5.3.取消预约
3.2.1 添加service接口与实现
在OrderService添加接口
//取消预约
Boolean cancelOrder(Long orderId);
在OrderServiceImpl添加实现
@Autowired
private WeixinService weixinService;//取消预约
@Override
public Boolean cancelOrder(Long orderId) {//获取订单信息OrderInfo orderInfo = baseMapper.selectById(orderId);//判断是否取消DateTime quitTime = new DateTime(orderInfo.getQuitTime());if(quitTime.isBeforeNow()){throw new YyghException(ResultCodeEnum.CANCEL_ORDER_NO);}//调用医院接口实现预约取消SignInfoVo signInfoVo = hospitalFeignClient.getSignInfoVo(orderInfo.getHoscode());if(null == signInfoVo) {throw new YyghException(ResultCodeEnum.PARAM_ERROR);}Map<String, Object> reqMap = new HashMap<>();reqMap.put("hoscode",orderInfo.getHoscode());reqMap.put("hosRecordId",orderInfo.getHosRecordId());reqMap.put("timestamp", HttpRequestHelper.getTimestamp());String sign = HttpRequestHelper.getSign(reqMap, signInfoVo.getSignKey());reqMap.put("sign", sign);JSONObject result = HttpRequestHelper.sendRequest(reqMap, signInfoVo.getApiUrl()+"/order/updateCancelStatus");//根据医院接口返回数据if(result.getInteger("code") != 200){throw new YyghException(result.getString("message"), ResultCodeEnum.FAIL.getCode());}else {//判断当前订单是否可以取消if(orderInfo.getOrderStatus().intValue() == OrderStatusEnum.PAID.getStatus().intValue()) {//已支付 退款boolean isRefund = weixinService.refund(orderId);if(!isRefund) {throw new YyghException(ResultCodeEnum.CANCEL_ORDER_FAIL);}//更新订单状态orderInfo.setOrderStatus(OrderStatusEnum.CANCLE.getStatus());baseMapper.updateById(orderInfo);//发送mq更新预约数量OrderMqVo orderMqVo = new OrderMqVo();orderMqVo.setScheduleId(orderInfo.getScheduleId());//短信提示MsmVo msmVo = new MsmVo();msmVo.setPhone(orderInfo.getPatientPhone());String reserveDate = new DateTime(orderInfo.getReserveDate()).toString("yyyy-MM-dd") + (orderInfo.getReserveTime()==0 ? "上午": "下午");Map<String,Object> param = new HashMap<String,Object>(){{put("title", orderInfo.getHosname()+"|"+orderInfo.getDepname()+"|"+orderInfo.getTitle());put("reserveDate", reserveDate);put("name", orderInfo.getPatientName());}};msmVo.setParam(param);orderMqVo.setMsmVo(msmVo);rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_ORDER, MqConst.ROUTING_ORDER, orderMqVo);return true;}}return false;
}
3.2.2 添加controller方法
在OrderApiController添加方法
//取消预约
@GetMapping("auth/cancelOrder/{orderId}")
public Result cancelOrder(@PathVariable Long orderId){Boolean isOrder = orderService.cancelOrder(orderId);return Result.ok(isOrder);
}
3.2.3 修改监听
操作:service-hosp模块
修改HospitalReceiver 类
@RabbitListener(bindings = @QueueBinding(value = @Queue(value = MqConst.QUEUE_ORDER, durable = "true"),exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_ORDER),key = {MqConst.ROUTING_ORDER}
))
public void receiver(OrderMqVo orderMqVo, Message message, Channel channel) throws IOException {if(orderMqVo.getAvailableNumber() != null){//下单成功更新预约数Schedule schedule = scheduleService.getScheduleById(orderMqVo.getScheduleId());schedule.setReservedNumber(orderMqVo.getReservedNumber());schedule.setAvailableNumber(orderMqVo.getAvailableNumber());scheduleService.update(schedule);}else {Schedule schedule = scheduleService.getScheduleById(orderMqVo.getScheduleId());int availableNumber = schedule.getAvailableNumber().intValue() + 1;schedule.setAvailableNumber(availableNumber);scheduleService.update(schedule);}//发送短信MsmVo msmVo = orderMqVo.getMsmVo();if(null != msmVo) {rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_MSM, MqConst.ROUTING_MSM_ITEM, msmVo);}
}
3.3 前端
3.3.1 封装api请求
添加/api/orderInfo.js文件
//取消订单
cancelOrder(orderId) {return request({url: `${api_name}/auth/cancelOrder/${orderId}`,method: 'get'})
}
3.3.2 页面展示
修改/pages/order/show.vue组件
//取消预约
cancelOrder() {this.$confirm('确定取消预约吗?', '提示', {confirmButtonText: '确定',cancelButtonText: '取消',type: 'warning'}).then(() => { // promise// 点击确定,远程调用return orderInfoApi.cancelOrder(this.orderId)}).then((response) => {this.$message.success('取消成功')this.init()}).catch(() => {this.$message.info('已取消取消预约')})
}
4.就医提醒功能
我们通过定时任务,每天8点执行,提醒就诊
4.1 搭建定时任务模块service-task
在service模块中创建service-task子模块
1.修改配置pom.xml
<dependencies><dependency><groupId>com.myproject</groupId><artifactId>rabbit_util</artifactId><version>1.0</version></dependency>
</dependencies>
2.添加配置文件
application.yml
server:port: 8207spring:application:name: service-taskprofiles:active: devcloud:nacos:server-addr: 127.0.0.1:8848rabbitmq:host: 192.168.50.224port: 5672username: adminpassword: admin
3. 添加启动类
package com.myproject.yygh.task;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.annotation.ComponentScan;@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)//取消数据源自动配置
@EnableDiscoveryClient
@ComponentScan(basePackages = {"com.myproject"})
public class ServiceTaskApplication {public static void main(String[] args) {SpringApplication.run(ServiceTaskApplication.class, args);}
}
4.添加常量配置
在rabbit-util模块com.myproject.common.rabbit.constant.MqConst类添加
public static final String EXCHANGE_DIRECT_TASK = "exchange.direct.task";
public static final String ROUTING_TASK_8 = "task.8";
//队列
public static final String QUEUE_TASK_8 = "queue.task.8";
5.添加定时任务
com.myproject.yygh.task.scheduled.ScheduledTask
package com.myproject.yygh.task.scheduled;import com.myproject.common.rabbit.constant.MqConst;
import com.myproject.common.rabbit.service.RabbitService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;@Component
@EnableScheduling
public class ScheduledTask {@Autowiredprivate RabbitService rabbitService;//每天8点执行方法,提醒就医//cron表达式,执行时间间隔//每天8点:0 0 8 * * ?@Scheduled(cron = "0/30 * * * * ?")public void taskPatient(){rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_TASK,MqConst.ROUTING_TASK_8,"");}
}
4.2 添加就医提醒处理
操作:service_order
1.添加service接口和接口实现
在OrderService类添加接口
//就诊人通知
void patientTips();
在OrderServiceImpl类添加接口实现
//就诊人通知
@Override
public void patientTips() {QueryWrapper<OrderInfo> wrapper = new QueryWrapper<>();wrapper.eq("reserve_date",new DateTime().toString("yyy-MM-dd"));wrapper.ne("order_status",OrderStatusEnum.CANCLE.getStatus());List<OrderInfo> orderInfoList = baseMapper.selectList(wrapper);for (OrderInfo orderInfo : orderInfoList) {//短信提示MsmVo msmVo = new MsmVo();msmVo.setPhone(orderInfo.getPatientPhone());String reserveDate = new DateTime(orderInfo.getReserveDate()).toString("yyyy-MM-dd") + (orderInfo.getReserveTime()==0 ? "上午": "下午");Map<String,Object> param = new HashMap<String,Object>(){{put("title", orderInfo.getHosname()+"|"+orderInfo.getDepname()+"|"+orderInfo.getTitle());put("reserveDate", reserveDate);put("name", orderInfo.getPatientName());}};msmVo.setParam(param);rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_MSM, MqConst.ROUTING_MSM_ITEM, msmVo);}
}
2.添加mq监听
com.myproject.yygh.order.receiver.OrderReceiver
package com.myproject.yygh.order.receiver;import com.myproject.common.rabbit.constant.MqConst;
import com.myproject.yygh.order.service.OrderService;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import java.io.IOException;@Component
public class OrderReceiver {@Autowiredprivate OrderService orderService;@RabbitListener(bindings = @QueueBinding(value = @Queue(value = MqConst.QUEUE_TASK_8, durable = "true"),exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_TASK),key = {MqConst.ROUTING_TASK_8}))public void patientTips(Message message, Channel channel) throws IOException {orderService.patientTips();}
}
5.预约统计
我们统计医院每天的预约情况,通过图表的形式展示,统计的数据都来自订单模块,因此我们在该模块封装好数据,在统计模块通过feign的形式获取数据。
我们为什么需要一个统计模块呢,因为在实际的生成环境中,有很多种各式统计,数据来源于各个服务模块,我们得有一个统计模块来专门管理
5.1 ECharts
简介
ECharts是百度的一个项目,后来百度把Echart捐给apache,用于图表展示,提供了常规的折线图、柱状图、散点图、饼图、K线图,用于统计的盒形图,用于地理数据可视化的地图、热力图、线图,用于关系数据可视化的关系图、treemap、旭日图,多维数据可视化的平行坐标,还有用于 BI 的漏斗图,仪表盘,并且支持图与图之间的混搭。
官方网站:.html
5.1.1 基本使用
echarts.min.js(链接: 提取码:pyrg)
1.引入ECharts
<!--引入 EChars 文件-->
<script src="../js/echarts.min.js"></script>
2.定义图表区域
<!-- 为ECharts准备一个具备大小(宽高)的Dom -->
<div id="main" style="width: 600px;height:400px;"></div>
3.渲染图表(折线图)
<script>var myChart = echarts.init(document.getElementById('main'));var option = {//x轴是类目轴(离散数据),必须通过data设置类目数据xAxis: {type: 'category',data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']},//y轴是数据轴(连续数据)yAxis: {type: 'value'},//系列列表。每个系列通过 type 决定自己的图表类型series: [{//系列中的数据内容数组data: [820, 932, 901, 934, 1290, 1330, 1320],//折线图type: 'line'}]};myChart.setOption(option);
</script>
4.渲染图表(柱状图)
<script>// 基于准备好的dom,初始化echarts实例var myChart = echarts.init(document.getElementById('main'));// 指定图表的配置项和数据var option = {title: {text: 'ECharts 入门示例'},tooltip: {},legend: {data:['销量']},xAxis: {data: ["衬衫","羊毛衫","雪纺衫","裤子","高跟鞋","袜子"]},yAxis: {},series: [{name: '销量',type: 'bar',data: [5, 20, 36, 10, 10, 20]}]};// 使用刚指定的配置项和数据显示图表。myChart.setOption(option);
</script>
4.项目中集成ECharts
在yygh-page中安装
npm install --save echarts@4.1.0
5.2 获取医院每天平台预约数据接口
操作模块:service-order
5.2.1 添加Mapper接口
1.在OrderMapper类添加接口
//查询预约统计数据的方法
List<OrderCountVo> selectOrderCount(@Param("vo") OrderCountQueryVo orderCountQueryVo);
2.在OrderMapper.xml文件添加方法
com/myproject/yygh/order/mapper/xml/OrderMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"".dtd">
<mapper namespace="com.myproject.yygh.order.mapper.OrderMapper"><select id="selectOrderCount" resultType="com.myproject.yygh.vo.order.OrderCountVo">select reserve_date as reserveDate, count(reserve_date) as countfrom order_info<where><if test="vo.hosname != null and vo.hosname != ''">and hosname like CONCAT('%',#{vo.hosname},'%')</if><if test="vo.reserveDateBegin != null and vo.reserveDateBegin != ''">and reserve_date >= #{vo.reserveDateBegin}</if><if test="vo.reserveDateEnd != null and vo.reserveDateEnd != ''">and reserve_date <= #{vo.reserveDateEnd}</if>and is_deleted = 0</where>group by reserve_dateorder by reserve_date</select>
</mapper>
3.添加application.yml配置
mybatis-plus:mapper-locations: classpath:com/myproject/yygh/order/mapper/xml/*.xml
4.在yygh_parent的pom.xml中添加
<!--项目打包时会将java目录中的*.xml文件也进行打包-->
<build><resources><resource><directory>src/main/java</directory><includes><include>**/*.xml</include></includes><filtering>false</filtering></resource></resources>
</build>
5.2.2 添加service接口和接口实现
在OrderService类添加接口
//预约统计
Map<String,Object> getCountMap(OrderCountQueryVo orderCountQueryVo);
在OrderServiceImpl类添加实现
//预约统计
@Override
public Map<String, Object> getCountMap(OrderCountQueryVo orderCountQueryVo) {//调用mapper方法得到数据List<OrderCountVo> orderCountVoList = baseMapper.selectOrderCount(orderCountQueryVo);//获取x需要数据,日期数据 list集合List<String> dateList = orderCountVoList.stream().map(OrderCountVo::getReserveDate).collect(Collectors.toList());//获取y需要数据,具体数量 list集合List<Integer> countList = orderCountVoList.stream().map(OrderCountVo::getCount).collect(Collectors.toList());Map<String, Object> map = new HashMap<>();map.put("dateList", dateList);map.put("countList", countList);return map;
}
5.2.3 添加controller方法
在OrderApiController类添加方法
//获取订单统计数据
@PostMapping("inner/getCountMap")
public Map<String, Object> getCountMap(@RequestBody OrderCountQueryVo orderCountQueryVo) {return orderService.getCountMap(orderCountQueryVo);
}
5.2.4 添加feign方法
创建模块:service-order-client
1.添加依赖
<dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-openfeign-core</artifactId></dependency><dependency><groupId>com.myproject</groupId><artifactId>model</artifactId><version>1.0</version><scope>compile</scope></dependency>
</dependencies>
2.添加feign接口
com.myproject.yygh.order.client.OrderFeignClient
package com.myproject.yygh.order.client;import com.myproject.yygh.vo.order.OrderCountQueryVo;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Repository;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;import java.util.Map;@FeignClient(value = "service-order")
@Repository
public interface OrderFeignClient {/*** 获取订单统计数据*/@PostMapping("/api/order/orderInfo/inner/getCountMap")Map<String, Object> getCountMap(@RequestBody OrderCountQueryVo orderCountQueryVo);
}
5.3 搭建service-statistics
创建service_statistics子模块
1.修改配置pom.xml
<dependencies><dependency><groupId>com.myproject</groupId><artifactId>service_order_client</artifactId><version>1.0</version></dependency>
</dependencies>
2.添加配置文件
application.yml
server:port: 8208
spring:application:name: service-statisticsprofiles:active: devcloud:nacos:server-addr: 127.0.0.1:8848
3.添加启动类
com.myproject.yygh.sta.ServiceStatisticsApplication
package com.myproject.yygh.sta;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.ComponentScan;@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)//取消数据源自动配置
@EnableDiscoveryClient
@EnableFeignClients(basePackages = {"com.myproject"})
@ComponentScan(basePackages = {"com.myproject"})
public class ServiceStatisticsApplication {public static void main(String[] args) {SpringApplication.run(ServiceStatisticsApplication.class, args);}
}
4.添加controller方法
com.myproject.yygh.sta.controller.StatisticsController
package com.myproject.yygh.sta.controller;import com.myproject.yygh.common.result.Result;
import com.myproject.yygh.order.client.OrderFeignClient;
import com.myproject.yygh.vo.order.OrderCountQueryVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.Map;@Api(tags = "统计管理接口")
@RestController
@RequestMapping("/admin/statistics")
public class StatisticsController {@Autowiredprivate OrderFeignClient orderFeignClient;//获取预约统计数据@GetMapping("getCountMap")public Result getCountMap(OrderCountQueryVo orderCountQueryVo) {Map<String,Object> countMap = orderFeignClient.getCountMap(orderCountQueryVo);return Result.ok(countMap);}
}
5.添加网关
- id: service-statisticsuri: lb://service-statisticspredicates:- name: Pathargs:- /*/statistics/**
5.4 前端展示
操作:yygh_page
1.添加路由
在 src/router/index.js 文件添加路由
{path: '/statistics',component: Layout,redirect: '/statistics/order/index',name: 'BasesInfo',meta: { title: '统计管理', icon: 'table' },alwaysShow: true,children: [{path: 'order/index',name: '预约统计',component: () =>import('@/views/statistics/order/index'),meta: { title: '预约统计' }}]
},
2.封装api请求
创建/api/sta.js
import request from '@/utils/request'const api_name = '/admin/statistics'export default {getCountMap(searchObj) {return request({url: `${api_name}/getCountMap`,method: 'get',params: searchObj})}
}
3.添加组件
创建/views/statistics/order/index.vue组件
<template><div class="app-container"><!--表单--><el-form :inline="true" class="demo-form-inline"><el-form-item><el-input v-model="searchObj.hosname" placeholder="点击输入医院名称"/></el-form-item><el-form-item><el-date-pickerv-model="searchObj.reserveDateBegin"type="date"placeholder="选择开始日期"value-format="yyyy-MM-dd"/></el-form-item><el-form-item><el-date-pickerv-model="searchObj.reserveDateEnd"type="date"placeholder="选择截止日期"value-format="yyyy-MM-dd"/></el-form-item><el-button:disabled="btnDisabled"type="primary"icon="el-icon-search"@click="showChart()">查询</el-button></el-form><div class="chart-container"><div id="chart" ref="chart"class="chart" style="height:500px;width:100%"/></div></div>
</template><script>
import echarts from 'echarts'
import statisticsApi from '@/api/sta'export default {data() {return {searchObj: {hosname: '',reserveDateBegin: '',reserveDateEnd: ''},btnDisabled: false,chart: null,title: '',xData: [], // x轴数据yData: [] // y轴数据}},methods: {// 初始化图表数据showChart() {statisticsApi.getCountMap(this.searchObj).then(response => {this.yData = response.data.countListthis.xData = response.data.dateListthis.setChartData()})},setChartData() {// 基于准备好的dom,初始化echarts实例var myChart = echarts.init(document.getElementById('chart'))// 指定图表的配置项和数据var option = {title: {text: this.title + '挂号量统计'},tooltip: {},legend: {data: [this.title]},xAxis: {data: this.xData},yAxis: {minInterval: 1},series: [{name: this.title,type: 'line',data: this.yData}]}// 使用刚指定的配置项和数据显示图表。myChart.setOption(option)},}
}
</script>