Files
sb-front/src/api/accountApi.js
T
ByungCheol 7d8f947156
CI / build (push) Failing after 12m18s
feat: 설정 - 엑셀 가져오기(복구) + 창 크기 가로·세로 분리 조절
- backup.js importBackup: .xlsx 파싱 → 이름 기준 payload → POST /account/restore
- SettingsView: '가져오기' 파일 선택 + 파괴적 작업 확인(이중) + 완료 후 새로고침
- accountApi.restore (데모에선 차단)
- 창 크기: 가로/세로 각각 선택(세로 700~1200), 한 축 변경 시 나머지 유지

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 08:38:38 +09:00

242 lines
7.4 KiB
JavaScript

import http from './http'
import { demo, demoApi } from '@/demo'
// 백엔드 /api/account 엔드포인트와 매핑 (본인 데이터만)
const realApi = {
list({ year, month, type, category, walletId, keyword, tagId } = {}) {
return http.get('/account/entries', { params: { year, month, type, category, walletId, keyword, tagId } })
},
summary({ year, month } = {}) {
return http.get('/account/summary', { params: { year, month } })
},
stats({ unit, year, month } = {}) {
return http.get('/account/stats', { params: { unit, year, month } })
},
categoryStats({ type, year, month } = {}) {
return http.get('/account/category-stats', { params: { type, year, month } })
},
netWorthTrend({ months, weeks, unit } = {}) {
return http.get('/account/networth/trend', { params: { months, weeks, unit } })
},
create(payload) {
return http.post('/account/entries', payload)
},
update(id, payload) {
return http.put(`/account/entries/${id}`, payload)
},
remove(id) {
return http.delete(`/account/entries/${id}`)
},
// 문자/푸시 텍스트 파싱(저장 안 함) → 추가 폼 자동채움
parseText({ title, text } = {}) {
return http.post('/account/entries/parse', { title, text })
},
// 자주 쓰는 내역(빠른 등록 템플릿)
quickEntries() {
return http.get('/account/quick-entries')
},
createQuickEntry(payload) {
return http.post('/account/quick-entries', payload)
},
removeQuickEntry(id) {
return http.delete(`/account/quick-entries/${id}`)
},
// 계좌/카드 (사용자별)
wallets() {
return http.get('/account/wallets')
},
netWorth() {
return http.get('/account/networth')
},
repayment(payload) {
return http.post('/account/repayment', payload)
},
// 정기/반복 거래
recurrings() {
return http.get('/account/recurrings')
},
createRecurring(payload) {
return http.post('/account/recurrings', payload)
},
updateRecurring(id, payload) {
return http.put(`/account/recurrings/${id}`, payload)
},
removeRecurring(id) {
return http.delete(`/account/recurrings/${id}`)
},
runRecurrings() {
return http.post('/account/recurrings/run')
},
// 예산 (사용자별)
budgets() {
return http.get('/account/budgets')
},
budgetStatus({ year, month }) {
return http.get('/account/budgets/status', { params: { year, month } })
},
budgetPeriod({ unit, year, month }) {
return http.get('/account/budgets/period', { params: { unit, year, month } })
},
expectedIncome({ year, month }) {
return http.get('/account/budgets/income', { params: { year, month } })
},
setExpectedIncome({ year, month, expectedIncome }) {
return http.put('/account/budgets/income', { expectedIncome }, { params: { year, month } })
},
createBudget(payload) {
return http.post('/account/budgets', payload)
},
updateBudget(id, payload) {
return http.put(`/account/budgets/${id}`, payload)
},
removeBudget(id) {
return http.delete(`/account/budgets/${id}`)
},
createWallet(payload) {
return http.post('/account/wallets', payload)
},
updateWallet(id, payload) {
return http.put(`/account/wallets/${id}`, payload)
},
removeWallet(id) {
return http.delete(`/account/wallets/${id}`)
},
reorderWallets(type, ids) {
return http.put('/account/wallets/reorder', { type, ids })
},
walletEntries(id) {
return http.get(`/account/wallets/${id}/entries`)
},
// 투자 포트폴리오 (C) — 종목/매매
investHoldings(walletId) {
return http.get('/account/invest/holdings', { params: { walletId } })
},
createHolding(payload) {
return http.post('/account/invest/holdings', payload)
},
updateHolding(id, payload) {
return http.put(`/account/invest/holdings/${id}`, payload)
},
removeHolding(id) {
return http.delete(`/account/invest/holdings/${id}`)
},
refreshPrices(walletId) {
return http.post('/account/invest/holdings/refresh-prices', null, { params: { walletId } })
},
refreshAllPrices() {
return http.post('/account/invest/refresh-prices')
},
holdingTrades(holdingId) {
return http.get(`/account/invest/holdings/${holdingId}/trades`)
},
addTrade(holdingId, payload) {
return http.post(`/account/invest/holdings/${holdingId}/trades`, payload)
},
updateTrade(id, payload) {
return http.put(`/account/invest/trades/${id}`, payload)
},
removeTrade(id) {
return http.delete(`/account/invest/trades/${id}`)
},
// 분류(카테고리) — 사용자별
categories() {
return http.get('/account/categories')
},
createCategory(payload) {
return http.post('/account/categories', payload)
},
updateCategory(id, payload) {
return http.put(`/account/categories/${id}`, payload)
},
removeCategory(id) {
return http.delete(`/account/categories/${id}`)
},
reorderCategories(type, ids) {
return http.put('/account/categories/reorder', { type, ids })
},
importCategories() {
return http.post('/account/categories/import')
},
// 사용자별 가계부 태그
tags() {
return http.get('/account/tags')
},
createTag(payload) {
return http.post('/account/tags', payload)
},
updateTag(id, payload) {
return http.put(`/account/tags/${id}`, payload)
},
removeTag(id) {
return http.delete(`/account/tags/${id}`)
},
reorderTags(ids) {
return http.put('/account/tags/reorder', { ids })
},
// 카드 결제 알림 자동인식 (미확인 내역)
pendingCount() {
return http.get('/account/entries/pending/count')
},
confirmEntry(id, payload) {
return http.post(`/account/entries/${id}/confirm`, payload || {})
},
// 데이터 복구(가져오기) — 전체 데이터 덮어쓰기
restore(payload) {
return http.post('/account/restore', payload)
},
// 영수증 OCR (백엔드가 Google Vision 호출 → 전체 텍스트 반환)
ocrReceipt(blob) {
const fd = new FormData()
fd.append('image', blob, 'receipt.jpg')
return http.post('/account/ocr/receipt', fd, {
headers: { 'Content-Type': 'multipart/form-data' },
timeout: 30000,
})
},
}
// ===== 둘러보기(데모) 모드 =====
// demo.on 이면 읽기는 더미 데이터, 쓰기는 차단(안내 메시지)으로 응답한다.
const DEMO_READS = {
list: demoApi.list,
summary: demoApi.summary,
wallets: demoApi.wallets,
netWorth: demoApi.netWorth,
categories: demoApi.categories,
recurrings: demoApi.recurrings,
quickEntries: demoApi.quickEntries,
pendingCount: demoApi.pendingCount,
tags: demoApi.tags,
walletEntries: demoApi.walletEntries,
}
const DEMO_WRITES = new Set([
'create', 'update', 'remove', 'parseText', 'createQuickEntry', 'removeQuickEntry', 'repayment',
'createRecurring', 'updateRecurring', 'removeRecurring', 'runRecurrings',
'createWallet', 'updateWallet', 'removeWallet', 'reorderWallets',
'createCategory', 'updateCategory', 'removeCategory', 'reorderCategories', 'importCategories',
'createTag', 'updateTag', 'removeTag', 'reorderTags', 'confirmEntry', 'ocrReceipt', 'restore',
'createBudget', 'updateBudget', 'removeBudget', 'setExpectedIncome',
'createHolding', 'updateHolding', 'removeHolding', 'addTrade', 'updateTrade', 'removeTrade',
'refreshPrices', 'refreshAllPrices',
])
export const accountApi = new Proxy(realApi, {
get(target, prop) {
if (demo.on) {
if (DEMO_READS[prop]) return DEMO_READS[prop]
if (DEMO_WRITES.has(prop)) return () => demoApi.block()
}
return target[prop]
},
})