fix(user): 默认头像不再写入用户资料 (#740)

This commit is contained in:
InfinityPacer
2026-09-01 21:14:22 +08:00
committed by GitHub
parent d7a6e9d142
commit b07d60ca34
4 changed files with 32 additions and 12 deletions
+7 -6
View File
@@ -46,7 +46,8 @@ const currentLoginUser = userStore.userName
const userName = ref('')
// 当前头像缓存
const currentAvatar = ref(avatar1)
const currentAvatar = ref('')
const displayedAvatar = computed(() => currentAvatar.value || avatar1)
// 用户名缓存
const currentUserName = ref('')
@@ -82,7 +83,7 @@ const userForm = ref<ExtendedUser>({
email: '',
is_active: true,
is_superuser: false,
avatar: avatar1,
avatar: '',
is_otp: false,
permissions: {
discovery: true,
@@ -267,13 +268,13 @@ function changeAvatar(file: Event) {
/** 将头像恢复为系统默认头像。 */
function resetDefaultAvatar() {
currentAvatar.value = avatar1
currentAvatar.value = ''
$toast.success(t('dialog.userAddEdit.resetAvatarSuccess'))
}
/** 还原为用户当前已保存的头像。 */
function restoreCurrentAvatar() {
currentAvatar.value = userForm.value.avatar
currentAvatar.value = userForm.value.avatar || ''
$toast.success(t('dialog.userAddEdit.restoreAvatarSuccess'))
}
@@ -282,7 +283,7 @@ async function fetchUserInfo() {
try {
userForm.value = await api.get(`user/${props.username}`)
if (userForm.value) {
userForm.value.avatar = userForm.value.avatar || avatar1
userForm.value.avatar = userForm.value.avatar || ''
userForm.value.nickname = userForm.value.settings?.nickname ?? ''
currentAvatar.value = userForm.value.avatar
currentUserName.value = userForm.value.name
@@ -455,7 +456,7 @@ onMounted(() => {
<VCardItem>
<!-- 👉 Avatar -->
<div class="flex flex-row">
<VAvatar rounded="lg" size="100" class="me-5" :image="currentAvatar" />
<VAvatar rounded="lg" size="100" class="me-5" :image="displayedAvatar" />
<!-- 👉 Upload Photo -->
<div class="flex flex-col justify-center gap-5">
<div class="flex flex-wrap gap-2">
@@ -350,4 +350,17 @@ describe('UserAddEditDialog', () => {
await waitFor(() => expect(mocks.apiPut).toHaveBeenCalledTimes(2))
expect(mocks.apiPut.mock.calls[1][1]).toMatchObject({ avatar: 'saved-avatar.png' })
})
it('persists an empty avatar after resetting a user to the built-in default', async () => {
mocks.apiGet.mockResolvedValue(createUser({ avatar: 'saved-avatar.png', name: 'alice' }))
mocks.apiPut.mockResolvedValue({ success: true })
await renderDialog('edit', 'alice')
await screen.findByDisplayValue('alice')
await fireEvent.click(screen.getByRole('button', { name: /重置默认头像/ }))
await fireEvent.click(screen.getByRole('button', { name: '保存' }))
await waitFor(() => expect(mocks.apiPut).toHaveBeenCalledOnce())
expect(mocks.apiPut.mock.calls[0][1]).toMatchObject({ avatar: '' })
})
})
+7 -6
View File
@@ -41,7 +41,8 @@ const isProfileLoading = ref(true)
const profileLoadFailed = ref(false)
// 当前头像缓存
const currentAvatar = ref(avatar1)
const currentAvatar = ref('')
const displayedAvatar = computed(() => currentAvatar.value || avatar1)
// 当前用户名
const currentUserName = ref('')
@@ -182,13 +183,13 @@ function changeAvatar(file: Event) {
// 重置默认头像
function resetDefaultAvatar() {
currentAvatar.value = avatar1
currentAvatar.value = ''
$toast.success(t('profile.resetAvatarSuccess'))
}
// 还原当前头像
function restoreCurrentAvatar() {
currentAvatar.value = accountInfo.value.avatar
currentAvatar.value = accountInfo.value.avatar || ''
$toast.success(t('profile.restoreAvatarSuccess'))
}
@@ -247,7 +248,7 @@ async function saveAccountInfo() {
const updatedUser = await api.put<User>('user/current', userData, { feedback: 'silent' })
applyUserProfile(updatedUser)
userStore.setUserName(updatedUser.name)
userStore.setAvatar(currentAvatar.value)
userStore.setAvatar(updatedUser.avatar || '')
// 凭据仅在服务端确认成功后清空,失败时保留输入便于修正或重试。
newPassword.value = ''
confirmPassword.value = ''
@@ -288,7 +289,7 @@ function applyUserProfile(user: User) {
nickname: user.settings?.nickname ?? '',
}
currentUserName.value = user.name
currentAvatar.value = user.avatar || avatar1
currentAvatar.value = user.avatar || ''
}
// 密码验证并执行回调
@@ -356,7 +357,7 @@ watch(
<VCard :title="t('profile.personalInfo')">
<VCardText class="flex">
<!-- 👉 Avatar -->
<VAvatar rounded="lg" size="100" class="me-6" :image="currentAvatar" />
<VAvatar rounded="lg" size="100" class="me-6" :image="displayedAvatar" />
<!-- 👉 Upload Photo -->
<form class="flex flex-col justify-center gap-5">
@@ -150,6 +150,7 @@ describe('UserProfileView', () => {
it('validates avatar files and supports restoring the saved or default avatar', async () => {
mockSuccessfulLoad()
mocks.apiPut.mockResolvedValue(currentUser({ avatar: '' }))
const { container } = await renderProfile()
await screen.findByDisplayValue('alice@example.com')
const fileInput = container.querySelector('input[type="file"]') as HTMLInputElement
@@ -167,6 +168,10 @@ describe('UserProfileView', () => {
await fireEvent.click(screen.getByRole('button', { name: '默认' }))
expect(mocks.toastSuccess).toHaveBeenCalledWith('已还原当前使用头像!')
expect(mocks.toastSuccess).toHaveBeenCalledWith('已重置为默认头像,待保存后生效!')
await fireEvent.click(screen.getByRole('button', { name: '保存' }))
await waitFor(() => expect(mocks.apiPut).toHaveBeenCalledOnce())
expect(mocks.apiPut.mock.calls[0][1]).toMatchObject({ avatar: '' })
})
it('keeps notification identity fields editable in the profile payload', async () => {