mirror of
https://gitee.com/dromara/go-view.git
synced 2026-07-16 04:21:07 +08:00
feat: add 新增自定义排行榜组件RankChart
This commit is contained in:
parent
7b565a5ad6
commit
13154d2c87
BIN
src/assets/images/chart/charts/rank-chart.png
Normal file
BIN
src/assets/images/chart/charts/rank-chart.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 142 KiB |
BIN
src/assets/images/chart/informations/richeng.png
Normal file
BIN
src/assets/images/chart/informations/richeng.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 34 KiB |
196
src/packages/components/Charts/Bars/RankChart/config.ts
Normal file
196
src/packages/components/Charts/Bars/RankChart/config.ts
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
import { echartOptionProfixHandle, PublicConfigClass } from '@/packages/public'
|
||||||
|
|
||||||
|
import { CreateComponentType } from '@/packages/index.d'
|
||||||
|
import { RankChartConfig } from './index'
|
||||||
|
// 深拷贝
|
||||||
|
import cloneDeep from 'lodash/cloneDeep'
|
||||||
|
// 默认数据
|
||||||
|
import dataJson from './data.json'
|
||||||
|
|
||||||
|
export const includes = ['legend', 'xAxis', 'grid']
|
||||||
|
|
||||||
|
const barName = "检测任务数";
|
||||||
|
export const seriesItem = {
|
||||||
|
name: barName,
|
||||||
|
type: "bar",
|
||||||
|
barWidth: 10, // 柱子宽度
|
||||||
|
MaxSize: 0,
|
||||||
|
showBackground: true,
|
||||||
|
backgroundStyle: {
|
||||||
|
color: "#fff",
|
||||||
|
borderRadius: 5, //设置背景的圆角
|
||||||
|
},
|
||||||
|
color: {
|
||||||
|
type: "linear",
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
x2: 1,
|
||||||
|
y2: 0,
|
||||||
|
colorStops: [
|
||||||
|
{
|
||||||
|
offset: 1,
|
||||||
|
color: "#036afaff", // 0% 处的颜色
|
||||||
|
},
|
||||||
|
{
|
||||||
|
offset: 0.5,
|
||||||
|
color: "#034299ff"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
offset: 0,
|
||||||
|
color: "#01142eff", // 100% 处的颜色
|
||||||
|
},
|
||||||
|
],
|
||||||
|
global: false, // 缺省为 false
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
show: true,
|
||||||
|
offset: [10, -15], // 标签偏移量
|
||||||
|
color: "#050505f6",
|
||||||
|
fontSize: 15,
|
||||||
|
fontWeight: 500,
|
||||||
|
position: "left",
|
||||||
|
align: "left",
|
||||||
|
formatter: function (params:any) {
|
||||||
|
// console.log(params);
|
||||||
|
return params.data.name;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const rankIcons = {
|
||||||
|
icon1: "https://goviewpro.goviewlink.com/cloudStorageStatic/13190/rank1.png",
|
||||||
|
icon2: "https://goviewpro.goviewlink.com/cloudStorageStatic/13190/rank2.png",
|
||||||
|
icon3: "https://goviewpro.goviewlink.com/cloudStorageStatic/13190/rank3.png",
|
||||||
|
icon: "https://goviewpro.goviewlink.com/cloudStorageStatic/13190/rank.png",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const option = {
|
||||||
|
backgroundColor: "transparent",
|
||||||
|
tooltip: {
|
||||||
|
trigger: "axis",
|
||||||
|
axisPointer: {
|
||||||
|
type: "shadow",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
left: "5%",
|
||||||
|
right: "5%",
|
||||||
|
top: "5%",
|
||||||
|
bottom: "5%",
|
||||||
|
containLabel: true,
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: "value",
|
||||||
|
show: false,
|
||||||
|
},
|
||||||
|
yAxis: [
|
||||||
|
{
|
||||||
|
type: "category",
|
||||||
|
splitLine: {
|
||||||
|
show: false,
|
||||||
|
},
|
||||||
|
axisLine: {
|
||||||
|
show: false,
|
||||||
|
},
|
||||||
|
axisTick: {
|
||||||
|
show: false,
|
||||||
|
},
|
||||||
|
inverse: true,
|
||||||
|
axisLabel: {
|
||||||
|
color: "#333",
|
||||||
|
fontSize: 16,
|
||||||
|
margin: 10,
|
||||||
|
formatter: (name: any, index: number) => {
|
||||||
|
const id = index + 1;
|
||||||
|
if (id == 1) {
|
||||||
|
return `{rank1|${id}}`;
|
||||||
|
} else if (id == 2) {
|
||||||
|
return `{rank2|${id}}`;
|
||||||
|
} else if (id == 3) {
|
||||||
|
return `{rank3|${id}}`;
|
||||||
|
} else {
|
||||||
|
return `{rank|${id}}`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
rich: {
|
||||||
|
rank1: {
|
||||||
|
width: 25,
|
||||||
|
height: 25,
|
||||||
|
lineHeight: 25,
|
||||||
|
fontSize: 16,
|
||||||
|
align: "center",
|
||||||
|
color: "#ffffff",
|
||||||
|
padding: [0, 10, 0, 0],
|
||||||
|
backgroundColor: {
|
||||||
|
image: rankIcons.icon1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
rank2: {
|
||||||
|
width: 25,
|
||||||
|
height: 25,
|
||||||
|
lineHeight: 25,
|
||||||
|
fontSize: 16,
|
||||||
|
align: "center",
|
||||||
|
color: "#ffffff",
|
||||||
|
padding: [0, 10, 0, 0],
|
||||||
|
backgroundColor: {
|
||||||
|
image: rankIcons.icon2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
rank3: {
|
||||||
|
width: 25,
|
||||||
|
height: 25,
|
||||||
|
lineHeight: 25,
|
||||||
|
fontSize: 16,
|
||||||
|
align: "center",
|
||||||
|
color: "#ffffff",
|
||||||
|
padding: [0, 10, 0, 0],
|
||||||
|
backgroundColor: {
|
||||||
|
image: rankIcons.icon3,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
rank: {
|
||||||
|
width: 25,
|
||||||
|
height: 25,
|
||||||
|
lineHeight: 25,
|
||||||
|
fontSize: 16,
|
||||||
|
align: "center",
|
||||||
|
color: "#ffffff",
|
||||||
|
padding: [0, 10, 0, 0],
|
||||||
|
backgroundColor: {
|
||||||
|
image: rankIcons.icon,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "category",
|
||||||
|
inverse: true,
|
||||||
|
axisTick: "none",
|
||||||
|
axisLine: "none",
|
||||||
|
show: true,
|
||||||
|
axisLabel: {
|
||||||
|
textStyle: {
|
||||||
|
// color: "#000000fd",
|
||||||
|
color: "#333", // 文字颜色
|
||||||
|
fontSize: 16,
|
||||||
|
},
|
||||||
|
formatter: function (value: any) {
|
||||||
|
return value + "个";
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data: dataJson.source.map((item) => item.value),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
series: [ seriesItem ],
|
||||||
|
dataset: { ...dataJson }, // 数据集
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class Config extends PublicConfigClass implements CreateComponentType {
|
||||||
|
public key: string = RankChartConfig.key
|
||||||
|
public chartConfig = cloneDeep(RankChartConfig)
|
||||||
|
// 图表配置项
|
||||||
|
public option = echartOptionProfixHandle(option, includes)
|
||||||
|
}
|
||||||
27
src/packages/components/Charts/Bars/RankChart/config.vue
Normal file
27
src/packages/components/Charts/Bars/RankChart/config.vue
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<template>
|
||||||
|
<!-- 遍历 seriesList -->
|
||||||
|
<global-setting :optionData="optionData" :in-chart="true"></global-setting>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { PropType, computed } from 'vue'
|
||||||
|
// 以下是封装的设置模块布局组件,具体效果可在官网查看
|
||||||
|
import {
|
||||||
|
GlobalSetting
|
||||||
|
} from '@/components/Pages/ChartItemSetting'
|
||||||
|
import { GlobalThemeJsonType } from '@/settings/chartThemes/index'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
optionData: {
|
||||||
|
type: Object as PropType<GlobalThemeJsonType>,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 去除options中的yAxis配置,不允许前端控制该属性
|
||||||
|
const optionData = computed(() => {
|
||||||
|
const { yAxis, ...rest } = props.optionData
|
||||||
|
return rest
|
||||||
|
})
|
||||||
|
|
||||||
|
</script>
|
||||||
48
src/packages/components/Charts/Bars/RankChart/data.json
Normal file
48
src/packages/components/Charts/Bars/RankChart/data.json
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
{
|
||||||
|
"dimensions": [
|
||||||
|
"name",
|
||||||
|
"value"
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
{
|
||||||
|
"name": "蔡洲",
|
||||||
|
"value": 691
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "孙磊",
|
||||||
|
"value": 544
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "张伟",
|
||||||
|
"value": 522
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "王文峰",
|
||||||
|
"value": 502
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "李强",
|
||||||
|
"value": 488
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "刘敏涛",
|
||||||
|
"value": 461
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "杨其",
|
||||||
|
"value": 395
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "王若娥",
|
||||||
|
"value": 389
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "童天宇",
|
||||||
|
"value": 335
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "杨欧鹏",
|
||||||
|
"value": 298
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
16
src/packages/components/Charts/Bars/RankChart/index.ts
Normal file
16
src/packages/components/Charts/Bars/RankChart/index.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { ConfigType, PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d'
|
||||||
|
import { ChatCategoryEnum, ChatCategoryEnumName } from '../../index.d'
|
||||||
|
|
||||||
|
import image from '@/assets/images/chart/charts/rank-chart.png'
|
||||||
|
|
||||||
|
export const RankChartConfig: ConfigType = {
|
||||||
|
key: 'RankChart',
|
||||||
|
chartKey: 'VRankChart',
|
||||||
|
conKey: 'VCRankChart',
|
||||||
|
title: '排行榜',
|
||||||
|
category: ChatCategoryEnum.BAR,
|
||||||
|
categoryName: ChatCategoryEnumName.BAR,
|
||||||
|
package: PackagesCategoryEnum.CHARTS,
|
||||||
|
chartFrame: ChartFrameEnum.ECHARTS,
|
||||||
|
image: image,
|
||||||
|
}
|
||||||
102
src/packages/components/Charts/Bars/RankChart/index.vue
Normal file
102
src/packages/components/Charts/Bars/RankChart/index.vue
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
<template>
|
||||||
|
<v-chart
|
||||||
|
ref="vChartRef"
|
||||||
|
:init-options="initOptions"
|
||||||
|
:theme="themeColor"
|
||||||
|
:option="option"
|
||||||
|
:manual-update="isPreview()"
|
||||||
|
autoresize
|
||||||
|
></v-chart>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, nextTick, computed, watch, PropType } from 'vue'
|
||||||
|
import VChart from 'vue-echarts'
|
||||||
|
import { useCanvasInitOptions } from '@/hooks/useCanvasInitOptions.hook'
|
||||||
|
import { use } from 'echarts/core'
|
||||||
|
import { CanvasRenderer } from 'echarts/renderers'
|
||||||
|
import { BarChart } from 'echarts/charts'
|
||||||
|
import config, { includes, seriesItem } from './config'
|
||||||
|
import { mergeTheme } from '@/packages/public/chart'
|
||||||
|
import { useChartDataFetch } from '@/hooks'
|
||||||
|
import { CreateComponentType } from '@/packages/index.d'
|
||||||
|
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
|
||||||
|
import { isPreview } from '@/utils'
|
||||||
|
import { DatasetComponent, GridComponent, TooltipComponent, LegendComponent } from 'echarts/components'
|
||||||
|
import isObject from 'lodash/isObject'
|
||||||
|
import cloneDeep from 'lodash/cloneDeep'
|
||||||
|
|
||||||
|
// 这里的 themeSetting、themeColor的作用是监听全局样式主题并进行设置,chartConfig 为图表的配置项数据
|
||||||
|
const props = defineProps({
|
||||||
|
themeSetting: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
themeColor: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
chartConfig: {
|
||||||
|
type: Object as PropType<config>,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const initOptions = useCanvasInitOptions(props.chartConfig.option, props.themeSetting)
|
||||||
|
|
||||||
|
// 动态注册 ECharts 图表内容
|
||||||
|
use([DatasetComponent, CanvasRenderer, BarChart, GridComponent, TooltipComponent, LegendComponent])
|
||||||
|
|
||||||
|
const replaceMergeArr = ref<string[]>()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 应用到图表的 option
|
||||||
|
const option = computed(() => {
|
||||||
|
return mergeTheme(props.chartConfig.option, props.themeSetting, includes)
|
||||||
|
})
|
||||||
|
|
||||||
|
// dataset 无法变更条数的补丁
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.chartConfig.option.dataset,
|
||||||
|
(newData: { dimensions: any }, oldData) => {
|
||||||
|
try {
|
||||||
|
if (!isObject(newData) || !('dimensions' in newData)) return
|
||||||
|
if (Array.isArray(newData?.dimensions)) {
|
||||||
|
const seriesArr = []
|
||||||
|
// 对oldData进行判断,防止传入错误数据之后对旧维度判断产生干扰
|
||||||
|
// 此处计算的是dimensions的Y轴维度,若是dimensions.length为0或1,则默认为1,排除X轴维度干扰
|
||||||
|
const oldDimensions = Array.isArray(oldData?.dimensions)&&oldData.dimensions.length >= 1 ? oldData.dimensions.length : 1;
|
||||||
|
const newDimensions = newData.dimensions.length >= 1 ? newData.dimensions.length : 1;
|
||||||
|
const dimensionsGap = newDimensions - oldDimensions;
|
||||||
|
if (dimensionsGap < 0) {
|
||||||
|
props.chartConfig.option.series.splice(newDimensions - 1)
|
||||||
|
} else if (dimensionsGap > 0) {
|
||||||
|
if(!oldData || !oldData?.dimensions || !Array.isArray(oldData?.dimensions) || !oldData?.dimensions.length ) {
|
||||||
|
props.chartConfig.option.series=[]
|
||||||
|
}
|
||||||
|
for (let i = 0; i < dimensionsGap; i++) {
|
||||||
|
seriesArr.push(cloneDeep(seriesItem))
|
||||||
|
}
|
||||||
|
props.chartConfig.option.series.push(...seriesArr)
|
||||||
|
}
|
||||||
|
replaceMergeArr.value = ['series']
|
||||||
|
nextTick(() => {
|
||||||
|
replaceMergeArr.value = []
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
deep: false
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
const { vChartRef } = useChartDataFetch(props.chartConfig, useChartEditStore, (newData: any) => {
|
||||||
|
props.chartConfig.option.dataset = newData
|
||||||
|
})
|
||||||
|
</script>
|
||||||
@ -2,5 +2,6 @@ import { BarCommonConfig } from './BarCommon/index'
|
|||||||
import { BarCrossrangeConfig } from './BarCrossrange/index'
|
import { BarCrossrangeConfig } from './BarCrossrange/index'
|
||||||
import { CapsuleChartConfig } from './CapsuleChart/index'
|
import { CapsuleChartConfig } from './CapsuleChart/index'
|
||||||
import { BarLineConfig } from './BarLine/index'
|
import { BarLineConfig } from './BarLine/index'
|
||||||
|
import { RankChartConfig } from './RankChart'
|
||||||
|
|
||||||
export default [BarCommonConfig, BarCrossrangeConfig, BarLineConfig, CapsuleChartConfig]
|
export default [BarCommonConfig, BarCrossrangeConfig, BarLineConfig, CapsuleChartConfig, RankChartConfig]
|
||||||
|
|||||||
@ -2,7 +2,8 @@ import { PublicConfigClass } from '@/packages/public'
|
|||||||
import { CreateComponentType } from '@/packages/index.d'
|
import { CreateComponentType } from '@/packages/index.d'
|
||||||
import { ImageConfig } from './index'
|
import { ImageConfig } from './index'
|
||||||
import cloneDeep from 'lodash/cloneDeep'
|
import cloneDeep from 'lodash/cloneDeep'
|
||||||
import logo from '@/assets/logo.png'
|
// import logo from '@/assets/logo.png'
|
||||||
|
import logo from '@/assets/images/chart/informations/richeng.png'
|
||||||
|
|
||||||
export const option = {
|
export const option = {
|
||||||
// 图片路径
|
// 图片路径
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user