Files
bdrp-webview/src/views/CancelAccount.vue
2026-04-22 17:49:33 +08:00

279 lines
8.3 KiB
Vue
Raw 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.

<script setup>
import { storeToRefs } from 'pinia'
import { computed, onMounted, onUnmounted, ref } from 'vue'
import { showConfirmDialog, showToast } from 'vant'
import AccountCancelAgreement from '@/views/AccountCancelAgreement.vue'
import useApiFetch from '@/composables/useApiFetch'
import { useAgentStore } from '@/stores/agentStore'
import { useUserStore } from '@/stores/userStore'
const router = useRouter()
const userStore = useUserStore()
const agentStore = useAgentStore()
const { mobile } = storeToRefs(userStore)
const { isAgent, level } = storeToRefs(agentStore)
const loading = ref(true)
const revenueData = ref(null)
const showSmsModal = ref(false)
const cancelAccountCode = ref('')
const cancelSmsCountdown = ref(0)
let cancelSmsTimer = null
function maskName(name) {
if (!name || name.length < 11)
return name
return `${name.substring(0, 3)}****${name.substring(7)}`
}
const hasWalletBalance = computed(() => {
const b = Number(revenueData.value?.balance ?? 0)
const f = Number(revenueData.value?.frozen_balance ?? 0)
return b > 0 || f > 0
})
const showBalanceWarning = computed(() => isAgent.value && hasWalletBalance.value)
const showVipLevelReminder = computed(() =>
isAgent.value && (level.value === 'VIP' || level.value === 'SVIP'),
)
const vipLevelLabel = computed(() => (level.value === 'SVIP' ? 'SVIP' : 'VIP'))
const showAnyReminder = computed(() => showBalanceWarning.value || showVipLevelReminder.value)
onMounted(async () => {
await userStore.fetchUserInfo()
if (!userStore.mobile) {
loading.value = false
showToast('请先绑定手机号')
setTimeout(() => router.back(), 1500)
return
}
try {
await agentStore.fetchAgentStatus()
if (agentStore.isAgent) {
const { data, error } = await useApiFetch('/agent/revenue').get().json()
if (!error.value && data.value?.code === 200)
revenueData.value = data.value.data
}
}
catch {
/* ignore */
}
finally {
loading.value = false
}
})
function onExit() {
router.back()
}
function startCancelSmsCountdown() {
cancelSmsCountdown.value = 60
if (cancelSmsTimer)
clearInterval(cancelSmsTimer)
cancelSmsTimer = setInterval(() => {
if (cancelSmsCountdown.value > 0)
cancelSmsCountdown.value--
else
clearInterval(cancelSmsTimer)
}, 1000)
}
onUnmounted(() => {
if (cancelSmsTimer)
clearInterval(cancelSmsTimer)
})
function openSmsModal() {
cancelAccountCode.value = ''
showSmsModal.value = true
}
function onConfirmTap() {
if (showBalanceWarning.value) {
showConfirmDialog({
title: '确认注销',
message: '您的代理账户仍有余额或待结账金额,注销后将无法通过本账号提现,确定继续注销?',
confirmButtonText: '继续',
cancelButtonText: '取消',
})
.then(() => openSmsModal())
.catch(() => {})
}
else {
openSmsModal()
}
}
function closeSmsModal() {
showSmsModal.value = false
cancelAccountCode.value = ''
}
async function sendCancelAccountSms() {
if (!mobile.value) {
showToast('请先绑定手机号')
return
}
if (cancelSmsCountdown.value > 0)
return
const { data, error } = await useApiFetch('/auth/sendSms')
.post({ mobile: mobile.value, actionType: 'cancelAccount', captchaVerifyParam: '' })
.json()
if (!error.value && data.value?.code === 200) {
showToast({ message: '验证码已发送' })
startCancelSmsCountdown()
}
else {
showToast({ message: data.value?.msg || '发送失败' })
}
}
function clearAuthAndGoHome() {
localStorage.removeItem('token')
localStorage.removeItem('refreshAfter')
localStorage.removeItem('accessExpire')
localStorage.removeItem('userInfo')
localStorage.removeItem('agentInfo')
userStore.resetUser()
agentStore.resetAgent()
window.location.href = '/'
}
async function submitCancelAccount() {
if (cancelAccountCode.value.length !== 6) {
showToast('请输入6位验证码')
return
}
const { data, error } = await useApiFetch('/user/cancelOut')
.post({ code: cancelAccountCode.value })
.json()
if (!error.value && data.value?.code === 200) {
showToast({ message: '账号已注销' })
closeSmsModal()
clearAuthAndGoHome()
}
else {
showToast({ message: data.value?.msg || '注销失败' })
}
}
</script>
<template>
<!-- 减导航栏占位高度避免整页超出视口 PageLayout van-nav-bar placeholder 配合 -->
<div
class="box-border flex flex-col bg-gray-50"
style="min-height: calc(100vh - var(--van-nav-bar-height, 46px)); height: calc(100vh - var(--van-nav-bar-height, 46px));"
>
<div v-if="loading" class="flex flex-1 items-center justify-center py-20 text-gray-500">
加载中...
</div>
<template v-else>
<div class="flex min-h-0 min-w-0 flex-1 flex-col">
<div class="min-h-0 flex-1 overflow-y-auto border-b border-gray-100 bg-white">
<AccountCancelAgreement />
</div>
<div
v-if="showAnyReminder"
class="flex-shrink-0 space-y-2 border-t border-gray-100 bg-gray-50 px-4 py-3"
>
<div
v-if="showBalanceWarning"
class="rounded-lg border border-amber-200 bg-amber-50 p-3 text-sm text-amber-900"
>
<p class="font-medium">
钱包提示
</p>
<p class="mt-1 leading-relaxed">
检测到您为代理且账户仍有余额¥{{ (revenueData?.balance ?? 0).toFixed(2) }}或待结账金额¥{{ (revenueData?.frozen_balance ?? 0).toFixed(2) }}注销后将无法通过本账号提现请确认已了解风险
</p>
</div>
<div
v-if="showVipLevelReminder"
class="rounded-lg border border-violet-200 bg-violet-50 p-3 text-sm text-violet-900"
>
<p class="font-medium">
会员提示
</p>
<p class="mt-1 leading-relaxed">
您当前为 {{ vipLevelLabel }} 代理会员注销后该账号下的代理身份与相关权益将按平台规则终止请确认已了解风险
</p>
</div>
</div>
</div>
<div class="flex-shrink-0 border-t border-gray-200 bg-gray-50 px-4 pb-[max(1rem,env(safe-area-inset-bottom))] pt-3">
<div class="flex gap-3">
<button
type="button"
class="flex-1 rounded-lg border border-gray-300 bg-white py-3 text-gray-800"
@click="onExit"
>
退出
</button>
<button
type="button"
class="flex-1 rounded-lg bg-red-500 py-3 text-white"
@click="onConfirmTap"
>
确认
</button>
</div>
</div>
</template>
<div
v-if="showSmsModal"
class="fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4"
@click.self="closeSmsModal"
>
<div class="w-full max-w-sm rounded-xl bg-white p-5 shadow-lg" @click.stop>
<p class="mb-2 text-base font-medium text-gray-800">
验证手机号
</p>
<p class="mb-4 text-sm text-gray-500">
将向 {{ maskName(mobile) }} 发送验证码
</p>
<input
v-model="cancelAccountCode"
type="text"
maxlength="6"
inputmode="numeric"
placeholder="请输入6位验证码"
class="mb-4 w-full rounded-lg border border-gray-200 px-3 py-2 text-base"
>
<div class="mb-4">
<button
type="button"
class="w-full rounded-lg bg-gray-100 py-2 text-sm text-gray-700 disabled:opacity-50"
:disabled="cancelSmsCountdown > 0"
@click="sendCancelAccountSms"
>
{{ cancelSmsCountdown > 0 ? `${cancelSmsCountdown}s` : '获取验证码' }}
</button>
</div>
<div class="flex gap-2">
<button
type="button"
class="flex-1 rounded-lg bg-gray-200 py-2 text-gray-800"
@click="closeSmsModal"
>
取消
</button>
<button
type="button"
class="flex-1 rounded-lg bg-red-500 py-2 text-white"
@click="submitCancelAccount"
>
确认注销
</button>
</div>
</div>
</div>
</div>
</template>