chore: setting页面拆分
This commit is contained in:
288
src/views/setting/useSettingsForm.ts
Normal file
288
src/views/setting/useSettingsForm.ts
Normal file
@@ -0,0 +1,288 @@
|
||||
import { computed, ref, shallowRef, watch, type Ref } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import {
|
||||
languageValues,
|
||||
regionValues,
|
||||
roleValues,
|
||||
type LanguageValue,
|
||||
type RegionValue,
|
||||
type RoleValue,
|
||||
type SecurityDraft,
|
||||
type SettingsData
|
||||
} from './types'
|
||||
|
||||
type Translate = (key: string, ...args: unknown[]) => string
|
||||
|
||||
interface UseSettingsFormOptions {
|
||||
t: Translate
|
||||
locale: Ref<string>
|
||||
}
|
||||
|
||||
const languageLocaleMap: Record<LanguageValue, 'ENGLISH' | 'CHINESE_SIMPLIFIED'> = {
|
||||
english: 'ENGLISH',
|
||||
chinese: 'CHINESE_SIMPLIFIED'
|
||||
}
|
||||
|
||||
const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
|
||||
|
||||
const createDefaultData = (): SettingsData => ({
|
||||
firstName: 'Alexandra',
|
||||
lastName: 'Chen',
|
||||
email: 'alex.chen@gmail.com',
|
||||
username: '@alexandra_chen',
|
||||
role: ['student', 'graphicDesigner'],
|
||||
language: 'english',
|
||||
region: 'hongKongSar'
|
||||
})
|
||||
|
||||
const cloneSettingsData = (data: SettingsData): SettingsData => ({
|
||||
firstName: data.firstName,
|
||||
lastName: data.lastName,
|
||||
email: data.email,
|
||||
username: data.username,
|
||||
role: [...data.role],
|
||||
language: data.language,
|
||||
region: data.region
|
||||
})
|
||||
|
||||
const createEmptySecurityDraft = (): SecurityDraft => ({
|
||||
newEmail: '',
|
||||
newPassword: '',
|
||||
currentPassword: ''
|
||||
})
|
||||
|
||||
export function useSettingsForm({ t, locale }: UseSettingsFormOptions) {
|
||||
const sourceData = ref<SettingsData>(createDefaultData())
|
||||
const draftData = ref<SettingsData>(cloneSettingsData(sourceData.value))
|
||||
const securityDraft = ref<SecurityDraft>(createEmptySecurityDraft())
|
||||
const isEditing = shallowRef(false)
|
||||
const saving = shallowRef(false)
|
||||
const isVerificationDialogVisible = shallowRef(false)
|
||||
const verificationTargetEmail = shallowRef('')
|
||||
const verifiedEmail = shallowRef('')
|
||||
|
||||
const roleList = computed(() =>
|
||||
roleValues.map((value) => ({
|
||||
name: t(`Settings.roles.${value}`),
|
||||
value
|
||||
}))
|
||||
)
|
||||
|
||||
const languageList = computed(() =>
|
||||
languageValues.map((value) => ({
|
||||
label: t(`Settings.languages.${value}`),
|
||||
value
|
||||
}))
|
||||
)
|
||||
|
||||
const regionList = computed(() =>
|
||||
regionValues.map((value) => ({
|
||||
label: t(`Settings.regions.${value}`),
|
||||
value
|
||||
}))
|
||||
)
|
||||
|
||||
const displayData = computed(() => (isEditing.value ? draftData.value : sourceData.value))
|
||||
const normalizedNewEmail = computed(() => securityDraft.value.newEmail.trim())
|
||||
const hasNewEmailChange = computed(
|
||||
() => normalizedNewEmail.value.length > 0 && normalizedNewEmail.value !== sourceData.value.email
|
||||
)
|
||||
const isEmailVerified = computed(
|
||||
() => hasNewEmailChange.value && verifiedEmail.value === normalizedNewEmail.value
|
||||
)
|
||||
const displayLanguageLabel = computed(() => t(`Settings.languages.${displayData.value.language}`))
|
||||
const displayRegionLabel = computed(() => t(`Settings.regions.${displayData.value.region}`))
|
||||
|
||||
const fullName = computed(() => {
|
||||
const data = displayData.value
|
||||
return `${data.firstName} ${data.lastName}`.trim()
|
||||
})
|
||||
|
||||
const roleModel = computed<RoleValue[]>({
|
||||
get: () => displayData.value.role,
|
||||
set: (value) => {
|
||||
if (isEditing.value) {
|
||||
draftData.value.role = value
|
||||
return
|
||||
}
|
||||
|
||||
sourceData.value.role = value
|
||||
}
|
||||
})
|
||||
|
||||
const resetEmailVerificationState = () => {
|
||||
isVerificationDialogVisible.value = false
|
||||
verificationTargetEmail.value = ''
|
||||
verifiedEmail.value = ''
|
||||
}
|
||||
|
||||
const syncAppLanguage = (language: LanguageValue) => {
|
||||
const nextLocale = languageLocaleMap[language]
|
||||
locale.value = nextLocale
|
||||
localStorage.setItem('language', nextLocale)
|
||||
}
|
||||
|
||||
const resetDraftState = () => {
|
||||
draftData.value = cloneSettingsData(sourceData.value)
|
||||
securityDraft.value = createEmptySecurityDraft()
|
||||
resetEmailVerificationState()
|
||||
}
|
||||
|
||||
const handleEdit = () => {
|
||||
resetDraftState()
|
||||
isEditing.value = true
|
||||
}
|
||||
|
||||
const resetSecurityEmail = () => {
|
||||
securityDraft.value.newEmail = ''
|
||||
resetEmailVerificationState()
|
||||
}
|
||||
|
||||
const resetSecurityPassword = () => {
|
||||
securityDraft.value.newPassword = ''
|
||||
securityDraft.value.currentPassword = ''
|
||||
}
|
||||
|
||||
const handleDiscard = () => {
|
||||
resetDraftState()
|
||||
isEditing.value = false
|
||||
}
|
||||
|
||||
const closeVerificationDialog = () => {
|
||||
isVerificationDialogVisible.value = false
|
||||
verificationTargetEmail.value = ''
|
||||
}
|
||||
|
||||
const handleVerifyEmail = () => {
|
||||
const nextEmail = normalizedNewEmail.value
|
||||
|
||||
if (!nextEmail) {
|
||||
ElMessage.warning(t('Settings.messages.enterNewEmailFirst'))
|
||||
return
|
||||
}
|
||||
|
||||
if (!emailPattern.test(nextEmail)) {
|
||||
ElMessage.warning(t('Settings.messages.invalidEmail'))
|
||||
return
|
||||
}
|
||||
|
||||
if (nextEmail === sourceData.value.email) {
|
||||
ElMessage.warning(t('Settings.messages.sameEmail'))
|
||||
return
|
||||
}
|
||||
|
||||
if (verifiedEmail.value === nextEmail) {
|
||||
ElMessage.success(t('Settings.messages.alreadyVerified'))
|
||||
return
|
||||
}
|
||||
|
||||
verificationTargetEmail.value = nextEmail
|
||||
handleSendVerifyCode()
|
||||
isVerificationDialogVisible.value = true
|
||||
}
|
||||
|
||||
const handleSendVerifyCode = () => {
|
||||
ElMessage.success(t('Settings.messages.verificationCodeSent'))
|
||||
}
|
||||
|
||||
const handleVerificationSubmit = (code: string) => {
|
||||
if (code.length !== 6) {
|
||||
ElMessage.warning(t('Settings.messages.enterVerificationCode'))
|
||||
return
|
||||
}
|
||||
|
||||
verifiedEmail.value = verificationTargetEmail.value
|
||||
closeVerificationDialog()
|
||||
ElMessage.success(t('Settings.messages.verificationCompleted'))
|
||||
}
|
||||
|
||||
const buildNextData = (): SettingsData => {
|
||||
const nextEmail = securityDraft.value.newEmail.trim() || draftData.value.email
|
||||
|
||||
return {
|
||||
firstName: draftData.value.firstName.trim(),
|
||||
lastName: draftData.value.lastName.trim(),
|
||||
username: draftData.value.username.trim(),
|
||||
email: nextEmail,
|
||||
role: [...draftData.value.role],
|
||||
language: draftData.value.language,
|
||||
region: draftData.value.region
|
||||
}
|
||||
}
|
||||
|
||||
const handleSave = async () => {
|
||||
if (hasNewEmailChange.value && !isEmailVerified.value) {
|
||||
ElMessage.warning(t('Settings.messages.verifyEmailBeforeSave'))
|
||||
return
|
||||
}
|
||||
|
||||
const nextData = buildNextData()
|
||||
const previousLanguage = sourceData.value.language
|
||||
saving.value = true
|
||||
|
||||
try {
|
||||
sourceData.value = cloneSettingsData(nextData)
|
||||
|
||||
if (nextData.language !== previousLanguage) {
|
||||
syncAppLanguage(nextData.language)
|
||||
}
|
||||
|
||||
draftData.value = cloneSettingsData(sourceData.value)
|
||||
securityDraft.value = createEmptySecurityDraft()
|
||||
resetEmailVerificationState()
|
||||
isEditing.value = false
|
||||
ElMessage.success(t('Settings.messages.settingsUpdated'))
|
||||
} catch (error) {
|
||||
console.warn(error)
|
||||
} finally {
|
||||
saving.value = false
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => securityDraft.value.newEmail,
|
||||
(value) => {
|
||||
const trimmedValue = value.trim()
|
||||
|
||||
if (verifiedEmail.value && trimmedValue !== verifiedEmail.value) {
|
||||
verifiedEmail.value = ''
|
||||
}
|
||||
|
||||
if (
|
||||
isVerificationDialogVisible.value &&
|
||||
verificationTargetEmail.value &&
|
||||
trimmedValue !== verificationTargetEmail.value
|
||||
) {
|
||||
closeVerificationDialog()
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
return {
|
||||
sourceData,
|
||||
draftData,
|
||||
securityDraft,
|
||||
isEditing,
|
||||
saving,
|
||||
isVerificationDialogVisible,
|
||||
verificationTargetEmail,
|
||||
roleList,
|
||||
languageList,
|
||||
regionList,
|
||||
displayData,
|
||||
isEmailVerified,
|
||||
displayLanguageLabel,
|
||||
displayRegionLabel,
|
||||
fullName,
|
||||
roleModel,
|
||||
handleEdit,
|
||||
handleDiscard,
|
||||
handleSave,
|
||||
resetSecurityEmail,
|
||||
resetSecurityPassword,
|
||||
handleVerifyEmail,
|
||||
handleSendVerifyCode,
|
||||
handleVerificationSubmit,
|
||||
closeVerificationDialog
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user