478 lines
13 KiB
Vue
478 lines
13 KiB
Vue
<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">
|
|
<ShopOutlined />
|
|
<div class="ele-cell-content">
|
|
<a-tooltip
|
|
class="ele-cell"
|
|
title="门店名称"
|
|
placement="topLeft"
|
|
>
|
|
{{ loginUser.merchantName || tenantName }}
|
|
</a-tooltip>
|
|
</div>
|
|
</div>
|
|
<div class="ele-cell">
|
|
<IdcardOutlined />
|
|
<div class="ele-cell-content">
|
|
<div v-for="(d, i) in loginUser.roles" :key="i">
|
|
<a-tooltip class="ele-cell" title="角色" placement="topLeft">
|
|
<div class="tag">
|
|
<a-tag color="blue">
|
|
{{ d.roleName }}
|
|
</a-tag>
|
|
</div>
|
|
</a-tooltip>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="ele-cell">
|
|
<SolutionOutlined />
|
|
<div class="ele-cell-content">
|
|
<a-tooltip
|
|
class="ele-cell"
|
|
title="所属部门"
|
|
placement="topLeft"
|
|
>
|
|
{{ loginUser.organizationName }}
|
|
</a-tooltip>
|
|
</div>
|
|
</div>
|
|
<div class="ele-cell">
|
|
<VerifiedOutlined />
|
|
<div class="ele-cell-content">
|
|
<div class="ele-cell">
|
|
{{ loginUser.gradeName }}
|
|
</div>
|
|
</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="用户ID" v-bind="validateInfos.userId">
|
|
<a-input disabled v-model:value="form.userId" allow-clear />
|
|
</a-form-item>
|
|
<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,
|
|
IdcardOutlined,
|
|
EnvironmentOutlined,
|
|
SolutionOutlined,
|
|
MailOutlined,
|
|
VerifiedOutlined
|
|
} 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 SexSelect from './components/sex-select.vue';
|
|
import { uploadOssAvatar } from '@/api/system/file';
|
|
import { authUser } from '@/api/user';
|
|
|
|
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: '',
|
|
gradeId: loginUser.value.gradeId,
|
|
gradeName: loginUser.value.gradeName,
|
|
// 街道地址
|
|
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];
|
|
if (form.sex === '男') {
|
|
form.sex = `1`;
|
|
}
|
|
if (form.sex === '女') {
|
|
form.sex = `2`;
|
|
}
|
|
authUser(form).then(() => {
|
|
loading.value = false;
|
|
setTimeout(() => {
|
|
message.success('保存成功');
|
|
}, 500);
|
|
});
|
|
})
|
|
.catch(() => {});
|
|
};
|
|
|
|
const onDone = (blob: Blob | null) => {
|
|
// 裁剪完成的回调
|
|
uploadOssAvatar(blob, 'avatar.png').then((res) => {
|
|
form.avatar = res.path;
|
|
visible.value = false;
|
|
authUser(form).then(() => {
|
|
loading.value = false;
|
|
setTimeout(() => {
|
|
message.success('保存成功');
|
|
}, 500);
|
|
});
|
|
});
|
|
};
|
|
|
|
/* 打开图片裁剪 */
|
|
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: rgb(228, 255, 215);
|
|
}
|
|
|
|
& + 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>
|