|
@@ -0,0 +1,285 @@
|
|
|
+<script setup>
|
|
|
+import { updateUserPwd, getUserProfile, uploadUserAvatar } from "@/api/system/user";
|
|
|
+import useUserStore from "@/store/modules/user";
|
|
|
+import { getToken } from '@/utils/auth'
|
|
|
+
|
|
|
+const baseURL = import.meta.env.VITE_APP_BASE_API;
|
|
|
+
|
|
|
+const pwdRef = ref(null);
|
|
|
+const userStore = useUserStore();
|
|
|
+
|
|
|
+const { proxy } = getCurrentInstance();
|
|
|
+
|
|
|
+const modelValue = defineModel('modelValue');
|
|
|
+
|
|
|
+const fileList = ref([]);
|
|
|
+
|
|
|
+const user = reactive({
|
|
|
+ oldPassword: undefined,
|
|
|
+ newPassword: undefined,
|
|
|
+ confirmPassword: undefined
|
|
|
+});
|
|
|
+
|
|
|
+const state = reactive({
|
|
|
+ user: {},
|
|
|
+ roleGroup: {},
|
|
|
+ postGroup: {}
|
|
|
+});
|
|
|
+
|
|
|
+const equalToPassword = (rule, value, callback) => {
|
|
|
+ if (user.newPassword !== value) {
|
|
|
+ callback(new Error("两次输入的密码不一致"));
|
|
|
+ } else {
|
|
|
+ callback();
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+const rules = ref({
|
|
|
+ oldPassword: [{ required: true, message: "旧密码不能为空", trigger: "blur" }],
|
|
|
+ newPassword: [{ required: true, message: "新密码不能为空", trigger: "blur" }, { min: 6, max: 20, message: "长度在 6 到 20 个字符", trigger: "blur" }, { pattern: /^[^<>"'|\\]+$/, message: "不能包含非法字符:< > \" ' \\\ |", trigger: "blur" }],
|
|
|
+ confirmPassword: [{ required: true, message: "确认密码不能为空", trigger: "blur" }, { required: true, validator: equalToPassword, trigger: "blur" }]
|
|
|
+});
|
|
|
+
|
|
|
+const submit = () => {
|
|
|
+ proxy.$refs.pwdRef.validate(valid => {
|
|
|
+ if (valid) {
|
|
|
+ updateUserPwd(user.oldPassword, user.newPassword).then(response => {
|
|
|
+ proxy.$modal.msgSuccess("修改成功");
|
|
|
+ userStore.avatar = res.data;
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+const close = () => {
|
|
|
+ modelValue.value = false;
|
|
|
+ pwdRef.value.resetFields();
|
|
|
+}
|
|
|
+
|
|
|
+const openDialog = () => {
|
|
|
+ getUserProfile().then(response => {
|
|
|
+ state.user = response.data;
|
|
|
+ state.roleGroup = response.roleGroup;
|
|
|
+ state.postGroup = response.postGroup;
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+const onFileSuccess = (res) => {
|
|
|
+ fileList.value = [];
|
|
|
+ uploadUserAvatar({ avatar: res.data }).then(() => {
|
|
|
+ userStore.avatar = res.data;
|
|
|
+ })
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<template>
|
|
|
+ <el-dialog v-model="modelValue" title="Tips" width="600" :before-close="handleClose" :show-close="false"
|
|
|
+ class="custom-pwd-dialog" @open="openDialog">
|
|
|
+ <template #header>
|
|
|
+ <div class="header">
|
|
|
+ <h4>个人资料</h4>
|
|
|
+ <el-icon class="icon" @click="close">
|
|
|
+ <Close />
|
|
|
+ </el-icon>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ <div class="main">
|
|
|
+ <div class="avatar-card">
|
|
|
+ <div class="avatar">
|
|
|
+ <img :src="userStore.avatar" class="w-full h-full"/>
|
|
|
+ </div>
|
|
|
+ <el-upload
|
|
|
+ ref="uploadRef"
|
|
|
+ class="upload-demo"
|
|
|
+ v-model:file-list="fileList"
|
|
|
+ :show-file-list="false"
|
|
|
+ :limit="1"
|
|
|
+ :action= 'baseURL + "/qiniuyun/upLoadImage"'
|
|
|
+ :headers="{
|
|
|
+ Authorization: 'Bearer ' + getToken()
|
|
|
+ }"
|
|
|
+ :on-success="onFileSuccess"
|
|
|
+ >
|
|
|
+ <div class="btn">上传头像</div>
|
|
|
+ </el-upload>
|
|
|
+ </div>
|
|
|
+ <ul class="list">
|
|
|
+ <li class="item mb-20">
|
|
|
+ <span class="label">用户名称</span>
|
|
|
+ <span class="value">{{ state.user.userName }}</span>
|
|
|
+ </li>
|
|
|
+ <li class="item mb-20">
|
|
|
+ <span class="label">手机号码</span>
|
|
|
+ <span class="value">{{ state.user.phonenumber }}</span>
|
|
|
+ </li>
|
|
|
+ <li class="item">
|
|
|
+ <span class="label">所属部门</span>
|
|
|
+ <span class="value" v-if="state.user.dept">{{ state.user.dept.deptName }}</span>
|
|
|
+ </li>
|
|
|
+ <li class="item">
|
|
|
+ <span class="label">所属角色</span>
|
|
|
+ <el-tooltip
|
|
|
+ effect="dark"
|
|
|
+ :content="state.roleGroup"
|
|
|
+ placement="top"
|
|
|
+ >
|
|
|
+ <span class="value">{{ state.roleGroup }}</span>
|
|
|
+ </el-tooltip>
|
|
|
+ </li>
|
|
|
+ </ul>
|
|
|
+
|
|
|
+ <el-form ref="pwdRef" :model="user" :rules="rules" hide-required-asterisk label-width="80px" class="form">
|
|
|
+ <el-form-item label="旧密码" prop="oldPassword">
|
|
|
+ <template #label><span class="label">旧密码<i>*</i></span></template>
|
|
|
+ <el-input v-model="user.oldPassword" placeholder="请输入旧密码" type="password" show-password />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="新密码" prop="newPassword">
|
|
|
+ <template #label><span class="label">新密码<i>*</i></span></template>
|
|
|
+ <el-input v-model="user.newPassword" placeholder="请输入新密码" type="password" show-password />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="确认密码" prop="confirmPassword">
|
|
|
+ <template #label><span class="label">确认密码<i>*</i></span></template>
|
|
|
+ <el-input v-model="user.confirmPassword" placeholder="请输入确认密码" type="password" show-password/>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ </div>
|
|
|
+ <template #footer>
|
|
|
+ <ul class="footer space-x-[12px]">
|
|
|
+ <li class="btn" @click="submit">保存</li>
|
|
|
+ <li class="btn" @click="close">取消</li>
|
|
|
+ </ul>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
+</template>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+
|
|
|
+</style>
|
|
|
+
|
|
|
+
|
|
|
+<style lang="scss">
|
|
|
+.custom-pwd-dialog {
|
|
|
+ padding: 0 !important;
|
|
|
+
|
|
|
+ .header {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ padding: 13px 20px;
|
|
|
+ color: #1D2129;
|
|
|
+ font-size: 18px;
|
|
|
+ font-weight: bold;
|
|
|
+ border-bottom: 1px solid #E5E6EB;
|
|
|
+
|
|
|
+ .icon {
|
|
|
+ cursor: pointer;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .main {
|
|
|
+ padding: 8px 68px 0px 68px;
|
|
|
+
|
|
|
+ .avatar-card {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ .avatar {
|
|
|
+ width: 84px;
|
|
|
+ height: 84px;
|
|
|
+ border: 1px solid #E5E6EB;
|
|
|
+ border-radius: 100%;
|
|
|
+ margin-right: 16px;
|
|
|
+ overflow: hidden;
|
|
|
+ }
|
|
|
+ .btn {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ width: 78px;
|
|
|
+ height: 30px;
|
|
|
+ flex-shrink: 0;
|
|
|
+ border-radius: 8px;
|
|
|
+ border: 1px solid #165DFF;
|
|
|
+ color: #165DFF;
|
|
|
+ font-size: 13px;
|
|
|
+ font-weight: bold;
|
|
|
+ cursor: pointer;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .list {
|
|
|
+ display: flex;
|
|
|
+ flex-flow: wrap;
|
|
|
+ padding: 20px 0;
|
|
|
+ border-bottom: 1px dashed #E5E6EB;
|
|
|
+ .mb-20 {
|
|
|
+ margin-bottom: 20px;
|
|
|
+ }
|
|
|
+ .item {
|
|
|
+ display: flex;
|
|
|
+ width: 50%;
|
|
|
+ font-size: 14px;
|
|
|
+ .label {
|
|
|
+ flex-shrink: 0;
|
|
|
+ margin-right: 20px;
|
|
|
+ color: #86909C;
|
|
|
+ }
|
|
|
+ .value {
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ overflow: hidden;
|
|
|
+ word-break: break-all;
|
|
|
+ white-space: nowrap;
|
|
|
+ color: #1D2129;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .form {
|
|
|
+ padding-top: 20px;
|
|
|
+ .label {
|
|
|
+ width: 70px;
|
|
|
+ flex-shrink: 0;
|
|
|
+ margin-right: 10px;
|
|
|
+ font-weight: normal;
|
|
|
+ color: #4E5969;
|
|
|
+ text-align: right;
|
|
|
+ font-size: 14px;
|
|
|
+ i {
|
|
|
+ font-size: 16px;
|
|
|
+ color: #FF3636;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .el-input__wrapper {
|
|
|
+ border-radius: 6px;
|
|
|
+ box-shadow: none;
|
|
|
+ background: #f2f4f7;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .footer {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ padding-top: 4px;
|
|
|
+ padding-bottom: 30px;
|
|
|
+ .btn {
|
|
|
+ width: 60px;
|
|
|
+ height: 36px;
|
|
|
+ flex-shrink: 0;
|
|
|
+ border-radius: 8px;
|
|
|
+ font-size: 14px;
|
|
|
+ line-height: 36px;
|
|
|
+ text-align: center;
|
|
|
+ cursor: pointer;
|
|
|
+ &:nth-child(1) {
|
|
|
+ background: #165DFF;
|
|
|
+ color: #fff;
|
|
|
+ }
|
|
|
+ &:nth-child(2) {
|
|
|
+ background: #F3F7FF;
|
|
|
+ color: #165DFF;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|