2026-09-09 11:46:36 +08:00
|
|
|
|
<template>
|
2026-09-09 12:00:13 +08:00
|
|
|
|
<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>
|
2026-09-09 11:46:36 +08:00
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
|
import NavHeader from "@/components/header.vue";
|
2026-09-09 12:00:13 +08:00
|
|
|
|
import { appDypayFun } from "@/utils/douyin-pay.js";
|
2026-09-09 11:46:36 +08:00
|
|
|
|
|
|
|
|
|
|
export default {
|
2026-09-09 12:00:13 +08:00
|
|
|
|
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
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
2026-09-09 11:46:36 +08:00
|
|
|
|
};
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
|
|
.test_page {
|
|
|
|
|
|
min-height: 100vh;
|
|
|
|
|
|
background-color: #F6F7FB;
|
|
|
|
|
|
padding-bottom: 60rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.test_container {
|
|
|
|
|
|
padding: 24rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.card_box {
|
|
|
|
|
|
background: #FFFFFF;
|
|
|
|
|
|
border-radius: 20rpx;
|
|
|
|
|
|
padding: 28rpx;
|
|
|
|
|
|
margin-bottom: 24rpx;
|
|
|
|
|
|
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.04);
|
|
|
|
|
|
|
|
|
|
|
|
.card_title {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
margin-bottom: 20rpx;
|
|
|
|
|
|
|
|
|
|
|
|
.title_text {
|
|
|
|
|
|
font-size: 30rpx;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
color: #1F2937;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.tag_badge {
|
|
|
|
|
|
font-size: 22rpx;
|
|
|
|
|
|
padding: 4rpx 14rpx;
|
|
|
|
|
|
border-radius: 20rpx;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
|
|
|
|
|
|
&.badge_app {
|
|
|
|
|
|
background-color: #EDE9FE;
|
|
|
|
|
|
color: #7934F6;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
&.badge_h5 {
|
|
|
|
|
|
background-color: #E0F2FE;
|
|
|
|
|
|
color: #0284C7;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.clear_link {
|
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
color: #7934F6;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.info_grid {
|
|
|
|
|
|
background: #F9FAFB;
|
|
|
|
|
|
border-radius: 12rpx;
|
|
|
|
|
|
padding: 16rpx 20rpx;
|
|
|
|
|
|
|
|
|
|
|
|
.info_row {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
font-size: 26rpx;
|
|
|
|
|
|
margin-bottom: 8rpx;
|
|
|
|
|
|
|
|
|
|
|
|
&:last-child {
|
|
|
|
|
|
margin-bottom: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.info_label {
|
|
|
|
|
|
color: #6B7280;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.info_val {
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
color: #111827;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.btn_row {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
gap: 16rpx;
|
|
|
|
|
|
|
|
|
|
|
|
.mini_btn {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
border-radius: 12rpx;
|
|
|
|
|
|
line-height: 2.2;
|
|
|
|
|
|
margin: 0;
|
|
|
|
|
|
border: none;
|
|
|
|
|
|
|
|
|
|
|
|
&.check_btn {
|
|
|
|
|
|
background: #F3F4F6;
|
|
|
|
|
|
color: #374151;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
&.open_btn {
|
|
|
|
|
|
background: #EDE9FE;
|
|
|
|
|
|
color: #7934F6;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.preset_section {
|
|
|
|
|
|
margin-bottom: 20rpx;
|
|
|
|
|
|
|
|
|
|
|
|
.section_label {
|
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
color: #6B7280;
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
margin-bottom: 12rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.preset_btn_group {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
|
gap: 12rpx;
|
|
|
|
|
|
|
|
|
|
|
|
.preset_chip {
|
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
color: #7934F6;
|
|
|
|
|
|
background: #F4EFFF;
|
|
|
|
|
|
border: 1rpx solid #E4D4FF;
|
|
|
|
|
|
border-radius: 30rpx;
|
|
|
|
|
|
padding: 8rpx 22rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.tip_box {
|
|
|
|
|
|
background: #FFFBEB;
|
|
|
|
|
|
border: 1rpx solid #FDE68A;
|
|
|
|
|
|
border-radius: 12rpx;
|
|
|
|
|
|
padding: 16rpx 20rpx;
|
|
|
|
|
|
margin-bottom: 24rpx;
|
|
|
|
|
|
|
|
|
|
|
|
.tip_text {
|
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
color: #B45309;
|
|
|
|
|
|
line-height: 1.5;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.form_item {
|
|
|
|
|
|
margin-bottom: 20rpx;
|
|
|
|
|
|
|
|
|
|
|
|
.form_label {
|
|
|
|
|
|
font-size: 26rpx;
|
|
|
|
|
|
color: #374151;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
margin-bottom: 10rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.form_input {
|
|
|
|
|
|
background: #F9FAFB;
|
|
|
|
|
|
border: 1rpx solid #E5E7EB;
|
|
|
|
|
|
border-radius: 12rpx;
|
|
|
|
|
|
height: 72rpx;
|
|
|
|
|
|
padding: 0 20rpx;
|
|
|
|
|
|
font-size: 26rpx;
|
|
|
|
|
|
color: #111827;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.form_textarea {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
|
background: #F9FAFB;
|
|
|
|
|
|
border: 1rpx solid #E5E7EB;
|
|
|
|
|
|
border-radius: 12rpx;
|
|
|
|
|
|
padding: 16rpx 20rpx;
|
|
|
|
|
|
font-size: 26rpx;
|
|
|
|
|
|
color: #111827;
|
|
|
|
|
|
height: 140rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.radio_group {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
gap: 30rpx;
|
|
|
|
|
|
|
|
|
|
|
|
.radio_item {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
font-size: 26rpx;
|
|
|
|
|
|
color: #374151;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
&.half {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
margin-bottom: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.form_row {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
gap: 20rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.action_section {
|
|
|
|
|
|
margin-bottom: 24rpx;
|
|
|
|
|
|
|
|
|
|
|
|
.main_pay_btn {
|
|
|
|
|
|
background: linear-gradient(135deg, #8B5CF6 0%, #7934F6 100%);
|
|
|
|
|
|
color: #FFFFFF;
|
|
|
|
|
|
font-size: 30rpx;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
height: 88rpx;
|
|
|
|
|
|
line-height: 88rpx;
|
|
|
|
|
|
border-radius: 44rpx;
|
|
|
|
|
|
box-shadow: 0 8rpx 20rpx rgba(121, 52, 246, 0.3);
|
|
|
|
|
|
border: none;
|
|
|
|
|
|
|
|
|
|
|
|
&:active {
|
|
|
|
|
|
opacity: 0.9;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.log_console {
|
|
|
|
|
|
background: #1E1E2E;
|
|
|
|
|
|
border-radius: 16rpx;
|
|
|
|
|
|
padding: 20rpx;
|
|
|
|
|
|
height: 380rpx;
|
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
|
|
|
|
|
|
|
.empty_log {
|
|
|
|
|
|
color: #6C7086;
|
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
padding: 60rpx 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.log_item {
|
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
font-family: monospace;
|
|
|
|
|
|
line-height: 1.6;
|
|
|
|
|
|
margin-bottom: 10rpx;
|
|
|
|
|
|
word-break: break-all;
|
|
|
|
|
|
|
|
|
|
|
|
.log_time {
|
|
|
|
|
|
color: #A6ADC8;
|
|
|
|
|
|
margin-right: 12rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
&.log_info .log_content {
|
|
|
|
|
|
color: #CDD6F4;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
&.log_success .log_content {
|
|
|
|
|
|
color: #A6E3A1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
&.log_warn .log_content {
|
|
|
|
|
|
color: #F9E2AF;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
&.log_error .log_content {
|
|
|
|
|
|
color: #F38BA8;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|