update pay ui

This commit is contained in:
2025-12-02 19:44:46 +08:00
parent dbc99fe492
commit 2feb4938c1
4 changed files with 16 additions and 42 deletions

15
app.py
View File

@@ -5913,11 +5913,12 @@ def get_stock_quotes():
# 使用 IN 子句一次查询所有股票,避免逐只循环查询 # 使用 IN 子句一次查询所有股票,避免逐只循环查询
try: try:
# 批量查询价格和涨跌幅数据(使用窗口函数) # 批量查询价格和涨跌幅数据(使用窗口函数)
# 涨跌幅基于当日开盘价计算:(最新价 - 开盘价) / 开盘价 * 100
batch_price_query = """ batch_price_query = """
WITH first_prices AS ( WITH open_prices AS (
SELECT SELECT
code, code,
close as first_price, open as open_price,
ROW_NUMBER() OVER (PARTITION BY code ORDER BY timestamp ASC) as rn ROW_NUMBER() OVER (PARTITION BY code ORDER BY timestamp ASC) as rn
FROM stock_minute FROM stock_minute
WHERE code IN %(codes)s WHERE code IN %(codes)s
@@ -5935,12 +5936,12 @@ def get_stock_quotes():
AND timestamp <= %(end)s AND timestamp <= %(end)s
) )
SELECT SELECT
fp.code, op.code,
lp.last_price, lp.last_price,
(lp.last_price - fp.first_price) / fp.first_price * 100 as change_pct (lp.last_price - op.open_price) / op.open_price * 100 as change_pct
FROM first_prices fp FROM open_prices op
INNER JOIN last_prices lp ON fp.code = lp.code INNER JOIN last_prices lp ON op.code = lp.code
WHERE fp.rn = 1 AND lp.rn = 1 WHERE op.rn = 1 AND lp.rn = 1
""" """
batch_data = client.execute(batch_price_query, { batch_data = client.execute(batch_price_query, {

View File

@@ -187,12 +187,13 @@ const StockListItem = ({
{onWatchlistToggle && ( {onWatchlistToggle && (
<IconButton <IconButton
size="xs" size="xs"
variant={isInWatchlist ? 'solid' : 'ghost'} variant={isInWatchlist ? 'solid' : 'outline'}
colorScheme={isInWatchlist ? 'yellow' : 'gray'} colorScheme={isInWatchlist ? 'yellow' : 'gray'}
icon={<StarIcon />} icon={<StarIcon color={isInWatchlist ? undefined : 'gray.400'} />}
onClick={handleWatchlistClick} onClick={handleWatchlistClick}
aria-label={isInWatchlist ? '已关注' : '加自选'} aria-label={isInWatchlist ? '已关注' : '加自选'}
borderRadius="full" borderRadius="full"
borderColor={isInWatchlist ? undefined : 'gray.300'}
/> />
)} )}
</HStack> </HStack>

View File

@@ -64,11 +64,6 @@ import MyFutureEvents from './components/MyFutureEvents';
import InvestmentPlanningCenter from './components/InvestmentPlanningCenter'; import InvestmentPlanningCenter from './components/InvestmentPlanningCenter';
export default function CenterDashboard() { export default function CenterDashboard() {
// 🔍 性能调试:记录组件渲染
const renderCountRef = React.useRef(0);
renderCountRef.current += 1;
console.log(`[Center] 🔄 渲染次数: ${renderCountRef.current}`, new Date().toISOString());
const { user } = useAuth(); const { user } = useAuth();
const location = useLocation(); const location = useLocation();
const navigate = useNavigate(); const navigate = useNavigate();
@@ -100,36 +95,19 @@ export default function CenterDashboard() {
const [quotesLoading, setQuotesLoading] = useState(false); const [quotesLoading, setQuotesLoading] = useState(false);
const loadData = useCallback(async () => { const loadData = useCallback(async () => {
console.log('[Center] 📡 loadData 开始', new Date().toISOString());
try { try {
const base = getApiBase(); const base = getApiBase();
const ts = Date.now(); const ts = Date.now();
console.log('[Center] 🌐 开始请求 API...', base); const [w, e, c] = await Promise.all([
fetch(base + `/api/account/watchlist?_=${ts}`, { credentials: 'include', cache: 'no-store', headers: { 'Cache-Control': 'no-cache' } }),
fetch(base + `/api/account/events/following?_=${ts}`, { credentials: 'include', cache: 'no-store', headers: { 'Cache-Control': 'no-cache' } }),
fetch(base + `/api/account/events/posts?_=${ts}`, { credentials: 'include', cache: 'no-store', headers: { 'Cache-Control': 'no-cache' } }),
]);
// 分开请求,方便定位哪个 API 卡住
console.time('[Center] API: watchlist');
const w = await fetch(base + `/api/account/watchlist?_=${ts}`, { credentials: 'include', cache: 'no-store', headers: { 'Cache-Control': 'no-cache' } });
console.timeEnd('[Center] API: watchlist');
console.log('[Center] ✅ watchlist 响应状态:', w.status);
console.time('[Center] API: events/following');
const e = await fetch(base + `/api/account/events/following?_=${ts}`, { credentials: 'include', cache: 'no-store', headers: { 'Cache-Control': 'no-cache' } });
console.timeEnd('[Center] API: events/following');
console.log('[Center] ✅ events/following 响应状态:', e.status);
console.time('[Center] API: events/posts');
const c = await fetch(base + `/api/account/events/posts?_=${ts}`, { credentials: 'include', cache: 'no-store', headers: { 'Cache-Control': 'no-cache' } });
console.timeEnd('[Center] API: events/posts');
console.log('[Center] ✅ events/posts 响应状态:', c.status);
console.log('[Center] 📥 开始解析 JSON...');
const jw = await w.json(); const jw = await w.json();
console.log('[Center] ✅ watchlist JSON 解析完成');
const je = await e.json(); const je = await e.json();
console.log('[Center] ✅ events/following JSON 解析完成');
const jc = await c.json(); const jc = await c.json();
console.log('[Center] ✅ events/posts JSON 解析完成');
if (jw.success) { if (jw.success) {
const watchlistData = Array.isArray(jw.data) ? jw.data : []; const watchlistData = Array.isArray(jw.data) ? jw.data : [];
setWatchlist(watchlistData); setWatchlist(watchlistData);

View File

@@ -70,11 +70,6 @@ const PanelLoadingFallback: React.FC = () => (
* InvestmentPlanningCenter 主组件 * InvestmentPlanningCenter 主组件
*/ */
const InvestmentPlanningCenter: React.FC = () => { const InvestmentPlanningCenter: React.FC = () => {
// 🔍 性能调试
const renderCountRef = React.useRef(0);
renderCountRef.current += 1;
console.log(`[InvestmentPlanningCenter] 🔄 渲染次数: ${renderCountRef.current}`, new Date().toISOString());
const toast = useToast(); const toast = useToast();
// 颜色主题 // 颜色主题
@@ -93,7 +88,6 @@ const InvestmentPlanningCenter: React.FC = () => {
* 加载所有事件数据(日历事件 + 计划 + 复盘) * 加载所有事件数据(日历事件 + 计划 + 复盘)
*/ */
const loadAllData = useCallback(async (): Promise<void> => { const loadAllData = useCallback(async (): Promise<void> => {
console.log('[InvestmentPlanningCenter] 📡 loadAllData 被调用', new Date().toISOString());
try { try {
setLoading(true); setLoading(true);
const base = getApiBase(); const base = getApiBase();