master
sergeybodin 2023-09-04 09:51:03 +03:00
parent 82dee82acb
commit 2a3b493949
32 changed files with 545 additions and 73 deletions

View File

@ -8,10 +8,12 @@ import {AdministrateCompanyComponent} from "@app/_modules/administration/company
import {AdministrateCommitteeComponent} from "@app/_modules/administration/committee/administrate-committee.component";
import {AdvisoriesModule} from "@app/_modules/advisories/advisories.module";
import {CompaniesModule} from "@app/_modules/companies/companies.module";
import {AdministrateSitePagesComponent} from "@app/_modules/administration/site-pages/administrate-site-pages.component";
import {PagesModule} from "@app/_modules/pages/pages.module";
type PathMatch = "full" | "prefix" | undefined;
const routes = [
{path: 'administrate', redirectTo: 'administrate/company', pathMatch: 'full' as PathMatch},
{path: 'administrate', redirectTo: 'administrate/site-pages', pathMatch: 'full' as PathMatch},
{path: 'administrate/:tab', component: AdministrationPageComponent, canActivate: [AuthGuard]}
];
@ -21,12 +23,14 @@ const routes = [
CommonModule,
RouterModule.forRoot(routes),
AdvisoriesModule,
CompaniesModule
CompaniesModule,
PagesModule,
],
declarations: [
AdministrationPageComponent,
AdministrateCompanyComponent,
AdministrateCommitteeComponent
AdministrateCommitteeComponent,
AdministrateSitePagesComponent
],
exports: [
RouterModule

View File

@ -1,11 +1,12 @@
<div class="container">
<h1>Панель управления</h1>
<div class="tabs default">
<button type="button" *ngFor="let tab of tabs" [class.active]="tab.active"
routerLink="/administrate/{{tab.name}}">{{tab.title}}</button>
<button type="button" *ngFor="let tab of tabs" [class.active]="tab.active" routerLink="/administrate/{{tab.name}}">{{tab.title}}</button>
</div>
<div class="container" [ngSwitch]="tab.name">
<div class="container" [ngSwitch]="tab?.name">
<administrate-company *ngSwitchCase="'company'" [companyId]="'main'"></administrate-company>
<administrate-committee *ngSwitchCase="'committee'"></administrate-committee>
<administrate-site-pages *ngSwitchCase="'site-pages'"></administrate-site-pages>
<p *ngSwitchDefault>Страница не найдена</p>
</div>
</div>

View File

@ -1,16 +1,17 @@
import {Component} from '@angular/core';
import {ActivatedRoute, NavigationEnd, Router} from "@angular/router";
import {Subscription} from "rxjs";
import {AuthenticationService} from "@app/_services";
@Component({
templateUrl: 'administration-page.component.html',
styleUrls: ['administration-page.component.scss']
})
export class AdministrationPageComponent {
public tabs = <any>[{name: 'company', title: 'Структура ФАУ «ФЦС»'}, {name: 'committee', title: 'Структура ТК 465'}];
public tabs = <any>[];
routeSubscription: Subscription;
constructor(private route: ActivatedRoute, private router: Router) {
constructor(private route: ActivatedRoute, private router: Router, private authService: AuthenticationService) {
this.routeSubscription = this.router.events.subscribe(event => {
if (event instanceof NavigationEnd && (this.route.snapshot.paramMap.get('tab') !== this.tab?.name)) this.switchTab(this.route.snapshot.paramMap.get('tab'));
});
@ -21,13 +22,21 @@ export class AdministrationPageComponent {
}
ngOnInit() {
this.authService.user.subscribe(val => {
this.makeTabs();
});
}
ngOnDestroy() {
this.routeSubscription?.unsubscribe();
}
makeTabs() {
//this.tabs = [{name: 'company', title: 'Структура ФАУ «ФЦС»'}, {name: 'committee', title: 'Структура ТК 465'}];
//if (this.authService.isSuperAdmin) this.tabs.push({name: 'site-pages', title: 'Структура сайта'});
this.tabs = [{name: 'site-pages', title: 'Структура сайта'}];
this.switchTab(this.route.snapshot.paramMap.get('tab'));
}
switchTab(name: string) {
this.tabs.map(tab => {tab.active = tab.name === name});

View File

@ -0,0 +1 @@
<pages-tree></pages-tree>

View File

@ -0,0 +1,15 @@
import {Component} from '@angular/core';
@Component({
selector: 'administrate-site-pages',
templateUrl: 'administrate-site-pages.component.html',
styleUrls: ['administrate-site-pages.component.scss']
})
export class AdministrateSitePagesComponent {
constructor() {
}
ngOnInit() {
}
}

View File

@ -6,7 +6,7 @@
<div class="dropdown" [class.hidden]="ddHidden" (mouseleave)="close()">
<ul>
<li (click)="link('profile')">Личный кабинет</li>
<li *ngIf="isJournalVisible" (click)="link('applications')">Журнал заявок</li>
<!--li *ngIf="isJournalVisible" (click)="link('applications')">Журнал заявок</li-->
<li *ngIf="authService.isAdmin" (click)="link('administrate')">Панель управления</li>
<li (click)="logout()">Выход из системы</li>
</ul>

View File

@ -19,6 +19,7 @@ export class HomepageComponent {
}
ngOnInit() {
this.router.navigate(['glavnaia']);
this.load();
}
ngOnDestroy() {

View File

@ -1,5 +1,4 @@
<ul class="breadcrumbs">
<li><a routerLink="/">Главная</a></li>
<li *ngFor="let parent of parents"><a [routerLink]="parent.link">{{parent.name}}</a></li>
<li>{{page.name}}</li>
</ul>

View File

@ -13,6 +13,9 @@ import {PaginationModule} from "@app/_modules/pagination/pagination.module";
import {SearchSectionsComponent} from "@app/_modules/pages/sections/search/search-sections.component";
import {SearchSectionsItemComponent} from "@app/_modules/pages/sections/search/item/search-sections-item.component";
import {SwiperModule} from "swiper/angular";
import {PagesTreeComponent} from "@app/_modules/pages/tree/pages-tree.component";
import {PagesTreeItemComponent} from "@app/_modules/pages/tree/item/pages-tree-item.component";
import {SortablejsModule} from "ngx-sortablejs";
@NgModule({
imports: [
@ -23,20 +26,24 @@ import {SwiperModule} from "swiper/angular";
RegistriesModule,
PublicationsModule,
PaginationModule,
SwiperModule
SwiperModule,
SortablejsModule,
],
declarations: [
PagesMenuComponent,
PagesMenuItemComponent,
PagesListComponent,
PagesListItemComponent,
PagesTreeComponent,
PagesTreeItemComponent,
SearchSectionsComponent,
SearchSectionsItemComponent
SearchSectionsItemComponent,
],
exports: [
PagesMenuComponent,
PagesListComponent,
SearchSectionsComponent
SearchSectionsComponent,
PagesTreeComponent,
]
})
export class PagesModule {}

View File

@ -37,6 +37,7 @@ export class AddSectionComponent {
return item;
});
let attach = {modelType: this.modelType, modelId: this.page.id, group: 'sections', ord: this.ord};
console.log(type);
this.formsService.createObject(type, {extraProps: {attach: attach}});
this.hideDD();
}

View File

@ -1,13 +1,6 @@
<div class="section">
<add-section *ngIf="editMode" [page]="page" [ord]="ord" [modelType]="modelType"></add-section>
<div class="menu" *ngIf="editMode">
<div class="block">
<button type="button" class="up" *ngIf="!isFirst" (click)="move(ord - 1)"></button>
<button type="button" class="down" *ngIf="!isLast" (click)="move(ord + 1)"></button>
<button type="button" class="edit" (click)="edit()"></button>
<button type="button" class="delete" (click)="delete()"></button>
</div>
</div>
<page-menu [editMode]="editMode" [index]="index" [page]="page" [section]="section" [modelType]="modelType"></page-menu>
<div class="content" [ngSwitch]="type?.name">
<header-section [section]="section" *ngSwitchCase="'page-section-header'"></header-section>
<text-section [section]="section" *ngSwitchCase="'page-section-text'"></text-section>
@ -21,7 +14,7 @@
<contact-section [section]="section" *ngSwitchCase="'page-section-contacts'"></contact-section>
<feedback-section [section]="section" *ngSwitchCase="'page-section-feedback'"></feedback-section>
<maps-section [section]="section" *ngSwitchCase="'page-section-maps'"></maps-section>
<member-section [section]="section" *ngSwitchCase="'page-section-list-members'"></member-section>
<member-section [section]="section" *ngSwitchCase="'page-section-list-members'" [editMode]="editMode"></member-section>
<image-section [section]="section" *ngSwitchCase="'page-section-image'"></image-section>
<document-section [section]="section" *ngSwitchCase="'page-section-document'"></document-section>
<p *ngSwitchDefault>section {{type?.name}} is undefined</p>

View File

@ -1,5 +1,4 @@
import {Component, Input} from '@angular/core';
import {FormsService, ListsService, ObjectsService} from "@app/_services";
@Component({
selector: 'page-section',
@ -13,7 +12,10 @@ export class PageSectionComponent {
@Input() editMode = false;
@Input() modelType: string;
constructor(private formsService: FormsService, private objectsService: ObjectsService, private listsService: ListsService) {
constructor() {
}
ngOnInit() {
}
@ -24,40 +26,4 @@ export class PageSectionComponent {
get ord() {
return this.section?.pivot?.ord;
}
get total() {
return this.page?.sections?.data?.length;
}
get isFirst() {
return this.index === 0;
}
get isLast() {
return (this.index + 1) === this.total;
}
ngOnInit() {
}
edit() {
this.formsService.editObject(this.section.id);
}
move(ord) {
this.objectsService.move(this.section.id, {modelType: this.modelType, modelId: this.page.id, ord: ord}).subscribe(res => {
this.listsService.refresh();
});
}
delete() {
//r u sure?
if (confirm('Удалить этот блок?')) this.objectsService.destroy(this.section.id).subscribe(res => {
this.listsService.refresh();
});
}
}

View File

@ -0,0 +1,8 @@
<div class="menu" *ngIf="editMode">
<div class="block">
<button type="button" class="up" *ngIf="!isFirst" (click)="move(ord - 1)"></button>
<button type="button" class="down" *ngIf="!isLast" (click)="move(ord + 1)"></button>
<button type="button" class="edit" (click)="edit()"></button>
<button type="button" class="delete" (click)="delete()"></button>
</div>
</div>

View File

@ -0,0 +1,52 @@
import {Component, Input} from '@angular/core';
import {FormsService, ListsService, ObjectsService} from "@app/_services";
@Component({
selector: 'page-menu',
templateUrl: 'page-menu.component.html',
styleUrls: ['page-menu.component.scss']
})
export class PageMenuComponent {
@Input() page: any;
@Input() section: any;
@Input() editMode = false;
@Input() index: number;
@Input() modelType: string;
constructor(private formsService: FormsService, private objectsService: ObjectsService, private listsService: ListsService) {
}
get ord() {
return this.section?.pivot?.ord;
}
get total() {
return this.page?.sections?.data?.length || 1;
}
get isFirst() {
return this.index === 0;
}
get isLast() {
return (this.index + 1) === this.total;
}
edit() {
this.formsService.editObject(this.section.id);
}
move(ord) {
this.objectsService.move(this.section.id, {modelType: this.modelType, modelId: this.page.id, ord: ord}).subscribe(res => {
this.listsService.refresh();
});
}
delete() {
//r u sure?
if (confirm('Удалить этот блок?')) this.objectsService.destroy(this.section.id).subscribe(res => {
this.listsService.refresh();
});
}
}

View File

@ -23,6 +23,7 @@ import {MapsSectionComponent} from "@app/_modules/pages/sections/types/basic/map
import {MemberSectionComponent} from "@app/_modules/pages/sections/types/basic/member/member-section.component";
import {ImageSectionComponent} from "@app/_modules/pages/sections/types/basic/image/image-section.component";
import {DocumentSectionComponent} from "@app/_modules/pages/sections/types/basic/document/document-section.component";
import {PageMenuComponent} from "@app/_modules/pages/sections/menu/page-menu.component";
@NgModule({
imports: [
@ -33,6 +34,7 @@ import {DocumentSectionComponent} from "@app/_modules/pages/sections/types/basic
SwiperModule,
],
declarations: [
PageMenuComponent,
PageSectionsComponent,
PageSectionComponent,
HeaderSectionComponent,

View File

@ -1 +1,15 @@
Member Section
<div class="member">
<div class="add">
<div class="title" [innerHTML]="title"></div>
<div *ngIf="editMode" class="toggle" (click)="add()"></div>
</div>
<div class="list">
<div class="item">
<page-menu [editMode]="editMode" [section]="section"></page-menu>
<div class="photo"><img src="assets/images/_remove/photo1.png" /></div>
<div class="name">Давид Мерабович Гоготишвили</div>
<div class="description">Генеральный директор ЧУ СЦ «ВНИИГАЗ-Сертификат»</div>
<div class="more"><a [href]="getLink('gogotishviki')">Подробнее</a></div>
</div>
</div>
</div>

View File

@ -0,0 +1,55 @@
.member {
display: flex;
flex-direction: column;
width: 100%;
max-width: 900px;
.add {
padding: 16px 12px;
display: flex;
justify-content: space-between;
width: 100%;
border-top: 1px solid #C0C0C0;
border-bottom: 1px solid #C0C0C0;
.title {
color: #6C6C6C;
font-size: 20px;
font-style: normal;
font-weight: 400;
line-height: 24px;
}
.toggle {
width: 24px;
height: 24px;
cursor: pointer;
background: url('~src/assets/images/icons/add_cirle_24dp.svg') center no-repeat;
}
}
.list {
margin: 32px 0;
display: grid;
gap: 32px 40px;
width: 100%;
grid-template-columns: repeat(3, 1fr);
.item {
object-fit: cover;
.menu {
}
.photo {
img {
width: calc(100%);
border-radius: 12px;
}
}
.name {
}
.description {
}
.more {
}
}
}
}

View File

@ -1,4 +1,5 @@
import {Component, Input} from '@angular/core';
import {FormsService} from "@app/_services";
@Component({
selector: 'member-section',
@ -7,12 +8,24 @@ import {Component, Input} from '@angular/core';
})
export class MemberSectionComponent {
@Input() section: any;
@Input() editMode = false;
constructor(
) {
constructor(private formsService: FormsService,) {
}
ngOnInit() {
console.log(this.section);
console.log();
}
get title() {
return this.section?.groups?.data[0]?.fields?.data[0]?.value?.data[0];
}
add() {
this.formsService.createObject('page-section-list-member');
}
getLink(slug: string) {
return '' + slug;
}
}

View File

@ -0,0 +1,28 @@
<div class="item" [class.active]="active" (click)="touched = true">
<div class="bar">
<div class="left"><button *ngIf="children?.length" type="button" class="toggle" (click)="toggle()"></button></div>
<div class="mid">
<div class="info">
<div class="logo">
<img *ngIf="logo" src="{{logo}}" alt="" />
<span *ngIf="!logo">{{noLogoLetters}}</span>
</div>
<div class="name">
<p><a [routerLink]="page.link" target="_blank">{{page.name}}</a></p>
<p class="sub">{{page.type?.title}}</p>
</div>
</div>
</div>
<div class="right">
<div class="menu">
<button type="button" class="btn icon move" title="Переместить"></button>
<button type="button" class="btn icon add" title="Добавить страницу" (click)="add()"></button>
<button type="button" class="btn icon edit" title="Редактировать" (click)="edit()"></button>
<button type="button" class="btn icon delete" title="Удалить" (click)="delete()"></button>
</div>
</div>
</div>
<div class="items">
<pages-tree *ngIf="active" [parent]="page"></pages-tree>
</div>
</div>

View File

@ -0,0 +1,76 @@
import {Component, Input} from '@angular/core';
import {Router} from "@angular/router";
import {PagesService} from "@app/_services/pages.service";
import {FormsService, ListsService} from "@app/_services";
import {Subscription} from "rxjs";
@Component({
selector: 'pages-tree-item',
templateUrl: 'pages-tree-item.component.html',
styleUrls: ['../pages-tree.component.scss', 'pages-tree-item.component.scss']
})
export class PagesTreeItemComponent {
@Input() page: any;
@Input() parent: any;
public active = false;
public touched = false;
public subscription: Subscription;
constructor(private router: Router, private pagesService: PagesService, private formsService: FormsService, private listsService: ListsService) {
}
get listId() {
return this.page.id;
}
get parentListId() {
return this.parent?.id || 'pages-tree-root';
}
get logo() {
return this.page?.logo?.data.links?.full;
}
get noLogoLetters() {
return this.page.name.replace(' ', '').slice(0, 2);
}
get children() {
return this.page.children?.data;
}
ngOnInit() {
this.subscription = this.listsService.controls(this.listId).subscribe(res => {
if (this.touched) this.fetch();
});
}
fetch() {
let include = ['children.children'];
this.pagesService.show(this.page.id, {include: include.join(',')}).subscribe(res => {
this.page = res.data;
});
}
add() {
this.formsService.createModel('page', {extraProps: {parent: this.page.id}}, this.listId);
this.active = true;
}
edit() {
this.formsService.editModel('page', this.page.id, null, this.listId);
}
delete() {
if (confirm('r u sure?')) this.pagesService.delete(this.page.id).subscribe(res => {
this.listsService.refresh(this.parentListId);
});
}
toggle() {
this.active = !this.active;
if (this.active) this.fetch();
}
}

View File

@ -0,0 +1,17 @@
<div class="item active" *ngIf="!parent">
<div class="bar">
<div class="left"></div>
<div class="mid">
<!--div class="info">
<div class="logo home"></div>
<div class="name"><p>Главная страница</p></div>
</div-->
</div>
<div class="right">
<div class="menu"><button type="button" class="btn icon add" (click)="add()"></button></div>
</div>
</div>
</div>
<div class="items" [sortablejs]="pages" [sortablejsOptions]="options">
<pages-tree-item [id]="page.id" [page]="page" [parent]="parent" *ngFor="let page of pages"></pages-tree-item>
</div>

View File

@ -0,0 +1,124 @@
.item {
.bar {
display: flex;
flex-direction: row;
align-items: center;
padding: 16px 0;
border-bottom: #E0E0E0 solid 1px;
.left {
flex-shrink: 0;
width: 40px;
height: 24px;
cursor: pointer;
.toggle {
width: 100%;
height: 100%;
background: transparent url("~src/assets/images/icons/circle_plus_24.svg") 50% 50% no-repeat;
}
}
.mid {
flex-grow: 1;
padding: 0 16px;
.info {
display: flex;
flex-direction: row;
align-items: center;
.logo {
display: flex;
align-items: center;
justify-content: center;
position: relative;
flex-shrink: 0;
width: 40px;
height: 40px;
margin-right: 16px;
border-radius: 100px;
background-color: #F9B417;
img {
width: 100%;
height: 100%;
border-radius: 100px;
object-fit: cover;
background-color: #ffffff;
}
}
.name {
p {
margin: 0;
a {
font-weight: bold;
color: var(--grey-7);
}
&.sub {
font-size: 0.875rem;
color: #7f7f7f;
}
}
}
}
}
.right {
display: flex;
flex-direction: row;
align-items: center;
flex-shrink: 0;
button {
margin-left: 24px;
&.edit {
background-image: url('~src/assets/images/icons/edit_24dp.svg');
}
&.add {
background-image: url('~src/assets/images/icons/add_library_dark_24.svg');
}
&.delete {
background-image: url('~src/assets/images/icons/close_24dp.svg');
}
&.move {
background-image: url('~src/assets/images/icons/drag-n-drop_24.svg');
cursor: move;
}
}
}
}
.items {
display: none;
padding-left: 56px;
}
&.active {
>.bar {
.left {
.toggle {
background-image: url('~src/assets/images/icons/circle_minus_24.svg');
}
}
}
>.items {
display: block;
}
}
}
@media screen and (max-width: 767px) {
.item {
.bar {
.mid {
padding: 0 12px;
.info .logo {
display: none;
}
}
.right {
display: none;
}
}
.items {
padding-left: 16px;
}
&.company {
.items {
padding-left: 40px;
}
}
}
}

View File

@ -0,0 +1,81 @@
import {Component, Input} from '@angular/core';
import {Router} from "@angular/router";
import {PagesService} from "@app/_services/pages.service";
import {FormsService, ListsService} from "@app/_services";
import {Subscription} from "rxjs";
import {SortableOptions} from "sortablejs";
@Component({
selector: 'pages-tree',
templateUrl: 'pages-tree.component.html',
styleUrls: ['pages-tree.component.scss']
})
export class PagesTreeComponent {
@Input() parent: any;
public pages = <any>[];
subscription: Subscription;
public options: SortableOptions = {
group: 'site-pages',
handle: '.move',
onUpdate: (event: any) => {
this.move(event);
},
onAdd: (event: any) => {
this.move(event);
}
};
constructor(private router: Router, private pagesService: PagesService, private listsService: ListsService, private formsService: FormsService) {
}
get listId() {
return 'pages-tree-root';
}
ngOnInit() {
if (!this.parent) this.subscription = this.listsService.controls(this.listId).subscribe(res => {
this.fetch();
});
}
ngOnChanges() {
this.pages = this.parent?.children?.data;
}
ngOnDestroy() {
this.subscription?.unsubscribe();
}
fetch() {
this.parent ? this.fetchSubpages() : this.fetchRootPages();
}
fetchRootPages() {
let include = ['children'];
this.pagesService.root({include: include}).subscribe(res => {
this.pages = res.data;
});
}
fetchSubpages() {
let include = ['children.children'];
this.pagesService.show(this.parent.id, {include: include.join(',')}).subscribe(res => {
this.pages = res.data?.children?.data;
});
}
add() {
this.formsService.createModel('page', null, this.listId);
}
move(event: any) {
this.pagesService.move(event.item.id, {parent: this.parent?.id, ord: event.newIndex}).subscribe(res => {
});
}
}

View File

@ -6,7 +6,6 @@
margin: 24px 0;
width: 100%;
.toggle {
.button {
display: inline-block;
font-size: 20px;
@ -15,18 +14,18 @@
padding-left: 8px;
&:hover{
color: var(--blue-2);
}
}
};
&::before{
content: "";
display: inline-block;
width: 24px;
height: 24px;
background: url('~src/assets/images/icons/add_cirle_24dp.svg') center no-repeat;
background: url('~src/assets/images/icons/add_cirle_24dp.svg') center no-repeat;
}
&:hover::before{
background: url('~src/assets/images/icons/add_cirle_hover_24dp.svg') center no-repeat;
}
}
}
}
}

View File

@ -19,10 +19,12 @@ export class AuthenticationService {
get oauthTokenValue() {
return this.token.value;
}
public get privileges() {
return this.user.value?.privileges;
}
get isSuperAdmin() {
return this.privileges?.superAdmin;
}
get isAdmin() {
return this.privileges?.admin;
}

View File

@ -33,4 +33,8 @@ export class PagesService {
deleteBackground(id: string): Observable<any> {
return this.http.delete(`${environment.apiUrl}/api/pages/background/${id}`);
}
move(id: string, data: any): Observable<any> {
return this.http.put(`${environment.apiUrl}/api/pages/${id}`, data);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 829 KiB

View File

@ -1,6 +1,6 @@
export const environment = {
production: true,
apiUrl: 'https://api-faufcc.testnir.ru',
apiUrl: 'https://api-vniigaz-cert-v2.testnir.ru',
clientId: 2,
clientSecret: 'TyqSDTRBjmCT2n8QhcZQJ1wqM1aHDajhet9kvFIq',
clientSecret: 'DBRNWIM1QZVgNJEl5PfGZPqbeCv0irPmez7djn8h',
};

View File

@ -6,7 +6,7 @@ export const environment = {
production: false,
apiUrl: 'http://api.vniigazv2.lc',
clientId: 2,
clientSecret: '5Q8Pe95YrQBwa7o7XDDIatg30ELu3dpS40Uo6jHi',
clientSecret: '0T64vQU8sHXFprE6A8UmGIuHjRA9j9xbjt3vBenR',
};
/*