@eeplatform/nuxt-layer-common 1.7.46 → 1.7.48
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/CHANGELOG.md +12 -0
- package/components/EnrollmentForm.vue +12 -0
- package/components/Layout/Header.vue +5 -5
- package/components/ListGroupSelection.vue +134 -0
- package/components/RoleForm.vue +327 -0
- package/components/RolePermissionMain.vue +131 -199
- package/composables/useApps.ts +58 -0
- package/composables/useLocal.ts +1 -1
- package/composables/useLocalAuth.ts +15 -0
- package/composables/usePermission.ts +97 -0
- package/composables/useRole.ts +24 -37
- package/package.json +1 -1
- package/types/local.d.ts +8 -4
- package/types/permission.d.ts +24 -0
- package/types/role.d.ts +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -1496,6 +1496,18 @@ const birthdateRules = [
|
|
|
1496
1496
|
}
|
|
1497
1497
|
return age >= 5 || "Learner must be at least 5 years old (Kindergarten age)";
|
|
1498
1498
|
},
|
|
1499
|
+
(v: any) => {
|
|
1500
|
+
if (!v) return true;
|
|
1501
|
+
const date = parseBirthdate(v);
|
|
1502
|
+
if (date.toString() === "Invalid Date") return true;
|
|
1503
|
+
const today = new Date();
|
|
1504
|
+
let age = today.getFullYear() - date.getFullYear();
|
|
1505
|
+
const monthDiff = today.getMonth() - date.getMonth();
|
|
1506
|
+
if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < date.getDate())) {
|
|
1507
|
+
age--;
|
|
1508
|
+
}
|
|
1509
|
+
return age <= 80 || "Learner must be at most 80 years old";
|
|
1510
|
+
},
|
|
1499
1511
|
];
|
|
1500
1512
|
|
|
1501
1513
|
const enrollment = defineModel<TLearner>({
|
|
@@ -79,7 +79,7 @@
|
|
|
79
79
|
|
|
80
80
|
<v-row no-gutters class="px-2 pb-2">
|
|
81
81
|
<v-col
|
|
82
|
-
v-for="item in
|
|
82
|
+
v-for="item in apps"
|
|
83
83
|
:key="item.title"
|
|
84
84
|
cols="4"
|
|
85
85
|
class="pa-2"
|
|
@@ -206,7 +206,7 @@ const props = defineProps({
|
|
|
206
206
|
default: "Title",
|
|
207
207
|
},
|
|
208
208
|
defaults: {
|
|
209
|
-
type: Array as PropType<
|
|
209
|
+
type: Array as PropType<Record<string, any>[]>,
|
|
210
210
|
default: () => [
|
|
211
211
|
{
|
|
212
212
|
title: "Account",
|
|
@@ -223,11 +223,11 @@ const props = defineProps({
|
|
|
223
223
|
],
|
|
224
224
|
},
|
|
225
225
|
apps: {
|
|
226
|
-
type: Array as PropType<
|
|
226
|
+
type: Array as PropType<Record<string, any>[]>,
|
|
227
227
|
default: () => [],
|
|
228
228
|
},
|
|
229
229
|
others: {
|
|
230
|
-
type: Array as PropType<
|
|
230
|
+
type: Array as PropType<Record<string, any>[]>,
|
|
231
231
|
default: () => [],
|
|
232
232
|
},
|
|
233
233
|
});
|
|
@@ -244,7 +244,7 @@ function setSearchValue() {
|
|
|
244
244
|
search.value = _search.value;
|
|
245
245
|
}
|
|
246
246
|
|
|
247
|
-
const { redirect, drawer } = useLocal();
|
|
247
|
+
const { redirect, drawer, apps } = useLocal();
|
|
248
248
|
|
|
249
249
|
const { APP_NAME, APP_NAME_ROUTE } = useRuntimeConfig().public;
|
|
250
250
|
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-card width="100%" v-bind="attrs">
|
|
3
|
+
<v-list
|
|
4
|
+
v-model:selected="selected"
|
|
5
|
+
lines="two"
|
|
6
|
+
:select-strategy="attrs.readonly ? 'classic' : 'leaf'"
|
|
7
|
+
class="pa-0"
|
|
8
|
+
density="compact"
|
|
9
|
+
read-only
|
|
10
|
+
open-strategy="single"
|
|
11
|
+
>
|
|
12
|
+
<template name="prepend"></template>
|
|
13
|
+
|
|
14
|
+
<template
|
|
15
|
+
v-for="(keyGroup, keyGroupIndex) in props.items"
|
|
16
|
+
:key="keyGroupIndex"
|
|
17
|
+
>
|
|
18
|
+
<v-divider v-if="keyGroupIndex > 0"></v-divider>
|
|
19
|
+
<v-list-group :value="keyGroup.title" fluid>
|
|
20
|
+
<template v-slot:activator="{ props }">
|
|
21
|
+
<v-list-item v-bind="props" density="compact">
|
|
22
|
+
<span class="text-capitalize">
|
|
23
|
+
{{ keyGroup.title }}
|
|
24
|
+
</span>
|
|
25
|
+
|
|
26
|
+
<template #prepend>
|
|
27
|
+
<v-chip class="mr-2" small>
|
|
28
|
+
{{ selectedActionCount(String(keyGroup.key)) }}
|
|
29
|
+
</v-chip>
|
|
30
|
+
</template>
|
|
31
|
+
</v-list-item>
|
|
32
|
+
</template>
|
|
33
|
+
|
|
34
|
+
<template
|
|
35
|
+
v-for="(item, itemIndex) in keyGroup.children"
|
|
36
|
+
:key="itemIndex"
|
|
37
|
+
>
|
|
38
|
+
<v-divider></v-divider>
|
|
39
|
+
<v-list-item v-if="attrs.readonly" density="compact">
|
|
40
|
+
<template #title>
|
|
41
|
+
<span class="text-subtitle-2 text-capitalize pl-11">
|
|
42
|
+
{{ item.title }}
|
|
43
|
+
</span>
|
|
44
|
+
</template>
|
|
45
|
+
|
|
46
|
+
<template #subtitle>
|
|
47
|
+
<span class="text-subtitle-2 pl-11">{{
|
|
48
|
+
item.description
|
|
49
|
+
}}</span>
|
|
50
|
+
</template>
|
|
51
|
+
</v-list-item>
|
|
52
|
+
|
|
53
|
+
<v-list-item v-else :value="item.key" density="compact">
|
|
54
|
+
<template #title>
|
|
55
|
+
<span class="text-subtitle-2 text-capitalize">
|
|
56
|
+
{{ item.title }}
|
|
57
|
+
</span>
|
|
58
|
+
</template>
|
|
59
|
+
|
|
60
|
+
<template #subtitle>
|
|
61
|
+
<span class="text-subtitle-2 text-capitalize">
|
|
62
|
+
{{ item.description }}
|
|
63
|
+
</span>
|
|
64
|
+
</template>
|
|
65
|
+
|
|
66
|
+
<template #prepend="{ isSelected }">
|
|
67
|
+
<v-list-item-action start class="pl-1">
|
|
68
|
+
<v-checkbox-btn
|
|
69
|
+
:model-value="isSelected"
|
|
70
|
+
readonly
|
|
71
|
+
@click="addItem(item.key)"
|
|
72
|
+
></v-checkbox-btn>
|
|
73
|
+
</v-list-item-action>
|
|
74
|
+
</template>
|
|
75
|
+
</v-list-item>
|
|
76
|
+
</template>
|
|
77
|
+
</v-list-group>
|
|
78
|
+
</template>
|
|
79
|
+
|
|
80
|
+
<slot v-if="noData" name="no-data">
|
|
81
|
+
<v-list-item>
|
|
82
|
+
<v-list-item-title>No data</v-list-item-title>
|
|
83
|
+
</v-list-item>
|
|
84
|
+
</slot>
|
|
85
|
+
|
|
86
|
+
<template name="append"></template>
|
|
87
|
+
</v-list>
|
|
88
|
+
</v-card>
|
|
89
|
+
</template>
|
|
90
|
+
|
|
91
|
+
<script setup lang="ts">
|
|
92
|
+
const selected = defineModel<Array<string>>({ default: [] });
|
|
93
|
+
const attrs = useAttrs();
|
|
94
|
+
|
|
95
|
+
function addItem(key: string) {
|
|
96
|
+
if (selected.value.includes(key)) {
|
|
97
|
+
// remove item from selected without reassigning the array
|
|
98
|
+
const index = selected.value.indexOf(key);
|
|
99
|
+
if (index > -1) {
|
|
100
|
+
selected.value.splice(index, 1);
|
|
101
|
+
}
|
|
102
|
+
} else {
|
|
103
|
+
selected.value.push(key);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
type TListGroup = {
|
|
108
|
+
title: string;
|
|
109
|
+
key: string;
|
|
110
|
+
children: { title: string; key: string; description: string }[];
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const props = defineProps({
|
|
114
|
+
items: {
|
|
115
|
+
// Array of object
|
|
116
|
+
type: Array as PropType<TListGroup[]>,
|
|
117
|
+
required: true,
|
|
118
|
+
default: () => [],
|
|
119
|
+
},
|
|
120
|
+
message: {
|
|
121
|
+
type: String,
|
|
122
|
+
default: "",
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
const selectedActionCount = (resource: string) => {
|
|
127
|
+
return selected.value.filter((permission) => permission.startsWith(resource))
|
|
128
|
+
.length;
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
const noData = computed(() => {
|
|
132
|
+
return Object.keys(props.items).length === 0;
|
|
133
|
+
});
|
|
134
|
+
</script>
|
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-card width="100%">
|
|
3
|
+
<v-toolbar>
|
|
4
|
+
<v-row no-gutters class="fill-height px-6" align="center">
|
|
5
|
+
<span class="font-weight-bold text-h5 text-capitalize">
|
|
6
|
+
{{ localProps.title }}
|
|
7
|
+
</span>
|
|
8
|
+
</v-row>
|
|
9
|
+
</v-toolbar>
|
|
10
|
+
|
|
11
|
+
<v-card-text style="max-height: 100vh; overflow-y: auto">
|
|
12
|
+
<v-form v-model="valid">
|
|
13
|
+
<v-row no-gutters>
|
|
14
|
+
<v-col v-if="isOrg" cols="12" class="mb-1">
|
|
15
|
+
<v-row no-gutters>
|
|
16
|
+
<InputLabel
|
|
17
|
+
class="text-capitalize"
|
|
18
|
+
title="App"
|
|
19
|
+
:required="isMutable"
|
|
20
|
+
/>
|
|
21
|
+
<v-col cols="12">
|
|
22
|
+
<v-select
|
|
23
|
+
v-model="role.app"
|
|
24
|
+
:items="apps"
|
|
25
|
+
item-title="name"
|
|
26
|
+
item-value="code"
|
|
27
|
+
:readonly="!isMutable"
|
|
28
|
+
:loading="loadingApps"
|
|
29
|
+
></v-select>
|
|
30
|
+
</v-col>
|
|
31
|
+
</v-row>
|
|
32
|
+
</v-col>
|
|
33
|
+
|
|
34
|
+
<v-col cols="12" class="mb-1">
|
|
35
|
+
<v-row no-gutters>
|
|
36
|
+
<InputLabel
|
|
37
|
+
class="text-capitalize"
|
|
38
|
+
title="Name"
|
|
39
|
+
:required="isMutable"
|
|
40
|
+
/>
|
|
41
|
+
<v-col cols="12">
|
|
42
|
+
<v-text-field
|
|
43
|
+
v-model="role.name"
|
|
44
|
+
:rules="isMutable ? [requiredRule] : []"
|
|
45
|
+
:readonly="!isMutable"
|
|
46
|
+
></v-text-field>
|
|
47
|
+
</v-col>
|
|
48
|
+
</v-row>
|
|
49
|
+
</v-col>
|
|
50
|
+
|
|
51
|
+
<v-col cols="12" class="mb-1">
|
|
52
|
+
<v-row no-gutters>
|
|
53
|
+
<InputLabel
|
|
54
|
+
class="text-capitalize"
|
|
55
|
+
title="Permissions"
|
|
56
|
+
:required="isMutable"
|
|
57
|
+
/>
|
|
58
|
+
<v-col cols="12">
|
|
59
|
+
<ListGroupSelection
|
|
60
|
+
v-model="role.permissions"
|
|
61
|
+
:items="permissions"
|
|
62
|
+
:readonly="!isMutable"
|
|
63
|
+
variant="outlined"
|
|
64
|
+
border="thin"
|
|
65
|
+
:loading="loadingPermissions"
|
|
66
|
+
/>
|
|
67
|
+
<v-input
|
|
68
|
+
:messages="errorPermissionSelection"
|
|
69
|
+
:error="!!errorPermissionSelection"
|
|
70
|
+
></v-input>
|
|
71
|
+
</v-col>
|
|
72
|
+
</v-row>
|
|
73
|
+
</v-col>
|
|
74
|
+
|
|
75
|
+
<v-col cols="12" class="mb-1">
|
|
76
|
+
<v-row no-gutters>
|
|
77
|
+
<InputLabel class="text-capitalize" title="Description" />
|
|
78
|
+
<v-col cols="12">
|
|
79
|
+
<v-textarea
|
|
80
|
+
v-model="role.description"
|
|
81
|
+
rows="2"
|
|
82
|
+
no-resize
|
|
83
|
+
:readonly="!isMutable"
|
|
84
|
+
></v-textarea>
|
|
85
|
+
</v-col>
|
|
86
|
+
</v-row>
|
|
87
|
+
</v-col>
|
|
88
|
+
</v-row>
|
|
89
|
+
</v-form>
|
|
90
|
+
|
|
91
|
+
<v-alert
|
|
92
|
+
v-if="message"
|
|
93
|
+
type="error"
|
|
94
|
+
variant="flat"
|
|
95
|
+
closable
|
|
96
|
+
position="absolute"
|
|
97
|
+
location="bottom"
|
|
98
|
+
style="bottom: 48px"
|
|
99
|
+
@click:close="message = ''"
|
|
100
|
+
width="100%"
|
|
101
|
+
tile
|
|
102
|
+
class="text-caption"
|
|
103
|
+
>
|
|
104
|
+
{{ message }}
|
|
105
|
+
</v-alert>
|
|
106
|
+
</v-card-text>
|
|
107
|
+
|
|
108
|
+
<v-toolbar density="compact">
|
|
109
|
+
<v-row no-gutters>
|
|
110
|
+
<v-col v-if="isMutable" cols="6">
|
|
111
|
+
<v-btn
|
|
112
|
+
tile
|
|
113
|
+
block
|
|
114
|
+
variant="text"
|
|
115
|
+
class="text-none"
|
|
116
|
+
size="48"
|
|
117
|
+
@click="emits('cancel')"
|
|
118
|
+
>
|
|
119
|
+
Cancel
|
|
120
|
+
</v-btn>
|
|
121
|
+
</v-col>
|
|
122
|
+
|
|
123
|
+
<v-col v-if="localProps.mode === 'view'" cols="6">
|
|
124
|
+
<v-btn
|
|
125
|
+
tile
|
|
126
|
+
block
|
|
127
|
+
variant="text"
|
|
128
|
+
class="text-none"
|
|
129
|
+
size="48"
|
|
130
|
+
@click="emits('close')"
|
|
131
|
+
>
|
|
132
|
+
Close
|
|
133
|
+
</v-btn>
|
|
134
|
+
</v-col>
|
|
135
|
+
|
|
136
|
+
<v-col v-if="localProps.mode === 'view'" cols="6">
|
|
137
|
+
<v-menu>
|
|
138
|
+
<template #activator="{ props }">
|
|
139
|
+
<v-btn
|
|
140
|
+
block
|
|
141
|
+
variant="flat"
|
|
142
|
+
color="black"
|
|
143
|
+
class="text-none"
|
|
144
|
+
height="48"
|
|
145
|
+
v-bind="props"
|
|
146
|
+
tile
|
|
147
|
+
>
|
|
148
|
+
More actions
|
|
149
|
+
</v-btn>
|
|
150
|
+
</template>
|
|
151
|
+
|
|
152
|
+
<v-list class="pa-0">
|
|
153
|
+
<v-list-item @click="emits('edit')">
|
|
154
|
+
<v-list-item-title class="text-subtitle-2">
|
|
155
|
+
Edit Role
|
|
156
|
+
</v-list-item-title>
|
|
157
|
+
</v-list-item>
|
|
158
|
+
|
|
159
|
+
<v-list-item @click="emits('delete')" class="text-red">
|
|
160
|
+
<v-list-item-title class="text-subtitle-2">
|
|
161
|
+
Delete Role
|
|
162
|
+
</v-list-item-title>
|
|
163
|
+
</v-list-item>
|
|
164
|
+
</v-list>
|
|
165
|
+
</v-menu>
|
|
166
|
+
</v-col>
|
|
167
|
+
|
|
168
|
+
<v-col v-if="isMutable" cols="6">
|
|
169
|
+
<v-btn
|
|
170
|
+
tile
|
|
171
|
+
block
|
|
172
|
+
variant="flat"
|
|
173
|
+
color="black"
|
|
174
|
+
class="text-none"
|
|
175
|
+
size="48"
|
|
176
|
+
@click="emits('submit')"
|
|
177
|
+
:disabled="!valid"
|
|
178
|
+
>
|
|
179
|
+
{{ localProps.mode === "add" ? "Add Role" : "Save Changes" }}
|
|
180
|
+
</v-btn>
|
|
181
|
+
</v-col>
|
|
182
|
+
</v-row>
|
|
183
|
+
</v-toolbar>
|
|
184
|
+
</v-card>
|
|
185
|
+
</template>
|
|
186
|
+
|
|
187
|
+
<script setup lang="ts">
|
|
188
|
+
const emits = defineEmits(["submit", "cancel", "close", "edit", "delete"]);
|
|
189
|
+
|
|
190
|
+
const isMutable = computed(() => ["add", "edit"].includes(localProps.mode));
|
|
191
|
+
|
|
192
|
+
const localProps = defineProps({
|
|
193
|
+
title: {
|
|
194
|
+
type: String,
|
|
195
|
+
default: "Role Form",
|
|
196
|
+
},
|
|
197
|
+
app: {
|
|
198
|
+
type: String,
|
|
199
|
+
default: "",
|
|
200
|
+
},
|
|
201
|
+
mode: {
|
|
202
|
+
type: String,
|
|
203
|
+
default: "add",
|
|
204
|
+
},
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
const role = defineModel<TRole>({
|
|
208
|
+
default: () => useRole().role.value,
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
const errorPermissionSelection = computed(() =>
|
|
212
|
+
requireListRule(role.value.permissions ?? [])
|
|
213
|
+
);
|
|
214
|
+
|
|
215
|
+
const message = defineModel("message", { default: "" });
|
|
216
|
+
|
|
217
|
+
const valid = ref(false);
|
|
218
|
+
|
|
219
|
+
const { requiredRule, requireListRule } = useUtils();
|
|
220
|
+
|
|
221
|
+
const apps = ref<TApp[]>([]);
|
|
222
|
+
|
|
223
|
+
const { getAll: getAllApps } = useApps();
|
|
224
|
+
|
|
225
|
+
const isOrg = computed(() => localProps.app === "org");
|
|
226
|
+
|
|
227
|
+
const {
|
|
228
|
+
data: appsData,
|
|
229
|
+
status: appsReqStatus,
|
|
230
|
+
refresh: refreshApps,
|
|
231
|
+
} = await useLazyAsyncData(
|
|
232
|
+
`role-form-get-apps-${localProps.app}`,
|
|
233
|
+
() =>
|
|
234
|
+
getAllApps({
|
|
235
|
+
limit: 20,
|
|
236
|
+
}),
|
|
237
|
+
{
|
|
238
|
+
immediate: isOrg.value,
|
|
239
|
+
}
|
|
240
|
+
);
|
|
241
|
+
|
|
242
|
+
const loadingApps = computed(() => appsReqStatus.value === "pending");
|
|
243
|
+
|
|
244
|
+
watchEffect(() => {
|
|
245
|
+
if (appsData.value) {
|
|
246
|
+
apps.value = appsData.value.items;
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
type PermChild = {
|
|
251
|
+
title: string;
|
|
252
|
+
key: string;
|
|
253
|
+
description: string;
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
type PermGroup = {
|
|
257
|
+
title: string;
|
|
258
|
+
key: string;
|
|
259
|
+
children: PermChild[];
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
const permissions = ref<PermGroup[]>([]);
|
|
263
|
+
|
|
264
|
+
const { getAllPerm } = usePermission();
|
|
265
|
+
|
|
266
|
+
const {
|
|
267
|
+
data: permissionsData,
|
|
268
|
+
status: permissionsReqStatus,
|
|
269
|
+
refresh: refreshPermissions,
|
|
270
|
+
} = await useLazyAsyncData(
|
|
271
|
+
`role-form-get-all-permission-${role.value.app}`,
|
|
272
|
+
() =>
|
|
273
|
+
getAllPerm({
|
|
274
|
+
app: role.value.app,
|
|
275
|
+
limit: 200,
|
|
276
|
+
}),
|
|
277
|
+
{
|
|
278
|
+
watch: [() => role.value.app],
|
|
279
|
+
}
|
|
280
|
+
);
|
|
281
|
+
|
|
282
|
+
const loadingPermissions = computed(
|
|
283
|
+
() => permissionsReqStatus.value === "pending"
|
|
284
|
+
);
|
|
285
|
+
|
|
286
|
+
function groupPermissions(permissions: TPerm[]): PermGroup[] {
|
|
287
|
+
const groups: Record<string, PermGroup> = {};
|
|
288
|
+
|
|
289
|
+
for (const perm of permissions) {
|
|
290
|
+
if (perm.status !== "active") continue;
|
|
291
|
+
|
|
292
|
+
const groupKey = perm.group;
|
|
293
|
+
|
|
294
|
+
if (!groups[groupKey]) {
|
|
295
|
+
groups[groupKey] = {
|
|
296
|
+
title: groupKey,
|
|
297
|
+
key: groupKey,
|
|
298
|
+
children: [],
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
groups[groupKey].children.push({
|
|
303
|
+
title: perm.name,
|
|
304
|
+
key: perm.key,
|
|
305
|
+
description: perm.description,
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
return Object.values(groups);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
watchEffect(() => {
|
|
313
|
+
if (
|
|
314
|
+
permissionsData.value &&
|
|
315
|
+
permissionsData.value &&
|
|
316
|
+
permissionsData.value.items
|
|
317
|
+
) {
|
|
318
|
+
let items = permissionsData.value.items;
|
|
319
|
+
if (localProps.mode === "view") {
|
|
320
|
+
items = permissionsData.value.items.filter((p: TPerm) =>
|
|
321
|
+
role.value.permissions?.includes(p.key)
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
permissions.value = groupPermissions(items);
|
|
325
|
+
}
|
|
326
|
+
});
|
|
327
|
+
</script>
|
|
@@ -6,11 +6,11 @@
|
|
|
6
6
|
class="text-none"
|
|
7
7
|
rounded="pill"
|
|
8
8
|
variant="tonal"
|
|
9
|
-
@click="
|
|
9
|
+
@click="setRole({ mode: 'add', dialog: true })"
|
|
10
10
|
size="large"
|
|
11
11
|
v-if="canCreateRole"
|
|
12
12
|
>
|
|
13
|
-
|
|
13
|
+
Add Role
|
|
14
14
|
</v-btn>
|
|
15
15
|
</v-row>
|
|
16
16
|
</v-col>
|
|
@@ -60,98 +60,66 @@
|
|
|
60
60
|
</span>
|
|
61
61
|
<v-chip>{{ value.length }}</v-chip>
|
|
62
62
|
</template>
|
|
63
|
-
|
|
64
|
-
<template #item.action-table="{ item }" v-if="canDeleteRole">
|
|
65
|
-
<v-menu :close-on-content-click="false" offset-y width="150">
|
|
66
|
-
<template v-slot:activator="{ props }">
|
|
67
|
-
<v-icon v-bind="props">mdi-dots-horizontal</v-icon>
|
|
68
|
-
</template>
|
|
69
|
-
<v-list>
|
|
70
|
-
<v-list-item @click="openDeleteDialog(item._id)">
|
|
71
|
-
Delete Role
|
|
72
|
-
</v-list-item>
|
|
73
|
-
</v-list>
|
|
74
|
-
</v-menu>
|
|
75
|
-
</template>
|
|
76
63
|
</v-data-table>
|
|
77
64
|
</v-card>
|
|
78
65
|
</v-col>
|
|
79
66
|
|
|
80
67
|
<!-- dialogs -->
|
|
81
|
-
<v-dialog v-model="
|
|
82
|
-
<
|
|
83
|
-
|
|
84
|
-
:
|
|
85
|
-
:
|
|
86
|
-
@
|
|
87
|
-
|
|
88
|
-
:types="props.types"
|
|
89
|
-
@success:create-more="getRoles()"
|
|
68
|
+
<v-dialog v-model="dialogAdd" width="500" persistent>
|
|
69
|
+
<RoleForm
|
|
70
|
+
v-model="role"
|
|
71
|
+
v-model:message="message"
|
|
72
|
+
:app="props.app"
|
|
73
|
+
@cancel="setRole({ mode: 'add' })"
|
|
74
|
+
@submit="submitAdd()"
|
|
90
75
|
/>
|
|
91
76
|
</v-dialog>
|
|
92
77
|
|
|
93
|
-
<v-dialog v-model="
|
|
94
|
-
<
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
:id="roleId"
|
|
78
|
+
<v-dialog v-model="dialogPreview" width="500" persistent>
|
|
79
|
+
<RoleForm
|
|
80
|
+
title="Role Details"
|
|
81
|
+
:app="props.app"
|
|
82
|
+
v-model="role"
|
|
83
|
+
@close="setRole({ mode: 'view' })"
|
|
84
|
+
@edit="handOpenEdit()"
|
|
85
|
+
@delete="handleOpenDelete()"
|
|
86
|
+
mode="view"
|
|
103
87
|
/>
|
|
104
88
|
</v-dialog>
|
|
105
89
|
|
|
106
|
-
<
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
<p class="text-subtitle-2">
|
|
117
|
-
Are you sure you want to delete this role? This action cannot be
|
|
118
|
-
undone.
|
|
119
|
-
</p>
|
|
120
|
-
</template>
|
|
121
|
-
|
|
122
|
-
<template #footer>
|
|
123
|
-
<v-btn
|
|
124
|
-
variant="text"
|
|
125
|
-
@click="confirmDialog = false"
|
|
126
|
-
:disabled="deleteLoading"
|
|
127
|
-
>
|
|
128
|
-
Close
|
|
129
|
-
</v-btn>
|
|
130
|
-
<v-btn
|
|
131
|
-
color="primary"
|
|
132
|
-
variant="flat"
|
|
133
|
-
@click="handleDeleteRole"
|
|
134
|
-
:loading="deleteLoading"
|
|
135
|
-
>
|
|
136
|
-
Delete Role
|
|
137
|
-
</v-btn>
|
|
138
|
-
</template>
|
|
139
|
-
</ConfirmDialog>
|
|
90
|
+
<v-dialog v-model="dialogEdit" width="500" persistent>
|
|
91
|
+
<RoleForm
|
|
92
|
+
title="Edit Role Details"
|
|
93
|
+
:app="props.app"
|
|
94
|
+
v-model="role"
|
|
95
|
+
@cancel="setRole({ mode: 'edit' })"
|
|
96
|
+
@submit="submitEdit()"
|
|
97
|
+
mode="edit"
|
|
98
|
+
/>
|
|
99
|
+
</v-dialog>
|
|
140
100
|
|
|
141
|
-
<
|
|
101
|
+
<v-dialog v-model="dialogDelete" width="450" persistent>
|
|
102
|
+
<ConfirmationPrompt
|
|
103
|
+
title="Delete Role"
|
|
104
|
+
action="Delete Role"
|
|
105
|
+
content="Are you sure you want to delete this role? This action cannot be undone."
|
|
106
|
+
@cancel="setRole({ mode: 'delete' })"
|
|
107
|
+
@confirm="submitDelete()"
|
|
108
|
+
v-model:message="message"
|
|
109
|
+
/>
|
|
110
|
+
</v-dialog>
|
|
142
111
|
</v-row>
|
|
143
112
|
</template>
|
|
144
113
|
|
|
145
114
|
<script setup lang="ts">
|
|
146
115
|
const props = defineProps({
|
|
147
|
-
|
|
116
|
+
app: {
|
|
148
117
|
type: String,
|
|
149
118
|
default: "",
|
|
150
119
|
},
|
|
151
|
-
|
|
152
|
-
type:
|
|
153
|
-
|
|
154
|
-
default: () => ({}),
|
|
120
|
+
org: {
|
|
121
|
+
type: String,
|
|
122
|
+
default: "",
|
|
155
123
|
},
|
|
156
124
|
types: {
|
|
157
125
|
type: Array as PropType<Array<{ title: string; value: string }>>,
|
|
@@ -168,7 +136,7 @@ const props = defineProps({
|
|
|
168
136
|
title: "permissions",
|
|
169
137
|
value: "permissions",
|
|
170
138
|
},
|
|
171
|
-
{ title: "
|
|
139
|
+
{ title: "App", value: "app" },
|
|
172
140
|
],
|
|
173
141
|
},
|
|
174
142
|
canCreateRole: {
|
|
@@ -193,40 +161,75 @@ const props = defineProps({
|
|
|
193
161
|
},
|
|
194
162
|
});
|
|
195
163
|
|
|
196
|
-
const type = defineModel<string>("type", {
|
|
197
|
-
type: String,
|
|
198
|
-
default: "",
|
|
199
|
-
});
|
|
200
|
-
|
|
201
164
|
const { headerSearch } = useLocal();
|
|
202
165
|
|
|
203
|
-
const {
|
|
166
|
+
const {
|
|
167
|
+
role,
|
|
168
|
+
add: addRole,
|
|
169
|
+
getAll: _getRoles,
|
|
170
|
+
updateById,
|
|
171
|
+
deleteById,
|
|
172
|
+
} = useRole();
|
|
204
173
|
|
|
205
174
|
const page = ref(1);
|
|
206
175
|
const pages = ref(0);
|
|
207
176
|
const pageRange = ref("-- - -- of --");
|
|
177
|
+
const modeRole = ref("");
|
|
208
178
|
|
|
209
179
|
const message = ref("");
|
|
210
|
-
|
|
211
|
-
|
|
180
|
+
|
|
181
|
+
function setRole({
|
|
182
|
+
mode = "",
|
|
183
|
+
dialog = false,
|
|
184
|
+
data = useRole().role.value,
|
|
185
|
+
} = {}) {
|
|
186
|
+
Object.assign(
|
|
187
|
+
role.value,
|
|
188
|
+
JSON.parse(
|
|
189
|
+
JSON.stringify({
|
|
190
|
+
...data,
|
|
191
|
+
app: mode === "admin" || mode === "add" ? props.app : data.app,
|
|
192
|
+
})
|
|
193
|
+
)
|
|
194
|
+
);
|
|
195
|
+
modeRole.value = mode;
|
|
196
|
+
message.value = "";
|
|
197
|
+
|
|
198
|
+
if (modeRole.value === "add") {
|
|
199
|
+
dialogAdd.value = dialog;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (modeRole.value === "view") {
|
|
203
|
+
dialogPreview.value = dialog;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if (modeRole.value === "edit") {
|
|
207
|
+
dialogEdit.value = dialog;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if (modeRole.value === "delete") {
|
|
211
|
+
dialogDelete.value = dialog;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
212
214
|
|
|
213
215
|
const items = ref<Array<Record<string, any>>>([]);
|
|
214
216
|
|
|
217
|
+
const isOrg = computed(() => props.app === "org");
|
|
218
|
+
|
|
215
219
|
const {
|
|
216
220
|
data: getRoleReq,
|
|
217
221
|
refresh: getRoles,
|
|
218
222
|
status: getRoleReqStatus,
|
|
219
223
|
} = useLazyAsyncData(
|
|
220
|
-
|
|
224
|
+
`roles-permissions-get-all-by-${props.app}-${props.org}-page-${page.value}`,
|
|
221
225
|
() =>
|
|
222
226
|
_getRoles({
|
|
223
227
|
page: page.value,
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
id: props.id,
|
|
228
|
+
org: props.org,
|
|
229
|
+
app: isOrg.value ? "" : props.app,
|
|
227
230
|
}),
|
|
228
231
|
{
|
|
229
|
-
watch: [page
|
|
232
|
+
watch: [page],
|
|
230
233
|
}
|
|
231
234
|
);
|
|
232
235
|
|
|
@@ -241,135 +244,64 @@ watchEffect(() => {
|
|
|
241
244
|
});
|
|
242
245
|
|
|
243
246
|
function tableRowClickHandler(_: any, data: any) {
|
|
244
|
-
|
|
245
|
-
roleId.value = data.item._id;
|
|
247
|
+
setRole({ data: data.item, mode: "view", dialog: true });
|
|
246
248
|
}
|
|
247
249
|
|
|
248
|
-
const
|
|
249
|
-
|
|
250
|
-
function success() {
|
|
251
|
-
createDialog.value = false;
|
|
252
|
-
type.value = "";
|
|
253
|
-
getRoles();
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
const previewDialog = ref(false);
|
|
257
|
-
|
|
258
|
-
const name = ref("");
|
|
259
|
-
const selectedPermissions = ref<Array<string>>([]);
|
|
260
|
-
const originalPermissions = ref<Array<string>>([]);
|
|
261
|
-
const edit = ref(false);
|
|
250
|
+
const dialogAdd = ref(false);
|
|
262
251
|
|
|
263
|
-
|
|
264
|
-
if (!edit.value) {
|
|
265
|
-
selectedPermissions.value = originalPermissions.value;
|
|
266
|
-
}
|
|
267
|
-
});
|
|
252
|
+
const dialogPreview = ref(false);
|
|
268
253
|
|
|
269
|
-
const
|
|
254
|
+
const { loggedInUser } = useLocalAuth();
|
|
270
255
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
})
|
|
283
|
-
|
|
284
|
-
watchEffect(() => {
|
|
285
|
-
if (role.value) {
|
|
286
|
-
name.value = role.value.name as any;
|
|
287
|
-
|
|
288
|
-
selectedPermissions.value = role.value.permissions as any;
|
|
289
|
-
originalPermissions.value = role.value.permissions as any;
|
|
256
|
+
async function submitAdd() {
|
|
257
|
+
try {
|
|
258
|
+
await addRole({
|
|
259
|
+
name: role.value.name,
|
|
260
|
+
permissions: role.value.permissions,
|
|
261
|
+
app: role.value.app,
|
|
262
|
+
org: props.org,
|
|
263
|
+
createdBy: loggedInUser(),
|
|
264
|
+
});
|
|
265
|
+
setRole({ mode: "add" });
|
|
266
|
+
getRoles();
|
|
267
|
+
} catch (error: any) {
|
|
268
|
+
message.value = error.response._data.message;
|
|
290
269
|
}
|
|
291
|
-
});
|
|
292
|
-
|
|
293
|
-
function filterPermissions(
|
|
294
|
-
allPermissions: TPermissions,
|
|
295
|
-
storedPermissions: string[]
|
|
296
|
-
) {
|
|
297
|
-
const filteredPermissions: TPermissions = {};
|
|
298
|
-
|
|
299
|
-
Object.entries(allPermissions).forEach(([resource, actions]) => {
|
|
300
|
-
const filteredActions = Object.entries(actions)
|
|
301
|
-
.filter(([action]) => storedPermissions.includes(`${resource}:${action}`))
|
|
302
|
-
.reduce((acc: Record<string, any>, [action, data]) => {
|
|
303
|
-
acc[action] = data;
|
|
304
|
-
return acc;
|
|
305
|
-
}, {});
|
|
306
|
-
|
|
307
|
-
if (Object.keys(filteredActions).length > 0) {
|
|
308
|
-
filteredPermissions[resource] = filteredActions;
|
|
309
|
-
}
|
|
310
|
-
});
|
|
311
|
-
|
|
312
|
-
return filteredPermissions;
|
|
313
270
|
}
|
|
314
271
|
|
|
315
|
-
const
|
|
316
|
-
const
|
|
317
|
-
|
|
318
|
-
const permissions = computed(() => {
|
|
319
|
-
if (role.value?.type === "organization") {
|
|
320
|
-
return orgPermissions;
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
if (role.value?.type === "school") {
|
|
324
|
-
return schoolPermissions;
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
return {};
|
|
328
|
-
});
|
|
329
|
-
|
|
330
|
-
const Permissions = computed(() => {
|
|
331
|
-
return edit.value
|
|
332
|
-
? permissions.value
|
|
333
|
-
: filterPermissions(permissions.value, selectedPermissions.value);
|
|
334
|
-
});
|
|
272
|
+
const dialogEdit = ref(false);
|
|
273
|
+
const dialogDelete = ref(false);
|
|
335
274
|
|
|
336
|
-
function
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
getRoleById();
|
|
340
|
-
edit.value = false;
|
|
275
|
+
function handOpenEdit() {
|
|
276
|
+
dialogPreview.value = false;
|
|
277
|
+
dialogEdit.value = true;
|
|
341
278
|
}
|
|
342
279
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
280
|
+
async function submitEdit() {
|
|
281
|
+
try {
|
|
282
|
+
await updateById(role.value._id ?? "", {
|
|
283
|
+
name: role.value.name,
|
|
284
|
+
permissions: role.value.permissions,
|
|
285
|
+
});
|
|
286
|
+
await setRole({ mode: "edit" });
|
|
287
|
+
await getRoles();
|
|
288
|
+
} catch (error: any) {
|
|
289
|
+
message.value = error.response._data.message;
|
|
290
|
+
}
|
|
350
291
|
}
|
|
351
292
|
|
|
352
|
-
function
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
messageSnackbar.value = true;
|
|
293
|
+
function handleOpenDelete() {
|
|
294
|
+
dialogPreview.value = false;
|
|
295
|
+
dialogDelete.value = true;
|
|
356
296
|
}
|
|
357
297
|
|
|
358
|
-
async function
|
|
359
|
-
if (!selectedRoleId.value) return;
|
|
360
|
-
deleteLoading.value = true;
|
|
298
|
+
async function submitDelete() {
|
|
361
299
|
try {
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
confirmDialog.value = false;
|
|
365
|
-
showMessage(res.message, "success");
|
|
300
|
+
await deleteById(role.value._id ?? "");
|
|
301
|
+
dialogDelete.value = false;
|
|
366
302
|
getRoles();
|
|
367
303
|
} catch (error: any) {
|
|
368
|
-
|
|
369
|
-
showMessage(errorMessage, "error");
|
|
370
|
-
} finally {
|
|
371
|
-
deleteLoading.value = false;
|
|
372
|
-
selectedRoleId.value = null;
|
|
304
|
+
message.value = error.response._data.message;
|
|
373
305
|
}
|
|
374
306
|
}
|
|
375
307
|
</script>
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
export default function useApps() {
|
|
2
|
+
const app = ref<TApp>({
|
|
3
|
+
_id: "",
|
|
4
|
+
code: "",
|
|
5
|
+
name: "",
|
|
6
|
+
description: "",
|
|
7
|
+
status: "active",
|
|
8
|
+
createdAt: "",
|
|
9
|
+
updatedAt: "",
|
|
10
|
+
deletedAt: "",
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
const resource = "/api/apps";
|
|
14
|
+
|
|
15
|
+
function add(value: TApp) {
|
|
16
|
+
return useNuxtApp().$api(resource, {
|
|
17
|
+
method: "POST",
|
|
18
|
+
body: value,
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function getAll({
|
|
23
|
+
page = 1,
|
|
24
|
+
limit = 10,
|
|
25
|
+
search = "",
|
|
26
|
+
status = "active",
|
|
27
|
+
type = "standard",
|
|
28
|
+
} = {}) {
|
|
29
|
+
return useNuxtApp().$api<Record<string, any>>(resource, {
|
|
30
|
+
method: "GET",
|
|
31
|
+
query: { page, limit, search, status, type },
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function updateById(
|
|
36
|
+
id: string,
|
|
37
|
+
value: { name: string; description: string }
|
|
38
|
+
) {
|
|
39
|
+
return useNuxtApp().$api(`${resource}/id/${id}`, {
|
|
40
|
+
method: "PATCH",
|
|
41
|
+
body: value,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function deleteById(id: string) {
|
|
46
|
+
return useNuxtApp().$api(`${resource}/id/${id}`, {
|
|
47
|
+
method: "DELETE",
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
app,
|
|
53
|
+
add,
|
|
54
|
+
getAll,
|
|
55
|
+
updateById,
|
|
56
|
+
deleteById,
|
|
57
|
+
};
|
|
58
|
+
}
|
package/composables/useLocal.ts
CHANGED
|
@@ -2,6 +2,18 @@ export default function useLocalAuth() {
|
|
|
2
2
|
const { cookieConfig } = useRuntimeConfig().public;
|
|
3
3
|
|
|
4
4
|
const currentUser = useState<TUser | null>("currentUser", () => null);
|
|
5
|
+
const permissions = useState<string[]>("permissions", () => []);
|
|
6
|
+
|
|
7
|
+
const hasPermission = (permissionKey: string): ComputedRef<boolean> => {
|
|
8
|
+
return computed(() => {
|
|
9
|
+
if (!permissions.value.length) return false;
|
|
10
|
+
return permissions.value.some((perm) => perm === permissionKey);
|
|
11
|
+
});
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
function loggedInUser() {
|
|
15
|
+
return useCookie("user", cookieConfig).value ?? "";
|
|
16
|
+
}
|
|
5
17
|
|
|
6
18
|
function authenticate() {
|
|
7
19
|
if (currentUser.value) {
|
|
@@ -128,6 +140,9 @@ export default function useLocalAuth() {
|
|
|
128
140
|
}
|
|
129
141
|
|
|
130
142
|
return {
|
|
143
|
+
loggedInUser,
|
|
144
|
+
permissions,
|
|
145
|
+
hasPermission,
|
|
131
146
|
authenticate,
|
|
132
147
|
login,
|
|
133
148
|
setSession,
|
|
@@ -47,8 +47,105 @@ export default function usePermission() {
|
|
|
47
47
|
return false;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
const perm = ref<TPerm>({
|
|
51
|
+
app: "",
|
|
52
|
+
key: "",
|
|
53
|
+
name: "",
|
|
54
|
+
group: "",
|
|
55
|
+
description: "",
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
function addPerm(value: TPerm) {
|
|
59
|
+
return useNuxtApp().$api("/api/permissions", {
|
|
60
|
+
method: "POST",
|
|
61
|
+
body: value,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function updatePermById(
|
|
66
|
+
id: string,
|
|
67
|
+
value: Pick<TPerm, "key" | "name" | "group" | "description">
|
|
68
|
+
) {
|
|
69
|
+
return useNuxtApp().$api(`/api/permissions/id/${id}`, {
|
|
70
|
+
method: "PATCH",
|
|
71
|
+
body: value,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function getAllPerm({
|
|
76
|
+
page = 1,
|
|
77
|
+
limit = 10,
|
|
78
|
+
search = "",
|
|
79
|
+
app = "",
|
|
80
|
+
status = "active",
|
|
81
|
+
} = {}) {
|
|
82
|
+
return useNuxtApp().$api<Record<string, any>>("/api/permissions", {
|
|
83
|
+
method: "GET",
|
|
84
|
+
query: { page, limit, search, app, status },
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function deletePermById(id: string) {
|
|
89
|
+
return useNuxtApp().$api(`/api/permissions/id/${id}`, {
|
|
90
|
+
method: "DELETE",
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const permGroup = ref<TPermGroup>({
|
|
95
|
+
app: "",
|
|
96
|
+
key: "",
|
|
97
|
+
label: "",
|
|
98
|
+
order: 0,
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
function addPermGroup(value: Pick<TPermGroup, "app" | "key" | "label">) {
|
|
102
|
+
return useNuxtApp().$api("/api/permissions/groups", {
|
|
103
|
+
method: "POST",
|
|
104
|
+
body: value,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function updatePermGroupById(
|
|
109
|
+
id: string,
|
|
110
|
+
value: Pick<TPermGroup, "key" | "label">
|
|
111
|
+
) {
|
|
112
|
+
return useNuxtApp().$api(`/api/permissions/groups/id/${id}`, {
|
|
113
|
+
method: "PATCH",
|
|
114
|
+
body: value,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function getAllPermGroup({
|
|
119
|
+
page = 1,
|
|
120
|
+
limit = 10,
|
|
121
|
+
search = "",
|
|
122
|
+
app = "",
|
|
123
|
+
status = "active",
|
|
124
|
+
} = {}) {
|
|
125
|
+
return useNuxtApp().$api<Record<string, any>>("/api/permissions/groups", {
|
|
126
|
+
method: "GET",
|
|
127
|
+
query: { page, limit, search, app, status },
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function deletePermGroupById(id: string) {
|
|
132
|
+
return useNuxtApp().$api(`/api/permissions/groups/id/${id}`, {
|
|
133
|
+
method: "DELETE",
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
50
137
|
return {
|
|
51
138
|
listPermissions,
|
|
52
139
|
hasPermission,
|
|
140
|
+
perm,
|
|
141
|
+
addPerm,
|
|
142
|
+
updatePermById,
|
|
143
|
+
getAllPerm,
|
|
144
|
+
deletePermById,
|
|
145
|
+
permGroup,
|
|
146
|
+
addPermGroup,
|
|
147
|
+
updatePermGroupById,
|
|
148
|
+
getAllPermGroup,
|
|
149
|
+
deletePermGroupById,
|
|
53
150
|
};
|
|
54
151
|
}
|
package/composables/useRole.ts
CHANGED
|
@@ -1,44 +1,36 @@
|
|
|
1
1
|
export default function useRole() {
|
|
2
|
-
function
|
|
3
|
-
|
|
4
|
-
name: string;
|
|
5
|
-
permissions: Array<string>;
|
|
6
|
-
type: string;
|
|
7
|
-
}
|
|
2
|
+
function add(
|
|
3
|
+
value: Pick<TRole, "name" | "permissions" | "app" | "org" | "createdBy">
|
|
8
4
|
) {
|
|
9
5
|
return useNuxtApp().$api("/api/roles", {
|
|
10
6
|
method: "POST",
|
|
11
|
-
body:
|
|
7
|
+
body: value,
|
|
12
8
|
});
|
|
13
9
|
}
|
|
14
10
|
|
|
15
|
-
function
|
|
11
|
+
function getAll({
|
|
16
12
|
search = "",
|
|
17
13
|
page = 1,
|
|
18
14
|
limit = 20,
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
app = "",
|
|
16
|
+
org = "",
|
|
21
17
|
} = {}) {
|
|
22
18
|
return useNuxtApp().$api<Record<string, any>>("/api/roles", {
|
|
23
19
|
method: "GET",
|
|
24
|
-
query: { search, page, limit,
|
|
20
|
+
query: { search, page, limit, app, org },
|
|
25
21
|
});
|
|
26
22
|
}
|
|
27
23
|
|
|
28
|
-
function
|
|
29
|
-
return useNuxtApp().$api<
|
|
24
|
+
function getById(id: string) {
|
|
25
|
+
return useNuxtApp().$api<Record<string, any>>(`/api/roles/id/${id}`, {
|
|
30
26
|
method: "GET",
|
|
31
27
|
});
|
|
32
28
|
}
|
|
33
29
|
|
|
34
|
-
function
|
|
35
|
-
|
|
36
|
-
name?: string,
|
|
37
|
-
permissions?: Array<string>
|
|
38
|
-
) {
|
|
39
|
-
return useNuxtApp().$api(`/api/roles/id/${_id}`, {
|
|
30
|
+
function updateById(id: string, value: Pick<TRole, "name" | "permissions">) {
|
|
31
|
+
return useNuxtApp().$api(`/api/roles/id/${id}`, {
|
|
40
32
|
method: "PATCH",
|
|
41
|
-
body:
|
|
33
|
+
body: value,
|
|
42
34
|
});
|
|
43
35
|
}
|
|
44
36
|
|
|
@@ -56,33 +48,28 @@ export default function useRole() {
|
|
|
56
48
|
});
|
|
57
49
|
}
|
|
58
50
|
|
|
59
|
-
function
|
|
51
|
+
function deleteById(_id: string) {
|
|
60
52
|
return useNuxtApp().$api<Record<string, any>>(`/api/roles/${_id}`, {
|
|
61
53
|
method: "DELETE",
|
|
62
54
|
});
|
|
63
55
|
}
|
|
64
56
|
|
|
65
|
-
const role =
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
createdAt: "",
|
|
72
|
-
updatedAt: "",
|
|
73
|
-
deletedAt: "",
|
|
74
|
-
default: false,
|
|
75
|
-
};
|
|
57
|
+
const role = ref<TRole>({
|
|
58
|
+
name: "",
|
|
59
|
+
org: "",
|
|
60
|
+
permissions: [],
|
|
61
|
+
app: "",
|
|
62
|
+
description: "",
|
|
76
63
|
});
|
|
77
64
|
|
|
78
65
|
return {
|
|
79
66
|
role,
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
67
|
+
add,
|
|
68
|
+
getAll,
|
|
69
|
+
getById,
|
|
70
|
+
updateById,
|
|
84
71
|
updateRoleFieldById,
|
|
85
|
-
|
|
72
|
+
deleteById,
|
|
86
73
|
updatePermissionById,
|
|
87
74
|
};
|
|
88
75
|
}
|
package/package.json
CHANGED
package/types/local.d.ts
CHANGED
|
@@ -19,8 +19,12 @@ declare type TNavigationItem = {
|
|
|
19
19
|
};
|
|
20
20
|
|
|
21
21
|
declare type TApp = {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
_id?: string;
|
|
23
|
+
code: string;
|
|
24
|
+
name: string;
|
|
25
|
+
description: string;
|
|
26
|
+
status?: string;
|
|
27
|
+
createdAt?: string | Date;
|
|
28
|
+
updatedAt?: string | Date;
|
|
29
|
+
deletedAt?: string | Date;
|
|
26
30
|
};
|
package/types/permission.d.ts
CHANGED
|
@@ -12,3 +12,27 @@ declare type TPermissions = {
|
|
|
12
12
|
[action: string]: TPermission;
|
|
13
13
|
};
|
|
14
14
|
};
|
|
15
|
+
|
|
16
|
+
declare type TPerm = {
|
|
17
|
+
_id?: string;
|
|
18
|
+
app: string;
|
|
19
|
+
name: string;
|
|
20
|
+
key: string;
|
|
21
|
+
group: string;
|
|
22
|
+
description: string;
|
|
23
|
+
status?: string;
|
|
24
|
+
createdAt?: string | Date;
|
|
25
|
+
updatedAt?: string | Date;
|
|
26
|
+
deletedAt?: string | Date;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
declare type TPermGroup = {
|
|
30
|
+
_id?: string;
|
|
31
|
+
app: string;
|
|
32
|
+
key: string;
|
|
33
|
+
label: string;
|
|
34
|
+
order: number;
|
|
35
|
+
createdAt?: string | Date;
|
|
36
|
+
updatedAt?: string | Date;
|
|
37
|
+
deletedAt?: string | Date;
|
|
38
|
+
};
|
package/types/role.d.ts
CHANGED