Merge branch 'lhj'
This commit is contained in:
@@ -12,12 +12,12 @@ const getApiBaseUrl = (): string => {
|
||||
const currentHost = window.location.hostname;
|
||||
const currentPort = window.location.port;
|
||||
|
||||
// 로컬 개발환경: localhost:9771 또는 localhost:3000 → localhost:8080
|
||||
// 🎯 로컬 개발환경: Next.js 프록시 사용 (대용량 요청 안정성)
|
||||
if (
|
||||
(currentHost === "localhost" || currentHost === "127.0.0.1") &&
|
||||
(currentPort === "9771" || currentPort === "3000")
|
||||
) {
|
||||
return "http://localhost:8080/api";
|
||||
return "/api"; // 프록시 사용
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -70,12 +70,76 @@ export interface UpdateMailTemplateDto extends Partial<CreateMailTemplateDto> {}
|
||||
export interface SendMailDto {
|
||||
accountId: string;
|
||||
templateId?: string;
|
||||
to: string[]; // 수신자 이메일 배열
|
||||
to: string[]; // 받는 사람
|
||||
cc?: string[]; // 참조 (Carbon Copy)
|
||||
bcc?: string[]; // 숨은참조 (Blind Carbon Copy)
|
||||
subject: string;
|
||||
variables?: Record<string, string>; // 템플릿 변수 치환
|
||||
customHtml?: string; // 템플릿 없이 직접 HTML 작성 시
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 발송 이력 타입
|
||||
// ============================================
|
||||
|
||||
export interface AttachmentInfo {
|
||||
filename: string;
|
||||
originalName: string;
|
||||
size: number;
|
||||
path: string;
|
||||
mimetype: string;
|
||||
}
|
||||
|
||||
export interface SentMailHistory {
|
||||
id: string;
|
||||
accountId: string;
|
||||
accountName: string;
|
||||
accountEmail: string;
|
||||
to: string[];
|
||||
cc?: string[];
|
||||
bcc?: string[];
|
||||
subject: string;
|
||||
htmlContent: string;
|
||||
templateId?: string;
|
||||
templateName?: string;
|
||||
attachments?: AttachmentInfo[];
|
||||
sentAt: string;
|
||||
status: 'success' | 'failed';
|
||||
messageId?: string;
|
||||
errorMessage?: string;
|
||||
accepted?: string[];
|
||||
rejected?: string[];
|
||||
}
|
||||
|
||||
export interface SentMailListQuery {
|
||||
page?: number;
|
||||
limit?: number;
|
||||
searchTerm?: string;
|
||||
status?: 'success' | 'failed' | 'all';
|
||||
accountId?: string;
|
||||
startDate?: string;
|
||||
endDate?: string;
|
||||
sortBy?: 'sentAt' | 'subject';
|
||||
sortOrder?: 'asc' | 'desc';
|
||||
}
|
||||
|
||||
export interface SentMailListResponse {
|
||||
items: SentMailHistory[];
|
||||
total: number;
|
||||
page: number;
|
||||
limit: number;
|
||||
totalPages: number;
|
||||
}
|
||||
|
||||
export interface MailStatistics {
|
||||
totalSent: number;
|
||||
successCount: number;
|
||||
failedCount: number;
|
||||
todayCount: number;
|
||||
thisMonthCount: number;
|
||||
successRate: number;
|
||||
}
|
||||
|
||||
export interface MailSendResult {
|
||||
success: boolean;
|
||||
messageId?: string;
|
||||
@@ -96,7 +160,7 @@ async function fetchApi<T>(
|
||||
|
||||
try {
|
||||
const response = await apiClient({
|
||||
url: `/mail${endpoint}`,
|
||||
url: endpoint, // `/mail` 접두사 제거 (apiClient는 이미 /api를 포함)
|
||||
method,
|
||||
data,
|
||||
});
|
||||
@@ -124,14 +188,14 @@ async function fetchApi<T>(
|
||||
* 전체 메일 계정 목록 조회
|
||||
*/
|
||||
export async function getMailAccounts(): Promise<MailAccount[]> {
|
||||
return fetchApi<MailAccount[]>('/accounts');
|
||||
return fetchApi<MailAccount[]>('/mail/accounts');
|
||||
}
|
||||
|
||||
/**
|
||||
* 특정 메일 계정 조회
|
||||
*/
|
||||
export async function getMailAccount(id: string): Promise<MailAccount> {
|
||||
return fetchApi<MailAccount>(`/accounts/${id}`);
|
||||
return fetchApi<MailAccount>(`/mail/accounts/${id}`);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -140,7 +204,7 @@ export async function getMailAccount(id: string): Promise<MailAccount> {
|
||||
export async function createMailAccount(
|
||||
data: CreateMailAccountDto
|
||||
): Promise<MailAccount> {
|
||||
return fetchApi<MailAccount>('/accounts', {
|
||||
return fetchApi<MailAccount>('/mail/accounts', {
|
||||
method: 'POST',
|
||||
data,
|
||||
});
|
||||
@@ -153,7 +217,7 @@ export async function updateMailAccount(
|
||||
id: string,
|
||||
data: UpdateMailAccountDto
|
||||
): Promise<MailAccount> {
|
||||
return fetchApi<MailAccount>(`/accounts/${id}`, {
|
||||
return fetchApi<MailAccount>(`/mail/accounts/${id}`, {
|
||||
method: 'PUT',
|
||||
data,
|
||||
});
|
||||
@@ -163,7 +227,7 @@ export async function updateMailAccount(
|
||||
* 메일 계정 삭제
|
||||
*/
|
||||
export async function deleteMailAccount(id: string): Promise<{ success: boolean }> {
|
||||
return fetchApi<{ success: boolean }>(`/accounts/${id}`, {
|
||||
return fetchApi<{ success: boolean }>(`/mail/accounts/${id}`, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
}
|
||||
@@ -172,7 +236,7 @@ export async function deleteMailAccount(id: string): Promise<{ success: boolean
|
||||
* SMTP 연결 테스트
|
||||
*/
|
||||
export async function testMailAccountConnection(id: string): Promise<{ success: boolean; message: string }> {
|
||||
return fetchApi<{ success: boolean; message: string }>(`/accounts/${id}/test-connection`, {
|
||||
return fetchApi<{ success: boolean; message: string }>(`/mail/accounts/${id}/test-connection`, {
|
||||
method: 'POST',
|
||||
});
|
||||
}
|
||||
@@ -185,7 +249,7 @@ export async function testMailConnection(id: string): Promise<{
|
||||
message: string;
|
||||
}> {
|
||||
return fetchApi<{ success: boolean; message: string }>(
|
||||
`/accounts/${id}/test-connection`,
|
||||
`/mail/accounts/${id}/test-connection`,
|
||||
{
|
||||
method: 'POST',
|
||||
}
|
||||
@@ -200,14 +264,14 @@ export async function testMailConnection(id: string): Promise<{
|
||||
* 전체 메일 템플릿 목록 조회
|
||||
*/
|
||||
export async function getMailTemplates(): Promise<MailTemplate[]> {
|
||||
return fetchApi<MailTemplate[]>('/templates-file');
|
||||
return fetchApi<MailTemplate[]>('/mail/templates-file');
|
||||
}
|
||||
|
||||
/**
|
||||
* 특정 메일 템플릿 조회
|
||||
*/
|
||||
export async function getMailTemplate(id: string): Promise<MailTemplate> {
|
||||
return fetchApi<MailTemplate>(`/templates-file/${id}`);
|
||||
return fetchApi<MailTemplate>(`/mail/templates-file/${id}`);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -216,7 +280,7 @@ export async function getMailTemplate(id: string): Promise<MailTemplate> {
|
||||
export async function createMailTemplate(
|
||||
data: CreateMailTemplateDto
|
||||
): Promise<MailTemplate> {
|
||||
return fetchApi<MailTemplate>('/templates-file', {
|
||||
return fetchApi<MailTemplate>('/mail/templates-file', {
|
||||
method: 'POST',
|
||||
data,
|
||||
});
|
||||
@@ -229,7 +293,7 @@ export async function updateMailTemplate(
|
||||
id: string,
|
||||
data: UpdateMailTemplateDto
|
||||
): Promise<MailTemplate> {
|
||||
return fetchApi<MailTemplate>(`/templates-file/${id}`, {
|
||||
return fetchApi<MailTemplate>(`/mail/templates-file/${id}`, {
|
||||
method: 'PUT',
|
||||
data,
|
||||
});
|
||||
@@ -239,7 +303,7 @@ export async function updateMailTemplate(
|
||||
* 메일 템플릿 삭제
|
||||
*/
|
||||
export async function deleteMailTemplate(id: string): Promise<{ success: boolean }> {
|
||||
return fetchApi<{ success: boolean }>(`/templates-file/${id}`, {
|
||||
return fetchApi<{ success: boolean }>(`/mail/templates-file/${id}`, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
}
|
||||
@@ -251,7 +315,7 @@ export async function previewMailTemplate(
|
||||
id: string,
|
||||
sampleData?: Record<string, string>
|
||||
): Promise<{ html: string }> {
|
||||
return fetchApi<{ html: string }>(`/templates-file/${id}/preview`, {
|
||||
return fetchApi<{ html: string }>(`/mail/templates-file/${id}/preview`, {
|
||||
method: 'POST',
|
||||
data: { sampleData },
|
||||
});
|
||||
@@ -265,7 +329,7 @@ export async function previewMailTemplate(
|
||||
* 메일 발송 (단건 또는 소규모 발송)
|
||||
*/
|
||||
export async function sendMail(data: SendMailDto): Promise<MailSendResult> {
|
||||
return fetchApi<MailSendResult>('/send/simple', {
|
||||
return fetchApi<MailSendResult>('/mail/send/simple', {
|
||||
method: 'POST',
|
||||
data,
|
||||
});
|
||||
@@ -407,6 +471,15 @@ export async function getReceivedMails(
|
||||
return fetchApi<ReceivedMail[]>(`/mail/receive/${accountId}?limit=${limit}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 오늘 수신한 메일 수 조회 (통계)
|
||||
*/
|
||||
export async function getTodayReceivedCount(accountId?: string): Promise<number> {
|
||||
const params = accountId ? `?accountId=${accountId}` : '';
|
||||
const response = await fetchApi<{ count: number }>(`/mail/receive/today-count${params}`);
|
||||
return response.count;
|
||||
}
|
||||
|
||||
/**
|
||||
* 메일 상세 조회
|
||||
*/
|
||||
@@ -439,3 +512,52 @@ export async function testImapConnection(
|
||||
method: 'POST',
|
||||
});
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 발송 이력 API
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* 발송 이력 목록 조회
|
||||
*/
|
||||
export async function getSentMailList(
|
||||
query: SentMailListQuery = {}
|
||||
): Promise<SentMailListResponse> {
|
||||
const params = new URLSearchParams();
|
||||
|
||||
if (query.page) params.append('page', query.page.toString());
|
||||
if (query.limit) params.append('limit', query.limit.toString());
|
||||
if (query.searchTerm) params.append('searchTerm', query.searchTerm);
|
||||
if (query.status && query.status !== 'all') params.append('status', query.status);
|
||||
if (query.accountId) params.append('accountId', query.accountId);
|
||||
if (query.startDate) params.append('startDate', query.startDate);
|
||||
if (query.endDate) params.append('endDate', query.endDate);
|
||||
if (query.sortBy) params.append('sortBy', query.sortBy);
|
||||
if (query.sortOrder) params.append('sortOrder', query.sortOrder);
|
||||
|
||||
return fetchApi(`/mail/sent?${params.toString()}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 특정 발송 이력 상세 조회
|
||||
*/
|
||||
export async function getSentMailById(id: string): Promise<SentMailHistory> {
|
||||
return fetchApi(`/mail/sent/${id}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 발송 이력 삭제
|
||||
*/
|
||||
export async function deleteSentMail(id: string): Promise<{ success: boolean; message: string }> {
|
||||
return fetchApi(`/mail/sent/${id}`, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 메일 발송 통계 조회
|
||||
*/
|
||||
export async function getMailStatistics(accountId?: string): Promise<MailStatistics> {
|
||||
const params = accountId ? `?accountId=${accountId}` : '';
|
||||
return fetchApi(`/mail/sent/statistics${params}`);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user