wing-ops/frontend/src/common/services/authApi.ts
leedano 3743027ce7 feat(weather): 기상 정보 기상 레이어 업데이트 (#78)
## Summary
- 기상 맵 컨트롤 컴포넌트 추가 및 KHOA API 연동 개선
- KHOA API 엔드포인트 교체 및 해양예측 오버레이 Canvas 렌더링 전환

## 변경 파일
- OceanForecastOverlay.tsx
- WeatherMapOverlay.tsx
- WeatherView.tsx
- useOceanForecast.ts
- khoaApi.ts
- vite.config.ts

## Test plan
- [ ] 기상정보 -> 기상 레이어 -> 해황 예보도 클릭 -> 이미지 렌더링 확인
- [ ] 기상정보 -> 기상 레이어 -> 백터 바람 클릭 -> 백터 이미지 렌더링 확인

Co-authored-by: Nan Kyung Lee <nankyunglee@Nanui-Macmini.local>
Reviewed-on: #78
Co-authored-by: leedano <dnlee@gcsc.co.kr>
Co-committed-by: leedano <dnlee@gcsc.co.kr>
2026-03-11 11:14:25 +09:00

293 lines
7.4 KiB
TypeScript

import { api } from './api'
export interface AuthUser {
id: string
account: string
name: string
rank: string | null
org: { sn: number; name: string; abbr: string } | null
roles: string[]
permissions: Record<string, string[]>
}
interface LoginResponse {
success: boolean
user: AuthUser
pending?: boolean
message?: string
}
export async function loginApi(account: string, password: string): Promise<AuthUser> {
const response = await api.post<LoginResponse>('/auth/login', { account, password })
return response.data.user
}
export class PendingApprovalError extends Error {
constructor(message: string) {
super(message)
this.name = 'PendingApprovalError'
}
}
export async function googleLoginApi(credential: string): Promise<AuthUser> {
const response = await api.post<LoginResponse>('/auth/oauth/google', { credential })
if (response.data.pending) {
throw new PendingApprovalError(response.data.message || '관리자 승인 후 로그인할 수 있습니다.')
}
return response.data.user
}
export async function logoutApi(): Promise<void> {
await api.post('/auth/logout')
}
export async function fetchMe(): Promise<AuthUser> {
const response = await api.get<AuthUser>('/auth/me')
return response.data
}
// 사용자 관리 API (ADMIN 전용)
export interface UserListItem {
id: string
account: string
name: string
rank: string | null
orgSn: number | null
orgName: string | null
orgAbbr: string | null
status: string
failCount: number
lastLogin: string | null
roles: string[]
roleSns: number[]
regDtm: string
oauthProvider: string | null
email: string | null
}
export async function fetchUsers(search?: string, status?: string): Promise<UserListItem[]> {
const params = new URLSearchParams()
if (search) params.set('search', search)
if (status) params.set('status', status)
const response = await api.get<UserListItem[]>(`/users?${params}`)
return response.data
}
export async function fetchUser(id: string): Promise<UserListItem> {
const response = await api.get<UserListItem>(`/users/${id}`)
return response.data
}
export async function createUserApi(data: {
account: string
password: string
name: string
rank?: string
orgSn?: number
roleSns?: number[]
}): Promise<{ id: string }> {
const response = await api.post<{ id: string }>('/users', data)
return response.data
}
export async function updateUserApi(id: string, data: {
name?: string
rank?: string
orgSn?: number | null
status?: string
}): Promise<void> {
await api.put(`/users/${id}`, data)
}
export async function changePasswordApi(id: string, password: string): Promise<void> {
await api.put(`/users/${id}/password`, { password })
}
export async function assignRolesApi(id: string, roleSns: number[]): Promise<void> {
await api.put(`/users/${id}/roles`, { roleSns })
}
// 조직 목록 API
export interface OrgItem {
orgSn: number
orgNm: string
orgAbbrNm: string | null
orgTpCd: string
upperOrgSn: number | null
}
export async function fetchOrgs(): Promise<OrgItem[]> {
const response = await api.get<OrgItem[]>('/users/orgs')
return response.data
}
// 역할/권한 API (ADMIN 전용)
export interface RoleWithPermissions {
sn: number
code: string
name: string
description: string | null
isDefault: boolean
permissions: Array<{
sn: number
resourceCode: string
operationCode: string
granted: boolean
}>
}
export async function fetchRoles(): Promise<RoleWithPermissions[]> {
const response = await api.get<RoleWithPermissions[]>('/roles')
return response.data
}
// 권한 트리 구조 API
export interface PermTreeNode {
code: string
parentCode: string | null
name: string
description: string | null
icon: string | null
level: number
sortOrder: number
children: PermTreeNode[]
}
export async function fetchPermTree(): Promise<PermTreeNode[]> {
const response = await api.get<PermTreeNode[]>('/roles/perm-tree')
return response.data
}
export async function updatePermissionsApi(
roleSn: number,
permissions: Array<{ resourceCode: string; operationCode: string; granted: boolean }>
): Promise<void> {
await api.put(`/roles/${roleSn}/permissions`, { permissions })
}
export async function updateRoleDefaultApi(roleSn: number, isDefault: boolean): Promise<void> {
await api.put(`/roles/${roleSn}/default`, { isDefault })
}
export async function createRoleApi(data: {
code: string
name: string
description?: string
}): Promise<RoleWithPermissions> {
const response = await api.post<RoleWithPermissions>('/roles', data)
return response.data
}
export async function updateRoleApi(
roleSn: number,
data: { name?: string; description?: string }
): Promise<void> {
await api.put(`/roles/${roleSn}`, data)
}
export async function deleteRoleApi(roleSn: number): Promise<void> {
await api.delete(`/roles/${roleSn}`)
}
// 사용자 승인/거절 API (ADMIN 전용)
export async function approveUserApi(id: string): Promise<void> {
await api.put(`/users/${id}/approve`)
}
export async function rejectUserApi(id: string): Promise<void> {
await api.put(`/users/${id}/reject`)
}
// 시스템 설정 API (ADMIN 전용)
export interface RegistrationSettings {
autoApprove: boolean
defaultRole: boolean
}
export async function fetchRegistrationSettings(): Promise<RegistrationSettings> {
const response = await api.get<RegistrationSettings>('/settings/registration')
return response.data
}
export async function updateRegistrationSettingsApi(
settings: Partial<RegistrationSettings>
): Promise<RegistrationSettings> {
const response = await api.put<RegistrationSettings>('/settings/registration', settings)
return response.data
}
// OAuth 설정 API (ADMIN 전용)
export interface OAuthSettings {
autoApproveDomains: string
}
export async function fetchOAuthSettings(): Promise<OAuthSettings> {
const response = await api.get<OAuthSettings>('/settings/oauth')
return response.data
}
export async function updateOAuthSettingsApi(
settings: Partial<OAuthSettings>
): Promise<OAuthSettings> {
const response = await api.put<OAuthSettings>('/settings/oauth', settings)
return response.data
}
// 메뉴 설정 API
export interface MenuConfigItem {
id: string
label: string
icon: string
enabled: boolean
order: number
}
export async function fetchMenuConfig(): Promise<MenuConfigItem[]> {
const response = await api.get<MenuConfigItem[]>('/menus')
return response.data
}
export async function updateMenuConfigApi(menus: MenuConfigItem[]): Promise<MenuConfigItem[]> {
const response = await api.put<MenuConfigItem[]>('/menus', { menus })
return response.data
}
// 감사 로그 API (ADMIN 전용)
export interface AuditLogItem {
logSn: number
userId: string
userName: string | null
userAccount: string | null
actionCd: string
actionDtl: string | null
httpMethod: string | null
crudType: string | null
reqUrl: string | null
reqDtm: string
resDtm: string | null
resStatus: number | null
resSize: number | null
ipAddr: string | null
userAgent: string | null
extra: Record<string, unknown> | null
}
export interface AuditLogListResult {
items: AuditLogItem[]
total: number
page: number
size: number
}
export async function fetchAuditLogs(params?: {
page?: number
size?: number
userId?: string
actionCd?: string
from?: string
to?: string
}): Promise<AuditLogListResult> {
const response = await api.get<AuditLogListResult>('/audit/logs', { params })
return response.data
}