Skip to content
This repository was archived by the owner on Aug 29, 2025. It is now read-only.

Commit 14f65ef

Browse files
AI 사용량 추가 및 스크롤 재수정
1 parent cf45830 commit 14f65ef

File tree

6 files changed

+118
-57
lines changed

6 files changed

+118
-57
lines changed

src/app/components/dashboard/dashboard.component.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { AiUsage } from './../../services/admin.service';
12
import { Component, OnInit } from '@angular/core';
23
import { CommonModule } from '@angular/common';
34
import { Router } from '@angular/router';
@@ -125,6 +126,44 @@ import { AdminService, SystemStatus, UserStats } from '../../services/admin.serv
125126
</div>
126127
</div>
127128
129+
<!-- AI 사용량 카드 -->
130+
<div class="md-card bg-md-sys-color-surface-container text-md-sys-color-on-surface hover:shadow-elevation-3 transition-all duration-300">
131+
<div class="flex items-center gap-3 mb-4">
132+
<mat-icon class="w-6 h-6 text-md-sys-color-primary">memory</mat-icon>
133+
<h2 class="md-typescale-title-large text-md-sys-color-on-surface">AI 사용량</h2>
134+
</div>
135+
<div class="flex-1">
136+
<div *ngIf="aiUsage" class="space-y-4">
137+
<div class="grid grid-cols-2 gap-4">
138+
<div class="text-center p-4 bg-md-sys-color-primary-container rounded-xl">
139+
<div class="text-3xl font-bold text-md-sys-color-on-primary-container mb-1">{{ aiUsage.total_credits }}</div>
140+
<div class="md-typescale-body-small text-md-sys-color-on-primary-container">충전된 크레딧</div>
141+
</div>
142+
<div class="text-center p-4 bg-md-sys-color-secondary-container rounded-xl">
143+
<div class="text-3xl font-bold text-md-sys-color-on-secondary-container mb-1">{{ aiUsage.total_usage }}</div>
144+
<div class="md-typescale-body-small text-md-sys-color-on-secondary-container">총 사용 크레딧</div>
145+
</div>
146+
</div>
147+
<div class="mt-4">
148+
<div class="flex justify-between items-center mb-2">
149+
<span class="md-typescale-body-small text-md-sys-color-on-surface-variant">사용량 추세</span>
150+
<span class="md-typescale-body-small text-md-sys-color-on-surface-variant">{{ aiUsage.total_usage }} 크레딧</span>
151+
</div>
152+
<div class="w-full bg-md-sys-color-surface-container-high rounded-full h-2">
153+
<div class="bg-md-sys-color-primary h-2 rounded-full transition-all duration-300"
154+
[style.width.%]="(aiUsage.total_usage / aiUsage.total_credits) * 100"></div>
155+
</div>
156+
</div>
157+
<div *ngIf="!aiUsage" class="flex items-center justify-center h-48 text-md-sys-color-on-surface-variant">
158+
<div class="flex items-center">
159+
<mat-icon class="w-5 h-5 animate-spin">refresh</mat-icon>
160+
<span class="md-typescale-body-medium">AI 통계를 불러오는 중...</span>
161+
</div>
162+
</div>
163+
</div>
164+
</div>
165+
</div>
166+
128167
<!-- 빠른 액션 카드 -->
129168
<div class="md-card bg-md-sys-color-surface-container text-md-sys-color-on-surface hover:shadow-elevation-3 transition-all duration-300">
130169
<div class="flex items-center gap-3 mb-4">
@@ -186,6 +225,7 @@ import { AdminService, SystemStatus, UserStats } from '../../services/admin.serv
186225
export class DashboardComponent implements OnInit {
187226
systemStatus: SystemStatus | null = null;
188227
userStats: UserStats | null = null;
228+
aiUsage: AiUsage | null = null;
189229

190230
constructor(private adminService: AdminService, private router: Router) {}
191231

@@ -195,6 +235,7 @@ export class DashboardComponent implements OnInit {
195235

196236
loadData() {
197237
this.loadSystemStatus();
238+
this.loadAiUsage();
198239
this.loadUserStats();
199240
}
200241

@@ -210,6 +251,18 @@ export class DashboardComponent implements OnInit {
210251
}
211252
});
212253
}
254+
loadAiUsage() {
255+
this.adminService.getAiUsage().subscribe({
256+
next: (response) => {
257+
if (response.success) {
258+
this.aiUsage = response.data;
259+
}
260+
},
261+
error: (error) => {
262+
console.error('AI 사용량 로드 실패:', error);
263+
}
264+
});
265+
}
213266

214267
loadUserStats() {
215268
this.adminService.getUserStats().subscribe({

src/app/components/database/database.component.ts

Lines changed: 34 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,10 @@ import { AdminService, TableInfo, TableData } from '../../services/admin.service
2929
MatChipsModule
3030
],
3131
template: `
32-
<div class="p-6 bg-md-sys-color-surface h-screen overflow-hidden">
32+
<div class="p-6 bg-md-sys-color-surface h-screen">
3333
<h1 class="md-typescale-headline-large text-md-sys-color-on-surface mb-6">데이터베이스 관리</h1>
3434
35-
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6 h-[calc(100%-3rem)]">
35+
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6" style="height: calc(100vh - 8rem);">
3636
<!-- 테이블 목록 -->
3737
<div class="md-card bg-md-sys-color-surface-container text-md-sys-color-on-surface lg:col-span-1">
3838
<div class="flex items-center justify-between mb-4">
@@ -97,9 +97,9 @@ import { AdminService, TableInfo, TableData } from '../../services/admin.service
9797
<p class="md-typescale-body-medium">테이블 데이터를 불러오는 중...</p>
9898
</div>
9999
100-
<div *ngIf="tableData && !loadingData" class="flex flex-col h-full overflow-hidden">
100+
<div *ngIf="tableData && !loadingData" class="flex flex-col h-full min-h-0 overflow-hidden">
101101
<!-- 컬럼 정보 -->
102-
<div class="mb-6">
102+
<div class="mb-6 flex-shrink-0">
103103
<h3 class="md-typescale-title-medium text-md-sys-color-on-surface mb-3 flex items-center gap-2">
104104
<mat-icon class="w-5 h-5 text-md-sys-color-primary">info</mat-icon>
105105
컬럼 정보
@@ -127,40 +127,42 @@ import { AdminService, TableInfo, TableData } from '../../services/admin.service
127127
</div>
128128
129129
<!-- 테이블 데이터 -->
130-
<div class="flex-1 flex flex-col overflow-hidden">
131-
<h3 class="md-typescale-title-medium text-md-sys-color-on-surface mb-3 flex items-center gap-2">
130+
<div class="flex-1 flex flex-col min-h-0 overflow-hidden">
131+
<h3 class="md-typescale-title-medium text-md-sys-color-on-surface mb-3 flex items-center gap-2 flex-shrink-0">
132132
<mat-icon class="w-5 h-5 text-md-sys-color-primary">table_rows</mat-icon>
133133
데이터 ({{ tableData.pagination.totalCount }}개 레코드)
134134
</h3>
135-
<div class="flex-1 overflow-auto border border-md-sys-color-outline-variant rounded-xl">
136-
<table mat-table [dataSource]="tableData.rows" class="w-full min-w-max">
137-
<ng-container *ngFor="let column of tableData.columns" [matColumnDef]="column.name">
138-
<th mat-header-cell *matHeaderCellDef class="bg-md-sys-color-surface-container-high">
139-
<div class="flex items-center gap-2 md-typescale-label-large font-medium text-md-sys-color-on-surface">
140-
<span>{{ column.name }}</span>
141-
<mat-icon
142-
*ngIf="column.key"
143-
class="w-4 h-4 text-md-sys-color-primary"
144-
[matTooltip]="getKeyTooltip(column.key)">
145-
{{ getKeyIcon(column.key) }}
146-
</mat-icon>
147-
</div>
148-
</th>
149-
<td mat-cell *matCellDef="let row" class="border-b border-md-sys-color-outline-variant">
150-
<div class="max-w-48 overflow-hidden text-ellipsis whitespace-nowrap md-typescale-body-medium text-md-sys-color-on-surface"
151-
[matTooltip]="formatCellValue(row[column.name])">
152-
{{ formatCellValue(row[column.name]) }}
153-
</div>
154-
</td>
155-
</ng-container>
135+
<div class="flex-1 min-h-0 overflow-hidden">
136+
<div class="h-full overflow-auto border border-md-sys-color-outline-variant rounded-xl">
137+
<table mat-table [dataSource]="tableData.rows" class="w-full min-w-max">
138+
<ng-container *ngFor="let column of tableData.columns" [matColumnDef]="column.name">
139+
<th mat-header-cell *matHeaderCellDef class="bg-md-sys-color-surface-container-high">
140+
<div class="flex items-center gap-2 md-typescale-label-large font-medium text-md-sys-color-on-surface">
141+
<span>{{ column.name }}</span>
142+
<mat-icon
143+
*ngIf="column.key"
144+
class="w-4 h-4 text-md-sys-color-primary"
145+
[matTooltip]="getKeyTooltip(column.key)">
146+
{{ getKeyIcon(column.key) }}
147+
</mat-icon>
148+
</div>
149+
</th>
150+
<td mat-cell *matCellDef="let row" class="border-b border-md-sys-color-outline-variant">
151+
<div class="max-w-48 overflow-hidden text-ellipsis whitespace-nowrap md-typescale-body-medium text-md-sys-color-on-surface"
152+
[matTooltip]="formatCellValue(row[column.name])">
153+
{{ formatCellValue(row[column.name]) }}
154+
</div>
155+
</td>
156+
</ng-container>
156157
157-
<tr mat-header-row *matHeaderRowDef="getDisplayedColumns()"></tr>
158-
<tr mat-row *matRowDef="let row; columns: getDisplayedColumns()" class="hover:bg-md-sys-color-surface-container-high"></tr>
159-
</table>
158+
<tr mat-header-row *matHeaderRowDef="getDisplayedColumns()"></tr>
159+
<tr mat-row *matRowDef="let row; columns: getDisplayedColumns()" class="hover:bg-md-sys-color-surface-container-high"></tr>
160+
</table>
161+
</div>
160162
</div>
161163
162164
<!-- 페이지네이션 -->
163-
<div class="mt-4">
165+
<div class="mt-4 flex-shrink-0">
164166
<mat-paginator
165167
[length]="tableData.pagination.totalCount"
166168
[pageSize]="tableData.pagination.limit"
@@ -183,6 +185,7 @@ import { AdminService, TableInfo, TableData } from '../../services/admin.service
183185
padding: 24px;
184186
display: flex;
185187
flex-direction: column;
188+
max-height: 100%;
186189
}
187190
188191
.md-button {

src/app/components/login-modal/login-modal.component.ts

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ import { MatIconModule } from '@angular/material/icon';
3535
text-decoration: none;
3636
transition: all 0.2s ease;
3737
}
38-
38+
3939
.md-button:hover {
4040
transform: translateY(-1px);
4141
filter: brightness(1.1);
@@ -45,14 +45,9 @@ import { MatIconModule } from '@angular/material/icon';
4545
export class LoginModalComponent {
4646
constructor(
4747
public dialogRef: MatDialogRef<LoginModalComponent>,
48-
@Inject(MAT_DIALOG_DATA) public data: { returnUrl: string }
4948
) {}
5049

5150
loginWithGoogle(): void {
52-
const baseUrl = 'https://api-dev.dimiplan.com';
53-
const adminPanelUrl = window.location.origin;
54-
const returnUrl = encodeURIComponent(`${adminPanelUrl}${this.data.returnUrl}`);
55-
56-
window.location.href = `${baseUrl}/auth/google?returnUrl=${returnUrl}`;
51+
window.location.href = `https://api-dev.dimiplan.com/auth/google?returnUrl=admin.dimiplan.com`;
5752
}
5853
}

src/app/components/logs/logs.component.ts

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,19 +27,19 @@ import { AdminService, LogFile, LogContent } from '../../services/admin.service'
2727
FormsModule
2828
],
2929
template: `
30-
<div class="p-6 bg-md-sys-color-surface h-screen overflow-hidden">
30+
<div class="p-6 bg-md-sys-color-surface h-screen">
3131
<h1 class="md-typescale-headline-large text-md-sys-color-on-surface mb-6">로그 관리</h1>
3232
33-
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6 h-[calc(100vh-8rem)]">
33+
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6" style="height: calc(100vh - 8rem);">
3434
<!-- 로그 파일 목록 -->
35-
<div class="md-card bg-md-sys-color-surface-container text-md-sys-color-on-surface lg:col-span-1">
35+
<div class="md-card bg-md-sys-color-surface-container text-md-sys-color-on-surface lg:col-span-1" style="max-height: 100%; display: flex; flex-direction: column;">
3636
<div class="flex items-center justify-between mb-4">
3737
<h2 class="md-typescale-title-large text-md-sys-color-on-surface">로그 파일 목록</h2>
3838
<button class="md-button md-button-text p-2 rounded-full" (click)="refreshLogFiles()">
3939
<mat-icon class="w-5 h-5 text-md-sys-color-primary">refresh</mat-icon>
4040
</button>
4141
</div>
42-
<div class="flex-1 overflow-y-auto">
42+
<div class="flex-1 overflow-y-auto" style="min-height: 0;">
4343
<div *ngIf="logFiles.length > 0" class="space-y-2">
4444
<div
4545
*ngFor="let file of logFiles"
@@ -68,7 +68,7 @@ import { AdminService, LogFile, LogContent } from '../../services/admin.service'
6868
</div>
6969
7070
<!-- 로그 내용 뷰어 -->
71-
<div class="md-card bg-md-sys-color-surface-container text-md-sys-color-on-surface lg:col-span-2">
71+
<div class="md-card bg-md-sys-color-surface-container text-md-sys-color-on-surface lg:col-span-2" style="max-height: 100%; display: flex; flex-direction: column;">
7272
<div class="flex items-center justify-between mb-4">
7373
<h2 class="md-typescale-title-large text-md-sys-color-on-surface">
7474
{{ selectedFile ? selectedFile.name : '로그 뷰어' }}
@@ -83,7 +83,7 @@ import { AdminService, LogFile, LogContent } from '../../services/admin.service'
8383
</button>
8484
</div>
8585
</div>
86-
<div class="flex-1 overflow-hidden">
86+
<div class="flex-1" style="min-height: 0; overflow: hidden;">
8787
<div *ngIf="!selectedFile" class="flex items-center justify-center h-full text-md-sys-color-on-surface-variant">
8888
<div class="text-center">
8989
<mat-icon class="w-16 h-16 mb-4 text-md-sys-color-outline">visibility</mat-icon>
@@ -103,8 +103,8 @@ import { AdminService, LogFile, LogContent } from '../../services/admin.service'
103103
<p class="md-typescale-body-medium">로그 내용을 불러오는 중...</p>
104104
</div>
105105
106-
<div *ngIf="logContent" class="flex flex-col h-full">
107-
<div class="flex items-center justify-between p-3 bg-md-sys-color-surface-container-high rounded-xl mb-4">
106+
<div *ngIf="logContent" style="height: 100%; display: flex; flex-direction: column;">
107+
<div class="flex items-center justify-between p-3 bg-md-sys-color-surface-container-high rounded-xl mb-4" style="flex-shrink: 0;">
108108
<span class="md-typescale-body-medium text-md-sys-color-on-surface">총 {{ logContent.lines }}줄 표시</span>
109109
<div class="flex gap-1">
110110
<button
@@ -121,13 +121,15 @@ import { AdminService, LogFile, LogContent } from '../../services/admin.service'
121121
(click)="setLogFilter('info')">정보</button>
122122
</div>
123123
</div>
124-
<div class="flex-1 bg-gray-900 rounded-xl overflow-auto">
125-
<div *ngFor="let line of getFilteredLogLines(); let i = index"
126-
[class]="'flex items-start gap-3 p-2 font-mono text-sm border-b border-gray-800 hover:bg-gray-800 ' + getLogLineClass(line)">
127-
<span class="w-12 text-gray-500 text-right select-none">{{ i + 1 }}</span>
128-
<span class="w-36 text-gray-400 shrink-0">{{ extractTimestamp(line) }}</span>
129-
<span [class]="'w-16 font-bold uppercase shrink-0 ' + getLogLevelColorClass(extractLogLevel(line))">{{ extractLogLevel(line) }}</span>
130-
<span class="flex-1 text-gray-200 break-words">{{ extractMessage(line) }}</span>
124+
<div style="flex: 1; min-height: 0; overflow: hidden;">
125+
<div class="bg-gray-900 rounded-xl" style="height: 100%; overflow-y: auto;">
126+
<div *ngFor="let line of getFilteredLogLines(); let i = index"
127+
[class]="'flex items-start gap-3 p-2 font-mono text-sm border-b border-gray-800 hover:bg-gray-800 ' + getLogLineClass(line)">
128+
<span class="w-12 text-gray-500 text-right select-none">{{ i + 1 }}</span>
129+
<span class="w-36 text-gray-400 shrink-0">{{ extractTimestamp(line) }}</span>
130+
<span [class]="'w-16 font-bold uppercase shrink-0 ' + getLogLevelColorClass(extractLogLevel(line))">{{ extractLogLevel(line) }}</span>
131+
<span class="flex-1 text-gray-200 break-words">{{ extractMessage(line) }}</span>
132+
</div>
131133
</div>
132134
</div>
133135
</div>
@@ -141,6 +143,7 @@ import { AdminService, LogFile, LogContent } from '../../services/admin.service'
141143
padding: 24px;
142144
display: flex;
143145
flex-direction: column;
146+
max-height: 100%;
144147
}
145148
146149
.md-button {

src/app/services/admin.service.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ export interface SystemStatus {
1313
timestamp: string;
1414
}
1515

16+
export interface AiUsage {
17+
total_credits: number;
18+
total_usage: number;
19+
}
20+
1621
export interface LogFile {
1722
name: string;
1823
size: number;
@@ -93,6 +98,10 @@ export class AdminService {
9398
return this.http.get<{ success: boolean; data: SystemStatus }>(`${this.baseUrl}/system-status`);
9499
}
95100

101+
getAiUsage(): Observable<{ success: boolean; data: AiUsage }> {
102+
return this.http.get<{ success: boolean; data: AiUsage }>(`${this.baseUrl}/ai-usage`);
103+
}
104+
96105
getLogFiles(): Observable<{ success: boolean; data: LogFile[] }> {
97106
return this.http.get<{ success: boolean; data: LogFile[] }>(`${this.baseUrl}/logs`);
98107
}

src/app/services/auth-modal.service.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,11 @@ export class AuthModalService {
99
constructor(private dialog: MatDialog) {}
1010

1111
openLoginModal(): void {
12-
const currentUrl = window.location.pathname + window.location.search;
13-
12+
// Open the login modal dialog
1413
this.dialog.open(LoginModalComponent, {
15-
data: { returnUrl: currentUrl },
1614
disableClose: true,
1715
width: '400px',
1816
panelClass: 'login-modal'
1917
});
2018
}
21-
}
19+
}

0 commit comments

Comments
 (0)