first commit
This commit is contained in:
@@ -0,0 +1,142 @@
|
||||
<template>
|
||||
<div class="groups">
|
||||
<at-collapse simple accordion @on-change="event => (opened = event)">
|
||||
<at-collapse-item
|
||||
v-for="(group, index) in groups"
|
||||
:key="index"
|
||||
:name="String(index)"
|
||||
:disabled="group.projects_count === 0"
|
||||
>
|
||||
<div slot="title">
|
||||
<div class="groups__header">
|
||||
<h5 :class="{ groups__disabled: group.projects_count === 0 }" class="groups__title">
|
||||
<span
|
||||
v-if="group.depth > 0 && group.breadCrumbs == null"
|
||||
:class="{ groups__disabled: group.projects_count === 0 }"
|
||||
class="groups__depth"
|
||||
>
|
||||
{{ group.depth | getSpaceByDepth }}
|
||||
</span>
|
||||
<span v-if="group.breadCrumbs" class="groups__bread-crumbs">
|
||||
<span
|
||||
v-for="(breadCrumb, index) in group.breadCrumbs"
|
||||
:key="index"
|
||||
class="groups__bread-crumbs__item"
|
||||
@click.stop="$emit('getTargetClickGroupAndChildren', breadCrumb.id)"
|
||||
>
|
||||
{{ breadCrumb.name }} /
|
||||
</span>
|
||||
</span>
|
||||
<span>{{ `${group.name} (${group.projects_count})` }}</span>
|
||||
</h5>
|
||||
<span @click.stop>
|
||||
<router-link
|
||||
v-if="$can('update', 'projectGroup')"
|
||||
class="groups__header__link"
|
||||
:to="{ name: 'ProjectGroups.crud.groups.edit', params: { id: group.id } }"
|
||||
target="_blank"
|
||||
rel="opener"
|
||||
>
|
||||
<i class="icon icon-external-link" />
|
||||
</router-link>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="group.projects_count > 0 && isOpen(index)" class="groups__projects-wrapper">
|
||||
<GroupProjects :group-id="group.id" class="groups__projects" @reloadData="$emit('reloadData')" />
|
||||
</div>
|
||||
</at-collapse-item>
|
||||
</at-collapse>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import GroupProjects from '../components/GroupProjects';
|
||||
|
||||
export default {
|
||||
name: 'GroupCollapsable',
|
||||
components: { GroupProjects },
|
||||
data() {
|
||||
return {
|
||||
opened: [],
|
||||
};
|
||||
},
|
||||
props: {
|
||||
groups: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
isOpen(index) {
|
||||
return this.opened[0] === String(index);
|
||||
},
|
||||
reloadData() {
|
||||
this.$emit('reloadData');
|
||||
},
|
||||
},
|
||||
filters: {
|
||||
getSpaceByDepth(value) {
|
||||
return ''.padStart(value, '-');
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.groups {
|
||||
&__title {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.icon-external-link {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
&__disabled {
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
&__depth {
|
||||
padding-right: 0.3em;
|
||||
letter-spacing: 0.1em;
|
||||
opacity: 0.3;
|
||||
font-weight: 300;
|
||||
}
|
||||
&__header {
|
||||
display: flex;
|
||||
&__link {
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
&__bread-crumbs {
|
||||
color: #0075b2;
|
||||
}
|
||||
&::v-deep {
|
||||
.at-collapse {
|
||||
&__item--active {
|
||||
background-color: #fff;
|
||||
.groups__title {
|
||||
color: $blue-2;
|
||||
}
|
||||
}
|
||||
&__header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
&__content {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
&__icon.icon-chevron-right {
|
||||
position: static;
|
||||
display: block;
|
||||
color: black;
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,291 @@
|
||||
<template>
|
||||
<div class="projects">
|
||||
<at-input
|
||||
v-model="query"
|
||||
type="text"
|
||||
:placeholder="$t('message.project_search_input_placeholder')"
|
||||
class="projects__search col-6"
|
||||
@input="onSearch"
|
||||
>
|
||||
<template v-slot:prepend>
|
||||
<i class="icon icon-search" />
|
||||
</template>
|
||||
</at-input>
|
||||
|
||||
<div class="at-container">
|
||||
<div ref="tableWrapper" class="table">
|
||||
<at-table ref="table" size="large" :columns="columns" :data="projects" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<at-pagination :total="projectsTotal" :current="page" :page-size="limit" @page-change="loadPage" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ProjectService from '@/services/resource/project.service';
|
||||
import TeamAvatars from '@/components/TeamAvatars';
|
||||
import i18n from '@/i18n';
|
||||
import debounce from 'lodash.debounce';
|
||||
|
||||
const service = new ProjectService();
|
||||
|
||||
export default {
|
||||
name: 'GroupProjects',
|
||||
props: {
|
||||
groupId: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
projects: [],
|
||||
projectsTotal: 0,
|
||||
limit: 15,
|
||||
query: '',
|
||||
page: 1,
|
||||
};
|
||||
},
|
||||
async created() {
|
||||
this.search = debounce(this.search, 350);
|
||||
await this.search();
|
||||
},
|
||||
methods: {
|
||||
async loadPage(page) {
|
||||
this.page = page;
|
||||
this.resetOptions();
|
||||
await this.loadOptions();
|
||||
},
|
||||
onSearch() {
|
||||
this.search();
|
||||
},
|
||||
async search() {
|
||||
this.totalPages = 0;
|
||||
this.resetOptions();
|
||||
await this.$nextTick();
|
||||
await this.loadOptions();
|
||||
await this.$nextTick();
|
||||
},
|
||||
async loadOptions() {
|
||||
const filters = {
|
||||
where: {
|
||||
group: ['in', [this.groupId]],
|
||||
},
|
||||
with: ['users', 'tasks', 'can'],
|
||||
withCount: ['tasks'],
|
||||
search: {
|
||||
query: this.query,
|
||||
fields: ['name'],
|
||||
},
|
||||
page: this.page,
|
||||
};
|
||||
|
||||
return service.getWithFilters(filters).then(({ data, pagination = data.pagination }) => {
|
||||
this.projectsTotal = pagination.total;
|
||||
this.currentPage = pagination.currentPage;
|
||||
data.data.forEach(option => this.projects.push(option));
|
||||
});
|
||||
},
|
||||
resetOptions() {
|
||||
this.projects = [];
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
columns() {
|
||||
const columns = [
|
||||
{
|
||||
title: this.$t('field.project'),
|
||||
key: 'name',
|
||||
},
|
||||
{
|
||||
title: this.$t('field.members'),
|
||||
key: 'users',
|
||||
render: (h, { item }) => {
|
||||
return h(TeamAvatars, {
|
||||
props: {
|
||||
users: item.users || [],
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
title: this.$t('field.amount_of_tasks'),
|
||||
key: 'tasks',
|
||||
render: (h, { item }) => {
|
||||
const amountOfTasks = item.tasks_count || 0;
|
||||
|
||||
return h(
|
||||
'span',
|
||||
i18n.tc('projects.amount_of_tasks', amountOfTasks, {
|
||||
count: amountOfTasks,
|
||||
}),
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const actions = [
|
||||
{
|
||||
title: 'control.view',
|
||||
icon: 'icon-eye',
|
||||
onClick: (router, { item }) => {
|
||||
this.$router.push({ name: 'Projects.crud.projects.view', params: { id: item.id } });
|
||||
},
|
||||
renderCondition({ $store }) {
|
||||
return true;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'projects.members',
|
||||
icon: 'icon-users',
|
||||
onClick: (router, { item }) => {
|
||||
this.$router.push({ name: 'Projects.members', params: { id: item.id } });
|
||||
},
|
||||
renderCondition({ $can }, item) {
|
||||
return $can('updateMembers', 'project', item);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'control.edit',
|
||||
icon: 'icon-edit',
|
||||
onClick: (router, { item }, context) => {
|
||||
this.$router.push({ name: 'Projects.crud.projects.edit', params: { id: item.id } });
|
||||
},
|
||||
renderCondition: ({ $can }, item) => {
|
||||
return $can('update', 'project', item);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'control.delete',
|
||||
actionType: 'error', // AT-UI action type,
|
||||
icon: 'icon-trash-2',
|
||||
onClick: async (router, { item }, context) => {
|
||||
const isConfirm = await this.$CustomModal({
|
||||
title: this.$t('notification.record.delete.confirmation.title'),
|
||||
content: this.$t('notification.record.delete.confirmation.message'),
|
||||
okText: this.$t('control.delete'),
|
||||
cancelText: this.$t('control.cancel'),
|
||||
showClose: false,
|
||||
styles: {
|
||||
'border-radius': '10px',
|
||||
'text-align': 'center',
|
||||
footer: {
|
||||
'text-align': 'center',
|
||||
},
|
||||
header: {
|
||||
padding: '16px 35px 4px 35px',
|
||||
color: 'red',
|
||||
},
|
||||
body: {
|
||||
padding: '16px 35px 4px 35px',
|
||||
},
|
||||
},
|
||||
width: 320,
|
||||
type: 'trash',
|
||||
typeButton: 'error',
|
||||
});
|
||||
|
||||
if (isConfirm !== 'confirm') {
|
||||
return;
|
||||
}
|
||||
|
||||
await service.deleteItem(item.id);
|
||||
this.$Notify({
|
||||
type: 'success',
|
||||
title: this.$t('notification.record.delete.success.title'),
|
||||
message: this.$t('notification.record.delete.success.message'),
|
||||
});
|
||||
|
||||
await this.search();
|
||||
this.$emit('reloadData');
|
||||
},
|
||||
renderCondition: ({ $can }, item) => {
|
||||
return $can('delete', 'project', item);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
columns.push({
|
||||
title: this.$t('field.actions'),
|
||||
render: (h, params) => {
|
||||
let cell = h(
|
||||
'div',
|
||||
{
|
||||
class: 'actions-column',
|
||||
},
|
||||
actions.map(item => {
|
||||
if (
|
||||
typeof item.renderCondition !== 'undefined'
|
||||
? item.renderCondition(this, params.item)
|
||||
: true
|
||||
) {
|
||||
return h(
|
||||
'AtButton',
|
||||
{
|
||||
props: {
|
||||
type: item.actionType || 'primary', // AT-ui button display type
|
||||
icon: item.icon || undefined, // Prepend icon to button
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
item.onClick(this.$router, params, this);
|
||||
},
|
||||
},
|
||||
class: 'action-button',
|
||||
style: {
|
||||
margin: '0 10px 0 0',
|
||||
},
|
||||
},
|
||||
this.$t(item.title),
|
||||
);
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
return cell;
|
||||
},
|
||||
});
|
||||
|
||||
return columns;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.projects {
|
||||
&__search {
|
||||
margin-bottom: $spacing-03;
|
||||
}
|
||||
|
||||
.at-container {
|
||||
margin-bottom: 1rem;
|
||||
.table {
|
||||
&::v-deep .at-table {
|
||||
&__cell {
|
||||
width: 100%;
|
||||
overflow-x: hidden;
|
||||
padding-top: $spacing-05;
|
||||
padding-bottom: $spacing-05;
|
||||
border-bottom: 2px solid $blue-3;
|
||||
position: relative;
|
||||
z-index: 0;
|
||||
&:last-child {
|
||||
max-width: unset;
|
||||
}
|
||||
}
|
||||
|
||||
.actions-column {
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
}
|
||||
|
||||
.action-button {
|
||||
margin-right: 1em;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"groups": {
|
||||
"grid-title": "Groups",
|
||||
"crud-title": "Group"
|
||||
},
|
||||
"navigation": {
|
||||
"project-groups": "By groups"
|
||||
},
|
||||
"message": {
|
||||
"loading_projects": "Loading projects",
|
||||
"project_search_input_placeholder": "type to find project",
|
||||
"group_search_input_placeholder": "type to find project"
|
||||
},
|
||||
"field": {
|
||||
"project": "Project",
|
||||
"members": "Members",
|
||||
"amount_of_tasks": "Amount of tasks",
|
||||
"parent_group": "Parent group",
|
||||
"loading_groups": "Loading groups"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"groups": {
|
||||
"grid-title": "Группы",
|
||||
"crud-title": "Группа"
|
||||
},
|
||||
"navigation": {
|
||||
"project-groups": "По группам"
|
||||
},
|
||||
"message": {
|
||||
"loading_projects": "Загрузка проектов",
|
||||
"project_search_input_placeholder": "введите, чтобы найти проект",
|
||||
"group_search_input_placeholder": "введите, чтобы найти группу"
|
||||
},
|
||||
"field": {
|
||||
"project": "Проект",
|
||||
"members": "Участники",
|
||||
"amount_of_tasks": "Кол-во задач",
|
||||
"parent_group": "Родительская группа",
|
||||
"loading_groups": "Загружаем группы"
|
||||
}
|
||||
}
|
||||
132
resources/frontend/core/modules/ProjectGroups/module.init.js
Normal file
132
resources/frontend/core/modules/ProjectGroups/module.init.js
Normal file
@@ -0,0 +1,132 @@
|
||||
import ProjectGroupsService from '@/services/resource/project-groups.service';
|
||||
import GroupSelect from '@/components/GroupSelect';
|
||||
import i18n from '@/i18n';
|
||||
import Vue from 'vue';
|
||||
|
||||
export const ModuleConfig = {
|
||||
routerPrefix: 'project-groups',
|
||||
loadOrder: 20,
|
||||
moduleName: 'ProjectGroups',
|
||||
};
|
||||
|
||||
export function init(context) {
|
||||
const crud = context.createCrud('groups.crud-title', 'groups', ProjectGroupsService);
|
||||
|
||||
const crudEditRoute = crud.edit.getEditRouteName();
|
||||
const crudNewRoute = crud.new.getNewRouteName();
|
||||
|
||||
const navigation = { edit: crudEditRoute, new: crudNewRoute };
|
||||
crud.new.addToMetaProperties('permissions', 'groups/create', crud.new.getRouterConfig());
|
||||
crud.new.addToMetaProperties('navigation', navigation, crud.new.getRouterConfig());
|
||||
|
||||
crud.edit.addToMetaProperties('permissions', 'groups/edit', crud.edit.getRouterConfig());
|
||||
|
||||
const fieldsToFill = [
|
||||
{
|
||||
key: 'id',
|
||||
displayable: false,
|
||||
},
|
||||
{
|
||||
label: 'field.name',
|
||||
key: 'name',
|
||||
type: 'text',
|
||||
placeholder: 'field.name',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
label: 'field.parent_group',
|
||||
key: 'parent_id',
|
||||
render: (h, data) => {
|
||||
return h(GroupSelect, {
|
||||
props: { value: data.values.group_parent },
|
||||
on: {
|
||||
input(value) {
|
||||
Vue.set(data.values, 'group_parent', value);
|
||||
data.values.parent_id = value?.id ?? null;
|
||||
},
|
||||
},
|
||||
});
|
||||
},
|
||||
required: false,
|
||||
},
|
||||
];
|
||||
|
||||
crud.new.addField(fieldsToFill);
|
||||
crud.edit.addField(fieldsToFill);
|
||||
|
||||
context.addRoute(crud.getRouterConfig());
|
||||
|
||||
crud.edit.addPageControlsToBottom([
|
||||
{
|
||||
title: 'control.delete',
|
||||
type: 'error',
|
||||
icon: 'icon-trash-2',
|
||||
onClick: async ({ service, $router }, item) => {
|
||||
const isConfirm = await Vue.prototype.$CustomModal({
|
||||
title: i18n.t('notification.record.delete.confirmation.title'),
|
||||
content: i18n.t('notification.record.delete.confirmation.message'),
|
||||
okText: i18n.t('control.delete'),
|
||||
cancelText: i18n.t('control.cancel'),
|
||||
showClose: false,
|
||||
styles: {
|
||||
'border-radius': '10px',
|
||||
'text-align': 'center',
|
||||
footer: {
|
||||
'text-align': 'center',
|
||||
},
|
||||
header: {
|
||||
padding: '16px 35px 4px 35px',
|
||||
color: 'red',
|
||||
},
|
||||
body: {
|
||||
padding: '16px 35px 4px 35px',
|
||||
},
|
||||
},
|
||||
width: 320,
|
||||
type: 'trash',
|
||||
typeButton: 'error',
|
||||
});
|
||||
|
||||
if (isConfirm !== 'confirm') {
|
||||
return;
|
||||
}
|
||||
|
||||
await service.deleteItem(item);
|
||||
Vue.prototype.$Notify({
|
||||
type: 'success',
|
||||
title: i18n.t('notification.record.delete.success.title'),
|
||||
message: i18n.t('notification.record.delete.success.message'),
|
||||
});
|
||||
|
||||
$router.push({ name: context.getModuleRouteName() });
|
||||
},
|
||||
renderCondition: ({ $can }) => {
|
||||
return $can('delete', 'projectGroup');
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
context.addRoute({
|
||||
path: `/${context.routerPrefix}`,
|
||||
name: context.getModuleRouteName(),
|
||||
component: () => import(/* webpackChunkName: "project-groups" */ './views/ProjectGroups.vue'),
|
||||
meta: {
|
||||
auth: true,
|
||||
},
|
||||
});
|
||||
|
||||
context.addNavbarEntryDropDown({
|
||||
label: 'navigation.project-groups',
|
||||
section: 'navigation.dropdown.projects',
|
||||
to: {
|
||||
name: context.getModuleRouteName(),
|
||||
},
|
||||
});
|
||||
|
||||
context.addLocalizationData({
|
||||
en: require('./locales/en'),
|
||||
ru: require('./locales/ru'),
|
||||
});
|
||||
|
||||
return context;
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
<template>
|
||||
<div class="project-groups">
|
||||
<h1 class="page-title">{{ $t('groups.grid-title') }}</h1>
|
||||
<div class="project-groups__search-container">
|
||||
<at-input
|
||||
v-model="query"
|
||||
type="text"
|
||||
:placeholder="$t('message.group_search_input_placeholder')"
|
||||
class="project-groups__search-container__search col-6"
|
||||
@input="onSearch"
|
||||
>
|
||||
<template slot="prepend">
|
||||
<i class="icon icon-search" />
|
||||
</template>
|
||||
</at-input>
|
||||
<div v-if="isGroupSelected" class="project-groups__selected-group">
|
||||
{{ groups[0].name }}
|
||||
<at-button
|
||||
icon="icon-x"
|
||||
circle
|
||||
size="small"
|
||||
class="project-groups__selected-group__clear"
|
||||
@click="onSearch"
|
||||
></at-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="at-container">
|
||||
<div v-if="Object.keys(groups).length && !isDataLoading">
|
||||
<GroupCollapsable
|
||||
:groups="groups"
|
||||
@getTargetClickGroupAndChildren="getTargetClickGroupAndChildren"
|
||||
@reloadData="onSearch"
|
||||
/>
|
||||
<div v-show="hasNextPage" ref="load" class="option__infinite-loader">
|
||||
{{ $t('field.loading_groups') }} <i class="icon icon-loader" />
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="at-container__inner no-data">
|
||||
<preloader v-if="isDataLoading" />
|
||||
<span>{{ $t('message.no_data') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ProjectGroupsService from '@/services/resource/project-groups.service';
|
||||
import GroupCollapsable from '../components/GroupCollapsable';
|
||||
import Preloader from '@/components/Preloader';
|
||||
import debounce from 'lodash.debounce';
|
||||
|
||||
const service = new ProjectGroupsService();
|
||||
|
||||
export default {
|
||||
name: 'ProjectGroups',
|
||||
components: {
|
||||
Preloader,
|
||||
GroupCollapsable,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
groups: [],
|
||||
isDataLoading: false,
|
||||
groupsTotal: 0,
|
||||
limit: 10,
|
||||
totalPages: 0,
|
||||
currentPage: 0,
|
||||
query: '',
|
||||
isGroupSelected: false,
|
||||
};
|
||||
},
|
||||
async created() {
|
||||
this.search = debounce(this.search, 350);
|
||||
this.requestTimestamp = Date.now();
|
||||
this.search(this.requestTimestamp);
|
||||
},
|
||||
mounted() {
|
||||
this.observer = new IntersectionObserver(this.infiniteScroll);
|
||||
},
|
||||
computed: {
|
||||
hasNextPage() {
|
||||
return this.currentPage < this.totalPages;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async infiniteScroll([{ isIntersecting, target }]) {
|
||||
if (isIntersecting) {
|
||||
const requestTimestamp = +target.dataset.requestTimestamp;
|
||||
|
||||
if (requestTimestamp === this.requestTimestamp) {
|
||||
await this.loadOptions(requestTimestamp);
|
||||
|
||||
await this.$nextTick();
|
||||
|
||||
this.observer.disconnect();
|
||||
this.observe(requestTimestamp);
|
||||
}
|
||||
}
|
||||
},
|
||||
onSearch() {
|
||||
this.isGroupSelected = false;
|
||||
|
||||
this.requestTimestamp = Date.now();
|
||||
|
||||
this.search(this.requestTimestamp);
|
||||
},
|
||||
async search(requestTimestamp) {
|
||||
this.observer.disconnect();
|
||||
this.totalPages = 0;
|
||||
this.currentPage = 0;
|
||||
this.resetOptions();
|
||||
await this.$nextTick();
|
||||
await this.loadOptions(requestTimestamp);
|
||||
await this.$nextTick();
|
||||
this.observe(requestTimestamp);
|
||||
},
|
||||
observe(requestTimestamp) {
|
||||
if (this.$refs.load) {
|
||||
this.$refs.load.dataset.requestTimestamp = requestTimestamp;
|
||||
this.observer.observe(this.$refs.load);
|
||||
}
|
||||
},
|
||||
async loadOptions() {
|
||||
const filters = {
|
||||
search: { query: this.query, fields: ['name'] },
|
||||
with: [],
|
||||
page: this.currentPage + 1,
|
||||
limit: this.limit,
|
||||
};
|
||||
|
||||
if (this.query !== '') {
|
||||
filters.with.push('groupParentsWithProjectsCount');
|
||||
}
|
||||
|
||||
return service.getWithFilters(filters).then(({ data, pagination }) => {
|
||||
this.groupsTotal = pagination.total;
|
||||
if (this.query === '') {
|
||||
this.totalPages = pagination.totalPages;
|
||||
this.currentPage = pagination.currentPage;
|
||||
data.forEach(option => this.groups.push(option));
|
||||
} else {
|
||||
this.totalPages = pagination.totalPages;
|
||||
this.currentPage = pagination.currentPage;
|
||||
data.forEach(option => {
|
||||
let breadCrumbs = [];
|
||||
option.group_parents_with_projects_count.forEach(el => {
|
||||
breadCrumbs.push({
|
||||
name: `${el.name} (${el.projects_count})`,
|
||||
id: el.id,
|
||||
});
|
||||
});
|
||||
option.breadCrumbs = breadCrumbs;
|
||||
this.groups.push(option);
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
resetOptions() {
|
||||
this.groups = [];
|
||||
},
|
||||
getTargetClickGroupAndChildren(id) {
|
||||
this.query = '';
|
||||
service
|
||||
.getWithFilters({
|
||||
where: { id },
|
||||
with: ['descendantsWithDepthAndProjectsCount'],
|
||||
})
|
||||
.then(({ data, pagination }) => {
|
||||
this.totalPages = pagination.totalPages;
|
||||
this.currentPage = pagination.currentPage;
|
||||
this.resetOptions();
|
||||
this.groups.push(data[0]);
|
||||
data[0].descendants_with_depth_and_projects_count.forEach(element => {
|
||||
this.groups.push(element);
|
||||
});
|
||||
this.isGroupSelected = true;
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.no-data {
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.project-groups {
|
||||
&__search-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: $spacing-03;
|
||||
}
|
||||
&__selected-group {
|
||||
background: #ddd;
|
||||
border-radius: 90px/100px;
|
||||
padding: 5px 20px;
|
||||
margin-left: 15px;
|
||||
align-items: center;
|
||||
|
||||
&__clear {
|
||||
margin-left: 10px;
|
||||
&:hover {
|
||||
background: rgba(97, 144, 232, 0.6);
|
||||
}
|
||||
}
|
||||
}
|
||||
&::v-deep {
|
||||
.at-container {
|
||||
overflow: hidden;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user