feat: 长期计划(目标→每日任务物化+进度条) / 详情页Markdown范围导出 / 记账与详情页改内容优先弹窗新增
This commit is contained in:
@@ -61,13 +61,9 @@ const incomeCats = ref<string[]>([])
|
||||
async function loadCats() {
|
||||
expenseCats.value = await getLedgerCategories('expense')
|
||||
incomeCats.value = await getLedgerCategories('income')
|
||||
if (fType.value === 'expense' && !expenseCats.value.includes(fCategory.value)) fCategory.value = expenseCats.value[0] || ''
|
||||
if (fType.value === 'income' && !incomeCats.value.includes(fCategory.value)) fCategory.value = incomeCats.value[0] || ''
|
||||
}
|
||||
loadCats()
|
||||
watch(fType, t => {
|
||||
fCategory.value = t === 'expense' ? (expenseCats.value[0] || '') : (incomeCats.value[0] || '')
|
||||
})
|
||||
|
||||
|
||||
const sorted = computed(() =>
|
||||
rows.value.slice().sort((a, b) => (a.date === b.date ? (b.id as number) - (a.id as number) : (a.date < b.date ? 1 : -1)))
|
||||
@@ -192,12 +188,24 @@ function openEdit(row: Transaction) {
|
||||
}
|
||||
dialogOpen.value = true
|
||||
}
|
||||
function openCreate() {
|
||||
editingId.value = null
|
||||
dialogInitial.value = { type: 'expense', category: (expenseCats.value[0] || ''), amountYuan: '', date: todayStr(), note: '', reimbursable: 0, reimbursed: 0 }
|
||||
dialogOpen.value = true
|
||||
}
|
||||
|
||||
async function onDialogSave(payload: { type: string; category: string; amount: number; date: string; note: string; reimbursable: number; reimbursed: number }) {
|
||||
const id = editingId.value as number
|
||||
await updateTransaction(id, payload)
|
||||
if (editingId.value) {
|
||||
await updateTransaction(editingId.value, payload)
|
||||
dialogOpen.value = false
|
||||
await load()
|
||||
showToast('账目已更新')
|
||||
return
|
||||
}
|
||||
await addTransaction({ type: payload.type, category: payload.category, amount: payload.amount, date: payload.date, note: payload.note, reimbursable: payload.reimbursable, reimbursed: payload.reimbursed })
|
||||
dialogOpen.value = false
|
||||
await load()
|
||||
showToast('账目已更新')
|
||||
showToast('已记一笔')
|
||||
}
|
||||
async function confirmDelete() {
|
||||
if (deleteTarget.value && deleteTarget.value.id) await deleteTransaction(deleteTarget.value.id)
|
||||
@@ -225,6 +233,7 @@ async function confirmDelete() {
|
||||
<option value="pending">待报销</option>
|
||||
<option value="done">已报销</option>
|
||||
</select>
|
||||
<button class="btn btn-primary btn-sm" @click="openCreate"><Icon name="plus" :size="14" /> 记一笔</button>
|
||||
</div>
|
||||
|
||||
<div class="cards">
|
||||
@@ -234,51 +243,6 @@ async function confirmDelete() {
|
||||
<div class="card stat-card"><div class="muted">待报销(元)</div><div class="stat-num num amt-warn">{{ yuan(summary.pending) }}</div></div>
|
||||
</div>
|
||||
|
||||
<div class="card sec">
|
||||
<div class="sec-head">
|
||||
<span class="sec-title">新增一笔</span>
|
||||
<span class="muted form-hint">金额必填,回车快速添加</span>
|
||||
</div>
|
||||
<div class="form-grid">
|
||||
<div class="field span2">
|
||||
<label>类型</label>
|
||||
<div class="seg">
|
||||
<button class="seg-btn" :class="{ active: fType === 'expense' }" @click="fType = 'expense'">支出</button>
|
||||
<button class="seg-btn" :class="{ active: fType === 'income' }" @click="fType = 'income'">收入</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>金额(元,必填)</label>
|
||||
<input class="input" :class="{ invalid: fError }" v-model="fAmount" type="number" min="0" step="0.01" placeholder="0.00" @keydown.enter="submit" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>日期</label>
|
||||
<input class="input" type="date" v-model="fDate" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>分类</label>
|
||||
<select class="select" v-model="fCategory">
|
||||
<option v-for="c in (fType === 'expense' ? expenseCats : incomeCats)" :key="c" :value="c">{{ c }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="field" v-if="fType === 'expense'">
|
||||
<label>报销</label>
|
||||
<button class="toggle-btn" :class="{ on: fReimb }" @click="fReimb = !fReimb">
|
||||
{{ fReimb ? '需要报销' : '无需报销' }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="field span2">
|
||||
<label>备注</label>
|
||||
<input class="input" v-model="fNote" placeholder="选填,如:客户现场午餐" @keydown.enter="submit" />
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="fError" class="form-error">{{ fError }}</div>
|
||||
<div class="form-footer">
|
||||
<button class="btn btn-sm" :disabled="!formDirty" @click="resetForm">重置</button>
|
||||
<button class="btn btn-primary btn-sm" :disabled="submitting" @click="submit">添加记录</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card sec" v-if="categoryStats.length">
|
||||
<div class="sec-title">本月支出分类</div>
|
||||
<div v-for="c in categoryStats" :key="c.name" class="bar-row">
|
||||
@@ -333,7 +297,7 @@ async function confirmDelete() {
|
||||
|
||||
<TransactionDialog
|
||||
:open="dialogOpen"
|
||||
:title="editingId ? '编辑账目' : '编辑账目'"
|
||||
:title="editingId ? '编辑账目' : '记一笔'"
|
||||
:initial="dialogInitial"
|
||||
@cancel="dialogOpen = false"
|
||||
@save="onDialogSave"
|
||||
|
||||
Reference in New Issue
Block a user