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.

477 lines
9.6 KiB

4 weeks ago
4 weeks ago
4 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
4 weeks ago
4 weeks ago
4 weeks ago
4 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
4 weeks ago
3 weeks ago
4 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
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
  1. <!-- @format -->
  2. <template>
  3. <view class="content">
  4. <!-- 市场子Tab -->
  5. <view class="sub_tabs">
  6. <view v-for="(tab, i) in marketTabs" :key="tab" :class="['tab_item', i === activeTabIndex ? 'active' : '']" @click="switchTab(i)">
  7. <text>{{ tab }}</text>
  8. </view>
  9. </view>
  10. <!-- 大盘指数 -->
  11. <view class="section" v-if="activeTabIndex === 0">
  12. <view class="section_header">
  13. <text class="section_title">大盘指数</text>
  14. <text class="section_action" @click="viewMore('indices')">查看更多 ></text>
  15. </view>
  16. <view class="indices_grid">
  17. <view v-for="(index, i) in countryInfo" :key="i" class="index_item">
  18. <IndexCard :market="index.market" :stockName="index.name" :currentPrice="index.price" :changeAmount="index.change" :changePercent="index.changePercent" :isRising="index.isRising" @click="viewIndexDetail(index,i)"/>
  19. </view>
  20. </view>
  21. <!-- 今日市场情绪温度 -->
  22. <view class="sentiment">
  23. <view class="section_subtitle">
  24. <text>今日市场情绪温度</text>
  25. </view>
  26. <view class="meters">
  27. <view class="meter_item" v-for="(m, i) in sentimentMeters" :key="i">
  28. <image class="meter_icon" :class="m.theme" :src="selectIcons[m.theme]" mode="aspectFit"></image>
  29. <view class="meter_info">
  30. <text class="meter_value" :class="m.theme">{{ m.value }}°C</text>
  31. <text class="meter_label" :class="m.theme">{{ m.label }}</text>
  32. </view>
  33. </view>
  34. </view>
  35. </view>
  36. </view>
  37. <!-- 板块 -->
  38. <view class="section" v-if="activeTabIndex === 1">
  39. <view class="section_header">
  40. <text class="section_title">板块</text>
  41. <text class="section_action" @click="viewMore('sectors')">查看更多 ></text>
  42. </view>
  43. <view class="sectors_grid">
  44. <view v-for="(sec, i) in countryInfo" :key="i" class="sector_item">
  45. <view class="sector_header">
  46. <text class="sector_name">{{ sec.name }}</text>
  47. <text :class="['sector_change', sec.isRising ? 'rising' : 'falling']">
  48. {{ sec.change }}
  49. </text>
  50. </view>
  51. <view class="sector_price">{{ sec.price }}</view>
  52. </view>
  53. </view>
  54. </view>
  55. <!-- 股票 -->
  56. <view class="section" v-if="activeTabIndex === 2">
  57. <view class="section_header">
  58. <text class="section_title">股票</text>
  59. <text class="section_action" @click="viewMore('stocks')">查看更多 ></text>
  60. </view>
  61. <view class="table">
  62. <view class="table_header">
  63. <text class="cell name">名称</text>
  64. <text class="cell price">最新</text>
  65. <text class="cell change">涨幅</text>
  66. </view>
  67. <view class="table_row" v-for="(stk, i) in countryInfo" :key="i">
  68. <view class="cell name">
  69. <text class="stk_name">{{ stk.name }}</text>
  70. <text class="stk_code">{{ stk.code }}</text>
  71. </view>
  72. <view class="cell price">
  73. <text class="stk_price">{{ stk.price }}</text>
  74. </view>
  75. <view class="cell change">
  76. <text :class="['stk_change', stk.isRising ? 'rising' : 'falling']">
  77. {{ stk.change }}
  78. </text>
  79. </view>
  80. </view>
  81. </view>
  82. </view>
  83. <!-- 底部安全区域 -->
  84. <view class="bottom_safe_area"></view>
  85. </view>
  86. </template>
  87. <script setup>
  88. import { ref, computed, onMounted, watch } from "vue";
  89. import IndexCard from "../../components/IndexCard.vue";
  90. import { queryStockDataAPI } from "@/api/marketSituation/marketSituation";
  91. import { useMarketSituationStore } from "../../stores/modules/marketSituation.js";
  92. const marketSituationStore = useMarketSituationStore();
  93. onMounted(() => {
  94. switchTab(0);
  95. });
  96. // 子Tab与操作
  97. // const marketTabs = ["全部", "美股", "纽交所", "纳斯达克"];
  98. const activeTabIndex = ref(0);
  99. const switchTab = (i) => {
  100. activeTabIndex.value = i;
  101. queryStockDataAPI({
  102. parentId: props.countryId,
  103. tradeId: activeTabIndex.value+1,
  104. }).then((res) => {
  105. if (res.code === 200) {
  106. countryInfo.value = res.data.dataPage.records;
  107. marketSituationStore.countryMarketCardData = countryInfo.value.map((item) => ({
  108. market: item.market,
  109. stockCode: item.code,
  110. stockName: item.name,
  111. }));
  112. console.log(res.data)
  113. console.log(res.data.dataPage.records)
  114. console.log(countryInfo.value);
  115. }
  116. });
  117. };
  118. // 今日情绪温度示例数据
  119. const sentimentMeters = [
  120. { value: 90, label: "道琼斯", theme: "hot" },
  121. { value: 60, label: "纳斯达克", theme: "warm" },
  122. { value: 20, label: "标普500", theme: "cool" },
  123. ];
  124. // 图标映射
  125. const selectIcons = {
  126. hot: "/static/marketSituation-image/hot.png",
  127. warm: "/static/marketSituation-image/warm.png",
  128. cool: "/static/marketSituation-image/cool.png",
  129. };
  130. // Props
  131. const props = defineProps({
  132. countryId: {
  133. type: Number,
  134. required: true,
  135. },
  136. marketTabs: {
  137. type: Array,
  138. },
  139. tabData: {
  140. type: Object,
  141. default: null
  142. },
  143. });
  144. // 计算当前国家信息
  145. const countryInfo = ref('')
  146. // 方法:查看指数详情
  147. const viewIndexDetail = (item, index) => {
  148. console.log("查看指数详情:", item);
  149. uni.navigateTo({
  150. url: `/pages/marketSituation/marketCondition?stockInformation=${encodeURIComponent(JSON.stringify(item))}&index=${index}&from=countryMarket`,
  151. });
  152. };
  153. // 处理从父组件接收的数据
  154. const handleTabData = (tabData) => {
  155. if (tabData && tabData.type === 'country' && tabData.data) {
  156. if (tabData.data.dataPage && tabData.data.dataPage.records) {
  157. countryInfo.value = tabData.data.dataPage.records;
  158. marketSituationStore.countryMarketCardData = countryInfo.value.map((item) => ({
  159. market: item.market,
  160. stockCode: item.code,
  161. stockName: item.name,
  162. }));
  163. console.log('countryMarket接收到数据:', countryInfo.value);
  164. }
  165. }
  166. };
  167. // 监听tabData变化
  168. watch(() => props.tabData, (newTabData) => {
  169. if (newTabData) {
  170. handleTabData(newTabData);
  171. }
  172. }, { immediate: true });
  173. // 查看更多占位
  174. const viewMore = (type) => {
  175. };
  176. </script>
  177. <style scoped>
  178. .content {
  179. padding: 0 20rpx 20rpx 20rpx;
  180. }
  181. /* 子Tab */
  182. .sub_tabs {
  183. display: flex;
  184. gap: 16rpx;
  185. padding: 0 20rpx 20rpx 20rpx;
  186. }
  187. .tab_item {
  188. padding: 6rpx 20rpx;
  189. border-radius: 5rpx;
  190. background: #f5f5f5;
  191. color: #666;
  192. font-size: 24rpx;
  193. }
  194. .tab_item.active {
  195. background: #ff4444;
  196. color: #fff;
  197. }
  198. .section {
  199. padding: 20rpx;
  200. border-radius: 16rpx;
  201. }
  202. .section_header {
  203. display: flex;
  204. justify-content: space-between;
  205. align-items: center;
  206. margin-bottom: 16rpx;
  207. }
  208. .section_title {
  209. font-size: 28rpx;
  210. font-weight: bold;
  211. color: #333;
  212. }
  213. .section_action {
  214. font-size: 24rpx;
  215. color: #999;
  216. }
  217. .indices_grid {
  218. display: grid;
  219. grid-template-columns: repeat(3, 1fr);
  220. }
  221. /* 情绪温度 */
  222. .sentiment {
  223. background-color: #f6f6f6;
  224. padding: 0 20rpx 20rpx 20rpx;
  225. }
  226. .section_subtitle {
  227. font-size: 24rpx;
  228. color: #000000;
  229. padding: 20rpx 0;
  230. }
  231. .meters {
  232. display: grid;
  233. grid-template-columns: repeat(3, 1fr);
  234. gap: 16rpx;
  235. }
  236. .meter_item {
  237. display: flex;
  238. align-items: center;
  239. /* padding: 10rpx; */
  240. background: #ffffff;
  241. border-radius: 12rpx;
  242. }
  243. .meter_item image {
  244. width: 100rpx;
  245. height: 100rpx;
  246. }
  247. .meter_info {
  248. display: flex;
  249. flex-direction: column;
  250. }
  251. .meter_value {
  252. font-size: 36rpx;
  253. }
  254. .meter_value.hot {
  255. color: #ff6b6b;
  256. }
  257. .meter_value.warm {
  258. color: #ffd166;
  259. }
  260. .meter_value.cool {
  261. color: #60a5fa;
  262. }
  263. .meter_label {
  264. font-size: 22rpx;
  265. }
  266. .meter_label.hot {
  267. color: #ff6b6b;
  268. }
  269. .meter_label.warm {
  270. color: #ffd166;
  271. }
  272. .meter_label.cool {
  273. color: #60a5fa;
  274. }
  275. /* 板块 */
  276. .sectors_grid {
  277. display: grid;
  278. grid-template-columns: repeat(3, 1fr);
  279. gap: 16rpx;
  280. }
  281. .sector_item {
  282. background: #fafafa;
  283. border-radius: 12rpx;
  284. padding: 16rpx;
  285. }
  286. .sector_header {
  287. display: flex;
  288. justify-content: space-between;
  289. align-items: center;
  290. margin-bottom: 12rpx;
  291. }
  292. .sector_name {
  293. font-size: 24rpx;
  294. color: #333;
  295. }
  296. .sector_change {
  297. font-size: 22rpx;
  298. }
  299. .sector_change.rising {
  300. color: #e74c3c;
  301. }
  302. .sector_change.falling {
  303. color: #27ae60;
  304. }
  305. .sector_price {
  306. font-size: 24rpx;
  307. color: #666;
  308. }
  309. /* 股票表 */
  310. .table {
  311. background: #fff;
  312. border-radius: 12rpx;
  313. overflow: hidden;
  314. }
  315. .table_header,
  316. .table_row {
  317. display: grid;
  318. grid-template-columns: 2fr 1fr 1fr;
  319. padding: 18rpx 20rpx;
  320. border-bottom: 1rpx solid #f0f0f0;
  321. }
  322. .table_header {
  323. background: #fafafa;
  324. }
  325. .cell.name {
  326. display: flex;
  327. flex-direction: column;
  328. }
  329. .stk_name {
  330. font-size: 26rpx;
  331. color: #333;
  332. }
  333. .stk_code {
  334. font-size: 22rpx;
  335. color: #999;
  336. }
  337. .stk_price {
  338. font-size: 26rpx;
  339. color: #333;
  340. }
  341. .stk_change {
  342. font-size: 24rpx;
  343. }
  344. .stk_change.rising {
  345. color: #e74c3c;
  346. }
  347. .stk_change.falling {
  348. color: #27ae60;
  349. }
  350. .index_item {
  351. background: #fff;
  352. border-radius: 12rpx;
  353. overflow: hidden;
  354. }
  355. .hot_stocks {
  356. margin-bottom: 30rpx;
  357. }
  358. .stocks_list {
  359. background: #fff;
  360. border-radius: 12rpx;
  361. overflow: hidden;
  362. }
  363. .stock_item {
  364. display: flex;
  365. justify-content: space-between;
  366. align-items: center;
  367. padding: 24rpx 20rpx;
  368. border-bottom: 1rpx solid #f0f0f0;
  369. }
  370. .stock_item:last-child {
  371. border-bottom: none;
  372. }
  373. .stock_info {
  374. flex: 1;
  375. }
  376. .stock_name {
  377. font-size: 28rpx;
  378. color: #333;
  379. display: block;
  380. margin-bottom: 8rpx;
  381. }
  382. .stock_code {
  383. font-size: 24rpx;
  384. color: #999;
  385. }
  386. .stock_price {
  387. text-align: right;
  388. }
  389. .price {
  390. font-size: 28rpx;
  391. color: #333;
  392. display: block;
  393. margin-bottom: 8rpx;
  394. }
  395. .change {
  396. font-size: 24rpx;
  397. }
  398. .change.rising {
  399. color: #e74c3c;
  400. }
  401. .change.falling {
  402. color: #27ae60;
  403. }
  404. .bottom_safe_area {
  405. height: 120rpx;
  406. }
  407. </style>