fix: 接入抖音原生支付并修复App支付服务缺失
This commit is contained in:
@@ -268,6 +268,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { appDypayFun, prepareDouyinPay, douyinPayTypes, filterDouyinPayWays } from '@/utils/douyin-pay.js';
|
||||
import { ORDER_TYPE, ORDER_STATUS, getValue, LOGISTICS_STATUS_UPDATE } from "@/utils/enumUtils.js";
|
||||
import QrcodePreview from "@/components/qrcode-preview.vue";
|
||||
import {
|
||||
@@ -285,7 +286,6 @@ import {
|
||||
import {
|
||||
appWxpayFun,
|
||||
zfbPayFun,
|
||||
douyinPayFun,
|
||||
jumpWayOk,
|
||||
jumpWayError,
|
||||
} from "@/utils/payUtils.js";
|
||||
@@ -357,7 +357,7 @@ export default {
|
||||
async getWayOption() {
|
||||
console.log("orderInfo", this.orderInfo);
|
||||
let params = {
|
||||
types: "1,2,3",
|
||||
types: douyinPayTypes("1,2,3"),
|
||||
};
|
||||
// #ifdef APP-PLUS
|
||||
params.types = "1,2,3,6"
|
||||
@@ -365,10 +365,10 @@ export default {
|
||||
|
||||
const result = await getSupportPay(params);
|
||||
if (result && result.bizcode === 100) {
|
||||
const data = result.data || [];
|
||||
const data = filterDouyinPayWays(result.data);
|
||||
const amount = this.orderInfo.sumAmount;
|
||||
let flag = data.some((item) =>
|
||||
["wechat", "alipay"].includes(item.type)
|
||||
["wechat", "alipay", "douyin"].includes(item.type)
|
||||
);
|
||||
// 没有支付宝和微信支付
|
||||
if (flag) {
|
||||
@@ -410,6 +410,9 @@ export default {
|
||||
},
|
||||
// 去支付
|
||||
async goPay() {
|
||||
if (this._paySubmitting) return;
|
||||
this._paySubmitting = true;
|
||||
try {
|
||||
const payway = this.wayForm.payway;
|
||||
if (!payway || payway === 0) {
|
||||
this.$refs.uToastRef.show({
|
||||
@@ -422,6 +425,7 @@ export default {
|
||||
id: this.orderInfo.id,
|
||||
payway,
|
||||
};
|
||||
if (!await prepareDouyinPay(payway)) return;
|
||||
const resp = await payment(params);
|
||||
// 提交订单成功,就唤起支付
|
||||
if (resp && resp.bizcode === 100) {
|
||||
@@ -430,7 +434,9 @@ export default {
|
||||
jumpWayOk();
|
||||
return;
|
||||
}
|
||||
if (item.wechat && Object.keys(item.wechat).length !== 0) {
|
||||
if (item.douyin) {
|
||||
await appDypayFun(item);
|
||||
} else if (item.wechat && Object.keys(item.wechat).length !== 0) {
|
||||
this.appWxpay(item.wechat, item.orderId, item.orderNum);
|
||||
} else if (
|
||||
item.alipay &&
|
||||
@@ -438,9 +444,6 @@ export default {
|
||||
item.alipay
|
||||
) {
|
||||
this.zfbPay(item.alipay, item.orderId, item.orderNum);
|
||||
} else if (item.douyin && Object.keys(item.douyin).length !== 0) {
|
||||
// 抖音支付
|
||||
this.appDouying(item.douyin, item.orderId, item.orderNum);
|
||||
} else {
|
||||
this.$refs.uToastRef.show({
|
||||
type: "error",
|
||||
@@ -453,19 +456,10 @@ export default {
|
||||
} else {
|
||||
this.getOrderInfo();
|
||||
}
|
||||
},
|
||||
// app 抖音支付
|
||||
async appDouying(douyin, orderId, orderNum) {
|
||||
try {
|
||||
const result = await douyinPayFun(douyin, orderId, orderNum);
|
||||
console.log("抖音支付发起成功", result);
|
||||
// 处理支付发起成功后的逻辑
|
||||
} catch (error) {
|
||||
console.error("抖音支付失败", error);
|
||||
// 处理支付失败后的逻辑
|
||||
}
|
||||
uni.showToast({ title: error.message || error.msg || '支付请求失败,请查看订单后重试', icon: 'none' });
|
||||
} finally { this._paySubmitting = false; }
|
||||
},
|
||||
|
||||
// app 微信支付
|
||||
async appWxpay(alipay, orderId, orderNum) {
|
||||
try {
|
||||
@@ -888,4 +882,4 @@ export default {
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -45,7 +45,8 @@
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script>
|
||||
import { appDypayFun, prepareDouyinPay, filterDouyinPayWays } from '@/utils/douyin-pay.js';
|
||||
import Header from '@/components/header.vue';
|
||||
import {
|
||||
getRechargeSupportPay,
|
||||
@@ -103,11 +104,14 @@
|
||||
async getWayOption() {
|
||||
const result = await getRechargeSupportPay();
|
||||
if (result && result.bizcode === 100) {
|
||||
this.wayOption = result.data;
|
||||
this.wayOption = filterDouyinPayWays(result.data);
|
||||
}
|
||||
},
|
||||
// 立即充值
|
||||
async rechargeOk() {
|
||||
async rechargeOk() {
|
||||
if (this._paySubmitting) return;
|
||||
this._paySubmitting = true;
|
||||
try {
|
||||
console.log('aaaaa', this.form);
|
||||
const params = this.form;
|
||||
if (!params.amount) {
|
||||
@@ -145,12 +149,15 @@
|
||||
|
||||
console.log("params---", params);
|
||||
|
||||
const result = await recharge(params);
|
||||
if (!await prepareDouyinPay(params.payway)) return;
|
||||
const result = await recharge(params);
|
||||
console.log("result", result);
|
||||
if (result && result.bizcode === 100) {
|
||||
const item = result.data;
|
||||
console.log("item", item);
|
||||
if (item.wechat && Object.keys(item.wechat).length !== 0) {
|
||||
if (item.douyin) {
|
||||
await appDypayFun(item);
|
||||
} else if (item.wechat && Object.keys(item.wechat).length !== 0) {
|
||||
this.appWxpay(item.wechat, item.orderId, item.orderNum);
|
||||
} else if (item.alipay && Object.keys(item.alipay).length !== 0 && item.alipay) {
|
||||
this.zfbPay(item.alipay, item.orderId, item.orderNum);
|
||||
@@ -162,8 +169,11 @@
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
// app 微信支付
|
||||
} catch (error) {
|
||||
uni.showToast({ title: error.message || error.msg || '充值请求失败,请查看订单后重试', icon: 'none' });
|
||||
} finally { this._paySubmitting = false; }
|
||||
},
|
||||
// app 微信支付
|
||||
async appWxpay(alipay, orderId, orderNum) {
|
||||
try {
|
||||
const result = await appWxpayFun(alipay, orderId, orderNum);
|
||||
@@ -263,4 +273,4 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
<style lang="scss" scoped></style>
|
||||
|
||||
@@ -218,10 +218,13 @@
|
||||
<image v-if="item.type == 'alipay'" src="https://static.tbmall.xin/static/new/zfb.png"></image>
|
||||
<image v-if="item.type == 'balance'" src="https://static.tbmall.xin/static/new/bank.png"></image>
|
||||
<image v-if="item.type == 'redpacket'" src="https://static.tbmall.xin/static/new/jf.png"></image>
|
||||
<image v-if="item.type == 'douyin'" src="https://static.tbmall.xin/static/new/jf.png"></image>
|
||||
|
||||
<text v-if="item.type == 'wechat' || item.type == 'alipay'" class="text-32 text-zu"
|
||||
style="margin-left: 20rpx">{{ item.name }}</text>
|
||||
<text v-if="item.type == 'douyin'" aria-hidden="true" style="display: inline-flex; align-items: center; justify-content: center; width: 48rpx; height: 48rpx; border-radius: 50%; background: #161823; color: #fff; font-size: 32rpx; flex-shrink: 0;">♪</text>
|
||||
<text v-if="item.type == 'wechat' || item.type == 'alipay' || item.type == 'douyin'" class="text-32 text-zu"
|
||||
style="margin-left: 20rpx">{{ item.name }}
|
||||
<!-- #ifdef H5 -->
|
||||
<text v-if="item.type == 'douyin'" style="font-size: 24rpx; color: #777; margin-left: 12rpx;">仅 App 支持</text>
|
||||
<!-- #endif -->
|
||||
</text>
|
||||
<text v-else style="margin-left: 20rpx" class="text-32 text-zu">{{ item.name }}
|
||||
<text style="color: #999; margin: 0 10rpx">可用:</text>
|
||||
{{ item.balance }}
|
||||
@@ -317,6 +320,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { appDypayFun, prepareDouyinPay, douyinPayTypes, filterDouyinPayWays } from '@/utils/douyin-pay.js';
|
||||
import Address from "@/components/address.vue";
|
||||
import { getGoodsDetail } from "@/api/product.js";
|
||||
import { getAddress } from "@/api/address.js";
|
||||
@@ -340,7 +344,6 @@ import { getUserInfo } from "@/api/auth.js";
|
||||
import {
|
||||
appWxpayFun,
|
||||
zfbPayFun,
|
||||
douyinPayFun,
|
||||
jumpWayOk,
|
||||
jumpWayError,
|
||||
} from "@/utils/payUtils.js";
|
||||
@@ -609,9 +612,10 @@ export default {
|
||||
|
||||
|
||||
|
||||
parmas.types = douyinPayTypes(parmas.types);
|
||||
const result = await getSupportPay(parmas);
|
||||
if (result && result.bizcode === 100) {
|
||||
const data = result.data || [];
|
||||
const data = filterDouyinPayWays(result.data);
|
||||
// const amount = this.orderInfo.amount;
|
||||
// let flag = data.some((item) =>
|
||||
// ["wechat", "alipay"].includes(item.type)
|
||||
@@ -978,6 +982,10 @@ export default {
|
||||
}
|
||||
},
|
||||
async passPay() {
|
||||
if (this._paySubmitting) return;
|
||||
this._paySubmitting = true;
|
||||
try {
|
||||
if (!await prepareDouyinPay(this.orderInfo.paymentMethod)) return;
|
||||
let params = {
|
||||
addrId: this.orderInfo.address.id, // 收货地址ID
|
||||
//结算的购物车ID,多个以逗号分割,ALL表示全选
|
||||
@@ -1069,7 +1077,9 @@ export default {
|
||||
jumpWayOk();
|
||||
return;
|
||||
}
|
||||
if (item.wechat && Object.keys(item.wechat).length !== 0) {
|
||||
if (item.douyin) {
|
||||
await appDypayFun(item);
|
||||
} else if (item.wechat && Object.keys(item.wechat).length !== 0) {
|
||||
this.appWxpay(item.wechat, item.orderId, item.orderNum);
|
||||
} else if (
|
||||
item.alipay &&
|
||||
@@ -1077,10 +1087,6 @@ export default {
|
||||
item.alipay
|
||||
) {
|
||||
this.zfbPay(item.alipay, item.orderId, item.orderNum);
|
||||
} else if (item.douyin &&
|
||||
Object.keys(item.douyin).length !== 0 &&
|
||||
item.douyin) {
|
||||
this.appDouying(item.douyin, item.orderId, item.orderNum);
|
||||
} else {
|
||||
this.$refs.uToastRef.show({
|
||||
type: "error",
|
||||
@@ -1093,20 +1099,10 @@ export default {
|
||||
} else {
|
||||
this.getOrder();
|
||||
}
|
||||
},
|
||||
|
||||
// app 抖音支付
|
||||
async appDouying(douyin, orderId, orderNum) {
|
||||
try {
|
||||
const result = await douyinPayFun(douyin, orderId, orderNum);
|
||||
console.log("抖音支付发起成功", result);
|
||||
// 处理支付发起成功后的逻辑
|
||||
} catch (error) {
|
||||
console.error("抖音支付失败", error);
|
||||
// 处理支付失败后的逻辑
|
||||
}
|
||||
uni.showToast({ title: error.message || error.msg || '支付请求失败,请查看订单后重试', icon: 'none' });
|
||||
} finally { this._paySubmitting = false; }
|
||||
},
|
||||
|
||||
// app 微信支付
|
||||
async appWxpay(alipay, orderId, orderNum) {
|
||||
try {
|
||||
|
||||
@@ -215,8 +215,13 @@
|
||||
<image v-if="item.type == 'alipay'" src="https://static.tbmall.xin/static/new/zfb.png"></image>
|
||||
<image v-if="item.type == 'balance'" src="https://static.tbmall.xin/static/new/bank.png"></image>
|
||||
<image v-if="item.type == 'redpacket'" src="https://static.tbmall.xin/static/new/jf.png"></image>
|
||||
<text v-if="item.type == 'wechat' || item.type == 'alipay'" class="text-32 text-zu"
|
||||
style="margin-left: 20rpx">{{ item.name }}</text>
|
||||
<text v-if="item.type == 'douyin'" aria-hidden="true" style="display: inline-flex; align-items: center; justify-content: center; width: 48rpx; height: 48rpx; border-radius: 50%; background: #161823; color: #fff; font-size: 32rpx; flex-shrink: 0;">♪</text>
|
||||
<text v-if="item.type == 'wechat' || item.type == 'alipay' || item.type == 'douyin'" class="text-32 text-zu"
|
||||
style="margin-left: 20rpx">{{ item.name }}
|
||||
<!-- #ifdef H5 -->
|
||||
<text v-if="item.type == 'douyin'" style="font-size: 24rpx; color: #777; margin-left: 12rpx;">仅 App 支持</text>
|
||||
<!-- #endif -->
|
||||
</text>
|
||||
<text v-else style="margin-left: 20rpx" class="text-32 text-zu">{{ item.name }}
|
||||
<text style="color: #999; margin: 0 10rpx">可用:</text>
|
||||
{{ item.balance }}
|
||||
@@ -309,7 +314,8 @@
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script>
|
||||
import { appDypayFun, prepareDouyinPay, douyinPayTypes, filterDouyinPayWays } from '@/utils/douyin-pay.js';
|
||||
import Address from "@/components/address.vue";
|
||||
import { getGoodsDetail } from "@/api/product.js";
|
||||
import { getAddress } from "@/api/address.js";
|
||||
@@ -597,9 +603,10 @@ export default {
|
||||
|
||||
|
||||
|
||||
const result = await getSupportPay(parmas);
|
||||
parmas.types = douyinPayTypes(parmas.types);
|
||||
const result = await getSupportPay(parmas);
|
||||
if (result && result.bizcode === 100) {
|
||||
const data = result.data || [];
|
||||
const data = filterDouyinPayWays(result.data);
|
||||
// const amount = this.orderInfo.amount;
|
||||
// let flag = data.some((item) =>
|
||||
// ["wechat", "alipay"].includes(item.type)
|
||||
@@ -943,7 +950,11 @@ export default {
|
||||
this.passPay();
|
||||
}
|
||||
},
|
||||
async passPay() {
|
||||
async passPay() {
|
||||
if (this._paySubmitting) return;
|
||||
this._paySubmitting = true;
|
||||
try {
|
||||
if (!await prepareDouyinPay(this.orderInfo.paymentMethod)) return;
|
||||
let params = {
|
||||
addrId: this.orderInfo.address.id, // 收货地址ID
|
||||
//结算的购物车ID,多个以逗号分割,ALL表示全选
|
||||
@@ -1034,7 +1045,9 @@ export default {
|
||||
jumpWayOk();
|
||||
return;
|
||||
}
|
||||
if (item.wechat && Object.keys(item.wechat).length !== 0) {
|
||||
if (item.douyin) {
|
||||
await appDypayFun(item);
|
||||
} else if (item.wechat && Object.keys(item.wechat).length !== 0) {
|
||||
this.appWxpay(item.wechat, item.orderId, item.orderNum);
|
||||
} else if (
|
||||
item.alipay &&
|
||||
@@ -1054,8 +1067,11 @@ export default {
|
||||
} else {
|
||||
this.getOrder();
|
||||
}
|
||||
},
|
||||
// app 微信支付
|
||||
} catch (error) {
|
||||
uni.showToast({ title: error.message || error.msg || '支付请求失败,请查看订单后重试', icon: 'none' });
|
||||
} finally { this._paySubmitting = false; }
|
||||
},
|
||||
// app 微信支付
|
||||
async appWxpay(alipay, orderId, orderNum) {
|
||||
try {
|
||||
const result = await appWxpayFun(alipay, orderId, orderNum);
|
||||
@@ -1509,4 +1525,4 @@ export default {
|
||||
align-items: baseline;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -1,333 +1,61 @@
|
||||
<template>
|
||||
<view class="test_page">
|
||||
<!-- 顶部导航 -->
|
||||
<NavHeader leftTitle="抖音支付测试" leftPathType="navigateTo" />
|
||||
|
||||
<view class="test_container">
|
||||
<!-- 状态与设备信息卡片 -->
|
||||
<view class="card_box">
|
||||
<view class="card_title">
|
||||
<text class="title_text">📱 设备与环境信息</text>
|
||||
<view class="tag_badge" :class="isApp ? 'badge_app' : 'badge_h5'">
|
||||
{{ envText }}
|
||||
</view>
|
||||
</view>
|
||||
<view class="info_grid">
|
||||
<view class="info_row">
|
||||
<text class="info_label">运行平台:</text>
|
||||
<text class="info_val">{{ platformText }}</text>
|
||||
</view>
|
||||
<view class="info_row">
|
||||
<text class="info_label">抖音安装状态:</text>
|
||||
<text class="info_val" :style="{ color: isDyInstalled ? '#00B578' : '#FA5151' }">
|
||||
{{ dyInstallStatusText }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="btn_row" style="margin-top: 20rpx;">
|
||||
<button class="mini_btn check_btn" @click="checkDouyinInstalled">
|
||||
🔍 检测是否安装抖音
|
||||
</button>
|
||||
<button class="mini_btn open_btn" @click="testDirectOpenDouyin">
|
||||
🚀 直接打开抖音客户端
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 支付测试参数配置 -->
|
||||
<view class="card_box">
|
||||
<view class="card_title">
|
||||
<text class="title_text">⚙️ 支付测试参数</text>
|
||||
</view>
|
||||
|
||||
<!-- 快捷预设模版 -->
|
||||
<view class="preset_section">
|
||||
<text class="section_label">快速填充测试数据:</text>
|
||||
<view class="preset_btn_group">
|
||||
<view class="preset_chip" @click="applyPreset('scheme')">普通App唤起 Scheme</view>
|
||||
<view class="preset_chip" @click="applyPreset('cashier')">模拟收银台 Scheme</view>
|
||||
<view class="preset_chip" @click="applyPreset('h5')">H5收银台链接</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="tip_box">
|
||||
<text class="tip_text">💡 提示:普通的 "snssdk1128://open" 仅能拉起抖音 App 首页。如需弹出【抖音收银台支付窗口】,orderStr 必须包含后端从字节/抖音开放平台获取的真实 pay_token 或收银台参数(如 snssdk1128://pay?pay_token=xxx 或 https://cashier.douyin.com/pay?token=xxx)。</text>
|
||||
</view>
|
||||
|
||||
<view class="form_item">
|
||||
<text class="form_label">支付类型 (type)</text>
|
||||
<radio-group class="radio_group" @change="onTypeChange">
|
||||
<label class="radio_item">
|
||||
<radio value="app" :checked="payType === 'app'" color="#7934F6" style="transform: scale(0.8);" />
|
||||
<text>app</text>
|
||||
</label>
|
||||
<label class="radio_item">
|
||||
<radio value="h5" :checked="payType === 'h5'" color="#7934F6" style="transform: scale(0.8);" />
|
||||
<text>h5</text>
|
||||
</label>
|
||||
</radio-group>
|
||||
</view>
|
||||
|
||||
<view class="form_item">
|
||||
<text class="form_label">支付串 / Scheme / URL (orderStr)</text>
|
||||
<textarea
|
||||
class="form_textarea"
|
||||
v-model="orderStr"
|
||||
placeholder="请输入或粘贴抖音支付链接 / Scheme(如 snssdk1128://... 或 https://...)"
|
||||
></textarea>
|
||||
</view>
|
||||
|
||||
<view class="form_row">
|
||||
<view class="form_item half">
|
||||
<text class="form_label">订单ID (orderId)</text>
|
||||
<input class="form_input" type="number" v-model="orderId" placeholder="例如: 10001" />
|
||||
</view>
|
||||
<view class="form_item half">
|
||||
<text class="form_label">订单编号 (orderNum)</text>
|
||||
<input class="form_input" v-model="orderNum" placeholder="例如: ORD20260905001" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 支付操作区域 -->
|
||||
<view class="action_section">
|
||||
<button class="main_pay_btn" :loading="loading" @click="handleTestPay">
|
||||
⚡ 调用 douyinPayFun 测试支付
|
||||
</button>
|
||||
</view>
|
||||
|
||||
<!-- 运行日志与调试面板 -->
|
||||
<view class="card_box">
|
||||
<view class="card_title">
|
||||
<text class="title_text">📋 运行日志与回调</text>
|
||||
<text class="clear_link" @click="clearLogs">清空日志</text>
|
||||
</view>
|
||||
<scroll-view scroll-y="true" class="log_console">
|
||||
<view v-if="logs.length === 0" class="empty_log">暂无测试日志,点击上方按钮开始测试</view>
|
||||
<view v-for="(log, idx) in logs" :key="idx" class="log_item" :class="'log_' + log.level">
|
||||
<text class="log_time">[{{ log.time }}]</text>
|
||||
<text class="log_content">{{ log.msg }}</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="test_page">
|
||||
<NavHeader leftTitle="抖音支付测试" leftPathType="navigateTo" />
|
||||
<view class="test_container">
|
||||
<view class="card_box">
|
||||
<view class="card_title">抖音 App 原生支付联调</view>
|
||||
<view class="tip_box">
|
||||
<text class="tip_text">粘贴 /order/payment 返回的完整 JSON(含 data.orderNum 和 data.douyin)。使用已集成 tb-douyin-pay 的自定义基座或完整安装包。测试将使用真实订单发起支付;最终结果以服务端查单为准。</text>
|
||||
</view>
|
||||
<view class="form_item">
|
||||
<text class="form_label">接口返回 JSON</text>
|
||||
<textarea class="form_textarea" v-model="paymentJson" placeholder="粘贴接口返回 JSON;也支持直接粘贴含 orderNum、douyin 的 data 对象" />
|
||||
</view>
|
||||
<button class="main_pay_btn" :loading="loading" :disabled="loading" @click="handleTestPay">发起该订单支付</button>
|
||||
</view>
|
||||
<view class="card_box">
|
||||
<view class="card_title">联调结果</view>
|
||||
<text>{{ resultText }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import NavHeader from "@/components/header.vue";
|
||||
import { douyinPayFun, jumpWayOk, jumpWayError } from "@/utils/payUtils.js";
|
||||
import { appDypayFun } from "@/utils/douyin-pay.js";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
NavHeader,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
payType: "app",
|
||||
orderStr: "snssdk1128://open", // 默认测试 scheme
|
||||
orderId: 99999,
|
||||
orderNum: "TEST_ORDER_" + Date.now(),
|
||||
loading: false,
|
||||
isApp: false,
|
||||
platformText: "未知",
|
||||
envText: "H5 / 网页",
|
||||
dyInstallStatusText: "待检测",
|
||||
isDyInstalled: false,
|
||||
logs: [],
|
||||
};
|
||||
},
|
||||
onLoad() {
|
||||
this.initPlatformInfo();
|
||||
this.addLog("页面初始化完成", "info");
|
||||
},
|
||||
methods: {
|
||||
initPlatformInfo() {
|
||||
// #ifdef APP-PLUS
|
||||
this.isApp = true;
|
||||
this.envText = "App 端 (App-Plus)";
|
||||
const platform = uni.getSystemInfoSync().platform;
|
||||
this.platformText = platform === "ios" ? "iOS App" : "Android App";
|
||||
this.checkDouyinInstalled();
|
||||
// #endif
|
||||
|
||||
// #ifdef H5
|
||||
this.isApp = false;
|
||||
this.envText = "H5 浏览器";
|
||||
this.platformText = "Web / H5";
|
||||
this.dyInstallStatusText = "Web端不支持检测安装";
|
||||
// #endif
|
||||
},
|
||||
addLog(msg, level = "info") {
|
||||
const now = new Date();
|
||||
const timeStr = `${String(now.getHours()).padStart(2, "0")}:${String(now.getMinutes()).padStart(2, "0")}:${String(now.getSeconds()).padStart(2, "0")}`;
|
||||
const formattedMsg = typeof msg === "object" ? JSON.stringify(msg, null, 2) : String(msg);
|
||||
this.logs.unshift({
|
||||
time: timeStr,
|
||||
msg: formattedMsg,
|
||||
level: level,
|
||||
});
|
||||
},
|
||||
clearLogs() {
|
||||
this.logs = [];
|
||||
},
|
||||
onTypeChange(e) {
|
||||
this.payType = e.detail.value;
|
||||
this.addLog(`切换支付类型为: ${this.payType}`, "info");
|
||||
},
|
||||
applyPreset(presetType) {
|
||||
if (presetType === "scheme") {
|
||||
this.payType = "app";
|
||||
this.orderStr = "snssdk1128://open";
|
||||
this.addLog("已加载基础唤起 Scheme: snssdk1128://open (仅打开App首页)", "info");
|
||||
} else if (presetType === "cashier") {
|
||||
this.payType = "app";
|
||||
this.orderStr = "snssdk1128://pay?pay_token=DEMO_PAY_TOKEN_123456&order_id=TEST_ORDER_001";
|
||||
this.addLog("已加载模拟收银台 Scheme 结构 (真实支付需要后端接口返回的合法 pay_token)", "info");
|
||||
} else if (presetType === "h5") {
|
||||
this.payType = "h5";
|
||||
this.orderStr = "https://cashier.douyin.com/pay?token=DEMO_PAY_TOKEN_123456";
|
||||
this.addLog("已加载 H5 收银台链接预设", "info");
|
||||
}
|
||||
},
|
||||
// 检测抖音是否已安装 (iOS & Android)
|
||||
checkDouyinInstalled() {
|
||||
// #ifdef APP-PLUS
|
||||
const platform = uni.getSystemInfoSync().platform;
|
||||
let installed = false;
|
||||
let foundPkg = "";
|
||||
try {
|
||||
if (platform === "android") {
|
||||
const androidPkgs = [
|
||||
{ name: "抖音", pname: "com.ss.android.ugc.aweme" },
|
||||
{ name: "抖音极速版", pname: "com.ss.android.ugc.aweme.lite" },
|
||||
{ name: "抖音火山版", pname: "com.ss.android.ugc.live" },
|
||||
];
|
||||
for (const pkg of androidPkgs) {
|
||||
if (plus.runtime.isApplicationExist({ pname: pkg.pname })) {
|
||||
installed = true;
|
||||
foundPkg = pkg.name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (platform === "ios") {
|
||||
const iosSchemes = [
|
||||
{ name: "抖音", action: "snssdk1128://" },
|
||||
{ name: "抖音(douyin)", action: "douyin://" },
|
||||
{ name: "抖音极速版", action: "snssdk141://" },
|
||||
];
|
||||
for (const sch of iosSchemes) {
|
||||
if (plus.runtime.isApplicationExist({ action: sch.action })) {
|
||||
installed = true;
|
||||
foundPkg = sch.name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.isDyInstalled = installed;
|
||||
this.dyInstallStatusText = installed ? `已检测到 (${foundPkg}) ✅` : "未检测到 ❌";
|
||||
this.addLog(`检测抖音客户端安装状态: ${this.dyInstallStatusText}`, installed ? "success" : "warn");
|
||||
if (!installed && platform === "ios") {
|
||||
this.addLog("说明: iOS检测需要将 Scheme 加入 LSApplicationQueriesSchemes。若在【标准基座】中调试,因标准基座无此配置会返回未检测到,需使用【自定义基座】运行", "info");
|
||||
}
|
||||
} catch (e) {
|
||||
this.dyInstallStatusText = "检测异常";
|
||||
this.addLog(`检测安装状态发生异常: ${e.message}`, "error");
|
||||
}
|
||||
// #endif
|
||||
|
||||
// #ifndef APP-PLUS
|
||||
this.addLog("当前环境为非 App 环境,无法直接调用 5+ isApplicationExist", "warn");
|
||||
// #endif
|
||||
},
|
||||
// 直接测试打开抖音客户端
|
||||
testDirectOpenDouyin() {
|
||||
this.addLog(`尝试打开抖音: ${this.orderStr || 'snssdk1128://open'}`, "info");
|
||||
const targetUrl = this.orderStr || "snssdk1128://open";
|
||||
// #ifdef APP-PLUS
|
||||
let opened = false;
|
||||
if (plus.os.name === "iOS") {
|
||||
try {
|
||||
const UIApplication = plus.ios.importClass("UIApplication");
|
||||
const NSURL = plus.ios.importClass("NSURL");
|
||||
const app = UIApplication.sharedApplication();
|
||||
const nsUrl = NSURL.URLWithString(targetUrl);
|
||||
if (app && nsUrl) {
|
||||
if (app.openURL(nsUrl)) {
|
||||
opened = true;
|
||||
this.addLog("iOS 原生 Native.js 成功拉起客户端", "success");
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn(e);
|
||||
}
|
||||
} else if (plus.os.name === "Android") {
|
||||
try {
|
||||
const Intent = plus.android.importClass("android.content.Intent");
|
||||
const Uri = plus.android.importClass("android.net.Uri");
|
||||
const main = plus.android.runtimeMainActivity();
|
||||
const intent = new Intent(Intent.ACTION_VIEW, Uri.parse(targetUrl));
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
main.startActivity(intent);
|
||||
opened = true;
|
||||
this.addLog("Android 原生 Native.js Intent 成功拉起客户端", "success");
|
||||
} catch (e) {
|
||||
console.warn(e);
|
||||
}
|
||||
}
|
||||
if (!opened) {
|
||||
plus.runtime.openURL(
|
||||
targetUrl,
|
||||
(err) => {
|
||||
this.addLog(`打开抖音失败: ${JSON.stringify(err)}`, "error");
|
||||
const isSim = plus.navigator && plus.navigator.isSimulator ? plus.navigator.isSimulator() : false;
|
||||
if (isSim) {
|
||||
this.addLog("提示: iOS模拟器未安装抖音客户端,无法响应 snssdk1128:// Scheme,请使用安装了抖音的真机测试", "warn");
|
||||
} else if (err && err.code === -3) {
|
||||
this.addLog("提示: 错误 code -3 说明设备上未检测到抖音应用或Scheme未添加白名单,请确认真机上已安装抖音", "warn");
|
||||
}
|
||||
uni.showToast({
|
||||
title: isSim ? "模拟器不支持打开Scheme,请在真机测试" : "拉起失败,请确认是否已安装抖音",
|
||||
icon: "none",
|
||||
duration: 3000,
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
// #endif
|
||||
// #ifdef H5
|
||||
window.location.href = targetUrl;
|
||||
this.addLog("已在 H5 环境尝试跳转: " + targetUrl, "info");
|
||||
// #endif
|
||||
},
|
||||
// 调用 payUtils.js 中的 douyinPayFun
|
||||
async handleTestPay() {
|
||||
if (!this.orderStr) {
|
||||
uni.showToast({
|
||||
title: "请先输入支付串或链接",
|
||||
icon: "none",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const payParams = {
|
||||
type: this.payType,
|
||||
orderStr: this.orderStr,
|
||||
};
|
||||
|
||||
this.loading = true;
|
||||
this.addLog(`开始调用 douyinPayFun,入参: ${JSON.stringify(payParams)}`, "info");
|
||||
|
||||
try {
|
||||
const result = await douyinPayFun(payParams, this.orderId, this.orderNum);
|
||||
this.addLog(`douyinPayFun 调用完成返回: ${JSON.stringify(result)}`, "success");
|
||||
} catch (err) {
|
||||
this.addLog(`douyinPayFun 抛出错误: ${JSON.stringify(err)}`, "error");
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
components: { NavHeader },
|
||||
data() {
|
||||
return { paymentJson: "", loading: false, resultText: "尚未调用支付" };
|
||||
},
|
||||
methods: {
|
||||
async handleTestPay() {
|
||||
if (this.loading) return;
|
||||
// #ifndef APP-PLUS
|
||||
this.resultText = "请使用已集成原生插件的 Android/iOS App 测试";
|
||||
return;
|
||||
// #endif
|
||||
// #ifdef APP-PLUS
|
||||
this.loading = true;
|
||||
try {
|
||||
const response = JSON.parse(this.paymentJson);
|
||||
if (response.bizcode != null && response.bizcode !== 100) throw new Error("请使用下单成功的接口返回");
|
||||
const payment = response.data || response;
|
||||
if (!payment.orderNum || !payment.douyin) throw new Error("缺少 orderNum 或 douyin");
|
||||
this.resultText = "正在调用原生 SDK,返回后查询订单状态";
|
||||
const result = await appDypayFun(payment);
|
||||
const labels = { paid: "服务端确认支付成功", failed: "服务端确认支付未成功", pending: "结果待确认,请稍后查看订单", error: "调用失败" };
|
||||
this.resultText = result ? (result.message || labels[result.state] || "结果待确认") : "支付正在处理中";
|
||||
} catch (error) {
|
||||
this.resultText = error.message || "调用失败";
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
// #endif
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user