@ramathibodi/nuxt-commons 0.1.73 → 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 -96
- package/dist/module.json +1 -1
- package/dist/module.mjs +1 -0
- package/dist/runtime/components/Alert.vue +58 -54
- package/dist/runtime/components/BarcodeReader.vue +130 -122
- package/dist/runtime/components/ExportCSV.vue +110 -102
- package/dist/runtime/components/FileBtn.vue +79 -67
- package/dist/runtime/components/ImportCSV.vue +151 -139
- package/dist/runtime/components/MrzReader.vue +168 -0
- package/dist/runtime/components/SplitterPanel.vue +67 -59
- package/dist/runtime/components/TabsGroup.vue +39 -31
- package/dist/runtime/components/TextBarcode.vue +66 -54
- package/dist/runtime/components/device/IdCardButton.vue +95 -83
- package/dist/runtime/components/device/IdCardWebSocket.vue +207 -195
- package/dist/runtime/components/device/Scanner.vue +350 -338
- package/dist/runtime/components/dialog/Confirm.vue +112 -100
- package/dist/runtime/components/dialog/Host.vue +88 -84
- package/dist/runtime/components/dialog/Index.vue +84 -72
- package/dist/runtime/components/dialog/Loading.vue +51 -39
- package/dist/runtime/components/dialog/default/Confirm.vue +112 -100
- package/dist/runtime/components/dialog/default/Loading.vue +60 -48
- package/dist/runtime/components/dialog/default/Notify.vue +82 -70
- package/dist/runtime/components/dialog/default/Printing.vue +46 -34
- package/dist/runtime/components/dialog/default/VerifyUser.vue +144 -132
- package/dist/runtime/components/document/Form.vue +50 -42
- package/dist/runtime/components/document/TemplateBuilder.vue +536 -524
- package/dist/runtime/components/form/ActionPad.vue +156 -144
- package/dist/runtime/components/form/Birthdate.vue +116 -104
- package/dist/runtime/components/form/CheckboxGroup.vue +99 -87
- package/dist/runtime/components/form/CodeEditor.vue +45 -37
- package/dist/runtime/components/form/Date.vue +270 -258
- package/dist/runtime/components/form/DateTime.vue +220 -208
- package/dist/runtime/components/form/Dialog.vue +178 -166
- package/dist/runtime/components/form/EditPad.vue +157 -145
- package/dist/runtime/components/form/File.vue +295 -283
- package/dist/runtime/components/form/Hidden.vue +44 -32
- package/dist/runtime/components/form/Iterator.vue +538 -526
- package/dist/runtime/components/form/Login.vue +143 -131
- package/dist/runtime/components/form/Pad.vue +399 -387
- package/dist/runtime/components/form/SignPad.vue +226 -218
- package/dist/runtime/components/form/System.vue +34 -26
- package/dist/runtime/components/form/Table.vue +391 -379
- package/dist/runtime/components/form/TableData.vue +236 -224
- package/dist/runtime/components/form/Time.vue +177 -165
- package/dist/runtime/components/form/images/Capture.vue +245 -237
- package/dist/runtime/components/form/images/Edit.vue +133 -121
- package/dist/runtime/components/form/images/Field.vue +331 -320
- package/dist/runtime/components/form/images/Pad.vue +54 -42
- package/dist/runtime/components/label/Date.vue +37 -29
- package/dist/runtime/components/label/DateAgo.vue +102 -94
- package/dist/runtime/components/label/DateCount.vue +152 -144
- package/dist/runtime/components/label/Field.vue +111 -103
- package/dist/runtime/components/label/FormatMoney.vue +37 -29
- package/dist/runtime/components/label/Mask.vue +46 -38
- package/dist/runtime/components/label/Object.vue +21 -13
- package/dist/runtime/components/master/Autocomplete.vue +89 -81
- package/dist/runtime/components/master/Combobox.vue +88 -80
- package/dist/runtime/components/master/RadioGroup.vue +90 -78
- package/dist/runtime/components/master/Select.vue +70 -62
- package/dist/runtime/components/master/label.vue +55 -47
- package/dist/runtime/components/model/Autocomplete.vue +91 -79
- package/dist/runtime/components/model/Combobox.vue +90 -78
- package/dist/runtime/components/model/Pad.vue +114 -102
- package/dist/runtime/components/model/Select.vue +78 -72
- package/dist/runtime/components/model/Table.vue +370 -358
- package/dist/runtime/components/model/iterator.vue +497 -489
- package/dist/runtime/components/model/label.vue +58 -50
- package/dist/runtime/components/pdf/Print.vue +75 -63
- package/dist/runtime/components/pdf/View.vue +146 -134
- package/dist/runtime/composables/alert.d.ts +4 -0
- package/dist/runtime/composables/api.d.ts +4 -0
- package/dist/runtime/composables/dialog.d.ts +1 -1
- package/dist/runtime/composables/document/templateFormHidden.d.ts +4 -0
- 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/localStorageModel.d.ts +4 -0
- package/dist/runtime/composables/lookupList.d.ts +4 -0
- package/dist/runtime/composables/menu.d.ts +4 -0
- package/dist/runtime/composables/useMrzReader.d.ts +48 -0
- package/dist/runtime/composables/useMrzReader.js +423 -0
- package/dist/runtime/composables/useTesseract.d.ts +16 -0
- package/dist/runtime/composables/useTesseract.js +45 -0
- 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/dist/runtime/utils/asset.d.ts +2 -0
- package/dist/runtime/utils/asset.js +49 -0
- package/package.json +131 -122
- package/scripts/enrich-vue-docs-from-ai.mjs +197 -0
- package/scripts/generate-ai-summary.mjs +321 -0
- package/scripts/generate-composables-md.mjs +129 -0
- package/scripts/postInstall.cjs +70 -70
- package/templates/.codegen/codegen.ts +32 -32
- package/templates/.codegen/plugin-schema-object.js +161 -161
- package/templates/public/tesseract/mrz.traineddata.gz +0 -0
- package/templates/public/tesseract/ocrb.traineddata.gz +0 -0
|
@@ -1,166 +1,178 @@
|
|
|
1
|
-
<script lang="ts" setup>
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
<
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
:
|
|
148
|
-
:
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
/**
|
|
3
|
+
* FormDialog is a schema-driven form field component that binds model data, renders field UI, and emits normalized updates.
|
|
4
|
+
* This doc block is consumed by vue-docgen for generated API documentation.
|
|
5
|
+
*/
|
|
6
|
+
import {computed, defineModel, ref, watch, watchEffect} from 'vue'
|
|
7
|
+
import {cloneDeep, isEqual} from 'lodash-es'
|
|
8
|
+
import type {FormDialogCallback} from '../../types/formDialog'
|
|
9
|
+
|
|
10
|
+
interface Props {
|
|
11
|
+
fullscreen?: boolean // Opens the dialog in fullscreen mode.
|
|
12
|
+
title?: string // Title text displayed in the component header or dialog.
|
|
13
|
+
initialData?: object // Initial form/object values used when creating a new record.
|
|
14
|
+
formData?: object // Configuration option used by Dialog.
|
|
15
|
+
saveCaption?: string // Label text for the save/confirm action button.
|
|
16
|
+
cancelCaption?: string // Label text for the cancel action button.
|
|
17
|
+
closeCaption?: string // Label text for the close action button.
|
|
18
|
+
saveAndStay?: boolean // Keeps editing context open after save for consecutive updates.
|
|
19
|
+
readonly?: boolean // renders as read-only while keeping value visible
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Public props accepted by FormDialog.
|
|
24
|
+
* Document each prop field with intent, defaults, and side effects for clear generated docs.
|
|
25
|
+
*/
|
|
26
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
27
|
+
saveCaption: 'บันทึก',
|
|
28
|
+
cancelCaption: 'ยกเลิก',
|
|
29
|
+
closeCaption: 'ปิด',
|
|
30
|
+
saveAndStay: false,
|
|
31
|
+
readonly: false,
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
const isShowing = defineModel<boolean>({ default: false })
|
|
35
|
+
const isSaving = ref<boolean>(false)
|
|
36
|
+
const isSavedAndStay = ref<boolean>(false)
|
|
37
|
+
const formPadRef = ref()
|
|
38
|
+
const formData = ref<object>({})
|
|
39
|
+
const formDataOriginalValue = ref<object>()
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Custom events emitted by FormDialog.
|
|
43
|
+
* Parents can listen to these events to react to user actions and internal state changes.
|
|
44
|
+
*/
|
|
45
|
+
const emit = defineEmits(['create', 'update'])
|
|
46
|
+
|
|
47
|
+
function save() {
|
|
48
|
+
if (formPadRef.value.isValid) {
|
|
49
|
+
isSaving.value = true
|
|
50
|
+
emit((isCreating.value) ? 'create' : 'update', cloneDeep(formData.value), (props.saveAndStay) ? stayCallback : callback)
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function cancel() {
|
|
55
|
+
isShowing.value = false
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const callback: FormDialogCallback = {
|
|
59
|
+
done: function () {
|
|
60
|
+
isSaving.value = false
|
|
61
|
+
isShowing.value = false
|
|
62
|
+
},
|
|
63
|
+
error: function () {
|
|
64
|
+
isSaving.value = false
|
|
65
|
+
},
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const stayCallback: FormDialogCallback = {
|
|
69
|
+
done: function () {
|
|
70
|
+
isSaving.value = false
|
|
71
|
+
isSavedAndStay.value = true
|
|
72
|
+
},
|
|
73
|
+
error: function () {
|
|
74
|
+
isSaving.value = false
|
|
75
|
+
},
|
|
76
|
+
setData: function (item: object) {
|
|
77
|
+
formData.value = cloneDeep(item)
|
|
78
|
+
formDataOriginalValue.value = cloneDeep(item)
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const isDataChange = computed(() => {
|
|
83
|
+
return !((isCreating.value) ? isEqual(formData.value, createOriginalValue.value) : isEqual(formData.value, formDataOriginalValue.value))
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
const isCreating = computed(() => {
|
|
87
|
+
return !props.formData && !isSavedAndStay.value
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
const createOriginalValue = computed(() => {
|
|
91
|
+
return Object.assign({}, props.initialData)
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
const loadFormData = () => {
|
|
95
|
+
if (props.formData) {
|
|
96
|
+
formData.value = cloneDeep(props.formData)
|
|
97
|
+
formDataOriginalValue.value = cloneDeep(props.formData)
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
formData.value = Object.assign({}, cloneDeep(props.initialData))
|
|
101
|
+
}
|
|
102
|
+
isSavedAndStay.value = false
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const operation = ref({ isDataChange, isCreating, isSaving, save, cancel })
|
|
106
|
+
|
|
107
|
+
watchEffect(loadFormData)
|
|
108
|
+
|
|
109
|
+
watch(() => isShowing.value, (newValue) => {
|
|
110
|
+
if (newValue) loadFormData()
|
|
111
|
+
})
|
|
112
|
+
</script>
|
|
113
|
+
|
|
114
|
+
<template>
|
|
115
|
+
<v-dialog
|
|
116
|
+
v-model="isShowing"
|
|
117
|
+
:fullscreen="fullscreen"
|
|
118
|
+
persistent
|
|
119
|
+
scrollable
|
|
120
|
+
>
|
|
121
|
+
<VCard>
|
|
122
|
+
<VToolbar>
|
|
123
|
+
<VToolbarTitle>
|
|
124
|
+
<slot name="title" :operation="operation">
|
|
125
|
+
{{ (isCreating) ? "New" : "Edit" }} {{ title }}
|
|
126
|
+
</slot>
|
|
127
|
+
</VToolbarTitle>
|
|
128
|
+
<VSpacer />
|
|
129
|
+
<VToolbarItems>
|
|
130
|
+
<VBtn
|
|
131
|
+
icon="mdi mdi-close"
|
|
132
|
+
@click="cancel"
|
|
133
|
+
/>
|
|
134
|
+
</VToolbarItems>
|
|
135
|
+
</VToolbar>
|
|
136
|
+
<VCardText>
|
|
137
|
+
<form-pad
|
|
138
|
+
ref="formPadRef"
|
|
139
|
+
v-model="formData"
|
|
140
|
+
:originalData="formDataOriginalValue"
|
|
141
|
+
:readonly="readonly"
|
|
142
|
+
isolated
|
|
143
|
+
>
|
|
144
|
+
<template #default="slotData">
|
|
145
|
+
<slot
|
|
146
|
+
v-bind="slotData"
|
|
147
|
+
:is-creating="isCreating"
|
|
148
|
+
:is-data-change="isDataChange"
|
|
149
|
+
/>
|
|
150
|
+
</template>
|
|
151
|
+
</form-pad>
|
|
152
|
+
</VCardText>
|
|
153
|
+
<VCardActions>
|
|
154
|
+
<slot name="action" :operation="operation">
|
|
155
|
+
<VSpacer />
|
|
156
|
+
<VBtn
|
|
157
|
+
color="primary"
|
|
158
|
+
variant="flat"
|
|
159
|
+
:loading="isSaving"
|
|
160
|
+
:disabled="!isDataChange"
|
|
161
|
+
@click="save"
|
|
162
|
+
v-if="!readonly"
|
|
163
|
+
>
|
|
164
|
+
{{ saveCaption }}
|
|
165
|
+
</VBtn>
|
|
166
|
+
<VBtn
|
|
167
|
+
color="error"
|
|
168
|
+
variant="flat"
|
|
169
|
+
:disabled="isSaving"
|
|
170
|
+
@click="cancel"
|
|
171
|
+
>
|
|
172
|
+
{{ (!isDataChange) ? closeCaption : cancelCaption }}
|
|
173
|
+
</VBtn>
|
|
174
|
+
</slot>
|
|
175
|
+
</VCardActions>
|
|
176
|
+
</VCard>
|
|
177
|
+
</v-dialog>
|
|
178
|
+
</template>
|
|
@@ -1,145 +1,157 @@
|
|
|
1
|
-
<script lang="ts" setup>
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
formPadRef.value?.
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
<
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
</
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
/**
|
|
3
|
+
* FormEditPad is a schema-driven form field component that binds model data, renders field UI, and emits normalized updates.
|
|
4
|
+
* This doc block is consumed by vue-docgen for generated API documentation.
|
|
5
|
+
*/
|
|
6
|
+
import {computed, defineExpose, ref, watchEffect} from 'vue'
|
|
7
|
+
import {cloneDeep, isEqual} from 'lodash-es'
|
|
8
|
+
import type {FormDialogCallback} from '../../types/formDialog'
|
|
9
|
+
import FormPadComponent from './Pad.vue'
|
|
10
|
+
|
|
11
|
+
interface Props extends /* @vue-ignore */ InstanceType<typeof FormPadComponent['$props']> {
|
|
12
|
+
title?: string // Title text displayed in the component header or dialog.
|
|
13
|
+
initialData?: object // Initial form/object values used when creating a new record.
|
|
14
|
+
formData?: object // Configuration option used by EditPad.
|
|
15
|
+
saveCaption?: string // Label text for the save/confirm action button.
|
|
16
|
+
cancelCaption?: string // Label text for the cancel action button.
|
|
17
|
+
readonly?: boolean // renders as read-only while keeping value visible
|
|
18
|
+
showTitle?: boolean // Shows or hides the component title/header area.
|
|
19
|
+
skipValidation?: boolean // Skips form validation before emitting save actions.
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Public props accepted by FormEditPad.
|
|
24
|
+
* Document each prop field with intent, defaults, and side effects for clear generated docs.
|
|
25
|
+
*/
|
|
26
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
27
|
+
saveCaption: 'บันทึก',
|
|
28
|
+
cancelCaption: 'ยกเลิก',
|
|
29
|
+
readonly: false,
|
|
30
|
+
showTitle: false,
|
|
31
|
+
skipValidation:false
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
const isSaving = ref<boolean>(false)
|
|
35
|
+
const formPadRef = ref()
|
|
36
|
+
const formData = ref<object>({})
|
|
37
|
+
const formDataOriginalValue = ref<object>()
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Custom events emitted by FormEditPad.
|
|
41
|
+
* Parents can listen to these events to react to user actions and internal state changes.
|
|
42
|
+
*/
|
|
43
|
+
const emit = defineEmits(['create', 'update'])
|
|
44
|
+
|
|
45
|
+
function save() {
|
|
46
|
+
if (props.skipValidation || formPadRef.value?.isValid) {
|
|
47
|
+
isSaving.value = true
|
|
48
|
+
emit((isCreating.value) ? 'create' : 'update', cloneDeep(formData.value), callback)
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function cancel() {
|
|
53
|
+
reset()
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function reset() {
|
|
57
|
+
formDataOriginalValue.value = undefined
|
|
58
|
+
formPadRef.value?.reset()
|
|
59
|
+
loadFormData()
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const callback: FormDialogCallback = {
|
|
63
|
+
done: function () {
|
|
64
|
+
isSaving.value = false
|
|
65
|
+
},
|
|
66
|
+
error: function () {
|
|
67
|
+
isSaving.value = false
|
|
68
|
+
},
|
|
69
|
+
setData: function (item: object) {
|
|
70
|
+
formData.value = cloneDeep(item)
|
|
71
|
+
formDataOriginalValue.value = cloneDeep(item)
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const isDataChange = computed(() => {
|
|
76
|
+
return !((isCreating.value) ? isEqual(formData.value, createOriginalValue.value) : isEqual(formData.value, formDataOriginalValue.value))
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
const isCreating = computed(() => {
|
|
80
|
+
return !props.formData
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
const createOriginalValue = computed(() => {
|
|
84
|
+
return Object.assign({}, props.initialData)
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
const loadFormData = () => {
|
|
88
|
+
if (props.formData) {
|
|
89
|
+
formData.value = cloneDeep(props.formData)
|
|
90
|
+
formDataOriginalValue.value = cloneDeep(props.formData)
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
formData.value = Object.assign({}, cloneDeep(props.initialData))
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const operation = ref({ isDataChange, isCreating, isSaving, save, cancel })
|
|
98
|
+
|
|
99
|
+
watchEffect(loadFormData)
|
|
100
|
+
|
|
101
|
+
defineExpose({operation,formPad:formPadRef})
|
|
102
|
+
</script>
|
|
103
|
+
|
|
104
|
+
<template>
|
|
105
|
+
<VCard flat>
|
|
106
|
+
<VToolbar v-if="showTitle">
|
|
107
|
+
<slot name="titleToolbar" :operation="operation">
|
|
108
|
+
<VToolbarTitle>
|
|
109
|
+
<slot name="title" :operation="operation">
|
|
110
|
+
{{ (isCreating) ? "New" : "Edit" }} {{ title }}
|
|
111
|
+
</slot>
|
|
112
|
+
</VToolbarTitle>
|
|
113
|
+
</slot>
|
|
114
|
+
</VToolbar>
|
|
115
|
+
<VCardText>
|
|
116
|
+
<form-pad
|
|
117
|
+
ref="formPadRef"
|
|
118
|
+
v-model="formData"
|
|
119
|
+
:originalData="formDataOriginalValue"
|
|
120
|
+
:readonly="readonly"
|
|
121
|
+
isolated
|
|
122
|
+
v-bind="$attrs"
|
|
123
|
+
>
|
|
124
|
+
<template #default="slotData">
|
|
125
|
+
<slot
|
|
126
|
+
v-bind="slotData"
|
|
127
|
+
:is-creating="isCreating"
|
|
128
|
+
:is-data-change="isDataChange"
|
|
129
|
+
/>
|
|
130
|
+
</template>
|
|
131
|
+
</form-pad>
|
|
132
|
+
</VCardText>
|
|
133
|
+
<VCardActions>
|
|
134
|
+
<slot name="action" :operation="operation">
|
|
135
|
+
<VSpacer />
|
|
136
|
+
<VBtn
|
|
137
|
+
color="primary"
|
|
138
|
+
variant="flat"
|
|
139
|
+
:loading="isSaving"
|
|
140
|
+
:disabled="!isDataChange"
|
|
141
|
+
@click="save"
|
|
142
|
+
v-if="!readonly"
|
|
143
|
+
>
|
|
144
|
+
{{ saveCaption }}
|
|
145
|
+
</VBtn>
|
|
146
|
+
<VBtn
|
|
147
|
+
color="error"
|
|
148
|
+
variant="flat"
|
|
149
|
+
:disabled="isSaving"
|
|
150
|
+
@click="cancel"
|
|
151
|
+
>
|
|
152
|
+
{{ cancelCaption }}
|
|
153
|
+
</VBtn>
|
|
154
|
+
</slot>
|
|
155
|
+
</VCardActions>
|
|
156
|
+
</VCard>
|
|
157
|
+
</template>
|