From 98a5da5c45462c865db8b56327315100ac295ac3 Mon Sep 17 00:00:00 2001 From: openclaw Date: Sat, 25 Jul 2026 01:18:13 +0800 Subject: [PATCH] fix: float notices and lock ledger currency --- apps/web/src/styles.css | 19 ++++++++++++++----- apps/web/src/views/LedgerSettingsView.vue | 2 +- apps/web/src/views/StatsView.vue | 6 +++--- services/api/src/server.ts | 15 ++++++++++----- 4 files changed, 28 insertions(+), 14 deletions(-) diff --git a/apps/web/src/styles.css b/apps/web/src/styles.css index b70ae29..78d2587 100644 --- a/apps/web/src/styles.css +++ b/apps/web/src/styles.css @@ -304,6 +304,7 @@ input:focus-visible { } .ledger-content { + position: relative; height: calc(100vh - 180px); height: calc(100dvh - 180px); min-height: 0; @@ -313,11 +314,16 @@ input:focus-visible { } .list-toolbar { + position: sticky; + top: 0; + z-index: 2; min-height: 70px; display: flex; align-items: center; justify-content: space-between; border-bottom: 1px solid #dce8e4; + background: #f7faf9; + box-shadow: 0 2px 6px rgba(32, 57, 51, 0.04); } .list-toolbar > .list-toolbar-copy { @@ -327,16 +333,19 @@ input:focus-visible { } .sync-notice { - min-height: 44px; + height: 32px; + min-height: 32px; display: flex; align-items: center; justify-content: space-between; gap: 10px; border-bottom: 1px solid #efd9c9; - padding: 6px 16px; + padding: 3px 16px; background: #fff8f2; color: #8e481e; font-size: 12px; + box-shadow: 0 2px 8px rgba(70, 43, 25, 0.1); + pointer-events: auto; } .sync-notice > span, @@ -348,7 +357,7 @@ input:focus-visible { .sync-notice button { flex: 0 0 auto; - min-height: 32px; + min-height: 26px; border: 0; border-radius: 7px; padding: 0 9px; @@ -755,8 +764,8 @@ input:focus-visible { line-height: 1.1; } -.ledger-notice-slot { height:38px; overflow:hidden; } -.conversion-notice { height:38px; display:flex; align-items:center; border-bottom:1px solid #eadfca; padding:7px 12px; background:#fff9ed; color:#775b24; font-size:12px; } +.ledger-notice-slot { position:absolute; top:0; right:0; left:0; z-index:4; height:0; overflow:visible; pointer-events:none; } +.conversion-notice { height:32px; display:flex; align-items:center; border-bottom:1px solid #eadfca; padding:4px 12px; background:#fff9ed; color:#775b24; font-size:11px; box-shadow:0 2px 8px rgba(58,43,17,.08); pointer-events:auto; } .conversion-notice span { display:flex; align-items:center; gap:6px; } .amount-value { diff --git a/apps/web/src/views/LedgerSettingsView.vue b/apps/web/src/views/LedgerSettingsView.vue index 7ed1d79..1b1192c 100644 --- a/apps/web/src/views/LedgerSettingsView.vue +++ b/apps/web/src/views/LedgerSettingsView.vue @@ -44,7 +44,7 @@ async function save() {
- +
账本主题 diff --git a/apps/web/src/views/StatsView.vue b/apps/web/src/views/StatsView.vue index 586a6e6..dcb4ad5 100644 --- a/apps/web/src/views/StatsView.vue +++ b/apps/web/src/views/StatsView.vue @@ -258,7 +258,7 @@ function dailyLabel(value: string) { .stats-header { height:74px; display:flex; align-items:center; justify-content:space-between; padding:14px 18px 8px; background:var(--ledger-gradient, #087f72); color:#fff; } .stats-header > strong { font-size: 20px; } .stats-header button { display: flex; align-items: center; gap: 5px; border: 0; border-radius: 7px; padding: 7px 9px; background: rgba(255,255,255,.14); color: #fff; font-size: 13px; } -.stats-scroll { height: calc(100% - 74px); overflow-y: auto; padding: 0 16px 104px; } +.stats-scroll { position:relative; height: calc(100% - 74px); overflow-y: auto; padding: 0 16px 104px; } .stats-range { display:grid; gap:10px; padding:12px 0; } .stats-range-modes { display:grid; grid-template-columns:repeat(3,1fr); gap:4px; border-radius:8px; padding:4px; background:#e7eeec; } .stats-range-modes button { height:34px; border:0; border-radius:6px; background:transparent; color:#71807c; font-size:12px; font-weight:680; } @@ -277,8 +277,8 @@ function dailyLabel(value: string) { .stats-summary .balance strong { font-size:24px; } .stats-summary .income { color: #0d8b67; } .stats-summary .expense { color: #d84c36; } -.stats-conversion-slot { height:34px; margin-top:8px; overflow:hidden; } -.stats-conversion-notice { margin:0; border-left:3px solid #d69a32; padding:7px 9px; background:#fff8e9; color:#755719; font-size:11px; } +.stats-conversion-slot { position:absolute; top:0; right:16px; left:16px; z-index:3; height:0; overflow:visible; pointer-events:none; } +.stats-conversion-notice { margin:0; border-left:3px solid #d69a32; padding:7px 9px; background:#fff8e9; color:#755719; font-size:11px; box-shadow:0 2px 8px rgba(58,43,17,.08); pointer-events:auto; } .stats-tabs { display: grid; grid-template-columns: repeat(3,1fr); gap: 4px; margin: 14px 0 10px; border-radius: 8px; padding: 4px; background: #e7eeec; } .stats-tabs button { height: 38px; border: 0; border-radius: 6px; background: transparent; color: #71807c; font-size: 13px; font-weight: 680; } .stats-tabs button.active { background: #fff; color: #087f72; box-shadow: 0 2px 7px rgba(28,52,47,.12); } diff --git a/services/api/src/server.ts b/services/api/src/server.ts index 75dcb24..5260199 100644 --- a/services/api/src/server.ts +++ b/services/api/src/server.ts @@ -345,10 +345,13 @@ server.patch<{ if (await ledgerRole(user.id, request.params.ledgerId) !== "owner") { return reply.code(403).send({ error: "只有账本拥有者可以修改设置" }); } - const personalLedger = await pool.query<{ isPersonal: boolean }>( - `SELECT (personal_owner_id IS NOT NULL) AS "isPersonal" FROM ledgers WHERE id = $1`, + const currentLedger = await pool.query<{ isPersonal: boolean; defaultCurrency: string }>( + `SELECT (personal_owner_id IS NOT NULL) AS "isPersonal", + default_currency AS "defaultCurrency" + FROM ledgers WHERE id = $1`, [request.params.ledgerId], ); + if (!currentLedger.rows[0]) return reply.code(404).send({ error: "账本不存在" }); const name = request.body.name?.trim() ?? ""; if (!name || name.length > 40) return reply.code(400).send({ error: "账本名称无效" }); if (request.body.theme !== undefined && !validLedgerTheme(request.body.theme)) { @@ -356,14 +359,16 @@ server.patch<{ } const theme = request.body.theme ?? ledgerThemeFromColor(request.body.color); const color = ledgerThemeAccents[theme]; - const defaultCurrency = request.body.defaultCurrency ?? "CNY"; - if (!isCurrencyCode(defaultCurrency)) return reply.code(400).send({ error: "默认币种无效" }); + const defaultCurrency = currentLedger.rows[0].defaultCurrency; + if (request.body.defaultCurrency !== undefined && request.body.defaultCurrency !== defaultCurrency) { + return reply.code(400).send({ error: "默认币种暂不可修改" }); + } const result = await pool.query( `UPDATE ledgers SET name = $1, color = $2, theme = $3, default_currency = $4, updated_at = now() WHERE id = $5 RETURNING id, name, color, theme, default_currency AS "defaultCurrency", created_at AS "createdAt", updated_at AS "updatedAt", archived_at AS "archivedAt"`, - [personalLedger.rows[0]?.isPersonal ? PERSONAL_LEDGER_NAME : name, color, theme, defaultCurrency, request.params.ledgerId], + [currentLedger.rows[0].isPersonal ? PERSONAL_LEDGER_NAME : name, color, theme, defaultCurrency, request.params.ledgerId], ); return { ledger: result.rows[0] }; });