From 8627d8404aa4a986fee11965f8ad034cd8484907 Mon Sep 17 00:00:00 2001 From: openclaw Date: Thu, 23 Jul 2026 00:17:49 +0800 Subject: [PATCH] Improve ledger monthly header --- apps/web/src/styles.css | 80 ++++++++++++++++++++++--------- apps/web/src/views/LedgerView.vue | 69 ++++++++++++++++---------- 2 files changed, 102 insertions(+), 47 deletions(-) diff --git a/apps/web/src/styles.css b/apps/web/src/styles.css index 54fe51d..b95b76d 100644 --- a/apps/web/src/styles.css +++ b/apps/web/src/styles.css @@ -73,7 +73,7 @@ input:focus-visible { .ledger-header { position: relative; z-index: 1; - min-height: 210px; + min-height: 180px; padding: max(18px, env(safe-area-inset-top)) 18px 20px; background: #087f72; color: #ffffff; @@ -211,8 +211,7 @@ input:focus-visible { background: #edf7f4; } -.ledger-switcher, -.month-switcher { +.ledger-switcher { display: inline-flex; align-items: center; justify-content: center; @@ -228,19 +227,12 @@ input:focus-visible { font-weight: 780; } -.month-switcher { - margin-top: 22px; - padding: 0; - color: rgba(255, 255, 255, 0.82); - font-size: 13px; -} - .monthly-summary { display: grid; - grid-template-columns: 1.35fr 1fr 1fr; - align-items: end; - gap: 12px; - margin-top: 9px; + grid-template-columns: minmax(0, 1fr) minmax(132px, .72fr); + align-items: center; + gap: 18px; + margin-top: 22px; } .summary-main, @@ -255,11 +247,14 @@ input:focus-visible { } .monthly-summary span { - margin-bottom: 3px; color: rgba(255, 255, 255, 0.72); font-size: 12px; } +.summary-main span { + margin-bottom: 4px; +} + .summary-main strong { overflow: hidden; font-size: 23px; @@ -267,17 +262,38 @@ input:focus-visible { text-overflow: ellipsis; } -.summary-stat { +.summary-main strong.compact { + font-size: 17px; +} + +.summary-secondary { + min-width: 0; border-left: 1px solid rgba(255, 255, 255, 0.22); padding-left: 12px; } +.summary-stat { + display: flex; + align-items: baseline; + justify-content: space-between; + gap: 6px; +} + +.summary-stat + .summary-stat { + margin-top: 8px; +} + .summary-stat strong { overflow: hidden; - font-size: 15px; + font-size: 14px; + text-align: right; text-overflow: ellipsis; } +.summary-stat strong.compact { + font-size: 10px; +} + .income-stat strong { color: #d9ffe7; } @@ -287,8 +303,8 @@ input:focus-visible { } .ledger-content { - height: calc(100vh - 210px); - height: calc(100dvh - 210px); + height: calc(100vh - 180px); + height: calc(100dvh - 180px); min-height: 0; overflow-y: auto; padding: 0 16px 112px; @@ -346,10 +362,29 @@ input:focus-visible { .list-toolbar-heading { display: flex; - align-items: baseline; + align-items: center; gap: 8px; } +.list-month-switcher { + min-height: 32px; + display: inline-flex; + align-items: center; + gap: 4px; + border: 0; + padding: 0; + background: transparent; + color: #26342f; +} + +.native-month-input { + position: absolute; + width: 1px; + height: 1px; + opacity: 0; + pointer-events: none; +} + .list-toolbar strong { font-size: 15px; } @@ -1368,14 +1403,15 @@ input:focus-visible { } .monthly-summary { - gap: 8px; + grid-template-columns: minmax(0, 1fr) minmax(126px, .72fr); + gap: 10px; } .summary-main strong { font-size: 20px; } - .summary-stat { + .summary-secondary { padding-left: 8px; } diff --git a/apps/web/src/views/LedgerView.vue b/apps/web/src/views/LedgerView.vue index da88d07..7e65e21 100644 --- a/apps/web/src/views/LedgerView.vue +++ b/apps/web/src/views/LedgerView.vue @@ -35,15 +35,23 @@ const generatingInvitation = ref(false); const visibleCount = ref(ENTRY_PAGE_SIZE); const ledgerContent = ref(null); const loadMoreTrigger = ref(null); +const monthInput = ref(null); +const selectedMonth = ref(toMonthValue(new Date())); let loadMoreObserver: IntersectionObserver | null = null; +const selectedMonthParts = computed(() => { + const match = /^(\d{4})-(\d{2})$/.exec(selectedMonth.value); + if (!match) return null; + return { year: Number(match[1]), month: Number(match[2]) - 1 }; +}); const monthlyEntries = computed(() => { - const current = new Date(); + const selected = selectedMonthParts.value; + if (!selected) return []; return store.entries.filter((entry) => { const occurredAt = new Date(entry.occurredAt); return entry.ledgerIds.includes(ledgerStore.currentLedgerId) - && occurredAt.getFullYear() === current.getFullYear() - && occurredAt.getMonth() === current.getMonth(); + && occurredAt.getFullYear() === selected.year + && occurredAt.getMonth() === selected.month; }); }); @@ -57,6 +65,9 @@ const totals = computed(() => { { income: 0, expense: 0 }, ); }); +const balanceText = computed(() => formatMoney(totals.value.income - totals.value.expense)); +const incomeText = computed(() => formatMoney(totals.value.income)); +const expenseText = computed(() => formatMoney(totals.value.expense)); const visibleMonthlyEntries = computed(() => monthlyEntries.value.slice(0, visibleCount.value)); const hasMoreEntries = computed(() => visibleCount.value < monthlyEntries.value.length); @@ -91,12 +102,8 @@ const groupedEntries = computed(() => { }); const monthTitle = computed(() => { - const date = new Date(); - return `${date.getFullYear()}年 ${date.getMonth() + 1}月`; -}); -const monthListTitle = computed(() => { - const date = new Date(); - return `${date.getFullYear()}年${date.getMonth() + 1}月流水`; + const selected = selectedMonthParts.value; + return selected ? `${selected.year}年${selected.month + 1}月` : "选择月份"; }); onMounted(async () => { @@ -129,6 +136,17 @@ function localDateKey(value: string) { return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`; } +function toMonthValue(date: Date) { + return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}`; +} + +function openMonthPicker() { + const input = monthInput.value; + if (!input) return; + if (typeof input.showPicker === "function") input.showPicker(); + else input.click(); +} + function dateHeading(value: string) { const date = new Date(`${value}T00:00:00`); const today = new Date(); @@ -261,23 +279,20 @@ async function shareLedger() { - - -
+
- 本月结余 - ¥ {{ formatMoney(totals.income - totals.expense) }} + 结余 + ¥ {{ balanceText }}
-
- 收入 - {{ formatMoney(totals.income) }} -
-
- 支出 - {{ formatMoney(totals.expense) }} +
+
+ 收入 + {{ incomeText }} +
+
+ 支出 + {{ expenseText }} +
@@ -292,7 +307,11 @@ async function shareLedger() {
- {{ monthListTitle }} + + {{ monthlyEntries.length }} 笔