123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114 |
- <template>
- <div class="metrics-cards">
- <MCard
- v-model="info.metric"
- :metric-items="allMetricItems"
- :color="info.color"
- v-for="info in displayMetrics"
- @change-metric="changedMetric"
- @click="clickCard(info.metric)"/>
- </div>
- </template>
- <script lang="ts" setup>
- import { ref, withDefaults, Ref, onBeforeMount, watch, computed,ComputedRef } from 'vue'
- import MCard from './mCard.vue'
- interface ModelData {
- metric: string,
- color: string
- }
- interface Props {
- modelValue: ModelData[],
- metricItems: MetricData[],
- colors?: string[]
- }
- const colorsMap: { [key: string]: boolean } = {}
- const props = withDefaults(defineProps<Props>(), { colors: () => ["aqua", "orange", "blue"] })
- const emits = defineEmits(['change', 'update:modelValue'])
- const allMetricItems = ref(props.metricItems)
- const selectedMetric = ref(props.modelValue)
- const displayMetrics: Ref<{metric:string, color?: string}[]> = ref([])
- onBeforeMount(()=> {
- for (const color of props.colors) {
- colorsMap[color] = false
- }
- const tmp:{[key: string]: boolean} = {}
- for (const info of selectedMetric.value) {
- displayMetrics.value.push({ metric: info.metric, color: info.color })
- tmp[info.metric] = true
- }
- for (const info of allMetricItems.value) {
- if (info.disabled && !tmp[info.value]) { displayMetrics.value.push({ metric: info.value }) }
- }
- })
- const getColor = () => {
- for (const [k,v] of Object.entries(colorsMap)) {
- if (!v) return k
- }
- return ""
- }
- const changedMetric = (oldVal: string, newVal: string) => {
- for (const info of allMetricItems.value) {
- if (info.value === newVal) {
- info.disabled = true
- } else if (info.value === oldVal) {
- info.disabled = false
- }
- }
- const index = selectedMetric.value.findIndex( info => info.metric === oldVal)
- if (index > -1) {
- selectedMetric.value[index].metric = newVal
- emits('update:modelValue', selectedMetric.value)
- emits('change', selectedMetric.value)
- }
- }
- const clickCard = (metric: string) => {
- const index = selectedMetric.value.findIndex( info => info.metric === metric)
- if (index > -1) { // 已存在则删除
- if (selectedMetric.value.length <= 1 ) return
- const tmp = selectedMetric.value[index]
- selectedMetric.value.splice(index, 1)
- colorsMap[tmp.color] = false
- emits('update:modelValue', selectedMetric.value)
- emits('change', selectedMetric.value)
- } else { // 不存在则添加
- if (selectedMetric.value.length === 3) {
- selectedMetric.value[2].metric = metric
- } else {
- const color = getColor()
- colorsMap[color] = true
- selectedMetric.value.push({ metric: metric, color: color})
- }
- emits('update:modelValue', selectedMetric.value)
- emits('change', selectedMetric.value)
- }
- }
- watch(selectedMetric.value, () => {
- const cache:{ [key: string]: string } = {}
- for (const info of selectedMetric.value) {
- cache[info.metric] = info.color
- }
- for (const info of displayMetrics.value) {
- const color = cache[info.metric]
- if (color) {
- info.color = color
- } else {
- info.color = undefined
- }
- }
- })
- </script>
- <style scoped>
- .metrics-cards {
- display: flex;
- justify-content: space-between;
- align-items: flex-start;
- gap: 12px;
- width: 100%;
- }
- </style>
|