<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>