diff --git a/brand/LAUNCH-PROGRESS.md b/brand/LAUNCH-PROGRESS.md index 13a7593..5040e7c 100644 --- a/brand/LAUNCH-PROGRESS.md +++ b/brand/LAUNCH-PROGRESS.md @@ -110,6 +110,15 @@ 5. (선택) 첫 실행 온보딩 / Play 인앱 리뷰 / 생체 인증 / 외화 환율 자동 고도화 6. **조직 계정 전환 + 기프트콘 교환** — 사업자등록→DUNS→앱이전, B2B 기프트콘 매입 +### 🤖 AI 기능 (★ 정식 출시 전 적용 희망) +- 전제: **LLM API 키**(Claude Haiku 4.5 권장 — 학습 미사용·톤 우수·저렴 / 또는 Gemini 무료쿼터) + **개인정보처리방침·데이터안전 갱신**(제3자 LLM 추가). 백엔드 프록시·키 서버보관·실패 시 폴백. +- **AI 입력 보조** (편의성, 1순위) + - ① **자연어 한 줄 입력** — "어제 스타벅스 5천원" → 폼 자동 채움(기존 parseText를 LLM 기반으로). 음성=기기STT+① + - ② **영수증 사진 → AI 구조화** — 멀티모달 LLM이 총액·날짜·가맹점·분류 추천(기존 Vision OCR 보강/대체) + - ③ **자동 분류 추천** — 가맹점/메모→분류 제안 + - 원칙: AI는 폼 prefill만, **사용자 확인 후 저장** +- **AI 재무 코멘트** — 자산·수입·예상지출 기반 한마디("이러다 파산각" 등). 일1회 캐시·집계수치만 전송. + --- ## 🔨 빌드 상태 diff --git a/src/views/account/AccountView.vue b/src/views/account/AccountView.vue index d810d16..475b0fa 100644 --- a/src/views/account/AccountView.vue +++ b/src/views/account/AccountView.vue @@ -276,25 +276,27 @@ async function loadCategories() { categories.value = [] } } -// 현재 구분(수입/지출)에 맞는 분류 + 편집 중 현재 값 보존 -// ===== 분류: 대분류 → 소분류 2단 선택 (긴 드롭다운 스크롤 방지) ===== -const categoryMajor = ref('') // 선택된 대분류 이름 -// 현재 구분의 대분류(부모 없음) 이름 + 편집 중 현재 대분류 보존 -const majorOptions = computed(() => { - const names = categories.value - .filter((c) => c.type === form.type && c.parentId == null) - .map((c) => c.name) - if (categoryMajor.value && !names.includes(categoryMajor.value)) names.unshift(categoryMajor.value) - return names -}) -// 선택된 대분류의 소분류 이름 목록 (없으면 대분류 자체가 분류) -const subOptions = computed(() => { - const major = categories.value.find( - (c) => c.type === form.type && c.parentId == null && c.name === categoryMajor.value, - ) - if (!major) return [] - return categories.value.filter((c) => c.parentId === major.id).map((c) => c.name) -}) +// ===== 분류: 대분류 아코디언 → 소분류 선택 ===== +const categoryMajor = ref('') // 펼쳐진 대분류 이름 +// 현재 구분의 대분류 객체 목록 +const majorOptionsData = computed(() => + categories.value.filter((c) => c.type === form.type && c.parentId == null) +) +// 특정 대분류의 소분류 객체 목록 +function subsByMajor(majorId) { + return categories.value.filter((c) => c.parentId === majorId) +} +// 대분류 클릭: 소분류 있으면 펼침 토글, 없으면 바로 선택 +function onMajorClick(major) { + if (categoryMajor.value === major.name) { + categoryMajor.value = '' + form.category = '' + } else { + categoryMajor.value = major.name + if (!subsByMajor(major.id).length) form.category = major.name + else form.category = '' + } +} // form.category 로부터 대분류 추론 (편집 진입 시) function syncCategoryMajor() { const cur = form.category @@ -310,10 +312,7 @@ function syncCategoryMajor() { categoryMajor.value = cur } } -// 대분류 변경: 소분류 있으면 소분류 선택 대기 / 없으면 대분류가 곧 분류 -function onMajorChange() { - form.category = subOptions.value.length ? '' : categoryMajor.value -} + // 필터용 전체 분류명 (중복 제거) const allCategoryNames = computed(() => [...new Set(categories.value.map((c) => c.name))]) @@ -1121,16 +1120,28 @@ onMounted(async () => {