From 7a56f172d2a004247147e85cca17a35d0233c825 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A8=8B=E5=BA=8F=E5=91=98=E4=B8=96=E6=9E=97?= <463572181@qq.com> Date: Mon, 27 Feb 2023 14:00:36 +0800 Subject: [PATCH] =?UTF-8?q?1=E3=80=81=E7=BB=84=E4=BB=B6=E8=81=94=E5=8A=A8?= =?UTF-8?q?=E6=A1=88=E4=BE=8B(=E6=9F=B1=E5=9B=BE=EF=BC=9A=E8=A7=A6?= =?UTF-8?q?=E5=8F=91=E8=80=85+=E6=8E=A5=E6=94=B6=E8=80=85;=20=E6=8A=98?= =?UTF-8?q?=E7=BA=BF=E5=9B=BE=EF=BC=9A=E8=A7=A6=E5=8F=91=E8=80=85+?= =?UTF-8?q?=E6=8E=A5=E6=94=B6=E8=80=85;=20=E7=99=BE=E5=88=86=E6=AF=94?= =?UTF-8?q?=E5=9B=BE=EF=BC=9A=E6=8E=A5=E6=94=B6=E8=80=85;=20)=202=E3=80=81?= =?UTF-8?q?=E4=BF=9D=E5=AD=98=E3=80=81=E9=A2=84=E8=A7=88=E3=80=81=E6=92=A4?= =?UTF-8?q?=E5=9B=9E=E6=8C=89=E9=92=AE=E5=8F=AF=E7=82=B9=E5=87=BB=E8=8C=83?= =?UTF-8?q?=E5=9B=B4=E8=B0=83=E6=95=B4;=203=E3=80=81=E6=8B=96=E5=85=A5?= =?UTF-8?q?=E7=BB=84=E4=BB=B6=E9=85=8D=E7=BD=AE=E9=A1=B9=E5=AE=9A=E4=BD=8D?= =?UTF-8?q?=E4=B8=8D=E5=87=86=E7=9A=84bug=E4=BF=AE=E5=A4=8D;=204=E3=80=81?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=88=9D=E5=A7=8B=E5=A4=A7=E5=B1=8F=E9=BB=98?= =?UTF-8?q?=E8=AE=A4=E8=83=8C=E6=99=AF=E8=89=B2=E4=B8=8D=E7=94=9F=E6=95=88?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- report-ui/src/store/index.js | 4 +- report-ui/src/store/modules/designer.js | 42 +++ .../designer/components/componentLinkage.vue | 290 ++++++++++++++++++ .../designer/components/dynamicForm.vue | 23 ++ .../bigscreenDesigner/designer/index.vue | 79 ++++- .../designer/linkageLogic.js | 128 ++++++++ .../configure/barCharts/widget-barchart.js | 12 + .../configure/lineCharts/widget-linechart.js | 12 + .../percentCharts/widget-pie-percentage.js | 12 + .../bigscreenDesigner/designer/tools/index.js | 7 +- .../bigscreenDesigner/designer/tools/main.js | 6 +- .../designer/widget/bar/widgetBarchart.vue | 27 +- .../designer/widget/line/widgetLinechart.vue | 27 +- .../percent/widgetPiePercentageChart.vue | 26 +- .../designer/widget/temp.vue | 6 +- .../designer/widget/widget.vue | 2 +- .../views/bigscreenDesigner/viewer/index.vue | 11 + 17 files changed, 684 insertions(+), 30 deletions(-) create mode 100644 report-ui/src/store/modules/designer.js create mode 100644 report-ui/src/views/bigscreenDesigner/designer/components/componentLinkage.vue create mode 100644 report-ui/src/views/bigscreenDesigner/designer/linkageLogic.js diff --git a/report-ui/src/store/index.js b/report-ui/src/store/index.js index f011f382..89cec40a 100644 --- a/report-ui/src/store/index.js +++ b/report-ui/src/store/index.js @@ -7,6 +7,7 @@ import app from './modules/app' import user from './modules/user' import cacheView from './modules/cachaView' import help from './modules/help' +import designer from './modules/designer' Vue.use(Vuex) @@ -18,7 +19,8 @@ const store = new Vuex.Store({ app, user, cacheView, - help + help, + designer }, state: { }, plugins: [initPlugin], diff --git a/report-ui/src/store/modules/designer.js b/report-ui/src/store/modules/designer.js new file mode 100644 index 00000000..ae275cac --- /dev/null +++ b/report-ui/src/store/modules/designer.js @@ -0,0 +1,42 @@ +/* + * @Author: chengsl + * @Date: 2022-11-08 10:30:37 + * @LastEditors: chengsl + * @LastEditTime: 2023-02-24 09:54:34 + * @Description: 设计器公用变量 + */ + +const designer = { + state: { + allComponentLinkage: [], // 所有组件之间的联动配置 + }, + + mutations: { + SET_ALL_COMPONENT_LINKAGE: (state, params) => { + var { index = -1, widgetId = '', linkageArr } = params + try { + console.log('params---', params) + linkageArr = linkageArr.map(item => { + const arr = item.widgetValue.split('-$-') + return { + originId: widgetId, + targetId: arr[0], + targetName: arr[1], + paramsConfig: item.paramsConfig + } + }) + } catch (error) { + linkageArr = [] // 兼容异常错误导致页面加载不出来 + } + state.allComponentLinkage[index] = { + index: +index, + widgetId, + linkageArr + } + } + }, + + actions: {} +} + +export default designer diff --git a/report-ui/src/views/bigscreenDesigner/designer/components/componentLinkage.vue b/report-ui/src/views/bigscreenDesigner/designer/components/componentLinkage.vue new file mode 100644 index 00000000..44f25771 --- /dev/null +++ b/report-ui/src/views/bigscreenDesigner/designer/components/componentLinkage.vue @@ -0,0 +1,290 @@ +<template> + <div class="component-linkage"> + <el-button + type="primary" + size="mini" + icon="el-icon-plus" + :disabled="formData.length === layerWidget.length -1" + plain + @click="handleAddClick" + > + 新增 + </el-button> + <el-table :data="formData" style="width: 100%"> + <el-table-column label="被联动组件名" align="left"> + <template slot-scope="scope"> + <div class="button-name" v-text="scope.row.widgetValue.split('-$-')[1]" /> + </template> + </el-table-column> + <el-table-column label="操作" align="center"> + <template slot-scope="scope"> + <span + class="editor" + @click="handleEditorClick(scope.$index, scope.row)" + > + <i class="el-icon-edit" /> 编辑 + </span> + <span + class="delete" + @click="handleDeleteClick(scope.$index, scope.row)" + > + <i class="el-icon-delete" /> 删除 + </span> + </template> + </el-table-column> + </el-table> + + <el-dialog + :title="isAddFlag ? '新增' : '修改'" + :visible.sync="dialogVisible" + width="30%" + :before-close="handleClose" + > + <el-form ref="myForm" v-model="linkageForm" label-width="100px"> + <el-form-item label="被联动的组件"> + <el-select + v-model="linkageForm.widgetValue" + size="mini" + clearable + placeholder="请选择" + > + <el-option + v-for="(item, index) in layerWidget" + :key="item.widgetId" + :disabled="widgetIndex === index || widgetIdList.includes(index)" + :label="item.label" + :value="`${item.widgetId}-$-${item.label}-$-${index}`" + /> + </el-select> + </el-form-item> + <el-form-item v-show="linkageForm.widgetValue" class="params-form-item" label="参数配置"> + <div class="params-config"> + <div + v-for="item in linkageForm.paramsConfig" + :key="item.originKey" + class="item-config" + > + <div class="label">{{ item.originKey }}</div> + <div class="value"> + <el-select + v-model="item.targetKey" + size="mini" + clearable + placeholder="请选择" + > + <el-option + v-for="paramKey in currentTargetParams" + :key="paramKey" + :label="paramKey" + :value="paramKey" + /> + </el-select> + </div> + </div> + </div> + </el-form-item> + </el-form> + <span slot="footer" class="dialog-footer"> + <el-button size="mini" @click="handleClose">取 消</el-button> + <el-button size="mini" type="primary" @click="handleSaveClick">确 定</el-button> + </span> + </el-dialog> + </div> +</template> + +<script> +import { getOneConfigByCode } from '../linkageLogic' +export default { + name: 'ComponentLinkage', + components: {}, + model: { + prop: 'formData', + event: 'input' + }, + props: { + formData: { + type: Array, + default: () => [] + }, + layerWidget: { // 当前设计器中所有组件的名称 + type: Array, + default: () => [] + }, + widgetParamsConfig: { // 当前设计器中所有组件的的数据集配置 + type: Array, + default: () => [] + }, + widgetIndex: { // 当前操作的组件下标 + require: true, + type: Number, + default: -1 + } + }, + data() { + return { + isAddFlag: true, // true 新增, false 编辑 + indexEditor: -1, // 编辑第几个数据 + linkageForm: { + widgetValue: '', // 选中的组件的名字 + paramsConfig: [] + }, + dialogVisible: false // 显示弹窗 + } + }, + computed: { + targetIndex() { // 当前选择联动的目标组件的下标 + if (!this.linkageForm.widgetValue) return -1 + return +this.linkageForm.widgetValue.split('-$-')[2] + }, + currentTargetParams() { // 当前选择联动的目标组件的数据集参数 + try { + return Object.keys(this.widgetParamsConfig[this.targetIndex].dynamicData.contextData) + } catch (error) { + return [] + } + }, + widgetIdList() { + return this.formData.map(item => { + return +item.widgetValue.split('-$-')[0] + }) + } + }, + watch: { + widgetIndex: { + handler(val) { + if (val !== -1) { + this.initFormDynamicData() + } + }, + immediate: true + } + }, + created() { + }, + mounted() {}, + methods: { + // 重置对象 + initFormDynamicData() { + let paramsKey = [] + const dynamicParamsWidget = ['widgetButtonGroup', 'widget-table'] + if (dynamicParamsWidget.includes(this.layerWidget[this.widgetIndex].code)) { // 参数不确定的 通过消息接收 + paramsKey = this.layerWidget[this.widgetIndex].paramsKeys || [] + } else { + const widgetConfigTemp = getOneConfigByCode(this.layerWidget[this.widgetIndex].code) + if (!widgetConfigTemp) return + // console.log('this.layerWidget[this.widgetIndex---', this.layerWidget, ' --- ', this.widgetIndex) + paramsKey = widgetConfigTemp.paramsKey + } + this.linkageForm = { + widgetValue: '', // 选中的组件的名字 + paramsConfig: paramsKey.map(item => { + return { + originKey: item, + targetKey: '' + } + }) + } + }, + // 弹出框关闭 + handleClose() { + this.dialogVisible = false + this.buttonLabel = '' + this.initFormDynamicData() + }, + // 新增按钮 + handleAddClick() { + this.buttonLabel = '' + this.initFormDynamicData() + this.isAddFlag = true + this.dialogVisible = true + }, + // 修改按钮 + handleEditorClick(index, row) { + this.isAddFlag = false + this.linkageForm = JSON.parse(JSON.stringify(this.formData[index])) + this.dialogVisible = true + this.indexEditor = index + }, + // 删除 + handleDeleteClick(index) { + this.formData.splice(index, 1) + this.$emit('input', this.formData) + this.$emit('change', this.formData) + }, + // 确定 + handleSaveClick() { + const obj = JSON.parse(JSON.stringify(this.linkageForm)) + if (this.isAddFlag) { + // 新增 + this.formData.push(obj) + this.dialogVisible = false + } else { + // 编辑 + this.formData[this.indexEditor] = obj + this.dialogVisible = false + } + this.$emit('input', this.formData) + this.$emit('change', this.formData) + } + } +} +</script> +<style lang='scss' scoped> +.component-linkage { + + .button-name { + width: 80px; + height: 30px; + line-height: 30px; + color: #A9B2BC; + border: 1px solid #23466F; + border-radius: 4px; + box-shadow: 0 0 3px #23466f inset; + text-align: center; + } + .editor, .delete { + color: #409eff; + cursor: pointer; + } + .delete { + margin-left: 10px; + } + + /deep/.el-table, + /deep/.el-table__expanded-cell, + /deep/.el-table th, + /deep/.el-table tr { + background-color: transparent !important; + color: #859094 !important; + } + /deep/.el-table td, + /deep/.el-table th.is-leaf { + border-bottom: none; + line-height: 26px; + } + /deep/.el-table tbody tr:hover > td { + background-color: #263445 !important; + } + /deep/.el-table::before { + height: 0; + } + /deep/.el-dialog { + background: #1b1e25; + .el-dialog__title { + color: #fff; + } + } + .params-form-item { + margin-top: 20px; + } + .item-config { + display: flex; + flex-wrap: nowrap; + align-items: center; + margin-bottom: 20px; + .label { + margin-right: 20px; + } + } +} +</style> diff --git a/report-ui/src/views/bigscreenDesigner/designer/components/dynamicForm.vue b/report-ui/src/views/bigscreenDesigner/designer/components/dynamicForm.vue index 2e607796..c44db5c7 100644 --- a/report-ui/src/views/bigscreenDesigner/designer/components/dynamicForm.vue +++ b/report-ui/src/views/bigscreenDesigner/designer/components/dynamicForm.vue @@ -294,6 +294,15 @@ v-model="formData[itemChildList.name]" @change="changed($event, itemChildList.name)" /> + <componentLinkage + v-if="itemChildList.type == 'componentLinkage'" + :key="'cl-' + idx" + v-model="formData[itemChildList.name]" + :layer-widget="layerWidget" + :widget-params-config="widgetParamsConfig" + :widget-index="widgetIndex" + @change="changed($event, itemChildList.name)" + /> </template> </el-collapse-item> </el-collapse> @@ -319,6 +328,7 @@ import dynamicAddTable from "./dynamicAddTable.vue"; import customUpload from "./customUpload.vue"; import dynamicAddRadar from "./dynamicAddRadar"; import MonacoEditor from "@/components/MonacoEditor/index"; +import componentLinkage from './componentLinkage'; export default { name: "DynamicForm", components: { @@ -330,6 +340,7 @@ export default { customUpload, dynamicAddRadar, MonacoEditor, + componentLinkage }, model: { prop: "value", @@ -341,6 +352,18 @@ export default { type: [Object], default: () => {}, }, + layerWidget: { + type: Array, + default: () => [] + }, + widgetParamsConfig: { + type: Array, + default: () => [] + }, + widgetIndex: { + type: Number, + default: -1 + } }, data() { return { diff --git a/report-ui/src/views/bigscreenDesigner/designer/index.vue b/report-ui/src/views/bigscreenDesigner/designer/index.vue index 63f0aa98..200a1a67 100644 --- a/report-ui/src/views/bigscreenDesigner/designer/index.vue +++ b/report-ui/src/views/bigscreenDesigner/designer/index.vue @@ -80,46 +80,46 @@ :style="{ width: middleWidth + 'px', height: middleHeight + 'px' }" > <div class="top-button"> - <span class="btn"> + <span class="btn" @click="saveData"> <el-tooltip class="item" effect="dark" content="保存" placement="bottom" > - <i class="iconfont iconsave" @click="saveData"></i> + <i class="iconfont iconsave"></i> </el-tooltip> </span> - <span class="btn"> + <span class="btn" @click="viewScreen"> <el-tooltip class="item" effect="dark" content="预览" placement="bottom" > - <i class="iconfont iconyulan" @click="viewScreen"></i> + <i class="iconfont iconyulan"></i> </el-tooltip> </span> - <span class="btn"> + <span class="btn" @click="handleUndo"> <el-tooltip class="item" effect="dark" content="撤销" placement="bottom" > - <i class="iconfont iconundo" @click="handleUndo"></i> + <i class="iconfont iconundo"></i> </el-tooltip> </span> - <span class="btn"> + <span class="btn" @click="handleRedo"> <el-tooltip class="item" effect="dark" content="恢复" placement="bottom" > - <i class="iconfont iconhuifubeifen" @click="handleRedo"></i> + <i class="iconfont iconhuifubeifen"></i> </el-tooltip> </span> @@ -321,6 +321,9 @@ <dynamicForm ref="formData" :options="widgetOptions.setup" + :layer-widget="layerWidget" + :widget-index="widgetIndex" + :widget-params-config="widgetParamsConfig" @onChanged="(val) => widgetValueChanged('setup', val)" /> </el-tab-pane> @@ -412,7 +415,7 @@ export default { title: "", // 大屏页面标题 width: 1920, // 大屏设计宽度 height: 1080, // 大屏设计高度 - backgroundColor: "", // 大屏背景色 + backgroundColor: "#1E1E1E", // 大屏背景色 backgroundImage: "", // 大屏背景图片 refreshSeconds: null, // 大屏刷新时间间隔 presetLine: [], // 辅助线 @@ -460,7 +463,9 @@ export default { activeName: "first", scaleNum: 0, // 当前缩放百分比的值 sizeRange: [20, 40, 60, 80, 100, 150, 200, 300, 400], // 缩放百分比 - currentSizeRangeIndex: -1 // 当前是哪个缩放比分比 + currentSizeRangeIndex: -1, // 当前是哪个缩放比分比, + currentWidgetTotal: 0, + widgetParamsConfig: [], // 各组件动态数据集的参数配置情况 }; }, computed: { @@ -530,6 +535,7 @@ export default { widgets: { handler(val) { this.handlerLayerWidget(val); + this.handlerdynamicDataParamsConfig(val) //以下部分是记录历史 this.$nextTick(() => { this.revoke.push(this.widgets); @@ -638,7 +644,13 @@ export default { const layerWidgetArr = []; for (let i = 0; i < val.length; i++) { const obj = {}; - obj.icon = getToolByCode(val[i].type).icon; + const myItem = getToolByCode(val[i].type) + obj.icon = myItem.icon; + obj.code = myItem.code // 组件类型code + obj.widgetId = val[i].value.widgetId || '' // 唯一id + if (val[i].value.paramsKeys) { + obj.paramsKeys = val[i].value.paramsKeys + } const options = val[i].options["setup"]; options.forEach((el) => { if (el.name == "layerName") { @@ -649,6 +661,12 @@ export default { } this.layerWidget = layerWidgetArr; }, + // 返回每个组件的动态数据集参数配置情况 + handlerdynamicDataParamsConfig(val) { + this.widgetParamsConfig = val.map(item => { + return item.value.data + }) + }, async initEchartData() { const reportCode = this.$route.query.reportCode; const { code, data } = await detailDashboard(reportCode); @@ -672,7 +690,7 @@ export default { } this.setOptionsOnClickScreen(); return { - backgroundColor: (data && data.backgroundColor) || "", + backgroundColor: (data && data.backgroundColor) || (!data ? '#1e1e1e' : ''), backgroundImage: (data && data.backgroundImage) || "", height: (data && data.height) || "1080", title: (data && data.title) || "", @@ -690,10 +708,19 @@ export default { data: widgets[i].value.data, position: widgets[i].value.position, }; - const tool = this.deepClone(getToolByCode(widgets[i].type)); + const tool = this.deepClone(getToolByCode(widgets[i].type)) + if (!tool) { + const message = '暂未提供该组件或该组件下线了,组件code: ' + widgets[i].type + console.error(message) + if (process.env.NODE_ENV === 'development') { // 40@remarks 看生产要不要提示 + this.$message.error(message) + } + continue // 找不到就跳过,避免整个报表都加载不出来 + } const option = tool.options; const options = this.handleOptionsData(widgets[i].value, option); obj.options = options; + obj.value.widgetId = obj.value.setup.widgetId widgetsData.push(obj); } return widgetsData; @@ -753,6 +780,9 @@ export default { }, widgets: this.widgets, }; + screenData.widgets.forEach(widget => { + widget.value.setup.widgetId = widget.value.widgetId + }) const { code, data } = await insertDashboard(screenData); if (code == "200") { this.$message.success("保存成功!"); @@ -831,9 +861,24 @@ export default { }, dragStart(widgetCode) { this.dragWidgetCode = widgetCode; + this.currentWidgetTotal = this.widgets.length // 当前操作面板上有多少各组件 }, dragEnd() { - this.dragWidgetCode = ""; + this.dragWidgetCode = "";/** + * 40@remarks 新增组件到操作面板后,右边的配置有更新,但是当前选中的组件没更新,导致配置错乱的bug; + * 由于拖动组件拖到非操作面板上是不会添加组件,还需判断是否添加组件到操作面板上; + */ + this.$nextTick(()=>{ + if (this.widgets.length === this.currentWidgetTotal + 1) { // 确实新增了一个组件到操作面板上 + console.log(`新添加 '${this.widgets[this.currentWidgetTotal].value.setup.layerName}' 组件到操作面板`) + const uuid = Number(Math.random().toString().substr(2)).toString(36) + this.widgets[this.currentWidgetTotal].value.widgetId = uuid + this.layerWidget[this.currentWidgetTotal].widgetId = uuid + const index = this.widgets.length - 1 + this.layerClick(index) // 选中当前新增的组件 + this.grade = false // 去除网格线 + } + }) }, dragOver(evt) { evt.preventDefault(); @@ -1080,7 +1125,13 @@ export default { // 复制 copylayer() { const obj = this.deepClone(this.widgets[this.rightClickIndex]); + obj.value.position.top += 40 // 复制的元素向右下角偏移一点 + obj.value.position.left += 40 + obj.value.widgetId = Number(Math.random().toString().substr(2)).toString(36) this.widgets.splice(this.widgets.length, 0, obj); + this.$nextTick(() => { + this.layerClick(this.widgets.length - 1) // 复制后定位到最新的组件 + }) }, // 置顶 istopLayer() { diff --git a/report-ui/src/views/bigscreenDesigner/designer/linkageLogic.js b/report-ui/src/views/bigscreenDesigner/designer/linkageLogic.js new file mode 100644 index 00000000..b00bf3f6 --- /dev/null +++ b/report-ui/src/views/bigscreenDesigner/designer/linkageLogic.js @@ -0,0 +1,128 @@ +/* + * @Author: chengsl + * @Date: 2023-02-24 09:40:13 + * @LastEditors: chengsl + * @LastEditTime: 2023-02-24 13:12:24 + * @Description: 各联动组件的参数配置 参数paramsKey的值具体封装时再改 + */ +import { eventBus as bus } from "@/utils/eventBus"; +export const lickageParamsConfig = [ + // { + // name: '按钮组', + // code: 'widgetButtonGroup', + // paramsKey: [] // 40@remarks 动态:[...row, index] + // }, + { + name: '柱图', + code: 'widget-barchart', + paramsKey: ['name', 'value'] + }, + // …… + { + name: '折线图', + code: 'widget-linechart', + paramsKey: ['name', 'value'] + }, + { + name: '百分比图', + code: 'widgetPiePercentageChart', + paramsKey: ['value'] + }, +] + +export const getOneConfigByCode = function(code) { + return lickageParamsConfig.find(item => { return item.code === code }) +} + +export const getOneConfigByName = function(name) { + return lickageParamsConfig.find(item => { return item.name === name }) +} + +/** + * 源组件 - 初始化联动逻辑 + * @param self 组件实例对象 this + * @param isActiveClick 主动触发(非echart类click事件触发) + * @param buttonConfig 按钮组组件的配置 + * 40@remarks + * 1、v-chart 需添加 ref="myVChart" 以获取实例 + * 2、 发消息发过去的对象 待封装配置动态兼容 + */ +export const originWidgetLinkageLogic = function(self, isActiveClick = false, buttonConfig = {}) { + // if (self.allComponentLinkage && self.allComponentLinkage.length && self.allComponentLinkage[self.widgetIndex].index !== -1 && self.allComponentLinkage[self.widgetIndex].linkageArr.length) { + if (self.optionsSetup.componentLinkage && self.optionsSetup.componentLinkage.length) { + if (isActiveClick) { // 主动触发 + self.allComponentLinkage[self.widgetIndex].linkageArr.forEach(item => { + console.log(`bus_${item.originId}_${item.targetId}`, ' -联动逻辑点击-发送消息', buttonConfig) + bus.$emit(`bus_${item.originId}_${item.targetId}`, buttonConfig.currentData) + }) + } else { // chart 组件 + self.$refs.myVChart.chart.on('click', function(params) { + self.allComponentLinkage[self.widgetIndex].linkageArr.forEach(item => { + console.log(`bus_${item.originId}_${item.targetId}`, ' -联动逻辑点击-发送消息', params) + let message = {} + const widgetConfigTemp = getOneConfigByCode(self.value.widgetCode) + if (widgetConfigTemp && widgetConfigTemp.paramsKey.length) { // 动态加载各组件的参数来封装 + widgetConfigTemp.paramsKey.forEach(key => { + message[key] = params[key] + }) + // 40@remarks 部分组件 传参需要特殊处理下 + // …… + // 40@remarks 专用于测试联动发消息 手动改造消息内容 + // if (self.value.widgetCode === 'widgetMap2d') { + // const nameTemp = ['苹果', '三星', '小米', '华为', 'OPPO', 'VIVO'] + // // message = { + // // name: nameTemp[(params.dataIndex % 6)], + // // value: params.value, + // // dataIndex: params.dataIndex + // // } + // // message.name = nameTemp[(+params.value % 6)] + // message.name = nameTemp[(parseInt(Math.random() * 6) % 6)] + // } + // if (self.value.widgetCode === 'widget-piechart') { + // message.name = (parseInt(Math.random() * 2) % 2) === 0 ? '深圳市' : '盐田区' + // } + } else { + message = { + name: params.name, + value: params.value + } + } + bus.$emit(`bus_${item.originId}_${item.targetId}`, message) + }) + }) + } + } +} + +/** + * 目标组件 - 初始化联动逻辑 + * @param self 组件实例对象 this + * @returns + */ +export const targetWidgetLinkageLogic = function(self) { + const busEvents = [] + // 有无有关联的组件 + if (!self.allComponentLinkage || !self.allComponentLinkage.length) return + self.allComponentLinkage.some(item => { + if (item.index !== -1 && item.linkageArr.length) { + item.linkageArr.some(obj => { + if (obj.targetId === self.value.setup.widgetId) { + self.hasLinkage = true + busEvents.push({ + eventName: `bus_${obj.originId}_${obj.targetId}`, + paramsConfig: obj.paramsConfig + }) + return true + } + }) + } + }) + if (self.hasLinkage) { + busEvents.forEach(item => { + bus.$on(item.eventName, e => { + console.log(item.eventName, ' 接收消息e', e) + self.setOptionsData(e, item.paramsConfig) + }) + }) + } +} diff --git a/report-ui/src/views/bigscreenDesigner/designer/tools/configure/barCharts/widget-barchart.js b/report-ui/src/views/bigscreenDesigner/designer/tools/configure/barCharts/widget-barchart.js index 2f55a78c..c55403b4 100644 --- a/report-ui/src/views/bigscreenDesigner/designer/tools/configure/barCharts/widget-barchart.js +++ b/report-ui/src/views/bigscreenDesigner/designer/tools/configure/barCharts/widget-barchart.js @@ -564,6 +564,18 @@ export const widgetBarchart = { }, ], }, + { + name: '组件联动', + list: [ + { + type: 'componentLinkage', + label: '', + name: 'componentLinkage', + required: false, + value: [] + } + ] + } ], ], // 数据 diff --git a/report-ui/src/views/bigscreenDesigner/designer/tools/configure/lineCharts/widget-linechart.js b/report-ui/src/views/bigscreenDesigner/designer/tools/configure/lineCharts/widget-linechart.js index f9fc91a1..b47cbdc6 100644 --- a/report-ui/src/views/bigscreenDesigner/designer/tools/configure/lineCharts/widget-linechart.js +++ b/report-ui/src/views/bigscreenDesigner/designer/tools/configure/lineCharts/widget-linechart.js @@ -587,6 +587,18 @@ export const widgetLinechart = { }, ], }, + { + name: '组件联动', + list: [ + { + type: 'componentLinkage', + label: '', + name: 'componentLinkage', + required: false, + value: [] + } + ] + } ], ], // 数据 diff --git a/report-ui/src/views/bigscreenDesigner/designer/tools/configure/percentCharts/widget-pie-percentage.js b/report-ui/src/views/bigscreenDesigner/designer/tools/configure/percentCharts/widget-pie-percentage.js index a8a349fe..3d1d9fc1 100644 --- a/report-ui/src/views/bigscreenDesigner/designer/tools/configure/percentCharts/widget-pie-percentage.js +++ b/report-ui/src/views/bigscreenDesigner/designer/tools/configure/percentCharts/widget-pie-percentage.js @@ -169,6 +169,18 @@ export const widgetPiePercentage = { value: '#173164' }, ] + }, + { + name: '组件联动', + list: [ + { + type: 'componentLinkage', + label: '', + name: 'componentLinkage', + required: false, + value: [] + } + ] } ], ], diff --git a/report-ui/src/views/bigscreenDesigner/designer/tools/index.js b/report-ui/src/views/bigscreenDesigner/designer/tools/index.js index 4a298073..7a20a42d 100644 --- a/report-ui/src/views/bigscreenDesigner/designer/tools/index.js +++ b/report-ui/src/views/bigscreenDesigner/designer/tools/index.js @@ -3,8 +3,8 @@ * @version: * @Author: qianlishi * @Date: 2021-08-29 06:43:07 - * @LastEditors: qianlishi qianlishi@anji-plus.com - * @LastEditTime: 2022-11-07 15:35:42 + * @LastEditors: chengsl + * @LastEditTime: 2023-02-24 10:29:26 */ import { widgetTool } from "./main" const screenConfig = { @@ -52,7 +52,7 @@ const screenConfig = { name: 'backgroundColor', required: false, placeholder: '', - value: 'rgba(45, 86, 126, 1)', + value: '#1E1E1E', }, { type: 'custom-upload', @@ -72,6 +72,7 @@ export const converArr = (data) => { let tempArr = [], newArr = [] for (let i = 0; i < data.length; i++) { const item = data[i] + item.widgetId = '' if (tempArr.indexOf(item.type) === -1) { newArr.push({ name: item.tabName, diff --git a/report-ui/src/views/bigscreenDesigner/designer/tools/main.js b/report-ui/src/views/bigscreenDesigner/designer/tools/main.js index 660c04cc..e7159139 100644 --- a/report-ui/src/views/bigscreenDesigner/designer/tools/main.js +++ b/report-ui/src/views/bigscreenDesigner/designer/tools/main.js @@ -3,8 +3,8 @@ * @version: * @Author: qianlishi * @Date: 2021-08-29 07:46:46 - * @LastEditors: qianlishi qianlishi@anji-plus.com - * @LastEditTime: 2023-01-09 13:16:19 + * @LastEditors: chengsl + * @LastEditTime: 2023-02-23 15:23:20 */ import { widgetText } from "./configure/texts/widget-text" @@ -70,7 +70,7 @@ export const widgetTool = [ widgetLineCompare, widgetDecoratePie, widgetMoreBarLine, - widgetWordCloud, + // widgetWordCloud, widgetHeatmap, widgetRadar, widgetBarLineStack, diff --git a/report-ui/src/views/bigscreenDesigner/designer/widget/bar/widgetBarchart.vue b/report-ui/src/views/bigscreenDesigner/designer/widget/bar/widgetBarchart.vue index c4d12d21..bfcd0ce7 100644 --- a/report-ui/src/views/bigscreenDesigner/designer/widget/bar/widgetBarchart.vue +++ b/report-ui/src/views/bigscreenDesigner/designer/widget/bar/widgetBarchart.vue @@ -1,10 +1,11 @@ <template> <div :style="styleObj"> - <v-chart :options="options" autoresize /> + <v-chart ref="myVChart" :options="options" autoresize /> </div> </template> <script> +import { originWidgetLinkageLogic, targetWidgetLinkageLogic } from '@/views/bigscreenDesigner/designer/linkageLogic' import { eventBusParams } from "@/utils/screen"; export default { name: "WidgetBarchart", @@ -12,6 +13,10 @@ export default { props: { value: Object, ispreview: Boolean, + widgetIndex: { + type: Number, + default: 0 + }, // 当前组件,在工作区变量widgetInWorkbench中的索引 }, data() { return { @@ -70,6 +75,9 @@ export default { background: this.optionsSetup.background, }; }, + allComponentLinkage() { + return this.$store.state.designer.allComponentLinkage + } }, watch: { value: { @@ -89,6 +97,8 @@ export default { this.optionsCollapse = this.value.setup; this.optionsSetup = this.value.setup; this.editorOptions(); + targetWidgetLinkageLogic(this) // 联动-目标组件逻辑 + originWidgetLinkageLogic(this) // 联动-源组件逻辑 eventBusParams( this.optionsSetup, @@ -302,9 +312,22 @@ export default { this.options = Object.assign({}, this.options); }, // 数据解析 - setOptionsData() { + setOptionsData(e, paramsConfig) { const optionsSetup = this.optionsSetup; const optionsData = this.optionsData; // 数据类型 静态 or 动态 + // 联动接收者逻辑开始 + optionsData.dynamicData = optionsData.dynamicData || {} // 兼容 dynamicData undefined + const myDynamicData = optionsData.dynamicData + clearInterval(this.flagInter) // 不管咋,先干掉上一次的定时任务,避免多跑 + if (e && optionsData.dataType !== 'staticData' && Object.keys(myDynamicData.contextData).length) { + const keyArr = Object.keys(myDynamicData.contextData) + paramsConfig.forEach(conf => { + if (keyArr.includes(conf.targetKey)) { + myDynamicData.contextData[conf.targetKey] = e[conf.originKey] + } + }) + } + // 联动接收者逻辑结束 optionsData.dataType == "staticData" ? this.staticDataFn(optionsData.staticData) : this.dynamicDataFn(optionsData.refreshTime); diff --git a/report-ui/src/views/bigscreenDesigner/designer/widget/line/widgetLinechart.vue b/report-ui/src/views/bigscreenDesigner/designer/widget/line/widgetLinechart.vue index fe88928a..c2f23057 100644 --- a/report-ui/src/views/bigscreenDesigner/designer/widget/line/widgetLinechart.vue +++ b/report-ui/src/views/bigscreenDesigner/designer/widget/line/widgetLinechart.vue @@ -1,10 +1,11 @@ <template> <div :style="styleObj"> - <v-chart :options="options" autoresize /> + <v-chart ref="myVChart" :options="options" autoresize /> </div> </template> <script> +import { originWidgetLinkageLogic, targetWidgetLinkageLogic } from '@/views/bigscreenDesigner/designer/linkageLogic' import { eventBusParams } from "@/utils/screen"; export default { name: "WidgetLinechart", @@ -12,6 +13,10 @@ export default { props: { value: Object, ispreview: Boolean, + widgetIndex: { + type: Number, + default: 0 + }, // 当前组件,在工作区变量widgetInWorkbench中的索引 }, data() { return { @@ -76,6 +81,9 @@ export default { background: this.optionsSetup.background, }; }, + allComponentLinkage() { + return this.$store.state.designer.allComponentLinkage + } }, watch: { value: { @@ -89,12 +97,14 @@ export default { deep: true, }, }, - created() { + mounted() { this.optionsStyle = this.value.position; this.optionsData = this.value.data; this.optionsCollapse = this.value.collapse; this.optionsSetup = this.value.setup; this.editorOptions(); + targetWidgetLinkageLogic(this) // 联动-目标组件逻辑 + originWidgetLinkageLogic(this) // 联动-源组件逻辑 eventBusParams( this.optionsSetup, this.optionsData, @@ -299,8 +309,19 @@ export default { this.options = Object.assign({}, this.options); }, // 处理数据 - setOptionsData() { + setOptionsData(e, paramsConfig) { const optionsData = this.optionsData; // 数据类型 静态 or 动态 + optionsData.dynamicData = optionsData.dynamicData || {} // 兼容 dynamicData undefined + const myDynamicData = optionsData.dynamicData + clearInterval(this.flagInter) // 不管咋,先干掉上一次的定时任务,避免多跑 + if (e && optionsData.dataType !== 'staticData' && Object.keys(myDynamicData.contextData).length) { + const keyArr = Object.keys(myDynamicData.contextData) + paramsConfig.forEach(conf => { + if (keyArr.includes(conf.targetKey)) { + myDynamicData.contextData[conf.targetKey] = e[conf.originKey] + } + }) + } optionsData.dataType == "staticData" ? this.staticDataFn(optionsData.staticData) : this.dynamicDataFn(optionsData.dynamicData, optionsData.refreshTime); diff --git a/report-ui/src/views/bigscreenDesigner/designer/widget/percent/widgetPiePercentageChart.vue b/report-ui/src/views/bigscreenDesigner/designer/widget/percent/widgetPiePercentageChart.vue index 86463d26..c6b69314 100644 --- a/report-ui/src/views/bigscreenDesigner/designer/widget/percent/widgetPiePercentageChart.vue +++ b/report-ui/src/views/bigscreenDesigner/designer/widget/percent/widgetPiePercentageChart.vue @@ -1,10 +1,11 @@ <template> <div :style="styleObj"> - <v-chart :options="options" autoresize /> + <v-chart ref="myVChart" :options="options" autoresize /> </div> </template> <script> +import { targetWidgetLinkageLogic } from '@/views/bigscreenDesigner/designer/linkageLogic' import { eventBusParams } from "@/utils/screen"; let per = 60; export default { @@ -13,6 +14,10 @@ export default { props: { value: Object, ispreview: Boolean, + widgetIndex: { + type: Number, + default: 0 + }, // 当前组件,在工作区变量widgetInWorkbench中的索引 }, data() { return { @@ -325,6 +330,9 @@ export default { background: this.optionsSetup.background, }; }, + allComponentLinkage() { + return this.$store.state.designer.allComponentLinkage + } }, watch: { value: { @@ -358,6 +366,7 @@ export default { this.angle = this.angle + 3 myChart.setOption(options,true) }, 1000);*/ + targetWidgetLinkageLogic(this) // 联动-目标组件逻辑 }, methods: { //轴point设置 @@ -437,8 +446,21 @@ export default { line["lineStyle"] = lineStyle; }, // 数据解析 - setOptionsData() { + setOptionsData(e, paramsConfig) { const optionsData = this.optionsData; // 数据类型 静态 or 动态 + optionsData.dynamicData = optionsData.dynamicData || {} // 兼容 dynamicData undefined + + const myDynamicData = optionsData.dynamicData + clearInterval(this.flagInter) // 不管咋,先干掉上一次的定时任务,避免多跑 + if (e && optionsData.dataType !== 'staticData' && Object.keys(myDynamicData.contextData).length) { + const keyArr = Object.keys(myDynamicData.contextData) + paramsConfig.forEach(conf => { + if (keyArr.includes(conf.targetKey)) { + myDynamicData.contextData[conf.targetKey] = e[conf.originKey] + } + }) + } + optionsData.dataType == "staticData" ? this.staticDataFn(optionsData.staticData) : this.dynamicDataFn(optionsData.dynamicData, optionsData.refreshTime); diff --git a/report-ui/src/views/bigscreenDesigner/designer/widget/temp.vue b/report-ui/src/views/bigscreenDesigner/designer/widget/temp.vue index a9e29d42..17a311eb 100644 --- a/report-ui/src/views/bigscreenDesigner/designer/widget/temp.vue +++ b/report-ui/src/views/bigscreenDesigner/designer/widget/temp.vue @@ -6,7 +6,7 @@ !--> <template> <div> - <component :is="type" :value="value" :ispreview="true" /> + <component :is="type" :value="value" :ispreview="true" :widget-index="index" /> </div> </template> @@ -90,6 +90,10 @@ export default { type: [Object], default: () => {}, }, + index: { + type: Number, + default: 0 + }, // 当前组件,在工作区变量widgetInWorkbench中的索引 }, data() { return {}; diff --git a/report-ui/src/views/bigscreenDesigner/designer/widget/widget.vue b/report-ui/src/views/bigscreenDesigner/designer/widget/widget.vue index fedd824f..96f80fba 100644 --- a/report-ui/src/views/bigscreenDesigner/designer/widget/widget.vue +++ b/report-ui/src/views/bigscreenDesigner/designer/widget/widget.vue @@ -17,7 +17,7 @@ @blur="handleBlur" > <!-- :z-index="-1" --> - <component :is="type" :value="value" /> + <component :is="type":widget-index="index" :value="value" /> </avue-draggable> </template> diff --git a/report-ui/src/views/bigscreenDesigner/viewer/index.vue b/report-ui/src/views/bigscreenDesigner/viewer/index.vue index 91b00976..e8ef91a1 100644 --- a/report-ui/src/views/bigscreenDesigner/viewer/index.vue +++ b/report-ui/src/views/bigscreenDesigner/viewer/index.vue @@ -12,6 +12,7 @@ v-for="(widget, index) in widgets" :key="index" v-model="widget.value" + :index="index" :type="widget.type" /> </div> @@ -56,6 +57,16 @@ export default { transform: `scale(${ratioEquipment}, ${ratioEquipment})`, "transform-origin": "0 0" }; + data.dashboard.widgets.forEach((item, index) => { + item.value.widgetId = item.value.setup.widgetId + if (item.value.setup.componentLinkage && item.value.setup.componentLinkage.length) { + this.$store.commit('SET_ALL_COMPONENT_LINKAGE', { + index, + widgetId: item.value.widgetId, + linkageArr: item.value.setup.componentLinkage + }) + } + }) this.widgets = data.dashboard.widgets; } }