@ramathibodi/nuxt-commons 0.1.74 → 0.1.75
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/README.md +115 -115
- package/dist/module.json +1 -1
- package/dist/runtime/components/Alert.vue +58 -58
- package/dist/runtime/components/BarcodeReader.vue +130 -130
- package/dist/runtime/components/ExportCSV.vue +110 -110
- package/dist/runtime/components/FileBtn.vue +79 -79
- package/dist/runtime/components/ImportCSV.vue +151 -151
- package/dist/runtime/components/MrzReader.vue +168 -168
- package/dist/runtime/components/SplitterPanel.vue +67 -67
- package/dist/runtime/components/TabsGroup.vue +39 -39
- package/dist/runtime/components/TextBarcode.vue +66 -66
- package/dist/runtime/components/device/IdCardButton.vue +95 -95
- package/dist/runtime/components/device/IdCardWebSocket.vue +207 -207
- package/dist/runtime/components/device/Scanner.vue +350 -350
- package/dist/runtime/components/dialog/Confirm.vue +112 -112
- package/dist/runtime/components/dialog/Host.vue +88 -88
- package/dist/runtime/components/dialog/Index.vue +84 -84
- package/dist/runtime/components/dialog/Loading.vue +51 -51
- package/dist/runtime/components/dialog/default/Confirm.vue +112 -112
- package/dist/runtime/components/dialog/default/Loading.vue +60 -60
- package/dist/runtime/components/dialog/default/Notify.vue +82 -82
- package/dist/runtime/components/dialog/default/Printing.vue +46 -46
- package/dist/runtime/components/dialog/default/VerifyUser.vue +144 -144
- package/dist/runtime/components/document/Form.vue +50 -50
- package/dist/runtime/components/document/TemplateBuilder.vue +536 -536
- package/dist/runtime/components/form/ActionPad.vue +156 -156
- package/dist/runtime/components/form/Birthdate.vue +116 -116
- package/dist/runtime/components/form/CheckboxGroup.vue +99 -99
- package/dist/runtime/components/form/CodeEditor.vue +45 -45
- package/dist/runtime/components/form/Date.vue +270 -270
- package/dist/runtime/components/form/DateTime.vue +220 -220
- package/dist/runtime/components/form/Dialog.vue +178 -178
- package/dist/runtime/components/form/EditPad.vue +157 -157
- package/dist/runtime/components/form/File.vue +295 -295
- package/dist/runtime/components/form/Hidden.vue +44 -44
- package/dist/runtime/components/form/Iterator.vue +538 -538
- package/dist/runtime/components/form/Login.vue +143 -143
- package/dist/runtime/components/form/Pad.vue +399 -399
- package/dist/runtime/components/form/SignPad.vue +226 -226
- package/dist/runtime/components/form/System.vue +34 -34
- package/dist/runtime/components/form/Table.vue +391 -391
- package/dist/runtime/components/form/TableData.vue +236 -236
- package/dist/runtime/components/form/Time.vue +177 -177
- package/dist/runtime/components/form/images/Capture.vue +245 -245
- package/dist/runtime/components/form/images/Edit.vue +133 -133
- package/dist/runtime/components/form/images/Field.vue +331 -331
- package/dist/runtime/components/form/images/Pad.vue +54 -54
- package/dist/runtime/components/label/Date.vue +37 -37
- package/dist/runtime/components/label/DateAgo.vue +102 -102
- package/dist/runtime/components/label/DateCount.vue +152 -152
- package/dist/runtime/components/label/Field.vue +111 -111
- package/dist/runtime/components/label/FormatMoney.vue +37 -37
- package/dist/runtime/components/label/Mask.vue +46 -46
- package/dist/runtime/components/label/Object.vue +21 -21
- package/dist/runtime/components/master/Autocomplete.vue +89 -89
- package/dist/runtime/components/master/Combobox.vue +88 -88
- package/dist/runtime/components/master/RadioGroup.vue +90 -90
- package/dist/runtime/components/master/Select.vue +70 -70
- package/dist/runtime/components/master/label.vue +55 -55
- package/dist/runtime/components/model/Autocomplete.vue +91 -91
- package/dist/runtime/components/model/Combobox.vue +90 -90
- package/dist/runtime/components/model/Pad.vue +114 -114
- package/dist/runtime/components/model/Select.vue +78 -84
- package/dist/runtime/components/model/Table.vue +370 -370
- package/dist/runtime/components/model/iterator.vue +497 -497
- package/dist/runtime/components/model/label.vue +58 -58
- package/dist/runtime/components/pdf/Print.vue +75 -75
- package/dist/runtime/components/pdf/View.vue +146 -146
- package/dist/runtime/composables/dialog.d.ts +1 -1
- package/dist/runtime/composables/graphql.d.ts +1 -1
- package/dist/runtime/composables/graphqlModel.d.ts +9 -9
- package/dist/runtime/composables/graphqlModelItem.d.ts +7 -7
- package/dist/runtime/composables/graphqlModelOperation.d.ts +6 -6
- package/dist/runtime/composables/userPermission.d.ts +1 -1
- package/dist/runtime/labs/Calendar.vue +99 -99
- package/dist/runtime/labs/form/EditMobile.vue +152 -152
- package/dist/runtime/labs/form/TextFieldMask.vue +43 -43
- package/dist/runtime/plugins/clientConfig.d.ts +1 -1
- package/dist/runtime/plugins/default.d.ts +1 -1
- package/dist/runtime/plugins/dialogManager.d.ts +1 -1
- package/dist/runtime/plugins/permission.d.ts +1 -1
- package/dist/runtime/types/alert.d.ts +11 -11
- package/dist/runtime/types/clientConfig.d.ts +13 -13
- package/dist/runtime/types/dialogManager.d.ts +35 -35
- package/dist/runtime/types/formDialog.d.ts +5 -5
- package/dist/runtime/types/graphqlOperation.d.ts +23 -23
- package/dist/runtime/types/menu.d.ts +31 -31
- package/dist/runtime/types/modules.d.ts +7 -7
- package/dist/runtime/types/permission.d.ts +13 -13
- package/package.json +131 -131
- package/scripts/enrich-vue-docs-from-ai.mjs +197 -197
- package/scripts/generate-ai-summary.mjs +321 -321
- package/scripts/generate-composables-md.mjs +129 -129
- package/scripts/postInstall.cjs +70 -70
- package/templates/.codegen/codegen.ts +32 -32
- package/templates/.codegen/plugin-schema-object.js +161 -161
|
@@ -1,536 +1,536 @@
|
|
|
1
|
-
<script lang="ts" setup>
|
|
2
|
-
/**
|
|
3
|
-
* DocumentTemplateBuilder supports document-template rendering and synchronizes template-defined field behavior with runtime data.
|
|
4
|
-
* This doc block is consumed by vue-docgen for generated API documentation.
|
|
5
|
-
*/
|
|
6
|
-
import {computed, ref, watch} from 'vue'
|
|
7
|
-
import * as prettier from 'prettier'
|
|
8
|
-
import prettierPluginHtml from 'prettier/plugins/html'
|
|
9
|
-
import {useDocumentTemplate, validationRulesRegex,optionStringToChoiceObject} from '../../composables/document/template'
|
|
10
|
-
import {autoActionHeader,templateToHeader} from "../../composables/document/templateFormTable";
|
|
11
|
-
import {cloneDeep} from "lodash-es";
|
|
12
|
-
import VueJsonPretty from 'vue-json-pretty';
|
|
13
|
-
import 'vue-json-pretty/lib/styles.css';
|
|
14
|
-
import {safeParseJSONDeep} from "../../utils/object";
|
|
15
|
-
|
|
16
|
-
interface Props {
|
|
17
|
-
title?: string // Title text displayed in the component header or dialog.
|
|
18
|
-
disableAdvanceMode?: boolean // Disables advanced editor mode toggles and actions.
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Public props accepted by DocumentTemplateBuilder.
|
|
23
|
-
* Document each prop field with intent, defaults, and side effects for clear generated docs.
|
|
24
|
-
*/
|
|
25
|
-
const props = withDefaults(defineProps<Props>(), {
|
|
26
|
-
title: "Document Template",
|
|
27
|
-
disableAdvanceMode: false,
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Custom events emitted by DocumentTemplateBuilder.
|
|
32
|
-
* Parents can listen to these events to react to user actions and internal state changes.
|
|
33
|
-
*/
|
|
34
|
-
const emit = defineEmits(['update:modelValue'])
|
|
35
|
-
const modelValue = defineModel<string|Record<string, any>[]>()
|
|
36
|
-
|
|
37
|
-
const advanceModeCode = ref<string>()
|
|
38
|
-
const isAdvanceMode = computed(() => {
|
|
39
|
-
return modelValue.value && ((typeof modelValue.value === "string") && !isValidJsonArrayOfObjects(modelValue.value))
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
const templateItems = ref<Record<string, any>[]>([])
|
|
43
|
-
|
|
44
|
-
const headers = ref([
|
|
45
|
-
{ title: '',
|
|
46
|
-
key: 'operation',
|
|
47
|
-
width: '120px',
|
|
48
|
-
},
|
|
49
|
-
{
|
|
50
|
-
title: 'Rec No.',
|
|
51
|
-
key: 'recNo',
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
title: 'Input Type',
|
|
55
|
-
key: 'inputType',
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
title: 'Width',
|
|
59
|
-
key: 'width',
|
|
60
|
-
},
|
|
61
|
-
{
|
|
62
|
-
title: 'Input Label',
|
|
63
|
-
key: 'inputLabel',
|
|
64
|
-
},
|
|
65
|
-
{
|
|
66
|
-
title: 'Variable Name',
|
|
67
|
-
key: 'variableName',
|
|
68
|
-
},
|
|
69
|
-
{
|
|
70
|
-
title: 'Configuration',
|
|
71
|
-
key: 'configuration',
|
|
72
|
-
},
|
|
73
|
-
{
|
|
74
|
-
title: 'Action',
|
|
75
|
-
key: 'action',
|
|
76
|
-
width: '120px',
|
|
77
|
-
},
|
|
78
|
-
])
|
|
79
|
-
|
|
80
|
-
const formTableHeaders = ref([
|
|
81
|
-
{
|
|
82
|
-
title: 'Title',
|
|
83
|
-
key: 'title',
|
|
84
|
-
},
|
|
85
|
-
{
|
|
86
|
-
title: 'Key',
|
|
87
|
-
key: 'key',
|
|
88
|
-
},
|
|
89
|
-
{
|
|
90
|
-
title: 'Width',
|
|
91
|
-
key: 'width',
|
|
92
|
-
},
|
|
93
|
-
{
|
|
94
|
-
title: 'Action',
|
|
95
|
-
key: 'action',
|
|
96
|
-
width: '120px',
|
|
97
|
-
},
|
|
98
|
-
])
|
|
99
|
-
|
|
100
|
-
const choiceHeaders = ref([
|
|
101
|
-
{
|
|
102
|
-
title: 'Label',
|
|
103
|
-
key: 'label',
|
|
104
|
-
},
|
|
105
|
-
{
|
|
106
|
-
title: 'Value',
|
|
107
|
-
key: 'value',
|
|
108
|
-
},
|
|
109
|
-
{
|
|
110
|
-
title: 'Action',
|
|
111
|
-
key: 'action',
|
|
112
|
-
width: '120px',
|
|
113
|
-
},
|
|
114
|
-
])
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
function isValidJsonArrayOfObjects(str: string | undefined) {
|
|
118
|
-
try {
|
|
119
|
-
const parsed = JSON.parse(str as string)
|
|
120
|
-
return Array.isArray(parsed) && parsed.every(item => typeof item === 'object' && item !== null && !Array.isArray(item))
|
|
121
|
-
}
|
|
122
|
-
catch (e) {
|
|
123
|
-
return false
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
watch(templateItems, (newValue) => {
|
|
128
|
-
if (!isAdvanceMode.value) modelValue.value = JSON.stringify(newValue)
|
|
129
|
-
}, { deep: true })
|
|
130
|
-
|
|
131
|
-
watch(modelValue, (newValue) => {
|
|
132
|
-
if (typeof newValue === "string" && isValidJsonArrayOfObjects(newValue)) templateItems.value = JSON.parse(newValue as string)
|
|
133
|
-
else if (typeof newValue === "string") advanceModeCode.value = newValue
|
|
134
|
-
else if (newValue) templateItems.value = cloneDeep(newValue)
|
|
135
|
-
}, { deep: true, immediate: true })
|
|
136
|
-
|
|
137
|
-
watch(advanceModeCode, (newValue)=>{
|
|
138
|
-
if (isAdvanceMode.value) modelValue.value = newValue
|
|
139
|
-
})
|
|
140
|
-
|
|
141
|
-
async function convertToAdvanceMode() {
|
|
142
|
-
if (!isAdvanceMode.value) {
|
|
143
|
-
modelValue.value = await prettier.format(useDocumentTemplate(templateItems.value).replaceAll('>', '>\n'), { parser: 'html', plugins: [prettierPluginHtml] })
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
const inputTypeChoice = ref([
|
|
147
|
-
{ label: 'Text Field', value: 'VTextField' },
|
|
148
|
-
{ label: 'Text Area', value: 'VTextarea' },
|
|
149
|
-
{ label: 'Text Date Picker', value: 'FormDate' },
|
|
150
|
-
{ label: 'Text Time Picker', value: 'FormTime' },
|
|
151
|
-
{ label: 'Text Date & Time Picker', value: 'FormDateTime' },
|
|
152
|
-
{ label: 'Select Dropdown', value: 'VSelect' },
|
|
153
|
-
{ label: 'Select Combobox', value: 'VCombobox' },
|
|
154
|
-
{ label: 'Autocomplete', value: 'VAutocomplete' },
|
|
155
|
-
{ label: 'Autocomplete from Master', value: 'MasterAutocomplete' },
|
|
156
|
-
{ label: 'Radio Buttons', value: 'VRadio' },
|
|
157
|
-
{ label: 'Radio Buttons Inline', value: 'VRadioInline' },
|
|
158
|
-
{ label: 'Checkbox', value: 'VCheckbox' },
|
|
159
|
-
{ label: 'Checkbox Group', value: 'FormCheckboxGroup' },
|
|
160
|
-
{ label: 'Switch', value: 'VSwitch' },
|
|
161
|
-
{ label: 'File Upload', value: 'FormFile' },
|
|
162
|
-
{ label: 'Signature Pad', value: 'FormSignPad' },
|
|
163
|
-
{ label: 'Table', value: 'FormTable' },
|
|
164
|
-
{ label: 'Table Data', value: 'FormTableData' },
|
|
165
|
-
{ label: '[Decoration] Header', value: 'Header' },
|
|
166
|
-
{ label: '[Decoration] Separator', value: 'Separator' },
|
|
167
|
-
{ label: '[Advanced] Hidden Field', value: 'FormHidden' },
|
|
168
|
-
{ label: '[Advanced] Inherit Form', value: 'DocumentForm' },
|
|
169
|
-
{ label: '[Advanced] Custom Code', value: 'CustomCode' },
|
|
170
|
-
]);
|
|
171
|
-
|
|
172
|
-
const requireOption = ref(['VSelect', 'VAutocomplete', 'VCombobox', 'VRadio', 'VRadioInline', 'MasterAutocomplete','FormTable','FormTableData','DocumentForm','FormCheckboxGroup'])
|
|
173
|
-
const notRequireVariable = ref(['Header', 'Separator', 'CustomCode','DocumentForm'])
|
|
174
|
-
const notRequireLabel = ref(['Separator', 'CustomCode', 'FormFile', 'FormHidden','DocumentForm'])
|
|
175
|
-
const notRequireWidth = ref(['Separator', 'FormHidden','DocumentForm'])
|
|
176
|
-
const notRequireOptions = ref(['Separator','CustomCode', 'FormFile'])
|
|
177
|
-
const notRequireRules = ref(['Separator','Header','CustomCode','FormHidden','DocumentForm'])
|
|
178
|
-
const notRequireInputAttributes = ref(['CustomCode','Header','DocumentForm'])
|
|
179
|
-
const notRequireColumnAttributes = ref(['Separator', 'FormHidden','DocumentForm'])
|
|
180
|
-
const notRequireAdvancedSetting = ref(['Separator','CustomCode'])
|
|
181
|
-
const notRequireClassAndStyle = ref(['FormHidden'])
|
|
182
|
-
|
|
183
|
-
const hasSpecificOption = ref(['FormHidden','FormTable','FormTableData'])
|
|
184
|
-
|
|
185
|
-
const choiceOption = ref(['VRadio', 'VRadioInline','VSelect', 'VAutocomplete', 'VCombobox','FormCheckboxGroup'])
|
|
186
|
-
const inputOptionsLabel = ref<Record<string,string>>({
|
|
187
|
-
'MasterAutocomplete' : "Group Key",
|
|
188
|
-
'Header' : "Class",
|
|
189
|
-
'DocumentForm': "Template Code",
|
|
190
|
-
})
|
|
191
|
-
|
|
192
|
-
const ruleOptions = (inputType: string) => (value: any) => {
|
|
193
|
-
if (choiceOption.value.includes(inputType) && !(/^[^'",]+(,[^'",]+)*$/.test(value))) return 'Invalid options format'
|
|
194
|
-
|
|
195
|
-
return true
|
|
196
|
-
}
|
|
197
|
-
</script>
|
|
198
|
-
|
|
199
|
-
<template>
|
|
200
|
-
<FormTable
|
|
201
|
-
v-if="!isAdvanceMode"
|
|
202
|
-
v-model="templateItems"
|
|
203
|
-
:headers="headers"
|
|
204
|
-
:title="props.title"
|
|
205
|
-
>
|
|
206
|
-
<template #toolbarItems>
|
|
207
|
-
<VBtn
|
|
208
|
-
color="primary"
|
|
209
|
-
variant="flat"
|
|
210
|
-
@click="convertToAdvanceMode()"
|
|
211
|
-
v-if="!disableAdvanceMode"
|
|
212
|
-
>
|
|
213
|
-
Convert To Advance
|
|
214
|
-
</VBtn>
|
|
215
|
-
</template>
|
|
216
|
-
<template #item.recNo="{internalItem}">
|
|
217
|
-
{{ internalItem.index }}
|
|
218
|
-
</template>
|
|
219
|
-
<template #form="{ data, rules }">
|
|
220
|
-
<v-container fluid>
|
|
221
|
-
<v-row dense>
|
|
222
|
-
<v-col cols="3">
|
|
223
|
-
<v-combobox
|
|
224
|
-
v-model="data.inputType"
|
|
225
|
-
label="Input Type"
|
|
226
|
-
:items="inputTypeChoice"
|
|
227
|
-
item-title="label"
|
|
228
|
-
item-value="value"
|
|
229
|
-
:return-object="false"
|
|
230
|
-
:rules="[rules.require()]"
|
|
231
|
-
/>
|
|
232
|
-
</v-col>
|
|
233
|
-
<v-col cols="1" v-if="!notRequireWidth.includes(data.inputType)">
|
|
234
|
-
<v-text-field
|
|
235
|
-
v-model="data.width"
|
|
236
|
-
label="Width"
|
|
237
|
-
:rules="[rules.require()]"
|
|
238
|
-
type="number"
|
|
239
|
-
/>
|
|
240
|
-
<form-hidden v-model="data.inputOptions" :item-value="data.inputType" :hook="(_result: any,model: any,newValue: any,oldValue: any)=>{return (newValue && oldValue) ? undefined : model}"></form-hidden>
|
|
241
|
-
</v-col>
|
|
242
|
-
<v-col cols="4" v-if="!notRequireLabel.includes(data.inputType)">
|
|
243
|
-
<v-text-field
|
|
244
|
-
v-model="data.inputLabel"
|
|
245
|
-
label="Input Label"
|
|
246
|
-
:rules="[rules.require()]"
|
|
247
|
-
/>
|
|
248
|
-
</v-col>
|
|
249
|
-
<v-col cols="4" v-if="!notRequireVariable.includes(data.inputType)">
|
|
250
|
-
<v-text-field
|
|
251
|
-
v-model="data.variableName"
|
|
252
|
-
label="Variable Name"
|
|
253
|
-
:rules="[rules.require()]"
|
|
254
|
-
/>
|
|
255
|
-
</v-col>
|
|
256
|
-
<v-col
|
|
257
|
-
v-if="!notRequireOptions.includes(data.inputType)"
|
|
258
|
-
cols="12"
|
|
259
|
-
>
|
|
260
|
-
<form-pad v-model="data.inputOptions" v-if="data.inputType=='FormTable'">
|
|
261
|
-
<template #default="{data: optionData}">
|
|
262
|
-
<v-row dense>
|
|
263
|
-
<v-col cols="12">
|
|
264
|
-
<form-table v-model="optionData.headers" :headers="formTableHeaders" title="Headers">
|
|
265
|
-
<template #form="{data: headerData,rules}">
|
|
266
|
-
<v-container fluid>
|
|
267
|
-
<v-row dense>
|
|
268
|
-
<v-col cols="6"><v-text-field v-model="headerData.title" label="Title"></v-text-field></v-col>
|
|
269
|
-
<v-col cols="3"><v-text-field v-model="headerData.key" label="Key" :rules="[rules.require()]"></v-text-field></v-col>
|
|
270
|
-
<v-col cols="3"><v-text-field v-model="headerData.width" label="Width"></v-text-field></v-col>
|
|
271
|
-
</v-row>
|
|
272
|
-
<v-row dense>
|
|
273
|
-
<v-col cols="12"><v-textarea v-model="headerData.template" label="Item Template"></v-textarea></v-col>
|
|
274
|
-
</v-row>
|
|
275
|
-
</v-container>
|
|
276
|
-
</template>
|
|
277
|
-
</form-table>
|
|
278
|
-
</v-col>
|
|
279
|
-
<v-col cols="12">
|
|
280
|
-
<document-template-builder v-model="optionData.formTemplate" title="Form Template"></document-template-builder>
|
|
281
|
-
</v-col>
|
|
282
|
-
</v-row>
|
|
283
|
-
</template>
|
|
284
|
-
</form-pad>
|
|
285
|
-
<form-pad v-model="data.inputOptions" v-if="data.inputType=='FormTableData'">
|
|
286
|
-
<template #default="{data: optionData}">
|
|
287
|
-
<v-row dense>
|
|
288
|
-
<v-col cols="12">
|
|
289
|
-
<tabs-group>
|
|
290
|
-
<template #tabs>
|
|
291
|
-
<v-tab value="itemTemplate">Item Template</v-tab>
|
|
292
|
-
<v-tab value="dataTemplate">Data Template</v-tab>
|
|
293
|
-
<v-tab value="header">Header</v-tab>
|
|
294
|
-
</template>
|
|
295
|
-
<template #items>
|
|
296
|
-
<v-tabs-window-item value="itemTemplate">
|
|
297
|
-
<document-template-builder v-model="optionData.itemTemplate" title="Item Template" disable-advance-mode></document-template-builder>
|
|
298
|
-
</v-tabs-window-item>
|
|
299
|
-
<v-tabs-window-item value="dataTemplate">
|
|
300
|
-
<document-template-builder v-model="optionData.dataTemplate" title="Data Template" disable-advance-mode></document-template-builder>
|
|
301
|
-
</v-tabs-window-item>
|
|
302
|
-
<v-tabs-window-item value="header">
|
|
303
|
-
<form-table v-model="optionData.headers" :headers="formTableHeaders" title="Headers">
|
|
304
|
-
<template #form="{data: headerData,rules}">
|
|
305
|
-
<v-container fluid>
|
|
306
|
-
<v-row dense>
|
|
307
|
-
<v-col cols="6"><v-text-field v-model="headerData.title" label="Title"></v-text-field></v-col>
|
|
308
|
-
<v-col cols="3"><v-text-field v-model="headerData.key" label="Key" :rules="[rules.require()]"></v-text-field></v-col>
|
|
309
|
-
<v-col cols="3"><v-text-field v-model="headerData.width" label="Width"></v-text-field></v-col>
|
|
310
|
-
</v-row>
|
|
311
|
-
<v-row dense>
|
|
312
|
-
<v-col cols="12"><v-text-field v-model="headerData.value" label="Value"></v-text-field></v-col>
|
|
313
|
-
<v-col cols="12"><v-textarea v-model="headerData.template" label="Item Template"></v-textarea></v-col>
|
|
314
|
-
</v-row>
|
|
315
|
-
</v-container>
|
|
316
|
-
</template>
|
|
317
|
-
</form-table>
|
|
318
|
-
</v-tabs-window-item>
|
|
319
|
-
</template>
|
|
320
|
-
</tabs-group>
|
|
321
|
-
</v-col>
|
|
322
|
-
<v-col cols="12">
|
|
323
|
-
<form-table v-model="optionData.items" :headers="(optionData.headers && optionData.headers.length>0) ? autoActionHeader(optionData.headers) : autoActionHeader(templateToHeader(optionData.itemTemplate))" title="Items">
|
|
324
|
-
<template #form="{data}">
|
|
325
|
-
<form-pad :model-value="data" :template="optionData.itemTemplate"></form-pad>
|
|
326
|
-
</template>
|
|
327
|
-
</form-table>
|
|
328
|
-
</v-col>
|
|
329
|
-
<v-col cols="12">
|
|
330
|
-
<v-row dense>
|
|
331
|
-
<v-col cols="4">
|
|
332
|
-
<v-radio-group v-model="optionData.disableApplyToAll" inline>
|
|
333
|
-
<template #prepend>
|
|
334
|
-
<span class="opacity-60"> Disable Apply to All</span>
|
|
335
|
-
</template>
|
|
336
|
-
<v-radio label="No" value="false" hide-details> </v-radio>
|
|
337
|
-
<v-radio label="Yes" value="true" hide-details> </v-radio>
|
|
338
|
-
<v-radio label="Partial" value="partial" hide-details> </v-radio>
|
|
339
|
-
</v-radio-group>
|
|
340
|
-
</v-col>
|
|
341
|
-
<v-col cols="8">
|
|
342
|
-
<VTextField
|
|
343
|
-
variant="underlined"
|
|
344
|
-
v-model="optionData.disableApplyToAllPartial"
|
|
345
|
-
label="Disable Apply To All Column"
|
|
346
|
-
v-if="optionData.disableApplyToAll=='partial'"
|
|
347
|
-
>
|
|
348
|
-
</VTextField>
|
|
349
|
-
</v-col>
|
|
350
|
-
</v-row>
|
|
351
|
-
</v-col>
|
|
352
|
-
</v-row>
|
|
353
|
-
</template>
|
|
354
|
-
</form-pad>
|
|
355
|
-
<form-pad v-model="data.inputOptions" v-if="data.inputType=='FormHidden'">
|
|
356
|
-
<template #default="{data: optionData}">
|
|
357
|
-
<v-row dense>
|
|
358
|
-
<v-col cols="12">
|
|
359
|
-
<v-text-field
|
|
360
|
-
v-model="optionData.hook"
|
|
361
|
-
label="Hook"
|
|
362
|
-
/>
|
|
363
|
-
</v-col>
|
|
364
|
-
<v-col cols="12">
|
|
365
|
-
<v-text-field
|
|
366
|
-
v-model="optionData.itemValue"
|
|
367
|
-
label="Item Value"
|
|
368
|
-
/>
|
|
369
|
-
</v-col>
|
|
370
|
-
</v-row>
|
|
371
|
-
</template>
|
|
372
|
-
</form-pad>
|
|
373
|
-
<form-table v-model="data.inputOptions" :headers="choiceHeaders" title="Choices" v-if="choiceOption.includes(data.inputType) && (!data.inputOptions || typeof data.inputOptions === 'object')">
|
|
374
|
-
<template #form="{data: optionData,rules}">
|
|
375
|
-
<v-container fluid>
|
|
376
|
-
<v-row dense>
|
|
377
|
-
<v-col cols="6"><v-text-field v-model="optionData.label" label="Label"></v-text-field></v-col>
|
|
378
|
-
<v-col cols="6"><v-text-field v-model="optionData.value" label="Value" :rules="[rules.require()]"></v-text-field></v-col>
|
|
379
|
-
</v-row>
|
|
380
|
-
</v-container>
|
|
381
|
-
</template>
|
|
382
|
-
</form-table>
|
|
383
|
-
<form-hidden v-model="data.inputOptions" :itemValue="data.inputOptions" :hook="(option: any)=>optionStringToChoiceObject(option)" v-if="choiceOption.includes(data.inputType) && data.inputOptions && typeof data.inputOptions === 'string'"></form-hidden>
|
|
384
|
-
<v-textarea
|
|
385
|
-
v-model="data.inputOptions"
|
|
386
|
-
:label="inputOptionsLabel[data.inputType] || 'Input Options'"
|
|
387
|
-
auto-grow
|
|
388
|
-
:rules="[rules.requireIf(requireOption.includes(data.inputType)), ruleOptions(data.inputType)]"
|
|
389
|
-
v-if="!hasSpecificOption.includes(data.inputType) && !choiceOption.includes(data.inputType)"
|
|
390
|
-
/>
|
|
391
|
-
</v-col>
|
|
392
|
-
|
|
393
|
-
<v-col
|
|
394
|
-
v-if="data.inputType=='CustomCode'"
|
|
395
|
-
cols="12"
|
|
396
|
-
>
|
|
397
|
-
<FormCodeEditor
|
|
398
|
-
v-model="data.inputCustomCode"
|
|
399
|
-
label="Custom Code"
|
|
400
|
-
:rules="[rules.require()]"
|
|
401
|
-
/>
|
|
402
|
-
</v-col>
|
|
403
|
-
</v-row>
|
|
404
|
-
<v-row dense>
|
|
405
|
-
<v-col>
|
|
406
|
-
<v-expansion-panels>
|
|
407
|
-
<v-expansion-panel v-if="!notRequireRules.includes(data.inputType)">
|
|
408
|
-
<v-expansion-panel-title collapse-icon="mdi mdi-minus" expand-icon="mdi mdi-plus" class="font-weight-bold">Validations</v-expansion-panel-title>
|
|
409
|
-
<v-expansion-panel-text>
|
|
410
|
-
<v-container fluid>
|
|
411
|
-
<v-row dense>
|
|
412
|
-
<v-col cols="12">
|
|
413
|
-
<v-text-field
|
|
414
|
-
v-model="data.validationRules"
|
|
415
|
-
label="Validation Rules"
|
|
416
|
-
:rules="[rules.regex(validationRulesRegex)]"
|
|
417
|
-
/>
|
|
418
|
-
<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
|
-
</v-col>
|
|
420
|
-
</v-row>
|
|
421
|
-
</v-container>
|
|
422
|
-
</v-expansion-panel-text>
|
|
423
|
-
</v-expansion-panel>
|
|
424
|
-
<v-expansion-panel v-if="!notRequireAdvancedSetting.includes(data.inputType)">
|
|
425
|
-
<v-expansion-panel-title collapse-icon="mdi mdi-minus" expand-icon="mdi mdi-plus" class="font-weight-bold">Advanced settings</v-expansion-panel-title>
|
|
426
|
-
<v-expansion-panel-text>
|
|
427
|
-
<v-container fluid>
|
|
428
|
-
<v-row dense>
|
|
429
|
-
<v-col cols="12" md="6" v-if="!notRequireInputAttributes.includes(data.inputType)">
|
|
430
|
-
<v-text-field
|
|
431
|
-
v-model="data.inputAttributes"
|
|
432
|
-
label="Input Attributes"
|
|
433
|
-
/>
|
|
434
|
-
</v-col>
|
|
435
|
-
<v-col cols="12" md="6" v-if="!notRequireColumnAttributes.includes(data.inputType)">
|
|
436
|
-
<v-text-field
|
|
437
|
-
v-model="data.columnAttributes"
|
|
438
|
-
label="Column Attributes"
|
|
439
|
-
/>
|
|
440
|
-
</v-col>
|
|
441
|
-
<v-col cols="12" md="6">
|
|
442
|
-
<v-text-field
|
|
443
|
-
v-model="data.conditionalDisplay"
|
|
444
|
-
label="Conditional Display"
|
|
445
|
-
/>
|
|
446
|
-
</v-col>
|
|
447
|
-
<v-col cols="12" md="6">
|
|
448
|
-
<v-text-field
|
|
449
|
-
v-model="data.computedValue"
|
|
450
|
-
label="Computed Value"
|
|
451
|
-
/>
|
|
452
|
-
</v-col>
|
|
453
|
-
<v-col cols="12" md="6">
|
|
454
|
-
<v-text-field
|
|
455
|
-
v-model="data.retrievedValue"
|
|
456
|
-
label="Retrieved Value"
|
|
457
|
-
/>
|
|
458
|
-
</v-col>
|
|
459
|
-
</v-row>
|
|
460
|
-
</v-container>
|
|
461
|
-
</v-expansion-panel-text>
|
|
462
|
-
</v-expansion-panel>
|
|
463
|
-
<v-expansion-panel v-if="!notRequireClassAndStyle.includes(data.inputType)">
|
|
464
|
-
<v-expansion-panel-title collapse-icon="mdi mdi-minus" expand-icon="mdi mdi-plus" class="font-weight-bold">Class and Styles</v-expansion-panel-title>
|
|
465
|
-
<v-expansion-panel-text>
|
|
466
|
-
<v-container fluid>
|
|
467
|
-
<v-row dense>
|
|
468
|
-
<v-col cols="12">
|
|
469
|
-
<v-text-field
|
|
470
|
-
v-model="data.customClass"
|
|
471
|
-
label="Custom Class"
|
|
472
|
-
/>
|
|
473
|
-
</v-col>
|
|
474
|
-
<v-col cols="12">
|
|
475
|
-
<v-text-field
|
|
476
|
-
v-model="data.customStyle"
|
|
477
|
-
label="Custom Styles"
|
|
478
|
-
/>
|
|
479
|
-
</v-col>
|
|
480
|
-
</v-row>
|
|
481
|
-
</v-container>
|
|
482
|
-
</v-expansion-panel-text>
|
|
483
|
-
</v-expansion-panel>
|
|
484
|
-
</v-expansion-panels>
|
|
485
|
-
</v-col>
|
|
486
|
-
</v-row>
|
|
487
|
-
</v-container>
|
|
488
|
-
</template>
|
|
489
|
-
<template #item.configuration="props">
|
|
490
|
-
<v-sheet
|
|
491
|
-
elevation="1"
|
|
492
|
-
max-height="250"
|
|
493
|
-
class="overflow-y-auto my-1 pa-2"
|
|
494
|
-
v-if="props.item.inputType=='CustomCode'
|
|
495
|
-
|| props.item.validationRules
|
|
496
|
-
|| props.item.inputOptions
|
|
497
|
-
|| props.item.inputAttributes
|
|
498
|
-
|| props.item.columnAttributes
|
|
499
|
-
|| props.item.conditionalDisplay
|
|
500
|
-
|| props.item.computedValue
|
|
501
|
-
|| props.item.retrievedValue"
|
|
502
|
-
>
|
|
503
|
-
<template v-if="props.item.inputType=='CustomCode'">
|
|
504
|
-
<b>Custom Code :</b><br>
|
|
505
|
-
<span style="white-space: pre-line">{{ props.item.inputCustomCode }}</span>
|
|
506
|
-
</template>
|
|
507
|
-
<template v-if="props.item.validationRules">
|
|
508
|
-
<b>Validation Rules :</b> {{ props.item.validationRules }}<br>
|
|
509
|
-
</template>
|
|
510
|
-
<template v-if="props.item.inputOptions">
|
|
511
|
-
<b>Input Options :</b>
|
|
512
|
-
<vue-json-pretty :data="safeParseJSONDeep(props.item.inputOptions)" />
|
|
513
|
-
</template>
|
|
514
|
-
<template v-if="props.item.inputAttributes">
|
|
515
|
-
<b>Input Attributes :</b> {{ props.item.inputAttributes }}<br>
|
|
516
|
-
</template>
|
|
517
|
-
<template v-if="props.item.columnAttributes">
|
|
518
|
-
<b>Column Attributes :</b> {{ props.item.columnAttributes }}<br>
|
|
519
|
-
</template>
|
|
520
|
-
<template v-if="props.item.conditionalDisplay">
|
|
521
|
-
<b>Conditional Display :</b> {{ props.item.conditionalDisplay }}<br>
|
|
522
|
-
</template>
|
|
523
|
-
<template v-if="props.item.computedValue">
|
|
524
|
-
<b>Computed Value :</b> {{ props.item.computedValue }}<br>
|
|
525
|
-
</template>
|
|
526
|
-
<template v-if="props.item.retrievedValue">
|
|
527
|
-
<b>Retrieved Value :</b> {{ props.item.retrievedValue }}<br>
|
|
528
|
-
</template>
|
|
529
|
-
</v-sheet>
|
|
530
|
-
</template>
|
|
531
|
-
</FormTable>
|
|
532
|
-
<FormCodeEditor
|
|
533
|
-
v-else
|
|
534
|
-
v-model="advanceModeCode"
|
|
535
|
-
/>
|
|
536
|
-
</template>
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
/**
|
|
3
|
+
* DocumentTemplateBuilder supports document-template rendering and synchronizes template-defined field behavior with runtime data.
|
|
4
|
+
* This doc block is consumed by vue-docgen for generated API documentation.
|
|
5
|
+
*/
|
|
6
|
+
import {computed, ref, watch} from 'vue'
|
|
7
|
+
import * as prettier from 'prettier'
|
|
8
|
+
import prettierPluginHtml from 'prettier/plugins/html'
|
|
9
|
+
import {useDocumentTemplate, validationRulesRegex,optionStringToChoiceObject} from '../../composables/document/template'
|
|
10
|
+
import {autoActionHeader,templateToHeader} from "../../composables/document/templateFormTable";
|
|
11
|
+
import {cloneDeep} from "lodash-es";
|
|
12
|
+
import VueJsonPretty from 'vue-json-pretty';
|
|
13
|
+
import 'vue-json-pretty/lib/styles.css';
|
|
14
|
+
import {safeParseJSONDeep} from "../../utils/object";
|
|
15
|
+
|
|
16
|
+
interface Props {
|
|
17
|
+
title?: string // Title text displayed in the component header or dialog.
|
|
18
|
+
disableAdvanceMode?: boolean // Disables advanced editor mode toggles and actions.
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Public props accepted by DocumentTemplateBuilder.
|
|
23
|
+
* Document each prop field with intent, defaults, and side effects for clear generated docs.
|
|
24
|
+
*/
|
|
25
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
26
|
+
title: "Document Template",
|
|
27
|
+
disableAdvanceMode: false,
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Custom events emitted by DocumentTemplateBuilder.
|
|
32
|
+
* Parents can listen to these events to react to user actions and internal state changes.
|
|
33
|
+
*/
|
|
34
|
+
const emit = defineEmits(['update:modelValue'])
|
|
35
|
+
const modelValue = defineModel<string|Record<string, any>[]>()
|
|
36
|
+
|
|
37
|
+
const advanceModeCode = ref<string>()
|
|
38
|
+
const isAdvanceMode = computed(() => {
|
|
39
|
+
return modelValue.value && ((typeof modelValue.value === "string") && !isValidJsonArrayOfObjects(modelValue.value))
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
const templateItems = ref<Record<string, any>[]>([])
|
|
43
|
+
|
|
44
|
+
const headers = ref([
|
|
45
|
+
{ title: '',
|
|
46
|
+
key: 'operation',
|
|
47
|
+
width: '120px',
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
title: 'Rec No.',
|
|
51
|
+
key: 'recNo',
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
title: 'Input Type',
|
|
55
|
+
key: 'inputType',
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
title: 'Width',
|
|
59
|
+
key: 'width',
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
title: 'Input Label',
|
|
63
|
+
key: 'inputLabel',
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
title: 'Variable Name',
|
|
67
|
+
key: 'variableName',
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
title: 'Configuration',
|
|
71
|
+
key: 'configuration',
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
title: 'Action',
|
|
75
|
+
key: 'action',
|
|
76
|
+
width: '120px',
|
|
77
|
+
},
|
|
78
|
+
])
|
|
79
|
+
|
|
80
|
+
const formTableHeaders = ref([
|
|
81
|
+
{
|
|
82
|
+
title: 'Title',
|
|
83
|
+
key: 'title',
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
title: 'Key',
|
|
87
|
+
key: 'key',
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
title: 'Width',
|
|
91
|
+
key: 'width',
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
title: 'Action',
|
|
95
|
+
key: 'action',
|
|
96
|
+
width: '120px',
|
|
97
|
+
},
|
|
98
|
+
])
|
|
99
|
+
|
|
100
|
+
const choiceHeaders = ref([
|
|
101
|
+
{
|
|
102
|
+
title: 'Label',
|
|
103
|
+
key: 'label',
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
title: 'Value',
|
|
107
|
+
key: 'value',
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
title: 'Action',
|
|
111
|
+
key: 'action',
|
|
112
|
+
width: '120px',
|
|
113
|
+
},
|
|
114
|
+
])
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
function isValidJsonArrayOfObjects(str: string | undefined) {
|
|
118
|
+
try {
|
|
119
|
+
const parsed = JSON.parse(str as string)
|
|
120
|
+
return Array.isArray(parsed) && parsed.every(item => typeof item === 'object' && item !== null && !Array.isArray(item))
|
|
121
|
+
}
|
|
122
|
+
catch (e) {
|
|
123
|
+
return false
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
watch(templateItems, (newValue) => {
|
|
128
|
+
if (!isAdvanceMode.value) modelValue.value = JSON.stringify(newValue)
|
|
129
|
+
}, { deep: true })
|
|
130
|
+
|
|
131
|
+
watch(modelValue, (newValue) => {
|
|
132
|
+
if (typeof newValue === "string" && isValidJsonArrayOfObjects(newValue)) templateItems.value = JSON.parse(newValue as string)
|
|
133
|
+
else if (typeof newValue === "string") advanceModeCode.value = newValue
|
|
134
|
+
else if (newValue) templateItems.value = cloneDeep(newValue)
|
|
135
|
+
}, { deep: true, immediate: true })
|
|
136
|
+
|
|
137
|
+
watch(advanceModeCode, (newValue)=>{
|
|
138
|
+
if (isAdvanceMode.value) modelValue.value = newValue
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
async function convertToAdvanceMode() {
|
|
142
|
+
if (!isAdvanceMode.value) {
|
|
143
|
+
modelValue.value = await prettier.format(useDocumentTemplate(templateItems.value).replaceAll('>', '>\n'), { parser: 'html', plugins: [prettierPluginHtml] })
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
const inputTypeChoice = ref([
|
|
147
|
+
{ label: 'Text Field', value: 'VTextField' },
|
|
148
|
+
{ label: 'Text Area', value: 'VTextarea' },
|
|
149
|
+
{ label: 'Text Date Picker', value: 'FormDate' },
|
|
150
|
+
{ label: 'Text Time Picker', value: 'FormTime' },
|
|
151
|
+
{ label: 'Text Date & Time Picker', value: 'FormDateTime' },
|
|
152
|
+
{ label: 'Select Dropdown', value: 'VSelect' },
|
|
153
|
+
{ label: 'Select Combobox', value: 'VCombobox' },
|
|
154
|
+
{ label: 'Autocomplete', value: 'VAutocomplete' },
|
|
155
|
+
{ label: 'Autocomplete from Master', value: 'MasterAutocomplete' },
|
|
156
|
+
{ label: 'Radio Buttons', value: 'VRadio' },
|
|
157
|
+
{ label: 'Radio Buttons Inline', value: 'VRadioInline' },
|
|
158
|
+
{ label: 'Checkbox', value: 'VCheckbox' },
|
|
159
|
+
{ label: 'Checkbox Group', value: 'FormCheckboxGroup' },
|
|
160
|
+
{ label: 'Switch', value: 'VSwitch' },
|
|
161
|
+
{ label: 'File Upload', value: 'FormFile' },
|
|
162
|
+
{ label: 'Signature Pad', value: 'FormSignPad' },
|
|
163
|
+
{ label: 'Table', value: 'FormTable' },
|
|
164
|
+
{ label: 'Table Data', value: 'FormTableData' },
|
|
165
|
+
{ label: '[Decoration] Header', value: 'Header' },
|
|
166
|
+
{ label: '[Decoration] Separator', value: 'Separator' },
|
|
167
|
+
{ label: '[Advanced] Hidden Field', value: 'FormHidden' },
|
|
168
|
+
{ label: '[Advanced] Inherit Form', value: 'DocumentForm' },
|
|
169
|
+
{ label: '[Advanced] Custom Code', value: 'CustomCode' },
|
|
170
|
+
]);
|
|
171
|
+
|
|
172
|
+
const requireOption = ref(['VSelect', 'VAutocomplete', 'VCombobox', 'VRadio', 'VRadioInline', 'MasterAutocomplete','FormTable','FormTableData','DocumentForm','FormCheckboxGroup'])
|
|
173
|
+
const notRequireVariable = ref(['Header', 'Separator', 'CustomCode','DocumentForm'])
|
|
174
|
+
const notRequireLabel = ref(['Separator', 'CustomCode', 'FormFile', 'FormHidden','DocumentForm'])
|
|
175
|
+
const notRequireWidth = ref(['Separator', 'FormHidden','DocumentForm'])
|
|
176
|
+
const notRequireOptions = ref(['Separator','CustomCode', 'FormFile'])
|
|
177
|
+
const notRequireRules = ref(['Separator','Header','CustomCode','FormHidden','DocumentForm'])
|
|
178
|
+
const notRequireInputAttributes = ref(['CustomCode','Header','DocumentForm'])
|
|
179
|
+
const notRequireColumnAttributes = ref(['Separator', 'FormHidden','DocumentForm'])
|
|
180
|
+
const notRequireAdvancedSetting = ref(['Separator','CustomCode'])
|
|
181
|
+
const notRequireClassAndStyle = ref(['FormHidden'])
|
|
182
|
+
|
|
183
|
+
const hasSpecificOption = ref(['FormHidden','FormTable','FormTableData'])
|
|
184
|
+
|
|
185
|
+
const choiceOption = ref(['VRadio', 'VRadioInline','VSelect', 'VAutocomplete', 'VCombobox','FormCheckboxGroup'])
|
|
186
|
+
const inputOptionsLabel = ref<Record<string,string>>({
|
|
187
|
+
'MasterAutocomplete' : "Group Key",
|
|
188
|
+
'Header' : "Class",
|
|
189
|
+
'DocumentForm': "Template Code",
|
|
190
|
+
})
|
|
191
|
+
|
|
192
|
+
const ruleOptions = (inputType: string) => (value: any) => {
|
|
193
|
+
if (choiceOption.value.includes(inputType) && !(/^[^'",]+(,[^'",]+)*$/.test(value))) return 'Invalid options format'
|
|
194
|
+
|
|
195
|
+
return true
|
|
196
|
+
}
|
|
197
|
+
</script>
|
|
198
|
+
|
|
199
|
+
<template>
|
|
200
|
+
<FormTable
|
|
201
|
+
v-if="!isAdvanceMode"
|
|
202
|
+
v-model="templateItems"
|
|
203
|
+
:headers="headers"
|
|
204
|
+
:title="props.title"
|
|
205
|
+
>
|
|
206
|
+
<template #toolbarItems>
|
|
207
|
+
<VBtn
|
|
208
|
+
color="primary"
|
|
209
|
+
variant="flat"
|
|
210
|
+
@click="convertToAdvanceMode()"
|
|
211
|
+
v-if="!disableAdvanceMode"
|
|
212
|
+
>
|
|
213
|
+
Convert To Advance
|
|
214
|
+
</VBtn>
|
|
215
|
+
</template>
|
|
216
|
+
<template #item.recNo="{internalItem}">
|
|
217
|
+
{{ internalItem.index }}
|
|
218
|
+
</template>
|
|
219
|
+
<template #form="{ data, rules }">
|
|
220
|
+
<v-container fluid>
|
|
221
|
+
<v-row dense>
|
|
222
|
+
<v-col cols="3">
|
|
223
|
+
<v-combobox
|
|
224
|
+
v-model="data.inputType"
|
|
225
|
+
label="Input Type"
|
|
226
|
+
:items="inputTypeChoice"
|
|
227
|
+
item-title="label"
|
|
228
|
+
item-value="value"
|
|
229
|
+
:return-object="false"
|
|
230
|
+
:rules="[rules.require()]"
|
|
231
|
+
/>
|
|
232
|
+
</v-col>
|
|
233
|
+
<v-col cols="1" v-if="!notRequireWidth.includes(data.inputType)">
|
|
234
|
+
<v-text-field
|
|
235
|
+
v-model="data.width"
|
|
236
|
+
label="Width"
|
|
237
|
+
:rules="[rules.require()]"
|
|
238
|
+
type="number"
|
|
239
|
+
/>
|
|
240
|
+
<form-hidden v-model="data.inputOptions" :item-value="data.inputType" :hook="(_result: any,model: any,newValue: any,oldValue: any)=>{return (newValue && oldValue) ? undefined : model}"></form-hidden>
|
|
241
|
+
</v-col>
|
|
242
|
+
<v-col cols="4" v-if="!notRequireLabel.includes(data.inputType)">
|
|
243
|
+
<v-text-field
|
|
244
|
+
v-model="data.inputLabel"
|
|
245
|
+
label="Input Label"
|
|
246
|
+
:rules="[rules.require()]"
|
|
247
|
+
/>
|
|
248
|
+
</v-col>
|
|
249
|
+
<v-col cols="4" v-if="!notRequireVariable.includes(data.inputType)">
|
|
250
|
+
<v-text-field
|
|
251
|
+
v-model="data.variableName"
|
|
252
|
+
label="Variable Name"
|
|
253
|
+
:rules="[rules.require()]"
|
|
254
|
+
/>
|
|
255
|
+
</v-col>
|
|
256
|
+
<v-col
|
|
257
|
+
v-if="!notRequireOptions.includes(data.inputType)"
|
|
258
|
+
cols="12"
|
|
259
|
+
>
|
|
260
|
+
<form-pad v-model="data.inputOptions" v-if="data.inputType=='FormTable'">
|
|
261
|
+
<template #default="{data: optionData}">
|
|
262
|
+
<v-row dense>
|
|
263
|
+
<v-col cols="12">
|
|
264
|
+
<form-table v-model="optionData.headers" :headers="formTableHeaders" title="Headers">
|
|
265
|
+
<template #form="{data: headerData,rules}">
|
|
266
|
+
<v-container fluid>
|
|
267
|
+
<v-row dense>
|
|
268
|
+
<v-col cols="6"><v-text-field v-model="headerData.title" label="Title"></v-text-field></v-col>
|
|
269
|
+
<v-col cols="3"><v-text-field v-model="headerData.key" label="Key" :rules="[rules.require()]"></v-text-field></v-col>
|
|
270
|
+
<v-col cols="3"><v-text-field v-model="headerData.width" label="Width"></v-text-field></v-col>
|
|
271
|
+
</v-row>
|
|
272
|
+
<v-row dense>
|
|
273
|
+
<v-col cols="12"><v-textarea v-model="headerData.template" label="Item Template"></v-textarea></v-col>
|
|
274
|
+
</v-row>
|
|
275
|
+
</v-container>
|
|
276
|
+
</template>
|
|
277
|
+
</form-table>
|
|
278
|
+
</v-col>
|
|
279
|
+
<v-col cols="12">
|
|
280
|
+
<document-template-builder v-model="optionData.formTemplate" title="Form Template"></document-template-builder>
|
|
281
|
+
</v-col>
|
|
282
|
+
</v-row>
|
|
283
|
+
</template>
|
|
284
|
+
</form-pad>
|
|
285
|
+
<form-pad v-model="data.inputOptions" v-if="data.inputType=='FormTableData'">
|
|
286
|
+
<template #default="{data: optionData}">
|
|
287
|
+
<v-row dense>
|
|
288
|
+
<v-col cols="12">
|
|
289
|
+
<tabs-group>
|
|
290
|
+
<template #tabs>
|
|
291
|
+
<v-tab value="itemTemplate">Item Template</v-tab>
|
|
292
|
+
<v-tab value="dataTemplate">Data Template</v-tab>
|
|
293
|
+
<v-tab value="header">Header</v-tab>
|
|
294
|
+
</template>
|
|
295
|
+
<template #items>
|
|
296
|
+
<v-tabs-window-item value="itemTemplate">
|
|
297
|
+
<document-template-builder v-model="optionData.itemTemplate" title="Item Template" disable-advance-mode></document-template-builder>
|
|
298
|
+
</v-tabs-window-item>
|
|
299
|
+
<v-tabs-window-item value="dataTemplate">
|
|
300
|
+
<document-template-builder v-model="optionData.dataTemplate" title="Data Template" disable-advance-mode></document-template-builder>
|
|
301
|
+
</v-tabs-window-item>
|
|
302
|
+
<v-tabs-window-item value="header">
|
|
303
|
+
<form-table v-model="optionData.headers" :headers="formTableHeaders" title="Headers">
|
|
304
|
+
<template #form="{data: headerData,rules}">
|
|
305
|
+
<v-container fluid>
|
|
306
|
+
<v-row dense>
|
|
307
|
+
<v-col cols="6"><v-text-field v-model="headerData.title" label="Title"></v-text-field></v-col>
|
|
308
|
+
<v-col cols="3"><v-text-field v-model="headerData.key" label="Key" :rules="[rules.require()]"></v-text-field></v-col>
|
|
309
|
+
<v-col cols="3"><v-text-field v-model="headerData.width" label="Width"></v-text-field></v-col>
|
|
310
|
+
</v-row>
|
|
311
|
+
<v-row dense>
|
|
312
|
+
<v-col cols="12"><v-text-field v-model="headerData.value" label="Value"></v-text-field></v-col>
|
|
313
|
+
<v-col cols="12"><v-textarea v-model="headerData.template" label="Item Template"></v-textarea></v-col>
|
|
314
|
+
</v-row>
|
|
315
|
+
</v-container>
|
|
316
|
+
</template>
|
|
317
|
+
</form-table>
|
|
318
|
+
</v-tabs-window-item>
|
|
319
|
+
</template>
|
|
320
|
+
</tabs-group>
|
|
321
|
+
</v-col>
|
|
322
|
+
<v-col cols="12">
|
|
323
|
+
<form-table v-model="optionData.items" :headers="(optionData.headers && optionData.headers.length>0) ? autoActionHeader(optionData.headers) : autoActionHeader(templateToHeader(optionData.itemTemplate))" title="Items">
|
|
324
|
+
<template #form="{data}">
|
|
325
|
+
<form-pad :model-value="data" :template="optionData.itemTemplate"></form-pad>
|
|
326
|
+
</template>
|
|
327
|
+
</form-table>
|
|
328
|
+
</v-col>
|
|
329
|
+
<v-col cols="12">
|
|
330
|
+
<v-row dense>
|
|
331
|
+
<v-col cols="4">
|
|
332
|
+
<v-radio-group v-model="optionData.disableApplyToAll" inline>
|
|
333
|
+
<template #prepend>
|
|
334
|
+
<span class="opacity-60"> Disable Apply to All</span>
|
|
335
|
+
</template>
|
|
336
|
+
<v-radio label="No" value="false" hide-details> </v-radio>
|
|
337
|
+
<v-radio label="Yes" value="true" hide-details> </v-radio>
|
|
338
|
+
<v-radio label="Partial" value="partial" hide-details> </v-radio>
|
|
339
|
+
</v-radio-group>
|
|
340
|
+
</v-col>
|
|
341
|
+
<v-col cols="8">
|
|
342
|
+
<VTextField
|
|
343
|
+
variant="underlined"
|
|
344
|
+
v-model="optionData.disableApplyToAllPartial"
|
|
345
|
+
label="Disable Apply To All Column"
|
|
346
|
+
v-if="optionData.disableApplyToAll=='partial'"
|
|
347
|
+
>
|
|
348
|
+
</VTextField>
|
|
349
|
+
</v-col>
|
|
350
|
+
</v-row>
|
|
351
|
+
</v-col>
|
|
352
|
+
</v-row>
|
|
353
|
+
</template>
|
|
354
|
+
</form-pad>
|
|
355
|
+
<form-pad v-model="data.inputOptions" v-if="data.inputType=='FormHidden'">
|
|
356
|
+
<template #default="{data: optionData}">
|
|
357
|
+
<v-row dense>
|
|
358
|
+
<v-col cols="12">
|
|
359
|
+
<v-text-field
|
|
360
|
+
v-model="optionData.hook"
|
|
361
|
+
label="Hook"
|
|
362
|
+
/>
|
|
363
|
+
</v-col>
|
|
364
|
+
<v-col cols="12">
|
|
365
|
+
<v-text-field
|
|
366
|
+
v-model="optionData.itemValue"
|
|
367
|
+
label="Item Value"
|
|
368
|
+
/>
|
|
369
|
+
</v-col>
|
|
370
|
+
</v-row>
|
|
371
|
+
</template>
|
|
372
|
+
</form-pad>
|
|
373
|
+
<form-table v-model="data.inputOptions" :headers="choiceHeaders" title="Choices" v-if="choiceOption.includes(data.inputType) && (!data.inputOptions || typeof data.inputOptions === 'object')">
|
|
374
|
+
<template #form="{data: optionData,rules}">
|
|
375
|
+
<v-container fluid>
|
|
376
|
+
<v-row dense>
|
|
377
|
+
<v-col cols="6"><v-text-field v-model="optionData.label" label="Label"></v-text-field></v-col>
|
|
378
|
+
<v-col cols="6"><v-text-field v-model="optionData.value" label="Value" :rules="[rules.require()]"></v-text-field></v-col>
|
|
379
|
+
</v-row>
|
|
380
|
+
</v-container>
|
|
381
|
+
</template>
|
|
382
|
+
</form-table>
|
|
383
|
+
<form-hidden v-model="data.inputOptions" :itemValue="data.inputOptions" :hook="(option: any)=>optionStringToChoiceObject(option)" v-if="choiceOption.includes(data.inputType) && data.inputOptions && typeof data.inputOptions === 'string'"></form-hidden>
|
|
384
|
+
<v-textarea
|
|
385
|
+
v-model="data.inputOptions"
|
|
386
|
+
:label="inputOptionsLabel[data.inputType] || 'Input Options'"
|
|
387
|
+
auto-grow
|
|
388
|
+
:rules="[rules.requireIf(requireOption.includes(data.inputType)), ruleOptions(data.inputType)]"
|
|
389
|
+
v-if="!hasSpecificOption.includes(data.inputType) && !choiceOption.includes(data.inputType)"
|
|
390
|
+
/>
|
|
391
|
+
</v-col>
|
|
392
|
+
|
|
393
|
+
<v-col
|
|
394
|
+
v-if="data.inputType=='CustomCode'"
|
|
395
|
+
cols="12"
|
|
396
|
+
>
|
|
397
|
+
<FormCodeEditor
|
|
398
|
+
v-model="data.inputCustomCode"
|
|
399
|
+
label="Custom Code"
|
|
400
|
+
:rules="[rules.require()]"
|
|
401
|
+
/>
|
|
402
|
+
</v-col>
|
|
403
|
+
</v-row>
|
|
404
|
+
<v-row dense>
|
|
405
|
+
<v-col>
|
|
406
|
+
<v-expansion-panels>
|
|
407
|
+
<v-expansion-panel v-if="!notRequireRules.includes(data.inputType)">
|
|
408
|
+
<v-expansion-panel-title collapse-icon="mdi mdi-minus" expand-icon="mdi mdi-plus" class="font-weight-bold">Validations</v-expansion-panel-title>
|
|
409
|
+
<v-expansion-panel-text>
|
|
410
|
+
<v-container fluid>
|
|
411
|
+
<v-row dense>
|
|
412
|
+
<v-col cols="12">
|
|
413
|
+
<v-text-field
|
|
414
|
+
v-model="data.validationRules"
|
|
415
|
+
label="Validation Rules"
|
|
416
|
+
:rules="[rules.regex(validationRulesRegex)]"
|
|
417
|
+
/>
|
|
418
|
+
<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
|
+
</v-col>
|
|
420
|
+
</v-row>
|
|
421
|
+
</v-container>
|
|
422
|
+
</v-expansion-panel-text>
|
|
423
|
+
</v-expansion-panel>
|
|
424
|
+
<v-expansion-panel v-if="!notRequireAdvancedSetting.includes(data.inputType)">
|
|
425
|
+
<v-expansion-panel-title collapse-icon="mdi mdi-minus" expand-icon="mdi mdi-plus" class="font-weight-bold">Advanced settings</v-expansion-panel-title>
|
|
426
|
+
<v-expansion-panel-text>
|
|
427
|
+
<v-container fluid>
|
|
428
|
+
<v-row dense>
|
|
429
|
+
<v-col cols="12" md="6" v-if="!notRequireInputAttributes.includes(data.inputType)">
|
|
430
|
+
<v-text-field
|
|
431
|
+
v-model="data.inputAttributes"
|
|
432
|
+
label="Input Attributes"
|
|
433
|
+
/>
|
|
434
|
+
</v-col>
|
|
435
|
+
<v-col cols="12" md="6" v-if="!notRequireColumnAttributes.includes(data.inputType)">
|
|
436
|
+
<v-text-field
|
|
437
|
+
v-model="data.columnAttributes"
|
|
438
|
+
label="Column Attributes"
|
|
439
|
+
/>
|
|
440
|
+
</v-col>
|
|
441
|
+
<v-col cols="12" md="6">
|
|
442
|
+
<v-text-field
|
|
443
|
+
v-model="data.conditionalDisplay"
|
|
444
|
+
label="Conditional Display"
|
|
445
|
+
/>
|
|
446
|
+
</v-col>
|
|
447
|
+
<v-col cols="12" md="6">
|
|
448
|
+
<v-text-field
|
|
449
|
+
v-model="data.computedValue"
|
|
450
|
+
label="Computed Value"
|
|
451
|
+
/>
|
|
452
|
+
</v-col>
|
|
453
|
+
<v-col cols="12" md="6">
|
|
454
|
+
<v-text-field
|
|
455
|
+
v-model="data.retrievedValue"
|
|
456
|
+
label="Retrieved Value"
|
|
457
|
+
/>
|
|
458
|
+
</v-col>
|
|
459
|
+
</v-row>
|
|
460
|
+
</v-container>
|
|
461
|
+
</v-expansion-panel-text>
|
|
462
|
+
</v-expansion-panel>
|
|
463
|
+
<v-expansion-panel v-if="!notRequireClassAndStyle.includes(data.inputType)">
|
|
464
|
+
<v-expansion-panel-title collapse-icon="mdi mdi-minus" expand-icon="mdi mdi-plus" class="font-weight-bold">Class and Styles</v-expansion-panel-title>
|
|
465
|
+
<v-expansion-panel-text>
|
|
466
|
+
<v-container fluid>
|
|
467
|
+
<v-row dense>
|
|
468
|
+
<v-col cols="12">
|
|
469
|
+
<v-text-field
|
|
470
|
+
v-model="data.customClass"
|
|
471
|
+
label="Custom Class"
|
|
472
|
+
/>
|
|
473
|
+
</v-col>
|
|
474
|
+
<v-col cols="12">
|
|
475
|
+
<v-text-field
|
|
476
|
+
v-model="data.customStyle"
|
|
477
|
+
label="Custom Styles"
|
|
478
|
+
/>
|
|
479
|
+
</v-col>
|
|
480
|
+
</v-row>
|
|
481
|
+
</v-container>
|
|
482
|
+
</v-expansion-panel-text>
|
|
483
|
+
</v-expansion-panel>
|
|
484
|
+
</v-expansion-panels>
|
|
485
|
+
</v-col>
|
|
486
|
+
</v-row>
|
|
487
|
+
</v-container>
|
|
488
|
+
</template>
|
|
489
|
+
<template #item.configuration="props">
|
|
490
|
+
<v-sheet
|
|
491
|
+
elevation="1"
|
|
492
|
+
max-height="250"
|
|
493
|
+
class="overflow-y-auto my-1 pa-2"
|
|
494
|
+
v-if="props.item.inputType=='CustomCode'
|
|
495
|
+
|| props.item.validationRules
|
|
496
|
+
|| props.item.inputOptions
|
|
497
|
+
|| props.item.inputAttributes
|
|
498
|
+
|| props.item.columnAttributes
|
|
499
|
+
|| props.item.conditionalDisplay
|
|
500
|
+
|| props.item.computedValue
|
|
501
|
+
|| props.item.retrievedValue"
|
|
502
|
+
>
|
|
503
|
+
<template v-if="props.item.inputType=='CustomCode'">
|
|
504
|
+
<b>Custom Code :</b><br>
|
|
505
|
+
<span style="white-space: pre-line">{{ props.item.inputCustomCode }}</span>
|
|
506
|
+
</template>
|
|
507
|
+
<template v-if="props.item.validationRules">
|
|
508
|
+
<b>Validation Rules :</b> {{ props.item.validationRules }}<br>
|
|
509
|
+
</template>
|
|
510
|
+
<template v-if="props.item.inputOptions">
|
|
511
|
+
<b>Input Options :</b>
|
|
512
|
+
<vue-json-pretty :data="safeParseJSONDeep(props.item.inputOptions)" />
|
|
513
|
+
</template>
|
|
514
|
+
<template v-if="props.item.inputAttributes">
|
|
515
|
+
<b>Input Attributes :</b> {{ props.item.inputAttributes }}<br>
|
|
516
|
+
</template>
|
|
517
|
+
<template v-if="props.item.columnAttributes">
|
|
518
|
+
<b>Column Attributes :</b> {{ props.item.columnAttributes }}<br>
|
|
519
|
+
</template>
|
|
520
|
+
<template v-if="props.item.conditionalDisplay">
|
|
521
|
+
<b>Conditional Display :</b> {{ props.item.conditionalDisplay }}<br>
|
|
522
|
+
</template>
|
|
523
|
+
<template v-if="props.item.computedValue">
|
|
524
|
+
<b>Computed Value :</b> {{ props.item.computedValue }}<br>
|
|
525
|
+
</template>
|
|
526
|
+
<template v-if="props.item.retrievedValue">
|
|
527
|
+
<b>Retrieved Value :</b> {{ props.item.retrievedValue }}<br>
|
|
528
|
+
</template>
|
|
529
|
+
</v-sheet>
|
|
530
|
+
</template>
|
|
531
|
+
</FormTable>
|
|
532
|
+
<FormCodeEditor
|
|
533
|
+
v-else
|
|
534
|
+
v-model="advanceModeCode"
|
|
535
|
+
/>
|
|
536
|
+
</template>
|