PaymentAgreementModal.vue 9.81 KB
<template>
    <nut-popup
        v-model:visible="visible"
        position="bottom"
        :catch-move="true"
        :style="{ width: '100%', height: '100%' }"
    >
        <div class="payment-agreement-modal">
            <!-- 标题 -->
            <div class="modal-header">
                <h2 class="title">在捡个电驴收款</h2>
            </div>

            <!-- 内容区域 -->
            <div class="modal-content">
                <!-- 收款说明 -->
                <div class="info-row">
                    <div class="label">收款说明</div>
                    <div class="content">{{ paymentDescription }}</div>
                </div>

                <!-- 扣费说明 -->
                <div class="info-row">
                    <div class="label">扣费说明</div>
                    <div class="content">{{ feeDescription }}</div>
                </div>

                <!-- 协议勾选区域 -->
                <div v-if="!hasAgreed" class="agreement-section">
                    <nut-checkbox v-model="isChecked" class="agreement-checkbox">
                        <view class="checkbox-text">
                            <text>我已阅读并同意</text>
                            <text class="agreement-link" @tap.stop="showProtocol">
                                《支付协议》
                            </text>
                        </view>
                    </nut-checkbox>
                </div>
            </div>

            <!-- 按钮区域 -->
            <div class="modal-footer">
                <div class="button-row">
                    <nut-button
                        type="default"
                        class="close-button"
                        @click="handleClose"
                    >
                        关闭
                    </nut-button>
                    <nut-button
                        v-if="!hasAgreed"
                        :disabled="!isChecked"
                        type="primary"
                        class="main-button"
                        color="orange"
                        @click="handleAgree"
                    >
                        同意
                    </nut-button>
                    <nut-button
                        v-else
                        type="primary"
                        class="main-button"
                        color="orange"
                        @click="handleConfirm"
                    >
                        确认
                    </nut-button>
                </div>
            </div>
        </div>

        <!-- 支付协议弹框 -->
        <nut-popup
            v-model:visible="protocolVisible"
            position="right"
            :closeable="true"
            :close-on-click-overlay="true"
            :safe-area-inset-bottom="true"
            :style="{ width: '100%', height: '100%' }"
            @close="protocolVisible = false"
        >
            <view class="protocol-container">
                <!-- 标题栏 -->
                <view class="protocol-header">
                    <text class="protocol-title">支付协议</text>
                    <view class="close-btn" @click="protocolVisible = false">
                        <text class="close-text">×</text>
                    </view>
                </view>

                <!-- 内容区域 -->
                <scroll-view class="protocol-scroll" :scroll-y="true">
                    <view class="protocol-body">
                        <view class="protocol-text">{{ protocolContent }}</view>
                    </view>
                </scroll-view>
            </view>
        </nut-popup>
    </nut-popup>
</template>

<script setup>
import { ref, computed, onMounted } from 'vue'
import { useUserStore } from '@/stores/user'

// 导入接口
import { updateProfileAPI, getProfileAPI } from '@/api/index'

/**
 * 用户收款说明组件
 * @param {Boolean} modelValue - 控制弹框显示隐藏
 * @param {Function} onAgree - 同意按钮回调
 * @param {Function} onConfirm - 确认按钮回调
 * @param {Function} onClose - 关闭弹框回调
 */
const props = defineProps({
    modelValue: {
        type: Boolean,
        default: false
    }
})

const emit = defineEmits(['update:modelValue', 'agree', 'confirm', 'close'])

const userStore = useUserStore()

// 弹框显示状态
const visible = computed({
    get: () => props.modelValue,
    set: (value) => emit('update:modelValue', value)
})

// 支付协议弹框显示状态
const protocolVisible = ref(false)

// 勾选状态
const isChecked = ref(false)

// 是否已同意过协议(mock数据)
const hasAgreed = ref(false)

// 收款说明内容
const paymentDescription = ref('交易金额会在交易完成后的3个工作日内,入账至你登记的收款账户。')

// 扣费说明内容
const feeDescription = ref('在每笔交易过程中,平台将抽取最终成交金额的1%作为平台服务费。')

// 支付协议内容
const protocolContent = ref(`
1. 用户在使用捡个电驴收款服务时,需遵守相关法律法规。
2. 平台有权对异常交易进行风险控制。
3. 用户应确保收款信息的真实性和准确性。
4. 平台将按照约定收取相应的服务费用。
5. 如有争议,双方应友好协商解决。
`)

/**
 * 检查用户是否已同意过协议
 */
const checkAgreementStatus = async () => {
    try {
        // 调用API获取用户信息
        const result = await getProfileAPI()

        if (result.code && result.data) {
            hasAgreed.value = result.data.is_signed || false
            // 更新用户store中的状态
            if (userStore.userInfo) {
                userStore.userInfo.is_signed = result.data.is_signed
            }
        } else {
            // 如果API调用失败,使用store中的数据作为备选
            hasAgreed.value = userStore.userInfo?.is_signed || false
        }
    } catch (error) {
        console.error('获取用户协议状态失败:', error)
        // 如果API调用失败,使用store中的数据作为备选
        hasAgreed.value = userStore.userInfo?.is_signed || false
    }
}

/**
 * 显示支付协议
 */
const showProtocol = () => {
    protocolVisible.value = true
}

/**
 * 处理同意按钮点击
 */
const handleAgree = async () => {
    if (!isChecked.value) return

    try {
        // 调用API更新用户协议状态
        const result = await updateProfileAPI({
            is_signed: true
        })

        if (result.code) {
            hasAgreed.value = true
            // 更新用户store中的状态
            if (userStore.userInfo) {
                userStore.userInfo.is_signed = true
            }
            emit('agree')
        } else {
            console.error('更新协议状态失败:', result.message)
        }
    } catch (error) {
        console.error('更新协议状态失败:', error)
    }
}

/**
 * 处理确认按钮点击
 */
const handleConfirm = () => {
    emit('confirm')
}

/**
 * 处理弹框关闭
 */
const handleClose = () => {
    emit('close')
}

// 组件挂载时检查协议状态
onMounted(async () => {
    checkAgreementStatus()
})
</script>

<style lang="less">
.payment-agreement-modal {
    display: flex;
    flex-direction: column;
    height: 100%;
    padding: 32rpx;
    padding-top: 80rpx;

    .modal-header {
        text-align: center;
        margin-bottom: 40rpx;

        .title {
            font-size: 36rpx;
            font-weight: 600;
            color: #333;
            margin: 0;
        }
    }

    .modal-content {
        flex: 1;
        display: flex;
        flex-direction: column;

        .info-row {
            display: flex;
            margin-bottom: 32rpx;

            .label {
                width: 160rpx;
                font-size: 28rpx;
                font-weight: 500;
                color: #333;
                flex-shrink: 0;
            }

            .content {
                flex: 1;
                font-size: 28rpx;
                color: #666;
                line-height: 1.6;
            }
        }

        .agreement-section {
            margin-top: 40rpx;
            text-align: center;

            .agreement-checkbox {
                font-size: 28rpx;

                .checkbox-text {
                    white-space: nowrap;
                    display: inline-block;
                }

                .agreement-link {
                    color: #ffa500;
                    text-decoration: underline;
                    cursor: pointer;
                }
            }
        }
    }

    .modal-footer {
        padding-top: 32rpx;
        border-top: 1rpx solid #eee;

        .button-row {
            display: flex;
            gap: 24rpx;
            align-items: center;

            .close-button {
                flex: 1;
                border: 1rpx solid #ddd;
                color: #666;
            }

            .main-button {
                flex: 1;
            }
        }
    }
}

/* 支付协议弹框样式 */
.protocol-container {
    width: 100%;
    height: 100vh;
    background: white;
    display: flex;
    flex-direction: column;
}

.protocol-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 32rpx 40rpx;
    border-bottom: 1rpx solid #eee;
    background: white;
    position: sticky;
    top: 0;
    z-index: 10;
}

.protocol-title {
    font-size: 36rpx;
    font-weight: bold;
    color: #333;
}

.close-btn {
    width: 60rpx;
    height: 60rpx;
    display: flex;
    align-items: center;
    justify-content: center;
    background: #f5f5f5;
    border-radius: 50%;
    cursor: pointer;
}

.close-text {
    font-size: 40rpx;
    color: #666;
    line-height: 1;
}

.protocol-scroll {
    flex: 1;
    height: 0;
}

.protocol-body {
    padding: 40rpx;
}

.protocol-text {
    font-size: 28rpx;
    line-height: 1.8;
    color: #666;
    white-space: pre-line;
    word-wrap: break-word;
}
</style>