privilege.nvue 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838
  1. <template>
  2. <view class="page" @click.stop catchtouchmove="true" :style="{'height':privilegeBoxHei+'px'}" >
  3. <view class="privilegeBox es es-ver es-br-38 es-pt-10 es-pb-30 ">
  4. <view class="es es-fx es-pc es-h-56 es-ml-30 es-mr-30 es-mt-10">
  5. <image class="es-w-74 es-h-40" style="position: absolute;left:55px;top:20rpx" src="/static/image/course/xiangyun.png"></image>
  6. <text class="es-fs-32 es-h-56 es-fw-500 prititle">
  7. {{(!isIos || (isIos&&showIOSPay==1)) ? '开通VIP专享以下特权':'芳华币兑换享以下特权'}}</text>
  8. <image class="es-w-74 es-h-40" style="position: absolute;right:55px;top:20rpx" src="/static/image/course/xiangyun2.png"></image>
  9. <image class="es-w-40 es-h-40" style="position: absolute;right:0;top:0" @tap="closePopup" src="/static/images/close40.png"></image>
  10. </view>
  11. <view class="sec1 es-mt-20 es-ml-48 es-mr-48 ">
  12. <view class="es x-bc es-pl-28 es-pt-12 fl-row" >
  13. <view class="l1">
  14. <view class="x-f fl-row">
  15. <image class="es-w-44 es-h-44" src="/static/image/course/privilege/fozhu.png"></image>
  16. <text class="es-ml-8 es-c-white es-fs-32 es-fw-600">名家讲堂</text>
  17. </view>
  18. <text class="es-fs-30 es-mt-10 es-c-99">{{(!isIos || (isIos&&showIOSPay==1)) ?"畅享10000+VIP视频":"畅享10000+视频"}}</text>
  19. </view>
  20. <view class="es">
  21. <image src="/static/image/course/zyx.png" class="es-w-183 es-h-98 es-br-15"></image>
  22. </view>
  23. </view>
  24. </view>
  25. <view class="sec2 es es-fx es-pc es-h-40 es-mt-40 es-ml-48 es-mr-48 fl-row">
  26. <text class="es-fs-30 es-h-56 es-fw-bold" style="color: #FFDAA3;">超多权益待你开启</text>
  27. </view>
  28. <!-- AI舌诊 -->
  29. <view class="primenu-box es es-fx es-pc es-mb-20 es-ml-48 es-mr-48 fl-row" >
  30. <view class="content-inner fl-row">
  31. <view class="item">
  32. <image class="img" src="/static/image/course/privilege/she.png" mode="heightFix"></image>
  33. <text class="label">AI舌诊</text>
  34. </view>
  35. <view class="item">
  36. <image class="img" src="/static/image/course/privilege/tizhi.png" mode="heightFix"></image>
  37. <text class="label">体质检测</text>
  38. </view>
  39. <view class="item" >
  40. <image class="img" src="/static/image/course/privilege/baike.png" mode="heightFix"></image>
  41. <text class="label">养生百科</text>
  42. </view>
  43. <view class="item">
  44. <image class="img" src="/static/image/course/privilege/yishu.png" mode="heightFix"></image>
  45. <text class="label">经典医书</text>
  46. </view>
  47. <view class="item">
  48. <image class="img" src="/static/image/course/privilege/more.png" mode="heightFix"></image>
  49. <text class="label">多设备登陆</text>
  50. </view>
  51. <view class="item">
  52. <image class="img" src="/static/image/course/privilege/ad.png" mode="heightFix"></image>
  53. <text class="label">去除广告</text>
  54. </view>
  55. </view>
  56. </view>
  57. <!-- 开通会员 -->
  58. <view v-if="!isIos || (isIos&&showIOSPay==1)" class="vipMethodBox es-ml-30 es-mr-30 es-mt-10 es-pt-10 es-pb-10 es-br-5">
  59. <view v-for="(item, index) in vipMethods" :key="index" @tap="changeVipMethod(index)" class="vipMethodItem es x-bc fl-row">
  60. <view class="x-bc es-ml-14 ">
  61. <text class="es-fs-32 es-fw-500 es-ml-14 color1" :class="index==1?'es-fw-bold color2':''">{{item}}</text>
  62. </view>
  63. <view class="es-w-40 es-h-40 es-mr-14 es-mr-26 circular" v-if="index==1&&vipMethodIdx!=index"></view>
  64. <image class="es-w-40 es-h-40 es-br-ban es-mr-14 es-mr-26" v-else :src="vipMethodIdx==index?'/static/image/course/vipBuy/check.png':'/static/image/course/vipBuy/check_mr.png'"></image>
  65. </view>
  66. </view>
  67. <view v-else class="vipMethodBox es-ml-48 es-mr-48 es-mt-10 es-pt-10 es-pb-10 es-br-5">
  68. <view @tap="changeVipMethod(1)" class="vipMethodItem es x-bc fl-row">
  69. <view class="x-bc es-ml-14 ">
  70. <text class="es-fs-32 es-fw-500 es-ml-14 es-fw-bold color2">{{vipMethods[vipMethodIdx]}}</text>
  71. </view>
  72. <image class="es-w-40 es-h-40 es-br-ban es-mr-14 es-mr-26" src="/static/image/course/vipBuy/check.png"></image>
  73. </view>
  74. </view>
  75. <!-- 支付方式 -->
  76. <view v-if="isShowPayType&&!isIos" class="payTypeBox es-ml-20 es-mr-10 es-mt-40 x-bc fl-row" >
  77. <view v-for="(item, index) in payTypes" :key="index" @tap="changePayType(index)" class="payTypeItem es x-c " :class="pickPayIndex==index?'pt_ac':''">
  78. <view class="x-bc es-ml-6">
  79. <image class="es-w-40 es-h-33" :src="index<=1?'/static/image/course/vipBuy/wx.png':'/static/image/course/vipBuy/zfb.png'"></image>
  80. <text class="es-fs-29 es-c-white es-ml-8">{{item}}</text>
  81. </view>
  82. <!-- <image v-if="pickPayIndex==index" src="/static/image/course/vipBuy/check.png" class="es-w-24 es-h-24 es-br-ban es-mr-14"></image>
  83. <text v-else class="es-w-24 es-h-24 es-br-ban es-mr-14 circle"></text> -->
  84. </view>
  85. </view>
  86. <view class="es es-mt-30 es-ml-48 es-mr-48 x-c fl-row">
  87. <view @tap="doBuy()" class="es-h-94 x-c vipCourseBtn vipAc es-br-46" style="width: 310rpx;">
  88. <text class="es-fw-700 es-fs-34" style="color: #1B1F22;">{{(!isIos || (isIos&&showIOSPay==1)) ?"立即购买":"立即兑换"}}</text>
  89. </view>
  90. </view>
  91. </view>
  92. </view>
  93. </template>
  94. <script>
  95. import { getIOSPayStatus } from '@/api/common.js';
  96. import { createCourseOrder,createIntegralOrder,createVipOrder,aliPayment,wxPayment,appleCoursePayment,setIapCertificate } from '@/api/course'
  97. import { showLoginPage } from '@/utils/login'
  98. export default {
  99. data() {
  100. return {
  101. vipSelIndex:0,
  102. vipMethods:["开通会员","芳华币兑换","0.01元购买"],
  103. vipMethodIdx:1,
  104. isShowPayType:false,
  105. payTypes:["微信支付","微信支付备用","支付宝支付"],
  106. payType:1,//微信支付1 微信支付备用2 支付宝支付3
  107. createType:2,//1直接购买,2芳华币兑换 3开通会员
  108. courseId:null,
  109. videoId:null,
  110. orderId:null,
  111. order:null,
  112. subNVue:null,
  113. sellPrice:0,
  114. privilegeBoxHei:0,
  115. catalogIndex:-1,
  116. integral: 0, // 芳华币
  117. isIos: false,
  118. showIOSPay: 0,
  119. isCanPay: true,
  120. iapChannel: null,
  121. restoreFlag: false,
  122. user: {},
  123. tzCashier:null,
  124. pickPayIndex:0
  125. }
  126. },
  127. mounted() {
  128. let that=this;
  129. this.user = uni.getStorageSync("userInfo")&&JSON.stringify(uni.getStorageSync("userInfo"))!='{}' ? JSON.parse(uni.getStorageSync("userInfo")) : {}
  130. this.subNVue= uni.getSubNVueById('privilege');
  131. uni.$on('privilege', (data) => {
  132. that.videoId=data.videoId;
  133. that.courseId=data.courseId;
  134. that.sellPrice=data.sellPrice;
  135. that.catalogIndex=data.catalogIndex;
  136. that.vipMethods=["开通会员", data.integral + "芳华币兑换", data.sellPrice+"元购买"];
  137. this.isIos = (plus.os.name == "iOS")
  138. // if(this.isIos) {
  139. // this.getIOSPayStatusFun()
  140. // }
  141. });
  142. this.tzCashier=uni.requireNativePlugin("TZBank-Cashier");
  143. uni.$on('closePrivilege', () => {
  144. that.closePopup();
  145. });
  146. const res = uni.getSystemInfoSync();
  147. this.privilegeBoxHei=uni.upx2px(1150);
  148. //let tempHei=res.windowHeight*0.65;
  149. console.log("privilege=====mounted====")
  150. this.restoreComplateRequest()
  151. },
  152. methods: {
  153. getIOSPayStatusFun() {
  154. getIOSPayStatus().then(res=>{
  155. if(res.code == 200) {
  156. this.showIOSPay = res.iosPayStatus
  157. }
  158. })
  159. },
  160. changeVip(index){
  161. this.vipSelIndex=index;
  162. if(index==2){
  163. this.showPopPrivilege();
  164. }
  165. },
  166. changeVipMethod(index){
  167. this.vipMethodIdx=index;
  168. const vipMethod=this.vipMethods[index];
  169. this.isShowPayType=false;
  170. if(vipMethod.indexOf('元购买')!=-1){ //直接购买
  171. this.isShowPayType=true;
  172. this.createType=1;
  173. //this.changeFrame(true);
  174. }
  175. if(vipMethod.indexOf('芳华币兑换')!=-1){ //芳华币兑换
  176. this.createType=2;
  177. //this.changeFrame(false);
  178. }
  179. if(vipMethod.indexOf('开通会员')!=-1){ //开通会员
  180. this.createType=3;
  181. //this.changeFrame(false);
  182. }
  183. },
  184. changePayType(index){
  185. this.pickPayIndex=index;
  186. if(index<=1){
  187. this.payType=1;
  188. }else{
  189. this.payType=2;
  190. }
  191. },
  192. doBuy(){
  193. if(this.createType==1){ //直接购买
  194. this.createCourseOrder();
  195. }
  196. else if(this.createType==2){ //芳华币兑换
  197. this.createIntegralOrder();
  198. }
  199. else{ //开通会员
  200. uni.navigateTo({url: './vipBuy' });
  201. setTimeout(e => {
  202. this.subNVue.hide();
  203. }, 500)
  204. }
  205. },
  206. createCourseOrder(){
  207. if(!this.isLogin()){
  208. uni.showToast({title:"请先登录",icon: 'none'});
  209. return;
  210. }
  211. // 苹果支付
  212. // if(this.isIos&&this.showIOSPay != 1) {
  213. // uni.showToast({
  214. // title: '请开通苹果支付',
  215. // icon: 'none'
  216. // });
  217. // return
  218. // }
  219. // if(this.isIos&&this.showIOSPay==1) {
  220. // this.payType = 2
  221. // }
  222. uni.showLoading({title:""});
  223. let payType=this.payType<=1?1:this.payType;
  224. let params={"courseId":this.courseId,"createType":this.createType,"videoId":this.videoId,"payType":this.payType};
  225. createCourseOrder(params).then(res => {
  226. uni.hideLoading();
  227. if(res.code==200){
  228. this.order=res.order;
  229. if(this.pickPayIndex==0){ //微信支付
  230. this.doWxPay();
  231. }
  232. else if(this.pickPayIndex==1){ //微信支付备用
  233. this.doWxPay1();
  234. }
  235. // else if (this.payType == 2) { //苹果
  236. // this.doApplePay()
  237. // }
  238. else{ //支付宝
  239. this.doAlipay();
  240. }
  241. }else{
  242. uni.showToast({title: res.msg,icon: 'error'});
  243. }
  244. },
  245. rej => {}
  246. );
  247. },
  248. createIntegralOrder(){
  249. if(!this.isLogin()){
  250. uni.showToast({title:"请先登录",icon: 'none'});
  251. return;
  252. }
  253. uni.showLoading({title:""});
  254. let params={"courseId":this.courseId,"videoId":this.videoId};
  255. createIntegralOrder(params).then(res => {
  256. uni.hideLoading();
  257. if(res.code==200){
  258. uni.showToast({title: "兑换成功",icon: 'success'});
  259. uni.$emit("refreshCatalog",this.catalogIndex);
  260. this.closePopup();
  261. }else{
  262. uni.showToast({title: res.msg,icon: 'error'});
  263. }
  264. },
  265. rej => {}
  266. );
  267. },
  268. doAlipay(){
  269. let that=this;
  270. var data = {orderId:this.order.orderId};
  271. // #ifdef APP-PLUS
  272. uni.showLoading();
  273. aliPayment(data).then(res => {
  274. uni.hideLoading();
  275. //that.$refs.popTip.open();
  276. if(res.code==200){
  277. if(res.type=="tz"){
  278. //console.log("qxj res:"+JSON.stringify(res));
  279. //console.log("qxj orderFlowNo:"+res.data.body.orderFlowNo+" businessCstNo:"+res.data.body.orderNo+" platMerCstNo:"+res.data.body.platMerCstNo);
  280. that.closePopup();
  281. const match = res.data.body.url.match(/[\?&]businessCstNo=([^&]+)/);
  282. const businessCstNo = match ? match[1] : null;
  283. console.log("qxj tzCashier:"+this.tzCashier+" businessCstNo:"+businessCstNo);
  284. this.tzCashier.pay({
  285. env:0,
  286. wxMiniProgramType:0,
  287. wxAppId:'wx703c4bd07bbd1695',
  288. wxUniversalLink:"https://yjf.runtzh.com/",
  289. orderFlowNo:res.data.body.orderFlowNo,
  290. businessCstNo:businessCstNo,
  291. platMerCstNo:res.data.body.platMerCstNo
  292. },(res)=>{
  293. uni.$emit('showPayTips', {"courseOrderId":that.order.orderId});
  294. });
  295. }
  296. else if(res.type=='hf'){
  297. //this.$refs.popTip.open()
  298. if(res.data.qr_code==null){
  299. uni.showToast({title:res.data.bank_message,icon:'none'});
  300. return;
  301. }
  302. this.closePopup();
  303. if (uni.getSystemInfoSync().platform == 'android') {
  304. var alipayScheme ='alipays://platformapi/startApp?&saId=10000007&qrcode=' + res.data.qr_code;
  305. }else{
  306. var alipayScheme ='alipay://platformapi/startApp?&saId=10000007&qrcode=' + res.data.qr_code;
  307. }
  308. // 在uni-app中使用plus.runtime.openURL打开URL
  309. plus.runtime.openURL(alipayScheme, function(error) {
  310. console.log("qxj alipayScheme error:"+error);
  311. if (error) {
  312. uni.showToast({title:error.message,icon:'error' });
  313. }
  314. });
  315. uni.$emit('showPayTips', {"courseOrderId":this.order.orderId});
  316. }
  317. }
  318. else{
  319. uni.showToast({title:res.msg,icon:'none'})
  320. }
  321. },
  322. rej => {}
  323. );
  324. // #endif
  325. },
  326. doWxPay(){
  327. var that=this;
  328. setTimeout(()=>{
  329. this.closePopup();
  330. },5000);
  331. var data = {orderId:this.order.orderId};
  332. uni.showLoading();
  333. plus.share.getServices(function(res){
  334. var sweixin = null;
  335. for(var i=0;i<res.length;i++){
  336. var t = res[i];
  337. if(t.id == 'weixin'){
  338. sweixin = t;
  339. }
  340. }
  341. if(sweixin){
  342. console.log('调起小程序');
  343. uni.$emit('showPayTips', { "courseOrderId":that.order.orderId });
  344. //唤起微信跳转小程序
  345. sweixin.launchMiniProgram({
  346. id:"gh_feb7753a310b",//gh_7a6a32e5ef61 御君方互医
  347. path:'/pages_order/courseOrderPayment?orderId='+that.order.orderId+"&payMethod=app",
  348. type:0 // 微信小程序版本类型,可取值: 0-正式版; 1-测试版; 2-体验版。 默认值为0。
  349. },function(){
  350. console.log("微信唤起成功");
  351. return true;
  352. },function(e){
  353. console.log("微信唤起失败",e);
  354. uni.showToast({
  355. title:'微信唤起失败,请检查是否有微信应用',
  356. icon:'none'
  357. });
  358. return false;
  359. });
  360. }else{
  361. uni.showToast({
  362. title:'微信唤起失败,请检查是否安装微信应用',
  363. icon:'none',
  364. duration:3000
  365. })
  366. return false;
  367. }
  368. },function(res){
  369. console.log(JSON.stringify(res));
  370. });
  371. },
  372. doWxPay1(){
  373. var that=this;
  374. // setTimeout(()=>{
  375. // this.closePopup();
  376. // },5000);
  377. var data = {orderId:this.order.orderId};
  378. uni.showLoading();
  379. wxPayment(data).then(res => {
  380. console.log("qxj wxPayment",res);
  381. uni.hideLoading();
  382. //that.$refs.popTip.open();
  383. if(res.code==200){
  384. if(res.type=="tz"){
  385. console.log("qxj body",res.data.body);
  386. let businessCstNo=that.user.userId;
  387. if(!!res.data.body.url){
  388. const match = res.data.body.url.match(/[\?&]businessCstNo=([^&]+)/);
  389. businessCstNo = match ? match[1] : null;
  390. }
  391. console.log("qxj tzCashier:"+this.tzCashier+" businessCstNo:"+businessCstNo);
  392. this.tzCashier.pay({
  393. env:0,
  394. wxMiniProgramType:0,
  395. wxAppId:"wx703c4bd07bbd1695",
  396. wxUniversalLink:"https://yjf.runtzh.com/",
  397. orderFlowNo:res.data.body.orderFlowNo,
  398. businessCstNo:businessCstNo,
  399. platMerCstNo:res.data.body.platMerCstNo
  400. },(res)=>{
  401. uni.$emit('closePrivilege', {});
  402. that.showPayTips=true;
  403. });
  404. }
  405. else if(res.type=='hf'){
  406. uni.$emit('closePrivilege', {});
  407. that.showPayTips=true;
  408. }
  409. }
  410. else{
  411. uni.showToast({title:res.msg,icon:'none'})
  412. }
  413. },
  414. rej => {}
  415. );
  416. // plus.share.getServices(function(res){
  417. // var sweixin = null;
  418. // for(var i=0;i<res.length;i++){
  419. // var t = res[i];
  420. // if(t.id == 'weixin'){
  421. // sweixin = t;
  422. // }
  423. // }
  424. // if(sweixin){
  425. // console.log('调起小程序');
  426. // uni.$emit('showPayTips', { "courseOrderId":that.order.orderId });
  427. // //唤起微信跳转小程序
  428. // sweixin.launchMiniProgram({
  429. // id:"gh_7a6a32e5ef61",
  430. // path:'/pages_order/courseOrderPayment?orderId='+that.order.orderId+"&payMethod=app",
  431. // type:0 // 微信小程序版本类型,可取值: 0-正式版; 1-测试版; 2-体验版。 默认值为0。
  432. // },function(){
  433. // console.log("微信唤起成功");
  434. // return true;
  435. // },function(e){
  436. // console.log("微信唤起失败",e);
  437. // uni.showToast({
  438. // title:'微信唤起失败,请检查是否有微信应用',
  439. // icon:'none'
  440. // });
  441. // return false;
  442. // });
  443. // }else{
  444. // uni.showToast({
  445. // title:'微信唤起失败,请检查是否安装微信应用',
  446. // icon:'none',
  447. // duration:3000
  448. // })
  449. // return false;
  450. // }
  451. // },function(res){
  452. // console.log(JSON.stringify(res));
  453. // });
  454. },
  455. changeFrame(isCheck){
  456. console.log("qxj changeFrame");
  457. let pHeight=isCheck?1320:1020;
  458. const subNVue = uni.getSubNVueById('privilege');
  459. subNVue.setStyle({
  460. "bottom": "0",
  461. "left": "0",
  462. "width": "100%",
  463. "height" : pHeight+'upx' ,
  464. });
  465. },
  466. closePopup() {
  467. const subNVue = uni.getSubNVueById('privilege');
  468. subNVue.hide('slide-out-bottom');
  469. },
  470. isLogin() {
  471. let obj=uni.getStorageSync("AppToken");
  472. return !!obj;
  473. },
  474. doApplePay(){
  475. console.log(this.order.orderId)
  476. var data = {
  477. orderId: this.order.orderId
  478. };
  479. let that = this;
  480. uni.showLoading({
  481. title: ""
  482. });
  483. appleCoursePayment(data).then(res => {
  484. uni.hideLoading();
  485. console.log("appleCoursePayment===",res)
  486. if (res.code == 200) {
  487. this.checkApplePay(res.payCode)
  488. } else {
  489. uni.showLoading({
  490. title: res.msg,
  491. icon: none
  492. })
  493. }
  494. }).catch(err => {
  495. uni.hideLoading();
  496. })
  497. },
  498. checkApplePay(payCode) {
  499. const that = this
  500. uni.showLoading({
  501. title: '检测支付环境...',
  502. mask: true
  503. })
  504. uni.getProvider({
  505. service: 'payment',
  506. success: (res) => {
  507. let iapChannel = res.providers.find((channel) => channel.id === 'appleiap');
  508. that.iapChannel = iapChannel
  509. if (!iapChannel) {
  510. console.log('Apple IAP channel not found. Check device & configuration.');
  511. uni.hideLoading()
  512. uni.showToast({
  513. title: "不支持苹果支付",
  514. icon: 'none'
  515. })
  516. return;
  517. }
  518. console.log(iapChannel)
  519. // 获取订单信息,必须调用此方法才能进行 iap 支付
  520. iapChannel.requestOrder(['course_001'], function(orderList) {
  521. console.log('requestOrder success666: ', orderList)
  522. that.applePay(payCode)
  523. }, function(e) {
  524. uni.showToast({
  525. title: "获取产品信息失败",
  526. icon: 'none'
  527. })
  528. console.log('requestOrder failed: ' + JSON.stringify(e));
  529. })
  530. },
  531. fail: (err) => {
  532. console.log('Failed to get payment provider:', err);
  533. uni.hideLoading()
  534. uni.showToast({
  535. title: "获取支付通道失败",
  536. icon: 'none'
  537. })
  538. }
  539. });
  540. },
  541. // 请求是否有已完成未关闭的订单
  542. restoreComplateRequest() {
  543. const that = this
  544. if (this.iapChannel) {
  545. this.iapChannel.restoreComplateRequest({
  546. manualFinishTransaction: true, // 3.5.1+ 支持,设置此参数后需要开发者主动关闭订单,参见下面的关闭订单方法 finishTransaction()
  547. username: "USERID_COURSE_"+ that.user.userId
  548. }, function(res) {
  549. // res 格式为数组存放恢复的IAP商品交易信息对象 IAPTransaction,需要将返回的支付凭证传给后端进行二次认证
  550. //如果有并且状态为已支付则请求关闭并回调给后端
  551. console.log("已完成未关闭的订单信息:", res)
  552. if (res.length > 0) {
  553. //轮询关闭订单
  554. res.map(item => {
  555. //如果状态为已完成的状态
  556. if (item.transactionState == '1') {
  557. //后端逻辑,此处省略,通常是完成上报凭证的操作,来完成补单
  558. //请求后端接口上传支付凭证
  559. let data = {
  560. payCode: item.transactionIdentifier,
  561. receipt: item.transactionReceipt,
  562. chooseEnv: false, // 是否选择正式环境
  563. payclassifyId: "course_001",
  564. classify: 'appvip', // appvip,course
  565. }
  566. that.submitMisson(data,item)
  567. } else {
  568. that.finishTransaction(item, that.iapChannel)
  569. }
  570. })
  571. }
  572. });
  573. }
  574. },
  575. // 关闭订单
  576. finishTransaction(transaction, iapChannel) {
  577. console.log("==finishTransaction===")
  578. return new Promise((resolve, reject) => {
  579. this.iapChannel.finishTransaction(transaction, (res) => {
  580. console.log("==fresolve inishTransaction===",res)
  581. resolve(res);
  582. }, (err) => {
  583. console.log("==err inishTransaction===",err)
  584. reject(err);
  585. });
  586. });
  587. },
  588. //苹果支付
  589. applePay(payCode) {
  590. console.log("苹果支付", this.order.orderId,payCode)
  591. let that = this
  592. uni.showLoading({
  593. title: '支付中...',
  594. mask: true
  595. })
  596. // this.restoreFlag = true
  597. console.log("苹果支付=1==")
  598. uni.requestPayment({
  599. provider: 'appleiap',
  600. orderInfo: {
  601. productid: "course_001",
  602. username: 'USERID_COURSE_' + this.user.userId, // 透传参数,一般用于标记订单和用户的关系,向苹果服务器二次验证票据时返回此字段
  603. quantity: 1, // 购买数量,至少大于等于 1
  604. manualFinishTransaction: false,
  605. optimize: true // 设置 optimize: true 解决丢单问题
  606. },
  607. async success(res) {
  608. console.log("苹果支付===", res)
  609. that.restoreFlag = false
  610. // {
  611. // "payment": {
  612. // "productid": "course_001",
  613. // "quantity": "1",
  614. // "username": "ORDERID562"
  615. // },
  616. // "transactionDate": "2025-07-02 18:20:37",
  617. // "transactionIdentifier": "2000000953130653",
  618. // "transactionReceipt": "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",
  619. // "transactionState": "1",
  620. // "errMsg": "requestPayment:ok"
  621. // }
  622. if(res.transactionState == '1'){
  623. //调用后端接口验签
  624. let data = {
  625. payCode: payCode,
  626. receipt: res.transactionReceipt,
  627. chooseEnv: false, // 是否选择正式环境
  628. payclassifyId: "course_001",
  629. classify: 4, // 5:appvip,4,course
  630. }
  631. that.submitMisson(data,res)
  632. }
  633. },
  634. fail(e) {
  635. console.log('调起苹果支付失败:', e)
  636. that.isCanPay = true
  637. uni.showLoading({
  638. title: '支付失败',
  639. icon: "error"
  640. })
  641. },
  642. complete(e) {
  643. console.log('调起苹果支付失败:', e)
  644. that.isCanPay = true
  645. uni.hideLoading()
  646. }
  647. })
  648. },
  649. // 苹果内购二次校验
  650. submitMisson(data,transaction) {
  651. const that = this
  652. uni.showLoading({
  653. title: '正在处理支付结果...',
  654. mask: true
  655. })
  656. setIapCertificate(data).then( async res => {
  657. uni.hideLoading()
  658. console.log("submitMisson===",res)
  659. if (res.code == 200) {
  660. //给支付按钮解锁
  661. that.isCanPay = true
  662. if (res.status == 1 || res.payTime != null) {
  663. // #ifdef APP-PLUS
  664. if (plus.runtime.channel == "baidu") { //获取渠道标识
  665. let bdCmdType = uni.getStorageSync("bdCmdType");
  666. if (bdCmdType != null && parseInt(bdCmdType) <= 2) {
  667. //this.$registerIdCode("orders",2,res.data.payMoney.toString()); //已下单
  668. }
  669. }
  670. // #endif
  671. that.getUserInfo();
  672. await that.iapChannel.finishTransaction(transaction)
  673. uni.showToast({
  674. title: "支付成功",
  675. icon: 'success'
  676. });
  677. } else {
  678. uni.showToast({
  679. title: "支付失败",
  680. icon: 'error'
  681. });
  682. }
  683. }
  684. }).catch(()=>{
  685. uni.hideLoading()
  686. })
  687. }
  688. },
  689. destroyed() {
  690. console.log("qxj privilege destroyed----")
  691. // 注销全局配置监听
  692. uni.$off("privilege");
  693. uni.$off("closePrivilege");
  694. }
  695. }
  696. </script>
  697. <style>
  698. .fl-row{
  699. display: flex;
  700. flex-direction: row;
  701. }
  702. .page{
  703. background-color:#171a1d;
  704. border-radius: 20rpx;
  705. }
  706. .privilegeBox{
  707. box-sizing: border-box;
  708. }
  709. .prititle{
  710. color: #ffdaa3 !important;
  711. text-align: center;
  712. margin-top: 20rpx;
  713. }
  714. .primenu-box {
  715. display: flex;
  716. flex: 1;
  717. justify-content: center;
  718. align-items: center;
  719. }
  720. .content-inner {
  721. display: flex;
  722. flex: 1;
  723. flex-wrap: wrap;
  724. justify-content: space-between;
  725. }
  726. .content-inner .item{
  727. width: 100px;
  728. height: 75px;
  729. display: flex;
  730. flex-direction: column;
  731. align-items: center;
  732. justify-content: center;
  733. margin-top: 26rpx;
  734. }
  735. .content-inner .item .img{
  736. width: 84rpx;
  737. height: 84rpx;
  738. margin-bottom: 8rpx;
  739. }
  740. .content-inner .item .label{
  741. font-size: 32rpx;
  742. color: #83878A;
  743. }
  744. .vipMethodBox{
  745. background:#2a2f32;
  746. display: flex;
  747. flex: 1;
  748. }
  749. .vipMethodItem{
  750. border-radius: 10rpx;
  751. height: 70rpx;
  752. color: #FDD8A1;
  753. }
  754. .payTypeBox{
  755. display: flex;
  756. flex: 1;
  757. }
  758. .payTypeItem{
  759. border:1px solid #fff;
  760. border-radius: 10rpx;
  761. display: flex;
  762. flex: 1;
  763. height: 94rpx;
  764. margin-right: 10rpx;
  765. }
  766. .circle{
  767. border:1px solid #FDD8A1;
  768. }
  769. .pt_ac{
  770. border:1px solid #FDD8A1;
  771. }
  772. .color1{
  773. color: #FFDAA3;
  774. }
  775. .color2 {
  776. color: #fff;
  777. }
  778. .circular {
  779. border-radius: 50%;
  780. border: 1px solid #fff;
  781. }
  782. .slider-box{
  783. flex:1
  784. }
  785. .vipCourseBtn{
  786. background: #1B1F22;
  787. border-radius: 46rpx;
  788. border: 1px solid #FFDAA3;
  789. color: #FFDAA3;
  790. width: calc(33.33333% - 23px);
  791. }
  792. .vipAc{
  793. background: linear-gradient(90deg, #FFE0B2, #F8BA8B);
  794. border-radius: 46rpx;
  795. border: 1px solid #FFDAA3;
  796. color: #1B1F22;
  797. }
  798. </style>