Parcourir la source

fix: 添加支付宝支付相关依赖, 新增支付拦截页面

YuJing il y a 1 mois
Parent
commit
28ac8a5c93

+ 1 - 1
AppScope/app.json5

@@ -1,6 +1,6 @@
 {
   "app": {
-    "bundleName": "com.ytpm.ltlab",
+    "bundleName": "com.ytpm.lxz",
     "vendor": "example",
     "versionCode": 1000000,
     "versionName": "1.0.0",

+ 4 - 3
build-profile.json5

@@ -3,13 +3,14 @@
     "signingConfigs": [
       {
         "name": "default",
+        "type": "HarmonyOS",
         "material": {
           "storeFile": "sign/basic.p12",
-          "storePassword": "000000181F0EECD983295AB4504A961E19D1B5914CB198FA414395A09865788F96EFF93C84981A55",
+          "storePassword": "00000018F5DFAE2EBE2BFFFABAEA8C0AE3C9D1E74F503F1AA0C3AF361B43581EF93759994E4AC6F2",
           "keyAlias": "yt112233",
-          "keyPassword": "0000001871572C6DAC842AAE8EF9A99F0F746307476E0F0ACF919CC12B0F81467CF5B0CCDBF97E2D",
+          "keyPassword": "000000181F2857420755F0B4EBD2EF4B8131723CA154C327BBD402B763507A8C7432F7242F56F24E",
           "signAlg": "SHA256withECDSA",
-          "profile": "sign/聊天恋爱宝调试证书.p7b",
+          "profile": "sign/鹿学长调试证书Debug.p7b",
           "certpath": "sign/调试证书.cer"
         }
       }

+ 1 - 1
commons/basic/Index.ets

@@ -127,7 +127,7 @@ export * from './src/main/ets/components/generalComp/YtDatePicker'
 
 export  * from '@ibestservices/area-data'
 
-
+export * from './src/main/ets/Pay/AliPay'
 
 
 

+ 2 - 1
commons/basic/oh-package.json5

@@ -21,7 +21,8 @@
     "anythink_network_csj": "file:../../libs/anythink_network_csj.har",
     "anythink_network_gdt": "file:../../libs/anythink_network_gdt.har",
     "anythink_network_huawei": "file:../../libs/anythink_network_huawei.har",
-    "@ibestservices/area-data": "^0.0.6"
+    "@ibestservices/area-data": "^0.0.6",
+    "@cashier_alipay/cashiersdk": "^15.8.39"
   },
   "devDependencies": {},
   "dynamicDependencies": {}

+ 3 - 0
commons/basic/src/main/ets/Pay/AbstractPay.ets

@@ -0,0 +1,3 @@
+export abstract class AbstractPay {
+  abstract launchPay(amount: number): void;
+}

+ 41 - 0
commons/basic/src/main/ets/Pay/AliPay.ets

@@ -0,0 +1,41 @@
+import { Pay } from '@cashier_alipay/cashiersdk/src/main/ets/api/Pay';
+import { yTRouter } from '../../../../Index';
+import { OrderInfoUtil } from '../utils/ts/utils/OrderInfoUtil';
+
+
+class AliPay_{
+  private pay: Pay;
+
+  constructor() {
+    this.pay = new Pay();
+    // this.pay.registerApp("9021000141640951")
+  }
+
+  // 拉起支付页面
+  // @parms orderInfo 支付请求参数
+  launchPay(orderInfo: string){
+    this.pay.payWithNav(orderInfo, true, undefined, yTRouter).then((result) => {
+      let message =
+        `resultStatus: ${result.get('resultStatus')} memo: ${result.get('memo')} result: ${result.get('result')}`;
+      console.log(message);
+    }).catch((error: Error) => {
+      console.log(error.message);
+    });
+  }
+
+
+  launchPayDemo(){
+    // OrderInfoUtil.getOrderInfo().then((orderInfo) => {
+    let orderInfo = 'app_id=2015052600090779&biz_content=%7B%22timeout_express%22%3A%2230m%22%2C%22seller_id%22%3A%22%22%2C%22product_code%22%3A%22QUICK_MSECURITY_PAY%22%2C%22total_amount%22%3A%220.02%22%2C%22subject%22%3A%221%22%2C%22body%22%3A%22%E6%88%91%E6%98%AF%E6%B5%8B%E8%AF%95%E6%95%B0%E6%8D%AE%22%2C%22out_trade_no%22%3A%22314VYGIAGG7ZOYY%22%7D&charset=utf-8&method=alipay.trade.app.pay&sign_type=RSA2&timestamp=2016-08-15%2012%3A12%3A15&version=1.0&sign=MsbylYkCzlfYLy9PeRwUUIg9nZPeN9SfXPNavUCroGKR5Kqvx0nEnd3eRmKxJuthNUx4ERCXe552EV9PfwexqW%2B1wbKOdYtDIb4%2B7PL3Pc94RZL0zKaWcaY3tSL89%2FuAVUsQuFqEJdhIukuKygrXucvejOUgTCfoUdwTi7z%2BZzQ%3D'
+      this.pay.payWithNav(orderInfo, true, undefined, yTRouter).then((result) => {
+        let message =
+          `resultStatus: ${result.get('resultStatus')} memo: ${result.get('memo')} result: ${result.get('result')}`;
+        console.log(message);
+      }).catch((error: Error) => {
+        console.log(error.message);
+      });
+    // })
+  }
+}
+
+export const AliPay = new AliPay_();

+ 79 - 0
commons/basic/src/main/ets/utils/ts/utils/OrderInfoUtil.ets

@@ -0,0 +1,79 @@
+import { SignUtils } from './SignUtils';
+
+export class OrderInfoUtil {
+  /**
+   * 商户应用id
+   */
+  static readonly APP_ID = '9021000141640951';
+  static totalAmount = 0.01;
+  /**
+   *  pkcs8 格式的商户私钥。
+   *
+   * 	如下私钥,本 Demo 将优先
+   * 	使用 RSA2_PRIVATE。RSA2_PRIVATE 可以保证商户交易在更加安全的环境下进行,建议商户使用
+   * 	RSA2_PRIVATE。
+   *
+   * 	建议使用支付宝提供的公私钥生成工具生成和获取 RSA2_PRIVATE。
+   * 	工具地址:https://doc.open.alipay.com/docs/doc.htm?treeId=291&articleId=106097&docType=1
+   */
+  // 请使用工具生成的私钥
+  static readonly RSA2_PRIVATE = '';
+
+  static async getOrderInfo(): Promise<string> {
+    const keyValues = OrderInfoUtil.buildOrderParamMap();
+    let orderParam = OrderInfoUtil.buildOrderParam(keyValues);
+    let sign = await OrderInfoUtil.getSign(keyValues);
+    return orderParam + '&sign=' + sign;
+  }
+
+  static buildOrderParam(keyValues: Map<string, string>): string {
+    let param = '';
+    keyValues.forEach((value, key) => {
+      param += key + '=' + encodeURIComponent(value) + '&';
+    });
+    param = param.substring(0, param.length - 1);
+    return param;
+  }
+
+  static async getSign(keyValues: Map<string, string>): Promise<string> {
+    let mapEntries = Array.from(keyValues.keys());
+    mapEntries.sort((a, b) => {
+      return a[0].localeCompare(b[0]);
+    });
+    let sortedKeyValues = new Map<string, string>();
+    mapEntries.forEach(entry => {
+      sortedKeyValues.set(entry[0], entry[1]);
+    });
+    let param = '';
+    keyValues.forEach((value, key) => {
+      param += key + '=' + value + '&';
+    });
+    param = param.substring(0, param.length - 1);
+    let oriSign = await SignUtils.sign(param, OrderInfoUtil.RSA2_PRIVATE);
+    return encodeURIComponent(oriSign);
+  }
+
+  static buildOrderParamMap(): Map<string, string> {
+    const keyValues = new Map<string, string>()
+    keyValues.set('app_id', OrderInfoUtil.APP_ID);
+    // 不能包含中文,否则加密会有问题。。。。。。。。。。。。
+    keyValues.set('biz_content', `{"timeout_express":"30m","product_code":"QUICK_MSECURITY_PAY","total_amount":"${OrderInfoUtil.totalAmount}","subject":"1","body":"xxx","out_trade_no":"${OrderInfoUtil.getOutTradeNo()}"}`);
+    OrderInfoUtil.totalAmount = OrderInfoUtil.totalAmount + 0.01;
+    keyValues.set('charset', 'utf-8');
+    keyValues.set('method', 'alipay.trade.app.pay');
+    keyValues.set('sign_type', 'RSA2');
+    keyValues.set('timestamp', '2016-07-29 16:55:53');
+    keyValues.set('version', '1.0');
+    return keyValues;
+  }
+
+  static getOutTradeNo() {
+    let date = new Date();
+    let key = (date.getMonth().toString() + date.getDate().toString() + date.getHours().toString() + date.getMinutes()
+      .toString() + date.getSeconds().toString()).toString();
+    let r = Math.random() * 10000000;
+    key = key + r;
+    key = key.substring(0, 15);
+    return key;
+  }
+}

+ 35 - 0
commons/basic/src/main/ets/utils/ts/utils/SignUtils.ets

@@ -0,0 +1,35 @@
+import {
+  stringToUint8ArrayWithEncoder,
+  uint8ArrayToStringWithDecoder} from '@cashier_alipay/cashiersdk/src/main/ets/utils/Utils';
+import { BusinessError } from '@kit.BasicServicesKit';
+import { cryptoFramework } from '@kit.CryptoArchitectureKit';
+import { util } from '@kit.ArkTS';
+import { hilog } from '@kit.PerformanceAnalysisKit';
+
+export class SignUtils {
+
+  static async sign(content: string, privateKey: string): Promise<string> {
+    return new Promise<string>((resolve, reject) => {
+      let keyGenerator = cryptoFramework.createAsyKeyGenerator('RSA2048|PRIMES_2');
+      let privateKeyBuffer = new util.Base64Helper().decodeSync(privateKey);
+      let privateKeyBlob = new Uint8Array(privateKeyBuffer!);
+      keyGenerator.convertKey(null, { data: privateKeyBlob }).then(async pubPair => {
+        let signer = cryptoFramework.createSign("RSA2048|PKCS1|SHA256");
+        signer.init(pubPair.priKey).then(async  () => {
+          let input: cryptoFramework.DataBlob = { data: stringToUint8ArrayWithEncoder(content) };
+          let signature = await signer.sign(input);
+          let result = await new util.Base64Helper().encode(signature.data);
+          hilog.debug(0, "Index", `SignUtils result resolve`);
+          resolve(uint8ArrayToStringWithDecoder(result));
+        }).catch((error: BusinessError) => {
+          hilog.debug(0, "Index", `SignUtils result reject error ${error.message} code ${error.code}`);
+          reject(error.message);
+        });
+
+      }).catch((error: BusinessError) => {
+        hilog.debug(0, "Index", `SignUtils result reject error ${error.message} code ${error.code}`);
+        reject(error.message);
+      });
+    });
+  }
+}

BIN
commons/basic/src/main/resources/base/media/ali_pay.png


+ 1 - 0
features/feature/oh-package.json5

@@ -9,5 +9,6 @@
   "dependencies": {
     "basic": "file:../../commons/basic",
     "user": "file:../../features/user",
+    "@yue/webview_javascript_bridge": "^1.0.0"
   }
 }

+ 44 - 31
features/feature/src/main/ets/pages/Order/OrderDetailPage.ets

@@ -46,26 +46,28 @@ struct OrderDetailPage {
           List({space: 16}){
             ListItem()
 
-            /** 地址栏 */
-            this.AddressBuilder()
+            if(this.vm.orderStatus == OrderStatus.UNCONFIRMED) {
+              /** 地址栏 */
+              this.AddressBuilder()
 
-            /** 订单状态信息 */
-            this.OrderStatusBuilder()
+              /** 租借的图书 */
+              this.OrderListBuilder()
 
-            /** 租借的图书 */
-            this.OrderListBuilder()
+              /** 订单信息 */
+              this.OrderInfoBuilder()
 
-            /** 订单信息 */
-            this.OrderInfoBuilder()
+              /** 支付方式 */
+              this.PayMethodBuilder()
 
-            /** 支付方式 */
-            this.PayMethodBuilder()
+              /** 备注 */
+              this.RemarkBuilder()
+            } else {
+              /** 订单状态信息 */
+              this.OrderStatusBuilder()
 
-            /** 备注 */
-            this.RemarkBuilder()
-
-            /** 订单信息 */
-            this.OrderPayBuilder()
+              /** 订单信息 */
+              this.OrderPayBuilder()
+            }
 
             ListItem()
           }.width('100%').height('100%')
@@ -228,23 +230,34 @@ struct OrderDetailPage {
 
         Divider().height(1).width('100%').backgroundColor('#FF666666')
 
-        Row(){
-          Row({space: 5}){
-            Image($r('[basic].media.icon_wx'))
-              .width(20)
+        Column({space: 16}){
+          ForEach(this.vm.payWayList, (item: BasicType, index) => {
+            Row(){
+              Row({space: 5}){
+                Image(item.src)
+                  .width(20)
+                  .aspectRatio(1)
+
+                Text(item.text)
+                  .attributeModifier(new CustomTextStyle({ size: 14, weight: 500, color: '#666666' }))
+              }
+
+              Row(){
+                if(this.vm.payWay == index){
+                  Image($r('[basic].media.icon_selectSvg'))
+                    .fillColor(item.color)
+                }
+              }
+              .width(14)
               .aspectRatio(1)
-
-            Text('微信支付')
-              .attributeModifier(new CustomTextStyle({ size: 14, weight: 500, color: '#666666' }))
-          }
-
-          Image($r('[basic].media.icon_selectSvg'))
-            .width(14)
-            .aspectRatio(1)
-            .fillColor('#20BB06')
-        }
-        .width('100%')
-        .justifyContent(FlexAlign.SpaceBetween)
+              .borderRadius(14)
+              .border({width: this.vm.payWay == index ? 0 : 1})
+            }
+            .width('100%')
+            .justifyContent(FlexAlign.SpaceBetween)
+            .onClick(() => { this.vm.changePayWay(index) })
+          })
+        }.width('100%')
       }
       .justifyContent(FlexAlign.Start)
       .alignItems(HorizontalAlign.Start)

+ 320 - 0
features/feature/src/main/ets/pages/PrivacyPolicyPage.ets

@@ -0,0 +1,320 @@
+import { promptAction, router } from '@kit.ArkUI'
+import { webview } from '@kit.ArkWeb'
+import { bundleManager, common } from '@kit.AbilityKit'
+import { BusinessError } from '@kit.BasicServicesKit'
+import { WebViewJavascriptBridge, WVJBResponseCallback } from '@yue/webview_javascript_bridge'
+
+
+@Component
+struct PrivacyPolicyPage {
+  @State targetUrl: string = ''
+  @State title: string = ''
+  // 是否有进度条
+  hasProgressBar: boolean = false
+  // 网络加载进度
+  @State progressNum: number = 0
+  // 网络是否在加载中
+  @State loading: boolean = true
+  // 是否显示
+  navBarShow: boolean = true
+  // 进入页面时,状态条颜色
+  onPageShowBarColor: StatusBarColor = StatusBarColor.Black
+  // 隐藏页面时,状态条颜色
+  onPageHideBarColor: StatusBarColor = StatusBarColor.Black
+  // 顶部安全高度
+  safeTop: number = AppStorage.get('safeTop') as number
+  // 底部安全高度
+  safeBottom: number = AppStorage.get('safeBottom') as number
+  controller: webview.WebviewController = new webview.WebviewController()
+  historyCurrIndex: number = 0
+  // WebViewJavascriptBridge 桥接
+  private bridge: WebViewJavascriptBridge | undefined;
+  private context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
+  // 是否安装支付宝应用
+  private canOpenAlipays = false;
+  // 是否安装微信应用
+  private canOpenWechat = false;
+  // 是否已拉起微信支付
+  private isWeixinPay = false;
+  // 支付订单页url,如果成功拉起微信支付以后取消会回到app,此时需要跳到订单页
+  private orderUrl: string = '';
+  // 监听网页加载是否出错
+  @State loadError: boolean = false;
+  // 点击返回键需要直接退出web组件的url集合
+  private excludedUrlList: string[] = [
+    'https://app.sightcloud.cn/storage/#/package',
+    'https://app.aikancloud.com/storage/#/packageOrder',
+    'https://wx.88iot.net'
+  ];
+
+  aboutToAppear(): void {
+    this.onPageShow()
+  }
+
+  onPageShow(): void {
+    // this.statusBarColorSelect(this.onPageShowBarColor)
+    // 判断是否安装支付宝
+    try {
+      this.canOpenAlipays = bundleManager.canOpenLink('alipays://');
+      this.canOpenWechat = bundleManager.canOpenLink('weixin://');
+    } catch (err) {
+      let message = (err as BusinessError).message;
+      console.log('canOpenLink call error:', message);
+    }
+    // 判断是否是跳转到微信以后再返回app,若是,则跳转到订单页,若没有拿到订单url,直接返回上一页
+    if (this.isWeixinPay) {
+      this.isWeixinPay = false
+      if (this.orderUrl) {
+        // 清跳转订单页
+        this.controller.loadUrl(this.orderUrl)
+      } else {
+        this.backMethod()
+      }
+    }
+  }
+
+  onPageHide(): void {
+    this.statusBarColorSelect(this.onPageHideBarColor)
+  }
+
+  // 状态条颜色选取函数
+  statusBarColorSelect(color: StatusBarColor) {
+    switch (color) {
+      case StatusBarColor.White:
+        // themeManager.settingStatusBarWhite()
+        break
+      case StatusBarColor.Black:
+        // themeManager.settingStatusBarBlack()
+        break
+      default:
+        // themeManager.settingStatusBarBlack()
+        break
+    }
+  }
+
+  // 页面自行处理返回逻辑,不进行页面路由
+  onBackPress() {
+    this.backMethod()
+    return true
+  }
+
+  backMethod() {
+    if (this.loadError) {
+      router.back()
+      return
+    }
+    const url = this.controller.getUrl()
+    if (this.excludedUrlList.some(item => url.startsWith(item))) {
+      router.back()
+      return
+    }
+    if (this.historyCurrIndex > 0) {
+      this.controller.backward()
+    } else {
+      router.back()
+    }
+  }
+
+  build() {
+    NavDestination() {
+      Column() {
+        if (this.navBarShow) {
+          // PrivacyPolicyPageTitle({ title: this.title })
+        }
+
+        Stack({ alignContent: Alignment.Top }) {
+          if (this.hasProgressBar && this.loading && !this.loadError) {
+            this.progress()
+          }
+          if (this.loadError) {
+            Column() {
+              Text('出错啦!点击空白处刷新')
+                .fontColor('#686868')
+                .fontSize(20)
+            }
+            // .width(StyleConstants.FULL_PARENT)
+            // .height(StyleConstants.FULL_PARENT)
+            .justifyContent(FlexAlign.Center)
+            .onClick(() => {
+              this.loadError = false
+            })
+          } else {
+            Scroll() {
+              Web({ src: $rawfile('index.html'), controller: this.controller })
+                .geolocationAccess(false)
+                .domStorageAccess(true)
+                .mixedMode(MixedMode.Compatible)
+                .fileAccess(true)
+                .multiWindowAccess(true)
+                .onControllerAttached(() => {
+                  this.setupWebViewJavascriptBridge();
+                })
+                .onProgressChange((date) => {
+                  if (date) {
+                    //记录加载进度
+                    this.progressNum = date.newProgress
+                    if (this.progressNum == 100) {
+                      //加载完成进度条消失
+                      animateTo({ duration: 800, delay: 300 }, () => {
+                        this.loading = false
+                      })
+                    }
+                  }
+                })
+                .onRefreshAccessedHistory((event) => {
+                  //H5页面间的跳转
+                  // if (this.controller.getTitle().length < 5) {
+                  //   this.title = this.controller.getTitle()
+                  // }
+                  if (event) {
+                    const history = this.controller.getBackForwardEntries()
+                    this.historyCurrIndex = history.currentIndex
+                  }
+                })
+                .onPageBegin((event) => {
+                  this.progressNum = 0
+                  this.loading = true
+                })
+                .onLoadIntercept((event) => {
+                  const isPayment = this.handlePaymentIntercept(event)
+                  return isPayment
+                })
+                .onPageEnd((event) => {
+                  if (this.orderUrl && event.url == this.orderUrl) {
+                    this.controller.clearHistory()
+                  }
+                })
+                .onErrorReceive((event) => {
+                  if (event.request.getRequestUrl() == this.controller.getUrl()) {
+                    console.error(`WebView load error: ${event.request.getRequestUrl()}, code: ${event.error.getErrorCode()}, message: ${event.error.getErrorInfo()}`);
+                    this.loadError = true; // 显示错误页面
+                  }
+                })
+            }
+            .margin({ bottom: this.navBarShow ? this.safeBottom : 0 })
+          }
+        }
+      }
+      .width('100%')
+      .height('100%')
+      .padding({ top: this.navBarShow ? this.safeTop : 0, bottom: this.navBarShow ? this.safeBottom : 0 })
+    }
+    .hideTitleBar(true)
+  }
+
+  // 处理支付相关的拦截逻辑
+  private handlePaymentIntercept(event: OnLoadInterceptEvent) {
+    let data = event.data;
+    let url = data.getRequestUrl();
+    console.log(`alipay: url: ${url}`);
+    // 点击商城回退时会触发该跳转,直接退出就好,不加载
+    if (url.includes('js_native://close')) {
+      router.back()
+      return true
+    }
+    // 拉起支付宝支付
+    if (url.startsWith('alipays://platformapi/startApp')) {
+      if (this.canOpenAlipays) {
+        try {
+          this.context.openLink(url).then(() => {
+            console.info('open alipays success.');
+          }).catch((err: BusinessError) => {
+            console.error(`open alipays failed. Code is ${err.code}, message is ${err.message}`);
+            promptAction.showToast({ message: '打开支付宝失败' })
+          })
+        } catch (paramError) {
+          console.error(`Failed to start alipays. Code is ${paramError.code}, message is ${paramError.message}`)
+          promptAction.showToast({ message: '打开支付宝失败,请稍后重试' })
+        }
+      } else {
+        promptAction.showToast({ message: '请先安装支付宝客户端' })
+      }
+    }
+    // 拉起微信支付链接,提前将支付成功微信支付跳转回app的订单页url保存,取消时同样需要跳转
+    if (url.startsWith('https://wx.tenpay.com')) {
+      // 提取 redirect_url 参数
+      const redirectUrl = this.getRedirectUrlFromTenpay(url);
+      if (redirectUrl) {
+        console.info('提取到重定向链接:', redirectUrl);
+        // 可以选择保存该链接用于后续操作
+        this.orderUrl = redirectUrl;
+      }
+      return false;
+    }
+    // 拉起微信支付链接
+    if (url.startsWith('weixin://')) {
+      if (this.canOpenWechat) {
+        try {
+          this.context.openLink(url).then(() => {
+            // 拉起微信支付成功
+            this.isWeixinPay = true
+            console.info('open weixin success.');
+          }).catch((err: BusinessError) => {
+            console.error(`open weixin failed. Code is ${err.code}, message is ${err.message}`);
+            promptAction.showToast({ message: '打开微信失败' })
+          })
+        } catch (paramError) {
+          console.error(`Failed to start weixin. Code is ${paramError.code}, message is ${paramError.message}`)
+          promptAction.showToast({ message: '打开微信失败,请稍后重试' })
+        }
+        return false
+      } else {
+        promptAction.showToast({ message: '请先安装微信客户端'})
+        return true
+      }
+    }
+    return false
+  }
+
+  // 从微信支付链接中提取 redirect_url 参数
+  private getRedirectUrlFromTenpay(url: string): string | null {
+    try {
+      // 使用正则提取 redirect_url 参数
+      const regex = /[?&]redirect_url=([^&]+)/;
+      const match = url.match(regex);
+      if (match && match[1]) {
+        let decodedUrl = decodeURIComponent(match[1]);
+        return decodedUrl;
+      }
+    } catch (e) {
+      console.error('解析 redirect_url 失败:', e);
+    }
+    return null;
+  }
+
+  @Builder
+  progress() {
+    Progress({ value: this.progressNum, total: 100, type: ProgressType.Linear })
+      .color('#17ab19')
+      .zIndex(1)
+  }
+
+  /**
+   * 设置 jsBridge
+   */
+  private setupWebViewJavascriptBridge() {
+    // 开启调试,控制台打印信息,默认无调试
+    WebViewJavascriptBridge.enableLogging();
+    // 创建 WebViewJavascriptBridge
+    this.bridge = new WebViewJavascriptBridge(this.controller);
+    this.registerHandlers(this.bridge)
+  }
+
+  // 注册原生处理函数 (这里需要知道H5端的方法名)
+  private registerHandlers(bridge: WebViewJavascriptBridge) {
+    bridge.registerHandler('backToNative', (data: object, responseCallback: WVJBResponseCallback) => {
+      this.backMethod();
+      responseCallback(null);
+    });
+  }
+}
+
+export enum StatusBarColor {
+  White = 'White',
+  Black = 'Black',
+}
+
+@Builder
+function PrivacyPolicyBuilder() {
+  PrivacyPolicyPage()
+}

+ 14 - 3
features/feature/src/main/ets/pages/viewModel/OrderDetailViewModel.ets

@@ -8,10 +8,8 @@ import { OrderDetailModel } from '../../model/RouterModel'
 @ObservedV2
 export class OrderDetailViewModel{
   @Trace safeBottom: number = AppStorage.get(YTAvoid.SAFE_BOTTOM_KEY) as number
-
   // 订单状态
   @Trace orderStatus: OrderStatus
-
   // 租借的图书 URL
   @Trace bookList: BookItem[] = []
   // 订单明细
@@ -22,6 +20,9 @@ export class OrderDetailViewModel{
   @Trace address: Address = {}
   // 用户订单备注
   @Trace remark: string = ''
+  // 用户选择的支付方式
+  @Trace payWay: number = 0
+
 
   // 提交订单校验
   orderValidation: OrderValidationData = {
@@ -36,15 +37,25 @@ export class OrderDetailViewModel{
     region: '福建-厦门-火炬园',
   }
 
+  // 支付方式遍历
+  payWayList: Array<BasicType> = [
+    { text: '微信支付', src: $r('[basic].media.icon_wx'), color: '#20BB06'},
+    { text: '支付宝支付', src: $r('[basic].media.ali_pay'), color: '#06B4FD'},
+  ]
+
   constructor(param: OrderDetailModel) {
     this.orderStatus = param.status
 
     if(param.status === OrderStatus.UNCONFIRMED) {
-      this.generateOrderDetail()
       this.bookList = param.bookList
+      this.generateOrderDetail()
     }
   }
 
+  // 切换支付方式
+  changePayWay(index: number) {
+    this.payWay = index
+  }
 
   /** 生成订单明细信息 */
   generateOrderDetail() {

+ 26 - 1
features/feature/src/main/ets/view/MainView.ets

@@ -1,9 +1,10 @@
-import { BasicType, BookItem, yTRouter } from "basic"
+import { AliPay, BasicType, BookItem, yTRouter } from "basic"
 import { tagItemComp } from "../components/BuilderIndex"
 import { DeerSearch } from "../components/DeerSearch"
 import { ytBuildComp } from "../components/ytComp/ytBuildComp"
 import { CustomTextStyle } from "../style/CustomTextStyle"
 import { MainViModel } from "./viewModel/MainViewModel"
+import common from "@ohos.app.ability.common"
 
 @ComponentV2
 export struct MainView {
@@ -13,6 +14,30 @@ export struct MainView {
     ytBuildComp(){
       RelativeContainer(){
         List(){
+          ListItem(){
+            Row({space: 20}){
+
+              Column(){
+                // Web({src: $rawfile('index.html'),controller: this.web})
+                //   .onRefreshAccessedHistory((event)=>{
+                //     console.log(`111111111 = ${JSON.stringify(111111111)}`)
+                //   })
+                Text('asdfasdf')
+                  .onClick(()=>{
+                    // yTRouter.pushPathByName
+                    (getContext(this) as common.UIAbilityContext).openLink('alipays://platformapi/startApp?appId=20000125&orderSuffix=h5_route_token%3D%22RZ54gBmd2erDuYtF1qBXxKZRBhBCyHmobilecashierRZ54%22%26is_h5_route%3D%22true%22%26h5_route_senior%3D%22true%22%26h5_route_date%3D%221762939090909%22%26h5_route_sign%3D%22cxKWtd2vsn5T%2Ftjj3VJlnvuJg%2BdhGCLdmvhhc4qCkRmElo7DF3TeLaQ1I95PqMGGEoVq%2B%2B%2FTxl%2FFXW2ej9XA1Vqj%2BO7oQsOkrXg%2BL26Q9hIBum0ieqBM6XLaOtZRwSmnlGP00bALeZx7bNLKjBke475areLjP%2FPPbk8yukL467DIi6uLDc88VpnaZlQvBEFNiPVVEdjrKqIZhPM6EK1BKvYDFNvgqxiYJc8prydf5VX%2FbgZQiQxQnp0Cl6UydZuvbQmhA2Lvr%2BlMv%2F3Mo6iarn6HIDe425vqib9f7Fs1wbzwV%2BttyxNoq58W%2F1n%2B92ZKyGvyOM1XyPAmlUvD%2FbtYQ97wo1SEubIqBypcYKLmDI4q5hE1Hrf31wMJKt%2FtGvbkvqGP1uvl2c8OKsf8WGnDgI5ZROzv%2ByedAV7qwRsRtV2EkNlG093iAzMt9S6spIU4lxgWzCpk3%2BrhWeciRK6sP9BGjpOArUvpDCN%2FCBQKXb%2BAy4WKUXrh719CcjsA5WsxRDCIrzkg5O40AwoFxpX%2Fuyu3rV4hgyAqx2%2Bp%2F%2F%2F%2Bd0Sr%2FSxwDSzy7cjQu0GnivwFys5X%2BA3uIUZ9NmF5sRDMxPP7c1V89ajLlqbIk62UshA5BcPjRK812Zsm8qtIuSxBZRoMqNA2K7YUtm1NtfQtTBcmahGx3zsmV2uy%2BC0oqRE%3D%22\n')
+                  })
+              }
+
+              Text('AliPay.launchPay')
+                .onClick(()=>{
+                  AliPay.launchPay('appId=20000125&orderSuffix=h5_route_token%3D%22RZ42h6OZuwA4DRMmT9dtuiCXi1z773mobilecashierRZ42%22%26is_h5_route%3D%22true%22%26h5_route_senior%3D%22true%22%26h5_route_date%3D%221762939818010%22%26h5_route_sign%3D%22LvtJ9OjEmMiS6I1FOCUms1MQz7HdQxlRU8g7R9ck92zBlcPQS0%2F4AHT%2BlGR1Yt8JDJqvCwys1ZAink5xU4lEwThTTyxjVu%2FIi%2FAOXjfhdHlHyXc8SOGBpmSue8%2BG2zJTyr8LHCeyBtGjRvhaXymDBav6%2FeIKyAAaUeeYbBeuBVgnUJQY4WPNXC5Mzh94v4gVjFqK%2Fdz%2BJlJ26jSwE6gOy9MSTwJNXiiEsHx1MVUWIbnIAEupjEiOd04kaClnpPwgu7BixGzoyB5loxeOk3JaqRiQ%2B%2FEVbgSKjxDcWznHQmKDVnWAOzdTDKn%2FoaPw3LfDTsDvwMeVXr27ZgdeWhURk7kvVzKOt6LyM6tZQ8bSrr3BtWEmP5v1IFpAiOSowg8%2Bm3Q1GIT%2BhhR7JTxlNEmzAzs7rARlto1871b5knz9fEOMR%2BLS%2B9WhYxF7oxirN94LnaITgB5lywGZ%2FQxqKImFMUftlhqJTsmU8GuQXza5bS0yMjFJGHa7si3tS41IPjje%2FpCMerwXyu%2BhTVXcNt75riP%2BwvXoECQ8MOQik36O%2FCpjOmITrBX2Gd1fLwKxr0PZ%2BVYIGJ%2FpMlNzKK0SHiAdGPHi4QBBiDaxkl7KFTwr3GT8cfEO7wnfMR8hgaGksiSCLg3GGWKnPGIgNPZ9FOOkj115AJ621VJ7Eh0cfZP6WuQ%3D%22')
+                })
+            }
+          }
+          .padding({top: 200})
+
+
           // logo
           ListItem(){
             Row({space: 14}){

+ 5 - 0
features/feature/src/main/resources/base/profile/router_map.json

@@ -84,6 +84,11 @@
       "name": "CashPledgeRecord",
       "pageSourceFile": "src/main/ets/pages/CashPledge/CashPledgeRecord.ets",
       "buildFunction": "CashPledgeRecordBuilder"
+    },
+    {
+      "name": "PrivacyPolicyPage",
+      "pageSourceFile": "src/main/ets/pages/PrivacyPolicyPage.ets",
+      "buildFunction": "PrivacyPolicyBuilder"
     }
   ]
 }

+ 9 - 9
features/feature/src/main/resources/rawfile/index.html

@@ -1,14 +1,14 @@
 <!DOCTYPE html>
 <html>
-    <body style="font-size:16px;color:rgba(0,0,0,0.6);flex-shrink:0;font-style:normal;font-weight:normal;background-color:rgb(255, 255, 255);">
 
-    <div id="content"></div>
-    <script>
-        function writeHtml(str) {
-          const el = document.querySelector('#content');
-          el.innerHTML = str;
-        }
-    </script>
 
-    </body>
+
+<body><form name="punchout_form" method="post" action="https://openapi.alipay.com/gateway.do?alipay_sdk=OpenAPI-Generator%2F3.1.0.ALL%2Fjava&charset=UTF-8&method=alipay.trade.wap.pay&format=json&sign=W2%2FEwN8Jvz2iDZ4Yajt2HkO%2ByHWaqycToaOj41gaggAn1bEhjrpykebn9bLUEl9GnoRlNizRTljN4Deqlpl3wcwSCZUpJ49Z64puLs6GN%2BS2q0TiGpwLwj5VNJ62YVP8SawHVjeB4V%2FI4tzYmh0gZ6L8QWSJ76iB5%2Bj%2BxWEAwxahmveEgPpOFupLTF9VWFzZPHzrHQD0JelAt0DLdWE6B%2BOkE3oSV%2FPh3Vo%2FJvPslbfaOyPMu%2BAoXbR0wrQz7kCVLWXqGh0osENd3astCIbWMcMFtQno1BvFfSvBuCkFnLc3Dy%2BNLIkLNKrKj3HAPjklQxw6TAoeGMw6r3NLvdn6mw%3D%3D&app_id=2021004172698934&version=1.0&sign_type=RSA2&timestamp=2025-11-12+16%3A03%3A08">
+    <input type="hidden" name="biz_content" value="{&quot;time_expire&quot;:&quot;2025-11-12 16:17:55&quot;,&quot;out_trade_no&quot;:&quot;TEST1762934557085&quot;,&quot;quit_url&quot;:&quot;https://your-server.com/alipay/quit&quot;,&quot;total_amount&quot;:&quot;0.01&quot;,&quot;subject&quot;:&quot;测试商品&quot;,&quot;product_code&quot;:&quot;QUICK_WAP_WAY&quot;,&quot;passback_params&quot;:&quot;custom_param\u003d123&quot;}">
+    <input type="hidden" name="notify_url" value="https://your-server.com/alipay/notify">
+    <input type="submit" value="立即支付" style="display:none" >
+</form>
+<script>document.forms[0].submit();</script>
+</body>
+
 </html>

+ 4 - 0
products/entry/src/main/module.json5

@@ -70,6 +70,10 @@
           }
         ]
       }
+    ],
+    "querySchemes": [
+      'alipays',
+      'https'
     ]
   }
 }

+ 14 - 0
products/entry/src/main/resources/rawfile/index.html

@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+
+
+
+<body><form name="punchout_form" method="post" action="https://openapi.alipay.com/gateway.do?alipay_sdk=OpenAPI-Generator%2F3.1.0.ALL%2Fjava&charset=UTF-8&method=alipay.trade.wap.pay&format=json&sign=W2%2FEwN8Jvz2iDZ4Yajt2HkO%2ByHWaqycToaOj41gaggAn1bEhjrpykebn9bLUEl9GnoRlNizRTljN4Deqlpl3wcwSCZUpJ49Z64puLs6GN%2BS2q0TiGpwLwj5VNJ62YVP8SawHVjeB4V%2FI4tzYmh0gZ6L8QWSJ76iB5%2Bj%2BxWEAwxahmveEgPpOFupLTF9VWFzZPHzrHQD0JelAt0DLdWE6B%2BOkE3oSV%2FPh3Vo%2FJvPslbfaOyPMu%2BAoXbR0wrQz7kCVLWXqGh0osENd3astCIbWMcMFtQno1BvFfSvBuCkFnLc3Dy%2BNLIkLNKrKj3HAPjklQxw6TAoeGMw6r3NLvdn6mw%3D%3D&app_id=2021004172698934&version=1.0&sign_type=RSA2&timestamp=2025-11-12+16%3A03%3A08">
+    <input type="hidden" name="biz_content" value="{&quot;time_expire&quot;:&quot;2025-11-12 16:17:55&quot;,&quot;out_trade_no&quot;:&quot;TEST1762934557085&quot;,&quot;quit_url&quot;:&quot;https://your-server.com/alipay/quit&quot;,&quot;total_amount&quot;:&quot;0.01&quot;,&quot;subject&quot;:&quot;测试商品&quot;,&quot;product_code&quot;:&quot;QUICK_WAP_WAY&quot;,&quot;passback_params&quot;:&quot;custom_param\u003d123&quot;}">
+    <input type="hidden" name="notify_url" value="https://your-server.com/alipay/notify">
+    <input type="submit" value="立即支付" style="display:none" >
+</form>
+<script>document.forms[0].submit();</script>
+</body>
+
+</html>

BIN
sign/鹿学长调试证书Debug.p7b