@ramathibodi/nuxt-commons 4.0.11 → 4.0.13
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/dialog/ImportProgress.d.vue.ts +35 -0
- package/dist/runtime/components/dialog/ImportProgress.vue +53 -0
- package/dist/runtime/components/dialog/ImportProgress.vue.d.ts +35 -0
- package/dist/runtime/components/document/TemplateBuilder.d.vue.ts +2 -2
- package/dist/runtime/components/document/TemplateBuilder.vue +113 -8
- package/dist/runtime/components/document/TemplateBuilder.vue.d.ts +2 -2
- package/dist/runtime/components/form/ActionPad.vue +1 -0
- package/dist/runtime/components/form/Birthdate.d.vue.ts +3 -3
- package/dist/runtime/components/form/Birthdate.vue.d.ts +3 -3
- package/dist/runtime/components/form/Date.vue +11 -6
- package/dist/runtime/components/form/Dialog.d.vue.ts +1 -5
- package/dist/runtime/components/form/Dialog.vue +1 -0
- package/dist/runtime/components/form/Dialog.vue.d.ts +1 -5
- package/dist/runtime/components/form/EditPad.vue +1 -0
- package/dist/runtime/components/form/Pad.d.vue.ts +24 -0
- package/dist/runtime/components/form/Pad.vue +11 -6
- package/dist/runtime/components/form/Pad.vue.d.ts +24 -0
- package/dist/runtime/components/form/Time.vue +10 -5
- package/dist/runtime/components/form/images/Edit.d.vue.ts +1 -3
- package/dist/runtime/components/form/images/Edit.vue.d.ts +1 -3
- package/dist/runtime/components/model/AutoRefreshChip.d.vue.ts +16 -0
- package/dist/runtime/components/model/AutoRefreshChip.vue +34 -0
- package/dist/runtime/components/model/AutoRefreshChip.vue.d.ts +16 -0
- package/dist/runtime/components/model/Pad.vue +2 -1
- package/dist/runtime/components/model/Table.d.vue.ts +158 -61
- package/dist/runtime/components/model/Table.vue +129 -7
- package/dist/runtime/components/model/Table.vue.d.ts +158 -61
- package/dist/runtime/components/model/iterator.d.vue.ts +198 -78
- package/dist/runtime/components/model/iterator.vue +140 -9
- package/dist/runtime/components/model/iterator.vue.d.ts +198 -78
- package/dist/runtime/composables/apiModel.d.ts +22 -3
- package/dist/runtime/composables/apiModel.js +27 -19
- package/dist/runtime/composables/autoRefresh.d.ts +42 -0
- package/dist/runtime/composables/autoRefresh.js +57 -0
- package/dist/runtime/composables/document/template.d.ts +61 -0
- package/dist/runtime/composables/document/template.js +60 -1
- package/dist/runtime/composables/document/validateTemplate.d.ts +62 -0
- package/dist/runtime/composables/document/validateTemplate.js +378 -0
- package/dist/runtime/composables/graphqlModel.d.ts +22 -3
- package/dist/runtime/composables/graphqlModel.js +27 -19
- package/dist/runtime/composables/graphqlModelOperation.d.ts +1 -0
- package/dist/runtime/composables/importProgress.d.ts +34 -0
- package/dist/runtime/composables/importProgress.js +50 -0
- package/dist/runtime/composables/modelAutoRefresh.d.ts +29 -0
- package/dist/runtime/composables/modelAutoRefresh.js +16 -0
- package/dist/runtime/composables/utils/validation.d.ts +4 -0
- package/dist/runtime/composables/utils/validation.js +2 -0
- package/dist/runtime/utils/virtualize.d.ts +15 -0
- package/dist/runtime/utils/virtualize.js +10 -0
- package/package.json +3 -2
- package/scripts/validate-document-template.mjs +158 -0
package/dist/module.json
CHANGED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public props accepted by DialogImportProgress.
|
|
3
|
+
* Document each prop field with intent, defaults, and side effects for clear generated docs.
|
|
4
|
+
*/
|
|
5
|
+
interface DialogImportProgressProps {
|
|
6
|
+
modelValue: boolean;
|
|
7
|
+
total: number;
|
|
8
|
+
processed: number;
|
|
9
|
+
succeeded?: number;
|
|
10
|
+
failed?: number;
|
|
11
|
+
percent: number;
|
|
12
|
+
title?: string;
|
|
13
|
+
color?: string;
|
|
14
|
+
}
|
|
15
|
+
declare var __VLS_20: {};
|
|
16
|
+
type __VLS_Slots = {} & {
|
|
17
|
+
default?: (props: typeof __VLS_20) => any;
|
|
18
|
+
};
|
|
19
|
+
declare const __VLS_base: import("vue").DefineComponent<DialogImportProgressProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
20
|
+
"update:modelValue": (...args: any[]) => void;
|
|
21
|
+
}, string, import("vue").PublicProps, Readonly<DialogImportProgressProps> & Readonly<{
|
|
22
|
+
"onUpdate:modelValue"?: ((...args: any[]) => any) | undefined;
|
|
23
|
+
}>, {
|
|
24
|
+
title: string;
|
|
25
|
+
succeeded: number;
|
|
26
|
+
failed: number;
|
|
27
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
28
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
29
|
+
declare const _default: typeof __VLS_export;
|
|
30
|
+
export default _default;
|
|
31
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
32
|
+
new (): {
|
|
33
|
+
$slots: S;
|
|
34
|
+
};
|
|
35
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { ref, watch } from "vue";
|
|
3
|
+
const props = defineProps({
|
|
4
|
+
modelValue: { type: Boolean, required: true },
|
|
5
|
+
total: { type: Number, required: true },
|
|
6
|
+
processed: { type: Number, required: true },
|
|
7
|
+
succeeded: { type: Number, required: false, default: 0 },
|
|
8
|
+
failed: { type: Number, required: false, default: 0 },
|
|
9
|
+
percent: { type: Number, required: true },
|
|
10
|
+
title: { type: String, required: false, default: "\u0E01\u0E33\u0E25\u0E31\u0E07\u0E19\u0E33\u0E40\u0E02\u0E49\u0E32\u0E02\u0E49\u0E2D\u0E21\u0E39\u0E25" },
|
|
11
|
+
color: { type: String, required: false }
|
|
12
|
+
});
|
|
13
|
+
const emit = defineEmits(["update:modelValue"]);
|
|
14
|
+
const dialogVisible = ref(props.modelValue);
|
|
15
|
+
watch(() => props.modelValue, (newValue) => {
|
|
16
|
+
dialogVisible.value = newValue;
|
|
17
|
+
});
|
|
18
|
+
watch(() => dialogVisible.value, (newValue) => {
|
|
19
|
+
emit("update:modelValue", newValue);
|
|
20
|
+
});
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
<template>
|
|
24
|
+
<v-dialog
|
|
25
|
+
v-model="dialogVisible"
|
|
26
|
+
persistent
|
|
27
|
+
max-width="500"
|
|
28
|
+
>
|
|
29
|
+
<v-card :color="props.color">
|
|
30
|
+
<v-card-text>
|
|
31
|
+
<div class="text-center mb-2">
|
|
32
|
+
<slot>{{ props.title }}</slot>
|
|
33
|
+
</div>
|
|
34
|
+
<div class="text-center text-body-2 mb-2">
|
|
35
|
+
{{ props.processed }} / {{ props.total }}
|
|
36
|
+
<span
|
|
37
|
+
v-if="props.failed > 0"
|
|
38
|
+
class="text-medium-emphasis"
|
|
39
|
+
>
|
|
40
|
+
(ล้มเหลว {{ props.failed }})
|
|
41
|
+
</span>
|
|
42
|
+
</div>
|
|
43
|
+
</v-card-text>
|
|
44
|
+
<v-progress-linear
|
|
45
|
+
:model-value="props.percent"
|
|
46
|
+
height="20"
|
|
47
|
+
color="primary"
|
|
48
|
+
>
|
|
49
|
+
<strong>{{ props.percent }}%</strong>
|
|
50
|
+
</v-progress-linear>
|
|
51
|
+
</v-card>
|
|
52
|
+
</v-dialog>
|
|
53
|
+
</template>
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public props accepted by DialogImportProgress.
|
|
3
|
+
* Document each prop field with intent, defaults, and side effects for clear generated docs.
|
|
4
|
+
*/
|
|
5
|
+
interface DialogImportProgressProps {
|
|
6
|
+
modelValue: boolean;
|
|
7
|
+
total: number;
|
|
8
|
+
processed: number;
|
|
9
|
+
succeeded?: number;
|
|
10
|
+
failed?: number;
|
|
11
|
+
percent: number;
|
|
12
|
+
title?: string;
|
|
13
|
+
color?: string;
|
|
14
|
+
}
|
|
15
|
+
declare var __VLS_20: {};
|
|
16
|
+
type __VLS_Slots = {} & {
|
|
17
|
+
default?: (props: typeof __VLS_20) => any;
|
|
18
|
+
};
|
|
19
|
+
declare const __VLS_base: import("vue").DefineComponent<DialogImportProgressProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
20
|
+
"update:modelValue": (...args: any[]) => void;
|
|
21
|
+
}, string, import("vue").PublicProps, Readonly<DialogImportProgressProps> & Readonly<{
|
|
22
|
+
"onUpdate:modelValue"?: ((...args: any[]) => any) | undefined;
|
|
23
|
+
}>, {
|
|
24
|
+
title: string;
|
|
25
|
+
succeeded: number;
|
|
26
|
+
failed: number;
|
|
27
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
28
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
29
|
+
declare const _default: typeof __VLS_export;
|
|
30
|
+
export default _default;
|
|
31
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
32
|
+
new (): {
|
|
33
|
+
$slots: S;
|
|
34
|
+
};
|
|
35
|
+
};
|
|
@@ -18,9 +18,9 @@ type __VLS_ModelProps = {
|
|
|
18
18
|
};
|
|
19
19
|
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
20
20
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
21
|
-
"update:modelValue": (
|
|
21
|
+
"update:modelValue": (value: string | Record<string, any>[] | undefined) => any;
|
|
22
22
|
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
23
|
-
"onUpdate:modelValue"?: ((
|
|
23
|
+
"onUpdate:modelValue"?: ((value: string | Record<string, any>[] | undefined) => any) | undefined;
|
|
24
24
|
}>, {
|
|
25
25
|
title: string;
|
|
26
26
|
disableAdvanceMode: boolean;
|
|
@@ -2,12 +2,21 @@
|
|
|
2
2
|
import { computed, ref, watch } from "vue";
|
|
3
3
|
import * as prettier from "prettier";
|
|
4
4
|
import prettierPluginHtml from "prettier/plugins/html";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
useDocumentTemplate,
|
|
7
|
+
validationRulesRegex,
|
|
8
|
+
optionStringToChoiceObject,
|
|
9
|
+
printConfigToRows,
|
|
10
|
+
rowsToPrintConfig,
|
|
11
|
+
printConfigToAttributes,
|
|
12
|
+
configStringToRows,
|
|
13
|
+
rowsToConfigString
|
|
14
|
+
} from "../../composables/document/template";
|
|
6
15
|
import {
|
|
7
16
|
useDocumentTemplateInputTypes
|
|
8
17
|
} from "../../composables/document/templateInputTypes";
|
|
9
18
|
import { autoActionHeader, templateToHeader } from "../../composables/document/templateFormTable";
|
|
10
|
-
import { cloneDeep } from "lodash-es";
|
|
19
|
+
import { cloneDeep, isPlainObject } from "lodash-es";
|
|
11
20
|
import VueJsonPretty from "vue-json-pretty";
|
|
12
21
|
import "vue-json-pretty/lib/styles.css";
|
|
13
22
|
import { safeParseJSONDeep } from "../../utils/object";
|
|
@@ -92,6 +101,51 @@ const choiceHeaders = ref([
|
|
|
92
101
|
width: "120px"
|
|
93
102
|
}
|
|
94
103
|
]);
|
|
104
|
+
const printConfigHeaders = ref([
|
|
105
|
+
{
|
|
106
|
+
title: "Attribute",
|
|
107
|
+
key: "key"
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
title: "Value",
|
|
111
|
+
key: "value"
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
title: "Action",
|
|
115
|
+
key: "action",
|
|
116
|
+
width: "120px"
|
|
117
|
+
}
|
|
118
|
+
]);
|
|
119
|
+
function itemsForEdit(items) {
|
|
120
|
+
return items.map((item) => isPlainObject(item.printConfig) ? { ...item, printConfig: printConfigToRows(item.printConfig) } : item);
|
|
121
|
+
}
|
|
122
|
+
function itemsForStore(items) {
|
|
123
|
+
return items.map((item) => {
|
|
124
|
+
if (Array.isArray(item.printConfig)) {
|
|
125
|
+
const map = rowsToPrintConfig(item.printConfig);
|
|
126
|
+
const { printConfig, ...rest } = item;
|
|
127
|
+
return Object.keys(map).length ? { ...rest, printConfig: map } : rest;
|
|
128
|
+
}
|
|
129
|
+
if (typeof item.printConfig === "string" && item.printConfig.trim() === "") {
|
|
130
|
+
const { printConfig, ...rest } = item;
|
|
131
|
+
return rest;
|
|
132
|
+
}
|
|
133
|
+
return item;
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
function setPrintConfigMode(item, mode) {
|
|
137
|
+
if (mode === "raw") {
|
|
138
|
+
if (typeof item.printConfig === "string") return;
|
|
139
|
+
item.printConfig = rowsToConfigString(Array.isArray(item.printConfig) ? item.printConfig : []);
|
|
140
|
+
} else {
|
|
141
|
+
if (Array.isArray(item.printConfig)) return;
|
|
142
|
+
item.printConfig = configStringToRows(typeof item.printConfig === "string" ? item.printConfig : "");
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
function printConfigPreview(printConfig) {
|
|
146
|
+
if (Array.isArray(printConfig)) return printConfigToAttributes(rowsToPrintConfig(printConfig));
|
|
147
|
+
return printConfigToAttributes(printConfig);
|
|
148
|
+
}
|
|
95
149
|
function isValidJsonArrayOfObjects(str) {
|
|
96
150
|
try {
|
|
97
151
|
const parsed = JSON.parse(str);
|
|
@@ -101,19 +155,19 @@ function isValidJsonArrayOfObjects(str) {
|
|
|
101
155
|
}
|
|
102
156
|
}
|
|
103
157
|
watch(templateItems, (newValue) => {
|
|
104
|
-
if (!isAdvanceMode.value) modelValue.value = JSON.stringify(newValue);
|
|
158
|
+
if (!isAdvanceMode.value) modelValue.value = JSON.stringify(itemsForStore(newValue));
|
|
105
159
|
}, { deep: true });
|
|
106
160
|
watch(modelValue, (newValue) => {
|
|
107
|
-
if (typeof newValue === "string" && isValidJsonArrayOfObjects(newValue)) templateItems.value = JSON.parse(newValue);
|
|
161
|
+
if (typeof newValue === "string" && isValidJsonArrayOfObjects(newValue)) templateItems.value = itemsForEdit(JSON.parse(newValue));
|
|
108
162
|
else if (typeof newValue === "string") advanceModeCode.value = newValue;
|
|
109
|
-
else if (newValue) templateItems.value = cloneDeep(newValue);
|
|
163
|
+
else if (newValue) templateItems.value = itemsForEdit(cloneDeep(newValue));
|
|
110
164
|
}, { deep: true, immediate: true });
|
|
111
165
|
watch(advanceModeCode, (newValue) => {
|
|
112
166
|
if (isAdvanceMode.value) modelValue.value = newValue;
|
|
113
167
|
});
|
|
114
168
|
async function convertToAdvanceMode() {
|
|
115
169
|
if (!isAdvanceMode.value) {
|
|
116
|
-
modelValue.value = await prettier.format(useDocumentTemplate(templateItems.value).replaceAll(">", ">\n"), { parser: "html", plugins: [prettierPluginHtml] });
|
|
170
|
+
modelValue.value = await prettier.format(useDocumentTemplate(itemsForStore(templateItems.value)).replaceAll(">", ">\n"), { parser: "html", plugins: [prettierPluginHtml] });
|
|
117
171
|
}
|
|
118
172
|
}
|
|
119
173
|
const inputTypes = computed(() => useDocumentTemplateInputTypes());
|
|
@@ -362,7 +416,7 @@ const ruleOptions = (inputType) => (value) => {
|
|
|
362
416
|
label="Validation Rules"
|
|
363
417
|
:rules="[rules.regex(validationRulesRegex)]"
|
|
364
418
|
/>
|
|
365
|
-
<b>Available rules :</b> require, requireIf(condition), requireTrue, requireTrueIf(condition), numeric, range(min,max), integer, unique, length(length), lengthGreater(length), lengthLess(length), telephone, email, regex(regex), idcard, DateFuture, DatetimeFuture, DateHappen, DatetimeHappen, DateAfter(date), DateBefore(Date), DateEqual(date)
|
|
419
|
+
<b>Available rules :</b> require, requireIf(condition), requireTrue, requireTrueIf(condition), requireNotEmpty, numeric, range(min,max), integer, unique, length(length), lengthGreater(length), lengthLess(length), telephone, email, regex(regex), idcard, DateFuture, DatetimeFuture, DateHappen, DatetimeHappen, DateAfter(date), DateBefore(Date), DateEqual(date)
|
|
366
420
|
</v-col>
|
|
367
421
|
</v-row>
|
|
368
422
|
</v-container>
|
|
@@ -403,6 +457,54 @@ const ruleOptions = (inputType) => (value) => {
|
|
|
403
457
|
label="Retrieved Value"
|
|
404
458
|
/>
|
|
405
459
|
</v-col>
|
|
460
|
+
<v-col cols="12">
|
|
461
|
+
<div class="d-flex align-center ga-2 mb-1">
|
|
462
|
+
<span class="opacity-60">Print Config</span>
|
|
463
|
+
<span class="text-caption opacity-60">— print/docx-only; ignored by the form renderer</span>
|
|
464
|
+
<v-spacer />
|
|
465
|
+
<v-btn-toggle
|
|
466
|
+
:model-value="typeof data.printConfig === 'string' ? 'raw' : 'map'"
|
|
467
|
+
@update:model-value="(mode) => setPrintConfigMode(data, mode)"
|
|
468
|
+
density="compact"
|
|
469
|
+
variant="outlined"
|
|
470
|
+
divided
|
|
471
|
+
mandatory
|
|
472
|
+
>
|
|
473
|
+
<v-btn value="map" size="small">Key / Value</v-btn>
|
|
474
|
+
<v-btn value="raw" size="small">Raw string</v-btn>
|
|
475
|
+
</v-btn-toggle>
|
|
476
|
+
</div>
|
|
477
|
+
<v-textarea
|
|
478
|
+
v-if="typeof data.printConfig === 'string'"
|
|
479
|
+
v-model="data.printConfig"
|
|
480
|
+
label="Print Config (raw attributes)"
|
|
481
|
+
placeholder="format=dd/MM/yyyy; locale=th_TH"
|
|
482
|
+
auto-grow
|
|
483
|
+
rows="1"
|
|
484
|
+
/>
|
|
485
|
+
<form-table
|
|
486
|
+
v-else
|
|
487
|
+
v-model="data.printConfig"
|
|
488
|
+
:headers="printConfigHeaders"
|
|
489
|
+
title="Print Config"
|
|
490
|
+
>
|
|
491
|
+
<template #form="{ data: rowData, rules }">
|
|
492
|
+
<v-container fluid>
|
|
493
|
+
<v-row density="compact">
|
|
494
|
+
<v-col cols="6">
|
|
495
|
+
<v-text-field v-model="rowData.key" label="Attribute" :rules="[rules.require()]" />
|
|
496
|
+
</v-col>
|
|
497
|
+
<v-col cols="6">
|
|
498
|
+
<v-text-field v-model="rowData.value" label="Value (blank = flag)" />
|
|
499
|
+
</v-col>
|
|
500
|
+
</v-row>
|
|
501
|
+
</v-container>
|
|
502
|
+
</template>
|
|
503
|
+
</form-table>
|
|
504
|
+
<div class="text-caption opacity-60 mt-1" v-if="printConfigPreview(data.printConfig)">
|
|
505
|
+
Appends to placeholder: <code>{{ printConfigPreview(data.printConfig) }}</code>
|
|
506
|
+
</div>
|
|
507
|
+
</v-col>
|
|
406
508
|
</v-row>
|
|
407
509
|
</v-container>
|
|
408
510
|
</v-expansion-panel-text>
|
|
@@ -438,7 +540,7 @@ const ruleOptions = (inputType) => (value) => {
|
|
|
438
540
|
elevation="1"
|
|
439
541
|
max-height="250"
|
|
440
542
|
class="overflow-y-auto my-1 pa-2"
|
|
441
|
-
v-if="props.item.inputType == 'CustomCode' || props.item.validationRules || props.item.inputOptions || props.item.inputAttributes || props.item.columnAttributes || props.item.conditionalDisplay || props.item.computedValue || props.item.retrievedValue"
|
|
543
|
+
v-if="props.item.inputType == 'CustomCode' || props.item.validationRules || props.item.inputOptions || props.item.inputAttributes || props.item.columnAttributes || props.item.conditionalDisplay || props.item.computedValue || props.item.retrievedValue || printConfigPreview(props.item.printConfig)"
|
|
442
544
|
>
|
|
443
545
|
<template v-if="props.item.inputType == 'CustomCode'">
|
|
444
546
|
<b>Custom Code :</b><br>
|
|
@@ -466,6 +568,9 @@ const ruleOptions = (inputType) => (value) => {
|
|
|
466
568
|
<template v-if="props.item.retrievedValue">
|
|
467
569
|
<b>Retrieved Value :</b> {{ props.item.retrievedValue }}<br>
|
|
468
570
|
</template>
|
|
571
|
+
<template v-if="printConfigPreview(props.item.printConfig)">
|
|
572
|
+
<b>Print Config :</b> <code>{{ printConfigPreview(props.item.printConfig) }}</code><br>
|
|
573
|
+
</template>
|
|
469
574
|
</v-sheet>
|
|
470
575
|
</template>
|
|
471
576
|
</FormTable>
|
|
@@ -18,9 +18,9 @@ type __VLS_ModelProps = {
|
|
|
18
18
|
};
|
|
19
19
|
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
20
20
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
21
|
-
"update:modelValue": (
|
|
21
|
+
"update:modelValue": (value: string | Record<string, any>[] | undefined) => any;
|
|
22
22
|
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
23
|
-
"onUpdate:modelValue"?: ((
|
|
23
|
+
"onUpdate:modelValue"?: ((value: string | Record<string, any>[] | undefined) => any) | undefined;
|
|
24
24
|
}>, {
|
|
25
25
|
title: string;
|
|
26
26
|
disableAdvanceMode: boolean;
|
|
@@ -17,6 +17,7 @@ const formData = ref({});
|
|
|
17
17
|
const formDataOriginalValue = ref();
|
|
18
18
|
const emit = defineEmits(["create", "update"]);
|
|
19
19
|
function save() {
|
|
20
|
+
formPadRef.value?.flushSanitize?.();
|
|
20
21
|
if (props.skipValidation || formPadRef.value?.isValid) {
|
|
21
22
|
isSaving.value = true;
|
|
22
23
|
emit(isCreating.value ? "create" : "update", cloneDeep(formData.value), callback);
|
|
@@ -26,10 +26,10 @@ type __VLS_ModelProps = {
|
|
|
26
26
|
};
|
|
27
27
|
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
28
28
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
29
|
-
"update:modelValue": (
|
|
30
|
-
"update:dobPrecision": (value: "year" | "yearMonthDay" | "yearMonth" | "estimated" | undefined) =>
|
|
29
|
+
"update:modelValue": (value: string | undefined) => any;
|
|
30
|
+
"update:dobPrecision": (value: "year" | "yearMonthDay" | "yearMonth" | "estimated" | undefined) => any;
|
|
31
31
|
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
32
|
-
"onUpdate:modelValue"?: ((
|
|
32
|
+
"onUpdate:modelValue"?: ((value: string | undefined) => any) | undefined;
|
|
33
33
|
"onUpdate:dobPrecision"?: ((value: "year" | "yearMonthDay" | "yearMonth" | "estimated" | undefined) => any) | undefined;
|
|
34
34
|
}>, {
|
|
35
35
|
flow: ("month" | "year" | "calendar" | "time" | "minutes" | "hours" | "seconds")[];
|
|
@@ -26,10 +26,10 @@ type __VLS_ModelProps = {
|
|
|
26
26
|
};
|
|
27
27
|
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
28
28
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
29
|
-
"update:modelValue": (
|
|
30
|
-
"update:dobPrecision": (value: "year" | "yearMonthDay" | "yearMonth" | "estimated" | undefined) =>
|
|
29
|
+
"update:modelValue": (value: string | undefined) => any;
|
|
30
|
+
"update:dobPrecision": (value: "year" | "yearMonthDay" | "yearMonth" | "estimated" | undefined) => any;
|
|
31
31
|
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
32
|
-
"onUpdate:modelValue"?: ((
|
|
32
|
+
"onUpdate:modelValue"?: ((value: string | undefined) => any) | undefined;
|
|
33
33
|
"onUpdate:dobPrecision"?: ((value: "year" | "yearMonthDay" | "yearMonth" | "estimated" | undefined) => any) | undefined;
|
|
34
34
|
}>, {
|
|
35
35
|
flow: ("month" | "year" | "calendar" | "time" | "minutes" | "hours" | "seconds")[];
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { ref, watch, watchEffect, nextTick, computed } from "vue";
|
|
3
3
|
import { VTextField } from "vuetify/components/VTextField";
|
|
4
|
-
import Datepicker from "@vuepic/vue-datepicker";
|
|
4
|
+
import { VueDatePicker as Datepicker } from "@vuepic/vue-datepicker";
|
|
5
5
|
import "@vuepic/vue-datepicker/dist/main.css";
|
|
6
6
|
import { isArray, isString } from "lodash-es";
|
|
7
7
|
import { Datetime } from "../../utils/datetime";
|
|
8
8
|
import { useRules } from "../../composables/utils/validation";
|
|
9
|
-
import { th } from "date-fns/locale";
|
|
9
|
+
import { th, enUS } from "date-fns/locale";
|
|
10
10
|
const props = defineProps({
|
|
11
11
|
locale: { type: String, required: false, default: "TH" },
|
|
12
12
|
format: { type: String, required: false, default: "shortDate" },
|
|
@@ -60,6 +60,8 @@ const computedRules = computed(() => {
|
|
|
60
60
|
});
|
|
61
61
|
const selectedDate = ref(null);
|
|
62
62
|
const displayedDate = ref(null);
|
|
63
|
+
const datepickerLocale = computed(() => props.locale === "TH" ? th : enUS);
|
|
64
|
+
const datepickerFlow = computed(() => props.flow.length ? { steps: props.flow, partial: true } : void 0);
|
|
63
65
|
const isMenuOpen = ref(false);
|
|
64
66
|
const isTextFieldFocused = ref(false);
|
|
65
67
|
const hasTextFieldInput = ref(false);
|
|
@@ -197,14 +199,13 @@ defineExpose({
|
|
|
197
199
|
<Datepicker
|
|
198
200
|
v-model="selectedDate"
|
|
199
201
|
model-type="yyyy-MM-dd"
|
|
200
|
-
:
|
|
201
|
-
:flow="
|
|
202
|
+
:time-config="{ enableTimePicker: false }"
|
|
203
|
+
:flow="datepickerFlow"
|
|
202
204
|
:min-date="props.minDate"
|
|
203
205
|
:max-date="props.maxDate"
|
|
204
206
|
auto-apply
|
|
205
207
|
inline
|
|
206
|
-
:locale="
|
|
207
|
-
:format-locale="locale == 'TH' ? th : void 0"
|
|
208
|
+
:locale="datepickerLocale"
|
|
208
209
|
@update:model-value="updateDatePicker"
|
|
209
210
|
>
|
|
210
211
|
<template #year="{ value }" v-if="locale == 'TH'">
|
|
@@ -216,3 +217,7 @@ defineExpose({
|
|
|
216
217
|
</Datepicker>
|
|
217
218
|
</v-menu>
|
|
218
219
|
</template>
|
|
220
|
+
|
|
221
|
+
<style scoped>
|
|
222
|
+
:deep(.dp__button.dp__overlay_action){display:none}
|
|
223
|
+
</style>
|
|
@@ -45,13 +45,9 @@ type __VLS_Slots = {} & {
|
|
|
45
45
|
action?: (props: typeof __VLS_69) => any;
|
|
46
46
|
};
|
|
47
47
|
declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
48
|
-
|
|
49
|
-
update: (...args: any[]) => void;
|
|
50
|
-
"update:modelValue": (value: boolean) => void;
|
|
48
|
+
"update:modelValue": (value: boolean) => any;
|
|
51
49
|
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
52
50
|
"onUpdate:modelValue"?: ((value: boolean) => any) | undefined;
|
|
53
|
-
onCreate?: ((...args: any[]) => any) | undefined;
|
|
54
|
-
onUpdate?: ((...args: any[]) => any) | undefined;
|
|
55
51
|
}>, {
|
|
56
52
|
readonly: boolean;
|
|
57
53
|
saveCaption: string;
|
|
@@ -20,6 +20,7 @@ const formData = ref({});
|
|
|
20
20
|
const formDataOriginalValue = ref();
|
|
21
21
|
const emit = defineEmits(["create", "update"]);
|
|
22
22
|
function save() {
|
|
23
|
+
formPadRef.value?.flushSanitize?.();
|
|
23
24
|
if (formPadRef.value.isValid) {
|
|
24
25
|
isSaving.value = true;
|
|
25
26
|
emit(isCreating.value ? "create" : "update", cloneDeep(formData.value), props.saveAndStay ? stayCallback : callback);
|
|
@@ -45,13 +45,9 @@ type __VLS_Slots = {} & {
|
|
|
45
45
|
action?: (props: typeof __VLS_69) => any;
|
|
46
46
|
};
|
|
47
47
|
declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
48
|
-
|
|
49
|
-
update: (...args: any[]) => void;
|
|
50
|
-
"update:modelValue": (value: boolean) => void;
|
|
48
|
+
"update:modelValue": (value: boolean) => any;
|
|
51
49
|
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
52
50
|
"onUpdate:modelValue"?: ((value: boolean) => any) | undefined;
|
|
53
|
-
onCreate?: ((...args: any[]) => any) | undefined;
|
|
54
|
-
onUpdate?: ((...args: any[]) => any) | undefined;
|
|
55
51
|
}>, {
|
|
56
52
|
readonly: boolean;
|
|
57
53
|
saveCaption: string;
|
|
@@ -18,6 +18,7 @@ const formData = ref({});
|
|
|
18
18
|
const formDataOriginalValue = ref();
|
|
19
19
|
const emit = defineEmits(["create", "update"]);
|
|
20
20
|
function save() {
|
|
21
|
+
formPadRef.value?.flushSanitize?.();
|
|
21
22
|
if (props.skipValidation || formPadRef.value?.isValid) {
|
|
22
23
|
isSaving.value = true;
|
|
23
24
|
emit(isCreating.value ? "create" : "update", cloneDeep(formData.value), callback);
|
|
@@ -12,6 +12,7 @@ interface Props {
|
|
|
12
12
|
dirtyOnCreate?: boolean;
|
|
13
13
|
sanitizeDelay?: number;
|
|
14
14
|
}
|
|
15
|
+
declare function flushSanitize(): void;
|
|
15
16
|
declare function reset(): void;
|
|
16
17
|
declare function validate(): void;
|
|
17
18
|
declare function resetValidate(): void;
|
|
@@ -75,6 +76,17 @@ declare var __VLS_10: {
|
|
|
75
76
|
* This doc block is consumed by vue-docgen for generated API documentation.
|
|
76
77
|
*/
|
|
77
78
|
) => string | true;
|
|
79
|
+
requireNotEmpty: (customError?: string) => (
|
|
80
|
+
/**
|
|
81
|
+
* FormPad is a schema-driven form field component that binds model data, renders field UI, and emits normalized updates.
|
|
82
|
+
* This doc block is consumed by vue-docgen for generated API documentation.
|
|
83
|
+
*/
|
|
84
|
+
value: any
|
|
85
|
+
/**
|
|
86
|
+
* FormPad is a schema-driven form field component that binds model data, renders field UI, and emits normalized updates.
|
|
87
|
+
* This doc block is consumed by vue-docgen for generated API documentation.
|
|
88
|
+
*/
|
|
89
|
+
) => string | true;
|
|
78
90
|
numeric: (customError?: string) => (
|
|
79
91
|
/**
|
|
80
92
|
* FormPad is a schema-driven form field component that binds model data, renders field UI, and emits normalized updates.
|
|
@@ -381,6 +393,17 @@ declare var __VLS_10: {
|
|
|
381
393
|
* This doc block is consumed by vue-docgen for generated API documentation.
|
|
382
394
|
*/
|
|
383
395
|
) => string | true;
|
|
396
|
+
requireNotEmpty: (customError?: string) => (
|
|
397
|
+
/**
|
|
398
|
+
* FormPad is a schema-driven form field component that binds model data, renders field UI, and emits normalized updates.
|
|
399
|
+
* This doc block is consumed by vue-docgen for generated API documentation.
|
|
400
|
+
*/
|
|
401
|
+
value: any
|
|
402
|
+
/**
|
|
403
|
+
* FormPad is a schema-driven form field component that binds model data, renders field UI, and emits normalized updates.
|
|
404
|
+
* This doc block is consumed by vue-docgen for generated API documentation.
|
|
405
|
+
*/
|
|
406
|
+
) => string | true;
|
|
384
407
|
numeric: (customError?: string) => (
|
|
385
408
|
/**
|
|
386
409
|
* FormPad is a schema-driven form field component that binds model data, renders field UI, and emits normalized updates.
|
|
@@ -650,6 +673,7 @@ declare const __VLS_base: import("vue").DefineComponent<Props, {
|
|
|
650
673
|
reset: typeof reset;
|
|
651
674
|
validate: typeof validate;
|
|
652
675
|
resetValidate: typeof resetValidate;
|
|
676
|
+
flushSanitize: typeof flushSanitize;
|
|
653
677
|
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
654
678
|
"update:modelValue": (...args: any[]) => void;
|
|
655
679
|
}, string, import("vue").PublicProps, Readonly<Props> & Readonly<{
|
|
@@ -61,11 +61,11 @@ function scheduleIdle(fn) {
|
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
63
|
const sanitizeBlankStrings = debounce((val, original) => {
|
|
64
|
-
scheduleIdle(() =>
|
|
64
|
+
scheduleIdle(() => sanitizeBlankStringsSync(val, original));
|
|
65
65
|
}, props.sanitizeDelay);
|
|
66
|
-
function
|
|
66
|
+
function sanitizeBlankStringsSync(val, original) {
|
|
67
67
|
if (!original && props.originalData) {
|
|
68
|
-
|
|
68
|
+
sanitizeBlankStringsSync(val, props.originalData);
|
|
69
69
|
return;
|
|
70
70
|
}
|
|
71
71
|
if (isArray(val)) {
|
|
@@ -74,7 +74,7 @@ function sanitizeBlankStringsRaw(val, original) {
|
|
|
74
74
|
if (isBlankString(item)) {
|
|
75
75
|
val.splice(i, 1);
|
|
76
76
|
} else if (isPlainObject(item) || isArray(item)) {
|
|
77
|
-
|
|
77
|
+
sanitizeBlankStringsSync(item, {});
|
|
78
78
|
} else {
|
|
79
79
|
if (item && typeof item === "string") val[i] = item.replace(/[ \t]+$/, "");
|
|
80
80
|
}
|
|
@@ -89,13 +89,17 @@ function sanitizeBlankStringsRaw(val, original) {
|
|
|
89
89
|
else val[key] = null;
|
|
90
90
|
} else if (isPlainObject(v) || isArray(v)) {
|
|
91
91
|
let originalChild = original && (isPlainObject(original[key]) || isArray(original[key])) ? original[key] : {};
|
|
92
|
-
|
|
92
|
+
sanitizeBlankStringsSync(v, originalChild);
|
|
93
93
|
} else {
|
|
94
94
|
if (v && typeof v === "string") val[key] = v.replace(/[ \t]+$/, "");
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
98
|
}
|
|
99
|
+
function flushSanitize() {
|
|
100
|
+
sanitizeBlankStrings.cancel();
|
|
101
|
+
sanitizeBlankStringsSync(formData.value, props.originalData ?? {});
|
|
102
|
+
}
|
|
99
103
|
function autoSanitizedDisplay(item, separator = ",") {
|
|
100
104
|
const isEmptyScalar = (v) => v === null || v === void 0 || typeof v === "string" && v.trim() === "" || typeof v === "number" && Number.isNaN(v);
|
|
101
105
|
const toStr = (v) => {
|
|
@@ -257,7 +261,8 @@ defineExpose({
|
|
|
257
261
|
readonly,
|
|
258
262
|
reset,
|
|
259
263
|
validate,
|
|
260
|
-
resetValidate
|
|
264
|
+
resetValidate,
|
|
265
|
+
flushSanitize
|
|
261
266
|
});
|
|
262
267
|
</script>
|
|
263
268
|
|
|
@@ -12,6 +12,7 @@ interface Props {
|
|
|
12
12
|
dirtyOnCreate?: boolean;
|
|
13
13
|
sanitizeDelay?: number;
|
|
14
14
|
}
|
|
15
|
+
declare function flushSanitize(): void;
|
|
15
16
|
declare function reset(): void;
|
|
16
17
|
declare function validate(): void;
|
|
17
18
|
declare function resetValidate(): void;
|
|
@@ -75,6 +76,17 @@ declare var __VLS_10: {
|
|
|
75
76
|
* This doc block is consumed by vue-docgen for generated API documentation.
|
|
76
77
|
*/
|
|
77
78
|
) => string | true;
|
|
79
|
+
requireNotEmpty: (customError?: string) => (
|
|
80
|
+
/**
|
|
81
|
+
* FormPad is a schema-driven form field component that binds model data, renders field UI, and emits normalized updates.
|
|
82
|
+
* This doc block is consumed by vue-docgen for generated API documentation.
|
|
83
|
+
*/
|
|
84
|
+
value: any
|
|
85
|
+
/**
|
|
86
|
+
* FormPad is a schema-driven form field component that binds model data, renders field UI, and emits normalized updates.
|
|
87
|
+
* This doc block is consumed by vue-docgen for generated API documentation.
|
|
88
|
+
*/
|
|
89
|
+
) => string | true;
|
|
78
90
|
numeric: (customError?: string) => (
|
|
79
91
|
/**
|
|
80
92
|
* FormPad is a schema-driven form field component that binds model data, renders field UI, and emits normalized updates.
|
|
@@ -381,6 +393,17 @@ declare var __VLS_10: {
|
|
|
381
393
|
* This doc block is consumed by vue-docgen for generated API documentation.
|
|
382
394
|
*/
|
|
383
395
|
) => string | true;
|
|
396
|
+
requireNotEmpty: (customError?: string) => (
|
|
397
|
+
/**
|
|
398
|
+
* FormPad is a schema-driven form field component that binds model data, renders field UI, and emits normalized updates.
|
|
399
|
+
* This doc block is consumed by vue-docgen for generated API documentation.
|
|
400
|
+
*/
|
|
401
|
+
value: any
|
|
402
|
+
/**
|
|
403
|
+
* FormPad is a schema-driven form field component that binds model data, renders field UI, and emits normalized updates.
|
|
404
|
+
* This doc block is consumed by vue-docgen for generated API documentation.
|
|
405
|
+
*/
|
|
406
|
+
) => string | true;
|
|
384
407
|
numeric: (customError?: string) => (
|
|
385
408
|
/**
|
|
386
409
|
* FormPad is a schema-driven form field component that binds model data, renders field UI, and emits normalized updates.
|
|
@@ -650,6 +673,7 @@ declare const __VLS_base: import("vue").DefineComponent<Props, {
|
|
|
650
673
|
reset: typeof reset;
|
|
651
674
|
validate: typeof validate;
|
|
652
675
|
resetValidate: typeof resetValidate;
|
|
676
|
+
flushSanitize: typeof flushSanitize;
|
|
653
677
|
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
654
678
|
"update:modelValue": (...args: any[]) => void;
|
|
655
679
|
}, string, import("vue").PublicProps, Readonly<Props> & Readonly<{
|