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.

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