@drax/identity-vue 0.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +61 -0
- package/package.json +65 -0
- package/src/assets/base.css +86 -0
- package/src/assets/logo.svg +1 -0
- package/src/assets/main.css +35 -0
- package/src/combobox/PermissionCombobox.vue +38 -0
- package/src/combobox/RoleCombobox.vue +37 -0
- package/src/components/IdentityChangeOwnPassword/IdentityChangeOwnPassword.vue +139 -0
- package/src/components/IdentityLogin/IdentityLogin.vue +124 -0
- package/src/components/IdentityProfileAvatar/IdentityProfileAvatar.vue +38 -0
- package/src/components/IdentityProfileDrawer/IdentityProfileDrawer.vue +82 -0
- package/src/components/IdentityProfileView/IdentityProfileView.vue +31 -0
- package/src/components/PermissionSelector/PermissionSelector.vue +89 -0
- package/src/composables/useAuth.ts +53 -0
- package/src/composables/useI18nValidation.ts +11 -0
- package/src/composables/useRole.ts +93 -0
- package/src/composables/useUser.ts +96 -0
- package/src/cruds/role-crud/RoleCrud.vue +165 -0
- package/src/cruds/role-crud/RoleList.vue +110 -0
- package/src/cruds/user-crud/UserCrud.vue +222 -0
- package/src/cruds/user-crud/UserList.vue +100 -0
- package/src/forms/RoleForm.vue +44 -0
- package/src/forms/UserCreateForm.vue +101 -0
- package/src/forms/UserEditForm.vue +87 -0
- package/src/forms/UserPasswordForm.vue +81 -0
- package/src/i18n/I18n.ts +10 -0
- package/src/i18n/I18nMessages.ts +21 -0
- package/src/icons/IconCommunity.vue +7 -0
- package/src/index.ts +51 -0
- package/src/pages/RoleCrudPage.vue +12 -0
- package/src/pages/UserCrudPage.vue +12 -0
- package/src/stores/auth/AuthStore.ts +38 -0
- package/src/views/RoleView.vue +32 -0
- package/src/views/UserView.vue +34 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import {useAuth} from "../../composables/useAuth";
|
|
3
|
+
import {defineModel, ref} from "vue";
|
|
4
|
+
import IdentityProfileView from "../IdentityProfileView/IdentityProfileView.vue";
|
|
5
|
+
import IdentityChangeOwnPassword from "../../components/IdentityChangeOwnPassword/IdentityChangeOwnPassword.vue";
|
|
6
|
+
|
|
7
|
+
const auth = useAuth()
|
|
8
|
+
const valueModel = defineModel()
|
|
9
|
+
const profile = ref(false)
|
|
10
|
+
const changePassword = ref(false)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<template>
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
<v-navigation-drawer
|
|
19
|
+
v-model="valueModel"
|
|
20
|
+
location="right"
|
|
21
|
+
>
|
|
22
|
+
|
|
23
|
+
<template v-if="auth.isAuthenticated()">
|
|
24
|
+
<identity-profile-view></identity-profile-view>
|
|
25
|
+
<v-divider></v-divider>
|
|
26
|
+
|
|
27
|
+
<v-list>
|
|
28
|
+
<v-list-item
|
|
29
|
+
@click="profile = !profile"
|
|
30
|
+
prepend-icon="mdi-account-cog"
|
|
31
|
+
:title="$t('user.profile')"
|
|
32
|
+
>
|
|
33
|
+
</v-list-item>
|
|
34
|
+
<v-list-item
|
|
35
|
+
@click="auth.logout()"
|
|
36
|
+
prepend-icon="mdi-logout"
|
|
37
|
+
:title="$t('user.logout')"
|
|
38
|
+
>
|
|
39
|
+
</v-list-item>
|
|
40
|
+
</v-list>
|
|
41
|
+
</template>
|
|
42
|
+
|
|
43
|
+
<template v-else>
|
|
44
|
+
<v-list>
|
|
45
|
+
<v-list-item
|
|
46
|
+
href="/login"
|
|
47
|
+
prepend-icon="mdi-login"
|
|
48
|
+
:title="$t('user.login')"
|
|
49
|
+
>
|
|
50
|
+
</v-list-item>
|
|
51
|
+
</v-list>
|
|
52
|
+
</template>
|
|
53
|
+
|
|
54
|
+
<v-dialog v-model="profile" fullscreen :on-after-leave="changePassword=false">
|
|
55
|
+
<v-toolbar>
|
|
56
|
+
<v-toolbar-title>
|
|
57
|
+
{{$t('user.profile')}}
|
|
58
|
+
</v-toolbar-title>
|
|
59
|
+
<v-spacer></v-spacer>
|
|
60
|
+
<v-btn icon @click="profile = !profile">
|
|
61
|
+
<v-icon>mdi-close</v-icon>
|
|
62
|
+
</v-btn>
|
|
63
|
+
</v-toolbar>
|
|
64
|
+
<v-card >
|
|
65
|
+
<v-card-text class="flex-shrink-1 flex-grow-0">
|
|
66
|
+
<identity-profile-view></identity-profile-view>
|
|
67
|
+
</v-card-text>
|
|
68
|
+
<v-card-text class="text-center flex-grow-1">
|
|
69
|
+
<IdentityChangeOwnPassword v-if="changePassword"></IdentityChangeOwnPassword>
|
|
70
|
+
<v-btn v-else color="blue" variant="tonal" @click="changePassword = true">{{$t('user.changeOwnPassword')}}</v-btn>
|
|
71
|
+
|
|
72
|
+
</v-card-text>
|
|
73
|
+
</v-card>
|
|
74
|
+
</v-dialog>
|
|
75
|
+
|
|
76
|
+
</v-navigation-drawer>
|
|
77
|
+
|
|
78
|
+
</template>
|
|
79
|
+
|
|
80
|
+
<style scoped>
|
|
81
|
+
|
|
82
|
+
</style>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import {useAuthStore} from "../../stores/auth/AuthStore.js";
|
|
3
|
+
import IdentityProfileAvatar from "../IdentityProfileAvatar/IdentityProfileAvatar.vue";
|
|
4
|
+
const emit = defineEmits(['click'])
|
|
5
|
+
const authStore = useAuthStore()
|
|
6
|
+
const onClick = () => {
|
|
7
|
+
emit('click')
|
|
8
|
+
}
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
<template>
|
|
12
|
+
<v-sheet class="position-relative d-flex justify-center align-center" height="150">
|
|
13
|
+
<v-sheet class="position-absolute bg-surface-light w-100 top-0" height="65"></v-sheet>
|
|
14
|
+
<v-sheet class="text-center">
|
|
15
|
+
<identity-profile-avatar :avatar-size="70"></identity-profile-avatar>
|
|
16
|
+
<h6 class="text-h6">{{ authStore.authUser?.username }}</h6>
|
|
17
|
+
</v-sheet>
|
|
18
|
+
</v-sheet>
|
|
19
|
+
|
|
20
|
+
<v-divider></v-divider>
|
|
21
|
+
<v-sheet class="d-flex justify-center align-center" height="50">
|
|
22
|
+
<v-sheet class="text-center">
|
|
23
|
+
<h6 class="text-caption">{{ authStore.authUser?.email }}</h6>
|
|
24
|
+
<h6 class="text-subtitle-2">role: {{ authStore.authUser?.role?.name }}</h6>
|
|
25
|
+
</v-sheet>
|
|
26
|
+
</v-sheet>
|
|
27
|
+
</template>
|
|
28
|
+
|
|
29
|
+
<style scoped>
|
|
30
|
+
|
|
31
|
+
</style>
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
|
|
3
|
+
import {ref, onMounted, defineModel, computed} from 'vue'
|
|
4
|
+
import type {PropType} from 'vue'
|
|
5
|
+
|
|
6
|
+
const props = defineProps({
|
|
7
|
+
errorMessages: {
|
|
8
|
+
type: String as PropType<string | string[] | undefined>,
|
|
9
|
+
}
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
const model = defineModel()
|
|
13
|
+
import {useRole} from "../../composables/useRole";
|
|
14
|
+
|
|
15
|
+
const {fetchPermissions} = useRole()
|
|
16
|
+
let items = ref([])
|
|
17
|
+
|
|
18
|
+
onMounted(async () => {
|
|
19
|
+
items.value = await fetchPermissions()
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
interface PermissionGroups {
|
|
23
|
+
[key: string]: string[];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const permissionGroups = computed(() => {
|
|
27
|
+
const groups = items.value.reduce((acc: PermissionGroups, permission: string) => {
|
|
28
|
+
if (permission.includes(':')) {
|
|
29
|
+
const [entity, action] = permission.split(':');
|
|
30
|
+
if (!acc[entity]) {
|
|
31
|
+
acc[entity] = [];
|
|
32
|
+
}
|
|
33
|
+
acc[entity].push(permission);
|
|
34
|
+
} else {
|
|
35
|
+
// Si el permiso no sigue el formato entidad:acción, lo asignamos al grupo 'general'
|
|
36
|
+
const generalGroup = 'general';
|
|
37
|
+
if (!acc[generalGroup]) {
|
|
38
|
+
acc[generalGroup] = [];
|
|
39
|
+
}
|
|
40
|
+
acc[generalGroup].push(permission);
|
|
41
|
+
}
|
|
42
|
+
return acc;
|
|
43
|
+
}, {});
|
|
44
|
+
|
|
45
|
+
return groups;
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
</script>
|
|
50
|
+
|
|
51
|
+
<template>
|
|
52
|
+
<v-sheet class="pa-2">
|
|
53
|
+
<h5 class="text-h5 mb-2">{{$t ? $t('permission.permissions') : 'Permissions'}}</h5>
|
|
54
|
+
<v-item-group
|
|
55
|
+
v-model="model"
|
|
56
|
+
variant="outlined"
|
|
57
|
+
divided
|
|
58
|
+
multiple
|
|
59
|
+
color="green"
|
|
60
|
+
>
|
|
61
|
+
<template v-for="(permissions, entity) in permissionGroups" :key="entity">
|
|
62
|
+
<v-card class="mb-2" variant="outlined">
|
|
63
|
+
<v-card-title class="text-capitalize">
|
|
64
|
+
{{ $t ? $t('permission.'+entity) : entity }}
|
|
65
|
+
</v-card-title>
|
|
66
|
+
<v-card-text>
|
|
67
|
+
<v-item
|
|
68
|
+
v-for="permission in permissions"
|
|
69
|
+
v-slot="{ isSelected, toggle }"
|
|
70
|
+
:value="permission"
|
|
71
|
+
>
|
|
72
|
+
<v-btn
|
|
73
|
+
:color="isSelected? 'green' : 'grey-darken-3'" class=""
|
|
74
|
+
@click="toggle" variant="flat" :rounded="false" border
|
|
75
|
+
>
|
|
76
|
+
{{ $t ? $t('permission.'+permission) : permission }}
|
|
77
|
+
</v-btn>
|
|
78
|
+
</v-item>
|
|
79
|
+
</v-card-text>
|
|
80
|
+
</v-card>
|
|
81
|
+
</template>
|
|
82
|
+
</v-item-group>
|
|
83
|
+
|
|
84
|
+
</v-sheet>
|
|
85
|
+
</template>
|
|
86
|
+
|
|
87
|
+
<style scoped>
|
|
88
|
+
|
|
89
|
+
</style>
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import {useAuthStore} from "../stores/auth/AuthStore";
|
|
2
|
+
import {AuthHelper, AuthSystem} from "@drax/identity-front";
|
|
3
|
+
import {inject} from "vue";
|
|
4
|
+
|
|
5
|
+
export function useAuth() {
|
|
6
|
+
|
|
7
|
+
const authStore = useAuthStore()
|
|
8
|
+
|
|
9
|
+
const authSystem = inject('AuthSystem') as AuthSystem
|
|
10
|
+
|
|
11
|
+
const login = async (username:string, password:string) => {
|
|
12
|
+
const {accessToken} = await authSystem.login(username, password)
|
|
13
|
+
authStore.setAccessToken(accessToken)
|
|
14
|
+
const authUser = await authSystem.me()
|
|
15
|
+
authStore.setAuthUser(authUser)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const changeOwnPassword = async (currentPassword:string, newPassword:string) => {
|
|
19
|
+
return await authSystem.changeOwnPassword(currentPassword, newPassword)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async function fetchAuthUser() {
|
|
23
|
+
const authUser = await authSystem.me()
|
|
24
|
+
authStore.setAuthUser(authUser)
|
|
25
|
+
return authUser
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function logout(){
|
|
29
|
+
authSystem.logout()
|
|
30
|
+
authStore.clearAuth()
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function hasPermission(permission:string) {
|
|
34
|
+
return authStore?.authUser?.role?.permissions ? authStore.authUser.role.permissions.includes(permission) : false
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function tokenIsValid(){
|
|
38
|
+
return authStore.accessToken ? AuthHelper.isJWTValid(authStore.accessToken) : false
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function isAuthenticated(){
|
|
42
|
+
if(tokenIsValid()){
|
|
43
|
+
return true
|
|
44
|
+
}else{
|
|
45
|
+
logout()
|
|
46
|
+
return false
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return {hasPermission, logout, tokenIsValid, isAuthenticated, fetchAuthUser, login, changeOwnPassword}
|
|
52
|
+
|
|
53
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import {useI18n} from "vue-i18n";
|
|
2
|
+
|
|
3
|
+
export function useI18nValidation() {
|
|
4
|
+
const {t} = useI18n()
|
|
5
|
+
|
|
6
|
+
function $ta(inputError: string[] | undefined): string | undefined {
|
|
7
|
+
return inputError ? inputError.map(error => t(error)).join(", ") : undefined
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
return {$ta}
|
|
11
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import {inject, ref} from "vue";
|
|
2
|
+
import type {IRole, RoleSystem} from "@drax/identity-front";
|
|
3
|
+
import {ClientError} from "@drax/common-front";
|
|
4
|
+
import type { IClientInputError} from "@drax/common-front";
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
export function useRole() {
|
|
8
|
+
|
|
9
|
+
const roleSystem = inject('RoleSystem') as RoleSystem
|
|
10
|
+
|
|
11
|
+
let roleError = ref<string>('')
|
|
12
|
+
let inputErrors = ref<IClientInputError>()
|
|
13
|
+
let loading = ref(false);
|
|
14
|
+
|
|
15
|
+
async function fetchPermissions(page = 1, perPage = 5) {
|
|
16
|
+
loading.value = true
|
|
17
|
+
let permissions = roleSystem.fetchPermissions()
|
|
18
|
+
loading.value = false
|
|
19
|
+
return permissions
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async function fetchRole(page = 1, perPage = 5) {
|
|
23
|
+
loading.value = true
|
|
24
|
+
let roles = roleSystem.fetchRole()
|
|
25
|
+
loading.value = false
|
|
26
|
+
return roles
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async function paginateRole(page = 1, perPage = 5, string = "") {
|
|
30
|
+
loading.value = true
|
|
31
|
+
let paginatedrole = roleSystem.paginateRole(page, perPage,string)
|
|
32
|
+
loading.value = false
|
|
33
|
+
return paginatedrole
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async function createRole(roleData: IRole) {
|
|
37
|
+
try {
|
|
38
|
+
loading.value = true
|
|
39
|
+
let role: IRole = await roleSystem.createRole(roleData)
|
|
40
|
+
return role
|
|
41
|
+
} catch (err) {
|
|
42
|
+
if (err instanceof ClientError) {
|
|
43
|
+
inputErrors.value = err.inputErrors
|
|
44
|
+
}if(err instanceof Error) {
|
|
45
|
+
roleError.value = err.message
|
|
46
|
+
}
|
|
47
|
+
throw err
|
|
48
|
+
}finally {
|
|
49
|
+
loading.value = false
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async function editRole(id: string, roleData: IRole) {
|
|
55
|
+
try {
|
|
56
|
+
loading.value = true
|
|
57
|
+
let role: IRole = await roleSystem.editRole(id, roleData)
|
|
58
|
+
return role
|
|
59
|
+
} catch (err) {
|
|
60
|
+
|
|
61
|
+
if (err instanceof ClientError) {
|
|
62
|
+
inputErrors.value = err.inputErrors
|
|
63
|
+
}
|
|
64
|
+
if(err instanceof Error) {
|
|
65
|
+
roleError.value = err.message
|
|
66
|
+
}
|
|
67
|
+
throw err
|
|
68
|
+
}finally {
|
|
69
|
+
loading.value = false
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async function deleteRole(id: string) {
|
|
74
|
+
try {
|
|
75
|
+
loading.value = true
|
|
76
|
+
await roleSystem.deleteRole(id)
|
|
77
|
+
} catch (err) {
|
|
78
|
+
console.log("composable deleteRole error: ", err, )
|
|
79
|
+
if (err instanceof ClientError) {
|
|
80
|
+
inputErrors.value = err.inputErrors
|
|
81
|
+
}
|
|
82
|
+
if(err instanceof Error) {
|
|
83
|
+
roleError.value = err.message
|
|
84
|
+
}
|
|
85
|
+
throw err
|
|
86
|
+
}finally {
|
|
87
|
+
loading.value = false
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return {fetchRole, fetchPermissions, paginateRole, createRole, editRole, deleteRole, loading, roleError, inputErrors}
|
|
92
|
+
|
|
93
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import {inject, ref} from "vue";
|
|
2
|
+
import type {IUserPassword, UserSystem} from "@drax/identity-front";
|
|
3
|
+
import type {IUser} from "@drax/identity-front";
|
|
4
|
+
import type {IClientInputError} from "@drax/common-front";
|
|
5
|
+
import {ClientError} from "@drax/common-front";
|
|
6
|
+
import type {IUserCreate, IUserUpdate} from "@drax/identity-front";
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
export function useUser() {
|
|
10
|
+
|
|
11
|
+
const userSystem = inject('UserSystem') as UserSystem
|
|
12
|
+
|
|
13
|
+
let userError = ref<string>('')
|
|
14
|
+
let inputErrors = ref<IClientInputError>()
|
|
15
|
+
let loading = ref(false);
|
|
16
|
+
|
|
17
|
+
async function paginateUser(page = 1, perPage = 5, search = "") {
|
|
18
|
+
loading.value = true
|
|
19
|
+
let paginatedUser = userSystem.paginateUser(page, perPage, search)
|
|
20
|
+
loading.value = false
|
|
21
|
+
return paginatedUser
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async function createUser(userData: IUserCreate) {
|
|
25
|
+
try {
|
|
26
|
+
loading.value = true
|
|
27
|
+
let user: IUser = await userSystem.createUser(userData)
|
|
28
|
+
return user
|
|
29
|
+
} catch (err) {
|
|
30
|
+
if (err instanceof ClientError) {
|
|
31
|
+
inputErrors.value = err.inputErrors
|
|
32
|
+
}if(err instanceof Error) {
|
|
33
|
+
userError.value = err.message
|
|
34
|
+
}
|
|
35
|
+
throw err
|
|
36
|
+
}finally {
|
|
37
|
+
loading.value = false
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async function changeUserPassword(id: string, newPassword: string){
|
|
43
|
+
try {
|
|
44
|
+
loading.value = true
|
|
45
|
+
return await userSystem.changeUserPassword(id, newPassword)
|
|
46
|
+
} catch (err) {
|
|
47
|
+
if (err instanceof ClientError) {
|
|
48
|
+
inputErrors.value = err.inputErrors
|
|
49
|
+
}
|
|
50
|
+
if(err instanceof Error) {
|
|
51
|
+
userError.value = err.message
|
|
52
|
+
}
|
|
53
|
+
throw err
|
|
54
|
+
}finally {
|
|
55
|
+
loading.value = false
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async function editUser(id: string, userData: IUserUpdate) {
|
|
60
|
+
try {
|
|
61
|
+
loading.value = true
|
|
62
|
+
let user: IUser = await userSystem.editUser(id, userData)
|
|
63
|
+
return user
|
|
64
|
+
} catch (err) {
|
|
65
|
+
if (err instanceof ClientError) {
|
|
66
|
+
inputErrors.value = err.inputErrors
|
|
67
|
+
}
|
|
68
|
+
if(err instanceof Error) {
|
|
69
|
+
userError.value = err.message
|
|
70
|
+
}
|
|
71
|
+
throw err
|
|
72
|
+
}finally {
|
|
73
|
+
loading.value = false
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async function deleteUser(id: string) {
|
|
78
|
+
try {
|
|
79
|
+
loading.value = true
|
|
80
|
+
await userSystem.deleteUser(id)
|
|
81
|
+
} catch (err) {
|
|
82
|
+
console.log("composable deleteUser error: ", err, )
|
|
83
|
+
if (err instanceof ClientError) {
|
|
84
|
+
inputErrors.value = err.inputErrors
|
|
85
|
+
}
|
|
86
|
+
if(err instanceof Error) {
|
|
87
|
+
userError.value = err.message
|
|
88
|
+
}
|
|
89
|
+
throw err
|
|
90
|
+
}finally {
|
|
91
|
+
loading.value = false
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return {paginateUser, createUser, editUser, changeUserPassword, deleteUser, loading, userError, inputErrors}
|
|
96
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import {computed, ref} from 'vue'
|
|
3
|
+
import RoleList from "./RoleList.vue";
|
|
4
|
+
import {useRole} from "../../composables/useRole";
|
|
5
|
+
import type {IRole} from "@drax/identity-front";
|
|
6
|
+
import RoleForm from "../../forms/RoleForm.vue";
|
|
7
|
+
import RoleView from "../../views/RoleView.vue";
|
|
8
|
+
|
|
9
|
+
const {createRole, editRole, deleteRole, loading, roleError, inputErrors} = useRole()
|
|
10
|
+
|
|
11
|
+
interface RoleList {
|
|
12
|
+
loadItems: () => void;
|
|
13
|
+
items: IRole[];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
type DialogMode = 'create' | 'edit' | 'delete' | null;
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
let dialog = ref(false);
|
|
20
|
+
let dialogMode = ref<DialogMode>(null);
|
|
21
|
+
let dialogTitle = ref('');
|
|
22
|
+
const roleList = ref<RoleList | null>(null);
|
|
23
|
+
let form = ref<IRole>({name: "", permissions: [], readonly: false})
|
|
24
|
+
let target = ref<IRole>();
|
|
25
|
+
let targetId = ref<string>('');
|
|
26
|
+
let filterEnable = ref(false);
|
|
27
|
+
|
|
28
|
+
function cancel() {
|
|
29
|
+
dialog.value = false
|
|
30
|
+
inputErrors.value = {}
|
|
31
|
+
roleError.value = '';
|
|
32
|
+
dialogMode.value = null
|
|
33
|
+
dialogTitle.value = ''
|
|
34
|
+
targetId.value = ''
|
|
35
|
+
target.value = undefined
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async function save() {
|
|
39
|
+
|
|
40
|
+
try {
|
|
41
|
+
if (dialogMode.value === 'create') {
|
|
42
|
+
await createRole(form.value)
|
|
43
|
+
} else if (dialogMode.value === 'edit') {
|
|
44
|
+
await editRole(targetId.value, form.value)
|
|
45
|
+
} else if (dialogMode.value === 'delete') {
|
|
46
|
+
await deleteRole(targetId.value)
|
|
47
|
+
}
|
|
48
|
+
dialog.value = false
|
|
49
|
+
inputErrors.value = {}
|
|
50
|
+
roleError.value = '';
|
|
51
|
+
if (roleList.value !== null) {
|
|
52
|
+
roleList.value.loadItems()
|
|
53
|
+
}
|
|
54
|
+
} catch (e) {
|
|
55
|
+
console.error(e)
|
|
56
|
+
if (e instanceof Error) {
|
|
57
|
+
roleError.value = e.message
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
let buttonText = computed(() => {
|
|
63
|
+
switch (dialogMode.value) {
|
|
64
|
+
case 'create':
|
|
65
|
+
return 'action.create'
|
|
66
|
+
case 'edit':
|
|
67
|
+
return 'action.update'
|
|
68
|
+
case 'delete':
|
|
69
|
+
return 'action.delete'
|
|
70
|
+
default:
|
|
71
|
+
return 'action.sent'
|
|
72
|
+
}
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
function toCreate() {
|
|
76
|
+
dialogMode.value = 'create';
|
|
77
|
+
dialogTitle.value = 'role.creating';
|
|
78
|
+
form.value = {name: "", permissions: [], readonly: false}
|
|
79
|
+
dialog.value = true;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function toEdit(item: IRole) {
|
|
83
|
+
console.log('toEdit', item)
|
|
84
|
+
dialogMode.value = 'edit';
|
|
85
|
+
dialogTitle.value = 'role.updating';
|
|
86
|
+
const {id, ...rest} = item;
|
|
87
|
+
targetId.value = id;
|
|
88
|
+
form.value = {...rest}
|
|
89
|
+
dialog.value = true;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function toDelete(item: IRole) {
|
|
93
|
+
console.log('toDelete', item)
|
|
94
|
+
dialogMode.value = 'delete';
|
|
95
|
+
dialogTitle.value = 'role.deleting';
|
|
96
|
+
target.value = item
|
|
97
|
+
const {id} = item;
|
|
98
|
+
targetId.value = id;
|
|
99
|
+
dialog.value = true;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
</script>
|
|
103
|
+
|
|
104
|
+
<template>
|
|
105
|
+
<v-container>
|
|
106
|
+
|
|
107
|
+
<v-sheet border rounded>
|
|
108
|
+
<v-toolbar>
|
|
109
|
+
<v-toolbar-title>{{$t('role.managing')}}</v-toolbar-title>
|
|
110
|
+
<v-spacer></v-spacer>
|
|
111
|
+
<v-btn icon @click="filterEnable = !filterEnable">
|
|
112
|
+
<v-icon>{{ filterEnable ? 'mdi-filter' : 'mdi-filter-off' }}</v-icon>
|
|
113
|
+
</v-btn>
|
|
114
|
+
<v-btn color="primary" @click="toCreate">
|
|
115
|
+
{{$t('action.create') }}
|
|
116
|
+
</v-btn>
|
|
117
|
+
</v-toolbar>
|
|
118
|
+
<v-theme-provider with-background class="pa-2 rounded-b">
|
|
119
|
+
<RoleList
|
|
120
|
+
ref="roleList"
|
|
121
|
+
@toEdit="toEdit"
|
|
122
|
+
@toDelete="toDelete"
|
|
123
|
+
:filterEnable="filterEnable"
|
|
124
|
+
/>
|
|
125
|
+
</v-theme-provider>
|
|
126
|
+
</v-sheet>
|
|
127
|
+
|
|
128
|
+
<v-dialog v-model="dialog" max-width="800">
|
|
129
|
+
<v-sheet border>
|
|
130
|
+
<v-toolbar>
|
|
131
|
+
<v-toolbar-title>{{ $t(dialogTitle) }}</v-toolbar-title>
|
|
132
|
+
</v-toolbar>
|
|
133
|
+
<v-card class="pa-10">
|
|
134
|
+
<v-card-text v-if="roleError">
|
|
135
|
+
<v-alert type="error">{{ roleError }}</v-alert>
|
|
136
|
+
</v-card-text>
|
|
137
|
+
<v-card-text>
|
|
138
|
+
<RoleForm v-if="dialogMode === 'create' || dialogMode === 'edit'"
|
|
139
|
+
v-model="form"
|
|
140
|
+
:inputErrors="inputErrors"
|
|
141
|
+
/>
|
|
142
|
+
<RoleView v-if="dialogMode === 'delete' && target" :role="target"></RoleView>
|
|
143
|
+
</v-card-text>
|
|
144
|
+
<v-card-actions>
|
|
145
|
+
<v-spacer></v-spacer>
|
|
146
|
+
<v-btn variant="text" @click="cancel" :loading="loading">Cancelar</v-btn>
|
|
147
|
+
<v-btn variant="flat"
|
|
148
|
+
:color="dialogMode==='delete' ? 'red' : 'primary'"
|
|
149
|
+
@click="save"
|
|
150
|
+
:loading="loading"
|
|
151
|
+
>
|
|
152
|
+
{{ $t(buttonText) }}
|
|
153
|
+
</v-btn>
|
|
154
|
+
</v-card-actions>
|
|
155
|
+
|
|
156
|
+
</v-card>
|
|
157
|
+
</v-sheet>
|
|
158
|
+
</v-dialog>
|
|
159
|
+
|
|
160
|
+
</v-container>
|
|
161
|
+
</template>
|
|
162
|
+
|
|
163
|
+
<style scoped>
|
|
164
|
+
|
|
165
|
+
</style>
|