You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

531 lines
15 KiB

4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
  1. <template>
  2. <view class="main">
  3. <!-- 顶部状态栏占位 -->
  4. <view class="top" :style="{ height: iSMT + 'px' }"></view>
  5. <!-- 标题图标部分 -->
  6. <deepExploration_header
  7. ></deepExploration_header>
  8. <view class="search">
  9. <input
  10. v-model="stockName"
  11. class="searchInput"
  12. type="text"
  13. placeholder="请输入股票名称、股票代码"
  14. placeholder-style="color: #A6A6A6; font-size: 22rpx;"
  15. />
  16. <image
  17. @click="searchStock"
  18. class="seachIcon"
  19. src="/static/deepExploration-images/search.png"
  20. mode="aspectFill"
  21. ></image>
  22. </view>
  23. <!-- 四大功能模块 -->
  24. <view class="select">
  25. <view class="selectItem" @click="toMain('主力追踪')">
  26. <image
  27. class="img"
  28. src="/static/deepExploration-images/icon3.png"
  29. mode="aspectFill"
  30. ></image>
  31. <view class="txt">主力追踪</view>
  32. </view>
  33. <view class="selectItem" @click="toMain('主力雷达')">
  34. <image
  35. class="img"
  36. src="/static/deepExploration-images/icon2.png"
  37. mode="aspectFill"
  38. ></image>
  39. <view class="txt">主力雷达</view>
  40. </view>
  41. <view class="selectItem" @click="toMain('主力解码')">
  42. <image
  43. class="img"
  44. src="/static/deepExploration-images/icon1.png"
  45. mode="aspectFill"
  46. ></image>
  47. <view class="txt">主力解码</view>
  48. </view>
  49. <view class="selectItem" @click="toMain('主力资金流')">
  50. <image
  51. class="img"
  52. src="/static/deepExploration-images/icon4.png"
  53. mode="aspectFill"
  54. ></image>
  55. <view class="txt">主力资金流</view>
  56. </view>
  57. </view>
  58. <!-- 灰色间隔 -->
  59. <view class="gap"></view>
  60. <!-- 选股策略 -->
  61. <view class="stockSelection">
  62. <view class="stockSelection_top">
  63. <view class="txt">
  64. <text>选股策略</text>
  65. </view>
  66. <view class="viewAll" @click="viewAll">
  67. <text>查看全部</text>
  68. </view>
  69. </view>
  70. <view class="stockSelection_content">
  71. <view class="selectionItem">
  72. <view class="header">
  73. <view class="left">
  74. <image
  75. src="/static/deepExploration-images/plus.png"
  76. mode="aspectFill"
  77. ></image>
  78. <text>抄底卖顶</text>
  79. </view>
  80. <view class="right">
  81. <image
  82. src="/static/deepExploration-images/Americle.png"
  83. mode="aspectFill"
  84. ></image>
  85. <text>美股</text>
  86. </view>
  87. </view>
  88. <view class="content">
  89. <view class="contentTitle">
  90. <view class="contentTitle_name">股票名称</view>
  91. <view class="contentTitle_close">最新收盘价</view>
  92. <view class="contentTitle_price">选股价格</view>
  93. </view>
  94. <view class="contentItem">
  95. <view class="row" v-for="(item, index) in stockData" :key="index">
  96. <view class="nameItem">{{ item.tscode }}</view>
  97. <view class="closeItem">{{ item.close }}</view>
  98. <view class="priceItem">{{ item.preClose }}</view>
  99. </view>
  100. </view>
  101. </view>
  102. </view>
  103. </view>
  104. <view class="stockSelection_content">
  105. <view class="selectionItem">
  106. <view class="header">
  107. <view class="left">
  108. <image
  109. src="/static/deepExploration-images/plus.png"
  110. mode="aspectFill"
  111. ></image>
  112. <text>波段行情</text>
  113. </view>
  114. <view class="right">
  115. <image
  116. src="/static/deepExploration-images/Americle.png"
  117. mode="aspectFill"
  118. ></image>
  119. <text>美股</text>
  120. </view>
  121. </view>
  122. <view class="content">
  123. <view class="contentTitle">
  124. <view class="contentTitle_name">股票名称</view>
  125. <view class="contentTitle_close">最新收盘价</view>
  126. <view class="contentTitle_price">选股价格</view>
  127. </view>
  128. <view class="contentItem">
  129. <view class="row" v-for="(item, index) in stockDataByName" :key="index">
  130. <view class="nameItem">{{ item.tscode }}</view>
  131. <view class="closeItem">{{ item.close }}</view>
  132. <view class="priceItem">{{ item.preClose }}</view>
  133. </view>
  134. </view>
  135. </view>
  136. </view>
  137. </view>
  138. </view>
  139. <footerBar class="static-footer" :type="type"></footerBar>
  140. </view>
  141. </template>
  142. <script setup>
  143. import {
  144. ref,
  145. onMounted
  146. } from 'vue'
  147. import footerBar from '@/components/footerBar.vue'
  148. import deepExploration_header from '@/components/deepExploration_header.vue'
  149. import { stocSelectApi, stocSelectByNameApi } from '@/api/deepExploration/deepExploration.js'
  150. const type = ref("deepExploration");
  151. const iSMT = ref(0);
  152. //查看全部选股策略
  153. const toMain = (val) => {
  154. if (val == "主力追踪") {
  155. uni.navigateTo({
  156. url: "/pages/deepExploration/MainForceActions?index=1",
  157. });
  158. } else if (val == "主力雷达") {
  159. uni.navigateTo({
  160. url: "/pages/deepExploration/MainForceActions?index=2",
  161. });
  162. } else if (val == "主力解码") {
  163. uni.navigateTo({
  164. url: "/pages/deepExploration/MainForceActions?index=3",
  165. });
  166. } else if (val == "主力资金流") {
  167. uni.navigateTo({
  168. url: "/pages/deepExploration/MainForceActions?index=4",
  169. });
  170. }
  171. };
  172. const stockName = ref("");
  173. //搜索股票
  174. const searchStock = () => {
  175. console.log("搜索参数:", stockName.value);
  176. uni.navigateTo({
  177. url: `/pages/deepExploration/MainForceActions?stockName=${stockName.value}`,
  178. });
  179. };
  180. //查看全部选股策略
  181. const viewAll = () => {
  182. uni.navigateTo({
  183. url: '/pages/deepExploration/stockSelectDetail'
  184. })
  185. }
  186. //选股策略数据(接口填充)
  187. const stockData = ref([]);
  188. const stockDataByName = ref([]); // 安徽板块数据(只显示前三条)
  189. // 加载选股策略(接口)
  190. const loadStockSelection = async () => {
  191. try {
  192. const res = await stocSelectApi({ language: 'cn', size: 3 })
  193. // console.log('选股策略接口响应原始:', typeof res === 'object' ? JSON.stringify(res) : res)
  194. const raw = res?.data
  195. const listCandidates = [
  196. raw?.list,
  197. raw?.data?.list,
  198. raw?.data?.rows,
  199. raw?.rows,
  200. Array.isArray(raw) ? raw : null
  201. ].filter(Array.isArray)
  202. let list = listCandidates.length ? listCandidates[0] : []
  203. // 若是对象包含多个数组(如不同市场),进行扁平化
  204. if ((!Array.isArray(list) || !list.length) && raw && typeof raw === 'object' && !Array.isArray(raw)) {
  205. const arrays = Object.values(raw).filter(Array.isArray)
  206. if (arrays.length) {
  207. list = arrays.flat()
  208. }
  209. }
  210. if (Array.isArray(list) && list.length) {
  211. const mapped = list.map(item => ({
  212. tscode: item.tsCode ?? item.tscode ?? item.code ?? '',
  213. close: item.close ?? item.lastClose ?? '',
  214. preClose: item.preClose ?? item.preclose ?? item.prevClose ?? ''
  215. }))
  216. stockData.value = mapped.slice(0, 3)
  217. console.log('选股策略列表长度:', stockData.value.length, '首项:', stockData.value[0])
  218. } else {
  219. console.warn('选股策略接口返回空列表或结构不匹配', raw)
  220. }
  221. } catch (e) {
  222. console.error('选股策略接口调用失败', e)
  223. uni.showToast({ title: '选股策略加载失败', icon: 'none' })
  224. }
  225. }
  226. // 安徽板块:按名称查询,仅前三条,字段映射不变
  227. const loadStockSelectionByName = async () => {
  228. try {
  229. const res = await stocSelectByNameApi({ name: '安徽' })
  230. const raw = res?.data
  231. const dataObj = raw?.data || raw
  232. let list = []
  233. if (Array.isArray(dataObj)) {
  234. list = dataObj
  235. } else if (dataObj && typeof dataObj === 'object') {
  236. const target = dataObj['安徽']
  237. if (Array.isArray(target)) {
  238. list = target
  239. } else {
  240. const firstArr = Object.values(dataObj).find(v => Array.isArray(v))
  241. if (Array.isArray(firstArr)) list = firstArr
  242. }
  243. }
  244. if (Array.isArray(list) && list.length) {
  245. const mapped = list.map(item => ({
  246. tscode: item.tsCode ?? item.tscode ?? item.code ?? '',
  247. close: item.close ?? item.lastClose ?? '',
  248. preClose: item.preClose ?? item.preclose ?? item.prevClose ?? ''
  249. }))
  250. stockDataByName.value = mapped.slice(0, 3)
  251. console.log('安徽板块列表长度:', stockDataByName.value.length, '首项:', stockDataByName.value[0])
  252. } else {
  253. console.warn('按名称(安徽)接口返回空列表或结构不匹配', raw)
  254. }
  255. } catch (e) {
  256. console.error('按名称(安徽)接口调用失败', e)
  257. uni.showToast({ title: '安徽板块加载失败', icon: 'none' })
  258. }
  259. }
  260. onMounted(() => {
  261. // 状态栏高度
  262. iSMT.value = uni.getSystemInfoSync().statusBarHeight;
  263. // 调用接口填充数据
  264. loadStockSelection()
  265. loadStockSelectionByName() // 安徽板块填充
  266. })
  267. </script>
  268. <style scoped lang="scss">
  269. .main {
  270. width: 100%;
  271. min-height: 100vh; // 保持至少一屏高度
  272. height: auto; // 允许内容超出时自动增高
  273. overflow-y: auto; // 开启纵向滚动
  274. background-color: #fff;
  275. padding-bottom: 120rpx; // 为固定底栏预留空间,避免遮挡
  276. .search {
  277. position: relative;
  278. display: flex;
  279. align-items: center;
  280. background-color: #f3f3f3;
  281. width: calc(100% - 60rpx);
  282. height: 80rpx;
  283. border-radius: 50rpx;
  284. box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
  285. padding: 0 40rpx;
  286. margin: 15rpx 30rpx 0 30rpx;
  287. .seachIcon {
  288. position: absolute;
  289. right: 50rpx;
  290. width: 32rpx;
  291. height: 32rpx;
  292. }
  293. .searchInput {
  294. color: #111;
  295. }
  296. }
  297. .select {
  298. display: flex;
  299. padding: 60rpx 10rpx 30rpx 30rpx;
  300. gap: 70rpx;
  301. align-items: center;
  302. justify-content: center;
  303. .selectItem {
  304. .img {
  305. width: 80rpx;
  306. height: 80rpx;
  307. display: block;
  308. margin: 0 auto;
  309. }
  310. .txt {
  311. color: #6a6a6a;
  312. font-family: "PingFang SC";
  313. font-size: 11px;
  314. font-style: normal;
  315. font-weight: 400;
  316. line-height: 14.5px;
  317. margin-top: 13rpx;
  318. white-space: nowrap;
  319. }
  320. }
  321. }
  322. .gap {
  323. width: 100%;
  324. height: 15rpx;
  325. background-color: #f3f3f3;
  326. }
  327. .stockSelection {
  328. width: 100%;
  329. padding: 32rpx 15rpx;
  330. .stockSelection_top {
  331. display: flex;
  332. justify-content: space-between;
  333. .txt {
  334. color: #000000;
  335. font-family: "PingFang SC";
  336. font-size: 38rpx;
  337. font-style: normal;
  338. font-weight: 400;
  339. line-height: 50rpx;
  340. }
  341. .viewAll {
  342. background-color: #000000;
  343. border-radius: 10rpx;
  344. padding: 6rpx 20rpx;
  345. color: #ffffff;
  346. font-family: "PingFang SC";
  347. font-size: 10rpx;
  348. font-style: normal;
  349. font-weight: 100;
  350. line-height: 29rpx;
  351. height: 40rpx;
  352. }
  353. }
  354. .stockSelection_content {
  355. .selectionItem {
  356. background-color: #f3f3f3;
  357. padding: 30rpx 15rpx 17rpx 30rpx;
  358. border-radius: 30rpx;
  359. margin-top: 30rpx;
  360. .header {
  361. display: flex;
  362. justify-content: space-between;
  363. align-items: center;
  364. .left {
  365. display: flex;
  366. justify-content: space-between;
  367. align-items: center;
  368. image {
  369. display: flex;
  370. justify-content: center;
  371. align-items: center;
  372. width: 15rpx;
  373. height: 15rpx;
  374. }
  375. text {
  376. margin-left: 15rpx;
  377. color: #000000;
  378. font-family: "PingFang SC";
  379. font-size: 28rpx;
  380. font-style: normal;
  381. font-weight: 400;
  382. line-height: 18.5px;
  383. }
  384. }
  385. .right {
  386. display: flex;
  387. justify-content: space-between;
  388. align-items: center;
  389. border-radius: 15rpx;
  390. background-color: #ffffff;
  391. padding: 6rpx 20rpx;
  392. image {
  393. display: flex;
  394. justify-content: center;
  395. align-items: center;
  396. width: 40rpx;
  397. height: 26.5rpx;
  398. }
  399. text {
  400. margin-left: 10rpx;
  401. color: #6a6a6a;
  402. font-family: "PingFang SC";
  403. font-size: 18rpx;
  404. font-style: normal;
  405. font-weight: 400;
  406. line-height: 24rpx;
  407. }
  408. }
  409. }
  410. .content {
  411. .contentTitle {
  412. display: flex;
  413. color: #6a6a6a;
  414. font-family: "PingFang SC";
  415. font-size: 11px;
  416. font-style: normal;
  417. font-weight: 400;
  418. line-height: 14.5px;
  419. margin-top: 24rpx;
  420. margin-bottom: 20rpx;
  421. .contentTitle_name {
  422. width: 100rpx;
  423. }
  424. .contentTitle_close {
  425. width: 130rpx;
  426. margin-left: 260rpx;
  427. }
  428. .contentTitle_price {
  429. width: 120rpx;
  430. margin-left: 60rpx;
  431. }
  432. }
  433. .contentItem {
  434. .row {
  435. display: flex;
  436. box-shadow: 0 -2rpx 5rpx rgba(0, 0, 0, 0.05);
  437. padding: 10rpx 0;
  438. margin-bottom: 10rpx;
  439. .nameItem {
  440. width: 260rpx;
  441. white-space: nowrap;
  442. overflow: hidden;
  443. text-overflow: ellipsis;
  444. color: #000000;
  445. font-family: "PingFang SC";
  446. font-size: 13px;
  447. font-style: normal;
  448. font-weight: 400;
  449. line-height: 17.5px;
  450. }
  451. .closeItem {
  452. width: 120rpx;
  453. margin-left: 100rpx;
  454. color: #25ba5d;
  455. font-family: "PingFang SC";
  456. font-size: 13px;
  457. font-style: normal;
  458. font-weight: 400;
  459. line-height: 17.5px;
  460. }
  461. .priceItem {
  462. width: 120rpx;
  463. margin-left: 73rpx;
  464. color: #25ba5d;
  465. font-family: "PingFang SC";
  466. font-size: 13px;
  467. font-style: normal;
  468. font-weight: 400;
  469. line-height: 17.5px;
  470. }
  471. }
  472. }
  473. }
  474. }
  475. }
  476. }
  477. .static-footer {
  478. position: fixed;
  479. bottom: 0;
  480. left: 0;
  481. right: 0;
  482. }
  483. }
  484. * {
  485. box-sizing: border-box;
  486. }
  487. </style>