@hostlink/nuxt-light 1.73.2 → 1.74.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.vue +0 -19
- package/dist/runtime/components/L/AppMain.d.vue.ts +3 -3
- package/dist/runtime/components/L/AppMain.vue +43 -10
- package/dist/runtime/components/L/AppMain.vue.d.ts +3 -3
- package/dist/runtime/components/L/FacebookButton.d.vue.ts +19 -3
- package/dist/runtime/components/L/FacebookButton.vue +73 -12
- package/dist/runtime/components/L/FacebookButton.vue.d.ts +19 -3
- package/dist/runtime/components/L/FavMenu.d.vue.ts +2 -0
- package/dist/runtime/components/L/FavMenu.vue +10 -2
- package/dist/runtime/components/L/FavMenu.vue.d.ts +2 -0
- package/dist/runtime/components/L/Form.d.vue.ts +29 -56
- package/dist/runtime/components/L/Form.vue +70 -80
- package/dist/runtime/components/L/Form.vue.d.ts +29 -56
- package/dist/runtime/components/L/FormLayout.d.vue.ts +36 -0
- package/dist/runtime/components/L/FormLayout.vue +36 -0
- package/dist/runtime/components/L/FormLayout.vue.d.ts +36 -0
- package/dist/runtime/components/L/Login.vue +1 -1
- package/dist/runtime/components/L/Menu.d.vue.ts +2 -0
- package/dist/runtime/components/L/Menu.vue +4 -4
- package/dist/runtime/components/L/Menu.vue.d.ts +2 -0
- package/dist/runtime/composables/useLight.d.ts +0 -4
- package/dist/runtime/formkit/Form.d.vue.ts +2 -2
- package/dist/runtime/formkit/Form.vue +15 -18
- package/dist/runtime/formkit/Form.vue.d.ts +2 -2
- package/dist/runtime/formkit/index.js +2 -0
- package/dist/runtime/locales/en.json +8 -2
- package/dist/runtime/locales/zh-hk.json +8 -2
- package/dist/runtime/pages/Role/[name]/update-child.vue +4 -1
- package/dist/runtime/pages/System/fs.vue +116 -15
- package/dist/runtime/pages/User/setting/index.vue +29 -12
- package/dist/runtime/pages/User/setting/information.vue +4 -28
- package/dist/runtime/pages/User/setting/open_id.vue +132 -91
- package/dist/runtime/pages/User/setting/two-factor-auth.vue +388 -143
- package/dist/runtime/pages/User/setting.vue +3 -4
- package/dist/runtime/types/form.d.ts +2 -0
- package/dist/runtime/types/form.js +0 -0
- package/dist/runtime/utils/filterMenuItems.d.ts +10 -0
- package/dist/runtime/utils/filterMenuItems.js +34 -0
- package/dist/runtime/utils/formLayout.d.ts +2 -0
- package/dist/runtime/utils/formLayout.js +7 -0
- package/dist/runtime/utils/socialSdk.d.ts +2 -0
- package/dist/runtime/utils/socialSdk.js +127 -0
- package/package.json +14 -14
- package/dist/runtime/pages/Role/add2.d.vue.ts +0 -3
- package/dist/runtime/pages/Role/add2.vue +0 -57
- package/dist/runtime/pages/Role/add2.vue.d.ts +0 -3
- package/dist/runtime/pages/System/test.d.vue.ts +0 -3
- package/dist/runtime/pages/System/test.vue +0 -13
- package/dist/runtime/pages/System/test.vue.d.ts +0 -3
package/dist/module.json
CHANGED
|
@@ -62,25 +62,6 @@ if (app.value.version != "dev") {
|
|
|
62
62
|
});
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
|
-
if (app.value.facebookAppId) {
|
|
66
|
-
(function(d, s, id) {
|
|
67
|
-
var js, fjs = d.getElementsByTagName(s)[0];
|
|
68
|
-
if (d.getElementById(id)) {
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
js = d.createElement(s);
|
|
72
|
-
js.id = id;
|
|
73
|
-
js.src = "https://connect.facebook.net/en_US/sdk.js";
|
|
74
|
-
fjs.parentNode.insertBefore(js, fjs);
|
|
75
|
-
})(document, "script", "facebook-jssdk");
|
|
76
|
-
window.fbAsyncInit = function() {
|
|
77
|
-
FB.init({
|
|
78
|
-
appId: app.value.facebookAppId,
|
|
79
|
-
xfbml: true,
|
|
80
|
-
version: "v21.0"
|
|
81
|
-
});
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
65
|
</script>
|
|
85
66
|
|
|
86
67
|
<template>
|
|
@@ -20,7 +20,7 @@ type __VLS_Props = {
|
|
|
20
20
|
userMenuItems?: UserMenuItem[];
|
|
21
21
|
headerButtons?: HeaderButton[];
|
|
22
22
|
};
|
|
23
|
-
declare var __VLS_38: {}, __VLS_61: `header-button-menu-${string}`, __VLS_62: {}, __VLS_132: `header-button-menu-${string}`, __VLS_133: {}, __VLS_340: {},
|
|
23
|
+
declare var __VLS_38: {}, __VLS_61: `header-button-menu-${string}`, __VLS_62: {}, __VLS_132: `header-button-menu-${string}`, __VLS_133: {}, __VLS_340: {}, __VLS_501: {}, __VLS_508: {};
|
|
24
24
|
type __VLS_Slots = {} & {
|
|
25
25
|
[K in NonNullable<typeof __VLS_61>]?: (props: typeof __VLS_62) => any;
|
|
26
26
|
} & {
|
|
@@ -30,9 +30,9 @@ type __VLS_Slots = {} & {
|
|
|
30
30
|
} & {
|
|
31
31
|
'user-menu'?: (props: typeof __VLS_340) => any;
|
|
32
32
|
} & {
|
|
33
|
-
'page-top'?: (props: typeof
|
|
33
|
+
'page-top'?: (props: typeof __VLS_501) => any;
|
|
34
34
|
} & {
|
|
35
|
-
'page-bottom'?: (props: typeof
|
|
35
|
+
'page-bottom'?: (props: typeof __VLS_508) => any;
|
|
36
36
|
};
|
|
37
37
|
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
38
38
|
logout: (...args: any[]) => void;
|
|
@@ -6,6 +6,7 @@ import { useI18n } from "vue-i18n";
|
|
|
6
6
|
import { ref, computed, reactive, provide, watch, toRaw, onMounted } from "vue";
|
|
7
7
|
import { useRuntimeConfig } from "nuxt/app";
|
|
8
8
|
import { logout } from "@hostlink/light";
|
|
9
|
+
import { filterMenuItems } from "../../utils/filterMenuItems";
|
|
9
10
|
const emits = defineEmits(["logout"]);
|
|
10
11
|
defineProps({
|
|
11
12
|
userMenuItems: { type: Array, required: false },
|
|
@@ -69,9 +70,6 @@ light.setMyFavorites(toRaw(my.myFavorites));
|
|
|
69
70
|
const myFavorites = computed(() => {
|
|
70
71
|
return light.getMyFavorites();
|
|
71
72
|
});
|
|
72
|
-
const myFavoritesCount = computed(() => {
|
|
73
|
-
return light.getMyFavorites().length;
|
|
74
|
-
});
|
|
75
73
|
$q.dark.set(light.isDarkMode());
|
|
76
74
|
const i18n = useI18n();
|
|
77
75
|
i18n.locale.value = my.language || "en";
|
|
@@ -81,8 +79,26 @@ for (let t of app.i18nMessages) {
|
|
|
81
79
|
messages[t.name] = t.value;
|
|
82
80
|
}
|
|
83
81
|
i18n.setLocaleMessage(i18n.locale.value, messages);
|
|
84
|
-
const menus = ref(app.menus);
|
|
85
|
-
const my_menus = ref(my.menu);
|
|
82
|
+
const menus = ref(app.menus || []);
|
|
83
|
+
const my_menus = ref(my.menu || []);
|
|
84
|
+
const menuSearch = ref("");
|
|
85
|
+
const translateMenuLabel = (label) => i18n.t(label);
|
|
86
|
+
const filteredMenus = computed(
|
|
87
|
+
() => filterMenuItems(menus.value, menuSearch.value, translateMenuLabel)
|
|
88
|
+
);
|
|
89
|
+
const filteredMyMenus = computed(
|
|
90
|
+
() => filterMenuItems(my_menus.value, menuSearch.value, translateMenuLabel)
|
|
91
|
+
);
|
|
92
|
+
const filteredMyFavorites = computed(
|
|
93
|
+
() => filterMenuItems(myFavorites.value, menuSearch.value, translateMenuLabel)
|
|
94
|
+
);
|
|
95
|
+
const normalizedMenuSearch = computed(
|
|
96
|
+
() => (menuSearch.value || "").trim().toLocaleLowerCase()
|
|
97
|
+
);
|
|
98
|
+
const isSearchingMenu = computed(() => normalizedMenuSearch.value.length > 0);
|
|
99
|
+
const hasMenuSearchResults = computed(
|
|
100
|
+
() => filteredMyMenus.value.length > 0 || filteredMyFavorites.value.length > 0 || filteredMenus.value.length > 0
|
|
101
|
+
);
|
|
86
102
|
const leftDrawerOpen = ref(false);
|
|
87
103
|
const rightDrawerOpen = ref(false);
|
|
88
104
|
const toggleLeftDrawer = () => {
|
|
@@ -142,8 +158,8 @@ const reloadMenu = async () => {
|
|
|
142
158
|
menu: true
|
|
143
159
|
}
|
|
144
160
|
});
|
|
145
|
-
menus.value = app2.menus;
|
|
146
|
-
my_menus.value
|
|
161
|
+
menus.value = app2.menus || [];
|
|
162
|
+
my_menus.value = my2.menu || [];
|
|
147
163
|
};
|
|
148
164
|
provide("reloadMenu", reloadMenu);
|
|
149
165
|
watch(() => style.footer, async (value) => await light.setStyle("footer", value));
|
|
@@ -413,9 +429,26 @@ const onLogout = async () => {
|
|
|
413
429
|
<!-- drawer content -->
|
|
414
430
|
<q-scroll-area class="fit">
|
|
415
431
|
<div class="q-mx-xs q-mt-xs">
|
|
416
|
-
<
|
|
417
|
-
|
|
418
|
-
|
|
432
|
+
<q-input v-if="!isMini" v-model="menuSearch" :placeholder="$t('Search menu')" dense outlined
|
|
433
|
+
clearable :dark="menuDark" class="q-mb-sm" input-class="text-body2"
|
|
434
|
+
:aria-label="$t('Search menu')" @keyup.esc="menuSearch = ''">
|
|
435
|
+
<template #prepend>
|
|
436
|
+
<q-icon name="sym_o_search" />
|
|
437
|
+
</template>
|
|
438
|
+
</q-input>
|
|
439
|
+
|
|
440
|
+
<l-menu :key="`my-${normalizedMenuSearch}`" :value="filteredMyMenus" :dense="style.dense"
|
|
441
|
+
:expand-all="isSearchingMenu" />
|
|
442
|
+
<l-fav-menu :value="filteredMyFavorites" :dense="style.dense"
|
|
443
|
+
:expand-all="isSearchingMenu" v-if="filteredMyFavorites.length > 0" />
|
|
444
|
+
<l-menu :key="`app-${normalizedMenuSearch}`" :value="filteredMenus" :dense="style.dense"
|
|
445
|
+
:expand-all="isSearchingMenu" />
|
|
446
|
+
|
|
447
|
+
<div v-if="isSearchingMenu && !hasMenuSearchResults"
|
|
448
|
+
class="column items-center text-grey-6 q-pa-lg">
|
|
449
|
+
<q-icon name="sym_o_search_off" size="md" class="q-mb-sm" />
|
|
450
|
+
<span>{{ $t("No matching menu") }}</span>
|
|
451
|
+
</div>
|
|
419
452
|
</div>
|
|
420
453
|
</q-scroll-area>
|
|
421
454
|
</q-drawer>
|
|
@@ -20,7 +20,7 @@ type __VLS_Props = {
|
|
|
20
20
|
userMenuItems?: UserMenuItem[];
|
|
21
21
|
headerButtons?: HeaderButton[];
|
|
22
22
|
};
|
|
23
|
-
declare var __VLS_38: {}, __VLS_61: `header-button-menu-${string}`, __VLS_62: {}, __VLS_132: `header-button-menu-${string}`, __VLS_133: {}, __VLS_340: {},
|
|
23
|
+
declare var __VLS_38: {}, __VLS_61: `header-button-menu-${string}`, __VLS_62: {}, __VLS_132: `header-button-menu-${string}`, __VLS_133: {}, __VLS_340: {}, __VLS_501: {}, __VLS_508: {};
|
|
24
24
|
type __VLS_Slots = {} & {
|
|
25
25
|
[K in NonNullable<typeof __VLS_61>]?: (props: typeof __VLS_62) => any;
|
|
26
26
|
} & {
|
|
@@ -30,9 +30,9 @@ type __VLS_Slots = {} & {
|
|
|
30
30
|
} & {
|
|
31
31
|
'user-menu'?: (props: typeof __VLS_340) => any;
|
|
32
32
|
} & {
|
|
33
|
-
'page-top'?: (props: typeof
|
|
33
|
+
'page-top'?: (props: typeof __VLS_501) => any;
|
|
34
34
|
} & {
|
|
35
|
-
'page-bottom'?: (props: typeof
|
|
35
|
+
'page-bottom'?: (props: typeof __VLS_508) => any;
|
|
36
36
|
};
|
|
37
37
|
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
38
38
|
logout: (...args: any[]) => void;
|
|
@@ -1,7 +1,23 @@
|
|
|
1
1
|
declare const _default: typeof __VLS_export;
|
|
2
2
|
export default _default;
|
|
3
|
-
declare const __VLS_export: import("vue").DefineComponent<
|
|
3
|
+
declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
4
|
+
appId: {
|
|
5
|
+
type: StringConstructor;
|
|
6
|
+
required: true;
|
|
7
|
+
};
|
|
8
|
+
disable: BooleanConstructor;
|
|
9
|
+
}>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
10
|
+
error: (...args: any[]) => void;
|
|
4
11
|
login: (...args: any[]) => void;
|
|
5
|
-
}, string, import("vue").PublicProps, Readonly<
|
|
12
|
+
}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
13
|
+
appId: {
|
|
14
|
+
type: StringConstructor;
|
|
15
|
+
required: true;
|
|
16
|
+
};
|
|
17
|
+
disable: BooleanConstructor;
|
|
18
|
+
}>> & Readonly<{
|
|
19
|
+
onError?: ((...args: any[]) => any) | undefined;
|
|
6
20
|
onLogin?: ((...args: any[]) => any) | undefined;
|
|
7
|
-
}>, {
|
|
21
|
+
}>, {
|
|
22
|
+
disable: boolean;
|
|
23
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
@@ -1,20 +1,81 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
2
|
+
import { onMounted, ref } from "vue";
|
|
3
|
+
import { useQuasar } from "quasar";
|
|
4
|
+
import { fabFacebookF } from "@quasar/extras/fontawesome-v7";
|
|
5
|
+
import { loadFacebookSdk } from "../../utils/socialSdk";
|
|
6
|
+
const props = defineProps({
|
|
7
|
+
appId: {
|
|
8
|
+
type: String,
|
|
9
|
+
required: true
|
|
10
|
+
},
|
|
11
|
+
disable: Boolean
|
|
9
12
|
});
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
+
const emit = defineEmits(["login", "error"]);
|
|
14
|
+
const $q = useQuasar();
|
|
15
|
+
const sdk = ref(null);
|
|
16
|
+
const loading = ref(true);
|
|
17
|
+
const loggingIn = ref(false);
|
|
18
|
+
const unavailable = ref(false);
|
|
19
|
+
const errorMessage = (error) => error instanceof Error ? error.message : String(error);
|
|
20
|
+
const loadSdk = async () => {
|
|
21
|
+
loading.value = true;
|
|
22
|
+
unavailable.value = false;
|
|
23
|
+
try {
|
|
24
|
+
sdk.value = await loadFacebookSdk(props.appId);
|
|
25
|
+
} catch (error) {
|
|
26
|
+
unavailable.value = true;
|
|
27
|
+
emit("error", error);
|
|
28
|
+
$q.notify({
|
|
29
|
+
message: errorMessage(error),
|
|
30
|
+
color: "negative",
|
|
31
|
+
icon: "sym_o_error"
|
|
32
|
+
});
|
|
33
|
+
} finally {
|
|
34
|
+
loading.value = false;
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
const onClick = async () => {
|
|
38
|
+
if (props.disable || loggingIn.value) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
if (!sdk.value) {
|
|
42
|
+
await loadSdk();
|
|
43
|
+
}
|
|
44
|
+
if (!sdk.value) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
loggingIn.value = true;
|
|
48
|
+
sdk.value.login((response) => {
|
|
49
|
+
loggingIn.value = false;
|
|
50
|
+
const accessToken = response.authResponse?.accessToken;
|
|
51
|
+
if (accessToken) {
|
|
52
|
+
emit("login", accessToken);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
if (response.status && response.status !== "unknown") {
|
|
56
|
+
const error = new Error("Facebook login did not return an access token");
|
|
57
|
+
emit("error", error);
|
|
58
|
+
$q.notify({
|
|
59
|
+
message: error.message,
|
|
60
|
+
color: "negative",
|
|
61
|
+
icon: "sym_o_error"
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}, {
|
|
65
|
+
scope: "public_profile,email"
|
|
13
66
|
});
|
|
14
67
|
};
|
|
68
|
+
onMounted(loadSdk);
|
|
15
69
|
</script>
|
|
16
70
|
|
|
17
71
|
<template>
|
|
18
|
-
<
|
|
19
|
-
|
|
72
|
+
<q-btn
|
|
73
|
+
no-caps
|
|
74
|
+
color="indigo"
|
|
75
|
+
:icon="fabFacebookF"
|
|
76
|
+
:label="$t('Continue with Facebook')"
|
|
77
|
+
:loading="loading || loggingIn"
|
|
78
|
+
:disable="disable || unavailable"
|
|
79
|
+
@click="onClick"
|
|
80
|
+
/>
|
|
20
81
|
</template>
|
|
@@ -1,7 +1,23 @@
|
|
|
1
1
|
declare const _default: typeof __VLS_export;
|
|
2
2
|
export default _default;
|
|
3
|
-
declare const __VLS_export: import("vue").DefineComponent<
|
|
3
|
+
declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
4
|
+
appId: {
|
|
5
|
+
type: StringConstructor;
|
|
6
|
+
required: true;
|
|
7
|
+
};
|
|
8
|
+
disable: BooleanConstructor;
|
|
9
|
+
}>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
10
|
+
error: (...args: any[]) => void;
|
|
4
11
|
login: (...args: any[]) => void;
|
|
5
|
-
}, string, import("vue").PublicProps, Readonly<
|
|
12
|
+
}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
13
|
+
appId: {
|
|
14
|
+
type: StringConstructor;
|
|
15
|
+
required: true;
|
|
16
|
+
};
|
|
17
|
+
disable: BooleanConstructor;
|
|
18
|
+
}>> & Readonly<{
|
|
19
|
+
onError?: ((...args: any[]) => any) | undefined;
|
|
6
20
|
onLogin?: ((...args: any[]) => any) | undefined;
|
|
7
|
-
}>, {
|
|
21
|
+
}>, {
|
|
22
|
+
disable: boolean;
|
|
23
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
@@ -3,7 +3,9 @@ export default _default;
|
|
|
3
3
|
declare const __VLS_export: import("vue").DefineComponent<{
|
|
4
4
|
value?: any;
|
|
5
5
|
dense?: any;
|
|
6
|
+
expandAll?: any;
|
|
6
7
|
}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{
|
|
7
8
|
value?: any;
|
|
8
9
|
dense?: any;
|
|
10
|
+
expandAll?: any;
|
|
9
11
|
}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { computed, ref, watch } from "vue";
|
|
3
3
|
import { useLight } from "#imports";
|
|
4
4
|
const light = useLight();
|
|
5
|
-
const props = defineProps(["value", "dense"]);
|
|
5
|
+
const props = defineProps(["value", "dense", "expandAll"]);
|
|
6
6
|
const favMenuExpanded = ref(
|
|
7
7
|
typeof window !== "undefined" ? JSON.parse(localStorage.getItem("fav-menu-expanded") || "false") : false
|
|
8
8
|
);
|
|
@@ -11,6 +11,14 @@ watch(favMenuExpanded, (newValue) => {
|
|
|
11
11
|
localStorage.setItem("fav-menu-expanded", JSON.stringify(newValue));
|
|
12
12
|
}
|
|
13
13
|
});
|
|
14
|
+
const displayedExpanded = computed({
|
|
15
|
+
get: () => props.expandAll || favMenuExpanded.value,
|
|
16
|
+
set: (value) => {
|
|
17
|
+
if (!props.expandAll) {
|
|
18
|
+
favMenuExpanded.value = value;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
});
|
|
14
22
|
const color1 = computed(() => {
|
|
15
23
|
return light.getColorValue();
|
|
16
24
|
});
|
|
@@ -27,7 +35,7 @@ const color2 = computed(() => {
|
|
|
27
35
|
|
|
28
36
|
<template>
|
|
29
37
|
<q-expansion-item :label="$t('My favorite')" :dense="dense" icon="sym_o_favorite"
|
|
30
|
-
v-model="
|
|
38
|
+
v-model="displayedExpanded">
|
|
31
39
|
<q-list class="q-pl-md menu-list" :dense="dense">
|
|
32
40
|
<q-item v-ripple :to="item.path" v-for="item in value">
|
|
33
41
|
<q-item-section avatar>
|
|
@@ -3,7 +3,9 @@ export default _default;
|
|
|
3
3
|
declare const __VLS_export: import("vue").DefineComponent<{
|
|
4
4
|
value?: any;
|
|
5
5
|
dense?: any;
|
|
6
|
+
expandAll?: any;
|
|
6
7
|
}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{
|
|
7
8
|
value?: any;
|
|
8
9
|
dense?: any;
|
|
10
|
+
expandAll?: any;
|
|
9
11
|
}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
@@ -1,70 +1,43 @@
|
|
|
1
|
-
|
|
1
|
+
import type { LFormGutter, LFormLayout } from "../../types/form.js";
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
actions?: boolean;
|
|
4
|
+
bordered?: boolean;
|
|
5
|
+
gutter?: LFormGutter;
|
|
6
|
+
layout?: LFormLayout;
|
|
7
|
+
modelValue?: Record<string, unknown>;
|
|
8
|
+
noRedirect?: boolean;
|
|
9
|
+
submitIcon?: string;
|
|
10
|
+
submitLabel?: string;
|
|
11
|
+
};
|
|
12
|
+
declare var __VLS_17: {}, __VLS_20: {
|
|
13
|
+
loading: boolean;
|
|
14
|
+
}, __VLS_22: {
|
|
15
|
+
loading: boolean;
|
|
16
|
+
};
|
|
2
17
|
type __VLS_Slots = {} & {
|
|
3
|
-
default?: (props: typeof
|
|
18
|
+
default?: (props: typeof __VLS_17) => any;
|
|
19
|
+
} & {
|
|
20
|
+
actions?: (props: typeof __VLS_20) => any;
|
|
21
|
+
} & {
|
|
22
|
+
buttons?: (props: typeof __VLS_22) => any;
|
|
4
23
|
};
|
|
5
|
-
declare const __VLS_base: import("vue").DefineComponent<import("vue").
|
|
6
|
-
modelValue: {
|
|
7
|
-
type: ObjectConstructor;
|
|
8
|
-
};
|
|
9
|
-
bordered: {
|
|
10
|
-
type: BooleanConstructor;
|
|
11
|
-
default: boolean;
|
|
12
|
-
};
|
|
13
|
-
gutter: {
|
|
14
|
-
type: StringConstructor;
|
|
15
|
-
default: string;
|
|
16
|
-
};
|
|
17
|
-
submitLabel: {
|
|
18
|
-
type: StringConstructor;
|
|
19
|
-
default: string;
|
|
20
|
-
};
|
|
21
|
-
submitIcon: {
|
|
22
|
-
type: StringConstructor;
|
|
23
|
-
default: string;
|
|
24
|
-
};
|
|
25
|
-
noRedirect: {
|
|
26
|
-
type: BooleanConstructor;
|
|
27
|
-
default: boolean;
|
|
28
|
-
};
|
|
29
|
-
}>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
24
|
+
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
30
25
|
submit: (...args: any[]) => void;
|
|
31
26
|
save: (...args: any[]) => void;
|
|
32
27
|
submitted: (...args: any[]) => void;
|
|
33
|
-
}, string, import("vue").PublicProps, Readonly<
|
|
34
|
-
modelValue: {
|
|
35
|
-
type: ObjectConstructor;
|
|
36
|
-
};
|
|
37
|
-
bordered: {
|
|
38
|
-
type: BooleanConstructor;
|
|
39
|
-
default: boolean;
|
|
40
|
-
};
|
|
41
|
-
gutter: {
|
|
42
|
-
type: StringConstructor;
|
|
43
|
-
default: string;
|
|
44
|
-
};
|
|
45
|
-
submitLabel: {
|
|
46
|
-
type: StringConstructor;
|
|
47
|
-
default: string;
|
|
48
|
-
};
|
|
49
|
-
submitIcon: {
|
|
50
|
-
type: StringConstructor;
|
|
51
|
-
default: string;
|
|
52
|
-
};
|
|
53
|
-
noRedirect: {
|
|
54
|
-
type: BooleanConstructor;
|
|
55
|
-
default: boolean;
|
|
56
|
-
};
|
|
57
|
-
}>> & Readonly<{
|
|
28
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
58
29
|
onSubmit?: ((...args: any[]) => any) | undefined;
|
|
59
30
|
onSave?: ((...args: any[]) => any) | undefined;
|
|
60
31
|
onSubmitted?: ((...args: any[]) => any) | undefined;
|
|
61
32
|
}>, {
|
|
33
|
+
actions: boolean;
|
|
62
34
|
bordered: boolean;
|
|
63
|
-
gutter:
|
|
64
|
-
|
|
65
|
-
submitIcon: string;
|
|
35
|
+
gutter: LFormGutter;
|
|
36
|
+
layout: LFormLayout;
|
|
66
37
|
noRedirect: boolean;
|
|
67
|
-
|
|
38
|
+
submitIcon: string;
|
|
39
|
+
submitLabel: string;
|
|
40
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
68
41
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
69
42
|
declare const _default: typeof __VLS_export;
|
|
70
43
|
export default _default;
|
|
@@ -1,48 +1,41 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import { computed, ref, useAttrs,
|
|
3
|
-
import {
|
|
4
|
-
import { useQuasar
|
|
2
|
+
import { computed, getCurrentInstance, ref, useAttrs, useSlots } from "vue";
|
|
3
|
+
import { useRoute, useRouter } from "vue-router";
|
|
4
|
+
import { useQuasar } from "quasar";
|
|
5
5
|
import { model } from "#imports";
|
|
6
|
+
defineOptions({ inheritAttrs: false });
|
|
7
|
+
const props = defineProps({
|
|
8
|
+
actions: { type: Boolean, required: false, default: true },
|
|
9
|
+
bordered: { type: Boolean, required: false, default: true },
|
|
10
|
+
gutter: { type: String, required: false, default: "md" },
|
|
11
|
+
layout: { type: String, required: false, default: "grid" },
|
|
12
|
+
modelValue: { type: Object, required: false },
|
|
13
|
+
noRedirect: { type: Boolean, required: false, default: false },
|
|
14
|
+
submitIcon: { type: String, required: false, default: "sym_o_save" },
|
|
15
|
+
submitLabel: { type: String, required: false, default: "Save" }
|
|
16
|
+
});
|
|
17
|
+
const emit = defineEmits(["save", "submit", "submitted"]);
|
|
18
|
+
const attrs = useAttrs();
|
|
19
|
+
const slots = useSlots();
|
|
6
20
|
const route = useRoute();
|
|
7
21
|
const router = useRouter();
|
|
8
22
|
const quasar = useQuasar();
|
|
9
23
|
const form = ref(null);
|
|
10
|
-
const props = defineProps({
|
|
11
|
-
modelValue: {
|
|
12
|
-
type: Object
|
|
13
|
-
},
|
|
14
|
-
bordered: {
|
|
15
|
-
type: Boolean,
|
|
16
|
-
default: true
|
|
17
|
-
},
|
|
18
|
-
gutter: {
|
|
19
|
-
type: String,
|
|
20
|
-
default: "md"
|
|
21
|
-
},
|
|
22
|
-
submitLabel: {
|
|
23
|
-
type: String,
|
|
24
|
-
default: "Save"
|
|
25
|
-
},
|
|
26
|
-
submitIcon: {
|
|
27
|
-
type: String,
|
|
28
|
-
default: "sym_o_save"
|
|
29
|
-
},
|
|
30
|
-
noRedirect: {
|
|
31
|
-
type: Boolean,
|
|
32
|
-
default: false
|
|
33
|
-
}
|
|
34
|
-
});
|
|
35
24
|
const loading = ref(false);
|
|
36
|
-
const attrs = useAttrs();
|
|
37
|
-
const emit = defineEmits(["save", "submit", "submitted"]);
|
|
38
25
|
const instance = getCurrentInstance();
|
|
39
|
-
const hasSubmitListener = computed(() =>
|
|
40
|
-
|
|
41
|
-
|
|
26
|
+
const hasSubmitListener = computed(() => Boolean(instance?.vnode.props?.onSubmit));
|
|
27
|
+
const hasCustomActions = computed(() => Boolean(slots.actions || slots.buttons));
|
|
28
|
+
const contentClass = computed(() => attrs.class);
|
|
29
|
+
const formAttrs = computed(() => Object.fromEntries(
|
|
30
|
+
Object.entries(attrs).filter(([key]) => key !== "class")
|
|
31
|
+
));
|
|
32
|
+
const routeParts = computed(() => typeof route.name === "string" ? route.name.split("-") : []);
|
|
33
|
+
const modelName = computed(() => routeParts.value[0]);
|
|
34
|
+
const idName = computed(() => routeParts.value[1]);
|
|
42
35
|
const save = async () => {
|
|
43
|
-
if (!form.value)
|
|
44
|
-
|
|
45
|
-
|
|
36
|
+
if (!form.value || !await form.value.validate()) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
46
39
|
emit("save");
|
|
47
40
|
if (hasSubmitListener.value) {
|
|
48
41
|
emit("submit", () => {
|
|
@@ -50,57 +43,54 @@ const save = async () => {
|
|
|
50
43
|
});
|
|
51
44
|
return;
|
|
52
45
|
}
|
|
53
|
-
if (props.modelValue
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
} else {
|
|
64
|
-
if (await model(module).add(props.modelValue)) {
|
|
65
|
-
if (!props.noRedirect) {
|
|
66
|
-
router.push(`/${module}`);
|
|
67
|
-
}
|
|
68
|
-
emit("submitted");
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
} catch (e) {
|
|
73
|
-
quasar.dialog({
|
|
74
|
-
title: "Error",
|
|
75
|
-
message: e.message,
|
|
76
|
-
ok: "OK"
|
|
77
|
-
});
|
|
46
|
+
if (!props.modelValue || !modelName.value) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
loading.value = true;
|
|
50
|
+
try {
|
|
51
|
+
const routeId = idName.value ? route.params[idName.value] : void 0;
|
|
52
|
+
const saved = routeId ? await model(modelName.value).update(Number(routeId), props.modelValue) : await model(modelName.value).add(props.modelValue);
|
|
53
|
+
if (!saved) {
|
|
54
|
+
return;
|
|
78
55
|
}
|
|
56
|
+
if (!props.noRedirect) {
|
|
57
|
+
await router.push(`/${modelName.value}`);
|
|
58
|
+
}
|
|
59
|
+
emit("submitted");
|
|
60
|
+
} catch (error) {
|
|
61
|
+
quasar.dialog({
|
|
62
|
+
title: "Error",
|
|
63
|
+
message: error instanceof Error ? error.message : String(error),
|
|
64
|
+
ok: "OK"
|
|
65
|
+
});
|
|
66
|
+
} finally {
|
|
67
|
+
loading.value = false;
|
|
79
68
|
}
|
|
80
|
-
loading.value = false;
|
|
81
69
|
};
|
|
82
|
-
const onSubmit = (
|
|
83
|
-
|
|
84
|
-
save();
|
|
70
|
+
const onSubmit = async (event) => {
|
|
71
|
+
event.preventDefault();
|
|
72
|
+
await save();
|
|
85
73
|
};
|
|
86
|
-
const localClass = computed(() => {
|
|
87
|
-
if (attrs.class) {
|
|
88
|
-
return attrs.class;
|
|
89
|
-
}
|
|
90
|
-
return "row q-col-gutter-" + props.gutter;
|
|
91
|
-
});
|
|
92
74
|
</script>
|
|
93
75
|
|
|
94
76
|
<template>
|
|
95
|
-
<q-form ref="form" @submit="onSubmit">
|
|
96
|
-
<l-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
77
|
+
<q-form ref="form" v-bind="formAttrs" @submit="onSubmit">
|
|
78
|
+
<l-form-layout
|
|
79
|
+
:actions="actions"
|
|
80
|
+
:bordered="bordered"
|
|
81
|
+
:content-class="contentClass"
|
|
82
|
+
:gutter="gutter"
|
|
83
|
+
:layout="layout"
|
|
84
|
+
:submit-icon="submitIcon"
|
|
85
|
+
:submit-label="submitLabel"
|
|
86
|
+
:submit-loading="loading"
|
|
87
|
+
>
|
|
88
|
+
<slot />
|
|
100
89
|
|
|
101
|
-
<
|
|
102
|
-
<
|
|
103
|
-
|
|
104
|
-
|
|
90
|
+
<template v-if="hasCustomActions" #actions>
|
|
91
|
+
<slot v-if="$slots.actions" name="actions" :loading="loading" />
|
|
92
|
+
<slot v-else name="buttons" :loading="loading" />
|
|
93
|
+
</template>
|
|
94
|
+
</l-form-layout>
|
|
105
95
|
</q-form>
|
|
106
96
|
</template>
|