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