|
|
@@ -2,58 +2,132 @@
|
|
|
<div class="profile-edit">
|
|
|
<el-button text @click="router.back()">← 返回</el-button>
|
|
|
<h1>修改个人资料</h1>
|
|
|
- <el-form ref="formRef" :model="form" :rules="rules" label-width="100px" class="form">
|
|
|
- <el-form-item label="昵称" prop="name">
|
|
|
- <el-input v-model="form.name" />
|
|
|
- </el-form-item>
|
|
|
- <el-form-item>
|
|
|
- <el-button type="primary" @click="handleSubmit">保存</el-button>
|
|
|
- <el-button @click="router.back()">取消</el-button>
|
|
|
- </el-form-item>
|
|
|
- </el-form>
|
|
|
+ <el-card v-loading="loading">
|
|
|
+ <el-form ref="formRef" :model="form" :rules="rules" label-width="100px" class="form">
|
|
|
+ <el-form-item label="头像">
|
|
|
+ <div class="avatar-upload">
|
|
|
+ <el-avatar :size="80" v-if="form.avatar">
|
|
|
+ <img :src="form.avatar" alt="avatar" />
|
|
|
+ </el-avatar>
|
|
|
+ <el-avatar :size="80" v-else>{{ form.name?.[0] }}</el-avatar>
|
|
|
+ <el-button size="small" class="upload-btn" @click="triggerUpload">更换头像</el-button>
|
|
|
+ <input
|
|
|
+ ref="fileInputRef"
|
|
|
+ type="file"
|
|
|
+ accept="image/*"
|
|
|
+ style="display: none"
|
|
|
+ @change="handleFileChange"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="昵称" prop="name">
|
|
|
+ <el-input v-model="form.name" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="邮箱" prop="email">
|
|
|
+ <el-input v-model="form.email" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="手机号" prop="phone">
|
|
|
+ <el-input v-model="form.phone" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item>
|
|
|
+ <el-button type="primary" @click="handleSubmit" :loading="submitting">保存</el-button>
|
|
|
+ <el-button @click="router.back()">取消</el-button>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ </el-card>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
-import { reactive, ref } from 'vue'
|
|
|
+import { reactive, ref, onMounted } from 'vue'
|
|
|
import { useRouter } from 'vue-router'
|
|
|
import { ElMessage } from 'element-plus'
|
|
|
import type { FormInstance, FormRules } from 'element-plus'
|
|
|
import { useLoginUserStore } from '@/store'
|
|
|
import { getUserController } from '@/api/user-controller'
|
|
|
+import { getImageController } from '@/api/image-controller'
|
|
|
import type { UserDto } from '@/api/models'
|
|
|
|
|
|
const router = useRouter()
|
|
|
const loginUserStore = useLoginUserStore()
|
|
|
|
|
|
const formRef = ref<FormInstance>()
|
|
|
+const fileInputRef = ref<HTMLInputElement>()
|
|
|
+const loading = ref(false)
|
|
|
+const submitting = ref(false)
|
|
|
|
|
|
const form = reactive({
|
|
|
- name: loginUserStore.loginUser.user?.name ?? ''
|
|
|
+ name: loginUserStore.loginUser.user?.name ?? '',
|
|
|
+ email: loginUserStore.loginUser.user?.email ?? '',
|
|
|
+ phone: loginUserStore.loginUser.user?.phone ?? '',
|
|
|
+ avatar: loginUserStore.loginUser.user?.avatar ?? ''
|
|
|
})
|
|
|
|
|
|
const rules: FormRules = {
|
|
|
name: [
|
|
|
{ required: true, message: '请输入昵称', trigger: 'blur' },
|
|
|
{ min: 2, message: '昵称至少 2 个字符', trigger: 'blur' }
|
|
|
+ ],
|
|
|
+ email: [
|
|
|
+ { type: 'email', message: '请输入正确的邮箱格式', trigger: 'blur' }
|
|
|
+ ],
|
|
|
+ phone: [
|
|
|
+ { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号格式', trigger: 'blur' }
|
|
|
]
|
|
|
}
|
|
|
|
|
|
+const triggerUpload = () => {
|
|
|
+ fileInputRef.value?.click()
|
|
|
+}
|
|
|
+
|
|
|
+const handleFileChange = async (e: Event) => {
|
|
|
+ const input = e.target as HTMLInputElement
|
|
|
+ const file = input.files?.[0]
|
|
|
+ if (!file) return
|
|
|
+
|
|
|
+ submitting.value = true
|
|
|
+ try {
|
|
|
+ const api = getImageController()
|
|
|
+ const res = await api.upload({ imageFile: file as Blob })
|
|
|
+ if (res.code === 200 && res.data) {
|
|
|
+ form.avatar = res.data
|
|
|
+ ElMessage.success('头像上传成功')
|
|
|
+ } else {
|
|
|
+ ElMessage.error(res.message || '头像上传失败')
|
|
|
+ }
|
|
|
+ } catch (err: any) {
|
|
|
+ ElMessage.error(err.message || '头像上传失败')
|
|
|
+ } finally {
|
|
|
+ submitting.value = false
|
|
|
+ input.value = ''
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
const handleSubmit = async () => {
|
|
|
const valid = await formRef.value?.validate().catch(() => false)
|
|
|
if (!valid) return
|
|
|
+
|
|
|
+ submitting.value = true
|
|
|
try {
|
|
|
const api = getUserController()
|
|
|
const dto: UserDto = {
|
|
|
id: Number(loginUserStore.userId),
|
|
|
- username: form.name
|
|
|
+ username: form.name,
|
|
|
+ email: form.email || undefined,
|
|
|
+ phone: form.phone || undefined,
|
|
|
+ avatar: form.avatar || undefined
|
|
|
}
|
|
|
const res = await api.edit(dto)
|
|
|
if (res.code === 200) {
|
|
|
loginUserStore.updateUser({
|
|
|
id: loginUserStore.loginUser.user?.id ?? '',
|
|
|
name: form.name,
|
|
|
- role: loginUserStore.loginUser.user?.role ?? 'user'
|
|
|
+ role: loginUserStore.loginUser.user?.role ?? 'user',
|
|
|
+ avatar: form.avatar,
|
|
|
+ email: form.email,
|
|
|
+ phone: form.phone,
|
|
|
+ account: loginUserStore.loginUser.user?.account,
|
|
|
+ enable: loginUserStore.loginUser.user?.enable
|
|
|
})
|
|
|
ElMessage.success('保存成功')
|
|
|
router.push('/profile')
|
|
|
@@ -62,8 +136,32 @@ const handleSubmit = async () => {
|
|
|
}
|
|
|
} catch (err: any) {
|
|
|
ElMessage.error(err.message || '保存失败')
|
|
|
+ } finally {
|
|
|
+ submitting.value = false
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const fetchUserInfo = async () => {
|
|
|
+ if (!loginUserStore.userId) return
|
|
|
+ loading.value = true
|
|
|
+ try {
|
|
|
+ const api = getUserController()
|
|
|
+ const res = await api.queryById(Number(loginUserStore.userId))
|
|
|
+ if (res.code === 200 && res.data) {
|
|
|
+ const u = res.data
|
|
|
+ form.name = u.username ?? form.name
|
|
|
+ form.email = u.email ?? form.email
|
|
|
+ form.phone = u.phone ?? form.phone
|
|
|
+ form.avatar = u.avatar ?? form.avatar
|
|
|
+ }
|
|
|
+ } catch {
|
|
|
+ // use cached data
|
|
|
+ } finally {
|
|
|
+ loading.value = false
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+onMounted(fetchUserInfo)
|
|
|
</script>
|
|
|
|
|
|
<style scoped>
|
|
|
@@ -76,4 +174,10 @@ const handleSubmit = async () => {
|
|
|
.form {
|
|
|
margin-top: 20px;
|
|
|
}
|
|
|
-</style>
|
|
|
+
|
|
|
+.avatar-upload {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 12px;
|
|
|
+}
|
|
|
+</style>
|