✨ feat: 增加图表预览
This commit is contained in:
212
gear-ui3/src/views/dashboard/grid/ChartLayoutPreview.vue
Normal file
212
gear-ui3/src/views/dashboard/grid/ChartLayoutPreview.vue
Normal file
@@ -0,0 +1,212 @@
|
||||
<!-- ChartLayoutPreview.vue -->
|
||||
<template>
|
||||
<div class="chart-layout-preview">
|
||||
<!-- 预览标题 -->
|
||||
<h3 class="preview-title">
|
||||
布局预览(同比缩放:{{ scaleRatio * 100 }}%)
|
||||
</h3>
|
||||
|
||||
<!-- 预览容器:通过transform实现同比缩小 -->
|
||||
<div
|
||||
class="preview-wrapper"
|
||||
:style="{
|
||||
transform: `scale(${scaleRatio})`,
|
||||
transformOrigin: 'top left', // 缩放原点:左上角(保证布局对齐)
|
||||
width: `${100 / scaleRatio}%`, // 反向计算宽度,避免缩放后内容溢出
|
||||
height: `${100 / scaleRatio}%` // 反向计算高度,配合overflow隐藏
|
||||
}"
|
||||
>
|
||||
<!-- 实际预览内容(与原逻辑一致,用el-row+el-col实现布局) -->
|
||||
<div class="preview-content">
|
||||
<!-- 空状态提示 -->
|
||||
<div v-if="!chartConfigs?.length" class="empty-preview">
|
||||
<el-empty description="暂无图表配置,无法预览" />
|
||||
</div>
|
||||
|
||||
<!-- 图表布局预览 -->
|
||||
<el-row
|
||||
v-else
|
||||
:gutter="16"
|
||||
class="chart-preview-row"
|
||||
>
|
||||
<el-col
|
||||
v-for="(chart, index) in chartConfigs"
|
||||
:key="chart.id || `chart-${index}`"
|
||||
:xs="chart.layout.xs"
|
||||
:sm="chart.layout.sm"
|
||||
:md="chart.layout.md"
|
||||
:lg="chart.layout.lg"
|
||||
:xl="chart.layout.xl"
|
||||
class="chart-preview-col"
|
||||
>
|
||||
<!-- 模拟图表卡片(高度同步配置) -->
|
||||
<el-card
|
||||
class="chart-preview-card"
|
||||
:style="{
|
||||
height: `${chart.height}px`,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
transition: 'all 0.3s ease'
|
||||
}"
|
||||
>
|
||||
<!-- 卡片头部:图表名称+标识 -->
|
||||
<div class="card-header">
|
||||
<span class="chart-title">{{ chart.title }}</span>
|
||||
<span class="chart-id">[{{ chart.id }}]</span>
|
||||
</div>
|
||||
|
||||
<!-- 模拟图表内容区 -->
|
||||
<div class="chart-placeholder" :style="{ flex: 1, marginTop: '8px' }">
|
||||
<div class="placeholder-bg"></div>
|
||||
<!-- 配置信息提示 -->
|
||||
<div class="placeholder-info">
|
||||
<p>高度:{{ chart.height }}px</p>
|
||||
<p>布局:xs={{ chart.layout.xs }} / sm={{ chart.layout.sm }} / md={{ chart.layout.md }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ElEmpty, ElRow, ElCol, ElCard } from 'element-plus';
|
||||
|
||||
// 组件Props:接收外部传递的配置数据和缩放比例
|
||||
const props = defineProps({
|
||||
/** 图表配置数组(与父组件tempChartConfigs结构一致) */
|
||||
chartConfigs: {
|
||||
type: Array,
|
||||
required: true,
|
||||
default: () => []
|
||||
},
|
||||
/** 同比缩放比例(0~1之间,默认0.5即缩小至50%) */
|
||||
scaleRatio: {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: 0.5,
|
||||
validator: (val) => val > 0 && val <= 1 // 限制缩放比例为0~1(避免放大导致溢出)
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 组件外层容器:控制整体大小和溢出 */
|
||||
.chart-layout-preview {
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
border-radius: 8px;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
/* 预览标题 */
|
||||
.preview-title {
|
||||
margin: 0 0 12px 0;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* 缩放容器:核心缩放逻辑载体 */
|
||||
.preview-wrapper {
|
||||
position: relative;
|
||||
/* 初始宽度100%,通过style绑定反向计算实际宽度(抵消scale缩小效果) */
|
||||
transform: scale(0.5);
|
||||
transform-origin: top left;
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
/* 实际预览内容容器 */
|
||||
.preview-content {
|
||||
padding: 8px;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
/* 空状态样式 */
|
||||
.empty-preview {
|
||||
height: 200px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* 图表行:清除el-row默认margin */
|
||||
.chart-preview-row {
|
||||
margin: 0 !important;
|
||||
margin-bottom: 16px !important;
|
||||
}
|
||||
|
||||
/* 图表列:控制间距 */
|
||||
.chart-preview-col {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
/* 图表卡片:模拟实际图表容器 */
|
||||
.chart-preview-card {
|
||||
overflow: hidden;
|
||||
border: 1px solid #e5e7eb !important;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
/* 卡片头部:名称+标识 */
|
||||
.card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 8px 12px;
|
||||
color: white;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
.chart-title {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.chart-id {
|
||||
font-size: 12px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* 模拟图表内容区 */
|
||||
.chart-placeholder {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.placeholder-bg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* 配置信息提示:底部半透明悬浮 */
|
||||
.placeholder-info {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
padding: 6px 12px;
|
||||
font-size: 12px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.placeholder-info p {
|
||||
margin: 2px 0;
|
||||
}
|
||||
|
||||
/* 响应式调整:小屏幕下优化缩放体验 */
|
||||
@media (max-width: 768px) {
|
||||
.chart-layout-preview {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.preview-title {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -5,7 +5,6 @@
|
||||
<h2 class="panel-title">图表布局设置</h2>
|
||||
<div class="header-actions">
|
||||
<el-button size="small" type="primary" @click="applySettings" :loading="saving">
|
||||
<el-icon v-if="saving"><Loading /></el-icon>
|
||||
<span>应用设置</span>
|
||||
</el-button>
|
||||
<el-button size="small" @click="resetToSession" :disabled="saving">
|
||||
@@ -14,12 +13,11 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 配置内容区 -->
|
||||
<!-- 配置内容区:表格 + 独立预览组件 -->
|
||||
<div class="settings-content">
|
||||
<!-- 原有图表配置表格 -->
|
||||
<div class="charts-config">
|
||||
<h3 class="section-title">
|
||||
<el-icon><Grid /></el-icon>
|
||||
图表配置
|
||||
</h3>
|
||||
<el-table
|
||||
@@ -28,7 +26,7 @@
|
||||
:height="tableHeight"
|
||||
row-key="id"
|
||||
:data="tempChartConfigs">
|
||||
<!-- 表格列内容保持不变 -->
|
||||
<!-- 表格列内容保持不变(与原代码一致) -->
|
||||
<el-table-column prop="title" label="图表名称" min-width="120" />
|
||||
<el-table-column prop="id" label="标识" min-width="100" />
|
||||
<el-table-column label="图表高度" min-width="120">
|
||||
@@ -140,60 +138,11 @@
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
<!-- 新增:布局预览区域 -->
|
||||
<div class="layout-preview">
|
||||
<h3 class="section-title">
|
||||
<el-icon><Eye /></el-icon>
|
||||
布局预览(实时同步配置)
|
||||
</h3>
|
||||
<!-- 预览容器:模拟仪表盘布局 -->
|
||||
<div class="preview-container">
|
||||
<!-- 无配置时显示提示 -->
|
||||
<div v-if="tempChartConfigs.length === 0" class="empty-preview">
|
||||
<el-empty description="暂无图表配置,无法预览" />
|
||||
</div>
|
||||
|
||||
<!-- 有配置时,用el-row+el-col渲染预览 -->
|
||||
<el-row
|
||||
v-else
|
||||
:gutter="16"
|
||||
class="preview-row"
|
||||
:style="{ marginBottom: '16px' }">
|
||||
<el-col
|
||||
v-for="(chart, index) in tempChartConfigs"
|
||||
:key="chart.id || index"
|
||||
:xs="chart.layout.xs"
|
||||
:sm="chart.layout.sm"
|
||||
:md="chart.layout.md"
|
||||
:lg="chart.layout.lg"
|
||||
:xl="chart.layout.xl"
|
||||
class="preview-col">
|
||||
<!-- 用Card模拟图表容器,高度同步配置 -->
|
||||
<el-card
|
||||
class="preview-card"
|
||||
:style="{
|
||||
height: `${chart.height}px`,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
transition: 'all 0.3s ease'
|
||||
}">
|
||||
<div class="card-header">
|
||||
<span class="chart-title">{{ chart.title }}</span>
|
||||
<span class="chart-id">[{{ chart.id }}]</span>
|
||||
</div>
|
||||
<!-- 模拟图表内容区域 -->
|
||||
<div class="chart-placeholder" :style="{ flex: 1, marginTop: '8px' }">
|
||||
<div class="placeholder-bg"></div>
|
||||
<div class="placeholder-info">
|
||||
<p>高度:{{ chart.height }}px</p>
|
||||
<p>布局:xs={{ chart.layout.xs }} / sm={{ chart.layout.sm }} / md={{ chart.layout.md }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 引入独立预览组件:传递配置和缩放比例 -->
|
||||
<ChartLayoutPreview
|
||||
:chart-configs="tempChartConfigs"
|
||||
:scale-ratio="0.5"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 提示信息 -->
|
||||
@@ -212,10 +161,10 @@ import { ref, onMounted, reactive } from 'vue';
|
||||
import { useStorage } from '@vueuse/core';
|
||||
import { useEventListener } from '@vueuse/core';
|
||||
import { ElMessage, ElMessageBox, ElEmpty, ElRow, ElCol, ElCard } from 'element-plus';
|
||||
// 新增导入预览用图标
|
||||
import { Loading, Grid, Eye } from '@element-plus/icons-vue';
|
||||
// 引入独立预览组件
|
||||
import ChartLayoutPreview from './ChartLayoutPreview.vue';
|
||||
|
||||
// 原有逻辑保持不变,仅新增预览相关变量(如有需要)
|
||||
// 原有逻辑保持不变(与原代码一致)
|
||||
const props = defineProps({
|
||||
storageKey: {
|
||||
type: String,
|
||||
@@ -259,7 +208,6 @@ const batchSettings = reactive({
|
||||
layout: { xs: null, sm: null, md: null, lg: null, xl: null }
|
||||
});
|
||||
|
||||
// 原有方法(onMounted、calculateTableHeight、resetToSession等)保持不变
|
||||
useEventListener('resize', () => {
|
||||
windowWidth.value = window.innerWidth;
|
||||
calculateTableHeight();
|
||||
@@ -403,7 +351,7 @@ defineExpose({ resetToSession, applySettings });
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 原有样式保持不变,新增预览区域样式 */
|
||||
/* 原有样式保持不变(删除原预览相关样式,预览样式已封装在子组件中) */
|
||||
.chart-settings-panel {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -489,92 +437,6 @@ defineExpose({ resetToSession, applySettings });
|
||||
border-top: 1px solid #eee;
|
||||
}
|
||||
|
||||
/* 新增:预览区域样式 */
|
||||
.layout-preview {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 12px;
|
||||
border: 1px solid #eee;
|
||||
border-radius: 8px;
|
||||
background-color: #fafafa;
|
||||
}
|
||||
|
||||
.preview-container {
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
padding: 8px;
|
||||
border-radius: 4px;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.empty-preview {
|
||||
height: 200px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.preview-row {
|
||||
margin: 0 !important; /* 清除el-row默认margin */
|
||||
}
|
||||
|
||||
.preview-col {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.preview-card {
|
||||
overflow: hidden;
|
||||
border: 1px solid #e5e7eb !important;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 8px 12px;
|
||||
background-color: #f9fafb;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
.chart-title {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.chart-id {
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.chart-placeholder {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.placeholder-bg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(135deg, #f0f2f5 0%, #e5e6eb 100%);
|
||||
}
|
||||
|
||||
.placeholder-info {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
padding: 6px 12px;
|
||||
background-color: rgba(255, 255, 255, 0.8);
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.placeholder-info p {
|
||||
margin: 2px 0;
|
||||
}
|
||||
|
||||
/* 响应式调整 */
|
||||
@media (max-width: 1200px) {
|
||||
.chart-settings-panel {
|
||||
@@ -607,9 +469,5 @@ defineExpose({ resetToSession, applySettings });
|
||||
.section-title {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.layout-preview {
|
||||
padding: 8px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -11,11 +11,6 @@
|
||||
style="margin-bottom: 20px;"
|
||||
/>
|
||||
|
||||
<!-- 页面标题:补充基础样式 -->
|
||||
<div style="font-size: 18px; font-weight: 500; margin-bottom: 20px;">
|
||||
数据分析页面
|
||||
</div>
|
||||
|
||||
<!-- 主内容区(数据加载成功才显示) -->
|
||||
<div v-if="!loading && !errorMsg">
|
||||
<!-- 第一行:四个指标卡 -->
|
||||
|
||||
Reference in New Issue
Block a user