- {funds
- .filter(f => currentTab === 'all' || favorites.has(f.code))
- .map((f) => (
-
-
-
-
-
- {f.name}
- #{f.code}
-
-
-
- 估值时间
- {f.gztime || f.time || '-'}
-
-
-
-
-
-
-
-
-
-
toggleCollapse(f.code)}
- >
-
-
- 前10重仓股票
-
-
-
涨跌幅 / 占比
-
-
- {Array.isArray(f.holdings) && f.holdings.length ? (
-
- {f.holdings.map((h, idx) => (
-
-
{h.name}
-
- {typeof h.change === 'number' && (
-
0 ? 'up' : h.change < 0 ? 'down' : ''}`} style={{ marginRight: 8 }}>
- {h.change > 0 ? '+' : ''}{h.change.toFixed(2)}%
-
- )}
-
{h.weight}
+
+
+ {viewMode === 'list' && (
+
+
基金名称
+
估值净值
+
涨跌幅
+
估值时间
+
操作
+
+ )}
+
+
+ {funds
+ .filter(f => currentTab === 'all' || favorites.has(f.code))
+ .sort((a, b) => {
+ if (sortBy === 'yield') {
+ const valA = typeof a.estGszzl === 'number' ? a.estGszzl : (Number(a.gszzl) || 0);
+ const valB = typeof b.estGszzl === 'number' ? b.estGszzl : (Number(b.gszzl) || 0);
+ return valB - valA;
+ }
+ if (sortBy === 'name') return a.name.localeCompare(b.name, 'zh-CN');
+ if (sortBy === 'code') return a.code.localeCompare(b.code);
+ return 0; // default order is the order in the array
+ })
+ .map((f) => (
+
+
+ {viewMode === 'list' ? (
+ <>
+
+
+
+ {f.name}
+ #{f.code}
+
+
+
+ {f.estPricedCoverage > 0.05 ? f.estGsz.toFixed(4) : (f.gsz ?? '—')}
+
+
+ 0.05 ? (f.estGszzl > 0 ? 'up' : f.estGszzl < 0 ? 'down' : '') : (Number(f.gszzl) > 0 ? 'up' : Number(f.gszzl) < 0 ? 'down' : '')} style={{ fontWeight: 700 }}>
+ {f.estPricedCoverage > 0.05 ? `${f.estGszzl > 0 ? '+' : ''}${f.estGszzl.toFixed(2)}%` : (typeof f.gszzl === 'number' ? `${f.gszzl > 0 ? '+' : ''}${f.gszzl.toFixed(2)}%` : f.gszzl ?? '—')}
+
+
+
+ {f.gztime || f.time || '-'}
+
+
+
+
+ >
+ ) : (
+ <>
+
+
+
+
+ {f.name}
+ #{f.code}
+
+
+
+
+
+ 估值时间
+ {f.gztime || f.time || '-'}
+
+
- ))}
+
+
+
+ 0.05 ? f.estGsz.toFixed(4) : (f.gsz ?? '—')} />
+ 0.05 ? `${f.estGszzl > 0 ? '+' : ''}${f.estGszzl.toFixed(2)}%` : (typeof f.gszzl === 'number' ? `${f.gszzl > 0 ? '+' : ''}${f.gszzl.toFixed(2)}%` : f.gszzl ?? '—')}
+ delta={f.estPricedCoverage > 0.05 ? f.estGszzl : (Number(f.gszzl) || 0)}
+ />
+
+ {f.estPricedCoverage > 0.05 && (
+
+ 基于 {Math.round(f.estPricedCoverage * 100)}% 持仓估算
+
+ )}
+
toggleCollapse(f.code)}
+ >
+
+
+ 前10重仓股票
+
+
+
涨跌幅 / 占比
+
+
+
+ {!collapsedCodes.has(f.code) && (
+
+ {Array.isArray(f.holdings) && f.holdings.length ? (
+
+ {f.holdings.map((h, idx) => (
+
+
{h.name}
+
+ {typeof h.change === 'number' && (
+ 0 ? 'up' : h.change < 0 ? 'down' : ''}`} style={{ marginRight: 8 }}>
+ {h.change > 0 ? '+' : ''}{h.change.toFixed(2)}%
+
+ )}
+ {h.weight}
+
+
+ ))}
+
+ ) : (
+ 暂无重仓数据
+ )}
+
+ )}
+
+ >
+ )}
- ) : (
- 暂无重仓数据
- )}
-
+
+ ))}
+
- ))}
-
+
+
)}
-
数据源:实时估值与重仓直连东方财富,无需后端,部署即用
+
+
数据源:实时估值与重仓直连东方财富,无需后端,部署即用
+
注:估算数据与真实结算数据会有1%左右误差
+
{settingsOpen && (
setSettingsOpen(false)}>
diff --git a/next.config.js b/next.config.js
index 75c2297..91ef62f 100644
--- a/next.config.js
+++ b/next.config.js
@@ -1,9 +1,6 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
- experimental: {
- appDir: true
- }
};
module.exports = nextConfig;
diff --git a/package-lock.json b/package-lock.json
index b85fc7e..7b7b970 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,6 +8,7 @@
"name": "real-time-fund",
"version": "0.1.0",
"dependencies": {
+ "framer-motion": "^12.29.2",
"next": "14.2.5",
"react": "18.3.1",
"react-dom": "18.3.1"
@@ -216,6 +217,33 @@
"integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==",
"license": "MIT"
},
+ "node_modules/framer-motion": {
+ "version": "12.29.2",
+ "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.29.2.tgz",
+ "integrity": "sha512-lSNRzBJk4wuIy0emYQ/nfZ7eWhqud2umPKw2QAQki6uKhZPKm2hRQHeQoHTG9MIvfobb+A/LbEWPJU794ZUKrg==",
+ "license": "MIT",
+ "dependencies": {
+ "motion-dom": "^12.29.2",
+ "motion-utils": "^12.29.2",
+ "tslib": "^2.4.0"
+ },
+ "peerDependencies": {
+ "@emotion/is-prop-valid": "*",
+ "react": "^18.0.0 || ^19.0.0",
+ "react-dom": "^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@emotion/is-prop-valid": {
+ "optional": true
+ },
+ "react": {
+ "optional": true
+ },
+ "react-dom": {
+ "optional": true
+ }
+ }
+ },
"node_modules/graceful-fs": {
"version": "4.2.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
@@ -240,6 +268,21 @@
"loose-envify": "cli.js"
}
},
+ "node_modules/motion-dom": {
+ "version": "12.29.2",
+ "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.29.2.tgz",
+ "integrity": "sha512-/k+NuycVV8pykxyiTCoFzIVLA95Nb1BFIVvfSu9L50/6K6qNeAYtkxXILy/LRutt7AzaYDc2myj0wkCVVYAPPA==",
+ "license": "MIT",
+ "dependencies": {
+ "motion-utils": "^12.29.2"
+ }
+ },
+ "node_modules/motion-utils": {
+ "version": "12.29.2",
+ "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.29.2.tgz",
+ "integrity": "sha512-G3kc34H2cX2gI63RqU+cZq+zWRRPSsNIOjpdl9TN4AQwC4sgwYPl/Q/Obf/d53nOm569T0fYK+tcoSV50BWx8A==",
+ "license": "MIT"
+ },
"node_modules/nanoid": {
"version": "3.3.11",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
diff --git a/package.json b/package.json
index 5bc5d36..a0b7911 100644
--- a/package.json
+++ b/package.json
@@ -8,6 +8,7 @@
"start": "next start"
},
"dependencies": {
+ "framer-motion": "^12.29.2",
"next": "14.2.5",
"react": "18.3.1",
"react-dom": "18.3.1"