|
|
|
|
<template>
|
|
|
|
|
<div class="left-tree-container">
|
|
|
|
|
<j-input placeholder="名称" v-model:value="searchValue" @pressEnter="search" @change="searchChange">
|
|
|
|
|
<template #suffix>
|
|
|
|
|
<AIcon type="SearchOutlined" @click="search" />
|
|
|
|
|
</template>
|
|
|
|
|
</j-input>
|
|
|
|
|
<div v-if="admin" class="add-btn">
|
|
|
|
|
|
|
|
|
|
<j-row :style="{ marginTop: '10px' }">
|
|
|
|
|
<j-button type="primary" @click="visible = true">
|
|
|
|
|
新增站点
|
|
|
|
|
</j-button>
|
|
|
|
|
</j-row>
|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
<div class="tree">
|
|
|
|
|
<j-spin :spinning='loading'>
|
|
|
|
|
<j-tree :tree-data="treeData" v-if="treeData.length" draggable @dragstart="dragstart"
|
|
|
|
|
:fieldNames="{ title: 'nodeName', key: 'id', children: 'children' }" blockNode
|
|
|
|
|
:default-expanded-keys="defaultExpandedKeys" :showLine="{ showLeafIcon: false }" :showIcon="true">
|
|
|
|
|
<template #title="{ nodeName, data, level, type, positionX, parentId, nodeType }">
|
|
|
|
|
<div v-if="selectId === data.id">
|
|
|
|
|
<j-input v-model:value="addName" @blur="() => saveGroup(data)" ref="inputRef"
|
|
|
|
|
:maxlength="64"></j-input>
|
|
|
|
|
</div>
|
|
|
|
|
<span v-else class='department-tree-item-content'>
|
|
|
|
|
<span class='title' :style="{
|
|
|
|
|
width: nodeType == '1' ? '80px' : '110px',
|
|
|
|
|
}">
|
|
|
|
|
<j-ellipsis>
|
|
|
|
|
<AIcon v-if="nodeType == '1'" type="HeartFilled" />
|
|
|
|
|
{{ nodeName }}
|
|
|
|
|
</j-ellipsis>
|
|
|
|
|
</span>
|
|
|
|
|
<span class="func-btns" :style="{
|
|
|
|
|
width: nodeType == '0' ? '120px' : '100px',
|
|
|
|
|
}" @click="(e) => e.stopPropagation()">
|
|
|
|
|
<PermissionButton type="link" :tooltip="{ title: '编辑' }" @click="editGroup(data)">
|
|
|
|
|
<AIcon type="EditOutlined" />
|
|
|
|
|
</PermissionButton>
|
|
|
|
|
<PermissionButton v-if="nodeType === '0' || parentId === '0'" type="link"
|
|
|
|
|
:tooltip="{ title: '组内监测点绑定设备' }" @click="openBindModel(data)">
|
|
|
|
|
<AIcon type="ApiOutlined" />
|
|
|
|
|
</PermissionButton>
|
|
|
|
|
<PermissionButton v-if="nodeType === '0' || parentId === '0'" type="link"
|
|
|
|
|
:tooltip="{ title: '新增子站' }" @click="addGroup(data, '0')">
|
|
|
|
|
<AIcon type="PlusOutlined" />
|
|
|
|
|
</PermissionButton>
|
|
|
|
|
<PermissionButton v-if="nodeType === '0' || parentId === '0'" type="link"
|
|
|
|
|
:tooltip="{ title: '新增子监测点' }" @click="addGroup(data, '1')">
|
|
|
|
|
<AIcon type="PlusCircleOutlined" />
|
|
|
|
|
</PermissionButton>
|
|
|
|
|
<PermissionButton type="link" :tooltip="{ title: '删除' }" :popConfirm="{
|
|
|
|
|
title: `确定要删除吗`,
|
|
|
|
|
onConfirm: () => { deleteGroup(data.id) },
|
|
|
|
|
}">
|
|
|
|
|
<AIcon type="DeleteOutlined" />
|
|
|
|
|
</PermissionButton>
|
|
|
|
|
<PermissionButton v-if="nodeType === '1'" type="link" :tooltip="{ title: '移除' }">
|
|
|
|
|
<AIcon type="CloseOutlined" />
|
|
|
|
|
</PermissionButton>
|
|
|
|
|
</span>
|
|
|
|
|
</span>
|
|
|
|
|
</template>
|
|
|
|
|
</j-tree>
|
|
|
|
|
<j-empty v-else description="暂无数据" />
|
|
|
|
|
</j-spin>
|
|
|
|
|
</div>
|
|
|
|
|
<j-row :gutter="10">
|
|
|
|
|
<j-col :span="12">
|
|
|
|
|
<j-button type="primary" @click="visible = true">
|
|
|
|
|
导入站点
|
|
|
|
|
</j-button>
|
|
|
|
|
</j-col>
|
|
|
|
|
<j-col :span="12">
|
|
|
|
|
<j-button type="primary" @click="visible = true">
|
|
|
|
|
导出站点
|
|
|
|
|
</j-button>
|
|
|
|
|
</j-col>
|
|
|
|
|
</j-row>
|
|
|
|
|
<AddGroup v-if="visible" :logicId="logicId" @close="visible = false" @save="() => { emit('getMonitorList') }" />
|
|
|
|
|
<BindDevice v-if="bindVisible" :checkNodeData="checkNodeData" @close="bindVisible = false"
|
|
|
|
|
@save="() => { emit('getMonitorList') }" />
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script lang="ts" setup>
|
|
|
|
|
import { onlyMessage } from '@/utils/comm';
|
|
|
|
|
import { useUserInfo } from '@/store/userInfo';
|
|
|
|
|
import { storeToRefs } from 'pinia';
|
|
|
|
|
import { filterTreeItem } from '@/utils/comm'
|
|
|
|
|
import { addMonitor, editMonitor, deleteMonitor } from '@/api/monitor';
|
|
|
|
|
import { randomString } from '@/utils/utils';
|
|
|
|
|
import AddGroup from './AddGroup.vue';
|
|
|
|
|
import BindDevice from './BindDevice.vue';
|
|
|
|
|
|
|
|
|
|
const visible = ref<boolean>(false);
|
|
|
|
|
const bindVisible = ref<boolean>(false);
|
|
|
|
|
const loading = ref<boolean>(false); // 数据加载状态
|
|
|
|
|
const emit = defineEmits(['selectData', 'getMonitorList']);
|
|
|
|
|
const treeData = ref([]);
|
|
|
|
|
const checkNodeData = ref([]);
|
|
|
|
|
const props = defineProps({
|
|
|
|
|
listData: {
|
|
|
|
|
type: Array,
|
|
|
|
|
default: []
|
|
|
|
|
},
|
|
|
|
|
logicId: {
|
|
|
|
|
type: String,
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
const userInfoStore = useUserInfo();
|
|
|
|
|
const { userInfos } = storeToRefs(userInfoStore);
|
|
|
|
|
const admin = computed(() => {
|
|
|
|
|
return userInfos.value?.username === 'admin';
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const searchValue = ref();
|
|
|
|
|
const inputRef = ref();
|
|
|
|
|
const addName = ref();
|
|
|
|
|
const selectId = ref();
|
|
|
|
|
const defaultExpandedKeys = ref<(number | string)[]>([]);
|
|
|
|
|
|
|
|
|
|
const isMonitorList = (node) => {
|
|
|
|
|
if (!node) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
const result = [];
|
|
|
|
|
const recurse = (arr) => {
|
|
|
|
|
arr.forEach(item => {
|
|
|
|
|
// 如果 nodeType 等于 1,直接添加到结果中
|
|
|
|
|
if (item.nodeType == 1) {
|
|
|
|
|
result.push(item);
|
|
|
|
|
} else if (item.children && Array.isArray(item.children)) {
|
|
|
|
|
// 如果 nodeType 等于 0,并且存在 children,则递归处理
|
|
|
|
|
recurse(item.children);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
recurse(node); // 开始递归处理
|
|
|
|
|
return result.length
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const openBindModel = (node) => {
|
|
|
|
|
if (isMonitorList(node?.children)) {
|
|
|
|
|
checkNodeData.value = node;
|
|
|
|
|
bindVisible.value = true;
|
|
|
|
|
} else {
|
|
|
|
|
onlyMessage('该组下无监测点')
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//获取全部id
|
|
|
|
|
const getTreeId = <T>(treeNode: T[]) => {
|
|
|
|
|
let result: any[] = [];
|
|
|
|
|
const traverse = (node: any) => {
|
|
|
|
|
result?.push(node.id)
|
|
|
|
|
if (node.children && Array.isArray(node.children)) {
|
|
|
|
|
node.children.forEach((child: any) => traverse(child))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
treeNode?.forEach((child: any) => traverse(child))
|
|
|
|
|
return result
|
|
|
|
|
}
|
|
|
|
|
watch(() => props.listData, (newValue) => {
|
|
|
|
|
treeData.value = newValue;
|
|
|
|
|
defaultExpandedKeys.value = getTreeId(treeData.value)
|
|
|
|
|
}, { deep: true, immediate: true })
|
|
|
|
|
const openGroup = () => {
|
|
|
|
|
visible.value = false;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const dragstart = ({ event, node }: { event: DragEvent, node: any }) => {
|
|
|
|
|
//event.preventDefault()
|
|
|
|
|
event.dataTransfer?.setData('monitorData', JSON.stringify(node.dataRef)); // 使用 text/plain 类型存储节点信息
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const queryGroup = async (select?: Boolean, searchName?: string) => {
|
|
|
|
|
// const params = searchName
|
|
|
|
|
// ? {
|
|
|
|
|
// sorts: [{ name: 'createTime', order: 'desc' }],
|
|
|
|
|
// terms: [
|
|
|
|
|
// {
|
|
|
|
|
// terms: [
|
|
|
|
|
// {
|
|
|
|
|
// value: '%' + searchName + '%',
|
|
|
|
|
// termType: 'like',
|
|
|
|
|
// column: 'name',
|
|
|
|
|
// },
|
|
|
|
|
// ],
|
|
|
|
|
// },
|
|
|
|
|
// ],
|
|
|
|
|
// }
|
|
|
|
|
// : { sorts: [{ name: 'createTime', order: 'desc' }] };
|
|
|
|
|
// const req: any = await queryRoleGroup(params);
|
|
|
|
|
// if (req.status === 200) {
|
|
|
|
|
// listData.value[0].children = req.result;
|
|
|
|
|
// if (req.result[req.result.length - 1].id === 'default_group') {
|
|
|
|
|
// req.result.unshift(req.result[req.result.length - 1]);
|
|
|
|
|
// req.result.pop();
|
|
|
|
|
// }
|
|
|
|
|
// // if(req.result.length && select){
|
|
|
|
|
// // selectGroup(req.result[0].id)
|
|
|
|
|
// // }
|
|
|
|
|
// }
|
|
|
|
|
};
|
|
|
|
|
const addGroup = async (data: any, nodeType: any) => {
|
|
|
|
|
|
|
|
|
|
addName.value = '';
|
|
|
|
|
const newId = randomString();
|
|
|
|
|
if (!data.children) {
|
|
|
|
|
data.children = []
|
|
|
|
|
};
|
|
|
|
|
data.children?.splice(1, 0, {
|
|
|
|
|
isNewChild: true,
|
|
|
|
|
nodeName: '',
|
|
|
|
|
logicId: props.logicId,
|
|
|
|
|
nodeType,
|
|
|
|
|
id: newId,
|
|
|
|
|
parentId: data.id,
|
|
|
|
|
});
|
|
|
|
|
treeData.value = [...treeData.value]
|
|
|
|
|
selectId.value = newId;
|
|
|
|
|
defaultExpandedKeys.value = getTreeId(treeData.value)
|
|
|
|
|
await nextTick(() => {
|
|
|
|
|
inputRef.value.focus();
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
const saveGroup = async (data: any) => {
|
|
|
|
|
|
|
|
|
|
if (data.nodeName !== addName.value) {
|
|
|
|
|
const saveData = {
|
|
|
|
|
...data,
|
|
|
|
|
nodeName: addName.value,
|
|
|
|
|
};
|
|
|
|
|
if (data.isNewChild) {
|
|
|
|
|
delete data.id;
|
|
|
|
|
}
|
|
|
|
|
const res = data.isNewChild ? await addMonitor(saveData) : await editMonitor(saveData);
|
|
|
|
|
if (res.status === 200) {
|
|
|
|
|
onlyMessage('操作成功!');
|
|
|
|
|
emit('getMonitorList');
|
|
|
|
|
} else {
|
|
|
|
|
onlyMessage('操作失败!');
|
|
|
|
|
}
|
|
|
|
|
} else if (data.isNewChild) {
|
|
|
|
|
const removeChild = (child) => {
|
|
|
|
|
child.forEach((item, index) => {
|
|
|
|
|
if (item.id == data.id) {
|
|
|
|
|
child.splice(index, 1);
|
|
|
|
|
} else if (item?.children?.length) {
|
|
|
|
|
removeChild(item.children)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
removeChild(treeData.value)
|
|
|
|
|
}
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
selectId.value = '';
|
|
|
|
|
}, 300);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const deleteGroup = async (id: string) => {
|
|
|
|
|
const res = await deleteMonitor(id);
|
|
|
|
|
if (res.status === 200) {
|
|
|
|
|
onlyMessage('操作成功!');
|
|
|
|
|
emit('getMonitorList');
|
|
|
|
|
} else {
|
|
|
|
|
onlyMessage('操作失败!');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const search = () => {
|
|
|
|
|
queryGroup(true, searchValue.value);
|
|
|
|
|
};
|
|
|
|
|
const searchChange = () => {
|
|
|
|
|
if (searchValue.value === '') {
|
|
|
|
|
queryGroup();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
const editGroup = (data: any) => {
|
|
|
|
|
if (!selectId.value) {
|
|
|
|
|
selectId.value = data.id;
|
|
|
|
|
addName.value = data.nodeName;
|
|
|
|
|
// listData.value[0].children?.forEach((item: any) => {
|
|
|
|
|
// if (item.id === data.id) {
|
|
|
|
|
// item.edit = true;
|
|
|
|
|
// }
|
|
|
|
|
// });
|
|
|
|
|
nextTick(() => {
|
|
|
|
|
inputRef.value.focus();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
});
|
|
|
|
|
</script>
|
|
|
|
|
<style lang="less" scoped>
|
|
|
|
|
.left-tree-container {
|
|
|
|
|
display: flex;
|
|
|
|
|
height: 100%;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
|
|
|
|
.add-btn {
|
|
|
|
|
margin: 24px 0;
|
|
|
|
|
|
|
|
|
|
:deep(.ant-btn-primary) {
|
|
|
|
|
width: 100%;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
:deep(.ant-tree-treenode-disabled) {
|
|
|
|
|
.ant-tree-node-content-wrapper {
|
|
|
|
|
color: rgba(0, 0, 0, 0.55)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
:deep(.ant-tree-treenode) {
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
|
|
|
|
.ant-tree-node-content-wrapper {
|
|
|
|
|
flex: 1 1 auto;
|
|
|
|
|
|
|
|
|
|
.ant-tree-title {
|
|
|
|
|
&:hover {
|
|
|
|
|
.func-btns {
|
|
|
|
|
display: block;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.tree {
|
|
|
|
|
overflow-y: auto;
|
|
|
|
|
overflow-x: auto;
|
|
|
|
|
flex: 1 1 auto;
|
|
|
|
|
|
|
|
|
|
.department-tree-item-content {
|
|
|
|
|
display: inline-flex;
|
|
|
|
|
align-items: stretch;
|
|
|
|
|
|
|
|
|
|
.title {
|
|
|
|
|
flex: 1;
|
|
|
|
|
margin-right: 80px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.func-btns {
|
|
|
|
|
display: none;
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
width: 100px;
|
|
|
|
|
margin-left: -80px;
|
|
|
|
|
|
|
|
|
|
:deep(.ant-btn-link) {
|
|
|
|
|
padding: 0 4px;
|
|
|
|
|
height: 24px;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.loading {
|
|
|
|
|
display: flex;
|
|
|
|
|
width: 100%;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
margin-top: 20px;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</style>
|