@ramathibodi/nuxt-commons 0.1.37 → 0.1.39
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/ExportCSV.vue +51 -18
- package/dist/runtime/components/ImportCSV.vue +63 -12
- package/dist/runtime/components/document/Form.vue +43 -0
- package/dist/runtime/components/document/TemplateBuilder.vue +198 -62
- package/dist/runtime/components/form/Iterator.vue +256 -230
- package/dist/runtime/components/form/Pad.vue +4 -2
- package/dist/runtime/components/form/SignPad.vue +1 -1
- package/dist/runtime/components/form/Table.vue +163 -137
- package/dist/runtime/components/form/images/Capture.vue +83 -76
- package/dist/runtime/components/form/images/Edit.vue +19 -11
- package/dist/runtime/components/master/Autocomplete.vue +43 -130
- package/dist/runtime/components/master/label.vue +20 -19
- package/dist/runtime/components/model/Autocomplete.vue +23 -17
- package/dist/runtime/components/model/label.vue +8 -5
- package/dist/runtime/composables/document/template.d.ts +23 -1
- package/dist/runtime/composables/document/template.js +70 -54
- package/dist/runtime/composables/document/templateFormHidden.d.ts +2 -0
- package/dist/runtime/composables/document/templateFormHidden.js +10 -0
- package/dist/runtime/composables/document/templateFormTable.d.ts +2 -0
- package/dist/runtime/composables/document/templateFormTable.js +9 -0
- package/package.json +2 -2
|
@@ -1,113 +1,56 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
2
|
import {VAutocomplete} from 'vuetify/components/VAutocomplete'
|
|
3
|
-
import {concat
|
|
4
|
-
import {computed
|
|
5
|
-
import {watchDebounced} from '@vueuse/core'
|
|
6
|
-
import {useFuzzy} from '../../composables/utils/fuzzy'
|
|
7
|
-
import {useGraphQl} from '../../composables/graphql'
|
|
3
|
+
import {concat} from 'lodash-es'
|
|
4
|
+
import {computed} from 'vue'
|
|
8
5
|
|
|
9
6
|
interface Props extends /* @vue-ignore */ InstanceType<typeof VAutocomplete['$props']> {
|
|
10
|
-
|
|
7
|
+
sortBy?: 'itemCode' | 'itemValue'
|
|
8
|
+
showCode?: boolean
|
|
9
|
+
|
|
11
10
|
groupKey: string
|
|
11
|
+
itemCodes?: string[]
|
|
12
12
|
lang?: 'TH' | 'EN'
|
|
13
|
-
fields?: string
|
|
13
|
+
fields?: Array<string | object>
|
|
14
14
|
noDataText?: string
|
|
15
15
|
filterText?: string
|
|
16
16
|
waitForFilter?: boolean
|
|
17
17
|
waitForFilterText?: string
|
|
18
|
-
modelValue?: string
|
|
19
|
-
sortBy?: 'itemCode' | 'itemValue'
|
|
20
|
-
showCode?: boolean
|
|
21
18
|
}
|
|
22
19
|
|
|
23
20
|
const props = withDefaults(defineProps<Props>(), {
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
sortBy: 'itemValue',
|
|
22
|
+
showCode: false,
|
|
23
|
+
|
|
26
24
|
lang: 'TH',
|
|
25
|
+
noDataText: 'ไม่พบข้อมูล',
|
|
27
26
|
waitForFilter: false,
|
|
28
|
-
sortBy: 'itemValue',
|
|
29
|
-
showCode: false
|
|
30
27
|
})
|
|
31
28
|
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
const masterItems = ref<Array<any>>([])
|
|
35
|
-
const items = ref<Array<any>>([])
|
|
36
|
-
const selectedItem = ref<any>()
|
|
37
|
-
|
|
38
|
-
const searchData = ref<string>('')
|
|
39
|
-
|
|
40
|
-
const isLoading = ref(false)
|
|
41
|
-
const isErrorLoading = ref(false)
|
|
42
|
-
|
|
43
|
-
function query(groupKey: string, filterText: string | undefined) {
|
|
29
|
+
const computedModelName = computed(()=>{
|
|
44
30
|
let operation = 'masterItemByGroupKey'
|
|
31
|
+
if (props.filterText) operation = 'masterItemByGroupKeyAndFilterText'
|
|
32
|
+
if (props.itemCodes && props.itemCodes.length>0) operation = 'masterItemByGroupKeyAndItemCodeIn'
|
|
33
|
+
if (props.waitForFilter && !props.filterText) operation = ""
|
|
34
|
+
return operation
|
|
35
|
+
})
|
|
45
36
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
37
|
+
const computedModelBy = computed(()=>{
|
|
38
|
+
let modelBy : Record<string,any> = {groupKey: props.groupKey}
|
|
39
|
+
if (props.filterText) {
|
|
40
|
+
modelBy["filterText"] = props.filterText
|
|
50
41
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
if (props.fields) fields = concat(fields, props.fields)
|
|
54
|
-
|
|
55
|
-
isLoading.value = true
|
|
56
|
-
|
|
57
|
-
useGraphQl().queryPromise(operation, fields, variables).then((result: any) => {
|
|
58
|
-
masterItems.value = result
|
|
59
|
-
items.value = result
|
|
60
|
-
isErrorLoading.value = false
|
|
61
|
-
}).catch((_error) => {
|
|
62
|
-
isErrorLoading.value = true
|
|
63
|
-
}).finally(() => {
|
|
64
|
-
isLoading.value = false
|
|
65
|
-
})
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
watchEffect(()=>{
|
|
69
|
-
if (props.waitForFilter && !props.filterText) {
|
|
70
|
-
masterItems.value = []
|
|
71
|
-
items.value = []
|
|
72
|
-
selectedItem.value = undefined
|
|
73
|
-
} else {
|
|
74
|
-
query(props.groupKey, props.filterText)
|
|
42
|
+
if (props.itemCodes && props.itemCodes.length>0) {
|
|
43
|
+
modelBy["itemCodes"] = props.itemCodes
|
|
75
44
|
}
|
|
45
|
+
return modelBy
|
|
76
46
|
})
|
|
77
47
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
}, { immediate: true })
|
|
81
|
-
|
|
82
|
-
watch(selectedItem, (newValue) => {
|
|
83
|
-
emit('update:modelValue', newValue)
|
|
48
|
+
const computedFields = computed(()=>{
|
|
49
|
+
return concat(['itemCode', 'itemValue', 'itemValueAlternative'],props.fields)
|
|
84
50
|
})
|
|
85
51
|
|
|
86
|
-
async function fuzzySearch() {
|
|
87
|
-
if (props.fuzzy) {
|
|
88
|
-
if (isEmpty(searchData.value)) {
|
|
89
|
-
items.value = masterItems.value
|
|
90
|
-
}
|
|
91
|
-
else {
|
|
92
|
-
let fields: any[] = ['itemCode', 'itemValue', 'itemValueAlternative']
|
|
93
|
-
if (props.fields) fields = concat(fields, props.fields)
|
|
94
|
-
|
|
95
|
-
const results: any = useFuzzy(searchData.value, masterItems.value, fields)
|
|
96
|
-
items.value = []
|
|
97
|
-
if (results.value.length) {
|
|
98
|
-
for (let i = 0; results.value.length > i; i++) {
|
|
99
|
-
if (results.value[i].item) items.value.push(results.value[i].item)
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
watchDebounced(searchData, fuzzySearch, { debounce: 1000, maxWait: 5000 })
|
|
107
|
-
|
|
108
52
|
const itemTitleField = computed(() => {
|
|
109
|
-
|
|
110
|
-
else return 'itemValueAlternative'
|
|
53
|
+
return (props.lang == 'TH') ? 'itemValue' : 'itemValueAlternative'
|
|
111
54
|
})
|
|
112
55
|
|
|
113
56
|
const computedNoDataText = computed(() => {
|
|
@@ -116,64 +59,34 @@ const computedNoDataText = computed(() => {
|
|
|
116
59
|
})
|
|
117
60
|
|
|
118
61
|
const computedSortBy = computed(()=>{
|
|
119
|
-
|
|
120
|
-
if (sortByField == 'itemValue') {
|
|
62
|
+
if (props.sortBy == 'itemValue') {
|
|
121
63
|
if (props.showCode) return ['itemCode']
|
|
122
64
|
else return [itemTitleField.value,'itemValue','itemCode']
|
|
123
65
|
} else {
|
|
124
|
-
return [
|
|
125
|
-
}
|
|
126
|
-
})
|
|
127
|
-
|
|
128
|
-
const computedItems = computed(()=>{
|
|
129
|
-
if (props.fuzzy && !isEmpty(searchData.value)) {
|
|
130
|
-
return items.value
|
|
131
|
-
} else {
|
|
132
|
-
return sortBy(items.value, computedSortBy.value)
|
|
66
|
+
return [props.sortBy]
|
|
133
67
|
}
|
|
134
68
|
})
|
|
135
69
|
</script>
|
|
136
70
|
|
|
137
71
|
<template>
|
|
138
|
-
<
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
:loading="isLoading"
|
|
72
|
+
<model-autocomplete
|
|
73
|
+
:model-name="computedModelName"
|
|
74
|
+
:model-by="computedModelBy"
|
|
75
|
+
:fields="computedFields"
|
|
76
|
+
:sort-by="computedSortBy"
|
|
77
|
+
:item-title="itemTitleField"
|
|
78
|
+
item-value="itemCode"
|
|
79
|
+
:no-data-text="computedNoDataText"
|
|
80
|
+
:show-code="props.showCode"
|
|
148
81
|
>
|
|
149
|
-
<!-- @ts-ignore -->
|
|
150
82
|
<template
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
#[name]="slotData"
|
|
154
|
-
>
|
|
155
|
-
<slot
|
|
156
|
-
:name="name"
|
|
157
|
-
v-bind="((slotData || {}) as object)"
|
|
158
|
-
:operation="operation"
|
|
159
|
-
/>
|
|
160
|
-
</template>
|
|
161
|
-
<template
|
|
162
|
-
v-if="!$slots.item"
|
|
163
|
-
#item="{ props, item }"
|
|
83
|
+
v-if="!$slots.item"
|
|
84
|
+
#item="{ props, item }"
|
|
164
85
|
>
|
|
165
86
|
<v-list-item
|
|
166
|
-
|
|
167
|
-
|
|
87
|
+
v-bind="props"
|
|
88
|
+
:title="(showCode ? item.raw.itemCode+'-' : '')+(item.title || item.raw.itemValue || item.raw.itemCode)"
|
|
168
89
|
/>
|
|
169
90
|
</template>
|
|
170
|
-
|
|
171
|
-
v-if="isErrorLoading"
|
|
172
|
-
#append
|
|
173
|
-
>
|
|
174
|
-
<v-icon color="error">
|
|
175
|
-
mdi mdi-alert
|
|
176
|
-
</v-icon>
|
|
177
|
-
</template>
|
|
178
|
-
</v-autocomplete>
|
|
91
|
+
</model-autocomplete>
|
|
179
92
|
</template>
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
|
-
import { computedAsync } from '@vueuse/core'
|
|
3
|
-
import { useGraphQl } from '../../composables/graphql'
|
|
4
|
-
|
|
5
2
|
interface Props {
|
|
6
3
|
groupKey?: string | null
|
|
7
4
|
itemCode?: string | null
|
|
8
5
|
locale?: string
|
|
6
|
+
|
|
9
7
|
notFoundText?: string
|
|
10
8
|
placeholder?: string
|
|
11
9
|
}
|
|
@@ -14,24 +12,27 @@ const props = withDefaults(defineProps<Props>(), {
|
|
|
14
12
|
locale: 'TH',
|
|
15
13
|
})
|
|
16
14
|
|
|
17
|
-
const
|
|
18
|
-
if (props.groupKey && props.itemCode) {
|
|
19
|
-
try {
|
|
20
|
-
const result = await useGraphQl().queryPromise<any>("masterItemByGroupKeyAndItemCode",['itemValue', 'itemValueAlternative'],{ groupKey: props.groupKey, itemCode: props.itemCode })
|
|
21
|
-
|
|
22
|
-
if (result) {
|
|
23
|
-
return props.locale === 'TH'
|
|
24
|
-
? result.itemValue
|
|
25
|
-
: result.itemValueAlternative || result.itemValue
|
|
26
|
-
}
|
|
27
|
-
} catch (e) {
|
|
28
|
-
console.error(e)
|
|
29
|
-
}
|
|
30
|
-
}
|
|
15
|
+
const computedNotFoundText = computed(()=>{
|
|
31
16
|
return props.notFoundText || `${props.itemCode}`
|
|
32
|
-
}
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
const computedPlaceholder = computed(()=>{
|
|
20
|
+
return props.placeholder || `${props.groupKey}(${props.itemCode})`
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
const computedItemTitle = computed(()=>{
|
|
24
|
+
return (props.locale == 'TH')
|
|
25
|
+
? "itemValue"
|
|
26
|
+
: (result : Record<string,any>) => result["itemValueAlternative"] || result["itemValue"]
|
|
27
|
+
})
|
|
33
28
|
</script>
|
|
34
29
|
|
|
35
30
|
<template>
|
|
36
|
-
|
|
31
|
+
<model-label
|
|
32
|
+
model-name="masterItemByGroupKeyAndItemCode"
|
|
33
|
+
:model-by="{groupKey: props.groupKey, itemCode: props.itemCode}"
|
|
34
|
+
:item-title="computedItemTitle"
|
|
35
|
+
:not-found-text="computedNotFoundText"
|
|
36
|
+
:placeholder="computedPlaceholder"
|
|
37
|
+
></model-label>
|
|
37
38
|
</template>
|
|
@@ -8,7 +8,7 @@ import {useGraphQlOperation} from "../../composables/graphqlOperation";
|
|
|
8
8
|
|
|
9
9
|
interface Props extends /* @vue-ignore */ InstanceType<typeof VAutocomplete['$props']> {
|
|
10
10
|
fuzzy?: boolean
|
|
11
|
-
sortBy?: string
|
|
11
|
+
sortBy?: string | string[]
|
|
12
12
|
showCode?: boolean
|
|
13
13
|
|
|
14
14
|
modelName: string
|
|
@@ -48,21 +48,28 @@ watchEffect(()=>{
|
|
|
48
48
|
variables[props.serverSearchKey] = searchData.value
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
if (props.modelName) {
|
|
52
|
+
isLoading.value = true
|
|
52
53
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
54
|
+
useGraphQlOperation('Query',props.modelName,fields,variables,props.cache).then((result: any) => {
|
|
55
|
+
if (isArray(result)) {
|
|
56
|
+
modelItems.value = result
|
|
57
|
+
items.value = result
|
|
58
|
+
isErrorLoading.value = false
|
|
59
|
+
} else {
|
|
60
|
+
isErrorLoading.value = true
|
|
61
|
+
}
|
|
62
|
+
}).catch((_error) => {
|
|
63
|
+
modelItems.value = []
|
|
64
|
+
items.value = []
|
|
59
65
|
isErrorLoading.value = true
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
+
}).finally(() => {
|
|
67
|
+
isLoading.value = false
|
|
68
|
+
})
|
|
69
|
+
} else {
|
|
70
|
+
modelItems.value = []
|
|
71
|
+
items.value = []
|
|
72
|
+
}
|
|
66
73
|
})
|
|
67
74
|
|
|
68
75
|
async function fuzzySearch() {
|
|
@@ -88,12 +95,12 @@ async function fuzzySearch() {
|
|
|
88
95
|
watchDebounced(searchData, fuzzySearch, { debounce: 1000, maxWait: 5000 })
|
|
89
96
|
|
|
90
97
|
const computedItems = computed(()=>{
|
|
91
|
-
let sortByField = props.sortBy || ((props.showCode) ? props.itemValue : props.itemTitle)
|
|
98
|
+
let sortByField = (!props.sortBy || typeof props.sortBy === "string") ? [props.sortBy || ((props.showCode) ? props.itemValue : props.itemTitle)] : props.sortBy
|
|
92
99
|
|
|
93
100
|
if (props.fuzzy && !isEmpty(searchData.value)) {
|
|
94
101
|
return items.value
|
|
95
102
|
} else {
|
|
96
|
-
return sortBy(items.value,
|
|
103
|
+
return sortBy(items.value, sortByField)
|
|
97
104
|
}
|
|
98
105
|
})
|
|
99
106
|
</script>
|
|
@@ -117,7 +124,6 @@ const computedItems = computed(()=>{
|
|
|
117
124
|
<slot
|
|
118
125
|
:name="name"
|
|
119
126
|
v-bind="((slotData || {}) as object)"
|
|
120
|
-
:operation="operation"
|
|
121
127
|
/>
|
|
122
128
|
</template>
|
|
123
129
|
<template
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
2
|
import { computedAsync } from '@vueuse/core'
|
|
3
3
|
import { useGraphQlOperation } from '../../composables/graphqlOperation'
|
|
4
|
+
import {concat} from "lodash-es";
|
|
4
5
|
|
|
5
6
|
interface Props {
|
|
6
7
|
modelName: string
|
|
7
8
|
modelBy?: object
|
|
8
|
-
itemTitle: string
|
|
9
|
+
itemTitle: string | ((result:Record<string,any>)=>void)
|
|
9
10
|
fields?: Array<string | object>
|
|
10
11
|
cache?: boolean
|
|
11
12
|
|
|
@@ -19,14 +20,16 @@ const props = withDefaults(defineProps<Props>(), {
|
|
|
19
20
|
|
|
20
21
|
const modelItemValue = computedAsync<string>(async () => {
|
|
21
22
|
if (props.modelName && props.itemTitle) {
|
|
22
|
-
let fields: any[] = [props.itemTitle]
|
|
23
|
+
let fields: any[] = (typeof props.itemTitle === "string") ? [props.itemTitle] : []
|
|
24
|
+
if (props.fields) fields = concat(fields, props.fields)
|
|
25
|
+
|
|
23
26
|
const variables: Record<string, any> = Object.assign({},props.modelBy)
|
|
27
|
+
const result : Record<string, any> = await useGraphQlOperation('Query',props.modelName,fields,variables,props.cache)
|
|
24
28
|
|
|
25
29
|
try {
|
|
26
|
-
const result : Record<string, any> = await useGraphQlOperation('Query',props.modelName,fields,variables,props.cache)
|
|
27
|
-
|
|
28
30
|
if (result) {
|
|
29
|
-
return result[props.itemTitle]
|
|
31
|
+
if (typeof props.itemTitle === "string") return result[props.itemTitle]
|
|
32
|
+
else return props.itemTitle(result)
|
|
30
33
|
}
|
|
31
34
|
} catch (e) {
|
|
32
35
|
console.error(e)
|
|
@@ -1,2 +1,24 @@
|
|
|
1
|
+
export interface DocumentTemplateItem {
|
|
2
|
+
inputType: string;
|
|
3
|
+
width?: string | number;
|
|
4
|
+
inputLabel?: string;
|
|
5
|
+
variableName?: string;
|
|
6
|
+
validationRules?: string;
|
|
7
|
+
inputOptions?: string | object;
|
|
8
|
+
inputAttributes?: string;
|
|
9
|
+
inputCustomCode?: string;
|
|
10
|
+
columnAttributes?: string;
|
|
11
|
+
conditionalDisplay?: string;
|
|
12
|
+
computedValue?: string;
|
|
13
|
+
retrievedValue?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface ChoiceItem {
|
|
16
|
+
label: string;
|
|
17
|
+
value: string;
|
|
18
|
+
}
|
|
1
19
|
export declare const validationRulesRegex: RegExp;
|
|
2
|
-
export declare function useDocumentTemplate(items: string | object): string;
|
|
20
|
+
export declare function useDocumentTemplate(items: string | object, parentTemplates?: string | string[]): string;
|
|
21
|
+
export declare function optionStringToChoiceObject(option: string | object): ChoiceItem[];
|
|
22
|
+
export declare function escapeObjectForInlineBinding(obj: object): string;
|
|
23
|
+
export declare function buildValidationRules(validationString: string): string;
|
|
24
|
+
export declare function processDefaultTemplate(item: DocumentTemplateItem, insideTemplate?: string, optionString?: string, validationRules?: string): string;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { processTemplateFormTable } from "./templateFormTable.js";
|
|
2
|
+
import { processTemplateFormHidden } from "./templateFormHidden.js";
|
|
1
3
|
export const validationRulesRegex = /^(require(?:\([^)]*\))?|requireIf(?:\([^)]*\))?|requireTrue(?:\([^)]*\))?|requireTrueIf(?:\([^)]*\))?|numeric(?:\([^)]*\))?|range(?:\([^)]*\))?|integer(?:\([^)]*\))?|unique(?:\([^)]*\))?|length(?:\([^)]*\))?|lengthGreater(?:\([^)]*\))?|lengthLess(?:\([^)]*\))?|telephone(?:\([^)]*\))?|email(?:\([^)]*\))?|regex(?:\([^)]*\))?)(,(require(?:\([^)]*\))?|requireIf(?:\([^)]*\))?|requireTrue(?:\([^)]*\))?|requireTrueIf(?:\([^)]*\))?|numeric(?:\([^)]*\))?|range(?:\([^)]*\))?|integer(?:\([^)]*\))?|unique(?:\([^)]*\))?|length(?:\([^)]*\))?|lengthGreater(?:\([^)]*\))?|lengthLess(?:\([^)]*\))?|telephone(?:\([^)]*\))?|email(?:\([^)]*\))?|regex(?:\([^)]*\))?))*$/;
|
|
2
|
-
export function useDocumentTemplate(items) {
|
|
4
|
+
export function useDocumentTemplate(items, parentTemplates) {
|
|
3
5
|
if (!items) return "";
|
|
4
6
|
if (typeof items === "string") {
|
|
5
7
|
try {
|
|
@@ -11,94 +13,108 @@ export function useDocumentTemplate(items) {
|
|
|
11
13
|
if (!Array.isArray(items) || !items.every((item) => typeof item === "object" && item !== null)) {
|
|
12
14
|
return "";
|
|
13
15
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
return templateString;
|
|
16
|
+
const templateString = items.map((item) => templateItemToString(item, parentTemplates || [])).join("");
|
|
17
|
+
return !parentTemplates || parentTemplates.length == 0 ? `<v-container fluid><v-row dense>${templateString}</v-row></v-container>` : `<v-row dense>${templateString}</v-row>`;
|
|
17
18
|
}
|
|
18
|
-
function templateItemToString(item) {
|
|
19
|
+
function templateItemToString(item, parentTemplates) {
|
|
19
20
|
let optionString = "";
|
|
20
|
-
let validationRules = "";
|
|
21
21
|
if (item.inputOptions) {
|
|
22
|
-
if (item.inputType
|
|
23
|
-
optionString +=
|
|
22
|
+
if (item.inputType === "MasterAutocomplete") {
|
|
23
|
+
optionString += `groupKey="${item.inputOptions}" `;
|
|
24
24
|
}
|
|
25
|
-
if (
|
|
25
|
+
if (["VSelect", "VAutocomplete", "VCombobox"].includes(item.inputType)) {
|
|
26
26
|
const choice = optionStringToChoiceObject(item.inputOptions);
|
|
27
|
-
optionString = `item-value="value" item-title="label" :items='
|
|
27
|
+
optionString = `item-value="value" item-title="label" :items='${escapeObjectForInlineBinding(choice)}' `;
|
|
28
28
|
}
|
|
29
|
-
if (
|
|
29
|
+
if (["VRadio", "VRadioInline"].includes(item.inputType)) {
|
|
30
30
|
const choice = optionStringToChoiceObject(item.inputOptions);
|
|
31
|
-
optionString = choice.map((choiceItem) => `<v-radio label="${choiceItem.label}" value="${choiceItem.value}" ${item.inputAttributes ? " " + item.inputAttributes : ""}></v-radio>`).join("");
|
|
31
|
+
optionString = choice.map((choiceItem) => `<v-radio label="${choiceItem.label || ""}" value="${choiceItem.value || ""}" ${item.inputAttributes ? " " + item.inputAttributes : ""}></v-radio>`).join("");
|
|
32
32
|
}
|
|
33
|
-
if (item.inputType
|
|
34
|
-
optionString = item.inputOptions.split(",").join(" ");
|
|
33
|
+
if (item.inputType === "Header") {
|
|
34
|
+
if (typeof item.inputOptions === "string") optionString = item.inputOptions.split(",").join(" ");
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
|
-
if (item.
|
|
38
|
-
|
|
37
|
+
if (item.conditionalDisplay) {
|
|
38
|
+
item.inputAttributes = `${item.inputAttributes?.trim() || ""} v-if="${item.conditionalDisplay}"`.trim();
|
|
39
|
+
}
|
|
40
|
+
if (item.inputType === "FormDateTime" && !item.inputAttributes?.includes("dense")) {
|
|
41
|
+
item.inputAttributes = `${item.inputAttributes?.trim() || ""} dense`.trim();
|
|
42
|
+
}
|
|
39
43
|
let templateString;
|
|
40
44
|
switch (item.inputType) {
|
|
41
45
|
case "CustomCode":
|
|
42
|
-
templateString =
|
|
46
|
+
templateString = item.inputCustomCode || "";
|
|
43
47
|
break;
|
|
44
48
|
case "VRadio":
|
|
45
|
-
templateString = `<v-radio-group v-model="data.${item.variableName}" label="${item.inputLabel || item.variableName}"${validationRules ? " " + validationRules.trim() : ""}>${optionString ? " " + optionString.trim() : ""}</v-radio-group>`;
|
|
46
|
-
break;
|
|
47
49
|
case "VRadioInline":
|
|
48
|
-
|
|
50
|
+
const inlineAttr = item.inputType === "VRadioInline" ? " inline" : "";
|
|
51
|
+
const validationRules = item.validationRules ? buildValidationRules(item.validationRules) || "" : "";
|
|
52
|
+
templateString = `<v-radio-group v-model="data.${item.variableName || ""}"${inlineAttr}${validationRules ? " " + validationRules.trim() : ""}>${item.inputLabel ? `<template #prepend>${item.inputLabel}</template>` : ""}${optionString ? " " + optionString.trim() : ""}</v-radio-group>`;
|
|
49
53
|
break;
|
|
50
54
|
case "Separator":
|
|
51
|
-
templateString =
|
|
55
|
+
templateString = "</v-row><v-row dense>";
|
|
52
56
|
break;
|
|
53
57
|
case "Header":
|
|
54
|
-
templateString = `<div class="${optionString
|
|
58
|
+
templateString = `<div class="${optionString || "text-h4 font-weight-medium"}">${item.inputLabel || item.variableName || ""}</div>`;
|
|
55
59
|
break;
|
|
56
60
|
case "FormTable":
|
|
57
|
-
templateString =
|
|
58
|
-
<template #form>${item.inputFormTable}</template>
|
|
59
|
-
</form-table>`;
|
|
61
|
+
templateString = processTemplateFormTable(item, parentTemplates);
|
|
60
62
|
break;
|
|
61
63
|
case "FormHidden":
|
|
62
|
-
templateString =
|
|
63
|
-
|
|
64
|
+
templateString = processTemplateFormHidden(item, parentTemplates);
|
|
65
|
+
break;
|
|
66
|
+
case "DocumentForm":
|
|
67
|
+
const parentTemplatesString = typeof parentTemplates === "string" ? parentTemplates : parentTemplates.join("|");
|
|
68
|
+
templateString = `<document-form v-model="data" templateCode="${item.inputOptions || ""}" parent-templates="${parentTemplatesString}"></document-form>`;
|
|
64
69
|
break;
|
|
65
70
|
default:
|
|
66
|
-
templateString =
|
|
71
|
+
templateString = processDefaultTemplate(item, void 0, optionString);
|
|
72
|
+
}
|
|
73
|
+
if (!["Separator"].includes(item.inputType)) templateString = `<v-col${item.width ? ` cols="${item.width}"` : ""}${item.columnAttributes ? " " + item.columnAttributes : ""}>${templateString}</v-col>`;
|
|
74
|
+
if (["Header", "DocumentForm"].includes(item.inputType)) templateString = `</v-row><v-row dense>${templateString}</v-row><v-row dense>`;
|
|
75
|
+
if (item.computedValue && item.variableName) {
|
|
76
|
+
templateString = `${templateString || ""}<FormHidden v-model="data.${item.variableName}" :item-value="data" :hook="()=>${item.computedValue}"/>`.trim();
|
|
67
77
|
}
|
|
68
|
-
|
|
69
|
-
if (["Header"].includes(item.inputType)) templateString = `</v-row><v-row dense><v-col${item.columnAttributes ? " " + item.columnAttributes : ""}>${templateString}</v-col></v-row><v-row dense>`;
|
|
70
|
-
return templateString;
|
|
78
|
+
return templateString || "";
|
|
71
79
|
}
|
|
72
|
-
function optionStringToChoiceObject(option) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
80
|
+
export function optionStringToChoiceObject(option) {
|
|
81
|
+
if (typeof option === "string") {
|
|
82
|
+
if (!/^[^'",]+(,[^'",]+)*$/.test(option.trim())) return [];
|
|
83
|
+
return option.split(",").map((item) => {
|
|
76
84
|
item = item.trim();
|
|
77
85
|
if (item.includes("|")) {
|
|
78
86
|
const [label, value] = item.split("|").map((str) => str.trim().replace(/^['"]|['"]$/g, ""));
|
|
79
|
-
return { label, value };
|
|
80
|
-
} else {
|
|
81
|
-
item = item.replace(/^['"]|['"]$/g, "");
|
|
82
|
-
return { label: item, value: item };
|
|
87
|
+
return { label: label || "", value: value || "" };
|
|
83
88
|
}
|
|
89
|
+
item = item.replace(/^['"]|['"]$/g, "");
|
|
90
|
+
return { label: item, value: item };
|
|
84
91
|
});
|
|
85
92
|
}
|
|
86
|
-
|
|
93
|
+
if (Array.isArray(option) && option.every((item) => typeof item === "object" && item !== null)) {
|
|
94
|
+
return option.sort((a, b) => (a.id ?? Infinity) - (b.id ?? Infinity)).map((item) => ({
|
|
95
|
+
label: item.label || item.value || "",
|
|
96
|
+
// Default to empty string if label is undefined
|
|
97
|
+
value: item.value || ""
|
|
98
|
+
// Default to empty string if value is undefined
|
|
99
|
+
}));
|
|
100
|
+
}
|
|
101
|
+
return [];
|
|
102
|
+
}
|
|
103
|
+
export function escapeObjectForInlineBinding(obj) {
|
|
104
|
+
return JSON.stringify(obj).replace(/'/g, "'");
|
|
87
105
|
}
|
|
88
|
-
function buildValidationRules(validationString) {
|
|
89
|
-
validationString = validationString.trim();
|
|
90
|
-
if (validationString.startsWith("[")) validationString = validationString.substring(1);
|
|
91
|
-
if (validationString.endsWith("]")) validationString = validationString.substring(0, validationString.length - 1);
|
|
106
|
+
export function buildValidationRules(validationString) {
|
|
107
|
+
validationString = validationString.replace(/^\[|]$/g, "").trim();
|
|
92
108
|
if (!validationRulesRegex.test(validationString)) return "";
|
|
93
|
-
|
|
109
|
+
const rules = validationString.split(",").map((rule) => {
|
|
94
110
|
rule = rule.trim();
|
|
95
|
-
if (!rule.startsWith("rules.")) {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
return
|
|
111
|
+
if (!rule.startsWith("rules.")) rule = `rules.${rule}`;
|
|
112
|
+
if (!/\(.+\)$/.test(rule)) rule += "()";
|
|
113
|
+
return rule.replace(/"/g, "'");
|
|
114
|
+
});
|
|
115
|
+
return `:rules="[${rules.join(",")}]"`;
|
|
116
|
+
}
|
|
117
|
+
export function processDefaultTemplate(item, insideTemplate, optionString, validationRules) {
|
|
118
|
+
if (!validationRules) validationRules = item.validationRules ? buildValidationRules(item.validationRules) || "" : "";
|
|
119
|
+
return `<${item.inputType} v-model="data.${item.variableName || ""}" label="${item.inputLabel || item.variableName || ""}"${item.inputAttributes ? " " + item.inputAttributes : ""}${optionString ? " " + optionString.trim() : ""}${validationRules ? " " + validationRules.trim() : ""}>${insideTemplate || ""}</${item.inputType}>`;
|
|
104
120
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export function processTemplateFormHidden(item, parentTemplates) {
|
|
2
|
+
let formHiddenOptions = Object.assign({ itemValue: "", hook: "" }, item.inputOptions);
|
|
3
|
+
if (formHiddenOptions.hook.trim()) {
|
|
4
|
+
formHiddenOptions.hook = formHiddenOptions.hook.replace(/\n/g, ";").trim();
|
|
5
|
+
if (!/^return\s/.test(formHiddenOptions.hook)) {
|
|
6
|
+
formHiddenOptions.hook = `return ${formHiddenOptions.hook}`;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
return `<form-hidden v-model="data.${item.variableName || ""}" :item-value="${formHiddenOptions.itemValue || "data"}" :hook="(data,modelValue) => {${formHiddenOptions.hook}}"></form-hidden>`;
|
|
10
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import {
|
|
2
|
+
escapeObjectForInlineBinding,
|
|
3
|
+
processDefaultTemplate,
|
|
4
|
+
useDocumentTemplate
|
|
5
|
+
} from "./template.js";
|
|
6
|
+
export function processTemplateFormTable(item, parentTemplates) {
|
|
7
|
+
let tableOptions = Object.assign({ title: item.inputLabel || "", formTemplate: "" }, item.inputOptions);
|
|
8
|
+
return processDefaultTemplate(item, `<template #form="{data,rules}">${useDocumentTemplate(tableOptions.formTemplate)}</template>`, `title="${tableOptions.title}" :headers='${escapeObjectForInlineBinding(tableOptions.headers || {})}'`);
|
|
9
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ramathibodi/nuxt-commons",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.39",
|
|
4
4
|
"description": "Ramathibodi Nuxt modules for common components",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -115,5 +115,5 @@
|
|
|
115
115
|
"vitest": "^1.6.0",
|
|
116
116
|
"vue-tsc": "2.0.29"
|
|
117
117
|
},
|
|
118
|
-
"packageManager": "pnpm@9.15.
|
|
118
|
+
"packageManager": "pnpm@9.15.4+sha512.b2dc20e2fc72b3e18848459b37359a32064663e5627a51e4c74b2c29dd8e8e0491483c3abb40789cfd578bf362fb6ba8261b05f0387d76792ed6e23ea3b1b6a0"
|
|
119
119
|
}
|