<template> <div class="menu-bar__content menu-bar-content home-list p-3"> <Breadcrumbs /> <div class="home-list__header pt-3 pb-0"> <div class="flex-grow-1"> <form class="search-form mx-0 w-100" role="search" @submit.prevent="sendQuery" > <div class="form-group"> <div class="d-flex"> <select v-model="listTypeId" class="form-control" @change="getList()" > <option v-for="subject in subjects" :key="subject.id" :value="subject.id" > {{ subject.title }} </option> </select> <div class="context-menu-dropdown"> <div class="dropdown"> <button class="btn pl-0" type="button" id="dropdownMenu2" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" > <i class="tavasi tavasi-Component-281--1"></i> </button> <div class="dropdown-menu" aria-labelledby="dropdownMenu2"> <button class="dropdown-item text-right" @click.prevent="showReplaceInput = !showReplaceInput" type="button" > <i class="tavasi tavasi-Component-78--9---2" ><span class="path1"></span><span class="path2"></span ></i> جستجو </button> <button data-toggle="modal" data-target="#new-item-modal" @click.prevent="openModal()" class="dropdown-item text-right" type="button" > <span class="tavasi tavasi-Component-133--1"></span> <!-- <span class="tavasi tavasi-add"></span> --> پوشه جدید </button> </div> </div> </div> </div> </div> <div v-if="showReplaceInput" class="form-group"> <div class="input-group"> <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="sendQuery()" @keydown="onKeyDown()" /> <div class="input-group-append"> <button @click="showReplaceInput = !showReplaceInput" type="button" class="input-group-text show-reset-btn" id="basic-addon1" > <i class="tavasi tavasi-Component-294--1"></i> </button> </div> </div> </div> </form> </div> </div> <div class="home-list__content scroll-needed" :class="{ loading: loading }"> <div class="last-search h-100"> <div class="last-search-content h-100"> <div v-if="list.length"> <div class="item mb-3 prev-level" v-if="meta.length"> <!-- <span style="font-size: 1.1rem;" class="tavasi tavasi-Component-71--1 ml-2"></span>--> <div v-for="(metaItem, index) in meta"> <a :key="metaItem.id" @click.prevent="getList(metaItem.parent)" :href="metaItem.title" class="title d-flex " :title="metaItem.title" > {{ metaItem.title }} </a> <span style="font-size: 1.4rem;" v-if="index < meta.length - 1" class="tavasi tavasi-arrow-down" ></span> </div> </div> <div v-for="(item, index) in list" :key="item.title" class="item"> <draggable :sort="false" :disabled="false" group="people" @add="onDrop($event, item)" > <div class="d-flex position-relative" :class="{ 'is-selected': item?.isSelected }" > <rename-form v-if=" item?.editMode && item?.parentComponent === 'subjectPanel' " :title="item.title" :loading="loading" @closeForm="item.editMode = false" @saveChanges="editItem($event, item, list)" ></rename-form> <div v-else> <a v-if="item.children" @click.prevent="getListChildren(item, index)" :href="item.title" class="title" :title="item.title" > <span v-if="item.children?.length" class="tavasi tavasi-remove" ></span> <!-- <span v-else class="tavasi tavasi-add"></span> --> <span v-else class="tavasi tavasi-Component-133--1" ></span> </a> <a :class="{ active: item?.active ?? false }" @click.prevent="getItems(item, index)" :href="item.title" class="title" :title="item.title" > <i v-if="!item.children || item.children.length === 0" class="tavasi tavasi-Component-149--3" ></i> <!-- <i v-if="item.children === 0" class="tavasi tavasi-Component-149--3"></i>--> <!-- <i v-else class="tavasi tavasi-Component-360--58">--> <!-- <span class="path1"></span>--> <!-- <span class="path2"></span>--> <!-- </i>--> {{ item.title }} </a> <div v-if="!item?.isSelected"> <context-menu :parentComponent="'subjectPanel'" :list="list" :clickedItem="item" :contextMenu="contextMenu" @remove-item="removeItem(item, list)" > </context-menu> </div> </div> </div> <ul v-if="Array.isArray(item.children)" class="children"> <li class="position-relative" v-for="(child, childIndex) in item.children" :key="child.title" > <rename-form v-if=" child?.editMode && child?.parentComponent === 'subjectPanel' " :title="child.title" :loading="loading" @closeForm="child.editMode = false" @saveChanges="editItem($event, child, item.children)" ></rename-form> <div v-else> <a @click.prevent="getItems(child, childIndex)" :href="child.title" class="title" :title="child.title" > <i v-if="child.children === 0" class="tavasi tavasi-Component-149--3" ></i> <i v-else class="tavasi tavasi-Component-360--58"> <span class="path1"></span> <span class="path2"></span> </i> {{ child.title }} </a> <div v-if="!child?.isSelected"> <context-menu :parentComponent="'subjectPanel'" :list="item.children" :clickedItem="child" :contextMenu="contextMenu" @remove-item="removeItem(child, item.children)" > </context-menu> </div> </div> </li> </ul> </draggable> </div> </div> <no-data v-else /> </div> <!-- <div class="last-search-footer" v-if="list.length > 0">--> <!-- <button class="btn last-search-more-btn" type="button">بیشتر</button>--> <!-- </div>--> </div> </div> <div v-if="showModal"> <NewListModal :listTypeId="listTypeId" :selectedItem="selectedItem" :parentId="parentId" @close-modal="closeModal" @delete-item="updateList" @update-list="updateList" /> </div> </div> </template> <script> import apis from "~/apis/listApi"; export default { props: ["items", "subjectId", "index"], emits: ["list-changed", "list-item-changed"], data() { return { contextMenu: [], subjects: [ { id: 0, title: "موضوعات", }, { id: 1, title: "نمایه", disabled: true, }, { id: 2, title: "برچسب", disabled: true, }, ], showModal: false, prevSelectedItemIndex: undefined, prevItem: undefined, meta: [], projects: [], list: [], listItem: [], listTypeId: 0, parentId: undefined, selectedItem: {}, typingTimer: 0, doneTypingInterval: 1000, cloneItems: [], loading: false, searchForm: { query: "", }, editMode: false, showReplaceInput: false, }; }, methods: { getListItem(subjectId, index) { this.markActive(index); if (this.fetchingData) return; this.fetchingData = true; const payload = { // projectid: this.listTypeId, bychilds: 0, projectid: 1, subjectid: this.subjectId, ...this.pagination, }; ApiService.formData(apis.subjectRelation.list, payload) .then((res) => { this.listItem = res.data.data; this.listItem.forEach((item, index) => { Object.keys(item).forEach((value, key) => { if (value === "resource") { item[value] = this.getProjectTitle(item[value]); } }); }); this.pagination = {...this.pagination,...res.data.pagination}; }) .finally(() => { this.fetchingData = false; }); }, addItemToList(itemId, listId) { const payload = { itemid: itemId, listid: listId, listtype: this.listTypeId, projectid: 1, }; ApiService.formData(apis.subject.add, payload).then((res) => { this.mySwalToast({ title: "تبریک", html: res.data.message, icon: "success", }); }); }, removeItem(listItem, listArray) { this.mySwalConfirm({ title: "هشدار!!!", html: `از حذف <b>${listItem.title}</b> اطمینان دارید؟ `, icon: "warning", }).then((result) => { if (result.isConfirmed) { const payload = { subjectid: listItem.id, }; ApiService.formData(apis.subject.delete, payload) .then((res) => { this.mySwalToast({ html: res.data.message, icon: "success", }); const indexOfList = listArray.findIndex( (item) => item.id === listItem.id ); listArray.splice(indexOfList, 1); }) .catch((err) => { this.mySwalToast({ title: "خطا!!!", html: err.message, icon: "error", }); }); } }); }, editItem(newTitle, subject, subjectArray) { if (this.loading) return; this.loading = true; const model = { title: newTitle, subjectid: subject.id, newparent: subject.parent ? subject.parent : 0, }; ApiService.formData(apis.subject.edit, model) .then((res) => { list.editMode = false; const resultIndex = subjectArray.findIndex( (item) => subject.id === item.id ); if (resultIndex > -1) { this.$set(subjectArray[resultIndex], "title", newTitle); } this.mySwalToast({ title: "تبریک", html: res.data.message, icon: "success", }); }) .catch((err) => { this.mySwalToast({ title: "خطا!!!", html: err?.message, icon: "error", }); }) .finally(() => (this.loading = false)); }, getListChildren(item, index) { if (Array.isArray(item.children)) { item = { ...item, ...{ children: item.children.length } }; this.$set(this.list, index, item); } else { const payload = { parent: item.id, sortby: "id", offset: 0, limit: 100, listtype: this.listTypeId, projectid: 1, }; ApiService.formData(apis.subject.list, payload).then((res) => { item = { ...item, ...{ children: res.data.data } }; this.$set(this.list, index, item); }); } }, getItems(item, index) { if (Array.isArray(item.children)) { this.$emit("set-selected-list", item.children[0]); this.getListItem(item.children[0].id, index); } else if (item.children > 0) { this.parentId = item.id; this.$emit("set-selected-list", item); this.getList(item.id); } else { this.$emit("set-selected-list", item); this.getListItem(item.id, index); } }, getList(parent = 0) { const payload = { parent: parent, sortby: "id", offset: 0, limit: 100, listtype: this.listTypeId, projectid: 1, }; ApiService.formData(apis.subject.list, payload).then((res) => { this.list = res.data.data; this.meta = res.data?.meta ?? []; this.$emit("list-changed", { subjectId: parent, listTypeId: this.listTypeId, }); // if (res.data.meta) // this.meta = res.data.meta.filter((item, index) => index > 0); }); }, updateList() { this.resetPagination(); this.closeModal(); this.getList(this.parentId); }, resetPagination() { this.pagination = { pages: 0, total: 0, page: 1, offset: 0,// page * per_page limit: 50//per_page } }, markActive(index) { if (this.prevSelectedItemIndex !== undefined) { this.$set(this.list[this.prevSelectedItemIndex], "active", false); } this.prevSelectedItemIndex = index; this.$set(this.list[index], "active", true); }, sendQuery() { // todo: show loading. // todo: send query and show result. // todo: hide loading. clearTimeout(this.typingTimer); this.typingTimer = setTimeout(() => { // request data from api }, this.doneTypingInterval); }, onKeyDown() { clearTimeout(this.typingTimer); }, resetForm() { this.searchForm.query = ""; this.searchForm.replaceWith = ""; this.cloneItems = structuredClone(this.items); }, onDrop(ev, list) { const itemId = ev.item["_underlying_vm_"]["id"]; const listId = list.id; this.addItemToList(itemId, listId); }, closeModal() { $("#new-item-modal").modal("hide"); setTimeout(() => { this.showModal = false; }, 500); }, openModal() { this.showModal = true; setTimeout(() => { $("#new-item-modal").modal( { backdrop: "static", keyboard: false }, "show" ); }, 500); }, }, mounted() { this.this.contextMenu = require(`~/json//subjectContextMenu.json`).filter( (item) => item.show ); }, }; </script> <style scoped lang="scss"> .menu-bar__content { position: static; flex: 1 1 100%; max-width: 305px; width: auto; } .home-list__content { /*max-height: calc(100vh - 12em);*/ height: calc(100vh - 8em); position: relative; overflow-x: hidden; padding-left: 0.3em; &.loading { //background-image: url('./img/item-loading.svg'); background-repeat: repeat-y; background-position: top right; background-size: 12em; &::before { content: ""; clear: both; position: absolute; right: 0; width: 0.5em; height: 100%; background-color: #fff; animation-name: example; animation-duration: 2s; animation-fill-mode: forwards; animation-iteration-count: infinite; animation-timing-function: ease-in-out; } } } </style>