Files
stock/stock-html/templates/index.html
T
selfrelease 79e869eeda fix: 修复外部因素数据源 - 北向资金改为南向资金,修复P0-P7全部外部因素
- P0资金面:DB数据过期时用麦蕊API获取资金流向
- P1市场情绪:去掉turnover字段依赖(DB无此字段)
- P2南向资金:北向实时数据已停公布,改用南向资金(港股通)替代
- P3美股:用腾讯财经API替代失效的AKShare接口
- P4大宗商品:用腾讯财经API替代,修复var_name解析
- P7汇率:用新浪财经API替代失效的AKShare接口
- 修复评分详情API技术得分硬编码问题
- 前端传入tech_score参数确保明细与列表分数一致
2026-07-18 16:45:58 +08:00

2305 lines
167 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
<title>股票投资</title>
<!-- PWA 全屏显示配置 -->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="apple-mobile-web-app-title" content="股票投资">
<meta name="mobile-web-app-capable" content="yes">
<meta name="theme-color" content="#0a0a0a">
<link rel="manifest" href="/static/manifest.json">
<!-- 添加到主屏幕图标 -->
<link rel="apple-touch-icon" href="/static/icon.svg">
<style>[v-cloak]{display:none!important}</style>
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>📈</text></svg>">
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<link rel="stylesheet" href="/static/css/base.css?v=20260719v2">
<link rel="stylesheet" href="/static/css/components.css?v=20260718v1">
<link rel="stylesheet" href="/static/css/auth.css?v=20260718v1">
<link rel="stylesheet" href="/static/css/pages.css?v=20260719v2">
<link rel="stylesheet" href="/static/css/scan.css?v=20260719v5">
<link rel="stylesheet" href="/static/css/responsive.css?v=20260719v1">
</head>
<body>
{% raw %}
<div id="app" v-cloak>
<!-- 全局 Toast 提示 -->
<transition name="toast-fade">
<div v-if="toastVisible" :class="['toast-container', toastType]" role="alert" aria-live="assertive">
<span class="toast-icon">
{{ toastType === 'success' ? '✓' : toastType === 'error' ? '✕' : toastType === 'warning' ? '⚠' : '' }}
</span>
<span class="toast-message">{{ toastMessage }}</span>
</div>
</transition>
<!-- 确认对话框 -->
<transition name="modal-fade">
<div v-if="confirmVisible" class="confirm-overlay" @click.self="handleConfirmCancel" role="dialog" aria-modal="true" aria-label="确认操作">
<div class="confirm-dialog">
<div class="confirm-message">{{ confirmMessage }}</div>
<div class="confirm-buttons">
<button type="button" class="confirm-btn cancel" @click="handleConfirmCancel">取消</button>
<button type="button" class="confirm-btn ok" @click="handleConfirmOk">确定</button>
</div>
</div>
</div>
</transition>
<!-- 智能执行结果模态框 -->
<transition name="modal-fade">
<div v-if="smartResultVisible" class="modal-overlay" @click.self="smartResultVisible = false">
<div class="smart-result-modal">
<div class="smart-result-header">
<div class="smart-result-title">
<span class="smart-result-icon" :class="smartResultData?.type === 'traded' ? 'success' : 'warning'">
{{ smartResultData?.type === 'traded' ? '✅' : '📋' }}
</span>
{{ smartResultData?.title || '执行结果' }}
</div>
<button type="button" class="modal-close-btn" @click="smartResultVisible = false">×</button>
</div>
<div class="smart-result-body" v-if="smartResultData">
<!-- 算法标识 -->
<div class="smart-result-algo">
<span class="algo-badge">{{ smartResultData.algo }}</span>
<span class="result-summary">{{ smartResultData.summary }}</span>
</div>
<!-- 交易结果列表 -->
<div v-if="smartResultData.results && smartResultData.results.length > 0" class="smart-result-trades">
<div class="result-section-title">📈 交易执行</div>
<div v-for="(r, i) in smartResultData.results" :key="i" class="result-trade-item" :class="r.type">
<span class="trade-type-tag" :class="r.type">{{ r.type === 'buy' ? '买入' : '卖出' }}</span>
<span class="trade-stock">{{ r.stock_code }} {{ r.stock_name }}</span>
<span class="trade-detail">¥{{ r.price?.toFixed(2) }} × {{ r.shares }}股</span>
<span v-if="r.fee > 0" class="trade-fee">手续费¥{{ r.fee?.toFixed(2) }}</span>
</div>
</div>
<!-- 详细原因 -->
<div v-if="smartResultData.reasons && smartResultData.reasons.length > 0" class="smart-result-reasons">
<div class="result-section-title">{{ smartResultData.type === 'no_trade' ? '📊 分析详情' : '💡 附加信息' }}</div>
<div v-for="(reason, i) in smartResultData.reasons" :key="i" class="result-reason-item" :class="getReasonClass(reason)">
<span class="reason-icon">{{ getReasonIcon(reason) }}</span>
<span class="reason-text">{{ reason }}</span>
</div>
</div>
<!-- 手续费摘要 -->
<div v-if="smartResultData.fees > 0" class="smart-result-fees">
<span>💰 总手续费: ¥{{ smartResultData.fees.toFixed(2) }}</span>
</div>
<!-- 可用资金 -->
<div v-if="smartResultData.availableCash > 0" class="smart-result-cash">
<span>💵 当前可用资金: ¥{{ smartResultData.availableCash.toLocaleString('zh-CN', {minimumFractionDigits: 2}) }}</span>
</div>
</div>
<div class="smart-result-footer">
<button type="button" class="confirm-btn ok" @click="smartResultVisible = false">我知道了</button>
</div>
</div>
</div>
</transition>
<!-- 登录弹窗 -->
<transition name="modal-fade">
<div v-if="showLoginModal" class="modal-overlay" @click.self="showLoginModal = false" role="dialog" aria-modal="true" aria-label="登录">
<div class="login-modal">
<div class="login-tabs">
<button type="button" :class="['login-tab', { active: !isRegister }]" @click="isRegister = false; loginError = ''">登录</button>
<button type="button" :class="['login-tab', { active: isRegister }]" @click="isRegister = true; loginError = ''">注册</button>
<button type="button" class="modal-close-btn" @click="showLoginModal = false">×</button>
</div>
<div class="login-body">
<div class="login-field">
<label>邮箱</label>
<input v-model="loginForm.email" type="email" placeholder="请输入邮箱地址" @keyup.enter="handleLogin">
</div>
<div class="login-field">
<label>密码</label>
<input v-model="loginForm.password" type="password" :placeholder="isRegister ? '设置密码(至少6位)' : '请输入密码'" @keyup.enter="handleLogin">
</div>
<div v-if="loginError" class="login-error">{{ loginError }}</div>
<button type="button" class="login-submit" @click="handleLogin" :disabled="loginLoading">
{{ loginLoading ? '处理中...' : (isRegister ? '注册' : '登录') }}
</button>
</div>
</div>
</div>
</transition>
<div class="container">
<!-- 未登录状态:只显示登录界面 -->
<div v-if="!currentUser && !checkingAuth" class="login-page">
<div class="login-page-header">
<svg class="login-icon" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8 36L16 26L22 32L32 18L40 28" stroke="url(#grad1)" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M34 18H40V24" stroke="url(#grad1)" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
<circle cx="16" cy="26" r="3" fill="#00ff88"/>
<circle cx="22" cy="32" r="3" fill="#00ff88"/>
<circle cx="32" cy="18" r="3" fill="#00ff88"/>
<defs>
<linearGradient id="grad1" x1="8" y1="18" x2="40" y2="36" gradientUnits="userSpaceOnUse">
<stop offset="0%" stop-color="#00ff88"/>
<stop offset="100%" stop-color="#00ccff"/>
</linearGradient>
</defs>
</svg>
<h1>股票投资</h1>
<p>请登录以访问您的投资数据</p>
</div>
<div class="login-modal login-modal-inline">
<div class="login-tabs">
<button type="button" :class="['login-tab', { active: !isRegister }]" @click="isRegister = false; loginError = ''">登录</button>
<button type="button" :class="['login-tab', { active: isRegister }]" @click="isRegister = true; loginError = ''">注册</button>
</div>
<div class="login-body">
<div class="login-field">
<label>邮箱</label>
<input v-model="loginForm.email" type="email" placeholder="请输入邮箱地址" @keyup.enter="handleLogin">
</div>
<div class="login-field">
<label>密码</label>
<input v-model="loginForm.password" type="password" :placeholder="isRegister ? '设置密码(至少6位)' : '请输入密码'" @keyup.enter="handleLogin">
</div>
<div v-if="loginError" class="login-error">{{ loginError }}</div>
<button type="button" class="login-submit" @click="handleLogin" :disabled="loginLoading">
{{ loginLoading ? '处理中...' : (isRegister ? '注册' : '登录') }}
</button>
</div>
</div>
</div>
<!-- 检查登录状态中 -->
<div v-else-if="checkingAuth" class="loading-auth">
<p>正在加载...</p>
</div>
<!-- 已登录状态:显示主内容 -->
<template v-else>
<div class="title-bar">
<div class="title-left">
<h1>股票投资 <span class="main-title-date">{{ todayDate }}<span v-if="dataLatestDate && dataLatestDate !== todayDate">{{ dataLatestDate }}</span></span> <span :class="['market-status', marketStatus.isOpen ? 'open' : 'closed']">{{ marketStatus.text }}</span></h1>
<div class="current-model">策略: 交易信号实战体系</div>
</div>
<div class="user-info">
<span class="username" @click="showPasswordModal = true" class="cursor-pointer">{{ currentUser?.username }}</span>
<button type="button" class="logout-btn" @click="handleLogout">退出</button>
</div>
</div>
<!-- 顶部导航 -->
<div class="nav-tabs nav-tabs-compact" role="tablist">
<button type="button" :class="['nav-tab', { active: activeTab === 'alerts' }]" role="tab" :aria-selected="activeTab === 'alerts'" @click="activeTab = 'alerts'">提醒</button>
<button type="button" :class="['nav-tab', { active: activeTab === 'trades' }]" role="tab" :aria-selected="activeTab === 'trades'" @click="activeTab = 'trades'; loadTrades()">交易</button>
<button type="button" :class="['nav-tab', { active: activeTab === 'analysis' }]" role="tab" :aria-selected="activeTab === 'analysis'" @click="activeTab = 'analysis'; if (analysisSubTab === 'scan') fetchFullScanResults(1)">分析</button>
<button type="button" :class="['nav-tab', { active: activeTab === 'model' }]" role="tab" :aria-selected="activeTab === 'model'" @click="activeTab = 'model'">模型</button>
</div>
<!-- 提醒页面 -->
<div v-show="activeTab === 'alerts'">
<!-- 信号汇总(始终显示在顶部) -->
<div class="alerts-summary top-summary">
<div class="summary-row">
<span class="summary-label">持有</span>
<span class="summary-value">{{ holdingStocks.length }}</span>
</div>
<div class="summary-row">
<span class="summary-label">关注</span>
<span class="summary-value">{{ watchingStocks.length }}</span>
</div>
<div class="summary-row buy">
<span class="summary-label">建议买入</span>
<span class="summary-value">{{ buyAlerts.length + holdingAlerts.filter(a => a.signalType === 'buy').length }}</span>
</div>
<div class="summary-row sell">
<span class="summary-label">建议卖出</span>
<span class="summary-value">{{ sellAlerts.length + holdingAlerts.filter(a => a.signalType === 'sell').length }}</span>
</div>
<button type="button" class="refresh-btn-inline" @click="refreshAlerts(true)" :disabled="alertsLoading">
{{ alertsLoading ? (alertsProgress.total > 0 ? `${alertsProgress.current}/${alertsProgress.total}` : '加载中...') : '刷新' }}
</button>
</div>
<!-- 子导航 -->
<div class="sub-tabs">
<button type="button" :class="['sub-tab', { active: alertSubTab === 'holding' }]" @click="alertSubTab = 'holding'">
持有 <span v-if="holdingStocks.length" class="sub-badge">{{ holdingStocks.length }}</span>
</button>
<button type="button" :class="['sub-tab', { active: alertSubTab === 'watching' }]" @click="alertSubTab = 'watching'">
关注 <span v-if="watchingStocks.length" class="sub-badge">{{ watchingStocks.length }}</span>
</button>
<button type="button" class="add-watch-btn" @click="showAddWatch = !showAddWatch" title="添加关注">+</button>
</div>
<!-- 添加关注输入框 -->
<div v-if="showAddWatch" class="add-watch-input">
<input v-model="newWatchCode" type="text" placeholder="输入股票代码" maxlength="6" @keyup.enter="addToWatch">
<button type="button" @click="addToWatch" :disabled="!newWatchCode || newWatchCode.length < 6">添加</button>
</div>
<div v-if="alertsLoading" class="loading">
<p>正在分析股票...</p>
</div>
<!-- 持有列表 -->
<div v-else-if="alertSubTab === 'holding'">
<div v-if="holdingStocks.length === 0" class="no-signal-tip">
暂无持有股票<br>在交易中记录买入后自动添加到持有列表
</div>
<div v-else>
<!-- 卖出信号(持有的股票出现卖出信号需要优先关注) -->
<div v-if="holdingAlerts.filter(a => a.signalType === 'sell').length > 0" class="alert-section">
<h4 class="section-title sell">卖出信号</h4>
<div v-for="alert in holdingAlerts.filter(a => a.signalType === 'sell')" :key="alert.code" class="alert-card sell" role="button" tabindex="0" @click="loadFundamental(alert.code, alert.name)" @keyup.enter="loadFundamental(alert.code, alert.name)">
<div class="alert-header">
<span class="alert-code">{{ alert.code }}</span>
<span class="alert-name">{{ alert.name }}</span>
</div>
<div class="alert-prices-dual">
<div class="price-col">
<span class="price-label">实时</span>
<span class="alert-price" v-if="alert.price">¥{{ alert.price.toFixed(2) }}</span>
<span class="alert-change" :class="alert.changePct >= 0 ? 'up' : 'down'" v-if="alert.changePct != null">{{ alert.changePct >= 0 ? '+' : '' }}{{ alert.changePct.toFixed(2) }}%</span>
</div>
<div class="price-col scan">
<span class="price-label">扫描</span>
<span class="alert-price" v-if="alert.scanPrice">¥{{ alert.scanPrice.toFixed(2) }}</span>
<span class="alert-change" :class="alert.scanChangePct >= 0 ? 'up' : 'down'" v-if="alert.scanChangePct != null">{{ alert.scanChangePct >= 0 ? '+' : '' }}{{ alert.scanChangePct.toFixed(2) }}%</span>
</div>
</div>
<div class="alert-signals" v-if="alert.triggeredSignals && alert.triggeredSignals.length">
<span v-for="sig in alert.triggeredSignals" :key="sig" class="alert-sig-tag">{{ sig }}</span>
</div>
<div class="alert-bottom">
<div class="alert-desc">{{ alert.reason }}</div>
<span class="recommend-rate sell">{{ alert.recommendRate }}%</span>
<button type="button" class="alert-action-btn sell" @click.stop="quickTradeFromAlert(alert, 'sell')">卖出</button>
</div>
</div>
</div>
<!-- 持有正向信号(加仓/持有) -->
<div v-if="holdingAlerts.filter(a => a.signalType === 'buy').length > 0" class="alert-section">
<h4 class="section-title buy">正向信号</h4>
<div v-for="alert in holdingAlerts.filter(a => a.signalType === 'buy')" :key="alert.code"
class="alert-card" :class="alert.recommendText === '加仓' ? 'buy' : 'hold'" role="button" tabindex="0" @click="loadFundamental(alert.code, alert.name)" @keyup.enter="loadFundamental(alert.code, alert.name)">
<div class="alert-header">
<span class="alert-code">{{ alert.code }}</span>
<span class="alert-name">{{ alert.name }}</span>
<span class="alert-rec-tag" :class="alert.recommendText === '加仓' ? 'tag-add' : 'tag-hold'">{{ alert.recommendText || '持有' }}</span>
</div>
<div class="alert-prices-dual">
<div class="price-col">
<span class="price-label">实时</span>
<span class="alert-price" v-if="alert.price">¥{{ alert.price.toFixed(2) }}</span>
<span class="alert-change" :class="alert.changePct >= 0 ? 'up' : 'down'" v-if="alert.changePct != null">{{ alert.changePct >= 0 ? '+' : '' }}{{ alert.changePct.toFixed(2) }}%</span>
</div>
<div class="price-col scan">
<span class="price-label">扫描</span>
<span class="alert-price" v-if="alert.scanPrice">¥{{ alert.scanPrice.toFixed(2) }}</span>
<span class="alert-change" :class="alert.scanChangePct >= 0 ? 'up' : 'down'" v-if="alert.scanChangePct != null">{{ alert.scanChangePct >= 0 ? '+' : '' }}{{ alert.scanChangePct.toFixed(2) }}%</span>
</div>
</div>
<div class="alert-signals" v-if="alert.triggeredSignals && alert.triggeredSignals.length">
<span v-for="sig in alert.triggeredSignals" :key="sig" class="alert-sig-tag">{{ sig }}</span>
</div>
<div class="alert-bottom">
<div class="alert-desc">{{ alert.reason }}</div>
<span class="recommend-rate" :class="alert.recommendText === '加仓' ? 'buy' : 'hold'">{{ alert.recommendRate }}%</span>
<button type="button"v-if="alert.recommendText === '加仓'" class="alert-action-btn buy" @click.stop="quickTradeFromAlert(alert, 'buy')">加仓</button>
</div>
</div>
</div>
<!-- 观望(持有的股票无明确信号) -->
<div v-if="holdingAlerts.filter(a => a.signalType === 'watch').length > 0" class="alert-section">
<h4 class="section-title watch">持有观望</h4>
<div v-for="alert in holdingAlerts.filter(a => a.signalType === 'watch')" :key="alert.code" class="alert-card watch" role="button" tabindex="0" @click="loadFundamental(alert.code, alert.name)" @keyup.enter="loadFundamental(alert.code, alert.name)">
<div class="alert-header">
<span class="alert-code">{{ alert.code }}</span>
<span class="alert-name">{{ alert.name }}</span>
</div>
<div class="alert-prices-dual">
<div class="price-col">
<span class="price-label">实时</span>
<span class="alert-price" v-if="alert.price">¥{{ alert.price.toFixed(2) }}</span>
<span class="alert-change" :class="alert.changePct >= 0 ? 'up' : 'down'" v-if="alert.changePct != null">{{ alert.changePct >= 0 ? '+' : '' }}{{ alert.changePct.toFixed(2) }}%</span>
</div>
<div class="price-col scan">
<span class="price-label">扫描</span>
<span class="alert-price" v-if="alert.scanPrice">¥{{ alert.scanPrice.toFixed(2) }}</span>
<span class="alert-change" :class="alert.scanChangePct >= 0 ? 'up' : 'down'" v-if="alert.scanChangePct != null">{{ alert.scanChangePct >= 0 ? '+' : '' }}{{ alert.scanChangePct.toFixed(2) }}%</span>
</div>
</div>
<div class="alert-signals" v-if="alert.triggeredSignals && alert.triggeredSignals.length">
<span v-for="sig in alert.triggeredSignals" :key="sig" class="alert-sig-tag">{{ sig }}</span>
</div>
<div class="alert-desc" v-if="alert.reason">{{ alert.reason }}</div>
</div>
</div>
</div>
</div>
<!-- 关注列表 -->
<div v-else-if="alertSubTab === 'watching'">
<div v-if="watchingStocks.length === 0" class="no-signal-tip">
暂无关注股票<br>请先在"分析"页面查询股票后自动添加到关注列表
</div>
<div v-else>
<!-- 买入提醒列表 -->
<div v-if="buyAlerts.length > 0" class="alert-section">
<h4 class="section-title buy">买入信号</h4>
<div v-for="alert in buyAlerts" :key="alert.code" class="alert-card buy" role="button" tabindex="0" @click="loadFundamental(alert.code, alert.name)" @keyup.enter="loadFundamental(alert.code, alert.name)">
<div class="alert-header">
<span class="alert-code">{{ alert.code }}</span>
<span class="alert-name">{{ alert.name }}</span>
<span class="alert-remove" @click.stop="removeFromWatch(alert.code)">×</span>
</div>
<div class="alert-prices-dual">
<div class="price-col">
<span class="price-label">实时</span>
<span class="alert-price" v-if="alert.price">¥{{ alert.price.toFixed(2) }}</span>
<span class="alert-change" :class="alert.changePct >= 0 ? 'up' : 'down'" v-if="alert.changePct != null">{{ alert.changePct >= 0 ? '+' : '' }}{{ alert.changePct.toFixed(2) }}%</span>
</div>
<div class="price-col scan">
<span class="price-label">扫描</span>
<span class="alert-price" v-if="alert.scanPrice">¥{{ alert.scanPrice.toFixed(2) }}</span>
<span class="alert-change" :class="alert.scanChangePct >= 0 ? 'up' : 'down'" v-if="alert.scanChangePct != null">{{ alert.scanChangePct >= 0 ? '+' : '' }}{{ alert.scanChangePct.toFixed(2) }}%</span>
</div>
</div>
<div class="alert-signals" v-if="alert.triggeredSignals && alert.triggeredSignals.length">
<span v-for="sig in alert.triggeredSignals" :key="sig" class="alert-sig-tag">{{ sig }}</span>
</div>
<div class="alert-bottom">
<div class="alert-desc">{{ alert.reason }}</div>
<div class="alert-desc holding-note" v-if="alert.holdingNote">{{ alert.holdingNote }}</div>
<span class="recommend-rate buy">{{ alert.recommendRate }}%</span>
<button type="button" class="alert-action-btn buy" @click.stop="quickTradeFromAlert(alert, 'buy')">买入</button>
</div>
</div>
</div>
<!-- 卖出提醒列表 -->
<div v-if="sellAlerts.length > 0" class="alert-section">
<h4 class="section-title sell">卖出信号</h4>
<div v-for="alert in sellAlerts" :key="alert.code" class="alert-card sell" role="button" tabindex="0" @click="loadFundamental(alert.code, alert.name)" @keyup.enter="loadFundamental(alert.code, alert.name)">
<div class="alert-header">
<span class="alert-code">{{ alert.code }}</span>
<span class="alert-name">{{ alert.name }}</span>
<span class="alert-remove" @click.stop="removeFromWatch(alert.code)">×</span>
</div>
<div class="alert-prices-dual">
<div class="price-col">
<span class="price-label">实时</span>
<span class="alert-price" v-if="alert.price">¥{{ alert.price.toFixed(2) }}</span>
<span class="alert-change" :class="alert.changePct >= 0 ? 'up' : 'down'" v-if="alert.changePct != null">{{ alert.changePct >= 0 ? '+' : '' }}{{ alert.changePct.toFixed(2) }}%</span>
</div>
<div class="price-col scan">
<span class="price-label">扫描</span>
<span class="alert-price" v-if="alert.scanPrice">¥{{ alert.scanPrice.toFixed(2) }}</span>
<span class="alert-change" :class="alert.scanChangePct >= 0 ? 'up' : 'down'" v-if="alert.scanChangePct != null">{{ alert.scanChangePct >= 0 ? '+' : '' }}{{ alert.scanChangePct.toFixed(2) }}%</span>
</div>
</div>
<div class="alert-signals" v-if="alert.triggeredSignals && alert.triggeredSignals.length">
<span v-for="sig in alert.triggeredSignals" :key="sig" class="alert-sig-tag">{{ sig }}</span>
</div>
<div class="alert-bottom">
<div class="alert-desc">{{ alert.reason }}</div>
<span class="recommend-rate sell">{{ alert.recommendRate }}%</span>
<button type="button" class="alert-action-btn sell" @click.stop="quickTradeFromAlert(alert, 'sell')">卖出</button>
</div>
</div>
</div>
<!-- 观望列表 -->
<div v-if="watchAlerts.length > 0" class="alert-section">
<h4 class="section-title watch">观望</h4>
<div v-for="alert in watchAlerts" :key="alert.code" class="alert-card watch" role="button" tabindex="0" @click="loadFundamental(alert.code, alert.name)" @keyup.enter="loadFundamental(alert.code, alert.name)">
<div class="alert-header">
<span class="alert-code">{{ alert.code }}</span>
<span class="alert-name">{{ alert.name }}</span>
<span class="alert-remove" @click.stop="removeFromWatch(alert.code)">×</span>
</div>
<div class="alert-prices-dual">
<div class="price-col">
<span class="price-label">实时</span>
<span class="alert-price" v-if="alert.price">¥{{ alert.price.toFixed(2) }}</span>
<span class="alert-change" :class="alert.changePct >= 0 ? 'up' : 'down'" v-if="alert.changePct != null">{{ alert.changePct >= 0 ? '+' : '' }}{{ alert.changePct.toFixed(2) }}%</span>
</div>
<div class="price-col scan">
<span class="price-label">扫描</span>
<span class="alert-price" v-if="alert.scanPrice">¥{{ alert.scanPrice.toFixed(2) }}</span>
<span class="alert-change" :class="alert.scanChangePct >= 0 ? 'up' : 'down'" v-if="alert.scanChangePct != null">{{ alert.scanChangePct >= 0 ? '+' : '' }}{{ alert.scanChangePct.toFixed(2) }}%</span>
</div>
</div>
<div class="alert-signals" v-if="alert.triggeredSignals && alert.triggeredSignals.length">
<span v-for="sig in alert.triggeredSignals" :key="sig" class="alert-sig-tag">{{ sig }}</span>
</div>
<div class="alert-desc" v-if="alert.reason && alert.reason !== '无核心信号触发'">{{ alert.reason }}</div>
</div>
</div>
</div><!-- v-else 关注内容结束 -->
</div><!-- 关注页面结束 -->
</div><!-- 提醒页面结束 -->
<!-- 基本面信息弹窗 -->
<div v-if="showFundamentalModal" class="modal-overlay" @click.self="showFundamentalModal = false">
<div class="modal-content fundamental-modal">
<div class="fundamental-header">
<h3>{{ fundamentalData?.stock_name || '股票' }} 基本面</h3>
<span class="fundamental-code">{{ fundamentalData?.stock_code }}</span>
<button type="button" class="modal-close" @click="showFundamentalModal = false">×</button>
</div>
<div v-if="fundamentalData" class="fundamental-actions">
<button type="button" v-if="!searchHistory.some(h => h.code === fundamentalData.stock_code)"
class="watch-btn add"
@click="addToWatchFromFundamental">
★ 添加关注
</button>
<button type="button" v-else
class="watch-btn remove"
@click="removeFromWatchFromFundamental">
☆ 取消关注
</button>
<button type="button" class="ai-analyze-btn"
@click="aiAnalyze(fundamentalData.stock_code, fundamentalData.stock_name)"
:disabled="aiAnalyzing">
{{ aiAnalyzing ? '分析中...' : 'AI分析' }}
</button>
</div>
<!-- AI分析结果(流式) -->
<div v-if="aiAnalysisResult || aiAnalyzing" class="ai-analysis-section">
<h4 class="section-title">AI分析</h4>
<!-- 思考过程(可折叠) -->
<div v-if="aiReasoningResult" class="ai-reasoning-section">
<div class="ai-reasoning-header" @click="aiReasoningExpanded = !aiReasoningExpanded">
<span>💭 思考过程</span>
<span class="expand-icon">{{ aiReasoningExpanded ? '▼' : '▶' }}</span>
</div>
<div v-show="aiReasoningExpanded" class="ai-reasoning-content">
{{ aiReasoningResult }}
</div>
</div>
<div class="ai-analysis-content" v-html="formatAiAnalysis(aiAnalysisResult)"></div>
<!-- 加载指示器 -->
<div v-if="aiAnalyzing" class="ai-loading-indicator">
<span class="loading-dot"></span> AI正在分析中...
</div>
<button type="button" v-if="!aiAnalyzing" class="ai-close-btn" @click="aiAnalysisResult = ''; aiReasoningResult = ''">关闭</button>
</div>
<div v-if="fundamentalLoading" class="fundamental-loading">
加载中...
</div>
<div v-else-if="fundamentalData" class="fundamental-body">
<!-- 交易信号状态 -->
<div class="fundamental-section signal-section" v-if="fundamentalData.signal_data">
<h4>🎯 交易信号 <span class="signal-count">触发 {{ fundamentalData.signal_data.triggered_count }}/7</span></h4>
<div class="signal-grid">
<div v-for="sig in fundamentalData.signal_data.signal_status" :key="sig.name"
class="signal-chip" :class="sig.triggered ? 'triggered' : 'inactive'">
<span class="signal-dot" :class="sig.triggered ? 'on' : 'off'"></span>
{{ sig.name }}
</div>
</div>
<div class="signal-summary" v-if="fundamentalData.signal_data.triggered_count >= 3">
<span class="signal-strong">⚡ 多信号共振({{ fundamentalData.signal_data.triggered_count }}个信号触发),关注度较高</span>
</div>
<div class="signal-summary" v-else-if="fundamentalData.signal_data.triggered_count >= 1">
<span class="signal-normal">📊 有信号触发,可结合基本面综合判断</span>
</div>
<div class="signal-summary" v-else>
<span class="signal-none">⏸ 暂无信号触发</span>
</div>
</div>
<!-- 估值指标 - 只有有数据时才显示整个区块 -->
<div class="fundamental-section" v-if="fundamentalData.pe_ttm || fundamentalData.pb || fundamentalData.roe">
<h4>📊 估值指标</h4>
<div class="fundamental-grid">
<div class="fundamental-item" v-if="fundamentalData.pe_ttm">
<span class="label">市盈率(动)</span>
<span class="value">{{ typeof fundamentalData.pe_ttm === 'number' ? fundamentalData.pe_ttm.toFixed(2) : fundamentalData.pe_ttm }}</span>
</div>
<div class="fundamental-item" v-if="fundamentalData.pb">
<span class="label">市净率</span>
<span class="value">{{ typeof fundamentalData.pb === 'number' ? fundamentalData.pb.toFixed(2) : fundamentalData.pb }}</span>
</div>
<div class="fundamental-item" v-if="fundamentalData.roe">
<span class="label">ROE</span>
<span class="value">{{ typeof fundamentalData.roe === 'number' ? fundamentalData.roe.toFixed(2) + '%' : fundamentalData.roe }}</span>
</div>
</div>
</div>
<!-- 市值规模 - 只有有数据时才显示整个区块 -->
<div class="fundamental-section" v-if="fundamentalData.total_market_cap || fundamentalData.circulating_market_cap || fundamentalData.industry">
<h4>💰 市值规模</h4>
<div class="fundamental-grid">
<div class="fundamental-item" v-if="fundamentalData.total_market_cap">
<span class="label">总市值</span>
<span class="value">{{ formatMarketCap(fundamentalData.total_market_cap) }}</span>
</div>
<div class="fundamental-item" v-if="fundamentalData.circulating_market_cap">
<span class="label">流通市值</span>
<span class="value">{{ formatMarketCap(fundamentalData.circulating_market_cap) }}</span>
</div>
<div class="fundamental-item" v-if="fundamentalData.industry">
<span class="label">行业</span>
<span class="value">{{ fundamentalData.industry }}</span>
</div>
</div>
</div>
<!-- 成长性 - 只有有数据时才显示整个区块 -->
<div class="fundamental-section" v-if="fundamentalData.revenue_yoy || fundamentalData.profit_yoy || fundamentalData.gross_margin">
<h4>📈 成长性</h4>
<div class="fundamental-grid">
<div class="fundamental-item" v-if="fundamentalData.revenue_yoy">
<span class="label">营收同比</span>
<span class="value" :class="fundamentalData.revenue_yoy >= 0 ? 'up' : 'down'">
{{ typeof fundamentalData.revenue_yoy === 'number' ? (fundamentalData.revenue_yoy >= 0 ? '+' : '') + fundamentalData.revenue_yoy.toFixed(2) + '%' : fundamentalData.revenue_yoy }}
</span>
</div>
<div class="fundamental-item" v-if="fundamentalData.profit_yoy">
<span class="label">净利润同比</span>
<span class="value" :class="fundamentalData.profit_yoy >= 0 ? 'up' : 'down'">
{{ typeof fundamentalData.profit_yoy === 'number' ? (fundamentalData.profit_yoy >= 0 ? '+' : '') + fundamentalData.profit_yoy.toFixed(2) + '%' : fundamentalData.profit_yoy }}
</span>
</div>
<div class="fundamental-item" v-if="fundamentalData.gross_margin">
<span class="label">毛利率</span>
<span class="value">{{ typeof fundamentalData.gross_margin === 'number' ? fundamentalData.gross_margin.toFixed(2) + '%' : fundamentalData.gross_margin }}</span>
</div>
</div>
</div>
<!-- 每股指标 - 只有有数据时才显示整个区块 -->
<div class="fundamental-section" v-if="fundamentalData.eps || fundamentalData.bps || fundamentalData.net_margin">
<h4>📋 每股指标</h4>
<div class="fundamental-grid">
<div class="fundamental-item" v-if="fundamentalData.eps">
<span class="label">每股收益</span>
<span class="value">{{ typeof fundamentalData.eps === 'number' ? fundamentalData.eps.toFixed(4) + '元' : fundamentalData.eps }}</span>
</div>
<div class="fundamental-item" v-if="fundamentalData.bps">
<span class="label">每股净资产</span>
<span class="value">{{ typeof fundamentalData.bps === 'number' ? fundamentalData.bps.toFixed(2) + '元' : fundamentalData.bps }}</span>
</div>
<div class="fundamental-item" v-if="fundamentalData.net_margin">
<span class="label">净利率</span>
<span class="value">{{ typeof fundamentalData.net_margin === 'number' ? fundamentalData.net_margin.toFixed(2) + '%' : fundamentalData.net_margin }}</span>
</div>
</div>
</div>
<div class="fundamental-section" v-if="fundamentalData.fund_flow_3days && fundamentalData.fund_flow_3days.length > 0">
<h4>💰 近3日资金流向</h4>
<div class="fundflow-table">
<div class="fundflow-header">
<span class="ff-col">日期</span>
<span class="ff-col">超大单</span>
<span class="ff-col">主力</span>
<span class="ff-col">涨跌</span>
</div>
<div v-for="flow in fundamentalData.fund_flow_3days" :key="flow.date" class="fundflow-row">
<span class="ff-col date">{{ flow.date }}</span>
<span class="ff-col" :class="flow.super_pct >= 0 ? 'up' : 'down'">
{{ flow.super_pct >= 0 ? '+' : '' }}{{ flow.super_pct.toFixed(1) }}%
</span>
<span class="ff-col" :class="flow.main_pct >= 0 ? 'up' : 'down'">
{{ flow.main_pct >= 0 ? '+' : '' }}{{ flow.main_pct.toFixed(1) }}%
</span>
<span class="ff-col" :class="flow.change_pct >= 0 ? 'up' : 'down'">
{{ flow.change_pct >= 0 ? '+' : '' }}{{ flow.change_pct.toFixed(2) }}%
</span>
</div>
</div>
</div>
<!-- K线图 -->
<div class="fundamental-section">
<div class="kline-header">
<h4>📈 股价走势</h4>
<div class="kline-period-tabs">
<button type="button" :class="['kline-tab', { active: klinePeriod === 'weekly' }]" @click="changeKlinePeriod('weekly')"></button>
<button type="button" :class="['kline-tab', { active: klinePeriod === 'monthly' }]" @click="changeKlinePeriod('monthly')"></button>
<button type="button" :class="['kline-tab', { active: klinePeriod === 'quarterly' }]" @click="changeKlinePeriod('quarterly')"></button>
<button type="button" :class="['kline-tab', { active: klinePeriod === 'yearly' }]" @click="changeKlinePeriod('yearly')"></button>
</div>
</div>
<div class="kline-chart-container" :class="{ loading: klineLoading }">
<canvas ref="klineCanvas"></canvas>
<div v-if="klineLoading" class="kline-loading">加载中...</div>
</div>
</div>
</div>
<div v-else class="fundamental-error">
无法获取基本面数据
</div>
</div>
</div>
<!-- 分析页面 -->
<div v-show="activeTab === 'analysis'">
<!-- 分析页子导航 -->
<div class="sub-tabs">
<button type="button" :class="['sub-tab', { active: analysisSubTab === 'scan' }]" @click="analysisSubTab = 'scan'; fetchFullScanResults(1)">
全景扫描
</button>
<button type="button" :class="['sub-tab', { active: analysisSubTab === 'bull' }]" @click="analysisSubTab = 'bull'">
个股深析
</button>
<button type="button" :class="['sub-tab', { active: analysisSubTab === 'buyanalysis' }]" @click="analysisSubTab = 'buyanalysis'; fetchBuyAnalysis()">
买入分析
</button>
</div>
<!-- 市场扫描子页面 -->
<div v-show="analysisSubTab === 'scan'">
<!-- 单股分析结果(保留原有功能) -->
<div v-if="result && !loading">
<!-- 交易建议卡片 -->
<div :class="['recommendation-card', tradingSignal.type]">
<div class="signal-icon">{{ tradingSignal.icon }}</div>
<div class="signal-text">{{ tradingSignal.title }}</div>
<div class="signal-desc">{{ tradingSignal.description }}</div>
<div class="signal-details">
<div class="signal-detail-item">
<h4>当前价格</h4>
<div class="value">{{ latestData.price?.toFixed(4) || '-' }} 元</div>
</div>
<div class="signal-detail-item">
<h4>价格位置</h4>
<div class="value">{{ latestData.pricePosition?.toFixed(1) || '-' }}%</div>
</div>
<div class="signal-detail-item">
<h4>超大单净流入</h4>
<div class="value">{{ latestData.superRatio?.toFixed(2) || '-' }}%</div>
</div>
<div class="signal-detail-item">
<h4>主力净流入</h4>
<div class="value">{{ latestData.mainRatio?.toFixed(2) || '-' }}%</div>
</div>
</div>
</div>
<!-- 图表分析区域(可折叠) -->
<div class="collapsible-section">
<div class="collapsible-header" @click="toggleSection('charts')">
<h3>图表分析</h3>
<span :class="['toggle-icon', { expanded: expandedSections.charts }]"></span>
</div>
<div :class="['collapsible-content', { expanded: expandedSections.charts }]">
<div class="analysis-grid" style="margin-top: 15px;">
<div class="card">
<div class="card-title">超大单流入/流出 对未来表现影响</div>
<div class="chart-container">
<canvas ref="superChart"></canvas>
</div>
</div>
<div class="card">
<div class="card-title">主力流入/流出 对未来表现影响</div>
<div class="chart-container">
<canvas ref="mainChart"></canvas>
</div>
</div>
</div>
</div>
</div>
<!-- 详细数据表格(可折叠) -->
<div class="collapsible-section">
<div class="collapsible-header" @click="toggleSection('table')">
<h3>详细数据</h3>
<span :class="['toggle-icon', { expanded: expandedSections.table }]"></span>
</div>
<div :class="['collapsible-content', { expanded: expandedSections.table }]">
<div class="card">
<table class="data-table">
<thead>
<tr>
<th>时间段</th>
<th>超大单流入</th>
<th>超大单流出</th>
<th>差异</th>
<th>主力流入</th>
<th>主力流出</th>
<th>差异</th>
</tr>
</thead>
<tbody>
<tr v-for="period in periods" :key="period">
<td><strong>{{ period }}</strong></td>
<td :class="getClass(getComparisonValue('超大单', period, '大额流入表现'))">
{{ formatPercent(getComparisonValue('超大单', period, '大额流入表现')) }}
</td>
<td :class="getClass(getComparisonValue('超大单', period, '大额流出表现'))">
{{ formatPercent(getComparisonValue('超大单', period, '大额流出表现')) }}
</td>
<td :class="getClass(getComparisonValue('超大单', period, '差异'))">
{{ formatPercent(getComparisonValue('超大单', period, '差异')) }}
</td>
<td :class="getClass(getComparisonValue('主力', period, '大额流入表现'))">
{{ formatPercent(getComparisonValue('主力', period, '大额流入表现')) }}
</td>
<td :class="getClass(getComparisonValue('主力', period, '大额流出表现'))">
{{ formatPercent(getComparisonValue('主力', period, '大额流出表现')) }}
</td>
<td :class="getClass(getComparisonValue('主力', period, '差异'))">
{{ formatPercent(getComparisonValue('主力', period, '差异')) }}
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<!-- 汇总统计(可折叠) -->
<div class="collapsible-section">
<div class="collapsible-header" @click="toggleSection('summary')">
<h3>数据汇总</h3>
<span :class="['toggle-icon', { expanded: expandedSections.summary }]"></span>
</div>
<div :class="['collapsible-content', { expanded: expandedSections.summary }]">
<div class="card">
<div class="summary-grid">
<div class="summary-item">
<h4>分析周期</h4>
<div class="value">{{ result.data['数据概览']['总交易日数'] }} 天</div>
<div class="sub">{{ result.data['数据概览']['日期范围']['开始'] }} 至 {{ result.data['数据概览']['日期范围']['结束'] }}</div>
</div>
<div class="summary-item">
<h4>超大单大额流入日</h4>
<div class="value">{{ result.data['数据概览']['超大单']['大额流入日数'] }} 天</div>
<div class="sub">占比 {{ (result.data['数据概览']['超大单']['大额流入日数'] / result.data['数据概览']['总交易日数'] * 100).toFixed(1) }}%</div>
</div>
<div class="summary-item">
<h4>超大单大额流出日</h4>
<div class="value">{{ result.data['数据概览']['超大单']['大额流出日数'] }} 天</div>
<div class="sub">占比 {{ (result.data['数据概览']['超大单']['大额流出日数'] / result.data['数据概览']['总交易日数'] * 100).toFixed(1) }}%</div>
</div>
<div class="summary-item">
<h4>主力大额流入日</h4>
<div class="value">{{ result.data['数据概览']['主力']['大额流入日数'] }} 天</div>
<div class="sub">占比 {{ (result.data['数据概览']['主力']['大额流入日数'] / result.data['数据概览']['总交易日数'] * 100).toFixed(1) }}%</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 单只股票检测 -->
<div class="tech-signal-header" style="margin-bottom:8px;">
<div class="tech-input-row">
<input v-model="techSignalCode" placeholder="输入股票代码" class="tech-input" @keyup.enter="fetchTechSignals()">
<button type="button" class="tech-btn" @click="fetchTechSignals()" :disabled="techLoading">
{{ techLoading ? '检测中...' : '检测信号' }}
</button>
<button type="button" class="tech-btn batch" @click="batchTechSignals" :disabled="techLoading">
批量扫描关注
</button>
</div>
<div class="tech-legend">
<span class="legend-item"><span class="dot s85"></span>主升浪85%</span>
<span class="legend-item"><span class="dot s80"></span>底背离80%</span>
<span class="legend-item"><span class="dot s75"></span>龙抬头75%</span>
<span class="legend-item"><span class="dot s70"></span>真龙70%</span>
<span class="legend-item"><span class="dot s65"></span>短底背离65%</span>
<span class="legend-item"><span class="dot s60"></span>老鼠仓60%</span>
<span class="legend-item"><span class="dot s55"></span>反弹55%</span>
</div>
</div>
<!-- 全量信号扫描区域 -->
<div class="full-scan-trigger-section">
<!-- 加载状态提示 -->
<div v-if="fullScanLoading && !fullScanStatus" class="scan-loading-hint">
<span class="loading-spinner"></span> 正在加载全景扫描数据...
</div>
<!-- 全量扫描结果 -->
<template v-if="fullScanStatus && (fullScanResults.length > 0 || fullScanFilterRecommend !== 'all')">
<div class="scan-summary-section">
<div class="scan-summary-header" role="button" tabindex="0" :aria-expanded="!scanSummaryCollapsed" @click="scanSummaryCollapsed = !scanSummaryCollapsed" @keyup.enter="scanSummaryCollapsed = !scanSummaryCollapsed">
<span class="scan-summary-text">扫描 <b>{{ fullScanStatus.scanned }}</b><small v-if="fullScanStatus.total && fullScanStatus.scanned < fullScanStatus.total">/{{ fullScanStatus.total }}</small> 只,有信号 <b class="highlight">{{ fullScanStatus.triggered }}</b></span>
<span class="scan-summary-actions">
<button type="button" class="section-close inline" @click.stop="fullScanStatus = null; fullScanResults = []" title="关闭"></button>
<span class="scan-summary-toggle">{{ scanSummaryCollapsed ? '▶' : '▼' }}</span>
</span>
</div>
<div v-show="!scanSummaryCollapsed" class="scan-summary-body">
<div class="scan-time-info" v-if="fullScanStatus.scan_end">
扫描时间: {{ fullScanStatus.scan_end?.substring(0, 19) }}
</div>
<div v-if="fullScanSignalDist.length > 0" class="signal-dist-bar">
<span v-for="d in fullScanSignalDist" :key="d.type" class="dist-tag"
:class="{ active: fullScanFilterTypes.includes(d.type) }" @click="toggleSignalFilter(d.type)">
{{ d.name }} <b>{{ d.count }}</b>
</span>
</div>
<div class="scan-filters">
<div class="scan-filter-row">
<span class="scan-filter-label">范围</span>
<span :class="['filter-tag', fullScanFilter === 'all' ? 'active' : '']" @click="changeFullScanFilter('all')">全部 <b v-if="fullScanStatus && fullScanStatus.scanned">{{ fullScanStatus.scanned }}</b></span>
<span :class="['filter-tag', fullScanFilter === 'triggered' ? 'active' : '']" @click="changeFullScanFilter('triggered')">有信号 <b v-if="fullScanStatus && fullScanStatus.triggered">{{ fullScanStatus.triggered }}</b></span>
</div>
<div class="scan-filter-row">
<span class="scan-filter-label">推荐</span>
<span :class="['filter-tag', 'rec-all', fullScanFilterRecommend === 'all' ? 'active' : '']" @click="changeFullScanFilterRecommend('all')">全部 {{ fullScanStatus ? fullScanStatus.scanned : '' }}</span>
<span v-for="opt in fullScanRecommendOptions" :key="opt.text"
:class="['filter-tag', getRecommendFilterClass(opt.text), fullScanFilterRecommend === opt.text ? 'active' : '']"
:title="opt.hint"
@click="changeFullScanFilterRecommend(opt.text)">
{{ opt.text }} <b v-if="opt.count > 0">{{ opt.count }}</b>
</span>
</div>
</div>
</div>
</div>
<div class="full-scan-list">
<div v-if="fullScanResultsFiltered.length === 0" class="scan-empty-hint">暂无符合条件的股票</div>
<div v-for="item in fullScanResultsFiltered" :key="item.code" class="scan-result-card"
:class="{ 'has-signal': item.triggered_count > 0, 'is-watched': searchHistory.some(h => h.code === item.code) }">
<div class="scan-card-header" @click="techSignalCode = item.code; analysisSubTab = 'scan'; fetchTechSignals(item)">
<span class="scan-watched-icon" v-if="searchHistory.some(h => h.code === item.code)"></span>
<span class="scan-code" @dblclick.stop="toggleWatchFromScan(item.code, item.name)" title="双击添加/取消关注">{{ item.code }}</span>
<span class="scan-name">{{ item.name }}</span>
<span :class="['scan-recommend', getScanRecommend(item).cls]">{{ getScanRecommend(item).text }}</span>
</div>
<div class="scan-card-info" @click="techSignalCode = item.code; analysisSubTab = 'scan'; fetchTechSignals(item)">
<span class="scan-info-left">
<span class="scan-price" v-if="item.price">¥{{ item.price.toFixed(2) }}</span>
<span class="scan-change" v-if="item.change_pct != null"
:class="item.change_pct >= 0 ? 'up' : 'down'">{{ item.change_pct >= 0 ? '+' : '' }}{{ item.change_pct.toFixed(2) }}%</span>
</span>
<span class="scan-score-pill" v-if="item.final_score != null"
:class="'score-' + (item.final_score >= 65 ? 'high' : item.final_score >= 50 ? 'mid' : 'low')"
:title="'技术' + item.technical_score + ' / 外部' + (item.external_score >= 0 ? '+' : '') + item.external_score">
{{ item.final_score }}分
</span>
<span class="scan-triggered" v-if="item.triggered_count > 0">🔔 {{ item.triggered_count }}个信号</span>
<span class="scan-no-signal" v-else>无信号</span>
</div>
<div class="scan-signals" v-if="item.signal_status && item.signal_status.length > 0">
<span v-for="ss in item.signal_status" :key="ss.type"
:class="['scan-signal-tag', ss.triggered ? 'active' : 'inactive']" :title="ss.description">
{{ ss.triggered ? '✅' : '○' }} {{ ss.name }}
</span>
</div>
<div class="scan-holding-note" v-if="item.holding_note">{{ item.holding_note }}</div>
</div>
</div>
<div v-if="fullScanTotalPages > 1" class="scan-pagination">
<button type="button" @click="fetchFullScanResults(fullScanPage - 1)" :disabled="fullScanPage <= 1">上一页</button>
<span>{{ fullScanPage }} / {{ fullScanTotalPages }}</span>
<button type="button" @click="fetchFullScanResults(fullScanPage + 1)" :disabled="fullScanPage >= fullScanTotalPages">下一页</button>
</div>
</template>
</div>
<!-- 单只股票检测结果 -->
<div v-if="techSignalResult" class="tech-result-card">
<div class="tech-result-header">
<h4>{{ techSignalResult.stock_code }} {{ techSignalResult.stock_name }}</h4>
<span class="signal-count" v-if="(techSignalResult.signal_status || []).filter(s => s.triggered).length > 0">
🔔 {{ (techSignalResult.signal_status || []).filter(s => s.triggered).length }} 个信号
</span>
<span class="signal-count none" v-else-if="!techSignalResult.has_scan_data">无信号</span>
<button type="button" class="section-close" @click="techSignalResult = null" title="关闭"></button>
</div>
<div class="tech-result-actions">
<button type="button" v-if="!searchHistory.some(h => h.code === techSignalResult.stock_code)"
class="watch-btn add" @click="addToWatchFromSignal">
★ 添加关注
</button>
<button type="button" v-else class="watch-btn remove" @click="removeFromWatchFromSignal">
☆ 取消关注
</button>
</div>
<!-- 方案C:来自扫描列表时,同时显示扫描结果和实时检测 -->
<template v-if="techSignalResult.has_scan_data">
<div class="signal-source-section">
<h5 class="signal-source-title">📋 扫描结果(与列表一致)</h5>
<span class="signal-count" v-if="techSignalResult.scan_triggered_count > 0">🔔 {{ techSignalResult.scan_triggered_count }} 个信号</span>
<span class="signal-count none" v-else>无信号</span>
</div>
<div v-if="techSignalResult.recommend_text" class="tech-recommend-bar" :class="'rec-' + (techSignalResult.recommend_type || 'watch')">
<span class="tech-recommend-label">综合推荐</span>
<span class="tech-recommend-text">{{ techSignalResult.recommend_text }}</span>
<span class="tech-recommend-rate" v-if="techSignalResult.recommend_rate">{{ techSignalResult.recommend_rate }}%</span>
<div class="tech-recommend-reason">{{ techSignalResult.recommend_reason }}</div>
</div>
<!-- 综合评分明细(外部因素) -->
<div v-if="techSignalResult.final_score != null" class="scan-score-breakdown">
<div class="score-breakdown-item">
<span class="breakdown-label">技术得分</span>
<span class="breakdown-value">{{ techSignalResult.technical_score }}</span>
</div>
<div class="score-breakdown-item">
<span class="breakdown-label">外部得分</span>
<span class="breakdown-value" :class="techSignalResult.external_score >= 0 ? 'pos' : 'neg'">
{{ techSignalResult.external_score >= 0 ? '+' : '' }}{{ techSignalResult.external_score }}
</span>
</div>
<div class="score-breakdown-item highlight">
<span class="breakdown-label">综合得分</span>
<span class="breakdown-value">{{ techSignalResult.final_score }}</span>
</div>
<div class="score-breakdown-item">
<span class="breakdown-label">评级</span>
<span class="breakdown-value">{{ techSignalResult.verdict }}</span>
</div>
</div>
<!-- 外部因素详情 -->
<div v-if="techSignalResult.score_detail_loading" class="scan-external-factors loading">
<span class="loading-spinner"></span> 正在加载外部因素...
</div>
<div v-else-if="techSignalResult.score_factors" class="scan-external-factors">
<div v-if="techSignalResult.score_factors.fund_flow" class="ext-factor-item">
<span class="ext-factor-label">💰 资金面</span>
<span class="ext-factor-score" :class="techSignalResult.score_factors.fund_flow.score >= 0 ? 'pos' : 'neg'">
{{ techSignalResult.score_factors.fund_flow.score >= 0 ? '+' : '' }}{{ techSignalResult.score_factors.fund_flow.score }}
</span>
<span class="ext-factor-summary">{{ techSignalResult.score_factors.fund_flow.summary }}</span>
</div>
<div v-if="techSignalResult.score_factors.market_sentiment" class="ext-factor-item">
<span class="ext-factor-label">📊 市场情绪</span>
<span class="ext-factor-score" :class="techSignalResult.score_factors.market_sentiment.score >= 0 ? 'pos' : 'neg'">
{{ techSignalResult.score_factors.market_sentiment.score >= 0 ? '+' : '' }}{{ techSignalResult.score_factors.market_sentiment.score }}
</span>
<span class="ext-factor-summary">{{ techSignalResult.score_factors.market_sentiment.sentiment || techSignalResult.score_factors.market_sentiment.summary }}</span>
</div>
<div v-if="techSignalResult.score_factors.external" class="ext-factor-item">
<span class="ext-factor-label">🌍 外部环境</span>
<span class="ext-factor-score" :class="techSignalResult.score_factors.external.total_score >= 0 ? 'pos' : 'neg'">
{{ techSignalResult.score_factors.external.total_score >= 0 ? '+' : '' }}{{ techSignalResult.score_factors.external.total_score }}
</span>
<span class="ext-factor-summary">{{ techSignalResult.score_factors.external.summary }}</span>
</div>
<div v-if="techSignalResult.score_factors.policy" class="ext-factor-item">
<span class="ext-factor-label">📜 政策面</span>
<span class="ext-factor-score" :class="techSignalResult.score_factors.policy.score >= 0 ? 'pos' : 'neg'">
{{ techSignalResult.score_factors.policy.score >= 0 ? '+' : '' }}{{ techSignalResult.score_factors.policy.score }}
</span>
<span class="ext-factor-summary">{{ techSignalResult.score_factors.policy.summary }}</span>
</div>
<div v-if="techSignalResult.score_factors.news" class="ext-factor-item">
<span class="ext-factor-label">📰 公告/异动</span>
<span class="ext-factor-score">{{ techSignalResult.score_factors.news.total_score }}</span>
<span class="ext-factor-summary">{{ techSignalResult.score_factors.news.summary }}</span>
</div>
</div>
<div v-if="techSignalResult.signal_status && techSignalResult.signal_status.length > 0" class="signal-status-list">
<div v-for="ss in techSignalResult.signal_status" :key="'scan-'+ss.type"
:class="['signal-status-item', ss.triggered ? 'triggered' : 'inactive']">
<div class="ss-header">
<span :class="['ss-dot', 's' + (ss.strength||70)]"></span>
<span class="ss-name">{{ ss.name }}</span>
<span class="ss-strength" v-if="ss.strength">{{ ss.strength }}%</span>
<span :class="['ss-badge', ss.triggered ? 'active' : 'wait']">{{ ss.triggered ? '已触发' : '未触发' }}</span>
</div>
<div class="ss-desc" v-if="ss.description">{{ ss.description }}</div>
</div>
</div>
<div class="signal-source-section">
<h5 class="signal-source-title">⚡ 当前实时检测</h5>
<span v-if="techSignalResult.realtime_loading" class="realtime-loading">加载中...</span>
<span v-else-if="techSignalResult.realtime_error" class="realtime-error">{{ techSignalResult.realtime_error }}</span>
<template v-else-if="techSignalResult.realtime_signal_status">
<span class="signal-count" v-if="techSignalResult.realtime_triggered_count > 0">🔔 {{ techSignalResult.realtime_triggered_count }} 个信号</span>
<span class="signal-count none" v-else>无信号</span>
</template>
</div>
<div v-if="!techSignalResult.realtime_loading && techSignalResult.realtime_recommend_text" class="tech-recommend-bar realtime-bar" :class="'rec-' + (techSignalResult.realtime_recommend_type || 'watch')">
<span class="tech-recommend-label">综合推荐</span>
<span class="tech-recommend-text">{{ techSignalResult.realtime_recommend_text }}</span>
<span class="tech-recommend-rate" v-if="techSignalResult.realtime_recommend_rate">{{ techSignalResult.realtime_recommend_rate }}%</span>
<div class="tech-recommend-reason">{{ techSignalResult.realtime_recommend_reason }}</div>
<div v-if="techSignalResult.realtime_holding_note" class="tech-holding-note">⚠️ {{ techSignalResult.realtime_holding_note }}</div>
</div>
<div v-if="!techSignalResult.realtime_loading && techSignalResult.realtime_signal_status && techSignalResult.realtime_signal_status.length > 0" class="signal-status-list">
<div v-for="ss in techSignalResult.realtime_signal_status" :key="'rt-'+ss.type"
:class="['signal-status-item', ss.triggered ? 'triggered' : 'inactive']">
<div class="ss-header">
<span :class="['ss-dot', 's' + (ss.strength||70)]"></span>
<span class="ss-name">{{ ss.name }}</span>
<span class="ss-strength" v-if="ss.strength">{{ ss.strength }}%</span>
<span :class="['ss-badge', ss.triggered ? 'active' : 'wait']">{{ ss.triggered ? '已触发' : '未触发' }}</span>
</div>
<div class="ss-desc" v-if="ss.description">{{ ss.description }}</div>
</div>
</div>
<div v-if="techSignalResult.realtime_indicators" class="tech-indicators">
<div class="indicator-group">
<span class="ind-label">MACD</span>
<span :class="['ind-val', (techSignalResult.realtime_indicators.macd?.dif||0) > 0 ? 'pos' : 'neg']">DIF {{ techSignalResult.realtime_indicators.macd?.dif }}</span>
<span :class="['ind-val', (techSignalResult.realtime_indicators.macd?.dea||0) > 0 ? 'pos' : 'neg']">DEA {{ techSignalResult.realtime_indicators.macd?.dea }}</span>
</div>
<div class="indicator-group">
<span class="ind-label">SKDJ</span>
<span :class="['ind-val', techSignalResult.realtime_indicators.skdj?.k < 20 ? 'oversold' : (techSignalResult.realtime_indicators.skdj?.k > 80 ? 'overbought' : '')]">K {{ techSignalResult.realtime_indicators.skdj?.k }}</span>
<span class="ind-val">D {{ techSignalResult.realtime_indicators.skdj?.d }}</span>
</div>
<div class="indicator-group">
<span class="ind-label">EMA</span>
<span class="ind-val">EMA3 {{ techSignalResult.realtime_indicators.ema?.ema3 }}</span>
<span class="ind-val">EMA21 {{ techSignalResult.realtime_indicators.ema?.ema21 }}</span>
</div>
</div>
</template>
<!-- 手动输入检测:仅显示实时结果 -->
<template v-else>
<div v-if="techSignalResult.recommend_text" class="tech-recommend-bar" :class="'rec-' + (techSignalResult.recommend_type || 'watch')">
<span class="tech-recommend-label">综合推荐</span>
<span class="tech-recommend-text">{{ techSignalResult.recommend_text }}</span>
<span class="tech-recommend-rate" v-if="techSignalResult.recommend_rate">{{ techSignalResult.recommend_rate }}%</span>
<div class="tech-recommend-reason">{{ techSignalResult.recommend_reason }}</div>
<div v-if="techSignalResult.holding_note" class="tech-holding-note">⚠️ {{ techSignalResult.holding_note }}</div>
</div>
<div class="tech-indicators" v-if="techSignalResult.indicators">
<div class="indicator-group">
<span class="ind-label">MACD</span>
<span :class="['ind-val', techSignalResult.indicators.macd?.dif > 0 ? 'pos' : 'neg']">DIF {{ techSignalResult.indicators.macd?.dif }}</span>
<span :class="['ind-val', techSignalResult.indicators.macd?.dea > 0 ? 'pos' : 'neg']">DEA {{ techSignalResult.indicators.macd?.dea }}</span>
</div>
<div class="indicator-group">
<span class="ind-label">SKDJ</span>
<span :class="['ind-val', techSignalResult.indicators.skdj?.k < 20 ? 'oversold' : (techSignalResult.indicators.skdj?.k > 80 ? 'overbought' : '')]">K {{ techSignalResult.indicators.skdj?.k }}</span>
<span class="ind-val">D {{ techSignalResult.indicators.skdj?.d }}</span>
</div>
<div class="indicator-group">
<span class="ind-label">EMA</span>
<span class="ind-val">EMA3 {{ techSignalResult.indicators.ema?.ema3 }}</span>
<span class="ind-val">EMA21 {{ techSignalResult.indicators.ema?.ema21 }}</span>
</div>
</div>
<div v-if="techSignalResult.signal_status && techSignalResult.signal_status.length > 0" class="signal-status-list">
<div v-for="ss in techSignalResult.signal_status" :key="ss.type"
:class="['signal-status-item', ss.triggered ? 'triggered' : 'inactive']">
<div class="ss-header">
<span :class="['ss-dot', 's' + ss.strength]"></span>
<span class="ss-name">{{ ss.name }}</span>
<span class="ss-strength">{{ ss.strength }}%</span>
<span :class="['ss-badge', ss.triggered ? 'active' : 'wait']">{{ ss.triggered ? '已触发' : '未触发' }}</span>
</div>
<div class="ss-desc">{{ ss.description }}</div>
</div>
</div>
</template>
<div v-if="(techSignalResult.signals || []).length > 0" class="tech-signal-list">
<h5 style="color:var(--text-secondary);margin:12px 0 8px;font-size:13px;">📋 近期触发记录</h5>
<div v-for="sig in techSignalResult.signals" :key="sig.date + sig.type"
:class="['tech-signal-item', 'strength-' + sig.strength]">
<div class="sig-header">
<span class="sig-name">{{ sig.name }}</span>
<span class="sig-strength">胜率 {{ sig.strength }}%</span>
<span class="sig-date">{{ sig.date }}</span>
</div>
<div class="sig-desc">{{ sig.description }}</div>
<div class="sig-price">价格: ¥{{ sig.price?.toFixed(2) }}</div>
</div>
</div>
</div>
<!-- 批量扫描结果(复用全景扫描卡片样式) -->
<div v-if="techBatchResults.length > 0" class="tech-batch-results">
<div class="batch-results-header">
<h4 class="section-title">关注股票信号扫描 <span class="badge">{{ techBatchResults.length }}</span></h4>
<button type="button" class="section-close" @click="techBatchResults = []" title="关闭"></button>
</div>
<div class="full-scan-list">
<div v-for="item in techBatchResults" :key="item.code" class="scan-result-card"
:class="{ 'has-signal': item.triggered_count > 0, 'is-watched': true }">
<div class="scan-card-header" @click="techSignalCode = item.code; analysisSubTab = 'scan'; fetchTechSignals(item)">
<span class="scan-watched-icon"></span>
<span class="scan-code" @dblclick.stop="toggleWatchFromScan(item.code, item.name)" title="双击取消关注">{{ item.code }}</span>
<span class="scan-name">{{ item.name }}</span>
<span :class="['scan-recommend', getScanRecommend(item).cls]">{{ getScanRecommend(item).text }}</span>
</div>
<div class="scan-card-info" @click="techSignalCode = item.code; analysisSubTab = 'scan'; fetchTechSignals(item)">
<span class="scan-info-left">
<span class="scan-price" v-if="item.price">¥{{ item.price.toFixed(2) }}</span>
<span class="scan-change" v-if="item.change_pct != null"
:class="item.change_pct >= 0 ? 'up' : 'down'">{{ item.change_pct >= 0 ? '+' : '' }}{{ item.change_pct.toFixed(2) }}%</span>
</span>
<span class="scan-triggered" v-if="item.triggered_count > 0">🔔 {{ item.triggered_count }}个信号</span>
<span class="scan-no-signal" v-else>无信号</span>
</div>
<div class="scan-signals" v-if="item.signal_status && item.signal_status.length > 0">
<span v-for="ss in item.signal_status" :key="ss.type"
:class="['scan-signal-tag', ss.triggered ? 'active' : 'inactive']" :title="ss.description">
{{ ss.triggered ? '✅' : '○' }} {{ ss.name }}
</span>
</div>
<div class="scan-holding-note" v-if="item.holding_note">{{ item.holding_note }}</div>
</div>
</div>
</div>
</div><!-- 全景扫描子页面结束 -->
<!-- 个股深析子页面 -->
<div v-show="analysisSubTab === 'bull'" class="deep-analysis-page">
<!-- 输入区 -->
<div class="deep-input-card">
<div class="deep-input-row">
<input v-model="deepCode" placeholder="输入股票代码,如 601609"
class="deep-code-input" @keyup.enter="fetchDeepAnalysis()" maxlength="6">
<button type="button" class="deep-analyze-btn" @click="fetchDeepAnalysis()" :disabled="deepLoading">
{{ deepLoading ? '分析中...' : '深度分析' }}
</button>
</div>
</div>
<!-- 加载状态 -->
<div v-if="deepLoading" class="skeleton-card">
<div class="skeleton-line medium"></div>
<div class="skeleton-line long"></div>
<div class="skeleton-grid">
<div class="skeleton-line short"></div>
<div class="skeleton-line short"></div>
</div>
<div class="skeleton-line long"></div>
<div class="skeleton-line medium"></div>
<div class="skeleton-line long"></div>
</div>
<!-- 分析报告 -->
<div v-if="deepReport && !deepLoading" class="deep-report">
<!-- 头部:股票信息+综合评分 -->
<div class="deep-header-card">
<div class="deep-header-left">
<div class="deep-stock-name">{{ deepReport.stock_name }}</div>
<div class="deep-stock-code">{{ deepReport.stock_code }}</div>
</div>
<div class="deep-header-center" v-if="deepReport.realtime">
<div class="deep-price">¥{{ deepReport.realtime.price.toFixed(2) }}</div>
<div class="deep-change" :class="deepReport.realtime.change_pct >= 0 ? 'up' : 'down'">
{{ deepReport.realtime.change_pct >= 0 ? '+' : '' }}{{ deepReport.realtime.change_pct.toFixed(2) }}%
</div>
</div>
<div class="deep-header-right">
<div class="deep-score-circle" :class="'score-' + (deepReport.deep_score >= 65 ? 'high' : deepReport.deep_score >= 50 ? 'mid' : 'low')">
<span class="score-num">{{ deepReport.deep_score }}</span>
</div>
<div class="deep-verdict">{{ deepReport.verdict }}</div>
</div>
</div>
<!-- 三项得分明细 -->
<div v-if="deepReport.comprehensive" class="deep-score-breakdown">
<div class="score-breakdown-item">
<span class="breakdown-label">技术得分</span>
<span class="breakdown-value">{{ deepReport.comprehensive.technical_score }}</span>
</div>
<div class="score-breakdown-item">
<span class="breakdown-label">外部得分</span>
<span class="breakdown-value" :class="deepReport.comprehensive.external_score >= 0 ? 'pos' : 'neg'">
{{ deepReport.comprehensive.external_score >= 0 ? '+' : '' }}{{ deepReport.comprehensive.external_score }}
</span>
</div>
<div class="score-breakdown-item highlight">
<span class="breakdown-label">综合得分</span>
<span class="breakdown-value">{{ deepReport.comprehensive.final_score }}</span>
</div>
</div>
<!-- AI通俗解说 -->
<div v-if="deepReport.ai_summary" class="deep-ai-summary">
<div class="deep-ai-title">💡 AI 解读</div>
<div class="deep-ai-text">
<p>{{ deepReport.ai_summary.text }}</p>
</div>
<div class="ai-action-tip">
<span class="ai-action-label">操作建议:</span>{{ deepReport.ai_summary.action_tip }}
</div>
</div>
<!-- 推荐操作 -->
<div class="deep-section">
<div class="deep-section-title">系统推荐</div>
<div class="deep-recommend-bar" :class="'rec-' + deepReport.recommend.signal_type">
<span class="rec-display">{{ deepReport.recommend.display }}</span>
<span class="rec-rate">{{ deepReport.recommend.rate }}分</span>
<span class="rec-reason-text">{{ deepReport.recommend.reason }}</span>
</div>
</div>
<!-- 信号列表 -->
<div class="deep-section" v-if="deepReport.signals && deepReport.signals.length">
<div class="deep-section-title">触发信号 ({{ deepReport.signals.length }}个)</div>
<div class="deep-signal-list">
<div v-for="sig in deepReport.signals" :key="sig.type" class="deep-signal-item">
<span class="deep-sig-name">{{ sig.name }}</span>
<span class="deep-sig-strength">{{ sig.strength }}%</span>
<span class="deep-sig-desc">{{ sig.description }}</span>
</div>
</div>
</div>
<!-- 价格位置 -->
<div class="deep-section">
<div class="deep-section-title">价格位置</div>
<div class="deep-position-grid">
<div v-for="(pos, key) in deepReport.position" :key="key" class="deep-pos-item">
<div class="pos-label">{{ key.replace('d','') }}日</div>
<div class="pos-range">{{ pos.low }} ~ {{ pos.high }}</div>
<div class="pos-bar-wrap">
<div class="pos-bar-bg">
<div class="pos-bar-fill" :style="{ width: pos.range_pct + '%' }"
:class="pos.range_pct > 80 ? 'high' : pos.range_pct < 30 ? 'low' : 'mid'"></div>
</div>
<span class="pos-pct">{{ pos.range_pct }}%</span>
</div>
<div class="pos-space">
<span class="space-up">↑{{ pos.up_space }}%</span>
<span class="space-down">↓{{ pos.down_risk }}%</span>
</div>
</div>
</div>
</div>
<!-- 支撑压力 -->
<div class="deep-section">
<div class="deep-section-title">支撑与压力</div>
<div class="deep-sr-grid">
<div class="sr-col">
<div class="sr-col-title support-title">支撑位</div>
<div v-for="s in deepReport.supports" :key="s.name" class="sr-item support">
<span class="sr-name">{{ s.name }}</span>
<span class="sr-level">{{ s.level }}</span>
</div>
<div v-if="!deepReport.supports.length" class="sr-empty"></div>
</div>
<div class="sr-col">
<div class="sr-col-title resist-title">压力位</div>
<div v-for="r in deepReport.resistances" :key="r.name" class="sr-item resist">
<span class="sr-name">{{ r.name }}</span>
<span class="sr-level">{{ r.level }}</span>
</div>
<div v-if="!deepReport.resistances.length" class="sr-empty"></div>
</div>
</div>
</div>
<!-- 量价与形态 -->
<div class="deep-section">
<div class="deep-section-title">量价分析</div>
<div class="deep-vol-info">
<span class="vol-tag" :class="deepReport.volume.ratio >= 1.3 ? 'vol-up' : deepReport.volume.ratio < 0.7 ? 'vol-dn' : ''">
{{ deepReport.volume.trend }}
</span>
<span class="vol-detail">量比 {{ deepReport.volume.ratio }}x · 5日均量 {{ (deepReport.volume.avg_5/10000).toFixed(0) }}万</span>
</div>
<div v-if="deepReport.patterns.length" class="deep-patterns">
<span v-for="p in deepReport.patterns" :key="p.name"
class="pattern-tag" :class="p.bullish === true ? 'bullish' : p.bullish === false ? 'bearish' : ''">
{{ p.name }} <small>{{ p.desc }}</small>
</span>
</div>
</div>
<!-- 均线与基本面 -->
<div class="deep-section">
<div class="deep-section-title">技术指标</div>
<div class="deep-ma-info">
<span class="ma-trend-tag" :class="deepReport.ma_trend">{{ deepReport.ma_trend_label }}</span>
<span v-for="(val, key) in deepReport.ma" :key="key" class="ma-val">
{{ key.toUpperCase() }}={{ val }}
</span>
</div>
<div v-if="deepReport.realtime" class="deep-fundamental">
<span v-if="deepReport.realtime.pe > 0">PE {{ deepReport.realtime.pe.toFixed(1) }}</span>
<span v-if="deepReport.realtime.pb > 0">PB {{ deepReport.realtime.pb.toFixed(1) }}</span>
<span v-if="deepReport.realtime.total_market_cap > 0">
市值 {{ (deepReport.realtime.total_market_cap/100000000).toFixed(0) }}亿
</span>
</div>
</div>
<!-- 评分明细 -->
<div class="deep-section">
<div class="deep-section-title">评分明细</div>
<div class="deep-score-details">
<span v-for="r in deepReport.score_reasons" :key="r" class="score-reason-tag"
:class="r.includes('+') ? 'positive' : 'negative'">{{ r }}</span>
</div>
</div>
</div>
<!-- 空状态 -->
<div v-if="!deepReport && !deepLoading" class="empty-state">
<div class="empty-state-icon">📊</div>
<div class="empty-state-title">个股深析</div>
<div class="empty-state-desc">输入股票代码,获取深度技术分析报告<br>包含价格位置、压力支撑、量价分析、空间估算、综合评分</div>
</div>
</div><!-- 个股深析子页面结束 -->
<!-- 买入分析子页面 -->
<div v-show="analysisSubTab === 'buyanalysis'" class="buy-analysis-page">
<div class="buy-analysis-header">
<div class="buy-analysis-title">买入股深度分析</div>
<div class="buy-analysis-desc">对全景扫描中推荐买入的股票批量执行深度分析</div>
<button type="button" class="deep-analyze-btn" @click="fetchBuyAnalysis()" :disabled="buyAnalysisLoading" style="margin-top:8px;">
{{ buyAnalysisLoading ? '分析中...' : '刷新分析' }}
</button>
</div>
<div v-if="buyAnalysisLoading" class="bull-loading">
<span class="loading-dot"></span> 正在批量分析买入推荐股...{{ buyAnalysisProgress }}/{{ buyAnalysisTotal }}
</div>
<div v-if="!buyAnalysisLoading && buyAnalysisList.length === 0" class="empty-state">
<div class="empty-state-icon">📋</div>
<div class="empty-state-title">暂无买入推荐股票</div>
<div class="empty-state-desc">当全景扫描中有买入推荐时,可在此批量执行深度分析</div>
</div>
<div v-if="buyAnalysisList.length > 0" class="buy-analysis-list">
<div v-for="(item, idx) in buyAnalysisList" :key="item.stock_code" class="buy-analysis-card">
<div class="buy-card-header" @click="item._expanded = !item._expanded">
<div class="buy-card-left">
<span class="buy-card-name">{{ item.stock_name }}</span>
<span class="buy-card-code">{{ item.stock_code }}</span>
</div>
<div class="buy-card-center">
<span class="buy-card-price" v-if="item.realtime">¥{{ item.realtime.price.toFixed(2) }}</span>
<span class="buy-card-change" v-if="item.realtime" :class="item.realtime.change_pct >= 0 ? 'up' : 'down'">
{{ item.realtime.change_pct >= 0 ? '+' : '' }}{{ item.realtime.change_pct.toFixed(2) }}%
</span>
</div>
<div class="buy-card-right">
<span class="buy-card-score" :class="'score-' + (item.deep_score >= 65 ? 'high' : item.deep_score >= 50 ? 'mid' : 'low')">
{{ item.deep_score }}分
</span>
<span class="buy-card-verdict">{{ item.verdict }}</span>
</div>
<span class="buy-card-arrow" :class="{ expanded: item._expanded }"></span>
</div>
<div v-show="item._expanded" class="buy-card-detail">
<div v-if="item.comprehensive" class="deep-score-breakdown" style="margin-bottom:8px;">
<div class="score-breakdown-item">
<span class="breakdown-label">技术得分</span>
<span class="breakdown-value">{{ item.comprehensive.technical_score }}</span>
</div>
<div class="score-breakdown-item">
<span class="breakdown-label">外部得分</span>
<span class="breakdown-value" :class="item.comprehensive.external_score >= 0 ? 'pos' : 'neg'">
{{ item.comprehensive.external_score >= 0 ? '+' : '' }}{{ item.comprehensive.external_score }}
</span>
</div>
<div class="score-breakdown-item highlight">
<span class="breakdown-label">综合得分</span>
<span class="breakdown-value">{{ item.comprehensive.final_score }}</span>
</div>
</div>
<div v-if="item.ai_summary" class="deep-ai-summary" style="margin-bottom:8px;">
<div class="deep-ai-title">💡 AI 解读</div>
<div class="deep-ai-text"><p>{{ item.ai_summary.text }}</p></div>
<div class="ai-action-tip">
<span class="ai-action-label">操作建议:</span>{{ item.ai_summary.action_tip }}
</div>
</div>
<div class="buy-detail-grid">
<div class="buy-detail-item">
<span class="buy-detail-label">系统推荐</span>
<span class="buy-detail-value" style="color:var(--up);font-weight:600;">{{ item.recommend.display }} {{ item.recommend.rate }}分</span>
</div>
<div class="buy-detail-item">
<span class="buy-detail-label">推荐理由</span>
<span class="buy-detail-value">{{ item.recommend.reason }}</span>
</div>
<div class="buy-detail-item" v-if="item.signals && item.signals.length">
<span class="buy-detail-label">触发信号</span>
<span class="buy-detail-value">
<span v-for="sig in item.signals" :key="sig.type" class="deep-sig-name" style="margin-right:6px;">{{ sig.name }}</span>
</span>
</div>
<div class="buy-detail-item" v-if="item.supports && item.supports.length">
<span class="buy-detail-label">支撑位</span>
<span class="buy-detail-value">{{ item.supports.map(s => s.level.toFixed(2)).join(' / ') }}</span>
</div>
<div class="buy-detail-item" v-if="item.resistances && item.resistances.length">
<span class="buy-detail-label">压力位</span>
<span class="buy-detail-value">{{ item.resistances.map(r => r.level.toFixed(2)).join(' / ') }}</span>
</div>
<div class="buy-detail-item">
<span class="buy-detail-label">量能</span>
<span class="buy-detail-value">{{ item.volume ? item.volume.trend + ' (量比' + item.volume.ratio + 'x)' : '-' }}</span>
</div>
<div class="buy-detail-item">
<span class="buy-detail-label">均线</span>
<span class="buy-detail-value">{{ item.ma_trend_label }}</span>
</div>
</div>
<button type="button" class="deep-analyze-btn" style="margin-top:8px;font-size:12px;padding:6px 12px;"
@click="deepCode = item.stock_code; analysisSubTab = 'bull'; fetchDeepAnalysis();">
查看完整报告 →
</button>
</div>
</div>
</div>
</div><!-- 买入分析子页面结束 -->
<!-- (模拟交易已移至模型tab) -->
<div class="hidden">
<!-- 模拟交易统计卡片 -->
<div class="sim-stats-card">
<div class="sim-stats-header">
<h4>智能交易 <span v-if="smartAlgoConfig" style="font-size:12px;color:var(--text-muted);">{{ smartAlgoConfig.algo_name }}</span></h4>
<div class="sim-actions">
<button type="button" class="sim-btn auto" @click="executeAutoTrade" :disabled="simAutoTrading">
{{ simAutoTrading ? '执行中...' : '执行' }}
</button>
<button type="button" class="sim-btn reset" @click="confirmResetSim">重置</button>
</div>
</div>
<div class="sim-stats-grid">
<div class="sim-stat-item">
<div class="sim-stat-value">{{ formatMoney(smartAlgoConfig?.total_capital || simStats.initial_capital || 200000) }}</div>
<div class="sim-stat-label">总本金</div>
</div>
<div class="sim-stat-item">
<div class="sim-stat-value">{{ formatMoney(simStats.total_market_value || 0) }}</div>
<div class="sim-stat-label">持仓市值</div>
</div>
<div class="sim-stat-item">
<div class="sim-stat-value">{{ formatMoney(simStats.cash || (smartAlgoConfig?.total_capital || 200000)) }}</div>
<div class="sim-stat-label">可用资金</div>
</div>
<div class="sim-stat-item" :class="(simStats.total_profit || 0) >= 0 ? 'profit' : 'loss'">
<div class="sim-stat-value">{{ (simStats.total_profit || 0) >= 0 ? '+' : '' }}{{ formatMoney(simStats.total_profit || 0) }}</div>
<div class="sim-stat-label">总盈亏</div>
</div>
<div class="sim-stat-item" :class="(simStats.profit_rate || 0) >= 0 ? 'profit' : 'loss'">
<div class="sim-stat-value">{{ (simStats.profit_rate || 0) >= 0 ? '+' : '' }}{{ (simStats.profit_rate || 0).toFixed(2) }}%</div>
<div class="sim-stat-label">收益率</div>
</div>
<div class="sim-stat-item">
<div class="sim-stat-value">{{ simStats.total_trades || 0 }}</div>
<div class="sim-stat-label">交易次数</div>
</div>
</div>
<div class="sim-stats-detail">
<span :class="(simStats.unrealized_profit || 0) >= 0 ? 'profit' : 'loss'">
浮动 {{ (simStats.unrealized_profit || 0) >= 0 ? '+' : '' }}{{ formatMoney(simStats.unrealized_profit || 0) }}
</span>
<span :class="(simStats.realized_profit || 0) >= 0 ? 'profit' : 'loss'">
已实现 {{ (simStats.realized_profit || 0) >= 0 ? '+' : '' }}{{ formatMoney(simStats.realized_profit || 0) }}
</span>
<button type="button" class="sim-btn refresh" @click="updateSimPrices" :disabled="simPositions.length === 0 || simPriceRefreshing" v-if="simPositions.length > 0" style="margin-left:auto;font-size:11px;padding:2px 8px;">
{{ simPriceRefreshing ? '刷新中...' : '刷新现价' }}
</button>
</div>
<!-- 模拟 vs 实盘 对比看板 -->
<div class="sim-compare-panel" v-if="simStats.total_fees > 0 || simStats.total_trades > 0">
<div class="sim-compare-header" @click="compareExpanded = !compareExpanded" class="cursor-pointer">
<span style="font-size:12px;font-weight:600;color:var(--text-secondary);">
<svg class="icon-xs" viewBox="0 0 24 24" fill="none" stroke="var(--warning)" stroke-width="2"><path d="M18 20V10"/><path d="M12 20V4"/><path d="M6 20v-6"/></svg>
模拟 vs 实盘对比
</span>
<span :class="['toggle-icon', { expanded: compareExpanded }]" style="color:var(--text-muted);font-size:10px;"></span>
</div>
<div v-show="compareExpanded" class="sim-compare-body">
<div class="sim-compare-row">
<div class="sim-compare-col">
<div class="sim-compare-label">毛收益 (不含费用)</div>
<div class="sim-compare-value" :class="(simStats.gross_profit || 0) >= 0 ? 'profit' : 'loss'">
{{ (simStats.gross_profit || 0) >= 0 ? '+' : '' }}{{ formatMoney(simStats.gross_profit || 0) }}
<small>({{ (simStats.gross_rate || 0) >= 0 ? '+' : '' }}{{ (simStats.gross_rate || 0).toFixed(2) }}%)</small>
</div>
</div>
<div class="sim-compare-arrow"></div>
<div class="sim-compare-col">
<div class="sim-compare-label">净收益 (扣除费用)</div>
<div class="sim-compare-value" :class="(simStats.net_profit || 0) >= 0 ? 'profit' : 'loss'">
{{ (simStats.net_profit || 0) >= 0 ? '+' : '' }}{{ formatMoney(simStats.net_profit || 0) }}
<small>({{ (simStats.net_rate || 0) >= 0 ? '+' : '' }}{{ (simStats.net_rate || 0).toFixed(2) }}%)</small>
</div>
</div>
</div>
<div class="sim-compare-fees">
<span>总手续费: <b style="color:var(--up);">-{{ formatMoney(simStats.total_fees || 0) }}</b></span>
<span style="color:var(--text-dim);font-size:11px;">
佣金 ¥{{ (simStats.total_commission || 0).toFixed(2) }} +
印花税 ¥{{ (simStats.total_stamp_tax || 0).toFixed(2) }}
</span>
</div>
<div class="sim-compare-tip" v-if="simStats.total_fees > 0">
<span style="color:var(--text-muted);font-size:11px;">
💡 手续费占毛利 {{ simStats.gross_profit > 0 ? ((simStats.total_fees / simStats.gross_profit) * 100).toFixed(1) : '0.0' }}%
| 每笔均费 ¥{{ simStats.total_trades > 0 ? (simStats.total_fees / simStats.total_trades).toFixed(2) : '0.00' }}
</span>
</div>
</div>
</div>
</div>
<!-- 算法配置卡片 -->
<div class="sim-rule-card collapsible">
<div class="sim-rule-header" @click="smartConfigExpanded = !smartConfigExpanded">
<h4>⚙️ 算法配置 <span v-if="smartAlgoIsDefault" style="color:var(--hold);font-size:12px;">(默认)</span></h4>
<span :class="['toggle-icon', { expanded: smartConfigExpanded }]"></span>
</div>
<div v-show="smartConfigExpanded" class="padding-y-sm">
<!-- 模板选择 -->
<div v-if="smartTemplates.length > 0" style="margin-bottom:12px;">
<div style="font-size:13px;font-weight:600;margin-bottom:6px;color:var(--text-secondary);">快速选择算法模板:</div>
<div class="flex-wrap-gap">
<button type="button" v-for="tpl in smartTemplates" :key="tpl.name"
class="sim-btn"
:class="{'auto': smartAlgoConfig?.algo_name === tpl.display_name}"
@click="applyAlgoTemplate(tpl.name)"
style="font-size:12px;padding:4px 10px;">
{{ tpl.display_name }}
<span v-if="tpl.backtest_annual_return" style="opacity:0.7;font-size:11px;"> (年化{{ tpl.backtest_annual_return }}%)</span>
</button>
</div>
</div>
<!-- 当前配置详情 -->
<div v-if="smartAlgoConfig" style="font-size:12px;color:var(--text-secondary);line-height:1.8;">
<div style="display:grid;grid-template-columns:1fr 1fr;gap:4px 16px;">
<span>止盈: <strong style="color:var(--teal);">{{ smartAlgoConfig.take_profit_pct }}%</strong></span>
<span>止损: <strong style="color:var(--up);">{{ smartAlgoConfig.stop_loss_pct }}%</strong></span>
<span>仓位: <strong>{{ smartAlgoConfig.position_pct }}%</strong> <span v-if="smartAlgoConfig.signal_weight">+信号加权</span></span>
<span>最长持仓: <strong>{{ smartAlgoConfig.max_hold_days }}</strong></span>
<span>部分止盈: <strong>{{ smartAlgoConfig.partial_exit_pct }}%</strong></span>
<span>跟踪回撤: <strong>{{ smartAlgoConfig.momentum_trail_gap }}%</strong></span>
<span>保本触发: <strong>{{ smartAlgoConfig.breakeven_at > 0 ? smartAlgoConfig.breakeven_at + '%' : '关闭' }}</strong></span>
<span>卖出确认: <strong>{{ smartAlgoConfig.sell_confirm_days }}</strong></span>
<span>买入时点: <strong style="color:var(--accent-cyan);">{{ smartAlgoConfig.buy_time }}</strong></span>
<span>卖出时点: <strong style="color:var(--accent-cyan);">{{ smartAlgoConfig.sell_time }}</strong></span>
<span>忽略卖信号: <strong>{{ smartAlgoConfig.ignore_sell_signal ? '是' : '否' }}</strong></span>
<span>连涨不平仓: <strong>{{ smartAlgoConfig.no_timeout_if_rising ? '是' : '否' }}</strong></span>
</div>
<!-- 编辑模式 -->
<div v-if="smartConfigEditing" class="border-top-divider">
<div class="grid-2col">
<label class="flex-center">
总本金: <input type="number" v-model.number="smartAlgoConfig.total_capital"
class="input-mini-wide">
</label>
<label class="flex-center">
止盈%: <input type="number" v-model.number="smartAlgoConfig.take_profit_pct" step="1"
class="input-mini">
</label>
<label class="flex-center">
止损%: <input type="number" v-model.number="smartAlgoConfig.stop_loss_pct" step="1"
class="input-mini">
</label>
<label class="flex-center">
仓位%: <input type="number" v-model.number="smartAlgoConfig.position_pct" step="1"
class="input-mini">
</label>
<label class="flex-center">
最长天数: <input type="number" v-model.number="smartAlgoConfig.max_hold_days"
class="input-mini">
</label>
<label class="flex-center">
部分止盈%: <input type="number" v-model.number="smartAlgoConfig.partial_exit_pct"
class="input-mini">
</label>
<label class="flex-center">
保本触发%: <input type="number" v-model.number="smartAlgoConfig.breakeven_at"
class="input-mini">
</label>
<label class="flex-center">
确认天数: <input type="number" v-model.number="smartAlgoConfig.sell_confirm_days"
class="input-mini">
</label>
</div>
<div style="margin-top:8px;display:flex;gap:8px;">
<button type="button" class="sim-btn auto" @click="saveSmartConfig" style="font-size:12px;">保存配置</button>
<button type="button" class="sim-btn" @click="smartConfigEditing = false; loadSmartAlgoConfig();" style="font-size:12px;">取消</button>
</div>
</div>
<div v-else style="margin-top:6px;">
<button type="button" class="sim-btn" @click="smartConfigEditing = true" style="font-size:11px;padding:2px 8px;">✏️ 自定义参数</button>
</div>
</div>
<!-- 自动执行时间说明 -->
<div style="margin-top:8px;font-size:11px;color:var(--text-dim);border-top:1px solid var(--border-glass);padding-top:6px;">
⏰ 每个交易日 <strong style="color:var(--accent-cyan);">{{ smartAlgoConfig?.buy_time || '09:35' }}</strong> 买入 /
<strong style="color:var(--accent-cyan);">{{ smartAlgoConfig?.sell_time || '13:40' }}</strong> 卖出 /
<strong>15:05</strong> 收盘更新 — 基于v7回测最优时点
</div>
</div>
</div>
<!-- 今日交易 -->
<div class="sim-section collapsible-section">
<div class="sim-section-header" @click="todayTradesExpanded = !todayTradesExpanded" class="cursor-pointer">
<h4 class="section-title"><svg class="icon-sm" viewBox="0 0 24 24" fill="none" stroke="var(--accent-cyan)" stroke-width="2"><path d="M12 20V10"/><path d="M18 20V4"/><path d="M6 20v-4"/></svg>今日交易 <span class="badge">{{ todayTrades.length }}</span></h4>
<span :class="['toggle-icon', { expanded: todayTradesExpanded }]" class="text-muted-2"></span>
</div>
<div v-show="todayTradesExpanded && todayTrades.length === 0" class="empty-tip">今日暂无交易</div>
<div v-show="todayTradesExpanded" class="sim-trades-list">
<div v-for="trade in todayTrades" :key="trade.id" :class="['sim-trade-item', trade.trade_type]" @click="loadFundamental(trade.stock_code, trade.stock_name)" class="cursor-pointer">
<div class="sim-trade-type" :class="trade.trade_type">
{{ trade.trade_type === 'buy' ? '买' : '卖' }}
</div>
<div class="sim-trade-content">
<div class="sim-trade-header">
<span class="sim-trade-stock">{{ trade.stock_code }} {{ trade.stock_name }}</span>
<span class="sim-trade-rate" v-if="trade.recommend_rate" title="信号强度评分">信号 {{ trade.recommend_rate }}%</span>
</div>
<div class="sim-trade-detail">
<span>¥{{ trade.price?.toFixed(2) }} × {{ trade.quantity }}股</span>
<span class="sim-trade-amount">{{ formatMoney(trade.price * trade.quantity) }}</span>
</div>
<div class="sim-trade-fee" v-if="trade.total_fee > 0" style="font-size:11px;color:var(--text-muted);">
手续费 ¥{{ trade.total_fee?.toFixed(2) }}
</div>
<div class="sim-trade-reason" v-if="trade.signal_reason">{{ trade.signal_reason }}</div>
<div class="sim-trade-date">{{ trade.trade_time?.substring(0,5) }}</div>
</div>
</div>
</div>
</div>
<!-- 模拟持仓列表(增强版:显示算法状态) -->
<div class="sim-section collapsible-section">
<div class="sim-section-header" @click="simPositionsExpanded = !simPositionsExpanded" class="cursor-pointer">
<h4 class="section-title"><svg class="icon-sm" viewBox="0 0 24 24" fill="none" stroke="var(--teal)" stroke-width="2"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/></svg>当前持仓 <span class="badge">{{ simPositions.length }}</span></h4>
<span :class="['toggle-icon', { expanded: simPositionsExpanded }]" class="text-muted-2"></span>
</div>
<div v-show="simPositionsExpanded && simPositions.length === 0" class="empty-tip">暂无持仓</div>
<div v-show="simPositionsExpanded" class="sim-positions-list">
<div v-for="pos in simPositions" :key="pos.stock_code" class="sim-position-item" @click="loadFundamental(pos.stock_code, pos.stock_name)">
<div class="sim-pos-header">
<span class="sim-pos-code">{{ pos.stock_code }}</span>
<span class="sim-pos-name">{{ pos.stock_name }}</span>
<span class="sim-pos-qty">{{ pos.quantity }}股</span>
</div>
<div class="sim-pos-detail">
<span>成本 ¥{{ pos.avg_cost?.toFixed(2) }}</span>
<span>现价 ¥{{ pos.current_price?.toFixed(2) }}</span>
<span :class="(pos.current_price - pos.avg_cost) >= 0 ? 'profit' : 'loss'">
{{ (pos.current_price - pos.avg_cost) >= 0 ? '+' : '' }}{{ ((pos.current_price - pos.avg_cost) / pos.avg_cost * 100).toFixed(1) }}%
({{ (pos.current_price - pos.avg_cost) >= 0 ? '+' : '' }}¥{{ ((pos.current_price - pos.avg_cost) * pos.quantity).toFixed(0) }})
</span>
</div>
<!-- 算法状态标签 -->
<div v-if="getActiveRules(pos.stock_code).length > 0 || getPositionMeta(pos.stock_code)"
class="sim-pos-algo-status" style="font-size:11px;color:var(--text-muted);margin-top:2px;display:flex;gap:6px;flex-wrap:wrap;">
<span v-for="rule in getActiveRules(pos.stock_code)" :key="rule"
style="background:var(--grad-strategy-text);padding:1px 6px;border-radius:8px;font-size:10px;">{{ rule }}</span>
<span v-if="getPositionMeta(pos.stock_code)?.days_held" style="color:var(--text-dim);">
持{{ getPositionMeta(pos.stock_code).days_held }}天
</span>
<span v-if="getPositionMeta(pos.stock_code)?.consecutive_up_days > 0" style="color:var(--teal);">
连涨{{ getPositionMeta(pos.stock_code).consecutive_up_days }}天
</span>
<span v-if="getPositionMeta(pos.stock_code)?.consecutive_sell_signals > 0" style="color:var(--hold);">
卖信号{{ getPositionMeta(pos.stock_code).consecutive_sell_signals }}天
</span>
</div>
</div>
</div>
</div>
<!-- 信号日志(可折叠) -->
<div class="sim-section collapsible-section">
<div class="sim-section-header" @click="smartSignalExpanded = !smartSignalExpanded" class="cursor-pointer">
<h4 class="section-title"><svg class="icon-sm" viewBox="0 0 24 24" fill="none" stroke="var(--hold)" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/><polyline points="10 9 9 9 8 9"/></svg>信号日志 <span class="badge">{{ smartSignals.length }}</span></h4>
<span :class="['toggle-icon', { expanded: smartSignalExpanded }]" class="text-muted-2"></span>
</div>
<div v-show="smartSignalExpanded">
<div v-if="smartSignals.length === 0" class="empty-tip">暂无信号记录</div>
<div v-else class="max-height-scroll">
<div v-for="sig in smartSignals" :key="sig.id"
style="padding:6px 0;border-bottom:1px solid var(--grad-strategy-text);font-size:12px;display:flex;gap:8px;align-items:flex-start;">
<span :style="{
color: sig.action === 'buy' ? 'var(--up)' :
sig.action === 'sell' ? 'var(--teal)' :
sig.action === 'partial_sell' ? 'var(--hold)' : 'var(--text-muted)',
fontWeight: 600, minWidth: '48px'
}">
{{ sig.action === 'buy' ? '买入' : sig.action === 'sell' ? '卖出' :
sig.action === 'partial_sell' ? '减仓' : sig.action === 'hold' ? '持有' : sig.action }}
</span>
<span style="color:var(--text-secondary);flex:1;">
{{ sig.stock_code }}
<span v-if="sig.algo_rule" style="color:var(--accent-cyan);font-size:11px;">[{{ sig.algo_rule }}]</span>
{{ sig.reason }}
<span v-if="sig.profit_pct" :style="{color: sig.profit_pct >= 0 ? 'var(--teal)' : 'var(--up)'}">
({{ sig.profit_pct >= 0 ? '+' : '' }}{{ sig.profit_pct?.toFixed(1) }}%)
</span>
</span>
<span style="color:var(--text-dim);font-size:11px;white-space:nowrap;">{{ sig.signal_date }}</span>
</div>
</div>
</div>
</div>
<!-- 模拟交易记录 -->
<div class="sim-section collapsible-section">
<div class="sim-section-header" @click="simTradesExpanded = !simTradesExpanded" class="cursor-pointer">
<h4 class="section-title"><svg class="icon-sm" viewBox="0 0 24 24" fill="none" stroke="var(--purple-light)" stroke-width="2"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>交易记录 <span class="badge">{{ simTrades.length }}</span></h4>
<span :class="['toggle-icon', { expanded: simTradesExpanded }]" class="text-muted-2"></span>
</div>
<div v-show="simTradesExpanded && simTrades.length === 0" class="empty-tip">暂无交易记录</div>
<div v-show="simTradesExpanded" class="sim-trades-list">
<div v-for="trade in simTrades" :key="trade.id" :class="['sim-trade-item', trade.trade_type]" @click="loadFundamental(trade.stock_code, trade.stock_name)" class="cursor-pointer">
<div class="sim-trade-type" :class="trade.trade_type">
{{ trade.trade_type === 'buy' ? '买' : '卖' }}
</div>
<div class="sim-trade-content">
<div class="sim-trade-header">
<span class="sim-trade-stock">{{ trade.stock_code }} {{ trade.stock_name }}</span>
<span class="sim-trade-rate" v-if="trade.recommend_rate" title="信号强度评分">信号 {{ trade.recommend_rate }}%</span>
</div>
<div class="sim-trade-detail">
<span>¥{{ trade.price?.toFixed(2) }} × {{ trade.quantity }}股</span>
<span class="sim-trade-amount">{{ formatMoney(trade.price * trade.quantity) }}</span>
</div>
<div class="sim-trade-fee" v-if="trade.total_fee > 0" style="font-size:11px;color:var(--text-muted);">
手续费 ¥{{ trade.total_fee?.toFixed(2) }}
<span style="color:var(--text-dim);">(佣金{{ trade.commission?.toFixed(2) }}{{ trade.stamp_tax > 0 ? ' + 印花税' + trade.stamp_tax?.toFixed(2) : '' }})</span>
</div>
<div class="sim-trade-reason" v-if="trade.signal_reason">{{ trade.signal_reason }}</div>
<div class="sim-trade-date">{{ trade.trade_date }} {{ trade.trade_time?.substring(0,5) }}</div>
</div>
</div>
</div>
</div>
</div><!-- 旧模拟交易占位结束 -->
</div><!-- 分析页面结束 -->
<!-- 模型页面 -->
<div v-show="activeTab === 'model'" class="model-page">
<!-- 模型页子导航 -->
<div class="sub-tabs">
<button type="button" :class="['sub-tab', { active: modelSubTab === 'system' }]" @click="modelSubTab = 'system'">
信号体系
</button>
<button type="button" :class="['sub-tab', { active: modelSubTab === 'sim' }]" @click="modelSubTab = 'sim'; loadSimData()">
模拟交易
</button>
</div>
<!-- 信号体系子页面 -->
<div v-show="modelSubTab === 'system'">
<!-- 信号胜率排行 -->
<div class="signal-system-section">
<h4 class="signal-system-title">交易信号胜率排行</h4>
<div class="signal-rank-list">
<div class="signal-rank-item rank-1">
<span class="rank-badge">1</span>
<span class="rank-name">★主升浪</span>
<span class="rank-rate">85%</span>
<span class="rank-desc">趋势走好,进入加速拉升阶段</span>
<span class="rank-param">MACD零上金叉</span>
</div>
<div class="signal-rank-item rank-2">
<span class="rank-badge">2</span>
<span class="rank-name">日线底背离</span>
<span class="rank-rate">80%</span>
<span class="rank-desc">真正跌透,迎来大级别反转</span>
<span class="rank-param">20日新低版</span>
</div>
<div class="signal-rank-item rank-3">
<span class="rank-badge">3</span>
<span class="rank-name">龙抬头</span>
<span class="rank-rate">75%</span>
<span class="rank-desc">短线起爆点,反弹稳定性强</span>
<span class="rank-param">SKDJ超跌+不漂移</span>
</div>
<div class="signal-rank-item rank-4">
<span class="rank-badge">4</span>
<span class="rank-name">真龙</span>
<span class="rank-rate">70%</span>
<span class="rank-desc">中期趋势刚刚启动</span>
<span class="rank-param">趋势启动</span>
</div>
<div class="signal-rank-item rank-5">
<span class="rank-badge">5</span>
<span class="rank-name">短底背离</span>
<span class="rank-rate">65%</span>
<span class="rank-desc">小级别反弹,灵敏度高但力度偏弱</span>
<span class="rank-param">10/30版</span>
</div>
<div class="signal-rank-item rank-6">
<span class="rank-badge">6</span>
<span class="rank-name">老鼠仓</span>
<span class="rank-rate">60%</span>
<span class="rank-desc">主力偷偷吸筹,上涨不具备即时性</span>
<span class="rank-param">异常量价</span>
</div>
<div class="signal-rank-item rank-7">
<span class="rank-badge">7</span>
<span class="rank-name">反弹</span>
<span class="rank-rate">55%</span>
<span class="rank-desc">普通均线金叉,震荡市适用</span>
<span class="rank-param">EMA3上穿EMA21</span>
</div>
</div>
</div>
<!-- 标准牛股启动信号顺序 -->
<div class="signal-system-section bull-flow-section">
<h4 class="signal-system-title">标准牛股启动顺序</h4>
<div class="bull-flow">
<div class="bull-step"><span class="bull-num">1</span><span class="bull-label">底背离/短底背离</span><span class="bull-hint">跌到底部,停止下跌</span></div>
<div class="bull-arrow"></div>
<div class="bull-step"><span class="bull-num">2</span><span class="bull-label">龙抬头</span><span class="bull-hint">资金进场,短线起爆</span></div>
<div class="bull-arrow"></div>
<div class="bull-step"><span class="bull-num">3</span><span class="bull-label">真龙</span><span class="bull-hint">趋势正式确立</span></div>
<div class="bull-arrow"></div>
<div class="bull-step"><span class="bull-num">4</span><span class="bull-label">★主升浪</span><span class="bull-hint">加速段,利润最快</span></div>
<div class="bull-arrow"></div>
<div class="bull-step"><span class="bull-num">5</span><span class="bull-label">反弹</span><span class="bull-hint">回调后补涨信号</span></div>
</div>
<div class="bull-note">老鼠仓可在底部任意位置提前出现,属于提前埋伏类信号</div>
</div>
<!-- 体系最强战法 -->
<div class="signal-system-section highlight-section">
<h4 class="signal-system-title">体系最强战法</h4>
<div class="strategy-steps">
<div class="strategy-step step-watch">
<span class="step-icon">👀</span>
<span class="step-action">关注</span>
<span class="step-rule">日线底背离出现 → 纳入关注范围</span>
</div>
<div class="strategy-step step-buy">
<span class="step-icon">💰</span>
<span class="step-action">买入</span>
<span class="step-rule">龙抬头出现 → 执行买入操作</span>
</div>
<div class="strategy-step step-add">
<span class="step-icon">📈</span>
<span class="step-action">加仓</span>
<span class="step-rule">真龙 / ★主升浪出现 → 持有并加仓</span>
</div>
<div class="strategy-step step-hold">
<span class="step-icon">🔒</span>
<span class="step-action">持有</span>
<span class="step-rule">不见主升浪 → 坚决不出场</span>
</div>
</div>
</div>
<!-- 核心信号一句话总结 -->
<div class="signal-system-section">
<h4 class="signal-system-title">核心信号一句话总结</h4>
<div class="signal-summary-list">
<div class="signal-summary-item"><span class="summary-tag core">★主升浪</span>最稳、最猛(利润核心阶段)</div>
<div class="signal-summary-item"><span class="summary-tag core">日线底背离</span>最安全抄底(反转前置信号)</div>
<div class="signal-summary-item"><span class="summary-tag core">龙抬头</span>最佳入场点(实操核心买点)</div>
<div class="signal-summary-item"><span class="summary-tag normal">真龙</span>趋势确认(中期行情定局信号)</div>
<div class="signal-summary-item"><span class="summary-tag aux">短底背离 / 反弹</span>仅作辅助参考,不单独作为核心决策依据</div>
</div>
</div>
</div><!-- 信号体系子页面结束 -->
<!-- 模拟交易子页面 -->
<div v-show="modelSubTab === 'sim'" class="sim-trade-page">
<!-- 模拟交易统计卡片 -->
<div class="sim-stats-card">
<div class="sim-stats-header">
<h4>智能交易 <span v-if="smartAlgoConfig" style="font-size:12px;color:var(--text-muted);">{{ smartAlgoConfig.algo_name }}</span></h4>
<div class="sim-actions">
<button type="button" class="sim-btn auto" @click="executeAutoTrade" :disabled="simAutoTrading">
{{ simAutoTrading ? '执行中...' : '执行' }}
</button>
<button type="button" class="sim-btn reset" @click="confirmResetSim">重置</button>
</div>
</div>
<div class="sim-stats-grid">
<div class="sim-stat-item">
<div class="sim-stat-value">{{ formatMoney(smartAlgoConfig?.total_capital || simStats.initial_capital || 200000) }}</div>
<div class="sim-stat-label">总本金</div>
</div>
<div class="sim-stat-item">
<div class="sim-stat-value">{{ formatMoney(simStats.total_market_value || 0) }}</div>
<div class="sim-stat-label">持仓市值</div>
</div>
<div class="sim-stat-item">
<div class="sim-stat-value">{{ formatMoney(simStats.cash || (smartAlgoConfig?.total_capital || 200000)) }}</div>
<div class="sim-stat-label">可用资金</div>
</div>
<div class="sim-stat-item" :class="(simStats.total_profit || 0) >= 0 ? 'profit' : 'loss'">
<div class="sim-stat-value">{{ (simStats.total_profit || 0) >= 0 ? '+' : '' }}{{ formatMoney(simStats.total_profit || 0) }}</div>
<div class="sim-stat-label">总盈亏</div>
</div>
<div class="sim-stat-item" :class="(simStats.profit_rate || 0) >= 0 ? 'profit' : 'loss'">
<div class="sim-stat-value">{{ (simStats.profit_rate || 0) >= 0 ? '+' : '' }}{{ (simStats.profit_rate || 0).toFixed(2) }}%</div>
<div class="sim-stat-label">收益率</div>
</div>
<div class="sim-stat-item">
<div class="sim-stat-value">{{ simStats.total_trades || 0 }}</div>
<div class="sim-stat-label">交易次数</div>
</div>
</div>
<div class="sim-stats-detail">
<span :class="(simStats.unrealized_profit || 0) >= 0 ? 'profit' : 'loss'">
浮动 {{ (simStats.unrealized_profit || 0) >= 0 ? '+' : '' }}{{ formatMoney(simStats.unrealized_profit || 0) }}
</span>
<span :class="(simStats.realized_profit || 0) >= 0 ? 'profit' : 'loss'">
已实现 {{ (simStats.realized_profit || 0) >= 0 ? '+' : '' }}{{ formatMoney(simStats.realized_profit || 0) }}
</span>
<button type="button" class="sim-btn refresh" @click="updateSimPrices" :disabled="simPositions.length === 0 || simPriceRefreshing" v-if="simPositions.length > 0" style="margin-left:auto;font-size:11px;padding:2px 8px;">
{{ simPriceRefreshing ? '刷新中...' : '刷新现价' }}
</button>
</div>
</div>
<!-- 模拟持仓和交易历史直接复用现有逻辑 -->
<div class="sim-section collapsible-section" v-if="simPositions.length > 0">
<div class="sim-section-header" class="cursor-pointer" @click="simPositionsExpanded = !simPositionsExpanded">
<h4 class="section-title">持仓 <span class="badge">{{ simPositions.length }}</span></h4>
<span class="expand-arrow" :class="{ expanded: simPositionsExpanded }"></span>
</div>
<div v-show="simPositionsExpanded" class="sim-positions-list">
<div v-for="pos in simPositions" :key="pos.stock_code" class="sim-position-item" @click="loadFundamental(pos.stock_code, pos.stock_name)" class="cursor-pointer">
<div class="sim-pos-header">
<span class="sim-pos-stock">{{ pos.stock_code }} {{ pos.stock_name }}</span>
<span class="sim-pos-profit" :class="(pos.unrealized_profit || 0) >= 0 ? 'profit' : 'loss'">
{{ (pos.unrealized_profit || 0) >= 0 ? '+' : '' }}{{ formatMoney(pos.unrealized_profit || 0) }}
({{ (pos.profit_rate || 0) >= 0 ? '+' : '' }}{{ (pos.profit_rate || 0).toFixed(2) }}%)
</span>
</div>
<div class="sim-pos-detail">
<span>{{ pos.quantity }}股 @ ¥{{ (pos.avg_cost || 0).toFixed(2) }}</span>
<span v-if="pos.current_price">现价 ¥{{ pos.current_price.toFixed(2) }}</span>
</div>
</div>
</div>
</div>
</div><!-- 模拟交易子页面结束 -->
</div><!-- 模型页面结束 -->
<!-- 交易记录页面 -->
<div v-show="activeTab === 'trades'">
<!-- 交易统计卡片 -->
<div class="trade-stats-card" v-if="tradeStats && tradeStats.total_trades > 0">
<h4>我的交易统计</h4>
<div class="stats-grid">
<div class="stat-item">
<div class="stat-value">{{ tradeStats.total_trades }}</div>
<div class="stat-label">交易次数</div>
</div>
<div class="stat-item">
<div class="stat-value">{{ formatMoney(tradeStats.total_market_value) }}</div>
<div class="stat-label">持仓市值</div>
</div>
<div class="stat-item" :class="tradeStats.total_profit >= 0 ? 'profit' : 'loss'">
<div class="stat-value">{{ tradeStats.total_profit >= 0 ? '+' : '' }}{{ formatMoney(tradeStats.total_profit) }}</div>
<div class="stat-label">总盈亏</div>
</div>
</div>
<div class="stats-detail">
<span :class="tradeStats.realized_profit >= 0 ? 'profit' : 'loss'">
已清仓 {{ tradeStats.realized_profit >= 0 ? '+' : '' }}{{ formatMoney(tradeStats.realized_profit || 0) }}
</span>
<span :class="tradeStats.unrealized_profit >= 0 ? 'profit' : 'loss'">
浮动 {{ tradeStats.unrealized_profit >= 0 ? '+' : '' }}{{ formatMoney(tradeStats.unrealized_profit) }}
</span>
</div>
<!-- 可用资金 -->
<div class="available-cash-row">
<span class="cash-label">可用资金</span>
<template v-if="!editingCash">
<span class="cash-value">{{ formatMoney(availableCash) }}</span>
<button type="button" class="cash-edit-btn" @click="startEditCash" title="编辑可用资金">✏️</button>
</template>
<template v-else>
<input type="number" ref="cashInput" v-model="cashInputValue" class="cash-input"
@keyup.enter="saveCash" @keyup.esc="cancelEditCash" placeholder="输入金额">
<button type="button" class="cash-save-btn" @click="saveCash"></button>
<button type="button" class="cash-cancel-btn" @click="cancelEditCash"></button>
</template>
</div>
<!-- 总资产 = 持仓市值 + 可用资金 -->
<div class="total-assets-row">
<span class="assets-label">总资产</span>
<span class="assets-value">{{ formatMoney((tradeStats.total_market_value || 0) + availableCash) }}</span>
</div>
</div>
<!-- 止损预警区(可折叠) -->
<div v-if="stopLossAlerts && stopLossAlerts.length > 0" class="stoploss-alerts-card stoploss-collapsible">
<div class="stoploss-alerts-header" role="button" tabindex="0" :aria-expanded="stopLossAlertsExpanded" @click="stopLossAlertsExpanded = !stopLossAlertsExpanded" @keyup.enter="stopLossAlertsExpanded = !stopLossAlertsExpanded">
<h4>⚠️ 止损预警 <span class="stoploss-badge">{{ stopLossAlerts.length }}</span></h4>
<span :class="['toggle-icon', { expanded: stopLossAlertsExpanded }]"></span>
</div>
<div v-show="stopLossAlertsExpanded" class="stoploss-alerts-body">
<div v-for="alert in stopLossAlerts" :key="alert.code" class="stoploss-alert-item">
<div class="stoploss-alert-header">
<span class="alert-stock">{{ alert.code }} {{ alert.name }}</span>
<span class="alert-loss">{{ alert.profit_percent.toFixed(1) }}%</span>
</div>
<div class="stoploss-alert-detail">
<span>成本 ¥{{ alert.avg_cost }}</span>
<span>现价 ¥{{ alert.current_price }}</span>
<span v-if="alert.stop_loss_price">止损 ¥{{ alert.stop_loss_price }}</span>
</div>
<div class="stoploss-alert-message">{{ alert.message }}</div>
<button type="button" class="stoploss-sell-btn" @click="quickSellFromStopLoss(alert)">立即卖出</button>
</div>
</div>
</div>
<!-- 操作按钮区 -->
<div class="trade-actions-bar">
<button type="button" class="add-trade-btn" @click="openTradeForm" :disabled="allStocksForTrade.length === 0">
{{ allStocksForTrade.length === 0 ? '请先分析股票' : '记录交易' }}
</button>
<button type="button" class="refresh-price-btn" @click="refreshHoldingPrices" :disabled="priceRefreshing">
{{ priceRefreshing ? '刷新中...' : '刷新价格' }}
</button>
</div>
<!-- 交易记录表单弹窗 -->
<div v-if="showTradeForm" class="modal-overlay" @click.self="showTradeForm = false" role="dialog" aria-modal="true" aria-label="记录交易">
<div class="modal-content">
<h3>记录交易</h3>
<form @submit.prevent="submitTrade">
<div class="form-row">
<label>股票 (关注/持有)</label>
<select v-model="selectedStockFromHistory" @change="onStockSelected" required>
<option value="">请选择股票</option>
<option v-for="item in allStocksForTrade" :key="item.code" :value="item.code">
{{ item.isHolding ? '📦 ' : '' }}{{ item.code }} - {{ item.name }}
</option>
</select>
</div>
<div class="form-row" v-if="selectedStockFromHistory">
<label>交易信号(自动获取)</label>
<div class="signal-display" :class="selectedStockSignal.type">
{{ selectedStockSignal.icon }} {{ selectedStockSignal.title }}: {{ selectedStockSignal.description }}
</div>
</div>
<div class="form-row">
<label>交易类型</label>
<select v-model="newTrade.trade_type" required>
<option value="buy">买入</option>
<option value="sell">卖出</option>
</select>
</div>
<div class="form-row">
<label>交易价格</label>
<input v-model="newTrade.price" type="number" step="0.0001" required>
</div>
<div class="form-row">
<label>交易数量</label>
<input v-model="newTrade.quantity" type="number" required>
</div>
<div class="form-row">
<label>交易日期</label>
<input v-model="newTrade.trade_date" type="date" required>
</div>
<div class="form-row">
<label>交易结果</label>
<select v-model="newTrade.result">
<option value="pending">待定</option>
<option value="profit">盈利</option>
<option value="loss">亏损</option>
</select>
</div>
<div class="form-row" v-if="newTrade.result !== 'pending'">
<label>盈亏金额</label>
<input v-model="newTrade.profit_amount" type="number" step="0.0001">
</div>
<div class="form-row" v-if="newTrade.trade_type === 'buy'">
<label>止损价(跌破此价提醒卖出)</label>
<input v-model="newTrade.stop_loss_price" type="number" step="0.01" placeholder="建议设为成本价的95%">
</div>
<div class="form-row">
<label>备注</label>
<textarea v-model="newTrade.notes" rows="2"></textarea>
</div>
<div class="form-actions">
<button type="button" @click="showTradeForm = false">取消</button>
<button type="submit">保存</button>
</div>
</form>
</div>
</div>
<!-- 持有/清仓 子Tab -->
<div class="trade-sub-tabs">
<button type="button" :class="['trade-sub-tab', { active: tradeViewType === 'holding' }]" @click="tradeViewType = 'holding'">
持有 <span class="tab-count">{{ holdingGroupCount }}</span>
</button>
<button type="button" :class="['trade-sub-tab', { active: tradeViewType === 'cleared' }]" @click="tradeViewType = 'cleared'">
清仓 <span class="tab-count">{{ clearedGroupCount }}</span>
</button>
</div>
<!-- 交易记录列表(按股票分组、时间倒序) -->
<div class="trades-list">
<div v-if="filteredGroupedTrades.length === 0" class="empty-trades">
{{ tradeViewType === 'holding' ? '暂无持有股票' : '暂无清仓记录' }}
</div>
<!-- 按股票分组显示 -->
<div v-for="group in filteredGroupedTrades" :key="group.code" class="trade-group">
<!-- 股票分组标题 -->
<div class="trade-group-header">
<button type="button" class="toggle-btn" @click.stop="toggleTradeGroup(group.code)">
{{ expandedTradeGroups[group.code] ? '▼' : '▶' }}
</button>
<div class="trade-group-content" role="button" tabindex="0" @click="loadFundamental(group.code, group.name)" @keyup.enter="loadFundamental(group.code, group.name)">
<!-- 第一行:股票信息 -->
<div class="trade-group-info">
<span class="trade-group-code">{{ group.code }}</span>
<span class="trade-group-name">{{ group.name }}</span>
<span class="trade-group-count">{{ group.trades.length }}笔</span>
<span v-if="holdingPositions[group.code]?.quantity > 0" class="holding-badge">{{ holdingPositions[group.code].quantity }}股</span>
</div>
<!-- 第二行:持有中显示现价、总市值和浮动盈亏 -->
<div class="trade-summary-stats" v-if="holdingPositions[group.code]?.quantity > 0 && holdingPositions[group.code].currentPrice">
<div class="summary-stat-item">
<div :class="['summary-stat-value', holdingPositions[group.code].priceDirection === 'up' ? 'price-up' : (holdingPositions[group.code].priceDirection === 'down' ? 'price-down' : '')]">{{ holdingPositions[group.code].currentPrice.toFixed(2) }}</div>
<div class="summary-stat-label">现价</div>
</div>
<div class="summary-stat-item">
<div class="summary-stat-value">{{ (holdingPositions[group.code].totalCost / holdingPositions[group.code].quantity).toFixed(2) }}</div>
<div class="summary-stat-label">平衡价</div>
</div>
<div class="summary-stat-item">
<div class="summary-stat-value">{{ formatMoney(holdingPositions[group.code].currentPrice * holdingPositions[group.code].quantity) }}</div>
<div class="summary-stat-label">市值</div>
</div>
<div class="summary-stat-item" :class="(holdingPositions[group.code].currentPrice * holdingPositions[group.code].quantity - holdingPositions[group.code].totalCost) >= 0 ? 'profit' : 'loss'">
<div class="summary-stat-value">{{ (holdingPositions[group.code].currentPrice * holdingPositions[group.code].quantity - holdingPositions[group.code].totalCost) >= 0 ? '+' : '' }}{{ formatMoney(holdingPositions[group.code].currentPrice * holdingPositions[group.code].quantity - holdingPositions[group.code].totalCost) }}</div>
<div class="summary-stat-label">盈亏</div>
</div>
</div>
<!-- 已清仓:显示已实现盈亏 -->
<div class="trade-group-summary" v-else-if="group.realizedProfit !== 0">
<span class="holding-badge cleared">已清仓</span>
<span :class="['holding-profit', group.realizedProfit >= 0 ? 'profit' : 'loss']">
已实现 {{ group.realizedProfit >= 0 ? '+' : '' }}{{ formatMoney(group.realizedProfit) }}
</span>
</div>
</div>
</div>
<!-- 该股票的交易记录(按时间倒序) -->
<div v-for="trade in group.trades" :key="trade.id" v-show="expandedTradeGroups[group.code]" :class="['trade-item', trade.trade_type]">
<div class="trade-type-indicator" :class="trade.trade_type">
{{ trade.trade_type === 'buy' ? '买' : '卖' }}
</div>
<div class="trade-content">
<div class="trade-header" v-if="trade.result !== 'pending'">
<span :class="['trade-result', trade.result]">
{{ trade.result === 'profit' ? '盈利' : '亏损' }}
</span>
</div>
<div class="trade-amount-row">
<div class="trade-amount">
¥{{ formatMoney(trade.price * trade.quantity) }}
</div>
<div v-if="holdingPositions[trade.stock_code]?.currentPrice && trade.trade_type === 'buy'"
:class="['trade-profit', (holdingPositions[trade.stock_code].currentPrice - trade.price) * trade.quantity >= 0 ? 'profit' : 'loss']">
{{ (holdingPositions[trade.stock_code].currentPrice - trade.price) * trade.quantity >= 0 ? '+' : '' }}{{ formatMoney((holdingPositions[trade.stock_code].currentPrice - trade.price) * trade.quantity) }}
</div>
</div>
<div class="trade-details">
<span>{{ trade.price }}元 × {{ trade.quantity }}股</span>
<span v-if="holdingPositions[trade.stock_code]?.currentPrice && trade.trade_type === 'buy'"
:class="[holdingPositions[trade.stock_code].priceDirection === 'up' ? 'price-up' : (holdingPositions[trade.stock_code].priceDirection === 'down' ? 'price-down' : '')]">
现价 {{ holdingPositions[trade.stock_code].currentPrice.toFixed(2) }}元
</span>
</div>
<div class="trade-reason" v-if="trade.reason">
信号: {{ trade.reason }}
</div>
<div class="trade-notes" v-if="trade.notes">
备注: {{ trade.notes }}
</div>
<div class="trade-date">{{ trade.trade_date }}</div>
</div>
<div class="trade-actions-vertical">
<button type="button" @click="editTrade(trade)">编辑</button>
<button type="button" @click="deleteTrade(trade.id)">删除</button>
</div>
</div>
</div>
</div>
</div><!-- 交易记录页面结束 -->
</template><!-- 已登录内容结束 -->
<!-- 修改密码弹窗(独立于条件链) -->
<div v-if="showPasswordModal" class="modal-overlay" @click.self="showPasswordModal = false">
<div class="login-modal">
<div class="login-header">
<h2>修改密码</h2>
</div>
<div class="login-body">
<div class="login-field">
<label>当前密码</label>
<input v-model="passwordForm.oldPassword" type="password" placeholder="请输入当前密码">
</div>
<div class="login-field">
<label>新密码</label>
<input v-model="passwordForm.newPassword" type="password" placeholder="请输入新密码(至少6位)">
</div>
<div class="login-field">
<label>确认新密码</label>
<input v-model="passwordForm.confirmPassword" type="password" placeholder="请再次输入新密码" @keyup.enter="handleChangePassword">
</div>
<div v-if="passwordError" class="login-error">{{ passwordError }}</div>
<div v-if="passwordSuccess" class="login-success">{{ passwordSuccess }}</div>
<div class="password-buttons">
<button type="button" class="btn-cancel" @click="showPasswordModal = false">关闭</button>
<button type="button" class="login-submit" @click="handleChangePassword" :disabled="passwordLoading">
{{ passwordLoading ? '处理中...' : '确认修改' }}
</button>
</div>
<a v-if="currentUser && currentUser.is_admin" href="/admin" target="_blank" class="admin-link-btn">进入管理后台</a>
</div>
</div>
</div>
</div>
</div>
{% endraw %}
<script src="/static/js/app.js?v=20260718v2"></script>
</body>
</html>