|
|
|
|
@@ -1,6 +1,13 @@
|
|
|
|
|
import { computed, ref, shallowRef, watch, type Ref } from 'vue'
|
|
|
|
|
import { ElMessage } from 'element-plus'
|
|
|
|
|
import { fetchUserProfile, type UserProfile, updateUserProfile } from '@/api/user'
|
|
|
|
|
import md5 from 'md5'
|
|
|
|
|
import {
|
|
|
|
|
fetchUserProfile,
|
|
|
|
|
type UserProfile,
|
|
|
|
|
updateUserProfile,
|
|
|
|
|
verifyEmailCode,
|
|
|
|
|
fetchVerifyCode
|
|
|
|
|
} from '@/api/user'
|
|
|
|
|
import regionList from '@/utils/area'
|
|
|
|
|
import {
|
|
|
|
|
languageValues,
|
|
|
|
|
@@ -10,6 +17,7 @@ import {
|
|
|
|
|
type SecurityDraft,
|
|
|
|
|
type SettingsData
|
|
|
|
|
} from './types'
|
|
|
|
|
import { validateCase, validateLength, validateSpecial } from '@/views/login/tools'
|
|
|
|
|
|
|
|
|
|
type Translate = (key: string, ...args: unknown[]) => string
|
|
|
|
|
|
|
|
|
|
@@ -79,6 +87,7 @@ export function useSettingsForm({ t, locale }: UseSettingsFormOptions) {
|
|
|
|
|
const isVerificationDialogVisible = shallowRef(false)
|
|
|
|
|
const verificationTargetEmail = shallowRef('')
|
|
|
|
|
const verifiedEmail = shallowRef('')
|
|
|
|
|
const verificationCode = shallowRef('')
|
|
|
|
|
|
|
|
|
|
const roleList = computed(() =>
|
|
|
|
|
roleValues.map((value) => ({
|
|
|
|
|
@@ -104,6 +113,10 @@ export function useSettingsForm({ t, locale }: UseSettingsFormOptions) {
|
|
|
|
|
const isEmailVerified = computed(
|
|
|
|
|
() => hasNewEmailChange.value && verifiedEmail.value === normalizedNewEmail.value
|
|
|
|
|
)
|
|
|
|
|
const hasNewPasswordChange = computed(() => securityDraft.value.newPassword.length > 0)
|
|
|
|
|
const needsEmailVerification = computed(
|
|
|
|
|
() => (hasNewEmailChange.value || hasNewPasswordChange.value) && !isEmailVerified.value
|
|
|
|
|
)
|
|
|
|
|
const displayLanguageLabel = computed(() =>
|
|
|
|
|
displayData.value.language ? t(`Settings.languages.${displayData.value.language}`) : ''
|
|
|
|
|
)
|
|
|
|
|
@@ -137,6 +150,7 @@ export function useSettingsForm({ t, locale }: UseSettingsFormOptions) {
|
|
|
|
|
isVerificationDialogVisible.value = false
|
|
|
|
|
verificationTargetEmail.value = ''
|
|
|
|
|
verifiedEmail.value = ''
|
|
|
|
|
verificationCode.value = ''
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const syncAppLanguage = (language: LanguageValue) => {
|
|
|
|
|
@@ -192,41 +206,67 @@ export function useSettingsForm({ t, locale }: UseSettingsFormOptions) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const handleVerifyEmail = () => {
|
|
|
|
|
if (!hasNewEmailChange.value && !hasNewPasswordChange.value) return
|
|
|
|
|
|
|
|
|
|
const nextEmail = normalizedNewEmail.value
|
|
|
|
|
const newPassword = securityDraft.value.newPassword
|
|
|
|
|
const currentPassword = securityDraft.value.currentPassword
|
|
|
|
|
let targetEmail = ''
|
|
|
|
|
|
|
|
|
|
if (!nextEmail) {
|
|
|
|
|
ElMessage.warning(t('Settings.messages.enterNewEmailFirst'))
|
|
|
|
|
return
|
|
|
|
|
if (hasNewPasswordChange.value) {
|
|
|
|
|
if (validateLength(newPassword)) {
|
|
|
|
|
ElMessage.warning(t('Settings.messages.passwordLengthError', { min: 6, max: 20 }))
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (validateSpecial(newPassword)) {
|
|
|
|
|
ElMessage.warning(t('Settings.messages.passwordSpecial'))
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (validateCase(newPassword)) {
|
|
|
|
|
ElMessage.warning(t('Settings.messages.passwordCase'))
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (newPassword === currentPassword) {
|
|
|
|
|
ElMessage.warning(t('Settings.messages.passwordNotSameAsOld'))
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!emailPattern.test(nextEmail)) {
|
|
|
|
|
ElMessage.warning(t('Settings.messages.invalidEmail'))
|
|
|
|
|
return
|
|
|
|
|
if (hasNewEmailChange.value) {
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
targetEmail = nextEmail
|
|
|
|
|
} else if (hasNewPasswordChange.value) {
|
|
|
|
|
targetEmail = sourceData.value.email
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (nextEmail === sourceData.value.email) {
|
|
|
|
|
ElMessage.warning(t('Settings.messages.sameEmail'))
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if (!targetEmail) return
|
|
|
|
|
|
|
|
|
|
if (verifiedEmail.value === nextEmail) {
|
|
|
|
|
ElMessage.success(t('Settings.messages.alreadyVerified'))
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
verificationTargetEmail.value = nextEmail
|
|
|
|
|
verificationTargetEmail.value = targetEmail
|
|
|
|
|
handleSendVerifyCode()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const handleSendVerifyCode = () => {
|
|
|
|
|
// AccountSendVerifyCode({
|
|
|
|
|
// email: verificationTargetEmail.value,
|
|
|
|
|
// operationType: 'FORGET_PWD'
|
|
|
|
|
// }).then((res) => {
|
|
|
|
|
// console.log(res)
|
|
|
|
|
// ElMessage.success(t('Settings.messages.verificationCodeSent'))
|
|
|
|
|
// isVerificationDialogVisible.value = true
|
|
|
|
|
// })
|
|
|
|
|
fetchVerifyCode().then(() => {
|
|
|
|
|
ElMessage.success(t('Settings.messages.verificationCodeSent'))
|
|
|
|
|
isVerificationDialogVisible.value = true
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const handleVerificationSubmit = (code: string) => {
|
|
|
|
|
@@ -234,24 +274,13 @@ export function useSettingsForm({ t, locale }: UseSettingsFormOptions) {
|
|
|
|
|
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,
|
|
|
|
|
roles: [...draftData.value.roles],
|
|
|
|
|
language: draftData.value.language,
|
|
|
|
|
region: draftData.value.region
|
|
|
|
|
}
|
|
|
|
|
// send code to backend and store the code locally so save() can include it
|
|
|
|
|
verifyEmailCode(code).then((res) => {
|
|
|
|
|
verificationCode.value = code
|
|
|
|
|
verifiedEmail.value = verificationTargetEmail.value
|
|
|
|
|
closeVerificationDialog()
|
|
|
|
|
ElMessage.success(t('Settings.messages.verificationCompleted'))
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const handleSave = async () => {
|
|
|
|
|
@@ -260,13 +289,47 @@ export function useSettingsForm({ t, locale }: UseSettingsFormOptions) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const nextData = buildNextData()
|
|
|
|
|
if (hasNewPasswordChange.value && !verificationCode.value) {
|
|
|
|
|
ElMessage.warning(t('Settings.messages.verifyEmailBeforeSave'))
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const nextEmail = securityDraft.value.newEmail.trim() || draftData.value.email
|
|
|
|
|
const nextData: UserProfile = {
|
|
|
|
|
firstName: draftData.value.firstName.trim(),
|
|
|
|
|
lastName: draftData.value.lastName.trim(),
|
|
|
|
|
username: draftData.value.username.trim(),
|
|
|
|
|
email: nextEmail,
|
|
|
|
|
roles: draftData.value.roles as string[],
|
|
|
|
|
language: draftData.value.language,
|
|
|
|
|
region: draftData.value.region
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 如果改邮箱或改密码,需要添加验证码和密码信息
|
|
|
|
|
if (hasNewEmailChange.value || hasNewPasswordChange.value) {
|
|
|
|
|
nextData.verifyCode = verificationCode.value
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (hasNewPasswordChange.value) {
|
|
|
|
|
nextData.oldPassword = md5(securityDraft.value.currentPassword)
|
|
|
|
|
nextData.newPassword = md5(securityDraft.value.newPassword)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const previousLanguage = sourceData.value.language
|
|
|
|
|
saving.value = true
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
await updateUserProfile(nextData)
|
|
|
|
|
sourceData.value = cloneSettingsData(nextData)
|
|
|
|
|
const settingsData: SettingsData = {
|
|
|
|
|
firstName: nextData.firstName,
|
|
|
|
|
lastName: nextData.lastName,
|
|
|
|
|
username: nextData.username,
|
|
|
|
|
email: nextData.email,
|
|
|
|
|
roles: nextData.roles as RoleValue[],
|
|
|
|
|
language: nextData.language as LanguageValue | '',
|
|
|
|
|
region: nextData.region as any
|
|
|
|
|
}
|
|
|
|
|
sourceData.value = cloneSettingsData(settingsData)
|
|
|
|
|
console.log(nextData)
|
|
|
|
|
|
|
|
|
|
if (nextData.language && nextData.language !== previousLanguage) {
|
|
|
|
|
@@ -321,6 +384,7 @@ export function useSettingsForm({ t, locale }: UseSettingsFormOptions) {
|
|
|
|
|
displayRegionLabel,
|
|
|
|
|
fullName,
|
|
|
|
|
roleModel,
|
|
|
|
|
needsEmailVerification,
|
|
|
|
|
handleEdit,
|
|
|
|
|
handleDiscard,
|
|
|
|
|
handleSave,
|
|
|
|
|
|