From 5214f618baec20a9caab37c04672db59b86ca8d1 Mon Sep 17 00:00:00 2001
From: hzm <934585316@qq.com>
Date: Tue, 24 Feb 2026 14:57:56 +0800
Subject: [PATCH] =?UTF-8?q?fix:=20=E5=88=9D=E5=A7=8B=E5=8C=96=E5=BD=93?=
=?UTF-8?q?=E6=97=A5=E6=94=B6=E7=9B=8A=E8=AE=A1=E7=AE=97=E9=80=BB=E8=BE=91?=
=?UTF-8?q?=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
app/page.jsx | 89 +++++++++++++++++++++++++++++++---------------------
1 file changed, 54 insertions(+), 35 deletions(-)
diff --git a/app/page.jsx b/app/page.jsx
index 3d44549..bc2c9fa 100644
--- a/app/page.jsx
+++ b/app/page.jsx
@@ -146,6 +146,7 @@ function GroupSummary({ funds, holdings, groupName, getProfit, stickyTop }) {
let totalHoldingReturn = 0;
let totalCost = 0;
let hasHolding = false;
+ let hasAnyTodayData = false;
funds.forEach(fund => {
const holding = holdings[fund.code];
@@ -154,7 +155,10 @@ function GroupSummary({ funds, holdings, groupName, getProfit, stickyTop }) {
if (profit) {
hasHolding = true;
totalAsset += profit.amount;
- totalProfitToday += profit.profitToday;
+ if (profit.profitToday != null) {
+ totalProfitToday += profit.profitToday;
+ hasAnyTodayData = true;
+ }
if (profit.profitTotal !== null) {
totalHoldingReturn += profit.profitTotal;
if (holding && typeof holding.cost === 'number' && typeof holding.share === 'number') {
@@ -166,7 +170,7 @@ function GroupSummary({ funds, holdings, groupName, getProfit, stickyTop }) {
const returnRate = totalCost > 0 ? (totalHoldingReturn / totalCost) * 100 : 0;
- return { totalAsset, totalProfitToday, totalHoldingReturn, hasHolding, returnRate };
+ return { totalAsset, totalProfitToday, totalHoldingReturn, hasHolding, returnRate, hasAnyTodayData };
}, [funds, holdings, getProfit]);
useLayoutEffect(() => {
@@ -233,16 +237,18 @@ function GroupSummary({ funds, holdings, groupName, getProfit, stickyTop }) {
当日收益
0 ? 'up' : summary.totalProfitToday < 0 ? 'down' : ''}
+ className={summary.hasAnyTodayData ? (summary.totalProfitToday > 0 ? 'up' : summary.totalProfitToday < 0 ? 'down' : '') : 'muted'}
style={{ fontSize: '18px', fontWeight: 700, fontFamily: 'var(--font-mono)' }}
>
{isMasked ? (
******
- ) : (
+ ) : summary.hasAnyTodayData ? (
<>
{summary.totalProfitToday > 0 ? '+' : summary.totalProfitToday < 0 ? '-' : ''}
>
+ ) : (
+ --
)}
@@ -539,14 +545,12 @@ export default function HomePage() {
const getHoldingProfit = (fund, holding) => {
if (!holding || typeof holding.share !== 'number') return null;
- const now = nowInTz();
- const isAfter9 = now.hour() >= 9;
const hasTodayData = fund.jzrq === todayStr;
const hasTodayValuation = typeof fund.gztime === 'string' && fund.gztime.startsWith(todayStr);
const canCalcTodayProfit = hasTodayData || hasTodayValuation;
// 如果是交易日且9点以后,且今日净值未出,则强制使用估值(隐藏涨跌幅列模式)
- const useValuation = isTradingDay && isAfter9 && !hasTodayData;
+ const useValuation = isTradingDay && !hasTodayData;
let currentNav;
let profitToday;
@@ -559,7 +563,24 @@ export default function HomePage() {
if (canCalcTodayProfit) {
const amount = holding.share * currentNav;
// 优先用 zzl (真实涨跌幅), 降级用 gszzl
- const rate = fund.zzl !== undefined ? Number(fund.zzl) : (Number(fund.gszzl) || 0);
+ // 若 gztime 日期 > jzrq,说明估值更新晚于净值日期,优先使用 gszzl 计算当日盈亏
+ const gz = typeof fund.gztime === 'string' ? toTz(fund.gztime) : null;
+ const jz = typeof fund.jzrq === 'string' ? toTz(fund.jzrq) : null;
+ const preferGszzl =
+ !!gz &&
+ !!jz &&
+ gz.isValid() &&
+ jz.isValid() &&
+ gz.startOf('day').isAfter(jz.startOf('day'));
+
+ let rate;
+ if (preferGszzl) {
+ rate = Number(fund.gszzl);
+ } else {
+ const zzl = fund.zzl !== undefined ? Number(fund.zzl) : Number.NaN;
+ rate = Number.isFinite(zzl) ? zzl : Number(fund.gszzl);
+ }
+ if (!Number.isFinite(rate)) rate = 0;
profitToday = amount - (amount / (1 + rate / 100));
} else {
profitToday = null;
@@ -661,7 +682,7 @@ export default function HomePage() {
if (type !== 'history') {
setActionModal({ open: false, fund: null });
}
-
+
if (type === 'edit') {
setHoldingModal({ open: true, fund });
} else if (type === 'clear') {
@@ -712,14 +733,14 @@ export default function HomePage() {
const share = netAmount / result.value;
newShare = current.share + share;
newCost = (current.cost * current.share + trade.amount) / newShare;
-
+
tradeShare = share;
tradeAmount = trade.amount;
} else {
newShare = Math.max(0, current.share - trade.share);
newCost = current.cost;
if (newShare === 0) newCost = 0;
-
+
tradeShare = trade.share;
tradeAmount = trade.share * result.value;
}
@@ -727,7 +748,7 @@ export default function HomePage() {
tempHoldings[trade.fundCode] = { share: newShare, cost: newCost };
stateChanged = true;
processedIds.add(trade.id);
-
+
// 记录交易历史
newTransactions.push({
id: trade.id,
@@ -969,7 +990,7 @@ export default function HomePage() {
const handleScanClick = () => {
setScanModalOpen(true);
};
-
+
const handleScanPick = () => {
if (fileInputRef.current) {
fileInputRef.current.click();
@@ -996,7 +1017,7 @@ export default function HomePage() {
setScanModalOpen(false); // 关闭选择弹窗
abortScanRef.current = false;
setScanProgress({ stage: 'ocr', current: 0, total: files.length });
-
+
try {
let worker = ocrWorkerRef.current;
if (!worker) {
@@ -1057,11 +1078,11 @@ export default function HomePage() {
const allCodes = new Set();
for (let i = 0; i < files.length; i++) {
if (abortScanRef.current) break;
-
+
const f = files[i];
// 更新进度:正在处理第 i+1 张
setScanProgress(prev => ({ ...prev, current: i + 1 }));
-
+
let text = '';
try {
const res = await recognizeWithTimeout(f, 30000);
@@ -1259,9 +1280,9 @@ export default function HomePage() {
// 这里为了保险,如果是空的,我们做全量
// 但通常 dirtyKeysRef 应该被填充了
}
-
+
const payload = collectLocalPayload(dirtyKeys.size > 0 ? dirtyKeys : null);
-
+
// 清空脏数据标记
dirtyKeysRef.current.clear();
@@ -1275,7 +1296,7 @@ export default function HomePage() {
lastSyncedRef.current = next;
syncUserConfig(userIdRef.current, false, payload, false);
}
- }, 2000);
+ }, 1000 * 5); // 往云端同步的防抖时间
}, []);
const storageHelper = useMemo(() => {
@@ -2326,7 +2347,7 @@ export default function HomePage() {
? all.funds.map((f) => f?.code).filter(Boolean)
: []
);
-
+
const cleanedHoldings = all.holdings && typeof all.holdings === 'object' && !Array.isArray(all.holdings)
? Object.entries(all.holdings).reduce((acc, [code, value]) => {
if (!fundCodes.has(code) || !value || typeof value !== 'object') return acc;
@@ -2367,7 +2388,7 @@ export default function HomePage() {
codes: Array.isArray(g.codes) ? g.codes.filter(c => fundCodes.has(c)) : []
}))
: [];
-
+
return {
funds: all.funds,
favorites: cleanedFavorites,
@@ -2511,7 +2532,7 @@ export default function HomePage() {
setIsSyncing(true);
const dataToSync = payload || collectLocalPayload(); // Fallback to full sync if no payload
const now = nowInTz().toISOString();
-
+
let upsertData = null;
let updateError = null;
@@ -2520,7 +2541,7 @@ export default function HomePage() {
const { error: rpcError } = await supabase.rpc('update_user_config_partial', {
payload: dataToSync
});
-
+
if (rpcError) {
console.error('增量同步失败,尝试全量同步', rpcError);
// RPC 失败回退到全量更新
@@ -3404,7 +3425,7 @@ export default function HomePage() {
涨跌幅
估值时间
持仓金额
- 当日盈亏
+ 当日收益
持有收益
操作
@@ -3519,10 +3540,8 @@ export default function HomePage() {
{(() => {
- const now = nowInTz();
- const isAfter9 = now.hour() >= 9;
const hasTodayData = f.jzrq === todayStr;
- const shouldHideChange = isTradingDay && isAfter9 && !hasTodayData;
+ const shouldHideChange = isTradingDay && !hasTodayData;
if (!shouldHideChange) {
// 如果涨跌幅列显示(即非交易时段或今日净值已更新),则显示单位净值和真实涨跌幅
@@ -3736,10 +3755,8 @@ export default function HomePage() {
) : (
<>
{(() => {
- const now = nowInTz();
- const isAfter9 = now.hour() >= 9;
const hasTodayData = f.jzrq === todayStr;
- const shouldHideChange = isTradingDay && isAfter9 && !hasTodayData;
+ const shouldHideChange = isTradingDay && !hasTodayData;
if (shouldHideChange) return null;
@@ -3794,9 +3811,11 @@ export default function HomePage() {
¥{profit.amount.toFixed(2)}
- 当日盈亏
- 0 ? 'up' : profit.profitToday < 0 ? 'down' : ''}`}>
- {profit.profitToday > 0 ? '+' : profit.profitToday < 0 ? '-' : ''}¥{Math.abs(profit.profitToday).toFixed(2)}
+ 当日收益
+ 0 ? 'up' : profit.profitToday < 0 ? 'down' : '') : 'muted'}`}>
+ {profit.profitToday != null
+ ? `${profit.profitToday > 0 ? '+' : profit.profitToday < 0 ? '-' : ''}¥${Math.abs(profit.profitToday).toFixed(2)}`
+ : '--'}
{profit.profitTotal !== null && (
@@ -3887,8 +3906,8 @@ export default function HomePage() {
)}
- toggleTrendCollapse(f.code)}
transactions={transactions[f.code] || []}