uni-pay.uvue 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196
  1. <template>
  2. <view class="uni-pay">
  3. <!-- PC版收银台弹窗开始 -->
  4. <uni-pay-popup v-if="modeCom == 'pc'" ref="payPopup" type="center" :safe-area="false">
  5. <view class="pc-pay-popup">
  6. <view class="pc-pay-popup-title"><text class="text">收银台</text></view>
  7. <view class="pc-pay-popup-flex">
  8. <view class="pc-pay-popup-qrcode-box">
  9. <image class="pc-pay-popup-qrcode-image" :src="orderRes['qr_code_image']"></image>
  10. <view class="pc-pay-popup-amount-box">
  11. <view class="pc-pay-popup-amount-tips">
  12. <text class="text" v-if="orderRes['provider'] == 'wxpay'">微信扫一扫付款</text>
  13. <text class="text" v-else-if="orderRes['provider'] == 'alipay'">支付宝扫一扫付款</text>
  14. <text class="text" v-else>扫一扫付款</text>
  15. </view>
  16. <view class="pc-pay-popup-amount"><text class="text">{{ (totalFeeCom / 100).toFixed(2) }}</text></view>
  17. </view>
  18. <view class="pc-pay-popup-complete-button" v-if="orderRes['qr_code_image']">
  19. <button type="primary" @click="_getOrder()">我已完成支付</button>
  20. </view>
  21. </view>
  22. <view class="pc-pay-popup-provider-list">
  23. <view class="pc-pay-popup-provider-item" v-if="currentProviders.indexOf('wxpay') > -1" :class="myOptions['provider'] == 'wxpay' ? 'active' : ''"
  24. @click="_pcChooseProvider('wxpay')">
  25. <image :src="images['wxpay']" class="pc-pay-popup-provider-image"></image>
  26. <text class="pc-pay-popup-provider-text">微信支付</text>
  27. </view>
  28. <view class="pc-pay-popup-provider-item" v-if="currentProviders.indexOf('alipay') > -1" :class="myOptions['provider'] == 'alipay' ? 'active' : ''"
  29. @click="_pcChooseProvider('alipay')">
  30. <image :src="images['alipay']" class="pc-pay-popup-provider-image"></image>
  31. <text class="pc-pay-popup-provider-text">支付宝支付</text>
  32. </view>
  33. <view class="pc-pay-popup-logo">
  34. <image class="image" :src="logo" mode="widthFix"></image>
  35. </view>
  36. </view>
  37. </view>
  38. </view>
  39. </uni-pay-popup>
  40. <!-- PC版收银台弹窗结束 -->
  41. <!-- 手机版收银台弹窗开始 -->
  42. <uni-pay-popup v-else ref="payPopup" type="bottom" :safe-area="false">
  43. <view class="mobile-pay-popup" :style="'min-height: '+height+';'">
  44. <view class="mobile-pay-popup-title"><text class="text">收银台</text></view>
  45. <view class="mobile-pay-popup-amount-box">
  46. <view><text class="text">待支付金额:</text></view>
  47. <view class="mobile-pay-popup-amount"><text class="text">{{ (totalFeeCom / 100).toFixed(2) }}</text></view>
  48. </view>
  49. <view class="mobile-pay-popup-provider-list">
  50. <view class="uni-list">
  51. <!-- #ifdef MP-WEIXIN || H5 || APP -->
  52. <view class="uni-list-item" v-if="currentProviders.indexOf('wxpay') > -1" @click="createOrderByProvider('wxpay')">
  53. <view class="uni-list-item__container container--right">
  54. <view class="uni-list-item__header">
  55. <image :src="images['wxpay']" class="image"></image>
  56. </view>
  57. <view class="uni-list-item__content uni-list-item__content--center">
  58. <text class="text">微信支付</text>
  59. </view>
  60. </view>
  61. <view class="arrowright"></view>
  62. </view>
  63. <!-- #endif -->
  64. <!-- #ifdef MP-ALIPAY || H5 || APP -->
  65. <view class="uni-list-item" v-if="currentProviders.indexOf('alipay') > -1" @click="createOrderByProvider('alipay')">
  66. <view class="uni-list-item__container container--right">
  67. <view class="uni-list-item__header">
  68. <image :src="images['alipay']" class="image"></image>
  69. </view>
  70. <view class="uni-list-item__content uni-list-item__content--center">
  71. <text class="text">支付宝</text>
  72. </view>
  73. </view>
  74. <view class="arrowright"></view>
  75. </view>
  76. <!-- #endif -->
  77. </view>
  78. </view>
  79. </view>
  80. </uni-pay-popup>
  81. <!-- 手机版收银台弹窗结束 -->
  82. <!-- 二维码支付弹窗开始 -->
  83. <uni-pay-popup ref="qrcodePopup" type="center" :safe-area="false" :animation="false" :mask-click="false" @close="clearQrcode">
  84. <view class="qrcode-popup-content">
  85. <image :src="orderRes['qr_code_image']" class="qrcode-image"></image>
  86. <view class="qrcode-popup-info">
  87. <view class="qrcode-popup-info-fee-box">
  88. <view class="qrcode-popup-info-fee">
  89. <text class="text">{{ (totalFeeCom / 100).toFixed(2) }}</text>
  90. </view>
  91. <view class="qrcode-popup-info-fee-unit">
  92. <text class="text">元</text>
  93. </view>
  94. </view>
  95. <view v-if="myOptions['provider'] == 'wxpay'"><text>请用微信扫码支付</text></view>
  96. <view v-else-if="myOptions['provider'] == 'alipay'"><text>请用支付宝扫码支付</text></view>
  97. </view>
  98. <button type="primary" @click="_getOrder()" class="qrcode-popup-btn-primary">我已完成支付</button>
  99. <view class="qrcode-popup-cancel" @click="closePopup('qrcodePopup')"><text class="qrcode-popup-cancel-text">暂不支付</text></view>
  100. </view>
  101. </uni-pay-popup>
  102. <!-- 二维码支付弹窗结束 -->
  103. <!-- 外部浏览器确认支付弹窗开始 -->
  104. <uni-pay-popup ref="payConfirmPopup" type="center" :safe-area="false" :animation="false" :mask-click="false">
  105. <view class="pay-confirm-popup-content">
  106. <view class="pay-confirm-popup-title"><text>请确认支付是否已完成</text></view>
  107. <view><button type="primary" @click="_getOrder()">已完成支付</button></view>
  108. <view class="pay-confirm-popup-refresh"><button type="default" @click="_afreshPayment()">支付遇到问题,重新支付</button></view>
  109. <view class="pay-confirm-popup-cancel" @click="closePopup('payConfirmPopup')"><text>暂不支付</text></view>
  110. </view>
  111. </uni-pay-popup>
  112. <!-- 外部浏览器确认支付弹窗结束 -->
  113. </view>
  114. </template>
  115. <script>
  116. import { checkPlatform, objectAssign, getWeixinCode, getAlipayCode } from "../../js_sdk/js_sdk"
  117. export default {
  118. name: "uni-pay",
  119. emits: ["success", "cancel", "fail", "create", "mounted", "qrcode"],
  120. props: {
  121. /**
  122. * Banner广告位id
  123. */
  124. adpid: {
  125. type: String,
  126. default: ""
  127. },
  128. /**
  129. * 是否自动跳转到插件内置的支付成功页面(具有看广告功能,可以增加开发者收益)默认true
  130. */
  131. toSuccessPage: {
  132. type: Boolean,
  133. default: true
  134. },
  135. /**
  136. * 支付成功后,点击查看订单按钮时跳转的页面地址
  137. */
  138. returnUrl: {
  139. type: String,
  140. default: ""
  141. },
  142. /**
  143. * 支付结果页主色调,默认支付宝小程序为#108ee9,其他端均为#01be6e
  144. * 建议:绿色系 #01be6e 蓝色系 #108ee9 咖啡色 #816a4e 粉红 #fe4070 橙黄 #ffac0c 橘黄 #ff7100
  145. */
  146. mainColor: {
  147. type: String,
  148. default: ""
  149. },
  150. /**
  151. * 收银台模式
  152. * mobile 手机版
  153. * pc 电脑版
  154. */
  155. mode: {
  156. type: String,
  157. default: ""
  158. },
  159. /**
  160. * PC收银台模式时,展示的logo
  161. */
  162. logo: {
  163. type: String,
  164. default: "/static/logo.png"
  165. },
  166. /**
  167. * 收银台高度(默认70vh)
  168. */
  169. height: {
  170. type: [String],
  171. default: "70vh"
  172. },
  173. /**
  174. * 是否打印运行过程日志
  175. */
  176. debug: {
  177. type: Boolean,
  178. default: false
  179. }
  180. },
  181. data() {
  182. return {
  183. // 支付参数
  184. myOptions: {} as UTSJSONObject,
  185. // 支付云对象返回结果
  186. orderRes: {
  187. order: "",
  188. order_no: "",
  189. out_trade_no: "",
  190. provider: "",
  191. provider_pay_type: "",
  192. errCode: 0,
  193. } as UTSJSONObject,
  194. images: {
  195. wxpay: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAAXNSR0IArs4c6QAABC9JREFUeF7tWk1a20AMlUzv0bDr13AAYAOcpLCBcoqQU1DYEE6C2QAHIP26q3sPPOqniU2cZMYj+SeGxN5kEXlm9ObpjaQxwpY/uOX+Qw9Az4AtR6APgS0nQC+CfQi0FQLfrvcHXwAGPP4bQMK/fy5f7O9HehphwPfb/dOIogEhHQHBcamDCDESPoIxMQPTNSi1ABj+OrwDpNMaO5og4P2bMZOugFADwNTewWhU0/FVzAgnKZnxuoFQAbB3vX9MET7U2PHgq4R09vv8ZRI0bMhADMDw9uAhGN8NLQrWyAYRAGt1PgcRIU5TOms7JIIAdOL8nElJauikTRBKAdi7ObwioFFTzHaMw3mBzRV8DwKOXy+ertpagxcAq/YR/g2d6TlNrUDu4EiiE0Why4T1rgyINoXRC4DgjE+mF8+7RYAkp4RrRyVztRUKTgCkuz89fz4pAiB5z7WbklBrKxScAEgWxI6joZPXy5c4B0H0nkPdhzcHFIxxhHgZ8OA7AgMnAMObA479UnF6H5twQpF5RBMdibPDvB4AAAL6IZ0rNbTb9IngAyC8IwJ0K5okQBgzqFEKSV4wcXg17bxl8fIiJXFc0bHAgYLjYlHEFaZlVUQDoAIbcVZaN1VRrgAgUfImASiKW6Yh4pAohmHVQqpLABI0dMYiKhJPCeoV0ueuQsDmEJrkSeJ/bqNJnOqfApqVzWznzrdYWkvzhnUDYGnPKLTdV5gpfLiOqJUIaTefF8RKH6wxtAOX2IdA8NcCmmRItmBLfVF5jRBnR58kGQtWlGUJlBeAxpQ5A4eFKTu/ufLzPQv1f2mRRDiZ/nyyYwYrypI0OlQOc/9PsgshDsh2v+BUwTFnD3K5DglVlD4WlDZEsqywNgiK2F9gQBkLi7EtyV59WhBsiTURCjy5QZMgYRn9cxbZWgCQ+IKlnH2sFQYTURHmCYMgAJaKs9aYPkXNXGK6QhQdt9xeC4UhTC+eV/wVASASmrKj6IMA4NIBMQDsX1VN4IlbuU0K7vmiQS0G5EOpmiW6I1Dpjtp8pYc5yxYVj0RtXcMJcwDFSiqYLh2x+QgqAJwnAuEEydxbkZtdj+fKPVfwbPIq7KngqvMVX4WoAmDBAcH9HTMmXw23s0LJSlPOOsZx0l8VAu/0Fzjuc2Td3aY5zf1VoZgBvPgmvuhoIrFSMSXQThcDoJo0YLxGLfBSv5IINgVC1XxCOb/oZrkTBtRJqkQgKG6ROgPgPbGq/6HVIiYK51WngAj5ikbBhoZi3FALbHmozhlQXFChTc75g6wRM2ufzb9N/IwMcG0wg8HZJf9HBF/tFZnBBBH+cW/BpBDnd4XLDNJcon4oBiiY7jS194mEI0IaSz+12ygAclSYEcXvFsqA3UgANEzqAdCgtYm2PQM2cVc1PvUM0KC1ibY9AzZxVzU+bT0D/gPs/oxfcUEcJAAAAABJRU5ErkJggg==",
  196. alipay: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAAXNSR0IArs4c6QAAA2FJREFUeF7tmU122jAQx2cMB2hp9yULeK+naHISwhJyiIRDBJaQkwRO0fdgEWff0h4ANH0yFc+m+hhbckKNvJUsaX76z4ckhAv/8MLthwggKuDCCUQXuHABxCAYXSC6wIUTiC7wFgL4MPveTaj9optrO+696ya8yeQRQFRAdIEYAxoVBD/PNtdCwHWpDIJwr+1PMCk1DgAkCSx/jHrLsv/p+lfKAp3HzQOYDAqxKtcYBJPtXe/B1Y3TXgmATGst0WIrgAC7JmBINOQsNN8HE0zfVQFlFxzrgFgHNLQOkNJuQ7vrcgkS1CXEua5fgnDj+l+172CX/h59Tbn9Of0qBUE1cGe2ngPhLWeiEH0krFDBT63HC8Cnx/VtFuFDfgl90UOldDvuX4WcSo7lBSD0YuR4H6ebZwRNkRUw9xdSah1G+IzZmW5IW7ERDX/e9Rc+YwerBEMvQo1nrhfqkf/ZuYCxxK5J/t4AjkFQBi71CXxFoFSWq2XTlkn+AndXodNf5SwgT4J7gnttoNL6BqUEmCZET/tkvzQZYj5g1Sf/0goIkfcJYIkEK5HsFnkYnen6BXQptUb5lwJgMz4zCihXD/BqAwVDuoy+Uqx399kACrkZaYECVjY5qxJZXpoQwrcDHB6UghfVvPssAMo35W4R7oZVg5EMmAJxUCZ2CNzfVJ2Pm6qdleDBNwFClaHZdRrQAEhWe25VSPCuAMo1tnQhdIzMNUixfDYBqAOGVQEKQB15OFMCwXPV3QsFww7g73E39Pudr/Gn0EyplQPXCkBF/5AKsBtPKRA+AdKAEx/0BhYLL9nHFkhZLiBvbkOcxFzG5wPtoe7gBUrrTiMttqO+8ebZCkAtWErs17jHvrrSLcj+lkCpKeV5g/ABIA05lqgVM4Er2nPhZgev7DHGnToLG+ALIC9budgWwoRzyuMUPlzj8waVBuELIFOB5iksi7xIKQh8PS4wu8/j+a3vBScbRAgABVfg5BZbH6SFgP0kVIl7UCjNja4RCkAGwecaPLDhp4yNsSYkADlp/mncdNLLu8fpud9XQK7//wERGoBrAefSfgRBsLI9pTtPg+diUNV1yLuJypVg1Un/p/8arwDXZkQALkJNb48KaPoOu+yLCnARanp7VEDTd9hlX1SAi1DT2/8AaakVXysj5qkAAAAASUVORK5CYII="
  197. } as UTSJSONObject,
  198. originalRroviders: ["wxpay", "alipay"] as Array<string>,
  199. currentProviders: ["wxpay", "alipay"] as Array<string>,
  200. openid: ""
  201. }
  202. },
  203. mounted() {
  204. // #ifdef MP-WEIXIN || MP-ALIPAY
  205. if (this.openid == "") {
  206. new Promise(async (resolve, reject) => {
  207. let code = await this.getCode();
  208. let res = await this.getOpenid({
  209. // #ifdef MP-WEIXIN
  210. provider: "wxpay",
  211. // #endif
  212. // #ifdef MP-ALIPAY
  213. provider: "alipay",
  214. // #endif
  215. code
  216. });
  217. resolve(res);
  218. }).then((res) => {
  219. if (res['openid'] != null) {
  220. this.openid = res['openid'];
  221. }
  222. }).catch((err) => {
  223. reject(err);
  224. })
  225. }
  226. // #endif
  227. // #ifdef MP-WEIXIN
  228. // 如果是微信小程序,则设置只支持微信支付
  229. this.originalRroviders = ["wxpay"];
  230. this.currentProviders = JSON.parse(JSON.stringify(this.originalRroviders));
  231. // #endif
  232. // #ifdef MP-ALIPAY
  233. // 如果是支付宝小程序,则设置只支持支付宝支付
  234. this.originalRroviders = ["alipay"];
  235. this.currentProviders = JSON.parse(JSON.stringify(this.originalRroviders));
  236. // #endif
  237. let insideData = {
  238. images: this.images as UTSJSONObject,
  239. originalRroviders: this.originalRroviders as Array<string>,
  240. currentProviders: this.currentProviders as Array<string>,
  241. } as UTSJSONObject;
  242. this.$emit("mounted", insideData);
  243. },
  244. methods: {
  245. // 发起支付 - 打开支付选项弹窗
  246. async open(options : UTSJSONObject) : Promise<void> {
  247. let provider = options['provider'] as string | null;
  248. if (provider != null && provider != "") {
  249. let providers : Array<string> = [];
  250. this.originalRroviders.map((item : string) => {
  251. if (provider == item) {
  252. providers.push(item);
  253. }
  254. });
  255. this.currentProviders = providers;
  256. options['provider'] = "";
  257. } else {
  258. this.currentProviders = JSON.parse(JSON.stringify(this.originalRroviders)) as Array<string>;
  259. }
  260. this.myOptions = options;
  261. if (this.currentProviders.length == 1) {
  262. this.createOrder({ provider: this.currentProviders[0] });
  263. } else {
  264. if (this.modeCom == "pc") {
  265. this._pcChooseProvider(this.currentProviders[0]);
  266. }
  267. this.openPopup("payPopup");
  268. }
  269. },
  270. createOrderByProvider(provider : string) {
  271. this.createOrder({
  272. provider
  273. })
  274. },
  275. // 创建支付
  276. async createOrder(data : UTSJSONObject) : Promise<void> {
  277. let options = this.myOptions;
  278. options['qr_code'] = false;
  279. options = objectAssign(options, data);
  280. if (options['provider'] == "appleiap") {
  281. // 苹果虚拟支付走特殊逻辑
  282. // #ifdef APP-IOS
  283. return this._appleiapCreateOrder(options);
  284. // #endif
  285. // #ifndef APP-IOS
  286. uni.showModal({
  287. title: "提示",
  288. content: "请在iOS系统中执行",
  289. showCancel: false
  290. })
  291. // #endif
  292. }
  293. // #ifdef APP
  294. if (options['provider'] == "wxpay") {
  295. // #ifdef uniVersion < 4.11
  296. uni.showModal({
  297. title: "提示",
  298. content: "请先升级HBX至4.11",
  299. showCancel: false
  300. })
  301. return;
  302. // #endif
  303. }
  304. // #endif
  305. // #ifdef H5
  306. // 判断如果是pc访问,则强制扫码模式
  307. if (checkPlatform() == "pc") {
  308. options['qr_code'] = true;
  309. }
  310. // #endif
  311. let createOrderData = {
  312. provider: options['provider'],
  313. total_fee: options.getNumber('total_fee'),
  314. order_no: options['order_no'],
  315. out_trade_no: options['out_trade_no'],
  316. description: options['description'],
  317. type: options['type'],
  318. qr_code: options.getBoolean('qr_code'),
  319. custom: options.getJSON('custom'),
  320. other: options.getJSON('other'),
  321. wxpay_virtual: options.getJSON('wxpay_virtual'), // 微信小程序虚拟支付需要
  322. } as UTSJSONObject;
  323. // #ifdef H5
  324. if (options['openid'] != "" && options['provider'] == "wxpay") {
  325. createOrderData['openid'] = options['openid'];
  326. }
  327. // #endif
  328. // #ifdef MP
  329. if (this.openid != "") {
  330. createOrderData['openid'] = this.openid;
  331. }
  332. // #endif
  333. try {
  334. // 引入支付云对象
  335. const uniPayCo = uniCloud.importObject("uni-pay-co");
  336. let res = await uniPayCo.createOrder(createOrderData);
  337. if (res['errCode'] == 0) {
  338. this.$emit("create", res);
  339. if (res['qr_code'] != null && res['qr_code'] == true && options.getBoolean('cancel_popup') != true) {
  340. this.orderRes = res;
  341. // 展示组件内置的二维码弹窗
  342. if (this.modeCom == "pc") {
  343. this.openPopup("payPopup");
  344. this._pcChooseProvider(options['provider'] as string);
  345. } else {
  346. this.openPopup("qrcodePopup");
  347. }
  348. } else {
  349. // 调起支付
  350. this.orderPayment(res);
  351. }
  352. } else {
  353. this.$emit("fail", res);
  354. }
  355. } catch (err) {
  356. this.$emit("fail", {
  357. errCode: -1,
  358. errMsg: (err as Error).message
  359. });
  360. }
  361. },
  362. // 调起支付
  363. orderPayment(res : UTSJSONObject) {
  364. this.orderRes = res;
  365. if (res['qr_code'] != null && res['qr_code'] != "") {
  366. this.$emit("qrcode", res);
  367. }
  368. // #ifdef H5
  369. let order = res.get('order') as UTSJSONObject;
  370. if (res['provider_pay_type'] == "jsapi") {
  371. // 微信公众号支付
  372. (window.WeixinJSBridge as any).invoke("getBrandWCPayRequest", order, (res : any) => {
  373. if (res.err_msg == "get_brand_wcpay_request:ok") {
  374. // 用户支付成功回调
  375. this._getOrder();
  376. } else if (res.err_msg == "get_brand_wcpay_request:cancel") {
  377. // 用户取消支付回调
  378. this.$emit("cancel", res);
  379. } else if (res.err_msg == "get_brand_wcpay_request:fail") {
  380. // 用户支付失败回调
  381. console.error('getBrandWCPayRequest-fail: ', res);
  382. this.$emit("fail", res);
  383. }
  384. });
  385. } else {
  386. // 外部浏览器支付
  387. let codeUrl = order['codeUrl'];
  388. let mwebUrl = order['h5Url'] || order['mwebUrl'] || order['mweb_url'];
  389. setTimeout(() => {
  390. this.openPopup("payConfirmPopup");
  391. window.location.href = codeUrl || mwebUrl;
  392. }, 200);
  393. }
  394. // #endif
  395. // #ifndef H5
  396. let _order = res.get('order');
  397. let orderStr = typeof _order == "string" ? _order as string : JSON.stringify(_order) as string;
  398. console.log('orderStr: ', orderStr)
  399. uni.requestPayment({
  400. provider: res['provider'] as string,
  401. orderInfo: orderStr,
  402. // #ifdef MP-WEIXIN
  403. ..._order,
  404. // #endif
  405. success: (res) => {
  406. console.log("requestPaymentSuccess", JSON.stringify(res))
  407. this._getOrder();
  408. },
  409. fail: (err) => {
  410. console.log("requestPaymentFail", JSON.stringify(err))
  411. let errCode = err.errCode;
  412. let errMsg = err.errMsg;
  413. if (errCode == 700601 || errMsg.indexOf("fail cancel") > -1) {
  414. // 用户取消支付
  415. this.$emit("cancel", {
  416. errCode: errCode,
  417. errMsg: errMsg
  418. });
  419. } else {
  420. // 发起支付失败
  421. console.error("uni.requestPayment:fail", err);
  422. this.$emit("fail", {
  423. errCode: errCode,
  424. errMsg: errMsg
  425. });
  426. }
  427. }
  428. });
  429. // #endif
  430. },
  431. // 打开弹窗
  432. openPopup(name : string) {
  433. let popupRef = this.$refs[name] as UniPayPopupComponentPublicInstance;
  434. popupRef.open();
  435. },
  436. // 关闭弹窗
  437. closePopup(name : string) {
  438. let popupRef = this.$refs[name] as UniPayPopupComponentPublicInstance;
  439. popupRef.close();
  440. },
  441. // 查询订单(查询支付情况)
  442. async getOrder(data : UTSJSONObject) : Promise<UTSJSONObject> {
  443. try {
  444. // 引入支付云对象
  445. const uniPayCo = uniCloud.importObject("uni-pay-co");
  446. let res = await uniPayCo.getOrder(data);
  447. return res;
  448. } catch (err) {
  449. return {
  450. errCode: -1,
  451. errMsg: (err as Error).message
  452. } as UTSJSONObject
  453. }
  454. },
  455. // 发起退款(此接口需要admin角色才可以访问)
  456. async refund(data : UTSJSONObject) : Promise<UTSJSONObject> {
  457. try {
  458. // 引入支付云对象
  459. const uniPayCo = uniCloud.importObject("uni-pay-co");
  460. let res = await uniPayCo.refund(data);
  461. return res;
  462. } catch (err) {
  463. return {
  464. errCode: -1,
  465. errMsg: (err as Error).message
  466. } as UTSJSONObject
  467. }
  468. },
  469. // 查询退款(查询退款情况)
  470. async getRefund(data : UTSJSONObject) : Promise<UTSJSONObject> {
  471. try {
  472. // 引入支付云对象
  473. const uniPayCo = uniCloud.importObject("uni-pay-co");
  474. let res = await uniPayCo.getRefund(data);
  475. return res;
  476. } catch (err) {
  477. return {
  478. errCode: -1,
  479. errMsg: (err as Error).message
  480. } as UTSJSONObject
  481. }
  482. },
  483. // 关闭订单
  484. async closeOrder(data : UTSJSONObject) : Promise<UTSJSONObject> {
  485. try {
  486. // 引入支付云对象
  487. const uniPayCo = uniCloud.importObject("uni-pay-co");
  488. let res = await uniPayCo.closeOrder(data);
  489. return res;
  490. } catch (err) {
  491. return {
  492. errCode: -1,
  493. errMsg: (err as Error).message
  494. } as UTSJSONObject
  495. }
  496. },
  497. // 获取支持的支付供应商
  498. async getPayProviderFromCloud(data : UTSJSONObject) : Promise<UTSJSONObject> {
  499. try {
  500. // 引入支付云对象
  501. const uniPayCo = uniCloud.importObject("uni-pay-co");
  502. let res = await uniPayCo.getPayProviderFromCloud(data);
  503. return res;
  504. } catch (err) {
  505. return {
  506. errCode: -1,
  507. errMsg: (err as Error).message
  508. } as UTSJSONObject
  509. }
  510. },
  511. // 获取支付配置内的appid(主要用于获取获取微信公众号的appid,用以获取code)
  512. async getProviderAppId(data : UTSJSONObject) : Promise<UTSJSONObject> {
  513. try {
  514. // 引入支付云对象
  515. const uniPayCo = uniCloud.importObject("uni-pay-co");
  516. let res = await uniPayCo.getProviderAppId(data);
  517. return res;
  518. } catch (err) {
  519. return {
  520. errCode: -1,
  521. errMsg: (err as Error).message
  522. } as UTSJSONObject
  523. }
  524. },
  525. // 根据code获取openid
  526. async getOpenid(data : UTSJSONObject) : Promise<UTSJSONObject> {
  527. try {
  528. // 引入支付云对象
  529. const uniPayCo = uniCloud.importObject("uni-pay-co");
  530. let res = await uniPayCo.getOpenid(data);
  531. return res;
  532. } catch (err) {
  533. return {
  534. errCode: -1,
  535. errMsg: (err as Error).message
  536. } as UTSJSONObject
  537. }
  538. },
  539. // 验证iosIap苹果内购支付凭据
  540. async verifyReceiptFromAppleiap(data : UTSJSONObject) : Promise<UTSJSONObject> {
  541. try {
  542. // 引入支付云对象
  543. const uniPayCo = uniCloud.importObject("uni-pay-co");
  544. let res = await uniPayCo.verifyReceiptFromAppleiap(data);
  545. return res;
  546. } catch (err) {
  547. return {
  548. errCode: -1,
  549. errMsg: (err as Error).message
  550. } as UTSJSONObject
  551. }
  552. },
  553. // 支付成功后的逻辑
  554. paySuccess(res : UTSJSONObject) {
  555. this.closePopup("payPopup");
  556. this.closePopup("payConfirmPopup");
  557. this.clearQrcode();
  558. let toSuccessPage = this.toSuccessPage as boolean;
  559. if (toSuccessPage) {
  560. // 跳转到支付成功的内置页面
  561. this.pageToSuccess(res);
  562. }
  563. this.$emit("success", res);
  564. },
  565. pageToSuccess(res : UTSJSONObject) {
  566. let out_trade_no = res['out_trade_no'] as string;
  567. let pay_order = res.getJSON('pay_order') as UTSJSONObject;
  568. let order_no = pay_order['order_no'] as string;
  569. //let pay_date = pay_order['pay_date'];
  570. let total_fee = pay_order.getNumber('total_fee');
  571. if (total_fee == null) {
  572. total_fee = 0;
  573. }
  574. let returnUrl = this.returnUrl as string;
  575. let adpid = this.adpid as string;
  576. let mainColor = this.mainColor as string;
  577. if (this.modeCom != "pc") {
  578. uni.navigateTo({
  579. url: `/uni_modules/uni-pay-x/pages/success/success?out_trade_no=${out_trade_no}&order_no=${order_no}&total_fee=${total_fee}&adpid=${adpid}&return_url=${returnUrl}&main_color=${mainColor}`
  580. });
  581. } else {
  582. if (returnUrl != "") {
  583. let url = returnUrl + `?out_trade_no=${out_trade_no}&order_no=${order_no}`;
  584. if (url.indexOf("/") != 0) url = `/${url}`;
  585. uni.navigateTo({
  586. url
  587. });
  588. }
  589. }
  590. },
  591. // 监听 - 关闭二维码弹窗
  592. clearQrcode() {
  593. this.orderRes["codeUrl"] = "";
  594. this.orderRes["qr_code_image"] = "";
  595. },
  596. // 内部函数查询支付状态
  597. async _getOrder() : Promise<void> {
  598. let out_trade_no = this.orderRes["out_trade_no"] as string;
  599. let res = await this.getOrder({
  600. out_trade_no,
  601. await_notify: true
  602. });
  603. if (res['errCode'] == 0) {
  604. let has_paid = res.getBoolean('has_paid');
  605. if (has_paid != null && has_paid == true) {
  606. this.closePopup("qrcodePopup");
  607. this.paySuccess(res);
  608. }
  609. }
  610. },
  611. // 重新发起支付
  612. _afreshPayment() {
  613. this.orderPayment(this.orderRes);
  614. },
  615. // pc版弹窗选择支付方式
  616. _pcChooseProvider(provider : string) {
  617. let _provider : string = this.myOptions["provider"] as string;
  618. if (provider != _provider) {
  619. this.createOrder({ provider: provider })
  620. }
  621. },
  622. // 苹果虚拟支付支付逻辑
  623. async _appleiapCreateOrder(options : UTSJSONObject) : Promise<void>{
  624. // #ifndef APP-IOS
  625. uni.showToast({
  626. title: "请在iOS系统中打开",
  627. icon: "none"
  628. })
  629. // #endif
  630. // #ifdef APP-IOS
  631. const virtualPaymentManager = uni.getVirtualPaymentManager();
  632. if (options.apple_virtual['product_type'] == 'nonconsumable') {
  633. uni.showLoading({
  634. title: "请求中...",
  635. mask: true
  636. })
  637. let purchased = await new Promise((resolve, reject) => {
  638. // 如果是非消耗性产品只能购买一次,需要先判断下
  639. virtualPaymentManager.restoreTransactions({
  640. success: (res) => {
  641. let transactions = res.transactions;
  642. let index = res.transactions.findIndex(transaction => {
  643. return transaction.productId == options.apple_virtual['product_id']
  644. })
  645. resolve(index > -1 ? true : false);
  646. }
  647. });
  648. });
  649. uni.hideLoading()
  650. if (purchased) {
  651. uni.showModal({
  652. title: "提示",
  653. content: "您已购买过此商品,请勿重复购买",
  654. showCancel: false
  655. });
  656. return;
  657. }
  658. }
  659. let createOrderData = {
  660. provider: options.provider,
  661. total_fee: options.total_fee,
  662. order_no: options.order_no,
  663. out_trade_no: options.out_trade_no,
  664. description: options.description,
  665. type: options.type,
  666. apple_virtual: options.apple_virtual,
  667. custom: options.custom,
  668. } as UTSJSONObject;
  669. // 引入支付云对象
  670. const uniPayCo = uniCloud.importObject("uni-pay-co");
  671. let res = await uniPayCo.createOrder(createOrderData);
  672. if (res.errCode == 0) {
  673. this.$emit("create", res);
  674. this.res = res;
  675. uni.showLoading({
  676. title: '支付请求中...'
  677. });
  678. try {
  679. // 请求苹果支付
  680. if (this.debug) console.log("正在请求苹果服务器", res.out_trade_no);
  681. uni.requestVirtualPayment({
  682. apple: {
  683. productId: options.getJSON('apple_virtual')!.getString('product_id')!,
  684. appAccountToken: res.appleiap_account_token,
  685. quantity: options.getJSON('apple_virtual')!.getNumber('buy_quantity')! || 1,
  686. },
  687. success: async (requestPaymentRes) => {
  688. uni.hideLoading()
  689. let transaction = requestPaymentRes?.apple;
  690. if (this.debug) console.log('用户支付成功', transaction);
  691. let transactionIdentifier : string = transaction.transactionIdentifier;
  692. let transactionDate : string = transaction.transactionDate;
  693. let outTradeNo : string = res.out_trade_no;
  694. uni.showLoading({
  695. title: '正在处理支付结果...'
  696. });
  697. // 云端请求苹果服务器验证票据
  698. let verifyRes = await this.verifyReceiptFromAppleiap({
  699. out_trade_no: outTradeNo,
  700. transaction_receipt: transaction.jsonRepresentation,
  701. transaction_identifier: transactionIdentifier
  702. });
  703. if (verifyRes.errCode == 0) {
  704. if (verifyRes.repeat) {
  705. uni.showModal({
  706. title: "提示",
  707. content: `当前道具只能购买一次`,
  708. showCancel: false,
  709. confirmText: "好的"
  710. });
  711. } else {
  712. //经过开发者server验证成功后请结束该交易
  713. virtualPaymentManager.finishTransaction({
  714. transaction: transaction,
  715. success: (r) => {
  716. if (this.debug) console.log("关单成功, 该productId= " + transaction.productId)
  717. },
  718. fail: (e) => {
  719. if (this.debug) console.log("关单失败, 该productId= " + transaction.roductId)
  720. }
  721. });
  722. uni.hideLoading();
  723. this.paySuccess(verifyRes);
  724. }
  725. } else {
  726. if (this.debug) console.log('verifyRes: ', verifyRes)
  727. }
  728. },
  729. fail: (err) => {
  730. uni.hideLoading();
  731. if (this.debug) console.log("购买失败:errSubject= " + err.errSubject + ", errCode= " + err.errCode + ", errMsg= " + err.errMsg);
  732. if ([700601].indexOf(err.errCode) > -1 || err.errMsg.indexOf("cancel") > -1) {
  733. this.$emit("cancel", err);
  734. } else {
  735. this.$emit("fail", {
  736. errCode: err.errCode,
  737. errMsg: err.errMsg
  738. });
  739. }
  740. }
  741. });
  742. } catch (err) {
  743. let code = err.errCode || err.code;
  744. if (code == 2) {
  745. // 用户取消支付
  746. if (this.debug) console.log("用户取消支付");
  747. this.$emit("cancel", err);
  748. } else {
  749. // 发起支付失败
  750. console.error("appleiapCreateOrder:fail", err);
  751. this.$emit("fail", {
  752. errCode: code,
  753. errMsg: err.errMsg || err.message
  754. });
  755. }
  756. uni.hideLoading();
  757. }
  758. }
  759. // #endif
  760. },
  761. // 苹果虚拟支付未完成订单检测
  762. appleiapRestore() {
  763. // #ifdef APP-IOS
  764. uni.showLoading({
  765. title: "",
  766. mask: true
  767. });
  768. try {
  769. const virtualPaymentManager = uni.getVirtualPaymentManager();
  770. virtualPaymentManager.getUnfinishedTransactions({
  771. success: async (res) => {
  772. uni.hideLoading()
  773. console.log("获取未结束的订单列表个数:" + res.transactions.length)
  774. res.transactions.forEach(async transaction => {
  775. console.log("getUnfinishedTransactions成功的交易productId= " + transaction.productId);
  776. let appAccountToken : string = transaction.appAccountToken;
  777. let transactionIdentifier : string = transaction.transactionIdentifier;
  778. //let originalTransactionIdentifier : string = transaction.originalTransactionIdentifier;
  779. let transactionDate : string = transaction.transactionDate;
  780. // 云端请求苹果服务器验证票据
  781. let verifyRes = await this.verifyReceiptFromAppleiap({
  782. appleiap_account_token: appAccountToken,
  783. transaction_receipt: transaction.jsonRepresentation,
  784. transaction_identifier: transactionIdentifier,
  785. });
  786. if (verifyRes.errCode == 0 || !appAccountToken) {
  787. // 经过开发者server验证成功后请结束该交易
  788. virtualPaymentManager.finishTransaction({
  789. transaction: transaction,
  790. success: (r) => {
  791. if (this.debug) console.log("关单成功, 该productId= " + transaction.productId)
  792. },
  793. fail: (e) => {
  794. if (this.debug) console.log("关单失败, 该productId= " + transaction.productId)
  795. }
  796. });
  797. uni.hideLoading();
  798. // 如果是自动续期,则不跳页面
  799. if (!verifyRes.is_subscribe && verifyRes.pay_order) {
  800. this.paySuccess(verifyRes);
  801. }
  802. } else {
  803. if (this.debug) console.log('verifyRes: ', verifyRes)
  804. }
  805. })
  806. },
  807. fail: (e) => {
  808. uni.hideLoading()
  809. console.log("获取未结束的订单列表失败:errSubject= " + e.errSubject + ", errCode= " + e.errCode + ", errMsg= " + e.errMsg)
  810. uni.showToast({
  811. title: "获取未结束的订单列表失败:errCode= " + e.errCode,
  812. icon: 'error'
  813. });
  814. }
  815. })
  816. } catch(err){
  817. console.error('err: ', err)
  818. uni.hideLoading()
  819. }
  820. // #endif
  821. },
  822. // #ifdef MP-WEIXIN || MP-ALIPAY
  823. // 获取code
  824. async getCode() : Promise<string>{
  825. // #ifdef MP-WEIXIN
  826. return getWeixinCode();
  827. // #endif
  828. // #ifdef MP-ALIPAY
  829. return getAlipayCode();
  830. // #endif
  831. },
  832. // #endif
  833. },
  834. watch: {
  835. },
  836. computed: {
  837. modeCom() : string {
  838. let mode = this.mode as string;
  839. if (mode != "") return mode;
  840. let systemInfo = uni.getDeviceInfo();
  841. return systemInfo.deviceType == "pc" ? "pc" : "mobile";
  842. },
  843. totalFeeCom() : number {
  844. let totalFee = this.myOptions.getNumber('total_fee');
  845. return totalFee != null ? totalFee : 0;
  846. }
  847. },
  848. }
  849. </script>
  850. <style lang="scss" scoped>
  851. $bgcolor: #f3f3f3;
  852. .uni-pay {}
  853. /* 手机版收银台弹窗开始 */
  854. .mobile-pay-popup {
  855. width: 100%;
  856. min-height: 450px;
  857. background-color: $bgcolor;
  858. border-radius: 15px 15px 0 0;
  859. overflow: hidden;
  860. .mobile-pay-popup-title {
  861. background-color: #ffffff;
  862. padding: 10px;
  863. .text {
  864. text-align: center;
  865. font-weight: bold;
  866. font-size: 20px;
  867. }
  868. }
  869. .mobile-pay-popup-amount-box {
  870. background-color: #ffffff;
  871. padding: 15px;
  872. .mobile-pay-popup-amount {
  873. margin-top: 10px;
  874. .text {
  875. color: #e43d33;
  876. font-size: 30px;
  877. }
  878. }
  879. }
  880. .mobile-pay-popup-provider-list {
  881. background-color: #ffffff;
  882. margin-top: 10px;
  883. .uni-list {
  884. display: flex;
  885. background-color: #fff;
  886. position: relative;
  887. flex-direction: column;
  888. .uni-list-item {
  889. display: flex;
  890. position: relative;
  891. justify-content: space-between;
  892. align-items: center;
  893. background-color: #fff;
  894. flex-direction: row;
  895. border-bottom: 1px solid #f8f8f8;
  896. /* #ifdef H5 */
  897. cursor: pointer;
  898. /* #endif */
  899. &:hover {
  900. background-color: #f1f1f1;
  901. }
  902. .uni-list-item__container {
  903. position: relative;
  904. display: flex;
  905. flex-direction: row;
  906. padding: 12px 15px;
  907. padding-left: 15px;
  908. flex: 1;
  909. overflow: hidden;
  910. .uni-list-item__header {
  911. display: flex;
  912. flex-direction: row;
  913. align-items: center;
  914. .image {
  915. width: 26px;
  916. height: 26px;
  917. margin-right: 9px;
  918. }
  919. }
  920. }
  921. .container--right {
  922. padding-right: 0;
  923. }
  924. .uni-list-item__content {
  925. display: flex;
  926. padding-right: 8px;
  927. flex: 1;
  928. flex-direction: column;
  929. justify-content: space-between;
  930. overflow: hidden;
  931. .text {
  932. color: #3b4144;
  933. font-size: 14px;
  934. }
  935. }
  936. .uni-list-item__content--center {
  937. justify-content: center;
  938. }
  939. .arrowright {
  940. border-top: 1px solid #bbbbbb;
  941. border-right: 1px solid #bbbbbb;
  942. width: 8px;
  943. height: 8px;
  944. margin-right: 15px;
  945. transform: rotate(45deg);
  946. }
  947. }
  948. }
  949. }
  950. }
  951. /* 手机版收银台弹窗结束 */
  952. /* PC版收银台弹窗开始 */
  953. .pc-pay-popup {
  954. width: 800px;
  955. height: 600px;
  956. background-color: $bgcolor;
  957. border-radius: 10px;
  958. overflow: hidden;
  959. .pc-pay-popup-title {
  960. background-color: #ffffff;
  961. height: 66px;
  962. .text {
  963. text-align: center;
  964. font-weight: bold;
  965. font-size: 20px;
  966. line-height: 66px;
  967. }
  968. }
  969. .pc-pay-popup-flex {
  970. width: 100%;
  971. display: flex;
  972. flex-direction: row;
  973. .pc-pay-popup-qrcode-box {
  974. height: 534px;
  975. flex: 1;
  976. background-color: #ffffff;
  977. display: flex;
  978. flex-direction: row;
  979. flex-direction: column;
  980. justify-content: center;
  981. align-items: center;
  982. .pc-pay-popup-qrcode-image {
  983. width: 225px;
  984. height: 225px;
  985. }
  986. .pc-pay-popup-amount-box {
  987. .pc-pay-popup-amount-tips {
  988. margin-top: 20px;
  989. .text {
  990. text-align: center;
  991. color: #333;
  992. font-size: 20px;
  993. }
  994. }
  995. .pc-pay-popup-amount {
  996. margin-top: 20px;
  997. .text {
  998. text-align: center;
  999. color: #dd524d;
  1000. font-weight: bold;
  1001. font-size: 32px;
  1002. }
  1003. }
  1004. }
  1005. .pc-pay-popup-complete-button {
  1006. margin-top: 20px;
  1007. }
  1008. }
  1009. .pc-pay-popup-provider-list {
  1010. width: 300px;
  1011. display: flex;
  1012. flex-direction: column;
  1013. .pc-pay-popup-provider-item {
  1014. padding: 20px;
  1015. display: flex;
  1016. flex-direction: row;
  1017. align-items: center;
  1018. .pc-pay-popup-provider-image {
  1019. width: 60px;
  1020. height: 60px;
  1021. }
  1022. .pc-pay-popup-provider-text {
  1023. color: #333;
  1024. font-size: 20px;
  1025. margin-left: 10px;
  1026. }
  1027. }
  1028. .pc-pay-popup-provider-item.active {
  1029. background-color: #ffffff;
  1030. }
  1031. .pc-pay-popup-provider-item:hover {
  1032. background-color: #ffffff;
  1033. /* #ifdef H5 */
  1034. cursor: pointer;
  1035. /* #endif */
  1036. }
  1037. .pc-pay-popup-logo {
  1038. flex: 1;
  1039. display: flex;
  1040. flex-direction: row;
  1041. align-items: center;
  1042. justify-content: center;
  1043. .image {
  1044. width: 120px;
  1045. }
  1046. }
  1047. }
  1048. }
  1049. }
  1050. /* PC版收银台弹窗结束 */
  1051. /* 二维码支付弹窗开始 */
  1052. .qrcode-popup-content {
  1053. width: 300px;
  1054. background-color: #ffffff;
  1055. border-radius: 5px;
  1056. padding: 20px;
  1057. box-sizing: border-box;
  1058. text-align: center;
  1059. display: flex;
  1060. flex-direction: column;
  1061. align-items: center;
  1062. justify-content: center;
  1063. .qrcode-image {
  1064. width: 225px;
  1065. height: 225px;
  1066. }
  1067. .qrcode-popup-info {
  1068. padding: 10px;
  1069. display: flex;
  1070. flex-direction: column;
  1071. align-items: center;
  1072. .qrcode-popup-info-fee-box {
  1073. display: flex;
  1074. flex-direction: row;
  1075. margin-bottom: 3px;
  1076. .qrcode-popup-info-fee {
  1077. .text {
  1078. color: red;
  1079. font-size: 30px;
  1080. font-weight: bold;
  1081. text-align: center;
  1082. }
  1083. }
  1084. .qrcode-popup-info-fee-unit {
  1085. display: flex;
  1086. flex-direction: row;
  1087. align-items: flex-end;
  1088. padding-bottom: 5px;
  1089. }
  1090. }
  1091. }
  1092. .qrcode-popup-btn-primary {
  1093. width: 260px;
  1094. }
  1095. .qrcode-popup-cancel {
  1096. margin-top: 10px;
  1097. width: 260px;
  1098. .qrcode-popup-cancel-text {
  1099. text-align: center;
  1100. }
  1101. }
  1102. }
  1103. /* 二维码支付弹窗结束 */
  1104. /* 外部浏览器H5支付弹窗确认开始 */
  1105. .pay-confirm-popup-content {
  1106. width: 275px;
  1107. background-color: #ffffff;
  1108. border-radius: 5px;
  1109. padding: 20px;
  1110. .pay-confirm-popup-title {
  1111. text-align: center;
  1112. padding: 10px 0;
  1113. margin-bottom: 15px;
  1114. }
  1115. .pay-confirm-popup-refresh {
  1116. margin-top: 10px;
  1117. }
  1118. .pay-confirm-popup-cancel {
  1119. margin-top: 10px;
  1120. text-align: center;
  1121. }
  1122. }
  1123. /* 外部浏览器H5支付弹窗确认结束 */
  1124. </style>