diff --git a/data-room-ui/packages/BasicComponents/Candlestick/setting.vue b/data-room-ui/packages/BasicComponents/Candlestick/setting.vue index 8e8a0bf3..60c86563 100644 --- a/data-room-ui/packages/BasicComponents/Candlestick/setting.vue +++ b/data-room-ui/packages/BasicComponents/Candlestick/setting.vue @@ -349,7 +349,6 @@ import { predefineColors } from 'data-room-ui/js/utils/colorList' export default { name: 'BarSetting', components: { - ColorSelect, ColorPicker, PosWhSetting, SettingTitle, diff --git a/data-room-ui/packages/BasicComponents/Sankey/index.vue b/data-room-ui/packages/BasicComponents/Sankey/index.vue new file mode 100644 index 00000000..c7b42865 --- /dev/null +++ b/data-room-ui/packages/BasicComponents/Sankey/index.vue @@ -0,0 +1,268 @@ +<!-- +@name: +@description: +@author: byx +@time: 桑基图 +--> +<template> + <div + :id="config.code + 'wrap'" + class="bs-design-wrap bs-bar" + style="width: 100%; height: 100%" + > + <div + :id="`chart${config.code}`" + style="width: 100%; height: 100%" + /> + </div> +</template> +<script> +import 'insert-css' +import * as echarts from 'echarts' +import commonMixins from 'data-room-ui/js/mixins/commonMixins.js' +import paramsMixins from 'data-room-ui/js/mixins/paramsMixins' +import linkageMixins from 'data-room-ui/js/mixins/linkageMixins' + +export default { + name: 'Sankey', + mixins: [paramsMixins, commonMixins, linkageMixins], + props: { + id: { + type: String, + default: '' + }, + config: { + type: Object, + default: () => ({}) + } + }, + data () { + return { + currentDeep: 0, + mapList: [], + charts: null, + hasData: false, + level: '', + option: {}, + links: [], + yData: [] + } + }, + computed: { + }, + watch: { + }, + mounted () { + this.chartInit() + // 监听窗口或者父盒子大小变化 + this.chartResize() + }, + beforeDestroy () { + this.charts?.clear() + }, + methods: { + chartResize () { + window.addEventListener('resize', () => { + if (this.charts) { + this.charts.resize() + } + }) + const dom = document.getElementById(`${this.config.code}wrap`) + if (dom) { + this.resizeObserver = new ResizeObserver(() => { + if (this.charts) { + this.charts.resize() + } + }) + this.resizeObserver.observe(dom) + } + }, + chartInit () { + const config = this.config + // key和code相等,说明是一进来刷新,调用list接口 + if (this.config.code === this.config.key || this.isPreview) { + // 改变数据 + this.changeDataByCode(config).then((res) => { + // 改变样式 + // config = this.changeStyle(res) + this.newChart(config) + }).catch(() => { + }) + } else { + // 否则说明是更新,这里的更新只指更新数据(改变样式时是直接调取changeStyle方法),因为更新数据会改变key,调用chart接口 + this.changeData(config).then((res) => { + // 初始化图表 + this.newChart(config) + }) + } + }, + /** + * 数据格式化 + * 该方法继承自commonMixins + * @param {*} config + * @param {Array} data + */ + dataFormatting (config, _data) { + const data = _data?.data + if (data && data.length) { + const list = data.map(item => [item[config.dataSource.dimensionField], item[config.dataSource.metricField]])?.flat() || [] + // 去重 + this.yData = [...new Set(list)]?.map(item => ({ name: item })) + this.links = data.map(item => ({ + source: item[config.dataSource.dimensionField], + target: item[config.dataSource.metricField], + value: item[config.dataSource.seriesField] + })) + } else { + this.links = [ + { + source: 'a', + target: 'a1', + value: 5 + }, + { + source: 'a', + target: 'a2', + value: 3 + }, + { + source: 'b', + target: 'b1', + value: 8 + }, + { + source: 'a', + target: 'b1', + value: 3 + }, + { + source: 'b1', + target: 'a1', + value: 1 + }, + { + source: 'b1', + target: 'c', + value: 2 + } + ] + this.yData = [ + { name: 'a' }, + { name: 'b' }, + { name: 'a1' }, + { name: 'a2' }, + { name: 'b1' }, + { name: 'c' } + ] + } + return config + }, + // 更新图表数据 + updateChartData (config) { + this.handleOption(config) + this.charts.setOption(this.option) + }, + changeStyle (config) { + this.handleOption(config) + this.charts.setOption(this.option) + }, + /** + * 初始化地图 + * 该方法继承自commonMixins + * @param {*} config + */ + async newChart (config) { + if (this.charts) { + this.charts.dispose() + } + this.charts = echarts.init( + document.getElementById(`chart${this.config.code}`) + ) + // 处理option,将配置项转换为echarts的option + this.handleOption(config) + this.charts.setOption(this.option) + }, + /** + * 处理配置项option + * @param {*} config + */ + handleOption (config) { + this.option = { + tooltip: { + // 显示提示框 + show: true, + trigger: 'item', + axisPointer: { + type: 'line' + } + }, + series: [ + { + type: 'sankey', + label: { + show: true, + position: config.customize.normal.labelPosition || 'right', + color: config.customize.normal.labelColor || '#fff', + fontSize: config.customize.normal.labelSize || 12, + fontWeight: config.customize.normal.labelFontWeight || 'bold' + }, + itemStyle: { + borderColor: config.customize.normal.itemBorderColor || '#aaa', + borderWidth: config.customize.normal.itemBorderWidth || 1, + borderType: config.customize.normal.itemBorderType || 'solid' + }, + lineStyle: { + color: config.customize.normal.lineColor || 'gradient', + curveness: config.customize.normal.lineCurveness || 0.5// 图形的弯曲程度 + + }, + emphasis: { // 聚焦文字时产生的高亮状态 + disabled: false, + focus: 'trajectory', + label: { + color: config.customize.emphasis.labelColor || '#fff', + fontSize: config.customize.emphasis.labelSize || 12, + fontWeight: config.customize.normal.labelFontWeight || 'bold', + }, + itemStyle: { + borderColor: config.customize.emphasis.itemBorderColor || '#aaa', + borderWidth: config.customize.emphasis.itemBorderWidth || 1, + borderType: config.customize.emphasis.itemBorderType || 'solid' + }, + lineStyle: { + color: config.customize.emphasis.lineColor || 'gradient' + } + + }, + data: this.yData, + links: this.links + } + ] + } + } + + } +} +</script> + +<style lang="scss" scoped> +@import '../../assets/style/echartStyle'; + +.light-theme { + background-color: #ffffff; + color: #000000; +} + +.auto-theme { + background-color: rgba(0, 0, 0, 0); +} + +.bs-design-wrap { + position: relative; + + .button { + position: absolute; + z-index: 999; + } +} +</style> diff --git a/data-room-ui/packages/BasicComponents/Sankey/setting.vue b/data-room-ui/packages/BasicComponents/Sankey/setting.vue new file mode 100644 index 00000000..0ce8885f --- /dev/null +++ b/data-room-ui/packages/BasicComponents/Sankey/setting.vue @@ -0,0 +1,496 @@ +<template> + <div class="bs-setting-wrap"> + <el-form + ref="form" + :model="config" + label-width="90px" + label-position="left" + class="setting-body bs-el-form" + > + <SettingTitle>标题</SettingTitle> + <div class="lc-field-body"> + <el-form-item + label="标题" + label-width="100px" + > + <el-input + v-model="config.title" + placeholder="请输入标题" + clearable + /> + </el-form-item> + </div> + <SettingTitle>位置</SettingTitle> + <div class="lc-field-body"> + <PosWhSetting :config="config" /> + </div> + <SettingTitle v-if="config.border"> + 边框 + </SettingTitle> + <div class="lc-field-body"> + <BorderSetting + v-if="config.border" + label-width="100px" + :config="config.border" + :big-title="config.title" + /> + </div> + <SettingTitle>旋转</SettingTitle> + <div class="lc-field-body"> + <RotateSetting + :config="config" + /> + </div> + <SettingTitle>图表</SettingTitle> + <div class="lc-field-body"> + <el-form-item + label="图形背景色" + label-width="100px" + > + <el-radio-group + v-model="lineColorType" + style="margin-bottom: 8px;" + > + <el-radio :label="'theme'"> + 颜色字段 + </el-radio> + <el-radio :label="'customize'"> + 自定义 + </el-radio> + </el-radio-group> + <el-select + v-if="lineColorType === 'theme'" + v-model="config.customize.normal.lineColor" + popper-class="bs-el-select" + class="bs-el-select" + placeholder="请选择颜色字段" + > + <el-option + v-for="item in colorFields" + :key="item.value" + :label="item.label" + :value="item.value" + /> + </el-select> + <ColorPicker + v-if="lineColorType === 'customize'" + v-model="config.customize.normal.lineColor" + :predefine-colors="predefineThemeColors" + /> + </el-form-item> + <el-form-item + label="图形弯曲度" + label-width="100px" + > + <el-input-number + v-model="config.customize.normal.lineCurveness" + class="bs-el-input-number" + /> + </el-form-item> + <el-form-item + label="矩形边框色" + label-width="100px" + > + <ColorPicker + v-model="config.customize.normal.itemBorderColor" + :predefine-colors="predefineThemeColors" + /> + </el-form-item> + <el-form-item + label="矩形边框宽度" + label-width="100px" + > + <el-input-number + v-model="config.customize.normal.itemBorderWidth" + class="bs-el-input-number" + /> + </el-form-item> + <el-form-item + + label="矩形边框样式" + label-width="100px" + > + <el-select + v-model="config.customize.normal.itemBorderType" + popper-class="bs-el-select" + class="bs-el-select" + placeholder="请选择位置" + > + <el-option + v-for="item in borderTypeList" + :key="item.value" + :label="item.label" + :value="item.value" + /> + </el-select> + </el-form-item> + <el-form-item + + label="标签位置" + label-width="100px" + > + <el-select + v-model="config.customize.normal.labelPosition" + popper-class="bs-el-select" + class="bs-el-select" + placeholder="请选择位置" + > + <el-option + v-for="item in labelPositionList" + :key="item.value" + :label="item.label" + :value="item.value" + /> + </el-select> + </el-form-item> + <el-form-item + label="标签颜色" + label-width="100px" + > + <ColorPicker + v-model="config.customize.normal.labelColor" + :predefine-colors="predefineThemeColors" + /> + </el-form-item> + <el-form-item + label="标签字体大小" + label-width="100px" + > + <el-input-number + v-model="config.customize.normal.labelSize" + class="bs-el-input-number" + /> + </el-form-item> + <el-form-item + label="标签字体粗细" + label-width="100px" + > + <el-select + v-model="config.customize.normal.labelFontWeight" + popper-class="bs-el-select" + class="bs-el-select" + placeholder="请选择位置" + > + <el-option + v-for="item in fontWeightList" + :key="item.value" + :label="item.label" + :value="item.value" + /> + </el-select> + </el-form-item> + </div> + <SettingTitle> + 高亮设置 + </SettingTitle> + <div class="lc-field-body"> + <el-form-item + label="图形背景色" + label-width="100px" + > + <el-radio-group v-model="lineColorType"> + <el-radio :label="'theme'"> + 颜色字段 + </el-radio> + <el-radio :label="'customize'"> + 自定义 + </el-radio> + </el-radio-group> + <el-select + v-if="lineColorType === 'theme'" + v-model="config.customize.emphasis.lineColor" + popper-class="bs-el-select" + class="bs-el-select" + placeholder="请选择颜色字段" + > + <el-option + v-for="item in colorFields" + :key="item.value" + :label="item.label" + :value="item.value" + /> + </el-select> + <ColorPicker + v-if="lineColorType === 'customize'" + v-model="config.customize.emphasis.lineColor" + :predefine-colors="predefineThemeColors" + /> + </el-form-item> + <el-form-item + label="矩形边框色" + label-width="100px" + > + <ColorPicker + v-model="config.customize.emphasis.itemBorderColor" + :predefine-colors="predefineThemeColors" + /> + </el-form-item> + <el-form-item + label="矩形边框宽度" + label-width="100px" + > + <el-input-number + v-model="config.customize.emphasis.itemBorderWidth" + class="bs-el-input-number" + /> + </el-form-item> + <el-form-item + + label="矩形边框样式" + label-width="100px" + > + <el-select + v-model="config.customize.emphasis.itemBorderType" + popper-class="bs-el-select" + class="bs-el-select" + placeholder="请选择位置" + > + <el-option + v-for="item in borderTypeList" + :key="item.value" + :label="item.label" + :value="item.value" + /> + </el-select> + </el-form-item> + <el-form-item + label="标签颜色" + label-width="100px" + > + <ColorPicker + v-model="config.customize.emphasis.labelColor" + :predefine-colors="predefineThemeColors" + /> + </el-form-item> + <el-form-item + label="标签字体大小" + label-width="100px" + > + <el-input-number + v-model="config.customize.emphasis.labelSize" + class="bs-el-input-number" + /> + </el-form-item> + <el-form-item + label="标签字体粗细" + label-width="100px" + > + <el-select + v-model="config.customize.emphasis.labelFontWeight" + popper-class="bs-el-select" + class="bs-el-select" + placeholder="请选择位置" + > + <el-option + v-for="item in fontWeightList" + :key="item.value" + :label="item.label" + :value="item.value" + /> + </el-select> + </el-form-item> + </div> + </el-form> + </div> +</template> +<script> +import SettingTitle from 'data-room-ui/SettingTitle/index.vue' +import { chartSettingMixins } from 'data-room-ui/js/mixins/chartSettingMixins' +import ColorSelect from 'data-room-ui/ColorMultipleSelect/index.vue' +import ColorPicker from 'data-room-ui/ColorPicker/index.vue' +import BorderSetting from 'data-room-ui/BigScreenDesign/RightSetting/BorderSetting.vue' +import PosWhSetting from 'data-room-ui/BigScreenDesign/RightSetting/PosWhSetting.vue' +import RotateSetting from 'data-room-ui/BigScreenDesign/RightSetting/RotateSetting.vue' +import { predefineColors } from 'data-room-ui/js/utils/colorList' +export default { + name: 'BarSetting', + components: { + ColorPicker, + SettingTitle, + PosWhSetting, + BorderSetting, + RotateSetting + }, + mixins: [chartSettingMixins], + props: {}, + data () { + return { + lineColorType: 'theme', + fontWeightList: [ + { + label: '正常', + value: 'normal' + }, + { + label: '粗体', + value: 'bold' + }, + { + label: '加粗', + value: 'bolder' + }, + { + label: '细体', + value: 'lighter' + } + ], + colorFields: [ + { + label: '起始字段', + value: 'source' + }, + { + label: '目标字段', + value: 'target' + }, + { + label: '渐变色', + value: 'gradient' + } + ], + borderTypeList: [ + { + label: '实线', + value: 'solid' + }, + { + label: '虚线', + value: 'dashed' + }, + { + label: '点线', + value: 'dotted' + } + ], + labelPositionList: [ + { + label: '顶部', + value: 'top' + }, + + { + label: '底部', + value: 'bottom' + }, + { + label: '靠左', + value: 'left' + }, + { + label: '靠右', + value: 'right' + }, + { + label: '内部', + value: 'inside' + }, + { + label: '内部靠左', + + value: 'insideLeft' + }, + { + label: '内部靠右', + value: 'insideRight' + }, + { + label: '内部顶部', + value: 'insideTop ' + }, + { + label: '内部底部', + value: 'insideBottom' + }, + { + label: '内部左上', + value: 'insideTopLeft' + }, + { + label: '内部右上', + value: 'insideTopRight' + }, + { + label: '内部左下', + value: 'insideBottomLeft' + }, + { + label: '内部右下', + value: 'insideBottomRight' + } + ], + colors: [], + mapList: [], + predefineThemeColors: predefineColors, + mapTree: [], + currentMap: {}, + axisPositionList: [ + { + label: '左', + value: 'start' + }, + { + label: '中', + value: 'center' + }, + { + label: '右', + value: 'end' + }] + } + }, + computed: { + config: { + get () { + return this.$store.state.bigScreen.activeItemConfig + }, + set (val) { + this.$store.state.bigScreen.activeItemConfig = val + } + } + }, + watch: {}, + mounted () { + this.colors = this.config.customize.rangeColor + }, + methods: { + delColor () { + if (this.colors.length <= 2) return + this.colors.pop() + this.config.customize.rangeColor.pop() + }, + addColor () { + this.colors.push('#fff') + }, + updateColorScheme (colors) { + this.colors = [...colors] + this.config.customize.rangeColor = [...colors] + } + } +} +</script> + +<style lang="scss" scoped> +@import '../../assets/style/settingWrap.scss'; +@import '../../assets/style/bsTheme.scss'; +// 筛选条件的按钮样式 +.add-filter-box { + position: relative; + .add-filter { + margin-left: 90px; + margin-bottom: 10px; + } + .add-filter-btn { + position: absolute; + top: 0; + } +} +.lc-field-body { + padding: 12px 16px; +} +::v-deep .bs-el-slider-dark { + + .el-slider__runway { + background-color: var(--bs-el-background-1) !important; + } +} +</style> diff --git a/data-room-ui/packages/BasicComponents/Sankey/settingConfig.js b/data-room-ui/packages/BasicComponents/Sankey/settingConfig.js new file mode 100644 index 00000000..5180548a --- /dev/null +++ b/data-room-ui/packages/BasicComponents/Sankey/settingConfig.js @@ -0,0 +1,101 @@ +import { commonConfig, displayOption } from 'data-room-ui/js/config' +import Icon from 'data-room-ui/assets/images/bigScreenIcon/export' +import cloneDeep from 'lodash/cloneDeep' + +export const settingConfig = { + padding: [10, 10, 10, 10], + legend: false, + isGroup: true, + data: [], + color: '', + theme: 'dark', + displayOption: { + ...displayOption, + params: { + enable: true + }, + dimensionField: { + // 指标 + label: '起始节点', + enable: true, + multiple: false // 是否多选 + }, + metricField: { + label: '目标节点', // 维度/查询字段 + enable: true, + multiple: false // 是否多选 + }, + seriesField: { + // 系列 + label: '权重', + enable: true, + multiple: false // 是否多选 + } + } +} +const customConfig = { + type: 'sankey', + root: { + version: '2023071001', + contribution: false, + // 绕x轴旋转角度 + rotateX: 0, + // 绕y轴旋转角度 + rotateY: 0, + // 绕z轴旋转角度 + rotateZ: 0, + // 透视距离 + perspective: 0, + skewX: 0, + skewY: 0 + }, + customize: { + // 自定义样式 + normal: { + labelPosition: 'right', + labelColor: '#fff', + labelFontSize: 12, + labelFontWeight: 'bold', + itemBorderColor: '#aaa', + itemBorderWidth: 1, + itemBorderType: 'solid', + lineColor: 'gradient', + lineCurveness: 0.5 + }, + emphasis: { + labelPosition: 'right', + labelColor: '#fff', + labelFontSize: 12, + labelFontWeight: 'bold', + itemBorderColor: '#aaa', + itemBorderWidth: 1, + itemBorderType: 'solid', + lineColor: 'gradient', + lineCurveness: 0.5 + } + } +} + +export const dataConfig = { + ...commonConfig(customConfig) +} + +export const sankeyData = { + name: '桑基图', + title: '桑基图', + icon: Icon.getNameList()[18], + border: { type: '', titleHeight: 60, fontSize: 16, isTitle: true, padding: [0, 0, 0, 0] }, + className: + 'com.gccloud.dataroom.core.module.chart.components.ScreenCandlestickChart', + w: 450, + h: 320, + x: 0, + y: 0, + type: 'sankey', + option: { + ...cloneDeep(settingConfig) + }, + setting: undefined, // 右侧面板自定义配置 + dataHandler: {}, // 数据自定义处理js脚本 + ...cloneDeep(dataConfig) +} diff --git a/data-room-ui/packages/BigScreenDesign/RightSetting/DataSetting.vue b/data-room-ui/packages/BigScreenDesign/RightSetting/DataSetting.vue index 996a3331..c58091bf 100644 --- a/data-room-ui/packages/BigScreenDesign/RightSetting/DataSetting.vue +++ b/data-room-ui/packages/BigScreenDesign/RightSetting/DataSetting.vue @@ -129,7 +129,7 @@ class="data-form-item" > <el-drag-select - v-if="config.option.displayOption.dimensionField.enable && config.option.displayOption.dimensionField.multiple" + v-if="config.option.displayOption.dimensionField.multiple" v-model="config.dataSource.dimensionFieldList" class="bs-el-select" popper-class="bs-el-select" @@ -212,6 +212,36 @@ </el-option> </el-select> </el-form-item> + <!--分组--> + <el-form-item + v-if="config.option.displayOption.metricField.enable" + :label="config.option.displayOption.seriesField.label" + prop="dataSource.metricField" + class="data-form-item" + > + <el-select + v-model="config.dataSource.seriesField" + class="bs-el-select" + popper-class="bs-el-select" + clearable + > + <el-option + v-for="(field, index) in dataSourceDataList" + :key="index" + :label="field.comment" + :value="field.name" + > + <div class="source-key-option"> + <div> + {{ field.comment !== "" ? field.comment : field.name }} + </div> + <div class="option-txt"> + {{ field.name }} + </div> + </div> + </el-option> + </el-select> + </el-form-item> </template> <!-- K线图数据配置 --> <template v-else-if="config.type === 'candlestick'"> diff --git a/data-room-ui/packages/G2Plots/plotList.js b/data-room-ui/packages/G2Plots/plotList.js index a4c1cf14..1ba905e7 100644 --- a/data-room-ui/packages/G2Plots/plotList.js +++ b/data-room-ui/packages/G2Plots/plotList.js @@ -7,6 +7,7 @@ import { dataConfig, settingConfig } from '../PlotRender/settingConfig' import { mapData } from 'data-room-ui/BasicComponents/Map/settingConfig' import { FlyMapData } from 'data-room-ui/BasicComponents/FlyMap/settingConfig' import { candlestickData } from 'data-room-ui/BasicComponents/Candlestick/settingConfig' +import { sankeyData } from 'data-room-ui/BasicComponents/Sankey/settingConfig' // import _ from 'lodash' import cloneDeep from 'lodash/cloneDeep' import sortList from './plotListSort' @@ -97,6 +98,6 @@ export function getCustomPlots () { return list } -const plots = [...plotList, ...customPlots, candlestickData, mapData, FlyMapData] +const plots = [...plotList, ...customPlots, sankeyData, candlestickData, mapData, FlyMapData] console.log('plotList', plots) export default plots