index.vue 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. <template>
  2. <div class="metrics-cards">
  3. <MCard
  4. v-model="info.metric"
  5. :metric-items="allMetricItems"
  6. :color="info.color"
  7. v-for="info in displayMetrics"
  8. @change-metric="changedMetric"
  9. @click="clickCard(info.metric)"/>
  10. </div>
  11. </template>
  12. <script lang="ts" setup>
  13. import { ref, withDefaults, Ref, onBeforeMount, watch, computed,ComputedRef } from 'vue'
  14. import MCard from './mCard.vue'
  15. interface ModelData {
  16. metric: string,
  17. color: string
  18. }
  19. interface Props {
  20. modelValue: ModelData[],
  21. metricItems: MetricData[],
  22. colors?: string[]
  23. }
  24. const colorsMap: { [key: string]: boolean } = {}
  25. const props = withDefaults(defineProps<Props>(), { colors: () => ["aqua", "orange", "blue"] })
  26. const emits = defineEmits(['change', 'update:modelValue'])
  27. const allMetricItems = ref(props.metricItems)
  28. const selectedMetric = ref(props.modelValue)
  29. const displayMetrics: Ref<{metric:string, color?: string}[]> = ref([])
  30. onBeforeMount(()=> {
  31. for (const color of props.colors) {
  32. colorsMap[color] = false
  33. }
  34. const tmp:{[key: string]: boolean} = {}
  35. for (const info of selectedMetric.value) {
  36. displayMetrics.value.push({ metric: info.metric, color: info.color })
  37. tmp[info.metric] = true
  38. }
  39. for (const info of allMetricItems.value) {
  40. if (info.disabled && !tmp[info.value]) { displayMetrics.value.push({ metric: info.value }) }
  41. }
  42. })
  43. const getColor = () => {
  44. for (const [k,v] of Object.entries(colorsMap)) {
  45. if (!v) return k
  46. }
  47. return ""
  48. }
  49. const changedMetric = (oldVal: string, newVal: string) => {
  50. for (const info of allMetricItems.value) {
  51. if (info.value === newVal) {
  52. info.disabled = true
  53. } else if (info.value === oldVal) {
  54. info.disabled = false
  55. }
  56. }
  57. const index = selectedMetric.value.findIndex( info => info.metric === oldVal)
  58. if (index > -1) {
  59. selectedMetric.value[index].metric = newVal
  60. emits('update:modelValue', selectedMetric.value)
  61. emits('change', selectedMetric.value)
  62. }
  63. }
  64. const clickCard = (metric: string) => {
  65. const index = selectedMetric.value.findIndex( info => info.metric === metric)
  66. if (index > -1) { // 已存在则删除
  67. if (selectedMetric.value.length <= 1 ) return
  68. const tmp = selectedMetric.value[index]
  69. selectedMetric.value.splice(index, 1)
  70. colorsMap[tmp.color] = false
  71. emits('update:modelValue', selectedMetric.value)
  72. emits('change', selectedMetric.value)
  73. } else { // 不存在则添加
  74. if (selectedMetric.value.length === 3) {
  75. selectedMetric.value[2].metric = metric
  76. } else {
  77. const color = getColor()
  78. colorsMap[color] = true
  79. selectedMetric.value.push({ metric: metric, color: color})
  80. }
  81. emits('update:modelValue', selectedMetric.value)
  82. emits('change', selectedMetric.value)
  83. }
  84. }
  85. watch(selectedMetric.value, () => {
  86. const cache:{ [key: string]: string } = {}
  87. for (const info of selectedMetric.value) {
  88. cache[info.metric] = info.color
  89. }
  90. for (const info of displayMetrics.value) {
  91. const color = cache[info.metric]
  92. if (color) {
  93. info.color = color
  94. } else {
  95. info.color = undefined
  96. }
  97. }
  98. })
  99. </script>
  100. <style scoped>
  101. .metrics-cards {
  102. display: flex;
  103. justify-content: space-between;
  104. align-items: flex-start;
  105. gap: 12px;
  106. width: 100%;
  107. }
  108. </style>