<template>
<div class="card">
<div class="card-header">
<div class="icon"></div>
<div class="title">{{ props.title }}</div>
<svg-icon class="tips" name="tips" />
<div class="buttons">
<div><el-link type="primary">WDR分析</el-link></div>
<div><el-link type="primary">智能诊断</el-link></div>
</div>
</div>
<div
class="card-body"
:class="{ 'is-collapse': isCollapse }"
ref="bodyRef"
:style="{
resize: props.resize ? 'vertical' : 'none',
}"
>
<div>
<slot />
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { useDebounceFn } from '@vueuse/core'
import { useWidthOverflow } from '@/hooks/dom'
const props = withDefaults(
defineProps<{
title: string
legend?: { color: string; name: string }[]
bodyPadding?: boolean
height?: string | number
collapse?: boolean
skipBodyHeight?: boolean
resize?: boolean
maxBodyHeight?: string
overflowHidden?: boolean
withTable?: boolean
}>(),
{
bodyPadding: true,
maxBodyHeight: 'unset',
overflowHidden: true,
withTable: false,
}
)
const hidden = ref(props.overflowHidden ? 'hidden' : 'unset')
const padding = ref(props.bodyPadding ? '24px 16px' : '0px')
const withTableBorderRadius = ref(props.withTable ? '2px 2px 0 0' : '2px')
const bodyRef = ref<HTMLDivElement>()
const bodyHeight = ref(`calc(100% - ${props.bodyPadding ? 90 : 42}px)`)
const minBodyHeight = ref(bodyHeight.value)
onMounted(() => {
nextTick(() => {
if (!props.skipBodyHeight && bodyRef && bodyRef.value) {
bodyHeight.value = `${bodyRef.value.offsetHeight + (props.bodyPadding && !props.collapse ? 48 : 0)}px`
}
if (bodyRef && bodyRef.value && props.resize && window && 'ResizeObserver' in window) {
const resizeObserver = new ResizeObserver((entries) => {
for (const entry of entries) {
if (!collapsing.value) {
bodyHeight.value = `${entry.contentRect.height}px`
if (minBodyHeight.value.startsWith('calc')) {
minBodyHeight.value = bodyHeight.value
}
myEmit('resize-body-height', entry.contentRect.height)
}
}
})
resizeObserver.observe(bodyRef.value)
}
})
})
const myEmit = defineEmits<{
(event: 'resize-body-height', height: number): void
}>()
const height = computed(() => {
if (!props.height) {
return '100%'
}
return ['%', 'px'].includes(`${props.height}`) ? props.height : `${props.height}px`
})
const isCollapse = ref(false)
const collapsing = ref(false)
const extraRef = ref()
const dropdownRef = ref()
const { trigger } = useWidthOverflow(extraRef, dropdownRef)
defineExpose({
trigger,
})
</script>
<style scoped lang="scss">
.card {
box-sizing: border-box;
height: v-bind(height);
border: 1px solid var(--el-og-border-color);
border-radius: v-bind(withTableBorderRadius);
overflow: v-bind(hidden);
.card-header {
display: flex;
overflow: hidden;
justify-content: space-between;
padding: 0 15px;
align-items: center;
min-width: 0;
height: 40px;
border-bottom: 1px solid var(--el-og-border-color);
.icon {
width: 4px;
height: 14px;
background: var(--primary-6);
border-radius: 1px;
margin-right: 4px;
}
.title {
font-weight: 500;
font-size: 14px;
line-height: 30px;
flex-shrink: 0;
> svg {
position: relative;
top: -2px;
margin-right: 12px;
transition: transform var(--el-transition-duration);
&.is-collapse {
transform: rotate(-90deg);
}
}
}
.tips {
margin-left: 6px;
padding-top: 2px;
}
.buttons {
position: relative;
display: flex;
justify-content: flex-end;
margin-left: 16px;
overflow: hidden;
flex: 1;
min-width: 0;
align-items: center;
font-size: 12px;
height: 40px;
> div {
display: flex;
flex-shrink: 0;
margin-right: 8px;
min-width: 0;
> span {
margin-left: 4px;
}
&:last-of-type {
margin-right: 0;
}
}
}
&--extra {
position: relative;
display: flex;
margin-left: 16px;
overflow: hidden;
flex: 1;
min-width: 0;
align-items: center;
font-size: 12px;
height: 40px;
> div {
display: flex;
flex-shrink: 0;
margin-right: 12px;
min-width: 0;
> span {
margin-left: 4px;
}
&:last-of-type {
margin-right: 0;
}
}
}
}
&-body {
position: relative;
box-sizing: border-box;
height: v-bind(bodyHeight);
min-height: v-bind(minBodyHeight);
max-height: v-bind(maxBodyHeight);
overflow: v-bind(hidden);
background-color: var(--el-bg-color-og);
border-radius: 0 0 8px 8px;
will-change: height;
> div {
box-sizing: border-box;
padding: v-bind(padding);
height: v-bind(bodyHeight);
}
&.is-collapse {
height: 0 !important;
}
}
}
.hover {
display: flex;
align-items: center;
> span {
margin-left: 4px;
}
}
.rect {
width: 16px;
height: 16px;
flex-shrink: 0;
}
</style>