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.

203 lines
4.4 KiB

3 weeks ago
  1. <!-- @format -->
  2. <template>
  3. <view class="index-card">
  4. <view class="card-header">
  5. <view class="flag-container">
  6. <image :src="getMarketFlag(market)" class="flag-icon" mode="aspectFit"></image>
  7. </view>
  8. <text class="index-name">{{ stockName }}</text>
  9. </view>
  10. <view class="price-info">
  11. <text class="current-price" :style="{ color: priceColor }">{{ currentPrice }}</text>
  12. <view class="change-info">
  13. <text class="change-amount" :style="{ color: priceColor }">{{ judgeSymbol(changeAmount) }}</text>
  14. <text class="change-percent" :style="{ color: priceColor }">{{ judgeSymbol(changePercent) }}</text>
  15. </view>
  16. </view>
  17. <view class="chart-container">
  18. <view class="mini-chart" >
  19. <image class="time-chart" :src="timeChart" mode="aspectFit"></image>
  20. </view>
  21. </view>
  22. </view>
  23. </template>
  24. <script setup>
  25. import { computed } from "vue";
  26. // 定义组件属性
  27. const props = defineProps({
  28. // 国旗图标路径
  29. market: {
  30. type: String,
  31. required: true,
  32. },
  33. // 指数名称
  34. stockName: {
  35. type: String,
  36. required: true,
  37. },
  38. // 当前价格
  39. currentPrice: {
  40. type: [String, Number],
  41. required: true,
  42. },
  43. // 涨跌金额
  44. changeAmount: {
  45. type: [String, Number],
  46. required: true,
  47. },
  48. // 涨跌幅
  49. changePercent: {
  50. type: [String, Number],
  51. required: true,
  52. },
  53. // 是否上涨
  54. isRising: {
  55. type: Boolean,
  56. default: true,
  57. },
  58. });
  59. const judgeSymbol = (num) => {
  60. // 兼容 undefined/null/数字/字符串
  61. if (num === null || num === undefined) return '';
  62. const n = Number(num);
  63. if (!isNaN(n)) {
  64. // 数值:正数加'+',负数原样
  65. return (n < 0 ? '' : '+') + n;
  66. }
  67. // 字符串:去空格后判断前缀
  68. const s = String(num).trim();
  69. if (s.startsWith('-')) return s;
  70. if (s.startsWith('+')) return s;
  71. return '+' + s;
  72. };
  73. const getMarketFlag = (market) => {
  74. let imagePath;
  75. if (market === "cn") {
  76. imagePath = "/static/marketSituation-image/country-flag/cn.png";
  77. } else if (market === "hk") {
  78. imagePath = "/static/marketSituation-image/country-flag/hk.png";
  79. } else if (market === "can") {
  80. imagePath = "/static/marketSituation-image/country-flag/can.png";
  81. } else if (market === "my") {
  82. imagePath = "/static/marketSituation-image/country-flag/my.png";
  83. } else if (market === "sg") {
  84. imagePath = "/static/marketSituation-image/country-flag/sg.png";
  85. } else if (market === "th") {
  86. imagePath = "/static/marketSituation-image/country-flag/th.png";
  87. } else if (market === "vi") {
  88. imagePath = "/static/marketSituation-image/country-flag/vi.png";
  89. } else if (market === "us" || market === "usa") {
  90. imagePath = "/static/marketSituation-image/country-flag/us.png";
  91. } else {
  92. imagePath = "/static/marketSituation-image/country-flag/global.png";
  93. }
  94. return imagePath;
  95. };
  96. // 计算价格颜色
  97. const priceColor = computed(() => {
  98. return props.isRising ? "#00C853" : "#FF1744";
  99. });
  100. const timeChart = computed(() => {
  101. return props.isRising ? "/static/marketSituation-image/upTimeChart.png" : "/static/marketSituation-image/downTimeChart.png";
  102. });
  103. // 计算图表背景色
  104. // const chartBgColor = computed(() => {
  105. // return props.isRising ? "#E8F5E8" : "#FFEBEE";
  106. // });
  107. </script>
  108. <style scoped>
  109. .index-card {
  110. background-color: #ffffff;
  111. border-radius: 12rpx;
  112. padding: 20rpx;
  113. margin: 16rpx;
  114. box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
  115. border: 1rpx solid #f0f0f0;
  116. }
  117. .card-header {
  118. display: flex;
  119. align-items: center;
  120. margin-bottom: 16rpx;
  121. }
  122. .flag-container {
  123. width: 48rpx;
  124. height: 32rpx;
  125. margin-right: 12rpx;
  126. border-radius: 4rpx;
  127. overflow: hidden;
  128. }
  129. .flag-icon {
  130. width: 100%;
  131. height: 100%;
  132. }
  133. .index-name {
  134. font-size: 28rpx;
  135. font-weight: 500;
  136. color: #333333;
  137. flex: 1;
  138. white-space: nowrap;
  139. overflow: hidden;
  140. text-overflow: ellipsis;
  141. }
  142. .price-info {
  143. margin-bottom: 20rpx;
  144. }
  145. .current-price {
  146. font-size: 36rpx;
  147. font-weight: bold;
  148. display: block;
  149. margin-bottom: 8rpx;
  150. }
  151. .change-info {
  152. display: flex;
  153. align-items: center;
  154. gap: 16rpx;
  155. }
  156. .change-amount {
  157. font-size: 24rpx;
  158. font-weight: 500;
  159. }
  160. .change-percent {
  161. font-size: 24rpx;
  162. font-weight: 500;
  163. }
  164. .chart-container {
  165. height: 80rpx;
  166. border-radius: 8rpx;
  167. overflow: hidden;
  168. }
  169. .mini-chart {
  170. width: 100%;
  171. height: 100%;
  172. position: relative;
  173. border-radius: 8rpx;
  174. }
  175. .time-chart {
  176. width: 100%;
  177. height: 100%;
  178. }
  179. </style>