|
|
@@ -1,124 +1,130 @@
|
|
|
<template>
|
|
|
- <scroll-view class="page" scroll-y>
|
|
|
- <!-- 顶部标题(量化选股大师) -->
|
|
|
- <view class="page-title">量化选股大师</view>
|
|
|
-
|
|
|
- <!-- 顶部查询卡片 -->
|
|
|
- <view class="card search-card" style="position: relative; z-index: 100;">
|
|
|
- <text class="card-title">量化分数实时查询 & 历史数据</text>
|
|
|
-
|
|
|
- <view class="search-row">
|
|
|
- <input
|
|
|
- class="search-input"
|
|
|
- type="text"
|
|
|
- placeholder="请输入股票代码/名称 (如: 600030)"
|
|
|
- placeholder-class="search-placeholder"
|
|
|
- confirm-type="search"
|
|
|
- v-model="keyword"
|
|
|
- @input="onKeywordChange"
|
|
|
- @confirm="onSearch"
|
|
|
- @blur="onInputBlur"
|
|
|
- />
|
|
|
- <view class="search-button" @click="onSearch">
|
|
|
- <text class="icon-search"></text>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
-
|
|
|
- <!-- 模糊搜索下拉列表 -->
|
|
|
- <view class="search-dropdown" v-if="showDropdown && suggestions.length > 0">
|
|
|
- <view
|
|
|
- v-for="(item, index) in suggestions"
|
|
|
- :key="index"
|
|
|
- class="dropdown-item"
|
|
|
- hover-class="dropdown-item-hover"
|
|
|
- @click.stop="onSelectSuggestion(item)"
|
|
|
- >
|
|
|
- <text class="item-name">{{item.name}}</text>
|
|
|
- <text class="item-code">{{item.code}}</text>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
-
|
|
|
- <text class="search-tip">支持A股代码或名称模糊查询</text>
|
|
|
+ <view class="page-container">
|
|
|
+ <!-- 顶部标题卡片 -->
|
|
|
+ <view class="page-title-card">
|
|
|
+ <text class="page-title-text">量化选股大师</text>
|
|
|
</view>
|
|
|
-
|
|
|
- <!-- 查询结果 -->
|
|
|
- <view v-if="hasSearched" class="card result-card">
|
|
|
- <view v-if="loading">
|
|
|
- <text class="result-loading">正在查询,请稍候...</text>
|
|
|
- </view>
|
|
|
- <view v-else-if="errorMsg">
|
|
|
- <text class="result-error">{{errorMsg}}</text>
|
|
|
- </view>
|
|
|
- <view v-else-if="result">
|
|
|
- <!-- 头部:名称 / 代码 / 分数徽章 -->
|
|
|
- <view class="detail-header">
|
|
|
- <view>
|
|
|
- <view class="detail-name">{{result.stockName}}({{result.stockCode}})</view>
|
|
|
- <view class="detail-sub">最新量化系统评分</view>
|
|
|
+ <scroll-view class="scroll-view" scroll-y>
|
|
|
+ <view class="content-wrapper">
|
|
|
+
|
|
|
+ <!-- 顶部查询卡片 -->
|
|
|
+ <view class="card search-card" style="position: relative; z-index: 100;">
|
|
|
+ <text class="card-title">量化分数实时查询 & 历史数据</text>
|
|
|
+
|
|
|
+ <view class="search-row">
|
|
|
+ <input
|
|
|
+ class="search-input"
|
|
|
+ type="text"
|
|
|
+ placeholder="请输入股票代码/名称 (如: 600030)"
|
|
|
+ placeholder-class="search-placeholder"
|
|
|
+ confirm-type="search"
|
|
|
+ v-model="keyword"
|
|
|
+ @input="onKeywordChange"
|
|
|
+ @confirm="onSearch"
|
|
|
+ @blur="onInputBlur"
|
|
|
+ />
|
|
|
+ <view class="search-button" @click="onSearch">
|
|
|
+ <text class="icon-search"></text>
|
|
|
+ </view>
|
|
|
</view>
|
|
|
- <view class="score-badge">{{result.score}}</view>
|
|
|
+
|
|
|
+ <!-- 模糊搜索下拉列表 -->
|
|
|
+ <view class="search-dropdown" v-if="showDropdown && suggestions && suggestions.length > 0">
|
|
|
+ <view
|
|
|
+ v-for="(item, index) in suggestions"
|
|
|
+ :key="index"
|
|
|
+ class="dropdown-item"
|
|
|
+ hover-class="dropdown-item-hover"
|
|
|
+ @tap.stop="onSelectSuggestion(item)"
|
|
|
+ >
|
|
|
+ <text class="item-name">{{item.name}}</text>
|
|
|
+ <text class="item-code">{{item.code}}</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <text class="search-tip">支持A股代码或名称模糊查询</text>
|
|
|
</view>
|
|
|
|
|
|
- <!-- 历史评分趋势 -->
|
|
|
- <view class="section">
|
|
|
- <view class="section-title">历史评分趋势</view>
|
|
|
- <view class="history-row" v-for="(item, index) in result.history" :key="index">
|
|
|
- <text class="history-date">{{item.date}} 的量化评分:</text>
|
|
|
- <text :class="['history-score', item.score >= 90 ? 'tag-danger' : (item.score >= 80 ? 'tag-success' : 'tag-info')]">
|
|
|
- {{item.score}}
|
|
|
- </text>
|
|
|
+ <!-- 查询结果 -->
|
|
|
+ <view v-if="hasSearched" class="card result-card">
|
|
|
+ <view v-if="loading">
|
|
|
+ <text class="result-loading">正在查询,请稍候...</text>
|
|
|
+ </view>
|
|
|
+ <view v-else-if="errorMsg">
|
|
|
+ <text class="result-error">{{errorMsg}}</text>
|
|
|
+ </view>
|
|
|
+ <view v-else-if="result">
|
|
|
+ <!-- 头部:名称 / 代码 / 分数徽章 -->
|
|
|
+ <view class="detail-header">
|
|
|
+ <view>
|
|
|
+ <view class="detail-name">{{result.stockName}}({{result.stockCode}})</view>
|
|
|
+ <view class="detail-sub">最新量化系统评分</view>
|
|
|
+ </view>
|
|
|
+ <view class="score-badge">{{result.score}}</view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 历史评分趋势 -->
|
|
|
+ <view class="section">
|
|
|
+ <view class="section-title">历史评分趋势</view>
|
|
|
+ <view class="history-row" v-for="(item, index) in result.history" :key="index">
|
|
|
+ <text class="history-date">{{item.date}} 的量化评分:</text>
|
|
|
+ <text :class="['history-score', item.score >= 90 ? 'tag-danger' : (item.score >= 80 ? 'tag-success' : 'tag-info')]">
|
|
|
+ {{item.score}}
|
|
|
+ </text>
|
|
|
+ </view>
|
|
|
+ <text class="history-note">(注意:此为模拟历史数据,仅供展示。)</text>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 评分因子构成 -->
|
|
|
+ <view class="section">
|
|
|
+ <view class="section-title">评分因子构成</view>
|
|
|
+ <view class="factor-row" v-for="(item, index) in result.factors" :key="index">
|
|
|
+ <text class="factor-name">{{item.name}}</text>
|
|
|
+ <text class="factor-score">{{item.value}}</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
</view>
|
|
|
- <text class="history-note">(注意:此为模拟历史数据,仅供展示。)</text>
|
|
|
</view>
|
|
|
|
|
|
- <!-- 评分因子构成 -->
|
|
|
- <view class="section">
|
|
|
- <view class="section-title">评分因子构成</view>
|
|
|
- <view class="factor-row" v-for="(item, index) in result.factors" :key="index">
|
|
|
- <text class="factor-name">{{item.name}}</text>
|
|
|
- <text class="factor-score">{{item.value}}</text>
|
|
|
+ <!-- 量化投资的优势 -->
|
|
|
+ <view class="card advantage-card">
|
|
|
+ <view class="card-header">
|
|
|
+ <view class="icon-circle">
|
|
|
+ <text class="icon-check">✓</text>
|
|
|
+ </view>
|
|
|
+ <text class="card-header-title">量化投资的优势</text>
|
|
|
</view>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
|
|
|
- <!-- 量化投资的优势 -->
|
|
|
- <view class="card advantage-card">
|
|
|
- <view class="card-header">
|
|
|
- <view class="icon-circle">
|
|
|
- <text class="icon-check">✓</text>
|
|
|
+ <view class="advantage-item">
|
|
|
+ <text class="advantage-label">客观纪律性:</text>
|
|
|
+ <text class="advantage-desc">排除情绪干扰,严格执行预设的交易信号。</text>
|
|
|
+ </view>
|
|
|
+ <view class="advantage-item">
|
|
|
+ <text class="advantage-label">高效覆盖广度:</text>
|
|
|
+ <text class="advantage-desc">能同时分析数千只股票,人工无法企及。</text>
|
|
|
+ </view>
|
|
|
</view>
|
|
|
- <text class="card-header-title">量化投资的优势</text>
|
|
|
- </view>
|
|
|
|
|
|
- <view class="advantage-item">
|
|
|
- <text class="advantage-label">客观纪律性:</text>
|
|
|
- <text class="advantage-desc">排除情绪干扰,严格执行预设的交易信号。</text>
|
|
|
- </view>
|
|
|
- <view class="advantage-item">
|
|
|
- <text class="advantage-label">高效覆盖广度:</text>
|
|
|
- <text class="advantage-desc">能同时分析数千只股票,人工无法企及。</text>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
+ <!-- 风险提示(免责声明) -->
|
|
|
+ <view class="card risk-card">
|
|
|
+ <view class="card-header">
|
|
|
+ <view class="icon-warning">
|
|
|
+ <text class="icon-warning-text">!</text>
|
|
|
+ </view>
|
|
|
+ <text class="card-header-title">风险提示(免责声明)</text>
|
|
|
+ </view>
|
|
|
|
|
|
- <!-- 风险提示(免责声明) -->
|
|
|
- <view class="card risk-card">
|
|
|
- <view class="card-header">
|
|
|
- <view class="icon-warning">
|
|
|
- <text class="icon-warning-text">!</text>
|
|
|
+ <text class="risk-text">
|
|
|
+ 本系统的量化分数和股票池信息均基于历史数据和特定模型计算,并非对未来市场的保证或预测。市场环境瞬息万变,
|
|
|
+ 量化模型可能存在失效或回撤风险。请勿将本系统数据作为投资决策的唯一依据,请您充分理解股票投资风险,并独立做出投资判断。
|
|
|
+ </text>
|
|
|
</view>
|
|
|
- <text class="card-header-title">风险提示(免责声明)</text>
|
|
|
- </view>
|
|
|
|
|
|
- <text class="risk-text">
|
|
|
- 本系统的量化分数和股票池信息均基于历史数据和特定模型计算,并非对未来市场的保证或预测。市场环境瞬息万变,
|
|
|
- 量化模型可能存在失效或回撤风险。请勿将本系统数据作为投资决策的唯一依据,请您充分理解股票投资风险,并独立做出投资判断。
|
|
|
- </text>
|
|
|
- </view>
|
|
|
-
|
|
|
- <!-- 预留底部空间,避免被 tabBar 遮挡 -->
|
|
|
- <view class="bottom-safe-area"></view>
|
|
|
- </scroll-view>
|
|
|
+ <!-- 预留底部空间,避免被 tabBar 遮挡 -->
|
|
|
+ <view class="bottom-safe-area"></view>
|
|
|
+ </view>
|
|
|
+ </scroll-view>
|
|
|
+ </view>
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
|
@@ -137,6 +143,7 @@ let timer = null
|
|
|
const onKeywordChange = (e) => {
|
|
|
const value = e.detail.value
|
|
|
keyword.value = value
|
|
|
+ console.log('输入关键词:', value)
|
|
|
|
|
|
if (timer) {
|
|
|
clearTimeout(timer)
|
|
|
@@ -155,17 +162,14 @@ const doSearchSuggestions = async (kw) => {
|
|
|
}
|
|
|
|
|
|
try {
|
|
|
- const res = await getSuggestions(kw.trim())
|
|
|
- if (res.code === 0) {
|
|
|
- const list = res.data || []
|
|
|
- suggestions.value = list
|
|
|
- showDropdown.value = list.length > 0
|
|
|
- } else {
|
|
|
- suggestions.value = []
|
|
|
- showDropdown.value = false
|
|
|
- }
|
|
|
+ // getSuggestions 已经通过 request 函数处理,返回的是 data 部分(数组)
|
|
|
+ const list = await getSuggestions(kw.trim())
|
|
|
+ console.log('模糊查询返回数据:', list)
|
|
|
+ suggestions.value = Array.isArray(list) ? list : []
|
|
|
+ showDropdown.value = suggestions.value.length > 0
|
|
|
+ console.log('下拉框状态:', { showDropdown: showDropdown.value, suggestionsLength: suggestions.value.length })
|
|
|
} catch (err) {
|
|
|
- console.error(err)
|
|
|
+ console.error('模糊查询错误:', err)
|
|
|
suggestions.value = []
|
|
|
showDropdown.value = false
|
|
|
}
|
|
|
@@ -190,16 +194,13 @@ const onSearch = () => {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
- // 如果输入格式是 "股票名称 (股票代码)",提取股票代码
|
|
|
+ let searchCode = kw
|
|
|
const codeMatch = kw.match(/\((\d{6})\)/)
|
|
|
if (codeMatch) {
|
|
|
- // 从建议项点击的情况,使用提取的代码
|
|
|
- doSearch(codeMatch[1])
|
|
|
- } else {
|
|
|
- // 用户直接输入股票代码或股票名称,直接传递给后端
|
|
|
- // 后端会智能识别是代码还是名称
|
|
|
- doSearch(kw)
|
|
|
+ searchCode = codeMatch[1]
|
|
|
}
|
|
|
+
|
|
|
+ doSearch(searchCode)
|
|
|
}
|
|
|
|
|
|
const doSearch = async (queryCode) => {
|
|
|
@@ -225,30 +226,50 @@ const doSearch = async (queryCode) => {
|
|
|
}
|
|
|
|
|
|
const onInputBlur = () => {
|
|
|
+ // 延迟关闭,给点击下拉项留出时间
|
|
|
setTimeout(() => {
|
|
|
showDropdown.value = false
|
|
|
- }, 200)
|
|
|
+ }, 300)
|
|
|
}
|
|
|
</script>
|
|
|
|
|
|
<style>
|
|
|
/** 首页量化查询界面样式 **/
|
|
|
|
|
|
-.page {
|
|
|
+.page-title-card {
|
|
|
+ background: #ffffff;
|
|
|
+ padding: 30rpx 0;
|
|
|
+ text-align: center;
|
|
|
+ box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
|
|
|
+ border-radius: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.page-title-text {
|
|
|
+ font-size: 36rpx;
|
|
|
+ font-weight: 800;
|
|
|
+ color: #3F51F7;
|
|
|
+ letter-spacing: 2rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.page-container {
|
|
|
height: 100vh;
|
|
|
- box-sizing: border-box;
|
|
|
- padding: 32rpx 32rpx 48rpx;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
background: #f5f6fb;
|
|
|
}
|
|
|
|
|
|
-.page-title {
|
|
|
- margin-top: 8rpx;
|
|
|
- margin-bottom: 24rpx;
|
|
|
- text-align: center;
|
|
|
- font-size: 32rpx;
|
|
|
- font-weight: 700;
|
|
|
- color: #5d55e8;
|
|
|
- letter-spacing: 4rpx;
|
|
|
+/* 移除旧的 custom-header 样式,或者保留也无妨,因为 HTML 中不再使用 */
|
|
|
+.custom-header {
|
|
|
+ display: none;
|
|
|
+}
|
|
|
+
|
|
|
+.scroll-view {
|
|
|
+ flex: 1;
|
|
|
+ height: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.content-wrapper {
|
|
|
+ padding: 32rpx 32rpx 48rpx;
|
|
|
}
|
|
|
|
|
|
.card {
|
|
|
@@ -257,12 +278,12 @@ const onInputBlur = () => {
|
|
|
padding: 32rpx 32rpx 36rpx;
|
|
|
box-shadow: 0 16rpx 40rpx rgba(37, 52, 94, 0.08);
|
|
|
margin-bottom: 32rpx;
|
|
|
- position: relative; /* 确保下拉列表定位参照此元素 */
|
|
|
+ position: relative;
|
|
|
}
|
|
|
|
|
|
.search-card {
|
|
|
margin-top: 16rpx;
|
|
|
- z-index: 10; /* 确保搜索卡片层级较高 */
|
|
|
+ z-index: 10;
|
|
|
}
|
|
|
|
|
|
.card-title {
|
|
|
@@ -336,15 +357,16 @@ const onInputBlur = () => {
|
|
|
/* 下拉列表样式 */
|
|
|
.search-dropdown {
|
|
|
position: absolute;
|
|
|
- top: 180rpx; /* 根据标题和输入框高度估算 */
|
|
|
- left: 32rpx;
|
|
|
- right: 32rpx;
|
|
|
+ top: 100%; /* 相对于父元素定位,在搜索框下方 */
|
|
|
+ left: 0;
|
|
|
+ right: 0;
|
|
|
+ margin-top: 8rpx;
|
|
|
background: #ffffff;
|
|
|
border-radius: 16rpx;
|
|
|
box-shadow: 0 10rpx 30rpx rgba(0, 0, 0, 0.15);
|
|
|
max-height: 400rpx;
|
|
|
overflow-y: auto;
|
|
|
- z-index: 999;
|
|
|
+ z-index: 1000; /* 提高层级,确保在最上层 */
|
|
|
border: 1rpx solid #f0f0f0;
|
|
|
}
|
|
|
|
|
|
@@ -374,7 +396,6 @@ const onInputBlur = () => {
|
|
|
color: #999;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
.result-card {
|
|
|
margin-top: 8rpx;
|
|
|
}
|