- 스크롤 중 실수로 순서가 바뀌는 것 방지 - 기본은 drag&drop 비활성, '순서변경' 토글 켤 때만 Sortable 생성 + 손잡이(≡) 표시 - 끄면(완료) destroy. 안내 문구도 모드별로 표시 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -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>
|
||||||
<button type="button" class="text-btn" @click="importDefaults">기본 분류 불러오기</button>
|
<div class="tabs-actions">
|
||||||
|
<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;
|
||||||
|
|||||||
Reference in New Issue
Block a user