bm-bmt/pages/assets/bmt-sign-agreement.vue

463 lines
11 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="asset-page asset-theme bmt-agree-page">
<asset-page-shell title="签约协议" />
<view v-if="signStatus">
<view class="bmt-agree-content glass-panel">
<scroll-view class="bmt-agree-scroll" scroll-y :style="{ height: scrollViewHeight + 'px' }"
:scroll-with-animation="false" :show-scrollbar="false" @scroll="handleScroll">
<text class="bmt-agree-title">{{ signData.name }}</text>
<view class="bmt-agree-desc">
<text class="bmt-agree-text">{{ signData.content || "暂无协议内容" }}</text>
<view v-if="!isReachBottom" class="bmt-agree-tip">请阅读到底部后签约</view>
<view class="bmt-agree-padding"></view>
</view>
</scroll-view>
</view>
<view class="bmt-agree-bottom">
<text class="bmt-agree-bottom__hint">{{ isReachBottom ? "已阅读到底部" : "向下滑动阅读签约" }}</text>
<view class="bmt-agree-bottom__row">
<view class="bmt-agree-btn bmt-agree-btn--ghost" @click="cancel">取消</view>
<view class="bmt-agree-btn bmt-agree-btn--primary"
:class="{ 'is-disabled': !isReachBottom || signing }" @click="toSign">
{{ signing ? "签约中..." : "确认签约" }}
</view>
</view>
<view class="bmt-agree-copy">
<image class="bmt-agree-copy__icon" src="https://imgs.agrimedia.cn/copy-icon-sign.png" mode="aspectFit" />
<text class="bmt-agree-copy__text">易保全在线签约系统</text>
</view>
</view>
</view>
<view v-else class="bmt-agree-success">
<image class="bmt-agree-success__image" src="https://imgs.agrimedia.cn/bm-bmt/success.png" mode="aspectFit" />
<text class="bmt-agree-success__text">恭喜签约完成</text>
<view class="bmt-agree-success__btn" :class="{ 'is-disabled': countdown > 0 }" @click="compute">
{{ countdown > 0 ? `完成(${countdown}s)` : "完成" }}
</view>
</view>
</view>
</template>
<script>
import AssetPageShell from "../../components/asset-page-shell.vue";
import { checkBmtSignCondition, startBmtSigning } from "../../api/bmt";
const READ_BOTTOM_THRESHOLD = 15;
const DONE_COUNTDOWN_SECONDS = 5;
export default {
components: {
AssetPageShell,
},
data() {
return {
signData: {
name: "",
content: "",
},
signStatus: true,
signing: false,
isReachBottom: false,
scrollViewHeight: 0,
scrollTimer: null,
countdownTimer: null,
countdown: 0,
contractId: "",
};
},
onLoad() {
this.loadAgreement();
},
onReady() {
this.$nextTick(() => {
setTimeout(() => {
this.calcScrollViewHeight();
}, 100);
});
},
onShow() {
this.$nextTick(() => {
setTimeout(() => {
this.calcScrollViewHeight();
}, 300);
});
},
onUnload() {
if (this.scrollTimer) {
clearTimeout(this.scrollTimer);
}
this.clearCountdownTimer();
},
methods: {
async loadAgreement() {
try {
// 协议内容与签约 id 都取自 go_to_sign_check_bmt
const data =
(await checkBmtSignCondition({}, {
showLoading: true,
loadingText: "加载中",
})) || {};
this.contractId = String(data.id || "");
this.signData = {
name: String(data.name || "签约协议"),
content: String(data.content || ""),
};
this.$nextTick(() => {
setTimeout(() => {
this.calcScrollViewHeight();
setTimeout(() => {
this.calcScrollViewHeight();
}, 200);
}, 100);
});
} catch (error) {
uni.showToast({
title: (error && error.message) || "获取签约信息失败,请重试",
icon: "none",
});
}
},
calcScrollViewHeight() {
const systemInfo = uni.getSystemInfoSync();
const windowHeight = Number(systemInfo.windowHeight || 0);
const query = uni.createSelectorQuery().in(this);
query.select(".bmt-agree-content").boundingClientRect();
query.select(".bmt-agree-desc").boundingClientRect();
query.select(".bmt-agree-bottom").boundingClientRect();
query.exec((res) => {
const contentRect = res && res[0];
const descRect = res && res[1];
const bottomRect = res && res[2];
const top = contentRect && contentRect.top ? Number(contentRect.top) : 0;
const bottomHeight =
bottomRect && bottomRect.height ? Number(bottomRect.height) : 150;
const available = windowHeight - top - bottomHeight - 16;
this.scrollViewHeight = Math.max(available, 200);
// 内容不足以滚动时,直接视为已读到底部,避免短协议无法签约
const descHeight = descRect && descRect.height ? Number(descRect.height) : 0;
if (descHeight && descHeight <= this.scrollViewHeight + READ_BOTTOM_THRESHOLD) {
this.isReachBottom = true;
}
});
},
handleScroll(event) {
if (this.scrollTimer) {
clearTimeout(this.scrollTimer);
}
this.scrollTimer = setTimeout(() => {
this.checkScrollBottom(event);
}, 50);
},
checkScrollBottom(event) {
if (this.isReachBottom) {
return;
}
const detail = (event && event.detail) || {};
const scrollTop = Number(detail.scrollTop || 0);
const scrollHeight = Number(detail.scrollHeight || 0);
const clientHeight = this.scrollViewHeight;
const scrollPercent = scrollHeight
? (scrollTop + clientHeight) / scrollHeight
: 1;
if (
scrollTop + clientHeight >= scrollHeight - READ_BOTTOM_THRESHOLD ||
scrollPercent >= 0.95
) {
this.isReachBottom = true;
this.$nextTick(() => {
setTimeout(() => {
this.calcScrollViewHeight();
}, 50);
});
uni.showToast({
title: "已阅读到底部",
icon: "none",
duration: 1000,
});
}
},
cancel() {
uni.navigateBack({
delta: 1,
});
},
async toSign() {
if (!this.isReachBottom || this.signing) {
return;
}
this.signing = true;
try {
// 签约 id 取自 go_to_sign_check_bmt
const result =
(await startBmtSigning(
{
id: this.contractId,
},
{
showLoading: true,
loadingText: "签约中",
},
)) || {};
console.log("[BMT签约] 协议页 start_signing_bmt_v2 返回:", result.raw);
if (Number(result.status) === 0 && result.saasShortLink) {
this.navigateToExternalUrl(result.saasShortLink);
return;
}
this.signStatus = false;
this.startCountdown();
} catch (error) {
this.signing = false;
uni.showToast({
title: (error && error.message) || "签约失败,请重试",
icon: "none",
});
}
},
navigateToExternalUrl(targetUrl) {
if (!targetUrl) {
return;
}
if (typeof window !== "undefined" && window.location) {
window.location.href = targetUrl;
return;
}
if (
typeof plus !== "undefined" &&
plus.webview &&
plus.webview.currentWebview
) {
const currentWebview = plus.webview.currentWebview();
if (currentWebview && typeof currentWebview.loadURL === "function") {
currentWebview.loadURL(targetUrl);
return;
}
}
uni.navigateTo({
url: targetUrl,
});
},
/** 签约完成后固定倒计时,结束后才允许点「完成」 */
startCountdown() {
this.clearCountdownTimer();
this.countdown = DONE_COUNTDOWN_SECONDS;
this.countdownTimer = setInterval(() => {
this.countdown -= 1;
if (this.countdown <= 0) {
this.countdown = 0;
this.clearCountdownTimer();
}
}, 1000);
},
clearCountdownTimer() {
if (this.countdownTimer) {
clearInterval(this.countdownTimer);
this.countdownTimer = null;
}
},
compute() {
// 倒计时结束前不可点击
if (this.countdown > 0) {
return;
}
uni.navigateBack({
delta: 1,
});
},
},
};
</script>
<style lang="scss" scoped>
@import "../../styles/tokens.scss";
@import "../../styles/common.scss";
.bmt-agree-page {
min-height: 100vh;
}
.bmt-agree-content {
margin: 12rpx 24rpx;
padding: 28rpx 26rpx;
}
.bmt-agree-scroll {
box-sizing: border-box;
}
.bmt-agree-title {
display: block;
margin-bottom: 30rpx;
font-size: 34rpx;
font-weight: 700;
text-align: center;
color: $asset-text-main;
}
.bmt-agree-desc {
box-sizing: border-box;
}
.bmt-agree-text {
display: block;
font-size: 26rpx;
line-height: 1.8;
white-space: pre-wrap;
word-break: break-word;
color: $asset-text-muted;
}
.bmt-agree-tip {
margin-top: 24rpx;
padding-top: 30rpx;
border-top: 1px solid rgba(255, 255, 255, 0.08);
text-align: center;
font-size: 24rpx;
color: $asset-text-subtle;
}
.bmt-agree-padding {
height: 1rpx;
opacity: 0;
}
.bmt-agree-bottom {
position: fixed;
left: 0;
right: 0;
bottom: 0;
padding: 22rpx 32rpx calc(22rpx + env(safe-area-inset-bottom));
border-top: 1px solid rgba(255, 255, 255, 0.08);
background: #191e32;
box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.18);
z-index: 30;
}
.bmt-agree-bottom__hint {
display: block;
margin-bottom: 20rpx;
text-align: center;
font-size: 24rpx;
color: $asset-text-subtle;
}
.bmt-agree-bottom__row {
display: flex;
align-items: center;
}
.bmt-agree-btn {
display: flex;
align-items: center;
justify-content: center;
flex: 1;
height: 80rpx;
border-radius: 40rpx;
font-size: 30rpx;
font-weight: 600;
}
.bmt-agree-btn+.bmt-agree-btn {
margin-left: 20rpx;
}
.bmt-agree-btn--ghost {
border: 1px solid rgba(255, 255, 255, 0.16);
background: rgba(255, 255, 255, 0.06);
color: $asset-text-main;
}
.bmt-agree-btn--primary {
background: linear-gradient(135deg, #7e6cff 0%, #6b56f6 100%);
box-shadow: 0 14rpx 24rpx rgba(93, 79, 225, 0.22);
color: #ffffff;
}
.bmt-agree-btn--primary.is-disabled {
opacity: 0.5;
}
.bmt-agree-copy {
display: flex;
align-items: center;
justify-content: center;
margin-top: 16rpx;
}
.bmt-agree-copy__icon {
width: 112rpx;
height: 32rpx;
margin-right: 10rpx;
}
.bmt-agree-copy__text {
font-size: 24rpx;
color: $asset-text-subtle;
}
.bmt-agree-success {
display: flex;
flex-direction: column;
align-items: center;
padding-top: 220rpx;
}
.bmt-agree-success__image {
width: 180rpx;
height: 180rpx;
}
.bmt-agree-success__text {
margin-top: 48rpx;
font-size: 36rpx;
font-weight: 500;
color: $asset-text-main;
}
.bmt-agree-success__btn {
display: flex;
align-items: center;
justify-content: center;
width: 328rpx;
height: 80rpx;
margin-top: 60rpx;
border-radius: 40rpx;
background: linear-gradient(135deg, #7e6cff 0%, #6b56f6 100%);
box-shadow: 0 14rpx 24rpx rgba(93, 79, 225, 0.22);
font-size: 32rpx;
font-weight: 600;
color: #ffffff;
}
.bmt-agree-success__btn.is-disabled {
opacity: 0.5;
}
</style>