update pay ui

This commit is contained in:
2025-12-13 16:30:50 +08:00
parent ed9d49da01
commit 4ccd43f025
17 changed files with 67 additions and 43 deletions

View File

@@ -62,7 +62,7 @@ server {
# ============================================ # ============================================
# CORS 配置(允许 CDN 域名访问) # CORS 配置(允许 CDN 域名访问)
# ============================================ # ============================================
set $cors_origin '*'; set $cors_origin 'https://valuefrontier.cn';
# 如果需要限制来源,取消下面注释 # 如果需要限制来源,取消下面注释
# set $cors_origin ''; # set $cors_origin '';
@@ -78,13 +78,20 @@ server {
if ($request_method = 'OPTIONS') { if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' $cors_origin always; add_header 'Access-Control-Allow-Origin' $cors_origin always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always; add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'Origin, Content-Type, Accept, Authorization, X-Requested-With' always; add_header 'Access-Control-Allow-Headers' 'Origin, Content-Type, Accept, Authorization, X-Requested-With, Cookie' always;
add_header 'Access-Control-Allow-Credentials' 'true' always; add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Max-Age' 86400; add_header 'Access-Control-Max-Age' 86400;
add_header 'Content-Length' 0; add_header 'Content-Length' 0;
return 204; return 204;
} }
# 隐藏后端返回的 CORS 头(避免重复)
proxy_hide_header 'Access-Control-Allow-Origin';
proxy_hide_header 'Access-Control-Allow-Credentials';
proxy_hide_header 'Access-Control-Allow-Methods';
proxy_hide_header 'Access-Control-Allow-Headers';
proxy_hide_header 'Access-Control-Expose-Headers';
proxy_pass http://127.0.0.1:5001; proxy_pass http://127.0.0.1:5001;
proxy_http_version 1.1; proxy_http_version 1.1;
proxy_set_header Host $host; proxy_set_header Host $host;
@@ -93,7 +100,7 @@ server {
proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Connection ""; proxy_set_header Connection "";
# CORS 头 # 统一添加 CORS 头
add_header 'Access-Control-Allow-Origin' $cors_origin always; add_header 'Access-Control-Allow-Origin' $cors_origin always;
add_header 'Access-Control-Allow-Credentials' 'true' always; add_header 'Access-Control-Allow-Credentials' 'true' always;

View File

@@ -37,6 +37,7 @@ import VerificationCodeInput from './VerificationCodeInput';
import WechatRegister from './WechatRegister'; import WechatRegister from './WechatRegister';
import { setCurrentUser } from '../../mocks/data/users'; import { setCurrentUser } from '../../mocks/data/users';
import { logger } from '../../utils/logger'; import { logger } from '../../utils/logger';
import { getApiBase } from '../../utils/apiConfig';
import { useAuthEvents } from '../../hooks/useAuthEvents'; import { useAuthEvents } from '../../hooks/useAuthEvents';
// 统一配置对象 // 统一配置对象
@@ -186,7 +187,7 @@ export default function AuthFormContent() {
purpose: config.api.purpose purpose: config.api.purpose
}; };
const response = await fetch('/api/auth/send-verification-code', { const response = await fetch(`${getApiBase()}/api/auth/send-verification-code`, {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@@ -300,7 +301,7 @@ export default function AuthFormContent() {
}; };
// 调用API根据模式选择不同的endpoint // 调用API根据模式选择不同的endpoint
const response = await fetch('/api/auth/login-with-code', { const response = await fetch(`${getApiBase()}/api/auth/login-with-code`, {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',

View File

@@ -20,6 +20,7 @@ import CitationMark from '@components/Citation/CitationMark';
import CitedContent from '@components/Citation/CitedContent'; import CitedContent from '@components/Citation/CitedContent';
import { processCitationData } from '@utils/citationUtils'; import { processCitationData } from '@utils/citationUtils';
import { logger } from '@utils/logger'; import { logger } from '@utils/logger';
import { getApiBase } from '@utils/apiConfig';
import './InvestmentCalendar.css'; import './InvestmentCalendar.css';
const { TabPane } = Tabs; const { TabPane } = Tabs;
@@ -153,7 +154,7 @@ const InvestmentCalendar = () => {
const code = codes[i]; const code = codes[i];
const originalCode = normalizedStocks[i].code; // 使用归一化后的代码作为key const originalCode = normalizedStocks[i].code; // 使用归一化后的代码作为key
try { try {
const response = await fetch(`/api/market/trade/${code}?days=1`); const response = await fetch(`${getApiBase()}/api/market/trade/${code}?days=1`);
if (response.ok) { if (response.ok) {
const data = await response.json(); const data = await response.json();
if (data.success && data.data && data.data.length > 0) { if (data.success && data.data && data.data.length > 0) {

View File

@@ -53,6 +53,7 @@ import {
FaChevronDown, FaChevronDown,
FaChevronUp, FaChevronUp,
} from 'react-icons/fa'; } from 'react-icons/fa';
import { getApiBase } from '../../utils/apiConfig';
export default function SubscriptionContent() { export default function SubscriptionContent() {
// Auth context // Auth context
@@ -129,7 +130,7 @@ export default function SubscriptionContent() {
const fetchSubscriptionPlans = async () => { const fetchSubscriptionPlans = async () => {
try { try {
logger.debug('SubscriptionContent', '正在获取订阅套餐'); logger.debug('SubscriptionContent', '正在获取订阅套餐');
const response = await fetch('/api/subscription/plans'); const response = await fetch(`${getApiBase()}/api/subscription/plans`);
if (response.ok) { if (response.ok) {
const data = await response.json(); const data = await response.json();
@@ -175,7 +176,7 @@ export default function SubscriptionContent() {
validPromoCode validPromoCode
}); });
const response = await fetch('/api/subscription/calculate-price', { const response = await fetch(`${getApiBase()}/api/subscription/calculate-price`, {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@@ -307,7 +308,7 @@ export default function SubscriptionContent() {
orderId: null // Will be set after order creation orderId: null // Will be set after order creation
}); });
const response = await fetch('/api/payment/create-order', { const response = await fetch(`${getApiBase()}/api/payment/create-order`, {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@@ -379,7 +380,7 @@ export default function SubscriptionContent() {
const checkInterval = setInterval(async () => { const checkInterval = setInterval(async () => {
try { try {
const response = await fetch(`/api/payment/order/${orderId}/status`, { const response = await fetch(`${getApiBase()}/api/payment/order/${orderId}/status`, {
credentials: 'include' credentials: 'include'
}); });
@@ -456,7 +457,7 @@ export default function SubscriptionContent() {
setForceUpdating(true); setForceUpdating(true);
try { try {
const response = await fetch(`/api/payment/order/${paymentOrder.id}/force-update`, { const response = await fetch(`${getApiBase()}/api/payment/order/${paymentOrder.id}/force-update`, {
method: 'POST', method: 'POST',
credentials: 'include' credentials: 'include'
}); });
@@ -517,7 +518,7 @@ export default function SubscriptionContent() {
setCheckingPayment(true); setCheckingPayment(true);
try { try {
const response = await fetch(`/api/payment/order/${paymentOrder.id}/status`, { const response = await fetch(`${getApiBase()}/api/payment/order/${paymentOrder.id}/status`, {
credentials: 'include' credentials: 'include'
}); });

View File

@@ -44,6 +44,7 @@ import { logger } from '../../utils/logger';
import { useAuth } from '../../contexts/AuthContext'; import { useAuth } from '../../contexts/AuthContext';
import { useSubscriptionEvents } from '../../hooks/useSubscriptionEvents'; import { useSubscriptionEvents } from '../../hooks/useSubscriptionEvents';
import { subscriptionConfig, themeColors } from '../../views/Pages/Account/subscription-content'; import { subscriptionConfig, themeColors } from '../../views/Pages/Account/subscription-content';
import { getApiBase } from '../../utils/apiConfig';
// 计费周期选择器组件 - 移动端垂直布局(年付在上),桌面端水平布局 // 计费周期选择器组件 - 移动端垂直布局(年付在上),桌面端水平布局
interface CycleSelectorProps { interface CycleSelectorProps {
@@ -207,8 +208,8 @@ export default function SubscriptionContentNew() {
// 优先使用 sessionStorage 中的 orderId否则使用 order_no 查询 // 优先使用 sessionStorage 中的 orderId否则使用 order_no 查询
const orderId = sessionStorage.getItem('alipay_order_id'); const orderId = sessionStorage.getItem('alipay_order_id');
const statusUrl = orderId const statusUrl = orderId
? `/api/payment/alipay/order/${orderId}/status` ? `${getApiBase()}/api/payment/alipay/order/${orderId}/status`
: `/api/payment/alipay/order-by-no/${orderNo}/status`; : `${getApiBase()}/api/payment/alipay/order-by-no/${orderNo}/status`;
const response = await fetch(statusUrl, { const response = await fetch(statusUrl, {
credentials: 'include', credentials: 'include',
@@ -261,7 +262,7 @@ export default function SubscriptionContentNew() {
const fetchSubscriptionPlans = async () => { const fetchSubscriptionPlans = async () => {
try { try {
logger.debug('SubscriptionContentNew', '正在获取订阅套餐'); logger.debug('SubscriptionContentNew', '正在获取订阅套餐');
const response = await fetch('/api/subscription/plans'); const response = await fetch(`${getApiBase()}/api/subscription/plans`);
if (response.ok) { if (response.ok) {
const data = await response.json(); const data = await response.json();
@@ -324,7 +325,7 @@ export default function SubscriptionContentNew() {
? promoCodeValue.trim() ? promoCodeValue.trim()
: null; : null;
const response = await fetch('/api/subscription/calculate-price', { const response = await fetch(`${getApiBase()}/api/subscription/calculate-price`, {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@@ -430,7 +431,7 @@ export default function SubscriptionContentNew() {
// 检查是否为免费升级(剩余价值足够抵扣新套餐价格) // 检查是否为免费升级(剩余价值足够抵扣新套餐价格)
if (price === 0 && priceInfo?.is_upgrade) { if (price === 0 && priceInfo?.is_upgrade) {
const response = await fetch('/api/subscription/free-upgrade', { const response = await fetch(`${getApiBase()}/api/subscription/free-upgrade`, {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@@ -479,8 +480,8 @@ export default function SubscriptionContentNew() {
// 根据支付方式选择不同的 API // 根据支付方式选择不同的 API
const apiUrl = paymentMethod === 'alipay' const apiUrl = paymentMethod === 'alipay'
? '/api/payment/alipay/create-order' ? `${getApiBase()}/api/payment/alipay/create-order`
: '/api/payment/create-order'; : `${getApiBase()}/api/payment/create-order`;
// 检测是否为移动端设备 // 检测是否为移动端设备
const userAgent = navigator.userAgent; const userAgent = navigator.userAgent;
@@ -615,8 +616,8 @@ export default function SubscriptionContentNew() {
const startAutoPaymentCheck = (orderId: string, method: 'wechat' | 'alipay' = 'wechat') => { const startAutoPaymentCheck = (orderId: string, method: 'wechat' | 'alipay' = 'wechat') => {
// 根据支付方式选择不同的状态查询 API // 根据支付方式选择不同的状态查询 API
const statusApiUrl = method === 'alipay' const statusApiUrl = method === 'alipay'
? `/api/payment/alipay/order/${orderId}/status` ? `${getApiBase()}/api/payment/alipay/order/${orderId}/status`
: `/api/payment/order/${orderId}/status`; : `${getApiBase()}/api/payment/order/${orderId}/status`;
const checkInterval = setInterval(async () => { const checkInterval = setInterval(async () => {
try { try {
@@ -666,8 +667,8 @@ export default function SubscriptionContentNew() {
// 根据订单的支付方式选择不同的查询 API // 根据订单的支付方式选择不同的查询 API
const orderPaymentMethod = (paymentOrder as any).payment_method || paymentMethod; const orderPaymentMethod = (paymentOrder as any).payment_method || paymentMethod;
const statusApiUrl = orderPaymentMethod === 'alipay' const statusApiUrl = orderPaymentMethod === 'alipay'
? `/api/payment/alipay/order/${(paymentOrder as any).id}/status` ? `${getApiBase()}/api/payment/alipay/order/${(paymentOrder as any).id}/status`
: `/api/payment/order/${(paymentOrder as any).id}/status`; : `${getApiBase()}/api/payment/order/${(paymentOrder as any).id}/status`;
const response = await fetch(statusApiUrl, { const response = await fetch(statusApiUrl, {
credentials: 'include', credentials: 'include',

View File

@@ -4,6 +4,7 @@ import { useNavigate } from 'react-router-dom';
import { useToast } from '@chakra-ui/react'; import { useToast } from '@chakra-ui/react';
import { logger } from '@utils/logger'; import { logger } from '@utils/logger';
import { performanceMonitor } from '@utils/performanceMonitor'; import { performanceMonitor } from '@utils/performanceMonitor';
import { getApiBase } from '@utils/apiConfig';
import { useNotification } from '@contexts/NotificationContext'; import { useNotification } from '@contexts/NotificationContext';
// ⚡ PostHog 延迟加载:移除同步导入,首屏减少 ~180KB // ⚡ PostHog 延迟加载:移除同步导入,首屏减少 ~180KB
// import { identifyUser, resetUser, trackEvent } from '@lib/posthog'; // import { identifyUser, resetUser, trackEvent } from '@lib/posthog';
@@ -119,7 +120,7 @@ export const AuthProvider = ({ children }) => {
controller.abort(new Error('Session check timeout after 5 seconds')); controller.abort(new Error('Session check timeout after 5 seconds'));
}, 5000); // 5秒超时 }, 5000); // 5秒超时
const response = await fetch(`/api/auth/session`, { const response = await fetch(`${getApiBase()}/api/auth/session`, {
method: 'GET', method: 'GET',
credentials: 'include', credentials: 'include',
headers: { headers: {
@@ -251,7 +252,7 @@ export const AuthProvider = ({ children }) => {
loginType loginType
}); });
const response = await fetch(`/api/auth/login`, { const response = await fetch(`${getApiBase()}/api/auth/login`, {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/x-www-form-urlencoded', 'Content-Type': 'application/x-www-form-urlencoded',
@@ -315,7 +316,7 @@ export const AuthProvider = ({ children }) => {
try { try {
setIsLoading(true); setIsLoading(true);
const response = await fetch(`/api/auth/register/phone`, { const response = await fetch(`${getApiBase()}/api/auth/register/phone`, {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@@ -370,7 +371,7 @@ export const AuthProvider = ({ children }) => {
// 发送手机验证码 // 发送手机验证码
const sendSmsCode = async (phone) => { const sendSmsCode = async (phone) => {
try { try {
const response = await fetch(`/api/auth/send-sms-code`, { const response = await fetch(`${getApiBase()}/api/auth/send-sms-code`, {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@@ -400,7 +401,7 @@ export const AuthProvider = ({ children }) => {
const logout = async () => { const logout = async () => {
try { try {
// 调用后端登出API // 调用后端登出API
await fetch(`/api/auth/logout`, { await fetch(`${getApiBase()}/api/auth/logout`, {
method: 'POST', method: 'POST',
credentials: 'include' credentials: 'include'
}); });

View File

@@ -3,6 +3,7 @@
import { useState, useEffect, useCallback, useRef } from 'react'; import { useState, useEffect, useCallback, useRef } from 'react';
import { logger } from '../utils/logger'; import { logger } from '../utils/logger';
import { getApiBase } from '../utils/apiConfig';
// 交易日数据会从后端获取,这里只做时间判断 // 交易日数据会从后端获取,这里只做时间判断
const TRADING_SESSIONS = [ const TRADING_SESSIONS = [
@@ -29,7 +30,7 @@ const isInTradingSession = () => {
*/ */
const fetchIndexRealtime = async (indexCode) => { const fetchIndexRealtime = async (indexCode) => {
try { try {
const response = await fetch(`/api/index/${indexCode}/realtime`); const response = await fetch(`${getApiBase()}/api/index/${indexCode}/realtime`);
if (!response.ok) { if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`); throw new Error(`HTTP error! status: ${response.status}`);
} }

View File

@@ -3,6 +3,7 @@ import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
import { eventService } from '../../services/eventService'; import { eventService } from '../../services/eventService';
import { logger } from '../../utils/logger'; import { logger } from '../../utils/logger';
import { localCacheManager, CACHE_EXPIRY_STRATEGY } from '../../utils/CacheManager'; import { localCacheManager, CACHE_EXPIRY_STRATEGY } from '../../utils/CacheManager';
import { getApiBase } from '../../utils/apiConfig';
// ==================== 常量定义 ==================== // ==================== 常量定义 ====================
@@ -284,7 +285,7 @@ export const toggleEventFollow = createAsyncThunk(
logger.debug('CommunityData', '切换事件关注状态', { eventId }); logger.debug('CommunityData', '切换事件关注状态', { eventId });
// 调用 API自动切换关注状态后端根据当前状态决定关注/取消关注) // 调用 API自动切换关注状态后端根据当前状态决定关注/取消关注)
const response = await fetch(`/api/events/${eventId}/follow`, { const response = await fetch(`${getApiBase()}/api/events/${eventId}/follow`, {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
credentials: 'include' credentials: 'include'

View File

@@ -63,7 +63,7 @@ if (typeof document !== 'undefined') {
*/ */
const fetchIndexKline = async (indexCode) => { const fetchIndexKline = async (indexCode) => {
try { try {
const response = await fetch(`/api/index/${indexCode}/kline?type=daily`); const response = await fetch(`${getApiBase()}/api/index/${indexCode}/kline?type=daily`);
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`); if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
const data = await response.json(); const data = await response.json();
return data; return data;

View File

@@ -37,6 +37,7 @@ import ReactECharts from 'echarts-for-react';
import { eventService } from '../../../services/eventService'; import { eventService } from '../../../services/eventService';
import CitedContent from '../../../components/Citation/CitedContent'; import CitedContent from '../../../components/Citation/CitedContent';
import { logger } from '../../../utils/logger'; import { logger } from '../../../utils/logger';
import { getApiBase } from '../../../utils/apiConfig';
import { PROFESSIONAL_COLORS } from '../../../constants/professionalTheme'; import { PROFESSIONAL_COLORS } from '../../../constants/professionalTheme';
// 节点样式配置 - 完全复刻Flask版本 // 节点样式配置 - 完全复刻Flask版本
@@ -522,7 +523,7 @@ const TransmissionChainAnalysis = ({ eventId }) => {
// 获取节点详情 - 完全复刻Flask版本API调用 // 获取节点详情 - 完全复刻Flask版本API调用
async function getChainNodeDetail(nodeId) { async function getChainNodeDetail(nodeId) {
try { try {
const response = await fetch(`/api/events/${eventId}/chain-node/${nodeId}`); const response = await fetch(`${getApiBase()}/api/events/${eventId}/chain-node/${nodeId}`);
const result = await response.json(); const result = await response.json();
if (result.success) { if (result.success) {
return result.data; return result.data;

View File

@@ -3,10 +3,11 @@
*/ */
import type { Exchange } from '../types'; import type { Exchange } from '../types';
import { getApiBase } from '@utils/apiConfig';
/** /**
* 获取 WebSocket 配置 * 获取 WebSocket 配置
* - 生产环境 (HTTPS): 通过 Nginx 代理使用 wss:// * - 生产环境 (HTTPS): 通过 API 服务器 Nginx 代理使用 wss://
* - 开发环境 (HTTP): 直连 ws:// * - 开发环境 (HTTP): 直连 ws://
*/ */
const getWsConfig = (): Record<Exchange, string> => { const getWsConfig = (): Record<Exchange, string> => {
@@ -19,13 +20,15 @@ const getWsConfig = (): Record<Exchange, string> => {
} }
const isHttps = window.location.protocol === 'https:'; const isHttps = window.location.protocol === 'https:';
const host = window.location.host;
if (isHttps) { if (isHttps) {
// 生产环境:通过 Nginx 代理 // 生产环境:通过 API 服务器的 Nginx 代理
// CDN 不支持 WebSocket需要连接到 api.valuefrontier.cn
const apiBase = getApiBase();
const apiHost = apiBase.replace(/^https?:\/\//, '');
return { return {
SSE: `wss://${host}/ws/sse`, // 上交所 - Nginx 代理 SSE: `wss://${apiHost}/ws/sse`, // 上交所 - 通过 API 服务器代理
SZSE: `wss://${host}/ws/szse`, // 深交所 - Nginx 代理 SZSE: `wss://${apiHost}/ws/szse`, // 深交所 - 通过 API 服务器代理
}; };
} }

View File

@@ -14,6 +14,7 @@
import { useState, useEffect, useRef, useCallback } from 'react'; import { useState, useEffect, useRef, useCallback } from 'react';
import { logger } from '@utils/logger'; import { logger } from '@utils/logger';
import { getApiBase } from '@utils/apiConfig';
import { WS_CONFIG, HEARTBEAT_INTERVAL, RECONNECT_INTERVAL } from './constants'; import { WS_CONFIG, HEARTBEAT_INTERVAL, RECONNECT_INTERVAL } from './constants';
import { getExchange, normalizeCode, calcChangePct } from './utils'; import { getExchange, normalizeCode, calcChangePct } from './utils';
import type { import type {
@@ -337,7 +338,7 @@ const fetchInitialQuotes = async (
if (codes.length === 0) return {}; if (codes.length === 0) return {};
try { try {
const response = await fetch('/api/flex-screen/quotes', { const response = await fetch(`${getApiBase()}/api/flex-screen/quotes`, {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ codes, include_order_book: includeOrderBook }), body: JSON.stringify({ codes, include_order_book: includeOrderBook }),

View File

@@ -62,6 +62,7 @@ import { useRealtimeQuote } from './hooks';
import { getFullCode } from './hooks/utils'; import { getFullCode } from './hooks/utils';
import QuoteTile from './components/QuoteTile'; import QuoteTile from './components/QuoteTile';
import { logger } from '@utils/logger'; import { logger } from '@utils/logger';
import { getApiBase } from '@utils/apiConfig';
import type { WatchlistItem, ConnectionStatus } from './types'; import type { WatchlistItem, ConnectionStatus } from './types';
// 本地存储 key // 本地存储 key
@@ -179,7 +180,7 @@ const FlexScreen: React.FC = () => {
setIsSearching(true); setIsSearching(true);
try { try {
const response = await fetch(`/api/stocks/search?q=${encodeURIComponent(query)}&limit=10`); const response = await fetch(`${getApiBase()}/api/stocks/search?q=${encodeURIComponent(query)}&limit=10`);
const data: SearchApiResponse = await response.json(); const data: SearchApiResponse = await response.json();
if (data.success) { if (data.success) {

View File

@@ -46,6 +46,7 @@ import {
} from 'lucide-react'; } from 'lucide-react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import axios from 'axios'; import axios from 'axios';
import { getApiBase } from '@utils/apiConfig';
import { colors, glassEffect } from '../../../theme/glassTheme'; import { colors, glassEffect } from '../../../theme/glassTheme';
import { import {
ALERT_TYPE_CONFIG, ALERT_TYPE_CONFIG,
@@ -408,7 +409,7 @@ const AlertDetailDrawer = ({ isOpen, onClose, alertData }) => {
setLoadingConcepts(prev => ({ ...prev, [conceptId]: true })); setLoadingConcepts(prev => ({ ...prev, [conceptId]: true }));
try { try {
const response = await axios.get(`/api/concept/${encodeURIComponent(conceptId)}/stocks`); const response = await axios.get(`${getApiBase()}/api/concept/${encodeURIComponent(conceptId)}/stocks`);
if (response.data?.success && response.data?.data?.stocks) { if (response.data?.success && response.data?.data?.stocks) {
setConceptStocks(prev => ({ setConceptStocks(prev => ({
...prev, ...prev,

View File

@@ -46,6 +46,7 @@ import {
} from 'lucide-react'; } from 'lucide-react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import axios from 'axios'; import axios from 'axios';
import { getApiBase } from '@utils/apiConfig';
import { import {
ALERT_TYPE_CONFIG, ALERT_TYPE_CONFIG,
METRIC_CONFIG, METRIC_CONFIG,
@@ -692,7 +693,7 @@ const ConceptAlertList = ({
}); });
try { try {
const response = await axios.get(`/api/concept/${encodeURIComponent(conceptId)}/stocks`); const response = await axios.get(`${getApiBase()}/api/concept/${encodeURIComponent(conceptId)}/stocks`);
if (response.data?.success && response.data?.data?.stocks) { if (response.data?.success && response.data?.data?.stocks) {
setConceptStocks(prev => ({ setConceptStocks(prev => ({
...prev, ...prev,

View File

@@ -4,6 +4,7 @@
*/ */
import { useState, useEffect, useCallback, useRef } from 'react'; import { useState, useEffect, useCallback, useRef } from 'react';
import { logger } from '@utils/logger'; import { logger } from '@utils/logger';
import { getApiBase } from '@utils/apiConfig';
/** /**
* @param {Date|null} selectedDate - 选中的交易日期 * @param {Date|null} selectedDate - 选中的交易日期
@@ -40,7 +41,7 @@ export const useHotspotData = (selectedDate) => {
const dateParam = selectedDate const dateParam = selectedDate
? `?date=${dateStr}` ? `?date=${dateStr}`
: ''; : '';
const response = await fetch(`/api/market/hotspot-overview${dateParam}`); const response = await fetch(`${getApiBase()}/api/market/hotspot-overview${dateParam}`);
const result = await response.json(); const result = await response.json();
if (result.success) { if (result.success) {

View File

@@ -1,5 +1,6 @@
import React, { useState, useEffect, useCallback, useRef } from 'react'; import React, { useState, useEffect, useCallback, useRef } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { getApiBase } from '@utils/apiConfig';
import { import {
Box, Box,
Container, Container,
@@ -146,7 +147,7 @@ const StockOverview = () => {
setIsSearching(true); setIsSearching(true);
try { try {
logger.debug('StockOverview', '开始搜索股票', { query }); logger.debug('StockOverview', '开始搜索股票', { query });
const response = await fetch(`/api/stocks/search?q=${encodeURIComponent(query)}&limit=10`); const response = await fetch(`${getApiBase()}/api/stocks/search?q=${encodeURIComponent(query)}&limit=10`);
const data = await response.json(); const data = await response.json();
logger.debug('StockOverview', 'API返回数据', { logger.debug('StockOverview', 'API返回数据', {
status: response.status, status: response.status,