base_ui/components/global/MyTable.vue

1131 lines
36 KiB
Vue
Raw Normal View History

2025-02-01 09:34:55 +00:00
<template>
<div class="table-container" :class="{ 'has-search': hasSearch }">
<!-- #region header -->
<div class="table-header d-flex align-items-center">
<div v-if="hasSearch">
<!-- <slot name="headerSearch"></slot> -->
<form class="table-search-form" role="search" @submit.prevent="search">
<div class="form-group">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text">
<svg
class=""
aria-hidden="true"
focusable="false"
data-prefix="fas"
data-icon="search"
role="img"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 512 512"
data-fa-i2svg=""
>
<path
fill="currentColor"
d="M505 442.7L405.3 343c-4.5-4.5-10.6-7-17-7H372c27.6-35.3 44-79.7 44-128C416 93.1 322.9 0 208 0S0 93.1 0 208s93.1 208 208 208c48.3 0 92.7-16.4 128-44v16.3c0 6.4 2.5 12.5 7 17l99.7 99.7c9.4 9.4 24.6 9.4 33.9 0l28.3-28.3c9.4-9.4 9.4-24.6.1-34zM208 336c-70.7 0-128-57.2-128-128 0-70.7 57.2-128 128-128 70.7 0 128 57.2 128 128 0 70.7-57.2 128-128 128z"
></path>
</svg>
</span>
</div>
<input
v-model="searchForm.query"
type="search"
required
class="form-control"
id="search-query"
placeholder="جستجو..."
name="search-query"
aria-label="جستجو در اسناد، عناوین و واژگان"
aria-describedby="basic-addon1"
size="50"
@keyup="search()"
@keydown="onKeyDown()"
/>
<div class="input-group-append">
<button
@click="resetForm()"
:class="{ 'show-reset-btn': searchForm.query.length > 0 }"
type="button"
class="input-group-text"
id="basic-addon1"
>
<svg class="icon icon-Component-294--1">
<use xlink:href="#icon-Component-294--1"></use>
</svg>
</button>
<!-- <div class="dropdown">
<button
class="btn dropdown-toggle"
type="button"
data-bs-toggle="dropdown"
aria-expanded="false"
>
<svg class="icon icon-filter" style="width: 1.3em">
<use xlink:href="#icon-filter"></use>
</svg>
عنوان
</button>
<div class="dropdown-menu">
<button class="dropdown-item" type="button" value="current">
عنوان
</button>
<button class="dropdown-item" type="button" value="all">
شماره
</button>
<button class="dropdown-item" type="button" value="all">
کد
</button>
</div>
</div> -->
</div>
</div>
</div>
</form>
</div>
<div class="me-auto">
<slot name="tableHeaderActions"></slot>
</div>
</div>
<!-- #endregion header -->
<!-- #region main -->
<div
class="table-responsive firefox-scrollbar"
:style="{
height: $attrs.height,
maxHeight: $attrs.maxHeight,
minHeight: $attrs.minHeight,
}"
>
<table
class="table table-hover table-striped"
:class="{ 'column-highlight-active': isColumnHighlightActive }"
id="table1"
>
<thead class="thead">
<tr>
<th scope="col">#</th>
<th
:class="{ 'cursor-title': activeTableColumnTitle }"
v-for="(tableColumn, index) in tableColumns"
:colspan="tableColumn.width"
@click="clickManagementTableColumns(tableColumn)"
:key="index"
scope="col"
v-tooltip="tableColumn?.titleTooltip"
>
{{ tableColumn.title }}
<button-component
:class="tableColumn.sortorder"
classes="p-0 sort-indicator"
buttonText=""
v-if="showHeaderSortButton"
>
<span class="tavasi tavasi-chevron-sort"></span>
<span class="tavasi tavasi-chevron-sort-asce"
><span class="path1"></span><span class="path2"></span
></span>
<span class="tavasi tavasi-chevron-sort-desc"
><span class="path1"></span><span class="path2"></span
></span>
<!-- <span class="tavasi tavasi-sort"></span> -->
<!-- <span class="tavasi tavasi-desc"></span> -->
<!-- <span class="tavasi tavasi-asce"></span> -->
<!-- <span class="tavasi tavasi-Component-132--1"></span> -->
</button-component>
</th>
<th v-if="showActions" scope="col">{{ $t("Operation") }}</th>
</tr>
</thead>
<template v-if="fetchingData">
<tbody>
<tr>
<td colspan="12">
<the-content-loading
:loadingTitle="'در حال دریافت اطلاعات'"
class="table-loading"
></the-content-loading>
</td>
</tr>
</tbody>
</template>
<template v-else>
<template v-if="cloneItems.length">
<draggable
handle=".my-handle"
:sort="isSortable"
:disabled="!isDraggable"
:list="cloneItems"
tag="tbody"
group="people"
:removeCloneOnHide="false"
@start="handleDragStart"
@sort="$emit('onSort', $event)"
>
<tr
v-for="(rowItem, index) in cloneItems"
:class="[
{ active: rowItem?.active ?? false },
{ unactive: getUnactiveClass(rowItem) },
]"
:key="rowItem.id_store ?? rowItem.id"
:id="rowItem.id_store ?? rowItem.id"
>
<th v-if="hasCheckbox">
<input
type="checkbox"
class="form-control"
:value="rowItem[tableColumn.key]"
:true-value="1"
:false-value="0"
@change="
$emit('checkbox-selected', {
rowItem,
newOrder: $event.target.value,
})
"
/>
</th>
<th scope="row" :class="{ 'my-handle': isDraggable }">
{{ paginationInfo.offset + index + 1 }}
{{ isDraggable ? "::" : "" }}
</th>
<!-- :class="{ 'my-handle': key < 1 }" -->
<td
:colspan="tableColumn.width"
v-for="(tableColumn, key) in tableColumns"
:key="key"
:class="[
tableColumn.textAlign
? `text-${tableColumn.textAlign}`
: 'text-center',
]"
>
<input
class="form-control"
style="width: 4em"
@input="
$emit('update-order', {
rowItem,
newOrder: $event.target.value,
})
"
type="number"
min="1"
v-if="tableColumn.key == 'subject_order'"
:value="rowItem[tableColumn.key]"
/>
<a
class="is-link show-text-decoration 1231231231313"
@click.prevent="
methodName('on-linked-title-click', {
rowItem,
tableColumn,
index,
})
"
@auxclick.prevent.stop="
methodName('on-linked-title-click', {
rowItem,
tableColumn,
index,
})
"
v-else-if="tableColumn.isLink"
:href="rowItem[tableColumn.key]"
:title="rowItem[tableColumn.key]"
v-html="getCellValue(rowItem, tableColumn)"
>
</a>
<template v-else
><span v-html="getCellValue(rowItem, tableColumn)"></span
></template>
</td>
<td v-if="showActions">
<span class="action-column">
<template v-for="(rowAction, j) in tableActions">
<template v-if="rowAction.toggle_icons">
<button
v-if="rowAction.key != 'tbookmark' || isRealUser"
:key="j"
@click="
methodName(rowAction.action, {
item: rowItem,
index: index,
rowAction: rowAction,
})
"
:title="rowAction.title"
class="btn"
:type="rowAction.type"
>
<svg
v-if="rowAction.key == 'tbookmark'"
class=""
:class="
rowItem._source[rowAction.key] == 1
? 'icon icon-' + rowAction.toggle_icons.icon1
: 'icon icon-' + rowAction.toggle_icons.icon2
"
>
<use
:xlink:href="
rowItem._source[rowAction.key] == 1
? '#icon-' + rowAction.toggle_icons.icon1
: '#icon-' + rowAction.toggle_icons.icon2
"
></use>
</svg>
<svg v-else :class="'icon icon-' + rowAction.icon">
<use :xlink:href="'#icon-' + rowAction.icon"></use>
</svg>
</button>
</template>
<template v-else>
<template v-if="rowAction.can">
<button-component
:key="j"
v-can="rowAction.can"
@click="
methodName(rowAction.action, {
item: rowItem,
index: index,
rowAction: rowAction,
})
"
buttonText=""
:classes="rowAction.class"
:title="rowAction.title"
>
<svg :class="`icon icon-${rowAction.icon}`">
<use
:xlink:href="`#icon-${rowAction.icon}`"
></use>
</svg>
</button-component>
</template>
<template v-else>
<button-component
:key="j"
@click="
methodName(rowAction.action, {
item: rowItem,
index: index,
rowAction: rowAction,
})
"
buttonText=""
:classes="rowAction.class"
>
<svg :class="`icon icon-${rowAction.icon}`">
<use
:xlink:href="`#icon-${rowAction.icon}`"
></use>
</svg>
<!-- <span v-else :class="rowAction.icon"></span> -->
</button-component>
</template>
</template>
</template>
<!-- <context-menu
style="position: static; display: inline-flex"
v-if="tableActions.length > 2"
:id="rowItem.id"
:contextMenu="tableActions"
@topicing="showSubjectForm(index)"
@other="methodName($event, index)"
>
</context-menu> -->
</span>
</td>
</tr>
</draggable>
<tfoot v-if="hasFooter">
<tr>
<td colspan="12">
<slot name="footer"></slot>
</td>
</tr>
</tfoot>
</template>
<tbody v-else-if="cloneItems.length == 0">
<table-no-data />
</tbody>
</template>
</table>
</div>
<!-- #endregion main -->
<!-- #region pagination -->
<jahat-pagination
v-if="hasPagination"
:paginationInfo="paginationInfo"
@page-changed="clickCallback"
@page-limit-changed="limitChanged"
>
</jahat-pagination>
<!-- #endregion pagination -->
</div>
</template>
<script>
import { VueDraggableNext } from "vue-draggable-next";
// import draggable from "vuedraggable";
// import VueDragDrop from "vue-drag-drop";
import { mapActions, mapState } from "pinia";
// const { moment } = useNuxtApp();
// import moment from "jalaliMoment";
// import tableAndListMixin from "~/mixins/tableAndListMixin";
/**
* @vue-prop {String} [canAddSubject=""] - مجوز افزودن موضوع
* @vue-prop {String} [canSeeSummary=""] - مجوز مشاهده خلاصه
* @vue-prop {String} [canSeeDetails=""] - مجوز مشاهده جزئیات
* @vue-prop {String} [canDelete=""] - مجوز حذف
* @vue-prop {String} [canEdit=""] - مجوز ویرایش
* @vue-prop {Boolean} [hasFooter=false] - مشخص کنید آیا فوتر وجود دارد یا خیر
* @vue-prop {Boolean} [hasSubject=false] - مشخص کنید آیا موضوع وجود دارد یا خیر
* @vue-prop {Boolean} [hasEdit=true] - مشخص کنید آیا قابلیت ویرایش وجود دارد یا خیر
* @vue-prop {Boolean} [hasDelete=true] - مشخص کنید آیا قابلیت حذف وجود دارد یا خیر
* @vue-prop {Boolean} [hasSummary=true] - مشخص کنید آیا خلاصه وجود دارد یا خیر
* @vue-prop {Boolean} [hasDetails=false] - مشخص کنید آیا جزئیات وجود دارد یا خیر
* @vue-prop {Boolean} [hasSearch=false] - مشخص کنید آیا قابلیت جستجو وجود دارد یا خیر
* @vue-prop {Boolean} [showActions=true] - مشخص کنید آیا اقدامات نمایش داده شود یا خیر
* @vue-prop {Boolean} [isDraggable=false] - مشخص کنید آیا قابلیت کشیدن و رها کردن وجود دارد یا خیر
* @vue-prop {Boolean} [isSortable=false] - مشخص کنید آیا قابلیت مرتب سازی وجود دارد یا خیر
* @vue-prop {Boolean} [showHeaderSortButton=false] - مشخص کنید آیا قابلیت مرتب سازی در هدر وجود دارد یا خیر
* @vue-prop {Array} [items=[]] - آیتمها
* @vue-prop {Array} [tableColumns=[]] - ستونهای جدول
* @vue-prop {Boolean} [fetchingData=false] - مشخص کنید آیا دادهها در حال دریافت هستند یا خیر
* @vue-prop {Object} [sortingInfo] - اطلاعات مربوط به مرتب سازی
* @vue-prop {Number} [sortingInfo.sortby="id"] - فیلد براساس آن مرتب سازی انجام شود
* @vue-prop {String} [sortingInfo.sortorder="desc"] - ترتیب مرتب سازی
* @vue-prop {Object} [paginationInfo] - اطلاعات مربوط به صفحه بندی
* @vue-prop {Number} [paginationInfo.pages=0] - تعداد کل صفحات
* @vue-prop {Number} [paginationInfo.total=0] - تعداد کل آیتمها
* @vue-prop {Number} [paginationInfo.page=1] - صفحه فعلی
* @vue-prop {Number} [paginationInfo.offset=0] - آفست (صفحه * تعداد در هر صفحه)
* @vue-prop {Number} [paginationInfo.limit=10] - تعداد در هر صفحه
* @vue-prop {Array} [tableActions] - اقدامات مربوط به جدول
* @vue-prop {Boolean} [tableActions.showOutside=true] - نمایش خارج از جدول
* @vue-prop {Boolean} [tableActions.show=true] - نمایش
* @vue-prop {String} [tableActions.icon="default"] - آیکون
* @vue-prop {String} [tableActions.title=""] - عنوان
* @vue-prop {Object} [tableActions.to] - مقصد لینک
* @vue-prop {Boolean} [tableActions.selected=false] - انتخاب شده یا نه
* @vue-prop {Boolean} [tableActions.disabled=false] - غیرفعال
* @vue-prop {String} [tableActions.howToOpen=""] - نحوه باز شدن لینک
* @vue-prop {String} [tableActions.href=""] - لینک
* @vue-prop {String} [tableActions.class=""] - کلاس
* @vue-prop {String} [tableActions.action=""] - اقدام
* @vue-prop {String} [tableActions.can=""] - مجوز
*
* @vue-data {String} [prevColumn=undefined] - ستونی که قبل از حالت فعلی مرتب سازی شده بود
* @vue-data {Number} [sortOrderIndicator=0] - نشانگر ترتیب مرتب سازی
* @vue-data {Object} [sortOrder] - ترتیب مرتب سازی ممکن (asc, desc, undefined)
* @vue-data {Boolean} [showDetailsPanel=false] - نشان دادن پنل جزئیات
* @vue-data {Boolean} [dragging=false] - در حال کشیدن
* @vue-data {Number} [page=1] - شماره صفحه فعلی
* @vue-data {Number} [typingTimer=0] - تایمر تایپ
* @vue-data {Number} [doneTypingInterval=1000] - فاصله زمانی برای اتمام تایپ
* @vue-data {Object} [selectedItem] - آیتم انتخاب شده
* @vue-data {Object} [selectedItemClone] - کپی از آیتم انتخاب شده
* @vue-data {Array} [cloneItems=[]] - آیتمهای کپی
* @vue-data {Number} [prevSelectedItemIndex=undefined] - اندیس آیتم انتخاب شده قبلی
* @vue-data {Object} [searchForm] - فرم جستجو
* @vue-data {String} [searchForm.query=""] - متن جستجو
*
* @vue-computed {Function} [mapState.selectedProjectGetter] - مپ کردن گترهای مورد نیاز از استور ماژول "list" به کامپوتد فعلی
* @vue-computed {Object} [tHead] - سرتیتر جدول
* @vue-computed {Array} [tBody] - بدنه جدول
*
* @vue-event {Function} mapActions.SET_LIST_ENTITY - تنظیم لیست انتیتی
* @vue-event {Function} mapActions.SET_ITEM_ENTITY - تنظیم ایتم انتیتی
* @vue-event {Function} mapActions.SET_SELECTED_ITEM -
*
*/
export default {
props: {
canAddSubject: {
default: "",
type: String,
},
canSeeSummary: {
default: "",
type: String,
},
canSeeDetails: {
default: "",
type: String,
},
canDelete: {
default: "",
type: String,
},
canEdit: {
default: "",
type: String,
},
hasCheckbox: {
default: false,
type: Boolean,
},
hasFooter: {
default: false,
type: Boolean,
},
hasSubject: {
default: false,
type: Boolean,
},
hasEdit: {
default: true,
type: Boolean,
},
hasDelete: {
default: true,
type: Boolean,
},
hasSummary: {
default: true,
type: Boolean,
},
hasDetails: {
default: false,
type: Boolean,
},
hasSearch: {
default: false,
type: Boolean,
},
showActions: {
default: true,
type: Boolean,
},
isDraggable: {
default: false,
type: Boolean,
},
isSortable: {
default: false,
type: Boolean,
},
showHeaderSortButton: {
default: true,
type: Boolean,
},
isColumnHighlightActive: {
default: false,
type: Boolean,
},
hasPagination: {
default: true,
type: Boolean,
},
items: {
default() {
return [];
},
},
tableColumns: {
default() {
return [];
},
},
fetchingData: {
default: false,
type: Boolean,
},
activeTableColumnTitle: {
default: false,
type: Boolean,
},
sortingInfo: {
default() {
return {
sortby: "id",
sortorder: "desc",
};
},
},
paginationInfo: {
default() {
return {
pages: 0,
total: 0,
page: 1,
offset: 0, // page * per_page
limit: 10, //per_page
};
},
},
tableActions: {
default() {
return [
{
showOutside: true,
show: true,
icon: "tavasi tavasi-Component-71--1",
title: "جزییات",
to: {
name: "undefined",
},
selected: false,
disabled: false,
howToOpen: "",
href: "",
class: "btn show-detail-btn -rotate-180",
action: "showDetails",
can: "",
},
{
showOutside: false,
show: true,
icon: "default",
title: "ویرایش",
to: {
name: "undefined",
},
selected: false,
disabled: false,
howToOpen: "",
href: "",
class: "edit-btn",
action: "edit-table-item",
can: "item-info_edit",
},
{
showOutside: false,
show: true,
icon: "default",
title: "حذف",
to: {
name: "undefined",
},
selected: false,
disabled: false,
howToOpen: "",
href: "",
class: "delete-btn",
action: "delete-table-item",
can: "item-list_delete",
},
];
},
},
},
emits: [
"open-form",
"delete-table-item",
"reset-form",
"search",
"show-summary",
"edit-table-item",
"page-changed",
"show-details",
],
mounted() {
// this.cloneItems = structuredClone(this.items);
this.cloneItems = this.items;
if (this.cloneItems)
this.cloneItems?.forEach((item, index) => {
if ("_source" in item)
this.cloneItems[index] = { ...item, ...item._source };
});
},
watch: {
items: {
handler(newVal) {
// this.cloneItems = structuredClone(newVal);
this.cloneItems = newVal;
if (!this.cloneItems) return;
this.cloneItems?.forEach((item, index) => {
if ("_source" in item)
this.cloneItems[index] = { ...item, ...item._source };
});
},
nested: true,
immediate: true,
},
},
data() {
return {
// sort
prevSelectedItemIndex: undefined,
prevColumn: undefined,
showDetailsPanel: false,
dragging: false,
sortOrderIndicator: 0,
page: 1,
typingTimer: 0,
doneTypingInterval: 1000,
sortOrder: {
0: "asc",
1: "desc",
2: undefined,
},
selectedItem: {},
selectedItemClone: {},
searchForm: {
query: "",
},
myTableActions: this.tableActions,
cloneItems: [],
};
},
computed: {
...mapState("list", ["selectedProjectGetter"]),
tHead() {
return Object.values(this.tableColumns);
},
tBody() {
return Object.keys(this.tableColumns);
},
},
methods: {
/**
* محاسبه مقدار در جدول براساس کلید مشخص شده و در صورت نیاز کوتاه کردن آن.
* @param {Object} rowItem - آیتم های ردیف جدول.
* @param {String} key - کلید مورد نظر برای بازیابی مقدار.
* @param {Number} [trancate_word=0] - تعداد کلمات حداکثر برای کوتاه کردن مقدار.
* @returns {String} - مقدار محاسبه شده .
*/
getCellValue(rowItem, column) {
let key = column.key;
let trancate_word = column?.trancate_word;
let value = "";
// ///////////////////////////////
if ("highlight" in rowItem && key in rowItem.highlight) {
if (Array.isArray(rowItem.highlight[key]))
value = rowItem.highlight[key][0];
else value = rowItem.highlight[key];
return value;
}
////////////////////////////////
// برای مقادیر فیلد خاص از یک آبجکت مثل :
// other_info__full_path == other_info -- > full_path
key = key.replace("__", ".");
if (key.includes(".")) {
let keys = key.split(".");
for (let i = 0; i < keys.length - 1; i++)
if (rowItem[keys[i]]) rowItem = rowItem[keys[i]];
key = keys[keys.length - 1];
}
/////////////////////////////////
if (rowItem[key]) value = rowItem[key];
if (trancate_word && trancate_word > 0) {
let words = value.split(" ");
if (words.length > trancate_word) {
value = words.slice(0, trancate_word).join(" ");
value += "...";
}
}
// برای وقتی که با یک محاسبه خاص مقدار برگردانده شود ، مثلا تعداد یک آرایه یا طول یک متن
if (column?.process) {
if (column.process == "len") return value.length;
else if (column.process == "convert_date") {
let date = new Date(value);
if (value.toString().length == 10) {
date = new Date(value * 1000);
}
return date.toLocaleDateString("fa-IR");
// return moment(value).format("jYYYY/jMM/jDD");
} else if (column.process == "convert_gdate") {
let date = new Date(value);
return date.toLocaleDateString("fa-IR");
}
}
if (column?.colors) {
if (value in column?.colors) {
value =
`<span style="color:${column?.colors[value]}">` + value + "</span>";
}
}
return value;
},
...mapActions("list", ["SET_SELECTED_ITEM", "SET_LIST"]),
...mapActions("entity", ["SET_ITEM_ENTITY", "SET_LIST_ENTITY"]),
handlerActions(item, rowAction, index, items) {
this.$emit("actions", {
item: item,
index: index,
items: items,
rowAction: rowAction,
});
// if (rowAction.key == "tbookmark")
// this.updateListAnswer(index, "tbookmark", 0);
},
updateListAnswer(index, key, value) {
// if (index in this.cloneItems) {
// if (key in this.cloneItems[index]["_source"])
// this.cloneItems[index]["_source"][key] = value;
// }
},
/**
* بررسی غیرفعال بودن آیتم.
* @param {Object} item - آیتم مورد نظر برای بررسی کلاس غیرفعال بودن
* @returns {boolean} - نتیجه بررسی کلاس غیرفعال بودن آیتم
*/
getUnactiveClass(item) {
let key = "is_active";
if ("islock" in item) key = "islock";
if (item[key] == undefined) return false;
else if (item[key] == 1) return true;
else if (item[key] == 0) return false;
},
/**
* مرتبسازی بر اساس ستون انتخاب شده.
* @param {Object} col - ستون برای مرتبسازی
*/
sortBy(col) {
// تنظیم مجدد به حالت صعودی اگر شماره نشانگر بیشتر از یک باشد
if (this.sortOrderIndicator > 1) this.sortOrderIndicator = 0;
// اگر ستون جدید انتخاب شده‌است، سفارش مرتب‌سازی ستون قبلی را پاک کنید و نشانگر مرتب‌سازی را دوباره تنظیم کنید
if (this.prevColumn && col.key != this.prevColumn.key) {
this.prevColumn.sortorder = undefined;
this.sortOrderIndicator = 0;
}
// به روز رسانی ستون جدول قبلی
this.prevColumn = col;
// به روز رسانی سفارش مرتب‌سازی فعلی ستون
col["sortorder"] = this.sortOrder[this.sortOrderIndicator];
// ارسال اطلاعات مرتب‌سازی به کامپوننت والد
this.$emit("sort-changed", {
sortby: col.key,
sortorder: this.sortOrder[this.sortOrderIndicator],
});
// افزایش یک واحد به شمارنده نشانگر مرتب‌سازی
this.sortOrderIndicator += 1;
},
/**
* انجام عملیات مربوط به دکمههای خارج از context menu (showOutside == true).
* @param {string} action - عملیات مورد نظر
* @param {number} index - اندیس مورد نظر
*/
methodName(action, data) {
// event.preventDefault();
if (action && action != "actions") {
try {
this[action](data);
} catch (err) {
if (action == "on-linked-title-click") this.$emit(action, data);
// "edit-table-item" , "delete-table-item"
else this.$emit(action, data.index);
}
} else {
//این حالت از بک اند می آید معمولا
data["items"] = this.cloneItems;
this.$emit("actions", data);
}
},
/**
* نمایش صفحه متنی.
* @param {number} index - اندیس مورد نظر
*/
showText(index) {
if (!this.cloneItems) return;
const clickedItem = this.markActive(index);
this.cloneItems?.forEach((element) => {
element["_id"] = element["id_store"];
});
this.SET_ITEM_ENTITY(this.cloneItems[index]);
this.SET_LIST_ENTITY(this.cloneItems);
localStorage.setItem("myList", JSON.stringify(this.cloneItems));
localStorage.setItem("myItem", JSON.stringify(this.cloneItems[index]));
let pageTitle = clickedItem.title ?? "بدون عنوان";
pageTitle = pageTitle.replaceAll(" ", "-");
const routeData = this.$router.resolve({
name: "navigation",
params: {
id: clickedItem.id_store,
key: this.selectedProjectGetter.index_name,
},
query: {
searchtext: this.pageTitle ?? undefined,
},
});
window.open(routeData.href, "_blank");
},
/**
* نمایش جزئیات آیتم انتخاب شده.
* @param {number} index - اندیس مورد نظر
*/
showDetails(index) {
this.SET_SELECTED_ITEM(this.markActive(index));
this.showDetailsPanel = !this.showDetailsPanel;
this.$emit("show-details", {
show: this.showDetailsPanel,
rowItem: this.markActive(index),
index,
});
},
/**
* نمایش فرم موضوع در صفحه لیست.
* @param {number} index - اندیس مورد نظر
*/
showSubjectForm(index) {
this.$emit("show-subject-form", { rowItem: this.markActive(index) });
},
/**
* حذف آیتم با شناسه مشخص شده.
* @param {string} itemId - شناسه آیتم برای حذف
*/
deleteItem(itemId) {
this.$emit("delete-item", itemId);
},
/**
* تغییر وضعیت پنل.
* @param {number} index - اندیس مورد نظر
*/
togglePanel(index = undefined) {
this.$emit("open-form", this.markActive(index));
},
/**
* تنظیم مجدد فرم.
*/
resetForm() {
this.searchForm.query = "";
this.$emit("reset-form");
},
/**
* جستجو با استفاده از فرم.
*/
search() {
clearTimeout(this.typingTimer);
this.typingTimer = setTimeout(() => {
this.$emit("search", this.searchForm.query);
}, this.doneTypingInterval);
},
/**
* اعمال عملیاتی هنگامی که دکمه کیبورد فشرده شدهاست.
*/
onKeyDown() {
clearTimeout(this.typingTimer);
},
/**
* تغییر در محدوده صفحهبندی.
* @param {Object} paging - اطلاعات مربوط به صفحهبندی
*/
limitChanged(paging) {
this.$emit("page-limit-changed", paging);
},
/**
* فراخوانی بازخوردی پس از کلیک بر روی صفحهبندی.
* @param {Object} paging - اطلاعات مربوط به صفحهبندی
*/
clickCallback(paging) {
this.$emit("page-changed", paging);
},
/**
* علامت گذاری آیتم فعال.
* @param {number} index - اندیس مورد نظر
* @returns {Object} - کپی آیتم فعال
*/
markActive(index) {
if (this.prevSelectedItemIndex !== undefined) {
this.cloneItems[this.prevSelectedItemIndex]["active"] = false;
}
this.prevSelectedItemIndex = index;
this.cloneItems[index]["active"] = true;
// this.selectedItemClone = structuredClone(this.cloneItems[index]);
this.selectedItemClone = this.cloneItems[index];
return this.selectedItemClone;
},
/**
* شروع هندل کردن draggable
* @param {Event} e - رویداد مربوطه
*/
handleDragStart(e) {
e.originalEvent.dataTransfer.setData(
"text",
e.clone.children[1].innerHTML
);
e.originalEvent.dataTransfer.setDragImage(new Image(), 0, 0);
},
clickManagementTableColumns(tableColumn) {
if (this.showHeaderSortButton) {
this.sortBy(tableColumn);
} else {
if (this.activeTableColumnTitle) {
this.$emit("click-table-column-title", tableColumn);
}
}
},
},
components: {
draggable: VueDraggableNext,
},
};
</script>
<style lang="scss">
.my-handle {
cursor: move;
}
.sort-indicator {
.tavasi-sort {
opacity: 0.3;
}
&:hover .tavasi-chevron-sort {
opacity: 0.5;
}
.tavasi-desc,
.tavasi-chevron-sort-desc {
display: none;
}
.tavasi-asce,
.tavasi-chevron-sort-asce {
display: none;
}
&:hover .tavasi-sort {
opacity: 0.5;
}
&:hover .tavasi-chevron-sort {
opacity: 1;
}
&.desc {
.tavasi-sort,
.tavasi-chevron-sort {
display: none;
}
.tavasi-desc,
.tavasi-chevron-sort-desc {
display: inline;
}
.tavasi-asce,
.tavasi-chevron-sort-asce {
display: none;
}
}
&.asc {
.tavasi-sort,
.tavasi-chevron-sort {
display: none;
}
.tavasi-desc,
.tavasi-chevron-sort-desc {
display: none;
}
.tavasi-asce,
.tavasi-chevron-sort-asce {
display: inline;
}
}
}
.show-text-decoration {
&:hover {
text-decoration: underline;
}
}
.thead {
z-index: 1;
}
// .sortable-ghost {
// visibility: hidden;
// opacity: 0;
// display: none;
// }
// .sortable-choosen {
// visibility: hidden;
// opacity: 0;
// display: none;
// }
.action-column {
svg {
font-size: 0.8rem !important;
}
span {
font-size: 1.3rem !important;
}
&:hover {
color: var(--primary-color) !important;
}
}
.cursor-title {
cursor: pointer;
}
.column-highlight-active {
th,
td {
border: 1px solid #ccc;
text-align: center;
padding: 8px;
}
}
</style>