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.

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