From babc36aa4e336060bac3d510cd7fec75ed0e9895 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Tue, 20 Jan 2026 11:56:50 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BA=86=E4=B8=80=E4=BA=9Bbu?= =?UTF-8?q?g?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Backend/app.py | 6 ++--- Frontend/src/components/FundScreening.vue | 32 ++++++++++++++--------- Frontend/src/components/FundWatchlist.vue | 5 ++-- 3 files changed, 25 insertions(+), 18 deletions(-) diff --git a/Backend/app.py b/Backend/app.py index 2a7af25..76f8202 100644 --- a/Backend/app.py +++ b/Backend/app.py @@ -1605,7 +1605,7 @@ def get_available_fund_types(): if strategy == 'high_sharpe': query = query.filter( - FundRiskMetrics.sharpe_ratio_1y > 1, + FundRiskMetrics.sharpe_ratio_1y > 2, FundRiskMetrics.volatility_1y < 25 ) elif strategy == 'low_volatility': @@ -1675,7 +1675,7 @@ def query_screening_funds(): elif strategy == 'high_sharpe': query = query.filter( - FundRiskMetrics.sharpe_ratio_1y > 1, + FundRiskMetrics.sharpe_ratio_1y > 2, FundRiskMetrics.volatility_1y < 25 ) @@ -1812,7 +1812,7 @@ def get_screening_strategies(): { 'id': 'high_sharpe', 'name': '高夏普比率', - 'description': '夏普比率 > 1,单位风险收益最优', + 'description': '夏普比率 > 2,单位风险收益最优', 'tags': ['风险调整', '收益优化'] }, { diff --git a/Frontend/src/components/FundScreening.vue b/Frontend/src/components/FundScreening.vue index b718920..3e8c6cd 100644 --- a/Frontend/src/components/FundScreening.vue +++ b/Frontend/src/components/FundScreening.vue @@ -636,12 +636,12 @@ export default { { name: '偏股型', icon: '📈', - patterns: ['混合型-偏股', '混合型-灵活', '混合型-平衡', '股票型', '股票指数', '联接基金', '增强指数', '被动指数'] + patterns: ['混合型-偏股', '混合型-灵活', '混合型-平衡', '股票型', '股票指数', '指数型-股票', '联接基金', '增强指数', '被动指数', '指数-股票'] }, { name: '偏债型', icon: '📊', - patterns: ['混合型-偏债', '债券型', '债券指数', '短债', '中短债', '长债', '纯债', '可转债'] + patterns: ['混合型-偏债', '债券型', '债券指数', '指数型-固收', '短债', '中短债', '长债', '纯债', '可转债', '指数-债券'] }, { name: 'FOF', @@ -651,15 +651,25 @@ export default { { name: 'QDII', icon: '🌍', - patterns: ['QDII'] + patterns: ['QDII', '海外指数', '指数型-海外'] }, { name: '货币/其他', icon: '💰', - patterns: ['货币型', 'REITs', '商品'] + patterns: ['货币', 'REITs', '商品', '指数-其他', '指数型-其他', '其他'] } ] + // 辅助函数:确定类型的归属分类(按顺序优先匹配,避免重复) + const getTypeCategoryName = (type) => { + for (const cat of quickTypeCategories) { + if (cat.patterns.some(p => type.includes(p))) { + return cat.name + } + } + return null + } + // 切换下拉菜单 const toggleQuickDropdown = (categoryName) => { if (activeQuickDropdown.value === categoryName) { @@ -681,15 +691,14 @@ export default { // 获取分类下在可用类型中的类型 const getFilteredCategoryTypes = (category) => { - return availableTypes.value.filter(type => { - return category.patterns.some(pattern => type.includes(pattern)) - }) + return availableTypes.value.filter(type => getTypeCategoryName(type) === category.name) } // 检查分类下是否有当前选中的类型 const isCategoryTypeActive = (category) => { if (!quickTypeFilter.value) return false - return category.patterns.some(pattern => quickTypeFilter.value.includes(pattern)) + // 如果当前选中的类型属于该分类 + return getTypeCategoryName(quickTypeFilter.value) === category.name } // 检查分类下是否有可用类型 @@ -699,10 +708,7 @@ export default { // 获取未分类的类型 const uncategorizedTypes = computed(() => { - const allPatterns = quickTypeCategories.flatMap(c => c.patterns) - return availableTypes.value.filter(type => { - return !allPatterns.some(pattern => type.includes(pattern)) - }) + return availableTypes.value.filter(type => getTypeCategoryName(type) === null) }) // 分页 @@ -1928,7 +1934,7 @@ export default { .quick-tag.active { background: #667eea; border-color: #667eea; - color: white; + color: rgb(50, 53, 218); } .quick-tag.has-active { diff --git a/Frontend/src/components/FundWatchlist.vue b/Frontend/src/components/FundWatchlist.vue index ed3f71f..f776b87 100644 --- a/Frontend/src/components/FundWatchlist.vue +++ b/Frontend/src/components/FundWatchlist.vue @@ -641,14 +641,15 @@ export default { .btn-danger:hover:not(:disabled) { background: #fee2e2; } .btn-secondary { background: #f3f4f6; color: #374151; } .btn-secondary:hover { background: #e5e7eb; } -.btn-refresh { background: #ecfdf5; color: #10b981; padding: 5px 8px; } +.btn-refresh { background: #ecfdf5; color: #10b981; padding: 5px 8px; display: inline-flex; align-items: center; justify-content: center; } .btn-refresh:hover:not(:disabled) { background: #d1fae5; } .btn-primary { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; } .btn-primary:hover:not(:disabled) { opacity: 0.9; } /* 旋转动画 */ .rotating { - display: inline-block; + display: block; + transform-origin: center; animation: spin 1s linear infinite; }