diff --git a/src/app/app.routing.ts b/src/app/app.routing.ts
index 64a8035..50d44a7 100644
--- a/src/app/app.routing.ts
+++ b/src/app/app.routing.ts
@@ -234,6 +234,13 @@ export const appRoutes: Route[] = [
'app/modules/admin/member/coupon-moneylog/coupon-moneylog.module'
).then((m: any) => m.CouponMoneylogModule),
},
+ {
+ path: 'coupon-log',
+ loadChildren: () =>
+ import(
+ 'app/modules/admin/member/coupon-log/coupon-log.module'
+ ).then((m: any) => m.CouponLogModule),
+ },
],
},
{
@@ -300,6 +307,25 @@ export const appRoutes: Route[] = [
},
],
},
+ {
+ path: 'report',
+ children: [
+ {
+ path: 'daily',
+ loadChildren: () =>
+ import('app/modules/admin/report/daily/daily.module').then(
+ (m: any) => m.DailyModule
+ ),
+ },
+ {
+ path: 'monthly',
+ loadChildren: () =>
+ import('app/modules/admin/report/monthly/monthly.module').then(
+ (m: any) => m.MonthlyModule
+ ),
+ },
+ ],
+ },
],
},
];
diff --git a/src/app/mock-api/apps/member/coupon-log/api.ts b/src/app/mock-api/apps/member/coupon-log/api.ts
new file mode 100644
index 0000000..f8007af
--- /dev/null
+++ b/src/app/mock-api/apps/member/coupon-log/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 { couponLogs as couponLogsData } from './data';
+
+@Injectable({
+ providedIn: 'root',
+})
+export class MemberCouponLogMockApi {
+ private _couponLogs: any[] = couponLogsData;
+
+ /**
+ * Constructor
+ */
+ constructor(private _fuseMockApiService: FuseMockApiService) {
+ // Register Mock API handlers
+ this.registerHandlers();
+ }
+
+ // -----------------------------------------------------------------------------------------------------
+ // @ Public methods
+ // -----------------------------------------------------------------------------------------------------
+
+ /**
+ * Register Mock API handlers
+ */
+ registerHandlers(): void {
+ // -----------------------------------------------------------------------------------------------------
+ // @ CouponLogs - GET
+ // -----------------------------------------------------------------------------------------------------
+ this._fuseMockApiService
+ .onGet('api/apps/member/coupon-log/coupon-logs', 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 couponLogs
+ let couponLogs: any[] | null = cloneDeep(this._couponLogs);
+
+ // Sort the couponLogs
+ if (sort === 'sku' || sort === 'name' || sort === 'active') {
+ couponLogs.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 {
+ couponLogs.sort((a, b) =>
+ order === 'asc' ? a[sort] - b[sort] : b[sort] - a[sort]
+ );
+ }
+
+ // If search exists...
+ if (search) {
+ // Filter the couponLogs
+ couponLogs = couponLogs.filter(
+ (contact: any) =>
+ contact.name &&
+ contact.name.toLowerCase().includes(search.toLowerCase())
+ );
+ }
+
+ // Paginate - Start
+ const couponLogsLength = couponLogs.length;
+
+ // Calculate pagination details
+ const begin = page * size;
+ const end = Math.min(size * (page + 1), couponLogsLength);
+ const lastPage = Math.max(Math.ceil(couponLogsLength / size), 1);
+
+ // Prepare the pagination object
+ let pagination = {};
+
+ // If the requested page number is bigger than
+ // the last possible page number, return null for
+ // couponLogs but also send the last possible page so
+ // the app can navigate to there
+ if (page > lastPage) {
+ couponLogs = null;
+ pagination = {
+ lastPage,
+ };
+ } else {
+ // Paginate the results by size
+ couponLogs = couponLogs.slice(begin, end);
+
+ // Prepare the pagination mock-api
+ pagination = {
+ length: couponLogsLength,
+ size: size,
+ page: page,
+ lastPage: lastPage,
+ startIndex: begin,
+ endIndex: end - 1,
+ };
+ }
+
+ // Return the response
+ return [
+ 200,
+ {
+ couponLogs,
+ pagination,
+ },
+ ];
+ });
+
+ // -----------------------------------------------------------------------------------------------------
+ // @ CouponLog - GET
+ // -----------------------------------------------------------------------------------------------------
+ this._fuseMockApiService
+ .onGet('api/apps/member/coupon-log/coupon-log')
+ .reply(({ request }) => {
+ // Get the id from the params
+ const id = request.params.get('id');
+
+ // Clone the couponLogs
+ const couponLogs = cloneDeep(this._couponLogs);
+
+ // Find the couponLog
+ const couponLog = couponLogs.find((item: any) => item.id === id);
+
+ // Return the response
+ return [200, couponLog];
+ });
+
+ // -----------------------------------------------------------------------------------------------------
+ // @ CouponLog - POST
+ // -----------------------------------------------------------------------------------------------------
+ this._fuseMockApiService
+ .onPost('api/apps/member/coupon-log/coupon-log')
+ .reply(() => {
+ // Generate a new couponLog
+ const newCouponLog = {
+ 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 couponLog
+ this._couponLogs.unshift(newCouponLog);
+
+ // Return the response
+ return [200, newCouponLog];
+ });
+
+ // -----------------------------------------------------------------------------------------------------
+ // @ CouponLog - PATCH
+ // -----------------------------------------------------------------------------------------------------
+ this._fuseMockApiService
+ .onPatch('api/apps/member/coupon-log/coupon-log')
+ .reply(({ request }) => {
+ // Get the id and couponLog
+ const id = request.body.id;
+ const couponLog = cloneDeep(request.body.couponLog);
+
+ // Prepare the updated couponLog
+ let updatedCouponLog = null;
+
+ // Find the couponLog and update it
+ this._couponLogs.forEach((item, index, couponLogs) => {
+ if (item.id === id) {
+ // Update the couponLog
+ couponLogs[index] = assign({}, couponLogs[index], couponLog);
+
+ // Store the updated couponLog
+ updatedCouponLog = couponLogs[index];
+ }
+ });
+
+ // Return the response
+ return [200, updatedCouponLog];
+ });
+
+ // -----------------------------------------------------------------------------------------------------
+ // @ CouponLog - DELETE
+ // -----------------------------------------------------------------------------------------------------
+ this._fuseMockApiService
+ .onDelete('api/apps/member/coupon-log/coupon-log')
+ .reply(({ request }) => {
+ // Get the id
+ const id = request.params.get('id');
+
+ // Find the couponLog and delete it
+ this._couponLogs.forEach((item, index) => {
+ if (item.id === id) {
+ this._couponLogs.splice(index, 1);
+ }
+ });
+
+ // Return the response
+ return [200, true];
+ });
+ }
+}
diff --git a/src/app/mock-api/apps/member/coupon-log/data.ts b/src/app/mock-api/apps/member/coupon-log/data.ts
new file mode 100644
index 0000000..9adbb02
--- /dev/null
+++ b/src/app/mock-api/apps/member/coupon-log/data.ts
@@ -0,0 +1,33 @@
+/* eslint-disable */
+
+export const couponLogs = [
+ {
+ 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/report/daily/api.ts b/src/app/mock-api/apps/report/daily/api.ts
new file mode 100644
index 0000000..1809429
--- /dev/null
+++ b/src/app/mock-api/apps/report/daily/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 { dailys as dailysData } from './data';
+
+@Injectable({
+ providedIn: 'root',
+})
+export class ReportDailyMockApi {
+ private _dailys: any[] = dailysData;
+
+ /**
+ * Constructor
+ */
+ constructor(private _fuseMockApiService: FuseMockApiService) {
+ // Register Mock API handlers
+ this.registerHandlers();
+ }
+
+ // -----------------------------------------------------------------------------------------------------
+ // @ Public methods
+ // -----------------------------------------------------------------------------------------------------
+
+ /**
+ * Register Mock API handlers
+ */
+ registerHandlers(): void {
+ // -----------------------------------------------------------------------------------------------------
+ // @ Dailys - GET
+ // -----------------------------------------------------------------------------------------------------
+ this._fuseMockApiService
+ .onGet('api/apps/report/daily/dailys', 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 dailys
+ let dailys: any[] | null = cloneDeep(this._dailys);
+
+ // Sort the dailys
+ if (sort === 'sku' || sort === 'name' || sort === 'active') {
+ dailys.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 {
+ dailys.sort((a, b) =>
+ order === 'asc' ? a[sort] - b[sort] : b[sort] - a[sort]
+ );
+ }
+
+ // If search exists...
+ if (search) {
+ // Filter the dailys
+ dailys = dailys.filter(
+ (contact: any) =>
+ contact.name &&
+ contact.name.toLowerCase().includes(search.toLowerCase())
+ );
+ }
+
+ // Paginate - Start
+ const dailysLength = dailys.length;
+
+ // Calculate pagination details
+ const begin = page * size;
+ const end = Math.min(size * (page + 1), dailysLength);
+ const lastPage = Math.max(Math.ceil(dailysLength / size), 1);
+
+ // Prepare the pagination object
+ let pagination = {};
+
+ // If the requested page number is bigger than
+ // the last possible page number, return null for
+ // dailys but also send the last possible page so
+ // the app can navigate to there
+ if (page > lastPage) {
+ dailys = null;
+ pagination = {
+ lastPage,
+ };
+ } else {
+ // Paginate the results by size
+ dailys = dailys.slice(begin, end);
+
+ // Prepare the pagination mock-api
+ pagination = {
+ length: dailysLength,
+ size: size,
+ page: page,
+ lastPage: lastPage,
+ startIndex: begin,
+ endIndex: end - 1,
+ };
+ }
+
+ // Return the response
+ return [
+ 200,
+ {
+ dailys,
+ pagination,
+ },
+ ];
+ });
+
+ // -----------------------------------------------------------------------------------------------------
+ // @ Daily - GET
+ // -----------------------------------------------------------------------------------------------------
+ this._fuseMockApiService
+ .onGet('api/apps/report/daily/daily')
+ .reply(({ request }) => {
+ // Get the id from the params
+ const id = request.params.get('id');
+
+ // Clone the dailys
+ const dailys = cloneDeep(this._dailys);
+
+ // Find the daily
+ const daily = dailys.find((item: any) => item.id === id);
+
+ // Return the response
+ return [200, daily];
+ });
+
+ // -----------------------------------------------------------------------------------------------------
+ // @ Daily - POST
+ // -----------------------------------------------------------------------------------------------------
+ this._fuseMockApiService.onPost('api/apps/report/daily/daily').reply(() => {
+ // Generate a new daily
+ const newDaily = {
+ 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 daily
+ this._dailys.unshift(newDaily);
+
+ // Return the response
+ return [200, newDaily];
+ });
+
+ // -----------------------------------------------------------------------------------------------------
+ // @ Daily - PATCH
+ // -----------------------------------------------------------------------------------------------------
+ this._fuseMockApiService
+ .onPatch('api/apps/report/daily/daily')
+ .reply(({ request }) => {
+ // Get the id and daily
+ const id = request.body.id;
+ const daily = cloneDeep(request.body.daily);
+
+ // Prepare the updated daily
+ let updatedDaily = null;
+
+ // Find the daily and update it
+ this._dailys.forEach((item, index, dailys) => {
+ if (item.id === id) {
+ // Update the daily
+ dailys[index] = assign({}, dailys[index], daily);
+
+ // Store the updated daily
+ updatedDaily = dailys[index];
+ }
+ });
+
+ // Return the response
+ return [200, updatedDaily];
+ });
+
+ // -----------------------------------------------------------------------------------------------------
+ // @ Daily - DELETE
+ // -----------------------------------------------------------------------------------------------------
+ this._fuseMockApiService
+ .onDelete('api/apps/report/daily/daily')
+ .reply(({ request }) => {
+ // Get the id
+ const id = request.params.get('id');
+
+ // Find the daily and delete it
+ this._dailys.forEach((item, index) => {
+ if (item.id === id) {
+ this._dailys.splice(index, 1);
+ }
+ });
+
+ // Return the response
+ return [200, true];
+ });
+ }
+}
diff --git a/src/app/mock-api/apps/report/daily/data.ts b/src/app/mock-api/apps/report/daily/data.ts
new file mode 100644
index 0000000..7a16563
--- /dev/null
+++ b/src/app/mock-api/apps/report/daily/data.ts
@@ -0,0 +1,33 @@
+/* eslint-disable */
+
+export const dailys = [
+ {
+ 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/report/monthly/api.ts b/src/app/mock-api/apps/report/monthly/api.ts
new file mode 100644
index 0000000..e7be7ac
--- /dev/null
+++ b/src/app/mock-api/apps/report/monthly/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 { monthlys as monthlysData } from './data';
+
+@Injectable({
+ providedIn: 'root',
+})
+export class ReportMonthlyMockApi {
+ private _monthlys: any[] = monthlysData;
+
+ /**
+ * Constructor
+ */
+ constructor(private _fuseMockApiService: FuseMockApiService) {
+ // Register Mock API handlers
+ this.registerHandlers();
+ }
+
+ // -----------------------------------------------------------------------------------------------------
+ // @ Public methods
+ // -----------------------------------------------------------------------------------------------------
+
+ /**
+ * Register Mock API handlers
+ */
+ registerHandlers(): void {
+ // -----------------------------------------------------------------------------------------------------
+ // @ Monthlys - GET
+ // -----------------------------------------------------------------------------------------------------
+ this._fuseMockApiService
+ .onGet('api/apps/report/montyly/monthlys', 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 monthlys
+ let monthlys: any[] | null = cloneDeep(this._monthlys);
+
+ // Sort the monthlys
+ if (sort === 'sku' || sort === 'name' || sort === 'active') {
+ monthlys.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 {
+ monthlys.sort((a, b) =>
+ order === 'asc' ? a[sort] - b[sort] : b[sort] - a[sort]
+ );
+ }
+
+ // If search exists...
+ if (search) {
+ // Filter the monthlys
+ monthlys = monthlys.filter(
+ (contact: any) =>
+ contact.name &&
+ contact.name.toLowerCase().includes(search.toLowerCase())
+ );
+ }
+
+ // Paginate - Start
+ const monthlysLength = monthlys.length;
+
+ // Calculate pagination details
+ const begin = page * size;
+ const end = Math.min(size * (page + 1), monthlysLength);
+ const lastPage = Math.max(Math.ceil(monthlysLength / size), 1);
+
+ // Prepare the pagination object
+ let pagination = {};
+
+ // If the requested page number is bigger than
+ // the last possible page number, return null for
+ // monthlys but also send the last possible page so
+ // the app can navigate to there
+ if (page > lastPage) {
+ monthlys = null;
+ pagination = {
+ lastPage,
+ };
+ } else {
+ // Paginate the results by size
+ monthlys = monthlys.slice(begin, end);
+
+ // Prepare the pagination mock-api
+ pagination = {
+ length: monthlysLength,
+ size: size,
+ page: page,
+ lastPage: lastPage,
+ startIndex: begin,
+ endIndex: end - 1,
+ };
+ }
+
+ // Return the response
+ return [
+ 200,
+ {
+ monthlys,
+ pagination,
+ },
+ ];
+ });
+
+ // -----------------------------------------------------------------------------------------------------
+ // @ Monthly - GET
+ // -----------------------------------------------------------------------------------------------------
+ this._fuseMockApiService
+ .onGet('api/apps/report/monthly/monthly')
+ .reply(({ request }) => {
+ // Get the id from the params
+ const id = request.params.get('id');
+
+ // Clone the monthlys
+ const monthlys = cloneDeep(this._monthlys);
+
+ // Find the monthly
+ const monthly = monthlys.find((item: any) => item.id === id);
+
+ // Return the response
+ return [200, monthly];
+ });
+
+ // -----------------------------------------------------------------------------------------------------
+ // @ Monthly - POST
+ // -----------------------------------------------------------------------------------------------------
+ this._fuseMockApiService
+ .onPost('api/apps/report/monthly/monthly')
+ .reply(() => {
+ // Generate a new monthly
+ const newMonthly = {
+ 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 monthly
+ this._monthlys.unshift(newMonthly);
+
+ // Return the response
+ return [200, newMonthly];
+ });
+
+ // -----------------------------------------------------------------------------------------------------
+ // @ Monthly - PATCH
+ // -----------------------------------------------------------------------------------------------------
+ this._fuseMockApiService
+ .onPatch('api/apps/report/monthly/monthly')
+ .reply(({ request }) => {
+ // Get the id and monthly
+ const id = request.body.id;
+ const monthly = cloneDeep(request.body.monthly);
+
+ // Prepare the updated monthly
+ let updatedMonthly = null;
+
+ // Find the monthly and update it
+ this._monthlys.forEach((item, index, monthlys) => {
+ if (item.id === id) {
+ // Update the monthly
+ monthlys[index] = assign({}, monthlys[index], monthly);
+
+ // Store the updated monthly
+ updatedMonthly = monthlys[index];
+ }
+ });
+
+ // Return the response
+ return [200, updatedMonthly];
+ });
+
+ // -----------------------------------------------------------------------------------------------------
+ // @ Monthly - DELETE
+ // -----------------------------------------------------------------------------------------------------
+ this._fuseMockApiService
+ .onDelete('api/apps/report/monthly/monthly')
+ .reply(({ request }) => {
+ // Get the id
+ const id = request.params.get('id');
+
+ // Find the monthly and delete it
+ this._monthlys.forEach((item, index) => {
+ if (item.id === id) {
+ this._monthlys.splice(index, 1);
+ }
+ });
+
+ // Return the response
+ return [200, true];
+ });
+ }
+}
diff --git a/src/app/mock-api/apps/report/monthly/data.ts b/src/app/mock-api/apps/report/monthly/data.ts
new file mode 100644
index 0000000..be97b0c
--- /dev/null
+++ b/src/app/mock-api/apps/report/monthly/data.ts
@@ -0,0 +1,33 @@
+/* eslint-disable */
+
+export const monthlys = [
+ {
+ 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 46a634b..f1b1e2f 100644
--- a/src/app/mock-api/common/navigation/data.ts
+++ b/src/app/mock-api/common/navigation/data.ts
@@ -130,6 +130,13 @@ export const defaultNavigation: FuseNavigationItem[] = [
icon: 'heroicons_outline:academic-cap',
link: '/member/coupon-moneylog',
},
+ {
+ id: 'member.coupon-log',
+ title: 'Coupon Log',
+ type: 'basic',
+ icon: 'heroicons_outline:academic-cap',
+ link: '/member/coupon-log',
+ },
],
},
{
@@ -208,6 +215,29 @@ export const defaultNavigation: FuseNavigationItem[] = [
},
],
},
+ {
+ id: 'report',
+ title: 'Report',
+ subtitle: 'report managements',
+ type: 'group',
+ icon: 'heroicons_outline:home',
+ children: [
+ {
+ id: 'report.daily',
+ title: 'Daily',
+ type: 'basic',
+ icon: 'heroicons_outline:academic-cap',
+ link: '/report/daily',
+ },
+ {
+ id: 'report.monthly',
+ title: 'Monthly',
+ type: 'basic',
+ icon: 'heroicons_outline:academic-cap',
+ link: '/report/monthly',
+ },
+ ],
+ },
];
export const compactNavigation: FuseNavigationItem[] = [
{
diff --git a/src/app/mock-api/index.ts b/src/app/mock-api/index.ts
index d48a734..c4aa2d4 100644
--- a/src/app/mock-api/index.ts
+++ b/src/app/mock-api/index.ts
@@ -23,6 +23,7 @@ import { MemberPartnerStoreMockApi } from './apps/member/partner-store/api';
import { MemberPartnerRecommendationMockApi } from './apps/member/partner-recommendation/api';
import { MemberCouponMockApi } from './apps/member/coupon/api';
import { MemberCouponMoneylogMockApi } from './apps/member/coupon-moneylog/api';
+import { MemberCouponLogMockApi } from './apps/member/coupon-log/api';
import { MessagesMockApi } from 'app/mock-api/common/messages/api';
import { NavigationMockApi } from 'app/mock-api/common/navigation/api';
import { NotesMockApi } from 'app/mock-api/apps/notes/api';
@@ -40,6 +41,8 @@ import { GameCasinoMockApi } from './apps/game/casino/api';
import { GameEvolutionMockApi } from './apps/game/evolution/api';
import { GameSlotMockApi } from './apps/game/slot/api';
import { BasicSettingMockApi } from './apps/settings/basic/api';
+import { ReportDailyMockApi } from './apps/report/daily/api';
+import { ReportMonthlyMockApi } from './apps/report/monthly/api';
export const mockApiServices = [
AcademyMockApi,
@@ -67,6 +70,7 @@ export const mockApiServices = [
MemberPartnerRecommendationMockApi,
MemberCouponMockApi,
MemberCouponMoneylogMockApi,
+ MemberCouponLogMockApi,
MessagesMockApi,
NavigationMockApi,
NotesMockApi,
@@ -84,4 +88,6 @@ export const mockApiServices = [
GameEvolutionMockApi,
GameSlotMockApi,
BasicSettingMockApi,
+ ReportDailyMockApi,
+ ReportMonthlyMockApi,
];
diff --git a/src/app/modules/admin/member/coupon-log/components/index.ts b/src/app/modules/admin/member/coupon-log/components/index.ts
new file mode 100644
index 0000000..04759eb
--- /dev/null
+++ b/src/app/modules/admin/member/coupon-log/components/index.ts
@@ -0,0 +1,3 @@
+import { ListComponent } from './list.component';
+
+export const COMPONENTS = [ListComponent];
diff --git a/src/app/modules/admin/member/coupon-log/components/list.component.html b/src/app/modules/admin/member/coupon-log/components/list.component.html
new file mode 100644
index 0000000..0a5803a
--- /dev/null
+++ b/src/app/modules/admin/member/coupon-log/components/list.component.html
@@ -0,0 +1,357 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 40
+ 60
+ 80
+ 100
+
+
+
+
+ LV.1
+ LV.2
+ LV.3
+ LV.4
+
+
+
+
+ 정상
+ 대기
+ 탈퇴
+ 휴면
+ 블랙
+ 정지
+
+
+
+
+ 카지노제한
+ 슬롯제한
+
+
+
+
+ 계좌입금
+
+
+
+
+ 카지노콤프
+ 슬롯콤프
+ 배팅콤프
+ 첫충콤프
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0; else noCouponLog">
+
+
+
+
+
요율
+
상부트리
+
관리
+
매장수
+
회원수
+
아이디
+
닉네임
+
예금주
+
연락처
+
정산
+
보유금
+
게임중머니
+
카지노->캐쉬
+
금일콤프
+
총입출
+
로그
+
상태
+
회원수
+
비고
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ couponLog.id }}
+
+
+
+
+
+ {{ couponLog.nickname }}
+
+
+
+ {{ couponLog.accountHolder }}
+
+
+
+ {{ couponLog.phoneNumber }}
+
+
+
+ {{ couponLog.calculateType }}
+
+
+
+ 캐쉬{{ couponLog.ownCash }} 콤프{{
+ couponLog.ownComp
+ }}
+ 쿠폰{{ couponLog.ownCoupon }}
+
+
+
+ {{ couponLog.gameMoney }}
+
+
+
+
+
+
+
+
+ {{ couponLog.todayComp }}P
+
+
+
+ 입금{{ couponLog.totalDeposit }} 출금{{
+ couponLog.totalWithdraw
+ }}
+ 차익{{ couponLog.balance }}
+
+
+
+ 가입{{ couponLog.registDate }} 최종{{
+ couponLog.finalSigninDate
+ }}
+ IP{{ couponLog.ip }}
+
+
+
+ {{ couponLog.state }}
+
+
+
+ {{ couponLog.memberCount }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ There are no coupon logs!
+
+
+
+
+
diff --git a/src/app/modules/admin/member/coupon-log/components/list.component.ts b/src/app/modules/admin/member/coupon-log/components/list.component.ts
new file mode 100644
index 0000000..04e9364
--- /dev/null
+++ b/src/app/modules/admin/member/coupon-log/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 '../../user/models/user';
+import { CouponLog } from '../models/coupon-log';
+import { CouponLogPagination } from '../models/coupon-log-pagination';
+import { CouponLogService } from '../services/coupon-log.service';
+import { Router } from '@angular/router';
+
+@Component({
+ selector: 'coupon-log-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;
+
+ couponLogs$!: Observable;
+ users$!: Observable;
+
+ isLoading = false;
+ searchInputControl = new FormControl();
+ selectedCouponLog?: CouponLog;
+ pagination?: CouponLogPagination;
+
+ private _unsubscribeAll: Subject = new Subject();
+
+ /**
+ * Constructor
+ */
+ constructor(
+ private _changeDetectorRef: ChangeDetectorRef,
+ private _fuseConfirmationService: FuseConfirmationService,
+ private _formBuilder: FormBuilder,
+ private _couponLogService: CouponLogService,
+ private router: Router
+ ) {}
+
+ // -----------------------------------------------------------------------------------------------------
+ // @ Lifecycle hooks
+ // -----------------------------------------------------------------------------------------------------
+
+ /**
+ * On init
+ */
+ ngOnInit(): void {
+ // Get the pagination
+ this._couponLogService.pagination$
+ .pipe(takeUntil(this._unsubscribeAll))
+ .subscribe((pagination: CouponLogPagination | undefined) => {
+ // Update the pagination
+ this.pagination = pagination;
+
+ // Mark for check
+ this._changeDetectorRef.markForCheck();
+ });
+
+ // Get the products
+ this.couponLogs$ = this._couponLogService.couponLogs$;
+ }
+
+ /**
+ * 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 couponLog 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._couponLogService.getCouponLogs(
+ 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/member/coupon-log/coupon-log.module.ts b/src/app/modules/admin/member/coupon-log/coupon-log.module.ts
new file mode 100644
index 0000000..b324df8
--- /dev/null
+++ b/src/app/modules/admin/member/coupon-log/coupon-log.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 { CouponLogRoutes } from './coupon-log.routing';
+
+@NgModule({
+ declarations: [COMPONENTS],
+ imports: [
+ TranslocoModule,
+ SharedModule,
+ RouterModule.forChild(CouponLogRoutes),
+
+ MatButtonModule,
+ MatFormFieldModule,
+ MatIconModule,
+ MatInputModule,
+ MatPaginatorModule,
+ MatProgressBarModule,
+ MatRippleModule,
+ MatSortModule,
+ MatSelectModule,
+ MatTooltipModule,
+ MatGridListModule,
+ MatSlideToggleModule,
+ MatRadioModule,
+ MatCheckboxModule,
+ ],
+})
+export class CouponLogModule {}
diff --git a/src/app/modules/admin/member/coupon-log/coupon-log.routing.ts b/src/app/modules/admin/member/coupon-log/coupon-log.routing.ts
new file mode 100644
index 0000000..64edb8b
--- /dev/null
+++ b/src/app/modules/admin/member/coupon-log/coupon-log.routing.ts
@@ -0,0 +1,24 @@
+import { Route } from '@angular/router';
+
+import { ListComponent } from './components/list.component';
+import { ViewComponent } from '../user/components/view.component';
+
+import { CouponLogsResolver } from './resolvers/coupon-log.resolver';
+import { UserResolver } from '../user/resolvers/user.resolver';
+
+export const CouponLogRoutes: Route[] = [
+ {
+ path: '',
+ component: ListComponent,
+ resolve: {
+ CouponLogs: CouponLogsResolver,
+ },
+ },
+ {
+ path: ':id',
+ component: ViewComponent,
+ resolve: {
+ users: UserResolver,
+ },
+ },
+];
diff --git a/src/app/modules/admin/member/coupon-log/models/coupon-log-pagination.ts b/src/app/modules/admin/member/coupon-log/models/coupon-log-pagination.ts
new file mode 100644
index 0000000..a4baa22
--- /dev/null
+++ b/src/app/modules/admin/member/coupon-log/models/coupon-log-pagination.ts
@@ -0,0 +1,8 @@
+export interface CouponLogPagination {
+ length: number;
+ size: number;
+ page: number;
+ lastPage: number;
+ startIndex: number;
+ endIndex: number;
+}
diff --git a/src/app/modules/admin/member/coupon-log/models/coupon-log.ts b/src/app/modules/admin/member/coupon-log/models/coupon-log.ts
new file mode 100644
index 0000000..cc36309
--- /dev/null
+++ b/src/app/modules/admin/member/coupon-log/models/coupon-log.ts
@@ -0,0 +1,29 @@
+export interface CouponLog {
+ 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/member/coupon-log/resolvers/coupon-log.resolver.ts b/src/app/modules/admin/member/coupon-log/resolvers/coupon-log.resolver.ts
new file mode 100644
index 0000000..6af30cd
--- /dev/null
+++ b/src/app/modules/admin/member/coupon-log/resolvers/coupon-log.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 { CouponLog } from '../models/coupon-log';
+import { CouponLogPagination } from '../models/coupon-log-pagination';
+import { CouponLogService } from '../services/coupon-log.service';
+
+@Injectable({
+ providedIn: 'root',
+})
+export class CouponLogResolver implements Resolve {
+ /**
+ * Constructor
+ */
+ constructor(
+ private _couponLogService: CouponLogService,
+ private _router: Router
+ ) {}
+
+ // -----------------------------------------------------------------------------------------------------
+ // @ Public methods
+ // -----------------------------------------------------------------------------------------------------
+
+ /**
+ * Resolver
+ *
+ * @param route
+ * @param state
+ */
+ resolve(
+ route: ActivatedRouteSnapshot,
+ state: RouterStateSnapshot
+ ): Observable {
+ return this._couponLogService
+ .getCouponLogById(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 CouponLogsResolver implements Resolve {
+ /**
+ * Constructor
+ */
+ constructor(private _couponLogService: CouponLogService) {}
+
+ // -----------------------------------------------------------------------------------------------------
+ // @ Public methods
+ // -----------------------------------------------------------------------------------------------------
+
+ /**
+ * Resolver
+ *
+ * @param route
+ * @param state
+ */
+ resolve(
+ route: ActivatedRouteSnapshot,
+ state: RouterStateSnapshot
+ ): Observable<{
+ pagination: CouponLogPagination;
+ couponLogs: CouponLog[];
+ }> {
+ return this._couponLogService.getCouponLogs();
+ }
+}
diff --git a/src/app/modules/admin/member/coupon-log/services/coupon-log.service.ts b/src/app/modules/admin/member/coupon-log/services/coupon-log.service.ts
new file mode 100644
index 0000000..ac2be33
--- /dev/null
+++ b/src/app/modules/admin/member/coupon-log/services/coupon-log.service.ts
@@ -0,0 +1,156 @@
+import { Injectable } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
+import {
+ BehaviorSubject,
+ filter,
+ map,
+ Observable,
+ of,
+ switchMap,
+ take,
+ tap,
+ throwError,
+} from 'rxjs';
+
+import { CouponLog } from '../models/coupon-log';
+import { CouponLogPagination } from '../models/coupon-log-pagination';
+
+@Injectable({
+ providedIn: 'root',
+})
+export class CouponLogService {
+ // Private
+ private __pagination = new BehaviorSubject(
+ undefined
+ );
+ private __couponLog = new BehaviorSubject(undefined);
+ private __couponLogs = new BehaviorSubject(
+ undefined
+ );
+
+ /**
+ * Constructor
+ */
+ constructor(private _httpClient: HttpClient) {}
+
+ // -----------------------------------------------------------------------------------------------------
+ // @ Accessors
+ // -----------------------------------------------------------------------------------------------------
+
+ /**
+ * Getter for pagination
+ */
+ get pagination$(): Observable {
+ return this.__pagination.asObservable();
+ }
+
+ /**
+ * Getter for couponLog
+ */
+ get couponLog$(): Observable {
+ return this.__couponLog.asObservable();
+ }
+
+ /**
+ * Getter for couponLogs
+ */
+ get couponLogs$(): Observable {
+ return this.__couponLogs.asObservable();
+ }
+
+ // -----------------------------------------------------------------------------------------------------
+ // @ Public methods
+ // -----------------------------------------------------------------------------------------------------
+
+ /**
+ * Get couponLogs
+ *
+ *
+ * @param page
+ * @param size
+ * @param sort
+ * @param order
+ * @param search
+ */
+ getCouponLogs(
+ page: number = 0,
+ size: number = 10,
+ sort: string = 'name',
+ order: 'asc' | 'desc' | '' = 'asc',
+ search: string = ''
+ ): Observable<{
+ pagination: CouponLogPagination;
+ couponLogs: CouponLog[];
+ }> {
+ return this._httpClient
+ .get<{
+ pagination: CouponLogPagination;
+ couponLogs: CouponLog[];
+ }>('api/apps/member/coupon-log/coupon-logs', {
+ params: {
+ page: '' + page,
+ size: '' + size,
+ sort,
+ order,
+ search,
+ },
+ })
+ .pipe(
+ tap((response) => {
+ this.__pagination.next(response.pagination);
+ this.__couponLogs.next(response.couponLogs);
+ })
+ );
+ }
+
+ /**
+ * Get product by id
+ */
+ getCouponLogById(id: string | null): Observable {
+ return this.__couponLogs.pipe(
+ take(1),
+ map((couponLogs) => {
+ // Find the product
+ const couponLog =
+ couponLogs?.find((item) => item.id === id) || undefined;
+
+ // Update the product
+ this.__couponLog.next(couponLog);
+
+ // Return the product
+ return couponLog;
+ }),
+ switchMap((product) => {
+ if (!product) {
+ return throwError('Could not found product with id of ' + id + '!');
+ }
+
+ return of(product);
+ })
+ );
+ }
+
+ /**
+ * Create product
+ */
+ createCouponLog(): Observable {
+ return this.couponLogs$.pipe(
+ take(1),
+ switchMap((couponLogs) =>
+ this._httpClient
+ .post('api/apps/member/coupon-log/product', {})
+ .pipe(
+ map((newCouponLog) => {
+ // Update the couponLogs with the new product
+ if (!!couponLogs) {
+ this.__couponLogs.next([newCouponLog, ...couponLogs]);
+ }
+
+ // Return the new product
+ return newCouponLog;
+ })
+ )
+ )
+ );
+ }
+}
diff --git a/src/app/modules/admin/report/daily/components/index.ts b/src/app/modules/admin/report/daily/components/index.ts
new file mode 100644
index 0000000..04759eb
--- /dev/null
+++ b/src/app/modules/admin/report/daily/components/index.ts
@@ -0,0 +1,3 @@
+import { ListComponent } from './list.component';
+
+export const COMPONENTS = [ListComponent];
diff --git a/src/app/modules/admin/report/daily/components/list.component.html b/src/app/modules/admin/report/daily/components/list.component.html
new file mode 100644
index 0000000..567a713
--- /dev/null
+++ b/src/app/modules/admin/report/daily/components/list.component.html
@@ -0,0 +1,353 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 40
+ 60
+ 80
+ 100
+
+
+
+
+ LV.1
+ LV.2
+ LV.3
+ LV.4
+
+
+
+
+ 정상
+ 대기
+ 탈퇴
+ 휴면
+ 블랙
+ 정지
+
+
+
+
+ 카지노제한
+ 슬롯제한
+
+
+
+
+ 계좌입금
+
+
+
+
+ 카지노콤프
+ 슬롯콤프
+ 배팅콤프
+ 첫충콤프
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0; else noDaily">
+
+
+
+
+
요율
+
상부트리
+
관리
+
매장수
+
회원수
+
아이디
+
닉네임
+
예금주
+
연락처
+
정산
+
보유금
+
게임중머니
+
카지노->캐쉬
+
금일콤프
+
총입출
+
로그
+
상태
+
회원수
+
비고
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ daily.id }}
+
+
+
+
+
+ {{ daily.nickname }}
+
+
+
+ {{ daily.accountHolder }}
+
+
+
+ {{ daily.phoneNumber }}
+
+
+
+ {{ daily.calculateType }}
+
+
+
+ 캐쉬{{ daily.ownCash }} 콤프{{ daily.ownComp }} 쿠폰{{
+ daily.ownCoupon
+ }}
+
+
+
+ {{ daily.gameMoney }}
+
+
+
+
+
+
+
+
+ {{ daily.todayComp }}P
+
+
+
+ 입금{{ daily.totalDeposit }} 출금{{
+ daily.totalWithdraw
+ }}
+ 차익{{ daily.balance }}
+
+
+
+ 가입{{ daily.registDate }} 최종{{
+ daily.finalSigninDate
+ }}
+ IP{{ daily.ip }}
+
+
+
+ {{ daily.state }}
+
+
+
+ {{ daily.memberCount }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ There are no dailys!
+
+
+
+
+
diff --git a/src/app/modules/admin/report/daily/components/list.component.ts b/src/app/modules/admin/report/daily/components/list.component.ts
new file mode 100644
index 0000000..4881464
--- /dev/null
+++ b/src/app/modules/admin/report/daily/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 { Daily } from '../models/daily';
+import { DailyPagination } from '../models/daily-pagination';
+import { DailyService } from '../services/daily.service';
+import { Router } from '@angular/router';
+
+@Component({
+ selector: 'partner-branch-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;
+
+ dailys$!: Observable;
+ users$!: Observable;
+
+ isLoading = false;
+ searchInputControl = new FormControl();
+ selectedDaily?: Daily;
+ pagination?: DailyPagination;
+
+ private _unsubscribeAll: Subject = new Subject();
+
+ /**
+ * Constructor
+ */
+ constructor(
+ private _changeDetectorRef: ChangeDetectorRef,
+ private _fuseConfirmationService: FuseConfirmationService,
+ private _formBuilder: FormBuilder,
+ private _dailyService: DailyService,
+ private router: Router
+ ) {}
+
+ // -----------------------------------------------------------------------------------------------------
+ // @ Lifecycle hooks
+ // -----------------------------------------------------------------------------------------------------
+
+ /**
+ * On init
+ */
+ ngOnInit(): void {
+ // Get the pagination
+ this._dailyService.pagination$
+ .pipe(takeUntil(this._unsubscribeAll))
+ .subscribe((pagination: DailyPagination | undefined) => {
+ // Update the pagination
+ this.pagination = pagination;
+
+ // Mark for check
+ this._changeDetectorRef.markForCheck();
+ });
+
+ // Get the products
+ this.dailys$ = this._dailyService.dailys$;
+ }
+
+ /**
+ * 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 daily 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._dailyService.getDailys(
+ 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/report/daily/daily.module.ts b/src/app/modules/admin/report/daily/daily.module.ts
new file mode 100644
index 0000000..2f20366
--- /dev/null
+++ b/src/app/modules/admin/report/daily/daily.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 { dailyRoutes } from './daily.routing';
+
+@NgModule({
+ declarations: [COMPONENTS],
+ imports: [
+ TranslocoModule,
+ SharedModule,
+ RouterModule.forChild(dailyRoutes),
+
+ MatButtonModule,
+ MatFormFieldModule,
+ MatIconModule,
+ MatInputModule,
+ MatPaginatorModule,
+ MatProgressBarModule,
+ MatRippleModule,
+ MatSortModule,
+ MatSelectModule,
+ MatTooltipModule,
+ MatGridListModule,
+ MatSlideToggleModule,
+ MatRadioModule,
+ MatCheckboxModule,
+ ],
+})
+export class DailyModule {}
diff --git a/src/app/modules/admin/report/daily/daily.routing.ts b/src/app/modules/admin/report/daily/daily.routing.ts
new file mode 100644
index 0000000..c1d6831
--- /dev/null
+++ b/src/app/modules/admin/report/daily/daily.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 { DailysResolver } from './resolvers/daily.resolver';
+import { UserResolver } from '../../member/user/resolvers/user.resolver';
+
+export const dailyRoutes: Route[] = [
+ {
+ path: '',
+ component: ListComponent,
+ resolve: {
+ dailys: DailysResolver,
+ },
+ },
+ {
+ path: ':id',
+ component: ViewComponent,
+ resolve: {
+ users: UserResolver,
+ },
+ },
+];
diff --git a/src/app/modules/admin/report/daily/models/daily-pagination.ts b/src/app/modules/admin/report/daily/models/daily-pagination.ts
new file mode 100644
index 0000000..4ca3b2f
--- /dev/null
+++ b/src/app/modules/admin/report/daily/models/daily-pagination.ts
@@ -0,0 +1,8 @@
+export interface DailyPagination {
+ length: number;
+ size: number;
+ page: number;
+ lastPage: number;
+ startIndex: number;
+ endIndex: number;
+}
diff --git a/src/app/modules/admin/report/daily/models/daily.ts b/src/app/modules/admin/report/daily/models/daily.ts
new file mode 100644
index 0000000..8cc0bc2
--- /dev/null
+++ b/src/app/modules/admin/report/daily/models/daily.ts
@@ -0,0 +1,29 @@
+export interface Daily {
+ 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/report/daily/resolvers/daily.resolver.ts b/src/app/modules/admin/report/daily/resolvers/daily.resolver.ts
new file mode 100644
index 0000000..f7aae2a
--- /dev/null
+++ b/src/app/modules/admin/report/daily/resolvers/daily.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 { Daily } from '../models/daily';
+import { DailyPagination } from '../models/daily-pagination';
+import { DailyService } from '../services/daily.service';
+
+@Injectable({
+ providedIn: 'root',
+})
+export class DailyResolver implements Resolve {
+ /**
+ * Constructor
+ */
+ constructor(private _dailyService: DailyService, private _router: Router) {}
+
+ // -----------------------------------------------------------------------------------------------------
+ // @ Public methods
+ // -----------------------------------------------------------------------------------------------------
+
+ /**
+ * Resolver
+ *
+ * @param route
+ * @param state
+ */
+ resolve(
+ route: ActivatedRouteSnapshot,
+ state: RouterStateSnapshot
+ ): Observable {
+ return this._dailyService.getDailyById(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 DailysResolver implements Resolve {
+ /**
+ * Constructor
+ */
+ constructor(private _dailyService: DailyService) {}
+
+ // -----------------------------------------------------------------------------------------------------
+ // @ Public methods
+ // -----------------------------------------------------------------------------------------------------
+
+ /**
+ * Resolver
+ *
+ * @param route
+ * @param state
+ */
+ resolve(
+ route: ActivatedRouteSnapshot,
+ state: RouterStateSnapshot
+ ): Observable<{
+ pagination: DailyPagination;
+ dailys: Daily[];
+ }> {
+ return this._dailyService.getDailys();
+ }
+}
diff --git a/src/app/modules/admin/report/daily/services/daily.service.ts b/src/app/modules/admin/report/daily/services/daily.service.ts
new file mode 100644
index 0000000..b92c54a
--- /dev/null
+++ b/src/app/modules/admin/report/daily/services/daily.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 { Daily } from '../models/daily';
+import { DailyPagination } from '../models/daily-pagination';
+
+@Injectable({
+ providedIn: 'root',
+})
+export class DailyService {
+ // Private
+ private __pagination = new BehaviorSubject(
+ undefined
+ );
+ private __daily = new BehaviorSubject(undefined);
+ private __dailys = new BehaviorSubject(undefined);
+
+ /**
+ * Constructor
+ */
+ constructor(private _httpClient: HttpClient) {}
+
+ // -----------------------------------------------------------------------------------------------------
+ // @ Accessors
+ // -----------------------------------------------------------------------------------------------------
+
+ /**
+ * Getter for pagination
+ */
+ get pagination$(): Observable {
+ return this.__pagination.asObservable();
+ }
+
+ /**
+ * Getter for daily
+ */
+ get daily$(): Observable {
+ return this.__daily.asObservable();
+ }
+
+ /**
+ * Getter for dailys
+ */
+ get dailys$(): Observable {
+ return this.__dailys.asObservable();
+ }
+
+ // -----------------------------------------------------------------------------------------------------
+ // @ Public methods
+ // -----------------------------------------------------------------------------------------------------
+
+ /**
+ * Get Dailys
+ *
+ *
+ * @param page
+ * @param size
+ * @param sort
+ * @param order
+ * @param search
+ */
+ getDailys(
+ page: number = 0,
+ size: number = 10,
+ sort: string = 'name',
+ order: 'asc' | 'desc' | '' = 'asc',
+ search: string = ''
+ ): Observable<{
+ pagination: DailyPagination;
+ dailys: Daily[];
+ }> {
+ return this._httpClient
+ .get<{
+ pagination: DailyPagination;
+ dailys: Daily[];
+ }>('api/apps/repoart/daily/dailys', {
+ params: {
+ page: '' + page,
+ size: '' + size,
+ sort,
+ order,
+ search,
+ },
+ })
+ .pipe(
+ tap((response) => {
+ this.__pagination.next(response.pagination);
+ this.__dailys.next(response.dailys);
+ })
+ );
+ }
+
+ /**
+ * Get product by id
+ */
+ getDailyById(id: string | null): Observable {
+ return this.__dailys.pipe(
+ take(1),
+ map((dailys) => {
+ // Find the product
+ const daily = dailys?.find((item) => item.id === id) || undefined;
+
+ // Update the product
+ this.__daily.next(daily);
+
+ // Return the product
+ return daily;
+ }),
+ switchMap((product) => {
+ if (!product) {
+ return throwError('Could not found product with id of ' + id + '!');
+ }
+
+ return of(product);
+ })
+ );
+ }
+
+ /**
+ * Create product
+ */
+ createDaily(): Observable {
+ return this.dailys$.pipe(
+ take(1),
+ switchMap((dailys) =>
+ this._httpClient.post('api/apps/report/daily/product', {}).pipe(
+ map((newDaily) => {
+ // Update the dailys with the new product
+ if (!!dailys) {
+ this.__dailys.next([newDaily, ...dailys]);
+ }
+
+ // Return the new product
+ return newDaily;
+ })
+ )
+ )
+ );
+ }
+}
diff --git a/src/app/modules/admin/report/monthly/components/index.ts b/src/app/modules/admin/report/monthly/components/index.ts
new file mode 100644
index 0000000..04759eb
--- /dev/null
+++ b/src/app/modules/admin/report/monthly/components/index.ts
@@ -0,0 +1,3 @@
+import { ListComponent } from './list.component';
+
+export const COMPONENTS = [ListComponent];
diff --git a/src/app/modules/admin/report/monthly/components/list.component.html b/src/app/modules/admin/report/monthly/components/list.component.html
new file mode 100644
index 0000000..7238dcb
--- /dev/null
+++ b/src/app/modules/admin/report/monthly/components/list.component.html
@@ -0,0 +1,355 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 40
+ 60
+ 80
+ 100
+
+
+
+
+ LV.1
+ LV.2
+ LV.3
+ LV.4
+
+
+
+
+ 정상
+ 대기
+ 탈퇴
+ 휴면
+ 블랙
+ 정지
+
+
+
+
+ 카지노제한
+ 슬롯제한
+
+
+
+
+ 계좌입금
+
+
+
+
+ 카지노콤프
+ 슬롯콤프
+ 배팅콤프
+ 첫충콤프
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0; else noMonthly">
+
+
+
+
+
요율
+
상부트리
+
관리
+
매장수
+
회원수
+
아이디
+
닉네임
+
예금주
+
연락처
+
정산
+
보유금
+
게임중머니
+
카지노->캐쉬
+
금일콤프
+
총입출
+
로그
+
상태
+
회원수
+
비고
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ monthly.id }}
+
+
+
+
+
+ {{ monthly.nickname }}
+
+
+
+ {{ monthly.accountHolder }}
+
+
+
+ {{ monthly.phoneNumber }}
+
+
+
+ {{ monthly.calculateType }}
+
+
+
+ 캐쉬{{ monthly.ownCash }} 콤프{{ monthly.ownComp }} 쿠폰{{
+ monthly.ownCoupon
+ }}
+
+
+
+ {{ monthly.gameMoney }}
+
+
+
+
+
+
+
+
+ {{ monthly.todayComp }}P
+
+
+
+ 입금{{ monthly.totalDeposit }} 출금{{
+ monthly.totalWithdraw
+ }}
+ 차익{{ monthly.balance }}
+
+
+
+ 가입{{ monthly.registDate }} 최종{{
+ monthly.finalSigninDate
+ }}
+ IP{{ monthly.ip }}
+
+
+
+ {{ monthly.state }}
+
+
+
+ {{ monthly.memberCount }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ There are no monthlys!
+
+
+
+
+
diff --git a/src/app/modules/admin/report/monthly/components/list.component.ts b/src/app/modules/admin/report/monthly/components/list.component.ts
new file mode 100644
index 0000000..8bd7258
--- /dev/null
+++ b/src/app/modules/admin/report/monthly/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 { Monthly } from '../models/monthly';
+import { MonthlyPagination } from '../models/monthly-pagination';
+import { MonthlyService } from '../services/monthly.service';
+import { Router } from '@angular/router';
+
+@Component({
+ selector: 'partner-branch-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;
+
+ monthlys$!: Observable;
+ users$!: Observable;
+
+ isLoading = false;
+ searchInputControl = new FormControl();
+ selectedMonthly?: Monthly;
+ pagination?: MonthlyPagination;
+
+ private _unsubscribeAll: Subject = new Subject();
+
+ /**
+ * Constructor
+ */
+ constructor(
+ private _changeDetectorRef: ChangeDetectorRef,
+ private _fuseConfirmationService: FuseConfirmationService,
+ private _formBuilder: FormBuilder,
+ private _monthlyService: MonthlyService,
+ private router: Router
+ ) {}
+
+ // -----------------------------------------------------------------------------------------------------
+ // @ Lifecycle hooks
+ // -----------------------------------------------------------------------------------------------------
+
+ /**
+ * On init
+ */
+ ngOnInit(): void {
+ // Get the pagination
+ this._monthlyService.pagination$
+ .pipe(takeUntil(this._unsubscribeAll))
+ .subscribe((pagination: MonthlyPagination | undefined) => {
+ // Update the pagination
+ this.pagination = pagination;
+
+ // Mark for check
+ this._changeDetectorRef.markForCheck();
+ });
+
+ // Get the products
+ this.monthlys$ = this._monthlyService.monthlys$;
+ }
+
+ /**
+ * 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 monthly 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._monthlyService.getMonthlys(
+ 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/report/monthly/models/monthly-pagination.ts b/src/app/modules/admin/report/monthly/models/monthly-pagination.ts
new file mode 100644
index 0000000..afd5b82
--- /dev/null
+++ b/src/app/modules/admin/report/monthly/models/monthly-pagination.ts
@@ -0,0 +1,8 @@
+export interface MonthlyPagination {
+ length: number;
+ size: number;
+ page: number;
+ lastPage: number;
+ startIndex: number;
+ endIndex: number;
+}
diff --git a/src/app/modules/admin/report/monthly/models/monthly.ts b/src/app/modules/admin/report/monthly/models/monthly.ts
new file mode 100644
index 0000000..fc883d8
--- /dev/null
+++ b/src/app/modules/admin/report/monthly/models/monthly.ts
@@ -0,0 +1,29 @@
+export interface Monthly {
+ 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/report/monthly/monthly.module.ts b/src/app/modules/admin/report/monthly/monthly.module.ts
new file mode 100644
index 0000000..cb0abdf
--- /dev/null
+++ b/src/app/modules/admin/report/monthly/monthly.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 { monthlyRoutes } from './monthly.routing';
+
+@NgModule({
+ declarations: [COMPONENTS],
+ imports: [
+ TranslocoModule,
+ SharedModule,
+ RouterModule.forChild(monthlyRoutes),
+
+ MatButtonModule,
+ MatFormFieldModule,
+ MatIconModule,
+ MatInputModule,
+ MatPaginatorModule,
+ MatProgressBarModule,
+ MatRippleModule,
+ MatSortModule,
+ MatSelectModule,
+ MatTooltipModule,
+ MatGridListModule,
+ MatSlideToggleModule,
+ MatRadioModule,
+ MatCheckboxModule,
+ ],
+})
+export class MonthlyModule {}
diff --git a/src/app/modules/admin/report/monthly/monthly.routing.ts b/src/app/modules/admin/report/monthly/monthly.routing.ts
new file mode 100644
index 0000000..b2ce27c
--- /dev/null
+++ b/src/app/modules/admin/report/monthly/monthly.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 { MonthlysResolver } from './resolvers/monthly.resolver';
+import { UserResolver } from '../../member/user/resolvers/user.resolver';
+
+export const monthlyRoutes: Route[] = [
+ {
+ path: '',
+ component: ListComponent,
+ resolve: {
+ monthlys: MonthlysResolver,
+ },
+ },
+ {
+ path: ':id',
+ component: ViewComponent,
+ resolve: {
+ users: UserResolver,
+ },
+ },
+];
diff --git a/src/app/modules/admin/report/monthly/resolvers/monthly.resolver.ts b/src/app/modules/admin/report/monthly/resolvers/monthly.resolver.ts
new file mode 100644
index 0000000..ca31eb8
--- /dev/null
+++ b/src/app/modules/admin/report/monthly/resolvers/monthly.resolver.ts
@@ -0,0 +1,87 @@
+import { Injectable } from '@angular/core';
+import {
+ ActivatedRouteSnapshot,
+ Resolve,
+ Router,
+ RouterStateSnapshot,
+} from '@angular/router';
+import { catchError, Observable, throwError } from 'rxjs';
+
+import { Monthly } from '../models/monthly';
+import { MonthlyPagination } from '../models/monthly-pagination';
+import { MonthlyService } from '../services/monthly.service';
+
+@Injectable({
+ providedIn: 'root',
+})
+export class MonthlyResolver implements Resolve {
+ /**
+ * Constructor
+ */
+ constructor(
+ private _monthlyService: MonthlyService,
+ private _router: Router
+ ) {}
+
+ // -----------------------------------------------------------------------------------------------------
+ // @ Public methods
+ // -----------------------------------------------------------------------------------------------------
+
+ /**
+ * Resolver
+ *
+ * @param route
+ * @param state
+ */
+ resolve(
+ route: ActivatedRouteSnapshot,
+ state: RouterStateSnapshot
+ ): Observable {
+ return this._monthlyService.getMonthlyById(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 MonthlysResolver implements Resolve {
+ /**
+ * Constructor
+ */
+ constructor(private _monthlyService: MonthlyService) {}
+
+ // -----------------------------------------------------------------------------------------------------
+ // @ Public methods
+ // -----------------------------------------------------------------------------------------------------
+
+ /**
+ * Resolver
+ *
+ * @param route
+ * @param state
+ */
+ resolve(
+ route: ActivatedRouteSnapshot,
+ state: RouterStateSnapshot
+ ): Observable<{
+ pagination: MonthlyPagination;
+ monthlys: Monthly[];
+ }> {
+ return this._monthlyService.getMonthlys();
+ }
+}
diff --git a/src/app/modules/admin/report/monthly/services/monthly.service.ts b/src/app/modules/admin/report/monthly/services/monthly.service.ts
new file mode 100644
index 0000000..6c5f7fe
--- /dev/null
+++ b/src/app/modules/admin/report/monthly/services/monthly.service.ts
@@ -0,0 +1,153 @@
+import { Injectable } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
+import {
+ BehaviorSubject,
+ filter,
+ map,
+ Observable,
+ of,
+ switchMap,
+ take,
+ tap,
+ throwError,
+} from 'rxjs';
+
+import { Monthly } from '../models/monthly';
+import { MonthlyPagination } from '../models/monthly-pagination';
+
+@Injectable({
+ providedIn: 'root',
+})
+export class MonthlyService {
+ // Private
+ private __pagination = new BehaviorSubject(
+ undefined
+ );
+ private __monthly = new BehaviorSubject(undefined);
+ private __monthlys = new BehaviorSubject(undefined);
+
+ /**
+ * Constructor
+ */
+ constructor(private _httpClient: HttpClient) {}
+
+ // -----------------------------------------------------------------------------------------------------
+ // @ Accessors
+ // -----------------------------------------------------------------------------------------------------
+
+ /**
+ * Getter for pagination
+ */
+ get pagination$(): Observable {
+ return this.__pagination.asObservable();
+ }
+
+ /**
+ * Getter for monthly
+ */
+ get monthly$(): Observable {
+ return this.__monthly.asObservable();
+ }
+
+ /**
+ * Getter for monthlys
+ */
+ get monthlys$(): Observable {
+ return this.__monthlys.asObservable();
+ }
+
+ // -----------------------------------------------------------------------------------------------------
+ // @ Public methods
+ // -----------------------------------------------------------------------------------------------------
+
+ /**
+ * Get Monthlys
+ *
+ *
+ * @param page
+ * @param size
+ * @param sort
+ * @param order
+ * @param search
+ */
+ getMonthlys(
+ page: number = 0,
+ size: number = 10,
+ sort: string = 'name',
+ order: 'asc' | 'desc' | '' = 'asc',
+ search: string = ''
+ ): Observable<{
+ pagination: MonthlyPagination;
+ monthlys: Monthly[];
+ }> {
+ return this._httpClient
+ .get<{
+ pagination: MonthlyPagination;
+ monthlys: Monthly[];
+ }>('api/apps/report/monthly/monthlys', {
+ params: {
+ page: '' + page,
+ size: '' + size,
+ sort,
+ order,
+ search,
+ },
+ })
+ .pipe(
+ tap((response) => {
+ this.__pagination.next(response.pagination);
+ this.__monthlys.next(response.monthlys);
+ })
+ );
+ }
+
+ /**
+ * Get product by id
+ */
+ getMonthlyById(id: string | null): Observable {
+ return this.__monthlys.pipe(
+ take(1),
+ map((monthlys) => {
+ // Find the product
+ const monthly = monthlys?.find((item) => item.id === id) || undefined;
+
+ // Update the product
+ this.__monthly.next(monthly);
+
+ // Return the product
+ return monthly;
+ }),
+ switchMap((product) => {
+ if (!product) {
+ return throwError('Could not found product with id of ' + id + '!');
+ }
+
+ return of(product);
+ })
+ );
+ }
+
+ /**
+ * Create product
+ */
+ createMonthly(): Observable {
+ return this.monthlys$.pipe(
+ take(1),
+ switchMap((monthlys) =>
+ this._httpClient
+ .post('api/apps/report/monthly/product', {})
+ .pipe(
+ map((newMonthly) => {
+ // Update the monthlys with the new product
+ if (!!monthlys) {
+ this.__monthlys.next([newMonthly, ...monthlys]);
+ }
+
+ // Return the new product
+ return newMonthly;
+ })
+ )
+ )
+ );
+ }
+}
diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json
index 5d79623..5b163c3 100644
--- a/src/assets/i18n/en.json
+++ b/src/assets/i18n/en.json
@@ -15,6 +15,7 @@
"Partner Recommendation": "Partner Recommendation",
"Coupon": "Coupon",
"Coupon Moneylog": "Coupon Moneylog",
+ "Coupon Log": "Coupon Log",
"Analytics": "Analytics",
"Deposit": "Deposit",
"Withdraw": "Withdraw",
@@ -22,5 +23,6 @@
"Casino": "Casino",
"Evolution": "Evolution",
"Slot": "Slot",
- "Current User": "Current User"
+ "Current User": "Current User",
+ "Daily": "Daily"
}
diff --git a/src/assets/i18n/ko.json b/src/assets/i18n/ko.json
index 029ce5b..9c627b3 100644
--- a/src/assets/i18n/ko.json
+++ b/src/assets/i18n/ko.json
@@ -15,6 +15,7 @@
"Partner Recommendation": "추천코드등록",
"Coupon": "쿠폰발행리스트",
"Coupon Moneylog": "쿠폰발행머니로그",
+ "Coupon Log": "쿠폰발행 로그",
"Analytics": "Analytics",
"Deposit": "입금관리",
"Withdraw": "출금관리",
@@ -23,5 +24,6 @@
"Evolution": "에볼루션배팅리스트",
"Slot": "슬롯배팅리스트",
"Current User": "현재접속자 & 쪽지전송",
- "Basic-Setting": "사이트 기본설정"
+ "Basic-Setting": "사이트 기본설정",
+ "Daily": "일일현황"
}