Initial commit
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
<!-- 角色选择下拉框 -->
|
||||
<template>
|
||||
<a-select
|
||||
show-search
|
||||
optionFilterProp="label"
|
||||
:options="data"
|
||||
allow-clear
|
||||
:value="value"
|
||||
:placeholder="placeholder"
|
||||
@update:value="updateValue"
|
||||
@blur="onBlur"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { getDictionaryOptions } from '@/utils/common';
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:value', value: string): void;
|
||||
(e: 'blur'): void;
|
||||
}>();
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
value?: string;
|
||||
placeholder?: string;
|
||||
}>(),
|
||||
{
|
||||
placeholder: '请选择性别'
|
||||
}
|
||||
);
|
||||
|
||||
// 字典数据
|
||||
const data = getDictionaryOptions('sex');
|
||||
|
||||
/* 更新选中数据 */
|
||||
const updateValue = (value: string) => {
|
||||
emit('update:value', value);
|
||||
};
|
||||
|
||||
/* 失去焦点 */
|
||||
const onBlur = () => {
|
||||
emit('blur');
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,456 @@
|
||||
<template>
|
||||
<div class="ele-body ele-body-card">
|
||||
<a-row :gutter="16">
|
||||
<a-col
|
||||
v-bind="
|
||||
styleResponsive
|
||||
? { xxl: 6, xl: 7, lg: 9, md: 10, sm: 24, xs: 24 }
|
||||
: { span: 6 }
|
||||
"
|
||||
>
|
||||
<a-card :bordered="false">
|
||||
<div class="ele-text-center">
|
||||
<div class="user-info-avatar-group" @click="openCropper">
|
||||
<a-avatar :size="110" :src="form.avatar">
|
||||
<template v-if="!form.avatar" #icon>
|
||||
<user-outlined />
|
||||
</template>
|
||||
</a-avatar>
|
||||
<upload-outlined class="user-info-avatar-icon" />
|
||||
</div>
|
||||
<h1>{{ loginUser.nickname }}</h1>
|
||||
<div>{{ loginUser.introduction }}</div>
|
||||
</div>
|
||||
<div class="user-info-list">
|
||||
<div class="ele-cell">
|
||||
<HomeOutlined />
|
||||
<div class="ele-cell-content">
|
||||
<span>{{ loginUser.tenantName || tenantName }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ele-cell">
|
||||
<user-outlined title="角色" />
|
||||
<div class="ele-cell-content">
|
||||
<a-tag v-for="(d, i) in loginUser.roles" :key="i" color="blue">
|
||||
{{ d.roleName }}
|
||||
</a-tag>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ele-cell">
|
||||
<environment-outlined />
|
||||
<div class="ele-cell-content">
|
||||
{{ loginUser.province }} • {{ loginUser.city }} •
|
||||
{{ loginUser.region }} {{ loginUser.address }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="ele-cell">
|
||||
<mail-outlined />
|
||||
<div class="ele-cell-content">
|
||||
{{ loginUser.email }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a-card>
|
||||
</a-col>
|
||||
<a-col
|
||||
v-bind="
|
||||
styleResponsive
|
||||
? { xxl: 14, xl: 14, lg: 15, md: 14, sm: 24, xs: 24 }
|
||||
: { span: 18 }
|
||||
"
|
||||
>
|
||||
<a-card
|
||||
:bordered="false"
|
||||
:body-style="{ paddingTop: '0px', minHeight: '600px' }"
|
||||
>
|
||||
<a-tabs v-model:active-key="active" size="large">
|
||||
<a-tab-pane tab="基本信息" key="info">
|
||||
<a-form
|
||||
:label-col="
|
||||
styleResponsive
|
||||
? { lg: 4, md: 6, sm: 4, xs: 24 }
|
||||
: { flex: '100px' }
|
||||
"
|
||||
:wrapper-col="
|
||||
styleResponsive
|
||||
? { lg: 20, md: 18, sm: 20, xs: 24 }
|
||||
: { flex: '1' }
|
||||
"
|
||||
style="max-width: 580px; margin-top: 20px"
|
||||
>
|
||||
<a-form-item label="登录账号" v-bind="validateInfos.username">
|
||||
<a-input
|
||||
disabled
|
||||
v-model:value="form.username"
|
||||
placeholder="请输入登录账号"
|
||||
allow-clear
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="手机号码" v-bind="validateInfos.phone">
|
||||
<a-input
|
||||
:disabled="form.phone"
|
||||
v-model:value="form.phone"
|
||||
placeholder="请输入手机号码"
|
||||
allow-clear
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="昵称" v-bind="validateInfos.nickname">
|
||||
<a-input
|
||||
v-model:value="form.nickname"
|
||||
placeholder="请输入昵称"
|
||||
allow-clear
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="性别" v-bind="validateInfos.sex">
|
||||
<sex-select
|
||||
v-model:value="form.sex"
|
||||
@blur="validate('sex', { trigger: 'blur' }).catch(() => {})"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="邮箱" v-bind="validateInfos.email">
|
||||
<a-input
|
||||
v-model:value="form.email"
|
||||
placeholder="请输入邮箱"
|
||||
allow-clear
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="个人简介">
|
||||
<a-textarea
|
||||
v-model:value="form.introduction"
|
||||
placeholder="请输入个人简介"
|
||||
:rows="4"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="所在地区" name="region">
|
||||
<div class="flex-sb">
|
||||
<regions-select
|
||||
v-model:value="city"
|
||||
valueField="label"
|
||||
placeholder="请选择省市区"
|
||||
class="ele-fluid"
|
||||
/>
|
||||
</div>
|
||||
</a-form-item>
|
||||
<a-form-item label="街道地址">
|
||||
<a-input
|
||||
v-model:value="form.address"
|
||||
placeholder="请输入街道地址"
|
||||
allow-clear
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
:wrapper-col="
|
||||
styleResponsive
|
||||
? {
|
||||
lg: { offset: 4 },
|
||||
md: { offset: 6 },
|
||||
sm: { offset: 4 }
|
||||
}
|
||||
: { offset: 4 }
|
||||
"
|
||||
>
|
||||
<a-button type="primary" :loading="loading" @click="save">
|
||||
{{ loading ? '保存中..' : '保存更改' }}
|
||||
</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</a-card>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<!-- 头像裁剪弹窗 -->
|
||||
<ele-cropper-modal
|
||||
:src="form.avatar"
|
||||
v-model:visible="visible"
|
||||
:to-blob="true"
|
||||
:options="{ autoCropArea: 1, viewMode: 1, dragMode: 'move' }"
|
||||
@done="onDone"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive, computed } from 'vue';
|
||||
import {
|
||||
ShopOutlined,
|
||||
UploadOutlined,
|
||||
UserOutlined,
|
||||
HomeOutlined,
|
||||
CloudOutlined,
|
||||
EnvironmentOutlined,
|
||||
TagOutlined,
|
||||
QqOutlined,
|
||||
MailOutlined,
|
||||
WechatOutlined,
|
||||
AlipayOutlined,
|
||||
BankOutlined
|
||||
} from '@ant-design/icons-vue';
|
||||
import { Form, message } from 'ant-design-vue';
|
||||
import { useUserStore } from '@/store/modules/user';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useThemeStore } from '@/store/modules/theme';
|
||||
import type { User } from '@/api/system/user/model';
|
||||
import { updateUser } from '@/api/system/user';
|
||||
import SexSelect from './components/sex-select.vue';
|
||||
import { getMobile } from '@/utils/common';
|
||||
import request from '@/utils/request';
|
||||
import { FILE_SERVER } from '@/config/setting';
|
||||
import { CenterPoint } from 'ele-admin-pro/es/ele-map-picker/types';
|
||||
|
||||
const useForm = Form.useForm;
|
||||
|
||||
// 是否开启响应式布局
|
||||
const themeStore = useThemeStore();
|
||||
const { styleResponsive } = storeToRefs(themeStore);
|
||||
|
||||
const userStore = useUserStore();
|
||||
|
||||
// tab 页选中
|
||||
const active = ref('info');
|
||||
|
||||
// 保存按钮 loading
|
||||
const loading = ref(false);
|
||||
|
||||
// 是否显示裁剪弹窗
|
||||
const visible = ref(false);
|
||||
const tenantName = localStorage.getItem('TenantName');
|
||||
// 登录用户信息
|
||||
const loginUser = computed(() => userStore.info ?? {});
|
||||
|
||||
// 表单数据
|
||||
const form = reactive<User>({
|
||||
// 用户id
|
||||
userId: loginUser.value.userId,
|
||||
// 登录账号
|
||||
username: loginUser.value.username,
|
||||
// 昵称
|
||||
nickname: loginUser.value.nickname,
|
||||
// 头像
|
||||
avatar: loginUser.value.avatar,
|
||||
// 性别(字典)
|
||||
sex: loginUser.value.sex,
|
||||
// 手机号
|
||||
phone: loginUser.value.phone,
|
||||
province: '',
|
||||
city: '',
|
||||
region: '',
|
||||
// 街道地址
|
||||
address: loginUser.value.address,
|
||||
// 邮箱
|
||||
email: loginUser.value.email,
|
||||
// 出生日期
|
||||
birthday: loginUser.value.birthday,
|
||||
// 个人简介
|
||||
introduction: loginUser.value.introduction,
|
||||
// 机构id
|
||||
organizationId: loginUser.value.organizationId,
|
||||
// 性别名称
|
||||
sexName: loginUser.value.sexName,
|
||||
// 机构名称
|
||||
organizationName: loginUser.value.organizationName
|
||||
});
|
||||
// 省市区
|
||||
const city = ref<string[]>([
|
||||
String(loginUser.value.province),
|
||||
String(loginUser.value.city),
|
||||
String(loginUser.value.region)
|
||||
]);
|
||||
|
||||
// 表单验证规则
|
||||
const rules = reactive({
|
||||
username: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入昵称',
|
||||
type: 'string'
|
||||
}
|
||||
],
|
||||
phone: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入昵称',
|
||||
type: 'string'
|
||||
}
|
||||
],
|
||||
nickname: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入昵称',
|
||||
type: 'string'
|
||||
}
|
||||
],
|
||||
sex: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择性别',
|
||||
type: 'string'
|
||||
}
|
||||
],
|
||||
email: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入邮箱',
|
||||
type: 'string'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
const { validate, validateInfos } = useForm(form, rules);
|
||||
|
||||
/* 保存更改 */
|
||||
const save = () => {
|
||||
validate()
|
||||
.then(() => {
|
||||
loading.value = true;
|
||||
form.province = city.value[0];
|
||||
form.city = city.value[1];
|
||||
form.region = city.value[2];
|
||||
updateUser(form).then((res) => {
|
||||
loading.value = false;
|
||||
message.success('保存成功');
|
||||
});
|
||||
})
|
||||
.catch(() => {});
|
||||
};
|
||||
|
||||
const onDone = (blob: Blob | null) => {
|
||||
// 裁剪完成的回调
|
||||
const formData = new FormData();
|
||||
formData.append('file', blob, 'avatar.jpg'); // 参数三可以设定文件名称
|
||||
// 使用 axios 上传
|
||||
request
|
||||
.post(FILE_SERVER + '/api/file/upload', formData)
|
||||
.then((res) => {
|
||||
form.avatar = res.data.data.thumbnail;
|
||||
visible.value = false;
|
||||
updateUser(form).then(() => {
|
||||
loading.value = false;
|
||||
message.success('保存成功');
|
||||
});
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
});
|
||||
};
|
||||
|
||||
/* 头像裁剪完成回调 */
|
||||
const onCrop = (result: string) => {
|
||||
console.log(result);
|
||||
form.avatar = result;
|
||||
visible.value = false;
|
||||
updateUser(form).then((res) => {
|
||||
loading.value = false;
|
||||
message.success('保存成功');
|
||||
});
|
||||
};
|
||||
|
||||
/* 打开图片裁剪 */
|
||||
const openCropper = () => {
|
||||
visible.value = true;
|
||||
};
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'UserProfile'
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
/* 用户资料卡片 */
|
||||
.user-info-avatar-group {
|
||||
margin: 16px 0;
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
|
||||
.user-info-avatar-icon {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
color: #fff;
|
||||
font-size: 30px;
|
||||
display: none;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
&:hover .user-info-avatar-icon {
|
||||
display: block;
|
||||
}
|
||||
|
||||
&:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 50%;
|
||||
background-color: transparent;
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
|
||||
&:hover:after {
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
& + h1 {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
/* 用户角色 */
|
||||
.role-list {
|
||||
padding-top: 22px;
|
||||
}
|
||||
|
||||
/* 用户信息列表 */
|
||||
.user-info-list {
|
||||
margin: 47px 0 32px 0;
|
||||
|
||||
.ele-cell + .ele-cell {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
& + .ant-divider {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
/* 用户标签 */
|
||||
.user-info-tags {
|
||||
margin: 16px 0 4px 0;
|
||||
|
||||
.ant-tag {
|
||||
margin: 0 12px 8px 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* 用户账号绑定列表 */
|
||||
.user-account-list {
|
||||
& > .ele-cell {
|
||||
padding: 16px 8px;
|
||||
}
|
||||
|
||||
.user-account-icon {
|
||||
color: #fff;
|
||||
padding: 8px;
|
||||
font-size: 26px;
|
||||
border-radius: 50%;
|
||||
|
||||
&.anticon-qq {
|
||||
background: #3492ed;
|
||||
}
|
||||
|
||||
&.anticon-wechat {
|
||||
background: #4daf29;
|
||||
}
|
||||
|
||||
&.anticon-alipay {
|
||||
background: #1476fe;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user