diff --git a/src/app/app.routing.ts b/src/app/app.routing.ts index 20016e4..ca868c3 100644 --- a/src/app/app.routing.ts +++ b/src/app/app.routing.ts @@ -445,6 +445,32 @@ export const appRoutes: Route[] = [ }, ], }, + { + path: 'board', + children: [ + { + path: 'notice', + loadChildren: () => + import('app/modules/admin/board/notice/notice.module').then( + (m: any) => m.NoticeModule + ), + }, + { + path: 'notice-oneline', + loadChildren: () => + import( + 'app/modules/admin/board/notice-oneline/notice-oneline.module' + ).then((m: any) => m.NoticeOnelineModule), + }, + { + path: 'popup', + loadChildren: () => + import('app/modules/admin/board/popup/popup.module').then( + (m: any) => m.PopupModule + ), + }, + ], + }, ], }, ]; diff --git a/src/app/mock-api/apps/board/notice-oneline/api.ts b/src/app/mock-api/apps/board/notice-oneline/api.ts new file mode 100644 index 0000000..af9ed95 --- /dev/null +++ b/src/app/mock-api/apps/board/notice-oneline/api.ts @@ -0,0 +1,223 @@ +import { Injectable } from '@angular/core'; +import { assign, cloneDeep } from 'lodash-es'; +import { FuseMockApiService, FuseMockApiUtils } from '@fuse/lib/mock-api'; +import { noticeOnelines as noticeOnelinesData } from './data'; + +@Injectable({ + providedIn: 'root', +}) +export class BoardNoticeOnelineMockApi { + private _noticeOnelines: any[] = noticeOnelinesData; + + /** + * Constructor + */ + constructor(private _fuseMockApiService: FuseMockApiService) { + // Register Mock API handlers + this.registerHandlers(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Register Mock API handlers + */ + registerHandlers(): void { + // ----------------------------------------------------------------------------------------------------- + // @ NoticeOnelines - GET + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService + .onGet('api/apps/board/notice-oneline/notice-onelines', 300) + .reply(({ request }) => { + // Get available queries + const search = request.params.get('search'); + const sort = request.params.get('sort') || 'name'; + const order = request.params.get('order') || 'asc'; + const page = parseInt(request.params.get('page') ?? '1', 10); + const size = parseInt(request.params.get('size') ?? '10', 10); + + // Clone the noticeOnelines + let noticeOnelines: any[] | null = cloneDeep(this._noticeOnelines); + + // Sort the noticeOnelines + if (sort === 'sku' || sort === 'name' || sort === 'active') { + noticeOnelines.sort((a, b) => { + const fieldA = a[sort].toString().toUpperCase(); + const fieldB = b[sort].toString().toUpperCase(); + return order === 'asc' + ? fieldA.localeCompare(fieldB) + : fieldB.localeCompare(fieldA); + }); + } else { + noticeOnelines.sort((a, b) => + order === 'asc' ? a[sort] - b[sort] : b[sort] - a[sort] + ); + } + + // If search exists... + if (search) { + // Filter the noticeOnelines + noticeOnelines = noticeOnelines.filter( + (contact: any) => + contact.name && + contact.name.toLowerCase().includes(search.toLowerCase()) + ); + } + + // Paginate - Start + const noticeOnelinesLength = noticeOnelines.length; + + // Calculate pagination details + const begin = page * size; + const end = Math.min(size * (page + 1), noticeOnelinesLength); + const lastPage = Math.max(Math.ceil(noticeOnelinesLength / size), 1); + + // Prepare the pagination object + let pagination = {}; + + // If the requested page number is bigger than + // the last possible page number, return null for + // noticeOnelines but also send the last possible page so + // the app can navigate to there + if (page > lastPage) { + noticeOnelines = null; + pagination = { + lastPage, + }; + } else { + // Paginate the results by size + noticeOnelines = noticeOnelines.slice(begin, end); + + // Prepare the pagination mock-api + pagination = { + length: noticeOnelinesLength, + size: size, + page: page, + lastPage: lastPage, + startIndex: begin, + endIndex: end - 1, + }; + } + + // Return the response + return [ + 200, + { + noticeOnelines, + pagination, + }, + ]; + }); + + // ----------------------------------------------------------------------------------------------------- + // @ NoticeOneline - GET + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService + .onGet('api/apps/board/notice-oneline/notice-oneline') + .reply(({ request }) => { + // Get the id from the params + const id = request.params.get('id'); + + // Clone the noticeOnelines + const noticeOnelines = cloneDeep(this._noticeOnelines); + + // Find the noticeOneline + const noticeOneline = noticeOnelines.find( + (item: any) => item.id === id + ); + + // Return the response + return [200, noticeOneline]; + }); + + // ----------------------------------------------------------------------------------------------------- + // @ NoticeOneline - POST + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService + .onPost('api/apps/board/notice-oneline/notice-oneline') + .reply(() => { + // Generate a new noticeOneline + const newNoticeOneline = { + id: FuseMockApiUtils.guid(), + category: '', + name: 'A New User', + description: '', + tags: [], + sku: '', + barcode: '', + brand: '', + vendor: '', + stock: '', + reserved: '', + cost: '', + basePrice: '', + taxPercent: '', + price: '', + weight: '', + thumbnail: '', + images: [], + active: false, + }; + + // Unshift the new noticeOneline + this._noticeOnelines.unshift(newNoticeOneline); + + // Return the response + return [200, newNoticeOneline]; + }); + + // ----------------------------------------------------------------------------------------------------- + // @ NoticeOneline - PATCH + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService + .onPatch('api/apps/board/notice-oneline/notice-oneline') + .reply(({ request }) => { + // Get the id and noticeOneline + const id = request.body.id; + const noticeOneline = cloneDeep(request.body.noticeOneline); + + // Prepare the updated noticeOneline + let updatedNoticeOneline = null; + + // Find the noticeOneline and update it + this._noticeOnelines.forEach((item, index, noticeOnelines) => { + if (item.id === id) { + // Update the noticeOneline + noticeOnelines[index] = assign( + {}, + noticeOnelines[index], + noticeOneline + ); + + // Store the updated noticeOneline + updatedNoticeOneline = noticeOnelines[index]; + } + }); + + // Return the response + return [200, updatedNoticeOneline]; + }); + + // ----------------------------------------------------------------------------------------------------- + // @ NoticeOneline - DELETE + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService + .onDelete('api/apps/board/notice-oneline/notice-oneline') + .reply(({ request }) => { + // Get the id + const id = request.params.get('id'); + + // Find the noticeOneline and delete it + this._noticeOnelines.forEach((item, index) => { + if (item.id === id) { + this._noticeOnelines.splice(index, 1); + } + }); + + // Return the response + return [200, true]; + }); + } +} diff --git a/src/app/mock-api/apps/board/notice-oneline/data.ts b/src/app/mock-api/apps/board/notice-oneline/data.ts new file mode 100644 index 0000000..3b7cabc --- /dev/null +++ b/src/app/mock-api/apps/board/notice-oneline/data.ts @@ -0,0 +1,33 @@ +/* eslint-disable */ + +export const noticeOnelines = [ + { + id: 'on00', + totalPartnerCount: '5', + totalHoldingMoney: 303675, + totalComp: 108933, + total: 412608, + branchCount: 1, + divisionCount: 1, + officeCount: 1, + storeCount: 1, + memberCount: 1, + nickname: 'on00', + accountHolder: '11', + phoneNumber: '010-1111-1111', + calculateType: '롤링', + ownCash: 50000, + ownComp: 1711, + ownCoupon: 50000, + gameMoney: 0, + todayComp: 0, + totalDeposit: 0, + totalWithdraw: 0, + balance: 0, + registDate: '2022-06-12 15:38', + finalSigninDate: '', + ip: '', + state: '정상', + note: '', + }, +]; diff --git a/src/app/mock-api/apps/board/notice/api.ts b/src/app/mock-api/apps/board/notice/api.ts new file mode 100644 index 0000000..af86cb9 --- /dev/null +++ b/src/app/mock-api/apps/board/notice/api.ts @@ -0,0 +1,217 @@ +import { Injectable } from '@angular/core'; +import { assign, cloneDeep } from 'lodash-es'; +import { FuseMockApiService, FuseMockApiUtils } from '@fuse/lib/mock-api'; +import { notices as noticesData } from './data'; + +@Injectable({ + providedIn: 'root', +}) +export class BoardNoticeMockApi { + private _notices: any[] = noticesData; + + /** + * Constructor + */ + constructor(private _fuseMockApiService: FuseMockApiService) { + // Register Mock API handlers + this.registerHandlers(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Register Mock API handlers + */ + registerHandlers(): void { + // ----------------------------------------------------------------------------------------------------- + // @ Notices - GET + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService + .onGet('api/apps/board/notice/notices', 300) + .reply(({ request }) => { + // Get available queries + const search = request.params.get('search'); + const sort = request.params.get('sort') || 'name'; + const order = request.params.get('order') || 'asc'; + const page = parseInt(request.params.get('page') ?? '1', 10); + const size = parseInt(request.params.get('size') ?? '10', 10); + + // Clone the notices + let notices: any[] | null = cloneDeep(this._notices); + + // Sort the notices + if (sort === 'sku' || sort === 'name' || sort === 'active') { + notices.sort((a, b) => { + const fieldA = a[sort].toString().toUpperCase(); + const fieldB = b[sort].toString().toUpperCase(); + return order === 'asc' + ? fieldA.localeCompare(fieldB) + : fieldB.localeCompare(fieldA); + }); + } else { + notices.sort((a, b) => + order === 'asc' ? a[sort] - b[sort] : b[sort] - a[sort] + ); + } + + // If search exists... + if (search) { + // Filter the notices + notices = notices.filter( + (contact: any) => + contact.name && + contact.name.toLowerCase().includes(search.toLowerCase()) + ); + } + + // Paginate - Start + const noticesLength = notices.length; + + // Calculate pagination details + const begin = page * size; + const end = Math.min(size * (page + 1), noticesLength); + const lastPage = Math.max(Math.ceil(noticesLength / size), 1); + + // Prepare the pagination object + let pagination = {}; + + // If the requested page number is bigger than + // the last possible page number, return null for + // notices but also send the last possible page so + // the app can navigate to there + if (page > lastPage) { + notices = null; + pagination = { + lastPage, + }; + } else { + // Paginate the results by size + notices = notices.slice(begin, end); + + // Prepare the pagination mock-api + pagination = { + length: noticesLength, + size: size, + page: page, + lastPage: lastPage, + startIndex: begin, + endIndex: end - 1, + }; + } + + // Return the response + return [ + 200, + { + notices, + pagination, + }, + ]; + }); + + // ----------------------------------------------------------------------------------------------------- + // @ Notice - GET + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService + .onGet('api/apps/board/notice/notice') + .reply(({ request }) => { + // Get the id from the params + const id = request.params.get('id'); + + // Clone the notices + const notices = cloneDeep(this._notices); + + // Find the notice + const notice = notices.find((item: any) => item.id === id); + + // Return the response + return [200, notice]; + }); + + // ----------------------------------------------------------------------------------------------------- + // @ Notice - POST + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService + .onPost('api/apps/board/notice/notice') + .reply(() => { + // Generate a new notice + const newNotice = { + id: FuseMockApiUtils.guid(), + category: '', + name: 'A New User', + description: '', + tags: [], + sku: '', + barcode: '', + brand: '', + vendor: '', + stock: '', + reserved: '', + cost: '', + basePrice: '', + taxPercent: '', + price: '', + weight: '', + thumbnail: '', + images: [], + active: false, + }; + + // Unshift the new notice + this._notices.unshift(newNotice); + + // Return the response + return [200, newNotice]; + }); + + // ----------------------------------------------------------------------------------------------------- + // @ Notice - PATCH + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService + .onPatch('api/apps/board/notice/notice') + .reply(({ request }) => { + // Get the id and notice + const id = request.body.id; + const notice = cloneDeep(request.body.notice); + + // Prepare the updated notice + let updatedNotice = null; + + // Find the notice and update it + this._notices.forEach((item, index, notices) => { + if (item.id === id) { + // Update the notice + notices[index] = assign({}, notices[index], notice); + + // Store the updated notice + updatedNotice = notices[index]; + } + }); + + // Return the response + return [200, updatedNotice]; + }); + + // ----------------------------------------------------------------------------------------------------- + // @ Notice - DELETE + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService + .onDelete('api/apps/board/notice/notice') + .reply(({ request }) => { + // Get the id + const id = request.params.get('id'); + + // Find the notice and delete it + this._notices.forEach((item, index) => { + if (item.id === id) { + this._notices.splice(index, 1); + } + }); + + // Return the response + return [200, true]; + }); + } +} diff --git a/src/app/mock-api/apps/board/notice/data.ts b/src/app/mock-api/apps/board/notice/data.ts new file mode 100644 index 0000000..85b9f0a --- /dev/null +++ b/src/app/mock-api/apps/board/notice/data.ts @@ -0,0 +1,33 @@ +/* eslint-disable */ + +export const notices = [ + { + id: 'on00', + totalPartnerCount: '5', + totalHoldingMoney: 303675, + totalComp: 108933, + total: 412608, + branchCount: 1, + divisionCount: 1, + officeCount: 1, + storeCount: 1, + memberCount: 1, + nickname: 'on00', + accountHolder: '11', + phoneNumber: '010-1111-1111', + calculateType: '롤링', + ownCash: 50000, + ownComp: 1711, + ownCoupon: 50000, + gameMoney: 0, + todayComp: 0, + totalDeposit: 0, + totalWithdraw: 0, + balance: 0, + registDate: '2022-06-12 15:38', + finalSigninDate: '', + ip: '', + state: '정상', + note: '', + }, +]; diff --git a/src/app/mock-api/apps/board/popup/api.ts b/src/app/mock-api/apps/board/popup/api.ts new file mode 100644 index 0000000..2cdc93a --- /dev/null +++ b/src/app/mock-api/apps/board/popup/api.ts @@ -0,0 +1,215 @@ +import { Injectable } from '@angular/core'; +import { assign, cloneDeep } from 'lodash-es'; +import { FuseMockApiService, FuseMockApiUtils } from '@fuse/lib/mock-api'; +import { popups as popupsData } from './data'; + +@Injectable({ + providedIn: 'root', +}) +export class BoardPopupMockApi { + private _popups: any[] = popupsData; + + /** + * Constructor + */ + constructor(private _fuseMockApiService: FuseMockApiService) { + // Register Mock API handlers + this.registerHandlers(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Register Mock API handlers + */ + registerHandlers(): void { + // ----------------------------------------------------------------------------------------------------- + // @ Popups - GET + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService + .onGet('api/apps/board/popup/popups', 300) + .reply(({ request }) => { + // Get available queries + const search = request.params.get('search'); + const sort = request.params.get('sort') || 'name'; + const order = request.params.get('order') || 'asc'; + const page = parseInt(request.params.get('page') ?? '1', 10); + const size = parseInt(request.params.get('size') ?? '10', 10); + + // Clone the popups + let popups: any[] | null = cloneDeep(this._popups); + + // Sort the popups + if (sort === 'sku' || sort === 'name' || sort === 'active') { + popups.sort((a, b) => { + const fieldA = a[sort].toString().toUpperCase(); + const fieldB = b[sort].toString().toUpperCase(); + return order === 'asc' + ? fieldA.localeCompare(fieldB) + : fieldB.localeCompare(fieldA); + }); + } else { + popups.sort((a, b) => + order === 'asc' ? a[sort] - b[sort] : b[sort] - a[sort] + ); + } + + // If search exists... + if (search) { + // Filter the popups + popups = popups.filter( + (contact: any) => + contact.name && + contact.name.toLowerCase().includes(search.toLowerCase()) + ); + } + + // Paginate - Start + const popupsLength = popups.length; + + // Calculate pagination details + const begin = page * size; + const end = Math.min(size * (page + 1), popupsLength); + const lastPage = Math.max(Math.ceil(popupsLength / size), 1); + + // Prepare the pagination object + let pagination = {}; + + // If the requested page number is bigger than + // the last possible page number, return null for + // popups but also send the last possible page so + // the app can navigate to there + if (page > lastPage) { + popups = null; + pagination = { + lastPage, + }; + } else { + // Paginate the results by size + popups = popups.slice(begin, end); + + // Prepare the pagination mock-api + pagination = { + length: popupsLength, + size: size, + page: page, + lastPage: lastPage, + startIndex: begin, + endIndex: end - 1, + }; + } + + // Return the response + return [ + 200, + { + popups, + pagination, + }, + ]; + }); + + // ----------------------------------------------------------------------------------------------------- + // @ Popup - GET + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService + .onGet('api/apps/board/popup/popup') + .reply(({ request }) => { + // Get the id from the params + const id = request.params.get('id'); + + // Clone the popups + const popups = cloneDeep(this._popups); + + // Find the popup + const popup = popups.find((item: any) => item.id === id); + + // Return the response + return [200, popup]; + }); + + // ----------------------------------------------------------------------------------------------------- + // @ Popup - POST + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService.onPost('api/apps/board/popup/popup').reply(() => { + // Generate a new popup + const newPopup = { + id: FuseMockApiUtils.guid(), + category: '', + name: 'A New User', + description: '', + tags: [], + sku: '', + barcode: '', + brand: '', + vendor: '', + stock: '', + reserved: '', + cost: '', + basePrice: '', + taxPercent: '', + price: '', + weight: '', + thumbnail: '', + images: [], + active: false, + }; + + // Unshift the new popup + this._popups.unshift(newPopup); + + // Return the response + return [200, newPopup]; + }); + + // ----------------------------------------------------------------------------------------------------- + // @ Popup - PATCH + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService + .onPatch('api/apps/board/popup/popup') + .reply(({ request }) => { + // Get the id and popup + const id = request.body.id; + const popup = cloneDeep(request.body.popup); + + // Prepare the updated popup + let updatedPopup = null; + + // Find the popup and update it + this._popups.forEach((item, index, popups) => { + if (item.id === id) { + // Update the popup + popups[index] = assign({}, popups[index], popup); + + // Store the updated popup + updatedPopup = popups[index]; + } + }); + + // Return the response + return [200, updatedPopup]; + }); + + // ----------------------------------------------------------------------------------------------------- + // @ Popup - DELETE + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService + .onDelete('api/apps/board/popup/popup') + .reply(({ request }) => { + // Get the id + const id = request.params.get('id'); + + // Find the popup and delete it + this._popups.forEach((item, index) => { + if (item.id === id) { + this._popups.splice(index, 1); + } + }); + + // Return the response + return [200, true]; + }); + } +} diff --git a/src/app/mock-api/apps/board/popup/data.ts b/src/app/mock-api/apps/board/popup/data.ts new file mode 100644 index 0000000..2945bfb --- /dev/null +++ b/src/app/mock-api/apps/board/popup/data.ts @@ -0,0 +1,33 @@ +/* eslint-disable */ + +export const popups = [ + { + id: 'on00', + totalPartnerCount: '5', + totalHoldingMoney: 303675, + totalComp: 108933, + total: 412608, + branchCount: 1, + divisionCount: 1, + officeCount: 1, + storeCount: 1, + memberCount: 1, + nickname: 'on00', + accountHolder: '11', + phoneNumber: '010-1111-1111', + calculateType: '롤링', + ownCash: 50000, + ownComp: 1711, + ownCoupon: 50000, + gameMoney: 0, + todayComp: 0, + totalDeposit: 0, + totalWithdraw: 0, + balance: 0, + registDate: '2022-06-12 15:38', + finalSigninDate: '', + ip: '', + state: '정상', + note: '', + }, +]; diff --git a/src/app/mock-api/common/navigation/data.ts b/src/app/mock-api/common/navigation/data.ts index 805f225..3f0f8fd 100644 --- a/src/app/mock-api/common/navigation/data.ts +++ b/src/app/mock-api/common/navigation/data.ts @@ -357,6 +357,36 @@ export const defaultNavigation: FuseNavigationItem[] = [ }, ], }, + { + id: 'board', + title: 'Board', + subtitle: 'board managements', + type: 'group', + icon: 'heroicons_outline:home', + children: [ + { + id: 'board.notice', + title: 'Notice', + type: 'basic', + icon: 'heroicons_outline:academic-cap', + link: '/board/notice', + }, + { + id: 'board.notice-oneline', + title: 'Notice Oneline', + type: 'basic', + icon: 'heroicons_outline:academic-cap', + link: '/board/notice-oneline', + }, + { + id: 'board.popup', + title: 'Popup', + type: 'basic', + icon: 'heroicons_outline:academic-cap', + link: '/board/popup', + }, + ], + }, ]; export const compactNavigation: FuseNavigationItem[] = [ { diff --git a/src/app/mock-api/index.ts b/src/app/mock-api/index.ts index defd1b9..f3aa174 100644 --- a/src/app/mock-api/index.ts +++ b/src/app/mock-api/index.ts @@ -60,6 +60,9 @@ import { ReportSessioninOverlapMockApi } from './apps/report/sessionin-overlap/a import { ReportSessioninAdminMockApi } from './apps/report/sessionin-admin/api'; import { ReportExcelLogMockApi } from './apps/report/excel-log/api'; import { ReportLoosingMockApi } from './apps/report/loosing/api'; +import { BoardNoticeMockApi } from './apps/board/notice/api'; +import { BoardNoticeOnelineMockApi } from './apps/board/notice-oneline/api'; +import { BoardPopupMockApi } from './apps/board/popup/api'; export const mockApiServices = [ AcademyMockApi, @@ -124,4 +127,7 @@ export const mockApiServices = [ ReportSessioninAdminMockApi, ReportExcelLogMockApi, ReportLoosingMockApi, + BoardNoticeMockApi, + BoardNoticeOnelineMockApi, + BoardPopupMockApi, ]; diff --git a/src/app/modules/admin/board/notice-oneline/components/index.ts b/src/app/modules/admin/board/notice-oneline/components/index.ts new file mode 100644 index 0000000..04759eb --- /dev/null +++ b/src/app/modules/admin/board/notice-oneline/components/index.ts @@ -0,0 +1,3 @@ +import { ListComponent } from './list.component'; + +export const COMPONENTS = [ListComponent]; diff --git a/src/app/modules/admin/board/notice-oneline/components/list.component.html b/src/app/modules/admin/board/notice-oneline/components/list.component.html new file mode 100644 index 0000000..c1f0b23 --- /dev/null +++ b/src/app/modules/admin/board/notice-oneline/components/list.component.html @@ -0,0 +1,359 @@ +
+ +
+ +
+ +
+ +
한줄공지
+ +
+ + + + + + + 40 + 60 + 80 + 100 + + + + + LV.1 + LV.2 + LV.3 + LV.4 + + + + + 정상 + 대기 + 탈퇴 + 휴면 + 블랙 + 정지 + + + + + 카지노제한 + 슬롯제한 + + + + + 계좌입금 + + + + + 카지노콤프 + 슬롯콤프 + 배팅콤프 + 첫충콤프 + + + + + + + + + + + + +
+
+ + +
+ +
+ + +
+ +
+ + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ + +
+
+ + +
+ There are no noticeOnelines! +
+
+
+
+
diff --git a/src/app/modules/admin/board/notice-oneline/components/list.component.ts b/src/app/modules/admin/board/notice-oneline/components/list.component.ts new file mode 100644 index 0000000..27e8944 --- /dev/null +++ b/src/app/modules/admin/board/notice-oneline/components/list.component.ts @@ -0,0 +1,198 @@ +import { + AfterViewInit, + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + OnDestroy, + OnInit, + ViewChild, + ViewEncapsulation, +} from '@angular/core'; +import { + FormBuilder, + FormControl, + FormGroup, + Validators, +} from '@angular/forms'; +import { MatCheckboxChange } from '@angular/material/checkbox'; +import { MatPaginator } from '@angular/material/paginator'; +import { MatSort } from '@angular/material/sort'; +import { + debounceTime, + map, + merge, + Observable, + Subject, + switchMap, + takeUntil, +} from 'rxjs'; +import { fuseAnimations } from '@fuse/animations'; +import { FuseConfirmationService } from '@fuse/services/confirmation'; + +import { User } from '../../../member/user/models/user'; +import { NoticeOneline } from '../models/notice-oneline'; +import { NoticeOnelinePagination } from '../models/notice-oneline-pagination'; +import { NoticeOnelineService } from '../services/notice-oneline.service'; +import { Router } from '@angular/router'; + +@Component({ + selector: 'notice-oneline-list', + templateUrl: './list.component.html', + styles: [ + /* language=SCSS */ + ` + .inventory-grid { + grid-template-columns: 60px auto 40px; + + @screen sm { + grid-template-columns: 60px 60px 60px 60px 60px 60px auto 60px; + } + + @screen md { + grid-template-columns: 60px 60px 60px 60px 60px 60px auto 60px 60px; + } + + @screen lg { + grid-template-columns: 60px 70px 70px 70px 70px 100px 60px 60px auto 60px 60px 60px 60px; + } + } + `, + ], + encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush, + animations: fuseAnimations, +}) +export class ListComponent implements OnInit, AfterViewInit, OnDestroy { + @ViewChild(MatPaginator) private _paginator!: MatPaginator; + @ViewChild(MatSort) private _sort!: MatSort; + + noticeOnelines$!: Observable; + users$!: Observable; + + isLoading = false; + searchInputControl = new FormControl(); + selectedNoticeOneline?: NoticeOneline; + pagination?: NoticeOnelinePagination; + + private _unsubscribeAll: Subject = new Subject(); + + /** + * Constructor + */ + constructor( + private _changeDetectorRef: ChangeDetectorRef, + private _fuseConfirmationService: FuseConfirmationService, + private _formBuilder: FormBuilder, + private _noticeOnelineService: NoticeOnelineService, + private router: Router + ) {} + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void { + // Get the pagination + this._noticeOnelineService.pagination$ + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe((pagination: NoticeOnelinePagination | undefined) => { + // Update the pagination + this.pagination = pagination; + + // Mark for check + this._changeDetectorRef.markForCheck(); + }); + + // Get the products + this.noticeOnelines$ = this._noticeOnelineService.noticeOnelines$; + } + + /** + * After view init + */ + ngAfterViewInit(): void { + if (this._sort && this._paginator) { + // Set the initial sort + this._sort.sort({ + id: 'name', + start: 'asc', + disableClear: true, + }); + + // Mark for check + this._changeDetectorRef.markForCheck(); + + // If the noticeOneline changes the sort order... + this._sort.sortChange + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(() => { + // Reset back to the first page + this._paginator.pageIndex = 0; + }); + + // Get products if sort or page changes + merge(this._sort.sortChange, this._paginator.page) + .pipe( + switchMap(() => { + this.isLoading = true; + return this._noticeOnelineService.getNoticeOnelines( + this._paginator.pageIndex, + this._paginator.pageSize, + this._sort.active, + this._sort.direction + ); + }), + map(() => { + this.isLoading = false; + }) + ) + .subscribe(); + } + } + + /** + * On destroy + */ + ngOnDestroy(): void { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(null); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + viewUserDetail(id: string): void { + let url: string = 'member/user/' + id; + this.router.navigateByUrl(url); + } + // ----------------------------------------------------------------------------------------------------- + // @ Private methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Create product + */ + __createProduct(): void {} + + /** + * Toggle product details + * + * @param productId + */ + __toggleDetails(productId: string): void {} + + /** + * Track by function for ngFor loops + * + * @param index + * @param item + */ + __trackByFn(index: number, item: any): any { + return item.id || index; + } +} diff --git a/src/app/modules/admin/board/notice-oneline/models/notice-oneline-pagination.ts b/src/app/modules/admin/board/notice-oneline/models/notice-oneline-pagination.ts new file mode 100644 index 0000000..0015771 --- /dev/null +++ b/src/app/modules/admin/board/notice-oneline/models/notice-oneline-pagination.ts @@ -0,0 +1,8 @@ +export interface NoticeOnelinePagination { + length: number; + size: number; + page: number; + lastPage: number; + startIndex: number; + endIndex: number; +} diff --git a/src/app/modules/admin/board/notice-oneline/models/notice-oneline.ts b/src/app/modules/admin/board/notice-oneline/models/notice-oneline.ts new file mode 100644 index 0000000..0bdc5a9 --- /dev/null +++ b/src/app/modules/admin/board/notice-oneline/models/notice-oneline.ts @@ -0,0 +1,29 @@ +export interface NoticeOneline { + id?: string; + totalPartnerCount?: number; + totalHoldingMoney?: number; + totalComp?: number; + total?: number; + branchCount?: number; + divisionCount?: number; + officeCount?: number; + storeCount?: number; + memberCount?: number; + nickname?: string; + accountHolder?: string; + phoneNumber?: string; + calculateType?: string; + ownCash?: number; + ownComp?: number; + ownCoupon?: number; + gameMoney?: number; + todayComp?: number; + totalDeposit?: number; + totalWithdraw?: number; + balance?: number; + registDate?: string; + finalSigninDate?: string; + ip?: string; + state?: string; + note?: string; +} diff --git a/src/app/modules/admin/board/notice-oneline/notice-oneline.module.ts b/src/app/modules/admin/board/notice-oneline/notice-oneline.module.ts new file mode 100644 index 0000000..a72789f --- /dev/null +++ b/src/app/modules/admin/board/notice-oneline/notice-oneline.module.ts @@ -0,0 +1,50 @@ +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; + +import { MatButtonModule } from '@angular/material/button'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatIconModule } from '@angular/material/icon'; +import { MatInputModule } from '@angular/material/input'; +import { MatPaginatorModule } from '@angular/material/paginator'; +import { MatProgressBarModule } from '@angular/material/progress-bar'; +import { MatRippleModule } from '@angular/material/core'; +import { MatSortModule } from '@angular/material/sort'; +import { MatSelectModule } from '@angular/material/select'; +import { MatTooltipModule } from '@angular/material/tooltip'; +import { MatGridListModule } from '@angular/material/grid-list'; +import { MatSlideToggleModule } from '@angular/material/slide-toggle'; +import { MatRadioModule } from '@angular/material/radio'; +import { MatCheckboxModule } from '@angular/material/checkbox'; + +import { TranslocoModule } from '@ngneat/transloco'; + +import { SharedModule } from 'app/shared/shared.module'; + +import { COMPONENTS } from './components'; + +import { noticeOnelineRoutes } from './notice-oneline.routing'; + +@NgModule({ + declarations: [COMPONENTS], + imports: [ + TranslocoModule, + SharedModule, + RouterModule.forChild(noticeOnelineRoutes), + + MatButtonModule, + MatFormFieldModule, + MatIconModule, + MatInputModule, + MatPaginatorModule, + MatProgressBarModule, + MatRippleModule, + MatSortModule, + MatSelectModule, + MatTooltipModule, + MatGridListModule, + MatSlideToggleModule, + MatRadioModule, + MatCheckboxModule, + ], +}) +export class NoticeOnelineModule {} diff --git a/src/app/modules/admin/board/notice-oneline/notice-oneline.routing.ts b/src/app/modules/admin/board/notice-oneline/notice-oneline.routing.ts new file mode 100644 index 0000000..06471ca --- /dev/null +++ b/src/app/modules/admin/board/notice-oneline/notice-oneline.routing.ts @@ -0,0 +1,24 @@ +import { Route } from '@angular/router'; + +import { ListComponent } from './components/list.component'; +import { ViewComponent } from '../../member/user/components/view.component'; + +import { NoticeOnelinesResolver } from './resolvers/notice-oneline.resolver'; +import { UserResolver } from '../../member/user/resolvers/user.resolver'; + +export const noticeOnelineRoutes: Route[] = [ + { + path: '', + component: ListComponent, + resolve: { + noticeOnelines: NoticeOnelinesResolver, + }, + }, + { + path: ':id', + component: ViewComponent, + resolve: { + users: UserResolver, + }, + }, +]; diff --git a/src/app/modules/admin/board/notice-oneline/resolvers/notice-oneline.resolver.ts b/src/app/modules/admin/board/notice-oneline/resolvers/notice-oneline.resolver.ts new file mode 100644 index 0000000..9cf54c8 --- /dev/null +++ b/src/app/modules/admin/board/notice-oneline/resolvers/notice-oneline.resolver.ts @@ -0,0 +1,89 @@ +import { Injectable } from '@angular/core'; +import { + ActivatedRouteSnapshot, + Resolve, + Router, + RouterStateSnapshot, +} from '@angular/router'; +import { catchError, Observable, throwError } from 'rxjs'; + +import { NoticeOneline } from '../models/notice-oneline'; +import { NoticeOnelinePagination } from '../models/notice-oneline-pagination'; +import { NoticeOnelineService } from '../services/notice-oneline.service'; + +@Injectable({ + providedIn: 'root', +}) +export class NoticeOnelineResolver implements Resolve { + /** + * Constructor + */ + constructor( + private _noticeOnelineService: NoticeOnelineService, + private _router: Router + ) {} + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Resolver + * + * @param route + * @param state + */ + resolve( + route: ActivatedRouteSnapshot, + state: RouterStateSnapshot + ): Observable { + return this._noticeOnelineService + .getNoticeOnelineById(route.paramMap.get('id')) + .pipe( + // Error here means the requested product is not available + catchError((error) => { + // Log the error + console.error(error); + + // Get the parent url + const parentUrl = state.url.split('/').slice(0, -1).join('/'); + + // Navigate to there + this._router.navigateByUrl(parentUrl); + + // Throw an error + return throwError(error); + }) + ); + } +} + +@Injectable({ + providedIn: 'root', +}) +export class NoticeOnelinesResolver implements Resolve { + /** + * Constructor + */ + constructor(private _noticeOnelineService: NoticeOnelineService) {} + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Resolver + * + * @param route + * @param state + */ + resolve( + route: ActivatedRouteSnapshot, + state: RouterStateSnapshot + ): Observable<{ + pagination: NoticeOnelinePagination; + noticeOnelines: NoticeOneline[]; + }> { + return this._noticeOnelineService.getNoticeOnelines(); + } +} diff --git a/src/app/modules/admin/board/notice-oneline/services/notice-oneline.service.ts b/src/app/modules/admin/board/notice-oneline/services/notice-oneline.service.ts new file mode 100644 index 0000000..611bfbf --- /dev/null +++ b/src/app/modules/admin/board/notice-oneline/services/notice-oneline.service.ts @@ -0,0 +1,161 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { + BehaviorSubject, + filter, + map, + Observable, + of, + switchMap, + take, + tap, + throwError, +} from 'rxjs'; + +import { NoticeOneline } from '../models/notice-oneline'; +import { NoticeOnelinePagination } from '../models/notice-oneline-pagination'; + +@Injectable({ + providedIn: 'root', +}) +export class NoticeOnelineService { + // Private + private __pagination = new BehaviorSubject< + NoticeOnelinePagination | undefined + >(undefined); + private __noticeOneline = new BehaviorSubject( + undefined + ); + private __noticeOnelines = new BehaviorSubject( + undefined + ); + + /** + * Constructor + */ + constructor(private _httpClient: HttpClient) {} + + // ----------------------------------------------------------------------------------------------------- + // @ Accessors + // ----------------------------------------------------------------------------------------------------- + + /** + * Getter for pagination + */ + get pagination$(): Observable { + return this.__pagination.asObservable(); + } + + /** + * Getter for noticeOneline + */ + get noticeOneline$(): Observable { + return this.__noticeOneline.asObservable(); + } + + /** + * Getter for noticeOnelines + */ + get noticeOnelines$(): Observable { + return this.__noticeOnelines.asObservable(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Get NoticeOnelines + * + * + * @param page + * @param size + * @param sort + * @param order + * @param search + */ + getNoticeOnelines( + page: number = 0, + size: number = 10, + sort: string = 'name', + order: 'asc' | 'desc' | '' = 'asc', + search: string = '' + ): Observable<{ + pagination: NoticeOnelinePagination; + noticeOnelines: NoticeOneline[]; + }> { + return this._httpClient + .get<{ + pagination: NoticeOnelinePagination; + noticeOnelines: NoticeOneline[]; + }>('api/apps/board/notice-oneline/notice-onelines', { + params: { + page: '' + page, + size: '' + size, + sort, + order, + search, + }, + }) + .pipe( + tap((response) => { + this.__pagination.next(response.pagination); + this.__noticeOnelines.next(response.noticeOnelines); + }) + ); + } + + /** + * Get product by id + */ + getNoticeOnelineById(id: string | null): Observable { + return this.__noticeOnelines.pipe( + take(1), + map((noticeOnelines) => { + // Find the product + const noticeOneline = + noticeOnelines?.find((item) => item.id === id) || undefined; + + // Update the product + this.__noticeOneline.next(noticeOneline); + + // Return the product + return noticeOneline; + }), + switchMap((product) => { + if (!product) { + return throwError('Could not found product with id of ' + id + '!'); + } + + return of(product); + }) + ); + } + + /** + * Create product + */ + createNoticeOneline(): Observable { + return this.noticeOnelines$.pipe( + take(1), + switchMap((noticeOnelines) => + this._httpClient + .post('api/apps/board/notice-oneline/product', {}) + .pipe( + map((newNoticeOneline) => { + // Update the noticeOnelines with the new product + if (!!noticeOnelines) { + this.__noticeOnelines.next([ + newNoticeOneline, + ...noticeOnelines, + ]); + } + + // Return the new product + return newNoticeOneline; + }) + ) + ) + ); + } +} diff --git a/src/app/modules/admin/board/notice/components/index.ts b/src/app/modules/admin/board/notice/components/index.ts new file mode 100644 index 0000000..04759eb --- /dev/null +++ b/src/app/modules/admin/board/notice/components/index.ts @@ -0,0 +1,3 @@ +import { ListComponent } from './list.component'; + +export const COMPONENTS = [ListComponent]; diff --git a/src/app/modules/admin/board/notice/components/list.component.html b/src/app/modules/admin/board/notice/components/list.component.html new file mode 100644 index 0000000..3b0681f --- /dev/null +++ b/src/app/modules/admin/board/notice/components/list.component.html @@ -0,0 +1,355 @@ +
+ +
+ +
+ +
+ +
공지사항
+ +
+ + + + + + + 40 + 60 + 80 + 100 + + + + + LV.1 + LV.2 + LV.3 + LV.4 + + + + + 정상 + 대기 + 탈퇴 + 휴면 + 블랙 + 정지 + + + + + 카지노제한 + 슬롯제한 + + + + + 계좌입금 + + + + + 카지노콤프 + 슬롯콤프 + 배팅콤프 + 첫충콤프 + + + + + + + + + + + + +
+
+ + +
+ +
+ + +
+ +
+ + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ + +
+
+ + +
+ There are no notices! +
+
+
+
+
diff --git a/src/app/modules/admin/board/notice/components/list.component.ts b/src/app/modules/admin/board/notice/components/list.component.ts new file mode 100644 index 0000000..812f993 --- /dev/null +++ b/src/app/modules/admin/board/notice/components/list.component.ts @@ -0,0 +1,198 @@ +import { + AfterViewInit, + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + OnDestroy, + OnInit, + ViewChild, + ViewEncapsulation, +} from '@angular/core'; +import { + FormBuilder, + FormControl, + FormGroup, + Validators, +} from '@angular/forms'; +import { MatCheckboxChange } from '@angular/material/checkbox'; +import { MatPaginator } from '@angular/material/paginator'; +import { MatSort } from '@angular/material/sort'; +import { + debounceTime, + map, + merge, + Observable, + Subject, + switchMap, + takeUntil, +} from 'rxjs'; +import { fuseAnimations } from '@fuse/animations'; +import { FuseConfirmationService } from '@fuse/services/confirmation'; + +import { User } from '../../../member/user/models/user'; +import { Notice } from '../models/notice'; +import { NoticePagination } from '../models/notice-pagination'; +import { NoticeService } from '../services/notice.service'; +import { Router } from '@angular/router'; + +@Component({ + selector: 'notice-list', + templateUrl: './list.component.html', + styles: [ + /* language=SCSS */ + ` + .inventory-grid { + grid-template-columns: 60px auto 40px; + + @screen sm { + grid-template-columns: 60px 60px 60px 60px 60px 60px auto 60px; + } + + @screen md { + grid-template-columns: 60px 60px 60px 60px 60px 60px auto 60px 60px; + } + + @screen lg { + grid-template-columns: 60px 70px 70px 70px 70px 100px 60px 60px auto 60px 60px 60px 60px; + } + } + `, + ], + encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush, + animations: fuseAnimations, +}) +export class ListComponent implements OnInit, AfterViewInit, OnDestroy { + @ViewChild(MatPaginator) private _paginator!: MatPaginator; + @ViewChild(MatSort) private _sort!: MatSort; + + notices$!: Observable; + users$!: Observable; + + isLoading = false; + searchInputControl = new FormControl(); + selectedNotice?: Notice; + pagination?: NoticePagination; + + private _unsubscribeAll: Subject = new Subject(); + + /** + * Constructor + */ + constructor( + private _changeDetectorRef: ChangeDetectorRef, + private _fuseConfirmationService: FuseConfirmationService, + private _formBuilder: FormBuilder, + private _noticeService: NoticeService, + private router: Router + ) {} + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void { + // Get the pagination + this._noticeService.pagination$ + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe((pagination: NoticePagination | undefined) => { + // Update the pagination + this.pagination = pagination; + + // Mark for check + this._changeDetectorRef.markForCheck(); + }); + + // Get the products + this.notices$ = this._noticeService.notices$; + } + + /** + * After view init + */ + ngAfterViewInit(): void { + if (this._sort && this._paginator) { + // Set the initial sort + this._sort.sort({ + id: 'name', + start: 'asc', + disableClear: true, + }); + + // Mark for check + this._changeDetectorRef.markForCheck(); + + // If the notice changes the sort order... + this._sort.sortChange + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(() => { + // Reset back to the first page + this._paginator.pageIndex = 0; + }); + + // Get products if sort or page changes + merge(this._sort.sortChange, this._paginator.page) + .pipe( + switchMap(() => { + this.isLoading = true; + return this._noticeService.getNotices( + this._paginator.pageIndex, + this._paginator.pageSize, + this._sort.active, + this._sort.direction + ); + }), + map(() => { + this.isLoading = false; + }) + ) + .subscribe(); + } + } + + /** + * On destroy + */ + ngOnDestroy(): void { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(null); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + viewUserDetail(id: string): void { + let url: string = 'member/user/' + id; + this.router.navigateByUrl(url); + } + // ----------------------------------------------------------------------------------------------------- + // @ Private methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Create product + */ + __createProduct(): void {} + + /** + * Toggle product details + * + * @param productId + */ + __toggleDetails(productId: string): void {} + + /** + * Track by function for ngFor loops + * + * @param index + * @param item + */ + __trackByFn(index: number, item: any): any { + return item.id || index; + } +} diff --git a/src/app/modules/admin/board/notice/models/notice-pagination.ts b/src/app/modules/admin/board/notice/models/notice-pagination.ts new file mode 100644 index 0000000..1df4d0a --- /dev/null +++ b/src/app/modules/admin/board/notice/models/notice-pagination.ts @@ -0,0 +1,8 @@ +export interface NoticePagination { + length: number; + size: number; + page: number; + lastPage: number; + startIndex: number; + endIndex: number; +} diff --git a/src/app/modules/admin/board/notice/models/notice.ts b/src/app/modules/admin/board/notice/models/notice.ts new file mode 100644 index 0000000..d88ca9e --- /dev/null +++ b/src/app/modules/admin/board/notice/models/notice.ts @@ -0,0 +1,29 @@ +export interface Notice { + id?: string; + totalPartnerCount?: number; + totalHoldingMoney?: number; + totalComp?: number; + total?: number; + branchCount?: number; + divisionCount?: number; + officeCount?: number; + storeCount?: number; + memberCount?: number; + nickname?: string; + accountHolder?: string; + phoneNumber?: string; + calculateType?: string; + ownCash?: number; + ownComp?: number; + ownCoupon?: number; + gameMoney?: number; + todayComp?: number; + totalDeposit?: number; + totalWithdraw?: number; + balance?: number; + registDate?: string; + finalSigninDate?: string; + ip?: string; + state?: string; + note?: string; +} diff --git a/src/app/modules/admin/board/notice/notice.module.ts b/src/app/modules/admin/board/notice/notice.module.ts new file mode 100644 index 0000000..0ffebc2 --- /dev/null +++ b/src/app/modules/admin/board/notice/notice.module.ts @@ -0,0 +1,50 @@ +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; + +import { MatButtonModule } from '@angular/material/button'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatIconModule } from '@angular/material/icon'; +import { MatInputModule } from '@angular/material/input'; +import { MatPaginatorModule } from '@angular/material/paginator'; +import { MatProgressBarModule } from '@angular/material/progress-bar'; +import { MatRippleModule } from '@angular/material/core'; +import { MatSortModule } from '@angular/material/sort'; +import { MatSelectModule } from '@angular/material/select'; +import { MatTooltipModule } from '@angular/material/tooltip'; +import { MatGridListModule } from '@angular/material/grid-list'; +import { MatSlideToggleModule } from '@angular/material/slide-toggle'; +import { MatRadioModule } from '@angular/material/radio'; +import { MatCheckboxModule } from '@angular/material/checkbox'; + +import { TranslocoModule } from '@ngneat/transloco'; + +import { SharedModule } from 'app/shared/shared.module'; + +import { COMPONENTS } from './components'; + +import { noticeRoutes } from './notice.routing'; + +@NgModule({ + declarations: [COMPONENTS], + imports: [ + TranslocoModule, + SharedModule, + RouterModule.forChild(noticeRoutes), + + MatButtonModule, + MatFormFieldModule, + MatIconModule, + MatInputModule, + MatPaginatorModule, + MatProgressBarModule, + MatRippleModule, + MatSortModule, + MatSelectModule, + MatTooltipModule, + MatGridListModule, + MatSlideToggleModule, + MatRadioModule, + MatCheckboxModule, + ], +}) +export class NoticeModule {} diff --git a/src/app/modules/admin/board/notice/notice.routing.ts b/src/app/modules/admin/board/notice/notice.routing.ts new file mode 100644 index 0000000..04c30c6 --- /dev/null +++ b/src/app/modules/admin/board/notice/notice.routing.ts @@ -0,0 +1,24 @@ +import { Route } from '@angular/router'; + +import { ListComponent } from './components/list.component'; +import { ViewComponent } from '../../member/user/components/view.component'; + +import { NoticesResolver } from './resolvers/notice.resolver'; +import { UserResolver } from '../../member/user/resolvers/user.resolver'; + +export const noticeRoutes: Route[] = [ + { + path: '', + component: ListComponent, + resolve: { + notices: NoticesResolver, + }, + }, + { + path: ':id', + component: ViewComponent, + resolve: { + users: UserResolver, + }, + }, +]; diff --git a/src/app/modules/admin/board/notice/resolvers/notice.resolver.ts b/src/app/modules/admin/board/notice/resolvers/notice.resolver.ts new file mode 100644 index 0000000..fb5b3b5 --- /dev/null +++ b/src/app/modules/admin/board/notice/resolvers/notice.resolver.ts @@ -0,0 +1,84 @@ +import { Injectable } from '@angular/core'; +import { + ActivatedRouteSnapshot, + Resolve, + Router, + RouterStateSnapshot, +} from '@angular/router'; +import { catchError, Observable, throwError } from 'rxjs'; + +import { Notice } from '../models/notice'; +import { NoticePagination } from '../models/notice-pagination'; +import { NoticeService } from '../services/notice.service'; + +@Injectable({ + providedIn: 'root', +}) +export class NoticeResolver implements Resolve { + /** + * Constructor + */ + constructor(private _noticeService: NoticeService, private _router: Router) {} + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Resolver + * + * @param route + * @param state + */ + resolve( + route: ActivatedRouteSnapshot, + state: RouterStateSnapshot + ): Observable { + return this._noticeService.getNoticeById(route.paramMap.get('id')).pipe( + // Error here means the requested product is not available + catchError((error) => { + // Log the error + console.error(error); + + // Get the parent url + const parentUrl = state.url.split('/').slice(0, -1).join('/'); + + // Navigate to there + this._router.navigateByUrl(parentUrl); + + // Throw an error + return throwError(error); + }) + ); + } +} + +@Injectable({ + providedIn: 'root', +}) +export class NoticesResolver implements Resolve { + /** + * Constructor + */ + constructor(private _noticeService: NoticeService) {} + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Resolver + * + * @param route + * @param state + */ + resolve( + route: ActivatedRouteSnapshot, + state: RouterStateSnapshot + ): Observable<{ + pagination: NoticePagination; + notices: Notice[]; + }> { + return this._noticeService.getNotices(); + } +} diff --git a/src/app/modules/admin/board/notice/services/notice.service.ts b/src/app/modules/admin/board/notice/services/notice.service.ts new file mode 100644 index 0000000..a8a52a8 --- /dev/null +++ b/src/app/modules/admin/board/notice/services/notice.service.ts @@ -0,0 +1,151 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { + BehaviorSubject, + filter, + map, + Observable, + of, + switchMap, + take, + tap, + throwError, +} from 'rxjs'; + +import { Notice } from '../models/notice'; +import { NoticePagination } from '../models/notice-pagination'; + +@Injectable({ + providedIn: 'root', +}) +export class NoticeService { + // Private + private __pagination = new BehaviorSubject( + undefined + ); + private __notice = new BehaviorSubject(undefined); + private __notices = new BehaviorSubject(undefined); + + /** + * Constructor + */ + constructor(private _httpClient: HttpClient) {} + + // ----------------------------------------------------------------------------------------------------- + // @ Accessors + // ----------------------------------------------------------------------------------------------------- + + /** + * Getter for pagination + */ + get pagination$(): Observable { + return this.__pagination.asObservable(); + } + + /** + * Getter for notice + */ + get notice$(): Observable { + return this.__notice.asObservable(); + } + + /** + * Getter for notices + */ + get notices$(): Observable { + return this.__notices.asObservable(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Get Notices + * + * + * @param page + * @param size + * @param sort + * @param order + * @param search + */ + getNotices( + page: number = 0, + size: number = 10, + sort: string = 'name', + order: 'asc' | 'desc' | '' = 'asc', + search: string = '' + ): Observable<{ + pagination: NoticePagination; + notices: Notice[]; + }> { + return this._httpClient + .get<{ + pagination: NoticePagination; + notices: Notice[]; + }>('api/apps/board/notice/notices', { + params: { + page: '' + page, + size: '' + size, + sort, + order, + search, + }, + }) + .pipe( + tap((response) => { + this.__pagination.next(response.pagination); + this.__notices.next(response.notices); + }) + ); + } + + /** + * Get product by id + */ + getNoticeById(id: string | null): Observable { + return this.__notices.pipe( + take(1), + map((notices) => { + // Find the product + const notice = notices?.find((item) => item.id === id) || undefined; + + // Update the product + this.__notice.next(notice); + + // Return the product + return notice; + }), + switchMap((product) => { + if (!product) { + return throwError('Could not found product with id of ' + id + '!'); + } + + return of(product); + }) + ); + } + + /** + * Create product + */ + createNotice(): Observable { + return this.notices$.pipe( + take(1), + switchMap((notices) => + this._httpClient.post('api/apps/board/notice/product', {}).pipe( + map((newNotice) => { + // Update the notices with the new product + if (!!notices) { + this.__notices.next([newNotice, ...notices]); + } + + // Return the new product + return newNotice; + }) + ) + ) + ); + } +} diff --git a/src/app/modules/admin/board/popup/components/index.ts b/src/app/modules/admin/board/popup/components/index.ts new file mode 100644 index 0000000..04759eb --- /dev/null +++ b/src/app/modules/admin/board/popup/components/index.ts @@ -0,0 +1,3 @@ +import { ListComponent } from './list.component'; + +export const COMPONENTS = [ListComponent]; diff --git a/src/app/modules/admin/board/popup/components/list.component.html b/src/app/modules/admin/board/popup/components/list.component.html new file mode 100644 index 0000000..68c5687 --- /dev/null +++ b/src/app/modules/admin/board/popup/components/list.component.html @@ -0,0 +1,353 @@ +
+ +
+ +
+ +
+ +
팝업
+ +
+ + + + + + + 40 + 60 + 80 + 100 + + + + + LV.1 + LV.2 + LV.3 + LV.4 + + + + + 정상 + 대기 + 탈퇴 + 휴면 + 블랙 + 정지 + + + + + 카지노제한 + 슬롯제한 + + + + + 계좌입금 + + + + + 카지노콤프 + 슬롯콤프 + 배팅콤프 + 첫충콤프 + + + + + + + + + + + + +
+
+ + +
+ +
+ + +
+ +
+ + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ + +
+
+ + +
+ There are no popups! +
+
+
+
+
diff --git a/src/app/modules/admin/board/popup/components/list.component.ts b/src/app/modules/admin/board/popup/components/list.component.ts new file mode 100644 index 0000000..9effff6 --- /dev/null +++ b/src/app/modules/admin/board/popup/components/list.component.ts @@ -0,0 +1,198 @@ +import { + AfterViewInit, + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + OnDestroy, + OnInit, + ViewChild, + ViewEncapsulation, +} from '@angular/core'; +import { + FormBuilder, + FormControl, + FormGroup, + Validators, +} from '@angular/forms'; +import { MatCheckboxChange } from '@angular/material/checkbox'; +import { MatPaginator } from '@angular/material/paginator'; +import { MatSort } from '@angular/material/sort'; +import { + debounceTime, + map, + merge, + Observable, + Subject, + switchMap, + takeUntil, +} from 'rxjs'; +import { fuseAnimations } from '@fuse/animations'; +import { FuseConfirmationService } from '@fuse/services/confirmation'; + +import { User } from '../../../member/user/models/user'; +import { Popup } from '../models/popup'; +import { PopupPagination } from '../models/popup-pagination'; +import { PopupService } from '../services/popup.service'; +import { Router } from '@angular/router'; + +@Component({ + selector: 'popup-list', + templateUrl: './list.component.html', + styles: [ + /* language=SCSS */ + ` + .inventory-grid { + grid-template-columns: 60px auto 40px; + + @screen sm { + grid-template-columns: 60px 60px 60px 60px 60px 60px auto 60px; + } + + @screen md { + grid-template-columns: 60px 60px 60px 60px 60px 60px auto 60px 60px; + } + + @screen lg { + grid-template-columns: 60px 70px 70px 70px 70px 100px 60px 60px auto 60px 60px 60px 60px; + } + } + `, + ], + encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush, + animations: fuseAnimations, +}) +export class ListComponent implements OnInit, AfterViewInit, OnDestroy { + @ViewChild(MatPaginator) private _paginator!: MatPaginator; + @ViewChild(MatSort) private _sort!: MatSort; + + popups$!: Observable; + users$!: Observable; + + isLoading = false; + searchInputControl = new FormControl(); + selectedPopup?: Popup; + pagination?: PopupPagination; + + private _unsubscribeAll: Subject = new Subject(); + + /** + * Constructor + */ + constructor( + private _changeDetectorRef: ChangeDetectorRef, + private _fuseConfirmationService: FuseConfirmationService, + private _formBuilder: FormBuilder, + private _popupService: PopupService, + private router: Router + ) {} + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void { + // Get the pagination + this._popupService.pagination$ + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe((pagination: PopupPagination | undefined) => { + // Update the pagination + this.pagination = pagination; + + // Mark for check + this._changeDetectorRef.markForCheck(); + }); + + // Get the products + this.popups$ = this._popupService.popups$; + } + + /** + * After view init + */ + ngAfterViewInit(): void { + if (this._sort && this._paginator) { + // Set the initial sort + this._sort.sort({ + id: 'name', + start: 'asc', + disableClear: true, + }); + + // Mark for check + this._changeDetectorRef.markForCheck(); + + // If the popup changes the sort order... + this._sort.sortChange + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(() => { + // Reset back to the first page + this._paginator.pageIndex = 0; + }); + + // Get products if sort or page changes + merge(this._sort.sortChange, this._paginator.page) + .pipe( + switchMap(() => { + this.isLoading = true; + return this._popupService.getPopups( + this._paginator.pageIndex, + this._paginator.pageSize, + this._sort.active, + this._sort.direction + ); + }), + map(() => { + this.isLoading = false; + }) + ) + .subscribe(); + } + } + + /** + * On destroy + */ + ngOnDestroy(): void { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(null); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + viewUserDetail(id: string): void { + let url: string = 'member/user/' + id; + this.router.navigateByUrl(url); + } + // ----------------------------------------------------------------------------------------------------- + // @ Private methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Create product + */ + __createProduct(): void {} + + /** + * Toggle product details + * + * @param productId + */ + __toggleDetails(productId: string): void {} + + /** + * Track by function for ngFor loops + * + * @param index + * @param item + */ + __trackByFn(index: number, item: any): any { + return item.id || index; + } +} diff --git a/src/app/modules/admin/board/popup/models/popup-pagination.ts b/src/app/modules/admin/board/popup/models/popup-pagination.ts new file mode 100644 index 0000000..64182c5 --- /dev/null +++ b/src/app/modules/admin/board/popup/models/popup-pagination.ts @@ -0,0 +1,8 @@ +export interface PopupPagination { + length: number; + size: number; + page: number; + lastPage: number; + startIndex: number; + endIndex: number; +} diff --git a/src/app/modules/admin/board/popup/models/popup.ts b/src/app/modules/admin/board/popup/models/popup.ts new file mode 100644 index 0000000..533f1bf --- /dev/null +++ b/src/app/modules/admin/board/popup/models/popup.ts @@ -0,0 +1,29 @@ +export interface Popup { + id?: string; + totalPartnerCount?: number; + totalHoldingMoney?: number; + totalComp?: number; + total?: number; + branchCount?: number; + divisionCount?: number; + officeCount?: number; + storeCount?: number; + memberCount?: number; + nickname?: string; + accountHolder?: string; + phoneNumber?: string; + calculateType?: string; + ownCash?: number; + ownComp?: number; + ownCoupon?: number; + gameMoney?: number; + todayComp?: number; + totalDeposit?: number; + totalWithdraw?: number; + balance?: number; + registDate?: string; + finalSigninDate?: string; + ip?: string; + state?: string; + note?: string; +} diff --git a/src/app/modules/admin/board/popup/popup.module.ts b/src/app/modules/admin/board/popup/popup.module.ts new file mode 100644 index 0000000..0691ccc --- /dev/null +++ b/src/app/modules/admin/board/popup/popup.module.ts @@ -0,0 +1,50 @@ +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; + +import { MatButtonModule } from '@angular/material/button'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatIconModule } from '@angular/material/icon'; +import { MatInputModule } from '@angular/material/input'; +import { MatPaginatorModule } from '@angular/material/paginator'; +import { MatProgressBarModule } from '@angular/material/progress-bar'; +import { MatRippleModule } from '@angular/material/core'; +import { MatSortModule } from '@angular/material/sort'; +import { MatSelectModule } from '@angular/material/select'; +import { MatTooltipModule } from '@angular/material/tooltip'; +import { MatGridListModule } from '@angular/material/grid-list'; +import { MatSlideToggleModule } from '@angular/material/slide-toggle'; +import { MatRadioModule } from '@angular/material/radio'; +import { MatCheckboxModule } from '@angular/material/checkbox'; + +import { TranslocoModule } from '@ngneat/transloco'; + +import { SharedModule } from 'app/shared/shared.module'; + +import { COMPONENTS } from './components'; + +import { popupRoutes } from './popup.routing'; + +@NgModule({ + declarations: [COMPONENTS], + imports: [ + TranslocoModule, + SharedModule, + RouterModule.forChild(popupRoutes), + + MatButtonModule, + MatFormFieldModule, + MatIconModule, + MatInputModule, + MatPaginatorModule, + MatProgressBarModule, + MatRippleModule, + MatSortModule, + MatSelectModule, + MatTooltipModule, + MatGridListModule, + MatSlideToggleModule, + MatRadioModule, + MatCheckboxModule, + ], +}) +export class PopupModule {} diff --git a/src/app/modules/admin/board/popup/popup.routing.ts b/src/app/modules/admin/board/popup/popup.routing.ts new file mode 100644 index 0000000..4a53e31 --- /dev/null +++ b/src/app/modules/admin/board/popup/popup.routing.ts @@ -0,0 +1,24 @@ +import { Route } from '@angular/router'; + +import { ListComponent } from './components/list.component'; +import { ViewComponent } from '../../member/user/components/view.component'; + +import { PopupsResolver } from './resolvers/popup.resolver'; +import { UserResolver } from '../../member/user/resolvers/user.resolver'; + +export const popupRoutes: Route[] = [ + { + path: '', + component: ListComponent, + resolve: { + popups: PopupsResolver, + }, + }, + { + path: ':id', + component: ViewComponent, + resolve: { + users: UserResolver, + }, + }, +]; diff --git a/src/app/modules/admin/board/popup/resolvers/popup.resolver.ts b/src/app/modules/admin/board/popup/resolvers/popup.resolver.ts new file mode 100644 index 0000000..ebd8222 --- /dev/null +++ b/src/app/modules/admin/board/popup/resolvers/popup.resolver.ts @@ -0,0 +1,84 @@ +import { Injectable } from '@angular/core'; +import { + ActivatedRouteSnapshot, + Resolve, + Router, + RouterStateSnapshot, +} from '@angular/router'; +import { catchError, Observable, throwError } from 'rxjs'; + +import { Popup } from '../models/popup'; +import { PopupPagination } from '../models/popup-pagination'; +import { PopupService } from '../services/popup.service'; + +@Injectable({ + providedIn: 'root', +}) +export class PopupResolver implements Resolve { + /** + * Constructor + */ + constructor(private _popupService: PopupService, private _router: Router) {} + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Resolver + * + * @param route + * @param state + */ + resolve( + route: ActivatedRouteSnapshot, + state: RouterStateSnapshot + ): Observable { + return this._popupService.getPopupById(route.paramMap.get('id')).pipe( + // Error here means the requested product is not available + catchError((error) => { + // Log the error + console.error(error); + + // Get the parent url + const parentUrl = state.url.split('/').slice(0, -1).join('/'); + + // Navigate to there + this._router.navigateByUrl(parentUrl); + + // Throw an error + return throwError(error); + }) + ); + } +} + +@Injectable({ + providedIn: 'root', +}) +export class PopupsResolver implements Resolve { + /** + * Constructor + */ + constructor(private _popupService: PopupService) {} + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Resolver + * + * @param route + * @param state + */ + resolve( + route: ActivatedRouteSnapshot, + state: RouterStateSnapshot + ): Observable<{ + pagination: PopupPagination; + popups: Popup[]; + }> { + return this._popupService.getPopups(); + } +} diff --git a/src/app/modules/admin/board/popup/services/popup.service.ts b/src/app/modules/admin/board/popup/services/popup.service.ts new file mode 100644 index 0000000..b228337 --- /dev/null +++ b/src/app/modules/admin/board/popup/services/popup.service.ts @@ -0,0 +1,151 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { + BehaviorSubject, + filter, + map, + Observable, + of, + switchMap, + take, + tap, + throwError, +} from 'rxjs'; + +import { Popup } from '../models/popup'; +import { PopupPagination } from '../models/popup-pagination'; + +@Injectable({ + providedIn: 'root', +}) +export class PopupService { + // Private + private __pagination = new BehaviorSubject( + undefined + ); + private __popup = new BehaviorSubject(undefined); + private __popups = new BehaviorSubject(undefined); + + /** + * Constructor + */ + constructor(private _httpClient: HttpClient) {} + + // ----------------------------------------------------------------------------------------------------- + // @ Accessors + // ----------------------------------------------------------------------------------------------------- + + /** + * Getter for pagination + */ + get pagination$(): Observable { + return this.__pagination.asObservable(); + } + + /** + * Getter for popup + */ + get popup$(): Observable { + return this.__popup.asObservable(); + } + + /** + * Getter for popups + */ + get popups$(): Observable { + return this.__popups.asObservable(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Get Popups + * + * + * @param page + * @param size + * @param sort + * @param order + * @param search + */ + getPopups( + page: number = 0, + size: number = 10, + sort: string = 'name', + order: 'asc' | 'desc' | '' = 'asc', + search: string = '' + ): Observable<{ + pagination: PopupPagination; + popups: Popup[]; + }> { + return this._httpClient + .get<{ + pagination: PopupPagination; + popups: Popup[]; + }>('api/apps/board/popup/popups', { + params: { + page: '' + page, + size: '' + size, + sort, + order, + search, + }, + }) + .pipe( + tap((response) => { + this.__pagination.next(response.pagination); + this.__popups.next(response.popups); + }) + ); + } + + /** + * Get product by id + */ + getPopupById(id: string | null): Observable { + return this.__popups.pipe( + take(1), + map((popups) => { + // Find the product + const popup = popups?.find((item) => item.id === id) || undefined; + + // Update the product + this.__popup.next(popup); + + // Return the product + return popup; + }), + switchMap((product) => { + if (!product) { + return throwError('Could not found product with id of ' + id + '!'); + } + + return of(product); + }) + ); + } + + /** + * Create product + */ + createPopup(): Observable { + return this.popups$.pipe( + take(1), + switchMap((popups) => + this._httpClient.post('api/apps/board/popup/product', {}).pipe( + map((newPopup) => { + // Update the popups with the new product + if (!!popups) { + this.__popups.next([newPopup, ...popups]); + } + + // Return the new product + return newPopup; + }) + ) + ) + ); + } +} diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index bad3712..e88cd37 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -37,5 +37,8 @@ "Sessionin Admin": "Sessionin Admin Info", "Sessionin Overlap": "Sessionin Overlap", "Excel Log": "Excel Download Logs", - "Loosing": "Loosing Management" + "Loosing": "Loosing Management", + "Notice": "Notice", + "Notice Oneline": "Notice Oneline", + "Popup": "Pop Up" } diff --git a/src/assets/i18n/ko.json b/src/assets/i18n/ko.json index 5622239..ea95cc5 100644 --- a/src/assets/i18n/ko.json +++ b/src/assets/i18n/ko.json @@ -43,5 +43,8 @@ "Sessionin Overlap": "중복로그인", "Sessionin Admin": "관리자 로그인정보", "Excel Log": "엑셀다운 로그", - "Loosing": "루징관리" + "Loosing": "루징관리", + "Notice": "공지사항", + "Notice Oneline": "한줄공지", + "Popup": "팝업" }