Merge remote-tracking branch 'origin/dev' into dev

qianming 2 years ago
commit b693c9dcbb

@ -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],

@ -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

@ -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>

@ -3,6 +3,12 @@
<div class="contentmenu__item" @click="deleteLayer">
<i class="iconfont iconguanbi"></i> 删除图层
</div>
<div class="contentmenu__item" @click="lockLayer">
<i class="iconfont iconfuzhi1"></i> 锁定图层
</div>
<div class="contentmenu__item" @click="noLockLayer">
<i class="iconfont iconfuzhi1"></i> 解除锁定
</div>
<div class="contentmenu__item" @click="copyLayer">
<i class="iconfont iconfuzhi1"></i> 复制图层
</div>
@ -24,7 +30,7 @@
export default {
props: {
styleObj: Object,
visible: Boolean
visible: Boolean,
},
data() {
return {};
@ -36,7 +42,7 @@ export default {
} else {
document.body.removeEventListener("click", this.closeMenu);
}
}
},
},
methods: {
closeMenu() {
@ -46,22 +52,28 @@ export default {
this.$confirm("是否删除所选图层?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
type: "warning",
})
.then(() => {
this.$emit("deletelayer");
this.$message({
type: "success",
message: "删除成功!"
message: "删除成功!",
});
})
.catch(() => {
this.$message({
type: "info",
message: "已取消删除"
message: "已取消删除",
});
});
},
lockLayer() {
this.$emit("lockLayer");
},
noLockLayer() {
this.$emit("noLockLayer");
},
copyLayer() {
this.$emit("copylayer");
},
@ -76,8 +88,8 @@ export default {
},
movedownLayer() {
this.$emit("movedownLayer");
}
}
},
},
};
</script>
<style lang="scss" scoped>

@ -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 {

@ -1,10 +1,3 @@
<!--
* @Descripttion: 大屏设计器
* @Author: lide1202@hotmail.com
* @Date: 2021-3-13 11:04:24
* @Last Modified by: lide1202@hotmail.com
* @Last Modified time: 2021-3-13 11:04:24
!-->
<template>
<div class="layout">
<div
@ -80,53 +73,53 @@
: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>
<span
:class="{
'btn': true,
'btn-disable': currentSizeRangeIndex === 0
btn: true,
'btn-disable': currentSizeRangeIndex === 0,
}"
@click="setSize(0)"
>
@ -138,7 +131,7 @@
placement="bottom"
>
<!-- <svg-icon style="font-size:16px;" icon-class="jianhao" class-name="icon" /> -->
<i class="el-icon-minus" style="font-size:16px;" />
<i class="el-icon-minus" style="font-size: 16px" />
</el-tooltip>
</span>
<!--
@ -146,9 +139,9 @@
:style="currentSizeRangeIndex === defaultSize.index ? 'cursor: no-drop;' : ''" -->
<span
:class="{
'btn': true,
btn: true,
'scale-num': true,
'btn-disable': currentSizeRangeIndex === defaultSize.index
'btn-disable': currentSizeRangeIndex === defaultSize.index,
}"
@click="setSize(2)"
>
@ -159,15 +152,13 @@
content="默认比例"
placement="bottom"
>
<span>
{{ parseInt(scaleNum) }}%
</span>
<span> {{ parseInt(scaleNum) }}% </span>
</el-tooltip>
</span>
<span
:class="{
'btn': true,
'btn-disable': currentSizeRangeIndex === 8
btn: true,
'btn-disable': currentSizeRangeIndex === 8,
}"
@click="setSize(1)"
>
@ -179,7 +170,7 @@
placement="bottom"
>
<!-- <svg-icon style="font-size:16px;" icon-class="jiahao" class-name="icon" /> -->
<i class="el-icon-plus" style="font-size:16px;" />
<i class="el-icon-plus" style="font-size: 16px" />
</el-tooltip>
</span>
@ -241,14 +232,11 @@
width: bigscreenWidthInWorkbench + 'px',
height: bigscreenHeightInWorkbench + 'px',
}" -->
<div
class="workbench-container"
@mousedown="handleMouseDown"
>
<div class="workbench-container" @mousedown="handleMouseDown">
<div
:style="{
width: ((+bigscreenWidth + 18) * bigscreenScaleInWorkbench) + 'px',
height: ((+bigscreenHeight + 18) * bigscreenScaleInWorkbench) + 'px'
width: (+bigscreenWidth + 18) * bigscreenScaleInWorkbench + 'px',
height: (+bigscreenHeight + 18) * bigscreenScaleInWorkbench + 'px',
}"
class="vue-ruler-tool-wrap"
>
@ -264,9 +252,12 @@
:visible.sync="dashboard.presetLineVisible"
:style="{
width: +bigscreenWidth + 18 + 'px',
height: +bigscreenHeight + 18 +'px',
transform: currentSizeRangeIndex === defaultSize.index ? workbenchTransform : `scale(${sizeRange[currentSizeRangeIndex]/100})`,
transformOrigin: '0 0'
height: +bigscreenHeight + 18 + 'px',
transform:
currentSizeRangeIndex === defaultSize.index
? workbenchTransform
: `scale(${sizeRange[currentSizeRangeIndex] / 100})`,
transformOrigin: '0 0',
}"
>
<div
@ -321,6 +312,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>
@ -353,6 +347,8 @@
:visible.sync="visibleContentMenu"
:style-obj="styleObj"
@deletelayer="deletelayer"
@lockLayer="lockLayer"
@noLockLayer="noLockLayer"
@copylayer="copylayer"
@istopLayer="istopLayer"
@setlowLayer="setlowLayer"
@ -412,7 +408,7 @@ export default {
title: "", //
width: 1920, //
height: 1080, //
backgroundColor: "", //
backgroundColor: "#1E1E1E", //
backgroundImage: "", //
refreshSeconds: null, //
presetLine: [], // 线
@ -460,7 +456,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: {
@ -502,19 +500,19 @@ export default {
defaultSize() {
const obj = {
index: -1,
size: '50'
}
size: "50",
};
this.sizeRange.some((item, index) => {
if (item <= (100 * this.bigscreenScaleInWorkbench)) {
obj.index = index
obj.size = 100 * this.bigscreenScaleInWorkbench // item
if (item <= 100 * this.bigscreenScaleInWorkbench) {
obj.index = index;
obj.size = 100 * this.bigscreenScaleInWorkbench; // item
}
})
});
if (obj.index === -1) {
obj.index = 0
obj.size = this.sizeRange[0]
obj.index = 0;
obj.size = this.sizeRange[0];
}
return obj
return obj;
},
//
bigscreenWidthInWorkbench() {
@ -530,6 +528,7 @@ export default {
widgets: {
handler(val) {
this.handlerLayerWidget(val);
this.handlerdynamicDataParamsConfig(val);
//
this.$nextTick(() => {
this.revoke.push(this.widgets);
@ -540,18 +539,18 @@ export default {
defaultSize: {
handler(val) {
if (val !== -1) {
this.currentSizeRangeIndex = val.index
this.scaleNum = val.size
this.currentSizeRangeIndex = val.index;
this.scaleNum = val.size;
}
},
immediate: true
immediate: true,
},
bigscreenWidth() {
this.initVueRulerTool()
this.initVueRulerTool();
},
bigscreenHeight() {
this.initVueRulerTool()
}
this.initVueRulerTool();
},
},
created() {
/* 以下是记录历史的 */
@ -565,8 +564,8 @@ export default {
this.grade = false;
});
this.$nextTick(() => {
this.initVueRulerTool() //
})
this.initVueRulerTool(); //
});
},
methods: {
/**
@ -574,41 +573,51 @@ export default {
* sizeRange: [20, 40, 60, 72, 100, 150, 200, 300, 400]
*/
setSize(num) {
if (num === 0) { //
if (this.currentSizeRangeIndex === 0) return
this.currentSizeRangeIndex -= 1
} else if (num === 1) { //
if (this.currentSizeRangeIndex === 8) return
this.currentSizeRangeIndex += 1
} else if (num === 2) { //
this.currentSizeRangeIndex = this.defaultSize.index
}
this.scaleNum = this.currentSizeRangeIndex === this.defaultSize.index ? this.defaultSize.size : this.sizeRange[this.currentSizeRangeIndex]
if (num === 0) {
//
if (this.currentSizeRangeIndex === 0) return;
this.currentSizeRangeIndex -= 1;
} else if (num === 1) {
//
if (this.currentSizeRangeIndex === 8) return;
this.currentSizeRangeIndex += 1;
} else if (num === 2) {
//
this.currentSizeRangeIndex = this.defaultSize.index;
}
this.scaleNum =
this.currentSizeRangeIndex === this.defaultSize.index
? this.defaultSize.size
: this.sizeRange[this.currentSizeRangeIndex];
},
//
initVueRulerTool() {
const vueRulerToolDom = this.$refs['vue-ruler-tool'].$el //
const contentDom = vueRulerToolDom.querySelector('.vue-ruler-content')
const vueRulerX = vueRulerToolDom.querySelector('.vue-ruler-h') //
const vueRulerY = vueRulerToolDom.querySelector('.vue-ruler-v') //
const vueRulerToolDom = this.$refs["vue-ruler-tool"].$el; //
const contentDom = vueRulerToolDom.querySelector(".vue-ruler-content");
const vueRulerX = vueRulerToolDom.querySelector(".vue-ruler-h"); //
const vueRulerY = vueRulerToolDom.querySelector(".vue-ruler-v"); //
// vueRulerToolDom.style.cssText += ';width:' + (this.bigscreenWidth + 18) + 'px !important;height:' + (this.bigscreenHeight + 18) + 'px !important;'
contentDom.style.width = '100%'
contentDom.style.height = '100%'
contentDom.style.width = "100%";
contentDom.style.height = "100%";
let xHtmlContent = '' // '<span class="n" style="left: 2px;">0</span>'
let yHtmlContent = '' // '<span class="n" style="top: 2px;">0</span>'
let currentNum = 0
let xHtmlContent = ""; // '<span class="n" style="left: 2px;">0</span>'
let yHtmlContent = ""; // '<span class="n" style="top: 2px;">0</span>'
let currentNum = 0;
while (currentNum < +this.bigscreenWidth) {
xHtmlContent += `<span class="n" style="left: ${currentNum + 2}px;">${currentNum}</span>`
currentNum += 50
xHtmlContent += `<span class="n" style="left: ${
currentNum + 2
}px;">${currentNum}</span>`;
currentNum += 50;
}
currentNum = 0
currentNum = 0;
while (currentNum < +this.bigscreenHeight) {
yHtmlContent += `<span class="n" style="top: ${currentNum + 2}px;">${currentNum}</span>`
currentNum += 50
yHtmlContent += `<span class="n" style="top: ${
currentNum + 2
}px;">${currentNum}</span>`;
currentNum += 50;
}
vueRulerX.innerHTML = xHtmlContent
vueRulerY.innerHTML = yHtmlContent
vueRulerX.innerHTML = xHtmlContent;
vueRulerY.innerHTML = yHtmlContent;
},
/**
* @description: 恢复
@ -638,7 +647,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 +664,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 +693,8 @@ 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) || "",
@ -691,9 +713,20 @@ export default {
position: widgets[i].value.position,
};
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 +786,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 +867,30 @@ export default {
},
dragStart(widgetCode) {
this.dragWidgetCode = widgetCode;
this.currentWidgetTotal = this.widgets.length; //
},
dragEnd() {
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();
@ -855,12 +912,12 @@ export default {
const targetScale =
this.currentSizeRangeIndex === this.defaultSize.index
? this.bigscreenScaleInWorkbench
: this.sizeRange[this.currentSizeRangeIndex] / 100
: this.sizeRange[this.currentSizeRangeIndex] / 100;
// x y
// const x = widgetLeftInWorkbench / this.bigscreenScaleInWorkbench
// const y = widgetTopInWorkbench / this.bigscreenScaleInWorkbench
const x = widgetLeftInWorkbench / targetScale
const y = widgetTopInWorkbench / targetScale
const x = widgetLeftInWorkbench / targetScale;
const y = widgetTopInWorkbench / targetScale;
//
let tool = getToolByCode(widgetType);
@ -1077,10 +1134,28 @@ export default {
deletelayer() {
this.widgets.splice(this.rightClickIndex, 1);
},
//
lockLayer() {
const obj = this.widgets[this.rightClickIndex];
this.$set(obj.value.position, "disabled", true);
},
//
noLockLayer() {
const obj = this.widgets[this.rightClickIndex];
this.$set(obj.value.position, "disabled", false);
},
//
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() {
@ -1277,7 +1352,7 @@ export default {
&.btn-disable {
cursor: no-drop;
&:hover {
background: #20262C
background: #20262c;
}
}
}
@ -1382,7 +1457,6 @@ export default {
&::-webkit-scrollbar-track-piece {
/*修改滚动条的背景和圆角*/
background: #29405c;
-webkit-border-radius: 7px;
}
&::-webkit-scrollbar-track {
@ -1402,13 +1476,13 @@ export default {
/*修改垂直滚动条的样式*/
&::-webkit-scrollbar-thumb:vertical {
background-color: #00113a;
-webkit-border-radius: 7px;
// -webkit-border-radius: 7px;
}
/*修改水平滚动条的样式*/
&::-webkit-scrollbar-thumb:horizontal {
background-color: #00113a;
-webkit-border-radius: 7px;
// -webkit-border-radius: 7px;
}
}
}
@ -1610,22 +1684,6 @@ li {
::-webkit-scrollbar {
width: 0;
}
/* 滚动槽 */
::-webkit-scrollbar-track {
-webkit-box-shadow: inset006pxrgba(0, 0, 0, 0.3);
}
/* 滚动条滑块 */
::-webkit-scrollbar-thumb {
background: rgba(0, 0, 0, 0.1);
-webkit-box-shadow: inset006pxrgba(0, 0, 0, 0.5);
}
::-webkit-scrollbar-thumb:window-inactive {
background: rgba(255, 0, 0, 0.4);
height: 10px;
}
</style>

@ -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
* 1v-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)
})
})
}
}

@ -564,6 +564,18 @@ export const widgetBarchart = {
},
],
},
{
name: '组件联动',
list: [
{
type: 'componentLinkage',
label: '',
name: 'componentLinkage',
required: false,
value: []
}
]
}
],
],
// 数据

@ -3,7 +3,7 @@
* @Author: qianlishi qianlishi@anji-plus.com
* @Date: 2023-01-09 13:02:59
* @LastEditors: qianlishi qianlishi@anji-plus.com
* @LastEditTime: 2023-01-12 16:44:50
* @LastEditTime: 2023-03-06 15:33:39
*/
export const widgetSelect = {
@ -33,7 +33,7 @@ export const widgetSelect = {
{
type: 'vue-color',
label: '字体颜色',
name: 'color',
name: 'select_color',
required: false,
placeholder: '',
value: '#FAD400',
@ -41,7 +41,7 @@ export const widgetSelect = {
{
type: 'vue-color',
label: '字体背景',
name: 'background',
name: 'select_fontSize',
required: false,
placeholder: '',
value: 'rgba(115,170,229,.5)',

@ -587,6 +587,18 @@ export const widgetLinechart = {
},
],
},
{
name: '组件联动',
list: [
{
type: 'componentLinkage',
label: '',
name: 'componentLinkage',
required: false,
value: []
}
]
}
],
],
// 数据

@ -169,6 +169,18 @@ export const widgetPiePercentage = {
value: '#173164'
},
]
},
{
name: '组件联动',
list: [
{
type: 'componentLinkage',
label: '',
name: 'componentLinkage',
required: false,
value: []
}
]
}
],
],

@ -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,

@ -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,

@ -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);

@ -2,12 +2,13 @@
<el-input
ref="input"
:style="styleObj"
v-model="inputValue" placeholder="请输入内容"
v-model="inputValue"
placeholder="请输入内容"
@[eventChange]="change"
/>
</template>
<script>
import {eventBus} from "@/utils/eventBus";
import { eventBus } from "@/utils/eventBus";
export default {
name: "WidgetInput",
@ -21,7 +22,7 @@ export default {
optionsStyle: {},
optionsData: {},
optionsSetup: {},
options:{}
options: {},
};
},
computed: {
@ -44,7 +45,6 @@ export default {
this.optionsSetup = val.setup;
this.optionsData = val.data;
this.optionsStyle = val.position;
this.setOptions()
},
deep: true,
},
@ -53,7 +53,6 @@ export default {
this.optionsSetup = this.value.setup;
this.optionsData = this.value.data;
this.optionsStyle = this.value.position;
this.setOptions()
},
methods: {
change(event) {

@ -10,7 +10,7 @@
/>
</template>
<script>
import {eventBus} from "@/utils/eventBus";
import { eventBus } from "@/utils/eventBus";
export default {
name: "WidgetSelect",
@ -24,17 +24,20 @@ export default {
optionsStyle: {},
optionsData: {},
optionsSetup: {},
options:{}
options: {},
};
},
computed: {
styleObj() {
console.log(this.optionsSetup);
return {
position: this.ispreview ? "absolute" : "static",
width: this.optionsStyle.width + "px",
height: this.optionsStyle.height + "px",
left: this.optionsStyle.left + "px",
top: this.optionsStyle.top + "px",
background: this.optionsSetup.select_fontSize,
color: this.optionsSetup.select_color,
};
},
eventChange() {
@ -47,7 +50,7 @@ export default {
this.optionsSetup = val.setup;
this.optionsData = val.data;
this.optionsStyle = val.position;
this.setOptions()
this.setOptions();
},
deep: true,
},
@ -56,7 +59,7 @@ export default {
this.optionsSetup = this.value.setup;
this.optionsData = this.value.data;
this.optionsStyle = this.value.position;
this.setOptions()
this.setOptions();
},
methods: {
change(event) {
@ -73,7 +76,7 @@ export default {
: this.dynamicDataFn(optionsData.dynamicData, optionsData.refreshTime);
},
staticData(data) {
this.options = data
this.options = data;
},
//
dynamicDataFn(val, refreshTime) {
@ -108,6 +111,11 @@ export default {
.el-input__inner {
height: 100%;
background: inherit;
color: inherit;
&::placeholder {
color: inherit;
}
}
}
}

@ -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);

@ -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);

@ -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 {};

@ -1,14 +1,9 @@
<!--
* @Author: lide1202@hotmail.com
* @Date: 2021-3-13 11:04:24
* @Last Modified by: lide1202@hotmail.com
* @Last Modified time: 2021-3-13 11:04:24
!-->
<template>
<avue-draggable
:step="step"
:width="widgetsWidth"
:height="widgetsHeight"
:disabled="widgetDisabled"
:left="widgetsLeft"
:top="widgetsTop"
ref="draggable"
@ -17,7 +12,7 @@
@blur="handleBlur"
>
<!-- :z-index="-1" -->
<component :is="type" :value="value" />
<component :is="type" :widget-index="index" :value="value" />
</avue-draggable>
</template>
@ -89,7 +84,7 @@ export default {
widgetRadar,
widgetBarLineStackChart,
widgetSelect,
widgetInput
widgetInput,
},
model: {
prop: "value",
@ -136,6 +131,9 @@ export default {
widgetsZIndex() {
return this.value.position.zIndex || 1;
},
widgetDisabled() {
return this.value.position.disabled || false;
},
},
mounted() {},
methods: {

@ -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;
}
}

Loading…
Cancel
Save