删除禁用账户功能及相关代码

- 删除个人资料标签页中的禁用/启用账户列表项
- 删除禁用账户对话框和启用账户对话框
- 删除反馈对话框(禁用账户后显示)
- 删除账户状态相关的状态变量和计算属性
- 删除 handleAccountStatus、handleDisableAccountConfirm、handleEnableAccountConfirm 等处理函数
- 删除反馈相关的状态变量和处理函数(feedbackRating、feedbackReason、feedbackNote 等)
- 从 API 模块中删除 disableAccount、enableAccount、submitFeedback 函数
- 删除账户状态对话框和星级评分的 CSS 样式
This commit is contained in:
jingrow 2026-01-04 21:34:33 +08:00
parent 423e28c09c
commit dfad1a1d80
2 changed files with 1 additions and 417 deletions

View File

@ -286,47 +286,6 @@ export const becomeDeveloper = async (teamName: string): Promise<{ success: bool
}
}
// 禁用账户
export const disableAccount = async (totpCode?: string): Promise<{ success: boolean; message?: string }> => {
try {
const response = await axios.post(
`/api/action/jcloud.api.account.disable_account`,
{ totp_code: totpCode || null },
{
headers: get_session_api_headers(),
withCredentials: true
}
)
return { success: true, message: response.data?.message || '账户已禁用' }
} catch (error: any) {
return {
success: false,
message: error.response?.data?.detail || error.response?.data?.message || error.message || '禁用账户失败'
}
}
}
// 启用账户
export const enableAccount = async (): Promise<{ success: boolean; message?: string }> => {
try {
const response = await axios.post(
`/api/action/jcloud.api.account.enable_account`,
{},
{
headers: get_session_api_headers(),
withCredentials: true
}
)
return { success: true, message: response.data?.message || '账户已启用' }
} catch (error: any) {
return {
success: false,
message: error.response?.data?.detail || error.response?.data?.message || error.message || '启用账户失败'
}
}
}
// 更新密码
export const updatePassword = async (params: {
@ -553,29 +512,3 @@ export const disable2FA = async (totpCode: string): Promise<{ success: boolean;
}
}
// 提交反馈
export const submitFeedback = async (team: string, message: string, note: string, rating: number, route?: string): Promise<{ success: boolean; message?: string }> => {
try {
const response = await axios.post(
`/api/action/jcloud.api.account.feedback`,
{
team,
message,
note,
rating,
route: route || null
},
{
headers: get_session_api_headers(),
withCredentials: true
}
)
return { success: true, message: response.data?.message || '反馈已提交' }
} catch (error: any) {
return {
success: false,
message: error.response?.data?.detail || error.response?.data?.message || error.message || '提交反馈失败'
}
}
}

View File

@ -107,25 +107,6 @@
</n-thing>
</n-list-item>
<!-- 禁用/启用账户 -->
<n-list-item>
<n-thing>
<template #header>
<span class="text-base font-medium">{{ accountStatusTitle }}</span>
</template>
<template #description>
<span class="text-sm text-gray-600">{{ accountStatusSubtitle }}</span>
</template>
<template #action>
<n-button
:type="teamEnabled ? 'error' : 'primary'"
@click="handleAccountStatus"
>
{{ accountStatusButtonLabel }}
</n-button>
</template>
</n-thing>
</n-list-item>
</n-list>
</n-card>
@ -775,130 +756,6 @@
</p>
</n-modal>
<!-- 禁用账户对话框 -->
<n-modal
v-model:show="showDisableAccountDialog"
preset="dialog"
type="warning"
:title="t('Disable Account')"
:positive-text="t('Disable Account')"
:positive-button-props="{ type: 'error' }"
:loading="disableAccountLoading"
:mask-closable="true"
:close-on-esc="true"
@positive-click="handleDisableAccountConfirm"
>
<div class="account-status-dialog-content">
<p class="account-status-dialog-title">{{ t('After confirming this action:') }}</p>
<ul class="account-status-dialog-list">
<li>{{ t('Your account will be disabled') }}</li>
<li>{{ t('Your activated sites will be suspended immediately and deleted after one week.') }}</li>
<li>{{ t('Your account billing will stop') }}</li>
</ul>
<p class="account-status-dialog-text">{{ t('You can log in later to re-enable your account. Do you want to continue?') }}</p>
</div>
</n-modal>
<!-- 启用账户对话框 -->
<n-modal
v-model:show="showEnableAccountDialog"
preset="dialog"
:title="t('Enable Account')"
:positive-text="t('Enable Account')"
:loading="enableAccountLoading"
:mask-closable="true"
:close-on-esc="true"
@positive-click="handleEnableAccountConfirm"
>
<div class="account-status-dialog-content">
<p class="account-status-dialog-title">{{ t('After confirming this action:') }}</p>
<ul class="account-status-dialog-list">
<li>{{ t('Your account will be enabled') }}</li>
<li>{{ t('Your suspended sites will be reactivated') }}</li>
<li>{{ t('Your account billing will resume') }}</li>
</ul>
<p class="account-status-dialog-text">{{ t('Do you want to continue?') }}</p>
</div>
</n-modal>
<!-- 反馈对话框 -->
<n-modal
v-model:show="showFeedbackDialog"
preset="card"
:title="t('Tell us why you are leaving')"
:style="{ width: '600px' }"
:mask-closable="false"
:close-on-esc="false"
>
<n-space vertical :size="20">
<p class="text-sm text-gray-800">
{{ t('By sharing your thoughts, help us improve your experience.') }}
</p>
<!-- 星级评分 -->
<div>
<span class="block text-sm leading-4 text-gray-600 mb-2">
{{ t('Please rate your experience') }}
</span>
<div class="star-rating">
<span
v-for="rating in [1, 2, 3, 4, 5]"
:key="rating"
class="star-rating-star"
@click="feedbackRating = rating"
@mouseenter="hoveredRating = rating"
@mouseleave="hoveredRating = 0"
>
<n-icon :size="20">
<Icon
:icon="(hoveredRating || feedbackRating) >= rating ? 'tabler:star-filled' : 'tabler:star'"
:style="{ color: (hoveredRating || feedbackRating) >= rating ? '#ECAC4B' : '#C0C6CC' }"
/>
</n-icon>
</span>
</div>
</div>
<!-- 原因选择 -->
<n-form-item :label="t('Select a reason')" required>
<n-select
v-model:value="feedbackReason"
:options="feedbackReasons.map(r => ({ label: r, value: r }))"
:placeholder="t('Select a reason')"
/>
</n-form-item>
<!-- 详细说明 -->
<n-form-item :label="t('The reason I am leaving Jingrow is...')">
<n-input
v-model:value="feedbackNote"
type="textarea"
:rows="4"
:placeholder="t('The reason I am leaving Jingrow is...')"
/>
</n-form-item>
<!-- 错误提示 -->
<n-alert
v-if="feedbackError"
type="error"
:title="feedbackError"
/>
</n-space>
<template #footer>
<n-space justify="end">
<n-button @click="closeFeedbackDialog">{{ t('Cancel') }}</n-button>
<n-button
type="primary"
:loading="feedbackLoading"
@click="handleSubmitFeedback"
>
{{ t('Submit') }}
</n-button>
</n-space>
</template>
</n-modal>
</div>
</template>
@ -949,8 +806,6 @@ import {
updateFeatureFlags,
getUserAccountInfo,
becomeDeveloper,
disableAccount,
enableAccount,
updatePassword,
testPasswordStrength,
validatePartnerCode,
@ -959,8 +814,7 @@ import {
getPartnerName,
get2FAQRCodeUrl,
enable2FA,
disable2FA,
submitFeedback
disable2FA
} from '../../shared/api/account'
import ClickToCopyField from '../../shared/components/ClickToCopyField.vue'
@ -1060,35 +914,6 @@ const twoFAError = ref('')
//
const showResetPasswordDialog = ref(false)
//
const teamEnabled = computed(() => teamInfo.value?.enabled || false)
const accountStatusTitle = computed(() => {
return teamEnabled.value ? t('Disable Account') : t('Enable Account')
})
const accountStatusSubtitle = computed(() => {
return teamEnabled.value
? t('Disable your account and stop billing')
: t('Enable your account and resume billing')
})
const accountStatusButtonLabel = computed(() => {
return teamEnabled.value ? t('Disable') : t('Enable')
})
//
const showDisableAccountDialog = ref(false)
const showEnableAccountDialog = ref(false)
const disableAccountLoading = ref(false)
const enableAccountLoading = ref(false)
//
const showFeedbackDialog = ref(false)
const feedbackRating = ref(0)
const feedbackReason = ref('')
const feedbackNote = ref('')
const feedbackLoading = ref(false)
const feedbackError = ref('')
const hoveredRating = ref(0)
// API Secret
const showCreateSecretDialog = ref(false)
const createSecretData = ref<{ api_key: string; api_secret: string } | null>(null)
@ -1749,128 +1574,6 @@ watch(show2FADialog, (newVal) => {
}
})
// /
const handleAccountStatus = () => {
if (teamEnabled.value) {
showDisableAccountDialog.value = true
} else {
showEnableAccountDialog.value = true
}
}
//
const handleDisableAccountConfirm = async () => {
disableAccountLoading.value = true
try {
const result = await disableAccount()
if (result.success) {
message.success(t('Your account has been disabled successfully'))
showDisableAccountDialog.value = false
await loadUserAccountInfo()
//
showFeedbackDialog.value = true
} else {
message.error(result.message || t('Failed to disable account'))
}
} finally {
disableAccountLoading.value = false
}
}
//
const feedbackReasons = [
t('我要迁移到其他产品'),
t('我只是在探索这个产品'),
t('我更喜欢自己托管实例'),
t('已将站点迁移到另一个Jingrow账户'),
t('我不喜欢Jingrow的体验'),
t('Jingrow对我来说太贵了'),
t('支付问题'),
t('缺少功能'),
t('我的原因不在此列表中')
]
//
const handleSubmitFeedback = async () => {
//
if (!feedbackReason.value) {
feedbackError.value = t('请选择一个原因')
return
}
if (feedbackRating.value === 0) {
feedbackError.value = t('请评价您的体验')
return
}
const requiresNote = [
t('支付问题'),
t('缺少功能'),
t('我的原因不在此列表中')
].includes(feedbackReason.value)
if (requiresNote && !feedbackNote.value) {
feedbackError.value = t('请简要说明原因')
return
}
feedbackLoading.value = true
feedbackError.value = ''
try {
const result = await submitFeedback(
teamInfo.value?.name || '',
feedbackReason.value,
feedbackNote.value,
feedbackRating.value
)
if (result.success) {
message.success(t('Your feedback has been submitted successfully'))
showFeedbackDialog.value = false
//
feedbackRating.value = 0
feedbackReason.value = ''
feedbackNote.value = ''
//
setTimeout(() => {
window.location.href = '/'
}, 1000)
} else {
feedbackError.value = result.message || t('提交反馈失败')
}
} catch (error: any) {
feedbackError.value = error.message || t('提交反馈失败')
} finally {
feedbackLoading.value = false
}
}
//
const closeFeedbackDialog = () => {
showFeedbackDialog.value = false
feedbackRating.value = 0
feedbackReason.value = ''
feedbackNote.value = ''
feedbackError.value = ''
}
//
const handleEnableAccountConfirm = async () => {
enableAccountLoading.value = true
try {
const result = await enableAccount()
if (result.success) {
message.success(t('Your account has been enabled successfully'))
showEnableAccountDialog.value = false
await loadUserAccountInfo()
} else {
message.error(result.message || t('Failed to enable account'))
}
} finally {
enableAccountLoading.value = false
}
}
// API Secret
const handleCreateSecret = async () => {
@ -2302,58 +2005,6 @@ onMounted(async () => {
border-color: transparent !important;
}
/* 账户状态对话框样式 */
.account-status-dialog-content {
padding: 16px 0;
}
.account-status-dialog-title {
font-size: 16px;
margin-bottom: 16px;
margin-top: 0;
}
.account-status-dialog-list {
list-style-type: disc;
list-style-position: inside;
margin: 0 0 16px 0;
padding-left: 0;
font-size: 14px;
color: #4b5563;
line-height: 1.6;
}
.account-status-dialog-list li {
margin-bottom: 8px;
}
.account-status-dialog-list li:last-child {
margin-bottom: 0;
}
.account-status-dialog-text {
font-size: 16px;
margin-bottom: 0;
margin-top: 0;
}
/* 星级评分样式 */
.star-rating {
display: flex;
gap: 4px;
align-items: center;
}
.star-rating-star {
display: inline-block;
cursor: pointer;
transition: transform 0.1s;
}
.star-rating-star:hover {
transform: scale(1.1);
}
/* 响应式设计 */
@media (max-width: 1200px) {
.settings-page :deep(.n-grid) {