update watchlist

This commit is contained in:
2025-12-16 14:48:40 +08:00
parent a25d8c365b
commit 8727e4dbaf
9 changed files with 160 additions and 16 deletions

36
app.py
View File

@@ -11682,7 +11682,39 @@ def initialize_event_polling():
print(f'[轮询] 只会推送 ID > {max(current_redis_max, db_max_id)} 的新事件') print(f'[轮询] 只会推送 ID > {max(current_redis_max, db_max_id)} 的新事件')
print(f'[轮询] ========== 初始化完成 ==========\n') print(f'[轮询] ========== 初始化完成 ==========\n')
# 创建后台调度器 # 检测是否在 eventlet 环境下运行
is_eventlet = False
try:
import eventlet
# 检查 eventlet 是否已经 monkey patch
if hasattr(eventlet, 'patcher') and eventlet.patcher.is_monkey_patched('socket'):
is_eventlet = True
except ImportError:
pass
if is_eventlet:
# Eventlet 环境:使用 eventlet 的协程定时器
print(f'[轮询] 检测到 Eventlet 环境,使用 eventlet 协程调度器')
def eventlet_polling_loop():
"""Eventlet 兼容的轮询循环"""
import eventlet
while True:
try:
eventlet.sleep(30) # 等待 30 秒
poll_new_events()
except Exception as e:
print(f'[轮询 ERROR] Eventlet 轮询循环出错: {e}')
import traceback
traceback.print_exc()
eventlet.sleep(30) # 出错后等待 30 秒再继续
# 启动 eventlet 协程
eventlet.spawn(eventlet_polling_loop)
print(f'[轮询] Eventlet 协程调度器已启动 (PID: {os.getpid()}),每 30 秒检查一次新事件')
else:
# 非 Eventlet 环境:使用 APScheduler
print(f'[轮询] 使用 APScheduler BackgroundScheduler')
scheduler = BackgroundScheduler() scheduler = BackgroundScheduler()
# 每 30 秒执行一次轮询 # 每 30 秒执行一次轮询
scheduler.add_job( scheduler.add_job(
@@ -11694,7 +11726,7 @@ def initialize_event_polling():
replace_existing=True replace_existing=True
) )
scheduler.start() scheduler.start()
print(f'[轮询] 调度器已启动 (PID: {os.getpid()}),每 30 秒检查一次新事件') print(f'[轮询] APScheduler 调度器已启动 (PID: {os.getpid()}),每 30 秒检查一次新事件')
_polling_initialized = True _polling_initialized = True

View File

@@ -135,6 +135,14 @@ def post_worker_init(worker):
"""Worker 初始化完成后调用""" """Worker 初始化完成后调用"""
print(f"✅ Eventlet Worker {worker.pid} 已初始化 (10,000 并发连接就绪)") print(f"✅ Eventlet Worker {worker.pid} 已初始化 (10,000 并发连接就绪)")
# 触发事件轮询初始化(使用 Redis 锁确保只有一个 Worker 启动调度器)
try:
from app import _auto_init_polling
print(f"[轮询] Worker {worker.pid} 尝试初始化事件轮询...")
_auto_init_polling()
except Exception as e:
print(f"[轮询] Worker {worker.pid} 初始化事件轮询失败: {e}")
def worker_abort(worker): def worker_abort(worker):
"""Worker 收到 SIGABRT 信号时调用(超时)""" """Worker 收到 SIGABRT 信号时调用(超时)"""

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 871 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

View File

@@ -18,6 +18,7 @@ import {
Link, Link,
Divider, Divider,
Avatar, Avatar,
Image,
useColorModeValue useColorModeValue
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { useNavigate, useLocation } from 'react-router-dom'; import { useNavigate, useLocation } from 'react-router-dom';
@@ -282,7 +283,55 @@ const MobileDrawer = memo(({
{/* 联系我们 */} {/* 联系我们 */}
<Box> <Box>
<Text fontWeight="bold" mb={2}>联系我们</Text> <Text fontWeight="bold" mb={2}>联系我们</Text>
<Text fontSize="sm" color={contactTextColor}>敬请期待</Text> <Text fontSize="xs" color={contactTextColor} mb={3}>
扫码添加获取更多资讯
</Text>
<HStack spacing={3} justify="center">
{/* 微信群二维码 */}
<VStack spacing={1}>
<Box
borderRadius="md"
overflow="hidden"
boxShadow="sm"
border="1px solid"
borderColor="gray.200"
p={1.5}
bg="white"
>
<Image
src="/images/services/wechat_group.png"
alt="微信群"
boxSize="90px"
objectFit="contain"
/>
</Box>
<Text fontSize="xs" color={contactTextColor}>
微信交流群
</Text>
</VStack>
{/* 小程序二维码 */}
<VStack spacing={1}>
<Box
borderRadius="md"
overflow="hidden"
boxShadow="sm"
border="1px solid"
borderColor="gray.200"
p={1.5}
bg="white"
>
<Image
src="/images/services/wechat_app2.jpg"
alt="小程序"
boxSize="90px"
objectFit="contain"
/>
</Box>
<Text fontSize="xs" color={contactTextColor}>
微信小程序
</Text>
</VStack>
</HStack>
</Box> </Box>
{/* 移动端登录/登出按钮 */} {/* 移动端登录/登出按钮 */}

View File

@@ -4,6 +4,7 @@
import React, { memo, useCallback } from 'react'; import React, { memo, useCallback } from 'react';
import { import {
HStack, HStack,
VStack,
Menu, Menu,
MenuButton, MenuButton,
MenuList, MenuList,
@@ -12,6 +13,8 @@ import {
Text, Text,
Flex, Flex,
Badge, Badge,
Image,
Box,
useColorModeValue useColorModeValue
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { ChevronDownIcon } from '@chakra-ui/icons'; import { ChevronDownIcon } from '@chakra-ui/icons';
@@ -279,12 +282,64 @@ const DesktopNav = memo(({ isAuthenticated, user }) => {
联系我们 联系我们
</MenuButton> </MenuButton>
<MenuList <MenuList
minW="260px" minW="340px"
p={4} p={4}
onMouseEnter={contactUsMenu.handleMouseEnter} onMouseEnter={contactUsMenu.handleMouseEnter}
onMouseLeave={contactUsMenu.handleMouseLeave} onMouseLeave={contactUsMenu.handleMouseLeave}
> >
<Text fontSize="sm" color={contactTextColor}>敬请期待</Text> <Text fontSize="sm" fontWeight="bold" mb={3} color={contactTextColor}>
扫码添加获取更多资讯
</Text>
<HStack spacing={4} justify="center">
{/* 微信群二维码 */}
<VStack spacing={2}>
<Box
borderRadius="lg"
overflow="hidden"
boxShadow="sm"
border="1px solid"
borderColor="gray.200"
p={2}
bg="white"
_hover={{ boxShadow: 'md', transform: 'scale(1.02)' }}
transition="all 0.2s"
>
<Image
src="/images/services/wechat_group.png"
alt="微信群"
boxSize="120px"
objectFit="contain"
/>
</Box>
<Text fontSize="xs" color={contactTextColor} fontWeight="medium">
微信交流群
</Text>
</VStack>
{/* 小程序二维码 */}
<VStack spacing={2}>
<Box
borderRadius="lg"
overflow="hidden"
boxShadow="sm"
border="1px solid"
borderColor="gray.200"
p={2}
bg="white"
_hover={{ boxShadow: 'md', transform: 'scale(1.02)' }}
transition="all 0.2s"
>
<Image
src="/images/services/wechat_app2.jpg"
alt="小程序"
boxSize="120px"
objectFit="contain"
/>
</Box>
<Text fontSize="xs" color={contactTextColor} fontWeight="medium">
微信小程序
</Text>
</VStack>
</HStack>
</MenuList> </MenuList>
</Menu> </Menu>
</HStack> </HStack>