@hostlink/nuxt-light 0.0.114 → 0.0.115

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 CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "light",
3
3
  "configKey": "light",
4
- "version": "0.0.114"
4
+ "version": "0.0.115"
5
5
  }
@@ -1,5 +1,9 @@
1
1
  <script setup>
2
- import { ref, computed } from "vue";
2
+ import { ref, computed, useAttrs } from "vue";
3
+ import { useLight } from '../';
4
+
5
+ const light = useLight();
6
+
3
7
  const props = defineProps({
4
8
  modelValue: {
5
9
  type: String
@@ -21,9 +25,22 @@ const localValue = computed({
21
25
  set: (value) => emit("update:modelValue", value),
22
26
  })
23
27
 
28
+ const attrs = {
29
+
30
+ ...{
31
+ filled: light.getStyle("inputFilled"),
32
+ outlined: light.getStyle("inputOutlined"),
33
+ standout: light.getStyle("inputStandout"),
34
+ rounded: light.getStyle("inputRounded"),
35
+ dense: light.getStyle("inputDense"),
36
+ square: light.getStyle("inputSquare"),
37
+ stackLabel: light.getStyle("inputStackLabel")
38
+ },
39
+ ...useAttrs(),
40
+ }
24
41
  </script>
25
42
  <template>
26
- <q-input v-model="localValue">
43
+ <q-input v-bind="attrs" v-model="localValue">
27
44
  <q-dialog v-model="show" full-height full-width>
28
45
  <l-file-manager closable @close="show = false" @input="onInput"></l-file-manager>
29
46
  </q-dialog>
@@ -1,5 +1,5 @@
1
1
  <script setup>
2
- import { computed, ref, useAttrs } from "vue";
2
+ import { computed, ref, useAttrs, useSlots } from "vue";
3
3
  import { useI18n } from 'vue-i18n';
4
4
  import tc2sc from "../lib/tc2sc";
5
5
  import { useLight } from '../';
@@ -164,12 +164,17 @@ const attrs = {
164
164
  },
165
165
  ...useAttrs(),
166
166
  }
167
+
168
+ const ss = Object.entries(useSlots()).map(([key, value]) => {
169
+ return key;
170
+ });
171
+
167
172
  </script>
168
173
  <template>
169
174
  <q-input v-bind="attrs" :label="localLabel" v-model="localValue" :rules="new_rules" hide-bottom-space :type="localType">
170
175
  <template v-if="translate" #prepend>
171
176
  <q-btn icon="sym_o_translate" flat dense rounded>
172
- <q-menu dens>
177
+ <q-menu dense>
173
178
  <q-list>
174
179
  <q-item clickable v-close-popup @click="onClickTc2Sc">
175
180
  <q-item-section>繁轉簡</q-item-section>
@@ -177,7 +182,10 @@ const attrs = {
177
182
  </q-list>
178
183
  </q-menu>
179
184
  </q-btn>
185
+ </template>
180
186
 
187
+ <template v-for="s in ss" v-slot:[s]="props" :key="s">
188
+ <slot :name="s" v-bind="props ?? {}"></slot>
181
189
  </template>
182
190
 
183
191
  <template v-if="localShowPassword" v-slot:append>
@@ -618,25 +618,25 @@ 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 v-model.number="filters[col.name]" @keydown.enter.prevent="onFilters"
622
- @clear="onFilters" mask="##########"></q-input>
621
+ <q-input dense clearable filled square v-model.number="filters[col.name]"
622
+ @keydown.enter.prevent="onFilters" @clear="onFilters" mask="##########"></q-input>
623
623
  </template>
624
624
 
625
625
  <template v-if="col.searchType == 'select'">
626
- <q-select dense v-model="filters[col.name]" @update:model-value="onFilters" clearable
627
- options-dense :options="col.searchOptions" emit-value map-options
628
- :multiple="col.searchMultiple" />
626
+ <q-select dense clearable filled square v-model="filters[col.name]"
627
+ @update:model-value="onFilters" options-dense :options="col.searchOptions" emit-value
628
+ map-options :multiple="col.searchMultiple" />
629
629
 
630
630
  </template>
631
631
 
632
632
  <template v-if="col.searchType == 'date'">
633
- <l-date-picker :outlined="false" hide-bottom-space v-model="filters[col.name]" dense
634
- @update:model-value="onFilters" clearable range @clear="onFilters" />
633
+ <l-date-picker dense clearable filled square :outlined="false" hide-bottom-space
634
+ v-model="filters[col.name]" @update:model-value="onFilters" range @clear="onFilters" />
635
635
  </template>
636
636
 
637
637
  <template v-if="!col.searchType">
638
- <q-input dense clearable v-model="filters[col.name]" @keydown.enter.prevent="onFilters"
639
- @clear="onFilters" enterkeyhint="search"></q-input>
638
+ <q-input dense clearable filled square v-model="filters[col.name]"
639
+ @keydown.enter.prevent="onFilters" @clear="onFilters" enterkeyhint="search"></q-input>
640
640
 
641
641
  </template>
642
642
 
@@ -1,5 +1,8 @@
1
1
  <script setup>
2
- import { computed, ref } from "vue";
2
+ import { computed, ref, useAttrs } from "vue";
3
+ import { useLight } from '../';
4
+ const light = useLight();
5
+
3
6
  const props = defineProps({
4
7
  modelValue: {
5
8
  type: [String, Object],
@@ -35,11 +38,23 @@ if (props.required) {
35
38
  }
36
39
 
37
40
 
41
+ const attrs = {
42
+ ...{
43
+ filled: light.getStyle("inputFilled"),
44
+ outlined: light.getStyle("inputOutlined"),
45
+ standout: light.getStyle("inputStandout"),
46
+ rounded: light.getStyle("inputRounded"),
47
+ dense: light.getStyle("inputDense"),
48
+ square: light.getStyle("inputSquare"),
49
+ stackLabel: light.getStyle("inputStackLabel")
50
+ },
51
+ ...useAttrs(),
52
+ }
38
53
 
39
54
 
40
55
  </script>
41
56
  <template>
42
- <q-input v-model="localValue" mask="time" :rules="rules" :label="$t(label)" :hint="$t(hint)">
57
+ <q-input v-bind="attrs" v-model="localValue" mask="time" :rules="rules" :label="$t(label)" :hint="$t(hint)">
43
58
  <template v-slot:prepend>
44
59
  <q-btn icon="sym_o_access_time" round dense flat>
45
60
  <q-popup-proxy cover transition-show="scale" transition-hide="scale" ref="popup">
@@ -0,0 +1,27 @@
1
+ <script setup>
2
+ import { getErrorMessage } from 'formkit-quasar';
3
+ import { computed, useSlots } from 'vue'
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
+ const ss = Object.entries(useSlots()).map(([key, value]) => {
14
+ return key;
15
+ });
16
+
17
+ const { error, errorMessage } = getErrorMessage(props.context.node);
18
+
19
+
20
+ </script>
21
+ <template>
22
+ <l-checkbox v-model="value" :label="context.label" v-bind="context.attrs" :error="error" :error-message="errorMessage">
23
+ <template v-for="s in ss" v-slot:[s]="props" :key="s">
24
+ <slot :name="s" v-bind="props ?? {}"></slot>
25
+ </template>
26
+ </l-checkbox>
27
+ </template>
@@ -0,0 +1,25 @@
1
+ <script setup>
2
+ import { computed, useSlots } 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
+ const ss = Object.entries(useSlots()).map(([key]) => key);
17
+ </script>
18
+ <template>
19
+ <l-date-picker v-model="value" :label="context.label" v-bind="context.attrs" :error="error" :type="context.inputType"
20
+ :error-message="errorMessage">
21
+ <template v-for="s in ss" v-slot:[s]="props" :key="s">
22
+ <slot :name="s" v-bind="props ?? {}"></slot>
23
+ </template>
24
+ </l-date-picker>
25
+ </template>
@@ -0,0 +1,33 @@
1
+ <script setup>
2
+ import { computed, useSlots } 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
+ const ss = Object.entries(useSlots()).map(([key]) => key);
17
+
18
+ const onBlur = () => {
19
+ if (errorMessage.value) {
20
+ error.value = true
21
+ } else {
22
+ error.value = false
23
+ }
24
+ }
25
+ </script>
26
+ <template>
27
+ <l-file v-model="value" :label="context.label" v-bind="context.attrs" :error="error" :type="context.inputType"
28
+ :error-message="errorMessage" @blur="onBlur">
29
+ <template v-for="s in ss" v-slot:[s]="props" :key="s">
30
+ <slot :name="s" v-bind="props ?? {}"></slot>
31
+ </template>
32
+ </l-file>
33
+ </template>
@@ -0,0 +1,72 @@
1
+ <script setup>
2
+ import { ref } from 'vue'
3
+ import { useRouter, useRoute } from "vue-router";
4
+ import { Dialog } from "quasar";
5
+ import { model } from "@hostlink/light"
6
+
7
+ const route = useRoute();
8
+ const router = useRouter();
9
+
10
+ let props = defineProps({
11
+ context: Object
12
+ });
13
+
14
+ let onSubmit = async () => {
15
+ props.context.handlers.submit(new Event("submit"));
16
+ }
17
+
18
+ const gutter = props.gutter ?? "md";
19
+
20
+ //check bordered is undefined
21
+ let bordered = true;
22
+ if (props.context.bordered !== undefined) {
23
+ bordered = props.context.bordered;
24
+ }
25
+ const loading = ref(false);
26
+ if (!props.context.onSubmit) {
27
+ props.context.node.props.onSubmit = async function () {
28
+ loading.value = true;
29
+ const [module, id_name] = route.name.split("-");
30
+
31
+ try {
32
+ if (route.params[id_name]) {//edit
33
+ if (await model(module).update(parseInt(route.params[id_name]), props.context.value)) {
34
+ router.go(-1);
35
+ return;
36
+ }
37
+ } else {
38
+ if (await model(module).add(props.context.value)) {
39
+ router.go(-1);
40
+ return;
41
+ }
42
+ }
43
+ } catch (e) {
44
+ Dialog.create({
45
+ title: "Error",
46
+ message: e.message,
47
+ ok: "OK"
48
+ });
49
+ }
50
+ loading.value = false;
51
+ }
52
+
53
+ }
54
+
55
+
56
+ </script>
57
+ <template>
58
+ <form v-bind="context.attrs">
59
+ <l-card :bordered="bordered">
60
+ <q-card-section>
61
+ <div :class="`q-gutter-${gutter}`">
62
+ <slot v-bind="context"></slot>
63
+ </div>
64
+ </q-card-section>
65
+
66
+ <q-card-actions align="right">
67
+ <l-btn color="primary" icon="sym_o_check" label="Submit" @click="onSubmit" :disabled="!context.state.dirty"
68
+ :loading="loading"></l-btn>
69
+ </q-card-actions>
70
+ </l-card>
71
+ </form>
72
+ </template>
@@ -0,0 +1,35 @@
1
+ <script setup>
2
+ import { computed, useSlots } 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
+ const ss = Object.entries(useSlots()).map(([key]) => key);
17
+
18
+ const onBlur = () => {
19
+ if (errorMessage.value) {
20
+ error.value = true
21
+ } else {
22
+ error.value = false
23
+ }
24
+ }
25
+
26
+
27
+ </script>
28
+ <template>
29
+ <l-input v-model="value" :label="context.label" v-bind="context.attrs" :error="error" :type="context.inputType"
30
+ :error-message="errorMessage" @blur="onBlur">
31
+ <template v-for="s in ss" v-slot:[s]="props" :key="s">
32
+ <slot :name="s" v-bind="props ?? {}"></slot>
33
+ </template>
34
+ </l-input>
35
+ </template>
@@ -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-field label="Roles" stack-label :label="context.label" :error="error" :error-message="errorMessage">
19
+ <q-option-group type="checkbox" :options="context.options" v-model="value" inline v-bind="context.attrs">
20
+ </q-option-group>
21
+ </l-field>
22
+ </template>
@@ -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
+ <q-radio v-model="value" :label="context.label" v-bind="context.attrs" :error="error" :type="context.inputType"
19
+ :error-message="errorMessage">
20
+ <slot></slot>
21
+ </q-radio>
22
+ </template>
@@ -0,0 +1,107 @@
1
+ <script setup>
2
+ import { ref, computed } from 'vue'
3
+
4
+ const props = defineProps({
5
+ context: Object
6
+ });
7
+
8
+ const node = props.context.node;
9
+ const min = props.context.node.props.min ?? 1;
10
+ const max = props.context.node.props.max ?? Infinity;
11
+
12
+ const localValue = ref(props.context.value)
13
+
14
+ if (localValue.value.length < min) {
15
+ for (let i = localValue.value.length; i < min; i++) {
16
+ localValue.value.push({})
17
+ }
18
+ }
19
+
20
+ if (localValue.value.length > max) {
21
+ localValue.value = localValue.value.slice(0, max)
22
+ }
23
+
24
+ const onAdd = () => {
25
+ if (localValue.value.length >= max) return;
26
+ localValue.value.push({})
27
+ }
28
+
29
+ const onRemove = (index) => {
30
+ if (localValue.value.length <= min) return;
31
+ localValue.value.splice(index, 1)
32
+ }
33
+
34
+ const onMoveUp = (index) => {
35
+ if (index > 0) {
36
+ let temp = localValue.value[index - 1]
37
+ localValue.value[index - 1] = localValue.value[index]
38
+ localValue.value[index] = temp
39
+ }
40
+ }
41
+
42
+ const onMoveDown = (index) => {
43
+ if (index < localValue.value.length - 1) {
44
+ let temp = localValue.value[index + 1]
45
+ localValue.value[index + 1] = localValue.value[index]
46
+ localValue.value[index] = temp
47
+ }
48
+ }
49
+
50
+ const isAllowRemove = computed(() => {
51
+ return localValue.value.length > min
52
+ })
53
+
54
+ const isAllowMoveUp = (index) => {
55
+ return index > 0
56
+ }
57
+
58
+ const isAllowMoveDown = (index) => {
59
+ return index < localValue.value.length - 1
60
+ }
61
+
62
+
63
+
64
+ </script>
65
+
66
+ <template>
67
+ <FormKit type="list" v-model="localValue" dynamic #default="{ items, node, value }">
68
+
69
+ <FormKit type="group" v-for="(item, index) in items " :index="index" :key="item">
70
+
71
+ <q-card class="q-mb-sm" flat>
72
+ <q-card-section>
73
+ <div class="row q-col-gutter-md">
74
+
75
+ <div class="col-shrink">
76
+ <div class="q-mb-sm">
77
+ <!-- up -->
78
+ <q-btn type="button" @click="onMoveUp(index)" icon="sym_o_arrow_upward" color="primary"
79
+ dense unelevated :disable="!isAllowMoveUp(index)"/>
80
+ </div>
81
+
82
+ <div class="q-mb-sm">
83
+ <q-btn type="button" @click="onRemove" icon="sym_o_remove" color="primary" dense unelevated
84
+ :disable="!isAllowRemove" />
85
+ </div>
86
+
87
+
88
+ <div class="q-mb-sm">
89
+ <!-- down -->
90
+ <q-btn type="button" @click="onMoveDown(index)" icon="sym_o_arrow_downward" color="primary"
91
+ dense unelevated :disable="!isAllowMoveDown(index)"/>
92
+ </div>
93
+
94
+ </div>
95
+
96
+ <div class="col">
97
+ <slot></slot>
98
+ </div>
99
+ </div>
100
+ </q-card-section>
101
+ </q-card>
102
+ </FormKit>
103
+
104
+ <q-btn color="primary" @click="onAdd" icon="sym_o_add" label="Add" :disable="localValue.length >= max"
105
+ unelevated></q-btn>
106
+ </FormKit>
107
+ </template>
@@ -0,0 +1,25 @@
1
+ <script setup>
2
+ import { getErrorMessage } from 'formkit-quasar';
3
+ import { computed, useSlots } from 'vue'
4
+ const props = defineProps({
5
+ context: Object
6
+ });
7
+
8
+ const { error, errorMessage } = getErrorMessage(props.context.node);
9
+
10
+ const value = computed({
11
+ get: () => props.context.value,
12
+ set: (val) => props.context.node.input(val)
13
+ })
14
+
15
+ const ss = Object.entries(useSlots()).map(([key, value]) => {
16
+ return key;
17
+ });
18
+ </script>
19
+ <template>
20
+ <l-select v-model="value" :label="context.label" v-bind="context.attrs" :error="error" :error-message="errorMessage">
21
+ <template v-for="s in ss" v-slot:[s]="props" :key="s">
22
+ <slot :name="s" v-bind="props ?? {}"></slot>
23
+ </template>
24
+ </l-select>
25
+ </template>
@@ -0,0 +1,25 @@
1
+ <script setup>
2
+ import { computed, useSlots } 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
+ const ss = Object.entries(useSlots()).map(([key]) => key);
17
+ </script>
18
+ <template>
19
+ <l-time-picker v-model="value" :label="context.label" v-bind="context.attrs" :error="error" :type="context.inputType"
20
+ :error-message="errorMessage">
21
+ <template v-for="s in ss" v-slot:[s]="props" :key="s">
22
+ <slot :name="s" v-bind="props ?? {}"></slot>
23
+ </template>
24
+ </l-time-picker>
25
+ </template>
@@ -0,0 +1,2 @@
1
+ import type { FormKitPlugin } from '@formkit/core';
2
+ export declare const createLightPlugin: () => FormKitPlugin;
@@ -0,0 +1,79 @@
1
+ import { forms, disablesChildren } from "@formkit/inputs";
2
+ import Input from "./Input.vue";
3
+ import SelectVue from "./Select.vue";
4
+ import RepeaterVue from "./Repeater.vue";
5
+ import FormVue from "./Form.vue";
6
+ import CheckboxVue from "./Checkbox.vue";
7
+ import RadioVue from "./Radio.vue";
8
+ import DatePickerVue from "./DatePicker.vue";
9
+ import TimePickerVue from "./TimePicker.vue";
10
+ import OptionGroupVue from "./OptionGroup.vue";
11
+ import FilePickerVue from "./FilePicker.vue";
12
+ export const createLightPlugin = () => {
13
+ return (node) => {
14
+ let type = node.props.type + "";
15
+ switch (type) {
16
+ case "l-file-picker":
17
+ return node.define({
18
+ type: "input",
19
+ component: FilePickerVue
20
+ });
21
+ case "l-option-group":
22
+ return node.define({
23
+ type: "input",
24
+ component: OptionGroupVue
25
+ });
26
+ case "l-time-picker":
27
+ return node.define({
28
+ type: "input",
29
+ component: TimePickerVue
30
+ });
31
+ case "l-date-picker":
32
+ return node.define({
33
+ type: "input",
34
+ component: DatePickerVue
35
+ });
36
+ case "l-radio":
37
+ return node.define({
38
+ type: "input",
39
+ component: RadioVue
40
+ });
41
+ case "l-checkbox":
42
+ return node.define({
43
+ type: "input",
44
+ component: CheckboxVue
45
+ });
46
+ case "l-input":
47
+ return node.define({
48
+ type: "input",
49
+ props: ["inputType"],
50
+ component: Input
51
+ });
52
+ case "l-select":
53
+ return node.define({
54
+ type: "input",
55
+ component: SelectVue
56
+ });
57
+ case "l-repeater":
58
+ return node.define({
59
+ type: "list",
60
+ props: ["min", "max"],
61
+ component: RepeaterVue
62
+ });
63
+ case "l-form":
64
+ return node.define({
65
+ type: "group",
66
+ component: FormVue,
67
+ props: [
68
+ "submitLabel",
69
+ "submit",
70
+ "actions",
71
+ "onSubmit",
72
+ "gutter",
73
+ "bordered"
74
+ ],
75
+ features: [forms, disablesChildren]
76
+ });
77
+ }
78
+ };
79
+ };
@@ -1,9 +1,5 @@
1
1
  <script setup>
2
- import { reactive } from 'vue'
3
2
  import { q } from '../../'
4
- const obj = reactive({
5
- childs: ["Users"],
6
- })
7
3
 
8
4
  let roles = await q("listRole", ["name"]);
9
5
  roles = roles.map((role) => {
@@ -13,18 +9,18 @@ roles = roles.map((role) => {
13
9
  };
14
10
  });
15
11
 
12
+ const onSubmit = (e) => {
13
+ e.preventDefault();
14
+ console.log("submit");
15
+ }
16
16
  </script>
17
17
 
18
18
  <template>
19
19
  <l-page>
20
- <l-form v-model="obj">
21
- <l-input v-model="obj.name" label="Name" required />
22
- <q-field label="Child" stack-label>
23
- <q-option-group type="checkbox" :options="roles" v-model="obj.childs" inline>
24
- </q-option-group>
25
- </q-field>
26
-
27
- </l-form>
20
+ <FormKit type="l-form" :value="{ childs: ['Users'] }" >
21
+ <FormKit type="l-input" name="name" label="Name" validation="required" />
22
+ <FormKit type="l-option-group" :options="roles" name="childs" label="Child" />
23
+ </FormKit>
28
24
 
29
25
  </l-page>
30
26
  </template>
@@ -1,31 +1,23 @@
1
1
  <script setup>
2
2
  import { q, m } from '../../../'
3
- import { useRouter, useRoute } from "vue-router"
4
- import { reactive } from "vue"
3
+ import { useRouter } from "vue-router"
5
4
  const system = await q("system", ["passwordPolicy"]);
6
5
  const router = useRouter();
7
- const route = useRoute();
8
6
 
9
- const obj = reactive({
10
- password: "",
11
- });
12
-
13
- const onUpdatePassword = async () => {
14
- if (await m("updateUserPassword", {
7
+ const onSubmit = async (data, form) => {
8
+ return await m("updateUserPassword", {
15
9
  id: route.params.user_id,
16
- password: obj.password
17
- })) {
10
+ password: data.password
11
+ }).then(() => {
18
12
  router.push("/User");
19
- }
13
+ });
20
14
  }
21
15
 
22
16
  </script>
23
17
  <template>
24
18
  <l-page>
25
- <l-form @save="onUpdatePassword">
26
- <l-input type="password" label="New password" v-model="obj.password" :rules="system.passwordPolicy">
27
- </l-input>
28
- </l-form>
29
-
19
+ <FormKit type="l-form" @submit="onSubmit">
20
+ <FormKit type="l-input" name="password" :validation="system.passwordPolicy" label="Password" input-type="password"></FormKit>
21
+ </FormKit>
30
22
  </l-page>
31
23
  </template>
@@ -18,11 +18,11 @@ roles = roles.map((role) => {
18
18
  };
19
19
  });
20
20
 
21
- const submit = async () => {
21
+ const submit = async (data, form) => {
22
22
 
23
23
  if (await m("updateUserRole", {
24
24
  user_id: obj.user_id,
25
- roles: obj.roles
25
+ roles: data.roles
26
26
  })) {
27
27
  //show success message
28
28
 
@@ -41,12 +41,11 @@ const submit = async () => {
41
41
  </script>
42
42
  <template>
43
43
  <l-page>
44
- <l-form @submit="submit">
45
- <l-field label="Roles" stack-label>
46
- <q-option-group type="checkbox" :options="roles" v-model="obj.roles" inline>
47
- </q-option-group>
48
- </l-field>
49
- </l-form>
44
+ <FormKit type="l-form" @submit="submit" :value="{ roles: obj.roles }">
45
+ <FormKit type="l-option-group" :options="roles" name="roles">
46
+ </FormKit>
47
+ </FormKit>
48
+
50
49
 
51
50
  </l-page>
52
51
  </template>
@@ -1,71 +1,94 @@
1
1
  <script setup>
2
2
  import { reactive } from "vue"
3
+ import { useRouter } from "vue-router";
4
+ import { model } from "@hostlink/light";
3
5
  import { q } from '../../'
6
+ const router = useRouter()
4
7
  const obj = reactive({
5
- roles: ['Users'],
8
+ username: null,
9
+ password: null,
10
+ first_name: null,
11
+ last_name: null,
12
+ email: null,
13
+ phone: null,
14
+ addr1: null,
15
+ addr2: null,
16
+ addr3: null,
17
+ join_date: new Date().toISOString().substring(0, 10), //YYYY-MM-DD (today)
18
+ expiry_date: null,
6
19
  status: 0,
7
20
  language: "en",
8
- //YYYY-MM-DD (today)
9
- join_date: new Date().toISOString().substring(0, 10),
10
-
21
+ default_page: null,
22
+ roles: ['Users'],
11
23
  })
12
24
 
13
- let roles = await q("listRole", ["name"]);
14
- roles = roles.map((role) => {
25
+ let { system, listRole } = await q({
26
+ system: {
27
+ passwordPolicy: true,
28
+ },
29
+ listRole: {
30
+ name: true,
31
+ }
32
+ })
33
+ const roles = listRole.map((role) => {
15
34
  return {
16
35
  label: role.name,
17
36
  value: role.name,
18
37
  };
19
38
  });
20
39
 
21
- const system = await q("system", ["passwordPolicy"]);
40
+
41
+ const options = [
42
+ { label: 'Active', value: 0 },
43
+ { label: 'Inactive', value: 1 }
44
+ ];
45
+
46
+ const languages = [
47
+ { label: 'English', value: 'en' },
48
+ { label: '中文', value: 'zh-hk' }
49
+ ]
50
+
51
+ const onSubmit = async (data) => {
52
+ return model("User").add(data).then((res) => {
53
+ router.push("/User");
54
+ }).catch((err) => {
55
+ console.log(err)
56
+ })
57
+ }
58
+
22
59
  </script>
23
60
  <template>
24
61
  <l-page>
25
- <l-form v-model="obj" gutter="none">
62
+ <FormKit type="l-form" :value="obj" @submit="onSubmit">
26
63
  <l-row>
27
64
  <l-col md="6" gutter="md">
28
- <l-input label="Username" v-model="obj.username" required />
29
- <l-input label="Password" v-model="obj.password" required type="password"
30
- :rules="system.passwordPolicy" />
31
- <l-input label="First name" v-model="obj.first_name" required />
32
- <l-input label="Last name" v-model="obj.last_name" />
33
- <l-input label="Email" v-model="obj.email" required type="email" />
65
+ <FormKit type="l-input" label="Username" name="username" validation="required" />
66
+ <FormKit type="l-input" label="Password" name="password" :validation="system.passwordPolicy"
67
+ input-type="password" />
68
+ <FormKit type="l-input" label="First name" name="first_name" validation="required" />
69
+ <FormKit type="l-input" label="Last name" name="last_name" />
70
+ <FormKit type="l-input" label="Email" name="email" validation="required|email" />
34
71
  </l-col>
72
+
35
73
  <l-col md="6" gutter="md">
36
- <l-input label="Phone" v-model="obj.phone" />
37
- <l-input label="Address1" v-model="obj.addr1" />
38
- <l-input label="Address2" v-model="obj.addr2" />
39
- <l-input label="Address3" v-model="obj.addr3" />
74
+ <FormKit type="l-input" label="Phone" name="phone" />
75
+ <FormKit type="l-input" label="Address1" name="addr1" />
76
+ <FormKit type="l-input" label="Address2" name="addr2" />
77
+ <FormKit type="l-input" label="Address3" name="addr3" />
40
78
  </l-col>
41
- <l-col gutter="md">
42
- <l-date-picker label="Join date" v-model="obj.join_date" required />
43
- <l-date-picker label="Expiry date" v-model="obj.expiry_date" />
44
-
45
- <l-select label="Status" :options="[{
46
- label: 'Active',
47
- value: 0
48
- }, {
49
- label: 'Inactive',
50
- value: 1
51
- }]" v-model="obj.status" required></l-select>
52
-
53
- <l-select label="Language" :options="[{
54
- label: 'English',
55
- value: 'en'
56
- }, {
57
- label: '中文',
58
- value: 'zh-hk'
59
- }]" v-model="obj.language" emit-value map-options required></l-select>
60
79
 
61
- <l-input label="Default page" v-model="obj.default_page"></l-input>
80
+ <l-col gutter="md">
81
+ <FormKit type="l-date-picker" label="Join date" name="join_date" validation="required" />
82
+ <FormKit type="l-date-picker" label="Expiry date" name="expiry_date" />
83
+ <FormKit type="l-select" label="Status" name="status" :options="options" validation="required" />
84
+ <FormKit type="l-select" label="Language" name="language" :options="languages" validation="required" />
85
+ <FormKit type="l-input" label="Default page" name="default_page" />
62
86
 
63
- <l-field label="Roles" stack-label>
64
- <q-option-group type="checkbox" :options="roles" v-model="obj.roles" inline>
65
- </q-option-group>
66
- </l-field>
87
+ <FormKit type="l-option-group" label="Roles" name="roles" :options="roles ?? []" />
67
88
  </l-col>
68
89
  </l-row>
69
- </l-form>
90
+
91
+ </FormKit>
92
+
70
93
  </l-page>
71
94
  </template>
@@ -1,5 +1,6 @@
1
1
  <script setup>
2
2
  import { reactive } from "vue"
3
+ import { reset } from "@formkit/core"
3
4
  import { q, m, notify } from '../../../'
4
5
 
5
6
  const obj = reactive(await q("my", ["username", "email", "first_name", "last_name"]))
@@ -18,16 +19,25 @@ const save = async () => {
18
19
  } catch (e) {
19
20
  notify(e.message, "red")
20
21
  }
21
-
22
-
23
-
22
+ }
23
+ const onSubmit = async (data, form) => {
24
+ return await m("updateMy", {
25
+ data: {
26
+ email: data.email,
27
+ first_name: data.first_name,
28
+ last_name: data.last_name
29
+ }
30
+ }).then(() => {
31
+ notify("Your profile has been updated")
32
+ reset(form, data)
33
+ });
24
34
  }
25
35
  </script>
26
36
  <template>
27
- <l-form @save="save" :bordered="false">
28
- <l-input label="Username" v-model="obj.username" readonly></l-input>
29
- <l-input label="Email" v-model="obj.email" required></l-input>
30
- <l-input label="First name" v-model="obj.first_name" required></l-input>
31
- <l-input label="Last name" v-model="obj.last_name"></l-input>
32
- </l-form>
37
+ <FormKit type="l-form" :value="obj" :bordered="false" @submit="onSubmit">
38
+ <FormKit type="l-input" label="Username" name="username" readonly></FormKit>
39
+ <FormKit type="l-input" label="Email" name="email" validation="required|email"></FormKit>
40
+ <FormKit type="l-input" label="First name" name="first_name" validation="required"></FormKit>
41
+ <FormKit type="l-input" label="Last name" name="last_name"></FormKit>
42
+ </FormKit>
33
43
  </template>
@@ -1,25 +1,26 @@
1
1
  <script setup>
2
- import { reactive } from "vue"
2
+ import { reset } from "@formkit/core"
3
3
  import { q, m, notify } from '../../../'
4
- const obj = reactive(await q("my", ["phone", "addr1", "addr2", "addr3"]))
5
- const save = async () => {
6
- try {
7
- await m("updateMy", {
8
- data: obj
9
- });
4
+ const obj = await q("my", ["phone", "addr1", "addr2", "addr3"])
5
+ const onSubmit = (data, form) => {
6
+ return m("updateMy", {
7
+ data: {
8
+ phone: data.phone,
9
+ addr1: data.addr1,
10
+ addr2: data.addr2,
11
+ addr3: data.addr3
12
+ }
13
+ }).then(() => {
10
14
  notify("Your information has been updated")
11
-
12
- } catch (e) {
13
- notify(e.message, "red")
14
- }
15
+ reset(form, data)
16
+ });
15
17
  }
16
18
  </script>
17
19
  <template>
18
- <l-form @save="save" :bordered="false">
19
- <l-input label="Phone" v-model="obj.phone"></l-input>
20
- <l-input label="Address1" v-model="obj.addr1"></l-input>
21
- <l-input label="Address2" v-model="obj.addr2"></l-input>
22
- <l-input label="Address3" v-model="obj.addr3"></l-input>
23
-
24
- </l-form>
20
+ <FormKit type="l-form" :value="obj" :bordered="false" @submit="onSubmit">
21
+ <FormKit type="l-input" label="Phone" name="phone"></FormKit>
22
+ <FormKit type="l-input" label="Address1" name="addr1"></FormKit>
23
+ <FormKit type="l-input" label="Address2" name="addr2"></FormKit>
24
+ <FormKit type="l-input" label="Address3" name="addr3"></FormKit>
25
+ </FormKit>
25
26
  </template>
@@ -76,7 +76,10 @@ const unlink = async () => {
76
76
 
77
77
 
78
78
 
79
- <l-btn label="Unlink" @click="unlink" icon="sym_o_delete"></l-btn>
79
+ <div>
80
+ <l-btn label="Unlink" @click="unlink" icon="sym_o_delete"></l-btn>
81
+ </div>
82
+
80
83
  </q-card-section>
81
84
 
82
85
  <q-card-section v-else>
@@ -1,21 +1,28 @@
1
1
  <script setup>
2
- import { reactive } from "vue"
3
- import { notify } from '../../../'
2
+
3
+ import { Dialog } from 'quasar';
4
+ import { reset } from "@formkit/core"
4
5
  import { updatePassword } from "@hostlink/light"
5
6
 
6
7
  import { q } from "#imports"
7
8
 
8
- const obj = reactive({
9
- old_password: "",
10
- new_password: "",
11
- confirm_password: ""
12
- })
9
+ const onSubmit = async (data, form) => {
10
+ if (await updatePassword(data.old_password, data.new_password)) {
11
+ reset(form);
12
+ await Dialog.create({
13
+ title: "Password updated",
14
+ message: "Your password has been updated",
15
+ ok: "OK"
16
+ })
13
17
 
14
- const onSave = async () => {
15
- if (await updatePassword(obj.old_password, obj.new_password)) {
16
- notify("Your password has been updated")
17
18
  } else {
18
- notify("Old password is incorrect", "red")
19
+ await Dialog.create({
20
+ title: "Error",
21
+ message: "Old password is incorrect",
22
+ ok: "OK"
23
+ })
24
+
25
+
19
26
  }
20
27
  }
21
28
 
@@ -23,20 +30,16 @@ const system = await q("system", ["passwordPolicy"])
23
30
 
24
31
  </script>
25
32
  <template>
26
- <l-form @save="onSave" :bordered="false">
27
- <l-input label="Old password" v-model="obj.old_password" type="password" required />
28
- <l-input label="New password" v-model="obj.new_password" type="password" :rules="system.passwordPolicy" />
29
- <l-input label="Confirm password" v-model="obj.confirm_password" type="password" :rules="[
30
- v => v == obj.new_password || 'Confirm password does not match'
31
- ]" />
32
- </l-form>
33
+ <FormKit type="l-form" :bordered="false" @submit="onSubmit">
34
+ <FormKit type="l-input" label="Old password" name="old_password" inputType="password" validation="required" />
35
+ <FormKit type="l-input" label="New password" name="new_password" inputType="password"
36
+ :validation="system.passwordPolicy" />
37
+ <FormKit type="l-input" label="Confirm password" name="new_password_confirm" inputType="password"
38
+ validation="required|confirm" />
39
+ </FormKit>
33
40
 
34
41
  <div>
35
42
  <div>Password policy</div>
36
- <ul>
37
- <li v-for="rule in system.passwordPolicy" :key="rule">
38
- {{ rule }}
39
- </li>
40
- </ul>
43
+ <div>{{ system.passwordPolicy }}</div>
41
44
  </div>
42
45
  </template>
@@ -47,8 +47,8 @@ const setDefault = async () => {
47
47
  styles.cardBordered = true;
48
48
  styles.cardSquare = false;
49
49
 
50
- styles.buttonOutline = true;
51
- styles.buttonRounded = true;
50
+ styles.buttonOutline = false;
51
+ styles.buttonRounded = false;
52
52
  styles.buttonUnelevated = false;
53
53
  styles.buttonDense = false;
54
54
 
@@ -8,12 +8,16 @@ import message_zh from "./locales/zh-hk.json";
8
8
  import routes from "./routes.mjs";
9
9
  import { defineModel } from "@hostlink/light";
10
10
  localStorage.getItem("locale") || localStorage.setItem("locale", "en");
11
+ import { createQuasarPlugin } from "formkit-quasar";
12
+ import { createLightPlugin } from "./formkit/index.mjs";
13
+ import { plugin, defaultConfig } from "@formkit/vue";
11
14
  import { useLight } from "./index.mjs";
12
15
  import TypeUser from "./types/User.mjs";
13
16
  import TypeUserLog from "./types/UserLog.mjs";
14
17
  import TypeSystemValue from "./types/SystemValue.mjs";
15
18
  import TypeMailLog from "./types/MailLog.mjs";
16
19
  import TypeEventLog from "./types/EventLog.mjs";
20
+ import { zhTW } from "@formkit/i18n";
17
21
  export default defineNuxtPlugin((nuxtApp) => {
18
22
  defineModel("User", TypeUser);
19
23
  defineModel("UserLog", TypeUserLog);
@@ -57,6 +61,17 @@ export default defineNuxtPlugin((nuxtApp) => {
57
61
  Loading
58
62
  }
59
63
  });
64
+ let locale = localStorage.getItem("locale") || "en";
65
+ if (locale == "zh-hk") {
66
+ locale = "zhTW";
67
+ }
68
+ nuxtApp.vueApp.use(plugin, defaultConfig({
69
+ plugins: [createQuasarPlugin(), createLightPlugin()],
70
+ locales: {
71
+ zhTW
72
+ },
73
+ locale
74
+ }));
60
75
  const router = useRouter();
61
76
  routes.forEach((route) => {
62
77
  router.addRoute(route);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hostlink/nuxt-light",
3
- "version": "0.0.114",
3
+ "version": "0.0.115",
4
4
  "description": "HostLink Nuxt Light Framework",
5
5
  "repository": "@hostlink/nuxt-light",
6
6
  "license": "MIT",
@@ -39,6 +39,7 @@
39
39
  "@nuxt/module-builder": "^0.5.2",
40
40
  "@quasar/extras": "^1.16.6",
41
41
  "axios": "^1.5.0",
42
+ "formkit-quasar": "^0.0.12",
42
43
  "json-to-graphql-query": "^2.2.5",
43
44
  "quasar": "^2.12.5",
44
45
  "unplugin-auto-import": "^0.16.6",