2025-02-01 09:34:55 +00:00
|
|
|
<template>
|
2025-02-20 06:22:41 +00:00
|
|
|
<NuxtLayout name="default" :menu="adminMenu">
|
2025-02-01 09:34:55 +00:00
|
|
|
<div>
|
|
|
|
<!-- <header>
|
|
|
|
<the-navbar></the-navbar>
|
2025-02-20 06:22:41 +00:00
|
|
|
</header> -->
|
|
|
|
|
2025-02-01 09:34:55 +00:00
|
|
|
|
|
|
|
<main class="pages-content-container">
|
|
|
|
<div class="pages-content mt-4 mt-lg-0">
|
|
|
|
<div class="p-3" :class="{ 'd-flex': showPanel }">
|
|
|
|
<div v-if="canView">
|
|
|
|
<my-table
|
|
|
|
:tableActions="tableActions"
|
|
|
|
height="calc(100vh - 17em)"
|
|
|
|
:hasSearch="true"
|
|
|
|
minHeight="25em"
|
|
|
|
maxHeight="calc(100dvh - 5em)"
|
|
|
|
:paginationInfo="pagination"
|
|
|
|
:sortingInfo="sorting"
|
|
|
|
:items="groups"
|
|
|
|
:fetchingData="fetchingData"
|
|
|
|
:tableColumns="tableColumns"
|
|
|
|
:totalPages="pagination.pages"
|
|
|
|
@search="searchGroups"
|
|
|
|
@reset-form="searchGroups"
|
|
|
|
@delete-table-item="deleteItem"
|
|
|
|
@edit-table-item="toggleUsersPanel"
|
|
|
|
@page-changed="pageChanged"
|
|
|
|
@page-limit-changed="pageLimitChanged"
|
|
|
|
@sort-changed="sortChanged"
|
|
|
|
>
|
2025-02-20 06:22:41 +00:00
|
|
|
|
|
|
|
<template v-slot:tableHeaderActions>
|
2025-02-01 09:34:55 +00:00
|
|
|
<div class="dropdown">
|
|
|
|
<button
|
|
|
|
class="btn dropdown-toggle"
|
|
|
|
type="button"
|
|
|
|
data-bs-toggle="dropdown"
|
|
|
|
aria-expanded="false"
|
|
|
|
>
|
|
|
|
{{ groupsTranslation[searchType] }}
|
|
|
|
</button>
|
|
|
|
<div class="dropdown-menu text-end">
|
|
|
|
<button
|
|
|
|
class="dropdown-item"
|
|
|
|
type="button"
|
|
|
|
@click.prevent="setSearchType('getGroupsWithoutAdmin')"
|
|
|
|
:class="{ active: searchType == 'getGroupsWithoutAdmin' }"
|
|
|
|
value="getGroupsWithoutAdmin"
|
|
|
|
>
|
|
|
|
{{ groupsTranslation["getGroupsWithoutAdmin"] }}
|
|
|
|
</button>
|
|
|
|
<button
|
|
|
|
class="dropdown-item"
|
|
|
|
type="button"
|
|
|
|
@click.prevent="setSearchType('getGroupsWithAdmin')"
|
|
|
|
:class="{ active: searchType == 'getGroupsWithAdmin' }"
|
|
|
|
value="getGroupsWithAdmin"
|
|
|
|
>
|
|
|
|
{{ groupsTranslation["getGroupsWithAdmin"] }}
|
|
|
|
</button>
|
|
|
|
</div>
|
|
|
|
</div>
|
2025-02-20 06:22:41 +00:00
|
|
|
</template>
|
2025-02-01 09:34:55 +00:00
|
|
|
</my-table>
|
|
|
|
</div>
|
|
|
|
<no-data v-else>
|
|
|
|
<the-content-loading v-if="fetchingData"></the-content-loading>
|
|
|
|
|
|
|
|
<div
|
|
|
|
v-else
|
|
|
|
class="d-flex justify-content-center align-items-center"
|
|
|
|
>
|
|
|
|
<div
|
|
|
|
class="alert alert-warning d-flex justify-content-center align-items-center"
|
|
|
|
>
|
|
|
|
<span
|
|
|
|
class="tavasi tavasi-warning-circle color-inherit ms-1 text__32"
|
|
|
|
></span>
|
|
|
|
عدم دسترسی
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</no-data>
|
|
|
|
<div class="side-panel" v-if="showPanel">
|
|
|
|
<div
|
|
|
|
class="side-panel-header d-flex mb-3 pb-3 border-bottom align-items-center"
|
|
|
|
>
|
|
|
|
<h5 class="m-0">جستجو و انتخاب مدیر گروه</h5>
|
|
|
|
|
|
|
|
<button
|
|
|
|
@click.prevent="toggleUsersPanel(undefined)"
|
|
|
|
class="btn me-auto"
|
|
|
|
type="button"
|
|
|
|
>
|
|
|
|
<svg class="icon icon-Component-294--1">
|
|
|
|
<use xlink:href="#icon-Component-294--1"></use>
|
|
|
|
</svg>
|
|
|
|
</button>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div class="side-panel-content">
|
2025-02-20 06:22:41 +00:00
|
|
|
<UsersSearch
|
2025-02-01 09:34:55 +00:00
|
|
|
v-if="showPanel"
|
|
|
|
:searchResults="users"
|
|
|
|
@on-send="searchUsers"
|
|
|
|
@set-as-admin="setAsAdmin"
|
2025-02-20 06:22:41 +00:00
|
|
|
></UsersSearch>
|
2025-02-01 09:34:55 +00:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</main>
|
|
|
|
</div>
|
2025-02-20 06:22:41 +00:00
|
|
|
</NuxtLayout>
|
2025-02-01 09:34:55 +00:00
|
|
|
</template>
|
|
|
|
|
|
|
|
<script>
|
|
|
|
import { mapState, mapActions } from "pinia";
|
2025-02-20 06:22:41 +00:00
|
|
|
import adminMenu from "~/json/admin/json/menu.json";
|
|
|
|
// import menu from "~/json/admin/json/menu.json";
|
2025-02-01 09:34:55 +00:00
|
|
|
import adminApi from "~/apis/adminApi";
|
|
|
|
import permitApis from "~/apis/permitApi";
|
2025-02-20 06:22:41 +00:00
|
|
|
import { defineAsyncComponent } from "vue";
|
|
|
|
import { useCommonStore } from "~/stores/commonStore";
|
|
|
|
import { usePermitStore } from "~/stores/permitStore";
|
2025-02-01 09:34:55 +00:00
|
|
|
export default {
|
|
|
|
name: "groupsWithoutAdmin",
|
|
|
|
setup() {
|
|
|
|
definePageMeta({
|
|
|
|
name: "groupsWithoutAdmin",
|
2025-02-20 06:22:41 +00:00
|
|
|
layout: false,
|
2025-02-01 09:34:55 +00:00
|
|
|
});
|
|
|
|
},
|
|
|
|
beforeMount() {
|
2025-02-20 06:22:41 +00:00
|
|
|
// this.httpService = new HttpService(import.meta.env.VITE_BASE_URL);
|
|
|
|
this.httpService = useNuxtApp()["$http"];
|
|
|
|
|
2025-02-01 09:34:55 +00:00
|
|
|
},
|
2025-02-20 06:22:41 +00:00
|
|
|
|
2025-02-01 09:34:55 +00:00
|
|
|
mounted() {
|
|
|
|
this.checkPermisionBeforGetList();
|
|
|
|
},
|
|
|
|
data() {
|
|
|
|
return {
|
2025-02-20 06:22:41 +00:00
|
|
|
adminMenu: adminMenu,
|
2025-02-01 09:34:55 +00:00
|
|
|
searchType: "getGroupsWithoutAdmin",
|
|
|
|
groupsTranslation: {
|
|
|
|
getGroupsWithoutAdmin: "گروه های بدون مدیر",
|
|
|
|
getGroupsWithAdmin: "گروه های دارای مدیر",
|
|
|
|
},
|
|
|
|
groups: [],
|
2025-02-20 06:22:41 +00:00
|
|
|
// menu: menu,
|
2025-02-01 09:34:55 +00:00
|
|
|
firstTimeSearching: false,
|
|
|
|
httpService: undefined,
|
|
|
|
tableActions: [
|
|
|
|
{
|
|
|
|
showOutside: true,
|
|
|
|
show: true,
|
|
|
|
icon: "tavasi tavasi-Component-242--1",
|
|
|
|
title: "تعیین مدیر",
|
|
|
|
to: {
|
|
|
|
name: "undefined",
|
|
|
|
},
|
|
|
|
selected: false,
|
|
|
|
disabled: false,
|
|
|
|
howToOpen: "",
|
|
|
|
href: "",
|
|
|
|
class: "edit-btn",
|
|
|
|
action: "edit-table-item",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
showOutside: true,
|
|
|
|
show: true,
|
|
|
|
icon: "tavasi tavasi-Component-295--1",
|
|
|
|
title: "حذف",
|
|
|
|
to: {
|
|
|
|
name: "undefined",
|
|
|
|
},
|
|
|
|
selected: false,
|
|
|
|
disabled: false,
|
|
|
|
howToOpen: "",
|
|
|
|
href: "",
|
|
|
|
class: "delete-btn",
|
|
|
|
action: "delete-table-item",
|
|
|
|
},
|
|
|
|
],
|
|
|
|
canView: false,
|
|
|
|
fetchingData: false,
|
|
|
|
tableColumns: [
|
|
|
|
{
|
|
|
|
isLink: true,
|
|
|
|
key: "title",
|
|
|
|
title: "عنوان",
|
|
|
|
width: "2",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
isLink: true,
|
|
|
|
key: "desc",
|
|
|
|
title: "توضیحات",
|
|
|
|
width: "2",
|
|
|
|
},
|
|
|
|
],
|
|
|
|
pagination: {
|
|
|
|
page: 1,
|
|
|
|
pages: 0,
|
|
|
|
total: 0,
|
|
|
|
offset: 0,
|
|
|
|
limit: 10,
|
|
|
|
},
|
|
|
|
sorting: {
|
|
|
|
sortby: "title",
|
|
|
|
sortorder: "asc", // asc | desc | none
|
|
|
|
},
|
|
|
|
users: [],
|
|
|
|
loading: false,
|
|
|
|
showPanel: false,
|
|
|
|
selectedItemClone: undefined,
|
|
|
|
|
|
|
|
prevSelectedItemIndex: undefined,
|
|
|
|
};
|
|
|
|
},
|
2025-02-20 06:22:41 +00:00
|
|
|
computed: {
|
|
|
|
...mapState(usePermitStore, ["projectGetter"]),
|
|
|
|
...mapState(useCommonStore, ["isSidebarCollapsed"]),
|
|
|
|
// ...mapState(["isSidebarCollapsed"]),
|
|
|
|
},
|
2025-02-01 09:34:55 +00:00
|
|
|
methods: {
|
2025-02-20 06:22:41 +00:00
|
|
|
// ...mapState(["isSidebarCollapsed"]),
|
|
|
|
// ...mapActions(["checkPermissions"]),
|
|
|
|
...mapActions(useCommonStore, ["checkPermissions"]),
|
|
|
|
|
2025-02-01 09:34:55 +00:00
|
|
|
|
|
|
|
checkPermisionBeforGetList() {
|
|
|
|
if (this.fetchingData) return;
|
|
|
|
this.fetchingData = true;
|
|
|
|
|
|
|
|
this.checkPermissions({ _this: this, permission: "groups_view" })
|
|
|
|
.then(() => {
|
|
|
|
this.getGroupsWithoutAdmin()
|
|
|
|
.then(() => {
|
|
|
|
this.canView = true;
|
|
|
|
this.fetchingData = false;
|
|
|
|
})
|
|
|
|
.catch(() => {
|
|
|
|
this.canView = false;
|
|
|
|
this.fetchingData = false;
|
|
|
|
});
|
|
|
|
})
|
|
|
|
.catch(() => {
|
|
|
|
this.canView = false;
|
|
|
|
this.fetchingData = false;
|
|
|
|
});
|
|
|
|
},
|
|
|
|
async getGroupsWithoutAdmin(query = "") {
|
|
|
|
let url = `${messageUrl()}/${adminApi.groups.groupsWithoutAdmin}`;
|
|
|
|
|
|
|
|
return await this.httpService
|
|
|
|
.getRequest(this.updateUrl(url, query))
|
|
|
|
.then((res) => {
|
|
|
|
this.groups = res.data;
|
|
|
|
this.pagination = { ...this.pagination, ...res.pagination };
|
|
|
|
});
|
|
|
|
},
|
|
|
|
getGroupsWithAdmin() {
|
|
|
|
if (this.fetchingData) return;
|
|
|
|
this.fetchingData = true;
|
|
|
|
|
|
|
|
let url = `${messageUrl()}/${adminApi.groups.groupsWithAdmin}`;
|
|
|
|
|
|
|
|
this.httpService
|
|
|
|
.getRequest(this.updateUrl(url))
|
|
|
|
.then((response) => {
|
|
|
|
this.groups = response.data;
|
|
|
|
this.pagination = { ...this.pagination, ...response.pagination };
|
|
|
|
})
|
|
|
|
|
|
|
|
.finally(() => {
|
|
|
|
this.fetchingData = false;
|
|
|
|
});
|
|
|
|
},
|
|
|
|
updateUrl(url, query = "") {
|
|
|
|
url = url.replace("@offset", this.pagination.offset);
|
|
|
|
url = url.replace("@limit", this.pagination.limit);
|
|
|
|
url = url.replace("@sortby", this.sorting.sortby);
|
|
|
|
url = url.replace("@sortorder", this.sorting.sortorder);
|
|
|
|
|
|
|
|
// for searching groups.
|
|
|
|
if (query?.length) url = url.replace("@query", query);
|
|
|
|
else url = url.replace("/@query", query);
|
|
|
|
return url;
|
|
|
|
},
|
|
|
|
async searchUsers(query = "") {
|
|
|
|
// this.resetPagination();
|
|
|
|
|
|
|
|
let url = loginUrl() + permitApis.users.search;
|
|
|
|
url = url.replace("{{offset}}", 0);
|
|
|
|
url = url.replace("{{limit}}", 50);
|
|
|
|
url = url.replace("{{sortby}}", "username");
|
|
|
|
url = url.replace("{{sortorder}}", "desc");
|
|
|
|
|
|
|
|
// removing '/' before query if query is empty.
|
|
|
|
if (query) url = url.replace("{{query}}", query);
|
|
|
|
else url = url.replace("/{{query}}", query);
|
|
|
|
|
|
|
|
return await this.httpService.getRequest(url).then((res) => {
|
|
|
|
this.users = res.data;
|
|
|
|
// this.pagination = { ...this.pagination, ...res.pagination };
|
|
|
|
});
|
|
|
|
},
|
|
|
|
// searchUsers(query = "") {
|
|
|
|
// this.resetPagination();
|
|
|
|
// this[this.searchType](query);
|
|
|
|
|
|
|
|
// // this.getGroupsWithoutAdmin(query);
|
|
|
|
// },
|
|
|
|
searchGroups(query) {
|
|
|
|
this.resetPagination();
|
|
|
|
this[this.searchType](query);
|
|
|
|
},
|
|
|
|
setSearchType(groupType) {
|
|
|
|
this.searchType = groupType;
|
|
|
|
|
|
|
|
this.resetPagination();
|
|
|
|
this[groupType]();
|
|
|
|
},
|
|
|
|
|
|
|
|
removeGroupMember() {},
|
|
|
|
setAsAdmin(user) {
|
|
|
|
if (this.loading) return;
|
|
|
|
this.loading = true;
|
|
|
|
|
|
|
|
const url = messageUrl() + "/" + chatApi.groups.setAdmin;
|
|
|
|
|
|
|
|
let payload = {
|
|
|
|
user_id: user.id,
|
|
|
|
group_id: this.selectedItemClone.id,
|
|
|
|
};
|
|
|
|
|
|
|
|
this.httpService
|
|
|
|
.postRequest(url, payload)
|
|
|
|
.then((res) => {
|
|
|
|
this.getGroupsWithoutAdmin().then(() => {
|
|
|
|
this.loading = false;
|
|
|
|
});
|
|
|
|
|
2025-02-20 06:22:41 +00:00
|
|
|
mySwalToast({
|
2025-02-01 09:34:55 +00:00
|
|
|
html: res.message,
|
|
|
|
});
|
|
|
|
|
|
|
|
this.showPanel = false;
|
|
|
|
this.resetForm();
|
|
|
|
})
|
|
|
|
.finally(() => {
|
|
|
|
this.loading = false;
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
toggleUsersPanel(index = undefined) {
|
|
|
|
if (index !== undefined) {
|
|
|
|
if (this.prevSelectedItemIndex !== undefined)
|
|
|
|
this.groups[this.prevSelectedItemIndex].active = false;
|
|
|
|
|
|
|
|
this.prevSelectedItemIndex = index;
|
|
|
|
this.$set(this.groups[index], "active", true);
|
|
|
|
this.selectedItemClone = structuredClone(this.groups[index]);
|
|
|
|
|
|
|
|
this.showPanel = true;
|
|
|
|
} else {
|
|
|
|
this.resetForm();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
resetForm() {
|
|
|
|
this.selectedItemClone = undefined;
|
|
|
|
this.users = [];
|
|
|
|
this.showPanel = false;
|
|
|
|
},
|
|
|
|
|
|
|
|
// pagination and sorting
|
|
|
|
resetPagination() {
|
|
|
|
this.pagination = {
|
|
|
|
pages: 0,
|
|
|
|
total: 0,
|
|
|
|
page: 1,
|
|
|
|
offset: 0,
|
|
|
|
limit: 10,
|
|
|
|
};
|
|
|
|
},
|
|
|
|
pageLimitChanged(paging) {
|
|
|
|
this.resetPagination();
|
|
|
|
this.pagination.limit = paging.limit;
|
|
|
|
|
|
|
|
this[this.searchType]();
|
|
|
|
},
|
|
|
|
pageChanged(paging) {
|
|
|
|
let page = paging.pageNumber;
|
|
|
|
page -= 1;
|
|
|
|
this.pagination.offset = page * paging.limit;
|
|
|
|
this.pagination.limit = paging.limit;
|
|
|
|
this.pagination.page = paging.pageNumber;
|
|
|
|
|
|
|
|
this[this.searchType]();
|
|
|
|
},
|
|
|
|
sortChanged(sorting) {
|
|
|
|
this.pagination.page = this.pagination.offset = 0;
|
|
|
|
this.sorting = sorting;
|
|
|
|
|
|
|
|
this[this.searchType]();
|
|
|
|
},
|
|
|
|
|
|
|
|
// not used yet.
|
|
|
|
deleteItem(index) {
|
|
|
|
if (this.loading) return;
|
|
|
|
this.loading = true;
|
|
|
|
|
|
|
|
let groupId = this.groups[index].id;
|
|
|
|
|
|
|
|
const payload = {
|
|
|
|
group_id: groupId,
|
|
|
|
};
|
|
|
|
|
|
|
|
const url = `${messageUrl()}/${adminApi.groups.delete}`;
|
|
|
|
|
2025-02-20 06:22:41 +00:00
|
|
|
mySwalConfirm({
|
2025-02-01 09:34:55 +00:00
|
|
|
title: "هشدار",
|
|
|
|
html: "با حذف گروه، تمامی مسائل و پاسخ های آن نیز حذف خواهد شد.",
|
|
|
|
icon: "warning",
|
|
|
|
}).then((result) => {
|
|
|
|
if (result.isConfirmed) {
|
|
|
|
this.httpService.postRequest(url, payload).then((res) => {
|
|
|
|
this[this.searchType]().then(() => {
|
|
|
|
this.loading = false;
|
|
|
|
// this.showPanel = false;
|
|
|
|
});
|
|
|
|
|
2025-02-20 06:22:41 +00:00
|
|
|
mySwalToast({
|
2025-02-01 09:34:55 +00:00
|
|
|
html: res.message,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
},
|
|
|
|
openCreatePanel() {
|
|
|
|
this.selectedItemClone = undefined;
|
|
|
|
this.showPanel = true;
|
|
|
|
},
|
|
|
|
},
|
2025-02-20 06:22:41 +00:00
|
|
|
components: {
|
|
|
|
UsersSearch: defineAsyncComponent(() =>
|
|
|
|
import("@/components/admin/components/UsersSearch.vue")
|
|
|
|
),
|
|
|
|
},
|
2025-02-01 09:34:55 +00:00
|
|
|
|
|
|
|
};
|
|
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
|
|
.side-panel {
|
|
|
|
padding: 1em;
|
|
|
|
width: 30em;
|
|
|
|
max-width: 100%;
|
|
|
|
background-color: #fafafa;
|
|
|
|
border-right: 1px solid #eee;
|
|
|
|
}
|
|
|
|
</style>
|