Skip to content

Commit

Permalink
feat: updated permission management
Browse files Browse the repository at this point in the history
  • Loading branch information
tikazyq committed Nov 13, 2024
1 parent fbe1bd1 commit 010a278
Show file tree
Hide file tree
Showing 35 changed files with 501 additions and 201 deletions.
82 changes: 77 additions & 5 deletions src/components/core/user/UserForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,44 @@ import useUser from '@/components/core/user/useUser';
import useUserDetail from '@/views/user/detail/useUserDetail';
import { isPro, translate } from '@/utils';
import { useRole } from '@/components';
import { useI18n } from 'vue-i18n';
const props = defineProps<{
form?: User;
isEdit?: boolean;
onChangePassword?: () => Promise<void>;
}>();
// i18n
const t = translate;
const { locale } = useI18n();
// store
const store = useStore();
const { activeId } = useUserDetail();
const { onChangePasswordFunc } = useUser(store);
const onChangePassword = () => onChangePasswordFunc(activeId.value);
const onChangePassword =
props.onChangePassword ||
(() => onChangePasswordFunc(props.form?._id || activeId.value));
const isDetail = computed<boolean>(() => !!activeId.value);
const { form, formRef, formRules, isSelectiveForm, isFormItemDisabled } =
useUser(store);
const {
form: userForm,
formRef,
formRules,
isSelectiveForm,
isFormItemDisabled,
} = useUser(store);
const form = computed<User>(() => {
if (props.form) return props.form;
return userForm.value;
});
const { allListSelectOptions: allRolesSelectOptions } = useRole(store);
Expand Down Expand Up @@ -62,7 +83,7 @@ defineOptions({ name: 'ClUserForm' });
required
>
<el-input
v-if="isSelectiveForm || !isDetail"
v-if="!isEdit && (isSelectiveForm || !isDetail)"
v-model="form.password"
:disabled="isFormItemDisabled('password')"
:placeholder="t('components.user.form.password')"
Expand All @@ -74,12 +95,63 @@ defineOptions({ name: 'ClUserForm' });
class-name="password"
:icon="['fa', 'lock']"
:label="t('components.user.form.changePassword')"
type="danger"
type="primary"
@click="onChangePassword"
/>
</cl-form-item>
<!-- ./Row -->

<!-- Row -->
<template v-if="locale === 'zh'">
<cl-form-item
:span="2"
:label="t('components.user.form.lastName')"
prop="last_name"
>
<el-input
v-model="form.last_name"
:disabled="isFormItemDisabled('last_name')"
:placeholder="t('components.user.form.lastName')"
/>
</cl-form-item>
<cl-form-item
:span="2"
:label="t('components.user.form.firstName')"
prop="first_name"
>
<el-input
v-model="form.first_name"
:disabled="isFormItemDisabled('first_name')"
:placeholder="t('components.user.form.firstName')"
/>
</cl-form-item>
</template>
<template v-else>
<cl-form-item
:span="2"
:label="t('components.user.form.firstName')"
prop="first_name"
>
<el-input
v-model="form.first_name"
:disabled="isFormItemDisabled('first_name')"
:placeholder="t('components.user.form.firstName')"
/>
</cl-form-item>
<cl-form-item
:span="2"
:label="t('components.user.form.lastName')"
prop="last_name"
>
<el-input
v-model="form.last_name"
:disabled="isFormItemDisabled('last_name')"
:placeholder="t('components.user.form.lastName')"
/>
</cl-form-item>
</template>
<!-- ./Row -->

<!-- Row -->
<cl-form-item
:span="2"
Expand Down
2 changes: 2 additions & 0 deletions src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ import useNotificationAlert from './core/notification/alert/useNotificationAlert
import useNotificationChannel from './core/notification/channel/useNotificationChannel';
import useNotificationSetting from './core/notification/setting/useNotificationSetting';
import useProject from './core/project/useProject';
import UserAvatar from './ui/avatar/UserAvatar.vue';
import UserForm from './core/user/UserForm.vue';
import useRichTextSetup from './ui/lexical/composables/useRichTextSetup';
import useRole from './core/role/useRole';
Expand Down Expand Up @@ -443,6 +444,7 @@ export {
useNotificationChannel as useNotificationChannel,
useNotificationSetting as useNotificationSetting,
useProject as useProject,
UserAvatar as ClUserAvatar,
UserForm as ClUserForm,
useRichTextSetup as useRichTextSetup,
useRole as useRole,
Expand Down
114 changes: 114 additions & 0 deletions src/components/ui/avatar/UserAvatar.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
<script setup lang="ts">
import { computed } from 'vue';
import { getUserShortName } from '@/utils/user';
const props = withDefaults(
defineProps<{
icon?: Icon;
size?: BasicSize | number;
shape?: 'circle' | 'square';
src?: string;
alt?: string;
fit?: 'fill' | 'contain' | 'cover' | 'none' | 'scale-down';
color?: string;
user?: User;
tooltip?: string;
}>(),
{
size: 36,
}
);
const emit = defineEmits<{
(e: 'click', event: MouseEvent): void;
}>();
const slots = defineSlots<{
default: any;
}>();
const userLabel = computed<string>(() => {
const { user } = props;
if (user) {
return getUserShortName(user);
}
return '';
});
const labelClass = computed(() => {
const length = userLabel.value.length;
const isChineseName = /[\u4e00-\u9fa5]/.test(userLabel.value);
return {
label: true,
'label--small': length === 3 || (isChineseName && length === 2),
'label--smaller': length === 4 || (isChineseName && length === 3),
'label--smallest': isChineseName && length === 4,
};
});
defineOptions({ name: 'ClUserAvatar' });
</script>

<template>
<div class="avatar">
<el-tooltip :content="tooltip" :disabled="!tooltip">
<el-avatar
v-bind="props"
class="avatar"
@click="(e: MouseEvent) => emit('click', e)"
>
<slot v-if="slots.default" name="default" />
<template v-else-if="user">
<span :class="labelClass">
{{ userLabel }}
</span>
</template>
<template v-else></template>
</el-avatar>
</el-tooltip>
</div>
</template>

<style scoped>
.avatar {
max-height: 50px;
.el-avatar {
background-color: var(--el-color-primary-dark-2);
color: #ffffff;
cursor: pointer;
max-height: 50px;
&:hover {
background-color: var(--cl-primary-color);
}
.label {
display: flex;
align-items: center;
justify-content: center;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 100%;
min-height: 100%;
font-size: 0.85em;
line-height: 1.5;
padding: 0 2px;
}
.label--small {
font-size: 0.8em;
}
.label--smaller {
font-size: 0.75em;
}
.label--smallest {
font-size: 0.7em;
}
}
}
</style>
2 changes: 1 addition & 1 deletion src/components/ui/button/LabelButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,6 @@ defineOptions({ name: 'ClLabelButton' });

<style scoped>
.icon-wrapper {
margin-right: 3px;
margin-right: 5px;
}
</style>
4 changes: 0 additions & 4 deletions src/components/ui/nav/NavActionGroupDetailCommon.vue
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,6 @@ defineOptions({ name: 'ClNavActionGroupDetailCommon' });

<style scoped>
.nav-action-group {
&:deep(.back-btn) {
margin-right: 10px;
}
.nav-action-item:last-child {
margin-right: 10px;
}
Expand Down
55 changes: 24 additions & 31 deletions src/components/ui/nav/NavActionItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,51 +15,44 @@ defineOptions({ name: 'ClNavActionItem' });
</div>
</template>

<style lang="scss" scoped>
<style scoped>
.nav-action-item {
margin: 10px 0;
//height: fit-content;
display: flex;
flex: 0 0 auto;
align-items: center;
color: var(--cl-nav-actions-item-color);
& + .nav-action-item {
//margin-left: 10px;
}
&.is-label {
margin-right: 10px;
}
}
</style>
<style scoped>
.nav-action-item:deep(.title) {
color: inherit;
}
.nav-action-item:deep(.label) {
color: inherit;
font-size: 14px;
margin-right: 5px;
margin-left: 5px;
}
&:deep(.title) {
color: inherit;
}
.nav-action-item:deep(.el-button.el-button--small) {
height: 32px;
}
&:deep(.label) {
color: inherit;
font-size: 14px;
margin-right: 5px;
}
.nav-action-item:deep(.el-button:not(.is-circle) .fa) {
margin-right: 0;
}
&:deep(.el-button.el-button--small) {
height: 32px;
}
.nav-action-item:deep(.el-button .icon + span) {
margin-left: 5px;
}
&:deep(.el-button:not(.is-circle) .fa) {
margin-right: 0;
}
&:deep(.el-button .icon + span) {
margin-left: 5px;
}
.nav-action-item:deep(.nav-action-item-label) {
color: inherit;
font-size: 12px;
margin-right: 5px;
&:deep(.nav-action-item-label) {
color: inherit;
font-size: 12px;
margin-right: 5px;
}
}
</style>
5 changes: 3 additions & 2 deletions src/components/ui/nav/NavLink.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const props = defineProps<{
label?: string | number | boolean;
icon?: Icon;
external?: boolean;
tooltip?: string;
}>();
const slots = defineSlots<{
Expand Down Expand Up @@ -36,11 +37,11 @@ defineOptions({ name: 'ClNavLink' });
<div class="nav-link" @click="onClick">
<cl-icon :icon="icon" class="icon" />
<slot v-if="slots.default" />
<span class="title" v-else>{{ label }}</span>
<span class="title" v-else-if="label">{{ label }}</span>
</div>
</template>

<style lang="scss" scoped>
<style scoped>
.nav-link {
cursor: pointer;
color: var(--cl-blue);
Expand Down
3 changes: 3 additions & 0 deletions src/components/ui/table/Table.vue
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,9 @@ defineOptions({ name: 'ClTable' });
align="center"
reserve-selection
type="selection"
:selectable="
() => (row: any, index: number) => selectableFunction?.(row, index)
"
width="40"
fixed="left"
/>
Expand Down
3 changes: 3 additions & 0 deletions src/i18n/lang/en/components/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ const user: LComponentsUser = {
username: 'Username',
password: 'Password',
changePassword: 'Change Password',
firstName: 'First Name',
lastName: 'Last Name',
fullName: 'Full Name',
email: 'Email',
role: 'Role',
newPassword: 'New Password',
Expand Down
1 change: 1 addition & 0 deletions src/i18n/lang/en/global.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const global: LGlobal = {
locale: '语言',
lang: 'English',
edition: {
community: 'Community',
Expand Down
Loading

0 comments on commit 010a278

Please sign in to comment.