guardia-esn/frontend/src/api/client.ts
2026-07-04 09:01:32 +09:00

162 lines
12 KiB
TypeScript

import axios from 'axios'
const api = axios.create({ baseURL: '' })
api.interceptors.request.use(config => {
const token = localStorage.getItem('esn_token')
if (token) config.headers.Authorization = `Bearer ${token}`
return config
})
api.interceptors.response.use(
res => res,
err => {
if (err.response?.status === 401) {
localStorage.removeItem('esn_token')
if (location.pathname !== '/login') location.href = '/login'
}
return Promise.reject(err)
}
)
export default api
const unwrap = (p: Promise<any>) => p.then(r => r.data?.data)
// ── Auth ──────────────────────────────────────────────────────────────────
export const login = (username: string, password: string) =>
api.post('/api/auth/login', { username, password })
export const getMe = () => api.get('/api/auth/me')
export const logout = () => api.post('/api/auth/logout')
// ── 2FA / OTP / 계정 보안 (마이페이지, access 토큰 필요) ─────────────────────
// 보안 불변: setup 응답(secret/qrImage)은 화면 표시용만 — 로그/저장 금지. raw 응답 반환(호출부 res.data.data).
export const otpSetup = () => api.post('/api/auth/otp/setup')
export const otpConfirm = (code: string) => api.post('/api/auth/otp/confirm', { code })
export const otpDisable = () => api.post('/api/auth/otp/disable')
export const changePassword = (currentPassword: string, newPassword: string) =>
api.post('/api/auth/change-password', { currentPassword, newPassword })
// 관리자 OTP 초기화 — 대상 사용자 OTP 해제(다음 로그인 시 재등록). 시크릿 미조회.
export const adminOtpReset = (id: number) => unwrap(api.post(`/api/users/${id}/otp-reset`))
// ── Auth: 로그인 보조 3종 (공개 — 회원가입 승인대기 / 아이디찾기 / 비밀번호 초기화) ──
export interface SignupReq {
username: string; password: string; name: string;
email: string; phone: string; tenantCode: string
}
export interface SignupRes { username: string; status: string }
export interface FindIdRes { found: boolean; maskedUsername: string }
export const signup = (d: SignupReq) =>
unwrap(api.post('/api/auth/signup', d)) as Promise<SignupRes>
export const findId = (name: string, email: string) =>
unwrap(api.post('/api/auth/find-id', { name, email })) as Promise<FindIdRes>
export const resetPassword = (username: string, name: string, email: string) =>
api.post('/api/auth/reset-password', { username, name, email })
// ── Dashboard ────────────────────────────────────────────────────────────
export const getDashboard = (tenantCode?: string) =>
unwrap(api.get(`/api/dashboard${tenantCode ? `?tenantCode=${tenantCode}` : ''}`))
// ── Tenants ──────────────────────────────────────────────────────────────
export const getTenants = () => unwrap(api.get('/api/tenants'))
export const createTenant = (d: object) => unwrap(api.post('/api/tenants', d))
export const updateTenant = (id: number, d: object) => unwrap(api.put(`/api/tenants/${id}`, d))
export const deleteTenant = (id: number) => api.delete(`/api/tenants/${id}`)
// ── Stores ───────────────────────────────────────────────────────────────
export const getStores = (params?: object) => unwrap(api.get('/api/stores', { params }))
export const getStore = (id: number) => unwrap(api.get(`/api/stores/${id}`))
export const createStore = (d: object) => unwrap(api.post('/api/stores', d))
export const updateStore = (id: number, d: object) => unwrap(api.put(`/api/stores/${id}`, d))
export const deleteStore = (id: number) => api.delete(`/api/stores/${id}`)
// ── Store Groups ─────────────────────────────────────────────────────────
export const getStoreGroups = (tenantCode?: string) =>
unwrap(api.get('/api/store-groups', { params: { tenantCode } }))
export const createStoreGroup = (d: object) => unwrap(api.post('/api/store-groups', d))
export const updateStoreGroup = (id: number, d: object) => unwrap(api.put(`/api/store-groups/${id}`, d))
export const deleteStoreGroup = (id: number) => api.delete(`/api/store-groups/${id}`)
// ── Templates ────────────────────────────────────────────────────────────
export const getTemplates = (params?: object) => unwrap(api.get('/api/templates', { params }))
export const createTemplate = (d: object) => unwrap(api.post('/api/templates', d))
export const updateTemplate = (id: number, d: object) => unwrap(api.put(`/api/templates/${id}`, d))
export const deleteTemplate = (id: number) => api.delete(`/api/templates/${id}`)
// ── POS CVT ──────────────────────────────────────────────────────────────
export const getPosCvt = (params?: object) => unwrap(api.get('/api/pos-cvt', { params }))
export const processPosCvt = (id: number) => unwrap(api.put(`/api/pos-cvt/${id}/process`))
export const ignorePosCvt = (id: number) => unwrap(api.put(`/api/pos-cvt/${id}/ignore`))
// ── Alarms ───────────────────────────────────────────────────────────────
export const getAlarms = (params?: object) => unwrap(api.get('/api/alarms', { params }))
export const createAlarm = (d: object) => unwrap(api.post('/api/alarms', d))
export const resolveAlarm = (id: number, resolution: string) =>
unwrap(api.put(`/api/alarms/${id}/resolve`, { resolution }))
export const deleteAlarm = (id: number) => api.delete(`/api/alarms/${id}`)
// ── HCore ────────────────────────────────────────────────────────────────
export const getHCore = (params?: object) => unwrap(api.get('/api/hcore', { params }))
export const updateHCoreStatus = (id: number, status: string) =>
unwrap(api.put(`/api/hcore/${id}/status`, { status }))
// ── Works ────────────────────────────────────────────────────────────────
export const getWorks = (params?: object) => unwrap(api.get('/api/works', { params }))
export const createWork = (d: object) => unwrap(api.post('/api/works', d))
export const updateWork = (id: number, d: object) => unwrap(api.put(`/api/works/${id}`, d))
export const deleteWork = (id: number) => api.delete(`/api/works/${id}`)
// ── Firmware ─────────────────────────────────────────────────────────────
export const getFirmware = (params?: object) => unwrap(api.get('/api/firmware', { params }))
export const createFirmware = (d: object) => unwrap(api.post('/api/firmware', d))
export const deleteFirmware = (id: number) => api.delete(`/api/firmware/${id}`)
// ── Users ────────────────────────────────────────────────────────────────
export const getUsers = (params?: object) => unwrap(api.get('/api/users', { params }))
export const createUser = (d: object) => unwrap(api.post('/api/users', d))
export const updateUser = (id: number, d: object) => unwrap(api.put(`/api/users/${id}`, d))
export const deleteUser = (id: number) => api.delete(`/api/users/${id}`)
// ── Products ─────────────────────────────────────────────────────────────
export const getProducts = (params?: object) => unwrap(api.get('/api/products', { params }))
export const createProduct = (d: object) => unwrap(api.post('/api/products', d))
export const updateProduct = (id: number, d: object) => unwrap(api.put(`/api/products/${id}`, d))
export const deleteProduct = (id: number) => api.delete(`/api/products/${id}`)
// ── Admin: 감사 로그 ───────────────────────────────────────────────────────
export const getAuditLogs = (params?: object) => unwrap(api.get('/api/admin/audit', { params }))
export const getAuditCount = (params?: object) => unwrap(api.get('/api/admin/audit/count', { params }))
// ── Admin: 시스템 설정 ─────────────────────────────────────────────────────
export const getSettings = (category?: string) =>
unwrap(api.get('/api/admin/settings', { params: category ? { category } : {} }))
export const updateSetting = (key: string, value: string) =>
unwrap(api.put(`/api/admin/settings/${encodeURIComponent(key)}`, { value }))
// ── Users (active toggle) ──────────────────────────────────────────────────
export const setUserActive = (id: number, active: boolean) =>
unwrap(api.put(`/api/users/${id}/active`, { active }))
// ── AI ───────────────────────────────────────────────────────────────────
export const analyzeAlarm = (d: object) => unwrap(api.post('/api/ai/analyze-alarm', d))
export const classifyPos = (d: object) => unwrap(api.post('/api/ai/classify-pos', d))
export const aiChat = (message: string) => unwrap(api.post('/api/ai/chat', { message }))
// ── AI 기법 (중앙 guardia-rag 경유 — 테넌트 격리) ─────────────────────────────
// X-Tenant-Code 헤더로 테넌트 격리. 토글 조회/변경 + 대표 기능(/agent·/structured) 경유.
export const ragToggles = (tenantCode?: string) =>
unwrap(api.get('/api/ai/rag/toggles', { params: { tenantCode } }))
export const ragUpdateToggle = (key: string, value: string | number | boolean, tenantCode?: string) =>
unwrap(api.put(`/api/ai/rag/toggles/${key}`, { value, tenantCode },
tenantCode ? { headers: { 'X-Tenant-Code': tenantCode } } : undefined))
export const ragAnalyzeAlarm = (d: object, tenantCode?: string) =>
unwrap(api.post('/api/ai/rag/analyze-alarm', d,
tenantCode ? { headers: { 'X-Tenant-Code': tenantCode } } : undefined))
export const ragClassifyPos = (d: object, tenantCode?: string) =>
unwrap(api.post('/api/ai/rag/classify-pos', d,
tenantCode ? { headers: { 'X-Tenant-Code': tenantCode } } : undefined))
export const ragFeedback = (d: object, tenantCode?: string) =>
unwrap(api.post('/api/ai/rag/feedback', d,
tenantCode ? { headers: { 'X-Tenant-Code': tenantCode } } : undefined))