修改看板

master
夜笙歌 1 week ago
parent 7459d457bd
commit 2a564258c2

@ -0,0 +1,71 @@
import request from '@/utils/request';
/**
* 查询数据库连接信息列表
* @param query
* @returns {*}
*/
export const listDatabaseLink = (query) => {
return request({
url: '/system/databaseLink/list', method: 'get', params: query
});
};
/**
* 查询数据库连接信息详细
* @param linkId
*/
export const getDatabaseLink = (linkId) => {
return request({
url: '/system/databaseLink/tables/' + linkId, method: 'get'
});
};
export const getFieldList = (linkId, tableName) => {
return request({
url: '/system/databaseLink/columns/' + linkId + '/' + tableName, method: 'get'
});
};
/**
* 新增数据库连接信息
* @param data
*/
export const addDatabaseLink = (data) => {
return request({
url: '/system/databaseLink', method: 'post', data: data
});
};
/**
* 修改数据库连接信息
* @param data
*/
export const updateDatabaseLink = (data) => {
return request({
url: '/system/databaseLink', method: 'put', data: data
});
};
/**
* 删除数据库连接信息
* @param linkId
*/
export const delDatabaseLink = (linkId) => {
return request({
url: '/system/databaseLink/' + linkId, method: 'delete'
});
};
/**
* 下拉框查询数据库连接信息列表
* @param query
* @returns {*}
*/
export function getSysDatabaseLinkList(query) {
return request({
url: '/system/databaseLink/getSysDatabaseLinkList', method: 'get', params: query
});
};

@ -14,7 +14,8 @@
</el-form>
</el-card>
<el-card style="margin: 8px">
<el-button plain type="primary" icon="Plus" @click="constructionData"></el-button>
<el-button plain type="primary" icon="Plus" @click="constructionData"></el-button>
<el-button plain type="primary" icon="Plus" @click="addSQL">SQL</el-button>
<!-- <el-button plain type="success" icon="Edit" @click="editData"></el-button>-->
<!-- <el-button plain type="danger" icon="Delete" @click="delData"></el-button>-->
</el-card>
@ -149,6 +150,66 @@
</div>
</template>
</el-dialog>
<el-dialog v-model="addSQLFormVisible" draggable width="800">
<template #header>
<div style="width: 100%">
<span>{{ constructionDataForm.dataSourceId ? '修改' : '构造' }}数据源</span>
</div>
</template>
<el-form :model="addSQLForm" label-width="auto">
<el-form-item label="数据库" prop="db">
<el-select @change="selectDb" v-model="addSQLForm.db" placeholder="选择数据库" style="width: 240px">
<el-option
v-for="item in dbList"
:key="item.value"
:label="`${item.linkName}(${item.host}:${item.port})`"
:value="item.linkId"
/>
</el-select>
</el-form-item>
<el-form-item label="SQL" prop="SQL">
<el-input
v-model="addSQLForm.SQL"
style="width: 100%"
:rows="2"
type="textarea"
placeholder=""
/>
</el-form-item>
<el-form-item label="关键字">
<el-tag type="success" style="margin-right: 8px;margin-bottom: 8px;" v-for="i in keyword"
@click="addSQLInput(i)">{{ i }}
</el-tag>
</el-form-item>
<el-form-item label="表">
<el-select @change="selectTable" v-model="addSQLForm.table" placeholder="选择表" style="width: 240px">
<el-option
v-for="item in tableList"
:key="item.value"
:label="item.tableName"
:value="item.tableName"
/>
</el-select>
</el-form-item>
<el-form-item label="字段">
<el-tag type="primary" style="margin-right: 8px;margin-bottom: 8px;" @click="addSQLInput(addSQLForm.table)">
{{ addSQLForm.table }}
</el-tag>
<el-tag type="success" style="margin-right: 8px;margin-bottom: 8px;" v-for="i in fieldList"
@click="addSQLInput(i.columnName)">{{ i.columnName
}}
</el-tag>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="addSQLFormVisible = false">关闭</el-button>
<el-button type="primary" @click="createSQL ">
{{ constructionDataForm.dataSourceId ? '确定' : '创建' }}
</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script lang="ts" setup>
@ -157,6 +218,7 @@ import request from '@/utils/request';
import { options } from './tool.js';
import { addDataSourceApi, delDataSourceApi, editDataSourceApi, getDataSourceList } from './api/dataSource';
import { ElMessage, ElMessageBox } from 'element-plus';
import { getDatabaseLink, getFieldList, listDatabaseLink } from '@/views/boardGenerate/api/db';
const comparisonTable = {
starttime: '开始时间',
@ -175,6 +237,21 @@ const total = ref(0);
const tableData = ref([{}]);
const constructionDataForm = ref({ designDataFieldList: [] });
const constructionDataFormVisible = ref(false);
const addSQLFormVisible = ref(false);
const addSQLForm = ref({});
const dbList = ref([]);
const tableList = ref([]);
const fieldList = ref([]);
const keyword = ref(['SELECT', 'FROM', 'WHERE', 'GROUP BY', 'HAVING', 'ORDER BY', 'LIMIT', 'TOP', 'DISTINCT', 'AS',
'INSERT INTO', 'VALUES', 'UPDATE', 'SET', 'DELETE',
'CREATE', 'DROP', 'ALTER', 'TRUNCATE', 'RENAME',
'PRIMARY KEY', 'FOREIGN KEY', 'UNIQUE', 'NOT NULL', 'DEFAULT', 'AUTO_INCREMENT', 'CHECK',
'GRANT', 'REVOKE',
'BEGIN', 'START TRANSACTION', 'COMMIT', 'ROLLBACK', 'SAVEPOINT',
'JOIN', 'LEFT JOIN', 'RIGHT JOIN', 'FULL JOIN', 'ON', 'IN', 'EXISTS', 'ANY', 'ALL',
'CASE', 'WHEN', 'THEN', 'ELSE', 'IS NULL', 'IS NOT NULL', 'LIKE', 'BETWEEN',
'UNION', 'UNION ALL', 'WITH']
);
const getList = async () => {
loading.value = true;
getDataSourceList(selectForm.value)
@ -199,6 +276,57 @@ const constructionData = () => {
constructionDataForm.value = { designDataFieldList: [] };
constructionDataFormVisible.value = true;
};
const addSQL = () => {
addSQLFormVisible.value = true;
addSQLForm.value = {};
getDbList();
};
const getDbList = () => {
listDatabaseLink().then(e => {
dbList.value = e.rows;
});
};
const selectDb = (e) => {
getDatabaseLink(e).then((res) => {
tableList.value = res.data;
});
};
const selectTable = () => {
getFieldList(addSQLForm.value.db, addSQLForm.value.table).then((res) => {
fieldList.value = res.data;
});
};
const addSQLInput = (data) => {
addSQLForm.value.SQL = (addSQLForm.value.SQL || '') + `${data} `;
};
const createSQL = () => {
let params = JSON.parse(JSON.stringify(addSQLForm.value));
params.activeFlag = '1';
if (addSQLForm.value.dataSourceId) {
editDataSourceApi(params).then(() => {
addSQLFormVisible.value = false;
ElMessage({
type: 'success',
message: '修改成功'
});
getList();
});
} else {
addDataSourceApi(params).then(() => {
addSQLFormVisible.value = false;
ElMessage({
type: 'success',
message: '创建成功'
});
getList();
});
}
// let nowData = JSON.parse(localStorage.getItem('DATANODE') || '[]');
// nowData.push(constructionDataForm.value);
// localStorage.setItem('DATANODE', JSON.stringify(nowData));
};
const editData = () => {
paramsTableData.value = [];
constructionDataForm.value = { designDataFieldList: [] };

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

@ -3,7 +3,7 @@
<div class="top">
<div class="componentMenu">
<el-popover
:width="620"
:width="880"
trigger="click"
placement="bottom-start">
<template #reference>
@ -23,7 +23,7 @@
@dragstart="onDragStart($event, 'line')" :style="{display:'inline-block',margin:'0 4px 4px 0'}"
:body-style="{padding:'4px 0'}">
<template #header>
<StarFilled />
<el-image style="width: 100%; height: 100%" :src="lineImg" fit="contain" />
</template>
<div class="moduleText">折线</div>
</el-card>
@ -32,7 +32,7 @@
:style="{display:'inline-block',margin:'0 4px 4px 0'}"
:body-style="{padding:'4px 0'}">
<template #header>
<StarFilled />
<el-image style="width: 100%; height: 100%" :src="multiLinesImg" fit="contain" />
</template>
<div class="moduleText">多折线</div>
</el-card>
@ -40,7 +40,7 @@
@dragstart="onDragStart($event, 'curve')" :style="{display:'inline-block',margin:'0 4px 4px 0'}"
:body-style="{padding:'4px 0'}">
<template #header>
<StarFilled />
<el-image style="width: 100%; height: 100%" :src="curveImg" fit="contain" />
</template>
<div class="moduleText">曲线</div>
</el-card>
@ -49,16 +49,26 @@
:style="{display:'inline-block',margin:'0 4px 4px 0'}"
:body-style="{padding:'4px 0'}">
<template #header>
<StarFilled />
<el-image style="width: 100%; height: 100%" :src="multiCurvesImg" fit="contain" />
</template>
<div class="moduleText">多曲线
</div>
</el-card>
<el-card class="moduleCard" shadow="never" :draggable="true"
@dragstart="onDragStart($event, 'lineBar')"
:style="{display:'inline-block',margin:'0 4px 4px 0'}"
:body-style="{padding:'4px 0'}">
<template #header>
<StarFilled />
</template>
<div class="moduleText">双轴图
</div>
</el-card>
<el-card class="moduleCard" shadow="never" :draggable="true"
@dragstart="onDragStart($event, 'bar')" :style="{display:'inline-block',margin:'0 4px 4px 0'}"
:body-style="{padding:'4px 0'}">
<template #header>
<StarFilled />
<el-image style="width: 100%; height: 100%" :src="barImg" fit="contain" />
</template>
<div class="moduleText">柱状图</div>
</el-card>
@ -67,7 +77,7 @@
:style="{display:'inline-block',margin:'0 4px 4px 0'}"
:body-style="{padding:'4px 0'}">
<template #header>
<StarFilled />
<el-image style="width: 100%; height: 100%" :src="backgroundBarImg" fit="contain" />
</template>
<div class="moduleText">背景柱状图</div>
</el-card>
@ -76,7 +86,7 @@
:style="{display:'inline-block',margin:'0 4px 4px 0'}"
:body-style="{padding:'4px 0'}">
<template #header>
<StarFilled />
<el-image style="width: 100%; height: 100%" :src="multiBarsImg" fit="contain" />
</template>
<div class="moduleText">多柱状图
</div>
@ -85,16 +95,42 @@
@dragstart="onDragStart($event, 'pie')" :style="{display:'inline-block',margin:'0 4px 4px 0'}"
:body-style="{padding:'4px 0'}">
<template #header>
<StarFilled />
<el-image style="width: 100%; height: 100%" :src="pieImg" fit="contain" />
</template>
<div class="moduleText">饼图</div>
</el-card>
<el-card class="moduleCard" shadow="never" :draggable="true"
@dragstart="onDragStart($event, 'annular')" :style="{display:'inline-block',margin:'0 4px 4px 0'}"
:body-style="{padding:'4px 0'}">
<template #header>
<el-image style="width: 100%; height: 100%" :src="annularImg" fit="contain" />
</template>
<div class="moduleText">中空饼图</div>
</el-card>
<el-card class="moduleCard" shadow="never" :draggable="true"
@dragstart="onDragStart($event, 'dashboard')"
:style="{display:'inline-block',margin:'0 4px 4px 0'}"
:body-style="{padding:'4px 0'}">
<template #header>
<el-image style="width: 100%; height: 100%" :src="dashboardImg" fit="contain" />
</template>
<div class="moduleText">仪表盘</div>
</el-card>
<el-card class="moduleCard" shadow="never" :draggable="true"
@dragstart="onDragStart($event, 'radar')"
:style="{display:'inline-block',margin:'0 4px 4px 0'}"
:body-style="{padding:'4px 0'}">
<template #header>
<el-image style="width: 100%; height: 100%" :src="radarImg" fit="contain" />
</template>
<div class="moduleText">雷达图</div>
</el-card>
<el-card class="moduleCard" shadow="never" :draggable="true"
@dragstart="onDragStart($event, 'nightingaleRoseDiagram')"
:style="{display:'inline-block',margin:'0 4px 4px 0'}"
:body-style="{padding:'4px 0'}">
<template #header>
<StarFilled />
<el-image style="width: 100%; height: 100%" :src="nightingaleRoseDiagramImg" fit="contain" />
</template>
<div class="moduleText">南丁格尔玫瑰图</div>
</el-card>
@ -102,7 +138,7 @@
@dragstart="onDragStart($event, 'carousel')" :style="{display:'inline-block',margin:'0 4px 4px 0'}"
:body-style="{padding:'4px 0'}">
<template #header>
<StarFilled />
<el-image style="width: 100%; height: 100%" :src="carouselImg" fit="contain" />
</template>
<div class="moduleText">轮播图</div>
</el-card>
@ -266,6 +302,15 @@
</template>
<div class="moduleText">滚动表格</div>
</el-card>
<el-card class="moduleCard" shadow="never" :draggable="true"
@dragstart="onDragStart($event, 'background')"
:style="{display:'inline-block',margin:'0 4px 4px 0'}"
:body-style="{padding:'4px 0'}">
<template #header>
<StarFilled />
</template>
<div class="moduleText">背景</div>
</el-card>
</div>
</el-popover>
</div>
@ -363,6 +408,10 @@
<MultiCurvesNode :inputData=getInputData(multiCurvesNodeProps.id) v-bind="multiCurvesNodeProps"
@resize="resize"></MultiCurvesNode>
</template>
<template #node-lineBar="lineBarNodeProps">
<LineBarNode :inputData=getInputData(lineBarNodeProps.id) v-bind="lineBarNodeProps"
@resize="resize"></LineBarNode>
</template>
<template #node-bar="barNodeProps">
<BarNode :inputData=getInputData(barNodeProps.id) v-bind="barNodeProps"
@resize="resize"></BarNode>
@ -379,6 +428,22 @@
<PieNode :inputData=getInputData(pieNodeProps.id) v-bind="pieNodeProps"
@resize="resize"></PieNode>
</template>
<template #node-annular="annularNodeProps">
<AnnularNode :inputData=getInputData(annularNodeProps.id)
v-bind="annularNodeProps"
@resize="resize"></AnnularNode>
</template>
<template #node-radar="radarNodeProps">
<RadarNode :inputData=getInputData(radarNodeProps.id)
v-bind="radarNodeProps"
@resize="resize"></RadarNode>
</template>
<template #node-dashboard="dashboardNodeProps">
<DashboardNode :inputData=getInputData(dashboardNodeProps.id)
v-bind="dashboardNodeProps"
@resize="resize"></DashboardNode>
</template>
<template #node-nightingaleRoseDiagram="nightingaleRoseDiagramNodeProps">
<NightingaleRoseDiagramNode :inputData=getInputData(nightingaleRoseDiagramNodeProps.id)
v-bind="nightingaleRoseDiagramNodeProps"
@ -441,6 +506,11 @@
<ScrollTableNode :inputData=getInputData(scrollTableNodeProps.id) v-bind="scrollTableNodeProps"
@resize="resize"></ScrollTableNode>
</template>
<template #node-background="backgroundNodeProps">
<BackgroundNode :inputData=getInputData(backgroundNodeProps.id) v-bind="backgroundNodeProps"
@resize="resize"></BackgroundNode>
</template>
</VueFlow>
</FlowRuler>
</div>
@ -482,307 +552,263 @@
<div class="tabItem" v-if="Object.keys(nodeAttrForm).length>0 && tabs === 1">
<el-form :model="nodeAttrForm" label-width="auto" style="max-width: 600px">
<el-collapse v-model="collapseActiveName" accordion expand-icon-position="left">
<el-collapse-item title="Consistency" name="1">
<el-collapse-item title="x轴设置" name="1">
<el-form-item label="x轴名称" v-if="Object.keys(nodeAttrForm).includes('xName')">
<el-input v-model="nodeAttrForm.xName" style="width: 100%" />
</el-form-item>
</el-collapse-item>
<el-collapse-item title="Feedback" name="2">
<div>
Operation feedback: enable the users to clearly perceive their
operations by style updates and interactive effects;
</div>
<div>
Visual feedback: reflect current state by updating or rearranging
elements of the page.
</div>
<el-collapse-item title="y轴设置" name="2">
<el-form-item label="y轴名称" v-if="Object.keys(nodeAttrForm).includes('yName')">
<el-input v-model="nodeAttrForm.yName" style="width: 100%" />
</el-form-item>
</el-collapse-item>
<el-collapse-item title="Efficiency" name="3">
<div>
Simplify the process: keep operating process simple and intuitive;
</div>
<div>
Definite and clear: enunciate your intentions clearly so that the
users can quickly understand and make decisions;
</div>
<div>
Easy to identify: the interface should be straightforward, which helps
the users to identify and frees them from memorizing and recalling.
</div>
<el-collapse-item title="边距设置" name="3">
<el-form-item label="顶部距离" v-if="Object.keys(nodeAttrForm).includes('gridTop')">
<el-input-number v-model="nodeAttrForm.gridTop" style="width: 100%" :min="0" :max="100" />
</el-form-item>
<el-form-item label="左侧距离" v-if="Object.keys(nodeAttrForm).includes('gridLeft')">
<el-input-number v-model="nodeAttrForm.gridLeft" style="width: 100%" :min="0" :max="100" />
</el-form-item>
<el-form-item label="底部距离" v-if="Object.keys(nodeAttrForm).includes('gridBottom')">
<el-input-number v-model="nodeAttrForm.gridBottom" style="width: 100%" :min="0" :max="100" />
</el-form-item>
<el-form-item label="右侧距离" v-if="Object.keys(nodeAttrForm).includes('gridRight')">
<el-input-number v-model="nodeAttrForm.gridRight" style="width: 100%" :min="0" :max="100" />
</el-form-item>
</el-collapse-item>
<el-collapse-item title="Controllability" name="4">
<div>
Decision making: giving advices about operations is acceptable, but do
not make decisions for the users;
</div>
<div>
Controlled consequences: users should be granted the freedom to
operate, including canceling, aborting or terminating current
operation.
</div>
<el-collapse-item title="表格设置" name="4">
<el-form-item label="表格列设置" v-if="Object.keys(nodeAttrForm).includes('tableOptions')">
<el-button class="optionsBtn" plain @click="tableOptionsVisible = true">
配置表格
</el-button>
</el-form-item>
<el-form-item label="表格动画设置" v-if="Object.keys(nodeAttrForm).includes('tableClassOption')">
<el-button class="optionsBtn" plain @click="tableClassOptionsVisible = true">
配置动画
</el-button>
</el-form-item>
<el-form-item label="表头高度" v-if="Object.keys(nodeAttrForm).includes('thHeight')">
<el-input v-model="nodeAttrForm.thHeight" style="width: 100%" />
</el-form-item>
<el-form-item label="行高度" v-if="Object.keys(nodeAttrForm).includes('tdHeight')">
<el-input v-model="nodeAttrForm.tdHeight" style="width: 100%" />
</el-form-item>
<el-form-item label="表头文字颜色" v-if="Object.keys(nodeAttrForm).includes('thColor')">
<el-color-picker v-model="nodeAttrForm.thColor" show-alpha />
</el-form-item>
<el-form-item label="行文字颜色" v-if="Object.keys(nodeAttrForm).includes('tdColor')">
<el-badge value="99" class="item" :offset="[-8,0]"
v-for="(i,k) in nodeAttrForm.tdColor">
<el-color-picker style="margin-right: 4px;" v-model="nodeAttrForm.tdColor[k]" show-alpha />
<template #content>
<div class="custom-content" @click="nodeAttrForm.tdColor.splice(k, 1)">
<el-icon>
<Close />
</el-icon>
</div>
</template>
</el-badge>
<el-button :icon="Plus" @click="nodeAttrForm.tdColor.push('#fff')" />
</el-form-item>
<el-form-item label="表头背景颜色" v-if="Object.keys(nodeAttrForm).includes('thBgColor')">
<el-color-picker v-model="nodeAttrForm.thBgColor" show-alpha />
</el-form-item>
<el-form-item label="行背景颜色" v-if="Object.keys(nodeAttrForm).includes('tdBgColor')">
<el-badge value="99" class="item" :offset="[-8,0]"
v-for="(i,k) in nodeAttrForm.tdBgColor">
<el-color-picker style="margin-right: 8px;"
v-model="nodeAttrForm.tdBgColor[k]" show-alpha />
<template #content>
<div class="custom-content" @click="nodeAttrForm.tdBgColor.splice(k, 1)">
<el-icon>
<Close />
</el-icon>
</div>
</template>
</el-badge>
<el-button :icon="Plus" @click="nodeAttrForm.tdBgColor.push('#fff')" />
</el-form-item>
</el-collapse-item>
<el-collapse-item title="通用设置" name="5">
<el-form-item label="默认内容" v-if="Object.keys(nodeAttrForm).includes('defaultInputArea')">
<el-input type="textarea" v-model="nodeAttrForm.defaultInputArea" style="width: 100%" />
</el-form-item>
<el-form-item label="默认内容" v-if="Object.keys(nodeAttrForm).includes('defaultInput')">
<el-input v-model="nodeAttrForm.defaultInput" style="width: 100%" />
</el-form-item>
<el-form-item label="默认内容" v-if="Object.keys(nodeAttrForm).includes('number')">
<el-input-number :controls="false" autocomplete="off" v-model="nodeAttrForm.number"
style="width: 100%" />
</el-form-item>
<el-form-item label="默认日期" v-if="Object.keys(nodeAttrForm).includes('defaultTime')">
<el-date-picker
v-model="nodeAttrForm.defaultTime"
type="datetimerange"
range-separator="到"
start-placeholder="开始时间"
end-placeholder="结束时间"
style="width: 100%;height: 100%"
:value-format="nodeAttrForm?.format||'YYYY/MM/DD HH:mm:ss'"
:format="nodeAttrForm?.format||'YYYY/MM/DD HH:mm:ss'"
/>
</el-form-item>
<el-form-item label="日期格式" v-if="Object.keys(nodeAttrForm).includes('format')">
<el-input v-model="nodeAttrForm.format" style="width: 100%" />
</el-form-item>
<el-form-item label="输出字段名" v-if="Object.keys(nodeAttrForm).includes('field')">
<el-input v-model="nodeAttrForm.field" />
</el-form-item>
<el-form-item label="时间戳字段名" v-if="Object.keys(nodeAttrForm).includes('timestampField')">
<el-input v-model="nodeAttrForm.timestampField" />
</el-form-item>
<el-form-item label="是否显示时间戳" v-if="Object.keys(nodeAttrForm).includes('isTimestamp')">
<el-switch v-model="nodeAttrForm.isTimestamp" />
</el-form-item>
<el-form-item label="开始时间字段名" v-if="Object.keys(nodeAttrForm).includes('startTimeId')">
<el-input v-model="nodeAttrForm.startTimeId" />
</el-form-item>
<el-form-item label="结束时间字段名" v-if="Object.keys(nodeAttrForm).includes('endTimeId')">
<el-input v-model="nodeAttrForm.endTimeId" />
</el-form-item>
<el-form-item label="数据映射" v-if="Object.keys(nodeAttrForm).includes('dataMap')">
<el-button class="optionsBtn" plain @click="mapOptionsVisible = true">
配置数据映射
</el-button>
</el-form-item>
<el-form-item label="内容" v-if="Object.keys(nodeAttrForm).includes('text')">
<el-input v-model="nodeAttrForm.text" style="width: 100%" />
</el-form-item>
<el-form-item label="对齐方式" v-if="Object.keys(nodeAttrForm).includes('align')">
<el-select
v-model="nodeAttrForm.align"
placeholder="Select"
style="width: 100%"
>
<el-option
label="左对齐"
value="left"
/>
<el-option
label="居中对齐"
value="center"
/>
<el-option
label="右对齐"
value="right"
/>
</el-select>
</el-form-item>
<el-form-item label="文字颜色" v-if="Object.keys(nodeAttrForm).includes('color')">
<el-color-picker v-model="nodeAttrForm.color" show-alpha />
</el-form-item>
<el-form-item label="背景颜色" v-if="Object.keys(nodeAttrForm).includes('backgroundColor')">
<el-color-picker v-model="nodeAttrForm.backgroundColor" show-alpha />
</el-form-item>
<el-form-item label="是否显示边框" v-if="Object.keys(nodeAttrForm).includes('isBorder')">
<el-switch v-model="nodeAttrForm.isBorder" />
</el-form-item>
<el-form-item label="边框颜色"
v-if="Object.keys(nodeAttrForm).includes('borderColor') && nodeAttrForm.isBorder">
<el-color-picker v-model="nodeAttrForm.borderColor" show-alpha />
</el-form-item>
<el-form-item label="时间戳颜色" v-if="Object.keys(nodeAttrForm).includes('timestampColor')">
<el-color-picker v-model="nodeAttrForm.timestampColor" show-alpha />
</el-form-item>
<el-form-item label="图片路径" v-if="Object.keys(nodeAttrForm).includes('imgSrc')">
<el-input v-model="nodeAttrForm.imgSrc" style="width: 100%" />
</el-form-item>
<el-form-item label="图标" v-if="Object.keys(nodeAttrForm).includes('icon')">
<el-popover
placement="bottom"
:width="400"
trigger="click"
>
<template #reference>
<el-input readonly v-model="nodeAttrForm.icon" style="width: 100%" placeholder="选择图标">
<template #prepend>
<el-button style="background-color: #0000">
<template #icon>
<el-icon class="el-icon--right" color="#fff">
<component :is="icon[nodeAttrForm.icon]" />
</el-icon>
</template>
</el-button>
</template>
</el-input>
</template>
<el-input v-model="selectIconInput" style="width: 100%" placeholder="筛选图标" />
<div style="height: 50vh;overflow-y: auto">
<!-- <el-tooltip-->
<!-- class="box-item"-->
<!-- effect="dark"-->
<!-- :content="i"--
<!-- placement="bottom"-->
<!-- v-for="i in icons.filter(e=>e.includes(selectIconInput))"-->
<!-- >-->
<el-button :icon="icon[i]" @click="nodeAttrForm.icon = i"
:type="nodeAttrForm.icon === i ? 'primary':''"
v-for="i in icons.filter(e=>e.includes(selectIconInput))"
style="margin-top: 4px;margin-left: 0;margin-right: 4px;" />
<!-- </el-tooltip>-->
</div>
</el-popover>
</el-form-item>
<el-form-item label="图标路径" v-if="Object.keys(nodeAttrForm).includes('iconSrc')">
<el-input v-model="nodeAttrForm.imgSrc" style="width: 100%" />
</el-form-item>
<el-form-item label="视频路径" v-if="Object.keys(nodeAttrForm).includes('videoSrc')">
<el-input v-model="nodeAttrForm.videoSrc" style="width: 100%" />
</el-form-item>
<el-form-item label="标题" v-if="Object.keys(nodeAttrForm).includes('title')">
<el-input v-model="nodeAttrForm.title" style="width: 100%" />
</el-form-item>
<el-form-item label="数据名称" v-if="Object.keys(nodeAttrForm).includes('yNames')">
<el-input-tag v-model="nodeAttrForm.yNames" placeholder="回车确认" />
</el-form-item>
<el-form-item label="超时时间" v-if="Object.keys(nodeAttrForm).includes('timeout')">
<el-input-number
v-model="nodeAttrForm.timeout"
:min="1000"
:step="1000"
controls-position="right"
/>
</el-form-item>
<el-form-item label="提示框" v-if="Object.keys(nodeAttrForm).includes('tooltip')">
<el-switch v-model="nodeAttrForm.tooltip" active-text="" inactive-text="" />
</el-form-item>
<el-form-item label="图例" v-if="Object.keys(nodeAttrForm).includes('legend')">
<el-switch v-model="nodeAttrForm.legend" active-text="" inactive-text="" />
</el-form-item>
<el-form-item label="饼图标签" v-if="Object.keys(nodeAttrForm).includes('label')">
<el-switch v-model="nodeAttrForm.label" active-text="" inactive-text="" />
</el-form-item>
<el-form-item label="轮播设置" v-if="Object.keys(nodeAttrForm).includes('swiperOptions')">
<el-button class="optionsBtn" plain @click="swiperOptionsVisible = true">
配置轮播图
</el-button>
</el-form-item>
<el-form-item label="图片显示方式" v-if="Object.keys(nodeAttrForm).includes('imageFit')">
<el-select
effect="dark"
v-model="nodeAttrForm.imageFit"
style="width: 100%"
>
<el-option
label="填充满"
value="fill"
/>
<el-option
label="固定比例"
value="contain"
/>
</el-select>
</el-form-item>
<el-form-item label="图片集" v-if="Object.keys(nodeAttrForm).includes('carouselImages')">
<el-input-tag v-model="nodeAttrForm.carouselImages" placeholder="回车确认" />
</el-form-item>
</el-collapse-item>
</el-collapse>
<el-form-item label="默认内容" v-if="Object.keys(nodeAttrForm).includes('defaultInputArea')">
<el-input type="textarea" v-model="nodeAttrForm.defaultInputArea" style="width: 100%" />
</el-form-item>
<el-form-item label="默认内容" v-if="Object.keys(nodeAttrForm).includes('defaultInput')">
<el-input v-model="nodeAttrForm.defaultInput" style="width: 100%" />
</el-form-item>
<el-form-item label="默认内容" v-if="Object.keys(nodeAttrForm).includes('number')">
<el-input-number :controls="false" autocomplete="off" v-model="nodeAttrForm.number" style="width: 100%" />
</el-form-item>
<el-form-item label="y轴名称" v-if="Object.keys(nodeAttrForm).includes('yName')">
<el-input v-model="nodeAttrForm.yName" style="width: 100%" />
</el-form-item>
<el-form-item label="顶部距离" v-if="Object.keys(nodeAttrForm).includes('gridTop')">
<el-input-number v-model="nodeAttrForm.gridTop" style="width: 100%" :min="0" :max="100" />
</el-form-item>
<el-form-item label="左侧距离" v-if="Object.keys(nodeAttrForm).includes('gridLeft')">
<el-input-number v-model="nodeAttrForm.gridLeft" style="width: 100%" :min="0" :max="100" />
</el-form-item>
<el-form-item label="底部距离" v-if="Object.keys(nodeAttrForm).includes('gridBottom')">
<el-input-number v-model="nodeAttrForm.gridBottom" style="width: 100%" :min="0" :max="100" />
</el-form-item>
<el-form-item label="右侧距离" v-if="Object.keys(nodeAttrForm).includes('gridRight')">
<el-input-number v-model="nodeAttrForm.gridRight" style="width: 100%" :min="0" :max="100" />
</el-form-item>
<el-form-item label="默认日期" v-if="Object.keys(nodeAttrForm).includes('defaultTime')">
<el-date-picker
v-model="nodeAttrForm.defaultTime"
type="datetimerange"
range-separator="到"
start-placeholder="开始时间"
end-placeholder="结束时间"
style="width: 100%;height: 100%"
:value-format="nodeAttrForm?.format||'YYYY/MM/DD HH:mm:ss'"
:format="nodeAttrForm?.format||'YYYY/MM/DD HH:mm:ss'"
/>
</el-form-item>
<el-form-item label="日期格式" v-if="Object.keys(nodeAttrForm).includes('format')">
<el-input v-model="nodeAttrForm.format" style="width: 100%" />
</el-form-item>
<el-form-item label="输出字段名" v-if="Object.keys(nodeAttrForm).includes('field')">
<el-input v-model="nodeAttrForm.field" />
</el-form-item>
<el-form-item label="时间戳字段名" v-if="Object.keys(nodeAttrForm).includes('timestampField')">
<el-input v-model="nodeAttrForm.timestampField" />
</el-form-item>
<el-form-item label="是否显示时间戳" v-if="Object.keys(nodeAttrForm).includes('isTimestamp')">
<el-switch v-model="nodeAttrForm.isTimestamp" />
</el-form-item>
<el-form-item label="开始时间字段名" v-if="Object.keys(nodeAttrForm).includes('startTimeId')">
<el-input v-model="nodeAttrForm.startTimeId" />
</el-form-item>
<el-form-item label="结束时间字段名" v-if="Object.keys(nodeAttrForm).includes('endTimeId')">
<el-input v-model="nodeAttrForm.endTimeId" />
</el-form-item>
<el-form-item label="数据映射" v-if="Object.keys(nodeAttrForm).includes('dataMap')">
<el-table :data="nodeAttrForm.dataMap" style="width: 100%">
<el-table-column label="源字段" min-width="120">
<template #default="scope">
<el-input v-model="scope.row.source" style="width: 100%" />
</template>
</el-table-column>
<el-table-column label="映射字段" min-width="120">
<template #default="scope">
<el-input v-model="scope.row.target" style="width: 100%" />
</template>
</el-table-column>
<el-table-column label="操作" min-width="120">
<template #default="scope">
<el-button link type="primary" size="small" @click="nodeAttrForm.dataMap.splice(scope.$index, 1)">
删除
</el-button>
</template>
</el-table-column>
</el-table>
<el-button style="width: 100%" @click="nodeAttrForm.dataMap.push({})">
添加映射
</el-button>
</el-form-item>
<el-form-item label="内容" v-if="Object.keys(nodeAttrForm).includes('text')">
<el-input v-model="nodeAttrForm.text" style="width: 100%" />
</el-form-item>
<el-form-item label="对齐方式" v-if="Object.keys(nodeAttrForm).includes('align')">
<el-select
v-model="nodeAttrForm.align"
placeholder="Select"
style="width: 100%"
>
<el-option
label="左对齐"
value="left"
/>
<el-option
label="居中对齐"
value="center"
/>
<el-option
label="右对齐"
value="right"
/>
</el-select>
</el-form-item>
<el-form-item label="文字颜色" v-if="Object.keys(nodeAttrForm).includes('color')">
<el-color-picker v-model="nodeAttrForm.color" show-alpha />
</el-form-item>
<el-form-item label="背景颜色" v-if="Object.keys(nodeAttrForm).includes('backgroundColor')">
<el-color-picker v-model="nodeAttrForm.backgroundColor" show-alpha />
</el-form-item>
<el-form-item label="是否显示边框" v-if="Object.keys(nodeAttrForm).includes('isBorder')">
<el-switch v-model="nodeAttrForm.isBorder" />
</el-form-item>
<el-form-item label="边框颜色"
v-if="Object.keys(nodeAttrForm).includes('borderColor') && nodeAttrForm.isBorder">
<el-color-picker v-model="nodeAttrForm.borderColor" show-alpha />
</el-form-item>
<el-form-item label="时间戳颜色" v-if="Object.keys(nodeAttrForm).includes('timestampColor')">
<el-color-picker v-model="nodeAttrForm.timestampColor" show-alpha />
</el-form-item>
<el-form-item label="图片路径" v-if="Object.keys(nodeAttrForm).includes('imgSrc')">
<el-input v-model="nodeAttrForm.imgSrc" style="width: 100%" />
</el-form-item>
<el-form-item label="图标" v-if="Object.keys(nodeAttrForm).includes('icon')">
<el-popover
placement="bottom"
:width="400"
trigger="click"
>
<template #reference>
<el-input readonly v-model="nodeAttrForm.icon" style="width: 100%" placeholder="选择图标">
<template #prepend>
<el-button style="background-color: #0000">
<template #icon>
<el-icon class="el-icon--right" color="#fff">
<component :is="icon[nodeAttrForm.icon]" />
</el-icon>
</template>
</el-button>
</template>
</el-input>
</template>
<el-input v-model="selectIconInput" style="width: 100%" placeholder="筛选图标" />
<div style="height: 50vh;overflow-y: auto">
<!-- <el-tooltip-->
<!-- class="box-item"-->
<!-- effect="dark"-->
<!-- :content="i"--
<!-- placement="bottom"-->
<!-- v-for="i in icons.filter(e=>e.includes(selectIconInput))"-->
<!-- >-->
<el-button :icon="icon[i]" @click="nodeAttrForm.icon = i"
:type="nodeAttrForm.icon === i ? 'primary':''"
v-for="i in icons.filter(e=>e.includes(selectIconInput))"
style="margin-top: 4px;margin-left: 0;margin-right: 4px;" />
<!-- </el-tooltip>-->
</div>
</el-popover>
</el-form-item>
<el-form-item label="图标路径" v-if="Object.keys(nodeAttrForm).includes('iconSrc')">
<el-input v-model="nodeAttrForm.imgSrc" style="width: 100%" />
</el-form-item>
<el-form-item label="视频路径" v-if="Object.keys(nodeAttrForm).includes('videoSrc')">
<el-input v-model="nodeAttrForm.videoSrc" style="width: 100%" />
</el-form-item>
<el-form-item label="标题" v-if="Object.keys(nodeAttrForm).includes('title')">
<el-input v-model="nodeAttrForm.title" style="width: 100%" />
</el-form-item>
<el-form-item label="数据名称" v-if="Object.keys(nodeAttrForm).includes('yNames')">
<el-input-tag v-model="nodeAttrForm.yNames" placeholder="回车确认" />
</el-form-item>
<el-form-item label="超时时间" v-if="Object.keys(nodeAttrForm).includes('timeout')">
<el-input-number
v-model="nodeAttrForm.timeout"
:min="1000"
:step="1000"
controls-position="right"
/>
</el-form-item>
<el-form-item label="提示框" v-if="Object.keys(nodeAttrForm).includes('tooltip')">
<el-switch v-model="nodeAttrForm.tooltip" active-text="" inactive-text="" />
</el-form-item>
<el-form-item label="图例" v-if="Object.keys(nodeAttrForm).includes('legend')">
<el-switch v-model="nodeAttrForm.legend" active-text="" inactive-text="" />
</el-form-item>
<el-form-item label="饼图标签" v-if="Object.keys(nodeAttrForm).includes('label')">
<el-switch v-model="nodeAttrForm.label" active-text="" inactive-text="" />
</el-form-item>
<el-form-item label="轮播设置" v-if="Object.keys(nodeAttrForm).includes('swiperOptions')">
<el-button class="optionsBtn" plain @click="swiperOptionsVisible = true">
配置轮播图
</el-button>
</el-form-item>
<el-form-item label="图片显示方式" v-if="Object.keys(nodeAttrForm).includes('imageFit')">
<el-select
effect="dark"
v-model="nodeAttrForm.imageFit"
style="width: 100%"
>
<el-option
label="填充满"
value="fill"
/>
<el-option
label="固定比例"
value="contain"
/>
</el-select>
</el-form-item>
<el-form-item label="图片集" v-if="Object.keys(nodeAttrForm).includes('carouselImages')">
<el-input-tag v-model="nodeAttrForm.carouselImages" placeholder="回车确认" />
</el-form-item>
<el-form-item label="表格列设置" v-if="Object.keys(nodeAttrForm).includes('tableOptions')">
<el-button class="optionsBtn" plain @click="tableOptionsVisible = true">
配置表格
</el-button>
</el-form-item>
<el-form-item label="表格动画设置" v-if="Object.keys(nodeAttrForm).includes('tableClassOption')">
<el-button class="optionsBtn" plain @click="tableClassOptionsVisible = true">
配置动画
</el-button>
</el-form-item>
<el-form-item label="表头高度" v-if="Object.keys(nodeAttrForm).includes('thHeight')">
<el-input v-model="nodeAttrForm.thHeight" style="width: 100%" />
</el-form-item>
<el-form-item label="行高度" v-if="Object.keys(nodeAttrForm).includes('tdHeight')">
<el-input v-model="nodeAttrForm.tdHeight" style="width: 100%" />
</el-form-item>
<el-form-item label="表头文字颜色" v-if="Object.keys(nodeAttrForm).includes('thColor')">
<el-color-picker v-model="nodeAttrForm.thColor" show-alpha />
</el-form-item>
<el-form-item label="行文字颜色" v-if="Object.keys(nodeAttrForm).includes('tdColor')">
<el-badge value="99" class="item" :offset="[-8,0]"
v-for="(i,k) in nodeAttrForm.tdColor">
<el-color-picker style="margin-right: 4px;" v-model="nodeAttrForm.tdColor[k]" show-alpha />
<template #content>
<div class="custom-content" @click="nodeAttrForm.tdColor.splice(k, 1)">
<el-icon>
<Close />
</el-icon>
</div>
</template>
</el-badge>
<el-button :icon="Plus" @click="nodeAttrForm.tdColor.push('#fff')" />
</el-form-item>
<el-form-item label="表头背景颜色" v-if="Object.keys(nodeAttrForm).includes('thBgColor')">
<el-color-picker v-model="nodeAttrForm.thBgColor" show-alpha />
</el-form-item>
<el-form-item label="行背景颜色" v-if="Object.keys(nodeAttrForm).includes('tdBgColor')">
<el-badge value="99" class="item" :offset="[-8,0]"
v-for="(i,k) in nodeAttrForm.tdBgColor">
<el-color-picker style="margin-right: 8px;"
v-model="nodeAttrForm.tdBgColor[k]" show-alpha />
<template #content>
<div class="custom-content" @click="nodeAttrForm.tdBgColor.splice(k, 1)">
<el-icon>
<Close />
</el-icon>
</div>
</template>
</el-badge>
<el-button :icon="Plus" @click="nodeAttrForm.tdBgColor.push('#fff')" />
</el-form-item>
</el-form>
</div>
</div>
@ -962,9 +988,51 @@
</div>
</template>
</el-dialog>
<el-dialog v-model="mapOptionsVisible" title="数据映射" width="500">
<el-table :data="nodeAttrForm.dataMap" style="width: 100%">
<el-table-column label="源字段" min-width="120">
<template #default="scope">
<el-input v-model="scope.row.source" style="width: 100%" />
</template>
</el-table-column>
<el-table-column label="映射字段" min-width="120">
<template #default="scope">
<el-input v-model="scope.row.target" style="width: 100%" />
</template>
</el-table-column>
<el-table-column label="操作" min-width="120">
<template #default="scope">
<el-button link type="primary" size="small" @click="nodeAttrForm.dataMap.splice(scope.$index, 1)">
删除
</el-button>
</template>
</el-table-column>
</el-table>
<el-button style="width: 100%" @click="nodeAttrForm.dataMap.push({})">
添加映射
</el-button>
<template #footer>
<div class="dialog-footer">
<el-button @click="mapOptionsVisible = false">关闭</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup>
import backgroundBarImg from './images/backgroundBarImg.png';
import pieImg from './images/pieImg.png';
import multiCurvesImg from './images/multiCurvesImg.png';
import multiLinesImg from './images/multiLinesImg.png';
import multiBarsImg from './images/multiBarsImg.png';
import annularImg from './images/annularImg.png';
import radarImg from './images/radarImg.png';
import carouselImg from './images/carouselImg.png';
import nightingaleRoseDiagramImg from './images/nightingaleRoseDiagramImg.png';
import curveImg from './images/curveImg.png';
import dashboardImg from './images/dashboardImg.png';
import lineImg from './images/lineImg.png';
import barImg from './images/barImg.png';
import FlowRuler from './FlowRuler.vue';
import {
@ -988,13 +1056,20 @@ import DataNode from '@/views/boardGenerate/nodes/data/dataNode.vue';
import ImgNode from '@/views/boardGenerate/nodes/form/imgNode.vue';
import TimelineNode from '@/views/boardGenerate/nodes/form/timelineNode.vue';
import ScrollTableNode from '@/views/boardGenerate/nodes/form/scrollTableNode.vue';
import BackgroundNode from '@/views/boardGenerate/nodes/form/backgroundNode.vue';
import TextNode from '@/views/boardGenerate/nodes/form/textNode.vue';
import CurveNode from '@/views/boardGenerate/nodes/board/curveNode.vue';
import PieNode from '@/views/boardGenerate/nodes/board/pieNode.vue';
import AnnularNode from '@/views/boardGenerate/nodes/board/annularNode.vue';
import DashboardNode from '@/views/boardGenerate/nodes/board/dashboardNode.vue';
import RadarNode from '@/views/boardGenerate/nodes/board/radarNode.vue';
import LineNode from '@/views/boardGenerate/nodes/board/lineNode.vue';
import MultiLinesNode from '@/views/boardGenerate/nodes/board/multiLinesNode.vue';
import BackgroundBarNode from '@/views/boardGenerate/nodes/board/backgroundBarNode.vue';
import MultiCurvesNode from '@/views/boardGenerate/nodes/board/multiCurvesNode.vue';
import LineBarNode from '@/views/boardGenerate/nodes/board/lineBarNode.vue';
import DigitalFlopNode from '@/views/boardGenerate/nodes/form/digitalFlopNode.vue';
import NightingaleRoseDiagramNode from '@/views/boardGenerate/nodes/board/nightingaleRoseDiagramNode.vue';
import IconNode from '@/views/boardGenerate/nodes/form/iconNode.vue';
@ -1115,6 +1190,7 @@ const pageSettingVisible = ref(false);
const tableOptionsVisible = ref(false);
const tableClassOptionsVisible = ref(false);
const swiperOptionsVisible = ref(false);
const mapOptionsVisible = ref(false);
const tabs = ref(0);
const nodes = ref([{
id: `area_${uuidv4().replaceAll('-', '_')}`,
@ -1644,7 +1720,7 @@ const pitchOnNode = (e) => {
}
.moduleCard {
width: 80px;
width: 100px;
vertical-align: top;
:deep(.el-card__body) {
@ -1652,6 +1728,10 @@ const pitchOnNode = (e) => {
padding: 0 !important;
}
:deep(.el-card__header) {
padding: 0 !important;
}
.moduleText {
display: flex;
justify-content: center;

@ -0,0 +1,164 @@
<template>
<div
:style="{width:props.dimensions.width+'px',height:props.dimensions.height+'px'}">
<NodeResizer color="#fff" v-if="!props.isView && !props.isHideHandle && props.selected" @resize="resize" />
<div class="custom-node"
:style="{width:props.dimensions.width+'px',height:props.dimensions.height+'px',pointerEvents:props.isView?'auto': 'none'}">
<div style="width: 100%;height: 100%" ref="chartRef" />
</div>
<Handle v-if="!props.isView" :id="`${props.id}.-t`" type="target" :position="Position.Left" />
</div>
</template>
<script setup>
import { defineEmits, defineProps, ref } from 'vue';
import { NodeResizer } from '@vue-flow/node-resizer';
import { Handle, Position } from '@vue-flow/core';
import * as echarts from 'echarts';
const props = defineProps({
isView: {
type: Boolean,
required: false
},
inputData: {
type: Object,
required: false
},
id: {
type: String,
required: true
},
isHideHandle: {
type: Boolean,
required: false
},
selected: {
type: Boolean,
required: false
},
data: {
type: Object,
required: true
},
dimensions: {
type: Object,
required: true
}
});
const chartRef = ref();
let chart = null;
const colorList = ['#9E87FF', '#73DDFF', '#fe9a8b', '#F56948', '#9E87FF'];
const getOption = () => {
const chartOption = {
title: {
text: props.data.options.title || '设备运行数量',
textStyle: {
fontSize: 12,
fontWeight: 400,
color: '#fff'
},
left: '0',
top: '5%'
},
legend: {
show: props.data?.options?.legend || false,
icon: 'circle',
top: '5%',
right: '5%',
itemWidth: 6,
itemGap: 20,
textStyle: {
color: '#fff'
}
},
tooltip: {
show: props.data?.options?.tooltip || false,
trigger: 'axis',
axisPointer: {
label: {
show: true,
backgroundColor: '#fff',
color: '#000',
borderColor: 'rgba(0,0,0,0)',
shadowColor: 'rgba(0,0,0,0)',
shadowOffsetY: 0
},
lineStyle: {
width: 0
}
},
backgroundColor: '#fff',
textStyle: {
color: '#000'
},
padding: [10, 10],
extraCssText: 'box-shadow: 1px 0 2px 0 rgba(163,163,163,0.5)'
},
grid: {
top: '30%',
bottom: '10%'
},
series: [
{
type: 'pie',
radius: ['42%', '50%'],
label: {
show: props.data?.options?.label || false,
formatter: '{b}: {d}%'
}
}
]
};
let xData = [props.inputData?.x1 || []];
let yData = [props.inputData?.y1 || []];
console.log(chartOption);
let length = Math.min(...xData.map(e => e.length), ...yData.map(e => e.length));
let source = [['product', ...[props.data.options?.yNames?.[0] || '数量']]];
Array(length).fill(0).forEach((_, i) => {
let item = [];
xData.forEach(e => {
item.push(e[i]);
});
yData.forEach(e => {
item.push(e[i]);
});
source.push(item);
});
console.log(source);
return {
...chartOption,
dataset: {
source
}
};
};
onMounted(() => {
chart = echarts.init(chartRef.value, 'macarons', {
renderer: 'svg'
});
chart.setOption(getOption(), true);
});
watch(() => [JSON.parse(JSON.stringify(props.inputData)), JSON.parse(JSON.stringify(props.data.options))], (obj1, obj2) => {
if (JSON.stringify(obj1) !== JSON.stringify(obj2)) {
chart && chart.setOption(getOption(), true);
}
}, { deep: true, immediate: true });
watch(() => JSON.parse(JSON.stringify(props.dimensions)), (obj1, obj2) => {
if (JSON.stringify(obj1) !== JSON.stringify(obj2)) {
chart?.resize();
}
}, { deep: true, immediate: true });
const emit = defineEmits(['resize']);
const resize = (e) => {
chart.resize();
emit('resize', e, props.id);
};
</script>
<style scoped>
.custom-node {
width: 100%;
height: 100%;
}
</style>

@ -227,7 +227,7 @@ const getOption = () => {
item.push(e[i]);
});
yData.forEach(e => {
item.push(e[i]);
item.push(parseFloat(e[i]));
});
source.push(item);
});

@ -0,0 +1,152 @@
<template>
<div
:style="{width:props.dimensions.width+'px',height:props.dimensions.height+'px'}">
<NodeResizer color="#fff" v-if="!props.isView && !props.isHideHandle && props.selected" @resize="resize" />
<div class="custom-node"
:style="{width:props.dimensions.width+'px',height:props.dimensions.height+'px',pointerEvents:props.isView?'auto': 'none'}">
<div style="width: 100%;height: 100%" ref="chartRef" />
</div>
<Handle v-if="!props.isView" :id="`${props.id}.-t`" type="target" :position="Position.Left" />
</div>
</template>
<script setup>
import { defineEmits, defineProps, ref } from 'vue';
import { NodeResizer } from '@vue-flow/node-resizer';
import { Handle, Position } from '@vue-flow/core';
import * as echarts from 'echarts';
const props = defineProps({
isView: {
type: Boolean,
required: false
},
inputData: {
type: Object,
required: false
},
id: {
type: String,
required: true
},
isHideHandle: {
type: Boolean,
required: false
},
selected: {
type: Boolean,
required: false
},
data: {
type: Object,
required: true
},
dimensions: {
type: Object,
required: true
}
});
const chartRef = ref();
let chart = null;
const colorList = ['#9E87FF', '#73DDFF', '#fe9a8b', '#F56948', '#9E87FF'];
const getOption = () => {
const chartOption = {
title: {
text: props.data.options.title || '设备运行数量',
textStyle: {
fontSize: 12,
fontWeight: 400,
color: '#fff'
},
left: '0',
top: '5%'
},
grid: {
top: '30%',
bottom: '10%'
},
series: [
{
type: 'gauge',
progress: {
show: true,
width: props.dimensions.width / 30
},
axisLine: {
lineStyle: {
width: props.dimensions.width / 30
}
},
axisTick: {
show: false
},
splitLine: {
length: props.dimensions.width / 30,
lineStyle: {
width: 2,
color: '#fff'
}
},
axisLabel: {
distance: props.dimensions.width / 30 + 10,
color: '#fff',
fontSize: props.dimensions.width / 30
},
anchor: {
show: true,
showAbove: true,
size: 25,
itemStyle: {
borderWidth: 6
}
},
title: {
show: false
},
detail: {
valueAnimation: true,
fontSize: props.dimensions.width / 10,
offsetCenter: [0, '70%']
},
data: [
{
value: 70
}
]
}
]
};
return {
...chartOption
};
};
onMounted(() => {
chart = echarts.init(chartRef.value, 'macarons', {
renderer: 'svg'
});
chart.setOption(getOption(), true);
});
watch(() => [JSON.parse(JSON.stringify(props.inputData)), JSON.parse(JSON.stringify(props.data.options))], (obj1, obj2) => {
if (JSON.stringify(obj1) !== JSON.stringify(obj2)) {
chart && chart.setOption(getOption(), true);
}
}, { deep: true, immediate: true });
watch(() => JSON.parse(JSON.stringify(props.dimensions)), (obj1, obj2) => {
if (JSON.stringify(obj1) !== JSON.stringify(obj2)) {
chart?.resize();
chart && chart.setOption(getOption(), true);
}
}, { deep: true, immediate: true });
const emit = defineEmits(['resize']);
const resize = (e) => {
chart.resize();
emit('resize', e, props.id);
};
</script>
<style scoped>
.custom-node {
width: 100%;
height: 100%;
}
</style>

@ -0,0 +1,296 @@
<template>
<div
:style="{width:props.dimensions.width+'px',height:props.dimensions.height+'px'}">
<NodeResizer color="#fff" v-if="!props.isView && !props.isHideHandle && props.selected" @resize="resize" />
<div class="custom-node"
:style="{width:props.dimensions.width+'px',height:props.dimensions.height+'px',pointerEvents:props.isView?'auto': 'none'}">
<div style="width: 100%;height: 100%" ref="chartRef" />
</div>
<Handle v-if="!props.isView" :id="`${props.id}.-t`" type="target" :position="Position.Left" />
</div>
</template>
<script setup>
import { defineEmits, defineProps, ref } from 'vue';
import { NodeResizer } from '@vue-flow/node-resizer';
import { Handle, Position } from '@vue-flow/core';
import * as echarts from 'echarts';
const props = defineProps({
isView: {
type: Boolean,
required: false
},
inputData: {
type: Object,
required: false
},
id: {
type: String,
required: true
},
isHideHandle: {
type: Boolean,
required: false
},
selected: {
type: Boolean,
required: false
},
data: {
type: Object,
required: true
},
dimensions: {
type: Object,
required: true
}
});
const chartRef = ref();
let chart = null;
const colorList = ['#9E87FF', '#73DDFF', '#fe9a8b', '#F56948', '#9E87FF'];
const defaultOption = {
title: {
text: props.data.options.title || '',
textStyle: {
fontSize: 12,
fontWeight: 400,
color: '#fff'
},
left: '0',
top: '5%'
},
legend: {
show: props.data?.options?.legend || false,
icon: 'circle',
top: '5%',
right: '5%',
itemWidth: 6,
itemGap: 20,
textStyle: {
color: '#fff'
}
},
tooltip: {
show: props.data?.options?.tooltip || false,
trigger: 'axis',
axisPointer: {
label: {
show: true,
backgroundColor: '#fff',
color: '#000',
borderColor: 'rgba(0,0,0,0)',
shadowColor: 'rgba(0,0,0,0)',
shadowOffsetY: 0
},
lineStyle: {
width: 0
}
},
backgroundColor: '#fff',
textStyle: {
color: '#000'
},
padding: [10, 10],
extraCssText: 'box-shadow: 1px 0 2px 0 rgba(163,163,163,0.5)'
},
grid: {
top: props.data?.options?.gridTop + '%' || '20%',
left: props.data?.options?.gridLeft + '%' || '20%',
bottom: props.data?.options?.gridBottom + '%' || '20%',
right: props.data?.options?.gridRight + '%' || '20%'
},
xAxis: [
{
name: props.data?.options?.xName || '',
type: 'category',
axisLine: {
lineStyle: {
color: '#DCE2E8'
}
},
axisTick: {
show: true
},
axisLabel: {
interval: 0,
textStyle: {
color: '#fff'
},
fontSize: 12,
margin: 3
},
axisPointer: {
label: {
padding: [0, 0, 0, 0],
margin: 0,
fontSize: 12
}
},
boundaryGap: true
}
],
yAxis: [
{
name: props.data?.options?.yName || '',
type: 'value',
axisTick: {
show: false
},
axisLine: {
show: true,
lineStyle: {
color: '#fff'
}
},
axisLabel: {
textStyle: {
color: '#fff'
}
},
splitLine: {
show: false
}
}
],
series: [
{
type: 'bar',
itemStyle: {
normal: {
color: new echarts.graphic.LinearGradient(0, 1, 0, 0, [{
offset: 0,
color: '#0372FF'
},
{
offset: 1,
color: '#75ECFF'
}
])
}
},
barMaxWidth: 50,
label: {
show: true,
position: 'top',
color: '#fff',
fontSize: 16
}
},
{
type: 'line',
symbolSize: 1,
symbol: 'circle',
smooth: false,
yAxisIndex: 0,
showSymbol: false,
lineStyle: {
width: 1,
color: new echarts.graphic.LinearGradient(0, 1, 0, 0, [
{
offset: 0,
color: '#9effff'
},
{
offset: 1,
color: '#9E87FF'
}
]),
shadowColor: 'rgba(158,135,255, 0.3)',
shadowBlur: 10,
shadowOffsetY: 20
},
itemStyle: {
normal: {
color: colorList[0],
borderColor: colorList[0]
}
}
}
]
};
const getOption = () => {
const chartOption = {
title: {
text: props.data.options.title || ''
},
legend: {
show: props.data?.options?.legend || false
},
tooltip: {
show: props.data?.options?.tooltip || false
},
grid: {
top: props.data?.options?.gridTop + '%' || '20%',
left: props.data?.options?.gridLeft + '%' || '20%',
bottom: props.data?.options?.gridBottom + '%' || '20%',
right: props.data?.options?.gridRight + '%' || '20%'
},
xAxis: [
{
name: props.data?.options?.xName || ''
}
],
yAxis: [
{
name: props.data?.options?.yName || ''
}
]
};
let xData = [props.inputData?.x1 || []];
let yData = [props.inputData?.y1 || []];
let yData1 = [props.inputData?.y2 || []];
let length = Math.min(...xData.map(e => e.length), ...yData.map(e => e.length));
let source = [['product', ...[props.data.options?.yNames?.[0] || '数量']]];
Array(length).fill(0).forEach((_, i) => {
let item = [];
xData.forEach(e => {
item.push(e[i]);
});
yData.forEach(e => {
item.push(parseFloat(e[i]));
});
yData1.forEach(e => {
item.push(parseFloat(e[i]));
});
source.push(item);
});
console.log(xData);
console.log(yData);
console.log(yData1);
return {
...chartOption,
dataset: {
source
}
};
};
onMounted(() => {
chart = echarts.init(chartRef.value, 'macarons', {
renderer: 'svg'
});
chart.setOption(defaultOption, true);
});
watch(() => [JSON.parse(JSON.stringify(props.inputData)), JSON.parse(JSON.stringify(props.data.options))], (obj1, obj2) => {
if (JSON.stringify(obj1) !== JSON.stringify(obj2)) {
chart && chart.setOption(getOption(), false);
}
}, { deep: true, immediate: true });
watch(() => JSON.parse(JSON.stringify(props.dimensions)), (obj1, obj2) => {
if (JSON.stringify(obj1) !== JSON.stringify(obj2)) {
chart?.resize();
}
}, { deep: true, immediate: true });
const emit = defineEmits(['resize']);
const resize = (e) => {
chart.resize();
emit('resize', e, props.id);
};
</script>
<style scoped>
.custom-node {
width: 100%;
height: 100%;
}
</style>

@ -243,7 +243,6 @@ onMounted(() => {
});
watch(() => [JSON.parse(JSON.stringify(props.inputData)), JSON.parse(JSON.stringify(props.data.options))], (obj1, obj2) => {
if (JSON.stringify(obj1) !== JSON.stringify(obj2)) {
console.log(1123);
chart && chart.setOption(getOption(), false);
}
}, { deep: true, immediate: true });

@ -0,0 +1,268 @@
<template>
<div
:style="{width:props.dimensions.width+'px',height:props.dimensions.height+'px'}">
<NodeResizer color="#fff" v-if="!props.isView && !props.isHideHandle && props.selected" @resize="resize" />
<div class="custom-node"
:style="{width:props.dimensions.width+'px',height:props.dimensions.height+'px',pointerEvents:props.isView?'auto': 'none'}">
<div style="width: 100%;height: 100%" ref="chartRef" />
</div>
<Handle v-if="!props.isView" :id="`${props.id}.-t`" type="target" :position="Position.Left" />
</div>
</template>
<script setup>
import { defineEmits, defineProps, ref } from 'vue';
import { NodeResizer } from '@vue-flow/node-resizer';
import { Handle, Position } from '@vue-flow/core';
import * as echarts from 'echarts';
const props = defineProps({
isView: {
type: Boolean,
required: false
},
inputData: {
type: Object,
required: false
},
id: {
type: String,
required: true
},
isHideHandle: {
type: Boolean,
required: false
},
selected: {
type: Boolean,
required: false
},
data: {
type: Object,
required: true
},
dimensions: {
type: Object,
required: true
}
});
const chartRef = ref();
let chart = null;
const colorList = ['#9E87FF', '#73DDFF', '#fe9a8b', '#F56948', '#9E87FF'];
const getOption = () => {
const chartOption = {
title: {
text: props.data.options.title || '',
textStyle: {
fontSize: 12,
fontWeight: 400,
color: '#fff'
},
left: '0',
top: '5%'
},
legend: {
show: props.data?.options?.legend || false,
icon: 'circle',
top: '5%',
right: '5%',
itemWidth: 6,
itemGap: 20,
textStyle: {
color: '#fff'
}
},
tooltip: {
show: props.data?.options?.tooltip || false,
trigger: 'axis',
axisPointer: {
label: {
show: true,
backgroundColor: '#fff',
color: '#000',
borderColor: 'rgba(0,0,0,0)',
shadowColor: 'rgba(0,0,0,0)',
shadowOffsetY: 0
},
lineStyle: {
width: 0
}
},
backgroundColor: '#fff',
textStyle: {
color: '#000'
},
padding: [10, 10],
extraCssText: 'box-shadow: 1px 0 2px 0 rgba(163,163,163,0.5)'
},
radar: {
center: ['50%', '50%'],
radius: '70%',
startAngle: 90,
splitNumber: 4,
shape: 'circle',
splitArea: {
areaStyle: {
color: ['transparent']
}
},
axisLabel: {
show: false,
fontSize: 18,
color: '#fff',
fontStyle: 'normal',
fontWeight: 'normal'
},
axisLine: {
show: true,
lineStyle: {
color: 'white' //
}
},
splitLine: {
show: true,
lineStyle: {
color: 'white' //
}
},
indicator: [
{
name: '数据1',
max: 88
},
{
name: '数据2',
max: 88
},
{
name: '数据3',
max: 88
},
{
name: '数据4',
max: 88
},
{
name: '数据5',
max: 88
},
{
name: '数据6',
max: 88
},
{
name: '数据7',
max: 88
},
{
name: '数据8',
max: 88
}
]
},
series: [
{
name: '高一(1)班',
type: 'radar',
symbol: 'circle',
symbolSize: 10,
areaStyle: {
normal: {
color: 'rgba(245, 166, 35, 0.4)'
}
},
itemStyle: {
color: 'rgba(245, 166, 35, 1)',
borderColor: 'rgba(245, 166, 35, 0.3)',
borderWidth: 10
},
lineStyle: {
normal: {
type: 'dashed',
color: 'rgba(245, 166, 35, 1)',
width: 2
}
},
data: [[80, 50, 55, 80, 50, 80, 48, 43]]
},
{
name: '高一(2)班',
type: 'radar',
symbol: 'circle',
symbolSize: 10,
itemStyle: {
normal: {
color: 'rgba(19, 173, 255, 1)',
borderColor: 'rgba(19, 173, 255, 0.4)',
borderWidth: 10
}
},
areaStyle: {
normal: {
color: 'rgba(19, 173, 255, 0.5)'
}
},
lineStyle: {
normal: {
color: 'rgba(19, 173, 255, 1)',
width: 2,
type: 'dashed'
}
},
data: [[60, 60, 65, 60, 70, 40, 80, 63]]
}
]
};
let xData = [props.inputData?.x1 || []];
let yData = [props.inputData?.y1 || []];
console.log(chartOption);
let length = Math.min(...xData.map(e => e.length), ...yData.map(e => e.length));
let source = [['product', ...[props.data.options?.yNames?.[0] || '数量']]];
Array(length).fill(0).forEach((_, i) => {
let item = [];
xData.forEach(e => {
item.push(e[i]);
});
yData.forEach(e => {
item.push(e[i]);
});
source.push(item);
});
console.log(source);
return {
...chartOption,
dataset: {
source
}
};
};
onMounted(() => {
chart = echarts.init(chartRef.value, 'macarons', {
renderer: 'svg'
});
chart.setOption(getOption(), true);
});
watch(() => [JSON.parse(JSON.stringify(props.inputData)), JSON.parse(JSON.stringify(props.data.options))], (obj1, obj2) => {
if (JSON.stringify(obj1) !== JSON.stringify(obj2)) {
chart && chart.setOption(getOption(), true);
}
}, { deep: true, immediate: true });
watch(() => JSON.parse(JSON.stringify(props.dimensions)), (obj1, obj2) => {
if (JSON.stringify(obj1) !== JSON.stringify(obj2)) {
chart?.resize();
}
}, { deep: true, immediate: true });
const emit = defineEmits(['resize']);
const resize = (e) => {
chart.resize();
emit('resize', e, props.id);
};
</script>
<style scoped>
.custom-node {
width: 100%;
height: 100%;
}
</style>

@ -0,0 +1,64 @@
<template>
<div
:style="{width:props.dimensions.width+'px',height:props.dimensions.height+'px'}">
<NodeResizer color="#fff" v-if="!props.isView && !props.isHideHandle && props.selected"
@resize="resize" />
<div class="custom-node"
:style="{width:props.dimensions.width+'px',height:props.dimensions.height+'px',pointerEvents:props.isView?'auto': 'none'}">
<div style="width: 100%; height: 100%;"
:style="{backgroundColor:props.data.options.backgroundColor,border:props.data.options.isBorder? ` 1px solid ${props.data.options.borderColor}` :''}">
</div>
</div>
<Handle v-if="!props.isView" :id="`${props.id}.-t`" type="target" :position="Position.Left" />
</div>
</template>
<script setup>
import { defineEmits, defineProps, ref } from 'vue';
import { NodeResizer } from '@vue-flow/node-resizer';
import { Handle, Position } from '@vue-flow/core';
const props = defineProps({
isView: {
type: Boolean,
required: false
},
inputData: {
type: Object,
required: false
},
id: {
type: String,
required: true
},
isHideHandle: {
type: Boolean,
required: false
},
selected: {
type: Boolean,
required: false
},
data: {
type: Object,
required: true
},
dimensions: {
type: Object,
required: true
}
});
const emit = defineEmits(['resize']);
const resize = (e) => {
emit('resize', e, props.id);
};
</script>
<style scoped>
.custom-node {
position: absolute;
}
</style>

@ -53,16 +53,20 @@ const props = defineProps({
const convertData = () => {
const rule = {};
props.data.options.dataMap.forEach(item => {
rule[item.source] = item.target;
rule[item.target] = item.source;
});
console.log('props.inputData', props.inputData);
console.log('rule', rule);
let res = {};
Object.keys(props.inputData).forEach(item => {
if (Object.keys(rule).includes(item)) {
res[rule[item]] = props.inputData[item];
Object.keys(rule).forEach(item => {
if (Object.keys(props.inputData).includes(rule[item])) {
// res[rule[item]] = props.inputData[item];
res[item] = props.inputData[rule[item]];
} else {
res[item] = props.inputData[item];
// res[item] = props.inputData[item];
}
});
console.log('res', res);
props.data.outputData = res;
};
watch(() => JSON.parse(JSON.stringify(props.inputData)), (obj1, obj2) => {

@ -17,8 +17,27 @@ const getOption = (e) => {
return { title: '', yNames: [], gridTop: 30, gridLeft: 5, gridBottom: 10, gridRight: 10, xName: '', yName: '', tooltip:true, legend:true,backgroundColor:'rgba(180, 180, 180, 0.2)' };
} else if (e === 'curve' || e === 'multiCurves') {
return { title: '', yNames: [], gridTop: 30, gridLeft: 5, gridBottom: 10, gridRight: 10, xName: '', yName: '', tooltip:true, legend:true };
} else if (e === 'pie' || e === 'nightingaleRoseDiagram') {
return { title: '', yNames: [], tooltip:true, legend:true,label:true };
} else if (e === 'lineBar') {
return {
title: '',
yNames: [],
gridTop: 30,
gridLeft: 5,
gridBottom: 10,
gridRight: 10,
xName: '',
yName: '',
tooltip: true,
legend: true
};
} else if (e === 'radar') {
return {
title: '', yNames: [], gridTop: 30, gridLeft: 5, gridBottom: 10, gridRight: 10, tooltip: true, legend: true
};
} else if (e === 'pie' || e === 'nightingaleRoseDiagram' || e === 'annular') {
return { title: '', yNames: [], tooltip: true, legend: true, label: true };
} else if (e === 'dashboard') {
return { title: '', yNames: [], tooltip: true, legend: true, label: true };
} else if (e === 'customBoard') {
return { title: '', yNames: [] };
} else if (e === 'data') {
@ -56,6 +75,8 @@ const getOption = (e) => {
}
} else if (e === 'carousel') {
return { swiperOptions: {}, imageFit: 'contain', carouselImages: [] };
} else if (e === 'background') {
return { backgroundColor: '#fff', isBorder: true, borderColor: '#fff' };
} else if (e === 'digitalFlop') {
return {
field: '', number: 1111, backgroundColor: 'rgba(180, 180, 180, 0.2)', isBorder: true, borderColor: '#fff'
@ -65,7 +86,7 @@ const getOption = (e) => {
}
};
const getNodeSize = (e) => {
if (e === 'line' || e === 'multiLines' || e === 'bar' || e === 'multiBars' || e === 'curve' || e === 'multiCurves' || e === 'customBoard' || e === 'pie') {
if (e === 'line' || e === 'multiLines' || e === 'bar' || e === 'multiBars' || e === 'curve' || e === 'multiCurves' || e === 'customBoard' || e === 'pie' || e === 'annular' || e === 'dashboard' || e === 'radar') {
return { width: 300, height: 150 };
} else if (e === 'data' || e === 'customData') {
return { width: 150, height: 50 };

@ -77,12 +77,41 @@
<ScrollTableNode :isView="true" :inputData=getInputData(i.id) v-bind="i"></ScrollTableNode>
</template>
<template v-if="i.type === 'background'">
<BackgroundNode :isView="true" :inputData=getInputData(i.id) v-bind="i"></BackgroundNode>
</template>
<template v-if="i.type === 'annular'">
<AnnularNode :isView="true" :inputData=getInputData(i.id) v-bind="i"></AnnularNode>
</template>
<template v-if="i.type === 'dashboard'">
<DashboardNode :isView="true" :inputData=getInputData(i.id) v-bind="i"></DashboardNode>
</template>
<template v-if="i.type === 'radar'">
<RadarNode :isView="true" :inputData=getInputData(i.id) v-bind="i"></RadarNode>
</template>
<template v-if="i.type === 'lineBar'">
<LineBarNode :isView="true" :inputData=getInputData(i.id) v-bind="i"></LineBarNode>
</template>
<template v-if="i.type === 'digitalFlop'">
<DigitalFlopNode :isView="true" :inputData=getInputData(i.id) v-bind="i"></DigitalFlopNode>
</template>
</div>
</div>
</template>
<script setup lang="ts">
import { useRouter } from 'vue-router';
import AreaNode from './nodes/other/areaNode.vue';
import BackgroundNode from '@/views/boardGenerate/nodes/form/backgroundNode.vue';
import AnnularNode from '@/views/boardGenerate/nodes/board/annularNode.vue';
import DashboardNode from '@/views/boardGenerate/nodes/board/dashboardNode.vue';
import RadarNode from '@/views/boardGenerate/nodes/board/radarNode.vue';
import LineBarNode from '@/views/boardGenerate/nodes/board/lineBarNode.vue';
import DigitalFlopNode from '@/views/boardGenerate/nodes/form/digitalFlopNode.vue';
import TimeNode from './nodes/form/timeNode.vue';
import DataNode from './nodes/data/dataNode.vue';
import LineNode from './nodes/board/lineNode.vue';

Loading…
Cancel
Save