diff --git a/frontend_vue/src/api/strategy.js b/frontend_vue/src/api/strategy.js index 6c2abae..fa96123 100644 --- a/frontend_vue/src/api/strategy.js +++ b/frontend_vue/src/api/strategy.js @@ -17,6 +17,7 @@ const api = { trades: '/api/strategies/trades', positions: '/api/strategies/positions', equityCurve: '/api/strategies/equityCurve', + logs: '/api/strategies/logs', notifications: '/api/strategies/notifications' } @@ -221,6 +222,19 @@ export function getStrategyEquityCurve (id) { }) } +/** + * 获取策略运行日志 + * @param {number} id - 策略ID + * @param {number} limit - 最大日志条数 + */ +export function getStrategyLogs (id, limit = 200) { + return request({ + url: api.logs, + method: 'get', + params: { id, limit } + }) +} + /** * Strategy signal notifications (browser channel persistence). * @param {Object} params diff --git a/frontend_vue/src/views/dashboard/index.vue b/frontend_vue/src/views/dashboard/index.vue index a6d4596..6946516 100644 --- a/frontend_vue/src/views/dashboard/index.vue +++ b/frontend_vue/src/views/dashboard/index.vue @@ -123,7 +123,7 @@ -
+
@@ -146,6 +146,24 @@
+
+
+
{{ tt('dashboard.setupGuide.title', 'Bring your first live strategy online') }}
+
{{ tt('dashboard.setupGuide.desc', 'The latest frontend adds a clearer handoff from overview into strategy management. Use this entry point to create, launch, and monitor a strategy flow faster.') }}
+
{{ tt('dashboard.setupGuide.path', 'Overview -> Strategy Manager -> Create Strategy') }}
+
+
+ + + {{ tt('dashboard.setupGuide.secondary', 'Open Strategy Manager') }} + + + + {{ tt('dashboard.setupGuide.primary', 'Create Strategy') }} + +
+
+
@@ -501,6 +519,12 @@ import { mapState } from 'vuex' export default { name: 'Dashboard', + props: { + hideSetupGuide: { + type: Boolean, + default: false + } + }, data () { return { summary: { @@ -549,6 +573,12 @@ export default { performance () { return this.summary.performance || {} }, + showSetupGuide () { + const strategyCount = Number(this.summary.indicator_strategy_count || 0) + const hasPositions = Array.isArray(this.summary.current_positions) && this.summary.current_positions.length > 0 + const hasRecentTrades = Array.isArray(this.summary.recent_trades) && this.summary.recent_trades.length > 0 + return strategyCount === 0 || (!hasPositions && !hasRecentTrades) + }, strategyStats () { return this.summary.strategy_stats || [] }, @@ -738,6 +768,16 @@ export default { if (this.hourlyChart) this.hourlyChart.dispose() }, methods: { + tt (key, fallback, params) { + const translated = this.$t(key, params) + return translated !== key ? translated : fallback + }, + goToStrategyManagement () { + this.$router.push('/trading-assistant?tab=strategy') + }, + goToStrategyCreate () { + this.$router.push('/trading-assistant?tab=strategy&mode=create') + }, async fetchData () { try { const res = await getDashboardSummary() @@ -1446,9 +1486,80 @@ export default { background: @bg-light; transition: background 0.3s; + .setup-guide-card { + display: flex; + align-items: center; + justify-content: space-between; + gap: 18px; + margin-bottom: 18px; + padding: 20px 22px; + border-radius: 24px; + border: 1px solid #dce7f3; + background: + radial-gradient(circle at top left, rgba(59, 130, 246, 0.14), transparent 36%), + radial-gradient(circle at bottom right, rgba(16, 185, 129, 0.1), transparent 34%), + linear-gradient(135deg, #ffffff 0%, #f8fbff 55%, #eef7ff 100%); + box-shadow: 0 16px 38px rgba(15, 23, 42, 0.08); + } + + .setup-guide-copy { + min-width: 0; + } + + .setup-guide-title { + color: #0f172a; + font-size: 24px; + font-weight: 700; + line-height: 1.2; + } + + .setup-guide-desc { + margin-top: 8px; + color: #475569; + font-size: 14px; + line-height: 1.7; + } + + .setup-guide-path { + margin-top: 10px; + color: #2563eb; + font-size: 12px; + font-weight: 600; + letter-spacing: 0.04em; + text-transform: uppercase; + } + + .setup-guide-actions { + display: flex; + gap: 10px; + flex-wrap: wrap; + justify-content: flex-end; + } + &.theme-dark { background: @bg-dark; + .setup-guide-card { + border-color: rgba(59, 130, 246, 0.16); + background: + radial-gradient(circle at top left, rgba(37, 99, 235, 0.24), transparent 36%), + radial-gradient(circle at bottom right, rgba(16, 185, 129, 0.12), transparent 34%), + linear-gradient(135deg, #161b22 0%, #111827 58%, #0f172a 100%); + box-shadow: 0 16px 38px rgba(0, 0, 0, 0.26); + } + + .setup-guide-title { + color: @text-primary-dark; + } + + .setup-guide-desc { + color: @text-secondary-dark; + } + + .setup-guide-path { + color: #60a5fa; + } + .kpi-card { background: @bg-card-dark; border-color: @border-dark; @@ -1563,6 +1674,24 @@ export default { margin-bottom: 20px; } + @media (max-width: 768px) { + .setup-guide-card { + flex-direction: column; + align-items: flex-start; + padding: 18px; + border-radius: 20px; + } + + .setup-guide-title { + font-size: 20px; + } + + .setup-guide-actions { + width: 100%; + justify-content: flex-start; + } + } + .kpi-card { position: relative; background: @bg-card-light; diff --git a/frontend_vue/src/views/indicator-analysis/index.vue b/frontend_vue/src/views/indicator-analysis/index.vue index e6ba7bd..b364923 100644 --- a/frontend_vue/src/views/indicator-analysis/index.vue +++ b/frontend_vue/src/views/indicator-analysis/index.vue @@ -369,6 +369,13 @@ @click.stop="handlePublishIndicator(indicator)" /> + + +
{{ indicator.description || '' }} @@ -380,6 +387,69 @@ {{ $t('dashboard.indicator.empty') }}
+ +
+
+ + + {{ $t('menu.dashboard.community') }} + +
+
+
+
+
+ + + {{ indicator.name }} + +
+ + + + + + + + + +
+
+ {{ indicator.description || '' }} +
+
+
+ + {{ $t('dashboard.indicator.emptyPurchased') }} +
+
+
@@ -3001,23 +3071,23 @@ getMarketColor, } .mobile-tab-content { - flex: 1; display: flex; flex-direction: column; - overflow: hidden; /* 不在这里滚动,让section-content滚动 */ + overflow-y: auto; + overflow-x: hidden; min-height: 0; height: 100%; width: 100%; + -webkit-overflow-scrolling: touch; } .section-content { - flex: 1; - overflow-y: auto !important; /* 只有这里滚动 */ + flex: none; + overflow: visible !important; overflow-x: hidden; padding: 12px; - min-height: 0; /* 使用flex: 1来占据剩余空间 */ - height: 100%; /* 使用100%高度,让flex生效 */ - -webkit-overflow-scrolling: touch; + min-height: auto; + height: auto; position: relative; } diff --git a/frontend_vue/src/views/trading-assistant/components/PerformanceAnalysis.vue b/frontend_vue/src/views/trading-assistant/components/PerformanceAnalysis.vue new file mode 100644 index 0000000..c376f61 --- /dev/null +++ b/frontend_vue/src/views/trading-assistant/components/PerformanceAnalysis.vue @@ -0,0 +1,485 @@ + + + + + diff --git a/frontend_vue/src/views/trading-assistant/components/PositionRecords.vue b/frontend_vue/src/views/trading-assistant/components/PositionRecords.vue index 74dbc78..2cc4f8a 100644 --- a/frontend_vue/src/views/trading-assistant/components/PositionRecords.vue +++ b/frontend_vue/src/views/trading-assistant/components/PositionRecords.vue @@ -1,5 +1,5 @@