@ramathibodi/nuxt-commons 0.1.35 → 0.1.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/module.json +1 -1
- package/dist/runtime/components/SplitterPanel.vue +1 -1
- package/dist/runtime/components/document/TemplateBuilder.vue +49 -19
- package/dist/runtime/components/form/ActionPad.vue +133 -0
- package/dist/runtime/components/form/Table.vue +27 -6
- package/dist/runtime/components/form/images/Field.vue +1 -1
- package/dist/runtime/composables/document/template.js +9 -0
- package/package.json +2 -2
package/dist/module.json
CHANGED
|
@@ -73,10 +73,14 @@ async function convertToAdvanceMode() {
|
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
const inputTypeChoice = ref(['VTextField', 'VTextarea', 'VSelect', 'VAutocomplete', 'FormDate', 'FormTime', 'FormDateTime', 'VCombobox', 'VRadio', 'VRadioInline', 'VCheckbox', 'VSwitch', 'MasterAutocomplete', 'Header', 'Separator', 'CustomCode'])
|
|
76
|
+
const inputTypeChoice = ref(['VTextField', 'VTextarea', 'VSelect', 'VAutocomplete', 'FormDate', 'FormTime', 'FormDateTime', 'VCombobox', 'VRadio', 'VRadioInline', 'VCheckbox', 'VSwitch', 'MasterAutocomplete', 'Header', 'Separator', 'CustomCode', 'FormTable', 'FormHidden', 'FormFile', 'FormSignPad'])
|
|
77
77
|
const requireOption = ref(['VSelect', 'VAutocomplete', 'VCombobox', 'VRadio', 'VRadioInline', 'MasterAutocomplete'])
|
|
78
78
|
const notRequireVariable = ref(['Header', 'Separator', 'CustomCode'])
|
|
79
|
-
const notRequireLabel = ref(['Separator', 'CustomCode'])
|
|
79
|
+
const notRequireLabel = ref(['Separator', 'CustomCode', 'FormFile', 'FormSignPad', 'FormTable', 'FormHidden'])
|
|
80
|
+
const notRequireOptions = ref(['CustomCode', 'FormSignPad', 'FormFile', 'FormTable'])
|
|
81
|
+
const notRequireRules = ref(['CustomCode', 'FormSignPad', 'FormFile', 'FormTable' ,'FormHidden'])
|
|
82
|
+
const notRequireInputAttributes = ref(['CustomCode', 'FormHidden'])
|
|
83
|
+
const notRequireColumnAttributes = ref(['Separator', 'FormHidden'])
|
|
80
84
|
|
|
81
85
|
const choiceOption = ref(['VSelect', 'VRadio', 'VRadioInline'])
|
|
82
86
|
|
|
@@ -128,25 +132,23 @@ const ruleOptions = (inputType: string) => (value: any) => {
|
|
|
128
132
|
type="number"
|
|
129
133
|
/>
|
|
130
134
|
</v-col>
|
|
131
|
-
<v-col cols="4">
|
|
135
|
+
<v-col cols="4" v-if="!notRequireLabel.includes(data.inputType)">
|
|
132
136
|
<v-text-field
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
:rules="[rules.require()]"
|
|
137
|
+
v-model="data.inputLabel"
|
|
138
|
+
label="Input Label"
|
|
139
|
+
:rules="[rules.require()]"
|
|
137
140
|
/>
|
|
138
141
|
</v-col>
|
|
139
|
-
<v-col cols="4">
|
|
142
|
+
<v-col cols="4" v-if="!notRequireVariable.includes(data.inputType)">
|
|
140
143
|
<v-text-field
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
:rules="[rules.require()]"
|
|
144
|
+
v-model="data.variableName"
|
|
145
|
+
label="Variable Name"
|
|
146
|
+
:rules="[rules.require()]"
|
|
145
147
|
/>
|
|
146
148
|
</v-col>
|
|
147
149
|
<v-col
|
|
148
|
-
|
|
149
|
-
|
|
150
|
+
v-if="!notRequireOptions.includes(data.inputType)"
|
|
151
|
+
cols="12"
|
|
150
152
|
>
|
|
151
153
|
<v-textarea
|
|
152
154
|
v-model="data.inputOptions"
|
|
@@ -179,9 +181,29 @@ const ruleOptions = (inputType: string) => (value: any) => {
|
|
|
179
181
|
cols="12"
|
|
180
182
|
>
|
|
181
183
|
<FormCodeEditor
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
184
|
+
v-model="data.inputCustomCode"
|
|
185
|
+
label="Custom Code"
|
|
186
|
+
:rules="[rules.require()]"
|
|
187
|
+
/>
|
|
188
|
+
</v-col>
|
|
189
|
+
<v-col
|
|
190
|
+
v-if="data.inputType=='FormTable'"
|
|
191
|
+
cols="12"
|
|
192
|
+
>
|
|
193
|
+
<FormCodeEditor
|
|
194
|
+
v-model="data.inputFormTable"
|
|
195
|
+
label="Form Table"
|
|
196
|
+
:rules="[rules.require()]"
|
|
197
|
+
/>
|
|
198
|
+
</v-col>
|
|
199
|
+
<v-col
|
|
200
|
+
v-if="data.inputType=='FormHidden'"
|
|
201
|
+
cols="12"
|
|
202
|
+
>
|
|
203
|
+
<FormCodeEditor
|
|
204
|
+
v-model="data.inputFormHidden"
|
|
205
|
+
label="Form Table"
|
|
206
|
+
:rules="[rules.require()]"
|
|
185
207
|
/>
|
|
186
208
|
</v-col>
|
|
187
209
|
</v-row>
|
|
@@ -201,10 +223,18 @@ const ruleOptions = (inputType: string) => (value: any) => {
|
|
|
201
223
|
<template v-if="props.item.inputAttributes">
|
|
202
224
|
<b>Input Attributes :</b> {{ props.item.inputAttributes }}<br>
|
|
203
225
|
</template>
|
|
226
|
+
<template v-if="props.item.inputType=='FormTable'">
|
|
227
|
+
<b>Form Table :</b><br>
|
|
228
|
+
<span style="white-space: pre-line">{{ props.item.inputFormTable }}</span>
|
|
229
|
+
</template>
|
|
230
|
+
<template v-if="props.item.inputType=='FormHidden'">
|
|
231
|
+
<b>Form Hidden :</b><br>
|
|
232
|
+
<span style="white-space: pre-line">{{ props.item.inputFormHidden }}</span>
|
|
233
|
+
</template>
|
|
204
234
|
</template>
|
|
205
235
|
</FormTable>
|
|
206
236
|
<FormCodeEditor
|
|
207
|
-
|
|
208
|
-
|
|
237
|
+
v-else
|
|
238
|
+
v-model="modelValue"
|
|
209
239
|
/>
|
|
210
240
|
</template>
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import {computed, defineExpose, ref, watchEffect} from 'vue'
|
|
3
|
+
import {cloneDeep, isEqual} from 'lodash-es'
|
|
4
|
+
import type {FormDialogCallback} from '../../types/formDialog'
|
|
5
|
+
|
|
6
|
+
interface Props {
|
|
7
|
+
title?: string
|
|
8
|
+
initialData?: object
|
|
9
|
+
createCaption?: string
|
|
10
|
+
updateCaption?: string
|
|
11
|
+
cancelCaption?: string
|
|
12
|
+
showTitle?: boolean
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
16
|
+
createCaption: 'Add',
|
|
17
|
+
updateCaption: 'Save',
|
|
18
|
+
cancelCaption: 'Cancel',
|
|
19
|
+
showTitle: false,
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
const isSaving = ref<boolean>(false)
|
|
23
|
+
const formPadRef = ref()
|
|
24
|
+
const formOriginalData = ref<object>()
|
|
25
|
+
const formData = ref<object>({})
|
|
26
|
+
|
|
27
|
+
const emit = defineEmits(['create', 'update'])
|
|
28
|
+
|
|
29
|
+
function save() {
|
|
30
|
+
if (formPadRef.value.isValid) {
|
|
31
|
+
isSaving.value = true
|
|
32
|
+
emit((isCreating.value) ? 'create' : 'update', cloneDeep(formData.value), callback)
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function cancel() {
|
|
37
|
+
reset()
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function reset() {
|
|
41
|
+
formOriginalData.value = undefined
|
|
42
|
+
loadFormData()
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const callback: FormDialogCallback = {
|
|
46
|
+
done: function () {
|
|
47
|
+
isSaving.value = false
|
|
48
|
+
reset()
|
|
49
|
+
},
|
|
50
|
+
error: function () {
|
|
51
|
+
isSaving.value = false
|
|
52
|
+
},
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const isDataChange = computed(() => {
|
|
56
|
+
return !((isCreating.value) ? isEqual(formData.value, createOriginalValue.value) : isEqual(formData.value, formOriginalData.value))
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
const isCreating = computed(() => {
|
|
60
|
+
return !formOriginalData.value
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
const createOriginalValue = computed(() => {
|
|
64
|
+
return Object.assign({}, props.initialData)
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
const loadFormData = () => {
|
|
68
|
+
if (formOriginalData.value) {
|
|
69
|
+
formData.value = cloneDeep(formOriginalData.value)
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
formData.value = Object.assign({}, props.initialData)
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
watchEffect(loadFormData)
|
|
77
|
+
|
|
78
|
+
function setOriginalData(originalData?: object) {
|
|
79
|
+
formOriginalData.value = originalData
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
defineExpose({setOriginalData,reset})
|
|
83
|
+
</script>
|
|
84
|
+
|
|
85
|
+
<template>
|
|
86
|
+
<VCard flat>
|
|
87
|
+
<VToolbar v-if="showTitle">
|
|
88
|
+
<VToolbarTitle>
|
|
89
|
+
<slot name="title">
|
|
90
|
+
{{ (isCreating) ? "New" : "Edit" }} {{ title }}
|
|
91
|
+
</slot>
|
|
92
|
+
</VToolbarTitle>
|
|
93
|
+
<VSpacer />
|
|
94
|
+
</VToolbar>
|
|
95
|
+
<VCardText>
|
|
96
|
+
<form-pad
|
|
97
|
+
ref="formPadRef"
|
|
98
|
+
v-model="formData"
|
|
99
|
+
isolated
|
|
100
|
+
>
|
|
101
|
+
<template #default="slotData">
|
|
102
|
+
<slot
|
|
103
|
+
v-bind="slotData"
|
|
104
|
+
:is-creating="isCreating"
|
|
105
|
+
:is-data-change="isDataChange"
|
|
106
|
+
/>
|
|
107
|
+
</template>
|
|
108
|
+
</form-pad>
|
|
109
|
+
</VCardText>
|
|
110
|
+
<VCardActions>
|
|
111
|
+
<slot name="action" :save="save" :cancel="cancel">
|
|
112
|
+
<VSpacer />
|
|
113
|
+
<VBtn
|
|
114
|
+
color="primary"
|
|
115
|
+
variant="flat"
|
|
116
|
+
:loading="isSaving"
|
|
117
|
+
:disabled="!isDataChange"
|
|
118
|
+
@click="save"
|
|
119
|
+
>
|
|
120
|
+
{{ (isCreating) ? createCaption : updateCaption }}
|
|
121
|
+
</VBtn>
|
|
122
|
+
<VBtn
|
|
123
|
+
color="error"
|
|
124
|
+
variant="flat"
|
|
125
|
+
:disabled="isSaving"
|
|
126
|
+
@click="cancel"
|
|
127
|
+
>
|
|
128
|
+
{{ cancelCaption }}
|
|
129
|
+
</VBtn>
|
|
130
|
+
</slot>
|
|
131
|
+
</VCardActions>
|
|
132
|
+
</VCard>
|
|
133
|
+
</template>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
2
|
import {VDataTable} from 'vuetify/components/VDataTable'
|
|
3
|
-
import {computed, defineOptions,defineExpose, nextTick, ref, useAttrs, watch} from 'vue'
|
|
3
|
+
import {computed, defineOptions,defineExpose, nextTick, ref, useAttrs, watch, useTemplateRef} from 'vue'
|
|
4
4
|
import {omit} from 'lodash-es'
|
|
5
5
|
import type {FormDialogCallback} from '../../types/formDialog'
|
|
6
6
|
|
|
@@ -20,6 +20,8 @@ interface Props extends /* @vue-ignore */ InstanceType<typeof VDataTable['$props
|
|
|
20
20
|
exportable?: boolean
|
|
21
21
|
insertable?: boolean
|
|
22
22
|
searchable?: boolean
|
|
23
|
+
inputPad?: boolean
|
|
24
|
+
inputPadOnly?: boolean
|
|
23
25
|
}
|
|
24
26
|
|
|
25
27
|
const props = withDefaults(defineProps<Props>(), {
|
|
@@ -31,6 +33,8 @@ const props = withDefaults(defineProps<Props>(), {
|
|
|
31
33
|
exportable: true,
|
|
32
34
|
insertable: true,
|
|
33
35
|
searchable: true,
|
|
36
|
+
inputPad: false,
|
|
37
|
+
inputPadOnly: false,
|
|
34
38
|
})
|
|
35
39
|
|
|
36
40
|
const emit = defineEmits(['update:modelValue'])
|
|
@@ -153,11 +157,15 @@ function deleteItem(deleteItem: Record<string, any>, callback?: FormDialogCallba
|
|
|
153
157
|
}
|
|
154
158
|
|
|
155
159
|
function openDialog(item?: object) {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
+
if (props.inputPadOnly) inputPadRef.value?.setOriginalData(item)
|
|
161
|
+
else {
|
|
162
|
+
currentItem.value = item
|
|
163
|
+
nextTick(() => {
|
|
164
|
+
isDialogOpen.value = true
|
|
165
|
+
})
|
|
166
|
+
}
|
|
160
167
|
}
|
|
168
|
+
const inputPadRef = useTemplateRef("inputPadRef")
|
|
161
169
|
|
|
162
170
|
const operation = ref({ openDialog, createItem, updateItem, deleteItem, moveUpItem, moveDownItem,moveToItem,setSearch })
|
|
163
171
|
|
|
@@ -219,7 +227,7 @@ defineExpose({operation})
|
|
|
219
227
|
:color="toolbarColor"
|
|
220
228
|
/>
|
|
221
229
|
<VBtn
|
|
222
|
-
v-if="props.insertable"
|
|
230
|
+
v-if="props.insertable && !props.inputPadOnly"
|
|
223
231
|
:color="toolbarColor"
|
|
224
232
|
prepend-icon="mdi:mdi-plus"
|
|
225
233
|
variant="flat"
|
|
@@ -282,6 +290,7 @@ defineExpose({operation})
|
|
|
282
290
|
:form-data="currentItem"
|
|
283
291
|
@create="createItem"
|
|
284
292
|
@update="updateItem"
|
|
293
|
+
v-if="!props.inputPadOnly"
|
|
285
294
|
>
|
|
286
295
|
<template #default="slotData">
|
|
287
296
|
<slot
|
|
@@ -291,4 +300,16 @@ defineExpose({operation})
|
|
|
291
300
|
</template>
|
|
292
301
|
</FormDialog>
|
|
293
302
|
</v-card>
|
|
303
|
+
<slot name="inputPad" :operation="operation">
|
|
304
|
+
<v-sheet border rounded class="mt-1" v-if="inputPad">
|
|
305
|
+
<form-action-pad ref="inputPadRef" :title="props.title" @create="createItem" @update="updateItem" :initial-data="initialData">
|
|
306
|
+
<template #default="slotData">
|
|
307
|
+
<slot
|
|
308
|
+
name="form"
|
|
309
|
+
v-bind="slotData"
|
|
310
|
+
/>
|
|
311
|
+
</template>
|
|
312
|
+
</form-action-pad>
|
|
313
|
+
</v-sheet>
|
|
314
|
+
</slot>
|
|
294
315
|
</template>
|
|
@@ -223,7 +223,7 @@ onMounted(() => {
|
|
|
223
223
|
</VToolbar>
|
|
224
224
|
<v-img
|
|
225
225
|
:src="image.data"
|
|
226
|
-
@click="() => { (readonly) ? openImageFullScreen(image) : setDataUpdate(image)}"
|
|
226
|
+
@click="() => { (props.readonly) ? openImageFullScreen(image) : setDataUpdate(image)}"
|
|
227
227
|
height="250"
|
|
228
228
|
/>
|
|
229
229
|
</VCard>
|
|
@@ -53,6 +53,15 @@ function templateItemToString(item) {
|
|
|
53
53
|
case "Header":
|
|
54
54
|
templateString = `<div class="${optionString ? optionString.trim() : "text-h4 font-weight-medium"}">${item.inputLabel || item.variableName}</div>`;
|
|
55
55
|
break;
|
|
56
|
+
case "FormTable":
|
|
57
|
+
templateString = `<form-table v-model="data.${item.variableName}" label="${item.inputLabel || item.variableName}"${validationRules ? " " + validationRules.trim() : ""} ${item.inputAttributes ? " " + item.inputAttributes : ""}>${optionString ? " " + optionString.trim() : ""}
|
|
58
|
+
<template #form>${item.inputFormTable}</template>
|
|
59
|
+
</form-table>`;
|
|
60
|
+
break;
|
|
61
|
+
case "FormHidden":
|
|
62
|
+
templateString = `${item.inputOptions} / ${item.inputFormHidden} <form-hidden v-model="data.${item.variableName}" :item-value="${item.inputOptions ? item.inputOptions : "data"}" :hook="() => {${item.inputFormHidden}}">
|
|
63
|
+
</form-hidden>`;
|
|
64
|
+
break;
|
|
56
65
|
default:
|
|
57
66
|
templateString = `<${item.inputType} v-model="data.${item.variableName}" label="${item.inputLabel || item.variableName}"${item.inputAttributes ? " " + item.inputAttributes : ""}${optionString ? " " + optionString.trim() : ""}${validationRules ? " " + validationRules.trim() : ""}></${item.inputType}>`;
|
|
58
67
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ramathibodi/nuxt-commons",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.36",
|
|
4
4
|
"description": "Ramathibodi Nuxt modules for common components",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -115,5 +115,5 @@
|
|
|
115
115
|
"vitest": "^1.6.0",
|
|
116
116
|
"vue-tsc": "2.0.29"
|
|
117
117
|
},
|
|
118
|
-
"packageManager": "pnpm@9.
|
|
118
|
+
"packageManager": "pnpm@9.15.0+sha512.76e2379760a4328ec4415815bcd6628dee727af3779aaa4c914e3944156c4299921a89f976381ee107d41f12cfa4b66681ca9c718f0668fa0831ed4c6d8ba56c"
|
|
119
119
|
}
|