前言
企业版可视化业务组件模块, 框架基于 vue-echarts、echarts 封装,提供一系列图表组件,如:柱状图、折线图、饼图、雷达图、散点图、地图、雷达图、关系图等。
配置&数据:
组件模块包含:
ChartTitle、 图表标题组件
ChartButtonGroup、 图表下载、导出、关闭等按钮
ToolBox、 多种图表切换按钮
FilterGroup、 config接口.dimensions.draw搜索条件渲染组件
ChartEmptyLoading、 图表空数据、加载中提示组件
ChartBox、 BarLine图表盒子容器,返回echarts图片tooltip、legend数据
BarLine、echarts折柱图
tooltip、 自定义 echarts图表tooltip
legend 自定义echarts图表legend
hooks依赖:
useChartTools、 图表下载、导出、excel 等工具函数
useChartRequest、 图表数据请求函数
config
config接口的地址为:/external/medical/databases/${数据库alias}/chart/global/config,用于请求全局分析的配置数据,返回的格式如下:
Details
{
"data": [
{
"id": 58,
"category": "销售趋势",
"hover": "",
"dimensions": [
{
"id": "year",
"name": "年度趋势",
"hover": "",
"checked": 1,
"route": "/external/medical/databases/d6a78428b3/chart/global/result/year",
"draw": {
"sort": {
"default": 1,
"options": [
{
"name": "年份升序",
"value": 1
},
]
},
"limit": null,
"filters": [],
"group": null,
"series": null,
"quota": null,
"cluster": null
},
"icon": "icon-nianduqushi"
},
]
},
]
}其中 dimensions 为全局分析 单个图形配置数据:
{
"id": "图表ID",
"name": "图表名称",
"hover": "",
"checked": "默认是否显示",
"route": "请求图表数据接口地址",
"draw": { // 图表的搜索栏配置项
"sort": "",
"limit": null,
"filters": [],
"group": null,
"series": null,
"quota": null,
"cluster": null
},
"icon": "icon-nianduqushi"
}queryData
queryData: 为企业版顶部搜索栏选中参数条件
Details
{
"query": "",
"p": [
],
"per_page": 15,
"page": 1,
"searches": [
{
"module_id": -245030,
"precise": 0,
"value": [
"化学药"
],
"_label": {
"title": "药品类型",
"data": "化学药"
},
"type": 1,
"subset_checked": true,
"arr_val": [
]
},
{
"module_id": -245040,
"precise": 0,
"value": [
"2020",
"2019",
"2018"
],
"_label": {
"title": "年份",
"data": "2020、2019、2018"
},
"type": 1,
"subset_checked": true,
"arr_val": [
]
},
{
"module_id": -245060280,
"precise": 0,
"value": "乙类",
"_label": {
"title": "OTC分类",
"data": "乙类"
},
"type": 1,
"subset_checked": true,
"arr_val": [
]
}
]
}WholeParseItem
WholeParseItem 为单个图表业务模块,每个数据库-全局分析-图表不同、逻辑不同,所以wholeParseItem不同;
需针对每个数据库全局分析自定义开发
药品销售-全国医院销售数据-销售趋势图.WholeParseItemJS 数据处理逻辑如下
const chartData = shallowRef({});
const reqCallBack = ({ sourceData }) => {
// 接受后端返回的 图表数据,调用makeBarLineData方法处理数据,返回BarLine 需要的格式
chartData.value = makeBarLineData(cloneDeep(sourceData))
};
const props = defineProps({
dimension: { type: Object, require: true }, // 当前图表维度信息 即config.dimensions
queryData: { type: Object }, //为企业版顶部搜索栏选中参数条件
});
// 图表请求数据hooks, 请求url为 props.dimension.route, 参数为 props.queryData和props.dimension.draw,详情可查看 useChartRequest介绍
const { chartState, _copy_dimension, changeFilterActiveDraw, createOrdinaryParam } = useChartRequest({
props: props,
isOrdinary: true,
reqCallBack,
});
// chart搜索条件改变
const bindFilterChange = event => {
changeFilterActiveDraw(event.filter);
};
const chartItemRef = shallowRef();
// 图表工具函数、详情可查看 useChartTools介绍
const { removeImg, saveImg, exportDimsExcel, goChartDetail } = useChartTools(chartItemRef, props.dimension.name);
// 导出 excel
const onExport = () =>
exportDimsExcel(_copy_dimension.value.alias, createOrdinaryParam(), _copy_dimension.value.scope);
const bindClose = () => {removeImg();};
const chartImgRef = shallowRef();
const activeTool = ref('bar');
const onSaveImg = () => {saveImg(_copy_dimension.value.name, options);
};
const route = useRoute();
const bindGoDetail = () => {goChartDetail();};
const chartTools = computed(() => {
const tools = (chartState.sourceData.option?.types ?? []).slice();
tools.push('dataView');
return tools;
});在JS部分的主要工作是通过config的dimensions配置和queryData条件,使用useChartRequest请求单个图表数据,并处理各个图表辅助控件之间的数据交互逻辑。
药品销售-全国医院销售数据-销售趋势图.WholeParseItemHTML 组件结构如下
<div class="chart-item-box p-box" ref="chartItemRef">
<div class="top">
<!-- 标题 -->
<div class="title hover-title" >
<chart-title :copyDimension="_copy_dimension":queryData="props.queryData"/>
</div>
<!-- 操作栏 -->
<ChartButtonGroup >
<ChartButton type="detail" title="点击跳转详情页" @click="bindGoDetail"></ChartButton>
<ChartButton type="export" title="导出" color="#3787FD"></ChartButton>
<ChartButton type="down" @click="onSaveImg"></ChartButton>
<ChartButton type="close" @click="bindClose"></ChartButton>
</ChartButtonGroup>
</div>
<div class="chart-content">
<!-- 排序规则 -->
<div class="filter-chart">
<div class="filter-content" >
<filter-group-row v-model="_copy_dimension.draw" @filter-change="bindFilterChange"></filter-group-row>
<ChartToolBox :toolTypes="chartTools" v-model="activeTool" />
</div>
<!-- 图表 -->
<div class="box-table-chart">
<chart-empty-loading :is-empty="chartState.isEmpty" :loading="chartState.loading">
<BarLineItem ref="chartImgRef" :chart-data="chartData"/>
</chart-empty-loading>
<Transition :duration="550">
<div class="data-table" v-show="activeTool === 'dataView'">
<BarLineTable
:data="chartData"
:x-name="chartState?.sourceData?.option?.xAxis"
></BarLineTable>
</div>
</Transition>
</div>
</div>
</div>
</div>上述HTML由图表辅助控件中的chartTitle、ChartButtonGroup、filter-group-row和chart-empty-loading组件,
以及自定义组件BarLineItem; 和BarLineTable组件的结合构成。
如果实际开发中现有的组件不能满足需求,也可以使用自定义的DIV替换ChartTitle,实现自定义标题。
BarLineItem
BarLineItem 单个ECharts图表的自定义渲染模块,根据业务要求自定义ECharts图表的样式。
由于每个数据库的图表存在细微的差异,因此BarLineItem需要针对每个数据库进行自定义开发。
BarLineItemHTML 组件结构如下 html<ChartBox ref="chartBoxRef"> <template #tooltip="{ data }"> <Tooltip :data="tooltipList?.length ? tooltipList : data"></Tooltip> </template> <template #chart> <BarLine ref="barLineRef" :option="option" :dataZoomOpen="true"></BarLine> </template> <template #legend="{ legends, legendSelect }"> <Legend :legendList="legends" @legendTap="legendSelect"></Legend> </template> </ChartBox>
BarLineItem的包括Tooltip、BarLine和Legend三个部分。如果需要,也可以根据业务需求自定义替换tooltip和legend组件。如果当前图表不需要展示legend组件,也可以将其删除。
,chartBox主要用于为tooltip和legend提供数据,如果tooltip和legend都不需要,那么chartBox也应被删除。
BarLineItemJS 数据处理逻辑如下
const props = defineProps({
chartData: Object,
dimId: String,
});
const barLineRef = shallowRef();
const chartBoxRef = shallowRef();
const option = shallowRef({
// 自定义 echarts.options 配置,会覆盖 定义的基础options配置
});
const tooltipList = shallowRef([]);
function drawChart(sourceData) {
const { seriesData, xData } = makeBarLineData(sourceData);
tooltipList.value = [];
// 渲染图表
barLineRef.value?.drawData(xData, seriesData);
nextTick(() => {
// 异步触发, 用户获取tooltip/legend数据
chartBoxRef.value?.drawData();
});
}
// 监听 wholeParseItem 传递的chartData数据
watch(
[() => props.chartData?.seriesData, () => chart.value?.chart],
() => {
const sourceData = toRaw(props.chartData);
if (chart.value?.chart && !$isEmpty(sourceData)) {
drawChart(sourceData);
}
},
{ immediate: true, flush: 'post' },
);监听来自WholeParseItem的chartData 数据,通过makeBarLineData()将其处理为统一格式数据,最终调用BarLine.drawData()方法渲染ECharts图表。
option配置注意事项:
options 中 xAxis 必须为对象; yAxis、dataZoom、visualMap 为数组对象;options.yAxis.type='y\_${seriesType}', 例如:BarLine.option= [{type: 'y_line'}, {type: 'y_bar'}]其它参考echarts.option 官方文档
More
以上为一个完整的 企业版-全局分析-图表开发流程。 WholeParseItem 负责图表的交互逻辑和数据获取。
BarLineItem 负责图表自定义渲染逻辑。