Ver código fonte

Merge remote-tracking branch 'origin/sunzee' into test-sunzee

# Conflicts:
#	src/assets/language/en.json
#	src/router/index.js
#	src/views/user.vue
soobin 2 anos atrás
pai
commit
e58a8a5f21

+ 2 - 0
package.json

@@ -11,6 +11,7 @@
     "lint": "vue-cli-service lint"
   },
   "dependencies": {
+    "@airwallex/payouts-web-sdk": "^1.3.0",
     "@amap/amap-jsapi-loader": "^1.0.1",
     "@vant/area-data": "^1.5.0",
     "@vant/touch-emulator": "^1.4.0",
@@ -22,6 +23,7 @@
     "core-js": "^3.6.5",
     "crypto-js": "^4.1.1",
     "dayjs": "^1.11.7",
+    "js-base64": "^3.7.5",
     "js-md5": "^0.7.3",
     "lib-flexible": "^0.3.2",
     "moment": "^2.29.4",

+ 13 - 2
src/assets/language/en.json

@@ -17,7 +17,7 @@
     "paymentMethod": "Payment method",
     "allDevices": "All devices",
     "commodityType": "Commodity type",
-    "whole": "All",
+    "whole": "whole",
     "noPaymentRequired": "No payment required",
     "coin": "Coin",
     "notes": "Notes",
@@ -603,6 +603,16 @@
       "roger": "Do not show again"
     }
   },
+  "airwallex": {
+    "sunzee": "Sunzee",
+    "airwallex": "Airwallex",
+    "wallet": "Airwallex wallet",
+    "amount": "Airwallex amount",
+    "payment": "New transfer",
+    "paymentDetail": "Payment details",
+    "payout": "Payout",
+    "beneficiary": "Beneficiary"
+  },
   "joinpayMch": {
     "withdrawalAccountNo": "Withdrawal account No",
     "merchantNameLabel": "Merchant name",
@@ -1214,7 +1224,8 @@
     "logOutContent": "Are you sure you want to log out",
     "corrEmailPlace": "Please enter the correct email address",
     "corrPhonePlace": "Please enter the correct mobile number",
-    "bindWechat": "Bind WeChat"
+    "bindWechat":"Bind WeChat",
+    "airwallex":"Airwallex"
   },
   "bindWechat": {
     "cancel": "Cancel",

+ 12 - 1
src/assets/language/zh.json

@@ -604,6 +604,16 @@
       "roger":"不再显示"
     }
   },
+  "airwallex": {
+    "sunzee": "申泽智能",
+    "airwallex": "空中云汇",
+    "wallet": "空中云汇钱包",
+    "amount": "钱包金额",
+    "payment": "付款转账",
+    "paymentDetail": "付款详情",
+    "payout": "付款单",
+    "beneficiary": "收款人"
+  },
   "joinpayMch": {
     "withdrawalAccountNo": "提现账号",
     "merchantNameLabel": "商户名称",
@@ -1222,7 +1232,8 @@
     "logOutContent":"确定需要退出登录吗",
     "corrEmailPlace":"请输入正确的邮箱",
     "corrPhonePlace":"请输入正确的手机号",
-    "bindWechat":"绑定微信"
+    "bindWechat":"绑定微信",
+    "airwallex":"空中云汇"
   },
   "bindWechat": {
     "cancel": "取消",

BIN
src/assets/user/airwallexIcon.png


+ 1 - 0
src/constants/const.js

@@ -0,0 +1 @@
+export const AIRWALLEX_ADMIN_CLIENTID = 'IBi-pVO4SSGzXIDHRYfVOA';

+ 7 - 0
src/constants/exchangeRates.json

@@ -0,0 +1,7 @@
+{
+    "USD": 1.0,
+    "EUR": 0.91,
+    "JPY": 109.46,
+    "CNY": 6.5
+}
+  

+ 440 - 79
src/router/index.js

@@ -1,140 +1,497 @@
-import { createRouter, createWebHashHistory } from 'vue-router'
-import { getLocal } from '@/common/js/utils';
+import { createRouter, createWebHashHistory } from "vue-router";
+import { getLocal } from "@/common/js/utils";
 
 const router = createRouter({
   // hash模式:createWebHashHistory,history模式:createWebHistory
   history: createWebHashHistory(),
   routes: [
     // 首页
-    { path: '/', redirect: '/home' },
-    { path: '/home', name: 'home', component: () => import('@/views/home/index.vue'), meta: { index: 1 } },
+    { path: "/", redirect: "/home" },
+    // Home 页面
+    {
+      path: "/home",
+      name: "home",
+      component: () => import("@/views/home/index.vue"),
+      meta: { index: 1 },
+    },
     // 登录页面
-    { path: '/login', name: 'login', component: () => import('@/views/login.vue'), meta: { index: 1, noLogin: true } },
+    {
+      path: "/login",
+      name: "login",
+      component: () => import("@/views/login.vue"),
+      meta: { index: 1, noLogin: true },
+    },
     // 微信登录跳板
-    { path: '/wxLogin', name: 'wxLogin', component: () => import('@/views/wxLogin.vue'), meta: { index: 1, noLogin: true } },
+    {
+      path: "/wxLogin",
+      name: "wxLogin",
+      component: () => import("@/views/wxLogin.vue"),
+      meta: { index: 1, noLogin: true },
+    },
     // 注册页面
-    { path: '/register', name: 'register', component: () => import('@/views/register.vue'), meta: { index: 1, noLogin: true } },
+    {
+      path: "/register",
+      name: "register",
+      component: () => import("@/views/register.vue"),
+      meta: { index: 1, noLogin: true },
+    },
     // 忘记密码页面
-    { path: '/forgetpassword', name: 'forgetPassword', component: () => import('@/views/forgetPassword'), meta: { index: 1, noLogin: true } },
+    {
+      path: "/forgetpassword",
+      name: "forgetPassword",
+      component: () => import("@/views/forgetPassword"),
+      meta: { index: 1, noLogin: true },
+    },
     // 绑定微信
-    { path: '/bindWechat', name: 'bindWechat', component: () => import('@/views/bindWechat.vue'), meta: { index: 1, noLogin: true } },
+    {
+      path: "/bindWechat",
+      name: "bindWechat",
+      component: () => import("@/views/bindWechat.vue"),
+      meta: { index: 1, noLogin: true },
+    },
     // 修改密码页面
-    { path: '/changepassword', name: 'changePassword', component: () => import('@/views/changePassword'), meta: { index: 1, noLogin: true } },
+    {
+      path: "/changepassword",
+      name: "changePassword",
+      component: () => import("@/views/changePassword"),
+      meta: { index: 1, noLogin: true },
+    },
     // 设备页面
-    { path: '/device', name: 'device', component: () => import('@/views/device/index'), meta: { index: 1 } },
+    {
+      path: "/device",
+      name: "device",
+      component: () => import("@/views/device/index"),
+      meta: { index: 1 },
+    },
     // 设备详情
-    { path: '/deviceSet', name: 'deviceSet', component: () => import('@/views/device/deviceSet'), meta: { index: 1 } },
+    {
+      path: "/deviceSet",
+      name: "deviceSet",
+      component: () => import("@/views/device/deviceSet"),
+      meta: { index: 1 },
+    },
     // 编辑标签
-    { path: '/editTag', name: 'editTag', component: () => import('@/views/device/tagSet/index.vue'), meta: { index: 1 } },
+    {
+      path: "/editTag",
+      name: "editTag",
+      component: () => import("@/views/device/tagSet/index.vue"),
+      meta: { index: 1 },
+    },
     // { path: '/deviceOpr', name: 'deviceOpr', component: () => import('@/views/device/deviceOper2.vue'), meta: { index: 1 } },
     // 音量调节
-    { path: '/modulation', name: 'modulation', component: () => import('@/views/device/modulation.vue'), meta: { index: 1 } },
+    {
+      path: "/modulation",
+      name: "modulation",
+      component: () => import("@/views/device/modulation.vue"),
+      meta: { index: 1 },
+    },
     // 远程开门
-    { path: '/openDoor', name: 'openDoor', component: () => import('@/views/device/openDoor.vue'), meta: { index: 1 } },
+    {
+      path: "/openDoor",
+      name: "openDoor",
+      component: () => import("@/views/device/openDoor.vue"),
+      meta: { index: 1 },
+    },
     // 远程做糖
-    { path: '/doSugar', name: 'doSugar', component: () => import('@/views/device/doSugar.vue'), meta: { index: 1 } },
+    {
+      path: "/doSugar",
+      name: "doSugar",
+      component: () => import("@/views/device/doSugar.vue"),
+      meta: { index: 1 },
+    },
     // 今日做糖列表
-    { path: '/toDaySugarList', name: 'toDaySugarList', component: () => import('@/views/device/toDaySugarList.vue'), meta: { index: 1 } },
+    {
+      path: "/toDaySugarList",
+      name: "toDaySugarList",
+      component: () => import("@/views/device/toDaySugarList.vue"),
+      meta: { index: 1 },
+    },
     // 定时开关
-    { path: '/alarmClock', name: 'alarmClock', component: () => import('@/views/device/alarmClock.vue'), meta: { index: 1 } },
+    {
+      path: "/alarmClock",
+      name: "alarmClock",
+      component: () => import("@/views/device/alarmClock.vue"),
+      meta: { index: 1 },
+    },
     // 设置闹钟
-    { path: '/alarmClockAdd', name: 'alarmClockAdd', component: () => import('@/views/device/alarmClockSet/index.vue'), meta: { index: 1 } },
-    { path: '/alarmClockSet', name: 'alarmClockSet', component: () => import('@/views/device/alarmClockSet/index.vue'), meta: { index: 1 } },
+    {
+      path: "/alarmClockAdd",
+      name: "alarmClockAdd",
+      component: () => import("@/views/device/alarmClockSet/index.vue"),
+      meta: { index: 1 },
+    },
+    {
+      path: "/alarmClockSet",
+      name: "alarmClockSet",
+      component: () => import("@/views/device/alarmClockSet/index.vue"),
+      meta: { index: 1 },
+    },
     // 参数设置
-    { path: '/paramsSet', name: 'paramsSet', component: () => import('@/views/device/paramsSet/index.vue'), meta: { index: 1 } },
-    { path: '/paramsSetInfo', name: 'paramsSetInfo', component: () => import('@/views/device/paramsSet/paramsSetInfo.vue'), meta: { index: 1 } },
+    {
+      path: "/paramsSet",
+      name: "paramsSet",
+      component: () => import("@/views/device/paramsSet/index.vue"),
+      meta: { index: 1 },
+    },
+    {
+      path: "/paramsSetInfo",
+      name: "paramsSetInfo",
+      component: () => import("@/views/device/paramsSet/paramsSetInfo.vue"),
+      meta: { index: 1 },
+    },
     // 添加分销人
-    { path: '/saveProportion', name: 'saveProportion', component: () => import('@/views/device/saveProportion/index.vue'), meta: { index: 1 } },
+    {
+      path: "/saveProportion",
+      name: "saveProportion",
+      component: () => import("@/views/device/saveProportion/index.vue"),
+      meta: { index: 1 },
+    },
     // 设备充值
-    { path: '/recharge', name: 'recharge', component: () => import('@/views/device/recharge.vue'), meta: { index: 1 } },
+    {
+      path: "/recharge",
+      name: "recharge",
+      component: () => import("@/views/device/recharge.vue"),
+      meta: { index: 1 },
+    },
     // 机器排行
-    { path: '/robotranking', name: 'robotranking', component: () => import('@/views/robotRanking.vue'), meta: { index: 1 } },
+    {
+      path: "/robotranking",
+      name: "robotranking",
+      component: () => import("@/views/robotRanking.vue"),
+      meta: { index: 1 },
+    },
     // 个人中心
-    { path: '/user', name: 'user', component: () => import('@/views/user.vue'), meta: { index: 1 } },
+    {
+      path: "/user",
+      name: "user",
+      component: () => import("@/views/user.vue"),
+      meta: { index: 1 },
+    },
     // 备用提现账号
-    { path: '/huifuMch', name: 'huifuMch', component: () => import('@/views/huifuMch/index'), meta: { index: 1 } },
+    {
+      path: "/huifuMch",
+      name: "huifuMch",
+      component: () => import("@/views/huifuMch/index"),
+      meta: { index: 1 },
+    },
     // 汇付信息修改
-    { path: '/huifuMchEdit', name: 'huifuMchEdit', component: () => import('@/views/huifuMch/update'), meta: { index: 1 } },
+    {
+      path: "/huifuMchEdit",
+      name: "huifuMchEdit",
+      component: () => import("@/views/huifuMch/update"),
+      meta: { index: 1 },
+    },
     // 提现账号
-    { path: '/joinpayMch', name: 'joinpayMch', component: () => import('@/views/joinpayMch/index'), meta: { index: 1 } },
+    {
+      path: "/joinpayMch",
+      name: "joinpayMch",
+      component: () => import("@/views/joinpayMch/index"),
+      meta: { index: 1 },
+    },
     // 自充值
-    { path: '/uniPay', name: 'uniPay', component: () => import('@/views/uniPay/index'), meta: { index: 1 } },
+    {
+      path: "/uniPay",
+      name: "uniPay",
+      component: () => import("@/views/uniPay/index"),
+      meta: { index: 1 },
+    },
     // 优惠码
-    { path: '/discountCode', name: 'discountCode', component: () => import('@/views/discountCode/index'), meta: { index: 1 } },
-    { path: '/payCode', name: 'payCode', component: () => import('@/views/discountCode/payCode'), meta: { index: 1 } },
+    {
+      path: "/discountCode",
+      name: "discountCode",
+      component: () => import("@/views/discountCode/index"),
+      meta: { index: 1 },
+    },
+    // Airwallex 钱包
+    {
+      path: "/airwallex",
+      name: "airwallex",
+      component: () => import("@/views/airwallex/index.vue"),
+      meta: { index: 1 },
+    },
+    // Airwallex 创建付款人
+    {
+      path: "/airwallexBeneficiary",
+      name: "airwallexBeneficiary",
+      component: () => import("@/views/airwallex/beneficiary.vue"),
+      meta: { index: 1 },
+    },
+    // Airwallex 付款单
+    {
+      path: "/airwallexPayout",
+      name: "airwallexPayout",
+      component: () => import("@/views/airwallex/payout.vue"),
+      meta: { index: 1},
+    },
+    // Airwallex 去付款
+    {
+      path: "/caPayment",
+      name: "caPayment",
+      component: () => import("@/views/airwallex/caPayment.vue"),
+      meta: { index: 1 },
+    },
+    // Airwallex 付款结果详情
+    {
+      path: "/paymentDetail",
+      name: "paymentDetail",
+      component: () => import("@/views/airwallex/paymentDetail.vue"),
+      meta: { index: 1 },
+    },
+    {
+      path: "/payCode",
+      name: "payCode",
+      component: () => import("@/views/discountCode/payCode"),
+      meta: { index: 1 },
+    },
     // 分销设置
-    { path: '/distributionSet', name: 'distributionSet', component: () => import('@/views/distributionSet/index'), meta: { index: 1 } },
-    { path: '/distributionDetail', name: 'distributionDetail', component: () => import('@/views/distributionSet/detail'), meta: { index: 1 } },
+    {
+      path: "/distributionSet",
+      name: "distributionSet",
+      component: () => import("@/views/distributionSet/index"),
+      meta: { index: 1 },
+    },
+    {
+      path: "/distributionDetail",
+      name: "distributionDetail",
+      component: () => import("@/views/distributionSet/detail"),
+      meta: { index: 1 },
+    },
     // 账号权限
-    { path: '/accountPer', name: 'accountPer', component: () => import('@/views/accountPer/index'), meta: { index: 1 } },
+    {
+      path: "/accountPer",
+      name: "accountPer",
+      component: () => import("@/views/accountPer/index"),
+      meta: { index: 1 },
+    },
     // 添加账号
-    { path: '/accountPerAdd', name: 'accountPerAdd', component: () => import('@/views/accountPer/add'), meta: { index: 1 } },
+    {
+      path: "/accountPerAdd",
+      name: "accountPerAdd",
+      component: () => import("@/views/accountPer/add"),
+      meta: { index: 1 },
+    },
     // 角色权限
-    { path: '/role', name: 'role', component: () => import('@/views/role/index'), meta: { index: 1 } },
-    { path: '/roleSet', name: 'roleSet', component: () => import('@/views/role/add'), meta: { index: 1 } },
+    {
+      path: "/role",
+      name: "role",
+      component: () => import("@/views/role/index"),
+      meta: { index: 1 },
+    },
+    {
+      path: "/roleSet",
+      name: "roleSet",
+      component: () => import("@/views/role/add"),
+      meta: { index: 1 },
+    },
     // 商户管理
-    { path: '/merchantManage', name: 'merchantManage', component: () => import('@/views/merchantManage/index'), meta: { index: 1 } },
-    { path: '/merchantSet', name: 'merchantSet', component: () => import('@/views/merchantManage/set'), meta: { index: 1 } },
+    {
+      path: "/merchantManage",
+      name: "merchantManage",
+      component: () => import("@/views/merchantManage/index"),
+      meta: { index: 1 },
+    },
+    {
+      path: "/merchantSet",
+      name: "merchantSet",
+      component: () => import("@/views/merchantManage/set"),
+      meta: { index: 1 },
+    },
     // 广告管理
-    { path: '/advertManage', name: 'advertManage', component: () => import('@/views/advertManage/index'), meta: { index: 1 } },
-    { path: '/advertSet', name: 'advertSet', component: () => import('@/views/advertManage/adSet.vue'), meta: { index: 1 } },
+    {
+      path: "/advertManage",
+      name: "advertManage",
+      component: () => import("@/views/advertManage/index"),
+      meta: { index: 1 },
+    },
+    {
+      path: "/advertSet",
+      name: "advertSet",
+      component: () => import("@/views/advertManage/adSet.vue"),
+      meta: { index: 1 },
+    },
     // 广告规则
-    { path: '/advertRule', name: 'advertRule', component: () => import('@/views/advertManage/advertRule/index.vue'), meta: { index: 1 } },
+    {
+      path: "/advertRule",
+      name: "advertRule",
+      component: () => import("@/views/advertManage/advertRule/index.vue"),
+      meta: { index: 1 },
+    },
     // 广告规则新增
-    { path: '/advertRuleAdd', name: 'advertRuleAdd', component: () => import('@/views/advertManage/advertRule/add.vue'), meta: { index: 1 } },
-    { path: '/advertRuleAddScreen', name: 'advertRuleAddScreen', component: () => import('@/views/advertManage/advertRule/screen.vue'), meta: { index: 1 } },
+    {
+      path: "/advertRuleAdd",
+      name: "advertRuleAdd",
+      component: () => import("@/views/advertManage/advertRule/add.vue"),
+      meta: { index: 1 },
+    },
+    {
+      path: "/advertRuleAddScreen",
+      name: "advertRuleAddScreen",
+      component: () => import("@/views/advertManage/advertRule/screen.vue"),
+      meta: { index: 1 },
+    },
     // apk管理
-    { path: '/apkManage', name: 'apkManage', component: () => import('@/views/apkManage/index'), meta: { index: 1 } },
+    {
+      path: "/apkManage",
+      name: "apkManage",
+      component: () => import("@/views/apkManage/index"),
+      meta: { index: 1 },
+    },
     // apk管理-新增
-    { path: '/apkManageAdd', name: 'apkManageAdd', component: () => import('@/views/apkManage/add'), meta: { index: 1 } },
+    {
+      path: "/apkManageAdd",
+      name: "apkManageAdd",
+      component: () => import("@/views/apkManage/add"),
+      meta: { index: 1 },
+    },
     // 报警历史
-    { path: '/alarmHistory', name: 'alarmHistory', component: () => import('@/views/alarmHistory/index'), meta: { index: 1 } },
+    {
+      path: "/alarmHistory",
+      name: "alarmHistory",
+      component: () => import("@/views/alarmHistory/index"),
+      meta: { index: 1 },
+    },
     // 订单导出
-    { path: '/orderExport', name: 'orderExport', component: () => import('@/views/orderExport/index'), meta: { index: 1 } },
+    {
+      path: "/orderExport",
+      name: "orderExport",
+      component: () => import("@/views/orderExport/index"),
+      meta: { index: 1 },
+    },
     // 杉德分账导出
-    { path: '/subLedgerManage', name: 'subLedgerManage', component: () => import('@/views/subLedgerManage/index'), meta: { index: 1 } },
+    {
+      path: "/subLedgerManage",
+      name: "subLedgerManage",
+      component: () => import("@/views/subLedgerManage/index"),
+      meta: { index: 1 },
+    },
     // 任务消息
-    { path: '/taskMessage', name: 'taskMessage', component: () => import('@/views/taskMessage/index'), meta: { index: 1 } },
+    {
+      path: "/taskMessage",
+      name: "taskMessage",
+      component: () => import("@/views/taskMessage/index"),
+      meta: { index: 1 },
+    },
     // 设备审批
-    { path: '/taskEquipment', name: 'taskEquipment', component: () => import('@/views/taskMessage/equipment'), meta: { index: 1 } },
+    {
+      path: "/taskEquipment",
+      name: "taskEquipment",
+      component: () => import("@/views/taskMessage/equipment"),
+      meta: { index: 1 },
+    },
     // 提现审批
-    { path: '/taskJoinPayMchCheck', name: 'taskJoinPayMchCheck', component: () => import('@/views/taskMessage/joinpayMchCheck'), meta: { index: 1 } },
+    {
+      path: "/taskJoinPayMchCheck",
+      name: "taskJoinPayMchCheck",
+      component: () => import("@/views/taskMessage/joinpayMchCheck"),
+      meta: { index: 1 },
+    },
     // 提现审批详情
-    { path: '/taskJoinPayMchCheckInfo', name: 'taskJoinPayMchCheckInfo', component: () => import('@/views/taskMessage/joinpayMchCheck/info'), meta: { index: 1 } },
+    {
+      path: "/taskJoinPayMchCheckInfo",
+      name: "taskJoinPayMchCheckInfo",
+      component: () => import("@/views/taskMessage/joinpayMchCheck/info"),
+      meta: { index: 1 },
+    },
     // 分销审批
-    { path: '/taskProportion', name: 'taskProportion', component: () => import('@/views/taskMessage/proportion'), meta: { index: 1 } },
+    {
+      path: "/taskProportion",
+      name: "taskProportion",
+      component: () => import("@/views/taskMessage/proportion"),
+      meta: { index: 1 },
+    },
     // 订单中心
-    { path: '/orderCenter', name: 'orderCenter', component: () => import('@/views/orderCenter/index'), meta: { index: 1 } },
+    {
+      path: "/orderCenter",
+      name: "orderCenter",
+      component: () => import("@/views/orderCenter/index"),
+      meta: { index: 1 },
+    },
     // 测试
-    { path: '/test', name: 'test', component: () => import('@/views/test'), meta: { index: 1 } },
+    {
+      path: "/test",
+      name: "test",
+      component: () => import("@/views/test"),
+      meta: { index: 1 },
+    },
     // 标签管理
-    { path: '/labelMan', name: 'labelMan', component: () => import('@/views/labelMan/index'), meta: { index: 1 } },
+    {
+      path: "/labelMan",
+      name: "labelMan",
+      component: () => import("@/views/labelMan/index"),
+      meta: { index: 1 },
+    },
     // 标签管理-新增
-    { path: '/labelManAdd', name: 'labelManAdd', component: () => import('@/views/labelMan/add'), meta: { index: 1 } },
+    {
+      path: "/labelManAdd",
+      name: "labelManAdd",
+      component: () => import("@/views/labelMan/add"),
+      meta: { index: 1 },
+    },
     // 修改价格
-    { path: '/modifyPrice', name: 'modifyPrice', component: () => import('@/views/device/modifyPrice/index'), meta: { index: 1 } },
+    {
+      path: "/modifyPrice",
+      name: "modifyPrice",
+      component: () => import("@/views/device/modifyPrice/index"),
+      meta: { index: 1 },
+    },
     // 屏蔽/展示商品
-    { path: '/showGoods', name: 'showGoods', component: () => import('@/views/device/showGoods/index'), meta: { index: 1 } },
+    {
+      path: "/showGoods",
+      name: "showGoods",
+      component: () => import("@/views/device/showGoods/index"),
+      meta: { index: 1 },
+    },
     // 修改机器密码
-    { path: '/devicePassword', name: 'devicePassword', component: () => import('@/views/device/devicePassword/index'), meta: { index: 1 } },
+    {
+      path: "/devicePassword",
+      name: "devicePassword",
+      component: () => import("@/views/device/devicePassword/index"),
+      meta: { index: 1 },
+    },
     // 查看定位
-    { path: '/viewPosition', name: 'viewPosition', component: () => import('@/views/device/viewPosition/index'), meta: { index: 1 } },
+    {
+      path: "/viewPosition",
+      name: "viewPosition",
+      component: () => import("@/views/device/viewPosition/index"),
+      meta: { index: 1 },
+    },
     // 设备编辑-编辑规则
-    { path: '/editAdRule', name: 'editAdRule', component: () => import('@/views/device/editAdRule/index'), meta: { index: 1 } },
+    {
+      path: "/editAdRule",
+      name: "editAdRule",
+      component: () => import("@/views/device/editAdRule/index"),
+      meta: { index: 1 },
+    },
     // 跳转空中云汇
-    { path: '/hpp', name: 'Hpp', component: () => import('@/views/Hpp.vue'), meta: { index: 1, noLogin: true } },
-    // 跳转汇付微信支付
-    { path: '/weChatPay', name: 'weChatPay', component: () => import('@/views/weChatPay.vue'), meta: { index: 1, noLogin: true } },
-    // 弹出微信支付
-    { path: '/popPayment', name: 'popPayment', component: () => import('@/views/popPayment.vue'), meta: { index: 1, noLogin: true } },
+    {
+      path: "/hpp",
+      name: "Hpp",
+      component: () => import("@/views/Hpp.vue"),
+      meta: { index: 1, noLogin: true },
+    },
     // 定制logo
-    { path: '/customLogo', name: 'customLogo', component: () => import('@/views/device/customLogo.vue'), meta: { index: 1 } },
+    {
+      path: "/customLogo",
+      name: "customLogo",
+      component: () => import("@/views/device/customLogo.vue"),
+      meta: { index: 1 },
+    },
     // 查看日志
-    { path: '/viewLogs', name: 'viewLogs', component: () => import('@/views/device/viewLogs/index'), meta: { index: 1 } },
+    {
+      path: "/viewLogs",
+      name: "viewLogs",
+      component: () => import("@/views/device/viewLogs/index"),
+      meta: { index: 1 },
+    },
     // 账户操作
-    { path: '/accountOperation', name: 'accountOperation', component: () => import('@/views/accountOperation/index'), meta: { index: 1 } },
+    {
+      path: "/accountOperation",
+      name: "accountOperation",
+      component: () => import("@/views/accountOperation/index"),
+      meta: { index: 1 },
+    },
     // apk管理,广告管理,订单导出 不是所有的帐号能看到
-  ]
+  ],
 });
 // 路由守卫处理
 router.beforeEach((to, from, next) => {
@@ -142,18 +499,22 @@ router.beforeEach((to, from, next) => {
   if (to.meta.noLogin) {
     next();
   } else {
-    const user = getLocal('loginUser');
-    if (!user || user === '') {
+    const user = getLocal("loginUser");
+    if (!user || user === "") {
       // 没有登录信息跳转登录页面
-      router.push('/login');
+      router.push("/login");
     } else {
       const userObject = JSON.parse(user);
       // 登录信息异常跳转登录页面
-      if (!userObject) { router.push('/login'); }
-      if (typeof userObject.id !== 'number') { router.push('/login'); }
+      if (!userObject) {
+        router.push("/login");
+      }
+      if (typeof userObject.id !== "number") {
+        router.push("/login");
+      }
     }
     next();
   }
 });
 
-export default router;
+export default router;

+ 26 - 0
src/service/airwallex/index.js

@@ -0,0 +1,26 @@
+import axios from '../../utils/axios';
+
+// 获取 AuthCode
+export function getAuthCode(getAuthCodeDTO) {
+    return axios.post(`/PAY-SERVER/api/airwallexPay/getAuthCode`, getAuthCodeDTO);
+}
+
+// 创建收款人
+export function createBeneficiary(payloadData) {
+    return axios.post(`/PAY-SERVER/api/airwallexPay/caBeneficiary`, payloadData);
+}
+
+// 新建一笔付款
+export function createPayment(reqData) {
+    return axios.post(`/PAY-SERVER/api/airwallexPay/caPayment`, reqData);
+}
+
+// 查询付款详情
+export function getPaymentById(paymentId) {
+    return axios.get(`/PAY-SERVER/api/airwallex/getPaymentById/${paymentId}`);
+}
+
+// 获取用户钱包详情
+export function getWallet(id) {
+    return axios.get(`/PAY-SERVER/tAirwallexWallet/getWallet?adminId=${id}`);
+}

+ 4 - 0
src/service/user.js

@@ -23,4 +23,8 @@ export function Api_getArea(params) {
 // 地址回显
 export function Api_getAreaDetail(params) {
   return axios.get(`/SZWL-SERVER/tArea/getById`, {params});
+}
+// 是否海外用户
+export function getIfForeign(adminId) {
+  return axios.get(`/SZWL-SERVER/tAdmin/getIfForeign/${adminId}`);
 }

+ 78 - 0
src/styles/airwallex/index.less

@@ -0,0 +1,78 @@
+.airwallexWallet {
+  background-color: #f8f8f8;
+  .amount {
+    margin-top: 40px;
+  }
+  .airwallexWalletBtn {
+    width: 100%;
+    margin-top: 20px;
+    text-align: center;
+    .register {
+      background-color: #4d6add;
+      border-radius: 17px;
+      height: 34px;
+      width: 220px;
+      margin-top: 60px;
+      font-size: 15px;
+      font-family: PingFangSC-Medium;
+    }
+  }
+  .cell-container {
+    margin-top: 20px;
+    /* 自定义间距,根据需要调整 */
+  }
+}
+
+.airwallexPayment {
+  width: 100%;
+  max-width: 100%; /* 设置上面的 div 的最大高度 */
+  background-color: #f8f8f8;
+  min-height: 100vh;
+  overflow: auto;
+  display: flex;
+  flex-direction: column;
+  position: relative;
+  overflow-x: hidden; /* 禁用底部水平滚动条 */
+  .form-container {
+    width: auto;
+    height: 620px;
+    background-repeat: no-repeat;
+    position: relative; /* 设置父容器为相对定位 */
+    // background-color: rgb(252, 240, 230);
+  }
+  // .form-container::after {
+  //   content: "";
+  //   position: absolute;
+  //   bottom: -1px; /* 将伪元素定位在下边框位置 */
+  //   left: 0;
+  //   width: 100%;
+  //   height: 3px; /* 渐变线高度 */
+  //   background-image: linear-gradient(to right, #f00, #0f0); /* 渐变色 */
+  // }
+  .button-container {
+    display: flex;
+    justify-content: space-between;
+    position: fixed; /* 让按钮固定在底部 */
+    bottom: 50px; /* 距离底部的距离 */
+    width: 100%;
+    align-items: center;
+  }
+  .cancel {
+    margin-left: 15%;
+  }
+  .register {
+    margin-right: 15%;
+  }
+}
+
+.payout-form-container {
+  overflow-y: auto; /* 配置右侧垂直滚动条 */
+  padding: 10px;
+  flex-grow: 1;
+}
+
+.beneficiary-form-container {
+  overflow-y: auto; /* 配置右侧垂直滚动条 */
+  padding: 10px;
+  flex-grow: 1;
+}

+ 11 - 0
src/styles/user/index.less

@@ -158,6 +158,17 @@
                         right: 0.2rem;
                         top: 0.4rem;
                     }
+                    
+                    &.airwallexIcon::after {
+                        content: "";
+                        position: absolute;
+                        background: #fff url("../../assets/user/airwallexIcon.png") top center no-repeat;
+                        background-size: 100%;
+                        width: 0.55rem;
+                        height: 0.55rem;
+                        right: 0.2rem;
+                        top: 0.4rem;
+                    }
 
                     &.shandeMchIcon::after {
                         content: "";

+ 5 - 1
src/utils/config.js

@@ -10,11 +10,15 @@ if (process.env.NODE_ENV === 'development') {
     // baseURL = 'http://120.25.151.99:49002/'
     // 编译环境
     // baseURL = 'http://127.0.0.1:8080/'
+    // baseURL = 'https://xavi.c1.sidoc.cn'
 } else {
+    // 判断当前页面的主机名是否包含 'szwltest.sunzee.com.cn'。如果包含,则条件成立(即为 true);否则,条件不成立
     if (window.location.host.indexOf('szwltest.sunzee.com.cn') !== -1) {
-        baseURL = 'https://szwl.sunzee.com.cn/'
+        // baseURL = 'https://szwl.sunzee.com.cn/'
+        baseURL = 'https://szwltest.sunzee.com.cn/'
     } else {
         baseURL = 'https://sz.sunzee.com.cn/'
+        // baseURL = 'https://xavi.c1.sidoc.cn'
     }
 }
 export default {

+ 2 - 1
src/views/Hpp.vue

@@ -1,7 +1,8 @@
 <template>
   <div>
+	<s-header :name="$t('airwallex.sunzee')" :noback="false"></s-header>
     <h2>申泽智能</h2>
-    <button @click="redirectHpp()">Redirect to HPP</button>
+    <button @click="redirectHpp()">去付款Redirect to HPP</button>
   </div>
 </template>
 

+ 280 - 0
src/views/airwallex/beneficiary.vue

@@ -0,0 +1,280 @@
+<template>
+    <div class="airwallexPayment">
+        <s-header :name="$t('airwallex.payment')" :noback="false"></s-header>
+        <br>
+        <div class="form-container">
+            <div id="beneficiary-form-container" class="beneficiary-form-container" style="height: 100%;"></div>
+        </div>
+        <div class="button-container" v-if="showButton">
+            <van-button type="primary" class="cancel" @click="handleCancel">取消</van-button>
+            <van-button id="submit-button" type="primary" class="register" @click="handleSubmit">Submit</van-button>
+        </div>
+    </div>
+</template>
+  
+<script>
+import sHeader from "@/components/SimpleHeader";
+import { init, createElement } from '@airwallex/payouts-web-sdk';
+import { Base64 } from 'js-base64';
+import { getAuthCode, createBeneficiary } from '@/service/airwallex/index';
+import { AIRWALLEX_ADMIN_CLIENTID } from '@/constants/const.js';
+import { onMounted, ref } from 'vue';
+import { useRouter } from 'vue-router';
+import { styleUrl } from '../../common/js/utils';
+
+export default {
+    components: { sHeader },
+    setup() {
+        const router = useRouter();
+        const ready = ref(false);
+        let beneficiaryComponent;
+        const showButton = ref(false);
+        // const beneficiaryComponent = ref(null);
+
+        onMounted(async () => {
+            try {
+                // 生成 code_verifier
+                const codeVerifier = generateCodeVerifier();
+
+                // 生成 code_challenge
+                const codeChallengeStr = await generateCodeChallengeFromVerifier(codeVerifier);
+
+                // 生成 getAuthCode 接口的参数
+                const getAuthCodeDTO = {
+                    code_challenge: codeChallengeStr,
+                    scope: [
+                        // onboarding component
+                        // "w:awx_action:onboarding"
+                        // payout or beneficiary component
+                        "w:awx_action:transfers_edit"
+                    ]
+                };
+
+                console.log("getAuthCodeDTO", getAuthCodeDTO);
+
+                // 调用后端 getAuthCode 接口获取 authCode
+                const authCodeResponse = await getAuthCode(getAuthCodeDTO);
+                const authCodeStr = authCodeResponse.data.authorization_code;
+
+                await init({
+                    langKey: 'en',
+                    env: 'demo',
+                    authCode: authCodeStr,
+                    clientId: AIRWALLEX_ADMIN_CLIENTID,
+                    codeVerifier: codeVerifier,
+                });
+
+                // 调用 SDK 的 createElement 方法创建付款交易单/收款方模块
+                beneficiaryComponent = await createElement(eleType);
+
+                beneficiaryComponent.mount('#beneficiary-form-container');
+
+                beneficiaryComponent.on('ready', () => {
+                    ready.value = true;
+                    // 添加组件渲染后的逻辑
+                    console.log('组件呈现后的逻辑...');
+                });
+                showButton.value = true;
+            } catch (error) {
+                console.error(error);
+                // 处理异常情况
+            }
+        });
+
+        const handleCancel = async () => {
+            router.push({
+                path: '/airwallex',
+            })
+        }
+
+        const handleSubmit = async () => {
+            if (ready.value) {
+                const formResult = await beneficiaryComponent.submit();
+                // Handle form results
+                console.log('submit 执行结果:', formResult);
+
+                // 提取收款人信息字段
+                const { beneficiary, nickname, payment_methods } = formResult.values;
+                const { company_name, entity_type, address, bank_details } = beneficiary;
+
+                // 验证收款人信息是否完整
+                if (!payment_methods || !entity_type || !address || !bank_details || !company_name) {
+                    throw new Error('收款人信息不完整');
+                }
+                
+                // 地址信息
+                const {
+                    city,
+                    country_code,
+                    postcode,
+                    state,
+                    street_address
+                } = address;
+                console.log("地址信息》》》", address);
+                // 验证地址信息是否完整
+                if (
+                    // !city ||
+                    !country_code ||
+                    // !postcode ||
+                    // !state ||
+                    !street_address
+                ) {
+                    throw new Error('地址信息不完整');
+                }
+
+                // 银行信息
+                const {
+                    account_currency,
+                    account_name,
+                    account_number,
+                    account_routing_type1,
+                    account_routing_value1,
+                    bank_country_code,
+                    bank_name,
+                    swift_code,
+                } = bank_details;
+                console.log("银行信息》》》", bank_details);
+                // 验证银行详细信息是否完整
+                if (
+                    !account_currency ||
+                    !account_name ||
+                    !account_number ||
+                    !bank_country_code ||
+                    !bank_name ||
+                    !swift_code
+                ) {
+                    throw new Error('银行详细信息不完整');
+                }
+
+                // 构建请求数据对象
+                const caBeneficiaryReq = {
+                    beneficiary: {
+                        company_name: company_name,
+                        entity_type: entity_type,
+                        address: {
+                            city: city,
+                            country_code: country_code,
+                            postcode: postcode,
+                            state: state,
+                            street_address: street_address,
+                        },
+                        bank_details: {
+                            account_currency: account_currency,
+                            account_name: account_name,
+                            account_number: account_number,
+                            account_routing_type1: account_routing_type1,
+                            account_routing_value1: account_routing_value1,
+                            bank_country_code: bank_country_code,
+                            bank_name: bank_name,
+                            swift_code: swift_code,
+                        },
+                    },
+                    nickname: nickname,
+                    payment_methods: payment_methods,
+                };
+
+                // const { field1, field2, field3 }  = formResult;
+                // let caBeneficiaryReq = {};
+
+                // caBeneficiaryReq.beneficiary = {
+                //     companyName: formResult.values.beneficiary.company_name,
+                //     entityType: formResult.values.beneficiary.entity_type,
+                // }
+                // caBeneficiaryReq.nickname = formResult.values.nickname;
+                // caBeneficiaryReq.paymentMethods = formResult.values.payment_methods;
+
+                // caBeneficiaryReq.beneficiary.address = {
+                //     city: formResult.values.beneficiary.address.city,
+                //     countryCode: formResult.values.beneficiary.address.country_code,
+                //     postcode: formResult.values.beneficiary.address.postcode,
+                //     state: formResult.values.beneficiary.address.state,
+                //     streetAddress: formResult.values.beneficiary.address.street_address,
+                // }
+                // caBeneficiaryReq.beneficiary.bankDetails = {
+                //     accountCurrency: formResult.values.beneficiary.bank_details.account_currency,
+                //     accountName: formResult.values.beneficiary.bank_details.account_name,
+                //     accountNumber: formResult.values.beneficiary.bank_details.account_number,
+                //     accountRoutingType1: formResult.values.beneficiary.bank_details.account_routing_type1,
+                //     accountRoutingValue1: formResult.values.beneficiary.bank_details.account_routing_value1,
+                //     bankCountryCode: formResult.values.beneficiary.bank_details.bank_country_code,
+                //     bankName: formResult.values.beneficiary.bank_details.bank_name,
+                //     swiftCode: formResult.values.beneficiary.bank_details.swift_code,
+                // }
+
+                // 请求后端接口 caBeneficiary
+                const respResult = await createBeneficiary(caBeneficiaryReq);
+                const beneficiaryId = respResult.data.beneficiary_id;
+                console.log("收款人id:", beneficiaryId);
+
+                // if 成功,将 beneficiary_id 缓存下来,跳转到付款单页面
+                if (beneficiaryId) {
+                    router.push({
+                        path: '/airwallexPayout',
+                        query: { beneficiaryId: beneficiaryId }
+                    })
+                }    
+
+
+                // 收款人发起付款请求,调用后端创建付款接口
+                // const paymentId = await createPayment(caPaymentDTO);
+                // console.log("付款交易id:", paymentId);
+
+                // if (paymentId) {
+                //     router.push({
+                //         path: '/paymentDetail',
+                //         query: { paymentId }
+                //     });
+                // }
+            }
+        };
+
+
+        // 生成 code_verifier
+        const dec2hex = (dec) => {
+            return ('0' + dec.toString(16)).slice(-2);
+        };
+
+        const generateCodeVerifier = () => {
+            // 生成 random length for code_verifier which should be between 43 and 128
+            const length = Math.random() * (129 - 43) + 43;
+            const array = new Uint32Array(length / 2);
+            window.crypto.getRandomValues(array);
+
+            return Array.from(array, dec2hex).join('');
+        };
+
+
+        // 生成 code_challenge
+        const sha256 = (plain) => {
+            const encoder = new TextEncoder();
+            const data = encoder.encode(plain);
+            return window.crypto.subtle.digest('SHA-256', data);
+        };
+
+        const base64urlencode = (hashed) => {
+            const bytes = new Uint8Array(hashed);
+            const base64encoded = Base64.fromUint8Array(bytes, true);
+            return base64encoded;
+        };
+
+        const generateCodeChallengeFromVerifier = async (codeVerifier) => {
+            const hashed = await sha256(codeVerifier);
+            const base64encoded = base64urlencode(hashed);
+            return base64encoded;
+        };
+
+        // type 字段:payoutForm(可选),beneficiaryForm
+        const eleType = "beneficiaryForm";
+
+        styleUrl("airwallex");
+
+        return {
+            ready,
+            handleSubmit,
+            showButton,
+            handleCancel
+        }
+    }
+}
+
+</script>

+ 210 - 0
src/views/airwallex/caPayment.vue

@@ -0,0 +1,210 @@
+<template>
+    <div class="airwallexPayment">
+        <s-header :name="$t('airwallex.payout')" :noback="false"></s-header>
+        <br>
+        <!-- 卡片展示付款信息 -->
+        <van-cell-group inset>
+            <van-cell title="您支付" :value="payment_amount + ' ' + source_currency" />
+            <van-cell title="付款日期" :value="payment_date" label="送达需要0~3个工作日" />
+            <!-- <van-cell title="收款方收到" :value="payment_amount + ' ' + payment_currency" /> -->
+        </van-cell-group>
+
+        <br>
+        <!-- 付款原因 -->
+        <van-cell-group inset>
+            <van-field v-model="reason" required is-link readonly label="付款原因" placeholder="选择付款原因"
+                @click="showPicker = true" />
+            <van-popup v-model:show="showPicker" round position="bottom">
+                <van-picker :columns="columns" @cancel="showPicker = false" @confirm="onConfirm" />
+            </van-popup>
+        </van-cell-group>
+
+        <br>
+        <!-- 交易附言 -->
+        <van-form>
+            <van-cell-group inset>
+                <van-field v-model="reference" required label="交易附言" placeholder="此信息可能会展示在收款方银行账单上,帮助收款方甄别此付款。"
+                    :rules="[{ required: true, message: '此项为必填项' }]" />
+            </van-cell-group>
+        </van-form>
+
+        <br>
+        <!-- 备注(选填) -->
+        <van-cell-group inset>
+            <van-field v-model="text" label="备注" placeholder="选填:你可以通过它给审批人或其他用户提供额外信息。" />
+        </van-cell-group>
+
+        <div class="button-container">
+            <van-button type="primary" class="cancel" @click="handleCancel">取消</van-button>
+            <van-button type="primary" class="register" @click="handleSubmit">提交付款</van-button>
+        </div>
+    </div>
+</template>
+<script>
+import sHeader from "@/components/SimpleHeader";
+import { styleUrl } from '../../common/js/utils';
+import { useRouter, useRoute } from 'vue-router';
+import { ref, onMounted } from 'vue';
+import { createPayment } from '@/service/airwallex/index';
+
+
+export default {
+    components: { sHeader },
+    setup() {
+
+        const router = useRouter();
+        const route = useRoute();
+        let caPaymentReq;
+
+        const source_amount = ref();
+        const source_currency = ref();
+        const payment_date = ref();
+        const payment_currency = ref();
+        const payment_amount = ref();
+        const payment_method = ref();
+        const beneficiary_id = ref();
+
+        const reference = ref('');
+        const regerenceError = ref(false);
+
+        const loginUserStr = localStorage.getItem('loginUser');
+        const loginUser = JSON.parse(loginUserStr);
+        const adminId = loginUser.id;
+
+        const columns = [
+            'wages_salary',
+            'donation_charitable_contribution',
+            'personal_remittance',
+            'transfer_to_own_account',
+            'pension',
+            'family_support',
+            'living_expenses',
+            'education_training',
+            'travel',
+            'investment_proceeds',
+            'investment_capital',
+            'loan_credit_repayment',
+            'taxes',
+            'goods_purchased',
+            'business_expenses',
+            'medical_services',
+            'professional_business_services',
+            'technical_services',
+            'other_services',
+            'construction',
+            'freight',
+            'real_estate',
+            'audio_visual_services'
+        ];
+
+        const reason = ref('');
+        const showPicker = ref(false);
+
+        const onConfirm = (selectedItem) => {
+            reason.value = selectedItem;
+            showPicker.value = false;
+        };
+
+        const handleCancel = async () => {
+            router.push({
+                path: '/airwallex',
+                query: {
+
+                }
+            })
+        }
+
+        onMounted(async () => {
+            try {
+                // 获取从 payout 页面获取到的参数
+                // const beneficiaryId = router.currentRoute.value.query.beneficiaryId;
+                // const payment_currency = router.currentRoute.value.query.payment_currency;
+                // const payment_method = router.currentRoute.value.query.payment_method;
+                // const source_currency = router.currentRoute.value.query.source_currency;
+                // const source_amount = router.currentRoute.value.query.source_amount;
+                // const fee_paid_by = router.currentRoute.value.query.fee_paid_by;
+                // const payment_date = router.currentRoute.value.query.payment_date;
+
+                beneficiary_id.value = route.query.beneficiary_id;
+                payment_currency.value = route.query.payment_currency;
+                payment_method.value = route.query.payment_method;
+                source_currency.value = route.query.source_currency;
+
+                payment_date.value = route.query.payment_date;
+                // const fee_paid_by = route.query.fee_paid_by;
+
+                // 注:这里的 payment_amount 用的是 source_amount
+                // source_amount.value = route.query.source_amount;
+                payment_amount.value = route.query.source_amount;
+
+                console.log("beneficiary_id >>> " + beneficiary_id.value);
+                console.log("payment_currency >>> " + payment_currency.value);
+                console.log("payment_method >>> " + payment_method.value);
+                console.log("source_currency >>> " + source_currency.value);
+                console.log("payment_amount >>> " + payment_amount.value);
+
+            } catch (error) {
+                console.error(error);
+                // 处理异常情况
+            }
+        });
+
+
+        const handleSubmit = async () => {
+            if (caPaymentReq !== null) {
+
+                if (reference.value === '') {
+                    regerenceError.value = true;
+                    return;
+                }
+                console.log("reference:::", reference.value);
+                console.log("reason:::", reason.value);
+
+                const caPaymentReq = {
+                    beneficiary_id: beneficiary_id.value,
+                    payment_currency: payment_currency.value,
+                    payment_method: payment_method.value,
+                    reason: reason.value,
+                    reference: reference.value,
+                    // request_id: request_id,
+                    source_currency: source_currency.value,
+                    payment_amount: payment_amount.value,
+                    adminId: adminId
+                }
+
+                // 请求后端接口
+                const resultsResp = await createPayment(caPaymentReq);
+                console.log("resultResp>>>", resultsResp);
+                console.log("paymentId>>>", resultsResp.data);
+
+                if (resultsResp) {
+                    router.push({
+                        path: '/paymentDetail',
+                        query: {
+                            paymentId: resultsResp.data,
+                        }
+                    })
+                }
+            }
+        }
+
+
+        styleUrl("airwallex");
+        return {
+            handleCancel,
+            handleSubmit,
+            source_amount,
+            source_currency,
+            payment_date,
+            payment_currency,
+            payment_amount,
+            reason,
+            columns,
+            onConfirm,
+            showPicker,
+            reference
+        }
+    }
+}
+
+</script>

+ 71 - 0
src/views/airwallex/index.vue

@@ -0,0 +1,71 @@
+<template>
+    <div class="airwallexWallet">
+        <s-header :name="$t('airwallex.wallet')" :noback="false"></s-header>
+        <div class="amount">
+            <van-cell-group inset>
+                <van-cell center :title="$t('airwallex.amount')" :value="amount" label="描述信息:可提取的金额" />
+            </van-cell-group>
+        </div>
+        <br>
+        <div class="cell-container">
+            <van-cell-group inset>
+                <van-cell title="创建付款单" is-link to="/airwallexPayout" />
+                <van-cell title="付款详情页" is-link to="/paymentDetail" />
+                <van-cell title="去百度" is-link url="https://www.baidu.com" />
+            </van-cell-group>
+        </div>
+        <br>
+        <div class="airwallexWalletBtn">
+            <van-button round type="primary" class="register" @click="handleWithdraw">提现</van-button>
+        </div>
+    </div>
+</template>
+
+<script>
+import { useRouter } from 'vue-router';
+import sHeader from "@/components/SimpleHeader";
+import { styleUrl } from '../../common/js/utils';
+import { ref, onMounted } from 'vue';
+import { getWallet } from '@/service/airwallex/index';
+
+export default {
+    setup() {
+        styleUrl("airwallex")
+        const router = useRouter();
+        // TODO: 设置默认金额为 100
+        const amount = ref(0.00);
+
+        const loginUserStr = localStorage.getItem('loginUser');
+        const loginUser = JSON.parse(loginUserStr);
+        const adminId = loginUser.id;
+
+        console.log("adminId>>>", adminId);
+
+        onMounted(async () => {
+            try {
+                // 请求后端接口: 获取钱包信息
+                const resp = await getWallet(adminId);
+                console.log("resp>>>", resp);
+                console.log("resp.data>>>", resp.data);
+                // amount = resp.data.;
+            } catch (error) {
+                console.error(error);
+                // 处理异常情况
+            }
+        })
+
+        const handleWithdraw = () => {
+
+            // 导航到提现页面
+            router.push('/airwallexBeneficiary');
+        };
+
+        return {
+            amount,
+            handleWithdraw
+        };
+    },
+    components: { sHeader },
+
+}
+</script>

+ 54 - 0
src/views/airwallex/paymentDetail.vue

@@ -0,0 +1,54 @@
+<template>
+    <div>
+        <s-header :name="$t('airwallex.paymentDetail')" :noback="false"></s-header>
+        <div>付款详情:</div>
+        
+        <div class="button-container">
+            <van-button round type="primary" @click="backToIndex">关闭</van-button>
+        </div>
+    </div>
+</template>
+  
+<script>
+import sHeader from "@/components/SimpleHeader";
+import { styleUrl } from '../../common/js/utils';
+import { useRouter, useRoute } from "vue-router";
+import { ref, onMounted } from 'vue';
+
+
+export default {
+    setup() {
+
+        const router = useRouter();
+        const route = useRoute();
+        const paymentId = ref();
+
+
+        styleUrl("airwallex");
+
+        onMounted(async () => {
+            try {
+                // 获取从 payout 页面获取到的参数
+                paymentId.value = route.query.paymentId;
+
+                console.log("paymentId >>> " + paymentId.value);
+
+            } catch (error) {
+                console.error(error);
+                // 处理异常情况
+            }
+        });
+
+
+        // 导航到 airwallex 页面
+        const backToIndex = async () => {
+            router.push('/airwallex');
+        }
+        return {
+            backToIndex
+        };
+    },
+    components: { sHeader },
+};
+</script>
+  

+ 279 - 0
src/views/airwallex/payout.vue

@@ -0,0 +1,279 @@
+<template>
+    <div class="airwallexPayment">
+        <s-header :name="$t('airwallex.payout')" :noback="false"></s-header>
+        <br>
+        <div class="form-container">
+            <div id="payout-form-container" class="payout-form-container" style="height: 100%;"></div>
+        </div>
+        <div class="button-container">
+            <van-button type="primary" class="cancel" @click="handleCancel">取消</van-button>
+            <van-button type="primary" class="register" @click="handleSubmit">继续</van-button>
+        </div>
+    </div>
+</template>
+
+<script>
+import sHeader from "@/components/SimpleHeader";
+import { init, createElement } from '@airwallex/payouts-web-sdk';
+import { Base64 } from 'js-base64';
+import { AIRWALLEX_ADMIN_CLIENTID } from '@/constants/const.js';
+import { getAuthCode } from '@/service/airwallex/index';
+import { onMounted, ref } from 'vue';
+import { styleUrl } from '../../common/js/utils';
+import { useRouter, useRoute } from 'vue-router';
+
+
+export default {
+    components: { sHeader },
+    setup() {
+        const router = useRouter();
+        const route = useRoute();
+        const ready = ref(false);
+        let payoutComponent;
+
+        onMounted(async () => {
+            try {
+                // 获取从 beneficiary 页面获取到的 beneficiaryId
+                // const beneficiaryId = router.currentRoute.value.query.beneficiaryId;
+                const beneficiaryId = route.query.beneficiaryId;
+                console.log("beneficiaryId >>> " + beneficiaryId);
+
+                // generate code_verifier
+                const codeVerifier = generateCodeVerifier();
+
+                // generate code_challenge
+                const codeChallengeStr = await generateCodeChallengeFromVerifier(codeVerifier);
+
+                // getAuthCode 接口参数
+                const getAuthCodeDTO = {
+                    code_challenge: codeChallengeStr,
+                    scope: [
+                        "w:awx_action:transfers_edit"
+                    ]
+                };
+
+                console.log("getAuthCodeDTO", getAuthCodeDTO);
+
+                // generate authCode
+                const authCodeResponse = await getAuthCode(getAuthCodeDTO);
+                const authCodeStr = authCodeResponse.data.authorization_code;
+
+                await init({
+                    langKey: 'en',
+                    env: 'demo',
+                    authCode: authCodeStr,
+                    clientId: AIRWALLEX_ADMIN_CLIENTID,
+                    codeVerifier: codeVerifier,
+                });
+
+                // 调用 SDK 的 createElement 方法创建付款交易单/收款方模块
+                payoutComponent = await createElement(eleType, {
+                    defaultValues: {
+                        beneficiary_id: beneficiaryId,
+                        // payment_currency: 'USD',
+                    }
+                });
+
+                payoutComponent.mount('#payout-form-container');
+
+                payoutComponent.on('ready', () => {
+                    ready.value = true;
+                    // 添加组件渲染后的逻辑
+                    console.log('组件呈现后的逻辑...');
+                });
+            } catch (error) {
+                console.error(error);
+                // 处理异常情况
+            }
+        });
+
+        const handleCancel = async () => {
+            router.push({
+                path: '/airwallex',
+            })
+        }
+
+        const handleSubmit = async () => {
+            if (ready.value) {
+                const formResult = await payoutComponent.submit();
+                // Handle form results
+                console.log('submit 执行结果:', formResult);
+
+                const {
+                    values
+                } = formResult;
+
+                const {
+                    beneficiary_id,
+                    payment_currency,
+                    payment_method,
+                    source_currency,
+                    source_amount,
+                    fee_paid_by,
+                    payment_date,
+                } = values;
+
+                // 校验 values 参数
+                if (
+                    !beneficiary_id ||
+                    !payment_currency ||
+                    !payment_method ||
+                    !source_currency
+                    // !reason ||
+                    // !reference ||
+                ) {
+                    throw new Error('缺少必要参数');
+                }
+
+                if (formResult) {
+                    router.push({
+                        path: '/caPayment',
+                        query: {
+                            beneficiary_id: beneficiary_id,
+                            payment_currency: payment_currency,
+                            payment_method: payment_method,
+                            // reason: reason,
+                            // reference: reference,
+                            source_currency: source_currency,
+                            // request_id: request_id,
+                            source_amount: source_amount,
+                            fee_paid_by: fee_paid_by,
+                            payment_date: payment_date,
+                        }
+                    })
+                }
+            }
+        }
+
+        // const handleSubmit = async () => {
+        //     if (ready.value) {
+        //         const formResult = await payoutComponent.submit();
+        //         // Handle form results
+        //         console.log('submit 执行结果:', formResult);
+
+        //         const {
+        //             values, additionalInfo
+        //         } = formResult;
+
+        //         const {
+        //             beneficiary_id,
+        //             source_currency,
+        //             payment_method,
+        //             payment_currency,
+        //             // source_amount,
+        //             // fee_paid_by,
+        //             // payment_date,
+        //         } = values;
+
+
+        //         // 校验 values 参数
+        //         if (
+        //             !beneficiary_id ||
+        //             !payment_currency ||
+        //             !payment_method ||
+        //             // !reason ||
+        //             // !reference ||
+        //             !source_currency
+        //         ) {
+        //             throw new Error('缺少必要参数');
+        //         }
+
+        //         // const reason = ref(additionalInfo.reason);
+
+        //         // 
+        //         // setTimeout(() => {
+        //         //     additionalInfo.value = {
+        //         //         reason: {
+        //         //             label: "Audiovisual services",
+        //         //             value: "audio_visual_services"
+        //         //         },
+        //         //         // 其他理由...
+        //         //     }
+        //         // }, 1000)
+
+        //         // const reason = additionalInfo.value.additionalInfo
+        //         // const regference = additionalInfo
+
+        //         // 把这些参数都带去新的页面,然后再去新的页面获取reason 和 sdfsdfs,最后再去请问
+
+        //         // 构建请求数据对象
+        //         // 后端必须的参数 
+        //         // beneficiary_id, 
+        //         // payment_currency, 
+        //         // payment_method, 
+        //         // reason, 
+        //         // reference, 
+        //         // request_id, 
+        //         // source_currency
+        //         const caPaymentReq = {
+        //             beneficiary_id: beneficiary_id,
+        //             payment_currency: payment_currency,
+        //             payment_method: payment_method,
+        //             // reason: reason,
+        //             // reference: reference,
+        //             // request_id: request_id,
+        //             source_currency: source_currency
+        //         }
+
+        //         // 请求后端接口
+        //         const resultsResp = await createPayment(caPaymentReq);
+        //         console.log("resultResp>>>", resultsResp);
+
+        //         // if 成功,将 
+        //         // if (resultsResp.code === "00000") {
+        //         //     router.push({
+        //         //         path: '/caPayment',
+        //         //         query: { beneficiaryId: beneficiaryId }
+        //         //     })
+        //         // }
+
+        //     }
+        // };
+
+
+        // 生成 code_verifier
+        const dec2hex = (dec) => {
+            return ('0' + dec.toString(16)).slice(-2);
+        };
+
+        const generateCodeVerifier = () => {
+            // 生成 random length for code_verifier which should be between 43 and 128
+            const length = Math.random() * (129 - 43) + 43;
+            const array = new Uint32Array(length / 2);
+            window.crypto.getRandomValues(array);
+
+            return Array.from(array, dec2hex).join('');
+        };
+
+
+        // 生成 code_challenge
+        const sha256 = (plain) => {
+            const encoder = new TextEncoder();
+            const data = encoder.encode(plain);
+            return window.crypto.subtle.digest('SHA-256', data);
+        };
+
+        const base64urlencode = (hashed) => {
+            const bytes = new Uint8Array(hashed);
+            const base64encoded = Base64.fromUint8Array(bytes, true);
+            return base64encoded;
+        };
+
+        const generateCodeChallengeFromVerifier = async (codeVerifier) => {
+            const hashed = await sha256(codeVerifier);
+            const base64encoded = base64urlencode(hashed);
+            return base64encoded;
+        };
+
+        // type 字段:payoutForm(可选),beneficiaryForm
+        const eleType = "payoutForm";
+
+        styleUrl("airwallex");
+        return {
+            ready,
+            handleSubmit,
+            handleCancel
+        }
+    }
+}
+</script>

+ 16 - 13
src/views/register.vue

@@ -139,6 +139,8 @@ export default {
       time: 0
     });
 
+    let phoneOrEmailStr = ref('');
+
     const router = useRouter();
 
     // 注册点击
@@ -148,15 +150,17 @@ export default {
         return false;
       }
       const { data } = await tAdminSave({
-        username: username.value,
-        name: name.value,
-        password: md5(password.value),
-        ifForeign: ifForeign.value,
-        phone: phone.value,
-        email: email.value,
-        code: code.value,
-        companyType: '0',
+          username: username.value,
+          name: name.value,
+          password: md5(password.value),
+          ifForeign: ifForeign.value,
+          // phone: phone.value,
+          // email: email.value,
+          phoneOrEmail: phoneOrEmailStr,
+          code: code.value,
+          companyType: '0'
       });
+
       if (data.code === '00000') {
         Toast('注册成功');
         router.push({ path: '/login' });
@@ -165,19 +169,18 @@ export default {
       }
     };
 
-    let phoneOrEmail = '';
     // 发送验证码
     const seedVerCode = async () => {
       if (ifForeign.value === '1') {
-        phoneOrEmail = email.value;
+        phoneOrEmailStr = email.value;
       } else if (ifForeign.value === '0' && logonMode.value === '10') {
-        phoneOrEmail = phone.value;
+        phoneOrEmailStr = phone.value;
       } else {
-        phoneOrEmail = email.value;
+        phoneOrEmailStr = email.value;
       }
       const { data } = await sentRegisterCode({
         ifForeign: ifForeign.value,
-        phoneOrEmail: phoneOrEmail
+        phoneOrEmail: phoneOrEmailStr
       });
       console.log('seedVerCodeSuccess', data);
       if (data.code === '00000') {

+ 33 - 5
src/views/user.vue

@@ -125,15 +125,23 @@
           </div>
 
           <!-- 提现帐号 -->
-          <div class="taskListRow flex-col" @click="pushPageList('/joinpayMch')">
+          <div v-if="isInland" class="taskListRow flex-col" @click="pushPageList('/joinpayMch')">
             <div class="taskIcon joinPayMchIcon"></div>
             <div class="taskRight">
               <div class="taskTitle">{{ $t("user.withdrawalAccountNo") }}</div>
             </div>
           </div>
 
+          <!-- Airwallex 钱包 -->
+          <div v-if="isAbroad" class="taskListRow flex-col" @click="pushPageList('/airwallex')">
+            <div class="taskIcon airwallexIcon"></div>
+            <div class="taskRight">
+              <div class="taskTitle">{{ $t("user.airwallex") }}</div>
+            </div>
+          </div>
+
           <!-- 备用提现账号 -->
-          <div class="taskListRow flex-col" @click="pushPageList('/huifuMch')">
+          <div v-if="isInland" class="taskListRow flex-col" @click="pushPageList('/huifuMch')">
             <div class="taskIcon shandeMchIcon"></div>
             <div class="taskRight">
               <div class="taskTitle">
@@ -162,7 +170,7 @@
           </div>
 
           <!-- 自动充值 -->
-          <div class="taskListRow flex-col" @click="operUnipay()">
+          <div v-if="isInland" class="taskListRow flex-col" @click="operUnipay()">
             <div class="taskIcon selfPayIcon"></div>
             <div class="taskRight">
               <div class="taskTitle">{{ $t("user.selfRecharging") }}</div>
@@ -207,7 +215,7 @@ import {
   $M_PhoneTest,
 } from "@/common/js/utils";
 import { useRouter } from "vue-router";
-import { tAdminGetRelation, tAdminSetRelationAdmin } from "@/service/user";
+import { tAdminGetRelation, tAdminSetRelationAdmin, getIfForeign } from "@/service/user";
 import { Toast } from "vant";
 import { useI18n } from "vue-i18n";
 import { styleUrl } from "../common/js/utils";
@@ -435,9 +443,26 @@ export default {
         isInWeChat.value = true;
       }
     };
+    // 是否内陆或海外
+    const isInland = ref(true);
+    const isAbroad = ref(false);
+    const checkIsAbroad = async () => {
+      try {
+        const { data } = await getIfForeign(user.id);
+        console.log("isAbroad >>> ", data);
 
+        if (data.data === '1') {
+          // TODO: 这里先把isAbroad设置为fasle,等开发完成再改成true;
+          isAbroad.value = false;
+          isInland.value = false;
+        }
+      } catch (error) {
+        console.error(error);
+      }
+    };
     onMounted(() => {
       checkInWechat();
+      checkIsAbroad();
     })
     // 获取回显的值
     const getAreaName = (e) => {
@@ -467,8 +492,11 @@ export default {
       areaPopFinish,
       isInWeChat,
       getAreaName,
+      isAbroad,
+      checkIsAbroad,
+      isInland
     };
-  },
+  }
 };
 </script>