修改组态化
parent
320f56e77c
commit
86e7401aac
File diff suppressed because one or more lines are too long
@ -0,0 +1,248 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<input type="file" id="importFileInput" style="display: none;" accept=".json">
|
||||||
|
<el-button type="primary" @click="constructBoard">构造图表</el-button>
|
||||||
|
<el-button type="primary" @click="constructionData">构造数据源</el-button>
|
||||||
|
<el-dialog v-model="constructBoardFormVisible" title="构造图表" width="500">
|
||||||
|
<el-form :model="constructBoardForm">
|
||||||
|
<el-form-item label="图表配置">
|
||||||
|
<el-button type="primary" plain @click="importJson">导入json</el-button>
|
||||||
|
<el-input type="textarea" v-model="constructBoardForm.option" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<el-button @click="constructBoardFormVisible = false">关闭</el-button>
|
||||||
|
<el-button type="primary" @click="createBoard ">
|
||||||
|
创建
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<el-dialog v-model="constructionDataFormVisible" width="800" draggable>
|
||||||
|
<template #header>
|
||||||
|
<div style="width: 100%">
|
||||||
|
<span>构造数据源</span>
|
||||||
|
<div style="text-align:right;display: inline-block;width: calc(100% - 100px)">
|
||||||
|
<span>简易模式</span>
|
||||||
|
<el-switch v-model="isEasy" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-form :model="constructionDataForm">
|
||||||
|
<el-form-item label="数据名称" prop="name">
|
||||||
|
<el-input v-model="constructionDataForm.name" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="请求地址" prop="url">
|
||||||
|
<el-input v-model="constructionDataForm.url">
|
||||||
|
<template #prepend>
|
||||||
|
<el-select v-model="constructionDataForm.method" style="width: 100px">
|
||||||
|
<el-option label="get" value="get" />
|
||||||
|
<el-option label="post" value="post" />
|
||||||
|
<el-option label="socket" value="socket" />
|
||||||
|
</el-select>
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="请求数据">
|
||||||
|
<el-table :data="constructionDataForm.inputData" style="width: 100%">
|
||||||
|
<el-table-column label="字段名称" min-width="120">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-input v-model="scope.row.name" style="width: 100%" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="备注" min-width="120">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-input v-model="scope.row.remark" style="width: 100%" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="测试数据" min-width="120" v-if="isEasy">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-input v-model="scope.row.test" 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="constructionDataForm.inputData.splice(scope.$index, 1)">
|
||||||
|
删除
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<el-button style="width: 100%" @click="constructionDataForm.inputData.push({})">
|
||||||
|
添加字段
|
||||||
|
</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="输出数据">
|
||||||
|
<el-table :data="constructionDataForm.outputData" style="width: 100%">
|
||||||
|
<el-table-column label="字段名称" min-width="120">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-input v-model="scope.row.name" style="width: 100%" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="字段层级" min-width="120" v-if="!isEasy">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-input v-model="scope.row.tier" style="width: 100%" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="备注" min-width="120">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-input v-model="scope.row.remark" 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="constructionDataForm.outputData.splice(scope.$index, 1)">
|
||||||
|
删除
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<el-button style="width: 100%" @click="constructionDataForm.outputData.push({})">
|
||||||
|
添加字段
|
||||||
|
</el-button>
|
||||||
|
<el-button style="width: 100%;margin: 12px 0 0 0" v-if="isEasy"
|
||||||
|
@click="findTier">
|
||||||
|
查找
|
||||||
|
</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<el-button @click="constructionDataFormVisible = false">关闭</el-button>
|
||||||
|
<el-button type="primary" @click="createData ">
|
||||||
|
创建
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import axios from 'axios';
|
||||||
|
import request from '@/utils/request';
|
||||||
|
|
||||||
|
const comparisonTable = {
|
||||||
|
starttime: '开始时间',
|
||||||
|
time: '时间',
|
||||||
|
value: '值'
|
||||||
|
};
|
||||||
|
|
||||||
|
// 判断是否是json
|
||||||
|
function isJSON(str) {
|
||||||
|
if (typeof str === 'string') {
|
||||||
|
try {
|
||||||
|
JSON.parse(str);
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
ElMessage({
|
||||||
|
message: '格式错误',
|
||||||
|
type: 'warning'
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isEasy = ref(false);
|
||||||
|
const constructBoardForm = ref({});
|
||||||
|
const constructionDataForm = ref({ inputData: [], outputData: [] });
|
||||||
|
const constructBoardFormVisible = ref(false);
|
||||||
|
const constructionDataFormVisible = ref(false);
|
||||||
|
const constructBoard = () => {
|
||||||
|
constructBoardForm.value = {};
|
||||||
|
constructBoardFormVisible.value = true;
|
||||||
|
};
|
||||||
|
const createBoard = () => {
|
||||||
|
constructBoardFormVisible.value = false;
|
||||||
|
};
|
||||||
|
const constructionData = () => {
|
||||||
|
constructionDataForm.value = { inputData: [], outputData: [] };
|
||||||
|
constructionDataFormVisible.value = true;
|
||||||
|
};
|
||||||
|
const createData = () => {
|
||||||
|
constructionDataFormVisible.value = false;
|
||||||
|
let nowData = JSON.parse(localStorage.getItem('DATANODE') || '[]');
|
||||||
|
nowData.push(constructionDataForm.value);
|
||||||
|
localStorage.setItem('DATANODE', JSON.stringify(nowData));
|
||||||
|
};
|
||||||
|
const importJson = () => {
|
||||||
|
const fileInput = document.getElementById('importFileInput');
|
||||||
|
let listenFun = (e) => {
|
||||||
|
getFileText(e.target.files[0]);
|
||||||
|
};
|
||||||
|
fileInput.addEventListener('change', listenFun, true);
|
||||||
|
fileInput.click();
|
||||||
|
const getFileText = (file) => {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = function(e) {
|
||||||
|
const fileContent = e.target.result;
|
||||||
|
fileInput.removeEventListener('change', listenFun, true);
|
||||||
|
fileInput.value = '';
|
||||||
|
if (isJSON(fileContent)) {
|
||||||
|
constructBoardForm.value.option = fileContent;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
reader.readAsText(file);
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
const findTier = () => {
|
||||||
|
let params = {};
|
||||||
|
(constructionDataForm.value.inputData || []).forEach((item) => {
|
||||||
|
params[item.name] = item.test;
|
||||||
|
});
|
||||||
|
|
||||||
|
axios.request({
|
||||||
|
method: constructionDataForm.value.method,
|
||||||
|
url: constructionDataForm.value.url,
|
||||||
|
params: constructionDataForm.value.method === 'get' ? params : '',
|
||||||
|
data: constructionDataForm.value.method === 'post' ? params : ''
|
||||||
|
}).then(res => {
|
||||||
|
// request({
|
||||||
|
// method: constructionDataForm.value.method,
|
||||||
|
// url: constructionDataForm.value.url,
|
||||||
|
// params: constructionDataForm.value.method === 'get' ? params : '',
|
||||||
|
// data: constructionDataForm.value.method === 'post' ? params : ''
|
||||||
|
// }).then(res => {
|
||||||
|
let data = res.data;
|
||||||
|
if (data.data) {
|
||||||
|
Object.keys(data.data?.[0]).forEach(key => {
|
||||||
|
constructionDataForm.value.outputData.push({
|
||||||
|
name: key,
|
||||||
|
remark: comparisonTable[key],
|
||||||
|
tier: `data,map%${key}`
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else if (data.rows) {
|
||||||
|
Object.keys(data.rows?.[0]).forEach(key => {
|
||||||
|
constructionDataForm.value.outputData.push({
|
||||||
|
name: key,
|
||||||
|
remark: comparisonTable[key],
|
||||||
|
tier: `data,map%${key}`
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
let exclude = ['code'];
|
||||||
|
Object.keys(data).forEach(key => {
|
||||||
|
if (!exclude.includes(key.toLowerCase())) {
|
||||||
|
if (typeof data[key] === 'string' || typeof data[key] === 'string') {
|
||||||
|
constructionDataForm.value.outputData.push({
|
||||||
|
name: key,
|
||||||
|
remark: comparisonTable[key],
|
||||||
|
tier: `data,${key}`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
</style>
|
@ -0,0 +1,122 @@
|
|||||||
|
<template>
|
||||||
|
<div
|
||||||
|
:style="{width:props.dimensions.width+'px',height:props.dimensions.height+'px'}">
|
||||||
|
<NodeResizer color="#000" 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'}">
|
||||||
|
<el-button type="primary" :style="{width:props.dimensions.width +'px',height:props.dimensions.height+'px'}"
|
||||||
|
:icon="Connection">{{ props.data.customData.name }}
|
||||||
|
</el-button>
|
||||||
|
<span style="color:#fff">
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<Handle v-if="!props.isView" :id="`${props.id}.-t`" type="target" :position="Position.Left" />
|
||||||
|
<Handle v-if="!props.isView" :id="`${props.id}.-s`" type="source" :position="Position.Right" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { defineEmits, defineProps, ref } from 'vue';
|
||||||
|
import { NodeResizer } from '@vue-flow/node-resizer';
|
||||||
|
import { Connection } from '@element-plus/icons-vue';
|
||||||
|
import { Handle, Position } from '@vue-flow/core';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
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 anyFun = (data, fun, key) => {
|
||||||
|
switch (fun) {
|
||||||
|
case 'map':
|
||||||
|
return data.map(e => e[key]);
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const parseData = (data, rule) => {
|
||||||
|
let resData = data;
|
||||||
|
let step = rule.split(',');
|
||||||
|
step.forEach((item) => {
|
||||||
|
if (resData) {
|
||||||
|
let fun = item.split('%');
|
||||||
|
if (fun.length === 1) {
|
||||||
|
resData = resData[fun[0]];
|
||||||
|
}
|
||||||
|
if (fun.length === 2) {
|
||||||
|
resData = anyFun(resData, fun[0], fun[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return resData;
|
||||||
|
|
||||||
|
};
|
||||||
|
const getOutputData = () => {
|
||||||
|
let params = {};
|
||||||
|
(props.data.customData.inputData || []).forEach((item) => {
|
||||||
|
params[item.name] = props.inputData[item.name];
|
||||||
|
});
|
||||||
|
axios.request({
|
||||||
|
method: props.data.customData.method,
|
||||||
|
url: props.data.customData.url,
|
||||||
|
params: props.data.customData.method === 'get' ? params : '',
|
||||||
|
data: props.data.customData.method === 'post' ? params : ''
|
||||||
|
}).then(res => {
|
||||||
|
let output = {};
|
||||||
|
props.data.customData.outputData.forEach(item => {
|
||||||
|
output[item.name] = parseData(res.data, item.tier);
|
||||||
|
});
|
||||||
|
props.data.outputData = output;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getOutputData();
|
||||||
|
});
|
||||||
|
|
||||||
|
let interval = setInterval(() => {
|
||||||
|
getOutputData();
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
clearInterval(interval);
|
||||||
|
interval = null;
|
||||||
|
});
|
||||||
|
const emit = defineEmits(['resize']);
|
||||||
|
const resize = (e) => {
|
||||||
|
emit('resize', e, props.id);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
.custom-node {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
@ -0,0 +1,84 @@
|
|||||||
|
<template>
|
||||||
|
<div
|
||||||
|
:style="{width:props.dimensions.width+'px',height:props.dimensions.height+'px'}">
|
||||||
|
<NodeResizer color="#000" 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'}">
|
||||||
|
<el-button type="primary" :style="{width:props.dimensions.width +'px',height:props.dimensions.height+'px'}"
|
||||||
|
:icon="Refresh">数据映射
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
<Handle v-if="!props.isView" :id="`${props.id}.-t`" type="target" :position="Position.Left" />
|
||||||
|
<Handle v-if="!props.isView" :id="`${props.id}.-s`" type="source" :position="Position.Right" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { defineEmits, defineProps, ref } from 'vue';
|
||||||
|
import { NodeResizer } from '@vue-flow/node-resizer';
|
||||||
|
import { Refresh } from '@element-plus/icons-vue';
|
||||||
|
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 convertData = () => {
|
||||||
|
const rule = {};
|
||||||
|
props.data.options.dataMap.forEach(item => {
|
||||||
|
rule[item.source] = item.target;
|
||||||
|
});
|
||||||
|
let res = {};
|
||||||
|
Object.keys(props.inputData).forEach(item => {
|
||||||
|
if (Object.keys(rule).includes(item)) {
|
||||||
|
res[rule[item]] = props.inputData[item];
|
||||||
|
} else {
|
||||||
|
res[item] = props.inputData[item];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
props.data.outputData = res;
|
||||||
|
};
|
||||||
|
watch(() => props.inputData, (obj1, obj2) => {
|
||||||
|
if (JSON.stringify(obj1) !== JSON.stringify(obj2)) {
|
||||||
|
convertData();
|
||||||
|
}
|
||||||
|
}, { deep: true, immediate: true });
|
||||||
|
const emit = defineEmits(['resize']);
|
||||||
|
const resize = (e) => {
|
||||||
|
emit('resize', e, props.id);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
.custom-node {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
Loading…
Reference in New Issue