节点:基础功能实现,机构:新增右键菜单,调整下拉选择树结构
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;
|
position: relative;
|
||||||
padding: $defaultPadding;
|
padding: $defaultPadding;
|
||||||
width: $defaultWidth + $defaultPadding * 2;
|
width: $defaultWidth + $defaultPadding * 2;
|
||||||
height: $defaultHeight + $defaultPadding * 2;
|
// min-height: $defaultHeight + $defaultPadding * 2;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
border: 1px solid #e4e7ed;
|
border: 1px solid #e4e7ed;
|
||||||
@ -64,7 +64,7 @@ $defaultPadding: 20px;
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
width: $defaultWidth;
|
width: $defaultWidth;
|
||||||
height: $defaultHeight;
|
// min-height: $defaultHeight;
|
||||||
.el-button {
|
.el-button {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
@ -5,11 +5,12 @@
|
|||||||
<template v-for="item in addFormItemList" :key="item.prop">
|
<template v-for="item in addFormItemList" :key="item.prop">
|
||||||
<el-form-item :prop="item.prop" :label="item.label" label-width="80" :rules="item.rules">
|
<el-form-item :prop="item.prop" :label="item.label" label-width="80" :rules="item.rules">
|
||||||
<template v-if="item.type === 'input'">
|
<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>
|
||||||
<template v-if="item.type === 'custom'">
|
<template v-if="item.type === 'custom'">
|
||||||
<el-select
|
<el-select
|
||||||
v-if="item.prop === 'province'"
|
v-if="item.prop === 'province'"
|
||||||
|
:disabled="formDisabled"
|
||||||
v-model="formModel[item.prop]"
|
v-model="formModel[item.prop]"
|
||||||
:placeholder="item.placeholder"
|
:placeholder="item.placeholder"
|
||||||
@change="changeProvince"
|
@change="changeProvince"
|
||||||
@ -18,19 +19,27 @@
|
|||||||
</el-select>
|
</el-select>
|
||||||
<el-select
|
<el-select
|
||||||
v-if="item.prop === 'county'"
|
v-if="item.prop === 'county'"
|
||||||
|
:disabled="formDisabled"
|
||||||
v-model="formModel[item.prop]"
|
v-model="formModel[item.prop]"
|
||||||
:placeholder="item.placeholder"
|
:placeholder="item.placeholder"
|
||||||
@change="changeCounty"
|
@change="changeCounty"
|
||||||
>
|
>
|
||||||
<el-option v-for="opt in countyOptions" :key="opt.value" :label="opt.label" :value="opt.value"></el-option>
|
<el-option v-for="opt in countyOptions" :key="opt.value" :label="opt.label" :value="opt.value"></el-option>
|
||||||
</el-select>
|
</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-option v-for="opt in cityOptions" :key="opt.value" :label="opt.label" :value="opt.value"></el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
<el-tree-select
|
<el-tree-select
|
||||||
v-if="item.prop === 'parentOrgId'"
|
v-if="item.prop === 'parentOrgId'"
|
||||||
v-model="formModel[item.prop]"
|
v-model="formModel[item.prop]"
|
||||||
|
:disabled="formDisabled"
|
||||||
lazy
|
lazy
|
||||||
|
:data="treeData"
|
||||||
:load="loadSelectTreeData"
|
:load="loadSelectTreeData"
|
||||||
check-strictly
|
check-strictly
|
||||||
:props="treeSelectReplaceProps"
|
:props="treeSelectReplaceProps"
|
||||||
@ -41,7 +50,7 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-form>
|
</el-form>
|
||||||
<template #footer>
|
<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>
|
<el-button @click="closeAddForm">关闭</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
@ -61,6 +70,7 @@
|
|||||||
node-key="id"
|
node-key="id"
|
||||||
:props="treeReplaceProps"
|
:props="treeReplaceProps"
|
||||||
@node-click="treeNodeClick"
|
@node-click="treeNodeClick"
|
||||||
|
@node-contextmenu="rightClick"
|
||||||
></el-tree>
|
></el-tree>
|
||||||
</el-main>
|
</el-main>
|
||||||
</el-aside>
|
</el-aside>
|
||||||
@ -70,7 +80,7 @@
|
|||||||
<el-input v-model="searchTableInput" class="searchInput"></el-input>
|
<el-input v-model="searchTableInput" class="searchInput"></el-input>
|
||||||
<el-button @click="searchTable" type="primary" :icon="Search" class="defaultBtn">{{ t('management.search') }}</el-button>
|
<el-button @click="searchTable" type="primary" :icon="Search" class="defaultBtn">{{ t('management.search') }}</el-button>
|
||||||
</div>
|
</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-header>
|
||||||
<el-main class="defaultMain">
|
<el-main class="defaultMain">
|
||||||
<el-table :data="tableData" class="tablePart">
|
<el-table :data="tableData" class="tablePart">
|
||||||
@ -110,11 +120,26 @@
|
|||||||
</el-main>
|
</el-main>
|
||||||
</el-container>
|
</el-container>
|
||||||
</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>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<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 {
|
import {
|
||||||
ElContainer,
|
ElContainer,
|
||||||
ElAside,
|
ElAside,
|
||||||
@ -133,7 +158,7 @@ import {
|
|||||||
ElMessage,
|
ElMessage,
|
||||||
ElPagination,
|
ElPagination,
|
||||||
} from 'element-plus'
|
} 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 type Node from 'element-plus/es/components/tree/src/model/node'
|
||||||
import { Plus, Search } from '@element-plus/icons-vue'
|
import { Plus, Search } from '@element-plus/icons-vue'
|
||||||
import {
|
import {
|
||||||
@ -155,6 +180,7 @@ import {
|
|||||||
getTreeDataReturnType,
|
getTreeDataReturnType,
|
||||||
allEnumType,
|
allEnumType,
|
||||||
} from './type'
|
} from './type'
|
||||||
|
import ContextMenu from '/@/views/backend/auth/model/contextMenu.vue'
|
||||||
import { pcaTextArr } from 'element-china-area-data'
|
import { pcaTextArr } from 'element-china-area-data'
|
||||||
import { useAdminInfo } from '/@/stores/adminInfo'
|
import { useAdminInfo } from '/@/stores/adminInfo'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
@ -281,11 +307,15 @@ const addFormItemList: formItemListType<addDataEnumKeyJointType>[] = [
|
|||||||
]
|
]
|
||||||
const dialogTitle = ref('新增机构')
|
const dialogTitle = ref('新增机构')
|
||||||
const dialogVible = ref(false)
|
const dialogVible = ref(false)
|
||||||
const addInstitutional = () => {
|
const addInstitutional = (rightClick = false) => {
|
||||||
dialogTitle.value = '新增机构'
|
dialogTitle.value = '新增机构'
|
||||||
formModel.value = JSON.parse(JSON.stringify(defaultFormModel))
|
formModel.value = JSON.parse(JSON.stringify(defaultFormModel))
|
||||||
formRef.value && formRef.value.resetFields()
|
formRef.value && formRef.value.resetFields()
|
||||||
dialogVible.value = true
|
dialogVible.value = true
|
||||||
|
if (!rightClick) {
|
||||||
|
formModel.value.parentOrgId = clickTreeMenuData.value?.id!
|
||||||
|
}
|
||||||
|
formDisabled.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
const submitAddForm = () => {
|
const submitAddForm = () => {
|
||||||
@ -294,13 +324,14 @@ const submitAddForm = () => {
|
|||||||
formRef.value.validate((valid) => {
|
formRef.value.validate((valid) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
if (dialogTitle.value === '新增机构') {
|
if (dialogTitle.value === '新增机构') {
|
||||||
|
formModel.value.parentOrgId = formModel.value.parentOrgId ?? '0'
|
||||||
addInstitutionalListReq(formModel.value)
|
addInstitutionalListReq(formModel.value)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
if (res.success) {
|
if (res.success) {
|
||||||
ElMessage.success('新增成功')
|
ElMessage.success('新增成功')
|
||||||
getInstitutionList()
|
getInstitutionList()
|
||||||
dialogVible.value = false
|
dialogVible.value = false
|
||||||
refreshTreeData()
|
refreshTreeData(formModel.value.parentOrgId)
|
||||||
} else {
|
} else {
|
||||||
ElMessage.error(res?.msg ?? '新增失败')
|
ElMessage.error(res?.msg ?? '新增失败')
|
||||||
}
|
}
|
||||||
@ -315,7 +346,7 @@ const submitAddForm = () => {
|
|||||||
ElMessage.success('编辑成功')
|
ElMessage.success('编辑成功')
|
||||||
getInstitutionList()
|
getInstitutionList()
|
||||||
dialogVible.value = false
|
dialogVible.value = false
|
||||||
refreshTreeData()
|
refreshTreeData(formModel.value.parentOrgId)
|
||||||
} else {
|
} else {
|
||||||
ElMessage.error(res?.msg ?? '编辑失败')
|
ElMessage.error(res?.msg ?? '编辑失败')
|
||||||
}
|
}
|
||||||
@ -333,7 +364,6 @@ const closeAddForm = () => {
|
|||||||
|
|
||||||
const getInstitutionList = (data: getDataType = { name: null }) => {
|
const getInstitutionList = (data: getDataType = { name: null }) => {
|
||||||
getInstitutionalListReq(data).then((res) => {
|
getInstitutionalListReq(data).then((res) => {
|
||||||
console.log(res)
|
|
||||||
pageTotal.value = res.total
|
pageTotal.value = res.total
|
||||||
originData.value = res.rows
|
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()
|
formRef.value?.resetFields()
|
||||||
formModel.value = JSON.parse(JSON.stringify(column))
|
formModel.value = JSON.parse(JSON.stringify(column))
|
||||||
dialogTitle.value = '编辑机构'
|
dialogTitle.value = '编辑机构'
|
||||||
dialogVible.value = true
|
dialogVible.value = true
|
||||||
|
formDisabled.value = onlyOpen
|
||||||
}
|
}
|
||||||
|
|
||||||
const delForm = (column: changeDataType) => {
|
const delForm = (column: getTreeDataReturnType) => {
|
||||||
delInstitutionalListReq({ id: column.id })
|
delInstitutionalListReq({ id: column.id })
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
if (res.success) {
|
if (res.success) {
|
||||||
ElMessage.success('删除成功')
|
ElMessage.success('删除成功')
|
||||||
getInstitutionList()
|
getInstitutionList()
|
||||||
refreshTreeData()
|
refreshTreeData(column.parentOrgId)
|
||||||
} else {
|
} else {
|
||||||
ElMessage.error(res?.msg ?? '删除失败')
|
ElMessage.error(res?.msg ?? '删除失败')
|
||||||
}
|
}
|
||||||
@ -438,7 +471,7 @@ const treeSelectReplaceProps = {
|
|||||||
}
|
}
|
||||||
const loadTreeData = (node: Node, resolve: any) => {
|
const loadTreeData = (node: Node, resolve: any) => {
|
||||||
if (node.level === 0) {
|
if (node.level === 0) {
|
||||||
return resolve([])
|
return
|
||||||
}
|
}
|
||||||
getTreeData(node.data.id)
|
getTreeData(node.data.id)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
@ -455,13 +488,12 @@ const loadTreeData = (node: Node, resolve: any) => {
|
|||||||
}
|
}
|
||||||
const loadSelectTreeData = (node: Node, resolve: any) => {
|
const loadSelectTreeData = (node: Node, resolve: any) => {
|
||||||
if (node.level === 0) {
|
if (node.level === 0) {
|
||||||
getTreeData(adminInfo.orgid)
|
return getTreeData(null)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
if (!res.length) {
|
if (!res.length) {
|
||||||
node.data.isLeaf = true
|
node.data.isLeaf = true
|
||||||
}
|
}
|
||||||
|
resolve(res)
|
||||||
return resolve(res)
|
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err)
|
console.log(err)
|
||||||
@ -497,6 +529,7 @@ const initData = () => {
|
|||||||
treeData.value = [...res]
|
treeData.value = [...res]
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
treeRef.value?.setCurrentKey(res[0]?.id!, false)
|
treeRef.value?.setCurrentKey(res[0]?.id!, false)
|
||||||
|
clickTreeMenuData.value = res[0]
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
})
|
})
|
||||||
@ -508,27 +541,51 @@ const initData = () => {
|
|||||||
originData.value = [...res]
|
originData.value = [...res]
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
const currentTreeId = ref<string | number>('')
|
const clickTreeMenuData = ref<getTreeDataReturnType>()
|
||||||
const refreshTreeData = () => {
|
const refreshTreeData = (parentOrgId: string | number | null) => {
|
||||||
getTreeData(currentTreeId.value).then((res) => {
|
const data = parentOrgId === 0 || parentOrgId === '0' ? null : parentOrgId
|
||||||
treeRef.value?.updateKeyChildren(currentTreeId.value, res)
|
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) => {
|
const treeNodeClick = (nodeData: getTreeDataReturnType, node: Node) => {
|
||||||
console.log(node.childNodes, nodeData.isLeaf)
|
|
||||||
if (node.childNodes.length || nodeData.isLeaf) {
|
if (node.childNodes.length || nodeData.isLeaf) {
|
||||||
getTreeData(nodeData.id).then((res) => {
|
getTreeData(nodeData.id).then((res) => {
|
||||||
pageTotal.value = res.length
|
pageTotal.value = res.length
|
||||||
originData.value = [...res]
|
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 searchTableInput = ref('')
|
||||||
const searchTable = () => {
|
const searchTable = () => {
|
||||||
// if (searchTableInput.value === '') return
|
// if (searchTableInput.value === '') return
|
||||||
getInstitutionList({ name: searchTableInput.value, parentOrgId: currentTreeId.value })
|
getInstitutionList({ name: searchTableInput.value, parentOrgId: clickTreeMenuData.value!.id! })
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
initData()
|
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>
|
</style>
|
||||||
|
@ -55,7 +55,7 @@ export type addDataType = {
|
|||||||
address: string
|
address: string
|
||||||
contactPhone: string
|
contactPhone: string
|
||||||
remarks: string
|
remarks: string
|
||||||
parentOrgId: number | null
|
parentOrgId: number | string | null
|
||||||
revision: number
|
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