mCard.vue 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. <template>
  2. <el-card class="metric-card">
  3. <div class="metric-card__color" :style="boardTopStyle"></div>
  4. <TextSelector v-model="metric" :options="props.metricItems" @change="changeMetric"></TextSelector>
  5. <div class="metric-value">{{ selectedData?.metricVal }}</div>
  6. <div class="metric-pre">
  7. <span>{{ selectedData?.preVal }}&nbsp;&nbsp;</span>
  8. <el-icon v-show="selectedData?.gapVal" style="display: inline-block; padding-top: 2px">
  9. <Top :class="colorClass" v-if="isBoost"/>
  10. <Bottom :class="colorClass" v-else/>
  11. </el-icon>
  12. <span :class="colorClass">{{ selectedData?.gapVal ? selectedData?.gapVal + '%' : '' }}</span>
  13. </div>
  14. </el-card>
  15. </template>
  16. <script lang="ts" setup>
  17. import { ref, computed } from 'vue'
  18. import TextSelector from '/@/components/TextSelector/index.vue'
  19. defineOptions({
  20. name: 'MCard'
  21. })
  22. interface Props {
  23. modelValue: string,
  24. metricItems: MetricData[],
  25. color?: string,
  26. }
  27. const props = defineProps<Props>()
  28. const emits = defineEmits(["update:modelValue", "change-metric"])
  29. const metric = ref(props.modelValue)
  30. const changeMetric = ( newVal: string, oldVal: string) => {
  31. emits('update:modelValue', newVal)
  32. emits('change-metric', newVal, oldVal)
  33. }
  34. const selectedData = computed(():MetricData|null => {
  35. const info = props.metricItems.find(item => item.value === metric.value)
  36. if(!info) return null
  37. return info
  38. })
  39. const boardTopStyle = computed(() => {
  40. const style_ = { "border-top-color": "rgb(232, 244, 255)" }
  41. if (props.color) { style_["border-top-color"] = props.color }
  42. return style_
  43. })
  44. const isBoost = computed(():boolean => {
  45. return (selectedData.value?.gapVal ?? -1) > 0
  46. })
  47. const colorClass = computed((): "green"|"red" => isBoost.value ? "green": "red")
  48. </script>
  49. <style scoped>
  50. :deep(.el-card__body) {
  51. padding: 0;
  52. }
  53. .metric-card {
  54. padding: 12px 8px;
  55. height: 100px;
  56. position: relative;
  57. min-width: 150px;
  58. overflow-y: hidden;
  59. line-height: 1.4;
  60. background-color: #fff;
  61. border-radius: 10px;
  62. box-shadow: 0 0 12px rgba(51,89,181,.1607843137254902);
  63. cursor: pointer;
  64. flex-grow: 1;
  65. }
  66. .metric-card__color {
  67. position: absolute;
  68. top: 0;
  69. left: 8px;
  70. width: calc(100% - 16px);
  71. height: 0;
  72. border-top: 4px solid #86909c;
  73. border-left: 2px solid transparent;
  74. border-right: 2px solid transparent;
  75. }
  76. .metric-value {
  77. padding: 8px 0;
  78. font-size: 18px;
  79. font-weight: 700;
  80. line-height: 25px;
  81. }
  82. .metric-pre {
  83. color: #6b7785;
  84. font-size: 12px;
  85. white-space: nowrap;
  86. }
  87. .red {
  88. color: red;
  89. }
  90. .green {
  91. color: #1cbc0e;
  92. }
  93. </style>