@ramathibodi/nuxt-commons 0.1.44 → 0.1.46
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.d.mts +2 -1
- package/dist/module.d.ts +2 -1
- package/dist/module.json +2 -2
- package/dist/runtime/components/ExportCSV.vue +3 -1
- package/dist/runtime/components/ImportCSV.vue +11 -1
- package/dist/runtime/components/form/CheckboxGroup.vue +0 -2
- package/dist/runtime/components/form/Date.vue +39 -45
- package/dist/runtime/components/form/DateTime.vue +35 -41
- package/dist/runtime/components/form/Dialog.vue +48 -22
- package/dist/runtime/components/form/Table.vue +21 -0
- package/dist/runtime/components/form/Time.vue +38 -43
- package/dist/runtime/components/label/Field.vue +13 -8
- package/dist/runtime/components/master/Autocomplete.vue +5 -0
- package/dist/runtime/components/master/Combobox.vue +11 -0
- package/dist/runtime/components/master/Select.vue +13 -1
- package/dist/runtime/components/master/label.vue +5 -0
- package/dist/runtime/components/model/Autocomplete.vue +1 -1
- package/dist/runtime/components/model/Table.vue +19 -0
- package/dist/runtime/components/model/label.vue +3 -3
- package/dist/runtime/composables/api.d.ts +5 -4
- package/dist/runtime/composables/api.js +38 -9
- package/dist/runtime/composables/document/template.js +2 -2
- package/dist/runtime/composables/graphql.d.ts +1 -1
- package/dist/runtime/composables/graphql.js +3 -3
- package/dist/runtime/composables/graphqlModel.d.ts +6 -6
- package/dist/runtime/composables/graphqlModel.js +2 -0
- package/dist/runtime/composables/graphqlModelItem.d.ts +4 -4
- package/dist/runtime/composables/graphqlModelOperation.d.ts +6 -6
- package/dist/runtime/composables/graphqlOperation.d.ts +1 -1
- package/dist/runtime/composables/menu.js +2 -2
- package/dist/runtime/types/formDialog.d.ts +1 -0
- package/dist/runtime/types/graphqlOperation.d.ts +1 -1
- package/dist/runtime/utils/datetime.d.ts +36 -161
- package/dist/runtime/utils/hash.d.ts +1 -0
- package/dist/runtime/utils/hash.js +7 -0
- package/dist/runtime/utils/object.d.ts +1 -0
- package/dist/runtime/utils/object.js +25 -0
- package/dist/types.d.mts +7 -1
- package/dist/types.d.ts +7 -1
- package/package.json +41 -39
- package/templates/.codegen/plugin-schema-object.js +2 -2
package/dist/module.d.mts
CHANGED
package/dist/module.d.ts
CHANGED
package/dist/module.json
CHANGED
|
@@ -8,11 +8,13 @@ interface ExportButtonProps extends /* @vue-ignore */ InstanceType<typeof VBtn['
|
|
|
8
8
|
fileName?: string
|
|
9
9
|
sheetName?: string
|
|
10
10
|
modelValue?: object[]
|
|
11
|
+
stringFields?: Array<string>
|
|
11
12
|
}
|
|
12
13
|
|
|
13
14
|
const props = withDefaults(defineProps<ExportButtonProps>(), {
|
|
14
15
|
fileName: 'download',
|
|
15
16
|
sheetName: 'Sheet1',
|
|
17
|
+
stringFields: ()=>[],
|
|
16
18
|
})
|
|
17
19
|
|
|
18
20
|
const alert = useAlert()
|
|
@@ -63,7 +65,7 @@ function flattenObject(obj: any, parentKey = '', separator = '.') {
|
|
|
63
65
|
const newKey = parentKey ? `${parentKey}${separator}${key}` : key
|
|
64
66
|
const value = obj[key]
|
|
65
67
|
|
|
66
|
-
if (value && typeof value === 'object' && !Array.isArray(value)) {
|
|
68
|
+
if (value && typeof value === 'object' && !Array.isArray(value) && !props.stringFields.includes(newKey)) {
|
|
67
69
|
Object.assign(acc, flattenObject(value, newKey, separator))
|
|
68
70
|
} else {
|
|
69
71
|
acc[newKey] = typeof value === 'object' ? JSON.stringify(value) : value
|
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
import * as XLSX from 'xlsx'
|
|
3
3
|
import { ref } from 'vue'
|
|
4
4
|
import { useAlert } from '../composables/alert'
|
|
5
|
+
import { VBtn } from 'vuetify/components/VBtn'
|
|
6
|
+
|
|
7
|
+
interface ImportButtonProps extends /* @vue-ignore */ InstanceType<typeof VBtn['$props']> {
|
|
8
|
+
stringFields?: Array<string>
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const props = withDefaults(defineProps<ImportButtonProps>(), {
|
|
12
|
+
stringFields: ()=>[],
|
|
13
|
+
})
|
|
5
14
|
|
|
6
15
|
const alert = useAlert()
|
|
7
16
|
const emit = defineEmits<{
|
|
@@ -59,7 +68,8 @@ const parseAndAggregateColumns = (items: any[]) => {
|
|
|
59
68
|
assignNestedValue(aggregatedItem[rootKey], subKeys, parseIfJson(item[key]))
|
|
60
69
|
} else {
|
|
61
70
|
// Directly assign root-level properties
|
|
62
|
-
aggregatedItem[key] =
|
|
71
|
+
if (props.stringFields.includes(key)) aggregatedItem[key] = item[key]
|
|
72
|
+
else aggregatedItem[key] = parseIfJson(item[key])
|
|
63
73
|
}
|
|
64
74
|
}
|
|
65
75
|
|
|
@@ -59,7 +59,6 @@ watch(props.modelValue, () => {
|
|
|
59
59
|
</script>
|
|
60
60
|
|
|
61
61
|
<template>
|
|
62
|
-
<v-container fluid>
|
|
63
62
|
<label class="text-body-1 opacity-60">{{props.label}}</label>
|
|
64
63
|
<div :class="`d-flex ${inline ? 'flex-row':'flex-column'}`">
|
|
65
64
|
<v-checkbox v-for="item in computeItems"
|
|
@@ -83,7 +82,6 @@ watch(props.modelValue, () => {
|
|
|
83
82
|
<label class="text-error text-subtitle-2 ml-1">
|
|
84
83
|
{{computedRules}}
|
|
85
84
|
</label>
|
|
86
|
-
</v-container>
|
|
87
85
|
|
|
88
86
|
</template>
|
|
89
87
|
|
|
@@ -6,7 +6,6 @@ import '@vuepic/vue-datepicker/dist/main.css'
|
|
|
6
6
|
import {isArray, isString} from "lodash-es";
|
|
7
7
|
import { type dateFormat, Datetime } from '../../utils/datetime'
|
|
8
8
|
import { useRules } from "../../composables/utils/validation";
|
|
9
|
-
import {VInput} from "vuetify/components/VInput";
|
|
10
9
|
|
|
11
10
|
interface Props extends /* @vue-ignore */ InstanceType<typeof VTextField['$props']> {
|
|
12
11
|
locale?: 'TH' | 'EN'
|
|
@@ -180,50 +179,45 @@ defineExpose({
|
|
|
180
179
|
</script>
|
|
181
180
|
|
|
182
181
|
<template>
|
|
183
|
-
<v-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
182
|
+
<v-menu
|
|
183
|
+
v-model="isMenuOpen"
|
|
184
|
+
:open-on-click="false"
|
|
185
|
+
>
|
|
186
|
+
<template #activator="{ props: activatorProps }">
|
|
187
|
+
<v-text-field
|
|
188
|
+
ref="textFieldRef"
|
|
189
|
+
v-model="displayedDate"
|
|
190
|
+
:rules="computedRules"
|
|
191
|
+
v-bind="$attrs"
|
|
192
|
+
@focus="handleTextFieldFocus"
|
|
193
|
+
@blur="handleTextFieldBlur"
|
|
194
|
+
@keydown="handleTextFieldInput"
|
|
195
|
+
@keyup.enter="handleTextFieldEnterKey"
|
|
196
|
+
@click:clear="handleTextFieldClear"
|
|
197
|
+
@click="toggleMenuOpen('textField')"
|
|
188
198
|
>
|
|
189
|
-
<template #
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
@keydown="handleTextFieldInput"
|
|
198
|
-
@keyup.enter="handleTextFieldEnterKey"
|
|
199
|
-
@click:clear="handleTextFieldClear"
|
|
200
|
-
@click="toggleMenuOpen('textField')"
|
|
201
|
-
>
|
|
202
|
-
<template #append-inner>
|
|
203
|
-
<v-icon v-if="!isReadonly.value"
|
|
204
|
-
v-bind="activatorProps"
|
|
205
|
-
@click="toggleMenuOpen('icon')"
|
|
206
|
-
>
|
|
207
|
-
fa:fa-regular fa-calendar
|
|
208
|
-
</v-icon>
|
|
209
|
-
</template>
|
|
210
|
-
</v-text-field>
|
|
199
|
+
<template #append="{ isReadonly, isDisabled }">
|
|
200
|
+
<v-icon
|
|
201
|
+
:disabled="isReadonly.value || isDisabled.value"
|
|
202
|
+
v-bind="activatorProps"
|
|
203
|
+
@click="toggleMenuOpen('icon')"
|
|
204
|
+
>
|
|
205
|
+
fa:fa-regular fa-calendar
|
|
206
|
+
</v-icon>
|
|
211
207
|
</template>
|
|
212
|
-
|
|
213
|
-
v-model="selectedDate"
|
|
214
|
-
model-type="yyyy-MM-dd"
|
|
215
|
-
:enable-time-picker="false"
|
|
216
|
-
:flow="flow"
|
|
217
|
-
:min-date="props.minDate"
|
|
218
|
-
:max-date="props.maxDate"
|
|
219
|
-
auto-apply
|
|
220
|
-
inline
|
|
221
|
-
:locale="locale"
|
|
222
|
-
@update:model-value="updateDatePicker"
|
|
223
|
-
/>
|
|
224
|
-
</v-menu>
|
|
208
|
+
</v-text-field>
|
|
225
209
|
</template>
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
210
|
+
<Datepicker
|
|
211
|
+
v-model="selectedDate"
|
|
212
|
+
model-type="yyyy-MM-dd"
|
|
213
|
+
:enable-time-picker="false"
|
|
214
|
+
:flow="flow"
|
|
215
|
+
:min-date="props.minDate"
|
|
216
|
+
:max-date="props.maxDate"
|
|
217
|
+
auto-apply
|
|
218
|
+
inline
|
|
219
|
+
:locale="locale"
|
|
220
|
+
@update:model-value="updateDatePicker"
|
|
221
|
+
/>
|
|
222
|
+
</v-menu>
|
|
223
|
+
</template>
|
|
@@ -4,7 +4,6 @@ import { union,isBoolean,isArray,isString } from 'lodash-es'
|
|
|
4
4
|
import { VTextField } from 'vuetify/components/VTextField'
|
|
5
5
|
import { type dateFormat, Datetime } from '../../utils/datetime'
|
|
6
6
|
import { useRules } from '../../composables/utils/validation'
|
|
7
|
-
import {VInput} from "vuetify/components/VInput";
|
|
8
7
|
|
|
9
8
|
interface Props {
|
|
10
9
|
modelValue?: string | null
|
|
@@ -97,7 +96,7 @@ const computedTimeRules = computed(() => union(computedRules.value, props.timeRu
|
|
|
97
96
|
|
|
98
97
|
const datePart = ref<string | null>(null)
|
|
99
98
|
const timePart = ref<string | null>(null)
|
|
100
|
-
const pauseEmit = ref(
|
|
99
|
+
const pauseEmit = ref(true)
|
|
101
100
|
|
|
102
101
|
function reset() {
|
|
103
102
|
datePart.value = null
|
|
@@ -159,43 +158,38 @@ watch(() => props.modelValue, () => {
|
|
|
159
158
|
</script>
|
|
160
159
|
|
|
161
160
|
<template>
|
|
162
|
-
<v-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
>
|
|
168
|
-
<
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
</v-row>
|
|
197
|
-
</v-container>
|
|
198
|
-
</template>
|
|
199
|
-
</v-input>
|
|
200
|
-
|
|
161
|
+
<v-container
|
|
162
|
+
:fluid="true"
|
|
163
|
+
class="pa-0"
|
|
164
|
+
>
|
|
165
|
+
<v-row :dense="dense">
|
|
166
|
+
<v-col cols="8">
|
|
167
|
+
<FormDate
|
|
168
|
+
v-model="datePart"
|
|
169
|
+
ref="dateRef"
|
|
170
|
+
:rules="computedDateRules"
|
|
171
|
+
:label="label"
|
|
172
|
+
:format="format"
|
|
173
|
+
:picker-only="pickerOnly"
|
|
174
|
+
:readonly="readonly"
|
|
175
|
+
:disabled="fixedDate"
|
|
176
|
+
:min-date="minDate"
|
|
177
|
+
:max-date="maxDate"
|
|
178
|
+
v-bind="$attrs"
|
|
179
|
+
/>
|
|
180
|
+
</v-col>
|
|
181
|
+
<v-col cols="4">
|
|
182
|
+
<FormTime
|
|
183
|
+
v-model="timePart"
|
|
184
|
+
ref="timeRef"
|
|
185
|
+
:rules="computedTimeRules"
|
|
186
|
+
:label="label"
|
|
187
|
+
:enable-seconds="enableSeconds"
|
|
188
|
+
:picker-only="pickerOnly"
|
|
189
|
+
:readonly="readonly"
|
|
190
|
+
v-bind="$attrs"
|
|
191
|
+
/>
|
|
192
|
+
</v-col>
|
|
193
|
+
</v-row>
|
|
194
|
+
</v-container>
|
|
201
195
|
</template>
|
|
@@ -11,24 +11,30 @@ interface Props {
|
|
|
11
11
|
formData?: object
|
|
12
12
|
saveCaption?: string
|
|
13
13
|
cancelCaption?: string
|
|
14
|
+
closeCaption?: string
|
|
15
|
+
saveAndStay?: boolean
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
const props = withDefaults(defineProps<Props>(), {
|
|
17
19
|
saveCaption: 'บันทึก',
|
|
18
20
|
cancelCaption: 'ยกเลิก',
|
|
21
|
+
closeCaption: 'ปิด',
|
|
22
|
+
saveAndStay: false,
|
|
19
23
|
})
|
|
20
24
|
|
|
21
25
|
const isShowing = defineModel<boolean>({ default: false })
|
|
22
26
|
const isSaving = ref<boolean>(false)
|
|
27
|
+
const isSavedAndStay = ref<boolean>(false)
|
|
23
28
|
const formPadRef = ref()
|
|
24
29
|
const formData = ref<object>({})
|
|
30
|
+
const formDataOriginalValue = ref<object>()
|
|
25
31
|
|
|
26
32
|
const emit = defineEmits(['create', 'update'])
|
|
27
33
|
|
|
28
34
|
function save() {
|
|
29
35
|
if (formPadRef.value.isValid) {
|
|
30
36
|
isSaving.value = true
|
|
31
|
-
emit((isCreating.value) ? 'create' : 'update', cloneDeep(formData.value), callback)
|
|
37
|
+
emit((isCreating.value) ? 'create' : 'update', cloneDeep(formData.value), (props.saveAndStay) ? stayCallback : callback)
|
|
32
38
|
}
|
|
33
39
|
}
|
|
34
40
|
|
|
@@ -46,12 +52,26 @@ const callback: FormDialogCallback = {
|
|
|
46
52
|
},
|
|
47
53
|
}
|
|
48
54
|
|
|
55
|
+
const stayCallback: FormDialogCallback = {
|
|
56
|
+
done: function () {
|
|
57
|
+
isSaving.value = false
|
|
58
|
+
isSavedAndStay.value = true
|
|
59
|
+
},
|
|
60
|
+
error: function () {
|
|
61
|
+
isSaving.value = false
|
|
62
|
+
},
|
|
63
|
+
setData: function (item: object) {
|
|
64
|
+
formData.value = cloneDeep(item)
|
|
65
|
+
formDataOriginalValue.value = cloneDeep(item)
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
49
69
|
const isDataChange = computed(() => {
|
|
50
|
-
return !((isCreating.value) ? isEqual(formData.value, createOriginalValue.value) : isEqual(formData.value,
|
|
70
|
+
return !((isCreating.value) ? isEqual(formData.value, createOriginalValue.value) : isEqual(formData.value, formDataOriginalValue.value))
|
|
51
71
|
})
|
|
52
72
|
|
|
53
73
|
const isCreating = computed(() => {
|
|
54
|
-
return !props.formData
|
|
74
|
+
return !props.formData && !isSavedAndStay.value
|
|
55
75
|
})
|
|
56
76
|
|
|
57
77
|
const createOriginalValue = computed(() => {
|
|
@@ -61,12 +81,16 @@ const createOriginalValue = computed(() => {
|
|
|
61
81
|
const loadFormData = () => {
|
|
62
82
|
if (props.formData) {
|
|
63
83
|
formData.value = cloneDeep(props.formData)
|
|
84
|
+
formDataOriginalValue.value = cloneDeep(props.formData)
|
|
64
85
|
}
|
|
65
86
|
else {
|
|
66
87
|
formData.value = Object.assign({}, props.initialData)
|
|
67
88
|
}
|
|
89
|
+
isSavedAndStay.value = false
|
|
68
90
|
}
|
|
69
91
|
|
|
92
|
+
const operation = ref({ isDataChange, isCreating, isSaving, save, cancel })
|
|
93
|
+
|
|
70
94
|
watchEffect(loadFormData)
|
|
71
95
|
|
|
72
96
|
watch(() => isShowing.value, (newValue) => {
|
|
@@ -85,7 +109,7 @@ watch(() => isShowing.value, (newValue) => {
|
|
|
85
109
|
<VCard>
|
|
86
110
|
<VToolbar>
|
|
87
111
|
<VToolbarTitle>
|
|
88
|
-
<slot name="title">
|
|
112
|
+
<slot name="title" :operation="operation">
|
|
89
113
|
{{ (isCreating) ? "New" : "Edit" }} {{ title }}
|
|
90
114
|
</slot>
|
|
91
115
|
</VToolbarTitle>
|
|
@@ -113,24 +137,26 @@ watch(() => isShowing.value, (newValue) => {
|
|
|
113
137
|
</form-pad>
|
|
114
138
|
</VCardText>
|
|
115
139
|
<VCardActions>
|
|
116
|
-
<
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
140
|
+
<slot name="action" :operation="operation">
|
|
141
|
+
<VSpacer />
|
|
142
|
+
<VBtn
|
|
143
|
+
color="primary"
|
|
144
|
+
variant="flat"
|
|
145
|
+
:loading="isSaving"
|
|
146
|
+
:disabled="!isDataChange"
|
|
147
|
+
@click="save"
|
|
148
|
+
>
|
|
149
|
+
{{ saveCaption }}
|
|
150
|
+
</VBtn>
|
|
151
|
+
<VBtn
|
|
152
|
+
color="error"
|
|
153
|
+
variant="flat"
|
|
154
|
+
:disabled="isSaving"
|
|
155
|
+
@click="cancel"
|
|
156
|
+
>
|
|
157
|
+
{{ (!isDataChange) ? closeCaption : cancelCaption }}
|
|
158
|
+
</VBtn>
|
|
159
|
+
</slot>
|
|
134
160
|
</VCardActions>
|
|
135
161
|
</VCard>
|
|
136
162
|
</v-dialog>
|
|
@@ -23,6 +23,8 @@ interface Props extends /* @vue-ignore */ InstanceType<typeof VDataTable['$props
|
|
|
23
23
|
searchable?: boolean
|
|
24
24
|
inputPad?: boolean
|
|
25
25
|
inputPadOnly?: boolean
|
|
26
|
+
saveAndStay?: boolean
|
|
27
|
+
stringFields?: Array<string>
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
const props = withDefaults(defineProps<Props>(), {
|
|
@@ -36,6 +38,8 @@ const props = withDefaults(defineProps<Props>(), {
|
|
|
36
38
|
searchable: true,
|
|
37
39
|
inputPad: false,
|
|
38
40
|
inputPadOnly: false,
|
|
41
|
+
saveAndStay: false,
|
|
42
|
+
stringFields: ()=>[],
|
|
39
43
|
})
|
|
40
44
|
|
|
41
45
|
const emit = defineEmits(['update:modelValue'])
|
|
@@ -85,6 +89,7 @@ function createItem(item: Record<string, any>, callback?: FormDialogCallback) {
|
|
|
85
89
|
|
|
86
90
|
items.value.push(item)
|
|
87
91
|
|
|
92
|
+
if (callback && callback.setData) callback.setData(item)
|
|
88
93
|
if (callback) callback.done()
|
|
89
94
|
}
|
|
90
95
|
|
|
@@ -102,6 +107,7 @@ function updateItem(newItem: Record<string, any>, callback?: FormDialogCallback)
|
|
|
102
107
|
items.value[index] = newItem
|
|
103
108
|
}
|
|
104
109
|
|
|
110
|
+
if (callback && callback.setData) callback.setData(newItem)
|
|
105
111
|
if (callback) callback.done()
|
|
106
112
|
}
|
|
107
113
|
|
|
@@ -238,6 +244,7 @@ defineExpose({
|
|
|
238
244
|
variant="flat"
|
|
239
245
|
@import="importItems"
|
|
240
246
|
:color="toolbarColor"
|
|
247
|
+
:stringFields="props.stringFields"
|
|
241
248
|
/>
|
|
242
249
|
<ExportCSV
|
|
243
250
|
v-if="props.exportable && items.length && !(isReadonly.value || isDisabled.value)"
|
|
@@ -246,6 +253,7 @@ defineExpose({
|
|
|
246
253
|
:file-name="title"
|
|
247
254
|
:model-value="items"
|
|
248
255
|
:color="toolbarColor"
|
|
256
|
+
:stringFields="props.stringFields"
|
|
249
257
|
/>
|
|
250
258
|
<VBtn
|
|
251
259
|
v-if="props.insertable && !props.inputPadOnly && !(isReadonly.value || isDisabled.value)"
|
|
@@ -313,6 +321,7 @@ defineExpose({
|
|
|
313
321
|
:form-data="currentItem"
|
|
314
322
|
@create="createItem"
|
|
315
323
|
@update="updateItem"
|
|
324
|
+
:saveAndStay="saveAndStay"
|
|
316
325
|
v-if="!props.inputPadOnly"
|
|
317
326
|
>
|
|
318
327
|
<template #default="slotData">
|
|
@@ -321,6 +330,18 @@ defineExpose({
|
|
|
321
330
|
v-bind="slotData"
|
|
322
331
|
/>
|
|
323
332
|
</template>
|
|
333
|
+
<template #title="slotData">
|
|
334
|
+
<slot
|
|
335
|
+
name="formTitle"
|
|
336
|
+
v-bind="slotData"
|
|
337
|
+
/>
|
|
338
|
+
</template>
|
|
339
|
+
<template #action="slotData">
|
|
340
|
+
<slot
|
|
341
|
+
name="formAction"
|
|
342
|
+
v-bind="slotData"
|
|
343
|
+
/>
|
|
344
|
+
</template>
|
|
324
345
|
</FormDialog>
|
|
325
346
|
</v-card>
|
|
326
347
|
<slot name="inputPad" :operation="operation" :isReadonly="isReadonly" :isDisabled="isDisabled">
|
|
@@ -4,7 +4,6 @@ import { VTextField } from 'vuetify/components/VTextField'
|
|
|
4
4
|
import Datepicker from '@vuepic/vue-datepicker'
|
|
5
5
|
import '@vuepic/vue-datepicker/dist/main.css'
|
|
6
6
|
import { Datetime } from '../../utils/datetime'
|
|
7
|
-
import {VInput} from "vuetify/components/VInput";
|
|
8
7
|
|
|
9
8
|
interface Props extends /* @vue-ignore */ InstanceType<typeof VTextField['$props']> {
|
|
10
9
|
enableSeconds?: boolean
|
|
@@ -123,49 +122,45 @@ defineExpose({
|
|
|
123
122
|
</script>
|
|
124
123
|
|
|
125
124
|
<template>
|
|
126
|
-
<v-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
125
|
+
<v-menu
|
|
126
|
+
v-model="isMenuOpen"
|
|
127
|
+
:close-on-content-click="false"
|
|
128
|
+
:open-on-click="false"
|
|
129
|
+
>
|
|
130
|
+
<template #activator="{ props }">
|
|
131
|
+
<v-text-field
|
|
132
|
+
ref="textFieldRef"
|
|
133
|
+
v-model="tempTime"
|
|
134
|
+
v-bind="$attrs"
|
|
135
|
+
@focus="onTextFieldFocus"
|
|
136
|
+
@blur="onTextFieldBlur"
|
|
137
|
+
@keydown="onTextFieldTyped"
|
|
138
|
+
@keyup.enter="onTextFieldEnterKey"
|
|
139
|
+
@click:clear="onTextFieldClear"
|
|
140
|
+
@click="toggleMenuOpen('textField')"
|
|
132
141
|
>
|
|
133
|
-
<template #
|
|
134
|
-
<v-
|
|
135
|
-
|
|
136
|
-
v-
|
|
137
|
-
|
|
138
|
-
@focus="onTextFieldFocus"
|
|
139
|
-
@blur="onTextFieldBlur"
|
|
140
|
-
@keydown="onTextFieldTyped"
|
|
141
|
-
@keyup.enter="onTextFieldEnterKey"
|
|
142
|
-
@click:clear="onTextFieldClear"
|
|
143
|
-
@click="toggleMenuOpen('textField')"
|
|
142
|
+
<template #append="{ isReadonly, isDisabled }">
|
|
143
|
+
<v-icon
|
|
144
|
+
:disabled="isReadonly.value || isDisabled.value"
|
|
145
|
+
v-bind="props"
|
|
146
|
+
@click="toggleMenuOpen('icon')"
|
|
144
147
|
>
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
v-bind="props"
|
|
148
|
-
@click="toggleMenuOpen('icon')"
|
|
149
|
-
>
|
|
150
|
-
fa:fa-regular fa-clock
|
|
151
|
-
</v-icon>
|
|
152
|
-
</template>
|
|
153
|
-
</v-text-field>
|
|
148
|
+
fa:fa-regular fa-clock
|
|
149
|
+
</v-icon>
|
|
154
150
|
</template>
|
|
155
|
-
|
|
156
|
-
v-model="time"
|
|
157
|
-
model-type="HH:mm:ss"
|
|
158
|
-
:enable-seconds="enableSeconds"
|
|
159
|
-
minutes-grid-increment="1"
|
|
160
|
-
time-picker
|
|
161
|
-
auto-apply
|
|
162
|
-
:close-on-auto-apply="false"
|
|
163
|
-
inline
|
|
164
|
-
:locale="locale"
|
|
165
|
-
@update:model-value="setDatePicker"
|
|
166
|
-
/>
|
|
167
|
-
</v-menu>
|
|
151
|
+
</v-text-field>
|
|
168
152
|
</template>
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
153
|
+
<Datepicker
|
|
154
|
+
v-model="time"
|
|
155
|
+
model-type="HH:mm:ss"
|
|
156
|
+
:enable-seconds="enableSeconds"
|
|
157
|
+
minutes-grid-increment="1"
|
|
158
|
+
time-picker
|
|
159
|
+
auto-apply
|
|
160
|
+
:close-on-auto-apply="false"
|
|
161
|
+
inline
|
|
162
|
+
:locale="locale"
|
|
163
|
+
@update:model-value="setDatePicker"
|
|
164
|
+
/>
|
|
165
|
+
</v-menu>
|
|
166
|
+
</template>
|
|
@@ -7,6 +7,7 @@ interface Props {
|
|
|
7
7
|
horizontal?: boolean;
|
|
8
8
|
size?: 'large' | 'medium';
|
|
9
9
|
truncate?: boolean;
|
|
10
|
+
notFoundText?: string
|
|
10
11
|
}
|
|
11
12
|
|
|
12
13
|
const props = withDefaults(defineProps<Props>(), {
|
|
@@ -15,6 +16,7 @@ const props = withDefaults(defineProps<Props>(), {
|
|
|
15
16
|
horizontal: false,
|
|
16
17
|
size: 'large',
|
|
17
18
|
truncate: false,
|
|
19
|
+
notFoundText : '-'
|
|
18
20
|
});
|
|
19
21
|
|
|
20
22
|
const valueText = ref<HTMLElement | null>(null);
|
|
@@ -27,6 +29,9 @@ const setTruncate = (event: Event) => {
|
|
|
27
29
|
const target = event.target as HTMLElement;
|
|
28
30
|
isTooltip.value = target.offsetWidth < target.scrollWidth;
|
|
29
31
|
};
|
|
32
|
+
const valueData = computed(()=>{
|
|
33
|
+
return (props.value) ? props.value : props.notFoundText
|
|
34
|
+
})
|
|
30
35
|
|
|
31
36
|
</script>
|
|
32
37
|
|
|
@@ -41,8 +46,8 @@ const setTruncate = (event: Event) => {
|
|
|
41
46
|
<slot name="label">{{ props.label }}:</slot>
|
|
42
47
|
</div>
|
|
43
48
|
<div :class="`ml-1 ${calTruncate}`" ref="valueText">
|
|
44
|
-
<slot name="value">
|
|
45
|
-
<div v-if="!props.truncate">{{
|
|
49
|
+
<slot name="value" :value="valueData">
|
|
50
|
+
<div v-if="!props.truncate">{{ valueData }}</div>
|
|
46
51
|
<div
|
|
47
52
|
v-else
|
|
48
53
|
@mouseover="setTruncate"
|
|
@@ -54,10 +59,10 @@ const setTruncate = (event: Event) => {
|
|
|
54
59
|
class="text-truncate"
|
|
55
60
|
v-bind="isTooltip ? props : ''"
|
|
56
61
|
>
|
|
57
|
-
{{
|
|
62
|
+
{{ valueData }}
|
|
58
63
|
</div>
|
|
59
64
|
</template>
|
|
60
|
-
<span>{{
|
|
65
|
+
<span>{{ valueData }}</span>
|
|
61
66
|
</v-tooltip>
|
|
62
67
|
</div>
|
|
63
68
|
</slot>
|
|
@@ -70,8 +75,8 @@ const setTruncate = (event: Event) => {
|
|
|
70
75
|
</VCardSubtitle>
|
|
71
76
|
<VCardText :class="`pa-0 mb-2 ${calSize}`">
|
|
72
77
|
<div :class="calTruncate" ref="valueText">
|
|
73
|
-
<slot name="value">
|
|
74
|
-
<div v-if="!props.truncate">{{
|
|
78
|
+
<slot name="value" :value="valueData">
|
|
79
|
+
<div v-if="!props.truncate">{{ valueData }}</div>
|
|
75
80
|
<div
|
|
76
81
|
v-else
|
|
77
82
|
@mouseover="setTruncate"
|
|
@@ -83,10 +88,10 @@ const setTruncate = (event: Event) => {
|
|
|
83
88
|
class="text-truncate"
|
|
84
89
|
v-bind="isTooltip ? props : ''"
|
|
85
90
|
>
|
|
86
|
-
{{
|
|
91
|
+
{{ valueData }}
|
|
87
92
|
</div>
|
|
88
93
|
</template>
|
|
89
|
-
<span>{{
|
|
94
|
+
<span>{{ valueData }}</span>
|
|
90
95
|
</v-tooltip>
|
|
91
96
|
</div>
|
|
92
97
|
</slot>
|