update pay ui
This commit is contained in:
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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',
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -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',
|
||||||
|
|||||||
@@ -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'
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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}`);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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'
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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 服务器代理
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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 }),
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
Reference in New Issue
Block a user