quasar-ui-danx 0.0.10 → 0.0.11
Sign up to get free protection for your applications and to get access to all the features.
- package/package.json +3 -2
- package/src/components/ActionTable/ActionTable.vue +135 -0
- package/src/components/ActionTable/BatchActionMenu.vue +60 -0
- package/src/components/ActionTable/EmptyTableState.vue +33 -0
- package/src/components/ActionTable/Filters/CollapsableFiltersSidebar.vue +36 -0
- package/src/components/ActionTable/Filters/FilterGroupItem.vue +28 -0
- package/src/components/ActionTable/Filters/FilterGroupList.vue +76 -0
- package/src/components/ActionTable/Filters/FilterListToggle.vue +50 -0
- package/src/components/ActionTable/Filters/FilterableField.vue +141 -0
- package/src/components/ActionTable/Form/Fields/BooleanField.vue +37 -0
- package/src/components/ActionTable/Form/Fields/ConfirmPasswordField.vue +46 -0
- package/src/components/ActionTable/Form/Fields/DateField.vue +59 -0
- package/src/components/ActionTable/Form/Fields/DateRangeField.vue +110 -0
- package/src/components/ActionTable/Form/Fields/DateTimeField.vue +50 -0
- package/src/components/ActionTable/Form/Fields/DateTimePicker.vue +59 -0
- package/src/components/ActionTable/Form/Fields/EditableDiv.vue +39 -0
- package/src/components/ActionTable/Form/Fields/FieldLabel.vue +32 -0
- package/src/components/ActionTable/Form/Fields/FileUploadButton.vue +78 -0
- package/src/components/ActionTable/Form/Fields/InlineDateTimeField.vue +44 -0
- package/src/components/ActionTable/Form/Fields/IntegerField.vue +26 -0
- package/src/components/ActionTable/Form/Fields/LabeledInput.vue +63 -0
- package/src/components/ActionTable/Form/Fields/MultiFileField.vue +91 -0
- package/src/components/ActionTable/Form/Fields/MultiKeywordField.vue +57 -0
- package/src/components/ActionTable/Form/Fields/NewPasswordField.vue +39 -0
- package/src/components/ActionTable/Form/Fields/NumberField.vue +94 -0
- package/src/components/ActionTable/Form/Fields/NumberRangeField.vue +140 -0
- package/src/components/ActionTable/Form/Fields/SelectDrawer.vue +136 -0
- package/src/components/ActionTable/Form/Fields/SelectField.vue +318 -0
- package/src/components/ActionTable/Form/Fields/SelectWithChildrenField.vue +81 -0
- package/src/components/ActionTable/Form/Fields/SingleFileField.vue +78 -0
- package/src/components/ActionTable/Form/Fields/TextField.vue +82 -0
- package/src/components/ActionTable/Form/Fields/WysiwygField.vue +46 -0
- package/src/components/ActionTable/Form/Fields/index.ts +23 -0
- package/src/components/ActionTable/Form/RenderedForm.vue +74 -0
- package/src/components/ActionTable/RenderComponentColumn.vue +22 -0
- package/src/components/ActionTable/TableSummaryRow.vue +95 -0
- package/src/components/ActionTable/index.ts +15 -0
- package/src/components/ActionTable/listActions.ts +361 -0
- package/src/components/ActionTable/tableColumns.ts +72 -0
- package/src/components/ActionTable/tableHelpers.ts +83 -0
- package/src/components/Utility/CollapsableSidebar.vue +119 -0
- package/src/components/Utility/ContentDrawer.vue +70 -0
- package/src/components/Utility/Dialogs/ConfirmDialog.vue +132 -0
- package/src/components/Utility/Dialogs/FullScreenDialog.vue +46 -0
- package/src/components/Utility/Dialogs/InfoDialog.vue +92 -0
- package/src/components/Utility/Dialogs/InputDialog.vue +35 -0
- package/src/components/Utility/Transitions/ListTransition.vue +50 -0
- package/src/components/Utility/Transitions/SlideTransition.vue +63 -0
- package/src/components/Utility/Transitions/StaggeredListTransition.vue +97 -0
- package/src/components/Utility/index.ts +9 -0
- package/src/components/index.ts +3 -0
- package/src/helpers/FileUpload.ts +294 -0
- package/src/helpers/FlashMessages.ts +79 -0
- package/src/helpers/array.ts +37 -0
- package/src/helpers/compatibility.ts +64 -0
- package/src/helpers/date.ts +5 -0
- package/src/helpers/download.ts +192 -0
- package/src/helpers/downloadPdf.ts +92 -0
- package/src/helpers/files.ts +52 -0
- package/src/helpers/formats.ts +183 -0
- package/src/helpers/http.ts +62 -0
- package/src/helpers/index.ts +10 -1
- package/src/helpers/multiFileUpload.ts +68 -0
- package/src/helpers/singleFileUpload.ts +54 -0
- package/src/helpers/storage.ts +8 -0
@@ -0,0 +1,59 @@
|
|
1
|
+
<template>
|
2
|
+
<div>
|
3
|
+
<div
|
4
|
+
v-if="label"
|
5
|
+
class="font-bold text-xs mb-2"
|
6
|
+
>
|
7
|
+
{{ label }}
|
8
|
+
</div>
|
9
|
+
<div class="flex items-center cursor-pointer">
|
10
|
+
<DateIcon class="w-5 text-blue-base" />
|
11
|
+
<div class="font-bold ml-3 hover:text-blue-base">
|
12
|
+
<template v-if="date">
|
13
|
+
{{ formattedDate }}
|
14
|
+
</template>
|
15
|
+
<template v-else>
|
16
|
+
- -
|
17
|
+
</template>
|
18
|
+
</div>
|
19
|
+
</div>
|
20
|
+
<QPopupProxy>
|
21
|
+
<QDate
|
22
|
+
v-model="date"
|
23
|
+
@update:model-value="onSave"
|
24
|
+
/>
|
25
|
+
</QPopupProxy>
|
26
|
+
</div>
|
27
|
+
</template>
|
28
|
+
|
29
|
+
<script setup>
|
30
|
+
import { CalendarIcon as DateIcon } from "@heroicons/vue/outline";
|
31
|
+
import { fDate, parseQDate } from "danx/src/helpers/formats";
|
32
|
+
import { computed, ref, watch } from "vue";
|
33
|
+
|
34
|
+
const emit = defineEmits(["update:model-value"]);
|
35
|
+
const props = defineProps({
|
36
|
+
modelValue: {
|
37
|
+
type: [String, Object],
|
38
|
+
default: null
|
39
|
+
},
|
40
|
+
label: {
|
41
|
+
type: String,
|
42
|
+
default: null
|
43
|
+
}
|
44
|
+
});
|
45
|
+
|
46
|
+
const formattedDate = computed(() => {
|
47
|
+
if (props.modelValue) {
|
48
|
+
return fDate(parseQDate(props.modelValue || "0000-00-00"));
|
49
|
+
}
|
50
|
+
return null;
|
51
|
+
});
|
52
|
+
|
53
|
+
const date = ref(props.modelValue);
|
54
|
+
watch(() => props.modelValue, val => date.value = val);
|
55
|
+
|
56
|
+
function onSave() {
|
57
|
+
emit("update:model-value", date.value);
|
58
|
+
}
|
59
|
+
</script>
|
@@ -0,0 +1,110 @@
|
|
1
|
+
<template>
|
2
|
+
<div>
|
3
|
+
<div
|
4
|
+
v-if="label"
|
5
|
+
class="font-bold text-xs mb-2"
|
6
|
+
>
|
7
|
+
{{ label }}
|
8
|
+
</div>
|
9
|
+
<template v-if="inline">
|
10
|
+
<QDate
|
11
|
+
v-model="dateRange"
|
12
|
+
range
|
13
|
+
class="reactive"
|
14
|
+
@update:model-value="onSave"
|
15
|
+
/>
|
16
|
+
</template>
|
17
|
+
<template v-else>
|
18
|
+
<div class="flex items-center cursor-pointer">
|
19
|
+
<DateIcon class="w-5 text-blue-base" />
|
20
|
+
<div class="font-bold ml-3 hover:text-blue-base">
|
21
|
+
<template v-if="dateRangeValue">
|
22
|
+
{{ formattedDates.from }} - {{ formattedDates.to }}
|
23
|
+
</template>
|
24
|
+
<template v-else>
|
25
|
+
- -
|
26
|
+
</template>
|
27
|
+
</div>
|
28
|
+
</div>
|
29
|
+
<QPopupProxy>
|
30
|
+
<QDate
|
31
|
+
v-model="dateRange"
|
32
|
+
range
|
33
|
+
@update:model-value="onSave"
|
34
|
+
/>
|
35
|
+
</QPopupProxy>
|
36
|
+
</template>
|
37
|
+
</div>
|
38
|
+
</template>
|
39
|
+
|
40
|
+
<script setup>
|
41
|
+
import { CalendarIcon as DateIcon } from "@heroicons/vue/outline";
|
42
|
+
import { fDate, parseQDate, parseQDateTime } from "danx/src/helpers/formats";
|
43
|
+
import { computed, ref, watch } from "vue";
|
44
|
+
|
45
|
+
const emit = defineEmits(["update:model-value"]);
|
46
|
+
const props = defineProps({
|
47
|
+
modelValue: {
|
48
|
+
type: Object,
|
49
|
+
default: null
|
50
|
+
},
|
51
|
+
label: {
|
52
|
+
type: String,
|
53
|
+
default: null
|
54
|
+
},
|
55
|
+
inline: Boolean,
|
56
|
+
withTime: Boolean
|
57
|
+
});
|
58
|
+
|
59
|
+
const formattedDates = computed(() => {
|
60
|
+
if (dateRangeValue.value) {
|
61
|
+
if (props.withTime) {
|
62
|
+
return {
|
63
|
+
from: fDate(parseQDateTime(dateRangeValue.value.from || "0000-00-00")),
|
64
|
+
to: fDate(parseQDateTime(dateRangeValue.value.to || "9999-12-31"))
|
65
|
+
};
|
66
|
+
}
|
67
|
+
|
68
|
+
return {
|
69
|
+
from: fDate(parseQDate(dateRangeValue.value.from || "0000-00-00")),
|
70
|
+
to: fDate(parseQDate(dateRangeValue.value.to || "9999-12-31"))
|
71
|
+
};
|
72
|
+
}
|
73
|
+
return {
|
74
|
+
from: null,
|
75
|
+
to: null
|
76
|
+
};
|
77
|
+
});
|
78
|
+
|
79
|
+
const dateRange = ref(toQDateValue(props.modelValue));
|
80
|
+
watch(() => props.modelValue, val => dateRange.value = toQDateValue(val));
|
81
|
+
|
82
|
+
function toQDateValue(val) {
|
83
|
+
if (val?.from && val?.to) {
|
84
|
+
return fDate(val.from) === fDate(val.to) ? val.from : val;
|
85
|
+
}
|
86
|
+
return null;
|
87
|
+
}
|
88
|
+
|
89
|
+
const dateRangeValue = computed(() => {
|
90
|
+
let range = dateRange.value;
|
91
|
+
|
92
|
+
if (typeof range === "string") {
|
93
|
+
range = {
|
94
|
+
from: range,
|
95
|
+
to: range
|
96
|
+
};
|
97
|
+
}
|
98
|
+
|
99
|
+
if (range?.from && range?.to && props.withTime) {
|
100
|
+
range.from += " 00:00:00";
|
101
|
+
range.to += " 23:59:59";
|
102
|
+
}
|
103
|
+
|
104
|
+
return range;
|
105
|
+
});
|
106
|
+
|
107
|
+
function onSave() {
|
108
|
+
emit("update:model-value", dateRangeValue.value);
|
109
|
+
}
|
110
|
+
</script>
|
@@ -0,0 +1,50 @@
|
|
1
|
+
<template>
|
2
|
+
<div>
|
3
|
+
<QInput
|
4
|
+
:model-value="fLocalizedDateTime(modelValue)"
|
5
|
+
:color="color"
|
6
|
+
class="bg-white rounded overflow-hidden px-2 w-48"
|
7
|
+
dense
|
8
|
+
readonly
|
9
|
+
@click="isShowing = true"
|
10
|
+
>
|
11
|
+
<template #append>
|
12
|
+
<QIcon name="event" class="cursor-pointer">
|
13
|
+
<QPopupProxy v-model="isShowing">
|
14
|
+
<DateTimePicker
|
15
|
+
v-model="dateTime"
|
16
|
+
@cancel="isShowing = false"
|
17
|
+
@save="onSave"
|
18
|
+
/>
|
19
|
+
</QPopupProxy>
|
20
|
+
</QIcon>
|
21
|
+
</template>
|
22
|
+
</QInput>
|
23
|
+
</div>
|
24
|
+
</template>
|
25
|
+
|
26
|
+
<script setup>
|
27
|
+
import DateTimePicker from "danx/src/components/ActionTable/Form/Fields/DateTimePicker";
|
28
|
+
import { fLocalizedDateTime } from "danx/src/helpers/formats";
|
29
|
+
import { ref } from "vue";
|
30
|
+
|
31
|
+
const emit = defineEmits(["update:model-value"]);
|
32
|
+
const props = defineProps({
|
33
|
+
modelValue: {
|
34
|
+
type: String,
|
35
|
+
required: true
|
36
|
+
},
|
37
|
+
color: {
|
38
|
+
type: String,
|
39
|
+
default: "blue-base"
|
40
|
+
}
|
41
|
+
});
|
42
|
+
|
43
|
+
const isShowing = ref(false);
|
44
|
+
const dateTime = ref(props.modelValue);
|
45
|
+
|
46
|
+
function onSave() {
|
47
|
+
emit("update:model-value", dateTime.value);
|
48
|
+
isShowing.value = false;
|
49
|
+
}
|
50
|
+
</script>
|
@@ -0,0 +1,59 @@
|
|
1
|
+
<template>
|
2
|
+
<QPopupProxy
|
3
|
+
:model-value="true"
|
4
|
+
cover
|
5
|
+
transition-show="scale"
|
6
|
+
transition-hide="scale"
|
7
|
+
class="bg-transparent shadow-none flex items-stretch"
|
8
|
+
>
|
9
|
+
<QDate v-model="dateTime" :mask="mask" :color="color">
|
10
|
+
<div class="flex items-center justify-center">
|
11
|
+
<div v-if="nullable" class="flex-grow">
|
12
|
+
<QBtn label="Clear" color="blue-base" flat @click="dateTime = null" />
|
13
|
+
</div>
|
14
|
+
<div>
|
15
|
+
<QBtn
|
16
|
+
label="Cancel"
|
17
|
+
color="blue-base"
|
18
|
+
flat
|
19
|
+
@click="$emit('cancel')"
|
20
|
+
/>
|
21
|
+
<QBtn label="Set" color="blue-base" flat @click="$emit('save')" />
|
22
|
+
</div>
|
23
|
+
</div>
|
24
|
+
</QDate>
|
25
|
+
<QTime v-model="dateTime" :mask="mask" :color="color" class="ml-3" />
|
26
|
+
</QPopupProxy>
|
27
|
+
</template>
|
28
|
+
<script setup>
|
29
|
+
import { dbDateTime, localizedDateTime, remoteDateTime } from "danx/src/helpers/formats";
|
30
|
+
import { computed } from "vue";
|
31
|
+
|
32
|
+
const emit = defineEmits(["update:modelValue", "save", "cancel", "clear"]);
|
33
|
+
const props = defineProps({
|
34
|
+
modelValue: {
|
35
|
+
type: String,
|
36
|
+
default: null
|
37
|
+
},
|
38
|
+
mask: {
|
39
|
+
type: String,
|
40
|
+
default: "YYYY-MM-DD HH:mm"
|
41
|
+
},
|
42
|
+
color: {
|
43
|
+
type: String,
|
44
|
+
default: "blue-base"
|
45
|
+
},
|
46
|
+
nullable: Boolean
|
47
|
+
});
|
48
|
+
|
49
|
+
const dateTime = computed({
|
50
|
+
get: () => dbDateTime(localizedDateTime(props.modelValue)),
|
51
|
+
set(value) {
|
52
|
+
const newValue = value ? dbDateTime(remoteDateTime(value)) : null;
|
53
|
+
|
54
|
+
if (newValue || props.nullable) {
|
55
|
+
emit("update:modelValue", newValue);
|
56
|
+
}
|
57
|
+
}
|
58
|
+
});
|
59
|
+
</script>
|
@@ -0,0 +1,39 @@
|
|
1
|
+
<template>
|
2
|
+
<div
|
3
|
+
contenteditable
|
4
|
+
class="inline-block hover:bg-blue-light focus:bg-blue-light transition duration-300 outline-none"
|
5
|
+
@input="onInput"
|
6
|
+
>
|
7
|
+
{{ text }}
|
8
|
+
</div>
|
9
|
+
</template>
|
10
|
+
|
11
|
+
<script setup>
|
12
|
+
import { useDebounceFn } from "@vueuse/core";
|
13
|
+
import { ref } from "vue";
|
14
|
+
|
15
|
+
const emit = defineEmits(["update:model-value", "change"]);
|
16
|
+
const props = defineProps({
|
17
|
+
modelValue: {
|
18
|
+
type: String,
|
19
|
+
required: true
|
20
|
+
},
|
21
|
+
debounceDelay: {
|
22
|
+
type: Number,
|
23
|
+
default: 500
|
24
|
+
}
|
25
|
+
});
|
26
|
+
|
27
|
+
const text = ref(props.modelValue);
|
28
|
+
|
29
|
+
const debouncedChange = useDebounceFn(() => {
|
30
|
+
emit("update:model-value", text.value);
|
31
|
+
emit("change", text.value);
|
32
|
+
}, props.debounceDelay);
|
33
|
+
|
34
|
+
function onInput(e) {
|
35
|
+
text.value = e.target.innerText;
|
36
|
+
debouncedChange();
|
37
|
+
}
|
38
|
+
|
39
|
+
</script>
|
@@ -0,0 +1,32 @@
|
|
1
|
+
<template>
|
2
|
+
<span>
|
3
|
+
<slot>
|
4
|
+
{{ labelText }}
|
5
|
+
<template v-if="showName">({{ field?.name }})</template>
|
6
|
+
</slot>
|
7
|
+
<span
|
8
|
+
v-if="requiredLabel"
|
9
|
+
class="text-red-dark ml-1 text-xs bottom-1 relative"
|
10
|
+
>{{ requiredLabel }}</span>
|
11
|
+
</span>
|
12
|
+
</template>
|
13
|
+
|
14
|
+
<script setup>
|
15
|
+
import { computed } from "vue";
|
16
|
+
|
17
|
+
const props = defineProps({
|
18
|
+
field: {
|
19
|
+
type: Object,
|
20
|
+
default: null
|
21
|
+
},
|
22
|
+
label: {
|
23
|
+
type: String,
|
24
|
+
default: null
|
25
|
+
},
|
26
|
+
showName: Boolean,
|
27
|
+
required: Boolean
|
28
|
+
});
|
29
|
+
|
30
|
+
const labelText = computed(() => props.label || props.field?.label);
|
31
|
+
const requiredLabel = computed(() => props.field?.required_group || (props.required || props.field?.required ? "*" : ""));
|
32
|
+
</script>
|
@@ -0,0 +1,78 @@
|
|
1
|
+
<template>
|
2
|
+
<QBtn v-bind="$props" @click="$refs.fileUpload.click()">
|
3
|
+
<slot>
|
4
|
+
<PlusIcon class="w-5 mr-2" />
|
5
|
+
{{ text }}
|
6
|
+
</slot>
|
7
|
+
|
8
|
+
<input
|
9
|
+
ref="fileUpload"
|
10
|
+
data-testid="file-upload"
|
11
|
+
type="file"
|
12
|
+
:accept="geolocation ? 'image/*;capture=camera' : undefined"
|
13
|
+
:capture="geolocation ? 'environment' : undefined"
|
14
|
+
class="hidden"
|
15
|
+
multiple
|
16
|
+
@change="onAttachFiles"
|
17
|
+
/>
|
18
|
+
</QBtn>
|
19
|
+
</template>
|
20
|
+
<script setup>
|
21
|
+
import { PlusIcon } from "@heroicons/vue/outline";
|
22
|
+
import { FileUpload } from "danx/src/helpers";
|
23
|
+
import { QBtn } from "quasar";
|
24
|
+
import { ref } from "vue";
|
25
|
+
|
26
|
+
defineExpose({ upload });
|
27
|
+
const emit = defineEmits([
|
28
|
+
"uploading",
|
29
|
+
"file-progress",
|
30
|
+
"file-complete",
|
31
|
+
"complete"
|
32
|
+
]);
|
33
|
+
const props = defineProps({
|
34
|
+
...QBtn.props,
|
35
|
+
text: {
|
36
|
+
type: String,
|
37
|
+
default: "Add File"
|
38
|
+
},
|
39
|
+
locationWaitMessage: {
|
40
|
+
type: String,
|
41
|
+
default: "Waiting for location..."
|
42
|
+
},
|
43
|
+
geolocation: Boolean
|
44
|
+
});
|
45
|
+
|
46
|
+
const fileUpload = ref(null);
|
47
|
+
|
48
|
+
function upload() {
|
49
|
+
fileUpload.value.click();
|
50
|
+
}
|
51
|
+
|
52
|
+
/**
|
53
|
+
* Upload newly attached files and emit events for progress / completion
|
54
|
+
*
|
55
|
+
* @param files
|
56
|
+
* @returns {Promise<void>}
|
57
|
+
*/
|
58
|
+
async function onAttachFiles({ target: { files } }) {
|
59
|
+
emit("uploading", files);
|
60
|
+
let fileUpload = new FileUpload(files)
|
61
|
+
.onProgress(({ file, progress }) => {
|
62
|
+
file.progress = progress;
|
63
|
+
emit("file-progress", file);
|
64
|
+
})
|
65
|
+
.onComplete(({ file, uploadedFile }) => {
|
66
|
+
emit("file-complete", { file, uploadedFile });
|
67
|
+
})
|
68
|
+
.onAllComplete(() => {
|
69
|
+
emit("complete", fileUpload.files);
|
70
|
+
});
|
71
|
+
|
72
|
+
if (props.geolocation) {
|
73
|
+
await fileUpload.resolveLocation(props.locationWaitMessage);
|
74
|
+
}
|
75
|
+
|
76
|
+
fileUpload.upload();
|
77
|
+
}
|
78
|
+
</script>
|
@@ -0,0 +1,44 @@
|
|
1
|
+
<template>
|
2
|
+
<div class="inline-block">
|
3
|
+
<div
|
4
|
+
class="cursor-pointer py-2 hover:bg-blue-light flex items-center justify-end"
|
5
|
+
>
|
6
|
+
{{ fLocalizedDateTime(modelValue, { empty: "Never" }) }}
|
7
|
+
<EditIcon class="w-4 font-bold ml-2 text-gray-base" />
|
8
|
+
<QPopupEdit
|
9
|
+
v-slot="scope"
|
10
|
+
:model-value="modelValue"
|
11
|
+
touch-position
|
12
|
+
:offset="[0, 20]"
|
13
|
+
class="bg-blue-base text-white !min-w-0"
|
14
|
+
>
|
15
|
+
<DateTimePicker
|
16
|
+
v-model="scope.value"
|
17
|
+
:nullable="nullable"
|
18
|
+
@save="onSave(scope)"
|
19
|
+
@cancel="scope.cancel"
|
20
|
+
/>
|
21
|
+
</QPopupEdit>
|
22
|
+
</div>
|
23
|
+
</div>
|
24
|
+
</template>
|
25
|
+
<script setup>
|
26
|
+
import { PencilIcon as EditIcon } from "@heroicons/vue/solid";
|
27
|
+
import DateTimePicker from "danx/src/components/ActionTable/Form/Fields/DateTimePicker";
|
28
|
+
import { fLocalizedDateTime } from "danx/src/helpers/formats";
|
29
|
+
|
30
|
+
const emit = defineEmits(["close", "save", "update:model-value"]);
|
31
|
+
defineProps({
|
32
|
+
modelValue: {
|
33
|
+
type: String,
|
34
|
+
default: null
|
35
|
+
},
|
36
|
+
nullable: Boolean
|
37
|
+
});
|
38
|
+
|
39
|
+
function onSave(scope) {
|
40
|
+
emit("update:model-value", scope.value);
|
41
|
+
emit("save", scope.value);
|
42
|
+
scope.set();
|
43
|
+
}
|
44
|
+
</script>
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<template>
|
2
|
+
<NumberField
|
3
|
+
:field="field"
|
4
|
+
:precision="0"
|
5
|
+
:model-value="modelValue"
|
6
|
+
:show-name="showName"
|
7
|
+
@update:model-value="$emit('update:model-value', $event)"
|
8
|
+
/>
|
9
|
+
</template>
|
10
|
+
|
11
|
+
<script setup>
|
12
|
+
import NumberField from "danx/src/components/ActionTable/Form/Fields/NumberField";
|
13
|
+
|
14
|
+
defineEmits(["update:model-value"]);
|
15
|
+
defineProps({
|
16
|
+
modelValue: {
|
17
|
+
type: [String, Number],
|
18
|
+
required: true
|
19
|
+
},
|
20
|
+
field: {
|
21
|
+
type: Object,
|
22
|
+
required: true
|
23
|
+
},
|
24
|
+
showName: Boolean
|
25
|
+
});
|
26
|
+
</script>
|
@@ -0,0 +1,63 @@
|
|
1
|
+
<template>
|
2
|
+
<div>
|
3
|
+
<label for="first_name" class="form-label">
|
4
|
+
<slot name="label">{{ label }}</slot>
|
5
|
+
</label>
|
6
|
+
<div class="mt-1">
|
7
|
+
<QInput
|
8
|
+
:model-value="modelValue"
|
9
|
+
:error-message="error"
|
10
|
+
:error="!!error"
|
11
|
+
no-error-icon
|
12
|
+
outlined
|
13
|
+
dense
|
14
|
+
:disable="disabled"
|
15
|
+
:readonly="disabled"
|
16
|
+
:type="type"
|
17
|
+
:name="name"
|
18
|
+
:placeholder="placeholder || label"
|
19
|
+
:required="required"
|
20
|
+
:rules="rules"
|
21
|
+
:lazy-rules="!!rules"
|
22
|
+
class="w-full"
|
23
|
+
@update:model-value="$emit('update:model-value', $event)"
|
24
|
+
/>
|
25
|
+
</div>
|
26
|
+
</div>
|
27
|
+
</template>
|
28
|
+
|
29
|
+
<script setup>
|
30
|
+
defineEmits(["update:model-value"]);
|
31
|
+
defineProps({
|
32
|
+
type: {
|
33
|
+
type: String,
|
34
|
+
default: "text"
|
35
|
+
},
|
36
|
+
name: {
|
37
|
+
type: String,
|
38
|
+
required: true
|
39
|
+
},
|
40
|
+
label: {
|
41
|
+
type: String,
|
42
|
+
default: null
|
43
|
+
},
|
44
|
+
placeholder: {
|
45
|
+
type: String,
|
46
|
+
default: null
|
47
|
+
},
|
48
|
+
modelValue: {
|
49
|
+
type: [String, Number],
|
50
|
+
required: true
|
51
|
+
},
|
52
|
+
error: {
|
53
|
+
type: String,
|
54
|
+
default: null
|
55
|
+
},
|
56
|
+
required: Boolean,
|
57
|
+
disabled: Boolean,
|
58
|
+
rules: {
|
59
|
+
type: Array,
|
60
|
+
default: null
|
61
|
+
}
|
62
|
+
});
|
63
|
+
</script>
|
@@ -0,0 +1,91 @@
|
|
1
|
+
<template>
|
2
|
+
<div
|
3
|
+
class="max-w-full relative overflow-auto"
|
4
|
+
:class="{'p-4 border rounded border-gray-medium': !readonly}"
|
5
|
+
@dragover.prevent
|
6
|
+
@drop.prevent="onDrop"
|
7
|
+
>
|
8
|
+
<FieldLabel
|
9
|
+
:field="field"
|
10
|
+
:show-name="showName"
|
11
|
+
class="text-sm font-semibold"
|
12
|
+
/>
|
13
|
+
<div
|
14
|
+
v-if="!disable && !readonly"
|
15
|
+
class="text-sm my-2"
|
16
|
+
>
|
17
|
+
<a
|
18
|
+
class="text-blue-base"
|
19
|
+
@click="$refs.file.click()"
|
20
|
+
>Upload</a>
|
21
|
+
<a
|
22
|
+
v-if="uploadedFiles.length > 0"
|
23
|
+
class="ml-3 text-red-dark"
|
24
|
+
@click="onClear"
|
25
|
+
>Clear</a>
|
26
|
+
<input
|
27
|
+
ref="file"
|
28
|
+
class="hidden"
|
29
|
+
type="file"
|
30
|
+
multiple
|
31
|
+
@change="onFilesSelected"
|
32
|
+
/>
|
33
|
+
</div>
|
34
|
+
|
35
|
+
<div class="max-w-[50em] flex items-stretch justify-start">
|
36
|
+
<ImagePreview
|
37
|
+
v-for="file in uploadedFiles"
|
38
|
+
:key="'file-upload-' + file.id"
|
39
|
+
class="w-32 m-2 cursor-pointer bg-neutral-plus-5"
|
40
|
+
:class="{'border border-dashed border-blue-base': !uploadedFiles.length}"
|
41
|
+
:image="file"
|
42
|
+
:related-files="uploadedFiles"
|
43
|
+
downloadable
|
44
|
+
:removable="!readonly && !disable"
|
45
|
+
@remove="onRemove(file)"
|
46
|
+
/>
|
47
|
+
<ImagePreview
|
48
|
+
v-if="!disable && !readonly"
|
49
|
+
class="w-32 m-2 cursor-pointer border border-dashed border-blue-base"
|
50
|
+
disabled
|
51
|
+
@click="$refs.file.click()"
|
52
|
+
/>
|
53
|
+
<div
|
54
|
+
v-if="readonly && uploadedFiles.length === 0"
|
55
|
+
class="p-1"
|
56
|
+
>
|
57
|
+
--
|
58
|
+
</div>
|
59
|
+
</div>
|
60
|
+
</div>
|
61
|
+
</template>
|
62
|
+
|
63
|
+
<script setup>
|
64
|
+
import ImagePreview from "components/Common/ImagePreview";
|
65
|
+
import FieldLabel from "danx/src/components/ActionTable/Form/Fields/FieldLabel";
|
66
|
+
import { useMultiFileUpload } from "src/helpers/multiFileUpload";
|
67
|
+
import { onMounted } from "vue";
|
68
|
+
|
69
|
+
const emit = defineEmits(["update:model-value"]);
|
70
|
+
const props = defineProps({
|
71
|
+
modelValue: {
|
72
|
+
type: [Object, String],
|
73
|
+
default: null
|
74
|
+
},
|
75
|
+
field: {
|
76
|
+
type: Object,
|
77
|
+
required: true
|
78
|
+
},
|
79
|
+
showName: Boolean,
|
80
|
+
disable: Boolean,
|
81
|
+
readonly: Boolean
|
82
|
+
});
|
83
|
+
|
84
|
+
const { onComplete, onDrop, onFilesSelected, uploadedFiles, onClear, onRemove } = useMultiFileUpload();
|
85
|
+
onMounted(() => {
|
86
|
+
if (props.modelValue) {
|
87
|
+
uploadedFiles.value = props.modelValue;
|
88
|
+
}
|
89
|
+
});
|
90
|
+
onComplete(() => emit("update:model-value", uploadedFiles.value));
|
91
|
+
</script>
|