mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-09-05 15:36:49 +08:00
feat(user): add username modification function.
This commit is contained in:
@@ -10,14 +10,20 @@ import UserAddEditDialog from '@/components/dialog/UserAddEditDialog.vue'
|
|||||||
|
|
||||||
// 定义输入变量
|
// 定义输入变量
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
|
// 用户信息
|
||||||
user: {
|
user: {
|
||||||
type: Object as PropType<User>,
|
type: Object as PropType<User>,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
|
// 所有用户
|
||||||
|
users: {
|
||||||
|
type: Array as PropType<User[]>,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
// 当前用户名称
|
// 当前用户名称
|
||||||
const currentUser = store.state.auth.userName
|
const currentLoginUser = store.state.auth.userName
|
||||||
|
|
||||||
// 定义触发的自定义事件
|
// 定义触发的自定义事件
|
||||||
const emit = defineEmits(['remove', 'save'])
|
const emit = defineEmits(['remove', 'save'])
|
||||||
@@ -52,13 +58,17 @@ async function fetchSubscriptions() {
|
|||||||
|
|
||||||
// 删除用户
|
// 删除用户
|
||||||
async function removeUser() {
|
async function removeUser() {
|
||||||
|
if (props.user.name == currentLoginUser) {
|
||||||
|
$toast.error('不能删除当前登录用户!')
|
||||||
|
return
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
const isConfirmed = await createConfirm({
|
const isConfirmed = await createConfirm({
|
||||||
title: '确认',
|
title: '注意',
|
||||||
content: `删除用户 ${props.user?.name} 的所有数据,是否确认?`,
|
content: `删除用户 ${props.user?.name} 的所有数据,是否确认?`,
|
||||||
})
|
})
|
||||||
if (!isConfirmed) return
|
if (!isConfirmed) return
|
||||||
const result: { [key: string]: any } = await api.delete(`user/${props.user.name}`)
|
const result: { [key: string]: any } = await api.delete(`user/id/${props.user.id}`)
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
$toast.success('用户删除成功')
|
$toast.success('用户删除成功')
|
||||||
emit('remove')
|
emit('remove')
|
||||||
@@ -83,7 +93,7 @@ const canEditUser = computed(() => {
|
|||||||
|
|
||||||
// 计算是否有用户管理权限
|
// 计算是否有用户管理权限
|
||||||
const canManageUser = computed(() => {
|
const canManageUser = computed(() => {
|
||||||
if (props.user.name == currentUser) return false
|
if (props.user.name == currentLoginUser) return false
|
||||||
return canEditUser
|
return canEditUser
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -169,6 +179,7 @@ onMounted(() => {
|
|||||||
v-if="userEditDialog"
|
v-if="userEditDialog"
|
||||||
v-model="userEditDialog"
|
v-model="userEditDialog"
|
||||||
:username="props.user?.name"
|
:username="props.user?.name"
|
||||||
|
:usernames="props.users.map(item => item.name)"
|
||||||
oper="edit"
|
oper="edit"
|
||||||
@save="onUserUpdate"
|
@save="onUserUpdate"
|
||||||
@close="userEditDialog = false"
|
@close="userEditDialog = false"
|
||||||
|
|||||||
@@ -19,21 +19,40 @@ const confirmPassword = ref('')
|
|||||||
// 输入参数
|
// 输入参数
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
username: String,
|
username: String,
|
||||||
|
usernames: Array,
|
||||||
oper: String,
|
oper: String,
|
||||||
})
|
})
|
||||||
|
|
||||||
// 当前登录用户名称
|
// 当前登录用户名称
|
||||||
const currentUser = store.state.auth.userName
|
const currentLoginUser = store.state.auth.userName
|
||||||
|
|
||||||
// 用户名
|
// 用户名
|
||||||
const userName = ref('')
|
const userName = ref('')
|
||||||
|
|
||||||
// 当前头像缓存
|
// 当前头像缓存
|
||||||
const nowAvatar = ref(avatar1)
|
const currentAvatar = ref(avatar1)
|
||||||
|
|
||||||
|
// 用户名缓存
|
||||||
|
const currentUserName = ref('')
|
||||||
|
|
||||||
// 注册事件
|
// 注册事件
|
||||||
const emit = defineEmits(['save', 'close'])
|
const emit = defineEmits(['save', 'close'])
|
||||||
|
|
||||||
|
// 创建新用户按钮运行状态
|
||||||
|
const isAdding = ref(false);
|
||||||
|
|
||||||
|
// 更新用户消息按钮运行状态
|
||||||
|
const isUpdating = ref(false);
|
||||||
|
|
||||||
|
// 提示框
|
||||||
|
const $toast = useToast()
|
||||||
|
|
||||||
|
// 状态下拉项
|
||||||
|
const statusItems = [
|
||||||
|
{ title: '激活', value: 1 },
|
||||||
|
{ title: '已停用', value: 0 },
|
||||||
|
]
|
||||||
|
|
||||||
// 用户编辑表单数据
|
// 用户编辑表单数据
|
||||||
const userForm = ref<User>({
|
const userForm = ref<User>({
|
||||||
id: 0,
|
id: 0,
|
||||||
@@ -62,7 +81,7 @@ function changeAvatar(file: Event) {
|
|||||||
fileReader.readAsDataURL(files[0])
|
fileReader.readAsDataURL(files[0])
|
||||||
fileReader.onload = () => {
|
fileReader.onload = () => {
|
||||||
if (typeof fileReader.result === 'string') {
|
if (typeof fileReader.result === 'string') {
|
||||||
nowAvatar.value = fileReader.result
|
currentAvatar.value = fileReader.result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -70,32 +89,24 @@ function changeAvatar(file: Event) {
|
|||||||
|
|
||||||
// 重置默认头像
|
// 重置默认头像
|
||||||
function resetDefaultAvatar() {
|
function resetDefaultAvatar() {
|
||||||
nowAvatar.value = avatar1
|
currentAvatar.value = avatar1
|
||||||
$toast.success('已重置为默认头像,待保存后生效!')
|
$toast.success('已重置为默认头像,待保存后生效!')
|
||||||
}
|
}
|
||||||
|
|
||||||
// 还原当前头像
|
// 还原当前头像
|
||||||
function restoreNowAvatar() {
|
function restoreCurrentAvatar() {
|
||||||
nowAvatar.value = userForm.value.avatar
|
currentAvatar.value = userForm.value.avatar
|
||||||
$toast.success('已还原当前使用头像!')
|
$toast.success('已还原当前使用头像!')
|
||||||
}
|
}
|
||||||
|
|
||||||
// 提示框
|
|
||||||
const $toast = useToast()
|
|
||||||
|
|
||||||
// 状态下拉项
|
|
||||||
const statusItems = [
|
|
||||||
{ title: '激活', value: 1 },
|
|
||||||
{ title: '已停用', value: 0 },
|
|
||||||
]
|
|
||||||
|
|
||||||
// 查询用户信息
|
// 查询用户信息
|
||||||
async function fetchUserInfo() {
|
async function fetchUserInfo() {
|
||||||
try {
|
try {
|
||||||
userForm.value = await api.get(`user/${props.username}`)
|
userForm.value = await api.get(`user/${props.username}`)
|
||||||
if (userForm.value) {
|
if (userForm.value) {
|
||||||
userForm.value.avatar = userForm.value.avatar || avatar1
|
userForm.value.avatar = userForm.value.avatar || avatar1
|
||||||
nowAvatar.value = userForm.value.avatar
|
currentAvatar.value = userForm.value.avatar
|
||||||
|
currentUserName.value = userForm.value.name
|
||||||
userName.value = userForm.value.name
|
userName.value = userForm.value.name
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -105,6 +116,19 @@ async function fetchUserInfo() {
|
|||||||
|
|
||||||
// 调用API 新增用户
|
// 调用API 新增用户
|
||||||
async function addUser() {
|
async function addUser() {
|
||||||
|
if (isAdding.value) {
|
||||||
|
$toast.error(`正在创建【${userForm.value.name}】用户,请稍后`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!currentUserName.value) {
|
||||||
|
$toast.error('用户名不能为空')
|
||||||
|
return
|
||||||
|
} else userForm.value.name = currentUserName.value
|
||||||
|
// 重名检查
|
||||||
|
if (props.usernames && props.usernames.includes(userForm.value.name)) {
|
||||||
|
$toast.error('用户名已存在')
|
||||||
|
return
|
||||||
|
}
|
||||||
if (!userForm.value?.name || !newPassword.value) return
|
if (!userForm.value?.name || !newPassword.value) return
|
||||||
if (newPassword.value || confirmPassword.value) {
|
if (newPassword.value || confirmPassword.value) {
|
||||||
if (newPassword.value !== confirmPassword.value) {
|
if (newPassword.value !== confirmPassword.value) {
|
||||||
@@ -113,23 +137,35 @@ async function addUser() {
|
|||||||
}
|
}
|
||||||
userForm.value.password = newPassword.value
|
userForm.value.password = newPassword.value
|
||||||
}
|
}
|
||||||
|
isAdding.value = true
|
||||||
startNProgress()
|
startNProgress()
|
||||||
try {
|
try {
|
||||||
const result: { [key: string]: string } = await api.post('user/', userForm.value)
|
const result: { [key: string]: string } = await api.post('user/', userForm.value)
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
$toast.success('新增用户成功')
|
$toast.success(`用户【${userForm.value.name}】创建成功`)
|
||||||
emit('save')
|
emit('save')
|
||||||
} else {
|
} else {
|
||||||
$toast.error(`新增用户失败:${result.message}`)
|
$toast.error(`创建用户失败:${result.message}`)
|
||||||
|
// 清除用户名
|
||||||
|
userForm.value.name = ''
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error)
|
console.error(error)
|
||||||
}
|
}
|
||||||
doneNProgress()
|
doneNProgress()
|
||||||
|
isAdding.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// 调用API更新用户信息
|
// 调用API更新用户信息
|
||||||
async function updateUser() {
|
async function updateUser() {
|
||||||
|
if (isUpdating.value) {
|
||||||
|
$toast.error(`正在更新【${userForm.value.name}】用户,请稍后`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!currentUserName.value) {
|
||||||
|
$toast.error('用户名不能为空')
|
||||||
|
return
|
||||||
|
}
|
||||||
if (newPassword.value || confirmPassword.value) {
|
if (newPassword.value || confirmPassword.value) {
|
||||||
if (newPassword.value !== confirmPassword.value) {
|
if (newPassword.value !== confirmPassword.value) {
|
||||||
$toast.error('两次输入的密码不一致')
|
$toast.error('两次输入的密码不一致')
|
||||||
@@ -137,26 +173,47 @@ async function updateUser() {
|
|||||||
}
|
}
|
||||||
userForm.value.password = newPassword.value
|
userForm.value.password = newPassword.value
|
||||||
}
|
}
|
||||||
|
const oldUserName = userForm.value.name
|
||||||
|
userForm.value.name = currentUserName.value
|
||||||
const oldAvatar = userForm.value.avatar
|
const oldAvatar = userForm.value.avatar
|
||||||
userForm.value.avatar = nowAvatar.value
|
userForm.value.avatar = currentAvatar.value
|
||||||
|
isUpdating.value = true
|
||||||
startNProgress()
|
startNProgress()
|
||||||
try {
|
try {
|
||||||
const result: { [key: string]: any } = await api.put('user/', userForm.value)
|
const result: { [key: string]: any } = await api.put('user/', userForm.value)
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
$toast.success(`${userForm.value?.name} 更新成功!`)
|
if (oldUserName !== currentUserName.value) {
|
||||||
// 通知 localStorage 立刻更新头像
|
$toast.success(`【${oldUserName}】更名【${currentUserName.value}】, 更新成功!`)
|
||||||
if (oldAvatar !== nowAvatar.value && isCurrentUser.value) {
|
// 如果是当前登录用户,更新当前用户名称显示
|
||||||
store.commit('auth/setAvatar', nowAvatar.value)
|
if (isCurrentUser.value) store.commit('auth/setUserName', currentUserName.value)
|
||||||
|
} else {
|
||||||
|
$toast.success(`【${userForm.value?.name}】更新成功!`)
|
||||||
|
}
|
||||||
|
// 更新本地头像显示
|
||||||
|
if (oldAvatar !== currentAvatar.value && isCurrentUser.value) {
|
||||||
|
store.commit('auth/setAvatar', currentAvatar.value)
|
||||||
}
|
}
|
||||||
emit('save')
|
emit('save')
|
||||||
} else {
|
} else {
|
||||||
$toast.error(`${userForm.value?.name} 更新失败:${result.message}`)
|
if (oldUserName !== currentUserName.value) {
|
||||||
|
$toast.error(`【${oldUserName}】更名【${currentUserName.value}】, 更新失败:${result.message}`)
|
||||||
|
currentUserName.value = oldUserName
|
||||||
|
} else {
|
||||||
|
$toast.error(`【${userForm.value?.name}】更新失败:${result.message}`)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
//失败缓存值还原
|
||||||
|
currentUserName.value = userForm.value.name
|
||||||
|
userForm.value.name = oldUserName
|
||||||
|
currentAvatar.value = userForm.value.avatar
|
||||||
|
userForm.value.avatar = oldAvatar
|
||||||
|
userForm.value.password = ''
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
$toast.error(`${userForm.value?.name} 更新失败!`)
|
$toast.error(`【${userForm.value?.name}】更新失败!`)
|
||||||
console.error(error)
|
console.error(error)
|
||||||
}
|
}
|
||||||
doneNProgress()
|
doneNProgress()
|
||||||
|
isUpdating.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// 用户状态转换,true/false转换为1/0
|
// 用户状态转换,true/false转换为1/0
|
||||||
@@ -180,7 +237,7 @@ const canControl = computed(() => {
|
|||||||
|
|
||||||
// 检查是否为当前用户
|
// 检查是否为当前用户
|
||||||
const isCurrentUser = computed(() => {
|
const isCurrentUser = computed(() => {
|
||||||
return props.username === currentUser
|
return props.username === currentLoginUser
|
||||||
})
|
})
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
@@ -189,10 +246,6 @@ onMounted(() => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// 监听 localStorage 中的头像变化
|
|
||||||
watch(() => store.state.auth.avatar, () => {
|
|
||||||
nowAvatar.value = store.state.auth.avatar
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -205,7 +258,7 @@ watch(() => store.state.auth.avatar, () => {
|
|||||||
<VDivider />
|
<VDivider />
|
||||||
<VCardText class="d-flex">
|
<VCardText class="d-flex">
|
||||||
<!-- 👉 Avatar -->
|
<!-- 👉 Avatar -->
|
||||||
<VAvatar rounded="lg" size="100" class="me-6" :image="nowAvatar" />
|
<VAvatar rounded="lg" size="100" class="me-6" :image="currentAvatar" />
|
||||||
|
|
||||||
<!-- 👉 Upload Photo -->
|
<!-- 👉 Upload Photo -->
|
||||||
<form class="d-flex flex-column justify-center gap-5">
|
<form class="d-flex flex-column justify-center gap-5">
|
||||||
@@ -218,14 +271,15 @@ watch(() => store.state.auth.avatar, () => {
|
|||||||
<input ref="refInputEl" type="file" name="file" accept=".jpeg,.png,.jpg,GIF" hidden @input="changeAvatar" />
|
<input ref="refInputEl" type="file" name="file" accept=".jpeg,.png,.jpg,GIF" hidden @input="changeAvatar" />
|
||||||
|
|
||||||
|
|
||||||
<VBtn type="reset" color="error" variant="tonal" @click="restoreNowAvatar">
|
<VBtn type="reset" color="info" variant="tonal" @click="restoreCurrentAvatar" v-if="props.oper !== 'add'">
|
||||||
<VIcon icon="mdi-refresh" />
|
<VIcon icon="mdi-refresh" />
|
||||||
<span v-if="display.mdAndUp.value" class="ms-2">还原当前头像</span>
|
<span v-if="display.mdAndUp.value" class="ms-2">重置</span>
|
||||||
</VBtn>
|
</VBtn>
|
||||||
|
|
||||||
<VBtn type="reset" color="error" variant="tonal" @click="resetDefaultAvatar">
|
<VBtn type="reset" :color="props.oper === 'add'? 'info' : 'error'" variant="tonal"
|
||||||
<VIcon icon="mdi-refresh" />
|
@click="resetDefaultAvatar">
|
||||||
<span v-if="display.mdAndUp.value" class="ms-2">重置默认头像</span>
|
<VIcon icon="mdi-image-sync-outline" />
|
||||||
|
<span v-if="display.mdAndUp.value" class="ms-2">默认</span>
|
||||||
</VBtn>
|
</VBtn>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -239,8 +293,13 @@ watch(() => store.state.auth.avatar, () => {
|
|||||||
<span>用户基础设置</span>
|
<span>用户基础设置</span>
|
||||||
</VDivider>
|
</VDivider>
|
||||||
<VRow>
|
<VRow>
|
||||||
<VCol md="6" cols="12" v-if="props.oper === 'add'">
|
<VCol md="6" cols="12">
|
||||||
<VTextField v-model="userForm.name" density="comfortable" label="用户名" />
|
<VTextField
|
||||||
|
v-model="currentUserName"
|
||||||
|
density="comfortable"
|
||||||
|
clearable
|
||||||
|
label="用户名"
|
||||||
|
/>
|
||||||
</VCol>
|
</VCol>
|
||||||
<VCol cols="12" md="6">
|
<VCol cols="12" md="6">
|
||||||
<VTextField
|
<VTextField
|
||||||
@@ -332,23 +391,27 @@ watch(() => store.state.auth.avatar, () => {
|
|||||||
<VSpacer />
|
<VSpacer />
|
||||||
<VBtn
|
<VBtn
|
||||||
v-if="props.oper === 'add'"
|
v-if="props.oper === 'add'"
|
||||||
|
:disabled="isAdding"
|
||||||
color="primary"
|
color="primary"
|
||||||
variant="elevated"
|
variant="elevated"
|
||||||
@click="addUser"
|
@click="addUser"
|
||||||
prepend-icon="mdi-plus"
|
prepend-icon="mdi-plus"
|
||||||
class="px-5"
|
class="px-5"
|
||||||
>
|
>
|
||||||
新增
|
<span v-if="isAdding">创建中...</span>
|
||||||
|
<span v-else>创建</span>
|
||||||
</VBtn>
|
</VBtn>
|
||||||
<VBtn
|
<VBtn
|
||||||
v-else
|
v-else
|
||||||
|
:disabled="isUpdating"
|
||||||
color="primary"
|
color="primary"
|
||||||
variant="elevated"
|
variant="elevated"
|
||||||
@click="updateUser"
|
@click="updateUser"
|
||||||
prepend-icon="mdi-content-save"
|
prepend-icon="mdi-content-save"
|
||||||
class="px-5"
|
class="px-5"
|
||||||
>
|
>
|
||||||
保存
|
<span v-if="isUpdating" >更新中...</span>
|
||||||
|
<span v-else>更新</span>
|
||||||
</VBtn>
|
</VBtn>
|
||||||
</VCardActions>
|
</VCardActions>
|
||||||
</VCard>
|
</VCard>
|
||||||
|
|||||||
@@ -63,8 +63,8 @@ async function restart() {
|
|||||||
const isCompactMode = ref(localStorage.getItem('MP_APPMODE') != '0')
|
const isCompactMode = ref(localStorage.getItem('MP_APPMODE') != '0')
|
||||||
|
|
||||||
// 从Vuex Store中获取信息
|
// 从Vuex Store中获取信息
|
||||||
const superUser = store.state.auth.superUser
|
const superUser = computed(() =>store.state.auth.superUser)
|
||||||
const userName = store.state.auth.userName
|
const userName = computed(() =>store.state.auth.userName)
|
||||||
const avatar = computed(() => store.state.auth.avatar || avatar1)
|
const avatar = computed(() => store.state.auth.avatar || avatar1)
|
||||||
|
|
||||||
// 监听精简模式切换
|
// 监听精简模式切换
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ onActivated(() => {
|
|||||||
<LoadingBanner v-if="!isRefreshed" class="mt-12" />
|
<LoadingBanner v-if="!isRefreshed" class="mt-12" />
|
||||||
|
|
||||||
<div v-if="allUsers.length > 0" class="grid gap-3 grid-user-card items-start">
|
<div v-if="allUsers.length > 0" class="grid gap-3 grid-user-card items-start">
|
||||||
<UserCard v-for="user in allUsers" :user="user" @remove="loadAllUsers" @save="loadAllUsers" />
|
<UserCard v-for="user in allUsers" :user="user" :users="allUsers" @remove="loadAllUsers" @save="loadAllUsers" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<NoDataFound
|
<NoDataFound
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import {useToast} from 'vue-toast-notification'
|
import { useToast } from 'vue-toast-notification'
|
||||||
import QrcodeVue from 'qrcode.vue'
|
import QrcodeVue from 'qrcode.vue'
|
||||||
import {VForm} from 'vuetify/lib/components/index.mjs'
|
import { VForm } from 'vuetify/lib/components/index.mjs'
|
||||||
import api from '@/api'
|
import api from '@/api'
|
||||||
import type {User} from '@/api/types'
|
import type { User } from '@/api/types'
|
||||||
import avatar1 from '@images/avatars/avatar-1.png'
|
import avatar1 from '@images/avatars/avatar-1.png'
|
||||||
import {useDisplay} from 'vuetify'
|
import { useDisplay } from 'vuetify'
|
||||||
import store from "@/store";
|
import store from '@/store'
|
||||||
|
|
||||||
// 显示器宽度
|
// 显示器宽度
|
||||||
const display = useDisplay()
|
const display = useDisplay()
|
||||||
@@ -34,7 +34,10 @@ const secret = ref('')
|
|||||||
const otpPassword = ref('')
|
const otpPassword = ref('')
|
||||||
|
|
||||||
// 当前头像缓存
|
// 当前头像缓存
|
||||||
const nowAvatar = ref(avatar1)
|
const currentAvatar = ref(avatar1)
|
||||||
|
|
||||||
|
// 当前用户名
|
||||||
|
const currentUserName = ref('')
|
||||||
|
|
||||||
// 当前用户信息
|
// 当前用户信息
|
||||||
const accountInfo = ref<User>({
|
const accountInfo = ref<User>({
|
||||||
@@ -71,7 +74,7 @@ function changeAvatar(file: Event) {
|
|||||||
fileReader.readAsDataURL(files[0])
|
fileReader.readAsDataURL(files[0])
|
||||||
fileReader.onload = () => {
|
fileReader.onload = () => {
|
||||||
if (typeof fileReader.result === 'string') {
|
if (typeof fileReader.result === 'string') {
|
||||||
nowAvatar.value = fileReader.result
|
currentAvatar.value = fileReader.result
|
||||||
$toast.success('新头像上传成功,待保存后生效!')
|
$toast.success('新头像上传成功,待保存后生效!')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -80,13 +83,13 @@ function changeAvatar(file: Event) {
|
|||||||
|
|
||||||
// 重置默认头像
|
// 重置默认头像
|
||||||
function resetDefaultAvatar() {
|
function resetDefaultAvatar() {
|
||||||
nowAvatar.value = avatar1
|
currentAvatar.value = avatar1
|
||||||
$toast.success('已重置为默认头像,待保存后生效!')
|
$toast.success('已重置为默认头像,待保存后生效!')
|
||||||
}
|
}
|
||||||
|
|
||||||
// 还原当前头像
|
// 还原当前头像
|
||||||
function restoreNowAvatar() {
|
function restoreCurrentAvatar() {
|
||||||
nowAvatar.value = accountInfo.value.avatar
|
currentAvatar.value = accountInfo.value.avatar
|
||||||
$toast.success('已还原当前使用头像!')
|
$toast.success('已还原当前使用头像!')
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,7 +102,8 @@ async function loadAccountInfo() {
|
|||||||
if (!accountInfo.value.avatar) {
|
if (!accountInfo.value.avatar) {
|
||||||
accountInfo.value.avatar = avatar1
|
accountInfo.value.avatar = avatar1
|
||||||
}
|
}
|
||||||
nowAvatar.value = accountInfo.value.avatar
|
currentAvatar.value = accountInfo.value.avatar
|
||||||
|
currentUserName.value = accountInfo.value.name
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error)
|
console.log(error)
|
||||||
}
|
}
|
||||||
@@ -107,26 +111,47 @@ async function loadAccountInfo() {
|
|||||||
|
|
||||||
// 保存用户信息
|
// 保存用户信息
|
||||||
async function saveAccountInfo() {
|
async function saveAccountInfo() {
|
||||||
|
if (!currentUserName.value) {
|
||||||
|
$toast.error('用户名不能为空')
|
||||||
|
return
|
||||||
|
}
|
||||||
if (newPassword.value || confirmPassword.value) {
|
if (newPassword.value || confirmPassword.value) {
|
||||||
if (newPassword.value !== confirmPassword.value) {
|
if (newPassword.value !== confirmPassword.value) {
|
||||||
$toast.error('两次输入的密码不一致')
|
$toast.error('两次输入的密码不一致')
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
accountInfo.value.password = newPassword.value
|
accountInfo.value.password = newPassword.value
|
||||||
}
|
}
|
||||||
|
const oldUserName = accountInfo.value.name
|
||||||
const oldAvatar = accountInfo.value.avatar
|
const oldAvatar = accountInfo.value.avatar
|
||||||
accountInfo.value.avatar = nowAvatar.value
|
accountInfo.value.avatar = currentAvatar.value
|
||||||
|
accountInfo.value.name = currentUserName.value
|
||||||
try {
|
try {
|
||||||
const result: { [key: string]: any } = await api.put('user/', accountInfo.value)
|
const result: { [key: string]: any } = await api.put('user/', accountInfo.value)
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
$toast.success('用户信息保存成功!')
|
if (oldUserName !== currentUserName.value) {
|
||||||
if (oldAvatar !== nowAvatar.value) {
|
$toast.success(`【${oldUserName}】更名【${currentUserName.value}】,用户信息保存成功!`)
|
||||||
// 通知 localStorage 中的用户头像发生变化
|
// 更新本地用户名显示
|
||||||
store.commit('auth/setAvatar', nowAvatar.value)
|
store.commit('auth/setUserName', currentUserName.value)
|
||||||
|
} else {
|
||||||
|
$toast.success('用户信息保存成功!')
|
||||||
}
|
}
|
||||||
|
// 更新本地头像显示
|
||||||
|
if (oldAvatar !== currentAvatar.value) {
|
||||||
|
store.commit('auth/setAvatar', currentAvatar.value)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (oldAvatar !== currentAvatar.value) {
|
||||||
|
$toast.error(`【${oldUserName}】更名【${currentUserName.value}】,信息保存失败:${result.message}!`)
|
||||||
|
} else {
|
||||||
|
$toast.error(`用户信息保存失败:${result.message}!`)
|
||||||
|
}
|
||||||
|
// 失败缓存值还原
|
||||||
|
currentUserName.value = accountInfo.value.name
|
||||||
|
accountInfo.value.name = oldUserName
|
||||||
|
currentAvatar.value = accountInfo.value.avatar
|
||||||
|
accountInfo.value.avatar = oldAvatar
|
||||||
}
|
}
|
||||||
else $toast.error(`用户信息保存失败:${result.message}!`)
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error)
|
console.log(error)
|
||||||
}
|
}
|
||||||
@@ -205,7 +230,7 @@ onMounted(() => {
|
|||||||
|
|
||||||
// 监听 localStorage 中的用户头像变化
|
// 监听 localStorage 中的用户头像变化
|
||||||
watch(() => store.state.auth.avatar, () => {
|
watch(() => store.state.auth.avatar, () => {
|
||||||
nowAvatar.value = store.state.auth.avatar
|
currentAvatar.value = store.state.auth.avatar
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -216,7 +241,7 @@ watch(() => store.state.auth.avatar, () => {
|
|||||||
<VCard title="个人信息">
|
<VCard title="个人信息">
|
||||||
<VCardText class="d-flex">
|
<VCardText class="d-flex">
|
||||||
<!-- 👉 Avatar -->
|
<!-- 👉 Avatar -->
|
||||||
<VAvatar rounded="lg" size="100" class="me-6" :image="nowAvatar" />
|
<VAvatar rounded="lg" size="100" class="me-6" :image="currentAvatar" />
|
||||||
|
|
||||||
<!-- 👉 Upload Photo -->
|
<!-- 👉 Upload Photo -->
|
||||||
<form class="d-flex flex-column justify-center gap-5">
|
<form class="d-flex flex-column justify-center gap-5">
|
||||||
@@ -235,14 +260,14 @@ watch(() => store.state.auth.avatar, () => {
|
|||||||
@input="changeAvatar"
|
@input="changeAvatar"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<VBtn type="reset" color="error" variant="tonal" @click="restoreNowAvatar">
|
<VBtn type="reset" color="info" variant="tonal" @click="restoreCurrentAvatar">
|
||||||
<VIcon icon="mdi-refresh" />
|
<VIcon icon="mdi-refresh" />
|
||||||
<span v-if="display.mdAndUp.value" class="ms-2">还原当前头像</span>
|
<span v-if="display.mdAndUp.value" class="ms-2">重置</span>
|
||||||
</VBtn>
|
</VBtn>
|
||||||
|
|
||||||
<VBtn type="reset" color="error" variant="tonal" @click="resetDefaultAvatar">
|
<VBtn type="reset" color="error" variant="tonal" @click="resetDefaultAvatar">
|
||||||
<VIcon icon="mdi-refresh" />
|
<VIcon icon="mdi-image-sync-outline" />
|
||||||
<span v-if="display.mdAndUp.value" class="ms-2">重置默认头像</span>
|
<span v-if="display.mdAndUp.value" class="ms-2">默认</span>
|
||||||
</VBtn>
|
</VBtn>
|
||||||
|
|
||||||
<VBtn
|
<VBtn
|
||||||
@@ -266,10 +291,21 @@ watch(() => store.state.auth.avatar, () => {
|
|||||||
<VForm class="mt-6">
|
<VForm class="mt-6">
|
||||||
<VRow>
|
<VRow>
|
||||||
<VCol md="6" cols="12">
|
<VCol md="6" cols="12">
|
||||||
<VTextField v-model="accountInfo.name" density="comfortable" readonly label="用户名" />
|
<VTextField
|
||||||
|
v-model="currentUserName"
|
||||||
|
density="comfortable"
|
||||||
|
clearable
|
||||||
|
label="用户名"
|
||||||
|
/>
|
||||||
</VCol>
|
</VCol>
|
||||||
<VCol cols="12" md="6">
|
<VCol cols="12" md="6">
|
||||||
<VTextField v-model="accountInfo.email" density="comfortable" label="邮箱" type="email" />
|
<VTextField
|
||||||
|
v-model="accountInfo.email"
|
||||||
|
density="comfortable"
|
||||||
|
clearable
|
||||||
|
label="邮箱"
|
||||||
|
type="email"
|
||||||
|
/>
|
||||||
</VCol>
|
</VCol>
|
||||||
<VCol cols="12" md="6">
|
<VCol cols="12" md="6">
|
||||||
<VTextField
|
<VTextField
|
||||||
@@ -277,6 +313,7 @@ watch(() => store.state.auth.avatar, () => {
|
|||||||
density="comfortable"
|
density="comfortable"
|
||||||
:type="isNewPasswordVisible ? 'text' : 'password'"
|
:type="isNewPasswordVisible ? 'text' : 'password'"
|
||||||
:append-inner-icon="isNewPasswordVisible ? 'mdi-eye-off-outline' : 'mdi-eye-outline'"
|
:append-inner-icon="isNewPasswordVisible ? 'mdi-eye-off-outline' : 'mdi-eye-outline'"
|
||||||
|
clearable
|
||||||
label="新密码"
|
label="新密码"
|
||||||
autocomplete=""
|
autocomplete=""
|
||||||
@click:append-inner="isNewPasswordVisible = !isNewPasswordVisible"
|
@click:append-inner="isNewPasswordVisible = !isNewPasswordVisible"
|
||||||
@@ -289,6 +326,7 @@ watch(() => store.state.auth.avatar, () => {
|
|||||||
density="comfortable"
|
density="comfortable"
|
||||||
:type="isConfirmPasswordVisible ? 'text' : 'password'"
|
:type="isConfirmPasswordVisible ? 'text' : 'password'"
|
||||||
:append-inner-icon="isConfirmPasswordVisible ? 'mdi-eye-off-outline' : 'mdi-eye-outline'"
|
:append-inner-icon="isConfirmPasswordVisible ? 'mdi-eye-off-outline' : 'mdi-eye-outline'"
|
||||||
|
clearable
|
||||||
label="确认新密码"
|
label="确认新密码"
|
||||||
@click:append-inner="isConfirmPasswordVisible = !isConfirmPasswordVisible"
|
@click:append-inner="isConfirmPasswordVisible = !isConfirmPasswordVisible"
|
||||||
/>
|
/>
|
||||||
@@ -301,22 +339,34 @@ watch(() => store.state.auth.avatar, () => {
|
|||||||
|
|
||||||
<VRow>
|
<VRow>
|
||||||
<VCol cols="12" md="6">
|
<VCol cols="12" md="6">
|
||||||
<VTextField v-model="accountInfo.settings.wechat_userid" density="comfortable" label="微信用户" />
|
<VTextField
|
||||||
|
v-model="accountInfo.settings.wechat_userid"
|
||||||
|
density="comfortable"
|
||||||
|
clearable
|
||||||
|
label="微信用户"
|
||||||
|
/>
|
||||||
</VCol>
|
</VCol>
|
||||||
<VCol cols="12" md="6">
|
<VCol cols="12" md="6">
|
||||||
<VTextField
|
<VTextField
|
||||||
v-model="accountInfo.settings.telegram_userid"
|
v-model="accountInfo.settings.telegram_userid"
|
||||||
density="comfortable"
|
density="comfortable"
|
||||||
|
clearable
|
||||||
label="Telegram用户"
|
label="Telegram用户"
|
||||||
/>
|
/>
|
||||||
</VCol>
|
</VCol>
|
||||||
<VCol cols="12" md="6">
|
<VCol cols="12" md="6">
|
||||||
<VTextField v-model="accountInfo.settings.slack_userid" density="comfortable" label="Slack用户" />
|
<VTextField
|
||||||
|
v-model="accountInfo.settings.slack_userid"
|
||||||
|
density="comfortable"
|
||||||
|
clearable
|
||||||
|
label="Slack用户"
|
||||||
|
/>
|
||||||
</VCol>
|
</VCol>
|
||||||
<VCol cols="12" md="6">
|
<VCol cols="12" md="6">
|
||||||
<VTextField
|
<VTextField
|
||||||
v-model="accountInfo.settings.vocechat_userid"
|
v-model="accountInfo.settings.vocechat_userid"
|
||||||
density="comfortable"
|
density="comfortable"
|
||||||
|
clearable
|
||||||
label="VoceChat用户"
|
label="VoceChat用户"
|
||||||
/>
|
/>
|
||||||
</VCol>
|
</VCol>
|
||||||
@@ -324,6 +374,7 @@ watch(() => store.state.auth.avatar, () => {
|
|||||||
<VTextField
|
<VTextField
|
||||||
v-model="accountInfo.settings.synologychat_userid"
|
v-model="accountInfo.settings.synologychat_userid"
|
||||||
density="comfortable"
|
density="comfortable"
|
||||||
|
clearable
|
||||||
label="SynologyChat用户"
|
label="SynologyChat用户"
|
||||||
/>
|
/>
|
||||||
</VCol>
|
</VCol>
|
||||||
|
|||||||
Reference in New Issue
Block a user