@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,226 +1,226 @@
|
|
|
1
|
-
<script lang="ts" setup>
|
|
2
|
-
/**
|
|
3
|
-
* FormSignPad 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 { VueSignaturePad } from 'vue-signature-pad'
|
|
7
|
-
import { VInput } from 'vuetify/components/VInput'
|
|
8
|
-
import { ref, computed, withDefaults, defineProps, defineExpose, watch } from 'vue'
|
|
9
|
-
import { useAssetFile, type Base64Asset, type Base64File } from '../../composables/assetFile'
|
|
10
|
-
|
|
11
|
-
interface SignatureProps extends /* @vue-ignore */ InstanceType<typeof VInput['$props']> {
|
|
12
|
-
title?: string // Title text displayed in the component header or dialog.
|
|
13
|
-
btnName?: string // Button label used to open the signature pad dialog.
|
|
14
|
-
titleConfirm?: string // Confirmation text shown before accepting the signature.
|
|
15
|
-
penColor?: string // Pen stroke color used while drawing the signature.
|
|
16
|
-
/** hydrate when id is present but base64String is missing */
|
|
17
|
-
autoHydrate?: boolean // Converts incoming serialized values into component runtime format on mount/watch.
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Public props accepted by FormSignPad.
|
|
22
|
-
* Document each prop field with intent, defaults, and side effects for clear generated docs.
|
|
23
|
-
*/
|
|
24
|
-
const props = withDefaults(defineProps<SignatureProps>(), {
|
|
25
|
-
title: 'Signature',
|
|
26
|
-
btnName: 'Draw Your Signature',
|
|
27
|
-
titleConfirm: 'I Accept My Signature',
|
|
28
|
-
penColor: '#303F9F',
|
|
29
|
-
autoHydrate: true,
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
const { hydrateAssetFile } = useAssetFile()
|
|
33
|
-
|
|
34
|
-
const model = defineModel<Base64Asset | string | null>({ default: null })
|
|
35
|
-
|
|
36
|
-
// refs
|
|
37
|
-
const inputRef = ref<InstanceType<typeof VInput> | null>(null)
|
|
38
|
-
const signaturePadRef = ref<InstanceType<typeof VueSignaturePad> | null>(null)
|
|
39
|
-
|
|
40
|
-
const isDialogOpen = ref(false)
|
|
41
|
-
|
|
42
|
-
// signature pad options from props
|
|
43
|
-
const signatureOptions = computed(() => ({
|
|
44
|
-
penColor: props.penColor,
|
|
45
|
-
minWidth: 0.5,
|
|
46
|
-
maxWidth: 4,
|
|
47
|
-
}))
|
|
48
|
-
|
|
49
|
-
// internal normalized value
|
|
50
|
-
const normalized = ref<Base64Asset | null>(null)
|
|
51
|
-
const imageDataUrl = computed(() => {
|
|
52
|
-
const val = normalized.value
|
|
53
|
-
if (!val?.base64String) return null
|
|
54
|
-
|
|
55
|
-
return useAssetFile().ensureDataUrl(val.base64String.trim(),(val as Base64File).fileType || "image/png")
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
// guards
|
|
60
|
-
let syncing = false // block re-entrancy while normalizing/hydrating
|
|
61
|
-
|
|
62
|
-
function wrapToAsset(input: Base64Asset | string | null): Base64Asset | null {
|
|
63
|
-
if (input == null) return null
|
|
64
|
-
return typeof input === 'string' ? { base64String: input } : input
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/** Normalize & (optionally) hydrate whenever external model changes */
|
|
68
|
-
watch(
|
|
69
|
-
model,
|
|
70
|
-
async (val) => {
|
|
71
|
-
if (syncing) return
|
|
72
|
-
syncing = true
|
|
73
|
-
try {
|
|
74
|
-
const asAsset = wrapToAsset(val)
|
|
75
|
-
normalized.value = asAsset
|
|
76
|
-
|
|
77
|
-
// If parent provided a string, convert and write back once
|
|
78
|
-
if (typeof val === 'string') {
|
|
79
|
-
model.value = asAsset
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// Hydrate if requested and needed (id present, no base64String)
|
|
83
|
-
if (props.autoHydrate && asAsset?.id != null && !asAsset.base64String) {
|
|
84
|
-
await hydrateAssetFile(asAsset) // mutates asAsset in-place
|
|
85
|
-
// reflect hydrated base64String back to parent (guarded)
|
|
86
|
-
model.value = asAsset
|
|
87
|
-
}
|
|
88
|
-
} finally {
|
|
89
|
-
syncing = false
|
|
90
|
-
}
|
|
91
|
-
},
|
|
92
|
-
{ immediate: true }
|
|
93
|
-
)
|
|
94
|
-
|
|
95
|
-
// signature actions
|
|
96
|
-
const undoSignature = () => signaturePadRef.value?.undoSignature()
|
|
97
|
-
const clearSignature = () => signaturePadRef.value?.clearSignature()
|
|
98
|
-
|
|
99
|
-
const closeDialog = () => {
|
|
100
|
-
isDialogOpen.value = false
|
|
101
|
-
signaturePadRef.value?.clearSignature()
|
|
102
|
-
signaturePadRef.value?.clearCacheImages?.()
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
const saveSignature = () => {
|
|
106
|
-
isDialogOpen.value = false
|
|
107
|
-
const result = signaturePadRef.value?.saveSignature()
|
|
108
|
-
if (!result) return
|
|
109
|
-
const { isEmpty, data } = result
|
|
110
|
-
if (isEmpty) {
|
|
111
|
-
normalized.value = null
|
|
112
|
-
model.value = null
|
|
113
|
-
} else {
|
|
114
|
-
const asset: Base64Asset = { base64String: data }
|
|
115
|
-
normalized.value = asset
|
|
116
|
-
model.value = asset
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
const openSignatureDialog = async () => {
|
|
121
|
-
// ensure hydration before opening to preview correctly
|
|
122
|
-
if (props.autoHydrate && normalized.value?.id != null && !normalized.value.base64String) {
|
|
123
|
-
await hydrateAssetFile(normalized.value)
|
|
124
|
-
model.value = normalized.value
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
isDialogOpen.value = true
|
|
128
|
-
|
|
129
|
-
const existing = normalized.value?.base64String
|
|
130
|
-
if (existing) {
|
|
131
|
-
// seed after dialog mount
|
|
132
|
-
requestAnimationFrame(() => signaturePadRef.value?.fromDataURL(existing))
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// validation passthrough
|
|
137
|
-
const isValid = computed(() => inputRef.value?.isValid)
|
|
138
|
-
const errorMessages = computed(() => inputRef.value?.errorMessages)
|
|
139
|
-
|
|
140
|
-
defineExpose({
|
|
141
|
-
errorMessages,
|
|
142
|
-
isValid,
|
|
143
|
-
reset: () => inputRef.value?.reset(),
|
|
144
|
-
resetValidation: () => inputRef.value?.resetValidation(),
|
|
145
|
-
validate: () => inputRef.value?.validate(),
|
|
146
|
-
})
|
|
147
|
-
</script>
|
|
148
|
-
|
|
149
|
-
<template>
|
|
150
|
-
<v-input v-model="model" v-bind="$attrs" ref="inputRef">
|
|
151
|
-
<template #default="{ isReadonly, isDisabled }">
|
|
152
|
-
<v-card class="w-100" flat :variant="$attrs.variant" :title="props.title">
|
|
153
|
-
<v-card-text v-if="normalized?.base64String">
|
|
154
|
-
<v-img :src="imageDataUrl" cover />
|
|
155
|
-
<v-icon
|
|
156
|
-
class="position-absolute"
|
|
157
|
-
style="top: 8px; right: 8px; z-index: 10;"
|
|
158
|
-
@click="model = null; normalized = null"
|
|
159
|
-
v-if="!isReadonly?.value"
|
|
160
|
-
>
|
|
161
|
-
mdi mdi-close-circle
|
|
162
|
-
</v-icon>
|
|
163
|
-
</v-card-text>
|
|
164
|
-
|
|
165
|
-
<v-card-actions v-if="!isReadonly?.value">
|
|
166
|
-
<v-btn
|
|
167
|
-
append-icon="mdi mdi-draw-pen"
|
|
168
|
-
block
|
|
169
|
-
class="text-none"
|
|
170
|
-
color="primary"
|
|
171
|
-
variant="flat"
|
|
172
|
-
@click="openSignatureDialog"
|
|
173
|
-
:readonly="isReadonly?.value"
|
|
174
|
-
:disabled="isDisabled?.value"
|
|
175
|
-
>
|
|
176
|
-
{{ props.btnName }}
|
|
177
|
-
</v-btn>
|
|
178
|
-
</v-card-actions>
|
|
179
|
-
|
|
180
|
-
<v-dialog v-model="isDialogOpen" height="auto" persistent width="100%">
|
|
181
|
-
<v-card>
|
|
182
|
-
<v-toolbar>
|
|
183
|
-
<v-toolbar-title class="text-no-wrap">
|
|
184
|
-
{{ props.title }}
|
|
185
|
-
</v-toolbar-title>
|
|
186
|
-
|
|
187
|
-
<v-btn icon @click="undoSignature">
|
|
188
|
-
<v-icon>fa-solid fa-arrow-rotate-left</v-icon>
|
|
189
|
-
</v-btn>
|
|
190
|
-
|
|
191
|
-
<v-btn icon @click="clearSignature">
|
|
192
|
-
<v-icon>fa-solid fa-trash</v-icon>
|
|
193
|
-
</v-btn>
|
|
194
|
-
|
|
195
|
-
<v-btn icon @click="closeDialog">
|
|
196
|
-
<v-icon>fa-solid fa-xmark</v-icon>
|
|
197
|
-
</v-btn>
|
|
198
|
-
</v-toolbar>
|
|
199
|
-
|
|
200
|
-
<v-card-text>
|
|
201
|
-
<VueSignaturePad
|
|
202
|
-
ref="signaturePadRef"
|
|
203
|
-
:options="signatureOptions"
|
|
204
|
-
height="40vh"
|
|
205
|
-
/>
|
|
206
|
-
</v-card-text>
|
|
207
|
-
|
|
208
|
-
<v-divider />
|
|
209
|
-
|
|
210
|
-
<v-card-actions class="justify-center">
|
|
211
|
-
<v-btn
|
|
212
|
-
class="text-none"
|
|
213
|
-
color="success"
|
|
214
|
-
prepend-icon="fa-solid fa-check"
|
|
215
|
-
variant="flat"
|
|
216
|
-
@click="saveSignature"
|
|
217
|
-
>
|
|
218
|
-
{{ props.titleConfirm }}
|
|
219
|
-
</v-btn>
|
|
220
|
-
</v-card-actions>
|
|
221
|
-
</v-card>
|
|
222
|
-
</v-dialog>
|
|
223
|
-
</v-card>
|
|
224
|
-
</template>
|
|
225
|
-
</v-input>
|
|
226
|
-
</template>
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
/**
|
|
3
|
+
* FormSignPad 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 { VueSignaturePad } from 'vue-signature-pad'
|
|
7
|
+
import { VInput } from 'vuetify/components/VInput'
|
|
8
|
+
import { ref, computed, withDefaults, defineProps, defineExpose, watch } from 'vue'
|
|
9
|
+
import { useAssetFile, type Base64Asset, type Base64File } from '../../composables/assetFile'
|
|
10
|
+
|
|
11
|
+
interface SignatureProps extends /* @vue-ignore */ InstanceType<typeof VInput['$props']> {
|
|
12
|
+
title?: string // Title text displayed in the component header or dialog.
|
|
13
|
+
btnName?: string // Button label used to open the signature pad dialog.
|
|
14
|
+
titleConfirm?: string // Confirmation text shown before accepting the signature.
|
|
15
|
+
penColor?: string // Pen stroke color used while drawing the signature.
|
|
16
|
+
/** hydrate when id is present but base64String is missing */
|
|
17
|
+
autoHydrate?: boolean // Converts incoming serialized values into component runtime format on mount/watch.
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Public props accepted by FormSignPad.
|
|
22
|
+
* Document each prop field with intent, defaults, and side effects for clear generated docs.
|
|
23
|
+
*/
|
|
24
|
+
const props = withDefaults(defineProps<SignatureProps>(), {
|
|
25
|
+
title: 'Signature',
|
|
26
|
+
btnName: 'Draw Your Signature',
|
|
27
|
+
titleConfirm: 'I Accept My Signature',
|
|
28
|
+
penColor: '#303F9F',
|
|
29
|
+
autoHydrate: true,
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
const { hydrateAssetFile } = useAssetFile()
|
|
33
|
+
|
|
34
|
+
const model = defineModel<Base64Asset | string | null>({ default: null })
|
|
35
|
+
|
|
36
|
+
// refs
|
|
37
|
+
const inputRef = ref<InstanceType<typeof VInput> | null>(null)
|
|
38
|
+
const signaturePadRef = ref<InstanceType<typeof VueSignaturePad> | null>(null)
|
|
39
|
+
|
|
40
|
+
const isDialogOpen = ref(false)
|
|
41
|
+
|
|
42
|
+
// signature pad options from props
|
|
43
|
+
const signatureOptions = computed(() => ({
|
|
44
|
+
penColor: props.penColor,
|
|
45
|
+
minWidth: 0.5,
|
|
46
|
+
maxWidth: 4,
|
|
47
|
+
}))
|
|
48
|
+
|
|
49
|
+
// internal normalized value
|
|
50
|
+
const normalized = ref<Base64Asset | null>(null)
|
|
51
|
+
const imageDataUrl = computed(() => {
|
|
52
|
+
const val = normalized.value
|
|
53
|
+
if (!val?.base64String) return null
|
|
54
|
+
|
|
55
|
+
return useAssetFile().ensureDataUrl(val.base64String.trim(),(val as Base64File).fileType || "image/png")
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
// guards
|
|
60
|
+
let syncing = false // block re-entrancy while normalizing/hydrating
|
|
61
|
+
|
|
62
|
+
function wrapToAsset(input: Base64Asset | string | null): Base64Asset | null {
|
|
63
|
+
if (input == null) return null
|
|
64
|
+
return typeof input === 'string' ? { base64String: input } : input
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Normalize & (optionally) hydrate whenever external model changes */
|
|
68
|
+
watch(
|
|
69
|
+
model,
|
|
70
|
+
async (val) => {
|
|
71
|
+
if (syncing) return
|
|
72
|
+
syncing = true
|
|
73
|
+
try {
|
|
74
|
+
const asAsset = wrapToAsset(val)
|
|
75
|
+
normalized.value = asAsset
|
|
76
|
+
|
|
77
|
+
// If parent provided a string, convert and write back once
|
|
78
|
+
if (typeof val === 'string') {
|
|
79
|
+
model.value = asAsset
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Hydrate if requested and needed (id present, no base64String)
|
|
83
|
+
if (props.autoHydrate && asAsset?.id != null && !asAsset.base64String) {
|
|
84
|
+
await hydrateAssetFile(asAsset) // mutates asAsset in-place
|
|
85
|
+
// reflect hydrated base64String back to parent (guarded)
|
|
86
|
+
model.value = asAsset
|
|
87
|
+
}
|
|
88
|
+
} finally {
|
|
89
|
+
syncing = false
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
{ immediate: true }
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
// signature actions
|
|
96
|
+
const undoSignature = () => signaturePadRef.value?.undoSignature()
|
|
97
|
+
const clearSignature = () => signaturePadRef.value?.clearSignature()
|
|
98
|
+
|
|
99
|
+
const closeDialog = () => {
|
|
100
|
+
isDialogOpen.value = false
|
|
101
|
+
signaturePadRef.value?.clearSignature()
|
|
102
|
+
signaturePadRef.value?.clearCacheImages?.()
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const saveSignature = () => {
|
|
106
|
+
isDialogOpen.value = false
|
|
107
|
+
const result = signaturePadRef.value?.saveSignature()
|
|
108
|
+
if (!result) return
|
|
109
|
+
const { isEmpty, data } = result
|
|
110
|
+
if (isEmpty) {
|
|
111
|
+
normalized.value = null
|
|
112
|
+
model.value = null
|
|
113
|
+
} else {
|
|
114
|
+
const asset: Base64Asset = { base64String: data }
|
|
115
|
+
normalized.value = asset
|
|
116
|
+
model.value = asset
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const openSignatureDialog = async () => {
|
|
121
|
+
// ensure hydration before opening to preview correctly
|
|
122
|
+
if (props.autoHydrate && normalized.value?.id != null && !normalized.value.base64String) {
|
|
123
|
+
await hydrateAssetFile(normalized.value)
|
|
124
|
+
model.value = normalized.value
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
isDialogOpen.value = true
|
|
128
|
+
|
|
129
|
+
const existing = normalized.value?.base64String
|
|
130
|
+
if (existing) {
|
|
131
|
+
// seed after dialog mount
|
|
132
|
+
requestAnimationFrame(() => signaturePadRef.value?.fromDataURL(existing))
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// validation passthrough
|
|
137
|
+
const isValid = computed(() => inputRef.value?.isValid)
|
|
138
|
+
const errorMessages = computed(() => inputRef.value?.errorMessages)
|
|
139
|
+
|
|
140
|
+
defineExpose({
|
|
141
|
+
errorMessages,
|
|
142
|
+
isValid,
|
|
143
|
+
reset: () => inputRef.value?.reset(),
|
|
144
|
+
resetValidation: () => inputRef.value?.resetValidation(),
|
|
145
|
+
validate: () => inputRef.value?.validate(),
|
|
146
|
+
})
|
|
147
|
+
</script>
|
|
148
|
+
|
|
149
|
+
<template>
|
|
150
|
+
<v-input v-model="model" v-bind="$attrs" ref="inputRef">
|
|
151
|
+
<template #default="{ isReadonly, isDisabled }">
|
|
152
|
+
<v-card class="w-100" flat :variant="$attrs.variant" :title="props.title">
|
|
153
|
+
<v-card-text v-if="normalized?.base64String">
|
|
154
|
+
<v-img :src="imageDataUrl" cover />
|
|
155
|
+
<v-icon
|
|
156
|
+
class="position-absolute"
|
|
157
|
+
style="top: 8px; right: 8px; z-index: 10;"
|
|
158
|
+
@click="model = null; normalized = null"
|
|
159
|
+
v-if="!isReadonly?.value"
|
|
160
|
+
>
|
|
161
|
+
mdi mdi-close-circle
|
|
162
|
+
</v-icon>
|
|
163
|
+
</v-card-text>
|
|
164
|
+
|
|
165
|
+
<v-card-actions v-if="!isReadonly?.value">
|
|
166
|
+
<v-btn
|
|
167
|
+
append-icon="mdi mdi-draw-pen"
|
|
168
|
+
block
|
|
169
|
+
class="text-none"
|
|
170
|
+
color="primary"
|
|
171
|
+
variant="flat"
|
|
172
|
+
@click="openSignatureDialog"
|
|
173
|
+
:readonly="isReadonly?.value"
|
|
174
|
+
:disabled="isDisabled?.value"
|
|
175
|
+
>
|
|
176
|
+
{{ props.btnName }}
|
|
177
|
+
</v-btn>
|
|
178
|
+
</v-card-actions>
|
|
179
|
+
|
|
180
|
+
<v-dialog v-model="isDialogOpen" height="auto" persistent width="100%">
|
|
181
|
+
<v-card>
|
|
182
|
+
<v-toolbar>
|
|
183
|
+
<v-toolbar-title class="text-no-wrap">
|
|
184
|
+
{{ props.title }}
|
|
185
|
+
</v-toolbar-title>
|
|
186
|
+
|
|
187
|
+
<v-btn icon @click="undoSignature">
|
|
188
|
+
<v-icon>fa-solid fa-arrow-rotate-left</v-icon>
|
|
189
|
+
</v-btn>
|
|
190
|
+
|
|
191
|
+
<v-btn icon @click="clearSignature">
|
|
192
|
+
<v-icon>fa-solid fa-trash</v-icon>
|
|
193
|
+
</v-btn>
|
|
194
|
+
|
|
195
|
+
<v-btn icon @click="closeDialog">
|
|
196
|
+
<v-icon>fa-solid fa-xmark</v-icon>
|
|
197
|
+
</v-btn>
|
|
198
|
+
</v-toolbar>
|
|
199
|
+
|
|
200
|
+
<v-card-text>
|
|
201
|
+
<VueSignaturePad
|
|
202
|
+
ref="signaturePadRef"
|
|
203
|
+
:options="signatureOptions"
|
|
204
|
+
height="40vh"
|
|
205
|
+
/>
|
|
206
|
+
</v-card-text>
|
|
207
|
+
|
|
208
|
+
<v-divider />
|
|
209
|
+
|
|
210
|
+
<v-card-actions class="justify-center">
|
|
211
|
+
<v-btn
|
|
212
|
+
class="text-none"
|
|
213
|
+
color="success"
|
|
214
|
+
prepend-icon="fa-solid fa-check"
|
|
215
|
+
variant="flat"
|
|
216
|
+
@click="saveSignature"
|
|
217
|
+
>
|
|
218
|
+
{{ props.titleConfirm }}
|
|
219
|
+
</v-btn>
|
|
220
|
+
</v-card-actions>
|
|
221
|
+
</v-card>
|
|
222
|
+
</v-dialog>
|
|
223
|
+
</v-card>
|
|
224
|
+
</template>
|
|
225
|
+
</v-input>
|
|
226
|
+
</template>
|
|
@@ -1,35 +1,35 @@
|
|
|
1
|
-
<script lang="ts" setup>
|
|
2
|
-
/**
|
|
3
|
-
* FormSystem 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 Pad from './Pad.vue'
|
|
7
|
-
import { watch } from 'vue'
|
|
8
|
-
import { useGraphQlOperation } from '../../composables/graphqlOperation'
|
|
9
|
-
|
|
10
|
-
interface Props extends /* @vue-ignore */ InstanceType<typeof Pad['$props']> {
|
|
11
|
-
templateId: string; // identifier value used to resolve business data
|
|
12
|
-
cache?: boolean | number // Enables cached requests; number values represent cache TTL in milliseconds.
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Public props accepted by FormSystem.
|
|
17
|
-
* Document each prop field with intent, defaults, and side effects for clear generated docs.
|
|
18
|
-
*/
|
|
19
|
-
const props = withDefaults(defineProps<Props>(),{
|
|
20
|
-
cache: false
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
const currentTemplate = ref<any>({})
|
|
24
|
-
|
|
25
|
-
watch(()=>props.templateId, (newValue) => {
|
|
26
|
-
useGraphQlOperation("Query","systemTemplateById",["template","templateScript"],{id: newValue},props.cache).then(result => {
|
|
27
|
-
currentTemplate.value = result
|
|
28
|
-
}).catch(_error => {
|
|
29
|
-
currentTemplate.value = {}
|
|
30
|
-
})
|
|
31
|
-
})
|
|
32
|
-
</script>
|
|
33
|
-
<template>
|
|
34
|
-
<FormPad v-bind="$attrs" :template="currentTemplate.template" :template-script="currentTemplate.templateScript" />
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
/**
|
|
3
|
+
* FormSystem 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 Pad from './Pad.vue'
|
|
7
|
+
import { watch } from 'vue'
|
|
8
|
+
import { useGraphQlOperation } from '../../composables/graphqlOperation'
|
|
9
|
+
|
|
10
|
+
interface Props extends /* @vue-ignore */ InstanceType<typeof Pad['$props']> {
|
|
11
|
+
templateId: string; // identifier value used to resolve business data
|
|
12
|
+
cache?: boolean | number // Enables cached requests; number values represent cache TTL in milliseconds.
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Public props accepted by FormSystem.
|
|
17
|
+
* Document each prop field with intent, defaults, and side effects for clear generated docs.
|
|
18
|
+
*/
|
|
19
|
+
const props = withDefaults(defineProps<Props>(),{
|
|
20
|
+
cache: false
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
const currentTemplate = ref<any>({})
|
|
24
|
+
|
|
25
|
+
watch(()=>props.templateId, (newValue) => {
|
|
26
|
+
useGraphQlOperation("Query","systemTemplateById",["template","templateScript"],{id: newValue},props.cache).then(result => {
|
|
27
|
+
currentTemplate.value = result
|
|
28
|
+
}).catch(_error => {
|
|
29
|
+
currentTemplate.value = {}
|
|
30
|
+
})
|
|
31
|
+
})
|
|
32
|
+
</script>
|
|
33
|
+
<template>
|
|
34
|
+
<FormPad v-bind="$attrs" :template="currentTemplate.template" :template-script="currentTemplate.templateScript" />
|
|
35
35
|
</template>
|