feat(个人中心): 个人中心部分接口

This commit is contained in:
baiqi 2023-12-07 11:49:40 +08:00 committed by f2c-ci-robot[bot]
parent 742d10690d
commit c1e82b45d8
5 changed files with 165 additions and 61 deletions

View File

@ -123,6 +123,7 @@
try {
Message.loading(t('personal.switchOrgLoading'));
await switchUserOrg(id, userStore.id || '');
switchOrgVisible.value = false;
Message.clear();
Message.success(t('personal.switchOrgSuccess'));
personalMenusVisible.value = false;
@ -145,6 +146,7 @@
}
});
const isActiveSwitchOrg = ref(false);
const personalMenus = [
{
label: t('personal.info'),
@ -155,10 +157,16 @@
},
{
label: t('personal.switchOrg'),
icon: <MsIcon type="icon-icon_switch_outlined1" class="text-[var(--color-text-4)]" />,
icon: () => (
<MsIcon
type="icon-icon_switch_outlined1"
class={isActiveSwitchOrg.value ? 'text-[rgb(var(--primary-5))]' : 'text-[var(--color-text-4)]'}
/>
),
isTrigger: true,
event: () => {
switchOrgVisible.value = true;
isActiveSwitchOrg.value = true;
},
},
{
@ -171,6 +179,14 @@
},
];
watch(
() => personalMenusVisible.value,
(val) => {
if (!val) {
isActiveSwitchOrg.value = false;
}
}
);
const personalInfoMenu = () => {
return (
<a-trigger
@ -189,24 +205,36 @@
}
if (e.isTrigger) {
return (
<a-dropdown
<a-trigger
v-model:popup-visible={switchOrgVisible.value}
trigger="click"
unmount-on-close={false}
popup-offset={14}
position="right"
class={['arco-trigger-menu switch-org-dropdown', switchOrgVisible.value ? 'block' : 'hidden']}
v-slots={{
content: () => (
<>
<div class="arco-trigger-menu-inner">
<a-input-search
v-model:model-value={orgKeyword.value}
placeholder={t('personal.searchOrgPlaceholder')}
/>
<a-divider class="ms-dropdown-divider" />
<a-divider margin="4px" />
<div class="switch-org-dropdown-list">
{orgList.value.map((item) => (
<a-doption
<div
key={item.id}
value={item.id}
class={item.id === appStore.currentOrgId ? 'active-org' : ''}
class={[
'arco-trigger-menu-item !w-[calc(100%-12px)]',
item.id === appStore.currentOrgId ? 'active-org' : '',
]}
onClick={() => {
switchOrg(item.id);
}}
>
{item.name}
<a-tooltip content={item.name}>
<div class="one-line-text max-w-[220px]">{item.name}</div>
</a-tooltip>
{item.id === appStore.currentOrgId ? (
<MsTag
type="primary"
@ -217,27 +245,27 @@
{t('personal.currentOrg')}
</MsTag>
) : null}
</a-doption>
</div>
))}
</>
</div>
</div>
),
}}
onSelect={(orgId: string) => {
switchOrg(orgId);
}}
>
<div
class="arco-trigger-menu-item"
class={
isActiveSwitchOrg.value ? 'active-org arco-trigger-menu-item' : 'arco-trigger-menu-item'
}
onClick={() => {
if (typeof e.event === 'function') {
e.event();
}
}}
>
{e.icon}
{e.icon()}
{e.label}
</div>
</a-dropdown>
</a-trigger>
);
}
return (
@ -434,6 +462,20 @@
}
}
}
.switch-org-dropdown {
@apply absolute max-h-none;
width: 300px;
.arco-trigger-popup-wrapper {
@apply max-h-full;
.switch-org-dropdown-list {
@apply overflow-y-auto;
.ms-scroll-bar();
max-height: 200px;
}
}
}
.active-org {
color: rgb(var(--primary-5));
background-color: rgb(var(--primary-1));

View File

@ -52,7 +52,7 @@
/>
</a-form-item>
<a-form-item>
<a-button type="primary" class="mr-[14px]" :loading="updateLoading" @click="updateBaseInfo">
<a-button type="primary" class="mr-[14px]" :loading="updateLoading" @click="editBaseInfo">
{{ t('common.update') }}
</a-button>
<a-button type="secondary" :disabled="updateLoading" @click="cancelEdit">{{ t('common.cancel') }}</a-button>
@ -89,11 +89,11 @@
class="check-icon"
/>
</div>
<div v-for="(avatar, index) of avatarList" :key="avatar" class="avatar" @click="changeAvatar(index)">
<div v-for="(avatar, index) of avatarList" :key="avatar" class="avatar" @click="changeAvatar(avatar)">
<MsAvatar :avatar="avatar" class="mb-[4px]" />
<div class="text-[12px] text-[var(--color-text-1)]">{{ t('ms.personal.avatar', { index: index }) }}</div>
<MsIcon
v-if="activeAvatar === index"
v-if="activeAvatar === avatar"
type="icon-icon_succeed_filled"
:style="{ color: 'rgb(var(--success-6))' }"
class="check-icon"
@ -126,6 +126,7 @@
import MsTag from '@/components/pure/ms-tag/ms-tag.vue';
import MsFormItemSub from '@/components/business/ms-form-item-sub/index.vue';
import { getBaseInfo, updateBaseInfo } from '@/api/modules/user';
import { useI18n } from '@/hooks/useI18n';
import useUserStore from '@/store/modules/user/index';
import { validateEmail, validatePhone } from '@/utils/validate';
@ -136,6 +137,7 @@
const { t } = useI18n();
const loading = ref(false);
const isEdit = ref(false);
const descriptions = ref<Description[]>([
{
@ -162,6 +164,19 @@
phone: userStore.phone,
});
const baseInfoFormRef = ref<FormInstance>();
const orgList = ref([]);
onBeforeMount(async () => {
try {
loading.value = true;
const res = await getBaseInfo(userStore.id || '');
console.log(res);
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
}
});
const updateLoading = ref(false);
function cancelEdit() {
@ -194,12 +209,20 @@
}
}
function updateBaseInfo() {
function editBaseInfo() {
baseInfoFormRef.value?.validate(async (errors) => {
if (!errors) {
try {
updateLoading.value = true;
await updateBaseInfo({
id: userStore.id || '',
username: baseInfoForm.value.name || '',
email: baseInfoForm.value.email || '',
phone: baseInfoForm.value.phone || '',
avatar: userStore.avatar || '',
});
Message.success(t('common.updateSuccess'));
await userStore.isLogin();
isEdit.value = false;
} catch (error) {
// eslint-disable-next-line no-console
@ -212,25 +235,8 @@
}
const avatarModalVisible = ref(false);
async function handleChangeAvatarConfirm(done: (closed: boolean) => void) {
try {
// if (replaceVersion.value !== '') {
// await useLatestVersion(replaceVersion.value);
// }
// await toggleVersionStatus(activeRecord.value.id);
Message.success(t('common.updateSuccess'));
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
done(false);
} finally {
done(true);
}
}
const activeAvatarType = ref<'builtIn' | 'word'>('builtIn');
const activeAvatar = ref<string | number>('default');
const activeAvatar = ref('default');
const avatarList = ref<string[]>([]);
let i = 1;
while (i <= 46) {
@ -238,9 +244,29 @@
i++;
}
function changeAvatar(avatar: string | number) {
function changeAvatar(avatar: string) {
activeAvatar.value = avatar;
}
async function handleChangeAvatarConfirm(done: (closed: boolean) => void) {
try {
await updateBaseInfo({
id: userStore.id || '',
username: baseInfoForm.value.name || '',
email: baseInfoForm.value.email || '',
phone: baseInfoForm.value.phone || '',
avatar: activeAvatar.value,
});
Message.success(t('common.updateSuccess'));
await userStore.isLogin();
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
done(false);
} finally {
done(true);
}
}
</script>
<style lang="less" scoped>

View File

@ -37,9 +37,15 @@
import MsPasswordInput from '@/components/pure/ms-password-input/index.vue';
import MsFormItemSub from '@/components/business/ms-form-item-sub/index.vue';
import { updatePsw } from '@/api/modules/user';
import { useI18n } from '@/hooks/useI18n';
import useUser from '@/hooks/useUser';
import useUserStore from '@/store/modules/user';
import { encrypted } from '@/utils';
import { validatePasswordLength, validateWordPassword } from '@/utils/validate';
const userStore = useUserStore();
const { logout } = useUser();
const { t } = useI18n();
const form = ref({
@ -80,12 +86,26 @@
],
};
const counting = ref(3);
function changePsw() {
formRef.value?.validate(async (errors) => {
if (!errors) {
try {
loading.value = true;
Message.success(t('common.updateSuccess'));
await updatePsw({
id: userStore.id || '',
newPassword: encrypted(form.value.newPsw) || '',
oldPassword: encrypted(form.value.password) || '',
});
Message.success({
content: t('ms.personal.updatePswSuccess', { count: counting.value }),
duration: 4000,
});
setInterval(() => counting.value--, 1000);
setTimeout(() => {
logout();
}, 3000);
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);

View File

@ -112,6 +112,25 @@ export interface UserRoleRelation {
createUser: string;
}
// 个人信息
export interface PersonalOrganization {
id: string;
num: number;
organizationId: string;
name: string;
description: string;
createTime: number;
updateTime: number;
updateUser: string;
createUser: string;
deleteTime: number;
deleted: boolean;
deleteUser: string;
enable: boolean;
moduleSetting: string;
}
export interface OrganizationProjectMap {
[key: string]: PersonalOrganization[];
}
export interface PersonalInfo {
id: string;
name: string;
@ -128,15 +147,9 @@ export interface PersonalInfo {
createUser: string;
updateUser: string;
deleted: boolean;
userRoles: UserRole[];
userRoleRelations: UserRoleRelation[];
userRolePermissions: UserRolePermission[];
platformInfo: string;
seleniumServer: string;
apiServer: string;
avatar: string;
organizationProjectMap: OrganizationProjectMap;
}
export interface UpdateBaseInfo {
id: string;
username: string;

View File

@ -4,6 +4,9 @@
<a-button type="primary" @click="handleAddClick">{{ t('project.fileManagement.addFile') }}</a-button>
<div class="header-right">
<a-select v-model="tableFileType" class="w-[240px]" :loading="fileTypeLoading" @change="searchList">
<template #prefix>
{{ t('project.fileManagement.type') }}
</template>
<a-option key="" value="">{{ t('common.all') }}</a-option>
<a-option v-for="item of tableFileTypeOptions" :key="item" :value="item">
{{ item }}