feat(account): 按原型完善左下角账户菜单与个人信息
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
import { computed, reactive, ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { toUserMessage } from '@/utils/api-response'
|
||||
import { getCurrentUser, updateProfile } from '@/api/auth'
|
||||
import { useLoginStore } from '@/stores/login'
|
||||
import type { CurrentUserResponse } from '@/types/auth'
|
||||
|
||||
export function useAccountPanel() {
|
||||
const loginStore = useLoginStore()
|
||||
const router = useRouter()
|
||||
const panel = ref<'profile' | 'password' | null>(null)
|
||||
const profile = ref<CurrentUserResponse | null>(null)
|
||||
const loading = ref(false)
|
||||
const saving = ref(false)
|
||||
const error = ref('')
|
||||
const contacts = reactive({ phone: '', email: '' })
|
||||
const password = reactive({ current: '', next: '', confirm: '' })
|
||||
const strength = computed(() => {
|
||||
const value = password.next
|
||||
if (!value) return '—'
|
||||
if (
|
||||
value.length < 12 ||
|
||||
!/[A-Z]/.test(value) ||
|
||||
!/[a-z]/.test(value) ||
|
||||
!/\d/.test(value) ||
|
||||
!/[^A-Za-z0-9]/.test(value)
|
||||
)
|
||||
return '弱(未满足要求)'
|
||||
return value.length >= 16 ? '很强' : '强'
|
||||
})
|
||||
|
||||
let loadId = 0
|
||||
|
||||
async function open(kind: 'profile' | 'password') {
|
||||
const currentLoad = ++loadId
|
||||
loading.value = false
|
||||
error.value = ''
|
||||
profile.value = null
|
||||
Object.assign(contacts, { phone: '', email: '' })
|
||||
Object.assign(password, { current: '', next: '', confirm: '' })
|
||||
panel.value = kind
|
||||
if (kind !== 'profile') return
|
||||
loading.value = true
|
||||
try {
|
||||
const result = await getCurrentUser()
|
||||
if (currentLoad !== loadId) return
|
||||
profile.value = result
|
||||
contacts.phone = profile.value.phone ?? ''
|
||||
contacts.email = profile.value.email ?? ''
|
||||
} catch (cause) {
|
||||
if (currentLoad === loadId) error.value = toUserMessage(cause, '个人信息加载失败,请重试')
|
||||
} finally {
|
||||
if (currentLoad === loadId) loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function close() {
|
||||
if (saving.value) return
|
||||
loadId++
|
||||
panel.value = null
|
||||
Object.assign(password, { current: '', next: '', confirm: '' })
|
||||
}
|
||||
|
||||
async function save() {
|
||||
if (saving.value || loading.value) return
|
||||
error.value = ''
|
||||
if (panel.value === 'password') {
|
||||
if (!password.current) error.value = '请输入当前密码'
|
||||
else if (strength.value.startsWith('弱') || !password.next || password.next.length > 128)
|
||||
error.value = '新密码须为 12–128 位,同时包含大小写字母、数字和特殊字符'
|
||||
else if (password.next !== password.confirm) error.value = '两次输入的新密码不一致'
|
||||
else if (password.current === password.next) error.value = '新密码不能与当前密码相同'
|
||||
} else {
|
||||
if (!profile.value) return
|
||||
const phone = contacts.phone.trim()
|
||||
const email = contacts.email.trim()
|
||||
if (phone !== (profile.value.phone ?? '') && phone && !/^[0-9+() -]{5,32}$/.test(phone))
|
||||
error.value = '请输入有效的完整手机号'
|
||||
else if (
|
||||
email !== (profile.value.email ?? '') &&
|
||||
email &&
|
||||
(email.includes('*') || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email))
|
||||
)
|
||||
error.value = '请输入有效的完整邮箱'
|
||||
}
|
||||
if (error.value) return
|
||||
saving.value = true
|
||||
try {
|
||||
if (panel.value === 'password') {
|
||||
await loginStore.changePassword({
|
||||
currentPassword: password.current,
|
||||
newPassword: password.next,
|
||||
})
|
||||
Object.assign(password, { current: '', next: '', confirm: '' })
|
||||
panel.value = null
|
||||
await router.replace({ name: 'login', query: { passwordChanged: '1' } })
|
||||
} else if (profile.value) {
|
||||
await updateProfile({
|
||||
phone:
|
||||
contacts.phone.trim() === (profile.value.phone ?? '')
|
||||
? undefined
|
||||
: contacts.phone.trim(),
|
||||
email:
|
||||
contacts.email.trim() === (profile.value.email ?? '')
|
||||
? undefined
|
||||
: contacts.email.trim(),
|
||||
expectedVersion: profile.value.version,
|
||||
})
|
||||
panel.value = null
|
||||
ElMessage.success('联系方式已保存')
|
||||
}
|
||||
} catch (cause) {
|
||||
error.value = toUserMessage(cause, '保存失败,请稍后重试')
|
||||
} finally {
|
||||
saving.value = false
|
||||
}
|
||||
}
|
||||
|
||||
return { panel, profile, loading, saving, error, contacts, password, strength, open, close, save }
|
||||
}
|
||||
Reference in New Issue
Block a user