From 8c7465b9c861f0dfb131dbfd3608313700a64aab Mon Sep 17 00:00:00 2001 From: hzm <934585316@qq.com> Date: Mon, 23 Feb 2026 20:54:25 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20currentTrends=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=88=B0=E5=AF=BC=E5=85=A5=E5=AF=BC=E5=87=BA=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 24 ++++++++++++------------ app/page.jsx | 24 +++++++++++++++++++----- 2 files changed, 31 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 676f0db..5751882 100644 --- a/README.md +++ b/README.md @@ -45,8 +45,8 @@ cp env.example .env.local ``` 按照 `env.example` 填入以下值: - - `NEXT_PUBLIC_SUPABASE_URL`:Supabase 项目 URL - - `NEXT_PUBLIC_SUPABASE_ANON_KEY`:Supabase 匿名公钥 + - `NEXT_PUBLIC_Supabase_URL`:Supabase 项目 URL + - `NEXT_PUBLIC_Supabase_ANON_KEY`:Supabase 匿名公钥 - `NEXT_PUBLIC_WEB3FORMS_ACCESS_KEY`:Web3Forms Access Key - `NEXT_PUBLIC_GA_ID`:Google Analytics Measurement ID(形如 `G-xxxx`) @@ -58,35 +58,35 @@ ``` 访问 [http://localhost:3000](http://localhost:3000) 查看效果。 -### supabase 配置说明 -1. NEXT_PUBLIC_SUPABASE_URL 和 NEXT_PUBLIC_SUPABASE_ANON_KEY 获取 +### Supabase 配置说明 +1. NEXT_PUBLIC_Supabase_URL 和 NEXT_PUBLIC_Supabase_ANON_KEY 获取 - NEXT_PUBLIC_SUPABASE_URL:supabase控制台 → Project Settings → General → Project ID - NEXT_PUBLIC_SUPABASE_ANON_KEY: supabase控制台 → Project Settings → API Keys → Publishable key + NEXT_PUBLIC_Supabase_URL:Supabase控制台 → Project Settings → General → Project ID + NEXT_PUBLIC_Supabase_ANON_KEY: Supabase控制台 → Project Settings → API Keys → Publishable key 2. 邮件数量修改 - supabase 免费项目自带每小时2条邮件服务。如果觉得额度不够,可以改成自己的邮箱SMTP。修改路径在 supabase控制台 → Authentication → Email → SMTP Settings。 + Supabase 免费项目自带每小时2条邮件服务。如果觉得额度不够,可以改成自己的邮箱SMTP。修改路径在 Supabase控制台 → Authentication → Email → SMTP Settings。 之后可在 Rate Limits ,自由修改每小时邮件数量。 3. 修改接收到的邮件为验证码 - 在 supabase控制台 → Authentication → Email → Confirm sign up,选择 `{{.token}}`。 + 在 Supabase控制台 → Authentication → Email → Confirm sign up,选择 `{{.token}}`。 4. 修改验证码位数 官方验证码位数默认为8位,可自行修改。常见一般为6位。 - 在 supabase控制台 → Authentication → Sign In / Providers → Auth Providers → email → Minimum password length。 + 在 Supabase控制台 → Authentication → Sign In / Providers → Auth Providers → email → Minimum password length 和 Email OTP Length 都改为6位。 5. 目前项目用到的 sql 语句,查看项目 supabase.sql 文件。 -更多 supabase 相关内容查阅官方文档。 +更多 Supabase 相关内容查阅官方文档。 ### 构建与部署 本项目已配置 GitHub Actions。每次推送到 `main` 分支时,会自动执行构建并部署到 GitHub Pages。 如需使用 GitHub Actions 部署,请在 GitHub 项目 Settings → Secrets and variables → Actions 中创建对应的 Repository secrets(字段名称与 `.env.local` 保持一致)。 -包括:`NEXT_PUBLIC_SUPABASE_URL`、`NEXT_PUBLIC_SUPABASE_ANON_KEY`、`NEXT_PUBLIC_WEB3FORMS_ACCESS_KEY`、`NEXT_PUBLIC_GA_ID`。 +包括:`NEXT_PUBLIC_Supabase_URL`、`NEXT_PUBLIC_Supabase_ANON_KEY`、`NEXT_PUBLIC_WEB3FORMS_ACCESS_KEY`、`NEXT_PUBLIC_GA_ID`。 若要手动构建: ```bash @@ -102,7 +102,7 @@ npm run build ```bash docker build -t real-time-fund . # 或通过 --build-arg 传入,例如: -# docker build -t real-time-fund --build-arg NEXT_PUBLIC_SUPABASE_URL=xxx --build-arg NEXT_PUBLIC_SUPABASE_ANON_KEY=xxx --build-arg NEXT_PUBLIC_GA_ID=G-xxxx . +# docker build -t real-time-fund --build-arg NEXT_PUBLIC_Supabase_URL=xxx --build-arg NEXT_PUBLIC_Supabase_ANON_KEY=xxx --build-arg NEXT_PUBLIC_GA_ID=G-xxxx . ``` 2. 启动容器 diff --git a/app/page.jsx b/app/page.jsx index d443c38..246de72 100644 --- a/app/page.jsx +++ b/app/page.jsx @@ -1443,7 +1443,8 @@ export default function HomePage() { setLoginSuccess(''); setLoginError(''); } - fetchCloudConfig(session.user.id); + // 仅在明确的登录动作(SIGNED_IN)时检查冲突;INITIAL_SESSION(刷新页面等)不检查,直接以云端为准 + fetchCloudConfig(session.user.id, event === 'SIGNED_IN'); }; supabase.auth.getSession().then(async ({ data, error }) => { @@ -2206,7 +2207,7 @@ export default function HomePage() { } }; - const fetchCloudConfig = async (userId) => { + const fetchCloudConfig = async (userId, checkConflict = false) => { if (!userId) return; try { const { data, error } = await supabase @@ -2229,9 +2230,14 @@ export default function HomePage() { const cloudComparable = getComparablePayload(data.data); if (localComparable !== cloudComparable) { - // 如果数据不一致,无论时间戳如何,都提示用户 - // 用户可以选择使用本地数据覆盖云端,或者使用云端数据覆盖本地 - setCloudConfigModal({ open: true, userId, type: 'conflict', cloudData: data.data }); + // 如果数据不一致 + if (checkConflict) { + // 只有明确要求检查冲突时才提示(例如刚登录时) + setCloudConfigModal({ open: true, userId, type: 'conflict', cloudData: data.data }); + return; + } + // 否则直接覆盖本地(例如已登录状态下的刷新) + await applyCloudConfig(data.data, data.updated_at); return; } @@ -2333,6 +2339,7 @@ export default function HomePage() { favorites: JSON.parse(localStorage.getItem('favorites') || '[]'), groups: JSON.parse(localStorage.getItem('groups') || '[]'), collapsedCodes: JSON.parse(localStorage.getItem('collapsedCodes') || '[]'), + collapsedTrends: JSON.parse(localStorage.getItem('collapsedTrends') || '[]'), refreshMs: parseInt(localStorage.getItem('refreshMs') || '30000', 10), viewMode: localStorage.getItem('viewMode') === 'list' ? 'list' : 'card', holdings: JSON.parse(localStorage.getItem('holdings') || '{}'), @@ -2389,6 +2396,7 @@ export default function HomePage() { const currentFavorites = JSON.parse(localStorage.getItem('favorites') || '[]'); const currentGroups = JSON.parse(localStorage.getItem('groups') || '[]'); const currentCollapsed = JSON.parse(localStorage.getItem('collapsedCodes') || '[]'); + const currentTrends = JSON.parse(localStorage.getItem('collapsedTrends') || '[]'); const currentPendingTrades = JSON.parse(localStorage.getItem('pendingTrades') || '[]'); let mergedFunds = currentFunds; @@ -2434,6 +2442,12 @@ export default function HomePage() { storageHelper.setItem('collapsedCodes', JSON.stringify(mergedCollapsed)); } + if (Array.isArray(data.collapsedTrends)) { + const mergedTrends = Array.from(new Set([...currentTrends, ...data.collapsedTrends])); + setCollapsedTrends(new Set(mergedTrends)); + storageHelper.setItem('collapsedTrends', JSON.stringify(mergedTrends)); + } + if (typeof data.refreshMs === 'number' && data.refreshMs >= 5000) { setRefreshMs(data.refreshMs); setTempSeconds(Math.round(data.refreshMs / 1000));