Day118.尚医通:订单列表、详情、微信支付、查询交易状态

目录

一、订单列表

1、后端接口

2、前端对接

二、订单详情

三、订单支付 -- 微信支付

1、微信扫码支付申请

2、获取二维码

(1). 准备工作

(2) 添加交易记录接口

(3) 生成二维码接口

(4) 前端实现

3、微信支付 (扫描后处理)

(1) 接口方案

(2) 实现查询交易状态接口

(3) 前端实现


一、订单列表

需要先登录再进行查询(先获取userId),带分页带条件的列表查询

1、后端接口

1. 需求分析

*参数:page,limit,OrderQueryVo,请求对象(userId)

*返回值:Page<OrderInfo>

2. order模块 添加分页插件

@Configuration
@EnableTransactionManagement
public class OrderConfig {
    //分页插件
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        return new PaginationInterceptor();
    }
}

3. controller 

    @ApiOperation(value = "带条件带分页查询订单列表")
    @GetMapping("auth/{page}/{limit}")
    public R list(@PathVariable Long page,
                  @PathVariable Long limit,
                  OrderQueryVo orderQueryVo, HttpServletRequest request) {
        //1.获取userId,存入orderQueryVo
        Long userId = AuthContextHolder.getUserId(request);
        orderQueryVo.setUserId(userId);
        //2.封装分页参数(苞米豆)
        Page<OrderInfo> pageParams = new Page<>(page,limit);
        //3.调用方法查询
        Page<OrderInfo> pageModel = orderService.selectPage(pageParams,orderQueryVo);
        return R.ok().data("pageModel",pageModel);
    }

    @ApiOperation(value = "获取订单状态")//下拉列选
    @GetMapping("auth/getStatusList")
    public R getStatusList() {
        return R.ok().data("statusList", OrderStatusEnum.getStatusList());
    }

4. service

    //带条件带分页查询订单列表
    @Override
    public Page<OrderInfo> selectPage(Page<OrderInfo> pageParams, OrderQueryVo orderQueryVo) {
        //1.取出参数
        Long userId = orderQueryVo.getUserId();
        String name = orderQueryVo.getKeyword(); //医院名称
        Long patientId = orderQueryVo.getPatientId(); //就诊人名称
        String orderStatus = orderQueryVo.getOrderStatus(); //订单状态
        String reserveDate = orderQueryVo.getReserveDate();//安排时间
        String createTimeBegin = orderQueryVo.getCreateTimeBegin();
        String createTimeEnd = orderQueryVo.getCreateTimeEnd();

        //2.验空,拼写筛选条件
        QueryWrapper<OrderInfo> wrapper = new QueryWrapper<>();
        if(!StringUtils.isEmpty(userId)){
            wrapper.eq("user_id",userId);
        }
        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.ge("reserve_date",reserveDate);
        }
        if(!StringUtils.isEmpty(createTimeBegin)) {
            wrapper.ge("create_time",createTimeBegin);
        }
        if(!StringUtils.isEmpty(createTimeEnd)) {
            wrapper.le("create_time",createTimeEnd);
        }
        //3.分页查询
        Page<OrderInfo> pageModel = baseMapper.selectPage(pageParams, wrapper);

        //4.翻译状态(根据枚举,不涉及跨模块调用)
        pageModel.getRecords().stream().forEach(item->{
            this.packOrderInfo(item);
        });
        return pageModel;
    }
    //根据枚举类翻译状态
    private OrderInfo packOrderInfo(OrderInfo orderInfo) {
        orderInfo.getParam().put("orderStatusString", OrderStatusEnum.getStatusNameByStatus(orderInfo.getOrderStatus()));
        return orderInfo;
    }

2、前端对接

1 确认入口,添加页面

2. 添加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'
        })
    },

3. 添加页面元素

<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-option v-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-option v-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" stripe style="width: 100%">
                        <el-table-column label="就诊时间" width="120">
                            <template slot-scope="scope">
                                {{ scope.row.reserveDate }} {{ scope.row.reserveTime === 0 ? '上午' : '下午' }}
                            </template>
                        </el-table-column>
                        <el-table-column prop="hosname" label="医院" width="100">
                        </el-table-column>
                        <el-table-column prop="depname" label="科室">
                        </el-table-column>
                        <el-table-column prop="title" label="医生">
                        </el-table-column>
                        <el-table-column prop="amount" label="医事服务费">
                        </el-table-column>
                        <el-table-column prop="patientName" label="就诊人">
                        </el-table-column>
                        <el-table-column prop="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-pagination class="pagination" layout="prev, pager, next" :current-page="page" :total="total"
                    :page-size="limit" @current-change="fetchData">
                </el-pagination>
            </div>
        </div>
        <!-- 右侧内容 #end -->
    </div>
    <!-- footer -->
</template>

4. 实现JS

<script>
    import '~/assets/css/hospital_personal.css'
    import '~/assets/css/hospital.css'
    import patientApi from '@/api/patient'
    import orderInfoApi from '@/api/orderinfo'

    export default {
        data() {
            return {
                list: [], // banner列表
                total: 0, // 数据库中的总记录数
                page: 1, // 默认页码
                limit: 10, // 每页记录数
                searchObj: {}, // 查询表单对象
                patientList: [], //就诊人集合
                statusList: []  //订单状态集合
            }
        },
        created() {

            this.orderId = this.$route.query.orderId
            //就诊人初始化            
            this.findPatientList()
            //状态初始化
            this.getStatusList()
            //列表数据初始化
            this.fetchData()
        },
        methods: {
            findPatientList() {
                patientApi.findList().then(response => {
                    this.patientList = response.data.list
                })
            },
            getStatusList() {
                orderInfoApi.getStatusList().then(response => {
                    this.statusList = response.data.statusList
                })
            },
            fetchData(page = 1) {
                this.page = page
                orderInfoApi.getPageList(this.page, this.limit, this.searchObj).then(response => {
                    console.log(response.data);
                    this.list = response.data.pageModel.records
                    this.total = response.data.pageModel.total
                })
            },
            //查看详情
            show(id) {
                window.location.href = '/order/show?orderId=' + id
            }
        }
    }
</script>

5. 测试

二、订单详情

1. controller

    @ApiOperation(value = "根据订单id查询订单详情")
    @GetMapping("auth/getOrders/{orderId}")
    public R getOrders(@PathVariable Long orderId) {
        OrderInfo orderInfo = orderService.getOrderById(orderId);
        return R.ok().data("orderInfo",orderInfo);
    }

2. service

    //根据订单id查询订单详情
    @Override
    public OrderInfo getOrderById(Long orderId) {
        //翻译字段并返回
        OrderInfo orderInfo = this.packOrderInfo(baseMapper.selectById(orderId));
        return this.packOrderInfo(orderInfo);
    }

3. 确认入口,创建页面,添加页面元素

<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="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>

4. API

//订单详情
getOrders(orderId) {
    return request({
        url: `${api_name}/auth/getOrders/${orderId}`,
        method: `get`
    })
},

5. JS实现,添加CSS

<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.orderId
            this.getOrderInfo()
        },
        methods: {
            getOrderInfo() {
                orderInfoApi.getOrders(this.orderId)
                .then(response => {
                    this.orderInfo = response.data.orderInfo
                })
            }
        }
    }
</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>

6. 测试

三、订单支付 -- 微信支付

1、微信扫码支付申请

在线微信支付开发文档:https://pay.weixin.qq.com/wiki/doc/api/index.html

1、微信扫码支付申请

微信扫码支付是商户系统按微信支付协议生成支付二维码,用户再用微信“扫一扫”完成支付的模式。该模式适用于PC网站支付、实体店单品或订单支付、媒体广告支付等场景。

申请步骤:(了解)

第一步:注册公众号(类型须为:服务号

请根据营业执照类型选择以下主体注册:个体工商户企业/公司政府媒体其他类型

第二步:认证公众号

公众号认证后才可申请微信支付,认证费:300元/年。

第三步:提交资料申请微信支付

登录公众平台,点击左侧菜单【微信支付】,开始填写资料等待审核,审核时间为1-5个工作日内。

第四步:开户成功,登录商户平台进行验证

资料审核通过后,请登录联系人邮箱查收商户号和密码,并登录商户平台填写财付通备付金打的小额资金数额,完成账户验证。

第五步:在线签署协议

本协议为线上电子协议,签署后方可进行交易及资金结算,签署完立即生效。

2、微信支付提供工具

(1) 获取随机字符串:WXPayUtil.generateNonceStr()

(2) MAP转换为XML字符串(自动添加签名): WXPayUtil.generateSignedXml(parampartnerkey)

(3) XML字符串转换为MAP:WXPayUtil.xmlToMap(result)

2、获取二维码

(1). 准备工作

1. service_orders 引入依赖

        <!--微信支付-->
        <dependency>
            <groupId>com.github.wxpay</groupId>
            <artifactId>wxpay-sdk</artifactId>
            <version>0.0.3</version>
        </dependency>

2. 添加配置

#redis
spring.redis.host=192.168.86.86
spring.redis.port=6379
spring.redis.database= 0
spring.redis.timeout=1800000
spring.redis.lettuce.pool.max-active=20
spring.redis.lettuce.pool.max-wait=-1
#最大阻塞等待时间(负数表示没限制)
spring.redis.lettuce.pool.max-idle=5
spring.redis.lettuce.pool.min-idle=0

#关联的公众号appid
weixin.pay.appid=wx74862e0dfcf69954
#商户号
weixin.pay.partner=1558950191
#商户key
weixin.pay.partnerkey=T6m9iK73b0kn9g5v426MKfHQH7X8rKwb

3. 添加工具类读取配置信息,注释属性 cert

(2) 添加交易记录接口

payment_info

1. 确认表

2. 搭建 payment接口、类

*参数:订单id,交易类型

*返回值:无

public interface PaymentService extends IService<PaymentInfo> {
    /**
     * 保存交易记录
     * @param orderInfo
     * @param paymentType 支付类型(1:支付宝 2:微信)
     */
    void savePaymentInfo(OrderInfo orderInfo, Integer paymentType);
}

@Service
public class PaymentServiceImpl extends
        ServiceImpl<PaymentMapper, PaymentInfo> implements PaymentService {
    
    //保存交易记录
    @Override
    public void savePaymentInfo(OrderInfo orderInfo, Integer paymentType) {
        //1.根据order订单id+交易类型,查询交易记录
        QueryWrapper<PaymentInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("order_id", orderInfo.getId());
        wrapper.eq("payment_type", paymentType);
        Integer count = baseMapper.selectCount(wrapper);
        if(count>0) return;

        //2.如果没有交易记录添加新的交易记录
        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) 生成二维码接口

1. controller

*参数:orderId

*返回值:Map

@Api(tags = "微信支付接口")
@RestController
@RequestMapping("/api/order/weixin")
public class WeixinController {
    @Autowired
    private WeixinService weixinPayService;

    @ApiOperation(value = "生成支付二维码")
    @GetMapping("/createNative/{orderId}")
    public R createNative(@PathVariable("orderId") Long orderId) {
        Map<String,Object> map = weixinPayService.createNative(orderId);
        return R.ok().data(map);
    }
}

2. service

@Service
public class WeixinServiceImpl implements WeixinService {

    @Autowired
    private OrderService orderService;
    @Autowired
    private PaymentService paymentService;
    @Autowired
    private RedisTemplate redisTemplate;

    //根据订单号下单,生成支付二维码
    @Override
    public Map<String,Object> createNative(Long orderId) {


        try {
            //Map payMap = (Map) redisTemplate.opsForValue().get(orderId.toString());
            //if(null != payMap) return payMap;
            //1.查询订单信息
            OrderInfo orderInfo = orderService.getById(orderId);
            if(orderId==null){
                throw new YyghException(20001,"订单信息有误");
            }
            //2.生成交易记录
            paymentService.savePaymentInfo(orderInfo,PaymentTypeEnum.WEIXIN.getStatus());

            //3.封装调用微信接口相关参数
            Map<String, String> 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", "http://guli.shop/api/order/weixinPay/weixinNotify");
            paramMap.put("trade_type", "NATIVE");

            //4.创建客户端对象 (设置访问url 参考文档)
            HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/pay/unifiedorder");

            //5.设置参数 (map=>xml)
            client.setXmlParam(WXPayUtil.generateSignedXml
                    (paramMap,ConstantPropertiesUtils.PARTNERKEY));

            //6.客户端发送请求
            client.setHttps(true); //开启加密方式  http与https区别:https是加密的
            client.post();

            //7.获取响应,转化响应类型(xml=>map)
            String xml = client.getContent();
            System.out.println("xml = " + xml);
            Map<String, String> resultMap = WXPayUtil.xmlToMap(xml);

            //8.封装返回结果
            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"));

            //if(null != resultMap.get("result_code")) {
                //微信支付二维码2小时过期,可采取2小时未支付取消订单
                //redisTemplate.opsForValue().set(orderId.toString(), map, 1000, TimeUnit.MINUTES);
            //}
            return map;
        } catch (Exception e) {
            e.printStackTrace();
            return new HashMap<>();
        }
    }
}

3. 测试:

(4) 前端实现

1. 安装vue-qriously

npm install vue-qriously

修改插件js文件

import Vue from 'vue'
import ElementUI from 'element-ui' //element-uid的全部组件
import VueQriously from 'vue-qriously'
import 'element-ui/lib/theme-chalk/index.css' //element-ui 的 css
Vue.use(ElementUI) //使用elementUI
Vue.use(VueQriously)

2. API

  //微信二维码
  createNative(orderId) {
    return request({
      url: `/api/order/weixin/createNative/${orderId}`,
      method: 'get'
    })
  }

3. order/show.vue 页面改造

    <div>
        <!-- <img src="images/weixin.jpg" alt=""> -->
        <qriously :value="payObj.codeUrl" :size="220" />
        
        <div style="text-align: center;line-height: 25px;margin-bottom: 40px;">
            请使用微信扫一扫<br />
            扫描二维码支付
        </div>
    </div>

4. JS改造

import weixinApi from '@/api/wx'

    ...

        //支付
        pay() {
            this.dialogPayVisible = true //打开对话框
            weixinApi.createNative(this.orderId)
            .then(response => {
                this.payObj = response.data
                if (this.payObj.codeUrl == '') {
                    this.dialogPayVisible = false
                    this.$message.error("支付错误")
                }
            })
        }

5. 测试

3、微信支付 (扫描后处理)

(1) 接口方案

(1) 微信回调接口

(2) 主动查询交易结果 (定时器,setInterval  clearInterval)

(2) 实现查询交易状态接口

*参数:orderId

*返回值:R.ok()

1. controller

    @ApiOperation(value = "查询支付状态")
    @GetMapping("/queryPayStatus/{orderId}")
    public R queryPayStatus(@PathVariable("orderId") Long orderId) {

        //1.根据参数查询交易状态
        Map<String, String> resultMap = weixinPayService
                .queryPayStatus(orderId, PaymentTypeEnum.WEIXIN.name());

        //2.判断交易是否失败
        if(resultMap == null){
            return R.error().message("支付出错");
        }

        //3.判断交易成功
        if("SUCCESS".equals(resultMap.get("trade_state"))){
            //交易成功,更新交易记录 (根据对外交易编号查询) 存储完整报文,更新订单状态
            String out_trade_no = resultMap.get("out_trade_no");
            paymentService.paySuccess(out_trade_no, PaymentTypeEnum.WEIXIN.getStatus(), resultMap);
            return R.ok().message("支付成功");
        }

        //4.支付中
        return R.ok().message("支付中");
    }

2. service

(1) weixinService 微信查询交易状态

    //根据参数查询交易状态
    @Override
    public Map<String, String> queryPayStatus(Long orderId, String paymentType) {
        try {
            //1.查询订单信息
            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.创建客户端对象 (设置访问url 参考文档)
            HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/pay/orderquery");

            //4.设置参数 (map=>xml)
            client.setXmlParam(WXPayUtil.generateSignedXml
                    (paramMap, ConstantPropertiesUtils.PARTNERKEY));

            //5.客户端发送请求
            client.setHttps(true);
            client.post();

            //6.获取响应
            String xml = client.getContent();
            Map<String, String> resultMap = WXPayUtil.xmlToMap(xml);

            return resultMap;
            
        } catch (Exception e) {
            e.printStackTrace();
            return null; //在controller判断失败
        }
    }

(2) PaymentService 更新交易记录

    //更新交易记录
    @Override
    public void paySuccess(String outTradeNo, Integer paymentType,
                           Map<String, String> resultMap) {
        //1.查询交易记录
        QueryWrapper<PaymentInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("out_trade_no",outTradeNo);
        wrapper.eq("payment_type", paymentType);
        PaymentInfo paymentInfo = baseMapper.selectOne(wrapper);
        if(paymentInfo==null){
            throw new YyghException(20001,"交易记录失效");
        }
        //2.判断交易记录状态 (PAID 2 已支付)
        if(paymentInfo.getPaymentStatus()==
                PaymentStatusEnum.PAID.getStatus()){
            return;
        }

        //3.更新交易记录
        paymentInfo.setPaymentStatus(PaymentStatusEnum.PAID.getStatus());//状态
        paymentInfo.setTradeNo(resultMap.get("transaction_id"));//交易编号
        paymentInfo.setCallbackTime(new Date());//时间
        paymentInfo.setCallbackContent(resultMap.toString());//完整报文
        baseMapper.updateById(paymentInfo);

        //4.更新订单状态
        OrderInfo orderInfo = orderService.getById(paymentInfo.getOrderId());
        orderInfo.setOrderStatus(OrderStatusEnum.PAID.getStatus()); //1 已支付
        orderService.updateById(orderInfo);
        
        //5.调用医院接口,更新订单状态 (省略)
    }

(3) 前端实现

1. wx API方法

  //支付后操作 更新状态
  queryPayStatus(orderId) {
    return request({
      url: `/api/order/weixin/queryPayStatus/${orderId}`,
      method: 'get'
    })
  }

2. 修改JS方法

/支付
            pay() {
                this.dialogPayVisible = true //打开对话框
                weixinApi.createNative(this.orderId)
                    .then(response => {
                        this.payObj = response.data
                        if (this.payObj.codeUrl == '') {
                            this.dialogPayVisible = false
                            this.$message.error("支付错误")
                        } else {
                            //定时器,查询订单状态
                            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);
                }
            }

3. 测试

 打开付款二维码后,循环查询 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值