@hostlink/nuxt-light 1.1.8 → 1.3.0
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/dist/module.json +1 -1
- package/dist/runtime/components/l-app-main.vue +96 -26
- package/dist/runtime/components/l-btn.vue +13 -15
- package/dist/runtime/components/l-card.vue +85 -10
- package/dist/runtime/components/l-customizer.vue +18 -1
- package/dist/runtime/components/l-fav-menu.vue +21 -0
- package/dist/runtime/components/l-file-upload.vue +5 -1
- package/dist/runtime/components/l-icon-picker.vue +3331 -0
- package/dist/runtime/components/l-login.vue +3 -3
- package/dist/runtime/components/l-menu.vue +4 -3
- package/dist/runtime/components/l-small-box.vue +4 -4
- package/dist/runtime/components/l-tabs.vue +4 -2
- package/dist/runtime/components/l-user-eventlog.vue +29 -0
- package/dist/runtime/components/l-user-overview.vue +79 -0
- package/dist/runtime/components/l-user-userlog.vue +13 -0
- package/dist/runtime/formkit/Select.vue +1 -1
- package/dist/runtime/index.d.ts +46 -2
- package/dist/runtime/index.mjs +35 -1
- package/dist/runtime/locales/zh-hk.json +3 -0
- package/dist/runtime/pages/System/menu/index.vue +136 -99
- package/dist/runtime/pages/System/setting.vue +96 -57
- package/dist/runtime/pages/User/_user_id/view.vue +28 -42
- package/dist/runtime/pages/User/profile.vue +47 -24
- package/dist/runtime/pages/User/setting/my_favorite.vue +74 -0
- package/dist/runtime/pages/User/setting.vue +4 -1
- package/dist/runtime/plugin.mjs +4 -2
- package/dist/runtime/routes.mjs +10 -0
- package/package.json +1 -1
package/dist/module.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { useRoute } from 'vue-router';
|
|
3
|
+
import { useLight, q, m } from "#imports";
|
|
4
|
+
import { useQuasar, Loading, Dialog } from 'quasar';
|
|
4
5
|
import { useI18n } from 'vue-i18n';
|
|
5
|
-
import {
|
|
6
|
-
import { ref, computed, reactive, provide, watch } from 'vue';
|
|
6
|
+
import { ref, computed, reactive, provide, watch, toRaw } from 'vue';
|
|
7
7
|
import { useRuntimeConfig } from 'nuxt/app';
|
|
8
8
|
|
|
9
|
+
Loading.show()
|
|
9
10
|
//download system value
|
|
10
11
|
/* import { download } from './../lib/SystemValue'
|
|
11
12
|
await download();
|
|
@@ -20,15 +21,28 @@ const tt = await q({
|
|
|
20
21
|
app: ["menus", "viewAsMode", "languages",
|
|
21
22
|
"copyrightYear",
|
|
22
23
|
"copyrightName",
|
|
24
|
+
"hasFavorite",
|
|
23
25
|
{ i18nMessages: ["name", "value"] }],
|
|
24
|
-
my: ['username', 'first_name', 'last_name', 'roles', "styles", "language",
|
|
26
|
+
my: ['username', 'first_name', 'last_name', 'roles', "styles", "language", "permissions", { myFavorites: ["my_favorite_id", "label", "path", "icon"] }],
|
|
25
27
|
})
|
|
26
28
|
|
|
27
29
|
let app = tt.app
|
|
28
|
-
let my = tt.my
|
|
30
|
+
let my = reactive(tt.my)
|
|
29
31
|
|
|
30
32
|
const light = useLight();
|
|
31
33
|
light.init(my.styles);
|
|
34
|
+
//set permission
|
|
35
|
+
light.setPermissions(my.permissions);
|
|
36
|
+
|
|
37
|
+
light.setMyFavorites(toRaw(my.myFavorites))
|
|
38
|
+
|
|
39
|
+
const myFavorites = computed(() => {
|
|
40
|
+
return light.getMyFavorites();
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const myFavoritesCount = computed(() => {
|
|
44
|
+
return light.getMyFavorites().length;
|
|
45
|
+
});
|
|
32
46
|
|
|
33
47
|
quasar.dark.set(light.isDarkMode());
|
|
34
48
|
|
|
@@ -36,7 +50,8 @@ const i18n = useI18n();
|
|
|
36
50
|
i18n.locale = my.language || 'en';
|
|
37
51
|
|
|
38
52
|
let system = null
|
|
39
|
-
|
|
53
|
+
|
|
54
|
+
if (light.isGranted("system.storage")) {
|
|
40
55
|
system = await q("system", ["diskFreeSpace", "diskUsageSpace", "diskTotalSpace", "diskFreeSpacePercent"]);
|
|
41
56
|
}
|
|
42
57
|
|
|
@@ -65,6 +80,7 @@ const toggleRightDrawer = () => {
|
|
|
65
80
|
let showViewAs = false;
|
|
66
81
|
if (my && my.roles.indexOf('Administrators') != -1) {
|
|
67
82
|
showViewAs = true;
|
|
83
|
+
light.isAdmin = true;
|
|
68
84
|
}
|
|
69
85
|
|
|
70
86
|
const menuOverlayHeader = ref(false)
|
|
@@ -188,19 +204,60 @@ const containerStyle = computed(() => {
|
|
|
188
204
|
}
|
|
189
205
|
})
|
|
190
206
|
|
|
191
|
-
const
|
|
207
|
+
const route = useRoute()
|
|
208
|
+
|
|
192
209
|
|
|
193
|
-
const
|
|
194
|
-
if (document.fullscreenElement) {
|
|
195
|
-
document.exitFullscreen();
|
|
196
|
-
fullscreen.value = false;
|
|
197
|
-
} else {
|
|
198
|
-
fullscreen.value = true;
|
|
210
|
+
const onToggleFav = async () => {
|
|
199
211
|
|
|
200
|
-
|
|
212
|
+
if (isFav.value) {
|
|
213
|
+
await m("removeMyFavorite", {
|
|
214
|
+
path: route.fullPath,
|
|
215
|
+
})
|
|
216
|
+
|
|
217
|
+
//reload my.myFavorites
|
|
218
|
+
light.reloadMyFavorites();
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
return;
|
|
201
222
|
}
|
|
223
|
+
|
|
224
|
+
Dialog.create({
|
|
225
|
+
title: 'Add to favorite',
|
|
226
|
+
message: 'Enter favorite label',
|
|
227
|
+
prompt: {
|
|
228
|
+
//get window title, remove - and replace with space
|
|
229
|
+
model: route.name.replace(/-/g, ' '),
|
|
230
|
+
},
|
|
231
|
+
cancel: true,
|
|
232
|
+
persistent: true,
|
|
233
|
+
}).onOk(async (data) => {
|
|
234
|
+
if (data === '') return;
|
|
235
|
+
if (await m("addMyFavorite", {
|
|
236
|
+
path: route.fullPath,
|
|
237
|
+
label: data,
|
|
238
|
+
})) {
|
|
239
|
+
light.reloadMyFavorites();
|
|
240
|
+
|
|
241
|
+
}
|
|
242
|
+
})
|
|
202
243
|
}
|
|
203
244
|
|
|
245
|
+
const isFav = computed(() => {
|
|
246
|
+
//check my.myFavorites
|
|
247
|
+
let fav = my.myFavorites.find((item) => {
|
|
248
|
+
return item.path == route.fullPath;
|
|
249
|
+
})
|
|
250
|
+
return fav;
|
|
251
|
+
})
|
|
252
|
+
|
|
253
|
+
Loading.hide()
|
|
254
|
+
|
|
255
|
+
const menuWidth = ref(my.styles.menuWidth || 280);
|
|
256
|
+
|
|
257
|
+
watch(menuWidth, () => {
|
|
258
|
+
light.setStyle("menuWidth", menuWidth.value)
|
|
259
|
+
})
|
|
260
|
+
|
|
204
261
|
</script>
|
|
205
262
|
|
|
206
263
|
<template>
|
|
@@ -218,26 +275,33 @@ const onFullscreen = () => {
|
|
|
218
275
|
|
|
219
276
|
<q-space />
|
|
220
277
|
|
|
221
|
-
<q-btn :icon="
|
|
222
|
-
|
|
278
|
+
<q-btn :icon="isFav ? 'favorite' : 'sym_o_favorite'" round flat dense class="q-mr-xs" @click="onToggleFav"
|
|
279
|
+
v-if="app.hasFavorite">
|
|
280
|
+
</q-btn>
|
|
223
281
|
|
|
282
|
+
<q-btn :icon="$q.fullscreen.isActive ? 'fullscreen_exit' : 'fullscreen'" round flat dense class="q-mr-xs"
|
|
283
|
+
@click="$q.fullscreen.toggle()">
|
|
224
284
|
</q-btn>
|
|
225
285
|
|
|
226
|
-
<q-btn v-if="languages.length > 1"
|
|
286
|
+
<q-btn v-if="languages.length > 1" round flat icon="language" class="q-mr-xs">
|
|
287
|
+
<q-tooltip>
|
|
288
|
+
{{ my.language }}
|
|
289
|
+
</q-tooltip>
|
|
227
290
|
<q-menu>
|
|
228
291
|
<q-list>
|
|
229
|
-
<q-item v-for="language
|
|
230
|
-
@click="onChangeLocale(language.value)">
|
|
292
|
+
<q-item v-for=" language in languages " :key="language.value" v-close-popup clickable
|
|
293
|
+
@click="onChangeLocale(language.value)" :active="language.value == my.language">
|
|
231
294
|
<q-item-section>
|
|
232
295
|
<q-item-label>{{ language.name }}</q-item-label>
|
|
233
296
|
</q-item-section>
|
|
234
297
|
</q-item>
|
|
235
298
|
</q-list>
|
|
236
299
|
</q-menu>
|
|
300
|
+
|
|
301
|
+
|
|
237
302
|
</q-btn>
|
|
238
303
|
|
|
239
|
-
<q-btn icon="sym_o_storage" flat round dense class="q-mr-sm" v-if="
|
|
240
|
-
:color="storageColor">
|
|
304
|
+
<q-btn icon="sym_o_storage" flat round dense class="q-mr-sm" v-if="system" :color="storageColor">
|
|
241
305
|
<q-menu>
|
|
242
306
|
<q-card style="width:250px">
|
|
243
307
|
<q-card-section>
|
|
@@ -310,12 +374,18 @@ const onFullscreen = () => {
|
|
|
310
374
|
</q-toolbar>
|
|
311
375
|
</q-header>
|
|
312
376
|
|
|
313
|
-
<q-drawer v-model="leftDrawerOpen" bordered show-if-above side="left" :dark="menuDark" :width="
|
|
377
|
+
<q-drawer v-model="leftDrawerOpen" bordered show-if-above side="left" :dark="menuDark" :width="menuWidth"
|
|
314
378
|
:mini-to-overlay="style.miniState" :mini="isMini" @mouseout="isMouseOnDrawer = false"
|
|
315
379
|
@mouseover="isMouseOnDrawer = true">
|
|
316
380
|
<!-- drawer content -->
|
|
317
381
|
<q-scroll-area class="fit">
|
|
318
|
-
|
|
382
|
+
|
|
383
|
+
<div class="q-mx-sm">
|
|
384
|
+
<l-fav-menu :value="myFavorites" :dense="style.dense" v-if="myFavoritesCount > 0" />
|
|
385
|
+
<l-menu v-for=" menu in menus " :value="menu" :dense="style.dense" />
|
|
386
|
+
|
|
387
|
+
</div>
|
|
388
|
+
|
|
319
389
|
</q-scroll-area>
|
|
320
390
|
</q-drawer>
|
|
321
391
|
|
|
@@ -324,14 +394,14 @@ const onFullscreen = () => {
|
|
|
324
394
|
<q-scroll-area class="fit">
|
|
325
395
|
<l-customizer v-model:color="light.color" v-model:theme="light.theme" v-model:miniState="style.miniState"
|
|
326
396
|
v-model:dense="style.dense" v-model:menuOverlayHeader="style.menuOverlayHeader"
|
|
327
|
-
v-model:footer="style.footer" />
|
|
397
|
+
v-model:footer="style.footer" v-model:menuWidth="menuWidth" />
|
|
328
398
|
</q-scroll-area>
|
|
329
399
|
</q-drawer>
|
|
330
400
|
|
|
331
401
|
<q-page-container :class="containerClass" :style="containerStyle">
|
|
332
402
|
|
|
333
403
|
<!-- Error message -->
|
|
334
|
-
<q-banner dense inline-actions class="bg-grey-4 q-ma-md" v-for="error
|
|
404
|
+
<q-banner dense inline-actions class="bg-grey-4 q-ma-md" v-for=" error in errors " rounded>
|
|
335
405
|
{{ error }}
|
|
336
406
|
<template v-slot:action>
|
|
337
407
|
<q-btn flat icon="sym_o_close" round dense @click="light.removeError(error)" />
|
|
@@ -1,29 +1,20 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { type QBtnProps } from "quasar";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { computed } from "vue";
|
|
4
|
+
import { useLight } from '#imports';
|
|
5
|
+
import { useI18n } from "vue-i18n";
|
|
5
6
|
|
|
6
7
|
export interface LBtnProps extends QBtnProps {
|
|
7
8
|
permission?: string;
|
|
8
9
|
}
|
|
9
10
|
|
|
11
|
+
const { t } = useI18n();
|
|
10
12
|
const props = defineProps<LBtnProps>();
|
|
11
13
|
|
|
12
14
|
const light = useLight();
|
|
13
15
|
|
|
14
|
-
const granted = ref(false);
|
|
15
|
-
if (props.permission) {
|
|
16
|
-
const my = await q("my", [f("granted", { right: props.permission }, [])]);
|
|
17
|
-
|
|
18
|
-
if (my.granted) {
|
|
19
|
-
granted.value = true;
|
|
20
|
-
}
|
|
21
|
-
} else {
|
|
22
|
-
granted.value = true;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
16
|
const attrs = computed(() => {
|
|
26
|
-
|
|
17
|
+
const a = {
|
|
27
18
|
...{
|
|
28
19
|
rounded: light.getStyle("buttonRounded"),
|
|
29
20
|
outline: light.getStyle("buttonOutline"),
|
|
@@ -32,12 +23,19 @@ const attrs = computed(() => {
|
|
|
32
23
|
},
|
|
33
24
|
...props,
|
|
34
25
|
}
|
|
26
|
+
|
|
27
|
+
if (a.label !== undefined) {
|
|
28
|
+
a.label = t(a.label)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return a;
|
|
32
|
+
|
|
35
33
|
});
|
|
36
34
|
|
|
37
35
|
|
|
38
36
|
</script>
|
|
39
37
|
<template>
|
|
40
|
-
<q-btn v-bind="attrs" color="primary" v-if="
|
|
38
|
+
<q-btn v-bind="attrs" color="primary" v-if="$light.isGranted(permission)">
|
|
41
39
|
<slot></slot>
|
|
42
40
|
</q-btn>
|
|
43
41
|
</template>
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { useLight } from '#imports'
|
|
2
|
+
import { useLight, q, m } from '#imports'
|
|
3
3
|
import { ref, computed } from 'vue'
|
|
4
4
|
import { type QCardProps } from 'quasar';
|
|
5
5
|
|
|
6
6
|
export interface LCardProps extends QCardProps {
|
|
7
7
|
loading?: boolean;
|
|
8
8
|
title?: string;
|
|
9
|
+
/**
|
|
10
|
+
* Permission to access this card, if not granted, the card will not be shown, if the user is admin, a lock icon will be shown to allow the user to grant the permission
|
|
11
|
+
*/
|
|
12
|
+
permission?: string
|
|
9
13
|
}
|
|
10
14
|
|
|
11
15
|
const light = useLight();
|
|
@@ -40,18 +44,89 @@ const fullScreenIcon = computed(() => fullScreen.value ? "sym_o_fullscreen_exit"
|
|
|
40
44
|
|
|
41
45
|
const showBody = computed(() => !minimize.value || fullScreen.value);
|
|
42
46
|
|
|
47
|
+
const showBar = computed(() => {
|
|
48
|
+
if (props.title !== undefined) return true;
|
|
49
|
+
if (showSecurity.value) return true;
|
|
50
|
+
return false;
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
const showSecurity = computed(() => {
|
|
55
|
+
if (props.permission === undefined) return false;
|
|
56
|
+
if (!light.isAdmin) return false;
|
|
57
|
+
return true;
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
const roles = ref<{
|
|
62
|
+
name: string;
|
|
63
|
+
granted: boolean;
|
|
64
|
+
}[]>([]);
|
|
65
|
+
|
|
66
|
+
if (props.permission && light.isAdmin) {
|
|
67
|
+
//get role
|
|
68
|
+
const data = await q({
|
|
69
|
+
listRole: {
|
|
70
|
+
name: true
|
|
71
|
+
},
|
|
72
|
+
listPermission: {
|
|
73
|
+
__args: {
|
|
74
|
+
filters: {
|
|
75
|
+
value: props.permission
|
|
76
|
+
}
|
|
77
|
+
}, data: {
|
|
78
|
+
role: true
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
roles.value = (data.listRole.map((r: any) => {
|
|
85
|
+
return {
|
|
86
|
+
name: r.name,
|
|
87
|
+
granted: data.listPermission.data.find((p: any) => p.role == r.name) != undefined
|
|
88
|
+
}
|
|
89
|
+
}));
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const onUpdatePermission = async (role: any) => {
|
|
93
|
+
if (role.granted) {
|
|
94
|
+
await m("addPermission", {
|
|
95
|
+
role: role.name,
|
|
96
|
+
value: props.permission,
|
|
97
|
+
});
|
|
98
|
+
} else {
|
|
99
|
+
//remove permission
|
|
100
|
+
await m("removePermission", {
|
|
101
|
+
role: role.name,
|
|
102
|
+
value: props.permission,
|
|
103
|
+
})
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
|
|
43
109
|
</script>
|
|
44
110
|
<template>
|
|
45
|
-
<q-card v-bind="attrs" :class="{ 'fullscreen': fullScreen, 'no-margin': fullScreen }"
|
|
46
|
-
|
|
47
|
-
|
|
111
|
+
<q-card v-bind="attrs" :class="{ 'fullscreen': fullScreen, 'no-margin': fullScreen }"
|
|
112
|
+
v-if="$light.isGranted(permission)" :dark="$q.dark.isActive">
|
|
113
|
+
<q-bar :class="cl" v-if="showBar">
|
|
114
|
+
<div>{{ $t(title ?? "") }}</div>
|
|
48
115
|
<q-space />
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
116
|
+
|
|
117
|
+
<q-btn dense flat icon="sym_o_lock" persistent v-if="showSecurity">
|
|
118
|
+
<q-menu>
|
|
119
|
+
<q-list>
|
|
120
|
+
<q-item clickable v-for="role in roles">
|
|
121
|
+
<q-item-section>
|
|
122
|
+
<q-checkbox :label="role.name" v-model="role.granted"
|
|
123
|
+
@update:model-value="onUpdatePermission(role)"></q-checkbox>
|
|
124
|
+
</q-item-section>
|
|
125
|
+
</q-item>
|
|
126
|
+
</q-list>
|
|
127
|
+
</q-menu>
|
|
128
|
+
</q-btn>
|
|
129
|
+
|
|
55
130
|
<q-btn dense flat @click="fullScreen = !fullScreen" :icon="fullScreenIcon" />
|
|
56
131
|
<q-btn dense flat :icon="icon" @click="minimize = !minimize" v-if="!fullScreen" />
|
|
57
132
|
</q-bar>
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
+
const menuWidth = defineModel('menuWidth', {
|
|
3
|
+
type: Number,
|
|
4
|
+
default: 280
|
|
5
|
+
});
|
|
6
|
+
|
|
2
7
|
const COLORS = [
|
|
3
8
|
'primary',
|
|
4
9
|
'secondary',
|
|
@@ -28,6 +33,8 @@ const COLORS = [
|
|
|
28
33
|
'blue-grey'
|
|
29
34
|
]
|
|
30
35
|
|
|
36
|
+
|
|
37
|
+
|
|
31
38
|
defineEmits(['update:theme', 'update:menuOverlayHeader', 'update:dense', 'update:color', 'update:miniState', 'update:footer'])
|
|
32
39
|
|
|
33
40
|
const props = defineProps({
|
|
@@ -54,7 +61,8 @@ const props = defineProps({
|
|
|
54
61
|
footer: {
|
|
55
62
|
type: Boolean,
|
|
56
63
|
default: false
|
|
57
|
-
}
|
|
64
|
+
},
|
|
65
|
+
|
|
58
66
|
})
|
|
59
67
|
|
|
60
68
|
</script>
|
|
@@ -132,6 +140,15 @@ const props = defineProps({
|
|
|
132
140
|
<q-toggle :model-value="footer" @update:model-value="$emit('update:footer', $event)" />
|
|
133
141
|
</q-item-section>
|
|
134
142
|
</q-item>
|
|
143
|
+
<q-separator />
|
|
144
|
+
<q-item-label header>{{ $t('Menu width') }}</q-item-label>
|
|
145
|
+
<q-item>
|
|
146
|
+
<q-item-section>
|
|
147
|
+
<q-slider v-model="menuWidth" :min="200" :max="360" label :color="$light.color" />
|
|
148
|
+
</q-item-section>
|
|
149
|
+
|
|
150
|
+
</q-item>
|
|
151
|
+
<q-separator />
|
|
135
152
|
|
|
136
153
|
</q-list>
|
|
137
154
|
</template>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
const props = defineProps(["value", "dense"])
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<style scoped>
|
|
6
|
+
.menu-list .q-item{border-radius:12px 12px 12px 12px}.menu-list .q-router-link--exact-active{background:linear-gradient(118deg,var(--q-primary),rgba(115,103,240,.7));color:#fff}
|
|
7
|
+
</style>
|
|
8
|
+
<template>
|
|
9
|
+
<q-expansion-item :label="$t('My favorite')" :dense="dense" ref="expansion" icon="sym_o_favorite">
|
|
10
|
+
<q-list class="q-pl-md menu-list">
|
|
11
|
+
<q-item v-ripple :to="item.path" v-for="item in value">
|
|
12
|
+
<q-item-section avatar>
|
|
13
|
+
<q-icon :name="item.icon ?? 'sym_o_link'" />
|
|
14
|
+
</q-item-section>
|
|
15
|
+
<q-item-section>
|
|
16
|
+
<q-item-label v-text="$t(item.label)"></q-item-label>
|
|
17
|
+
</q-item-section>
|
|
18
|
+
</q-item>
|
|
19
|
+
</q-list>
|
|
20
|
+
</q-expansion-item>
|
|
21
|
+
</template>
|
|
@@ -167,7 +167,7 @@ const onUploadFile = async () => {
|
|
|
167
167
|
</q-card-section>
|
|
168
168
|
|
|
169
169
|
<q-card-actions align="right">
|
|
170
|
-
<q-btn flat :label="$t('Cancel')" color="primary" v-close-popup></q-btn>
|
|
170
|
+
<q-btn flat :label="$t('Cancel')" color="primary" @click="uploadFile = null" v-close-popup></q-btn>
|
|
171
171
|
<q-btn flat :label="$t('Upload')" color="primary" @click="onUploadFile"></q-btn>
|
|
172
172
|
</q-card-actions>
|
|
173
173
|
</l-card>
|
|
@@ -175,5 +175,9 @@ const onUploadFile = async () => {
|
|
|
175
175
|
<template v-slot:prepend>
|
|
176
176
|
<q-btn dense flat round icon="sym_o_file_upload" @click="show = true"></q-btn>
|
|
177
177
|
</template>
|
|
178
|
+
|
|
179
|
+
<template v-for="(s, name) in $slots" v-slot:[name]="props" :key="name">
|
|
180
|
+
<slot :name="name" v-bind="props ?? {}"></slot>
|
|
181
|
+
</template>
|
|
178
182
|
</q-input>
|
|
179
183
|
</template>
|