feat: 计划模式(时间段+打卡+计时时钟) / 工作详情范围导出 / 工作与记账分类自定义(含历史迁移)

This commit is contained in:
root
2026-10-26 11:48:14 +08:00
parent a1f2a45623
commit 284f8ebd46
24 changed files with 768 additions and 81 deletions
@@ -1,7 +1,7 @@
<script setup lang="ts">
import { computed, nextTick, onUnmounted, ref, watch } from 'vue'
import Icon from './Icon.vue'
import { EXPENSE_CATEGORIES, INCOME_CATEGORIES } from '../db/schema'
import { getLedgerCategories, setLedgerCategories } from '../db/categories'
const props = defineProps<{
open: boolean
@@ -15,7 +15,7 @@ const emit = defineEmits<{
}>()
const fType = ref<'expense' | 'income'>('expense')
const fCategory = ref('餐饮')
const fCategory = ref('')
const fAmount = ref('')
const fDate = ref('')
const fNote = ref('')
@@ -30,6 +30,7 @@ function onKey(e: KeyboardEvent) {
}
watch(() => props.open, async v => {
if (v) {
await loadCats()
fType.value = (props.initial.type === 'income' ? 'income' : 'expense')
fCategory.value = props.initial.category
fAmount.value = props.initial.amountYuan
@@ -51,7 +52,20 @@ watch(fType, t => {
fCategory.value = t === 'expense' ? EXPENSE_CATEGORIES[0] : INCOME_CATEGORIES[0]
})
const categoryOptions = computed(() => (fType.value === 'expense' ? EXPENSE_CATEGORIES : INCOME_CATEGORIES))
const categoryOptions = ref<string[]>([])
async function loadCats() {
categoryOptions.value = await getLedgerCategories(fType.value)
}
const newCat = ref('')
async function addCategory() {
const name = newCat.value.trim()
if (!name) return
if (categoryOptions.value.includes(name)) { newCat.value = ''; return }
categoryOptions.value.push(name)
await setLedgerCategories(fType.value, categoryOptions.value)
fCategory.value = name
newCat.value = ''
}
function computedCategory() {
return (fCategory.value && categoryOptions.value.includes(fCategory.value)) ? fCategory.value : categoryOptions.value[0]
}
@@ -109,10 +123,14 @@ function save() {
<input class="input" type="date" v-model="fDate" />
</div>
<div class="field">
<label>分类</label>
<label>分类(可直接新增)</label>
<select class="select" v-model="fCategory">
<option v-for="c in categoryOptions" :key="c" :value="c">{{ c }}</option>
</select>
<div class="add-cat">
<input class="input add-cat-input" v-model="newCat" placeholder="新增分类名" @keydown.enter.prevent="addCategory" />
<button class="btn btn-xs" type="button" @click="addCategory">添加</button>
</div>
</div>
<div class="field" v-if="fType === 'expense'">
<label>报销状态</label>
@@ -164,6 +182,8 @@ function save() {
border-bottom: 1px solid var(--border);
}
.dialog-title { font-size: 14px; font-weight: 600; color: var(--text-1); }
.add-cat { display: flex; gap: 6px; margin-top: 6px; }
.add-cat-input { flex: 1; height: 28px; font-size: 12px; }
.dialog-body { padding: 16px 20px; }
.dialog-btns {
display: flex;