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.

544 lines
14 KiB

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