WholeProcessPlatform/frontend/src/modules/qixidiliuliangbianhua/index.vue

815 lines
26 KiB
Vue
Raw Normal View History

2026-05-09 17:04:48 +08:00
<!-- SidePanelItem.vue -->
<template>
2026-06-03 17:10:34 +08:00
<SidePanelItem title="水文监测" :select="select" :scopeDate="datetimePicker" @update-values="handlePanelChange1">
<div class="chart-wrapper">
<a-spin :spinning="loading">
<!-- 始终渲染图表容器确保有固定宽高 -->
<div ref="chartRef" class="echarts-chart"></div>
<!-- 无数据时显示Empty但不影响容器尺寸 -->
<div v-if="!loading && !hasData" class="empty-overlay">
<a-empty description="暂无数据" />
</div>
</a-spin>
2026-05-09 17:04:48 +08:00
</div>
</SidePanelItem>
</template>
<script lang="ts" setup>
2026-06-03 17:10:34 +08:00
import { ref, onMounted, onUnmounted, nextTick, watch } from 'vue';
2026-05-09 17:04:48 +08:00
import * as echarts from 'echarts';
import type { EChartsOption } from 'echarts';
import SidePanelItem from '@/components/SidePanelItem/index.vue';
2026-06-03 17:10:34 +08:00
import { useJidiSelectEventStore } from "@/store/modules/jidiSelectEvent";
import { msstbprptGetKendoList, sdriverdaysGetKendoList } from '@/api/qxd';
import { useModelStore } from "@/store/modules/model";
2026-05-09 17:04:48 +08:00
// 定义组件名
defineOptions({
name: 'qixidiliuliangbianhua'
});
// ==================== 选择器配置 ====================
2026-06-03 17:10:34 +08:00
const JidiSelectEventStore = useJidiSelectEventStore();
const baseid = ref('')
const modelStore = useModelStore();
// Loading 状态和数据状态
const loading = ref(false);
const hasData = ref(true); // 初始化为 true因为 initChart 时会渲染
2026-05-09 17:04:48 +08:00
const select = ref({
show: true,
value: undefined,
options: [],
picker: undefined,
format: undefined
});
2026-05-12 08:47:27 +08:00
// 日期选择器配置
2026-06-03 17:10:34 +08:00
const datetimePicker: any = ref({
2026-05-12 08:47:27 +08:00
show: true,
value: (() => {
const now = new Date();
const currentMonth = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}`;
const lastMonth = new Date(now.getFullYear(), now.getMonth() - 1, 1);
const lastMonthStr = `${lastMonth.getFullYear()}-${String(lastMonth.getMonth() + 1).padStart(2, '0')}`;
return [lastMonthStr, currentMonth];
})(),
format: 'YY-MM',
picker: 'month' as const,
options: []
});
2026-05-09 17:04:48 +08:00
// ==================== 图表相关响应式数据 ====================
const chartRef = ref<HTMLElement | null>(null);
let chartInstance: echarts.ECharts | null = null;
2026-06-03 17:10:34 +08:00
// 图表数据(初始为空数组)
const echartsData = ref<any[]>([]);
2026-05-09 17:04:48 +08:00
// 图表配置引用(用于 legendselectchanged 时读取最新配置)
const echartOptionRef = ref<EChartsOption>({});
// ==================== 工具函数omit ====================
const omit = (obj: any, key: string) => {
const newObj = { ...obj };
delete newObj[key];
return newObj;
};
// ==================== 多Y轴动态布局算法 ====================
/**
* 根据图例选中状态动态调整 Y 轴布局和 grid 边距
* @param selected - 图例选中状态对象 { '系列名': boolean }
* @param options - ECharts 配置对象
*
* 规则
* - 左侧最多 1 Y 第一个可见系列
* - 右侧可以显示多个 Y 其余可见系列
*/
const yAxisShowDynamic = (selected: Record<string, boolean>, options: any) => {
const allShow = options.yAxis?.filter((item: any) => item.show);
const showCount = allShow?.length || 0;
// 没有显示的Y轴
if (showCount === 0) {
return;
}
// 只有一个Y轴统一置于左侧
if (showCount === 1) {
options.grid = omit(options.grid, 'right');
2026-06-03 17:10:34 +08:00
options.grid.left = '60px';
2026-05-09 17:04:48 +08:00
options.yAxis = options.yAxis.map((item: any) => {
if (item.show) {
return {
...item,
position: 'left',
offset: 0
};
}
return item;
});
return;
}
// 两个及以上Y轴左侧1个右侧其余
if (showCount >= 2) {
let leftIndex = 0; // 左侧Y轴索引
let rightIndex = 0; // 右侧Y轴计数
options.yAxis = options.yAxis.map((item: any) => {
if (!item.show) {
return item;
}
// 第一个可见的Y轴放在左侧
if (leftIndex === 0) {
leftIndex++;
options.grid = omit(options.grid, 'right');
2026-06-03 17:10:34 +08:00
options.grid.left = '60px';
2026-05-09 17:04:48 +08:00
return {
...item,
position: 'left',
offset: 0
};
} else {
// 其余Y轴放在右侧
rightIndex++;
// 右侧有多个Y轴时需要增加右边距并设置偏移
if (rightIndex > 1) {
options.grid.right = '100px';
return {
...item,
position: 'right',
offset: 60
};
} else {
options.grid.right = '60px';
return {
...item,
position: 'right',
offset: 0
};
}
}
});
}
};
// ==================== 图表初始化 ====================
const initChart = () => {
if (!chartRef.value) {
console.warn('图表容器未就绪');
return;
}
// 初始化 ECharts 实例
chartInstance = echarts.init(chartRef.value);
// 监听图例选择变化事件
chartInstance.on('legendselectchanged', (params: any) => {
const { selected } = params;
2026-06-03 17:10:34 +08:00
// ✅ 方案A手动构建新配置对象保留所有函数引用包括formatter
const currentOptions = echartOptionRef.value as any;
2026-05-09 17:04:48 +08:00
2026-06-03 17:10:34 +08:00
const options: any = {
...currentOptions,
legend: {
...currentOptions.legend,
selected: selected
},
yAxis: Array.isArray(currentOptions.yAxis)
? currentOptions.yAxis.map((item: any) => {
let isShow = true;
for (const key in selected) {
if (key === item.name) {
isShow = selected[key];
}
}
return { ...item, show: isShow }; // ✅ 保留formatter等函数
})
: currentOptions.yAxis
};
2026-05-09 17:04:48 +08:00
// 触发布局调整
yAxisShowDynamic(selected, options);
// 完全替换模式更新配置
chartInstance?.setOption(options, true);
echartOptionRef.value = options;
});
// 监听数据点点击事件
chartInstance.on('click', (params: any) => {
2026-06-03 17:10:34 +08:00
// ✅ 判断是否点击的是数据点series中的点
if (params.componentType === 'series') {
modelStore.modalVisible = true;
modelStore.params.sttp = "fh_zq_point";
modelStore.title = "水文监测";
modelStore.params.stcd = select.value.value;
modelStore.showStcdSelector = true
modelStore.stcdOptions = select.value.options
2026-06-03 17:10:34 +08:00
}
2026-05-09 17:04:48 +08:00
});
};
// ==================== 图表配置生成 ====================
const updateChart = () => {
if (!chartInstance) return;
2026-06-03 17:10:34 +08:00
// ✅ 计算数据统计值用于Y轴动态范围
const qValues = echartsData.value.map(item => item.q).filter(v => v != null && !isNaN(v));
const zValues = echartsData.value.map(item => item.z).filter(v => v != null && !isNaN(v));
const vValues = echartsData.value.map(item => item.v).filter(v => v != null && !isNaN(v));
const minQ = qValues.length > 0 ? Math.min(...qValues) : 0;
const maxQ = qValues.length > 0 ? Math.max(...qValues) : 0;
const minZ = zValues.length > 0 ? Math.min(...zValues) : 0;
const maxZ = zValues.length > 0 ? Math.max(...zValues) : 0;
const minV = vValues.length > 0 ? Math.min(...vValues) : 0;
const maxV = vValues.length > 0 ? Math.max(...vValues) : 0;
2026-05-09 17:04:48 +08:00
2026-06-03 17:10:34 +08:00
// ✅ 颜色和Y轴配置
const Color = ['#9556a4', '#56c2e3', '#78c300'];
const _legendData = ['流量(m³/s)', '水位(m)', '流速(m/s)'];
2026-05-09 17:04:48 +08:00
const setting: EChartsOption = {
// Tooltip 配置
tooltip: {
trigger: 'axis',
backgroundColor: 'rgba(0, 0, 0, 0.5)',
borderColor: 'transparent',
textStyle: {
color: '#ffffff'
},
valueFormatter: (value: any) => (value === undefined ? '-' : value),
formatter: (params: any) => {
let res = `${params[0].name}<br/>`;
params.forEach((item: any) => {
const seriesName = item.seriesName ?? '';
const regx = /\(([^()]+?)\)/;
const unit = seriesName.match(regx);
if (item.value !== undefined && item.value !== null) {
2026-06-03 17:10:34 +08:00
// ✅ 保留两位小数
const formattedValue = Number(item.value).toFixed(2);
res += `<span style="background: ${item.color}; height:10px; width: 10px; border-radius: 50%; display: inline-block; margin-right:10px;"></span>${item.seriesName} ${formattedValue}${unit?.[1] || ''}<br/>`;
} else {
res += `<span style="background: ${item.color}; height:10px; width: 10px; border-radius: 50%; display: inline-block; margin-right:10px;"></span>${item.seriesName} -${unit?.[1] || ''}<br/>`;
2026-05-09 17:04:48 +08:00
}
});
return res;
}
},
2026-06-03 17:10:34 +08:00
// ✅ 颜色配置:流量-紫色,水位-青色,流速-绿色
2026-05-09 17:04:48 +08:00
color: Color,
// 图例配置
legend: {
data: _legendData,
selectedMode: 'multiple',
top: 0,
left: 'center',
itemGap: 15,
// 默认只选中"水温",其他系列隐藏
selected: {
2026-06-03 17:10:34 +08:00
'流速(m/s)': false,
'流量(m³/s)': true,
2026-05-09 17:04:48 +08:00
'水位(m)': false
}
},
axisPointer: {
type: 'shadow',
label: {
show: false
},
shadowStyle: {
color: 'rgba(84, 112, 198, 0.2)'
}
},
// 网格配置 - 为三个Y轴预留空间
grid: {
left: '0px',
right: '60px',
bottom: '10%',
top: '65px'
},
// 数据缩放配置
dataZoom: {
type: 'inside',
start: 0,
end: 100
},
// X轴配置
xAxis: {
type: 'category',
data: echartsData.value.map(item => item.dt),
boundaryGap: true,
axisLabel: {
2026-06-03 17:10:34 +08:00
show: true,
// ✅ X轴标签显示策略最多显示5个标签强制显示首尾
interval: (index: number) => {
const total = echartsData.value.length;
if (total <= 5) return true; // 数据少于等于5个全部显示
if (index === 0 || index === total - 1) return true; // 首尾必显
// 中间标签均匀分布
const step = Math.floor((total - 1) / 3); // 中间显示3个
return index % step === 0;
}
2026-05-09 17:04:48 +08:00
},
axisLine: {
show: true
},
splitLine: {
show: true,
lineStyle: {
type: 'solid',
color: '#e0e0e0'
}
},
axisPointer: {
type: 'shadow',
shadowStyle: {
color: 'rgba(84, 112, 198, 0.2)'
}
}
},
2026-06-03 17:10:34 +08:00
// Y轴配置 - 三个独立Y轴按期望顺序流量、水位、流速
2026-05-09 17:04:48 +08:00
yAxis: [
{
type: 'value',
2026-06-03 17:10:34 +08:00
name: '流量(m³/s)',
2026-05-09 17:04:48 +08:00
position: 'left',
offset: 0,
show: true,
2026-06-03 17:10:34 +08:00
// ✅ 动态范围floor(min) ~ ceil(max)+5
min: qValues.length > 0 ? Math.floor(minQ) : undefined,
max: qValues.length > 0 ? Math.ceil(maxQ) : undefined,
2026-05-09 17:04:48 +08:00
splitLine: {
show: true,
lineStyle: {
type: 'solid',
color: '#e0e0e0'
}
},
axisTick: {
show: true
},
axisLabel: {
show: true,
formatter: '{value}',
2026-06-03 17:10:34 +08:00
color: '#9556a4'
2026-05-09 17:04:48 +08:00
},
axisLine: {
show: true,
lineStyle: {
color: '#6e7079',
width: 2
}
},
nameTextStyle: {
2026-06-03 17:10:34 +08:00
color: '#9556a4',
2026-05-09 17:04:48 +08:00
fontSize: 12
}
},
{
type: 'value',
2026-06-03 17:10:34 +08:00
name: '水位(m)',
2026-05-09 17:04:48 +08:00
position: 'left',
offset: 60,
show: false,
2026-06-03 17:10:34 +08:00
// ✅ 动态范围min-0.01 ~ max+0.04
min: zValues.length > 0 ? minZ : undefined,
max: zValues.length > 0 ? maxZ : undefined,
2026-05-09 17:04:48 +08:00
splitLine: { show: false },
axisTick: {
show: true
},
axisLabel: {
show: true,
2026-06-03 17:10:34 +08:00
// ✅ Y轴刻度保留两位小数使用函数形式
formatter: (value: any) => value.toFixed(2),
color: '#56c2e3'
2026-05-09 17:04:48 +08:00
},
axisLine: {
show: true,
lineStyle: {
color: '#6e7079',
width: 2
}
},
nameTextStyle: {
2026-06-03 17:10:34 +08:00
color: '#56c2e3',
2026-05-09 17:04:48 +08:00
fontSize: 12
}
},
{
type: 'value',
2026-06-03 17:10:34 +08:00
name: '流速(m/s)',
2026-05-09 17:04:48 +08:00
position: 'right',
offset: 0,
show: false,
2026-06-03 17:10:34 +08:00
// ✅ 动态范围min-0.2 ~ max+0.5
min: vValues.length > 0 ? minV - 0.02 : undefined,
max: vValues.length > 0 ? maxV + 0.02 : undefined,
2026-05-09 17:04:48 +08:00
splitLine: { show: false },
axisTick: {
show: true
},
axisLabel: {
show: true,
2026-06-03 17:10:34 +08:00
// ✅ Y轴刻度保留三位小数
formatter: (value: any) => value.toFixed(3),
color: '#78c300'
2026-05-09 17:04:48 +08:00
},
axisLine: {
show: true,
lineStyle: {
color: '#6e7079',
width: 2
}
},
nameTextStyle: {
2026-06-03 17:10:34 +08:00
color: '#78c300',
2026-05-09 17:04:48 +08:00
fontSize: 12
}
}
],
2026-06-03 17:10:34 +08:00
// 系列配置(按期望顺序:流量、水位、流速)
2026-05-09 17:04:48 +08:00
series: [
2026-06-03 17:10:34 +08:00
2026-05-09 17:04:48 +08:00
{
2026-06-03 17:10:34 +08:00
name: '流量(m³/s)',
data: echartsData.value.map(item => item.q),
2026-05-09 17:04:48 +08:00
type: 'line',
smooth: true,
2026-06-03 17:10:34 +08:00
// connectNulls: true,
symbolSize: 3,
2026-05-09 17:04:48 +08:00
symbol: 'circle',
itemStyle: {
2026-06-03 17:10:34 +08:00
color: '#9556a4'
2026-05-09 17:04:48 +08:00
},
lineStyle: {
2026-06-03 17:10:34 +08:00
width: 2
2026-05-09 17:04:48 +08:00
},
yAxisIndex: 0
},
{
2026-06-03 17:10:34 +08:00
name: '水位(m)',
data: echartsData.value.map(item => item.z),
2026-05-09 17:04:48 +08:00
type: 'line',
smooth: true,
2026-06-03 17:10:34 +08:00
// connectNulls: true,
symbolSize: 3,
2026-05-09 17:04:48 +08:00
symbol: 'circle',
itemStyle: {
2026-06-03 17:10:34 +08:00
color: '#56c2e3'
2026-05-09 17:04:48 +08:00
},
lineStyle: {
2026-06-03 17:10:34 +08:00
width: 2
2026-05-09 17:04:48 +08:00
},
yAxisIndex: 1
},
{
2026-06-03 17:10:34 +08:00
name: '流速(m/s)',
data: echartsData.value.map(item => item.v),
2026-05-09 17:04:48 +08:00
type: 'line',
smooth: true,
2026-06-03 17:10:34 +08:00
// connectNulls: true,
symbolSize: 3,
2026-05-09 17:04:48 +08:00
symbol: 'circle',
itemStyle: {
2026-06-03 17:10:34 +08:00
color: '#78c300'
2026-05-09 17:04:48 +08:00
},
lineStyle: {
2026-06-03 17:10:34 +08:00
width: 2
2026-05-09 17:04:48 +08:00
},
yAxisIndex: 2
2026-06-03 17:10:34 +08:00
},
2026-05-09 17:04:48 +08:00
]
};
// 保存配置引用
echartOptionRef.value = setting;
// 完全替换模式更新图表
chartInstance.setOption(setting, true);
2026-06-03 17:10:34 +08:00
// ✅ 初始化时应用动态布局算法确保只有流量Y轴显示
2026-05-09 17:04:48 +08:00
yAxisShowDynamic({
2026-06-03 17:10:34 +08:00
'流量(m³/s)': true,
'水位(m)': false,
'流速(m/s)': false
2026-05-09 17:04:48 +08:00
}, setting);
// 再次应用调整后的配置
chartInstance.setOption(setting, true);
};
// ==================== 生命周期钩子 ====================
onMounted(async () => {
// 双重等待机制nextTick + setTimeout
await nextTick();
setTimeout(() => {
initChart();
updateChart();
}, 50);
});
onUnmounted(() => {
// 销毁图表实例,防止内存泄漏
if (chartInstance) {
chartInstance.dispose();
chartInstance = null;
}
});
2026-06-03 17:10:34 +08:00
//获取水温监测下拉框
const getselsectData = async () => {
let params = {
"filter": {
"logic": "and",
"filters": [
baseid.value != 'all' ? {
"field": "baseId",
"operator": "eq",
"dataType": "string",
"value": baseid.value
} : null,
{
"field": "fhstcd",
"operator": "isnotnull"
},
{
"logic": "or",
"filters": [
{
"field": "sttpCode",
"operator": "eq",
"dataType": "string",
"value": "ZQ"
}
]
}
].filter(Boolean)
},
"select": [
"stcd",
"stnm",
"fhstcd",
"fhstnm",
"sttpCode"
]
}
let res = await msstbprptGetKendoList(params)
console.log(res)
if (!res?.data?.data) {
select.value.value = ''
select.value.options = []
return
}
select.value.value = res.data.data[0].stcd
select.value.options = res.data.data.map((item: any) => {
return {
label: item.stnm,
value: item.stcd
}
})
// debugger
};
const convertDateRange = (dateRange: string[]) => {
if (!dateRange || dateRange.length !== 2) {
return null;
}
// debugger
const [startStr, endStr] = dateRange;
// 获取今天的日期(日部分)
const today = new Date();
const currentDay = today.getDate();
// 解析开始日期 YY-MM
const [startYearStr, startMonthStr] = startStr.split('-');
const startYear = parseInt(startYearStr);
const startMonth = parseInt(startMonthStr);
const fullStartYear = startYear < 100 ? 2000 + startYear : startYear;
// 解析结束日期 YY-MM
const [endYearStr, endMonthStr] = endStr.split('-');
const endYear = parseInt(endYearStr);
const endMonth = parseInt(endMonthStr);
const fullEndYear = endYear < 100 ? 2000 + endYear : endYear;
// 开始日期:基于第一个值的年月 + 今天的日期 + 00:00:00
// 需要处理月份天数边界问题如今天是31号但2月只有28天
const startMonthLastDay = new Date(fullStartYear, startMonth, 0).getDate();
const actualStartDay = Math.min(currentDay, startMonthLastDay);
const startDate = `${fullStartYear}-${String(startMonth).padStart(2, '0')}-${String(actualStartDay).padStart(2, '0')} 00:00:00`;
// 结束日期:基于第二个值的年月 + 今天的日期 + 23:59:59
// 同样需要处理月份天数边界问题
const endMonthLastDay = new Date(fullEndYear, endMonth, 0).getDate();
const actualEndDay = Math.min(currentDay, endMonthLastDay);
const endDate = `${fullEndYear}-${String(endMonth).padStart(2, '0')}-${String(actualEndDay).padStart(2, '0')} 23:59:59`;
return {
startDate,
endDate
};
};
/**
* 加载图表数据
* @param startDate 开始日期 (格式: YYYY-MM-DD HH:mm:ss)
* @param endDate 结束日期 (格式: YYYY-MM-DD HH:mm:ss)
* @param stcd 测站代码
*/
const getChartData = async (startDate: string, endDate: string, stcd: string) => {
try {
console.log('=== 开始加载图表数据 ===');
console.log('请求参数:', { startDate, endDate, stcd });
// 设置 loading 状态
loading.value = true;
hasData.value = false;
const params = {
"filter": {
"logic": "and",
"filters": [
{
"field": "DT",
"operator": "gte",
"value": startDate
},
{
"field": "DT",
"operator": "lte",
"value": endDate
},
{
"field": "stcd",
"operator": "eq",
"dataType": "string",
"value": stcd
}
]
},
"sort": [
{
"field": "dt",
"dir": "asc"
}
]
};
// 调用实际的API获取数据
const res = await sdriverdaysGetKendoList(params);
console.log('API返回结果:', res);
let data = res?.data?.data || [];
console.log('原始数据条数:', data.length);
// 处理空数据情况
if (!data || data.length === 0) {
echartsData.value = [];
hasData.value = false;
await nextTick();
updateChart();
console.warn('未查询到水文数据');
return;
}
// ✅ 数据预处理:验证字段存在性并转换类型
const processedData = data
.map(item => {
// 验证必要字段
if (!item.dt || typeof item.dt !== 'string') {
console.warn('无效的日期数据:', item);
return null;
}
2026-06-03 17:10:34 +08:00
// 确保数值类型
const q = typeof item.q === 'number' ? item.q : parseFloat(item.q);
const z = typeof item.z === 'number' ? item.z : parseFloat(item.z);
const v = typeof item.v === 'number' ? item.v : parseFloat(item.v);
2026-06-03 17:10:34 +08:00
if (isNaN(q) || isNaN(z) || isNaN(v)) {
console.warn('无效的水文数据:', item);
return null;
}
2026-06-03 17:10:34 +08:00
return {
dt: item.dt.split(' ')[0], // 提取日期部分 "2026-05-03"
v: v, // 确保数值类型
q: q,
z: z
};
})
.filter(Boolean); // 过滤掉无效数据
console.log('处理后数据条数:', processedData.length);
console.log('处理后数据示例:', processedData[0]);
// ✅ 更新响应式数据
echartsData.value = processedData;
// 判断是否有数据
hasData.value = echartsData.value.length > 0;
console.log('hasData 设置为:', hasData.value);
// ✅ 刷新图表确保DOM更新后执行
await nextTick();
updateChart();
console.log('图表已更新');
} catch (error) {
console.error('获取图表数据失败:', error);
hasData.value = false;
} finally {
// 关闭 loading 状态
await nextTick();
console.log('关闭 loading 状态');
loading.value = false;
}
};
const handlePanelChange1 = async (data) => {
console.log('=== 用户交互触发 ===');
console.log('当前所有控件状态:', data);
// scopeDate: ['26-05', '26-06']
// select: "0836000011"
if (data.scopeDate && data.scopeDate.length > 0 && data.select) {
console.log('参数验证通过,开始加载数据');
// 转换日期格式并加载数据
const dateRange = convertDateRange(data.scopeDate);
if (dateRange) {
console.log('日期转换结果:', dateRange);
await getChartData(dateRange.startDate, dateRange.endDate, data.select);
} else {
console.error('日期转换失败');
}
} else {
loading.value = false;
hasData.value = false;
// 清空图表数据
echartsData.value = [];
// 更新图表显示空状态
await nextTick();
updateChart();
console.warn('参数不完整:', {
scopeDate: data.scopeDate,
select: data.select
});
}
}
watch(
() => JidiSelectEventStore.selectedItem,
(newVal) => {
baseid.value = newVal.wbsCode;
getselsectData()
},
{ deep: true, immediate: true }
);
2026-05-09 17:04:48 +08:00
</script>
<style lang="scss" scoped>
2026-06-03 17:10:34 +08:00
.chart-wrapper {
width: 100%;
2026-05-09 17:04:48 +08:00
height: 231px;
min-height: 231px;
position: relative;
2026-06-03 17:10:34 +08:00
/* 为empty-overlay提供定位上下文 */
2026-05-09 17:04:48 +08:00
.echarts-chart {
2026-06-03 17:10:34 +08:00
width: 100% !important;
height: 100% !important;
min-width: 100%;
min-height: 231px;
}
.empty-overlay {
position: absolute;
top: 0;
left: 0;
2026-05-09 17:04:48 +08:00
width: 100%;
2026-06-03 17:10:34 +08:00
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background: rgba(255, 255, 255);
z-index: 10;
2026-05-09 17:04:48 +08:00
}
}
</style>