502 lines
22 KiB
Vue
Executable File
502 lines
22 KiB
Vue
Executable File
<template>
|
|
<div :ref="selectedTabDetails" class="w-full">
|
|
<div class="container-fluid max-w-full px-3">
|
|
<div class="row">
|
|
<div class="col-12 px-3">
|
|
<div
|
|
class="mt-3 mb-1 flex h-auto items-center justify-between bg-gray-100 dark:bg-dark-primary-800 rounded-md p-1"
|
|
>
|
|
<div class="w-full">
|
|
<div
|
|
v-for="(headerItems, index) in headerTools"
|
|
:key="index"
|
|
class="flex justify-between items-center my-2"
|
|
>
|
|
<div class="flex justify-between w-full flex-wrap px-2">
|
|
<div
|
|
v-for="(my_item, idx) in getArrayItems(headerItems)"
|
|
:key="idx"
|
|
class="flex items-center flex-wrap"
|
|
>
|
|
<template v-if="isArrayItems(my_item)">
|
|
<div
|
|
v-for="(headItem, myItemIndex) in getArrayItems(
|
|
my_item,
|
|
)"
|
|
:key="myItemIndex"
|
|
class="flex items-center"
|
|
>
|
|
<DropdownSetting
|
|
v-if="headItem.type === 'dropdownSetting'"
|
|
:schema="headItem"
|
|
@dropdown-setting-btn-clicked="
|
|
(val) =>
|
|
emitHandler('dropdown-setting', { data: val })
|
|
"
|
|
/>
|
|
<div
|
|
v-else-if="headItem.key === 'label'"
|
|
class="mr-3"
|
|
v-tooltip="headItem.tooltip || ''"
|
|
>
|
|
<span class="text-primary font-medium px-3">{{
|
|
headItem.label
|
|
}}</span>
|
|
</div>
|
|
<div
|
|
v-else-if="headItem.key === 'text'"
|
|
class="mr-3"
|
|
v-tooltip="headItem.tooltip || ''"
|
|
>
|
|
<span class="text-primary font-medium px-3"
|
|
>{{ headItem.label }}:</span
|
|
>
|
|
<span>{{ getDataValue(headItem.source_key) }}</span>
|
|
</div>
|
|
<div v-else-if="headItem.key === 'switch'" class="mr-2">
|
|
<SwitchButtons
|
|
:switchSchema="headItem.switchSchema"
|
|
@update:model-value="
|
|
(val) =>
|
|
emitHandler('switch-component-change', {
|
|
data: {
|
|
name: headItem.name,
|
|
value: val,
|
|
item: headItem,
|
|
},
|
|
})
|
|
"
|
|
/>
|
|
</div>
|
|
<div
|
|
v-else-if="headItem.key === 'range'"
|
|
class="flex items-center mx-1"
|
|
>
|
|
<label
|
|
v-if="headItem.label"
|
|
class="text-sm text-gray-600 me-2"
|
|
>
|
|
{{ headItem.label }}
|
|
</label>
|
|
<input
|
|
type="range"
|
|
class="form-range appearance-none h-1.5 w-24 bg-gray-200 rounded-lg outline-none"
|
|
:min="headItem.min || 0"
|
|
:max="headItem.max || 5"
|
|
:step="headItem.step || 1"
|
|
:value="headItem.value"
|
|
@input="(e) => handleRange(e, headItem)"
|
|
/>
|
|
<span class="ms-2 text-sm min-w-[18px] text-center">{{
|
|
headItem.value
|
|
}}</span>
|
|
</div>
|
|
<button
|
|
v-else-if="headItem.key === 'icon'"
|
|
class="btn p-2 rounded hover:text-primary transition-colors"
|
|
:title="headItem.label"
|
|
v-tooltip="headItem.tooltip || ''"
|
|
@click="emitHandler('icon-click', { data: headItem })"
|
|
>
|
|
<!-- <svg :class="'icon icon-' + headItem.icon">
|
|
<use :xlink:href="'#icon-' + headItem.icon" />
|
|
</svg> -->
|
|
<UIcon
|
|
:name="headItem.icon"
|
|
:class="headItem.size"
|
|
class="cursor-pointer"
|
|
/>
|
|
</button>
|
|
<div
|
|
v-else-if="
|
|
headItem.key === 'multiSelect' ||
|
|
headItem.key === 'dropdown'
|
|
"
|
|
class="mx-1"
|
|
>
|
|
<MySelect
|
|
v-model:dropdownSchema="headItem.dropdownSchema"
|
|
:selectSchema="headItem.dropdownSchema"
|
|
@dropdownSelectEvents="
|
|
(event) => {
|
|
if (!event) return;
|
|
if (event.action !== 'change') return;
|
|
|
|
emitHandler('multiselect-click', {
|
|
data: {
|
|
name: headItem.name,
|
|
value: event.payload,
|
|
item: headItem,
|
|
},
|
|
});
|
|
}
|
|
"
|
|
/>
|
|
</div>
|
|
<div
|
|
v-else-if="headItem.key === 'button'"
|
|
v-tooltip="headItem.tooltip || ''"
|
|
>
|
|
<button
|
|
class="btn bg-primary text-white px-3 py-1 rounded hover:bg-primary-dark"
|
|
@click="
|
|
emitHandler('button-click', { data: headItem })
|
|
"
|
|
>
|
|
{{ headItem.label }}
|
|
</button>
|
|
</div>
|
|
<div
|
|
v-else-if="headItem.key === 'iconButton'"
|
|
v-tooltip="headItem.tooltip || ''"
|
|
>
|
|
<button
|
|
class="btn flex items-center gap-1 px-2 py-1 rounded hover:text-primary"
|
|
@click="
|
|
emitHandler('iconButton-click', {
|
|
data: headItem,
|
|
})
|
|
"
|
|
:style="{ color: headItem.color }"
|
|
>
|
|
<svg
|
|
v-if="headItem.side === 'right'"
|
|
:class="'icon icon-' + headItem.icon"
|
|
>
|
|
<use :xlink:href="'#icon-' + headItem.icon" />
|
|
</svg>
|
|
{{ headItem.label }}
|
|
<svg
|
|
v-if="headItem.side === 'left'"
|
|
:class="'icon icon-' + headItem.icon"
|
|
>
|
|
<use :xlink:href="'#icon-' + headItem.icon" />
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
<div
|
|
v-else-if="
|
|
headItem.key === 'rangeDate' && !headItem.isShow
|
|
"
|
|
>
|
|
<RangeDateToolsHeader
|
|
@date-picker-handler="
|
|
(val) => emitHandler('date-picker', { data: val })
|
|
"
|
|
/>
|
|
</div>
|
|
<div v-else-if="headItem.key === 'autoComplation'">
|
|
<AutoComplation
|
|
@auto-complation-handler="
|
|
(val) =>
|
|
emitHandler('auto-complation', { data: val })
|
|
"
|
|
:autoComplationSchema="{
|
|
placeholder: headItem.placeholder,
|
|
autocompleteUrl: headItem.autocompleteUrl,
|
|
debounceTime: headItem.debounceTime,
|
|
minCharsForAutocomplete:
|
|
headItem.minCharsForAutocomplete,
|
|
maxHistoryItems: headItem.maxHistoryItems,
|
|
showSearchButton: headItem.showSearchButton,
|
|
filters: headItem.filters,
|
|
}"
|
|
/>
|
|
</div>
|
|
<div
|
|
v-else-if="headItem.key === 'prevNext'"
|
|
class="flex items-center gap-2"
|
|
>
|
|
<button
|
|
class="flex items-center btn bg-primary text-white pl-2 py-1 rounded hover:bg-primary-700 transition-colors duration-300 ease-in-out disabled:cursor-not-allowed"
|
|
:disabled="headItem.prevDisabled"
|
|
@click="
|
|
emitHandler('prev-click', { data: headItem })
|
|
"
|
|
>
|
|
<UIcon
|
|
name="i-lucide-chevron-right"
|
|
class="w-6 h-6"
|
|
/>
|
|
<span>قبلی</span>
|
|
</button>
|
|
|
|
<button
|
|
class="flex items-center btn bg-primary text-white pr-2 py-1 rounded hover:bg-primary-700 transition-colors duration-300 ease-in-out disabled:cursor-not-allowed"
|
|
:disabled="headItem.nextDisabled"
|
|
@click="
|
|
emitHandler('next-click', { data: headItem })
|
|
"
|
|
>
|
|
<span>بعدی</span>
|
|
<UIcon
|
|
name="i-lucide-chevron-left"
|
|
class="w-6 h-6"
|
|
/>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<!-- Non-array items -->
|
|
<template v-else>
|
|
<DropdownSetting
|
|
v-if="my_item.type === 'dropdownSetting'"
|
|
:schema="my_item"
|
|
@dropdown-setting-btn-clicked="
|
|
(val) =>
|
|
emitHandler('dropdown-setting', { data: val })
|
|
"
|
|
/>
|
|
<div
|
|
v-else-if="my_item.key === 'label'"
|
|
class="mr-3"
|
|
v-tooltip="my_item.tooltip || ''"
|
|
>
|
|
<span class="text-primary font-medium px-3">{{
|
|
my_item.label
|
|
}}</span>
|
|
</div>
|
|
<div
|
|
v-else-if="my_item.key === 'text'"
|
|
class="mr-3"
|
|
v-tooltip="my_item.tooltip || ''"
|
|
>
|
|
<span class="text-primary font-medium px-3"
|
|
>{{ my_item.label }}:</span
|
|
>
|
|
<span>{{ getDataValue(my_item.source_key) }}</span>
|
|
</div>
|
|
<!-- جایگزینی سوئیچ قدیمی -->
|
|
<div v-else-if="my_item.key === 'switch'" class="mr-2">
|
|
<SwitchButtons
|
|
:switchSchema="my_item.switchSchema"
|
|
@update:model-value="
|
|
(val) =>
|
|
emitHandler('switch-component-change', {
|
|
data: {
|
|
name: my_item.name,
|
|
value: val,
|
|
item: my_item,
|
|
},
|
|
})
|
|
"
|
|
/>
|
|
</div>
|
|
<div
|
|
v-else-if="my_item.key === 'range'"
|
|
class="flex items-center mx-1"
|
|
>
|
|
<label
|
|
v-if="my_item.label"
|
|
class="text-sm text-gray-600 me-2"
|
|
>
|
|
{{ my_item.label }}
|
|
</label>
|
|
<input
|
|
type="range"
|
|
class="form-range appearance-none h-1.5 w-24 bg-gray-200 rounded-lg outline-none"
|
|
:min="my_item.min || 0"
|
|
:max="my_item.max || 5"
|
|
:step="my_item.step || 1"
|
|
:value="my_item.value"
|
|
@input="(e) => handleRange(e, my_item)"
|
|
/>
|
|
<span class="ms-2 text-sm min-w-[18px] text-center">{{
|
|
my_item.value
|
|
}}</span>
|
|
</div>
|
|
<button
|
|
v-else-if="my_item.key === 'icon'"
|
|
class="btn p-2 rounded hover:text-primary transition-colors"
|
|
:title="my_item.label"
|
|
v-tooltip="my_item.tooltip || ''"
|
|
@click="emitHandler('icon-click', { data: my_item })"
|
|
>
|
|
<!-- <svg :class="'icon icon-' + my_item.icon">
|
|
<use :xlink:href="'#icon-' + my_item.icon" />
|
|
</svg> -->
|
|
<UIcon :name="my_item.icon" :class="my_item.size" />
|
|
</button>
|
|
<div
|
|
v-else-if="
|
|
my_item.key === 'multiSelect' ||
|
|
my_item.key === 'dropdown'
|
|
"
|
|
class="mx-1"
|
|
>
|
|
<MySelect
|
|
v-model:dropdownSelectConfig="my_item.dropdownSchema"
|
|
:selectSchema="my_item.dropdownSchema"
|
|
@dropdownSelectEvents="
|
|
(event) => {
|
|
if (event.action !== 'change') return;
|
|
|
|
emitHandler('multiselect-click', {
|
|
data: {
|
|
name: my_item.name,
|
|
value: event.payload,
|
|
item: my_item,
|
|
},
|
|
});
|
|
}
|
|
"
|
|
/>
|
|
</div>
|
|
<div
|
|
v-else-if="my_item.key === 'button'"
|
|
v-tooltip="my_item.tooltip || ''"
|
|
>
|
|
<button
|
|
class="btn bg-primary text-white px-3 py-1 rounded hover:bg-primary-dark"
|
|
@click="
|
|
emitHandler('button-click', { data: my_item })
|
|
"
|
|
>
|
|
{{ my_item.label }}
|
|
</button>
|
|
</div>
|
|
<div
|
|
v-else-if="my_item.key === 'iconButton'"
|
|
v-tooltip="my_item.tooltip || ''"
|
|
>
|
|
<button
|
|
class="btn flex items-center gap-1 px-2 py-1 rounded hover:text-primary"
|
|
@click="
|
|
emitHandler('iconButton-click', { data: my_item })
|
|
"
|
|
:style="{ color: my_item.color }"
|
|
>
|
|
<svg
|
|
v-if="my_item.side === 'right'"
|
|
:class="'icon icon-' + my_item.icon"
|
|
>
|
|
<use :xlink:href="'#icon-' + my_item.icon" />
|
|
</svg>
|
|
{{ my_item.label }}
|
|
<svg
|
|
v-if="my_item.side === 'left'"
|
|
:class="'icon icon-' + my_item.icon"
|
|
>
|
|
<use :xlink:href="'#icon-' + my_item.icon" />
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
<div
|
|
v-else-if="
|
|
my_item.key === 'rangeDate' && !my_item.isShow
|
|
"
|
|
>
|
|
<RangeDateToolsHeader
|
|
@date-picker-handler="
|
|
(val) => emitHandler('date-picker', { data: val })
|
|
"
|
|
/>
|
|
</div>
|
|
<div v-else-if="my_item.key === 'autoComplation'">
|
|
<AutoComplation
|
|
@auto-complation-handler="
|
|
(val) =>
|
|
emitHandler('auto-complation', { data: val })
|
|
"
|
|
:autoComplationSchema="{
|
|
autocompleteUrl: my_item.autocompleteUrl,
|
|
placeholder: my_item.placeholder,
|
|
debounceTime: my_item.debounceTime,
|
|
minCharsForAutocomplete:
|
|
my_item.minCharsForAutocomplete,
|
|
maxHistoryItems: my_item.maxHistoryItems,
|
|
showSearchButton: my_item.showSearchButton,
|
|
filters: my_item.filters,
|
|
}"
|
|
/>
|
|
</div>
|
|
<div
|
|
v-else-if="my_item.key === 'prevNext'"
|
|
class="flex items-center gap-2"
|
|
>
|
|
<button
|
|
class="flex items-center btn bg-primary text-white pl-2 py-1 rounded hover:bg-primary-700 transition-colors duration-300 ease-in-out disabled:cursor-not-allowed"
|
|
:disabled="my_item.prevDisabled"
|
|
@click="emitHandler('prev-click', { data: my_item })"
|
|
>
|
|
<UIcon
|
|
name="i-lucide-chevron-right"
|
|
class="w-6 h-6"
|
|
/>
|
|
<span>قبلی</span>
|
|
</button>
|
|
|
|
<button
|
|
class="flex items-center btn bg-primary text-white pr-2 py-1 rounded hover:bg-primary-700 transition-colors duration-300 ease-in-out disabled:cursor-not-allowed"
|
|
:disabled="my_item.nextDisabled"
|
|
@click="emitHandler('next-click', { data: my_item })"
|
|
>
|
|
<span>بعدی</span>
|
|
<UIcon name="i-lucide-chevron-left" class="w-6 h-6" />
|
|
</button>
|
|
</div>
|
|
</template>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, computed } from "vue";
|
|
|
|
const props = defineProps({
|
|
headerTools: { type: Array, default: () => [] },
|
|
entity: { type: Object, default: () => ({}) },
|
|
});
|
|
|
|
const emit = defineEmits(["header-tools-action"]);
|
|
|
|
function emitHandler(action, payload) {
|
|
emit("header-tools-action", {
|
|
action,
|
|
data: payload.data,
|
|
});
|
|
}
|
|
|
|
const selectedTabDetails = ref(null);
|
|
const localEntity = computed(() => props.entity || {});
|
|
|
|
function isArrayItems(item) {
|
|
return Array.isArray(item) || (item && item.items && !item.type);
|
|
}
|
|
|
|
function getArrayItems(item) {
|
|
return item.items ? item.items : Array.isArray(item) ? item : [];
|
|
}
|
|
|
|
function getDataValue(key) {
|
|
if (!localEntity.value) return "--";
|
|
const _source = localEntity.value._source || localEntity.value;
|
|
let res = "";
|
|
|
|
const keys = key.split("/");
|
|
for (const k of keys) {
|
|
const kv = k.split(".");
|
|
const value = kv.length === 2 ? _source[kv[0]]?.[kv[1]] : _source[k];
|
|
if (value) {
|
|
res = res ? `${res} / ${value}` : value;
|
|
}
|
|
}
|
|
|
|
return res || _source[key] || _source.qanon_title || _source.title || "--";
|
|
}
|
|
|
|
function handleRange(event, item) {
|
|
const value = parseInt(event.target.value, 10);
|
|
item.value = value;
|
|
emitHandler("range-change", { data: { name: item.name, value, item } });
|
|
}
|
|
</script>
|