Browse Source

提交代码

master
肖正 5 months ago
parent
commit
98ac38e38c
  1. 46
      src/views/pages/regulatory/customNode.vue
  2. 408
      src/views/pages/regulatory/index.vue
  3. 2
      src/views/system/equipment/index.vue

46
src/views/pages/regulatory/customNode.vue

@ -0,0 +1,46 @@
<template>
<div class="custom-node">
<div class="node-title">{{props?.node?.data?.name}}</div>
<div class="node-content">{{props?.node?.label}}</div>
</div>
</template>
<script lang="ts" setup>
import { onMounted } from 'vue';
const props = defineProps({
node: Object,
});
onMounted(async () => {
// console.log(8888, props.node);
});
</script>
<style lang="scss" scoped>
.custom-node {
border: 1px solid transparent;
// padding: 8px;
border-radius: 3px;
display: flex;
flex-direction: column;
justify-content: center;
width: 150px;
}
.node-title {
font-weight: bold;
background-color: orange;
font-size: 13px;
padding: 2px 10px;
// margin: -1px -1px 0 -1px;
border-top-left-radius: 3px;
border-top-right-radius: 3px;
}
.node-content {
padding-top: 4px;
padding: 3px 10px;
font-size: 12px;
background-color: #f2f2f2;
border-bottom-left-radius: 3px;
border-bottom-right-radius: 3px;
}
</style>

408
src/views/pages/regulatory/index.vue

@ -11,27 +11,14 @@
</span> </span>
</template> </template>
<el-collapse v-model="collapseActiveNames"> <el-collapse v-model="collapseActiveNames">
<el-collapse-item title="Consistency" name="1"> <el-collapse-item :title="item.equipmentName" v-for="(item, i) in state.equipmentData" :key="item.id" :name="i + 1 + ''">
<ul class="el-collapse"> <ul class="el-collapse">
<li class="container-widget-item"> <li class="container-widget-item" v-for="(val, j) in item.taskChainList" :key="val.id" @click="chainClick(i, j)">
<el-icon :size="17" style="color: #409eff;vertical-align: middle;margin: 0 5px;"><Grid /></el-icon> <el-icon :size="17" style="color: #409eff;vertical-align: middle;margin: 0 5px;"><Grid /></el-icon>
<span>skadhjf</span> <span>{{val.name}}</span>
</li> </li>
<li class="container-widget-item"> <li v-if="item.taskChainList.length < 1" style="position: relative;">
<el-icon :size="17" style="color: #409eff;vertical-align: middle;margin: 0 5px;"><Grid /></el-icon> <div class="no-widget-hint">该设备暂无任务链</div>
<span>skadhjf</span>
</li>
<li class="container-widget-item">
<el-icon :size="17" style="color: #409eff;vertical-align: middle;margin: 0 5px;"><Grid /></el-icon>
<span>skadhjf</span>
</li>
<li class="container-widget-item">
<el-icon :size="17" style="color: #409eff;vertical-align: middle;margin: 0 5px;"><Grid /></el-icon>
<span>skadhjf</span>
</li>
<li class="container-widget-item">
<el-icon :size="17" style="color: #409eff;vertical-align: middle;margin: 0 5px;"><Grid /></el-icon>
<span>skadhjf</span>
</li> </li>
</ul> </ul>
</el-collapse-item> </el-collapse-item>
@ -40,34 +27,41 @@
</el-tabs> </el-tabs>
</div> </div>
<div class="fx-box" id="fx-box-id01" v-loading="state.loading"> <div class="fx-box" id="fx-box-id01" v-loading="state.loading">
<div class="box-header"></div> <div class="box-header">
<el-icon style="cursor: pointer;" @click="fitView" size="18"><Aim /></el-icon>
</div>
<div class="fx-content"> <div class="fx-content">
<div class="no-widget-hint" v-if="!state.taskChainList.length">请从左侧列表中选择组件.</div> <!-- <div class="no-widget-hint" v-if="!state.taskChainList.length">请从左侧列表中选择组件.</div> -->
<!-- <div v-for="(item, i) in state.taskChainList" ref="capture" :key="i" class="img-box"
:class="{block: item['姓名'].length > 3, break: i%2 == 1, marginTop: i%2 == 0,left3: item['姓名'].length == 3}">
<div class="text">
<div class="name-box">
<div class="name">asdf</div>
<span class="pinying">{{item['拼音']}}</span>
</div>
<div class="aprt" v-html="item['二级部门'].replace('*','<br>')"></div>
</div>
</div> -->
<!-- <el-row class="mb-4">
<el-button type="primary" @click="resetTransform">重置</el-button>
<el-button type="primary" @click="updatePos">修改属性</el-button>
<el-button type="primary" @click="toggleclass">修改样式</el-button>
<el-button type="primary" @click="logToObject">查看属性</el-button>
</el-row> -->
<VueFlow fit-view-on-init class="my-flow" v-model="elements"> <VueFlow fit-view-on-init class="my-flow" v-model="elements" @nodeClick="nodeClickHandler" disable>
<Background /> <Background />
<!-- <Panel :position="PanelPosition.TopRight"></Panel> --> <!-- <Panel :position="PanelPosition.TopRight"></Panel> -->
<!-- <Controls /> --> <!-- <Controls /> -->
<template #node-custom="props">
<CustomNode :node="props" />
</template>
</VueFlow> </VueFlow>
</div> </div>
</div> </div>
<div class="fx-east"></div> <div class="fx-east">
<el-tabs v-model="state.activeSet" class="demo-tabs">
<el-tab-pane name="first">
<template #label>
<span class="custom-tabs-label">
<el-icon style="vertical-align: middle;margin: 0 5px;"><calendar /></el-icon>
<span>属性设置</span>
</span>
</template>
<el-divider content-position="left">层级设置</el-divider>
<el-button style="margin-left: 10px;" type="primary" @click="leaveSet(-1)">提升</el-button>
<el-button type="primary" @click="leaveSet(1)">下降</el-button>
<el-divider content-position="left">是否 await</el-divider>
<el-switch @change="changeSwitch" style="margin-left: 10px;"
v-model="isAwait" size="large"
/>
</el-tab-pane>
</el-tabs>
</div>
</div> </div>
</template> </template>
@ -76,35 +70,37 @@ import '@vue-flow/core/dist/style.css';
/* import the default theme (optional) */ /* import the default theme (optional) */
import '@vue-flow/core/dist/theme-default.css'; import '@vue-flow/core/dist/theme-default.css';
import { Background, Panel, PanelPosition, Controls } from '@vue-flow/additional-components' import { Background, Panel, Controls } from '@vue-flow/additional-components'
import { VueFlow, useVueFlow } from '@vue-flow/core' import { VueFlow, useVueFlow } from '@vue-flow/core'
import { onMounted, reactive, ref } from 'vue'; import { onMounted, reactive, ref } from 'vue';
import { Calendar, Grid } from '@element-plus/icons-vue' import { Calendar, Grid, Aim } from '@element-plus/icons-vue'
import { ElMessageBox, ElMessage } from 'element-plus'; import { ElMessageBox, ElMessage } from 'element-plus';
import { SysMenu } from '/@/api-services/models'; import CustomNode from './customNode.vue'
import { getEquipmentList, del } from '/@/api/equipment'; import { getEquipmentList, del } from '/@/api/equipment';
import { Session } from '/@/utils/storage'; import { Session } from '/@/utils/storage';
const { nodes, addNodes, updateEdge, removeEdges, getElements, getNode, addEdges, fitView, updateNode, edges } = useVueFlow()
const data = [ const data = [
{ id: '1', type: 'process', label: 'Node 1', position: { x: 250, y: 5 }, background: '#42B983' }, // { id: '1', type: 'process', label: 'Node 1', position: { x: 250, y: 5 }, background: '#42B983' },
{ id: '2', label: 'Node 2', position: { x: 100, y: 100 } }, // { id: '2', label: 'Node 2', position: { x: 100, y: 100 } },
{ id: '3', label: 'Node 3', position: { x: 400, y: 100 } }, // { id: '3', label: 'Node 3', position: { x: 400, y: 100 } },
{ id: '4', label: 'Node 4', position: { x: 400, y: 200 } }, // { id: '4', label: 'Node 4', position: { x: 400, y: 200 } },
{ id: '5', label: 'Node 5', position: { x: 100, y: 200 } }, // { id: '5', label: 'Node 5', position: { x: 100, y: 200 } },
{ id: '6', label: 'Node 6', position: { x: 400, y: 200 } }, // { id: '6', label: 'Node 6', position: { x: 400, y: 200 } },
{ id: 'e1-2', source: '1', target: '2', type: 'animation' }, // { id: 'e1-2', source: '1', target: '2', type: 'animation' },
{ id: 'e1-3', source: '1', target: '3', type: 'edgeType' }, // { id: 'e1-3', source: '1', target: '3', type: 'edgeType' },
{ id: 'e1-4', source: '5', target: '6', type: 'edgeType' }, // { id: 'e1-4', source: '5', target: '6', type: 'edgeType' },
] ]
let elements = ref(data) let elements = ref(data)
const isHidden = ref(false)
const collapseActiveNames = ref<string[]>(['1', '2', '3']); const collapseActiveNames = ref<string[]>(['1', '2', '3']);
const isAwait = ref(false);
// const addEquipmentRef = ref<InstanceType<typeof AddEquipment>>(); // const addEquipmentRef = ref<InstanceType<typeof AddEquipment>>();
const state = reactive({ const state = reactive({
loading: false, loading: false,
activeName: 'first', activeName: 'first',
equipmentData: [] as Array<SysMenu>, activeSet: 'first',
equipmentData: [] as Array<any>,
taskChainList: [ taskChainList: [
] as any, ] as any,
orgData: [] as any, orgData: [] as any,
@ -126,40 +122,174 @@ onMounted(async () => {
state.queryParams.position = state.orgData[0]?.code || ''; state.queryParams.position = state.orgData[0]?.code || '';
handleQuery(); handleQuery();
}); });
// watch: { const nodeClickHandler = () => {
// isHidden: { console.log(nodes.value, edges.value)
// immediate: false, }
// handler: function () {
// nodes.value.forEach((n) => (n.hidden = isHidden.value))
// edges.value.forEach((e) => (e.hidden = isHidden.value))
// }
// }
// }
const onPaneReady = (({ fitView }) => { // await
fitView() const changeSwitch = () => {
}) var node = nodes.value.find((el) => el.selected);
// const onNodeDragStop((e) => console.log('drag stop', e)) if (!node) {
// const onConnect((params) => addEdges([params])) ElMessage.warning('请先选择一个节点');
return;
}
var nexts = nodes.value.filter((el) => el.data.level === node.data.level + 1);
if (nexts?.length < 1 && isAwait.value) {
ElMessage.warning('已是最后一个节点,无需等待');
isAwait.value = false;
return;
}
if (isAwait.value) {
nexts.forEach((next) => {
let edge = edges.value.find((el) => el.source === node.id && el.target === next.id);
const len = edges.value.length;
if (!edge) {
const newEdge = {
id: parseInt(edges.value[len - 1].id.split('_')[0]) + 1 + '_edge',
source: node.id,
label: 'await',
target: next.id,
labelStyle: { fill: 'red', fontSize: 12},
}
addEdges([newEdge]);
}
})
} else {
edges.value.forEach((el) => {
if (el.source === node.id) {
removeEdges(el.id);
}
})
}
}
//
const chainClick = (i, j) => {
const len = nodes.value.length;
const nodeId = (len + 1).toString()+'_add';
const equipment = state.equipmentData[i];
const level = len > 0 ? nodes.value[len - 1].data.level + 1 : 1;
const newNode = {
id: nodeId,
label: equipment.taskChainList[j]?.name,
// name: equipment.equipmentName,
type:'custom',
position: { x: 250, y: 120 * level },
data:{...JSON.parse(JSON.stringify(equipment.taskChainList[j])), level, ...{name: equipment.equipmentName,}}
}
const updatePos = () => { addNodes([newNode])
nodes.value.forEach((el) => { if (len > 0) {
el.position = { const newEdge = {
x: Math.random() * 400, id: (len + 1).toString() + '_edge',
y: Math.random() * 400, source: nodes.value[len - 1].id,
// type: img_params.value.edge.type,
label: 'await',
target: nodeId,
// updatable: img_params.value.edge.updatable,
// events: { click: clickadd },
// labelBgPadding: [8, 4],
labelStyle: { fill: 'red', fontSize: 12},
// labelBgBorderRadius: 4,
// labelBgStyle: { fill: '#10b981', color: '#fff', fillOpacity: 1 },
} }
}) addEdges([newEdge]);
};
const logToObject = () => { }
ElMessage.info(JSON.stringify(toObject())); setTimeout(() => {
}; fitView()
const resetTransform = () => { }, 200)
elements.value = data
setTransform({ x: 0, y: 0, zoom: 1 })
}; };
const toggleclass = () => nodes.value.forEach((el) => (el.class = el.class === 'node-light' ? 'node-dark' : 'node-light'))
const leaveSet = (i) => {
var node = nodes.value.find((el) => el.selected);
if (!node) {
ElMessage.warning('请先选择一个节点');
return;
}
if (node.data.level === 1 && i < 0) {
ElMessage.warning('已是第一个节点,无法上移');
return;
}
if (nodes.value.length === node.data.level && i > 0) {
ElMessage.warning('已是最后一个节点,无法下移');
return;
}
node.data.level += i;
//
nodes.value.sort((a, b) => a.data.level - b.data.level);
//
// debugger;
for (let j = 0; j < nodes.value.length; j++) {
let item = nodes.value[j];
//
if (j > 0 && item.data.level !== nodes.value[j - 1].data.level && item.data.level !== nodes.value[j-1].data.level + 1) {
// 1
for (let i = j; i < nodes.value.length; i++) {
nodes.value[i].data.level--;
}
}
//
if (i > 0 &&node.id !==item.id && node.data.level <= item.data.level) {
item.data.level++;
}
}
updateNodes();
updateEdges(i, node);
}
const updateNodes = () => {
const width = 180;
var frequencyMap = {};
const len = nodes.value.length;
// debugger;
for (let j = 0; j < len; j++) {
if (!frequencyMap[nodes.value[j].data.level]) {
frequencyMap[nodes.value[j].data.level] = 1
} else {
frequencyMap[nodes.value[j].data.level]++;
}
}
// value
let maxFrequency = 0;
for (const value in frequencyMap) {
if (frequencyMap[value] > maxFrequency) {
maxFrequency = frequencyMap[value];
}
}
var centX = width * maxFrequency / 2 + 100;
var setMap = {};
nodes.value.forEach((el) => {
if (!setMap[el.data.level]) {
setMap[el.data.level] = 0;
}
el.position = { x: centX - frequencyMap[el.data.level] * width / 2 + setMap[el.data.level] * width, y: 120 * el.data.level }
setMap[el.data.level]++;
updateNode(el.id, el);
})
setTimeout(() => {
fitView()
}, 300)
}
const updateEdges = (i, node) => {
const len = edges.value.length;
for (let i = 0; i < len; i++) {
if (edges.value[i]?.target === node.id) {
removeEdges(edges.value[i].id);
}
}
let index = nodes.value.findIndex((el) => el.id === node.id);
if (index > 0 && i > 0) {
const newEdge = {
id: parseInt(edges.value[len - 1].id.split('_')[0]) + 1 + '_edge',
source: nodes.value[index - 1].id,
label: 'await',
target: node.id,
labelStyle: { fill: 'red', fontSize: 12},
}
addEdges([newEdge]);
}
}
// //
const handleQuery = async () => { const handleQuery = async () => {
@ -240,6 +370,9 @@ const delMenu = (row: any) => {
overflow-y: auto; overflow-y: auto;
// padding: 0 20px; // padding: 0 20px;
box-sizing: border-box; box-sizing: border-box;
text-align: right;
line-height: 40px;
padding: 0 40px;
} }
ul.el-collapse { ul.el-collapse {
padding-left: 10px; padding-left: 10px;
@ -266,71 +399,13 @@ ul.el-collapse {
.left-content { .left-content {
padding-left: 20px; padding-left: 20px;
} }
.img-box {
position: relative;
margin: 0 auto;
font-family: 'MiSans-Regular';
color: #000;
width: 850.4px;
height: 472.8px;
background: url('../assets/bg.png') no-repeat;
background-size: 100% 100%;
padding-top: 140px;
padding-left: 80px;
box-sizing: border-box;
.text {
position: relative;
}
.name-box {
display: inline-block;
width: 45%;
vertical-align: middle;
.name {
font-size: 100px;
font-family: 'MiSans-Demibold';
font-weight: bold;
}
.pinying {
font-size: 50px;
}
}
.aprt {
position: absolute;
top: 28px;
left: 45%;
font-size: 70px;
width: 52%;
&.width5 {
width: 50%;
}
&.topLine {
top: 9px;
padding-left: 20px;
}
}
&.left3 .aprt {
left: 47%;
}
&.break {
page-break-after:always
}
&.block {
padding-top: 100px;
.name-box {
width: 100%;
}
.aprt {
position: static;
width: 100%;
margin-top: 40px;
font-size: 56px;
padding-left: 0;
}
}
}
</style> </style>
<style lang="scss"> <style lang="scss">
.vue-flow__node-default.selected, .vue-flow__node-custom.selected .custom-node {
border: 1px solid red;
box-shadow: 0 0 0 0.5px red;
}
.el-scrollbar__view { .el-scrollbar__view {
height: 100%; height: 100%;
} }
@ -378,6 +453,7 @@ ul.el-collapse {
box-shadow: 0 0 4px 0 rgba(0, 0, 0, .1); box-shadow: 0 0 4px 0 rgba(0, 0, 0, .1);
margin: 10px 10px 0 10px; margin: 10px 10px 0 10px;
overflow-y: auto; overflow-y: auto;
position: relative;
} }
.phone-box { .phone-box {
width: 320px; width: 320px;
@ -420,49 +496,5 @@ ul.el-collapse {
box-shadow: 0 0 4px 0 rgba(0, 0, 0, .1); box-shadow: 0 0 4px 0 rgba(0, 0, 0, .1);
border-left: solid 1px #e0e0e0; border-left: solid 1px #e0e0e0;
} }
.pagelist-item {
padding: 10px 5px;
transition: all .5s ease;
border-bottom: 1px solid #f3f3f3;
position: relative;
&.active {
background: rgb(233,240,254);
}
.icon-close {
position: absolute;
top: 0;
right: 0;
bottom: 0;
width: 46px;
line-height: 46px;
font-size: 15px;
text-align: center;
color: #fff;
cursor: pointer;
// background-image: linear-gradient(to right, #fff , #666);
background: red;
transition: all .5s ease;
opacity: 0;
}
&:hover {
background: #f1f1f1;
.icon-close {
opacity: 1;
}
}
.time {
font-size: 12px;
float: right;
line-height: 25px;
}
.title {
display: inline-block;
width: 140px;
font-size: 14px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
} }
</style> </style>

2
src/views/system/equipment/index.vue

@ -87,7 +87,7 @@ import { Session } from '/@/utils/storage';
const addEquipmentRef = ref<InstanceType<typeof AddEquipment>>(); const addEquipmentRef = ref<InstanceType<typeof AddEquipment>>();
const state = reactive({ const state = reactive({
loading: false, loading: false,
equipmentData: [] as Array<SysMenu>, equipmentData: [] as Array<any>,
equipmentType: [] as any, equipmentType: [] as any,
orgData: [] as any, orgData: [] as any,
queryParams: { queryParams: {

Loading…
Cancel
Save