539 lines
15 KiB
Vue
539 lines
15 KiB
Vue
<template>
|
||
<div>
|
||
<el-card class="box-card box-card-h">
|
||
<el-row justify="space-between" class="x-y-axis">
|
||
<el-text>值轴/{{ boxName }}</el-text>
|
||
<el-tooltip
|
||
effect="dark"
|
||
:content="boxName+',数据类型必须一致!'"
|
||
placement="bottom"
|
||
>
|
||
<el-icon>
|
||
<Warning/>
|
||
</el-icon>
|
||
</el-tooltip>
|
||
</el-row>
|
||
<div class="drag-block">
|
||
<draggable
|
||
class="list-group"
|
||
:list="dragList"
|
||
itemKey="id"
|
||
:group="group"
|
||
@start="startDrag"
|
||
@change="dragChartItem"
|
||
>
|
||
<template #item="{ element,index }">
|
||
<div :id="element.dataType==='value'?'card_'+index:''" tabindex="1"
|
||
@click.stop="handleClickValueCard(element,index)">
|
||
<el-card shadow="hover" class="cards x-y-cards"
|
||
:style="{borderWidth:1,borderColor:element.dataType==='value'?element.color:'#e4e7ed'}">
|
||
<el-col :span="3">
|
||
<div>{{ element.label }}</div>
|
||
</el-col>
|
||
<el-col :span="13">
|
||
<div v-if="element.dataType==='value'" class="update-color">
|
||
<div class="update-color" @click.stop>
|
||
<span>图形:</span>
|
||
<el-color-picker v-model="element.color" :color="element.color"
|
||
@change="changeEchartsColor($event,index)" @active-change="handleActiveChange"/>
|
||
</div>
|
||
<div v-if="currentChart==='line'" class="update-color" @click.stop>
|
||
<span>阴影:</span>
|
||
<el-color-picker v-model="element.lineStyle.shadowColor" :color="element.lineStyle.shadowColor"
|
||
@change="changeShadowColor($event,index)" @active-change="handleActiveChange"/>
|
||
</div>
|
||
<div v-if="currentChart==='bar'" class="update-color" @click.stop>
|
||
<span>背景: </span>
|
||
<el-color-picker v-model="element.backgroundStyle.color" :color="element.backgroundStyle.color"
|
||
@change="changeBackgroundColor($event,index)" @active-change="handleActiveChange"/>
|
||
</div>
|
||
<div v-if="currentChart==='bar'" class="update-color" @click.stop>
|
||
<span >描边: </span>
|
||
<el-color-picker v-model="element.backgroundStyle.borderColor" :color="element.backgroundStyle.borderColor"
|
||
@change="changeBackgroundBorderColor($event,index)" @active-change="handleActiveChange"/>
|
||
</div>
|
||
</div>
|
||
</el-col>
|
||
<el-col :span="4">
|
||
<div class="cards-right">
|
||
<span>{{ element.dataType }}</span>
|
||
<el-icon size="20" color="red" @click.stop="handleCancelAxis(element,index)"
|
||
style="cursor: pointer">
|
||
<CircleClose/>
|
||
</el-icon>
|
||
</div>
|
||
</el-col>
|
||
</el-card>
|
||
</div>
|
||
</template>
|
||
</draggable>
|
||
</div>
|
||
</el-card>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import draggable from 'vuedraggable'
|
||
|
||
const emit = defineEmits(["editBasicSettingList"])
|
||
const props = defineProps({
|
||
//box名字
|
||
boxName: {
|
||
type: String,
|
||
default: ''
|
||
},
|
||
//可供拖动的选项列表
|
||
dragOptions: {
|
||
type: Array,
|
||
default: []
|
||
},
|
||
//用于拖拽区域存放选项列表
|
||
dragList: {
|
||
type: Array,
|
||
default: []
|
||
},
|
||
//用于X轴区域存放拖动的选项
|
||
xAxisList: {
|
||
type: Array,
|
||
default: []
|
||
},
|
||
//用于Y轴区域存放拖动的选项
|
||
yAxisList: {
|
||
type: Array,
|
||
default: []
|
||
},
|
||
//标记正在拖动选项的数据类型是否value
|
||
flag: {
|
||
type: Boolean,
|
||
default: false
|
||
},
|
||
//获取正在拖动选项的数据类型
|
||
startDataType: {
|
||
type: String,
|
||
default: ''
|
||
},
|
||
//初始化加载echarts函数
|
||
initCharts: {
|
||
type: Function,
|
||
default: null
|
||
},
|
||
//echarts的配置属性
|
||
chartOption: {
|
||
type: Array,
|
||
default: []
|
||
},
|
||
//当前echarts图形
|
||
currentChart: {
|
||
type: String,
|
||
default: 'line'
|
||
}
|
||
})
|
||
//基础设置列表
|
||
const lineChartBasicSettingList = ref()
|
||
const barChartBasicSettingList = ref()
|
||
//选中类型为value的item所处的list列表
|
||
const valueCardInList = ref([])
|
||
//简化代码
|
||
let xList = reactive(props.xAxisList)
|
||
let yList = reactive(props.yAxisList)
|
||
let option = reactive(props.chartOption)
|
||
//路由刷新
|
||
const reload = inject("reload")
|
||
//自定义X/Y分组的拖入拖出事件
|
||
const group = ref({
|
||
name: 'people',
|
||
pull: true,
|
||
put: props.flag === true ? false : (props.boxName === 'X轴' ? () => handleGroupPut(xList, yList) : () => handleGroupPut(yList, xList))
|
||
})
|
||
//将改变的数据传到父组件
|
||
watch(() => lineChartBasicSettingList.value, (newVal) => {
|
||
emit("getLineChartBasicSettingList", newVal)
|
||
})
|
||
//将改变的数据传到父组件
|
||
watch(() => barChartBasicSettingList.value, (newVal) => {
|
||
emit("getBarChartBasicSettingList", newVal)
|
||
})
|
||
onMounted(() => {
|
||
document.addEventListener('click', nullBlockClick)
|
||
})
|
||
onBeforeUnmount(() => {
|
||
document.removeEventListener('click', nullBlockClick)
|
||
})
|
||
/**
|
||
* 设置chart的lineStyle
|
||
* @param sItem chartItem
|
||
* @param opacity 透明度
|
||
*/
|
||
const handleChangeLineStyle = (sItem, opacity) => {
|
||
sItem.lineStyle = {
|
||
shadowColor: sItem.lineStyle.shadowColor,
|
||
shadowBlur: sItem.lineStyle.shadowBlur,
|
||
opacity: opacity
|
||
}
|
||
}
|
||
/**
|
||
* 用于取消charts选中透明度
|
||
*/
|
||
const handleChangeOpacity = (type, item) => {
|
||
if (props.currentChart === 'line') {
|
||
option.series.forEach((sItem) => {
|
||
if (type === 'more') {
|
||
if (sItem.name === item.label) {
|
||
handleChangeLineStyle(sItem, 1)
|
||
} else {
|
||
handleChangeLineStyle(sItem, 0.2)
|
||
}
|
||
} else if (type === 'single') {
|
||
handleChangeLineStyle(sItem, 1)
|
||
} else {
|
||
if (sItem.name !== item.label) {
|
||
handleChangeLineStyle(sItem, 1)
|
||
}
|
||
}
|
||
})
|
||
}
|
||
}
|
||
/**
|
||
* 点击空白处, 清除选项选中状态
|
||
*/
|
||
const nullBlockClick = () => {
|
||
if (valueCardInList.value.length === 0) return;
|
||
valueCardInList.value.forEach((aItem, aIndex) => {
|
||
const card = document.getElementById('card_' + aIndex)
|
||
card.classList.remove('card-active')
|
||
})
|
||
clearBasicSetting()
|
||
//加载echarts
|
||
props.initCharts()
|
||
}
|
||
/**
|
||
* 封装自定义X/Y分组的拖入事件
|
||
* @param aType 传入x/y区域数组
|
||
* @param bType 传入x/y区域数组
|
||
* @returns {boolean} 返回 true/false
|
||
*/
|
||
const handleGroupPut = (aType, bType) => {
|
||
let flag = false
|
||
let aLen = aType.length
|
||
let bLen = bType.length
|
||
if (aLen === 0 && bLen === 0) {
|
||
flag = props.startDataType === 'key';
|
||
} else if (aLen === 0 && bLen !== 0) {
|
||
flag = bType[0].dataType === 'key';
|
||
} else if (aLen !== 0 && bLen !== 0) {
|
||
const dragType = localStorage.getItem('dragType')
|
||
flag = props.startDataType === aType[0].dataType;
|
||
if (dragType === 'key') {
|
||
flag = aType[0].dataType !== 'value';
|
||
}
|
||
}
|
||
return flag
|
||
}
|
||
/**
|
||
* 封装切换坐标轴数据类型为Category
|
||
* @param item 拖动的项
|
||
* @param label 坐标轴名称
|
||
* @param type 切换x/y轴
|
||
*/
|
||
const changeTypeToCategory = (item, label, type) => {
|
||
let axis
|
||
if (type === 'xAxis') {
|
||
axis = option.xAxis
|
||
} else {
|
||
axis = option.yAxis
|
||
}
|
||
axis.type = 'category'
|
||
axis.name = label
|
||
axis.data = item.data
|
||
}
|
||
|
||
/**
|
||
* 封装清除坐标轴数据
|
||
* @param type 标志清除x/y轴
|
||
*/
|
||
const clearAxisData = (type) => {
|
||
let axis
|
||
if (type === 'xAxis') {
|
||
axis = option.xAxis
|
||
} else {
|
||
axis = option.yAxis
|
||
}
|
||
axis.name = ''
|
||
axis.data = []
|
||
}
|
||
/**
|
||
* 封装key拖入左侧时的重置事件
|
||
* @param aList x/yList
|
||
* @param type x/yAxis
|
||
* @param item 选项item
|
||
* @param label 选项名
|
||
*/
|
||
const restoreChart = (aList, type,item,label) => {
|
||
let axis
|
||
if (type === 'xAxis') {
|
||
axis = option.xAxis
|
||
} else {
|
||
axis = option.yAxis
|
||
}
|
||
if (aList[0].dataType === 'value') {
|
||
aList.map((item) => {
|
||
props.dragOptions.unshift(item)
|
||
option.legend.selected[item.label] = false
|
||
})
|
||
aList.splice(0, aList.length)
|
||
option.legend.data.splice(0, option.legend.data.length)
|
||
option.series.splice(0, option.series.length)
|
||
axis.name = ''
|
||
option.xAxis.type = 'category'
|
||
option.yAxis.type = 'value'
|
||
} else {
|
||
changeTypeToCategory(item, label, type)
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 拖拽类型为key的选项事件
|
||
* @param item 选项item
|
||
* @param label 选项名
|
||
*/
|
||
const dragTypeToKey = (item, label) => {
|
||
if (xList.length !== 0 && yList.length === 0) {
|
||
restoreChart(xList, 'xAxis',item,label)
|
||
clearAxisData('yAxis')
|
||
} else if (xList.length === 0 && yList.length !== 0) {
|
||
restoreChart(yList, 'yAxis',item,label)
|
||
clearAxisData('xAxis')
|
||
} else if (xList.length === 0 && yList.length === 0) {
|
||
//移入左侧待选列表
|
||
clearAxisData('xAxis')
|
||
clearAxisData('yAxis')
|
||
}
|
||
}
|
||
/**
|
||
* 拖拽类型为value的选项事件
|
||
* @param label 选项名
|
||
*/
|
||
const dragTypeToValue = (label) => {
|
||
//删除选中选项的图例
|
||
const legendIndex = option.legend.data.findIndex(object => object === label);
|
||
option.legend.data.splice(legendIndex, 1)
|
||
//删除echarts配置项series中符合该拖拽选项的item
|
||
const objectIndex = option.series.findIndex(object => object.name === label);
|
||
option.legend.selected[label] = false
|
||
option.series.splice(objectIndex, 1)
|
||
if (xList.length === 0) {
|
||
option.xAxis.name = ''
|
||
} else if (yList.length === 0) {
|
||
option.yAxis.name = ''
|
||
}
|
||
clearBasicSetting()
|
||
handleDeleteClassName(xList, yList)
|
||
}
|
||
/**
|
||
* 封装清空基本设置
|
||
*/
|
||
const clearBasicSetting=()=>{
|
||
if(props.currentChart==='line'){
|
||
lineChartBasicSettingList.value = []
|
||
handleChangeOpacity('single')
|
||
}else if(props.currentChart==='bar'){
|
||
barChartBasicSettingList.value=[]
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 开始拖拽事件
|
||
* @param event event事件
|
||
*/
|
||
const startDrag = (event) => {
|
||
localStorage.setItem('dragType', event.item._underlying_vm_.dataType)
|
||
}
|
||
|
||
/**
|
||
* 从X轴/Y轴区域移动选项到左/右侧结束事件
|
||
* @param event event事件
|
||
*/
|
||
const dragChartItem = (event) => {
|
||
if (event.removed === undefined) return;
|
||
let item = event.removed.element
|
||
let label = item.label
|
||
//拖动key的选项
|
||
if (item.dataType === "key") {
|
||
dragTypeToKey(item, label)
|
||
} else {
|
||
dragTypeToValue(label)
|
||
}
|
||
props.initCharts()
|
||
localStorage.removeItem('dragType')
|
||
}
|
||
|
||
/**
|
||
* 选中数据类型为value的点击事件
|
||
* @param item 点击的选项item
|
||
* @param index 点击选项的下标
|
||
*/
|
||
const handleClickValueCard = (item, index) => {
|
||
document.addEventListener('click', nullBlockClick)
|
||
if (item.dataType === 'value' ) {
|
||
if(props.currentChart === 'line'){
|
||
changeCardActive(props.dragList, item)
|
||
lineChartBasicSettingList.value = [item]
|
||
}else if(props.currentChart === 'bar'){
|
||
changeCardActive(props.dragList, item)
|
||
barChartBasicSettingList.value = [item]
|
||
}
|
||
}
|
||
props.initCharts()
|
||
}
|
||
|
||
/**
|
||
* 封装选中类型为value的数据高亮
|
||
* @param list x/y区域list
|
||
* @param item 点击选项的item
|
||
*/
|
||
const changeCardActive = (list, item) => {
|
||
valueCardInList.value = list
|
||
emit('getCardActiveList',list)
|
||
if (list.length !== 0 && list[0].dataType === 'value') {
|
||
handleChangeOpacity('more', item)
|
||
list.forEach((aItem, aIndex) => {
|
||
const card = document.getElementById('card_' + aIndex)
|
||
if (aItem.label === item.label) {
|
||
card.classList.add('card-active')
|
||
} else {
|
||
card.classList.remove('card-active')
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 基础设置: 修改echarts数据颜色
|
||
* @param val 修改的标记大小
|
||
* @param index 修改的chart项下标
|
||
*/
|
||
const changeEchartsColor = (val, index) => {
|
||
document.addEventListener('click', nullBlockClick)
|
||
option.series[index].color = val
|
||
props.initCharts()
|
||
}
|
||
/**
|
||
* 当选择颜色时移除空白点击事件
|
||
*/
|
||
const handleActiveChange = () => {
|
||
document.removeEventListener('click', nullBlockClick)
|
||
}
|
||
|
||
/**
|
||
* 基础设置: 修改echarts数据颜色
|
||
* @param val 修改的标记大小
|
||
* @param index 修改的chart项下标
|
||
*/
|
||
const changeShadowColor = (val, index) => {
|
||
option.series[index].lineStyle.shadowColor = val
|
||
props.initCharts()
|
||
}
|
||
/**
|
||
* 基础设置:修改柱条背景颜色
|
||
* @param val 柱条颜色
|
||
* @param index 修改的chart项下标
|
||
*/
|
||
const changeBackgroundColor = (val, index) => {
|
||
option.series[index].backgroundStyle.color = val
|
||
props.initCharts()
|
||
}
|
||
/**
|
||
* 基础设置:修改柱条描边颜色
|
||
* @param val 柱条描边颜色
|
||
* @param index 修改的chart项下标
|
||
*/
|
||
const changeBackgroundBorderColor = (val, index) => {
|
||
option.series[index].backgroundStyle.borderColor = val
|
||
props.initCharts()
|
||
}
|
||
/**
|
||
* 封装从右侧区域拖出事件
|
||
* @param element 获取点击该拖出的选项事件
|
||
* @param index 点击该拖出选项的索引
|
||
* @param aList x/y区域的值
|
||
* @param bList x/y区域的值
|
||
* @param aAxis echarts配置项的x/y轴
|
||
* @param bAxis echarts配置项的x/y轴
|
||
*/
|
||
const handleCancel = (element, index, aList, bList, aAxis, bAxis) => {
|
||
aList.splice(index, 1)
|
||
props.dragOptions.push(element)
|
||
if (element.dataType === "key") {
|
||
aAxis.name = ''
|
||
aAxis.data = []
|
||
bAxis.name=''
|
||
bList.map((item) => {
|
||
props.dragOptions.unshift(item)
|
||
option.legend.selected[item.label] = false
|
||
})
|
||
bList.splice(0, bList.length)
|
||
option.legend.data.splice(0, option.legend.data.length)
|
||
option.series.splice(0, option.series.length)
|
||
// reload
|
||
props.initCharts()
|
||
} else {
|
||
if (bList.length !== 0 && aList.length === 0) {
|
||
if (bList[0].dataType === 'key') {
|
||
aAxis.name = ''
|
||
} else {
|
||
bAxis.name = ''
|
||
}
|
||
}
|
||
|
||
option.legend.data.splice(index, 1)
|
||
const objectIndex = option.series.findIndex(object => object.name === element.label);
|
||
option.legend.selected[element.label] = false
|
||
option.series.splice(objectIndex, 1)
|
||
props.initCharts()
|
||
}
|
||
if(props.currentChart==='line'){
|
||
handleChangeOpacity('not', element)
|
||
if (lineChartBasicSettingList.value === undefined) return;
|
||
lineChartBasicSettingList.value.splice(0, 1)
|
||
}else if(props.currentChart==='bar'){
|
||
if (barChartBasicSettingList.value === undefined) return;
|
||
barChartBasicSettingList.value.splice(0, 1)
|
||
}
|
||
// const basicIndex = lineChartBasicSettingList.value.findIndex(object => object.label === element.label)
|
||
// if (basicIndex !== -1) {
|
||
// lineChartBasicSettingList.value.splice(basicIndex, 1)
|
||
// }
|
||
handleDeleteClassName(aList, bList)
|
||
props.initCharts()
|
||
}
|
||
/**
|
||
* 拖拽选项后,清除选中选项阴影
|
||
* @param aList x/y list
|
||
* @param bList x/y list
|
||
*/
|
||
const handleDeleteClassName = (aList, bList) => {
|
||
let axis = []
|
||
if (aList.length !== 0 && aList[0].dataType === 'value') {
|
||
axis = aList
|
||
} else if (bList.length !== 0 && bList[0].dataType === 'value') {
|
||
axis = bList
|
||
}
|
||
axis.forEach((aItem, aIndex) => {
|
||
const card = document.getElementById('card_' + aIndex)
|
||
card.classList.remove('card-active')
|
||
})
|
||
}
|
||
/**
|
||
* 从右侧x/y轴区域取消选项
|
||
* @param element 该取消的项
|
||
* @param index 该取消项的下标
|
||
*/
|
||
const handleCancelAxis = (element, index) => {
|
||
if (props.boxName === 'X轴') {
|
||
handleCancel(element, index, xList, yList, option.xAxis, option.yAxis)
|
||
} else {
|
||
handleCancel(element, index, yList, xList, option.yAxis, option.xAxis)
|
||
}
|
||
}
|
||
</script>
|