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.

533 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 }}{{ item.stockName }}</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 }}{{ item.stockName }}</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. stockName: item.stockName ?? item.name ?? '',
  214. close: item.close ?? item.lastClose ?? '',
  215. preClose: item.preClose ?? item.preclose ?? item.prevClose ?? ''
  216. }))
  217. stockData.value = mapped.slice(0, 3)
  218. console.log('选股策略列表长度:', stockData.value.length, '首项:', stockData.value[0])
  219. } else {
  220. console.warn('选股策略接口返回空列表或结构不匹配', raw)
  221. }
  222. } catch (e) {
  223. console.error('选股策略接口调用失败', e)
  224. uni.showToast({ title: '选股策略加载失败', icon: 'none' })
  225. }
  226. }
  227. // 安徽板块:按名称查询,仅前三条,字段映射不变
  228. const loadStockSelectionByName = async () => {
  229. try {
  230. const res = await stocSelectByNameApi({ name: '安徽' })
  231. const raw = res?.data
  232. const dataObj = raw?.data || raw
  233. let list = []
  234. if (Array.isArray(dataObj)) {
  235. list = dataObj
  236. } else if (dataObj && typeof dataObj === 'object') {
  237. const target = dataObj['安徽']
  238. if (Array.isArray(target)) {
  239. list = target
  240. } else {
  241. const firstArr = Object.values(dataObj).find(v => Array.isArray(v))
  242. if (Array.isArray(firstArr)) list = firstArr
  243. }
  244. }
  245. if (Array.isArray(list) && list.length) {
  246. const mapped = list.map(item => ({
  247. tscode: item.tsCode ?? item.tscode ?? item.code ?? '',
  248. stockName: item.stockName ?? item.name ?? '',
  249. close: item.close ?? item.lastClose ?? '',
  250. preClose: item.preClose ?? item.preclose ?? item.prevClose ?? ''
  251. }))
  252. stockDataByName.value = mapped.slice(0, 3)
  253. console.log('安徽板块列表长度:', stockDataByName.value.length, '首项:', stockDataByName.value[0])
  254. } else {
  255. console.warn('按名称(安徽)接口返回空列表或结构不匹配', raw)
  256. }
  257. } catch (e) {
  258. console.error('按名称(安徽)接口调用失败', e)
  259. uni.showToast({ title: '安徽板块加载失败', icon: 'none' })
  260. }
  261. }
  262. onMounted(() => {
  263. // 状态栏高度
  264. iSMT.value = uni.getSystemInfoSync().statusBarHeight;
  265. // 调用接口填充数据
  266. loadStockSelection()
  267. loadStockSelectionByName() // 安徽板块填充
  268. })
  269. </script>
  270. <style scoped lang="scss">
  271. .main {
  272. width: 100%;
  273. min-height: 100vh; // 保持至少一屏高度
  274. height: auto; // 允许内容超出时自动增高
  275. overflow-y: auto; // 开启纵向滚动
  276. background-color: #fff;
  277. padding-bottom: 120rpx; // 为固定底栏预留空间,避免遮挡
  278. .search {
  279. position: relative;
  280. display: flex;
  281. align-items: center;
  282. background-color: #f3f3f3;
  283. width: calc(100% - 60rpx);
  284. height: 80rpx;
  285. border-radius: 50rpx;
  286. box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
  287. padding: 0 40rpx;
  288. margin: 15rpx 30rpx 0 30rpx;
  289. .seachIcon {
  290. position: absolute;
  291. right: 50rpx;
  292. width: 32rpx;
  293. height: 32rpx;
  294. }
  295. .searchInput {
  296. color: #111;
  297. }
  298. }
  299. .select {
  300. display: flex;
  301. padding: 60rpx 10rpx 30rpx 30rpx;
  302. gap: 70rpx;
  303. align-items: center;
  304. justify-content: center;
  305. .selectItem {
  306. .img {
  307. width: 80rpx;
  308. height: 80rpx;
  309. display: block;
  310. margin: 0 auto;
  311. }
  312. .txt {
  313. color: #6a6a6a;
  314. font-family: "PingFang SC";
  315. font-size: 11px;
  316. font-style: normal;
  317. font-weight: 400;
  318. line-height: 14.5px;
  319. margin-top: 13rpx;
  320. white-space: nowrap;
  321. }
  322. }
  323. }
  324. .gap {
  325. width: 100%;
  326. height: 15rpx;
  327. background-color: #f3f3f3;
  328. }
  329. .stockSelection {
  330. width: 100%;
  331. padding: 32rpx 15rpx;
  332. .stockSelection_top {
  333. display: flex;
  334. justify-content: space-between;
  335. .txt {
  336. color: #000000;
  337. font-family: "PingFang SC";
  338. font-size: 38rpx;
  339. font-style: normal;
  340. font-weight: 400;
  341. line-height: 50rpx;
  342. }
  343. .viewAll {
  344. background-color: #000000;
  345. border-radius: 10rpx;
  346. padding: 6rpx 20rpx;
  347. color: #ffffff;
  348. font-family: "PingFang SC";
  349. font-size: 10rpx;
  350. font-style: normal;
  351. font-weight: 100;
  352. line-height: 29rpx;
  353. height: 40rpx;
  354. }
  355. }
  356. .stockSelection_content {
  357. .selectionItem {
  358. background-color: #f3f3f3;
  359. padding: 30rpx 15rpx 17rpx 30rpx;
  360. border-radius: 30rpx;
  361. margin-top: 30rpx;
  362. .header {
  363. display: flex;
  364. justify-content: space-between;
  365. align-items: center;
  366. .left {
  367. display: flex;
  368. justify-content: space-between;
  369. align-items: center;
  370. image {
  371. display: flex;
  372. justify-content: center;
  373. align-items: center;
  374. width: 15rpx;
  375. height: 15rpx;
  376. }
  377. text {
  378. margin-left: 15rpx;
  379. color: #000000;
  380. font-family: "PingFang SC";
  381. font-size: 28rpx;
  382. font-style: normal;
  383. font-weight: 400;
  384. line-height: 18.5px;
  385. }
  386. }
  387. .right {
  388. display: flex;
  389. justify-content: space-between;
  390. align-items: center;
  391. border-radius: 15rpx;
  392. background-color: #ffffff;
  393. padding: 6rpx 20rpx;
  394. image {
  395. display: flex;
  396. justify-content: center;
  397. align-items: center;
  398. width: 40rpx;
  399. height: 26.5rpx;
  400. }
  401. text {
  402. margin-left: 10rpx;
  403. color: #6a6a6a;
  404. font-family: "PingFang SC";
  405. font-size: 18rpx;
  406. font-style: normal;
  407. font-weight: 400;
  408. line-height: 24rpx;
  409. }
  410. }
  411. }
  412. .content {
  413. .contentTitle {
  414. display: flex;
  415. color: #6a6a6a;
  416. font-family: "PingFang SC";
  417. font-size: 11px;
  418. font-style: normal;
  419. font-weight: 400;
  420. line-height: 14.5px;
  421. margin-top: 24rpx;
  422. margin-bottom: 20rpx;
  423. .contentTitle_name {
  424. width: 100rpx;
  425. }
  426. .contentTitle_close {
  427. width: 130rpx;
  428. margin-left: 260rpx;
  429. }
  430. .contentTitle_price {
  431. width: 120rpx;
  432. margin-left: 60rpx;
  433. }
  434. }
  435. .contentItem {
  436. .row {
  437. display: flex;
  438. box-shadow: 0 -2rpx 5rpx rgba(0, 0, 0, 0.05);
  439. padding: 10rpx 0;
  440. margin-bottom: 10rpx;
  441. .nameItem {
  442. width: 260rpx;
  443. white-space: nowrap;
  444. overflow: hidden;
  445. text-overflow: ellipsis;
  446. color: #000000;
  447. font-family: "PingFang SC";
  448. font-size: 13px;
  449. font-style: normal;
  450. font-weight: 400;
  451. line-height: 17.5px;
  452. }
  453. .closeItem {
  454. width: 120rpx;
  455. margin-left: 100rpx;
  456. color: #25ba5d;
  457. font-family: "PingFang SC";
  458. font-size: 13px;
  459. font-style: normal;
  460. font-weight: 400;
  461. line-height: 17.5px;
  462. }
  463. .priceItem {
  464. width: 120rpx;
  465. margin-left: 73rpx;
  466. color: #25ba5d;
  467. font-family: "PingFang SC";
  468. font-size: 13px;
  469. font-style: normal;
  470. font-weight: 400;
  471. line-height: 17.5px;
  472. }
  473. }
  474. }
  475. }
  476. }
  477. }
  478. }
  479. .static-footer {
  480. position: fixed;
  481. bottom: 0;
  482. left: 0;
  483. right: 0;
  484. }
  485. }
  486. * {
  487. box-sizing: border-box;
  488. }
  489. </style>