Merge branch 'dev'
Deploy / deploy (push) Failing after 13m42s

This commit is contained in:
ByungCheol
2026-06-29 21:36:18 +09:00
2 changed files with 32 additions and 6 deletions
+1 -1
View File
@@ -110,7 +110,7 @@
3) **추천 +5 / 비추 -1** (일일 최대 적립 50포인트) 3) **추천 +5 / 비추 -1** (일일 최대 적립 50포인트)
4) 다른 사용자 글에 **추천 누르면 +1** (일일 10 제한), 추천 **취소 시 -1** 4) 다른 사용자 글에 **추천 누르면 +1** (일일 10 제한), 추천 **취소 시 -1**
5. **분류 화면 순서변경 보호** — 스크롤하다 실수로 순서 바뀌는 것 방지: 기본은 drag&drop 비활성, **"순서변경" 버튼 클릭 시에만** 드래그 가능 5. **분류 화면 순서변경 보호** — 스크롤하다 실수로 순서 바뀌는 것 방지: 기본은 drag&drop 비활성, **"순서변경" 버튼 클릭 시에만** 드래그 가능
6. **[버그] 앱 잠금이 카메라/갤러리 복귀 시 오작동** — 영수증 OCR(카메라)·이미지 선택 등 앱 내 네이티브 동작 후 돌아오면 PIN 잠금 화면이 뜸. 원인: 앱 잠금이 `visibilitychange`(화면 숨김)으로 백그라운드를 감지하는데, 카메라/갤러리 호출도 숨김으로 인식됨. 수정: 네이티브 동작 직전 "다음 1회 잠금 건너뛰기" 플래그를 세워 복귀 시 잠금 안 걸리게(진짜 앱 이탈만 잠금). (이번 세션 앱잠금 추가로 생긴 회귀) 6. **[버그·수정완료] 앱 잠금이 카메라/갤러리 복귀 시 오작동** — appLock.suppressLock() 추가, 파일선택은 App.vue 전역 리스너, 카메라/공유는 호출부에서 suppress. (코드 배포됨 — 테스터에게 반영하려면 versionCode 2로 AAB 재빌드 업로드 필요)
--- ---
+30 -4
View File
@@ -62,15 +62,21 @@ async function reload() {
} }
// ===== 계층 드래그 정렬 (대분류 블록 / 대분류 내 소분류) ===== // ===== 계층 드래그 정렬 (대분류 블록 / 대분류 내 소분류) =====
// 스크롤하다 실수로 순서가 바뀌는 것 방지: 기본은 드래그 비활성, '순서변경' 버튼으로 켠다.
const majorListEl = ref(null) const majorListEl = ref(null)
const reorderMode = ref(false)
let sortables = [] let sortables = []
function destroySortables() { function destroySortables() {
sortables.forEach((s) => s.destroy()) sortables.forEach((s) => s.destroy())
sortables = [] sortables = []
} }
function toggleReorder() {
reorderMode.value = !reorderMode.value
nextTick(() => initSortable()) // 켜면 생성, 끄면 destroy 후 early-return
}
function initSortable() { function initSortable() {
destroySortables() destroySortables()
if (!majorListEl.value) return if (!majorListEl.value || !reorderMode.value) return
// 대분류 순서 — 블록 단위라 소분류가 함께 이동 // 대분류 순서 — 블록 단위라 소분류가 함께 이동
sortables.push( sortables.push(
Sortable.create(majorListEl.value, { Sortable.create(majorListEl.value, {
@@ -189,7 +195,12 @@ onBeforeUnmount(destroySortables)
<button type="button" :class="{ active: activeType === 'EXPENSE' }" @click="activeType = 'EXPENSE'">지출 분류</button> <button type="button" :class="{ active: activeType === 'EXPENSE' }" @click="activeType = 'EXPENSE'">지출 분류</button>
<button type="button" :class="{ active: activeType === 'INCOME' }" @click="activeType = 'INCOME'">수입 분류</button> <button type="button" :class="{ active: activeType === 'INCOME' }" @click="activeType = 'INCOME'">수입 분류</button>
</div> </div>
<div class="tabs-actions">
<button type="button" class="text-btn" @click="importDefaults">기본 분류 불러오기</button> <button type="button" class="text-btn" @click="importDefaults">기본 분류 불러오기</button>
<button type="button" class="text-btn reorder-btn" :class="{ active: reorderMode }" @click="toggleReorder">
{{ reorderMode ? '완료' : '순서변경' }}
</button>
</div>
</div> </div>
<form class="new-cat" @submit.prevent="addCategory"> <form class="new-cat" @submit.prevent="addCategory">
@@ -202,7 +213,10 @@ onBeforeUnmount(destroySortables)
<IconBtn icon="plus" title="추가" variant="primary" type="submit" size="sm" /> <IconBtn icon="plus" title="추가" variant="primary" type="submit" size="sm" />
</div> </div>
</form> </form>
<p class="hint sm"> 손잡이로 순서 변경 <b>대분류</b> 소분류와 함께, <b>소분류</b> 대분류 안에서만 이동합니다.</p> <p class="hint sm">
<template v-if="reorderMode"> 손잡이를 끌어 순서를 바꾸세요 <b>대분류</b> 소분류와 함께, <b>소분류</b> 대분류 안에서만 이동. 끝나면 <b>완료</b>.</template>
<template v-else><b>순서변경</b> 누르면 분류 순서를 바꿀 있어요. (평소엔 스크롤 실수 방지로 잠겨 있어요)</template>
</p>
<p v-if="error" class="msg error">{{ error }}</p> <p v-if="error" class="msg error">{{ error }}</p>
<p v-if="loading" class="msg">불러오는 중...</p> <p v-if="loading" class="msg">불러오는 중...</p>
@@ -211,7 +225,7 @@ onBeforeUnmount(destroySortables)
<li v-for="g in tree" :key="g.major.id" :data-id="g.major.id" class="major-block"> <li v-for="g in tree" :key="g.major.id" :data-id="g.major.id" class="major-block">
<div class="cat-row major-row"> <div class="cat-row major-row">
<div class="cat-main"> <div class="cat-main">
<span class="drag-handle major-handle" title="대분류 순서 변경(소분류 함께 이동)"></span> <span v-show="reorderMode" class="drag-handle major-handle" title="대분류 순서 변경(소분류 함께 이동)"></span>
<input v-model="g.major.name" class="cat-name" @keyup.enter="saveCategory(g.major)" /> <input v-model="g.major.name" class="cat-name" @keyup.enter="saveCategory(g.major)" />
<IconBtn icon="check" title="저장" size="sm" @click="saveCategory(g.major)" /> <IconBtn icon="check" title="저장" size="sm" @click="saveCategory(g.major)" />
<IconBtn icon="trash" title="삭제" variant="danger" size="sm" @click="removeCategory(g.major)" /> <IconBtn icon="trash" title="삭제" variant="danger" size="sm" @click="removeCategory(g.major)" />
@@ -220,7 +234,7 @@ onBeforeUnmount(destroySortables)
<ul class="sub-list" :data-parent="g.major.id"> <ul class="sub-list" :data-parent="g.major.id">
<li v-for="s in g.children" :key="s.id" :data-id="s.id" class="sub-item cat-row child"> <li v-for="s in g.children" :key="s.id" :data-id="s.id" class="sub-item cat-row child">
<div class="cat-main"> <div class="cat-main">
<span class="drag-handle sub-handle" title="소분류 순서 변경"></span> <span v-show="reorderMode" class="drag-handle sub-handle" title="소분류 순서 변경"></span>
<span class="sub-mark"></span> <span class="sub-mark"></span>
<input v-model="s.name" class="cat-name" @keyup.enter="saveCategory(s)" /> <input v-model="s.name" class="cat-name" @keyup.enter="saveCategory(s)" />
<IconBtn icon="check" title="저장" size="sm" @click="saveCategory(s)" /> <IconBtn icon="check" title="저장" size="sm" @click="saveCategory(s)" />
@@ -306,6 +320,18 @@ button.danger {
.tabs-row .tabs { .tabs-row .tabs {
margin-bottom: 0; margin-bottom: 0;
} }
.tabs-actions {
display: flex;
align-items: center;
gap: 0.5rem;
flex-wrap: wrap;
justify-content: flex-end;
}
.reorder-btn.active {
color: #fff;
background: hsla(160, 100%, 37%, 1);
border-radius: 6px;
}
.tabs { .tabs {
display: flex; display: flex;
gap: 0.25rem; gap: 0.25rem;