节点:基础功能实现,机构:新增右键菜单,调整下拉选择树结构
This commit is contained in:
parent
8e93b4e34d
commit
ced0fbc907
100
ui/dasadmin/src/api/backend/node/request.ts
Normal file
100
ui/dasadmin/src/api/backend/node/request.ts
Normal file
@ -0,0 +1,100 @@
|
||||
import {
|
||||
nodeType,
|
||||
RequestReturnType,
|
||||
RequestReturnRowType,
|
||||
addNodeType,
|
||||
updateNodeType,
|
||||
delNodeType,
|
||||
getLinkType,
|
||||
addLinkType,
|
||||
updateLinkType,
|
||||
delLinkType,
|
||||
linkType,
|
||||
} from '/@/views/backend/node/type'
|
||||
import createAxios from '/@/utils/axios'
|
||||
|
||||
export const getNodeListReq = () => {
|
||||
return createAxios<never, RequestReturnType>({
|
||||
url: '/api/node/list',
|
||||
method: 'post',
|
||||
})
|
||||
}
|
||||
|
||||
export const updateNodeListReq = (data: updateNodeType) => {
|
||||
return createAxios<never, RequestReturnType<nodeType>>({
|
||||
url: '/api/node/update',
|
||||
method: 'post',
|
||||
data: data,
|
||||
})
|
||||
}
|
||||
|
||||
export const delNodeListReq = (data: delNodeType) => {
|
||||
return createAxios<never, RequestReturnType>({
|
||||
url: '/api/node/delete',
|
||||
method: 'post',
|
||||
data: data,
|
||||
})
|
||||
}
|
||||
|
||||
export const addNodeListReq = (data: addNodeType) => {
|
||||
return createAxios<never, RequestReturnType<nodeType>>({
|
||||
url: '/api/node/add',
|
||||
method: 'post',
|
||||
data: data,
|
||||
})
|
||||
}
|
||||
|
||||
export const submitNodeConfigReq = () => {
|
||||
return createAxios({
|
||||
url: '/api/node/configUpdate',
|
||||
method: 'post',
|
||||
})
|
||||
}
|
||||
|
||||
export const getLinkListReq = (data: getLinkType) => {
|
||||
return createAxios<never, RequestReturnType<linkType>>({
|
||||
url: '/api/node/link/list',
|
||||
method: 'post',
|
||||
data: data,
|
||||
})
|
||||
}
|
||||
|
||||
export const updateLinkListReq = (data: updateLinkType) => {
|
||||
return createAxios<never, RequestReturnType<linkType>>({
|
||||
url: '/api/node/link/update',
|
||||
method: 'post',
|
||||
data: data,
|
||||
})
|
||||
}
|
||||
|
||||
export const delLinkListReq = (data: delLinkType) => {
|
||||
return createAxios<never, RequestReturnType>({
|
||||
url: '/api/node/link/delete',
|
||||
method: 'post',
|
||||
data: data,
|
||||
})
|
||||
}
|
||||
|
||||
export const addLinkListReq = (data: addLinkType) => {
|
||||
return createAxios<never, RequestReturnType<linkType>>({
|
||||
url: '/api/node/link/add',
|
||||
method: 'post',
|
||||
data: data,
|
||||
})
|
||||
}
|
||||
|
||||
export const downloadNodeReq = (data:any) => {
|
||||
return createAxios({
|
||||
url: '',
|
||||
method: 'post',
|
||||
data: data,
|
||||
})
|
||||
}
|
||||
|
||||
export const uploadNodeReq = (data:any) => {
|
||||
return createAxios({
|
||||
url: '',
|
||||
method: 'post',
|
||||
data: data,
|
||||
})
|
||||
}
|
79
ui/dasadmin/src/components/container/index.vue
Normal file
79
ui/dasadmin/src/components/container/index.vue
Normal file
@ -0,0 +1,79 @@
|
||||
<template>
|
||||
<el-container class="containerPart" v-if="props.hasAside">
|
||||
<el-aside class="asidePart">
|
||||
<el-header class="asideHeader">
|
||||
<slot name="asideHeader"></slot>
|
||||
</el-header>
|
||||
<el-main class="treeMain">
|
||||
<slot name="asideMain"></slot>
|
||||
</el-main>
|
||||
</el-aside>
|
||||
<el-container class="mainContainer">
|
||||
<el-header class="mainHeader">
|
||||
<slot name="mainHeader"></slot>
|
||||
</el-header>
|
||||
<el-main class="mainMain">
|
||||
<slot name="mainMain"></slot>
|
||||
</el-main>
|
||||
</el-container>
|
||||
</el-container>
|
||||
<el-container class="containerPart" v-else>
|
||||
<el-header class="mainHeader">
|
||||
<slot name="mainHeader"></slot>
|
||||
</el-header>
|
||||
<el-main class="mainMain">
|
||||
<slot name="mainMain"></slot>
|
||||
</el-main>
|
||||
</el-container>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { ElContainer, ElAside, ElHeader, ElMain } from 'element-plus'
|
||||
|
||||
const props = defineProps<{ hasAside: boolean }>()
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
$headerHeight: 60px;
|
||||
$defaultBackgroundColor: #fff;
|
||||
$defaultAsideWidth: 260px;
|
||||
|
||||
.containerPart {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
.asidePart {
|
||||
width: $defaultAsideWidth;
|
||||
height: 100%;
|
||||
border-right: 1px solid #eaebed;
|
||||
.asideHeader {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.treeMain {
|
||||
height: calc(100% - $headerHeight);
|
||||
overflow-y: auto;
|
||||
.treePart {
|
||||
height: 100%;
|
||||
background-color: $defaultBackgroundColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
.mainContainer {
|
||||
width: calc(100% - $defaultAsideWidth);
|
||||
height: 100%;
|
||||
.mainHeader {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
height: $headerHeight;
|
||||
padding: 0 20px;
|
||||
border-bottom: 1px solid #eaebed;
|
||||
}
|
||||
.mainMain {
|
||||
height: calc(100% - $headerHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -54,7 +54,7 @@ $defaultPadding: 20px;
|
||||
position: relative;
|
||||
padding: $defaultPadding;
|
||||
width: $defaultWidth + $defaultPadding * 2;
|
||||
height: $defaultHeight + $defaultPadding * 2;
|
||||
// min-height: $defaultHeight + $defaultPadding * 2;
|
||||
background-color: #fff;
|
||||
border-radius: 10px;
|
||||
border: 1px solid #e4e7ed;
|
||||
@ -64,7 +64,7 @@ $defaultPadding: 20px;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: $defaultWidth;
|
||||
height: $defaultHeight;
|
||||
// min-height: $defaultHeight;
|
||||
.el-button {
|
||||
margin: 0;
|
||||
}
|
||||
|
@ -5,11 +5,12 @@
|
||||
<template v-for="item in addFormItemList" :key="item.prop">
|
||||
<el-form-item :prop="item.prop" :label="item.label" label-width="80" :rules="item.rules">
|
||||
<template v-if="item.type === 'input'">
|
||||
<el-input v-model="formModel[item.prop]" :placeholder="item.placeholder"></el-input>
|
||||
<el-input :disabled="formDisabled" v-model="formModel[item.prop]" :placeholder="item.placeholder"></el-input>
|
||||
</template>
|
||||
<template v-if="item.type === 'custom'">
|
||||
<el-select
|
||||
v-if="item.prop === 'province'"
|
||||
:disabled="formDisabled"
|
||||
v-model="formModel[item.prop]"
|
||||
:placeholder="item.placeholder"
|
||||
@change="changeProvince"
|
||||
@ -18,19 +19,27 @@
|
||||
</el-select>
|
||||
<el-select
|
||||
v-if="item.prop === 'county'"
|
||||
:disabled="formDisabled"
|
||||
v-model="formModel[item.prop]"
|
||||
:placeholder="item.placeholder"
|
||||
@change="changeCounty"
|
||||
>
|
||||
<el-option v-for="opt in countyOptions" :key="opt.value" :label="opt.label" :value="opt.value"></el-option>
|
||||
</el-select>
|
||||
<el-select v-if="item.prop === 'city'" v-model="formModel[item.prop]" :placeholder="item.placeholder">
|
||||
<el-select
|
||||
v-if="item.prop === 'city'"
|
||||
:disabled="formDisabled"
|
||||
v-model="formModel[item.prop]"
|
||||
:placeholder="item.placeholder"
|
||||
>
|
||||
<el-option v-for="opt in cityOptions" :key="opt.value" :label="opt.label" :value="opt.value"></el-option>
|
||||
</el-select>
|
||||
<el-tree-select
|
||||
v-if="item.prop === 'parentOrgId'"
|
||||
v-model="formModel[item.prop]"
|
||||
:disabled="formDisabled"
|
||||
lazy
|
||||
:data="treeData"
|
||||
:load="loadSelectTreeData"
|
||||
check-strictly
|
||||
:props="treeSelectReplaceProps"
|
||||
@ -41,7 +50,7 @@
|
||||
</template>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button type="primary" @click="submitAddForm">提交</el-button>
|
||||
<el-button type="primary" @click="submitAddForm" :disabled="formDisabled">提交</el-button>
|
||||
<el-button @click="closeAddForm">关闭</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
@ -61,6 +70,7 @@
|
||||
node-key="id"
|
||||
:props="treeReplaceProps"
|
||||
@node-click="treeNodeClick"
|
||||
@node-contextmenu="rightClick"
|
||||
></el-tree>
|
||||
</el-main>
|
||||
</el-aside>
|
||||
@ -70,7 +80,7 @@
|
||||
<el-input v-model="searchTableInput" class="searchInput"></el-input>
|
||||
<el-button @click="searchTable" type="primary" :icon="Search" class="defaultBtn">{{ t('management.search') }}</el-button>
|
||||
</div>
|
||||
<el-button type="primary" :icon="Plus" class="defaultBtn" @click="addInstitutional">{{ t('management.add') }}</el-button>
|
||||
<el-button type="primary" :icon="Plus" class="defaultBtn" @click="addInstitutional(false)">{{ t('management.add') }}</el-button>
|
||||
</el-header>
|
||||
<el-main class="defaultMain">
|
||||
<el-table :data="tableData" class="tablePart">
|
||||
@ -110,11 +120,26 @@
|
||||
</el-main>
|
||||
</el-container>
|
||||
</el-container>
|
||||
<ContextMenu v-model:visible="contextMenuVisible" :pos="contextMenuPos">
|
||||
<template #default>
|
||||
<div class="modelOperate">
|
||||
<el-button @click="editForm(rightClickMenuData!, true)" :icon="Reading">查看</el-button>
|
||||
<el-button @click="addInstitutional(true)" :icon="DocumentAdd">新增</el-button>
|
||||
<el-button @click="editForm(rightClickMenuData!)" :icon="DocumentChecked">修改</el-button>
|
||||
<el-popconfirm title="确认删除?" @confirm="delForm(rightClickMenuData!)">
|
||||
<template #reference>
|
||||
<el-button :icon="DocumentDelete" @click.stop>删除</el-button>
|
||||
</template>
|
||||
</el-popconfirm>
|
||||
</div>
|
||||
</template>
|
||||
</ContextMenu>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref, computed,nextTick } from 'vue'
|
||||
import { onMounted, ref, reactive, computed, nextTick } from 'vue'
|
||||
import { Reading, DocumentAdd, DocumentChecked, DocumentDelete } from '@element-plus/icons-vue'
|
||||
import {
|
||||
ElContainer,
|
||||
ElAside,
|
||||
@ -133,7 +158,7 @@ import {
|
||||
ElMessage,
|
||||
ElPagination,
|
||||
} from 'element-plus'
|
||||
import type { FormInstance, TreeInstance } from 'element-plus'
|
||||
import type { FormInstance, TreeInstance, TreeNode } from 'element-plus'
|
||||
import type Node from 'element-plus/es/components/tree/src/model/node'
|
||||
import { Plus, Search } from '@element-plus/icons-vue'
|
||||
import {
|
||||
@ -155,6 +180,7 @@ import {
|
||||
getTreeDataReturnType,
|
||||
allEnumType,
|
||||
} from './type'
|
||||
import ContextMenu from '/@/views/backend/auth/model/contextMenu.vue'
|
||||
import { pcaTextArr } from 'element-china-area-data'
|
||||
import { useAdminInfo } from '/@/stores/adminInfo'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
@ -281,11 +307,15 @@ const addFormItemList: formItemListType<addDataEnumKeyJointType>[] = [
|
||||
]
|
||||
const dialogTitle = ref('新增机构')
|
||||
const dialogVible = ref(false)
|
||||
const addInstitutional = () => {
|
||||
const addInstitutional = (rightClick = false) => {
|
||||
dialogTitle.value = '新增机构'
|
||||
formModel.value = JSON.parse(JSON.stringify(defaultFormModel))
|
||||
formRef.value && formRef.value.resetFields()
|
||||
dialogVible.value = true
|
||||
if (!rightClick) {
|
||||
formModel.value.parentOrgId = clickTreeMenuData.value?.id!
|
||||
}
|
||||
formDisabled.value = false
|
||||
}
|
||||
|
||||
const submitAddForm = () => {
|
||||
@ -294,13 +324,14 @@ const submitAddForm = () => {
|
||||
formRef.value.validate((valid) => {
|
||||
if (valid) {
|
||||
if (dialogTitle.value === '新增机构') {
|
||||
formModel.value.parentOrgId = formModel.value.parentOrgId ?? '0'
|
||||
addInstitutionalListReq(formModel.value)
|
||||
.then((res) => {
|
||||
if (res.success) {
|
||||
ElMessage.success('新增成功')
|
||||
getInstitutionList()
|
||||
dialogVible.value = false
|
||||
refreshTreeData()
|
||||
refreshTreeData(formModel.value.parentOrgId)
|
||||
} else {
|
||||
ElMessage.error(res?.msg ?? '新增失败')
|
||||
}
|
||||
@ -315,7 +346,7 @@ const submitAddForm = () => {
|
||||
ElMessage.success('编辑成功')
|
||||
getInstitutionList()
|
||||
dialogVible.value = false
|
||||
refreshTreeData()
|
||||
refreshTreeData(formModel.value.parentOrgId)
|
||||
} else {
|
||||
ElMessage.error(res?.msg ?? '编辑失败')
|
||||
}
|
||||
@ -333,7 +364,6 @@ const closeAddForm = () => {
|
||||
|
||||
const getInstitutionList = (data: getDataType = { name: null }) => {
|
||||
getInstitutionalListReq(data).then((res) => {
|
||||
console.log(res)
|
||||
pageTotal.value = res.total
|
||||
originData.value = res.rows
|
||||
})
|
||||
@ -402,20 +432,23 @@ const tableColumn: tableColumnType<allEnumType>[] = [
|
||||
},
|
||||
]
|
||||
|
||||
const editForm = (column: changeDataType) => {
|
||||
const formDisabled = ref(false)
|
||||
|
||||
const editForm = (column: getTreeDataReturnType, onlyOpen = false) => {
|
||||
formRef.value?.resetFields()
|
||||
formModel.value = JSON.parse(JSON.stringify(column))
|
||||
dialogTitle.value = '编辑机构'
|
||||
dialogVible.value = true
|
||||
formDisabled.value = onlyOpen
|
||||
}
|
||||
|
||||
const delForm = (column: changeDataType) => {
|
||||
const delForm = (column: getTreeDataReturnType) => {
|
||||
delInstitutionalListReq({ id: column.id })
|
||||
.then((res) => {
|
||||
if (res.success) {
|
||||
ElMessage.success('删除成功')
|
||||
getInstitutionList()
|
||||
refreshTreeData()
|
||||
refreshTreeData(column.parentOrgId)
|
||||
} else {
|
||||
ElMessage.error(res?.msg ?? '删除失败')
|
||||
}
|
||||
@ -438,7 +471,7 @@ const treeSelectReplaceProps = {
|
||||
}
|
||||
const loadTreeData = (node: Node, resolve: any) => {
|
||||
if (node.level === 0) {
|
||||
return resolve([])
|
||||
return
|
||||
}
|
||||
getTreeData(node.data.id)
|
||||
.then((res) => {
|
||||
@ -455,13 +488,12 @@ const loadTreeData = (node: Node, resolve: any) => {
|
||||
}
|
||||
const loadSelectTreeData = (node: Node, resolve: any) => {
|
||||
if (node.level === 0) {
|
||||
getTreeData(adminInfo.orgid)
|
||||
return getTreeData(null)
|
||||
.then((res) => {
|
||||
if (!res.length) {
|
||||
node.data.isLeaf = true
|
||||
}
|
||||
|
||||
return resolve(res)
|
||||
resolve(res)
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err)
|
||||
@ -497,6 +529,7 @@ const initData = () => {
|
||||
treeData.value = [...res]
|
||||
nextTick(() => {
|
||||
treeRef.value?.setCurrentKey(res[0]?.id!, false)
|
||||
clickTreeMenuData.value = res[0]
|
||||
})
|
||||
return
|
||||
})
|
||||
@ -508,27 +541,51 @@ const initData = () => {
|
||||
originData.value = [...res]
|
||||
})
|
||||
}
|
||||
const currentTreeId = ref<string | number>('')
|
||||
const refreshTreeData = () => {
|
||||
getTreeData(currentTreeId.value).then((res) => {
|
||||
treeRef.value?.updateKeyChildren(currentTreeId.value, res)
|
||||
const clickTreeMenuData = ref<getTreeDataReturnType>()
|
||||
const refreshTreeData = (parentOrgId: string | number | null) => {
|
||||
const data = parentOrgId === 0 || parentOrgId === '0' ? null : parentOrgId
|
||||
getTreeData(data).then((res) => {
|
||||
console.log('res,', res)
|
||||
console.log(data)
|
||||
if (data) {
|
||||
treeRef.value?.updateKeyChildren(parentOrgId!, res)
|
||||
} else {
|
||||
treeData.value = [...res]
|
||||
}
|
||||
})
|
||||
}
|
||||
const treeNodeClick = (nodeData: getTreeDataReturnType, node: Node) => {
|
||||
console.log(node.childNodes, nodeData.isLeaf)
|
||||
if (node.childNodes.length || nodeData.isLeaf) {
|
||||
getTreeData(nodeData.id).then((res) => {
|
||||
pageTotal.value = res.length
|
||||
originData.value = [...res]
|
||||
})
|
||||
}
|
||||
currentTreeId.value = nodeData.id
|
||||
clickTreeMenuData.value = nodeData
|
||||
}
|
||||
|
||||
const rightClickMenuData = ref<getTreeDataReturnType>()
|
||||
const rightClickNodeLevel = ref(0)
|
||||
const contextMenuVisible = ref(false)
|
||||
const contextMenuPos = reactive({
|
||||
x: 0,
|
||||
y: 0,
|
||||
})
|
||||
|
||||
const rightClick = (event: any, data: getTreeDataReturnType, node: TreeNode) => {
|
||||
contextMenuPos.x = event.pageX
|
||||
contextMenuPos.y = event.pageY
|
||||
contextMenuVisible.value = true
|
||||
rightClickMenuData.value = data
|
||||
rightClickNodeLevel.value = node.level!
|
||||
}
|
||||
|
||||
const searchTableInput = ref('')
|
||||
const searchTable = () => {
|
||||
// if (searchTableInput.value === '') return
|
||||
getInstitutionList({ name: searchTableInput.value, parentOrgId: currentTreeId.value })
|
||||
getInstitutionList({ name: searchTableInput.value, parentOrgId: clickTreeMenuData.value!.id! })
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
initData()
|
||||
})
|
||||
@ -616,5 +673,26 @@ $paginationHeight: 32px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.modelOperate {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 80px;
|
||||
height: 200px;
|
||||
.el-button {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
.addOrgPopover {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
height: 70px;
|
||||
.el-button {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -55,7 +55,7 @@ export type addDataType = {
|
||||
address: string
|
||||
contactPhone: string
|
||||
remarks: string
|
||||
parentOrgId: number | null
|
||||
parentOrgId: number | string | null
|
||||
revision: number
|
||||
}
|
||||
|
||||
|
328
ui/dasadmin/src/views/backend/node/index.vue
Normal file
328
ui/dasadmin/src/views/backend/node/index.vue
Normal file
@ -0,0 +1,328 @@
|
||||
<template>
|
||||
<div class="node">
|
||||
<el-dialog v-model="nodeVisible" :title="nodeTitle" width="600">
|
||||
<el-form :model="nodeForm" ref="nodeFormRef" :label-width="100" :rules="nodeFormRules">
|
||||
<el-form-item prop="nodeName" label="节点名称">
|
||||
<el-input v-model="nodeForm.nodeName" :disabled="nodeFormDisabled" placeholder="请输入节点名称"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="nodeIp" label="节点IP">
|
||||
<el-input v-model="nodeForm.nodeIp" :disabled="nodeFormDisabled" placeholder="请输入节点IP"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="orgId" label="所属机构">
|
||||
<el-tree-select
|
||||
v-model="nodeForm.orgId"
|
||||
:disabled="nodeFormDisabled"
|
||||
lazy
|
||||
:load="loadSelectOrgTreeData"
|
||||
check-strictly
|
||||
placeholder="请选择所属机构"
|
||||
></el-tree-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button type="primary" @click="submitNodeForm" :disabled="nodeFormDisabled">提交</el-button>
|
||||
<el-button @click="closeNodeForm">关闭</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<Container :has-aside="true">
|
||||
<template #asideHeader>
|
||||
<el-input v-model="searchTreeInput" class="defaultSearchInput"></el-input>
|
||||
</template>
|
||||
<template #asideMain>
|
||||
<el-tree
|
||||
:data="treeData"
|
||||
:props="replaceTreeProps"
|
||||
node-key="id"
|
||||
@node-click="nodeClick"
|
||||
@node-contextmenu="nodeContextMenu"
|
||||
></el-tree>
|
||||
</template>
|
||||
<template #mainHeader>
|
||||
<div class="mainHeaderCenter">
|
||||
<el-input class="defaultSearchInput tableSearchInput"></el-input>
|
||||
<el-button :icon="Search" type="primary">查询</el-button>
|
||||
</div>
|
||||
<div class="mainHeaderRight">
|
||||
<el-button :icon="Plus" type="primary">新增</el-button>
|
||||
<el-upload :show-file-list="false" :limit="1">
|
||||
<template #trigger>
|
||||
<el-button :icon="Upload">导入</el-button>
|
||||
</template>
|
||||
</el-upload>
|
||||
<el-button :icon="Download">导出</el-button>
|
||||
</div>
|
||||
</template>
|
||||
<template #mainMain>
|
||||
<el-table W></el-table>
|
||||
</template>
|
||||
</Container>
|
||||
<ContextMenu v-model:visible="nodeContextMenuVisible" :pos="nodeContextMenuPos">
|
||||
<template #default>
|
||||
<div class="modelOperate">
|
||||
<el-button @click="openNode">查看</el-button>
|
||||
<el-button @click="addNode">新增</el-button>
|
||||
<el-button @click="editNode">编辑</el-button>
|
||||
<el-popconfirm @confirm="delNode" title="确认删除?">
|
||||
<template #reference>
|
||||
<el-button @click.stop>删除</el-button>
|
||||
</template>
|
||||
</el-popconfirm>
|
||||
<el-popconfirm @confirm="submitNode">
|
||||
<template #reference>
|
||||
<el-button @click.stop>配置下发</el-button>
|
||||
</template>
|
||||
</el-popconfirm>
|
||||
</div>
|
||||
</template>
|
||||
</ContextMenu>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ElInput, ElButton, ElTree, ElTable, ElMessage } from 'element-plus'
|
||||
import type { FormInstance } from 'element-plus'
|
||||
import { Search, Plus, Upload, Download } from '@element-plus/icons-vue'
|
||||
import { ref } from 'vue'
|
||||
import { nodeType } from '/@/views/backend/node/type'
|
||||
import ContextMenu from '/@/views/backend/auth/model/contextMenu.vue'
|
||||
import Container from '/@/components/container/index.vue'
|
||||
import {
|
||||
getNodeListReq,
|
||||
addNodeListReq,
|
||||
updateNodeListReq,
|
||||
delNodeListReq,
|
||||
getLinkListReq,
|
||||
addLinkListReq,
|
||||
updateLinkListReq,
|
||||
delLinkListReq,
|
||||
downloadNodeReq,
|
||||
uploadNodeReq,
|
||||
submitNodeConfigReq,
|
||||
} from '/@/api/backend/node/request'
|
||||
import { getInstitutionalTreeListReq } from '/@/api/backend/org/request'
|
||||
import { getTreeDataReturnType } from '/@/views/backend/auth/org/type'
|
||||
const searchTreeInput = ref('')
|
||||
|
||||
const replaceTreeProps = { label: 'nodeName' }
|
||||
const treeData = ref([])
|
||||
|
||||
const nodeVisible = ref(false)
|
||||
const nodeTitle = ref('新增节点')
|
||||
const originNodeData: nodeType = {
|
||||
id: undefined,
|
||||
nodeName: '',
|
||||
nodeIp: '',
|
||||
orgName: '',
|
||||
orgId: '',
|
||||
revision: 1,
|
||||
}
|
||||
const nodeForm = ref<nodeType>(JSON.parse(JSON.stringify(originNodeData)))
|
||||
const nodeFormRef = ref<FormInstance>()
|
||||
const nodeFormRules = {
|
||||
nodeName: [{ required: true, message: '请输入节点名称', trigger: 'blur' }],
|
||||
nodeIp: [
|
||||
{
|
||||
required: true,
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
if (!value) {
|
||||
callback(new Error('请输入节点IP'))
|
||||
} else if (!/^((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)$/.test(value)) {
|
||||
callback(new Error('请输入正确的IP地址'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
},
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
orgId: [{ required: true, message: '请选择所属组织', trigger: 'blur' }],
|
||||
}
|
||||
const getTreeData = (orgId: number | string | null) => {
|
||||
return new Promise((resolve: (data: { label: string; value: string }[]) => unknown) => {
|
||||
getInstitutionalTreeListReq({ parentOrgId: orgId }).then((res) => {
|
||||
if (res.data) {
|
||||
const result = res.data.map((item) => {
|
||||
return {
|
||||
label: item.name,
|
||||
value: item.id,
|
||||
}
|
||||
})
|
||||
resolve(result)
|
||||
} else {
|
||||
resolve([])
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const loadSelectOrgTreeData = (node: any, resolve: any) => {
|
||||
if (node.level === 0) {
|
||||
return getTreeData(null)
|
||||
.then((res) => {
|
||||
if (!res.length) {
|
||||
node.data.isLeaf = true
|
||||
}
|
||||
resolve(res)
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err)
|
||||
})
|
||||
}
|
||||
getTreeData(node.data.id)
|
||||
.then((res) => {
|
||||
if (!res.length) {
|
||||
node.data.isLeaf = true
|
||||
}
|
||||
return resolve(res)
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err)
|
||||
})
|
||||
}
|
||||
|
||||
const nodeContextMenuVisible = ref(false)
|
||||
const nodeContextMenuPos = ref({
|
||||
x: 0,
|
||||
y: 0,
|
||||
})
|
||||
|
||||
const contextMenuTreeData = ref<nodeType>()
|
||||
const clickTreeData = ref<nodeType>()
|
||||
const nodeClick = (node: any, nodeData: nodeType) => {}
|
||||
const nodeContextMenu = (event: any, nodeData: nodeType) => {
|
||||
nodeContextMenuPos.value.x = event.pageX
|
||||
nodeContextMenuPos.value.y = event.pageY
|
||||
contextMenuTreeData.value = nodeData
|
||||
nodeContextMenuVisible.value = true
|
||||
}
|
||||
const nodeFormDisabled = ref(false)
|
||||
const openNode = () => {
|
||||
nodeTitle.value = '查看节点'
|
||||
nodeForm.value = JSON.parse(JSON.stringify(contextMenuTreeData.value))
|
||||
nodeFormDisabled.value = true
|
||||
nodeVisible.value = true
|
||||
}
|
||||
const addNode = () => {
|
||||
nodeTitle.value = '新增节点'
|
||||
nodeForm.value = JSON.parse(JSON.stringify(originNodeData))
|
||||
nodeFormDisabled.value = false
|
||||
nodeVisible.value = true
|
||||
}
|
||||
const editNode = () => {
|
||||
nodeTitle.value = '编辑节点'
|
||||
nodeForm.value = JSON.parse(JSON.stringify(contextMenuTreeData.value))
|
||||
nodeFormDisabled.value = false
|
||||
nodeVisible.value = true
|
||||
}
|
||||
const delNode = () => {
|
||||
delNodeListReq({ id: contextMenuTreeData.value!.id! })
|
||||
.then((res) => {
|
||||
if (res.success) {
|
||||
ElMessage.success(res.msg ?? '删除成功')
|
||||
getNodeList()
|
||||
} else {
|
||||
ElMessage.error(res.msg ?? '删除失败')
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
ElMessage.error(err?.response?.data?.msg ?? '删除失败')
|
||||
})
|
||||
}
|
||||
const submitNode = () => {}
|
||||
|
||||
const submitNodeForm = () => {
|
||||
nodeFormRef.value?.validate((valid: boolean) => {
|
||||
if (valid) {
|
||||
if (nodeTitle.value === '新增节点') {
|
||||
addNodeListReq(nodeForm.value)
|
||||
.then((res) => {
|
||||
if (res.success) {
|
||||
ElMessage.success(res.msg ?? '新增成功')
|
||||
nodeVisible.value = false
|
||||
getNodeList()
|
||||
} else {
|
||||
ElMessage.error(res.msg ?? '新增失败')
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
ElMessage.error(err?.response?.data?.msg ?? '新增失败')
|
||||
})
|
||||
} else if (nodeTitle.value === '编辑节点') {
|
||||
updateNodeListReq(nodeForm.value)
|
||||
.then((res) => {
|
||||
if (res.success) {
|
||||
ElMessage.success(res.msg ?? '编辑成功')
|
||||
nodeVisible.value = false
|
||||
getNodeList()
|
||||
} else {
|
||||
ElMessage.error(res.msg ?? '编辑失败')
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
ElMessage.error(err?.response?.data?.msg ?? '编辑失败')
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
const closeNodeForm = () => {
|
||||
nodeFormRef.value?.resetFields()
|
||||
nodeForm.value = JSON.parse(JSON.stringify(originNodeData))
|
||||
nodeVisible.value = false
|
||||
}
|
||||
|
||||
const getNodeList = () => {
|
||||
getNodeListReq()
|
||||
.then((res) => {
|
||||
if (res.success) {
|
||||
treeData.value = res.data!
|
||||
} else {
|
||||
ElMessage.error(res.msg ?? '查询失败')
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
ElMessage.error(err?.response?.data?.msg ?? '查询失败')
|
||||
})
|
||||
}
|
||||
getNodeList()
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.node {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
.defaultSearchInput {
|
||||
height: 40px;
|
||||
}
|
||||
.el-button {
|
||||
width: 88px;
|
||||
height: 40px;
|
||||
}
|
||||
.mainHeaderCenter {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 320px;
|
||||
.tableSearchInput {
|
||||
width: 220px;
|
||||
}
|
||||
}
|
||||
.mainHeaderRight {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 290px;
|
||||
}
|
||||
.modelOperate {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 80px;
|
||||
height: 220px;
|
||||
.el-button {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
66
ui/dasadmin/src/views/backend/node/type.ts
Normal file
66
ui/dasadmin/src/views/backend/node/type.ts
Normal file
@ -0,0 +1,66 @@
|
||||
export type RequestReturnType<T = never> = Promise<{
|
||||
code: number
|
||||
msg: string
|
||||
success: boolean
|
||||
data?: T
|
||||
}>
|
||||
|
||||
export type RequestReturnRowType<T = never> = Promise<{
|
||||
code: number
|
||||
msg: string
|
||||
rows: T
|
||||
total: number
|
||||
}>
|
||||
|
||||
export enum nodeKeyEnum {
|
||||
id = 'id',
|
||||
nodeName = '节点名称',
|
||||
nodeIp = '节点IP',
|
||||
orgName = '组织名称',
|
||||
orgId = '组织机构',
|
||||
}
|
||||
export type nodeKeyType = keyof typeof nodeKeyEnum
|
||||
|
||||
export type nodeType = {
|
||||
id?: string
|
||||
nodeName: string
|
||||
nodeIp: string
|
||||
orgName?: string
|
||||
orgId: string
|
||||
revision?: number
|
||||
}
|
||||
|
||||
export type addNodeType = Pick<nodeType, 'nodeName' | 'nodeIp' | 'orgId'>
|
||||
|
||||
export type updateNodeType = Pick<nodeType, 'id' | 'nodeName' | 'nodeIp' | 'orgId' | 'revision'>
|
||||
|
||||
export type delNodeType = Pick<nodeType, 'id'>
|
||||
|
||||
export enum linkEnum {
|
||||
id = '链路ID',
|
||||
linkName = '链路名称',
|
||||
protocol = '协议类型',
|
||||
params = '参数',
|
||||
nodeName = '节点名称',
|
||||
nodeId = '节点ID',
|
||||
revision = '乐观锁',
|
||||
}
|
||||
|
||||
export type linkType = {
|
||||
id?: string
|
||||
linkName: string
|
||||
protocol: string
|
||||
params: string
|
||||
nodeName: string
|
||||
nodeId: string
|
||||
revision: number
|
||||
}
|
||||
export type getLinkType = Pick<linkType, 'nodeId'>
|
||||
|
||||
export type addLinkType = Pick<linkType, 'linkName' | 'protocol' | 'params' | 'nodeId'>
|
||||
|
||||
export type updateLinkType = Pick<linkType, 'id' | 'linkName' | 'protocol' | 'params' | 'nodeName' | 'nodeId' | 'revision'>
|
||||
|
||||
export type delLinkType = Pick<linkType, 'id'>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user