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.

492 lines
9.7 KiB

4 weeks ago
  1. <template>
  2. <view class="content">
  3. <!-- 市场子Tab -->
  4. <view class="sub_tabs">
  5. <view v-for="(tab, i) in marketTabs" :key="tab" :class="['tab_item', i === activeTabIndex ? 'active' : '']"
  6. @click="switchTab(i)">
  7. <text>{{ tab }}</text>
  8. </view>
  9. </view>
  10. <!-- 大盘指数 -->
  11. <view class="section">
  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.mainIndices" :key="i" class="index_item">
  18. <IndexCard :flagIcon="countryInfo.flag" :indexName="index.name" :currentPrice="index.price"
  19. :changeAmount="index.change" :changePercent="index.changePercent" :isRising="index.isRising" />
  20. </view>
  21. </view>
  22. <!-- 今日市场情绪温度 -->
  23. <view class="sentiment">
  24. <view class="section_subtitle">
  25. <text>今日市场情绪温度</text>
  26. </view>
  27. <view class="meters">
  28. <view class="meter_item" v-for="(m, i) in sentimentMeters" :key="i">
  29. <image class="meter_icon" :class="m.theme" :src="selectIcons[m.theme]" mode="aspectFit"></image>
  30. <view class="meter_info">
  31. <text class="meter_value" :class="m.theme">{{ m.value }}°C</text>
  32. <text class="meter_label" :class="m.theme">{{ m.label }}</text>
  33. </view>
  34. </view>
  35. </view>
  36. </view>
  37. </view>
  38. <!-- 板块 -->
  39. <view class="section">
  40. <view class="section_header">
  41. <text class="section_title">板块</text>
  42. <text class="section_action" @click="viewMore('sectors')">查看更多 ></text>
  43. </view>
  44. <view class="sectors_grid">
  45. <view v-for="(sec, i) in sectors" :key="i" class="sector_item">
  46. <view class="sector_header">
  47. <text class="sector_name">{{ sec.name }}</text>
  48. <text :class="['sector_change', sec.isRising ? 'rising' : 'falling']">
  49. {{ sec.change }}
  50. </text>
  51. </view>
  52. <view class="sector_price">{{ sec.price }}</view>
  53. </view>
  54. </view>
  55. </view>
  56. <!-- 股票 -->
  57. <view class="section">
  58. <view class="section_header">
  59. <text class="section_title">股票</text>
  60. <text class="section_action" @click="viewMore('stocks')">查看更多 ></text>
  61. </view>
  62. <view class="table">
  63. <view class="table_header">
  64. <text class="cell name">名称</text>
  65. <text class="cell price">最新</text>
  66. <text class="cell change">涨幅</text>
  67. </view>
  68. <view class="table_row" v-for="(stk, i) in stocks" :key="i">
  69. <view class="cell name">
  70. <text class="stk_name">{{ stk.name }}</text>
  71. <text class="stk_code">{{ stk.code }}</text>
  72. </view>
  73. <view class="cell price">
  74. <text class="stk_price">{{ stk.price }}</text>
  75. </view>
  76. <view class="cell change">
  77. <text :class="['stk_change', stk.isRising ? 'rising' : 'falling']">
  78. {{ stk.change }}
  79. </text>
  80. </view>
  81. </view>
  82. </view>
  83. </view>
  84. <!-- 底部安全区域 -->
  85. <view class="bottom_safe_area"></view>
  86. </view>
  87. </template>
  88. <script setup>
  89. import { ref, computed, onMounted } from 'vue'
  90. import IndexCard from '../../components/IndexCard.vue'
  91. // 子Tab与操作
  92. const marketTabs = ['全部', '美股', '纽交所', '纳斯达克']
  93. const activeTabIndex = ref(0)
  94. const switchTab = (i) => {
  95. activeTabIndex.value = i
  96. }
  97. // 今日情绪温度示例数据
  98. const sentimentMeters = [
  99. { value: 90, label: '道琼斯', theme: 'hot' },
  100. { value: 60, label: '纳斯达克', theme: 'warm' },
  101. { value: 20, label: '标普500', theme: 'cool' }
  102. ]
  103. // 图标映射
  104. const selectIcons = {
  105. hot: '/static/marketSituation-image/hot.png',
  106. warm: '/static/marketSituation-image/warm.png',
  107. cool: '/static/marketSituation-image/cool.png'
  108. }
  109. // Props
  110. const props = defineProps({
  111. countryId: {
  112. type: Number,
  113. required: true
  114. }
  115. })
  116. // 国家/地区信息映射
  117. const countryInfoMap = {
  118. 2: { // 新加坡
  119. name: '新加坡',
  120. flag: '🇸🇬',
  121. isMarketOpen: true,
  122. mainIndices: [
  123. { name: '海峡时报指数', price: '3,234.56', change: '+12.34', changePercent: '+0.38%', isRising: true },
  124. { name: 'FTSE ST Mid Cap', price: '1,234.56', change: '-5.67', changePercent: '-0.46%', isRising: false }
  125. ],
  126. hotStocks: [
  127. { name: '星展银行', code: 'D05.SI', price: '35.20', change: '+0.15', isRising: true },
  128. { name: '华侨银行', code: 'O39.SI', price: '13.45', change: '-0.05', isRising: false }
  129. ]
  130. },
  131. 3: { // 马来西亚
  132. name: '马来西亚',
  133. flag: '🇲🇾',
  134. isMarketOpen: false,
  135. mainIndices: [
  136. { name: '富时大马KLCI指数', price: '1,567.89', change: '+8.90', changePercent: '+0.57%', isRising: true }
  137. ],
  138. hotStocks: [
  139. { name: '马来亚银行', code: '1155.KL', price: '9.85', change: '+0.10', isRising: true },
  140. { name: '大众银行', code: '1295.KL', price: '4.32', change: '-0.02', isRising: false }
  141. ]
  142. },
  143. 4: { // 印度尼西亚
  144. name: '印度尼西亚',
  145. flag: '🇮🇩',
  146. isMarketOpen: true,
  147. mainIndices: [
  148. { name: '雅加达综合指数', price: '7,234.56', change: '+45.67', changePercent: '+0.63%', isRising: true }
  149. ],
  150. hotStocks: []
  151. },
  152. 5: { // 美国
  153. name: '美国',
  154. flag: '🇺🇸',
  155. isMarketOpen: false,
  156. mainIndices: [
  157. { name: '道琼斯', price: '45,757.90', change: '-125.22', changePercent: '-0.27%', isRising: false },
  158. { name: '纳斯达克', price: '22,333.96', change: '+125.22', changePercent: '+0.47%', isRising: true },
  159. { name: '标普500', price: '6,606.08', change: '+125.22', changePercent: '+0.27%', isRising: true }
  160. ],
  161. hotStocks: [
  162. { name: '苹果', code: 'AAPL', price: '195.89', change: '+2.34', isRising: true },
  163. { name: '微软', code: 'MSFT', price: '378.85', change: '-1.23', isRising: false }
  164. ]
  165. }
  166. }
  167. // 计算当前国家信息
  168. const countryInfo = computed(() => {
  169. return countryInfoMap[props.countryId] || {
  170. name: '未知地区',
  171. flag: '🌍',
  172. isMarketOpen: false,
  173. mainIndices: [],
  174. hotStocks: []
  175. }
  176. })
  177. // 计算当前国家的板块与股票
  178. const sectors = computed(() => {
  179. return countryInfoMap[props.countryId]?.sectors || []
  180. })
  181. const stocks = computed(() => {
  182. return countryInfoMap[props.countryId]?.stocks || []
  183. })
  184. // 查看更多占位
  185. const viewMore = (type) => {
  186. // 可根据 type 跳转到相应页面或加载更多
  187. // 例如:indices/sectors/stocks
  188. // uni.navigateTo({ url: `/pages/marketSituation/${type}List` })
  189. }
  190. </script>
  191. <style scoped>
  192. .content {
  193. padding: 0 20rpx 20rpx 20rpx;
  194. }
  195. /* 子Tab */
  196. .sub_tabs {
  197. display: flex;
  198. gap: 16rpx;
  199. padding: 0 20rpx 20rpx 20rpx;
  200. }
  201. .tab_item {
  202. padding: 6rpx 20rpx;
  203. border-radius: 5rpx;
  204. background: #f5f5f5;
  205. color: #666;
  206. font-size: 24rpx;
  207. }
  208. .tab_item.active {
  209. background: #ff4444;
  210. color: #fff;
  211. }
  212. .section {
  213. padding: 20rpx;
  214. border-radius: 16rpx;
  215. }
  216. .section_header {
  217. display: flex;
  218. justify-content: space-between;
  219. align-items: center;
  220. margin-bottom: 16rpx;
  221. }
  222. .section_title {
  223. font-size: 28rpx;
  224. font-weight: bold;
  225. color: #333;
  226. }
  227. .section_action {
  228. font-size: 24rpx;
  229. color: #999;
  230. }
  231. .indices_grid {
  232. padding: 20rpx;
  233. display: grid;
  234. grid-template-columns: repeat(3, 1fr);
  235. gap: 20rpx;
  236. background-color: #F6F6F6;
  237. }
  238. /* 情绪温度 */
  239. .sentiment {
  240. background-color: #F6F6F6;
  241. padding: 0 20rpx 20rpx 20rpx;
  242. }
  243. .section_subtitle {
  244. font-size: 24rpx;
  245. color: #000000;
  246. padding: 20rpx 0;
  247. }
  248. .meters {
  249. display: grid;
  250. grid-template-columns: repeat(3, 1fr);
  251. gap: 16rpx;
  252. }
  253. .meter_item {
  254. display: flex;
  255. align-items: center;
  256. /* padding: 10rpx; */
  257. background: #ffffff;
  258. border-radius: 12rpx;
  259. }
  260. .meter_item image {
  261. width: 100rpx;
  262. height: 100rpx;
  263. }
  264. .meter_info {
  265. display: flex;
  266. flex-direction: column;
  267. }
  268. .meter_value {
  269. font-size: 36rpx;
  270. }
  271. .meter_value.hot {
  272. color: #ff6b6b;
  273. }
  274. .meter_value.warm {
  275. color: #ffd166;
  276. }
  277. .meter_value.cool {
  278. color: #60a5fa;
  279. }
  280. .meter_label {
  281. font-size: 22rpx;
  282. }
  283. .meter_label.hot {
  284. color: #ff6b6b;
  285. }
  286. .meter_label.warm {
  287. color: #ffd166;
  288. }
  289. .meter_label.cool {
  290. color: #60a5fa;
  291. }
  292. /* 板块 */
  293. .sectors_grid {
  294. display: grid;
  295. grid-template-columns: repeat(3, 1fr);
  296. gap: 16rpx;
  297. }
  298. .sector_item {
  299. background: #fafafa;
  300. border-radius: 12rpx;
  301. padding: 16rpx;
  302. }
  303. .sector_header {
  304. display: flex;
  305. justify-content: space-between;
  306. align-items: center;
  307. margin-bottom: 12rpx;
  308. }
  309. .sector_name {
  310. font-size: 24rpx;
  311. color: #333;
  312. }
  313. .sector_change {
  314. font-size: 22rpx;
  315. }
  316. .sector_change.rising {
  317. color: #e74c3c;
  318. }
  319. .sector_change.falling {
  320. color: #27ae60;
  321. }
  322. .sector_price {
  323. font-size: 24rpx;
  324. color: #666;
  325. }
  326. /* 股票表 */
  327. .table {
  328. background: #fff;
  329. border-radius: 12rpx;
  330. overflow: hidden;
  331. }
  332. .table_header,
  333. .table_row {
  334. display: grid;
  335. grid-template-columns: 2fr 1fr 1fr;
  336. padding: 18rpx 20rpx;
  337. border-bottom: 1rpx solid #f0f0f0;
  338. }
  339. .table_header {
  340. background: #fafafa;
  341. }
  342. .cell.name {
  343. display: flex;
  344. flex-direction: column;
  345. }
  346. .stk_name {
  347. font-size: 26rpx;
  348. color: #333;
  349. }
  350. .stk_code {
  351. font-size: 22rpx;
  352. color: #999;
  353. }
  354. .stk_price {
  355. font-size: 26rpx;
  356. color: #333;
  357. }
  358. .stk_change {
  359. font-size: 24rpx;
  360. }
  361. .stk_change.rising {
  362. color: #e74c3c;
  363. }
  364. .stk_change.falling {
  365. color: #27ae60;
  366. }
  367. .index_item {
  368. background: #fff;
  369. border-radius: 12rpx;
  370. overflow: hidden;
  371. }
  372. .hot_stocks {
  373. margin-bottom: 30rpx;
  374. }
  375. .stocks_list {
  376. background: #fff;
  377. border-radius: 12rpx;
  378. overflow: hidden;
  379. }
  380. .stock_item {
  381. display: flex;
  382. justify-content: space-between;
  383. align-items: center;
  384. padding: 24rpx 20rpx;
  385. border-bottom: 1rpx solid #f0f0f0;
  386. }
  387. .stock_item:last-child {
  388. border-bottom: none;
  389. }
  390. .stock_info {
  391. flex: 1;
  392. }
  393. .stock_name {
  394. font-size: 28rpx;
  395. color: #333;
  396. display: block;
  397. margin-bottom: 8rpx;
  398. }
  399. .stock_code {
  400. font-size: 24rpx;
  401. color: #999;
  402. }
  403. .stock_price {
  404. text-align: right;
  405. }
  406. .price {
  407. font-size: 28rpx;
  408. color: #333;
  409. display: block;
  410. margin-bottom: 8rpx;
  411. }
  412. .change {
  413. font-size: 24rpx;
  414. }
  415. .change.rising {
  416. color: #e74c3c;
  417. }
  418. .change.falling {
  419. color: #27ae60;
  420. }
  421. .bottom_safe_area {
  422. height: 120rpx;
  423. }
  424. </style>