| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395 |
- <template>
- <view class="app-content awaitPayYe awaitPayYe">
- <view class="callback-wrap">
- <view class="bg_01"></view>
- <view class="callback-blo">
- <block>
- <view class="icon">
- <i class="iconfont icondaizhifu"></i>
- </view>
- </block>
- <view class="wait">待付款</view>
- <block>
- <view class="price">
- <span class="app-size-36 app-bold">¥{{ parseFloat(actPrice)}}</span>
- </view>
- </block>
- <view>
- <view style="text-align:center;margin:10upx auto 10upx auto;">
- <view class="balance" style="margin-bottom:25upx;" v-if="goPay == 0">请扫客户付款码</view>
- <view class="balance" style="margin-bottom:25upx;" v-if="goPay == 1">请求中</view>
- <view style="text-align:center;">
- <image style="width:40upx;height:40upx;margin:0 auto;" :src="`${constant.imgUrl}/icon/loading.gif`" v-if="goPay == 1" mode="scaleToFill" />
- <block v-if="goPay == 2">
- <view style="color:red;font-weight:bold;font-size:32upx;margin-bottom:20upx;">{{ remindText }}</view>
- <view style="width:100%;text-align:center;" v-if="returnCode=='BBS11105' || returnCode=='BBS10000'">
- <button style="width:25vh;background-color:red;border:1upx solid red;color:white;" class="admin-button-com big" @click="checkResult()">查询结果</button>
- </view>
- </block>
- </view>
- <view style="margin-top:20upx;">
- <button style="width:25vh;" @click="beginScan()" class="admin-button-com big blue">点击扫码</button>
- </view>
- <view style="margin-top:20upx;">
- <button style="width:25vh;" class="admin-button-com big blue" @click="gotoOrderDetail()">订单详情</button>
- </view>
- <view style="margin-top:20upx;">
- <button style="width:25vh;" @click="changePayWay(2)" class="admin-button-com big default">挂账</button>
- </view>
- <view style="margin-top:20upx;">
- <button style="width:25vh;" @click="toCancel()" class="admin-button-com big default">取消</button>
- </view>
- </view>
- </view>
- <view style="margin-top:20upx;">
- <button style="width:25vh;" @click="goBack()" class="admin-button-com big default">返回首页</button>
- </view>
- <view style="color:#CCCCCC;margin-top:20upx;">10分钟后未付款自动取消</view>
- </view>
- </view>
- </view>
- </template>
- <script>
- /**
- * 扫码支付组件(零售花店App/微信端)
- * 优化转圈状态锁死问题,支持低频自动复查及网络异常优雅降级
- */
- import { cancelOrder,debtPay,getDetail,codePay,codePayCheck,codePayVerify} from "@/api/order";
- export default {
- name: "toPay",
- components: {
- },
- mixins: [],
- computed: {},
- data() {
- return {
- orderId:0,
- actPrice:0,
- orderSn:'',
- showQrCode:false,
- payQrCodeUrl:'',
- payWay:0,
- isCashier:false,
- orderInfo:{orderType:0},
- expire:0,
- goPay:0, // 0: 请扫付款码,1: 请求中/自动复查中,2: 支付失败或异常提示
- textscan: '扫码',
- typescan: 'scan-listener',
- remindText:'',
- returnCode:'',
- pollingTimer:null, // 后台自动复查定时器
- pollingCount:0, // 自动复查次数
- isPaymentProcessing:false // 防重复扫码标志
- };
- },
- mounted() {
- },
- onUnload() {
- this.clearPolling()
- },
- beforeDestroy() {
- this.clearPolling()
- },
- onLoad(option) {
- this.orderId = option.orderId
- this.actPrice = option.actPrice
- this.orderSn = option.orderSn
- this.option = option // 保存 option 变量,防止 detail 跳转报错
- if(!this.$util.isEmpty(option.orderId)){
- getDetail({ id: option.orderId }).then(res=>{
- if(res.code == 1){
- this.orderInfo = res.data
- }
- })
- }
- },
- methods: {
- gotoOrderDetail() {
- let id = this.option.orderId ? this.option.orderId : 0
- this.$util.pageTo({url: "/admin/order/detail?id="+id,type:2})
- },
- beginScan(){
- this.clearPolling()
- this.remindText = ''
- this.returnCode = ''
- this.isPaymentProcessing = false
- // #ifdef MP-WEIXIN
- this.toScan()
- // #endif
- // #ifdef APP-PLUS
- let platformType = uni.getSystemInfoSync().platform
- if(platformType == 'android'){
- this.toScan()
- }else if(platformType == 'ios'){
- this.toScan()
- }else{
- this.$msg('系统错误')
- }
- // #endif
- },
- toScan(){
- let that = this
- uni.scanCode({
- onlyFromCamera: true,
- success: function (res) {
- let payCode = res.result
- let newPayCode = payCode.replace(/\s+/g, "")
- if(that.$util.isEmpty(newPayCode)){
- that.$msg('没扫到,请重新扫哦')
- return false
- }
- if(!that.isAllDigits(newPayCode)){
- that.$msg('没扫到,请重新扫')
- return false
- }
- that.requestCodePay(newPayCode)
- }
- })
- },
- isAllDigits(str) {
- return /^\d+$/.test(str)
- },
- requestCodePay(authCode){
- if(this.isPaymentProcessing){
- this.$msg('支付处理中,请稍候')
- return
- }
- let that = this
- this.goPay = 1
- this.isPaymentProcessing = true
- this.remindText = ''
- this.returnCode = ''
- this.clearPolling()
- codePay({id:this.orderId,authCode:authCode}).then(res=>{
- if(res.code == 1){
- if(res.data.returnStatus == 'SUCCESS'){
- that.isPaymentProcessing = false
- setTimeout(function(){
- that.payFinish()
- },1200)
- }else{
- that.remindText = res.msg || '等待支付...'
- that.returnCode = res.data.returnCode ? res.data.returnCode : ''
- that.goPay = 2
-
- // 11105(用户输入密码中) 或 10000(其它密码状态),启动4秒一次、最多3次(12秒)的自动复查定时器
- if (that.returnCode == 'BBS11105' || that.returnCode == 'BBS10000') {
- that.startPolling()
- } else {
- that.isPaymentProcessing = false
- }
- }
- } else {
- that.isPaymentProcessing = false
- that.remindText = res.msg || '支付请求失败'
- that.goPay = 2
- }
- }).catch(err=>{
- // 请求超时或网络断开时,重置支付状态,同时自动运行一轮轮询查询,防万一扣款成功
- that.isPaymentProcessing = false
- that.remindText = '网络异常,正在自动复查支付结果...'
- that.goPay = 2
- that.startPolling()
- })
- },
- /**
- * 启动低频后台付款复查定时器
- * 4秒轮询一次,限查3次,极大地减轻服务器压力的同时保证业务流闭环
- */
- startPolling(){
- this.clearPolling()
- this.pollingCount = 0
- this.isPaymentProcessing = true
- this.goPay = 1 // 显示请求中
- let that = this
- this.pollingTimer = setInterval(() => {
- that.pollingCount++
- if (that.pollingCount > 3) {
- that.clearPolling()
- that.isPaymentProcessing = false
- that.goPay = 2
- that.remindText = '支付确认超时,请确认顾客扣款,并点查询结果'
- return
- }
- that.remindText = `正在自动复查支付结果 (${that.pollingCount}/3)...`
- codePayVerify({id:that.orderId}).then(res=>{
- if(res.code == 1){
- if(res.data && res.data.returnStatus == 'SUCCESS'){
- that.clearPolling()
- that.isPaymentProcessing = false
- setTimeout(function(){
- that.payFinish()
- },1000)
- }
- }
- }).catch(err=>{
- console.error('Code pay check failed', err)
- })
- }, 4000)
- },
- clearPolling(){
- if(this.pollingTimer){
- clearInterval(this.pollingTimer)
- this.pollingTimer = null
- }
- },
- init(){
- },
- payFinish(){
- this.clearPolling()
- this.$util.pageTo({ url: '/admin/billing/result?orderId='+this.orderId,type:2})
- },
- changePayWay(payWay){
- this.payWay = payWay
- let that = this
- if(payWay == 2){
- that.$util.confirmModal({content:'确认挂账?'},() => {
- debtPay({id:this.orderId}).then(res=>{
- if(res.code == 1){
- that.$util.pageTo({ url: '/admin/billing/result?orderId='+this.orderId,type:2})
- }
- })
- })
- }
- },
- checkResult(){
- let that = this
- uni.showLoading({mask:true})
- codePayVerify({ id:this.orderId}).then(res=>{
- uni.hideLoading()
- if(res.code == 1){
- if(res.data && res.data.returnStatus == 'SUCCESS'){
- that.clearPolling()
- that.isPaymentProcessing = false
- this.$msg('付款成功')
- setTimeout(function(){
- that.payFinish()
- },1000)
- }else{
- this.$msg(res.msg || '还没有付款成功')
- }
- } else {
- this.$msg(res.msg || '查询失败')
- }
- }).catch(err => {
- uni.hideLoading()
- this.$msg('网络异常')
- })
- },
- goBack(){
- this.clearPolling()
- uni.navigateBack()
- },
- toCancel(){
- let that = this
- let content = '确认取消?'
- if(this.returnCode == 'BBS11105' || this.returnCode == 'BBS10000'){
- content = '确认取消?'
- }
- // 取消支付时,必须清除定时器和支付占用状态
- that.$util.confirmModal({content:content,cancelText:'返回'},() => {
- that.clearPolling()
- that.isPaymentProcessing = false
- cancelOrder({id:this.orderId}).then(res=>{
- if(res.code == 1){
- that.$msg(res.msg)
- setTimeout(function(){
- uni.navigateBack()
- },1000)
- }
- })
- })
- }
- },
- };
- </script>
- <style lang="scss" scoped>
- .app-content {
- .callback-wrap {
- padding-top: 30upx;
- background-repeat: no-repeat;
- background-size: 100% auto;
- position: relative;
- .bg_01 {
- position: absolute;
- top: 0;
- left: 0;
- /* 手机mobile屏幕小于1000px */
- @media screen and (max-width: 1100px) {
- width: 100vw;
- }
- /* 收银台cashier屏幕大于1000px */
- @media screen and (min-width:1100px) {
- width: 40vw;
- }
- height: 290upx;
- background: #3385ff;
- border-radius: 0upx 0upx 83upx 83upx;
- z-index: 1;
- }
- .callback-blo {
- position: absolute;
- z-index: 9;
- left: 50%;
- transform: translateX(-50%);
- width: 90%;
- margin: 0 auto;
- padding: 70upx 0;
- background-color: #fff;
- box-shadow: 2upx 2upx 16upx 0upx rgba(181, 181, 181, 0.29);
- border-radius: 10upx;
- text-align: center;
- // 使用icon
- .icon {
- .iconfont {
- font-size: 130upx;
- }
- }
- // 一个按钮
- .call-one-btn {
- margin-top:50upx;
- .mobile-scan{
- color:#b3b1b1;
- margin-top:30upx;
- font-size:30upx;
- }
- }
- }
- }
- }
- // 待支付 - 公共
- .awaitPayWx,
- .awaitPayYe {
- .status-text {
- margin-top: 22upx;
- margin-bottom: 52upx;
- color: #ffa92e;
- }
- .surplus {
- margin-top: 22upx;
- margin-bottom: 38upx;
- }
- .icon {
- .iconfont {
- color: #ffa92e;
- }
- }
- }
- .wait {
- color: #ffa92e;
- font-size: 30upx;
- font-weight: 700;
- margin: 20upx 0;
- }
- .balance{
- margin-top:30upx;
- font-size:32upx;
- font-weight: bold;
- }
- </style>
|