164 lines
4.7 KiB
Vue
164 lines
4.7 KiB
Vue
<script setup lang="ts">
|
|
import { ref } from "vue";
|
|
import { message } from "@/utils/message";
|
|
import type { FormInstance } from "element-plus";
|
|
import ReCropperPreview from "@/components/ReCropperPreview";
|
|
import { deviceDetection } from "@pureadmin/utils";
|
|
import uploadLine from "@iconify-icons/ri/upload-line";
|
|
import { postUploadAvatarAPI, putUpdateBaseUserInfoAPI } from "@/api/user";
|
|
import { useUserStoreHook } from "@/store/modules/user";
|
|
import { userInfoKey } from "@/utils/auth";
|
|
import { storageLocal } from "@pureadmin/utils";
|
|
import { useUserInfo } from "../utils/hooks";
|
|
defineOptions({
|
|
name: "Profile"
|
|
});
|
|
|
|
const { userInfo, getUserInfo } = useUserInfo();
|
|
const imgSrc = ref("");
|
|
const cropperBlob = ref();
|
|
const cropRef = ref();
|
|
const uploadRef = ref();
|
|
const isShow = ref(false);
|
|
const userInfoFormRef = ref<FormInstance>();
|
|
|
|
const disabledDate = (time: Date) => {
|
|
return time.getTime() > Date.now();
|
|
};
|
|
|
|
const onChange = uploadFile => {
|
|
const reader = new FileReader();
|
|
reader.onload = e => {
|
|
imgSrc.value = e.target.result as string;
|
|
isShow.value = true;
|
|
};
|
|
reader.readAsDataURL(uploadFile.raw);
|
|
};
|
|
|
|
const handleClose = () => {
|
|
cropRef.value.hidePopover();
|
|
uploadRef.value.clearFiles();
|
|
isShow.value = false;
|
|
};
|
|
|
|
const onCropper = ({ blob }) => (cropperBlob.value = blob);
|
|
|
|
const handleSubmitImage = async () => {
|
|
const res = await postUploadAvatarAPI(userInfo.id, {
|
|
file: cropperBlob.value
|
|
});
|
|
if (res.code === 200) {
|
|
message("更新头像成功", { type: "success" });
|
|
userInfo.avatar = `/file/${res.data.id}`;
|
|
const user = storageLocal().getItem<object>(userInfoKey);
|
|
storageLocal().setItem(userInfoKey, {
|
|
...user,
|
|
avatar: `/file/${res.data.id}`
|
|
});
|
|
useUserStoreHook().SET_AVATAR(`/file/${res.data.id}`);
|
|
handleClose();
|
|
} else {
|
|
message("更新头像失败", { type: "error" });
|
|
}
|
|
};
|
|
|
|
// 更新信息
|
|
const onSubmit = async (formEl: FormInstance) => {
|
|
await formEl.validate(async (valid, fields) => {
|
|
if (valid) {
|
|
let updateForm = {
|
|
name: userInfo.nickname,
|
|
gender: userInfo.gender
|
|
};
|
|
const res = await putUpdateBaseUserInfoAPI(updateForm);
|
|
if (res.code === 200) {
|
|
message(res.msg, { type: "success" });
|
|
await getUserInfo();
|
|
} else {
|
|
message(res.msg, { type: "error" });
|
|
}
|
|
} else {
|
|
console.log("error submit!", fields);
|
|
}
|
|
});
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<div
|
|
:class="[
|
|
'min-w-[180px]',
|
|
deviceDetection() ? 'max-w-[100%]' : 'max-w-[70%]'
|
|
]"
|
|
>
|
|
<h3 class="my-8">个人信息</h3>
|
|
<el-form ref="userInfoFormRef" label-position="top" :model="userInfo">
|
|
<el-form-item label="头像">
|
|
<el-avatar :size="80" :src="`/api/${userInfo.avatar}`" />
|
|
<el-upload
|
|
ref="uploadRef"
|
|
accept="image/*"
|
|
action="#"
|
|
:limit="1"
|
|
:auto-upload="false"
|
|
:show-file-list="false"
|
|
:on-change="onChange"
|
|
>
|
|
<el-button plain class="ml-4">
|
|
<IconifyIconOffline :icon="uploadLine" />
|
|
<span class="ml-2">更新头像</span>
|
|
</el-button>
|
|
</el-upload>
|
|
</el-form-item>
|
|
<el-form-item label="账号" prop="userId">
|
|
<el-input
|
|
v-model="userInfo.username"
|
|
placeholder="请输入账号~"
|
|
disabled
|
|
/>
|
|
</el-form-item>
|
|
<el-form-item
|
|
label="姓名"
|
|
prop="name"
|
|
:rules="[
|
|
{
|
|
required: true,
|
|
message: '请输入用户姓名~',
|
|
trigger: 'blur'
|
|
}
|
|
]"
|
|
>
|
|
<el-input v-model="userInfo.nickname" placeholder="请输入姓名~" />
|
|
</el-form-item>
|
|
<el-form-item label="性别" prop="gender">
|
|
<el-radio-group v-model="userInfo.gender" class="ml-4">
|
|
<el-radio :value="1" size="default">男</el-radio>
|
|
<el-radio :value="0" size="default">女</el-radio>
|
|
</el-radio-group>
|
|
</el-form-item>
|
|
<el-button type="primary" @click="onSubmit(userInfoFormRef)">
|
|
更新信息
|
|
</el-button>
|
|
</el-form>
|
|
<el-dialog
|
|
v-model="isShow"
|
|
width="40%"
|
|
title="编辑头像"
|
|
destroy-on-close
|
|
:closeOnClickModal="false"
|
|
:before-close="handleClose"
|
|
:fullscreen="deviceDetection()"
|
|
>
|
|
<ReCropperPreview ref="cropRef" :imgSrc="imgSrc" @cropper="onCropper" />
|
|
<template #footer>
|
|
<div class="dialog-footer">
|
|
<el-button bg text @click="handleClose">取消</el-button>
|
|
<el-button bg text type="primary" @click="handleSubmitImage">
|
|
确定
|
|
</el-button>
|
|
</div>
|
|
</template>
|
|
</el-dialog>
|
|
</div>
|
|
</template>
|