✨ 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>
|
<h2 class="panel-title">图表布局设置</h2>
|
||||||
<div class="header-actions">
|
<div class="header-actions">
|
||||||
<el-button size="small" type="primary" @click="applySettings" :loading="saving">
|
<el-button size="small" type="primary" @click="applySettings" :loading="saving">
|
||||||
<el-icon v-if="saving"><Loading /></el-icon>
|
|
||||||
<span>应用设置</span>
|
<span>应用设置</span>
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button size="small" @click="resetToSession" :disabled="saving">
|
<el-button size="small" @click="resetToSession" :disabled="saving">
|
||||||
@@ -14,12 +13,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 配置内容区 -->
|
<!-- 配置内容区:表格 + 独立预览组件 -->
|
||||||
<div class="settings-content">
|
<div class="settings-content">
|
||||||
<!-- 原有图表配置表格 -->
|
<!-- 原有图表配置表格 -->
|
||||||
<div class="charts-config">
|
<div class="charts-config">
|
||||||
<h3 class="section-title">
|
<h3 class="section-title">
|
||||||
<el-icon><Grid /></el-icon>
|
|
||||||
图表配置
|
图表配置
|
||||||
</h3>
|
</h3>
|
||||||
<el-table
|
<el-table
|
||||||
@@ -28,7 +26,7 @@
|
|||||||
:height="tableHeight"
|
:height="tableHeight"
|
||||||
row-key="id"
|
row-key="id"
|
||||||
:data="tempChartConfigs">
|
:data="tempChartConfigs">
|
||||||
<!-- 表格列内容保持不变 -->
|
<!-- 表格列内容保持不变(与原代码一致) -->
|
||||||
<el-table-column prop="title" label="图表名称" min-width="120" />
|
<el-table-column prop="title" label="图表名称" min-width="120" />
|
||||||
<el-table-column prop="id" label="标识" min-width="100" />
|
<el-table-column prop="id" label="标识" min-width="100" />
|
||||||
<el-table-column label="图表高度" min-width="120">
|
<el-table-column label="图表高度" min-width="120">
|
||||||
@@ -140,60 +138,11 @@
|
|||||||
</el-table>
|
</el-table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 新增:布局预览区域 -->
|
<!-- 引入独立预览组件:传递配置和缩放比例 -->
|
||||||
<div class="layout-preview">
|
<ChartLayoutPreview
|
||||||
<h3 class="section-title">
|
:chart-configs="tempChartConfigs"
|
||||||
<el-icon><Eye /></el-icon>
|
:scale-ratio="0.5"
|
||||||
布局预览(实时同步配置)
|
/>
|
||||||
</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>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 提示信息 -->
|
<!-- 提示信息 -->
|
||||||
@@ -212,10 +161,10 @@ import { ref, onMounted, reactive } from 'vue';
|
|||||||
import { useStorage } from '@vueuse/core';
|
import { useStorage } from '@vueuse/core';
|
||||||
import { useEventListener } from '@vueuse/core';
|
import { useEventListener } from '@vueuse/core';
|
||||||
import { ElMessage, ElMessageBox, ElEmpty, ElRow, ElCol, ElCard } from 'element-plus';
|
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({
|
const props = defineProps({
|
||||||
storageKey: {
|
storageKey: {
|
||||||
type: String,
|
type: String,
|
||||||
@@ -259,7 +208,6 @@ const batchSettings = reactive({
|
|||||||
layout: { xs: null, sm: null, md: null, lg: null, xl: null }
|
layout: { xs: null, sm: null, md: null, lg: null, xl: null }
|
||||||
});
|
});
|
||||||
|
|
||||||
// 原有方法(onMounted、calculateTableHeight、resetToSession等)保持不变
|
|
||||||
useEventListener('resize', () => {
|
useEventListener('resize', () => {
|
||||||
windowWidth.value = window.innerWidth;
|
windowWidth.value = window.innerWidth;
|
||||||
calculateTableHeight();
|
calculateTableHeight();
|
||||||
@@ -403,7 +351,7 @@ defineExpose({ resetToSession, applySettings });
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
/* 原有样式保持不变,新增预览区域样式 */
|
/* 原有样式保持不变(删除原预览相关样式,预览样式已封装在子组件中) */
|
||||||
.chart-settings-panel {
|
.chart-settings-panel {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@@ -489,92 +437,6 @@ defineExpose({ resetToSession, applySettings });
|
|||||||
border-top: 1px solid #eee;
|
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) {
|
@media (max-width: 1200px) {
|
||||||
.chart-settings-panel {
|
.chart-settings-panel {
|
||||||
@@ -607,9 +469,5 @@ defineExpose({ resetToSession, applySettings });
|
|||||||
.section-title {
|
.section-title {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.layout-preview {
|
|
||||||
padding: 8px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -11,11 +11,6 @@
|
|||||||
style="margin-bottom: 20px;"
|
style="margin-bottom: 20px;"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- 页面标题:补充基础样式 -->
|
|
||||||
<div style="font-size: 18px; font-weight: 500; margin-bottom: 20px;">
|
|
||||||
数据分析页面
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 主内容区(数据加载成功才显示) -->
|
<!-- 主内容区(数据加载成功才显示) -->
|
||||||
<div v-if="!loading && !errorMsg">
|
<div v-if="!loading && !errorMsg">
|
||||||
<!-- 第一行:四个指标卡 -->
|
<!-- 第一行:四个指标卡 -->
|
||||||
|
|||||||
Reference in New Issue
Block a user