@hostlink/nuxt-light 1.0.1 → 1.0.3
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/module.mjs +2 -13
- package/dist/runtime/components/l-app-main.vue +13 -4
- package/dist/runtime/components/l-card.vue +1 -1
- package/dist/runtime/components/l-col.vue +1 -1
- package/dist/runtime/components/l-customizer.vue +3 -4
- package/dist/runtime/components/l-file-manager.vue +4 -4
- package/dist/runtime/components/l-input-xlsx.vue +78 -0
- package/dist/runtime/components/l-login.vue +17 -9
- package/dist/runtime/components/l-page.vue +7 -0
- package/dist/runtime/components/l-row.vue +4 -2
- package/dist/runtime/components/l-table.vue +5 -4
- package/dist/runtime/formkit/File.vue +51 -0
- package/dist/runtime/formkit/Form.vue +2 -2
- package/dist/runtime/formkit/InputXlsx.vue +22 -0
- package/dist/runtime/formkit/Toggle.vue +18 -0
- package/dist/runtime/formkit/index.mjs +12 -0
- package/dist/runtime/lib/index.mjs +1 -1
- package/dist/runtime/locales/en.json +5 -12
- package/dist/runtime/locales/zh-hk.json +15 -2
- package/dist/runtime/pages/Permission/all.vue +1 -1
- package/dist/runtime/pages/Role/add.vue +1 -5
- package/dist/runtime/pages/Role/index.vue +21 -5
- package/dist/runtime/pages/System/database/backup.vue +25 -2
- package/dist/runtime/pages/System/database/table.vue +5 -3
- package/dist/runtime/pages/System/index.vue +3 -2
- package/dist/runtime/pages/System/menu/index.vue +6 -1
- package/dist/runtime/pages/System/package.vue +21 -2
- package/dist/runtime/pages/System/setting.vue +65 -9
- package/dist/runtime/pages/System/test.vue +1 -0
- package/dist/runtime/pages/System/view_as.vue +38 -11
- package/dist/runtime/pages/Translate/index.vue +5 -4
- package/dist/runtime/pages/User/_user_id/edit.vue +13 -12
- package/dist/runtime/pages/User/add.vue +18 -10
- package/dist/runtime/pages/User/setting/bio-auth.vue +4 -7
- package/dist/runtime/pages/User/setting/password.vue +29 -11
- package/dist/runtime/pages/User/setting/two-factor-auth.vue +13 -7
- package/dist/types.d.mts +2 -2
- package/package.json +2 -4
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { defineNuxtModule, createResolver, addComponentsDir, addImports, addPlugin } from '@nuxt/kit';
|
|
2
|
-
import AutoImport from 'unplugin-auto-import/vite';
|
|
3
2
|
|
|
4
3
|
const module = defineNuxtModule({
|
|
5
4
|
meta: {
|
|
@@ -20,17 +19,6 @@ const module = defineNuxtModule({
|
|
|
20
19
|
rel: "stylesheet",
|
|
21
20
|
href: "https://fonts.googleapis.com/css2?family=Noto+Sans&family=Noto+Sans+HK&family=Noto+Sans+TC&family=Material+Symbols+Outlined"
|
|
22
21
|
});
|
|
23
|
-
nuxt.options.vite.plugins?.push(AutoImport({
|
|
24
|
-
imports: [{
|
|
25
|
-
"quasar": [
|
|
26
|
-
"useQuasar"
|
|
27
|
-
]
|
|
28
|
-
}, {
|
|
29
|
-
"vue-i18n": [
|
|
30
|
-
"useI18n"
|
|
31
|
-
]
|
|
32
|
-
}]
|
|
33
|
-
}));
|
|
34
22
|
addComponentsDir({
|
|
35
23
|
path: resolver.resolve("./runtime/components")
|
|
36
24
|
});
|
|
@@ -60,7 +48,8 @@ const module = defineNuxtModule({
|
|
|
60
48
|
{ name: "getModelFields", from },
|
|
61
49
|
{ name: "getModelField", from },
|
|
62
50
|
{ name: "getGQLFields", from },
|
|
63
|
-
{ name: "model", from }
|
|
51
|
+
{ name: "model", from },
|
|
52
|
+
{ name: "notify", from }
|
|
64
53
|
]);
|
|
65
54
|
addPlugin({
|
|
66
55
|
src: resolver.resolve("./runtime/plugin"),
|
|
@@ -16,7 +16,11 @@ const appVersion = config.public.appVersion ?? '0.0.1';
|
|
|
16
16
|
|
|
17
17
|
const quasar = useQuasar();
|
|
18
18
|
const tt = await q({
|
|
19
|
-
|
|
19
|
+
system: ["devMode"],
|
|
20
|
+
app: ["menus", "viewAsMode", "languages",
|
|
21
|
+
"copyrightYear",
|
|
22
|
+
"copyrightName",
|
|
23
|
+
{ i18nMessages: ["name", "value"] }],
|
|
20
24
|
my: ['username', 'first_name', 'last_name', 'roles', "styles", "language", f('granted_storage:granted', { right: "system.storage" }, [])],
|
|
21
25
|
})
|
|
22
26
|
|
|
@@ -194,6 +198,9 @@ const containerStyle = computed(() => {
|
|
|
194
198
|
|
|
195
199
|
<q-toolbar-title>
|
|
196
200
|
{{ light.getCompany() }}
|
|
201
|
+
<template v-if="tt.system.devMode">
|
|
202
|
+
- Development mode
|
|
203
|
+
</template>
|
|
197
204
|
</q-toolbar-title>
|
|
198
205
|
|
|
199
206
|
<q-space />
|
|
@@ -212,7 +219,7 @@ const containerStyle = computed(() => {
|
|
|
212
219
|
</q-btn>
|
|
213
220
|
|
|
214
221
|
<q-btn icon="sym_o_storage" flat round dense class="q-mr-sm" v-if="my.granted_storage"
|
|
215
|
-
:color="storageColor"
|
|
222
|
+
:color="storageColor">
|
|
216
223
|
<q-menu>
|
|
217
224
|
<q-card style="width:250px">
|
|
218
225
|
<q-card-section>
|
|
@@ -304,7 +311,7 @@ const containerStyle = computed(() => {
|
|
|
304
311
|
</q-drawer>
|
|
305
312
|
|
|
306
313
|
<q-page-container :class="containerClass" :style="containerStyle">
|
|
307
|
-
|
|
314
|
+
|
|
308
315
|
<!-- Error message -->
|
|
309
316
|
<q-banner dense inline-actions class="bg-grey-4 q-ma-md" v-for="error in errors" rounded>
|
|
310
317
|
{{ error }}
|
|
@@ -328,7 +335,9 @@ const containerStyle = computed(() => {
|
|
|
328
335
|
<q-footer bordered v-if="style.footer">
|
|
329
336
|
<q-item>
|
|
330
337
|
<q-item-section>
|
|
331
|
-
{{ light.getCompany() }} {{ appVersion }} - Copyright
|
|
338
|
+
{{ light.getCompany() }} {{ appVersion }} - Copyright {{ app.copyrightYear }} {{ app.copyrightName }}.
|
|
339
|
+
Build {{
|
|
340
|
+
light.getVersion() }}
|
|
332
341
|
</q-item-section>
|
|
333
342
|
</q-item>
|
|
334
343
|
</q-footer>
|
|
@@ -38,7 +38,7 @@ const showBody = computed(() => !minimize.value || fullScreen.value);
|
|
|
38
38
|
<template>
|
|
39
39
|
<q-card v-bind="attrs" :class="{ 'fullscreen': fullScreen, 'no-margin': fullScreen }">
|
|
40
40
|
<q-bar :class="cl" v-if="title">
|
|
41
|
-
<div>{{ title }}</div>
|
|
41
|
+
<div>{{ $t(title) }}</div>
|
|
42
42
|
<q-space />
|
|
43
43
|
<!-- q-btn-dropdown dense flat icon="sym_o_search" persistent>
|
|
44
44
|
<div class="q-ma-md">
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import { defineModel } from 'vue'
|
|
3
2
|
const COLORS = [
|
|
4
3
|
'primary',
|
|
5
4
|
'secondary',
|
|
@@ -84,7 +83,7 @@ const props = defineProps({
|
|
|
84
83
|
<q-separator />
|
|
85
84
|
<q-item>
|
|
86
85
|
<q-item-section>
|
|
87
|
-
<q-item-label>Color</q-item-label>
|
|
86
|
+
<q-item-label>{{ $t('Color') }}</q-item-label>
|
|
88
87
|
<div class="row">
|
|
89
88
|
<div v-for="c in COLORS" :key="c" :class="`bg-${c}`" style="width: 1.5rem; height: 1.5rem;"
|
|
90
89
|
class="q-ma-xs cursor-pointer rounded-borders" @click="$emit('update:color', c)" />
|
|
@@ -115,7 +114,7 @@ const props = defineProps({
|
|
|
115
114
|
|
|
116
115
|
<q-item>
|
|
117
116
|
<q-item-section>
|
|
118
|
-
<q-item-label>Menu overlay header
|
|
117
|
+
<q-item-label>Menu overlay header</q-item-label>
|
|
119
118
|
</q-item-section>
|
|
120
119
|
<q-item-section side>
|
|
121
120
|
<q-toggle :model-value="menuOverlayHeader"
|
|
@@ -127,7 +126,7 @@ const props = defineProps({
|
|
|
127
126
|
|
|
128
127
|
<q-item>
|
|
129
128
|
<q-item-section>
|
|
130
|
-
<q-item-label>Show footer</q-item-label>
|
|
129
|
+
<q-item-label>{{ $t('Show footer') }}</q-item-label>
|
|
131
130
|
</q-item-section>
|
|
132
131
|
<q-item-section side>
|
|
133
132
|
<q-toggle :model-value="footer" @update:model-value="$emit('update:footer', $event)" />
|
|
@@ -464,7 +464,7 @@ const isDark = computed(() => light.isDarkMode());
|
|
|
464
464
|
</script>
|
|
465
465
|
<template>
|
|
466
466
|
<q-layout view="hHh lpR fFf" :class="isDark ? '' : 'bg-white'" container :style="{ 'min-height': height }">
|
|
467
|
-
<q-header bordered :class="isDark?'':'bg-white text-grey-8'" height-hint="64">
|
|
467
|
+
<q-header bordered :class="isDark ? '' : 'bg-white text-grey-8'" height-hint="64">
|
|
468
468
|
<q-toolbar>
|
|
469
469
|
<q-btn flat round @click="toggleLeftDrawer" aria-label="Menu" icon="menu" class="q-mr-sm" />
|
|
470
470
|
|
|
@@ -629,7 +629,7 @@ const isDark = computed(() => light.isDarkMode());
|
|
|
629
629
|
|
|
630
630
|
<q-table flat bordered :columns="columns" :rows="items" @row-dblclick="onDblclickRow" @row-click="onClickRow"
|
|
631
631
|
:pagination="pagination" row-key="path" selection="multiple" v-model:selected="selected" dense
|
|
632
|
-
:loading="loading">
|
|
632
|
+
:loading="loading" :loading-label="$t('Loading...')" :no-data-label="$t('No data available')">
|
|
633
633
|
<template #body-cell-icon="props">
|
|
634
634
|
<q-td auto-width>
|
|
635
635
|
<q-icon name="sym_o_folder" v-if="props.value == 'folder'" size="sm" />
|
|
@@ -646,14 +646,14 @@ const isDark = computed(() => light.isDarkMode());
|
|
|
646
646
|
<q-item-section avatar>
|
|
647
647
|
<q-icon name="sym_o_delete"></q-icon>
|
|
648
648
|
</q-item-section>
|
|
649
|
-
<q-item-section>{{ $t('Delete') }}
|
|
649
|
+
<q-item-section>{{ $t('Delete') }}</q-item-section>
|
|
650
650
|
</q-item>
|
|
651
651
|
|
|
652
652
|
<q-item v-if="props.row.type == 'file'" clickable v-close-popup @click="onDownloadRow(props.row)">
|
|
653
653
|
<q-item-section avatar>
|
|
654
654
|
<q-icon name="sym_o_download"></q-icon>
|
|
655
655
|
</q-item-section>
|
|
656
|
-
<q-item-section>Download</q-item-section>
|
|
656
|
+
<q-item-section>{{ $t('Download') }}</q-item-section>
|
|
657
657
|
</q-item>
|
|
658
658
|
|
|
659
659
|
<q-item clickable v-close-popup @click="onRenameRow(props.row)" v-if="canRenameRow(props.row)">
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
|
|
2
|
+
<script setup>
|
|
3
|
+
import * as XLSX from "xlsx";
|
|
4
|
+
import { computed, ref, useAttrs, useSlots } from "vue";
|
|
5
|
+
import { useLight } from "#imports"
|
|
6
|
+
|
|
7
|
+
const emit = defineEmits(["update:modelValue"]);
|
|
8
|
+
|
|
9
|
+
const light = useLight();
|
|
10
|
+
const attrs = {
|
|
11
|
+
...{
|
|
12
|
+
filled: light.getStyle("inputFilled"),
|
|
13
|
+
outlined: light.getStyle("inputOutlined"),
|
|
14
|
+
standout: light.getStyle("inputStandout"),
|
|
15
|
+
rounded: light.getStyle("inputRounded"),
|
|
16
|
+
dense: light.getStyle("inputDense"),
|
|
17
|
+
square: light.getStyle("inputSquare"),
|
|
18
|
+
stackLabel: light.getStyle("inputStackLabel")
|
|
19
|
+
},
|
|
20
|
+
...useAttrs(),
|
|
21
|
+
|
|
22
|
+
}
|
|
23
|
+
const loading = ref(false);
|
|
24
|
+
const localData = ref([]);
|
|
25
|
+
const hasFile = ref(false);
|
|
26
|
+
const file = ref(null);
|
|
27
|
+
const onChange = () => {
|
|
28
|
+
hasFile.value = true;
|
|
29
|
+
loading.value = true;
|
|
30
|
+
file.value.files[0].arrayBuffer().then((data) => {
|
|
31
|
+
const workbook = XLSX.read(data);
|
|
32
|
+
const sheet = workbook.Sheets[workbook.SheetNames[0]];
|
|
33
|
+
const json = XLSX.utils.sheet_to_json(sheet);
|
|
34
|
+
localData.value = json;
|
|
35
|
+
loading.value = false;
|
|
36
|
+
|
|
37
|
+
emit("update:modelValue", json);
|
|
38
|
+
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const onClear = () => {
|
|
44
|
+
hasFile.value = false;
|
|
45
|
+
localData.value = [];
|
|
46
|
+
emit("update:modelValue", []);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const showView = ref(false);
|
|
50
|
+
</script>
|
|
51
|
+
|
|
52
|
+
<template>
|
|
53
|
+
<q-field v-bind="attrs" :loading="loading" :model-value="localData" @update:model-value="onClear" :clearable="hasFile">
|
|
54
|
+
<template v-slot:control>
|
|
55
|
+
<template v-if="!hasFile">
|
|
56
|
+
<input type="file" accept=".xlsx" @change="onChange" ref="file" />
|
|
57
|
+
</template>
|
|
58
|
+
|
|
59
|
+
<template v-else>
|
|
60
|
+
{{ localData.length }} records
|
|
61
|
+
</template>
|
|
62
|
+
|
|
63
|
+
</template>
|
|
64
|
+
|
|
65
|
+
<template v-slot:prepend v-if="hasFile">
|
|
66
|
+
<q-icon name="sym_o_table_view" @click="showView = true" class="cursor-pointer" />
|
|
67
|
+
</template>
|
|
68
|
+
|
|
69
|
+
<q-dialog v-model="showView" full-width>
|
|
70
|
+
<q-card>
|
|
71
|
+
<q-card-section>
|
|
72
|
+
<q-table :rows="localData" />
|
|
73
|
+
</q-card-section>
|
|
74
|
+
</q-card>
|
|
75
|
+
</q-dialog>
|
|
76
|
+
|
|
77
|
+
</q-field>
|
|
78
|
+
</template>
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { useLight } from "#imports";
|
|
3
3
|
import { ref, reactive, onMounted } from 'vue'
|
|
4
|
-
import { useQuasar, Notify } from 'quasar';
|
|
4
|
+
import { useQuasar, Notify, Dialog } from 'quasar';
|
|
5
5
|
import { useI18n } from 'vue-i18n';
|
|
6
|
-
import { m, notify } from '
|
|
6
|
+
import { m, notify } from '#imports';
|
|
7
7
|
|
|
8
8
|
import { login, webauthnLogin } from '@hostlink/light';
|
|
9
9
|
|
|
@@ -35,9 +35,7 @@ const submit = async () => {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
const forgetPassword = async () => {
|
|
38
|
-
|
|
39
|
-
//show dialog
|
|
40
|
-
qua.dialog({
|
|
38
|
+
Dialog.create({
|
|
41
39
|
title: i18n.t("Forget password"),
|
|
42
40
|
message: "Please enter your email address, we will send you a code to reset your password",
|
|
43
41
|
prompt: {
|
|
@@ -50,9 +48,9 @@ const forgetPassword = async () => {
|
|
|
50
48
|
return;
|
|
51
49
|
}
|
|
52
50
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
51
|
+
try {
|
|
52
|
+
await m("forgetPassword", { email: email });
|
|
53
|
+
Dialog.create({
|
|
56
54
|
title: "Enter your code",
|
|
57
55
|
message: "Please enter the code sent to your email, your code will expire in 10 minutes",
|
|
58
56
|
prompt: {
|
|
@@ -67,7 +65,7 @@ const forgetPassword = async () => {
|
|
|
67
65
|
}
|
|
68
66
|
|
|
69
67
|
if (await m("verifyCode", { code: code, email: email })) {
|
|
70
|
-
|
|
68
|
+
Dialog.create({
|
|
71
69
|
title: "Reset password",
|
|
72
70
|
message: "Please enter your new password",
|
|
73
71
|
prompt: {
|
|
@@ -101,9 +99,19 @@ const forgetPassword = async () => {
|
|
|
101
99
|
}
|
|
102
100
|
|
|
103
101
|
|
|
102
|
+
});
|
|
103
|
+
} catch (e) {
|
|
104
|
+
qua.notify({
|
|
105
|
+
message: e.message,
|
|
106
|
+
color: "negative",
|
|
107
|
+
icon: "sym_o_error",
|
|
108
|
+
position: "top",
|
|
109
|
+
timeout: 2000
|
|
104
110
|
});
|
|
105
111
|
}
|
|
106
112
|
});
|
|
113
|
+
|
|
114
|
+
|
|
107
115
|
};
|
|
108
116
|
|
|
109
117
|
const hasBioLogin = ref(false);
|
|
@@ -92,6 +92,12 @@ useHead({
|
|
|
92
92
|
|
|
93
93
|
<template>
|
|
94
94
|
<q-page padding>
|
|
95
|
+
<!-- q-breadcrumbs>
|
|
96
|
+
<q-breadcrumbs-el icon="home" to="/" />
|
|
97
|
+
<q-breadcrumbs-el label="Permission" to="/Permission" />
|
|
98
|
+
<q-breadcrumbs-el label="Build" />
|
|
99
|
+
</q-breadcrumbs -->
|
|
100
|
+
|
|
95
101
|
<q-toolbar v-if="showToolbar">
|
|
96
102
|
<l-back-btn v-if="showBackBtn" />
|
|
97
103
|
<l-add-btn v-if="showAddBtn" />
|
|
@@ -100,6 +106,7 @@ useHead({
|
|
|
100
106
|
<q-toolbar-title>{{ $t(title) }}</q-toolbar-title>
|
|
101
107
|
</q-toolbar>
|
|
102
108
|
|
|
109
|
+
|
|
103
110
|
<div class="q-gutter-sm q-mb-sm">
|
|
104
111
|
<slot name="header"></slot>
|
|
105
112
|
</div>
|
|
@@ -589,7 +589,7 @@ const getCellClass = (col: any, row: any) => {
|
|
|
589
589
|
|
|
590
590
|
|
|
591
591
|
<template #top-right="props" v-if="fullscreen || searchable">
|
|
592
|
-
<q-input v-if="searchable" outlined dense debounce="300" v-model="filter" placeholder="Search">
|
|
592
|
+
<q-input v-if="searchable" outlined dense debounce="300" v-model="filter" :placeholder="$t('Search')">
|
|
593
593
|
<template v-slot:append>
|
|
594
594
|
<q-icon name="search" />
|
|
595
595
|
</template>
|
|
@@ -618,8 +618,9 @@ const getCellClass = (col: any, row: any) => {
|
|
|
618
618
|
<template v-if="col.searchable">
|
|
619
619
|
|
|
620
620
|
<template v-if="col.searchType == 'number'">
|
|
621
|
-
<q-input dense clearable filled square
|
|
622
|
-
@keydown.enter.prevent="onFilters" @clear="onFilters"
|
|
621
|
+
<q-input style="min-width: 80px;" dense clearable filled square
|
|
622
|
+
v-model.number="filters[col.name]" @keydown.enter.prevent="onFilters" @clear="onFilters"
|
|
623
|
+
mask="##########"></q-input>
|
|
623
624
|
</template>
|
|
624
625
|
|
|
625
626
|
<template v-if="col.searchType == 'select'">
|
|
@@ -635,7 +636,7 @@ const getCellClass = (col: any, row: any) => {
|
|
|
635
636
|
</template>
|
|
636
637
|
|
|
637
638
|
<template v-if="!col.searchType">
|
|
638
|
-
<q-input dense clearable filled square v-model="filters[col.name]"
|
|
639
|
+
<q-input style="min-width: 80px;" dense clearable filled square v-model="filters[col.name]"
|
|
639
640
|
@keydown.enter.prevent="onFilters" @clear="onFilters" enterkeyhint="search"></q-input>
|
|
640
641
|
|
|
641
642
|
</template>
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { computed, useSlots } from 'vue'
|
|
3
|
+
import { getErrorMessage } from 'formkit-quasar';
|
|
4
|
+
import { useLight } from '#imports';
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
const props = defineProps({
|
|
8
|
+
context: Object
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
const { error, errorMessage } = getErrorMessage(props.context.node);
|
|
12
|
+
|
|
13
|
+
const value = computed({
|
|
14
|
+
get: () => props.context.value,
|
|
15
|
+
set: (val) => props.context.node.input(val)
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
const ss = Object.entries(useSlots()).map(([key]) => key);
|
|
19
|
+
|
|
20
|
+
const onBlur = () => {
|
|
21
|
+
if (errorMessage.value) {
|
|
22
|
+
error.value = true
|
|
23
|
+
} else {
|
|
24
|
+
error.value = false
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const light = useLight();
|
|
29
|
+
|
|
30
|
+
const attrs = {
|
|
31
|
+
...{
|
|
32
|
+
filled: light.getStyle("inputFilled"),
|
|
33
|
+
outlined: light.getStyle("inputOutlined"),
|
|
34
|
+
standout: light.getStyle("inputStandout"),
|
|
35
|
+
rounded: light.getStyle("inputRounded"),
|
|
36
|
+
dense: light.getStyle("inputDense"),
|
|
37
|
+
square: light.getStyle("inputSquare"),
|
|
38
|
+
stackLabel: light.getStyle("inputStackLabel")
|
|
39
|
+
},
|
|
40
|
+
...props.context.attrs
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
</script>
|
|
44
|
+
<template>
|
|
45
|
+
<q-file v-model="value" :label="context.label" v-bind="attrs" :error="error" :error-message="errorMessage"
|
|
46
|
+
@blur="onBlur">
|
|
47
|
+
<template v-for="s in ss" v-slot:[s]="props" :key="s">
|
|
48
|
+
<slot :name="s" v-bind="props ?? {}"></slot>
|
|
49
|
+
</template>
|
|
50
|
+
</q-file>
|
|
51
|
+
</template>
|
|
@@ -77,13 +77,13 @@ if (!props.context.onSubmit) {
|
|
|
77
77
|
<form v-bind="context.attrs">
|
|
78
78
|
<l-card :bordered="bordered">
|
|
79
79
|
<q-card-section>
|
|
80
|
-
<div :class="`q-
|
|
80
|
+
<div :class="`q-gutter-${gutter}`">
|
|
81
81
|
<slot v-bind="context"></slot>
|
|
82
82
|
</div>
|
|
83
83
|
</q-card-section>
|
|
84
84
|
|
|
85
85
|
<q-card-actions align="right">
|
|
86
|
-
<l-btn
|
|
86
|
+
<l-btn icon="sym_o_check" label="Submit" @click="onSubmit" :disabled="!context.state.dirty"
|
|
87
87
|
:loading="loading"></l-btn>
|
|
88
88
|
</q-card-actions>
|
|
89
89
|
</l-card>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { computed } from 'vue'
|
|
3
|
+
import { getErrorMessage } from 'formkit-quasar';
|
|
4
|
+
|
|
5
|
+
const props = defineProps({
|
|
6
|
+
context: Object
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
const { error, errorMessage } = getErrorMessage(props.context.node);
|
|
10
|
+
|
|
11
|
+
const value = computed({
|
|
12
|
+
get: () => props.context.value,
|
|
13
|
+
set: (val) => props.context.node.input(val)
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
</script>
|
|
17
|
+
<template>
|
|
18
|
+
<l-input-xlsx v-model="value" :label="context.label" v-bind="context.attrs" :error="error" :type="context.inputType"
|
|
19
|
+
:error-message="errorMessage">
|
|
20
|
+
<slot></slot>
|
|
21
|
+
</l-input-xlsx>
|
|
22
|
+
</template>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { computed } from 'vue'
|
|
3
|
+
|
|
4
|
+
const props = defineProps({
|
|
5
|
+
context: Object
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
const value = computed({
|
|
9
|
+
get: () => props.context.value,
|
|
10
|
+
set: (val) => props.context.node.input(val)
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
</script>
|
|
15
|
+
<template>
|
|
16
|
+
<q-toggle v-model="value" :label="context.label" v-bind="context.attrs">
|
|
17
|
+
</q-toggle>
|
|
18
|
+
</template>
|
|
@@ -9,10 +9,22 @@ import DatePickerVue from "./DatePicker.vue";
|
|
|
9
9
|
import TimePickerVue from "./TimePicker.vue";
|
|
10
10
|
import OptionGroupVue from "./OptionGroup.vue";
|
|
11
11
|
import FilePickerVue from "./FilePicker.vue";
|
|
12
|
+
import FileVue from "./File.vue";
|
|
13
|
+
import InputXlsxVue from "./InputXlsx.vue";
|
|
12
14
|
export const createLightPlugin = () => {
|
|
13
15
|
return (node) => {
|
|
14
16
|
let type = node.props.type + "";
|
|
15
17
|
switch (type) {
|
|
18
|
+
case "l-input-xlsx":
|
|
19
|
+
return node.define({
|
|
20
|
+
type: "input",
|
|
21
|
+
component: InputXlsxVue
|
|
22
|
+
});
|
|
23
|
+
case "l-file":
|
|
24
|
+
return node.define({
|
|
25
|
+
type: "input",
|
|
26
|
+
component: FileVue
|
|
27
|
+
});
|
|
16
28
|
case "l-file-picker":
|
|
17
29
|
return node.define({
|
|
18
30
|
type: "input",
|
|
@@ -18,7 +18,7 @@ import getModelFields from "./getModelFields.mjs";
|
|
|
18
18
|
import getModelColumns from "./getModelColumns.mjs";
|
|
19
19
|
import sv from "./sv.mjs";
|
|
20
20
|
import model from "./model.mjs";
|
|
21
|
-
const notify = function(message, color = "
|
|
21
|
+
const notify = function(message, color = "positive") {
|
|
22
22
|
Notify.create({
|
|
23
23
|
message,
|
|
24
24
|
color,
|
|
@@ -1,16 +1,9 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
3
|
-
"
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"mail-test": "Mail test",
|
|
8
|
-
"vx-table-message": "Showing {0} to {1} of {2} entries",
|
|
9
|
-
"vx-per-page": "Per page",
|
|
10
|
-
"Dashboard": "Dashboard",
|
|
11
|
-
"Theme Customizer": "Theme Customizer",
|
|
12
|
-
"Customize & Preview in Real Time": "Customize & Preview in Real Time",
|
|
13
|
-
"Permission": "Permission",
|
|
2
|
+
"Must contain at least {0} characters": "Must contain at least {0} characters",
|
|
3
|
+
"contains_uppercase": "Must contain at least one uppercase letter",
|
|
4
|
+
"contains_lowercase": "Must contain at least one lowercase letter",
|
|
5
|
+
"contains_numeric": "Must contain at least one number",
|
|
6
|
+
"contains_symbol": "Must contain at least one special character",
|
|
14
7
|
"storage_usage": "{0} free of {1}",
|
|
15
8
|
"input_required": "Please input {0}",
|
|
16
9
|
"input_min": "Please input at least {0} characters"
|
|
@@ -1,4 +1,19 @@
|
|
|
1
1
|
{
|
|
2
|
+
"Password policy": "密碼規則",
|
|
3
|
+
"Must contain at least {0} characters": "必須包含至少{0}個字元",
|
|
4
|
+
"contains_symbol": "必須包含符號",
|
|
5
|
+
"contains_numeric": "必須包含數字",
|
|
6
|
+
"contains_lowercase": "必須包含小寫字母",
|
|
7
|
+
"contains_uppercase": "必須包含大寫字母",
|
|
8
|
+
"Last access time": "最後存取時間",
|
|
9
|
+
"Default": "預設",
|
|
10
|
+
"Register": "註冊",
|
|
11
|
+
"Reset your 2FA": "重設雙重認證",
|
|
12
|
+
"Result": "結果",
|
|
13
|
+
"Update password": "更新密碼",
|
|
14
|
+
"Two factor auth": "雙重認證",
|
|
15
|
+
"Color": "顏色",
|
|
16
|
+
"Show footer": "顯示頁尾",
|
|
2
17
|
"Date": "日期",
|
|
3
18
|
"Online": "在線",
|
|
4
19
|
"Update": "更新",
|
|
@@ -108,8 +123,6 @@
|
|
|
108
123
|
"Rename": "重新命名",
|
|
109
124
|
"Database": "資料庫",
|
|
110
125
|
"Charset": "字元編碼",
|
|
111
|
-
"vx-table-message": "顯示 {0} 至 {1} 共 {2} 項資料",
|
|
112
|
-
"vx-per-page": "每頁顯示",
|
|
113
126
|
"Role": "角色",
|
|
114
127
|
"Permission": "權限",
|
|
115
128
|
"Old password": "舊密碼",
|
|
@@ -69,7 +69,7 @@ const onUpdate = (value, role, permission) => {
|
|
|
69
69
|
|
|
70
70
|
<template>
|
|
71
71
|
<l-page>
|
|
72
|
-
<q-table :columns="columns" flat bordered :rows="rows" :pagination="{ rowsPerPage: 0 }">
|
|
72
|
+
<q-table :columns="columns" flat bordered :rows="rows" :pagination="{ rowsPerPage: 0 }" dense>
|
|
73
73
|
<template #body="props">
|
|
74
74
|
<q-tr :props="props">
|
|
75
75
|
<q-td>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import { q } from '
|
|
2
|
+
import { q } from '#imports'
|
|
3
3
|
|
|
4
4
|
let roles = await q("listRole", ["name"]);
|
|
5
5
|
roles = roles.map((role) => {
|
|
@@ -9,10 +9,6 @@ roles = roles.map((role) => {
|
|
|
9
9
|
};
|
|
10
10
|
});
|
|
11
11
|
|
|
12
|
-
const onSubmit = (e) => {
|
|
13
|
-
e.preventDefault();
|
|
14
|
-
console.log("submit");
|
|
15
|
-
}
|
|
16
12
|
</script>
|
|
17
13
|
|
|
18
14
|
<template>
|