图表封装组件

news/2025/1/15 13:34:23/文章来源:https://www.cnblogs.com/nwy2012/p/18672469

图表封装:

 


图表封装使用:
<template>
<!--软件模块复用率图表-->
<chart-and-table
ref="chartAndTableRef"
:chart-desc="chartDesc"
:chart-loading="chartLoading"
:columns="columns"
:list="list"
:table-loading="tableLoading"
:total-count="totalCount"
chart-title="模块复用率"
table-title="软件模块清单"
@changePage="getTableData"
>
<template #operation>
<div class="chart-operation" style="width: 400px; display: flex;align-items: center">
<div style="width: 80px;font-size: 15px;font-weight: bolder">排序维度:</div>
<el-select v-model="queryForm.sort" style="width: 150px;">

<el-option v-for="item in sortDimensionOptions"
:key="item.value"
:label="item.label"
:value="item.value">

</el-option>
</el-select>
<el-radio-group v-model="queryForm.sortDirection" style="margin-left: 20px;">
<el-radio label="升序" value="asc"/>
<el-radio label="降序" value="desc"/>
</el-radio-group>
</div>
</template>
</chart-and-table>
</template>
引用:
import {MODULE_REUSE_RATE_DESC} from "@/settings/base.ts";
import {AXIS_LABEL_CONFIG, AXIS_LINE_CONFIG, COLOR_DEFAULT, GRID, LEGEND_CONFIG, SERIES_LABEL_CONFIG, SPLIT_LINE_CONFIG, TOOLTIP_CONFIG} from "@/settings/charts.ts";
import {AG_SW_MODULE_COLUMNS} from "@/settings/columns.ts";
import {$swpT} from "@/utils";
import ChartAndTable from "@/views/platformMeasure/chartAndTable.vue";
import {onMounted, reactive, ref, watch} from "vue";

const chartLoading = ref(false);
const tableLoading = ref(false);
const totalCount = ref(0);

const chartDesc = MODULE_REUSE_RATE_DESC;
const columns = AG_SW_MODULE_COLUMNS;
const list = ref<any>([]);
const sourceData = ref<any>([]);
const chartAndTableRef = ref();
const queryForm = reactive<any>({});
const queryFormRef = ref<any>();

watch(() => [queryForm.sort, queryForm.sortDirection], () => {
getTableData();
});
onMounted(() => {
getBarData();
getTableData();
// 渲染默认数据
queryForm.sort = "checkReuseRate";
queryForm.sortDirection = "asc";
});
// 重置搜索
const resetSearch = () => {
if (queryFormRef.value) {
queryFormRef.value.resetFields();
}
Object.keys(queryForm).forEach(fieldName => {
delete queryForm[fieldName];
});
getTableData();
};

在这里使用import {MODULE_REUSE_RATE_DESC} from "@/settings/base.ts";
// 模块复用率
export const MODULE_REUSE_RATE_DESC = [{
title: "数据范围",
desc: "根据搜索条件,以“项目+ECU+是否自研”为单位,取“校验节点非空”的“最新审批发布”的“软件模块选型方案”中软件模块“Base版本和校验版本同时有值的数据条目”;"
}, {
title: "计算公式",
desc: "软件模块复用度=获取数据软件模块复用度求和÷软件模块条目总数;应用项目数=引用该软件模块项目去重求和;工时=该软件模块评估工时求和"
}, {
title: "展示形式",
desc: "显示排名前10或后10的数据(可人工定义排序规则)"
}, {
title: "术语说明",
desc: "校验复用率-代码维度计算,评估复用率-工时维度计算"
}];

在这里使用import {AXIS_LABEL_CONFIG, AXIS_LINE_CONFIG, COLOR_DEFAULT, GRID, LEGEND_CONFIG, SERIES_LABEL_CONFIG, SPLIT_LINE_CONFIG, TOOLTIP_CONFIG} from "@/settings/charts.ts";

/**
* 图表配置
*
*
* @date 2024-11-25
*/
import {variables} from "@/styles";

// 颜色值预设
export const COLOR_DEFAULT = [
"#5470c6",
"#ed7d31",
"#a3a3a3",
"#ffc30a",
"#5ab1ef",
"#d87a80",
"#8d98b3",
"#e5cf0d",
"#97b552",
"#2ec7c9"
];

// 糖果色
export const COLOR_CANDY = [
"#fc97af",
"#87f7cf",
"#f7f494",
"#72ccff",
"#f7c5a0",
"#d4a4eb",
"#d2f5a6",
"#76f2f2"
];

// 图例配置
export const LEGEND_CONFIG = {
top: "bottom",
itemWidth: 12,
itemHeight: 12,
textStyle: {
color: variables.black,
fontSize: 12,
lineHeight: 14
}
};

// 栅格配置
export const GRID = {
left: 10,
right: 10,
bottom: 25,
containLabel: true
};

// 提示器配置
export const TOOLTIP_CONFIG = {
padding: [5, 10, 5, 10],
axisPointer: {
label: {
backgroundColor: variables.black,
color: variables.white
},
type: "cross"
},
backgroundColor: variables.bgLight,
textStyle: {
color: variables.black,
fontSize: 13
}
};

// 栅格线配置
export const SPLIT_LINE_CONFIG = {
show: true,
lineStyle: {
color: variables.border,
type: "dashed",
width: 1.25
}
};

// 坐标标签配置
export const AXIS_LABEL_CONFIG = {
show: true,
color: variables.dark
};

// 坐标线配置
export const AXIS_LINE_CONFIG = {
lineStyle: {
color: variables.border
}
};

// 数据块配置
export const SERIES_LABEL_CONFIG = {
show: true,
position: "inside",
fontSize: 13
};

 

在这里使用import {AG_SW_MODULE_COLUMNS} from "@/settings/columns.ts";

// 平台化度量-软件模块清单
export const AG_SW_MODULE_COLUMNS = [AG_INDEXES, {
field: "project",
headerName: $swpT("page.swModulePlan.project"), // 项目
headerTooltip: $swpT("page.swModulePlan.project"), // 项目
tooltipField: "project",
minWidth: 150,
editable: false
}, {
field: "ecu",
headerName: "ECU",
headerTooltip: "ECU",
tooltipField: "",
minWidth: 150,
editable: false
}]


使用: 在这里拆出来options 为了适用多个图表

// 获取软件模块复用率柱状图数据
const getBarData = () => {
const dataset = {
dimensions: ["moduleName", "校验复用率", "评估复用率", "评估工时", "应用项目数"],
source: sourceData.value
};
const option = {
color: COLOR_DEFAULT,
legend: {
...LEGEND_CONFIG
},
tooltip: {
...TOOLTIP_CONFIG,
trigger: "axis"
},
xAxis: {
type: "category",
axisLabel: {
...AXIS_LABEL_CONFIG,
show: true,
interval: 0,
rotate: 20 // X轴文本过长时可倾斜
},
axisLine: AXIS_LINE_CONFIG
},
yAxis: [{
type: "value",
nameTextStyle: {
...AXIS_LABEL_CONFIG
},
name: "平均复用率",
position: "left",
axisLabel: {
...AXIS_LABEL_CONFIG,
formatter: "{value} %"
},
splitLine: SPLIT_LINE_CONFIG
}, {
type: "value",
nameTextStyle: {
...AXIS_LABEL_CONFIG
},
name: "应用项目数/评估工时",
position: "right",
splitLine: SPLIT_LINE_CONFIG,
axisLabel: {
...AXIS_LABEL_CONFIG
}
}],
dataZoom: {
show: true,
height: 20,
bottom: 40,
type: "slider",
start: 0,
end: 100, // 可根据数据长度调整
backgroundColor: "rgba(255,255,255,0)",
dataBackgroundColor: "rgba(114,204,255,1)",
fillerColor: "rgba(114,204,255,0.2)",
handleColor: "#72ccff",
textStyle: {
color: "#aaaaaa"
}
},
dataset: dataset,
grid: {
...GRID,
top: 70,
bottom: 55,
left: 60,
right: 60
},
series: [{
type: "bar", barMaxWidth: 60, label: {...SERIES_LABEL_CONFIG, show: true}
}, {
type: "bar", barMaxWidth: 60, label: {...SERIES_LABEL_CONFIG, show: true}
}, {
type: "line", yAxisIndex: 0, label: {
...SERIES_LABEL_CONFIG,
show: true, formatter: ({value}: { value: any }) => {
return `${value["评估工时"]} %`;
}
}
}, {
type: "line", yAxisIndex: 1, label: {...SERIES_LABEL_CONFIG, show: true}
}]
};
chartAndTableRef.value.init(option);
};
在这里使用import {$swpT} from "@/utils";
/**
* 注册template下国际化翻译
*
* @param key
* @param value
*/
export const $swpT = (key: any = "", value: any = "") => {
return window.$swpT(key, value);
};

在这里中的utils/common.js
/**
* 公共方法
*
*
* @date 2024-06-11
*/
import storage from "@/libs/storage.ts";
import {excelCellStyle, excelHeaderStyle, excelLinkCellStyleFont, excelTwoCellStyle} from "@/settings/exportExcelStyle.ts";
import {formatExportLink} from "@/settings/urlUtil";
import {ElMessage} from "element-plus";
import * as Exceljs from "exceljs";
import {saveAs} from "file-saver";
import _, {isEmpty} from "lodash";
import {LocationQueryValue} from "vue-router";

// *** 获取环境变量 - 不同于webpack的引入环境变量 *** //
const {VITE_APP_TITLE} = import.meta.env;

图表封装的页面:

<template>
<div
v-loading="props.chartLoading"
:fullscreen="isFullscreen"
:style="{ height: height ? `${chartItemHeight}` : '' }"
class="chart-item"
>
<!--图表-->
<div v-loading="props.chartLoading" class="chart-item">
<div class="chart-hd">
<span>{{ props.chartTitle }}</span>
<el-tooltip effect="dark" placement="right">
<template #content>
<TipWord :chart-desc="props.chartDesc"/>
</template>
<el-icon style="all: initial;margin-top: 3px;">
<InfoFilled/>
</el-icon>
</el-tooltip>
<span v-if="canFullscreen" class="pointer" style="font-size: 20px" title="全屏" @click="isFullscreen = !isFullscreen">
<el-icon :size="26">
<FullScreen/>
</el-icon>
</span>
<!-- <span v-if="isDataView" :title="dataView ? '图表' : '数据视图'" @click="chartDataView">-->
<!-- <el-icon :size="26"><PieChart/></el-icon>-->
<!-- </span>-->
<span v-if="hasDownload" title="下载" @click="onChartDownload">
<el-icon :size="26"><Download/></el-icon>
</span>
</div>
<div class="chart-bd">
<slot name="operation"/>
<div ref="chartRef" class="chart-instance"/>
</div>
</div>
</div>
<!--表格-->
<div v-loading="props.tableLoading" class="chart-item">
<div class="chart-hd">
<span>{{ props.tableTitle }}</span>
</div>
<div class="chart-bd">
<div class="chart-instance">
<div class="chart-operation">
<el-button plain type="primary" @click="exportData">
<el-icon :size="16">
<svg-icon iconName="icon-shujuguanli-daohang-daorushuju"/>
</el-icon>&nbsp;
{{ $swpT("common.export") }}
</el-button>
</div>
<ag-grid-vue
:columnDefs="props.columns"
:rowData="props.list"
style="height: calc(100% - 30px);padding: 50px 0 10px 0; "
v-bind="settings"
@grid-ready="readyTable"
/>
<div class="chart-operation">
<el-pagination
v-model:current-page="pageState.pageNo"
v-model:page-size="pageState.pageSize"
:total="total"
v-bind="PAGINATION_CONFIG"
@size-change="pageState.pageNo = 1;changePage();
"
@current-change="changePage()"
></el-pagination>
</div>
</div>
</div>
</div>
</template>

<script lang="ts" setup>
// 搜索+图表+表格
import SvgIcon from "@/components/iconfont/SvgIcon.vue";
import TipWord from "@/components/tipWord.vue";
import {PAGINATION_CONFIG, PAGINATION_DEFAULT} from "@/constant/golbalConstantDemo.ts";
import {AG_SETTINGS} from "@/settings/columns.ts";
import {$swpT} from "@/utils";
import {AgGridVue} from "ag-grid-vue3";
import * as echarts from "echarts";
import {computed, defineEmits, defineExpose, defineProps, reactive, ref} from "vue";

const emits = defineEmits(["changePage"]);
const chartRef = ref();
const chart = ref<{
instance: echarts.ECharts | null;
value: HTMLElement | null;
}>({
instance: null,
value: chartRef
});
const isFullscreen = ref(false);
const props = defineProps({
// 图表标题
chartTitle: {
type: String,
default: "图表"
},
// 表格标题
tableTitle: {
type: String,
default: "表格"
},
// 图表loading
chartLoading: {
type: Boolean,
default: false
},
// 表格loading
tableLoading: {
type: Boolean,
default: false
},
// 图表描述
chartDesc: {
type: Array,
default: () => []
},
// 列配置
columns: {
type: Array,
default: () => []
},
// 列表数据
list: {
type: Array,
default: () => []
},
// 图表 高度
height: {
type: [Number, String],
default: 390
},
// 是否全屏
canFullscreen: {
type: Boolean,
default: true
},
// 是否切换表格
isDataView: {
type: Boolean,
default: true
},
// 是否下载
hasDownload: {
type: Boolean,
default: true
},
// 总条数
totalCount: {
type: Number,
default: 0
}
});
const agInstance = ref<any>();
const settings = ref({
...AG_SETTINGS,
suppressContextMenu: true, // 关闭右键菜单
stopEditingWhenCellsLoseFocus: false
});
// 分页
let pageState = reactive({
...PAGINATION_DEFAULT
});
const total = computed(() => {
return props.totalCount || 0;
});

// 表格预处理
const readyTable = (params: any) => {
agInstance.value = params;
autoFixTable();
};

// 调整宽度
const autoFixTable = () => {
window.onresize = () => {
sizeColumnsToFit();
};
sizeColumnsToFit();
};

// 列宽充满表格
const sizeColumnsToFit = () => {
agInstance.value?.api.sizeColumnsToFit();
};

// 生成图表
const init = (option: any) => {
const _chart = echarts.init(chart.value.value);
_chart.clear();
_chart.setOption(option);
_chart.resize();
chart.value.instance = _chart;
window.addEventListener("resize", _chart.resize);
};

// 分页切换
const changePage = () => {
emits("changePage", pageState);
};

// 导出
const exportData = () => {
const fileName = props.tableTitle;
agInstance.value.api.exportDataAsExcel({fileName});
};

// 元素高度
const chartItemHeight = computed(() => {
const propHeight = props.height;
return typeof propHeight !== "number" ? propHeight : `${propHeight}px`;
});

// 触发下载事件
const onChartDownload = () => {
if (!chart.value.instance) {
console.error("ECharts instance is not initialized");
return;
}

// 获取图表数据url
const dataUrl = chart.value.instance.getDataURL({
type: "png",
backgroundColor: "#ffffff",
pixelRatio: 2 // 2倍清晰度
});

// 创建隐藏的a标签
const a = document.createElement("a");
a.href = dataUrl;
a.download = `${props.chartTitle}.png`;
document.body.appendChild(a);
// 触发点击
a.click();
document.body.removeChild(a);
};

defineExpose({
init
});
</script>

<script lang="ts">
export default {
name: "ChartAndTable"
};
</script>


在这里中的import TipWord from "@/components/tipWord.vue";
<template>
<div v-if="Array.isArray(props.chartDesc)">
<div v-for="(item, index) in props.chartDesc" :key="index" style="width: 600px;margin: 5px;">
<span :style="{ fontWeight: 'bold', color: '#ffa500' }">{{ index + 1 + "、" + item.title + ":" }}</span>
{{ item.desc }}<br/>
</div>
</div>
</template>

<script lang="ts" setup>
// 提示词
import {defineProps} from "vue";

interface ChartDescItem {
title: string;
desc: string;
}
// TODO: 后面可能会有其他类型的描述,这里先只处理数组的情况
const props = defineProps({
chartDesc: {
type: Array as () => ChartDescItem[]
}
});
</script>

<style lang="less" scoped>

</style>

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/869570.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vue3+ts展示条项字段

展示条项组件:<el-form v-if="currentStep === 4" label-position="left" label-width="120px" style="display: flex;flex-wrap: wrap;justify-content: flex-start;margin-left: 138px;"> <el-row v-for="(ro…

elasticsearch的RestAPI之操作文档

RestClient操作文档 新增文档 将DB表中的数据同步到elasticsearch 1)查询数据库 1.1)数据库查询后的结果是一个Hotel类型的对象1 @Data2 @TableName("tb_hotel")3 public class Hotel {4 @TableId(type = IdType.INPUT)5 private Long id;6 private St…

【VPX303】基于 3U VPX 总线架构的双银河飞腾 FT-M6678 DSP 信号处理平台(100%全国产化)

​产品概述 VPX303 是一款基于 3U VPX 总线架构的高性能信号处理板,板载 2 片国防科大银河飞腾 FT-M6678 多核浮点运算 DSP,可以实现各种实时性要求较高的信号处理算法。板卡每个 DSP 均支持 5 片 DDR3 SDRAM 实现数据缓存,两片DSP 之间通过 X4 SRIO 进行互联。每个 DSP 均引…

第七章 中断

本文是对《操作系统真象还原》第七章学习的笔记,欢迎大家一起交流。第七章 中断 本文是对《操作系统真象还原》第七章学习的笔记,欢迎大家一起交流。 a 启用中断 本节的主要任务是打开中断,并且使用时钟中断测试 知识部分 中断分类 中断可以分为外部中断和内部中断,这已经是…

PHP语法进阶

PHP语法进阶 数组 数组能够在单个变量中存储多个值,并且可以根据 键 访问其中的 值PHP有两种数组:数值数组、关联数组。 数值和关联两个词都是针对数组的键而言的。 先介绍下数值数组,数值数组是指数组的键是整数的数组,并且键的整数顺序是从0开始,依次类推。 数值数组 $m…

Agentic RAG 系统的崛起

探秘智能检索新境界:Agentic RAG 系统的崛起 📖阅读时长:10分钟 🕙发布时间:202探秘智能检索新境界:Agentic RAG 系统的崛起 📖阅读时长:10分钟 🕙发布时间:2025-01-15近日热文:全网最全的神经网络数学原理(代码和公式)直观解释 欢迎关注知乎和公众号的专栏内…

5、提升Java的并发性

CompletableFuture及反应式编程背后的概念 :::info ❏线程、Future以及推动Java支持更丰富的并发API的进化动力 ❏ 异步API ❏ 从“线框与管道”的角度看并发计算 ❏ 使用CompletableFuture结合器动态地连接线框❏ 构成Java 9反应式编程Flow API基础的“发布-订阅”协议❏ 反应…

goal vs objective vs target

goal 680 objective 2421 target 1284GOAL vs OBJECTIVE left 4WORD 1: GOAL 过滤200WORD W1 W2SCORED 1423 1 He has scored a further five goals in the Spanish Supercup and the Champions League.他在西班牙超级杯和冠军联赛中又打进了五个进球。 scored Barcas fourth…

大模型备案流程-简易易懂

大模型备案除了资料撰写难度高外,难点还在于各省没有统一标准。备案流程、资料要求、考察重点都会有些许差异。不过,各省的大体申报流程都如下文所示(各省主要差异点我会标出,具体内容可以一起沟通交流): 一、备案申请 报请申请者所在省份/直辖市/自治区网信:向企业注册地…

KingbaseES RAC集群案例之---jmeter压测

KingbaseES RAC、jmeter案例说明: 通过jmeter压测,测试KingbaseES RAC集群负载均衡功能。 数据库版本: test=# select version();version ---------------------KingbaseES V008R006 (1 row)测试架构:一、jmeter版本 1、系统jiava版本 [root@node203 ~]# java -version ope…

{LOJ #6041. 「雅礼集训 2017 Day7」事情的相似度 题解

\(\text{LOJ \#6041. 「雅礼集训 2017 Day7」事情的相似度 题解}\) 解法一 由 parent 树的性质得到,前缀 \(s_i,s_j\) 的最长公共后缀实质上就是 \(i,j\) 在 SAM 中的 \(\operatorname{LCA}\) 在 SAM 中的 \(\operatorname{len}\)。让我们考虑如何处理 \((l,r)\) 区间内的询问…