ui: 分类管理去原生弹窗(自绘输入弹窗带内联校验 + 危险确认框) + 通用InputDialog组件
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
import { onMounted, ref, watch } from 'vue'
|
||||
import Icon from '../components/Icon.vue'
|
||||
import ConfirmDialog from '../components/ConfirmDialog.vue'
|
||||
import InputDialog from '../components/InputDialog.vue'
|
||||
import {
|
||||
addProject, exportAll, getLocationPresets, getSetting, getWorkRule, importAll,
|
||||
listAttendanceBetween, listLogItemsBetween, listProjects,
|
||||
@@ -39,37 +40,53 @@ async function loadCategories() {
|
||||
expenseCats.value = await getLedgerCategories('expense')
|
||||
incomeCats.value = await getLedgerCategories('income')
|
||||
}
|
||||
async function addCat(kind: 'log' | 'expense' | 'income') {
|
||||
const name = window.prompt('新分类名称')
|
||||
if (!name || !name.trim()) return
|
||||
const list = kind === 'log' ? logCats.value : kind === 'expense' ? expenseCats.value : incomeCats.value
|
||||
const clean = name.trim()
|
||||
if (list.includes(clean)) { showToast('分类已存在'); return }
|
||||
const next = [...list, clean]
|
||||
// ---- 分类编辑:自绘输入弹窗 + 危险确认框(替代浏览器原生 prompt/confirm)----
|
||||
type CatKind = 'log' | 'expense' | 'income'
|
||||
const catDialog = ref<{ open: boolean; kind: CatKind; index: number; initial: string }>({ open: false, kind: 'log', index: -1, initial: '' })
|
||||
const delCat = ref<{ kind: CatKind; index: number; name: string } | null>(null)
|
||||
|
||||
function catListOf(kind: CatKind): string[] {
|
||||
return kind === 'log' ? logCats.value : kind === 'expense' ? expenseCats.value : incomeCats.value
|
||||
}
|
||||
async function writeCats(kind: CatKind, next: string[]) {
|
||||
if (kind === 'log') { logCats.value = next; await setLogCategories(next) }
|
||||
else if (kind === 'expense') { expenseCats.value = next; await setLedgerCategories('expense', next) }
|
||||
else { incomeCats.value = next; await setLedgerCategories('income', next) }
|
||||
showToast('分类已添加')
|
||||
}
|
||||
async function renameCat(kind: 'log' | 'expense' | 'income', index: number, oldName: string) {
|
||||
const name = window.prompt('修改分类名称', oldName)
|
||||
if (!name || !name.trim() || name.trim() === oldName) return
|
||||
const list = kind === 'log' ? logCats.value : kind === 'expense' ? expenseCats.value : incomeCats.value
|
||||
const next = list.map((x, i) => (i === index ? name.trim() : x))
|
||||
if (kind === 'log') { logCats.value = next; await setLogCategories(next) }
|
||||
else if (kind === 'expense') { expenseCats.value = next; await setLedgerCategories('expense', next) }
|
||||
else { incomeCats.value = next; await setLedgerCategories('income', next) }
|
||||
showToast('分类已更新(历史记录自动跟随显示)')
|
||||
function openCatAdd(kind: CatKind) {
|
||||
catDialog.value = { open: true, kind, index: -1, initial: '' }
|
||||
}
|
||||
async function removeCat(kind: 'log' | 'expense' | 'income', index: number) {
|
||||
const list = kind === 'log' ? logCats.value : kind === 'expense' ? expenseCats.value : incomeCats.value
|
||||
function openCatRename(kind: CatKind, index: number, oldName: string) {
|
||||
catDialog.value = { open: true, kind, index, initial: oldName }
|
||||
}
|
||||
function validateCat(v: string): string | null {
|
||||
const { kind, index } = catDialog.value
|
||||
const list = catListOf(kind)
|
||||
if (list.includes(v) && !(index >= 0 && list[index] === v)) return '该分类已存在'
|
||||
return null
|
||||
}
|
||||
async function onCatDialogConfirm(v: string) {
|
||||
const { kind, index } = catDialog.value
|
||||
if (index >= 0) {
|
||||
await writeCats(kind, catListOf(kind).map((x, i) => (i === index ? v : x)))
|
||||
showToast('分类已更新(历史记录自动跟随显示)')
|
||||
} else {
|
||||
await writeCats(kind, [...catListOf(kind), v])
|
||||
showToast('分类已添加')
|
||||
}
|
||||
catDialog.value.open = false
|
||||
}
|
||||
function askRemoveCat(kind: CatKind, index: number) {
|
||||
const list = catListOf(kind)
|
||||
if (list.length <= 1) { showToast('至少保留一个分类'); return }
|
||||
if (!window.confirm('删除分类「' + list[index] + '」?历史记录不受影响。')) return
|
||||
const next = list.filter((_, i) => i !== index)
|
||||
if (kind === 'log') { logCats.value = next; await setLogCategories(next) }
|
||||
else if (kind === 'expense') { expenseCats.value = next; await setLedgerCategories('expense', next) }
|
||||
else { incomeCats.value = next; await setLedgerCategories('income', next) }
|
||||
delCat.value = { kind, index, name: list[index] }
|
||||
}
|
||||
async function confirmRemoveCat() {
|
||||
if (!delCat.value) return
|
||||
const { kind, index } = delCat.value
|
||||
await writeCats(kind, catListOf(kind).filter((_, i) => i !== index))
|
||||
showToast('分类已删除')
|
||||
delCat.value = null
|
||||
}
|
||||
|
||||
const fileInput = ref<HTMLInputElement | null>(null)
|
||||
@@ -424,32 +441,32 @@ async function doImport() {
|
||||
<div class="card section">
|
||||
<div class="section-title">工作分类</div>
|
||||
<div class="cat-block">
|
||||
<div class="cat-head"><span class="muted">工作记录分类</span><button class="btn btn-xs" @click="addCat('log')">添加</button></div>
|
||||
<div class="cat-head"><span class="muted">工作记录分类</span><button class="btn btn-xs" @click="openCatAdd('log')">添加</button></div>
|
||||
<div class="cat-chips">
|
||||
<span v-for="(c, i) in logCats" :key="c + i" class="cat-chip">
|
||||
{{ c }}
|
||||
<button class="chip-btn" title="修改" @click="renameCat('log', i, c)">改</button>
|
||||
<button class="chip-btn" title="删除" @click="removeCat('log', i)">删</button>
|
||||
<button class="chip-btn" title="修改" @click="openCatRename('log', i, c)">改</button>
|
||||
<button class="chip-btn" title="删除" @click="askRemoveCat('log', i)">删</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cat-block">
|
||||
<div class="cat-head"><span class="muted">记账支出分类</span><button class="btn btn-xs" @click="addCat('expense')">添加</button></div>
|
||||
<div class="cat-head"><span class="muted">记账支出分类</span><button class="btn btn-xs" @click="openCatAdd('expense')">添加</button></div>
|
||||
<div class="cat-chips">
|
||||
<span v-for="(c, i) in expenseCats" :key="c + i" class="cat-chip">
|
||||
{{ c }}
|
||||
<button class="chip-btn" title="修改" @click="renameCat('expense', i, c)">改</button>
|
||||
<button class="chip-btn" title="删除" @click="removeCat('expense', i)">删</button>
|
||||
<button class="chip-btn" title="修改" @click="openCatRename('expense', i, c)">改</button>
|
||||
<button class="chip-btn" title="删除" @click="askRemoveCat('expense', i)">删</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cat-block">
|
||||
<div class="cat-head"><span class="muted">记账收入分类</span><button class="btn btn-xs" @click="addCat('income')">添加</button></div>
|
||||
<div class="cat-head"><span class="muted">记账收入分类</span><button class="btn btn-xs" @click="openCatAdd('income')">添加</button></div>
|
||||
<div class="cat-chips">
|
||||
<span v-for="(c, i) in incomeCats" :key="c + i" class="cat-chip">
|
||||
{{ c }}
|
||||
<button class="chip-btn" title="修改" @click="renameCat('income', i, c)">改</button>
|
||||
<button class="chip-btn" title="删除" @click="removeCat('income', i)">删</button>
|
||||
<button class="chip-btn" title="修改" @click="openCatRename('income', i, c)">改</button>
|
||||
<button class="chip-btn" title="删除" @click="askRemoveCat('income', i)">删</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -471,6 +488,27 @@ async function doImport() {
|
||||
<div class="muted backup-note">数据保存在云端服务器;导出的 JSON 备份用于跨设备迁移或灾后恢复。</div>
|
||||
</div>
|
||||
|
||||
<InputDialog
|
||||
:open="catDialog.open"
|
||||
:title="catDialog.index >= 0 ? '修改分类名称' : '添加分类'"
|
||||
label="分类名称"
|
||||
placeholder="如:制度学习 / 差旅交通"
|
||||
:initial="catDialog.initial"
|
||||
:validate="validateCat"
|
||||
confirm-text="保存"
|
||||
@cancel="catDialog.open = false"
|
||||
@confirm="onCatDialogConfirm"
|
||||
/>
|
||||
|
||||
<ConfirmDialog
|
||||
:open="!!delCat"
|
||||
title="删除分类"
|
||||
:message="delCat ? '将删除分类「' + delCat.name + '」。历史记录不受影响,仍按原分类展示。' : ''"
|
||||
confirm-text="删除" danger
|
||||
@cancel="delCat = null"
|
||||
@confirm="confirmRemoveCat"
|
||||
/>
|
||||
|
||||
<ConfirmDialog
|
||||
:open="!!pendingImport"
|
||||
title="导入确认"
|
||||
|
||||
Reference in New Issue
Block a user