Compare commits
11 Commits
a1273452bf
...
feature_bu
| Author | SHA1 | Date | |
|---|---|---|---|
| f5023d9ce6 | |||
| c589516633 | |||
| c88f13db89 | |||
| 5804aa27c4 | |||
| 413e327a19 | |||
| f9163b1228 | |||
| 193aad3458 | |||
| fff13edcdf | |||
|
|
4e9a942d66 | ||
| 0310c40323 | |||
| aed16c8c6b |
Binary file not shown.
Binary file not shown.
@@ -1030,3 +1030,51 @@ async def get_stock_intraday_statistics(
|
||||
except Exception as e:
|
||||
logger.error(f"[ClickHouse] 日内统计失败: {e}", exc_info=True)
|
||||
return {"success": False, "error": str(e)}
|
||||
|
||||
|
||||
async def get_stock_code_by_name(stock_name: str) -> Dict[str, Any]:
|
||||
"""
|
||||
根据股票名称查询股票代码
|
||||
|
||||
Args:
|
||||
stock_name: 股票名称(支持模糊匹配)
|
||||
|
||||
Returns:
|
||||
匹配的股票列表,包含代码和名称
|
||||
"""
|
||||
pool = await get_pool()
|
||||
|
||||
async with pool.acquire() as conn:
|
||||
async with conn.cursor(aiomysql.DictCursor) as cursor:
|
||||
# 使用 LIKE 进行模糊匹配
|
||||
query = """
|
||||
SELECT DISTINCT
|
||||
SECCODE as code,
|
||||
SECNAME as name,
|
||||
F030V as industry
|
||||
FROM ea_baseinfo
|
||||
WHERE SECNAME LIKE %s
|
||||
OR SECNAME = %s
|
||||
ORDER BY
|
||||
CASE WHEN SECNAME = %s THEN 0 ELSE 1 END,
|
||||
SECCODE
|
||||
LIMIT 10
|
||||
"""
|
||||
|
||||
# 精确匹配和模糊匹配
|
||||
like_pattern = f"%{stock_name}%"
|
||||
|
||||
await cursor.execute(query, (like_pattern, stock_name, stock_name))
|
||||
results = await cursor.fetchall()
|
||||
|
||||
if not results:
|
||||
return {
|
||||
"success": False,
|
||||
"error": f"未找到名称包含 '{stock_name}' 的股票"
|
||||
}
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"data": results,
|
||||
"count": len(results)
|
||||
}
|
||||
|
||||
938
mcp_server.py
938
mcp_server.py
File diff suppressed because it is too large
Load Diff
@@ -32,6 +32,8 @@ import {
|
||||
Input,
|
||||
InputGroup,
|
||||
InputRightElement,
|
||||
Checkbox,
|
||||
Link as ChakraLink,
|
||||
} from '@chakra-ui/react';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { logger } from '../../utils/logger';
|
||||
@@ -55,6 +57,12 @@ import {
|
||||
} from 'react-icons/fa';
|
||||
import { getApiBase } from '../../utils/apiConfig';
|
||||
|
||||
// 会员协议 URL 配置
|
||||
const AGREEMENT_URLS = {
|
||||
pro: 'https://valuefrontier.cn/htmls/pro-member-agreement.html',
|
||||
max: 'https://valuefrontier.cn/htmls/max-member-agreement.html',
|
||||
};
|
||||
|
||||
export default function SubscriptionContent() {
|
||||
// Auth context
|
||||
const { user } = useAuth();
|
||||
@@ -97,6 +105,9 @@ export default function SubscriptionContent() {
|
||||
const [validatingPromo, setValidatingPromo] = useState(false);
|
||||
const [priceInfo, setPriceInfo] = useState(null); // 价格信息(包含升级计算)
|
||||
|
||||
// 会员协议确认状态
|
||||
const [agreementChecked, setAgreementChecked] = useState(false);
|
||||
|
||||
// 加载订阅套餐数据
|
||||
useEffect(() => {
|
||||
fetchSubscriptionPlans();
|
||||
@@ -286,6 +297,9 @@ export default function SubscriptionContent() {
|
||||
|
||||
setSelectedPlan(plan);
|
||||
|
||||
// 切换套餐时重置协议勾选状态
|
||||
setAgreementChecked(false);
|
||||
|
||||
// 计算价格(包含升级判断)
|
||||
await calculatePrice(plan, selectedCycle, promoCodeApplied ? promoCode : null);
|
||||
|
||||
@@ -1603,11 +1617,45 @@ export default function SubscriptionContent() {
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{/* 会员协议确认 */}
|
||||
<Checkbox
|
||||
isChecked={agreementChecked}
|
||||
onChange={(e) => setAgreementChecked(e.target.checked)}
|
||||
colorScheme="green"
|
||||
size="md"
|
||||
>
|
||||
<Text fontSize="sm" color={secondaryText}>
|
||||
我已阅读并同意
|
||||
<ChakraLink
|
||||
href={AGREEMENT_URLS[selectedPlan?.name?.toLowerCase()] || AGREEMENT_URLS.pro}
|
||||
isExternal
|
||||
color="blue.500"
|
||||
textDecoration="underline"
|
||||
mx={1}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
《{selectedPlan?.name?.toLowerCase() === 'max' ? 'MAX' : 'PRO'}会员服务协议》
|
||||
</ChakraLink>
|
||||
</Text>
|
||||
</Checkbox>
|
||||
|
||||
<Button
|
||||
colorScheme="green"
|
||||
size="lg"
|
||||
leftIcon={<Icon as={FaWeixin} />}
|
||||
onClick={handleCreateOrder}
|
||||
onClick={() => {
|
||||
if (!agreementChecked) {
|
||||
toast({
|
||||
title: '请先阅读并同意会员服务协议',
|
||||
status: 'warning',
|
||||
duration: 3000,
|
||||
isClosable: true,
|
||||
position: 'top',
|
||||
});
|
||||
return;
|
||||
}
|
||||
handleCreateOrder();
|
||||
}}
|
||||
isLoading={loading}
|
||||
loadingText="创建订单中..."
|
||||
isDisabled={!selectedPlan}
|
||||
|
||||
@@ -23,6 +23,8 @@ import {
|
||||
Icon,
|
||||
Container,
|
||||
useBreakpointValue,
|
||||
Checkbox,
|
||||
Link as ChakraLink,
|
||||
} from '@chakra-ui/react';
|
||||
import {
|
||||
FaWeixin,
|
||||
@@ -46,6 +48,12 @@ import { useSubscriptionEvents } from '../../hooks/useSubscriptionEvents';
|
||||
import { subscriptionConfig, themeColors } from '../../views/Pages/Account/subscription-content';
|
||||
import { getApiBase } from '../../utils/apiConfig';
|
||||
|
||||
// 会员协议 URL 配置
|
||||
const AGREEMENT_URLS = {
|
||||
pro: 'https://valuefrontier.cn/htmls/pro-member-agreement.html',
|
||||
max: 'https://valuefrontier.cn/htmls/max-member-agreement.html',
|
||||
};
|
||||
|
||||
// 计费周期选择器组件 - 移动端垂直布局(年付在上),桌面端水平布局
|
||||
interface CycleSelectorProps {
|
||||
options: any[];
|
||||
@@ -154,6 +162,9 @@ export default function SubscriptionContentNew() {
|
||||
|
||||
const [openFaqIndex, setOpenFaqIndex] = useState(null);
|
||||
|
||||
// 会员协议确认状态
|
||||
const [agreementChecked, setAgreementChecked] = useState(false);
|
||||
|
||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||
const toast = useToast();
|
||||
|
||||
@@ -418,6 +429,10 @@ export default function SubscriptionContentNew() {
|
||||
);
|
||||
|
||||
setSelectedPlan(plan);
|
||||
|
||||
// 切换套餐时重置协议勾选状态
|
||||
setAgreementChecked(false);
|
||||
|
||||
await calculatePrice(plan, selectedCycle, promoCodeApplied ? promoCode : null);
|
||||
onOpen();
|
||||
};
|
||||
@@ -1607,6 +1622,28 @@ export default function SubscriptionContentNew() {
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{/* 会员协议确认 */}
|
||||
<Checkbox
|
||||
isChecked={agreementChecked}
|
||||
onChange={(e) => setAgreementChecked(e.target.checked)}
|
||||
colorScheme="green"
|
||||
size="md"
|
||||
>
|
||||
<Text fontSize="sm" color="rgba(255, 255, 255, 0.7)">
|
||||
我已阅读并同意
|
||||
<ChakraLink
|
||||
href={AGREEMENT_URLS[(selectedPlan as any)?.name?.toLowerCase()] || AGREEMENT_URLS.pro}
|
||||
isExternal
|
||||
color="#3182CE"
|
||||
textDecoration="underline"
|
||||
mx={1}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
《{(selectedPlan as any)?.name?.toLowerCase() === 'max' ? 'MAX' : 'PRO'}会员服务协议》
|
||||
</ChakraLink>
|
||||
</Text>
|
||||
</Checkbox>
|
||||
|
||||
<Button
|
||||
w="full"
|
||||
size="lg"
|
||||
@@ -1615,7 +1652,19 @@ export default function SubscriptionContentNew() {
|
||||
: 'linear-gradient(135deg, #07C160, #059048)'}
|
||||
color="white"
|
||||
fontWeight="bold"
|
||||
onClick={handleCreatePaymentOrder}
|
||||
onClick={() => {
|
||||
if (!agreementChecked) {
|
||||
toast({
|
||||
title: '请先阅读并同意会员服务协议',
|
||||
status: 'warning',
|
||||
duration: 3000,
|
||||
isClosable: true,
|
||||
position: 'top',
|
||||
});
|
||||
return;
|
||||
}
|
||||
handleCreatePaymentOrder();
|
||||
}}
|
||||
isLoading={loading}
|
||||
isDisabled={!selectedPlan}
|
||||
leftIcon={paymentMethod === 'alipay'
|
||||
|
||||
Reference in New Issue
Block a user