feat: 订单加贡献值

This commit is contained in:
2026-09-11 19:13:31 +08:00
parent 75bbbf9089
commit 9b09d6469d
9 changed files with 808 additions and 364 deletions
+1 -1
View File
@@ -15,7 +15,7 @@
"iOSProjectStandardBaseHistory" : {
"current" : "iOS_debug_5.24.ipa"
},
"playground" : "custom",
"playground" : "standard",
"runSignStatus" : 0,
"type" : "uni-app:app-ios"
},
+2 -2
View File
@@ -2,8 +2,8 @@
"name" : "信任桥",
"appid" : "__UNI__4910728",
"description" : "信任桥优品是一款集线上商城、线下联盟商家的DAO聚合商城;通过“有趣”“有利”“有希望”的卖货玩法,吸引消费者、推广者、商家、投资人参与生态,共同打造共创共享的全球产业生态。",
"versionName" : "1.0.6",
"versionCode" : 175,
"versionName" : "1.0.8",
"versionCode" : 176,
"transformPx" : false,
/* 5+App特有相关 */
"app-plus" : {
+180 -1
View File
@@ -285,6 +285,55 @@
</view>
</up-popup>
<!-- 确认收货成功弹窗 -->
<up-popup :show="receiptSuccessShow" mode="center" :round="16" :closeOnClickOverlay="true"
@close="receiptSuccessShow = false">
<view class="receipt_success_popup">
<!-- 顶部对勾图标与标题 -->
<image class="receipt_icon_img" src="https://static.tbmall.xin/static/mine-purse/icon_arrow_black_3.png"
mode="aspectFit"></image>
<view class="receipt_title">收货成功</view>
<!-- 贡献值 -->
<view class="receipt_item_group">
<view class="receipt_row">
<text class="receipt_label">贡献值</text>
<text class="receipt_value">+{{ receiptOrderItem.expendNum || 0 }}</text>
</view>
<view class="receipt_row sub_row" @click="goToPurse">
<text class="receipt_sub_text">可在【我的-钱包】中查看</text>
<view class="receipt_action">
<text class="action_text">去查看</text>
<u-icon name="arrow-right" size="12" color="#808080"></u-icon>
</view>
</view>
</view>
<view class="receipt_divider"></view>
<!-- 抽奖次数 -->
<view class="receipt_item_group">
<view class="receipt_row">
<text class="receipt_label">抽奖次数</text>
<text class="receipt_value">+{{ receiptOrderItem.raffleNum || 0 }}次</text>
</view>
<view class="receipt_row sub_row" @click="goToLottery">
<text class="receipt_sub_text">可在【首页-抽奖】中参与</text>
<view class="receipt_action">
<text class="action_text">去查看</text>
<u-icon name="arrow-right" size="12" color="#808080"></u-icon>
</view>
</view>
</view>
<!-- 底部确定按钮 -->
<view class="receipt_confirm_btn" @click="receiptSuccessShow = false">
确定
</view>
</view>
</up-popup>
<!-- 腾讯电子签H5 → 集成到UniApp -->
<web-view v-if="signUrl" :src="signUrl" @message="handleMessage"></web-view>
@@ -427,7 +476,9 @@ export default {
deleteShow: false,
deleteInfo: {},
mpWarpStyle: {},
mpHeaderStyle: {}
mpHeaderStyle: {},
receiptSuccessShow: false, // 确认收货成功弹窗
receiptOrderItem: {}, // 确认收货的当前订单对象
};
},
onLoad(options) {
@@ -845,6 +896,7 @@ export default {
content: "是否确认收货?",
success: function (res) {
if (res.confirm) {
console.log("是否确认收货?", item)
then.confirmReceiptFun(item);
}
},
@@ -856,6 +908,8 @@ export default {
};
const resp = await confirmReceipt(params);
if (resp && resp.bizcode === 100) {
this.receiptOrderItem = item;
this.receiptSuccessShow = true;
this.orderList = [];
this.form.page = 1;
this.loadData();
@@ -866,6 +920,28 @@ export default {
}
}
},
goToPurse() {
this.receiptSuccessShow = false;
uni.navigateTo({
url: '/pages/mine_package/mine_purse/mine_purse',
fail: () => {
uni.navigateTo({
url: 'pages/mine_package/mine_purse/mine_purse',
});
}
});
},
goToLottery() {
this.receiptSuccessShow = false;
uni.navigateTo({
url: '/pages/other_package/nine-grid/nine-grid',
fail: () => {
uni.navigateTo({
url: 'pages/other_package/nine-grid/nine-grid',
});
}
});
},
// 判断是否已经签名
async checkSigned() {
@@ -1351,4 +1427,107 @@ export default {
text-align: center;
}
}
/* 确认收货成功弹窗高保真样式 */
.receipt_success_popup {
width: 580rpx;
background: #ffffff;
border-radius: 32rpx;
padding: 48rpx 36rpx 40rpx;
box-sizing: border-box;
display: flex;
flex-direction: column;
align-items: center;
.receipt_icon_img {
width: 96rpx;
height: 96rpx;
}
.receipt_title {
font-size: 34rpx;
font-weight: bold;
color: #111111;
margin-top: 20rpx;
margin-bottom: 36rpx;
line-height: 1.4;
}
.receipt_item_group {
width: 100%;
display: flex;
flex-direction: column;
.receipt_row {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
.receipt_label {
font-size: 30rpx;
font-weight: bold;
color: #111111;
line-height: 1.4;
}
.receipt_value {
font-size: 32rpx;
font-weight: bold;
color: #7934f6;
line-height: 1.4;
}
}
.sub_row {
margin-top: 10rpx;
.receipt_sub_text {
font-size: 24rpx;
color: #666666;
line-height: 1.4;
}
.receipt_action {
display: flex;
flex-direction: row;
align-items: center;
cursor: pointer;
.action_text {
font-size: 24rpx;
color: #666666;
margin-right: 4rpx;
}
}
}
}
.receipt_divider {
width: 100%;
height: 1rpx;
background: #f0f0f0;
margin: 24rpx 0;
}
.receipt_confirm_btn {
width: 100%;
height: 80rpx;
background: #7934f6;
border-radius: 16rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 30rpx;
color: #ffffff;
font-weight: 500;
margin-top: 40rpx;
cursor: pointer;
transition: opacity 0.15s ease;
&:active {
opacity: 0.85;
}
}
}
</style>
@@ -178,6 +178,16 @@
<view class="item_title">下单时间</view>
<view class="item_value">{{ formatDate(orderInfo.ctdate) }}</view>
</view>
<view class="data_item">
<view class="item_title">预估获得贡献值</view>
<view class="item_value">
<image class="coin_icon" src="https://static.tbmall.xin/static/mine-purse/vcoin_1.png"
mode="aspectFit">
</image>
<text class="value_num">{{ orderInfo.expendNum }}</text>
</view>
</view>
</view>
<view class="code_content" v-if="orderInfo.antChainHash">
@@ -261,6 +271,55 @@
<view class="popup_but" @click="wayShow = false"> 确认 </view>
</view>
</up-popup>
<!-- 确认收货成功弹窗 -->
<up-popup :show="receiptSuccessShow" mode="center" :round="16" :closeOnClickOverlay="true"
@close="receiptSuccessShow = false">
<view class="receipt_success_popup">
<!-- 顶部对勾图标与标题 -->
<image class="receipt_icon_img" src="https://static.tbmall.xin/static/mine-purse/icon_arrow_black_3.png"
mode="aspectFit"></image>
<view class="receipt_title">收货成功</view>
<!-- 贡献值 -->
<view class="receipt_item_group">
<view class="receipt_row">
<text class="receipt_label">贡献值</text>
<text class="receipt_value">+{{ orderInfo.expendNum }}</text>
</view>
<view class="receipt_row sub_row" @click="goToPurse">
<text class="receipt_sub_text">可在【我的-钱包】中查看</text>
<view class="receipt_action">
<text class="action_text">去查看</text>
<u-icon name="arrow-right" size="12" color="#808080"></u-icon>
</view>
</view>
</view>
<view class="receipt_divider"></view>
<!-- 抽奖次数 -->
<view class="receipt_item_group">
<view class="receipt_row">
<text class="receipt_label">抽奖次数</text>
<text class="receipt_value">+{{ orderInfo.raffleNum }}次</text>
</view>
<view class="receipt_row sub_row" @click="goToLottery">
<text class="receipt_sub_text">可在【首页-抽奖】中参与</text>
<view class="receipt_action">
<text class="action_text">去查看</text>
<u-icon name="arrow-right" size="12" color="#808080"></u-icon>
</view>
</view>
</view>
<!-- 底部确定按钮 -->
<view class="receipt_confirm_btn" @click="receiptSuccessShow = false">
确定
</view>
</view>
</up-popup>
<up-toast ref="uToastRef"></up-toast>
<QrcodePreview ref="qrcodePreviewRef" :qrcodeVal="qrcodeVal" />
<qiaobao-assistant page-key="pages/mine_package/mine_order_info/mine_order_info" title="订单详情" />
@@ -320,7 +379,10 @@ export default {
isShowBalance: false,
qrcodeVal: '',
returnType: 1,
isExpandExpress: false
isExpandExpress: false,
receiptSuccessShow: false, // 确认收货成功弹窗
expendNum: 0, // 贡献值
raffleNum: 0, // 抽奖次数
};
},
onLoad(options) {
@@ -413,49 +475,49 @@ export default {
if (this._paySubmitting) return;
this._paySubmitting = true;
try {
const payway = this.wayForm.payway;
if (!payway || payway === 0) {
this.$refs.uToastRef.show({
type: "error",
message: "请先选择支付方式",
});
return;
}
const params = {
id: this.orderInfo.id,
payway,
};
if (!await prepareDouyinPay(payway)) return;
const resp = await payment(params);
// 提交订单成功,就唤起支付
if (resp && resp.bizcode === 100) {
const item = resp.data;
if (item.status === 1) {
jumpWayOk();
return;
}
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);
} else {
const payway = this.wayForm.payway;
if (!payway || payway === 0) {
this.$refs.uToastRef.show({
type: "error",
message: "订单支付失败",
message: "请先选择支付方式",
});
setTimeout(() => {
jumpWayError();
}, 2000);
return;
}
const params = {
id: this.orderInfo.id,
payway,
};
if (!await prepareDouyinPay(payway)) return;
const resp = await payment(params);
// 提交订单成功,就唤起支付
if (resp && resp.bizcode === 100) {
const item = resp.data;
if (item.status === 1) {
jumpWayOk();
return;
}
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);
} else {
this.$refs.uToastRef.show({
type: "error",
message: "订单支付失败",
});
setTimeout(() => {
jumpWayError();
}, 2000);
}
} else {
this.getOrderInfo();
}
} else {
this.getOrderInfo();
}
} catch (error) {
uni.showToast({ title: error.message || error.msg || '支付请求失败,请查看订单后重试', icon: 'none' });
} finally { this._paySubmitting = false; }
@@ -509,11 +571,38 @@ export default {
};
const resp = await confirmReceipt(params);
if (resp && resp.bizcode === 100) {
this.orderList = [];
this.form.page = 1;
this.loadData();
if (resp.data) {
if (resp.data.expendNum !== undefined) this.expendNum = resp.data.expendNum;
if (resp.data.raffleNum !== undefined) this.raffleNum = resp.data.raffleNum;
if (resp.data.contribution !== undefined) this.expendNum = resp.data.contribution;
if (resp.data.drawCount !== undefined) this.raffleNum = resp.data.drawCount;
}
this.receiptSuccessShow = true;
this.getOrderInfo();
}
},
goToPurse() {
this.receiptSuccessShow = false;
uni.navigateTo({
url: '/pages/mine_package/mine_purse/mine_purse',
fail: () => {
uni.navigateTo({
url: 'pages/mine_package/mine_purse/mine_purse',
});
}
});
},
goToLottery() {
this.receiptSuccessShow = false;
uni.navigateTo({
url: '/pages/other_package/nine-grid/nine-grid',
fail: () => {
uni.navigateTo({
url: 'pages/other_package/nine-grid/nine-grid',
});
}
});
},
/**
* 去充值
*/
@@ -775,6 +864,15 @@ export default {
line-height: 60rpx;
font-weight: bold;
font-size: 24rpx;
}
.coin_icon {
width: 40rpx;
height: 40rpx;
margin-right: 10rpx;
vertical-align: middle;
}
.item_title {
@@ -784,6 +882,7 @@ export default {
.item_value {
color: #1a1a1a;
display: flex;
align-items: center;
}
.order_way_warp {
@@ -882,4 +981,107 @@ export default {
}
}
}
/* 确认收货成功弹窗高保真样式 */
.receipt_success_popup {
width: 580rpx;
background: #ffffff;
border-radius: 32rpx;
padding: 48rpx 36rpx 40rpx;
box-sizing: border-box;
display: flex;
flex-direction: column;
align-items: center;
.receipt_icon_img {
width: 96rpx;
height: 96rpx;
}
.receipt_title {
font-size: 34rpx;
font-weight: bold;
color: #111111;
margin-top: 20rpx;
margin-bottom: 36rpx;
line-height: 1.4;
}
.receipt_item_group {
width: 100%;
display: flex;
flex-direction: column;
.receipt_row {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
.receipt_label {
font-size: 30rpx;
font-weight: bold;
color: #111111;
line-height: 1.4;
}
.receipt_value {
font-size: 32rpx;
font-weight: bold;
color: #7934f6;
line-height: 1.4;
}
}
.sub_row {
margin-top: 10rpx;
.receipt_sub_text {
font-size: 24rpx;
color: #666666;
line-height: 1.4;
}
.receipt_action {
display: flex;
flex-direction: row;
align-items: center;
cursor: pointer;
.action_text {
font-size: 24rpx;
color: #666666;
margin-right: 4rpx;
}
}
}
}
.receipt_divider {
width: 100%;
height: 1rpx;
background: #f0f0f0;
margin: 24rpx 0;
}
.receipt_confirm_btn {
width: 100%;
height: 80rpx;
background: #7934f6;
border-radius: 16rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 30rpx;
color: #ffffff;
font-weight: 500;
margin-top: 40rpx;
cursor: pointer;
transition: opacity 0.15s ease;
&:active {
opacity: 0.85;
}
}
}
</style>
+1 -1
View File
@@ -163,7 +163,7 @@ export default {
vcoin: {
subTitle: "数字积分:",
detail:
"根据贡献值按照比例进行转换获得1. 商城贡献值10W内的贡献值1:1转换成数字积分2. 商城贡献值10W外的根据数字积分数量和总贡献值及贡献值占比进行获得。",
"根据贡献值按照比例进行转换获得\n1. 商城贡献值10W内的贡献值1:1转换成数字积分\n2. 商城贡献值10W外的根据数字积分数量和总贡献值及贡献值占比进行获得。",
},
rights: {
subTitle: "消费者权益:",
@@ -60,7 +60,7 @@
<view class="content_right_total">
<view>¥<text style="font-size: 36rpx">{{
pItem.totalPrice
}}</text></view>
}}</text></view>
<view>每件到手价¥{{ pItem.unitPrice }}</view>
</view>
<view class="shopping_info_quantity">
@@ -84,7 +84,7 @@
<view class="content_right_total">
<view>¥<text style="font-size: 36rpx">{{
pItem.totalPrice
}}</text></view>
}}</text></view>
<view>每件到手价¥{{ pItem.unitPrice }}</view>
</view>
<view class="shopping_info_quantity">
@@ -108,7 +108,7 @@
<view class="order_freight_item">
<view>运费<text style="color: #c0c3c6; margin-left: 20rpx">{{
getValue(PRODUCT_DELIVERY_TIME, addItem.deliveryTime)
}}</text></view>
}}</text></view>
<view class="value_">
{{ orderInfo.postage ? "¥" + orderInfo.postage : "包邮" }}
</view>
@@ -207,6 +207,17 @@
</view>
</view>
<view class="order_way_warp_two">
<view class="price-view">
<text class="text-32 text-zu">预估获得贡献值</text>
<text class="text-32 text-zu text-bold">
<image class="uni-image" src="https://static.tbmall.xin/static/mine-purse/vcoin_1.png"></image>{{
orderInfo.expendNum
}}
</text>
</view>
</view>
<view class="order_way_warp_two">
<text class="text-32 text-zu">支付方式</text>
<up-radio-group v-model="orderInfo.paymentMethod" placement="column">
@@ -1069,13 +1080,20 @@ export default {
if (this.selectedCoupon) {
params["couponUserId"] = this.getCouponUserId(this.selectedCoupon);
}
console.log("秦星星----2", params);
resp = await settle(params);
}
console.log("getWayOption", resp);
// 提交订单成功,就唤起支付
// 临时缓存订单提交结果(写入前先清空)
uni.removeStorageSync("order_submit_temp");
if (resp) {
uni.setStorageSync("order_submit_temp", {
expendNum:
resp?.data?.expendNum || 0
});
}
if (resp && resp.bizcode === 100) {
console.log("提交订单成功", resp.data);
const item = resp.data;
@@ -1086,13 +1104,13 @@ export default {
if (item.douyin) {
await appDypayFun(item);
} else if (item.wechat && Object.keys(item.wechat).length !== 0) {
this.appWxpay(item.wechat, item.orderId, item.orderNum);
this.appWxpay(item.wechat, item.orderId, item.orderNum, item);
} else if (
item.alipay &&
Object.keys(item.alipay).length !== 0 &&
item.alipay
) {
this.zfbPay(item.alipay, item.orderId, item.orderNum);
this.zfbPay(item.alipay, item.orderId, item.orderNum, item);
} else {
this.$refs.uToastRef.show({
type: "error",
@@ -1110,9 +1128,9 @@ export default {
} finally { this._paySubmitting = false; }
},
// app 微信支付
async appWxpay(alipay, orderId, orderNum) {
async appWxpay(alipay, orderId, orderNum, item) {
try {
const result = await appWxpayFun(alipay, orderId, orderNum);
const result = await appWxpayFun(alipay, orderId, orderNum, item);
console.log("支付成功", result);
// 处理支付成功后的逻辑,如更新订单状态等
} catch (error) {
@@ -1121,9 +1139,9 @@ export default {
}
},
// 支付宝支付
async zfbPay(alipay, orderId, orderNum) {
async zfbPay(alipay, orderId, orderNum, item) {
try {
const result = await zfbPayFun(alipay, orderId, orderNum);
const result = await zfbPayFun(alipay, orderId, orderNum, item);
console.log("支付成功", result);
// 处理支付成功后的逻辑,如更新订单状态等
} catch (error) {
@@ -1321,6 +1339,13 @@ export default {
padding: 4rpx 12rpx;
margin-right: 8rpx;
}
.uni-image {
width: 36rpx;
height: 36rpx;
margin-right: 10rpx;
vertical-align: middle;
}
}
.way-option {
@@ -2,15 +2,33 @@
<view class="order_sumbit_ok_warp">
<Header leftTitle="" left-path-type="switchTab" left-path="/pages/mine/mine" />
<view class="order_sumbit_ok_content_warp">
<view class="ok_img">
<up-image src="https://static.tbmall.xin/static/ok.png" width="120" height="120"
bgColor="#f1f6ff00"></up-image>
<view class="ok_img_msg">支付成功</view>
<!-- 支付成功图标与标题 -->
<view class="success_header">
<image class="success_icon_img" src="https://static.tbmall.xin/static/mine-purse/icon_arrow_black_3.png"
mode="aspectFit"></image>
<view class="success_title">支付成功</view>
</view>
<!-- 贡献值卡片 -->
<view class="contribution_card" v-if="expendNum">
<view class="card_subtitle">本单预计获得</view>
<view class="card_value_row">
<image class="coin_icon" src="https://static.tbmall.xin/static/mine-purse/vcoin_1.png"
mode="aspectFit"></image>
<text class="value_num">{{ expendNum }}</text>
<text class="value_unit">贡献值</text>
</view>
<view class="card_tips">退款或售后将按平台规则调整</view>
</view>
<view class="ok_but" @click="jumpHome">确认</view>
</view>
<qiaobao-assistant page-key="pages/order_package/order_submit_ok/order_submit_ok" title="订单状态与支付" />
</view>
<!-- 底部确定按钮 -->
<view class="bottom_btn_wrap">
<view class="confirm_btn" @click="jumpHome">确定</view>
</view>
<qiaobao-assistant page-key="pages/order_package/order_submit_ok/order_submit_ok" title="订单状态与支付" />
</view>
</template>
<script>
@@ -20,14 +38,37 @@ export default {
components: { Header },
data() {
return {
expendNum: 0, // 贡献值字段
}
},
onLoad(options) {
if (options && options.expendNum !== undefined) {
this.expendNum = options.expendNum;
}
// 获取临时缓存并更新 expendNum,获取完成后清空缓存
const cache = uni.getStorageSync('order_submit_temp');
if (cache !== '' && cache !== null && cache !== undefined) {
let expendNum = 0;
if (typeof cache === 'object') {
expendNum = cache.expendNum !== undefined
? cache.expendNum
: (cache.data?.expendNum !== undefined ? cache.data.expendNum : cache.data?.contribution);
} else {
expendNum = cache;
}
if (expendNum !== undefined && expendNum !== null && expendNum !== '') {
this.expendNum = expendNum;
}
uni.removeStorageSync('order_submit_temp');
}
},
methods: {
jumpHome() {
uni.switchTab({
url: '/pages/home/home',
})
});
}
}
}
@@ -35,31 +76,128 @@ export default {
<style lang="scss" scoped>
.order_sumbit_ok_warp {
height: calc(100vh - 80rpx);
text-align: center;
min-height: 100vh;
background-color: #ffffff;
display: flex;
flex-direction: column;
box-sizing: border-box;
padding-bottom: calc(140rpx + env(safe-area-inset-bottom));
.order_sumbit_ok_content_warp {
padding: 40rpx;
display: flex;
flex-direction: column;
align-items: center;
padding: 48rpx 36rpx 0;
box-sizing: border-box;
}
.ok_img {
display: grid;
.success_header {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
.ok_img_msg {
font-weight: bold;
.success_icon_img {
width: 100rpx;
height: 100rpx;
}
.success_title {
font-size: 36rpx;
color: $app-bt-bj;
font-weight: bold;
color: #111111;
margin-top: 24rpx;
line-height: 1.4;
}
}
.ok_but {
margin-top: 100rpx;
background: $app-bt-bj;
border-radius: 16rpx;
text-align: center;
padding: 20rpx 0;
height: 46rpx;
color: #FFF;
.contribution_card {
width: 100%;
background: #f8f5fe;
border-radius: 24rpx;
padding: 40rpx 32rpx;
margin-top: 56rpx;
box-sizing: border-box;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
.card_subtitle {
font-size: 30rpx;
color: #333333;
font-weight: 500;
line-height: 1.4;
}
.card_value_row {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
margin-top: 18rpx;
.coin_icon {
width: 40rpx;
height: 40rpx;
margin-right: 10rpx;
vertical-align: middle;
}
.value_num {
font-size: 44rpx;
font-weight: bold;
color: #7934f6;
line-height: 1.2;
}
.value_unit {
font-size: 30rpx;
font-weight: 500;
color: #7934f6;
margin-left: 4rpx;
line-height: 1.2;
}
}
.card_tips {
font-size: 26rpx;
color: #999999;
margin-top: 24rpx;
line-height: 1.4;
text-align: center;
}
}
.bottom_btn_wrap {
position: fixed;
left: 0;
right: 0;
bottom: 0;
padding: 20rpx 36rpx;
padding-bottom: calc(24rpx + env(safe-area-inset-bottom));
background: #ffffff;
box-sizing: border-box;
z-index: 99;
.confirm_btn {
width: 100%;
height: 88rpx;
background: #7934f6;
border-radius: 16rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 32rpx;
color: #ffffff;
font-weight: 500;
cursor: pointer;
transition: opacity 0.15s ease;
&:active {
opacity: 0.85;
}
}
}
}
</style>
+140 -7
View File
@@ -82,7 +82,7 @@
<view class="content_data_series">
<!-- 暂时隐藏 -->
<view class="content_data_series_tag" v-if="orderInfo.contribution" @click="onContributionTip">
<image class="uni-image" src="https://static.tbmall.xin/static/mine-purse/vcoin.png"></image>
<image class="uni-image" src="https://static.tbmall.xin/static/mine-purse/vcoin_1.png"></image>
下单预计获得{{ orderInfo.contribution }}贡献值
<image src="/pages/rwa_package/static/tips.png" class="uni-image" style="margin-left: 5rpx;"></image>
</view>
@@ -472,6 +472,48 @@
</view>
</view>
</up-popup>
<!-- 贡献值说明弹窗 -->
<up-popup :show="contributionTipShow" mode="bottom" :round="16" :closeOnClickOverlay="true"
@close="contributionTipShow = false">
<view class="contribution_popup_container">
<!-- 头部 -->
<view class="contribution_popup_header">
<text class="contribution_header_title">贡献值说明</text>
<view class="contribution_header_close" @click="contributionTipShow = false">
<u-icon name="close" size="18" color="#71737c"></u-icon>
</view>
</view>
<!-- 内容主体 -->
<scroll-view scroll-y class="contribution_popup_body">
<view class="contribution_section">
<view class="contribution_section_title">我能获得多少贡献值?</view>
<view class="contribution_text">1.商品详情页中展示为预估获得贡献值。</view>
<view class="contribution_text">2.实际赠送的贡献值将根据订单实付金额及商品贡献系数综合计算,其中商品贡献系数由商品毛利等因素确定。</view>
<view class="contribution_text">3.使用优惠券、发生退款或售后时,贡献值可能相应调整,最终以订单完成后的实际到账为准。</view>
</view>
<view class="contribution_section">
<view class="contribution_section_title">生效条件</view>
<view class="contribution_text">1.收到商品后,在订单中点击【确认收货】时,立马到账。可在【我的-钱包】贡献值进行查看</view>
<view class="contribution_text">2.消费者权益次日到账,可在【我的-钱包】数字积分-消费者权益中进行查看</view>
</view>
<view class="contribution_section">
<view class="contribution_section_title">售后调整</view>
<view class="contribution_text">1.如发生退货/退款,所有的贡献值、消费者权益将会进行扣除。</view>
</view>
</scroll-view>
<!-- 底部按钮 -->
<view class="contribution_popup_footer">
<view class="contribution_btn_confirm" @click="contributionTipShow = false">
我知道了
</view>
</view>
</view>
</up-popup>
<view class="hideCanvasView">
<canvas id="myCanvas" canvas-id="myCanvas" :style="{
@@ -528,6 +570,7 @@ export default {
shareShow: false,
addressShow: false, // 收件地址选择
couponPopupShow: false, // 优惠券弹框显示 (图二)
contributionTipShow: false, // 贡献值说明弹框显示
goodsCouponList: [], // 商品可用优惠券列表
evaluateDialogShow: false, // 评价弹框显示
shareOpen: false,
@@ -655,12 +698,7 @@ export default {
methods: {
assembleAddress,
onContributionTip() {
uni.showModal({
title: '提示',
content: '页面展示的贡献值为预估值。实际赠送的贡献值将根据订单实付金额及商品贡献系数综合计算,其中商品贡献系数由商品毛利等因素确定。使用优惠券、发生退款或售后时,贡献值可能相应调整,最终以订单完成后的实际到账为准。',
showCancel: false,
confirmText: '我知道了'
});
this.contributionTipShow = true;
},
limit999(n) {
const num = Number(n);
@@ -2574,4 +2612,99 @@ export default {
}
}
}
/* 贡献值说明弹窗高保真样式 */
.contribution_popup_container {
background: #ffffff;
border-radius: 32rpx 32rpx 0 0;
display: flex;
flex-direction: column;
max-height: 80vh;
box-sizing: border-box;
.contribution_popup_header {
display: flex;
justify-content: center;
align-items: center;
position: relative;
padding: 32rpx 32rpx 16rpx;
.contribution_header_title {
font-weight: 500;
font-size: 32rpx;
color: #71737c;
}
.contribution_header_close {
position: absolute;
right: 32rpx;
top: 28rpx;
width: 48rpx;
height: 48rpx;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
}
}
.contribution_popup_body {
max-height: 60vh;
padding: 10rpx 36rpx 20rpx;
box-sizing: border-box;
.contribution_section {
margin-bottom: 28rpx;
&:last-child {
margin-bottom: 10rpx;
}
.contribution_section_title {
font-size: 34rpx;
font-weight: bold;
color: #111111;
margin-bottom: 20rpx;
line-height: 1.4;
}
.contribution_text {
font-size: 28rpx;
line-height: 1.75;
color: #666666;
margin-bottom: 16rpx;
&:last-child {
margin-bottom: 0;
}
}
}
}
.contribution_popup_footer {
padding: 20rpx 36rpx;
padding-bottom: calc(24rpx + env(safe-area-inset-bottom));
background: #ffffff;
box-sizing: border-box;
.contribution_btn_confirm {
width: 100%;
height: 88rpx;
background: #7934f6;
border-radius: 16rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 32rpx;
color: #ffffff;
font-weight: 500;
cursor: pointer;
transition: opacity 0.15s ease;
&:active {
opacity: 0.85;
}
}
}
}
</style>
-233
View File
@@ -1,233 +0,0 @@
# 抖音支付:前端调用商城后端接口文档
日期:2026-09-05。适用:商城 App 前端。本文只描述前端调用我们后端的接口,不涉及抖音官方服务端接口、证书配置或插件开发。
## 一、公共约定
测试环境 Base URL:`https://api.o.tbmall.xin`。生产环境沿用项目正式用户端 API 配置,不要使用后台管理 API 地址。
请求头沿用现有登录请求封装:
```http
Authorization: <项目当前环境的应用授权值>
HSM-AUTH: <当前用户登录令牌>
Content-Type: application/x-www-form-urlencoded
```
POST 参数以表单提交,不是 JSON body;GET 使用 URL 查询参数。不要把后台管理 Token 填到 HSM-AUTH。
业务响应统一格式:
```json
{ "bizcode": 100, "errcode": 0, "msg": "成功", "data": {} }
```
`bizcode=100` 表示本次接口调用成功,不等于用户已付款。其他业务码按 msg 提示;HTTP 错误、超时或网络失败不能视作付款成功。以下所有 ID、金额、签名均为示例。
## 二、调用顺序
1. 调用 `/cart/getSupportPay`,判断返回列表是否包含 `type=douyin`。
2. 根据业务场景选择一个下单/支付接口,提交 `payway=douyin`。
3. 保存返回的 `data.orderNum`,把 `data.douyin` 中的支付参数交给 App 支付能力拉起抖音。
4. 用户返回 App 后调用 `/payment/queryResult` 查询结果,只有 `data.state=2` 才提示支付成功。
**重点:支付方式筛选传 `types=6`;实际支付传 `payway=douyin`,不是 `payway=6`。**
## 三、查询支付方式
**POST `/cart/getSupportPay`**
| 参数 | 类型 | 必填 | 说明 |
| ----------- | ------- | ---- | -------------------------------------------- |
| types | string | 否 | 只查抖音传 `6`;多种传 `1,2,6`;全部传 `ALL` |
| isDeduction | boolean | 否 | 默认 false,沿用现有抵扣券结算逻辑 |
请求表单:
```text
types=6&isDeduction=false
```
已启用抖音支付时的响应示例:
```json
{
"bizcode": 100,
"errcode": 0,
"msg": "成功",
"data": [{ "type": "douyin", "name": "抖音支付", "balance": 0 }]
}
```
没有启用对应配置时,列表可能为空。显示名称使用 name,提交支付方式使用 type;balance 不是抖音钱包余额。
## 四、发起支付(按场景选一个)
### 4.1 已创建订单,继续支付
**POST `/order/payment`**
| 参数 | 类型 | 必填 | 说明 |
| ------ | ------ | ---- | ----------------------- |
| id | long | 是 | 待支付的商城业务订单 ID |
| payway | string | 是 | 固定 `douyin` |
```text
id=123456&payway=douyin
```
后端接口还接受可选 password/code,但抖音支付不需要提交。成功响应见第五节。
### 4.2 商品直接购买并支付
**POST `/cart/settlementOrder`**
| 参数 | 类型 | 必填 | 说明 |
| ------------ | ------- | -------- | ------------------------------------ |
| addrId | long | 是 | 收货地址 ID |
| goodsId | long | 是 | 商品 ID |
| specsId | long | 是 | 规格 ID |
| goodsNum | decimal | 是 | 购买数量 |
| payway | string | 本流程是 | `douyin` |
| payway2 | string | 否 | `vcoin` 表示抵扣券,沿用现有结算选择 |
| couponUserId | long | 否 | 已选用户优惠券 ID |
| remark | string | 否 | 现有分组备注 JSON 字符串 |
```text
addrId=10001&goodsId=20001&specsId=30001&goodsNum=1&payway=douyin
```
remark 格式为 `[{"gkey":"结算返回的分组标识","rmk":"备注内容"}]`,通过现有请求封装表单编码。金额由后端计算,不传前端自算金额。优惠券、抵扣券沿用结算规则,不因选择抖音改变适用范围。
### 4.3 购物车结算并支付
**POST `/cart/settle`**
| 参数 | 类型 | 必填 | 说明 |
| ------------ | ------ | ---- | ---------------------------------- |
| addrId | long | 是 | 收货地址 ID |
| cartIds | string | 是 | 购物车 ID 逗号分隔,`ALL` 表示全选 |
| payway | string | 是 | `douyin` |
| couponUserId | long | 否 | 用户优惠券 ID |
| remark | string | 否 | 分组备注 JSON 字符串,同上一接口 |
```text
addrId=10001&cartIds=40001,40002&payway=douyin
```
购物车可能拆分业务订单并合并支付,查询支付结果仍使用本次返回的 orderNum。
### 4.4 余额充值
**POST `/finance/recharge`**
| 参数 | 类型 | 必填 | 说明 |
| -------- | ------- | ---- | -------------------- |
| category | string | 是 | 余额充值传 `balance` |
| amount | decimal | 是 | 充值金额,单位元 |
| payway | string | 是 | `douyin` |
```text
category=balance&amount=1.00&payway=douyin
```
注意:上述四个 POST 都可能创建支付单,请勿反复点击或自动重试创建。新下单接口已经返回支付参数时,不要紧接着再调用 `/order/payment`。
## 五、下单/支付接口统一返回
上述四个接口均返回 PayInfoDto。抖音待支付响应示例(省略其他业务字段):
```json
{
"bizcode": 100,
"errcode": 0,
"msg": "成功",
"data": {
"orderId": 123456,
"orderNum": "PAY_EXAMPLE_001",
"amount": 1.0,
"status": 0,
"douyin": {
"appId": "EXAMPLE_APP_ID",
"mchId": "EXAMPLE_MERCHANT_ID",
"prepayId": "EXAMPLE_PREPAY_ID",
"callbackScheme": "trustbridgeapp",
"packageValue": "Sign=DYPay",
"nonceStr": "0123456789abcdef0123456789abcdef",
"timeStamp": "1788585600",
"sign": "EXAMPLE_BASE64_SIGNATURE"
}
}
}
```
| 字段 | 类型 | 前端用途 |
| --------------------- | ------- | ---------------------------------------------- |
| orderId | long | 后端返回的订单 ID |
| orderNum | string | 保存下来,支付结果查询必须用它 |
| amount | decimal | 实际支付金额(元) |
| status | integer | 此 DTO 中 0=待支付、1=已支付;不同于查单 state |
| douyin | object | App 拉起抖音所需参数 |
| douyin.appId | string | 抖音应用 ID |
| douyin.mchId | string | 抖音商户 ID |
| douyin.prepayId | string | 预支付 ID |
| douyin.callbackScheme | string | App 返回 Scheme |
| douyin.packageValue | string | `Sign=DYPay` |
| douyin.nonceStr | string | 随机字符串 |
| douyin.timeStamp | string | 秒级时间戳,保留字符串类型 |
| douyin.sign | string | 后端生成的签名,原样使用 |
后端已处理签名,前端无需请求商户私钥或另调签名接口。参数缺失时停止拉起,提示支付参数异常并反馈后端,不要自行伪造字段。
若 App 支付桥接要求 SDK 小写字段,映射如下;这不是另一个 HTTP 请求:
```js
const d = response.data.douyin;
const payInfo = {
appid: d.appId,
partnerid: d.mchId,
prepayid: d.prepayId,
package: d.packageValue,
noncestr: d.nonceStr,
timestamp: d.timeStamp,
sign: d.sign,
};
```
## 六、查询支付结果
**GET `/payment/queryResult`**
| 参数 | 类型 | 必填 | 说明 |
| -------- | ------ | ---- | ------------------------------------------------------- |
| orderNum | string | 是 | 发起支付接口返回的 data.orderNum,不是 orderId/prepayId |
```http
GET https://api.o.tbmall.xin/payment/queryResult?orderNum=PAY_EXAMPLE_001
```
```json
{
"bizcode": 100,
"errcode": 0,
"msg": "成功",
"data": { "state": 2 }
}
```
| state | 含义 | 前端处理 |
| ----- | ---------- | -------------------------------- |
| 0 | 订单不存在 | 核对支付编号及环境,不能提示成功 |
| 1 | 支付处理中 | 稍后再次查询 |
| 2 | 支付成功 | 展示成功,刷新订单或充值余额 |
| 3 | 支付失败 | 提示失败,刷新订单状态 |
当前 App 采用最多 5 次、间隔 1.5 秒的查询;这属于前端策略,不是后端强制限制。暂未确认、断网或超时应显示“支付结果确认中”,保存编号以便回前台再次查询,避免直接重复付款。
用户取消或支付 SDK 提示成功后,都需要以服务端查询结果为准。不要调用 `/payment/feedback` 上报成功来替代查单;前端也不需要调用后端的抖音通知/退款回调接口。
## 七、对接范围与发布注意
- 本文按当前工作区后端代码整理;SDK 签名新增字段(packageValue、nonceStr、timeStamp、sign)尚未确认已部署到测试/生产服务器。
- 后台配置已完成不代表预下单、签名、支付回调均验收通过,实际支付链路仍需联调。
- 本次抖音支付是 App 原生支付;H5 仅可检查适用的后端业务请求,不能凭网页调用拉起此原生能力。