Files
fe.ems.vue3/src/views/account/profile.vue
2023-11-28 21:08:26 +08:00

224 lines
6.9 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script lang="ts" setup>
import { PageContainer } from 'antdv-pro-layout';
import { message } from 'ant-design-vue/lib';
import { getUserProfile } from '@/api/profile';
import { reactive, ref, onMounted } from 'vue';
import { parseDateToStr } from '@/utils/date-utils';
import useUserStore from '@/store/modules/user';
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
import { useRoute } from 'vue-router';
import useAppStore from '@/store/modules/app';
import useI18n from '@/hooks/useI18n';
const appStore = useAppStore();
const route = useRoute();
const { t } = useI18n();
/**加载状态 */
let loading = ref<boolean>(true);
/**Tab标签激活 */
let activeKey = ref<string>('list');
/**个人信息数据状态 */
let state = reactive<{
user: Record<string, any>;
postGroup: string[];
roleGroup: string[];
}>({
user: {},
postGroup: [],
roleGroup: [],
});
/**列表数据 */
let listData = ref([
{
id: 'Vue',
title: 'Vue.js - 渐进式 JavaScript 框架 | Vue.js',
description:
'基于标准 HTML、CSS 和 JavaScript 构建,提供容易上手的 API 和一流的文档。 性能出色 经过编译器优化、完全响应式的渲染系统,几乎不需要手动优化。',
},
{
id: 'Vue Router',
title: 'Vue Router | Vue.js 的官方路由',
description:
'为Vue.js 提供富有表现力、可配置的、方便的路由,用直观且强大的语法来定义静态或动态路由。',
},
{
id: 'Pinia',
title: 'Pinia | The intuitive store for Vue.js',
description:
'Pinia hooks into Vue devtools to give you an enhanced development experience in both Vue 2 and Vue 3. ',
},
{
id: 'Vite',
title: 'Vite | 下一代的前端工具链',
description:
'Vite(法语意为 "快速的",发音 /vit/,发音同 "veet")是一种新型前端构建工具,能够显著提升前端开发体验',
},
]);
/**查询用户个人信息 */
function fnGetProfile() {
getUserProfile().then(res => {
if (res.code === RESULT_CODE_SUCCESS && res.data) {
const { user, roleGroup, postGroup } = res.data;
state.user = user;
state.roleGroup = roleGroup;
state.postGroup = postGroup;
// 头像解析
state.user.avatar = useUserStore().fnAvatar(user.avatar);
loading.value = false;
} else {
message.error(res.msg, 3);
}
});
}
/**
* 国际化翻译转换
*/
function fnLocale() {
let title = route.meta.title as string;
if (title.indexOf('router.') !== -1) {
title = t(title);
}
appStore.setTitle(title);
}
onMounted(() => {
fnLocale();
// 获取信息
fnGetProfile();
});
</script>
<template>
<PageContainer :loading="loading">
<a-row :gutter="16">
<a-col :lg="6" :md="6" :xs="24">
<a-card :body-style="{ padding: '0px' }" style="margin-bottom: 16px">
<template #title>
<div class="info-top">
<div class="info-top-no">No{{ state.user.userId }}</div>
<a-avatar
shape="circle"
:size="96"
:src="state.user.avatar"
:alt="state.user.userName"
></a-avatar>
<div class="info-top-nickname" :title="state.user.nickName">
{{ state.user.nickName }}
</div>
</div>
</template>
<a-descriptions
size="small"
layout="vertical"
:bordered="true"
:column="1"
>
<a-descriptions-item
:label="t('views.account.profile.phonenumber')"
>
{{ state.user.phonenumber || '-' }}
</a-descriptions-item>
<a-descriptions-item :label="t('views.account.profile.email')">
{{ state.user.email || '-' }}
</a-descriptions-item>
<a-descriptions-item :label="t('views.account.profile.deptName')">
{{ state.user.dept?.deptName || '-' }}
</a-descriptions-item>
<a-descriptions-item :label="t('views.account.profile.postGroup')">
<span v-if="state.postGroup.length === 0">-</span>
<a-tag v-else v-for="v in state.postGroup" :key="v">
{{ v }}
</a-tag>
</a-descriptions-item>
<a-descriptions-item :label="t('views.account.profile.roleGroup')">
<span v-if="state.roleGroup.length === 0">-</span>
<a-tag v-else v-for="v in state.roleGroup" :key="v">
{{ v }}
</a-tag>
</a-descriptions-item>
<a-descriptions-item :label="t('views.account.profile.loginIp')">
{{ state.user.loginIp || '-' }}
</a-descriptions-item>
<a-descriptions-item :label="t('views.account.profile.loginDate')">
<span v-if="+state.user.loginDate > 0">
{{ parseDateToStr(+state.user.loginDate) }}
</span>
<span v-else>-</span>
</a-descriptions-item>
</a-descriptions>
</a-card>
</a-col>
<a-col :lg="18" :md="18" :xs="24">
<a-card>
<a-tabs
tab-position="top"
:destroy-inactive-tab-pane="true"
v-model:activeKey="activeKey"
>
<a-tab-pane key="list" :tab="t('views.account.profile.list')">
<a-list
item-layout="horizontal"
:data-source="listData"
row-key="id"
>
<template #renderItem="{ item }">
<a-list-item>
<a-list-item-meta>
<template #title>
{{ item.title }}
</template>
<template #description>
{{ item.description }}
</template>
<template #avatar>
<a-avatar>{{ item.id }}</a-avatar>
</template>
</a-list-item-meta>
</a-list-item>
</template>
</a-list>
</a-tab-pane>
<a-tab-pane key="empty" :tab="t('views.account.profile.empty')">
<a-empty>
<template #description>
{{ t('views.account.profile.description') }}
</template>
<a-button type="primary">
{{ t('commom.reloadText') }}
</a-button>
</a-empty>
</a-tab-pane>
</a-tabs>
</a-card>
</a-col>
</a-row>
</PageContainer>
</template>
<style lang="less" scoped>
.info-top {
display: flex;
flex-direction: column;
align-items: center;
&-no {
align-self: flex-start;
font-size: 14px;
margin-bottom: 16px;
}
&-nickname {
margin-top: 16px;
font-size: 24px;
align-self: flex-start;
text-align: center;
text-overflow: ellipsis;
overflow: hidden;
width: 100%;
}
}
</style>