推荐系统初始化
3
web/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
node_modules
|
||||
.idea
|
||||
dist
|
||||
24
web/README.md
Normal file
@@ -0,0 +1,24 @@
|
||||
# map-web
|
||||
|
||||
## Project setup
|
||||
```
|
||||
npm install
|
||||
```
|
||||
|
||||
### Compiles and hot-reloads for development
|
||||
```
|
||||
npm run serve
|
||||
```
|
||||
|
||||
### Compiles and minifies for production
|
||||
```
|
||||
npm run build
|
||||
```
|
||||
|
||||
### Lints and fixes files
|
||||
```
|
||||
npm run lint
|
||||
```
|
||||
|
||||
### Customize configuration
|
||||
See [Configuration Reference](https://cli.vuejs.org/config/).
|
||||
5
web/babel.config.js
Normal file
@@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
presets: [
|
||||
'@vue/cli-plugin-babel/preset'
|
||||
]
|
||||
}
|
||||
15578
web/package-lock.json
generated
Normal file
72
web/package.json
Normal file
@@ -0,0 +1,72 @@
|
||||
{
|
||||
"name": "web-home",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build",
|
||||
"lint": "vue-cli-service lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@antv/g6": "^4.2.7",
|
||||
"@antv/x6": "^1.30.1",
|
||||
"@antv/x6-vue-shape": "^1.3.1",
|
||||
"@vue/composition-api": "^1.4.9",
|
||||
"axios": "^0.21.1",
|
||||
"core-js": "^3.6.5",
|
||||
"cssnano": "^5.0.8",
|
||||
"echarts": "^5.3.2",
|
||||
"element-ui": "^2.15.10",
|
||||
"js-base64": "^3.7.2",
|
||||
"js-cookie": "^2.2.0",
|
||||
"less-loader": "^5.0.0",
|
||||
"lodash": "^4.17.21",
|
||||
"node-sass": "^6.0",
|
||||
"normalize.css": "^8.0.1",
|
||||
"postcss-aspect-ratio-mini": "^1.1.0",
|
||||
"postcss-cssnext": "^3.1.1",
|
||||
"postcss-px-to-viewport": "^1.1.1",
|
||||
"postcss-viewport-units": "^0.1.6",
|
||||
"postcss-write-svg": "^3.0.1",
|
||||
"sortablejs": "^1.14.0",
|
||||
"vue": "^2.6.11",
|
||||
"vue-axios": "^3.2.4",
|
||||
"vue-json-editor": "^1.4.3",
|
||||
"vue-quill-editor": "^3.0.6",
|
||||
"vuex": "^3.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli-plugin-babel": "~4.5.0",
|
||||
"@vue/cli-plugin-eslint": "~4.5.0",
|
||||
"@vue/cli-service": "~4.5.0",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"d3": "^7.4.0",
|
||||
"eslint": "^6.7.2",
|
||||
"eslint-plugin-vue": "^6.2.2",
|
||||
"sass-loader": "^10.0",
|
||||
"stylus-loader": "^3.0.2",
|
||||
"vue-router": "^3.5.1",
|
||||
"vue-template-compiler": "^2.6.11"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"root": true,
|
||||
"env": {
|
||||
"node": true
|
||||
},
|
||||
"extends": [
|
||||
"plugin:vue/essential",
|
||||
"eslint:recommended"
|
||||
],
|
||||
"parserOptions": {
|
||||
"parser": "babel-eslint"
|
||||
},
|
||||
"rules": {
|
||||
"no-unused-vars": "off"
|
||||
}
|
||||
},
|
||||
"browserslist": [
|
||||
"> 1%",
|
||||
"last 2 versions",
|
||||
"not dead"
|
||||
]
|
||||
}
|
||||
14
web/postcss.config.js
Normal file
@@ -0,0 +1,14 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
autoprefixer: {},
|
||||
"postcss-px-to-viewport": {
|
||||
viewportWidth: 1920,//视窗的宽度,对应的是我们设计稿的宽度
|
||||
viewportHeight: 1080,//视窗的高度,对应的是我们设计稿的高度
|
||||
unitPrecision: 5,//制定‘px’转换为视窗单位的小数位数(很多时候无法整除)
|
||||
viewportUnit: 'vw',//指定需要转换成的视窗单位,建议使用vw
|
||||
selectorBlackList: ['ignore', 'tab-bar', 'tab-bar-item'],//指定不需要转换的类,
|
||||
minPixelValue: 1,//小于或等于‘1px’不转换为视窗单位
|
||||
mediaQuery: false//允许在媒体查询中转换为‘px’
|
||||
}
|
||||
}
|
||||
}
|
||||
17
web/public/index.html
Normal file
@@ -0,0 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||
</noscript>
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
</body>
|
||||
</html>
|
||||
BIN
web/public/实例数据.zip
Normal file
BIN
web/public/武器装备-本体模型.xlsx
Normal file
73
web/src/App.vue
Normal file
@@ -0,0 +1,73 @@
|
||||
<template>
|
||||
<div id="app">
|
||||
<router-view></router-view>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'App',
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
body {
|
||||
overflow: auto;
|
||||
min-width: 1280px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
html, body, #app {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.el-table th.is-leaf {
|
||||
background: rgba(250, 250, 250, 1);
|
||||
border-top: 1px solid #EBEEF5;
|
||||
}
|
||||
|
||||
.menu-content {
|
||||
margin: 25px;
|
||||
background: #FFFFFF;
|
||||
overflow: auto;
|
||||
position: absolute;
|
||||
left: 290px;
|
||||
top: 100px;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
padding: 25px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.page-box {
|
||||
text-align: center;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.menu-content .el-table td, .menu-content .el-table th {
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
.avatar-uploader .el-upload {
|
||||
border: 1px dashed #d9d9d9;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.avatar-uploader .el-upload:hover {
|
||||
border-color: #409EFF;
|
||||
}
|
||||
.avatar-uploader-icon {
|
||||
font-size: 28px;
|
||||
color: #8c939d;
|
||||
width: 178px;
|
||||
height: 178px;
|
||||
line-height: 178px;
|
||||
text-align: center;
|
||||
}
|
||||
.avatar {
|
||||
width: 178px;
|
||||
height: 178px;
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
16
web/src/api/user.js
Normal file
@@ -0,0 +1,16 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function login(data) {
|
||||
return request({
|
||||
url: '/login/user',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function getInfoAdmin(data) {
|
||||
return request({
|
||||
url: '/user/info_admin',
|
||||
method: 'post',
|
||||
})
|
||||
}
|
||||
BIN
web/src/assets/404_images/404.png
Normal file
|
After Width: | Height: | Size: 96 KiB |
BIN
web/src/assets/404_images/404_cloud.png
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
BIN
web/src/assets/image/614/1a.jpg
Normal file
|
After Width: | Height: | Size: 171 KiB |
BIN
web/src/assets/image/614/1b.jpg
Normal file
|
After Width: | Height: | Size: 111 KiB |
BIN
web/src/assets/image/614/2a.jpg
Normal file
|
After Width: | Height: | Size: 234 KiB |
BIN
web/src/assets/image/614/2b.jpg
Normal file
|
After Width: | Height: | Size: 212 KiB |
BIN
web/src/assets/image/614/2c.jpg
Normal file
|
After Width: | Height: | Size: 249 KiB |
BIN
web/src/assets/image/614/2d.jpg
Normal file
|
After Width: | Height: | Size: 225 KiB |
BIN
web/src/assets/image/614/2f.jpg
Normal file
|
After Width: | Height: | Size: 277 KiB |
BIN
web/src/assets/image/614/3a.jpg
Normal file
|
After Width: | Height: | Size: 120 KiB |
BIN
web/src/assets/image/614/3b.jpg
Normal file
|
After Width: | Height: | Size: 131 KiB |
BIN
web/src/assets/image/614/3c.jpg
Normal file
|
After Width: | Height: | Size: 121 KiB |
BIN
web/src/assets/image/614/3d.jpg
Normal file
|
After Width: | Height: | Size: 137 KiB |
BIN
web/src/assets/image/614/3e.jpg
Normal file
|
After Width: | Height: | Size: 136 KiB |
BIN
web/src/assets/image/614/3f.jpg
Normal file
|
After Width: | Height: | Size: 122 KiB |
BIN
web/src/assets/image/614/3g.jpg
Normal file
|
After Width: | Height: | Size: 114 KiB |
BIN
web/src/assets/image/614/3h.jpg
Normal file
|
After Width: | Height: | Size: 121 KiB |
BIN
web/src/assets/image/614/3i.jpg
Normal file
|
After Width: | Height: | Size: 119 KiB |
BIN
web/src/assets/image/614/3j.jpg
Normal file
|
After Width: | Height: | Size: 132 KiB |
BIN
web/src/assets/image/614/3k.jpg
Normal file
|
After Width: | Height: | Size: 126 KiB |
BIN
web/src/assets/image/614/3l.jpg
Normal file
|
After Width: | Height: | Size: 129 KiB |
BIN
web/src/assets/image/614/3m.jpg
Normal file
|
After Width: | Height: | Size: 139 KiB |
BIN
web/src/assets/image/614/3n.jpg
Normal file
|
After Width: | Height: | Size: 124 KiB |
BIN
web/src/assets/image/614/3o.jpg
Normal file
|
After Width: | Height: | Size: 132 KiB |
BIN
web/src/assets/image/614/3p.jpg
Normal file
|
After Width: | Height: | Size: 135 KiB |
BIN
web/src/assets/image/614/3q.jpg
Normal file
|
After Width: | Height: | Size: 128 KiB |
BIN
web/src/assets/image/614/4a.jpg
Normal file
|
After Width: | Height: | Size: 104 KiB |
BIN
web/src/assets/image/614/4b.jpg
Normal file
|
After Width: | Height: | Size: 106 KiB |
BIN
web/src/assets/image/614/4c.jpg
Normal file
|
After Width: | Height: | Size: 92 KiB |
BIN
web/src/assets/image/614/4d.jpg
Normal file
|
After Width: | Height: | Size: 98 KiB |
BIN
web/src/assets/image/614/4e.jpg
Normal file
|
After Width: | Height: | Size: 88 KiB |
BIN
web/src/assets/image/614/4f.jpg
Normal file
|
After Width: | Height: | Size: 116 KiB |
BIN
web/src/assets/image/614/4g.jpg
Normal file
|
After Width: | Height: | Size: 109 KiB |
BIN
web/src/assets/image/614/4h.jpg
Normal file
|
After Width: | Height: | Size: 87 KiB |
BIN
web/src/assets/image/614/4j.jpg
Normal file
|
After Width: | Height: | Size: 92 KiB |
BIN
web/src/assets/image/614/5a.jpg
Normal file
|
After Width: | Height: | Size: 127 KiB |
BIN
web/src/assets/image/614/5b.jpg
Normal file
|
After Width: | Height: | Size: 140 KiB |
BIN
web/src/assets/image/614/5c.jpg
Normal file
|
After Width: | Height: | Size: 102 KiB |
BIN
web/src/assets/image/614/5d.jpg
Normal file
|
After Width: | Height: | Size: 152 KiB |
BIN
web/src/assets/image/614/5e.jpg
Normal file
|
After Width: | Height: | Size: 104 KiB |
BIN
web/src/assets/image/614/5f.jpg
Normal file
|
After Width: | Height: | Size: 160 KiB |
BIN
web/src/assets/image/614/5g.jpg
Normal file
|
After Width: | Height: | Size: 110 KiB |
BIN
web/src/assets/image/614/5h.jpg
Normal file
|
After Width: | Height: | Size: 85 KiB |
BIN
web/src/assets/image/614/6a.jpg
Normal file
|
After Width: | Height: | Size: 132 KiB |
BIN
web/src/assets/image/614/6b.jpg
Normal file
|
After Width: | Height: | Size: 129 KiB |
BIN
web/src/assets/image/614/6c.jpg
Normal file
|
After Width: | Height: | Size: 148 KiB |
BIN
web/src/assets/image/614/6d.jpg
Normal file
|
After Width: | Height: | Size: 129 KiB |
BIN
web/src/assets/image/614/6e.jpg
Normal file
|
After Width: | Height: | Size: 142 KiB |
BIN
web/src/assets/image/614/6f.jpg
Normal file
|
After Width: | Height: | Size: 144 KiB |
BIN
web/src/assets/image/614/6g.jpg
Normal file
|
After Width: | Height: | Size: 168 KiB |
BIN
web/src/assets/image/icon/arrowTop-fill-active.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
web/src/assets/image/icon/arrowTop-fill.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
web/src/assets/image/icon/baocun.png
Normal file
|
After Width: | Height: | Size: 5.9 KiB |
BIN
web/src/assets/image/icon/bg-add.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
web/src/assets/image/icon/changyonggoupiaorenshanchu.png
Normal file
|
After Width: | Height: | Size: 6.0 KiB |
BIN
web/src/assets/image/icon/fanhui.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
web/src/assets/image/icon/search.png
Normal file
|
After Width: | Height: | Size: 5.5 KiB |
BIN
web/src/assets/image/icon/shuxingicon.png
Normal file
|
After Width: | Height: | Size: 8.7 KiB |
BIN
web/src/assets/image/icon/shuxingtu.png
Normal file
|
After Width: | Height: | Size: 5.3 KiB |
BIN
web/src/assets/image/icon/tongji.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
web/src/assets/image/icon/tupian.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
web/src/assets/image/manage-bg.jpg
Normal file
|
After Width: | Height: | Size: 74 KiB |
854
web/src/assets/index.css
Normal file
@@ -0,0 +1,854 @@
|
||||
/** reset **/
|
||||
body, h1, h2, h3, h4, h5, h6, hr, p, blockquote, dl, dt, dd, ul, ol, li, pre, form, fieldset, legend, button, input, textarea, th, td, img{border:medium none;margin: 0;padding: 0;font-size: 100%;}
|
||||
body,button, input, select, textarea{font-size: 14px;line-height: 1.5;font-family: Arial, 'Microsoft Yahei';}
|
||||
h1, h2, h3, h4, h5, h6{font-weight: normal;}
|
||||
em{font-style:normal;}
|
||||
ul, ol{list-style: none;}
|
||||
|
||||
button{background: none;border: none;outline: none;-webkit-appearance: none;}
|
||||
textarea{resize: none;}
|
||||
a{text-decoration: none;color:#333;}
|
||||
a:hover{text-decoration: none;
|
||||
color:#0D6DFF;
|
||||
-moz-transition: all 0.3s ease-in;
|
||||
-webkit-transition: all 0.3s ease-in;
|
||||
-o-transition: all 0.3s ease-in;
|
||||
transition: all 0.3s ease-in;
|
||||
}
|
||||
img{border:0px; outline-width:0px; vertical-align:top;}
|
||||
.clearfix { *zoom: 1; }
|
||||
.clearfix:before, .clearfix:after { display: table; line-height: 0; content: ""; }
|
||||
.clearfix:after { clear: both; }
|
||||
.fl { float:left;}
|
||||
.fr { float:right;}
|
||||
.hide { display:none !important;}
|
||||
.show { display:block !important;}
|
||||
|
||||
|
||||
/*******************************************
|
||||
-****公共样式****-
|
||||
********************************************/
|
||||
html,body{overflow-x: hidden;}
|
||||
.wp{width: 1200px;max-width: 94%;margin: 0 auto;}
|
||||
|
||||
#hd{height: 68px;background: #0571FF;position: relative;z-index: 11;}
|
||||
.hd-logo{height: 100%;line-height: 68px;margin-left: 40px;}
|
||||
.hd-logo img{vertical-align: middle;max-height: 80%;}
|
||||
.hd-nav{margin-left: 9.3%;}
|
||||
.hd-nav ul li{float: left;margin: 0 20px;}
|
||||
.hd-nav ul li h3 a{display: block;line-height: 68px;padding: 0 10px;font-size: 16px;color: #fff;position: relative;overflow: hidden;}
|
||||
.hd-nav ul li h3 a::after{display: block;content: "";width: 100%;height: 2px;position: absolute;bottom: 0;left: 0;}
|
||||
.hd-nav ul li.on h3 a::after{background: #00FF66;-webkit-transition: 0.4s ease;-ms-transition: 0.4s ease;transition: 0.4s ease;}
|
||||
@media screen and (min-width: 1366px) {
|
||||
.hd-nav ul li h3 a:hover::after{background: #00FF66;-webkit-transition: 0.4s ease;-ms-transition: 0.4s ease;transition: 0.4s ease;}
|
||||
}
|
||||
.hd-nav ul li .subnav{position: absolute;width: 100%;left: 0;top: 100%;background: rgba(255, 255, 255, 0.95);padding: 30px;text-align: center;display: none;}
|
||||
.hd-nav ul li .sub-inner{width: 1000px;max-width: 60%;margin: 0 auto;}
|
||||
.hd-nav ul li .sub-inner a{float: left;line-height: 24px;display: inline-block;margin: 5px 40px;}
|
||||
.hd-bar h3{float: left;font-size: 14px;line-height: 20px;border-right: 1px solid #fff;margin: 24px 0 0 0;padding-right: 49px;color: #fff;}
|
||||
.hd-bar .hd-user{padding: 19px 40px 0;height: 68px;position: relative;}
|
||||
.hd-bar .hd-user .photo{display: block;width: 30px;height: 30px;border-radius: 100%;overflow: hidden;}
|
||||
.hd-bar .hd-user .photo img{width: 100%;height: 100%;}
|
||||
.hd-bar .hd-user .dropdown{position: absolute;width: 100%;right: 0;top: 100%;background: rgba(255, 255, 255, 0.3);padding: 0 10px;display: none;}
|
||||
.hd-bar .hd-user .dropdown ul li a{display: block;line-height: 48px;color: rgba(255, 255, 255, 0.5);border-bottom: 1px solid rgba(255, 255, 255, 0.3);}
|
||||
.hd-bar .hd-user .dropdown ul li a:hover{color: #fff;transition: 0.4s ease;}
|
||||
.hd-bar .hd-user .dropdown .signout{display: block;line-height: 38px;color: #fff;}
|
||||
|
||||
|
||||
#ft{background: #222C3A;}
|
||||
#ft .ft-infos{padding: 32px 0;}
|
||||
#ft .ft-infos .hot-line{color: #fff;line-height: 30px;}
|
||||
#ft .ft-infos .hot-line h4{font-size: 18px;margin-bottom: 15px;}
|
||||
#ft .ft-infos .hot-line h4 img{vertical-align: top;margin: 0 10px 0 0;}
|
||||
#ft .ft-infos .hot-line h3{font-size: 22px;letter-spacing: 1px;}
|
||||
#ft .ft-infos dl{float: right;margin-left: 80px;}
|
||||
#ft .ft-infos dl dt{font-size: 16px;line-height: 22px;color: #fff;margin-bottom: 24px;}
|
||||
#ft .ft-infos dl dd{font-size: 12px;line-height: 28px;color: #ccc;}
|
||||
#ft .ft-infos dl dd a{color: #ccc;}
|
||||
#ft .ft-infos dl dd a:hover{color: #fff;}
|
||||
#ft .ft-infos .erweima li{float: left;margin-left: 46px;text-align: center;}
|
||||
#ft .ft-infos .erweima li img{}
|
||||
#ft .ft-infos .erweima li p{line-height: 24px;color: #fff;margin-top: 14px;font-size: 13px;}
|
||||
#ft .copyright{border-top: 1px solid rgba(216, 216, 216, 0.1);padding: 10px 20px;}
|
||||
#ft .copyright p{text-align: center;line-height: 20px;font-size: 12px;color: #888;}
|
||||
|
||||
.sidebar{position: fixed;top: 50%;right: 30px;z-index: 97;width: 48px;-webkit-transform: translateY(-50%);-ms-transform: translateY(-50%);transform: translateY(-50%);}
|
||||
.sidebar a{display: block;width: 48px;height: 48px;box-sizing: border-box;border: 1px solid #e6e6e6;background-color: #fff;}
|
||||
.sidebar .backtop{background-image: url('index/icon3.png');background-size: 100% 100%;margin-top: 36px;transform: translateX(200%);transition: 0.4s;}
|
||||
.sidebar .backtop:hover{background: #0066FF url('index/icon3-on.png');background-size: 100% 100%;border-color: #0066FF;}
|
||||
.sidebar .backtop.backtop-show{transform: translateX(0);transition: 0.4s;}
|
||||
.sidebar .side-inner{border: 1px solid #D7D7D7;background: #fff;border-radius: 4px;box-shadow: 0 0 5px rgba(0, 0, 0, 0.2);position: relative;}
|
||||
.sidebar .side-inner::before{display: block;content: "";width: 4px;height: 4px;border: 1px solid #fff;border-color: #d7d7d7 #d7d7d7 #fff #fff;background: #fff;position: absolute;top: 50%;right: -4px;margin-top: -4px;transform: rotate(45deg);}
|
||||
.sidebar .side-phone{position: relative;}
|
||||
.sidebar .side-phone .phone-num{position: absolute;top: 50%;right: 100%;-webkit-transform: translateY(-50%);-ms-transform: translateY(-50%);transform: translateY(-50%);padding-right: 10px;display: none;}
|
||||
.sidebar .side-phone .phone-num span{display: block;line-height: 56px;padding: 0 15px;white-space: nowrap;font-size: 16px;color: #666;}
|
||||
.sidebar .side-phone:hover .phone-num{display: block;}
|
||||
.sidebar .side-erweima{position: relative;margin-top: 20px;}
|
||||
.sidebar .side-erweima .erweima{position: absolute;top: 50%;right: 100%;-webkit-transform: translateY(-50%);-ms-transform: translateY(-50%);transform: translateY(-50%);padding-right: 10px;display: none;}
|
||||
.sidebar .side-erweima:hover .erweima{display: block;}
|
||||
|
||||
@media screen and (max-width: 1280px) {
|
||||
.hd-nav{margin-left: 5%;}
|
||||
.hd-nav ul li .sub-inner{max-width: 80%;}
|
||||
.hd-nav ul li{margin: 0 12px;}
|
||||
.hd-bar h3{padding-right: 20px;}
|
||||
.hd-bar .hd-user{padding: 19px 20px 0;}
|
||||
|
||||
#ft .ft-infos dl{margin-left: 3%;max-width: 200px;}
|
||||
#ft .ft-infos .erweima li{margin-left: 24px;}
|
||||
#ft .ft-infos .erweima li img{width: 100px;}
|
||||
}
|
||||
|
||||
|
||||
@media screen and (max-width: 1000px) {
|
||||
.hd-nav{margin-left: 3%;}
|
||||
.hd-nav ul li{margin: 0 10px;}
|
||||
.hd-nav ul li .sub-inner{max-width: 94%;}
|
||||
.hd-bar h3{padding-right: 10px;}
|
||||
.hd-bar .hd-user{padding: 19px 8px 0;}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************
|
||||
-****首页样式****-
|
||||
********************************************/
|
||||
#banner{height: 500px;width: 100%;}
|
||||
#banner .wp{height: 100%;position: relative;}
|
||||
#banner .text{float: left;width: 50%;color: #fff;position: relative;top: 50%;-webkit-transform: translateY(-50%);-ms-transform: translateY(-50%);transform: translateY(-50%);}
|
||||
#banner .text h2{font-size: 36px;line-height: 50px;}
|
||||
#banner .text p{font-size: 16px;line-height: 32px;margin-top: 23px;}
|
||||
#banner .text a{display: block;vertical-align: top;margin-top: 46px;width: 201px;line-height: 34px;background: #74FF00;border-radius: 4px;text-align: center;}
|
||||
#banner .img{float: right;width: 50%;height: 100%;position: relative;}
|
||||
#banner .img img{max-width: 90%;max-height: 90%;position: absolute;right: 0;top: 50%;-webkit-transform: translateY(-50%);-ms-transform: translateY(-50%);transform: translateY(-50%);}
|
||||
#banner .swiper-pagination-bullet{width: 18px;height: 18px;background: url('index/hexagon.png');background-size: 100% 100%;}
|
||||
|
||||
.title{text-align: center;margin-bottom: 90px;}
|
||||
.title h3 span{display: inline-block;vertical-align: top;line-height: 40px;font-size: 28px;color: #0D1A26;position: relative;}
|
||||
.title h3 span::before,
|
||||
.title h3 span::after{display: inline-block;content: "";width: 188px;height: 1px;background: #ADBAC6;position: absolute;top: 50%;}
|
||||
.title h3 span::before{left: -236px;}
|
||||
.title h3 span::after{right: -236px;}
|
||||
.title p{margin-top: 28px;font-size: 16px;line-height: 22px;color: #314659;}
|
||||
.title.white h3 span{color: #fff;}
|
||||
.title.white h3 ::before,
|
||||
.title.white h3 ::after{background: #fff;}
|
||||
.title.white p{color: #fff;}
|
||||
|
||||
.index-sec1{padding: 86px 0 130px;}
|
||||
.index-sec1 ul{margin: 0 -14px;}
|
||||
.index-sec1 ul li{float: left;width: 25%;box-sizing: border-box;padding: 0 14px;}
|
||||
.index-sec1 .item-box{padding: 70px 20px 31px;background: #F6F8FA;border-radius: 4px;text-align: center;overflow: hidden;}
|
||||
.index-sec1 .item-box .inner-wp{transition: 0.4s;}
|
||||
.index-sec1 .item-box span{display: block;width: 60px;height: 60px;margin: 0 auto 26px;position: relative;}
|
||||
.index-sec1 .item-box span img{width: 100%;height: 100%;transition: 0.4s;}
|
||||
.index-sec1 .item-box span .img-hover{position: absolute;top: 0;left: 0;opacity: 0;}
|
||||
.index-sec1 .item-box p{font-size: 18px;line-height: 28px;color: #666;}
|
||||
.index-sec1 .item-box a{display: block;display: block;width: 90px;line-height: 32px;margin: 22px auto 0;text-align: center;color: #fff;font-size: 18px;color: #666;cursor: auto}
|
||||
.index-sec1 .item-box:hover{background: #375EEE;transition: 0.4s;}
|
||||
/*.index-sec1 .item-box:hover .inner-wp{transition: 0.4s;transform: translateY(-30px);}*/
|
||||
.index-sec1 .item-box:hover span .img{opacity: 0;transition: 0.4s;}
|
||||
.index-sec1 .item-box:hover span .img-hover{opacity: 1;transition: 0.4s;}
|
||||
.index-sec1 .item-box:hover p{color: #fff;transition: 0.4s;}
|
||||
.index-sec1 .item-box:hover a{transform: translateY(0);transition: 0.4s ease in;color: #fff}
|
||||
|
||||
|
||||
.index-sec2{padding: 72px 0 32px;background: #F6F8FA;}
|
||||
.index-sec2 ul li{float: left;width: 25%;margin-bottom: 88px;text-align: center;}
|
||||
.index-sec2 ul li a{display: block;}
|
||||
.index-sec2 ul li span{display: block;width: 102px;height: 102px;background: #fff;border-radius: 100%;overflow: hidden;margin: 0 auto 40px;transition: 0.4s ease-in-out;}
|
||||
.index-sec2 ul li span img{width: 100%;height: 100%;}
|
||||
.index-sec2 ul li h4{font-size: 18px;line-height: 25px;}
|
||||
.index-sec2 ul li p{color: #385064;height: 40px;overflow: hidden;line-height: 20px;max-width: 188px;margin: 8px auto 0;}
|
||||
.index-sec2 ul li:hover h4{color: #0066FF;transition: 0.4s;}
|
||||
.index-sec2 ul li:hover p{color: #0066FF;transition: 0.4s;}
|
||||
.index-sec2 ul li:hover span{transition: 0.4s ease-in-out;transform: translateY(-10px);}
|
||||
|
||||
|
||||
.index-sec3{background: #396CEF url('index/pattern.png');background-size: 100% 100%;padding: 86px 0 124px;}
|
||||
.index-sec3 .item-swiper{margin: 0 -15px;position: relative;}
|
||||
.index-sec3 .item-swiper .swiper-slide{padding: 0 15px;}
|
||||
.index-sec3 .item-swiper .item-box{display: block;border-radius: 4px;overflow: hidden;}
|
||||
.index-sec3 .item-swiper .item-box .img{overflow: hidden;height: 300px;border-bottom:1px solid #ADBAC6;background: #ffffff;padding: 20px}
|
||||
.index-sec3 .item-swiper .item-box .img span{display: block;height: 100%;border-radius: 4px 4px 0 0;overflow: hidden;}
|
||||
.index-sec3 .item-swiper .item-box .img img{width: 100%;height: 100%;transition: 0.4s;}
|
||||
.index-sec3 .item-swiper .item-box .text{padding: 20px 40px;background: #fff;text-align: center;}
|
||||
.index-sec3 .item-swiper .item-box .text h4{font-size: 16px;line-height: 22px;color: #2A2A2A;}
|
||||
.index-sec3 .item-swiper .item-box .text p{margin-top: 18px;font-size: 12px;line-height: 18px;color: #385064;height: 36px;overflow: hidden;}
|
||||
.index-sec3 .item-swiper .item-box .text .links{margin-top: 16px;}
|
||||
.index-sec3 .item-swiper .item-box .text .links span{display: inline-block;vertical-align: top;width: 36px;height: 36px;border-radius: 100%;overflow: hidden;margin: 0 14px;}
|
||||
.index-sec3 .item-swiper .item-box:hover{filter: grayscale(0%);transition: 0.4s;}
|
||||
.index-sec3 .item-swiper .item-box:hover .img img{transition: 0.4s;transform: scale(1.1);}
|
||||
.index-sec3 .item-swiper .swiper-button-prev,
|
||||
.index-sec3 .item-swiper .swiper-button-next{width: 24px;height: 36px;margin-top: -18px;outline: none;}
|
||||
.index-sec3 .item-swiper .swiper-button-prev{background: url('index/prev.png');background-size: 100% 100%;left: -40px;}
|
||||
.index-sec3 .item-swiper .swiper-button-next{background: url('index/next.png');background-size: 100% 100%;right: -40px;}
|
||||
|
||||
|
||||
|
||||
.index-sec4{padding: 97px 0 100px;}
|
||||
.index-sec4 .title{margin-bottom: 60px;}
|
||||
.index-sec4 ul li{float: left;width: 25%;}
|
||||
.index-sec4 ul li a{display: table-cell;width: 300px;height: 90px;text-align: center;vertical-align: middle;margin-bottom: 30px;}
|
||||
.index-sec4 ul li a img{max-height: 90%;max-width: 90%;}
|
||||
|
||||
|
||||
@media screen and (max-width: 1320px) {
|
||||
.index-sec3 .item-swiper .swiper-button-prev{left: 0px;}
|
||||
.index-sec3 .item-swiper .swiper-button-next{right: 0px;}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************
|
||||
-****内页样式****-
|
||||
********************************************/
|
||||
.page-banner{height: 260px;background: url('index/download-banner.jpg') center 0;position: relative;}
|
||||
.page-banner .text{position: absolute;left: 0;width: 100%;top: 50%;-webkit-transform: translateY(-50%);-ms-transform: translateY(-50%);transform: translateY(-50%);color: #fff;text-align: center;}
|
||||
.page-banner .text h1{font-size: 68px;line-height: 95px;}
|
||||
.page-banner .text h5{font-size: 20px;line-height: 28px;margin-top: 11px;}
|
||||
|
||||
|
||||
|
||||
/* 解决方案 */
|
||||
.solution .sol-wp{width: 1400px;max-width: 94%;margin: 0 auto;}
|
||||
.solution .sol-wp .img{text-align: center;}
|
||||
.solution .sol-wp .img img{max-width: 100%;}
|
||||
|
||||
.solution .sol-sec1{background: #F6F8FA;/* padding: 85px 0 123px; */}
|
||||
.solution .sol-sec2{/* padding: 88px 0 153px; */}
|
||||
.solution .sol-sec3{/* padding: 81px 0 123px; */background: url('index/sol-bg3.png');background-size: 100% 100%;}
|
||||
.solution .sol-sec4{/* padding: 87px 0 99px; */}
|
||||
|
||||
|
||||
/* 资源下载 */
|
||||
.download{padding: 30px 0 129px;}
|
||||
.download>ul>li{padding: 16px 0px 14px 16px;background: #fff;position: relative;}
|
||||
.download ul li .text h4{font-size: 18px;line-height: 25px;color: #0D1A26;margin-bottom: 14px;}
|
||||
.download ul li .text p{font-size: 13px;line-height: 18px;margin-bottom: 7px;color: #555;display: -webkit-box;-webkit-box-orient: vertical;-webkit-line-clamp: 2;overflow: hidden;}
|
||||
.download ul li .text h5{font-size: 12px;line-height: 17px;color: #314659;}
|
||||
.download ul li .btns{position: absolute;right: 16px;top: 50%;margin-top: -25px;height: 50px;}
|
||||
.download ul li .btns a{float: left;}
|
||||
.download ul li .btns a.see-btn{color: #0066FF;line-height: 22px;margin: 14px 20px 0 0;}
|
||||
.download ul li .btns a.download-btn{line-height: 50px;padding: 0 25px;background: #0066FF;border-radius: 4px;color: #fff;}
|
||||
.download ul li:hover{box-shadow: 0px 5px 12px 1px rgba(105, 105, 105, 0.12);z-index: 11;}
|
||||
|
||||
|
||||
/**
|
||||
* Swiper 4.4.2
|
||||
* Most modern mobile touch slider and framework with hardware accelerated transitions
|
||||
* http://www.idangero.us/swiper/
|
||||
*
|
||||
* Copyright 2014-2018 Vladimir Kharlampidi
|
||||
*
|
||||
* Released under the MIT License
|
||||
*
|
||||
* Released on: November 1, 2018
|
||||
*/
|
||||
.swiper-container {
|
||||
margin: 0 auto;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
/* Fix of Webkit flickering */
|
||||
z-index: 1;
|
||||
}
|
||||
.swiper-container-no-flexbox .swiper-slide {
|
||||
float: left;
|
||||
}
|
||||
.swiper-container-vertical > .swiper-wrapper {
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-box-direction: normal;
|
||||
-webkit-flex-direction: column;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column;
|
||||
}
|
||||
.swiper-wrapper {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 1;
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-transition-property: -webkit-transform;
|
||||
transition-property: -webkit-transform;
|
||||
-o-transition-property: transform;
|
||||
transition-property: transform;
|
||||
transition-property: transform, -webkit-transform;
|
||||
-webkit-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
}
|
||||
.swiper-container-android .swiper-slide,
|
||||
.swiper-wrapper {
|
||||
-webkit-transform: translate3d(0px, 0, 0);
|
||||
transform: translate3d(0px, 0, 0);
|
||||
}
|
||||
.swiper-container-multirow > .swiper-wrapper {
|
||||
-webkit-flex-wrap: wrap;
|
||||
-ms-flex-wrap: wrap;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.swiper-container-free-mode > .swiper-wrapper {
|
||||
-webkit-transition-timing-function: ease-out;
|
||||
-o-transition-timing-function: ease-out;
|
||||
transition-timing-function: ease-out;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.swiper-slide {
|
||||
-webkit-flex-shrink: 0;
|
||||
-ms-flex-negative: 0;
|
||||
flex-shrink: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
-webkit-transition-property: -webkit-transform;
|
||||
transition-property: -webkit-transform;
|
||||
-o-transition-property: transform;
|
||||
transition-property: transform;
|
||||
transition-property: transform, -webkit-transform;
|
||||
}
|
||||
.swiper-slide-invisible-blank {
|
||||
visibility: hidden;
|
||||
}
|
||||
/* Auto Height */
|
||||
.swiper-container-autoheight,
|
||||
.swiper-container-autoheight .swiper-slide {
|
||||
height: auto;
|
||||
}
|
||||
.swiper-container-autoheight .swiper-wrapper {
|
||||
-webkit-box-align: start;
|
||||
-webkit-align-items: flex-start;
|
||||
-ms-flex-align: start;
|
||||
align-items: flex-start;
|
||||
-webkit-transition-property: height, -webkit-transform;
|
||||
transition-property: height, -webkit-transform;
|
||||
-o-transition-property: transform, height;
|
||||
transition-property: transform, height;
|
||||
transition-property: transform, height, -webkit-transform;
|
||||
}
|
||||
/* 3D Effects */
|
||||
.swiper-container-3d {
|
||||
-webkit-perspective: 1200px;
|
||||
perspective: 1200px;
|
||||
}
|
||||
.swiper-container-3d .swiper-wrapper,
|
||||
.swiper-container-3d .swiper-slide,
|
||||
.swiper-container-3d .swiper-slide-shadow-left,
|
||||
.swiper-container-3d .swiper-slide-shadow-right,
|
||||
.swiper-container-3d .swiper-slide-shadow-top,
|
||||
.swiper-container-3d .swiper-slide-shadow-bottom,
|
||||
.swiper-container-3d .swiper-cube-shadow {
|
||||
-webkit-transform-style: preserve-3d;
|
||||
transform-style: preserve-3d;
|
||||
}
|
||||
.swiper-container-3d .swiper-slide-shadow-left,
|
||||
.swiper-container-3d .swiper-slide-shadow-right,
|
||||
.swiper-container-3d .swiper-slide-shadow-top,
|
||||
.swiper-container-3d .swiper-slide-shadow-bottom {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
pointer-events: none;
|
||||
z-index: 10;
|
||||
}
|
||||
.swiper-container-3d .swiper-slide-shadow-left {
|
||||
background-image: -webkit-gradient(linear, right top, left top, from(rgba(0, 0, 0, 0.5)), to(rgba(0, 0, 0, 0)));
|
||||
background-image: -webkit-linear-gradient(right, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
|
||||
background-image: -o-linear-gradient(right, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
|
||||
background-image: linear-gradient(to left, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
|
||||
}
|
||||
.swiper-container-3d .swiper-slide-shadow-right {
|
||||
background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, 0.5)), to(rgba(0, 0, 0, 0)));
|
||||
background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
|
||||
background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
|
||||
background-image: linear-gradient(to right, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
|
||||
}
|
||||
.swiper-container-3d .swiper-slide-shadow-top {
|
||||
background-image: -webkit-gradient(linear, left bottom, left top, from(rgba(0, 0, 0, 0.5)), to(rgba(0, 0, 0, 0)));
|
||||
background-image: -webkit-linear-gradient(bottom, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
|
||||
background-image: -o-linear-gradient(bottom, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
|
||||
background-image: linear-gradient(to top, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
|
||||
}
|
||||
.swiper-container-3d .swiper-slide-shadow-bottom {
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(0, 0, 0, 0.5)), to(rgba(0, 0, 0, 0)));
|
||||
background-image: -webkit-linear-gradient(top, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
|
||||
background-image: -o-linear-gradient(top, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
|
||||
background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
|
||||
}
|
||||
/* IE10 Windows Phone 8 Fixes */
|
||||
.swiper-container-wp8-horizontal,
|
||||
.swiper-container-wp8-horizontal > .swiper-wrapper {
|
||||
-ms-touch-action: pan-y;
|
||||
touch-action: pan-y;
|
||||
}
|
||||
.swiper-container-wp8-vertical,
|
||||
.swiper-container-wp8-vertical > .swiper-wrapper {
|
||||
-ms-touch-action: pan-x;
|
||||
touch-action: pan-x;
|
||||
}
|
||||
.swiper-button-prev,
|
||||
.swiper-button-next {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
width: 27px;
|
||||
height: 44px;
|
||||
margin-top: -22px;
|
||||
z-index: 10;
|
||||
cursor: pointer;
|
||||
background-size: 27px 44px;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
.swiper-button-prev.swiper-button-disabled,
|
||||
.swiper-button-next.swiper-button-disabled {
|
||||
opacity: 0.35;
|
||||
cursor: auto;
|
||||
pointer-events: none;
|
||||
}
|
||||
.swiper-button-prev,
|
||||
.swiper-container-rtl .swiper-button-next {
|
||||
background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2027%2044'%3E%3Cpath%20d%3D'M0%2C22L22%2C0l2.1%2C2.1L4.2%2C22l19.9%2C19.9L22%2C44L0%2C22L0%2C22L0%2C22z'%20fill%3D'%23007aff'%2F%3E%3C%2Fsvg%3E");
|
||||
left: 10px;
|
||||
right: auto;
|
||||
}
|
||||
.swiper-button-next,
|
||||
.swiper-container-rtl .swiper-button-prev {
|
||||
background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2027%2044'%3E%3Cpath%20d%3D'M27%2C22L27%2C22L5%2C44l-2.1-2.1L22.8%2C22L2.9%2C2.1L5%2C0L27%2C22L27%2C22z'%20fill%3D'%23007aff'%2F%3E%3C%2Fsvg%3E");
|
||||
right: 10px;
|
||||
left: auto;
|
||||
}
|
||||
.swiper-button-prev.swiper-button-white,
|
||||
.swiper-container-rtl .swiper-button-next.swiper-button-white {
|
||||
background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2027%2044'%3E%3Cpath%20d%3D'M0%2C22L22%2C0l2.1%2C2.1L4.2%2C22l19.9%2C19.9L22%2C44L0%2C22L0%2C22L0%2C22z'%20fill%3D'%23ffffff'%2F%3E%3C%2Fsvg%3E");
|
||||
}
|
||||
.swiper-button-next.swiper-button-white,
|
||||
.swiper-container-rtl .swiper-button-prev.swiper-button-white {
|
||||
background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2027%2044'%3E%3Cpath%20d%3D'M27%2C22L27%2C22L5%2C44l-2.1-2.1L22.8%2C22L2.9%2C2.1L5%2C0L27%2C22L27%2C22z'%20fill%3D'%23ffffff'%2F%3E%3C%2Fsvg%3E");
|
||||
}
|
||||
.swiper-button-prev.swiper-button-black,
|
||||
.swiper-container-rtl .swiper-button-next.swiper-button-black {
|
||||
background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2027%2044'%3E%3Cpath%20d%3D'M0%2C22L22%2C0l2.1%2C2.1L4.2%2C22l19.9%2C19.9L22%2C44L0%2C22L0%2C22L0%2C22z'%20fill%3D'%23000000'%2F%3E%3C%2Fsvg%3E");
|
||||
}
|
||||
.swiper-button-next.swiper-button-black,
|
||||
.swiper-container-rtl .swiper-button-prev.swiper-button-black {
|
||||
background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2027%2044'%3E%3Cpath%20d%3D'M27%2C22L27%2C22L5%2C44l-2.1-2.1L22.8%2C22L2.9%2C2.1L5%2C0L27%2C22L27%2C22z'%20fill%3D'%23000000'%2F%3E%3C%2Fsvg%3E");
|
||||
}
|
||||
.swiper-button-lock {
|
||||
display: none;
|
||||
}
|
||||
.swiper-pagination {
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
-webkit-transition: 300ms opacity;
|
||||
-o-transition: 300ms opacity;
|
||||
transition: 300ms opacity;
|
||||
-webkit-transform: translate3d(0, 0, 0);
|
||||
transform: translate3d(0, 0, 0);
|
||||
z-index: 10;
|
||||
}
|
||||
.swiper-pagination.swiper-pagination-hidden {
|
||||
opacity: 0;
|
||||
}
|
||||
/* Common Styles */
|
||||
.swiper-pagination-fraction,
|
||||
.swiper-pagination-custom,
|
||||
.swiper-container-horizontal > .swiper-pagination-bullets {
|
||||
bottom: 10px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
}
|
||||
/* Bullets */
|
||||
.swiper-pagination-bullets-dynamic {
|
||||
overflow: hidden;
|
||||
font-size: 0;
|
||||
}
|
||||
.swiper-pagination-bullets-dynamic .swiper-pagination-bullet {
|
||||
-webkit-transform: scale(0.33);
|
||||
-ms-transform: scale(0.33);
|
||||
transform: scale(0.33);
|
||||
position: relative;
|
||||
}
|
||||
.swiper-pagination-bullets-dynamic .swiper-pagination-bullet-active {
|
||||
-webkit-transform: scale(1);
|
||||
-ms-transform: scale(1);
|
||||
transform: scale(1);
|
||||
}
|
||||
.swiper-pagination-bullets-dynamic .swiper-pagination-bullet-active-main {
|
||||
-webkit-transform: scale(1);
|
||||
-ms-transform: scale(1);
|
||||
transform: scale(1);
|
||||
}
|
||||
.swiper-pagination-bullets-dynamic .swiper-pagination-bullet-active-prev {
|
||||
-webkit-transform: scale(0.66);
|
||||
-ms-transform: scale(0.66);
|
||||
transform: scale(0.66);
|
||||
}
|
||||
.swiper-pagination-bullets-dynamic .swiper-pagination-bullet-active-prev-prev {
|
||||
-webkit-transform: scale(0.33);
|
||||
-ms-transform: scale(0.33);
|
||||
transform: scale(0.33);
|
||||
}
|
||||
.swiper-pagination-bullets-dynamic .swiper-pagination-bullet-active-next {
|
||||
-webkit-transform: scale(0.66);
|
||||
-ms-transform: scale(0.66);
|
||||
transform: scale(0.66);
|
||||
}
|
||||
.swiper-pagination-bullets-dynamic .swiper-pagination-bullet-active-next-next {
|
||||
-webkit-transform: scale(0.33);
|
||||
-ms-transform: scale(0.33);
|
||||
transform: scale(0.33);
|
||||
}
|
||||
.swiper-pagination-bullet {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
display: inline-block;
|
||||
border-radius: 100%;
|
||||
background: #000;
|
||||
opacity: 0.2;
|
||||
}
|
||||
button.swiper-pagination-bullet {
|
||||
border: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
-webkit-box-shadow: none;
|
||||
box-shadow: none;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
}
|
||||
.swiper-pagination-clickable .swiper-pagination-bullet {
|
||||
cursor: pointer;
|
||||
}
|
||||
.swiper-pagination-bullet-active {
|
||||
opacity: 1;
|
||||
background: #007aff;
|
||||
}
|
||||
.swiper-container-vertical > .swiper-pagination-bullets {
|
||||
right: 10px;
|
||||
top: 50%;
|
||||
-webkit-transform: translate3d(0px, -50%, 0);
|
||||
transform: translate3d(0px, -50%, 0);
|
||||
}
|
||||
.swiper-container-vertical > .swiper-pagination-bullets .swiper-pagination-bullet {
|
||||
margin: 6px 0;
|
||||
display: block;
|
||||
}
|
||||
.swiper-container-vertical > .swiper-pagination-bullets.swiper-pagination-bullets-dynamic {
|
||||
top: 50%;
|
||||
-webkit-transform: translateY(-50%);
|
||||
-ms-transform: translateY(-50%);
|
||||
transform: translateY(-50%);
|
||||
width: 8px;
|
||||
}
|
||||
.swiper-container-vertical > .swiper-pagination-bullets.swiper-pagination-bullets-dynamic .swiper-pagination-bullet {
|
||||
display: inline-block;
|
||||
-webkit-transition: 200ms top, 200ms -webkit-transform;
|
||||
transition: 200ms top, 200ms -webkit-transform;
|
||||
-o-transition: 200ms transform, 200ms top;
|
||||
transition: 200ms transform, 200ms top;
|
||||
transition: 200ms transform, 200ms top, 200ms -webkit-transform;
|
||||
}
|
||||
.swiper-container-horizontal > .swiper-pagination-bullets .swiper-pagination-bullet {
|
||||
margin: 0 4px;
|
||||
}
|
||||
.swiper-container-horizontal > .swiper-pagination-bullets.swiper-pagination-bullets-dynamic {
|
||||
left: 50%;
|
||||
-webkit-transform: translateX(-50%);
|
||||
-ms-transform: translateX(-50%);
|
||||
transform: translateX(-50%);
|
||||
white-space: nowrap;
|
||||
}
|
||||
.swiper-container-horizontal > .swiper-pagination-bullets.swiper-pagination-bullets-dynamic .swiper-pagination-bullet {
|
||||
-webkit-transition: 200ms left, 200ms -webkit-transform;
|
||||
transition: 200ms left, 200ms -webkit-transform;
|
||||
-o-transition: 200ms transform, 200ms left;
|
||||
transition: 200ms transform, 200ms left;
|
||||
transition: 200ms transform, 200ms left, 200ms -webkit-transform;
|
||||
}
|
||||
.swiper-container-horizontal.swiper-container-rtl > .swiper-pagination-bullets-dynamic .swiper-pagination-bullet {
|
||||
-webkit-transition: 200ms right, 200ms -webkit-transform;
|
||||
transition: 200ms right, 200ms -webkit-transform;
|
||||
-o-transition: 200ms transform, 200ms right;
|
||||
transition: 200ms transform, 200ms right;
|
||||
transition: 200ms transform, 200ms right, 200ms -webkit-transform;
|
||||
}
|
||||
/* Progress */
|
||||
.swiper-pagination-progressbar {
|
||||
background: rgba(0, 0, 0, 0.25);
|
||||
position: absolute;
|
||||
}
|
||||
.swiper-pagination-progressbar .swiper-pagination-progressbar-fill {
|
||||
background: #007aff;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
-webkit-transform: scale(0);
|
||||
-ms-transform: scale(0);
|
||||
transform: scale(0);
|
||||
-webkit-transform-origin: left top;
|
||||
-ms-transform-origin: left top;
|
||||
transform-origin: left top;
|
||||
}
|
||||
.swiper-container-rtl .swiper-pagination-progressbar .swiper-pagination-progressbar-fill {
|
||||
-webkit-transform-origin: right top;
|
||||
-ms-transform-origin: right top;
|
||||
transform-origin: right top;
|
||||
}
|
||||
.swiper-container-horizontal > .swiper-pagination-progressbar,
|
||||
.swiper-container-vertical > .swiper-pagination-progressbar.swiper-pagination-progressbar-opposite {
|
||||
width: 100%;
|
||||
height: 4px;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
.swiper-container-vertical > .swiper-pagination-progressbar,
|
||||
.swiper-container-horizontal > .swiper-pagination-progressbar.swiper-pagination-progressbar-opposite {
|
||||
width: 4px;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
.swiper-pagination-white .swiper-pagination-bullet-active {
|
||||
background: #ffffff;
|
||||
}
|
||||
.swiper-pagination-progressbar.swiper-pagination-white {
|
||||
background: rgba(255, 255, 255, 0.25);
|
||||
}
|
||||
.swiper-pagination-progressbar.swiper-pagination-white .swiper-pagination-progressbar-fill {
|
||||
background: #ffffff;
|
||||
}
|
||||
.swiper-pagination-black .swiper-pagination-bullet-active {
|
||||
background: #000000;
|
||||
}
|
||||
.swiper-pagination-progressbar.swiper-pagination-black {
|
||||
background: rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
.swiper-pagination-progressbar.swiper-pagination-black .swiper-pagination-progressbar-fill {
|
||||
background: #000000;
|
||||
}
|
||||
.swiper-pagination-lock {
|
||||
display: none;
|
||||
}
|
||||
/* Scrollbar */
|
||||
.swiper-scrollbar {
|
||||
border-radius: 10px;
|
||||
position: relative;
|
||||
-ms-touch-action: none;
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
.swiper-container-horizontal > .swiper-scrollbar {
|
||||
position: absolute;
|
||||
left: 1%;
|
||||
bottom: 3px;
|
||||
z-index: 50;
|
||||
height: 5px;
|
||||
width: 98%;
|
||||
}
|
||||
.swiper-container-vertical > .swiper-scrollbar {
|
||||
position: absolute;
|
||||
right: 3px;
|
||||
top: 1%;
|
||||
z-index: 50;
|
||||
width: 5px;
|
||||
height: 98%;
|
||||
}
|
||||
.swiper-scrollbar-drag {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
border-radius: 10px;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
.swiper-scrollbar-cursor-drag {
|
||||
cursor: move;
|
||||
}
|
||||
.swiper-scrollbar-lock {
|
||||
display: none;
|
||||
}
|
||||
.swiper-zoom-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-pack: center;
|
||||
-webkit-justify-content: center;
|
||||
-ms-flex-pack: center;
|
||||
justify-content: center;
|
||||
-webkit-box-align: center;
|
||||
-webkit-align-items: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
}
|
||||
.swiper-zoom-container > img,
|
||||
.swiper-zoom-container > svg,
|
||||
.swiper-zoom-container > canvas {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
-o-object-fit: contain;
|
||||
object-fit: contain;
|
||||
}
|
||||
.swiper-slide-zoomed {
|
||||
cursor: move;
|
||||
}
|
||||
/* Preloader */
|
||||
.swiper-lazy-preloader {
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
margin-left: -21px;
|
||||
margin-top: -21px;
|
||||
z-index: 10;
|
||||
-webkit-transform-origin: 50%;
|
||||
-ms-transform-origin: 50%;
|
||||
transform-origin: 50%;
|
||||
-webkit-animation: swiper-preloader-spin 1s steps(12, end) infinite;
|
||||
animation: swiper-preloader-spin 1s steps(12, end) infinite;
|
||||
}
|
||||
.swiper-lazy-preloader:after {
|
||||
display: block;
|
||||
content: '';
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg%20viewBox%3D'0%200%20120%20120'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20xmlns%3Axlink%3D'http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink'%3E%3Cdefs%3E%3Cline%20id%3D'l'%20x1%3D'60'%20x2%3D'60'%20y1%3D'7'%20y2%3D'27'%20stroke%3D'%236c6c6c'%20stroke-width%3D'11'%20stroke-linecap%3D'round'%2F%3E%3C%2Fdefs%3E%3Cg%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(30%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(60%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(90%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(120%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(150%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.37'%20transform%3D'rotate(180%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.46'%20transform%3D'rotate(210%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.56'%20transform%3D'rotate(240%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.66'%20transform%3D'rotate(270%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.75'%20transform%3D'rotate(300%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.85'%20transform%3D'rotate(330%2060%2C60)'%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E");
|
||||
background-position: 50%;
|
||||
background-size: 100%;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
.swiper-lazy-preloader-white:after {
|
||||
background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg%20viewBox%3D'0%200%20120%20120'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20xmlns%3Axlink%3D'http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink'%3E%3Cdefs%3E%3Cline%20id%3D'l'%20x1%3D'60'%20x2%3D'60'%20y1%3D'7'%20y2%3D'27'%20stroke%3D'%23fff'%20stroke-width%3D'11'%20stroke-linecap%3D'round'%2F%3E%3C%2Fdefs%3E%3Cg%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(30%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(60%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(90%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(120%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(150%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.37'%20transform%3D'rotate(180%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.46'%20transform%3D'rotate(210%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.56'%20transform%3D'rotate(240%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.66'%20transform%3D'rotate(270%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.75'%20transform%3D'rotate(300%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.85'%20transform%3D'rotate(330%2060%2C60)'%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E");
|
||||
}
|
||||
@-webkit-keyframes swiper-preloader-spin {
|
||||
100% {
|
||||
-webkit-transform: rotate(360deg);
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
@keyframes swiper-preloader-spin {
|
||||
100% {
|
||||
-webkit-transform: rotate(360deg);
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
/* a11y */
|
||||
.swiper-container .swiper-notification {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
z-index: -1000;
|
||||
}
|
||||
.swiper-container-fade.swiper-container-free-mode .swiper-slide {
|
||||
-webkit-transition-timing-function: ease-out;
|
||||
-o-transition-timing-function: ease-out;
|
||||
transition-timing-function: ease-out;
|
||||
}
|
||||
.swiper-container-fade .swiper-slide {
|
||||
pointer-events: none;
|
||||
-webkit-transition-property: opacity;
|
||||
-o-transition-property: opacity;
|
||||
transition-property: opacity;
|
||||
}
|
||||
.swiper-container-fade .swiper-slide .swiper-slide {
|
||||
pointer-events: none;
|
||||
}
|
||||
.swiper-container-fade .swiper-slide-active,
|
||||
.swiper-container-fade .swiper-slide-active .swiper-slide-active {
|
||||
pointer-events: auto;
|
||||
}
|
||||
.swiper-container-cube {
|
||||
overflow: visible;
|
||||
}
|
||||
.swiper-container-cube .swiper-slide {
|
||||
pointer-events: none;
|
||||
-webkit-backface-visibility: hidden;
|
||||
backface-visibility: hidden;
|
||||
z-index: 1;
|
||||
visibility: hidden;
|
||||
-webkit-transform-origin: 0 0;
|
||||
-ms-transform-origin: 0 0;
|
||||
transform-origin: 0 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.swiper-container-cube .swiper-slide .swiper-slide {
|
||||
pointer-events: none;
|
||||
}
|
||||
.swiper-container-cube.swiper-container-rtl .swiper-slide {
|
||||
-webkit-transform-origin: 100% 0;
|
||||
-ms-transform-origin: 100% 0;
|
||||
transform-origin: 100% 0;
|
||||
}
|
||||
.swiper-container-cube .swiper-slide-active,
|
||||
.swiper-container-cube .swiper-slide-active .swiper-slide-active {
|
||||
pointer-events: auto;
|
||||
}
|
||||
.swiper-container-cube .swiper-slide-active,
|
||||
.swiper-container-cube .swiper-slide-next,
|
||||
.swiper-container-cube .swiper-slide-prev,
|
||||
.swiper-container-cube .swiper-slide-next + .swiper-slide {
|
||||
pointer-events: auto;
|
||||
visibility: visible;
|
||||
}
|
||||
.swiper-container-cube .swiper-slide-shadow-top,
|
||||
.swiper-container-cube .swiper-slide-shadow-bottom,
|
||||
.swiper-container-cube .swiper-slide-shadow-left,
|
||||
.swiper-container-cube .swiper-slide-shadow-right {
|
||||
z-index: 0;
|
||||
-webkit-backface-visibility: hidden;
|
||||
backface-visibility: hidden;
|
||||
}
|
||||
.swiper-container-cube .swiper-cube-shadow {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #000;
|
||||
opacity: 0.6;
|
||||
-webkit-filter: blur(50px);
|
||||
filter: blur(50px);
|
||||
z-index: 0;
|
||||
}
|
||||
.swiper-container-flip {
|
||||
overflow: visible;
|
||||
}
|
||||
.swiper-container-flip .swiper-slide {
|
||||
pointer-events: none;
|
||||
-webkit-backface-visibility: hidden;
|
||||
backface-visibility: hidden;
|
||||
z-index: 1;
|
||||
}
|
||||
.swiper-container-flip .swiper-slide .swiper-slide {
|
||||
pointer-events: none;
|
||||
}
|
||||
.swiper-container-flip .swiper-slide-active,
|
||||
.swiper-container-flip .swiper-slide-active .swiper-slide-active {
|
||||
pointer-events: auto;
|
||||
}
|
||||
.swiper-container-flip .swiper-slide-shadow-top,
|
||||
.swiper-container-flip .swiper-slide-shadow-bottom,
|
||||
.swiper-container-flip .swiper-slide-shadow-left,
|
||||
.swiper-container-flip .swiper-slide-shadow-right {
|
||||
z-index: 0;
|
||||
-webkit-backface-visibility: hidden;
|
||||
backface-visibility: hidden;
|
||||
}
|
||||
.swiper-container-coverflow .swiper-wrapper {
|
||||
/* Windows 8 IE 10 fix */
|
||||
-ms-perspective: 1200px;
|
||||
}
|
||||
238
web/src/components/dialog/EdgeAdd.vue
Normal file
@@ -0,0 +1,238 @@
|
||||
<template>
|
||||
<!-- 实例节点的详细信息 -->
|
||||
<div class="node-box">
|
||||
<div class="title">添加关系</div>
|
||||
<el-form ref="form" label-width="80px" :model="form" :rules="rules" style="height: 600px;overflow-y: auto">
|
||||
<el-form-item label="所属关系" prop="edge">
|
||||
<el-select v-model="form.edge" >
|
||||
<el-option v-for="edge in edgeList" :key="edge.Name" :label="edge.comment"
|
||||
:value="edge.Name"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="头节点" prop="srcId">
|
||||
<el-select v-model="form.srcLabel" placeholder="请选择概念" @change="form.srcId = '';srcOptions = []" filterable>
|
||||
<el-option v-for="label in labelList" :key="label.Name" :label="label.comment" :value="label.Name"></el-option>
|
||||
</el-select>
|
||||
<el-select v-model="form.srcId" filterable remote reserve-keyword placeholder="请输入关键词" :remote-method="remoteMethodSrc" @change="changeSelect"
|
||||
:loading="srcLoading">
|
||||
<el-option
|
||||
v-for="item in srcOptions"
|
||||
:key="item.vid"
|
||||
:label="item.properties.name"
|
||||
:value="item.vid">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="尾节点" prop="dstId">
|
||||
<el-select v-model="form.dstLabel" placeholder="请选择概念" @change="form.dstId = '';dstOptions = []" filterable>
|
||||
<el-option v-for="label in labelList" :key="label.Name" :label="label.comment" :value="label.Name"></el-option>
|
||||
</el-select>
|
||||
<el-select v-model="form.dstId" filterable remote reserve-keyword placeholder="请输入关键词" :remote-method="remoteMethodDst" @change="changeSelect"
|
||||
:loading="dstLoading">
|
||||
<el-option
|
||||
v-for="item in dstOptions"
|
||||
:key="item.vid"
|
||||
:label="item.properties.name"
|
||||
:value="item.vid">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="btn-box">
|
||||
<el-button type="primary" @click="submitUpdate">保 存</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import request from '@/utils/request';
|
||||
import {getFirstStringProperty} from "@/utils/common";
|
||||
|
||||
var vm;
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
space: '',
|
||||
form: {
|
||||
edge: '',
|
||||
srcId: '',
|
||||
dstId: '',
|
||||
srcLabel: '',
|
||||
dstLabel: ''
|
||||
},
|
||||
rules: {
|
||||
edge: [
|
||||
{required: true, message: '请选择所属关系'}
|
||||
],
|
||||
srcId: [
|
||||
{required: true, message: '请选择头节点'}
|
||||
],
|
||||
dstId: [
|
||||
{required: true, message: '请选择尾节点'}
|
||||
],
|
||||
},
|
||||
edgeList:[],
|
||||
labelList:[],
|
||||
srcOptions:[],
|
||||
dstOptions:[],
|
||||
srcLoading:false,
|
||||
dstLoading:false
|
||||
}
|
||||
},
|
||||
created() {
|
||||
vm = this;
|
||||
},
|
||||
mounted() {
|
||||
|
||||
},
|
||||
methods: {
|
||||
//模糊搜索
|
||||
remoteMethodSrc(query) {
|
||||
if(vm.form.srcLabel){
|
||||
if (query !== '') {
|
||||
vm.srcLoading = true;
|
||||
request({
|
||||
url: `/nebula_operate/findnodebykeyword/${vm.space}/${vm.form.srcLabel}`,
|
||||
method: 'post',
|
||||
data: {keyword:query}
|
||||
}).then(res => {
|
||||
vm.srcOptions = res.data;
|
||||
vm.srcLoading = false;
|
||||
});
|
||||
} else {
|
||||
vm.form.srcId = "";
|
||||
vm.srcOptions = [];
|
||||
}
|
||||
}else{
|
||||
vm.$message.warning("请输入头节点概念");
|
||||
}
|
||||
|
||||
},
|
||||
//模糊搜索
|
||||
remoteMethodDst(query) {
|
||||
if(vm.form.dstLabel){
|
||||
if (query !== '') {
|
||||
vm.dstLoading = true;
|
||||
request({
|
||||
url: `/nebula_operate/findnodebykeyword/${vm.space}/${vm.form.dstLabel}`,
|
||||
method: 'post',
|
||||
data: {keyword:query}
|
||||
}).then(res => {
|
||||
vm.dstOptions = res.data;
|
||||
vm.dstLoading = false;
|
||||
});
|
||||
} else {
|
||||
vm.form.dstId = "";
|
||||
vm.dstOptions = [];
|
||||
}
|
||||
}else{
|
||||
vm.$message.warning("请输入尾节点概念");
|
||||
}
|
||||
},
|
||||
changeSelect(){
|
||||
|
||||
},
|
||||
queryEdgeList() {
|
||||
request({
|
||||
url: `/nebula_operate/showedge/${vm.space}`,
|
||||
method: 'get',
|
||||
data: {}
|
||||
}).then(res => {
|
||||
vm.edgeList = res.data;
|
||||
});
|
||||
},
|
||||
queryTagList() { // 查询tag列表
|
||||
vm.propsInfoVisible = false;
|
||||
request({
|
||||
url: `/nebula_operate/showtag/${vm.space}`,
|
||||
method: 'get',
|
||||
data: {}
|
||||
}).then(res => {
|
||||
vm.labelList = res.data;
|
||||
});
|
||||
},
|
||||
createItem(space) {
|
||||
vm.space = space;
|
||||
vm.form = {
|
||||
edge: '',
|
||||
srcId: '',
|
||||
dstId: '',
|
||||
srcLabel: '',
|
||||
dstLabel: ''
|
||||
};
|
||||
vm.queryEdgeList();
|
||||
vm.queryTagList();
|
||||
},
|
||||
submitUpdate() { // 更新
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 添加关系
|
||||
request({
|
||||
url: `/nebula_operate/insertedgeline/${vm.space}/${vm.form.edge}`,
|
||||
method: 'post',
|
||||
data: vm.form
|
||||
}).then(res => {
|
||||
vm.$parent.findOnePathBySrcidAndDctid(vm.form.srcId,vm.form.dstId);
|
||||
});
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.form-box {
|
||||
height: 900px;
|
||||
overflow-y: auto;
|
||||
|
||||
}
|
||||
|
||||
.el-input__inner {
|
||||
height: 40px !important;
|
||||
}
|
||||
|
||||
|
||||
.btn-box {
|
||||
text-align: right;
|
||||
margin-top: 25px;
|
||||
}
|
||||
|
||||
.node-box {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.node-box .title {
|
||||
font-size: 18px;
|
||||
margin-bottom: 35px;
|
||||
}
|
||||
|
||||
.form-title {
|
||||
font-size: 16px;
|
||||
margin: 15px 0;
|
||||
|
||||
}
|
||||
|
||||
.add-attribute-box {
|
||||
margin-top: 10px;
|
||||
color: #409EFF;
|
||||
cursor: pointer;
|
||||
text-align: right;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.info-content > div {
|
||||
margin-bottom: 5px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.loading-box {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
250
web/src/components/dialog/EdgeDetail.vue
Normal file
@@ -0,0 +1,250 @@
|
||||
<template>
|
||||
<!-- 实例节点关系的详细信息 -->
|
||||
<div class="node-box">
|
||||
<div class="title"> 关系属性</div>
|
||||
<el-form ref="form" label-width="80px" :model="form" :rules="rules" style="height: 600px;overflow-y: auto">
|
||||
<el-form-item label="类型" prop="labels">
|
||||
<el-select v-model="form.labels" :disabled="editFlag" @change="handleLabelChange">
|
||||
<el-option v-for="label in labelList" :key="label.Name" :label="label.comment"
|
||||
:value="label.Name"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="头实例">
|
||||
<el-input v-model="form.start" disabled></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="尾实例">
|
||||
<el-input v-model="form.end" disabled></el-input>
|
||||
</el-form-item>
|
||||
<div class="loading-box" v-show="loading">
|
||||
<i class="el-icon-loading"></i>
|
||||
<label>查询中</label>
|
||||
</div>
|
||||
<el-form-item :label="item.comment" v-for="item in infoList" :key="item.field">
|
||||
<el-input v-model="item.value"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="btn-box">
|
||||
<el-button type="danger" @click="removeItem" v-show="editFlag">删 除</el-button>
|
||||
<el-button type="primary" @click="submitUpdate">保 存</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import request from '@/utils/request';
|
||||
import {getFirstStringProperty} from "@/utils/common";
|
||||
|
||||
var vm;
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
space: '',
|
||||
editFlag: false,
|
||||
labelList: [],
|
||||
selectObj: {},
|
||||
loading: false,
|
||||
form: {
|
||||
labels: '',
|
||||
start: '',
|
||||
end: '',
|
||||
},
|
||||
infoList: [],
|
||||
rules: {
|
||||
labels: [
|
||||
{required: true, message: '请选择类型'}
|
||||
],
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
vm = this;
|
||||
},
|
||||
mounted() {
|
||||
},
|
||||
methods: {
|
||||
queryEdgeList() {
|
||||
vm.propsInfoVisible = false;
|
||||
request({
|
||||
url: `/nebula_operate/showedge/${vm.space}`,
|
||||
method: 'get',
|
||||
data: {}
|
||||
}).then(res => {
|
||||
vm.labelList = res.data;
|
||||
});
|
||||
},
|
||||
createItem(space, srcId, dstId) {
|
||||
vm.editFlag = false;
|
||||
vm.space = space;
|
||||
vm.form.labels = "";
|
||||
vm.infoList = [];
|
||||
vm.selectObj.vid = null;
|
||||
vm.selectObj.srcId = srcId;
|
||||
vm.selectObj.dstId = dstId;
|
||||
vm.queryNodeForEdge(srcId, 'start');
|
||||
vm.queryNodeForEdge(dstId, 'end');
|
||||
vm.queryEdgeList();
|
||||
},
|
||||
queryDetail(space, {edgeType, srcVid, dstVid}) {
|
||||
vm.editFlag = true;
|
||||
vm.space = space;
|
||||
vm.queryEdgeList();
|
||||
vm.queryEdgeDetail(edgeType, srcVid, dstVid);
|
||||
},
|
||||
queryNodeForEdge(vid, comment) {
|
||||
request({
|
||||
url: `/nebula_operate/findnodebyid/${vm.space}/${vid}`,
|
||||
method: 'get',
|
||||
data: {}
|
||||
}).then(res => {
|
||||
vm.form[comment] = getFirstStringProperty(res.data.properties);
|
||||
});
|
||||
},
|
||||
queryEdgeDetail(edgeType, srcVid, dstVid) {
|
||||
vm.queryNodeForEdge(srcVid, 'start');
|
||||
vm.queryNodeForEdge(dstVid, 'end');
|
||||
vm.selectObj = {
|
||||
srcId: srcVid,
|
||||
dstId: dstVid
|
||||
};
|
||||
request({
|
||||
url: `/nebula_operate/descedge/${vm.space}/${edgeType}`,
|
||||
method: 'get',
|
||||
data: {}
|
||||
}).then(res0 => {
|
||||
let map = {};
|
||||
res0.data.forEach(item => {
|
||||
map[item.field] = item.comment;
|
||||
});
|
||||
request({
|
||||
url: `/nebula_operate/findrelationbyid/${vm.space}/${edgeType}/${srcVid}/${dstVid}`,
|
||||
method: 'get',
|
||||
data: {}
|
||||
}).then(res => {
|
||||
vm.form.labels = res.data.edgeName;
|
||||
vm.resolveProperties(res.data.properties, map);
|
||||
});
|
||||
});
|
||||
|
||||
},
|
||||
handleLabelChange() {
|
||||
vm.loading = true;
|
||||
request({
|
||||
url: `/nebula_operate/descedge/${vm.space}/${vm.form.labels}`,
|
||||
method: 'get',
|
||||
data: {}
|
||||
}).then(res => {
|
||||
vm.loading = false;
|
||||
vm.infoList = res.data;
|
||||
});
|
||||
},
|
||||
resolveProperties(properties, map) { // 处理节点和边的属性
|
||||
let _infoList = [];
|
||||
Reflect.ownKeys(properties).forEach(key => {
|
||||
_infoList.push({
|
||||
comment: map[key],
|
||||
field: key,
|
||||
value: properties[key]
|
||||
});
|
||||
});
|
||||
vm.infoList = _infoList;
|
||||
},
|
||||
removeItem() {
|
||||
this.$confirm('此操作将永久删除选中关系, 是否继续?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
request({
|
||||
url: `/nebula_operate/deleteedgeline/${vm.space}/${vm.form.labels}`,
|
||||
method: 'post',
|
||||
data: {
|
||||
srcId: vm.selectObj.srcId,
|
||||
dstId: vm.selectObj.dstId,
|
||||
}
|
||||
}).then(res => {
|
||||
vm.$message.success("删除成功");
|
||||
vm.$parent.querySpaceGraphData();
|
||||
});
|
||||
}).catch(() => {
|
||||
});
|
||||
},
|
||||
submitUpdate() { // 更新
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
let _ob = {};
|
||||
vm.infoList.forEach(info => {
|
||||
_ob[info.field] = info.value;
|
||||
});
|
||||
// 添加关系
|
||||
request({
|
||||
url: `/nebula_operate/insertedgeline/${vm.space}/${vm.form.labels}`,
|
||||
method: 'post',
|
||||
data: {
|
||||
srcId: vm.selectObj.srcId,
|
||||
dstId: vm.selectObj.dstId,
|
||||
ob: _ob
|
||||
}
|
||||
}).then(res => {
|
||||
vm.$parent.querySpaceGraphData();
|
||||
});
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.form-box {
|
||||
height: 900px;
|
||||
overflow-y: auto;
|
||||
|
||||
}
|
||||
|
||||
.el-input__inner {
|
||||
height: 40px !important;
|
||||
}
|
||||
|
||||
|
||||
.btn-box {
|
||||
text-align: right;
|
||||
margin-top: 25px;
|
||||
}
|
||||
|
||||
.node-box {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.node-box .title {
|
||||
font-size: 18px;
|
||||
margin-bottom: 35px;
|
||||
}
|
||||
|
||||
.form-title {
|
||||
font-size: 16px;
|
||||
margin: 15px 0;
|
||||
|
||||
}
|
||||
|
||||
.add-attribute-box {
|
||||
margin-top: 10px;
|
||||
color: #409EFF;
|
||||
cursor: pointer;
|
||||
text-align: right;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.info-content > div {
|
||||
margin-bottom: 5px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.loading-box {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
270
web/src/components/dialog/EdgeTypeModify.vue
Normal file
@@ -0,0 +1,270 @@
|
||||
<template>
|
||||
<!-- 边类型信息修改 -->
|
||||
<div class="node-box">
|
||||
<div class="title">{{ editFlag ? '编辑' : '新建' }}</div>
|
||||
<el-form ref="relationForm" label-width="100px" label-position="left">
|
||||
<el-form-item label="*边类型名称">
|
||||
<el-input v-model="modifyCmd.name" :disabled="editFlag"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="描述">
|
||||
<el-input v-model="modifyCmd.comment"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="form-title">定义属性</div>
|
||||
<el-table :data="fields"
|
||||
border
|
||||
style="width: 100%">
|
||||
<el-table-column prop="field" label="属性名称"></el-table-column>
|
||||
<el-table-column prop="type" label="数据类型"></el-table-column>
|
||||
<!-- <el-table-column prop="Null" label="允许空值"></el-table-column>-->
|
||||
<!-- <el-table-column prop="Default" label="默认值"></el-table-column>-->
|
||||
<!-- <el-table-column prop="Comment" label="描述"></el-table-column>-->
|
||||
<el-table-column label="操作" width="120">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="text" size="small" @click="modifyField(scope.row, scope.$index)">编辑</el-button>
|
||||
<el-button type="text" size="small" @click="removeField(scope.row, scope.$index)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="add-attribute-box" @click="showAddFieldDialog('source')">添加字段</div>
|
||||
<br/>
|
||||
<br/>
|
||||
<div class="btn-box">
|
||||
<el-button type="danger" @click="removeEdge" v-show="editFlag">删 除</el-button>
|
||||
<el-button type="primary" @click="submitUpdateNode" >保 存</el-button>
|
||||
</div>
|
||||
<el-dialog
|
||||
:title="dialogName"
|
||||
:append-to-body="true"
|
||||
:visible.sync="fieldDialogVisible"
|
||||
width="40%">
|
||||
<el-form ref="fieldCmd" label-width="80px">
|
||||
<el-form-item label="属性名称">
|
||||
<el-input v-model="fieldCmd.field" :disabled="dialogName == '编辑属性'"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="数据类型">
|
||||
<el-select v-model="fieldCmd.type" style="width: 100%">
|
||||
<el-option :label="item" :value="item" v-for="item in dataType"
|
||||
:key="item"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="允许空值">-->
|
||||
<!-- <el-switch-->
|
||||
<!-- v-model="fieldCmd.Null"-->
|
||||
<!-- active-color="#13ce66"-->
|
||||
<!-- inactive-color="#ff4949"-->
|
||||
<!-- active-value="YES"-->
|
||||
<!-- inactive-value="NO">-->
|
||||
<!-- </el-switch>-->
|
||||
<!-- </el-form-item>-->
|
||||
<!-- <el-form-item label="默认值">-->
|
||||
<!-- <el-input v-model="fieldCmd.Default"></el-input>-->
|
||||
<!-- </el-form-item>-->
|
||||
<!-- <el-form-item label="描述">-->
|
||||
<!-- <el-input v-model="fieldCmd.Comment" type="textarea"></el-input>-->
|
||||
<!-- </el-form-item>-->
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="fieldDialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="submitAddField">确 定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import request from '@/utils/request';
|
||||
|
||||
var vm;
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
space: '',
|
||||
modifyCmd: {
|
||||
name: '',
|
||||
fields: []
|
||||
},
|
||||
editFlag: false,
|
||||
fields: [],
|
||||
fieldDialogVisible: false,
|
||||
fieldCmd: {
|
||||
field: '',
|
||||
type: ''
|
||||
},
|
||||
dialogName: '添加属性',
|
||||
selectObj: {
|
||||
type: '',
|
||||
value: {}
|
||||
},
|
||||
dataType: ["INT64", "INT32", "INT16", "INT8", "FLOAT", "DOUBLE", "BOOL", "STRING", "DATE", "TIME", "DATETIME", "FIXED_STRING"],
|
||||
}
|
||||
},
|
||||
created() {
|
||||
vm = this;
|
||||
},
|
||||
mounted() {
|
||||
|
||||
},
|
||||
methods: {
|
||||
updateValue(space, name) {
|
||||
vm.space = space;
|
||||
vm.modifyCmd.name = name;
|
||||
if (name.length > 0) {
|
||||
vm.queryEdgeDescribe();
|
||||
request({
|
||||
url: `/nebula_operate/showcreateedge/${vm.space}/${vm.modifyCmd.name}`,
|
||||
method: 'get',
|
||||
data: {}
|
||||
}).then(res => {
|
||||
vm.modifyCmd.comment = res.data.comment;
|
||||
vm.modifyCmd = JSON.parse(JSON.stringify(vm.modifyCmd))
|
||||
});
|
||||
vm.editFlag = true;
|
||||
} else {
|
||||
vm.editFlag = false;
|
||||
vm.fields = [];
|
||||
}
|
||||
},
|
||||
queryEdgeDescribe() {
|
||||
request({
|
||||
url: `/nebula_operate/descedge/${vm.space}/${vm.modifyCmd.name}`,
|
||||
method: 'get',
|
||||
data: {}
|
||||
}).then(res => {
|
||||
res.data.forEach(item => {
|
||||
item.type = item.type.toUpperCase();
|
||||
});
|
||||
vm.fields = res.data;
|
||||
});
|
||||
},
|
||||
modifyField(item, index) {
|
||||
vm.dialogName = '编辑属性';
|
||||
vm.fieldCmd = JSON.parse(JSON.stringify(item));
|
||||
vm.fieldCmd.index = index;
|
||||
vm.fieldDialogVisible = true;
|
||||
},
|
||||
removeField(item, index) {
|
||||
vm.fields.splice(index, 1);
|
||||
if (vm.editFlag) { // 编辑tag,需要提交请求
|
||||
vm.modifyCmd.fields = [item];
|
||||
request({
|
||||
url: `/nebula_operate/alterdropedge/${vm.space}`,
|
||||
method: 'post',
|
||||
data: vm.modifyCmd
|
||||
}).then(res => {
|
||||
vm.fieldDialogVisible = false;
|
||||
});
|
||||
}
|
||||
},
|
||||
showAddFieldDialog(type) {
|
||||
vm.fieldCmd = {
|
||||
field: '',
|
||||
type: '',
|
||||
null: 'YES',
|
||||
};
|
||||
vm.dialogName = '添加属性';
|
||||
vm.fieldDialogVisible = true;
|
||||
},
|
||||
submitAddField() {
|
||||
if (!vm.editFlag) { // 新建的tag,不需要即时提交
|
||||
if (vm.dialogName == '添加属性') {
|
||||
vm.fields.push(vm.fieldCmd);
|
||||
} else if (vm.dialogName == '编辑属性') {
|
||||
vm.fields[vm.fieldCmd.index] = vm.fieldCmd;
|
||||
}
|
||||
vm.fieldDialogVisible = false;
|
||||
} else {
|
||||
vm.modifyCmd.fields = [vm.fieldCmd];
|
||||
if (vm.dialogName == '添加属性') {
|
||||
request({
|
||||
url: `/nebula_operate/alteraddedge/${vm.space}`,
|
||||
method: 'post',
|
||||
data: vm.modifyCmd
|
||||
}).then(res => {
|
||||
vm.fields.push(vm.fieldCmd);
|
||||
vm.fieldDialogVisible = false;
|
||||
});
|
||||
} else if (vm.dialogName == '编辑属性') {
|
||||
request({
|
||||
url: `/nebula_operate/alterchangeedge/${vm.space}`,
|
||||
method: 'post',
|
||||
data: vm.modifyCmd
|
||||
}).then(res => {
|
||||
vm.fields[vm.fieldCmd.index] = vm.fieldCmd;
|
||||
vm.fieldDialogVisible = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
submitUpdateNode() { // 更新
|
||||
if(vm.modifyCmd.name.length === 0) {
|
||||
vm.$message.warning("边类型名称不能为空");
|
||||
return false;
|
||||
}
|
||||
vm.modifyCmd.fields = vm.fields;
|
||||
if (!vm.editFlag) { // 新建
|
||||
request({
|
||||
url: `/nebula_operate/createedge/${vm.space}`,
|
||||
method: 'post',
|
||||
data: vm.modifyCmd
|
||||
}).then(res => {
|
||||
vm.$parent.queryEdgeList();
|
||||
});
|
||||
} else { // 编辑
|
||||
vm.$parent.queryEdgeList();
|
||||
}
|
||||
},
|
||||
removeEdge() {
|
||||
vm.$confirm('此操作将永久删除记录, 是否继续?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
request({
|
||||
url: `/nebula_operate/dropedge/${vm.space}/${vm.modifyCmd.name}`,
|
||||
method: 'get',
|
||||
data: {}
|
||||
}).then(res => {
|
||||
vm.$message.success("删除成功");
|
||||
vm.$parent.queryEdgeList();
|
||||
});
|
||||
}).catch(() => {
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
.btn-box {
|
||||
text-align: right;
|
||||
margin-top: 25px;
|
||||
}
|
||||
|
||||
.node-box {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.form-title {
|
||||
font-size: 16px;
|
||||
margin: 15px 0;
|
||||
|
||||
}
|
||||
|
||||
.add-attribute-box {
|
||||
margin-top: 10px;
|
||||
color: #409EFF;
|
||||
cursor: pointer;
|
||||
text-align: right;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.info-content > div {
|
||||
margin-bottom: 5px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
144
web/src/components/dialog/GraphSpaceAdd.vue
Normal file
@@ -0,0 +1,144 @@
|
||||
<template>
|
||||
<el-dialog title="新建实例" :visible.sync="cmdDialogVisible" width="40%">
|
||||
<el-steps :active="active" finish-status="success" style="margin-bottom: 20px">
|
||||
<el-step title="新建实例空间"></el-step>
|
||||
<el-step title="选择本体"></el-step>
|
||||
</el-steps>
|
||||
<el-form ref="cmd" label-width="120px" :model="cmd" v-if="active == 0">
|
||||
<el-form-item label="实例空间名称:">
|
||||
<el-input v-model="cmd.name" style="width: 100%" ></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="实例空间描述:">
|
||||
<el-input v-model="cmd.comment" style="width: 100%" ></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer" v-if="active == 0">
|
||||
<el-button type="primary" @click="createSpace">下一步</el-button>
|
||||
</span>
|
||||
<el-form ref="cmd" label-width="130px" :model="cmd" v-if="active == 1">
|
||||
<el-form-item label="选择本体:">
|
||||
<el-select v-model="cmd.ontologyId" placeholder="请选择本体" style="width: 100%">
|
||||
<el-option v-for="item in ontologyList" :key="item.id" :label="item.name" :value="item.id"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer" v-if="active == 1">
|
||||
<el-button @click="cmdDialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="submitModify" :loading="loading">确 定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import request from "@/utils/request";
|
||||
|
||||
let data;
|
||||
var _this;
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
cmd:{},
|
||||
cmdDialogVisible:false,
|
||||
spaceList:[],
|
||||
active:0,
|
||||
ontologyList:[],
|
||||
}
|
||||
},
|
||||
created() {
|
||||
_this = this;
|
||||
},
|
||||
methods: {
|
||||
queryOntology() {
|
||||
request({
|
||||
url: `/ontology/query_list`,
|
||||
method: 'post',
|
||||
data: {EQI_sourceType: 1}
|
||||
}).then(res => {
|
||||
_this.ontologyList = res.data;
|
||||
});
|
||||
},
|
||||
openDialog() {
|
||||
_this.queryOntology();
|
||||
_this.active = 0;
|
||||
_this.cmd = {
|
||||
ontologyId:"",
|
||||
name:"",
|
||||
comment:""
|
||||
}
|
||||
_this.loading = false;
|
||||
_this.cmdDialogVisible = true;
|
||||
},
|
||||
createSpace(){
|
||||
if(!_this.cmd.name){
|
||||
_this.$message.warning("请输入实例空间名称");
|
||||
return false;
|
||||
}
|
||||
if(!_this.cmd.comment){
|
||||
_this.$message.warning("请输入实例空间描述");
|
||||
return false;
|
||||
}
|
||||
_this.active = 1;
|
||||
},
|
||||
submitModify(){
|
||||
if(!_this.cmd.ontologyId){
|
||||
_this.$message.warning("请选择本体");
|
||||
return false;
|
||||
}
|
||||
|
||||
_this.loading = true;
|
||||
this.$message({
|
||||
message: '正在初始化图空间,请等待...',
|
||||
type:"info",
|
||||
duration:20000
|
||||
});
|
||||
request({
|
||||
url: '/nebula_operate/createspace',
|
||||
method: 'post',
|
||||
data: {name:_this.cmd.name,comment:_this.cmd.comment}
|
||||
}).then(res => {
|
||||
var timer = setTimeout(function(){
|
||||
request({
|
||||
url: '/nebula_model/initgraphdatabase/'+_this.cmd.ontologyId+'/'+_this.cmd.name,
|
||||
method: 'get',
|
||||
data: {}
|
||||
}).then(res => {
|
||||
_this.$message.success("新建实例成功");
|
||||
clearTimeout(timer);
|
||||
_this.loading = false;
|
||||
_this.cmdDialogVisible = false;
|
||||
_this.$parent.querySpaceList();
|
||||
});
|
||||
},20000)
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
.node-box {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.form-title {
|
||||
font-size: 16px;
|
||||
margin: 15px 0;
|
||||
|
||||
}
|
||||
|
||||
.add-attribute-box {
|
||||
margin-top: 10px;
|
||||
color: #409EFF;
|
||||
cursor: pointer;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.info-content > div {
|
||||
margin-bottom: 5px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
187
web/src/components/dialog/GraphSpaceAdd1.vue
Normal file
@@ -0,0 +1,187 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
title="新建知识图谱实例"
|
||||
:visible.sync="selectModelDialogVisible"
|
||||
width="40%">
|
||||
<el-steps :space="200" :active="activeStep" finish-status="success">
|
||||
<el-step title="知识图谱本体选择"></el-step>
|
||||
<el-step title="知识图谱实例命名"></el-step>
|
||||
</el-steps>
|
||||
<div v-show="activeStep == 1">
|
||||
<div>
|
||||
<el-form :inline="true" :model="modelQo" class="demo-form-inline">
|
||||
<el-form-item>
|
||||
<el-input v-model="modelQo.LIKES_name" placeholder="请输入知识图谱本体名称"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" @click="modelQo.pageNo=1;queryModelData()">搜 索</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<div>
|
||||
<el-table :data="modelResult.records" style="width: 100%" @selection-change="handleSelectionChange"
|
||||
ref="modelTable">
|
||||
<el-table-column
|
||||
type="selection"
|
||||
width="55">
|
||||
</el-table-column>
|
||||
<el-table-column prop="name" label="知识图谱本体"></el-table-column>
|
||||
<el-table-column prop="description" label="本体描述"></el-table-column>
|
||||
<!-- <el-table-column prop="createTime" label="创建时间"></el-table-column>-->
|
||||
</el-table>
|
||||
</div>
|
||||
<div class="page-box">
|
||||
<el-pagination background
|
||||
@current-change="handleModelCurrentChange"
|
||||
:current-page="modelQo.pageNo"
|
||||
:page-size="modelQo.pageSize"
|
||||
layout="total, prev, pager, next"
|
||||
:total="modelResult.total">
|
||||
</el-pagination>
|
||||
</div>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="nextStep">下一步</el-button>
|
||||
</span>
|
||||
</div>
|
||||
<div v-show="activeStep == 2">
|
||||
<el-form ref="cmd" :model="cmd" label-width="180px" :rules="cmdRules">
|
||||
<el-form-item label="知识图谱实例名称" prop="space">
|
||||
<el-input v-model="cmd.space" placeholder="请输入新建的知识图谱实例名称,英文数字下划线组合"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="知识图谱实例描述">
|
||||
<el-input v-model="cmd.spaceComment" placeholder="请输入新建的知识图谱实例描述,中文描述"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="activeStep = 1">上一步</el-button>
|
||||
<el-button type="primary" @click="gotoCreateGraphSpace">确 定</el-button>
|
||||
</span>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import request from "@/utils/request";
|
||||
|
||||
let data;
|
||||
var _this;
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
selectModelDialogVisible: false,
|
||||
activeStep: 1,
|
||||
selectModelId: '',
|
||||
graphSpaceName: '',
|
||||
cmd: {},
|
||||
modelQo: {
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
LIKES_name: '',
|
||||
EQI_sourceType:1
|
||||
},
|
||||
modelResult: {
|
||||
records: [],
|
||||
total: 0
|
||||
},
|
||||
modelSelection: [],
|
||||
cmdRules: {
|
||||
space: [
|
||||
{required: true, message: '请输入知识图谱实例名称', trigger: 'blur'},
|
||||
],
|
||||
},
|
||||
}
|
||||
},
|
||||
created() {
|
||||
_this = this;
|
||||
},
|
||||
methods: {
|
||||
openDialog() {
|
||||
|
||||
_this.modelQo.pageNo = 1;
|
||||
_this.cmd = {
|
||||
space: '',
|
||||
ontologyId: '',
|
||||
spaceComment: ''
|
||||
};
|
||||
_this.activeStep = 1;
|
||||
_this.modelSelection = [];
|
||||
_this.queryModelData();
|
||||
_this.selectModelDialogVisible = true;
|
||||
},
|
||||
handleSelectionChange(val) {
|
||||
if(val.length > 0) {
|
||||
for (let i = 0; i < val.length - 1; i++) {
|
||||
this.$refs.modelTable.toggleRowSelection(val[i]);
|
||||
}
|
||||
_this.modelSelection = [val[val.length - 1]];
|
||||
} else {
|
||||
_this.modelSelection = [];
|
||||
}
|
||||
},
|
||||
nextStep() {
|
||||
if (_this.modelSelection.length == 0) {
|
||||
_this.$message.warning("请选择知识图谱本体");
|
||||
return;
|
||||
}
|
||||
_this.activeStep = 2;
|
||||
},
|
||||
queryModelData() {
|
||||
request({
|
||||
url: '/ontology/query_pages',
|
||||
method: 'post',
|
||||
data: _this.modelQo
|
||||
}).then(res => {
|
||||
_this.modelResult.records = res.data.records;
|
||||
_this.modelResult.total = res.data.total;
|
||||
});
|
||||
},
|
||||
handleModelCurrentChange(val) {
|
||||
_this.modelQo.pageNo = val;
|
||||
_this.queryModelData();
|
||||
},
|
||||
gotoCreateGraphSpace() {
|
||||
_this.$refs['cmd'].validate((valid) => {
|
||||
if (valid) {
|
||||
request({
|
||||
url: `/nebula_model/initgraphdatabase/${_this.modelSelection[0].id}/${_this.cmd.space}`,
|
||||
method: 'get',
|
||||
data: {}
|
||||
}).then(res => {
|
||||
_this.$message.success("创建成功");
|
||||
_this.selectModelDialogVisible = false;
|
||||
_this.$parent.querySpaceList();
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
.node-box {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.form-title {
|
||||
font-size: 16px;
|
||||
margin: 15px 0;
|
||||
|
||||
}
|
||||
|
||||
.add-attribute-box {
|
||||
margin-top: 10px;
|
||||
color: #409EFF;
|
||||
cursor: pointer;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.info-content > div {
|
||||
margin-bottom: 5px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
201
web/src/components/dialog/IndexAdd.vue
Normal file
@@ -0,0 +1,201 @@
|
||||
<template>
|
||||
<!-- 边类型信息修改 -->
|
||||
<div>
|
||||
<el-dialog
|
||||
title="添加"
|
||||
:visible.sync="indexDialogVisible"
|
||||
width="60%">
|
||||
<el-form ref="fieldCmd" label-width="80px">
|
||||
<el-form-item label="索引类型">
|
||||
<el-select v-model="indexCmd.type" style="width: 100%" @change="handleIndexTypeChange">
|
||||
<el-option :label="item" :value="item" v-for="item in indexTypeList"
|
||||
:key="item"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="名称">
|
||||
<el-select v-model="indexCmd.onName" style="width: 100%" @change="handleIndexOnNameChange">
|
||||
<template v-if="indexCmd.type == 'TAG'">
|
||||
<el-option :label="item.Name" :value="item.Name" v-for="item in tagList"
|
||||
:key="item.Name"></el-option>
|
||||
</template>
|
||||
<template v-if="indexCmd.type == 'EDGE'">
|
||||
<el-option :label="item.Name" :value="item.Name" v-for="item in edgeList"
|
||||
:key="item.Name"></el-option>
|
||||
</template>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="索引名称">
|
||||
<el-input v-model="indexCmd.name"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="索引属性">
|
||||
<el-tag style="margin-right: 15px"
|
||||
v-for="tagObj in indexCmd.fields"
|
||||
:key="tagObj.fieldName"
|
||||
@close="handleIndexFieldClose(tagObj)"
|
||||
closable>
|
||||
{{ tagObj.fieldName }}({{ tagObj.len }})
|
||||
</el-tag>
|
||||
<el-button @click="showAddIndexFieldDialog" type="text" size="small">添加</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="indexDialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="submitAddIndex">确 定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
<el-dialog
|
||||
title="添加索引属性"
|
||||
:append-to-body="true"
|
||||
:visible.sync="indexFieldDialogVisible"
|
||||
width="40%">
|
||||
<el-form ref="fieldCmd" label-width="140px">
|
||||
<el-form-item label="选择关联的属性">
|
||||
<el-select v-model="indexFieldCmd.fieldName" style="width: 100%">
|
||||
<el-option :label="item.Field" :value="item.Field" v-for="item in indexFields"
|
||||
:key="item.Field" v-show="filterSelected(item.Field)"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="长度">
|
||||
<el-input v-model="indexFieldCmd.len"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="indexFieldDialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="addFieldToIndexCmd">确 定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import request from '@/utils/request';
|
||||
|
||||
var vm;
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
space: '',
|
||||
tagList: [],
|
||||
edgeList: [],
|
||||
indexDialogVisible: false,
|
||||
indexCmd: {},
|
||||
indexTypeList: ['TAG', 'EDGE'],
|
||||
indexFields: [],
|
||||
indexFieldCmd: {},
|
||||
indexFieldDialogVisible: false
|
||||
}
|
||||
},
|
||||
created() {
|
||||
vm = this;
|
||||
},
|
||||
mounted() {
|
||||
|
||||
},
|
||||
methods: {
|
||||
showAddIndexDialog(space) {
|
||||
vm.space = space;
|
||||
vm.indexCmd = {
|
||||
space: vm.space,
|
||||
onName: '',
|
||||
name: '',
|
||||
type: 'TAG',
|
||||
fields: []
|
||||
};
|
||||
vm.queryTagList();
|
||||
vm.queryEdgeList();
|
||||
vm.indexDialogVisible = true;
|
||||
},
|
||||
queryTagList() {
|
||||
request({
|
||||
url: `/nebula_operate/showtag/${vm.space}`,
|
||||
method: 'get',
|
||||
data: {}
|
||||
}).then(res => {
|
||||
vm.tagList = res.data;
|
||||
});
|
||||
},
|
||||
queryEdgeList() {
|
||||
request({
|
||||
url: `/nebula_operate/showedge/${vm.space}`,
|
||||
method: 'get',
|
||||
data: {}
|
||||
}).then(res => {
|
||||
vm.edgeList = res.data;
|
||||
});
|
||||
},
|
||||
handleIndexTypeChange() {
|
||||
vm.indexCmd.onName = '';
|
||||
vm.indexCmd.fields = [];
|
||||
},
|
||||
handleIndexFieldClose(tagObj) {
|
||||
vm.indexCmd.fields.splice(vm.indexCmd.fields.indexOf(tagObj), 1);
|
||||
},
|
||||
handleIndexOnNameChange() {
|
||||
vm.indexCmd.fields = [];
|
||||
let url = '';
|
||||
if (vm.indexCmd.type == 'TAG') {
|
||||
url = `/nebula_operate/desctag/${vm.space}/${vm.indexCmd.onName}`;
|
||||
} else {
|
||||
url = `/nebula_operate/descedge/${vm.space}/${vm.indexCmd.onName}`;
|
||||
}
|
||||
request({
|
||||
url: url,
|
||||
method: 'get',
|
||||
data: {}
|
||||
}).then(res => {
|
||||
vm.indexFields = res.data;
|
||||
});
|
||||
},
|
||||
showAddIndexFieldDialog() {
|
||||
if (vm.indexCmd.onName.length == 0) {
|
||||
vm.$message.warning("请选择名称");
|
||||
return;
|
||||
}
|
||||
vm.indexFieldCmd = {
|
||||
fieldName: '',
|
||||
len: ''
|
||||
};
|
||||
vm.indexFieldDialogVisible = true;
|
||||
},
|
||||
addFieldToIndexCmd() {
|
||||
vm.indexCmd.fields.push(vm.indexFieldCmd);
|
||||
vm.indexFieldDialogVisible = false;
|
||||
},
|
||||
filterSelected(fieldName) {
|
||||
let _index = vm.indexCmd.fields.findIndex(row => {
|
||||
return row.fieldName == fieldName;
|
||||
});
|
||||
return _index < 0; // 存在了
|
||||
},
|
||||
submitAddIndex() {
|
||||
if (vm.indexCmd.onName.length == 0) {
|
||||
vm.$message.warning("请选择名称");
|
||||
return;
|
||||
}
|
||||
if (vm.indexCmd.name.length == 0) {
|
||||
vm.$message.warning("请填写索引名称");
|
||||
return;
|
||||
}
|
||||
request({
|
||||
url: `/nebula_operate/createindex/${vm.space}`,
|
||||
method: 'post',
|
||||
data: vm.indexCmd
|
||||
}).then(res => {
|
||||
vm.indexDialogVisible = false;
|
||||
vm.$parent.queryIndexList();
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
.info-content > div {
|
||||
margin-bottom: 5px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
224
web/src/components/dialog/NodeDetail.vue
Normal file
@@ -0,0 +1,224 @@
|
||||
<template>
|
||||
<!-- 实例节点的详细信息 -->
|
||||
<div class="node-box">
|
||||
<div class="title">实例属性</div>
|
||||
<el-form ref="form" label-width="80px" :model="form" :rules="rules" style="height: 600px;overflow-y: auto">
|
||||
<el-form-item label="所属概念" prop="labels">
|
||||
<el-select v-model="form.labels" :disabled="editFlag" @change="handleLabelChange">
|
||||
<el-option v-for="label in labelList" :key="label.Name" :label="label.comment"
|
||||
:value="label.Name"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<div class="loading-box" v-show="loading">
|
||||
<i class="el-icon-loading"></i>
|
||||
<label>查询中</label>
|
||||
</div>
|
||||
<el-form-item :label="item.comment" v-for="item in infoList" :key="item.field">
|
||||
<el-input v-model="item.value"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="btn-box">
|
||||
<el-button type="danger" @click="removeItem" v-show="editFlag">删 除</el-button>
|
||||
<el-button type="primary" @click="submitUpdate">保 存</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import request from '@/utils/request';
|
||||
import {getFirstStringProperty} from "@/utils/common";
|
||||
|
||||
var vm;
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
space: '',
|
||||
editFlag: false,
|
||||
labelList: [],
|
||||
selectObj: {},
|
||||
loading: false,
|
||||
form: {
|
||||
labels: '',
|
||||
},
|
||||
infoList: [],
|
||||
rules: {
|
||||
labels: [
|
||||
{required: true, message: '请选择所属概念'}
|
||||
],
|
||||
},
|
||||
tag:""
|
||||
}
|
||||
},
|
||||
created() {
|
||||
vm = this;
|
||||
},
|
||||
mounted() {
|
||||
|
||||
},
|
||||
methods: {
|
||||
queryTagList() { // 查询tag列表
|
||||
vm.propsInfoVisible = false;
|
||||
request({
|
||||
url: `/nebula_operate/showtag/${vm.space}`,
|
||||
method: 'get',
|
||||
data: {}
|
||||
}).then(res => {
|
||||
vm.labelList = res.data;
|
||||
});
|
||||
},
|
||||
createItem(space) {
|
||||
vm.editFlag = false;
|
||||
vm.space = space;
|
||||
vm.form.labels = "";
|
||||
vm.infoList = [];
|
||||
vm.selectObj.vid = null;
|
||||
vm.queryTagList();
|
||||
},
|
||||
queryDetail(space, {tag, vid}) {
|
||||
vm.editFlag = true;
|
||||
vm.space = space;
|
||||
vm.tag = tag;
|
||||
vm.queryTagList();
|
||||
vm.queryNodeDetail(tag, vid);
|
||||
},
|
||||
queryNodeDetail(tag, vid) {
|
||||
vm.selectObj = {
|
||||
vid: vid
|
||||
};
|
||||
request({
|
||||
url: `/nebula_operate/desctag/${vm.space}/${tag}`,
|
||||
method: 'get',
|
||||
data: {}
|
||||
}).then(res0 => {
|
||||
let map = {};
|
||||
res0.data.forEach(item => {
|
||||
map[item.field] = item.comment;
|
||||
});
|
||||
request({
|
||||
url: `/nebula_operate/findnodebyid/${vm.space}/${tag}/${vid}`,
|
||||
method: 'get',
|
||||
data: {}
|
||||
}).then(res => {
|
||||
vm.form.labels = res.data.labels;
|
||||
vm.resolveProperties(res.data.properties, map);
|
||||
});
|
||||
});
|
||||
},
|
||||
handleLabelChange() {
|
||||
vm.loading = true;
|
||||
request({
|
||||
url: `/nebula_operate/desctag/${vm.space}/${vm.form.labels}`,
|
||||
method: 'get',
|
||||
data: {}
|
||||
}).then(res => {
|
||||
vm.loading = false;
|
||||
vm.infoList = res.data;
|
||||
});
|
||||
},
|
||||
resolveProperties(properties, map) { // 处理节点和边的属性
|
||||
let _infoList = [];
|
||||
Reflect.ownKeys(properties).forEach(key => {
|
||||
_infoList.push({
|
||||
comment: map[key],
|
||||
field: key,
|
||||
value: properties[key]
|
||||
});
|
||||
});
|
||||
vm.infoList = _infoList;
|
||||
},
|
||||
removeItem() {
|
||||
this.$confirm('此操作将永久删除选中节点, 是否继续?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
request({
|
||||
url: `/nebula_operate/deletevertex/${vm.selectObj.vid}`,
|
||||
method: 'get',
|
||||
data: {}
|
||||
}).then(res => {
|
||||
vm.$message.success("删除成功");
|
||||
vm.$parent.querySpaceGraphData();
|
||||
});
|
||||
}).catch(() => {
|
||||
});
|
||||
},
|
||||
submitUpdate() { // 更新
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
let _ob = {};
|
||||
vm.infoList.forEach(info => {
|
||||
_ob[info.field] = info.value;
|
||||
});
|
||||
// 添加节点
|
||||
request({
|
||||
url: `/nebula_operate/insertvertex/${vm.space}/${vm.form.labels}`,
|
||||
method: 'post',
|
||||
data: {
|
||||
vid: vm.selectObj.vid,
|
||||
ob: _ob
|
||||
}
|
||||
}).then(res => {
|
||||
vm.$parent.findNodeById(vm.tag,res.data.vid);
|
||||
});
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.form-box {
|
||||
height: 900px;
|
||||
overflow-y: auto;
|
||||
|
||||
}
|
||||
|
||||
.el-input__inner {
|
||||
height: 40px !important;
|
||||
}
|
||||
|
||||
|
||||
.btn-box {
|
||||
text-align: right;
|
||||
margin-top: 25px;
|
||||
}
|
||||
|
||||
.node-box {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.node-box .title {
|
||||
font-size: 18px;
|
||||
margin-bottom: 35px;
|
||||
}
|
||||
|
||||
.form-title {
|
||||
font-size: 16px;
|
||||
margin: 15px 0;
|
||||
|
||||
}
|
||||
|
||||
.add-attribute-box {
|
||||
margin-top: 10px;
|
||||
color: #409EFF;
|
||||
cursor: pointer;
|
||||
text-align: right;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.info-content > div {
|
||||
margin-bottom: 5px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.loading-box {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
174
web/src/components/dialog/NoumenonEdgeModify.vue
Normal file
@@ -0,0 +1,174 @@
|
||||
<template>
|
||||
<!-- 本体间关系信息修改 -->
|
||||
<div class="node-box">
|
||||
<div class="form-title">关系配置</div>
|
||||
<el-form ref="relationForm" label-width="100px" label-position="left">
|
||||
<el-form-item label="*关系名称">
|
||||
<el-input v-model="modifyCmd.edgeName" disabled></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="关系描述">
|
||||
<el-input v-model="modifyCmd.label"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否显示箭头">
|
||||
<el-radio v-model="modifyCmd.arrow" :label="true" disabled>是</el-radio>
|
||||
<el-radio v-model="modifyCmd.arrow" :label="false" disabled>否</el-radio>
|
||||
</el-form-item>
|
||||
<el-form-item label="头概念">
|
||||
<el-input v-model="modifyCmd.start" disabled></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="尾概念">
|
||||
<el-input v-model="modifyCmd.end" disabled></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="form-title">关系属性(选填)</div>
|
||||
<el-table :data="fields"
|
||||
border
|
||||
style="width: 100%">
|
||||
<el-table-column prop="field" label="属性名"></el-table-column>
|
||||
<el-table-column prop="comment" label="描述"></el-table-column>
|
||||
<el-table-column prop="type" label="类型"></el-table-column>
|
||||
<!-- <el-table-column prop="len" label="长度"></el-table-column>-->
|
||||
<el-table-column label="操作" width="80">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="text" size="small" @click="removeAttribute(scope.row, scope.$index)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="add-attribute-box" @click="showAddAttributeDialog('source')">添加字段</div>
|
||||
<el-button type="primary" @click="submitUpdateEdge" style="float: right;margin-top: 20px">确 定</el-button>
|
||||
<el-dialog
|
||||
title="新增属性"
|
||||
:append-to-body="true"
|
||||
:visible.sync="addAttributeDialogVisible"
|
||||
width="40%">
|
||||
<el-form ref="addAttributeCmd" label-width="80px">
|
||||
<el-form-item label="属性名">
|
||||
<el-input v-model="addAttributeCmd.field"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="描述">
|
||||
<el-input v-model="addAttributeCmd.comment"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="类型">
|
||||
<el-select v-model="addAttributeCmd.type" style="width: 100%">
|
||||
<el-option :label="item" :value="item" v-for="item in type" :key="item"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="长度">-->
|
||||
<!-- <el-input v-model="addAttributeCmd.len"></el-input>-->
|
||||
<!-- </el-form-item>-->
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="addAttributeDialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="submitAddAttribute">确 定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import request from '@/utils/request';
|
||||
|
||||
var vm;
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
modifyCmd: {
|
||||
edgeName: '',
|
||||
label: '',
|
||||
arrow: '',
|
||||
start: '',
|
||||
end: ''
|
||||
},
|
||||
fields: [],
|
||||
addAttributeDialogVisible: false,
|
||||
addAttributeCmd: {
|
||||
field: '',
|
||||
type: '',
|
||||
comment: ''
|
||||
},
|
||||
selectObj: {
|
||||
type: '',
|
||||
value: {}
|
||||
},
|
||||
type: ["INT64", "INT32", "INT16", "INT8", "FLOAT", "DOUBLE", "BOOL", "STRING", "DATE", "TIME", "DATETIME", "FIXED_STRING"],
|
||||
}
|
||||
},
|
||||
created() {
|
||||
vm = this;
|
||||
},
|
||||
mounted() {
|
||||
|
||||
},
|
||||
methods: {
|
||||
updateValue(edgeName, label, arrow, fields, sourceVid, targetVid) {
|
||||
vm.modifyCmd = {
|
||||
edgeName: edgeName,
|
||||
label: label,
|
||||
arrow: arrow,
|
||||
start: '',
|
||||
end: ''
|
||||
};
|
||||
vm.fields = fields || [];
|
||||
vm.queryNode(sourceVid, "start");
|
||||
vm.queryNode(targetVid, "end");
|
||||
},
|
||||
queryNode(vid, comment) {
|
||||
request({
|
||||
url: `/nebula_model/findnodebyid/${vm.ontologyId}/${vid}`,
|
||||
method: 'get',
|
||||
data: {}
|
||||
}).then(res => {
|
||||
vm.modifyCmd[comment] = res.data.properties.label;
|
||||
console.log(vm.modifyCmd)
|
||||
});
|
||||
},
|
||||
removeAttribute(item, index) {
|
||||
vm.fields.splice(index, 1);
|
||||
},
|
||||
showAddAttributeDialog(type) {
|
||||
vm.addAttributeCmd = {
|
||||
type: '',
|
||||
field: '',
|
||||
comment: ''
|
||||
};
|
||||
vm.addAttributeDialogVisible = true;
|
||||
vm.attributeType = type;
|
||||
},
|
||||
submitAddAttribute() {
|
||||
vm.fields.push(vm.addAttributeCmd);
|
||||
vm.addAttributeDialogVisible = false;
|
||||
},
|
||||
submitUpdateEdge() { // 更新
|
||||
vm.$parent.submitUpdateEdge(vm.modifyCmd);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
.node-box {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.form-title {
|
||||
font-size: 16px;
|
||||
margin: 15px 0;
|
||||
|
||||
}
|
||||
|
||||
.add-attribute-box {
|
||||
margin-top: 10px;
|
||||
color: #409EFF;
|
||||
cursor: pointer;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.info-content > div {
|
||||
margin-bottom: 5px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
307
web/src/components/dialog/NoumenonInfo.vue
Normal file
@@ -0,0 +1,307 @@
|
||||
<template>
|
||||
<!-- 本体节点信息 -->
|
||||
<div style="display: flex">
|
||||
<div class="node-box" style="flex:1;padding-right: 20px">
|
||||
<div class="form-title">概念描述</div>
|
||||
<el-form ref="relationForm" label-width="100px" label-position="left">
|
||||
<el-form-item label="概念名">
|
||||
<el-input v-model="modifyCmd.tagName" disabled></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="概念描述">
|
||||
<el-input v-model="modifyCmd.label" @change="handleNodeCommentChange"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="form-title">概念属性</div>
|
||||
<el-table :data="fields"
|
||||
height="500"
|
||||
border
|
||||
style="width: 100%">
|
||||
<el-table-column prop="comment" label="属性描述">
|
||||
<template slot-scope="scope">
|
||||
<el-select v-model="scope.row.comment" v-if="scope.$index === fields.length - 1"
|
||||
@change="(fieldId) => {handleFieldSelectChange(fieldId, scope.$index)}" filterable>
|
||||
<template v-for="field in fieldList">
|
||||
<el-option :value="field.id" :label="field.comment" v-if="judgeExist(field)"
|
||||
:key="field.id"></el-option>
|
||||
</template>
|
||||
</el-select>
|
||||
<label v-else>{{ scope.row.comment }}</label>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- <el-table-column prop="comment" label="描述"></el-table-column>-->
|
||||
<el-table-column prop="type" label="类型"></el-table-column>
|
||||
<el-table-column label="删除" width="80">
|
||||
<template slot-scope="scope">
|
||||
<el-button @click.native.prevent="removeField(scope.row,scope.$index)" type="text" size="small">
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<div class="node-box" style="flex:1;border-right: 1px solid #EBEEF5;padding-left: 20px;">
|
||||
<div class="form-title" style="margin-top: 0px">对象属性</div>
|
||||
<el-table :data="relationData"
|
||||
height="675"
|
||||
border
|
||||
style="width: 100%">
|
||||
<el-table-column prop="edgeName" label="关系">
|
||||
<template slot-scope="scope">
|
||||
<el-select v-model="scope.row.label" v-if="scope.$index === relationData.length - 1"
|
||||
@change="handleRelationSelectChange(scope.row.label,scope.row.dstId, scope.$index)" filterable>
|
||||
<template v-for="relation in relationOptions">
|
||||
<el-option :value="relation.label" :label="relation.label"
|
||||
:key="relation.label"></el-option>
|
||||
</template>
|
||||
</el-select>
|
||||
<label v-else>{{ scope.row.label }}</label>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="type" label="尾概念">
|
||||
<template slot-scope="scope">
|
||||
<el-select v-model="scope.row.dstId" v-if="scope.$index === relationData.length - 1"
|
||||
@change="handleRelationSelectChange(scope.row.label,scope.row.dstId, scope.$index)" filterable>
|
||||
<template v-for="node in nodeOptions">
|
||||
<el-option :value="node.ownId" :label="node.label"
|
||||
:key="node.ownId"></el-option>
|
||||
</template>
|
||||
</el-select>
|
||||
<label v-else>{{nodeObj[scope.row.dstId]}}</label>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="删除" width="80">
|
||||
<template slot-scope="scope">
|
||||
<el-button @click.native.prevent="removeRelation(scope.row,scope.$index)" type="text" size="small">
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import request from '@/utils/request';
|
||||
|
||||
var vm;
|
||||
var _ = require('lodash');
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
modifyCmd: {
|
||||
id: '',
|
||||
tagName: '',
|
||||
label: '',
|
||||
ownId:'',
|
||||
ontologyId:''
|
||||
},
|
||||
fields: [],
|
||||
fieldList: [],
|
||||
relationData:[],
|
||||
relationOptions:[],
|
||||
nodeOptions:[],
|
||||
nodeObj:{}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
vm = this;
|
||||
},
|
||||
mounted() {
|
||||
},
|
||||
methods: {
|
||||
updateValue(ontologyId, ownId, id) {
|
||||
vm.queryFieldList(ontologyId);
|
||||
vm.queryRelations(ontologyId);
|
||||
vm.queryNodes(ontologyId, ownId);
|
||||
vm.modifyCmd.id = id;
|
||||
vm.modifyCmd.ownId = ownId;
|
||||
vm.modifyCmd.ontologyId = ontologyId;
|
||||
vm.queryField(ontologyId, ownId)
|
||||
},
|
||||
//查询概念属性
|
||||
queryField(ontologyId,ownId){
|
||||
request({
|
||||
url: `/nebula_model/findnodebyid/${ontologyId}/${ownId}`,
|
||||
method: 'get',
|
||||
data: {}
|
||||
}).then(res => {
|
||||
vm.modifyCmd.tagName = _.get(res.data, "properties.tagName", '');
|
||||
vm.modifyCmd.label = _.get(res.data, "properties.label", '');
|
||||
let _fields = _.get(res.data, "properties.nebulafieldsnapshot", '');
|
||||
if (!_fields) {
|
||||
_fields = [];
|
||||
}
|
||||
_fields.push({
|
||||
comment: '',
|
||||
type: '',
|
||||
field:''
|
||||
});
|
||||
vm.fields = _fields;
|
||||
});
|
||||
},
|
||||
//查询对象属性列表
|
||||
queryRelationData(ontologyId,ownId){
|
||||
vm.relationData = [];
|
||||
request({
|
||||
url: `/nebula_model/findlistpathbyid/${ontologyId}/${ownId}`,
|
||||
method: 'get',
|
||||
data: {}
|
||||
}).then(res => {
|
||||
if(res.data){
|
||||
res.data.forEach(item => {
|
||||
vm.relationData.push({label:item.relation.properties.label,
|
||||
ontologyId:item.relation.properties.ontologyId,srcId:item.relation.srcId,dstId:item.relation.dstId});
|
||||
})
|
||||
}
|
||||
vm.relationData.push({label:"",
|
||||
ontologyId:ontologyId,srcId:ownId,dstId:""});
|
||||
});
|
||||
},
|
||||
//查询关系列表
|
||||
queryRelations(ontologyId){
|
||||
request({
|
||||
url: `/ontology-relation/query_list/${ontologyId}`,
|
||||
method: 'post',
|
||||
data: {}
|
||||
}).then(res => {
|
||||
vm.relationOptions = res.data;
|
||||
});
|
||||
},
|
||||
//查询尾结点列表
|
||||
queryNodes(ontologyId, ownId){
|
||||
request({
|
||||
url: `/ontology-concept/query_list/${ontologyId}`,
|
||||
method: 'post',
|
||||
data: {}
|
||||
}).then(res => {
|
||||
res.data.forEach(item => {
|
||||
vm.nodeObj[item.ownId] = item.label
|
||||
})
|
||||
vm.nodeOptions = res.data;
|
||||
vm.queryRelationData(ontologyId,ownId);
|
||||
});
|
||||
},
|
||||
judgeExist(field) {
|
||||
let index = vm.fields.findIndex(f => {
|
||||
return f.comment === field.comment;
|
||||
});
|
||||
return index < 0;
|
||||
},
|
||||
handleFieldSelectChange(fieldId, rowIndex) { // 值属性选择框变化
|
||||
let fieldIndex = vm.fieldList.findIndex(f => {
|
||||
return f.id === fieldId;
|
||||
});
|
||||
if (fieldId >= 0) {
|
||||
vm.fields[rowIndex] = {
|
||||
comment:vm.fieldList[fieldIndex].comment,
|
||||
type: vm.fieldList[fieldIndex].type,
|
||||
field:vm.fieldList[fieldIndex].field
|
||||
};
|
||||
request({
|
||||
url: '/nebula_model/insertmodelvertex',
|
||||
method: 'post',
|
||||
data: {vid:vm.modifyCmd.ownId,ontologyId:vm.modifyCmd.ontologyId,tagName:vm.modifyCmd.tagName,label:vm.modifyCmd.label,fields:vm.fields}
|
||||
}).then(res => {
|
||||
vm.queryField(vm.modifyCmd.ontologyId, vm.modifyCmd.ownId);
|
||||
vm.$message.success("添加成功");
|
||||
});
|
||||
|
||||
}
|
||||
},
|
||||
//关系、尾结点选择框变化
|
||||
handleRelationSelectChange(label,dstId,rowIndex){
|
||||
if(label && dstId){
|
||||
request({
|
||||
url: '/nebula_model/insertmodeledge',
|
||||
method: 'post',
|
||||
data: vm.relationData[rowIndex]
|
||||
}).then(res => {
|
||||
vm.relationData.push({label:"",
|
||||
ontologyId:vm.modifyCmd.ontologyId,srcId:vm.modifyCmd.ownId,dstId:""});
|
||||
vm.$message.success("添加成功");
|
||||
});
|
||||
}
|
||||
},
|
||||
removeRelation(row,index) { // 删除对象属性
|
||||
// 对接接口
|
||||
request({
|
||||
url: '/nebula_model/deletemodeledge',
|
||||
method: 'post',
|
||||
data: row
|
||||
}).then(res => {
|
||||
vm.$message.success("删除成功");
|
||||
vm.relationData.splice(index,1);
|
||||
vm.relationData.push({label:"",
|
||||
ontologyId:vm.modifyCmd.ontologyId,srcId:vm.modifyCmd.ownId,dstId:""});
|
||||
});
|
||||
},
|
||||
queryFieldList(ontologyId) { // 查询全部的值属性
|
||||
request({
|
||||
url: `/ontology-field/query_list/${ontologyId}`,
|
||||
method: 'post',
|
||||
data: {}
|
||||
}).then(res => {
|
||||
vm.fieldList = res.data;
|
||||
});
|
||||
},
|
||||
removeField(row, index) { // 删除值属性
|
||||
var newFields = JSON.parse(JSON.stringify(vm.fields));
|
||||
newFields.splice(newFields.length - 1,1);
|
||||
newFields.splice(index,1);
|
||||
// 对接接口
|
||||
request({
|
||||
url: '/nebula_model/insertmodelvertex',
|
||||
method: 'post',
|
||||
data: {vid:vm.modifyCmd.ownId,ontologyId:vm.modifyCmd.ontologyId,tagName:vm.modifyCmd.tagName,label:vm.modifyCmd.label,fields:newFields}
|
||||
}).then(res => {
|
||||
vm.queryField(vm.modifyCmd.ontologyId, vm.modifyCmd.ownId);
|
||||
vm.$message.success("删除成功");
|
||||
});
|
||||
},
|
||||
handleNodeCommentChange() { // 概念描述修改,自动保存
|
||||
request({
|
||||
url: '/ontology-concept/modify',
|
||||
method: 'post',
|
||||
data: {
|
||||
ownId: vm.modifyCmd.ownId,
|
||||
label: vm.modifyCmd.label
|
||||
}
|
||||
}).then(res => {
|
||||
vm.$message.success("概念描述修改成功");
|
||||
vm.$parent.queryTreeData();
|
||||
});
|
||||
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.node-box {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.form-title {
|
||||
font-size: 16px;
|
||||
margin: 15px 0;
|
||||
|
||||
}
|
||||
|
||||
.add-attribute-box {
|
||||
margin-top: 10px;
|
||||
color: #409EFF;
|
||||
cursor: pointer;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.info-content > div {
|
||||
margin-bottom: 5px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
142
web/src/components/dialog/NoumenonModify.vue
Normal file
@@ -0,0 +1,142 @@
|
||||
<template>
|
||||
<!-- 本体节点信息修改 -->
|
||||
<div class="node-box">
|
||||
<div class="form-title">节点配置</div>
|
||||
<el-form ref="relationForm" label-width="100px" label-position="left">
|
||||
<el-form-item label="*概念名">
|
||||
<el-input v-model="modifyCmd.tagName" disabled></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="概念描述">
|
||||
<el-input v-model="modifyCmd.label"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="form-title">概念属性(选填)</div>
|
||||
<el-table :data="fields"
|
||||
height="500"
|
||||
border
|
||||
style="width: 100%">
|
||||
<el-table-column prop="field" label="属性名"></el-table-column>
|
||||
<el-table-column prop="comment" label="描述"></el-table-column>
|
||||
<el-table-column prop="type" label="类型"></el-table-column>
|
||||
<el-table-column label="操作" width="80">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="text" size="small" @click="removeAttribute(scope.row, scope.$index)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="add-attribute-box" @click="showAddAttributeDialog('source')">添加字段</div>
|
||||
<el-button type="primary" @click="submitUpdateNode" style="float: right;margin-top: 20px">确 定</el-button>
|
||||
<el-dialog
|
||||
title="新增属性"
|
||||
:append-to-body="true"
|
||||
:visible.sync="addAttributeDialogVisible"
|
||||
width="40%">
|
||||
<el-form ref="addAttributeCmd" label-width="80px">
|
||||
<el-form-item label="属性名称">
|
||||
<el-input v-model="addAttributeCmd.field"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="描述">
|
||||
<el-input v-model="addAttributeCmd.comment"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="类型">
|
||||
<el-select v-model="addAttributeCmd.type" style="width: 100%">
|
||||
<el-option :label="item" :value="item" v-for="item in dataType" :key="item"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="addAttributeDialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="submitAddAttribute">确 定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import request from '@/utils/request';
|
||||
|
||||
var vm;
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
modifyCmd: {
|
||||
vid: '',
|
||||
tagName: '',
|
||||
label: '',
|
||||
},
|
||||
fields: [],
|
||||
addAttributeDialogVisible: false,
|
||||
addAttributeCmd: {
|
||||
field: '',
|
||||
type: '',
|
||||
comment: ''
|
||||
},
|
||||
selectObj: {
|
||||
type: '',
|
||||
value: {}
|
||||
},
|
||||
dataType: ["INT64", "INT32", "INT16", "INT8", "FLOAT", "DOUBLE", "BOOL", "STRING", "DATE", "TIME", "DATETIME", "FIXED_STRING"],
|
||||
}
|
||||
},
|
||||
created() {
|
||||
vm = this;
|
||||
},
|
||||
mounted() {
|
||||
|
||||
},
|
||||
methods: {
|
||||
updateValue(tagName, label, fields) {
|
||||
vm.modifyCmd.tagName = tagName;
|
||||
vm.modifyCmd.label = label;
|
||||
vm.fields = fields;
|
||||
},
|
||||
removeAttribute(item, index) {
|
||||
vm.fields.splice(index, 1);
|
||||
},
|
||||
showAddAttributeDialog(type) {
|
||||
vm.addAttributeCmd = {
|
||||
type: '',
|
||||
field: '',
|
||||
comment: ''
|
||||
};
|
||||
vm.addAttributeDialogVisible = true;
|
||||
vm.attributeType = type;
|
||||
},
|
||||
submitAddAttribute() {
|
||||
vm.fields.push(vm.addAttributeCmd);
|
||||
vm.addAttributeDialogVisible = false;
|
||||
},
|
||||
submitUpdateNode() { // 更新
|
||||
vm.$parent.submitUpdateNode(vm.modifyCmd);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.node-box {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.form-title {
|
||||
font-size: 16px;
|
||||
margin: 15px 0;
|
||||
|
||||
}
|
||||
|
||||
.add-attribute-box {
|
||||
margin-top: 10px;
|
||||
color: #409EFF;
|
||||
cursor: pointer;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.info-content > div {
|
||||
margin-bottom: 5px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
278
web/src/components/dialog/TagModify.vue
Normal file
@@ -0,0 +1,278 @@
|
||||
<template>
|
||||
<!-- 标签信息修改 -->
|
||||
<div class="node-box">
|
||||
<div class="title"> {{ editFlag ? '编辑' : '新建' }}</div>
|
||||
<el-form ref="relationForm" label-width="100px" label-position="left">
|
||||
<el-form-item label="*标签名称">
|
||||
<el-input v-model="modifyCmd.name" :disabled="editFlag"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="描述">
|
||||
<el-input v-model="modifyCmd.comment"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="form-title">定义属性</div>
|
||||
<el-table :data="fields"
|
||||
height="550"
|
||||
border
|
||||
style="width: 100%">
|
||||
<el-table-column prop="comment" label="属性名称"></el-table-column>
|
||||
<el-table-column prop="type" label="数据类型"></el-table-column>
|
||||
<!-- <el-table-column prop="Null" label="允许空值"></el-table-column>-->
|
||||
<!-- <el-table-column prop="Default" label="默认值"></el-table-column>-->
|
||||
<!-- <el-table-column prop="Comment" label="描述"></el-table-column>-->
|
||||
<el-table-column label="操作" width="120">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="text" size="small" @click="modifyField(scope.row, scope.$index)">编辑</el-button>
|
||||
<el-button type="text" size="small" @click="removeField(scope.row, scope.$index)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="add-attribute-box" @click="showAddFieldDialog('source')">添加字段</div>
|
||||
<br/>
|
||||
<br/>
|
||||
<div class="btn-box">
|
||||
<el-button type="danger" @click="removeTag" v-show="editFlag">删 除</el-button>
|
||||
<el-button type="primary" @click="submitUpdateNode">保 存</el-button>
|
||||
</div>
|
||||
<el-dialog
|
||||
:title="dialogName"
|
||||
:append-to-body="true"
|
||||
:visible.sync="fieldDialogVisible"
|
||||
width="40%">
|
||||
<el-form ref="fieldCmd" label-width="80px">
|
||||
<el-form-item label="属性名称">
|
||||
<el-input v-model="fieldCmd.comment" :disabled="dialogName == '编辑属性'"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="数据类型">
|
||||
<el-select v-model="fieldCmd.type" style="width: 100%">
|
||||
<el-option :label="item" :value="item" v-for="item in dataType"
|
||||
:key="item"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="允许空值">-->
|
||||
<!-- <el-switch-->
|
||||
<!-- v-model="fieldCmd.Null"-->
|
||||
<!-- active-color="#13ce66"-->
|
||||
<!-- inactive-color="#ff4949"-->
|
||||
<!-- active-value="YES"-->
|
||||
<!-- inactive-value="NO">-->
|
||||
<!-- </el-switch>-->
|
||||
<!-- </el-form-item>-->
|
||||
<!-- <el-form-item label="默认值">-->
|
||||
<!-- <el-input v-model="fieldCmd.Default"></el-input>-->
|
||||
<!-- </el-form-item>-->
|
||||
<!-- <el-form-item label="描述">-->
|
||||
<!-- <el-input v-model="fieldCmd.Comment" type="textarea"></el-input>-->
|
||||
<!-- </el-form-item>-->
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="fieldDialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="submitAddField">确 定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import request from '@/utils/request';
|
||||
|
||||
var vm;
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
space: '',
|
||||
modifyCmd: {
|
||||
name: '',
|
||||
fields: []
|
||||
},
|
||||
editFlag: false,
|
||||
fields: [],
|
||||
fieldDialogVisible: false,
|
||||
fieldCmd: {
|
||||
field: '',
|
||||
type: ''
|
||||
},
|
||||
dialogName: '添加属性',
|
||||
selectObj: {
|
||||
type: '',
|
||||
value: {}
|
||||
},
|
||||
dataType: ["INT64", "INT32", "INT16", "INT8", "FLOAT", "DOUBLE", "BOOL", "STRING", "DATE", "TIME", "DATETIME", "FIXED_STRING"],
|
||||
}
|
||||
},
|
||||
created() {
|
||||
vm = this;
|
||||
},
|
||||
mounted() {
|
||||
|
||||
},
|
||||
methods: {
|
||||
updateValue(space, name) {
|
||||
vm.space = space;
|
||||
vm.modifyCmd.name = name;
|
||||
if (name.length > 0) {
|
||||
vm.queryTagDescribe();
|
||||
request({
|
||||
url: `/nebula_operate/showcreatetag/${vm.space}/${vm.modifyCmd.name}`,
|
||||
method: 'get',
|
||||
data: {}
|
||||
}).then(res => {
|
||||
vm.modifyCmd.comment = res.data.comment;
|
||||
vm.modifyCmd = JSON.parse(JSON.stringify(vm.modifyCmd))
|
||||
});
|
||||
vm.editFlag = true;
|
||||
} else {
|
||||
vm.editFlag = false;
|
||||
vm.fields = [];
|
||||
vm.modifyCmd.comment = "";
|
||||
}
|
||||
},
|
||||
queryTagDescribe() {
|
||||
request({
|
||||
url: `/nebula_operate/desctag/${vm.space}/${vm.modifyCmd.name}`,
|
||||
method: 'get',
|
||||
data: {}
|
||||
}).then(res => {
|
||||
res.data.forEach(item => {
|
||||
item.type = item.type.toUpperCase()
|
||||
});
|
||||
vm.fields = res.data;
|
||||
});
|
||||
},
|
||||
modifyField(item, index) {
|
||||
vm.dialogName = '编辑属性';
|
||||
vm.fieldCmd = JSON.parse(JSON.stringify(item));
|
||||
vm.fieldCmd.index = index;
|
||||
vm.fieldDialogVisible = true;
|
||||
},
|
||||
removeField(item, index) {
|
||||
vm.fields.splice(index, 1);
|
||||
if (vm.editFlag) { // 编辑tag,需要提交请求
|
||||
vm.modifyCmd.fields = [item];
|
||||
request({
|
||||
url: `/nebula_operate/alterdroptag/${vm.space}`,
|
||||
method: 'post',
|
||||
data: vm.modifyCmd
|
||||
}).then(res => {
|
||||
vm.$message.success("删除成功");
|
||||
});
|
||||
}
|
||||
},
|
||||
showAddFieldDialog(type) {
|
||||
vm.fieldCmd = {
|
||||
field: '',
|
||||
type: '',
|
||||
null: 'YES',
|
||||
};
|
||||
vm.dialogName = '添加属性';
|
||||
vm.fieldDialogVisible = true;
|
||||
},
|
||||
submitAddField() {
|
||||
if (!vm.editFlag) { // 新建的tag,不需要即时提交
|
||||
if (vm.dialogName == '添加属性') {
|
||||
vm.fields.push(vm.fieldCmd);
|
||||
} else if (vm.dialogName == '编辑属性') {
|
||||
vm.fields[vm.fieldCmd.index] = vm.fieldCmd;
|
||||
}
|
||||
vm.fieldDialogVisible = false;
|
||||
} else {
|
||||
vm.modifyCmd.fields = [vm.fieldCmd];
|
||||
if (vm.dialogName == '添加属性') {
|
||||
request({
|
||||
url: `/nebula_operate/alteraddtag/${vm.space}`,
|
||||
method: 'post',
|
||||
data: vm.modifyCmd
|
||||
}).then(res => {
|
||||
vm.fields.push(vm.fieldCmd);
|
||||
console.log(vm.fields);
|
||||
vm.fieldDialogVisible = false;
|
||||
});
|
||||
} else if (vm.dialogName == '编辑属性') {
|
||||
request({
|
||||
url: `/nebula_operate/alterchangetag/${vm.space}`,
|
||||
method: 'post',
|
||||
data: vm.modifyCmd
|
||||
}).then(res => {
|
||||
vm.fields[vm.fieldCmd.index] = vm.fieldCmd;
|
||||
vm.fieldDialogVisible = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
submitUpdateNode() { // 更新
|
||||
if (vm.modifyCmd.name.length === 0) {
|
||||
vm.$message.warning("标签名称不能为空");
|
||||
return false;
|
||||
}
|
||||
|
||||
vm.modifyCmd.fields = vm.fields;
|
||||
if (!vm.editFlag) { // 新建
|
||||
request({
|
||||
url: `/nebula_operate/createtag/${vm.space}`,
|
||||
method: 'post',
|
||||
data: vm.modifyCmd
|
||||
}).then(res => {
|
||||
vm.$parent.queryTagList();
|
||||
});
|
||||
} else { // 编辑
|
||||
vm.$parent.queryTagList();
|
||||
}
|
||||
},
|
||||
removeTag() {
|
||||
vm.$confirm('此操作将永久删除记录, 是否继续?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
request({
|
||||
url: `/nebula_operate/droptag/${vm.space}/${vm.modifyCmd.name}`,
|
||||
method: 'get',
|
||||
data: {}
|
||||
}).then(res => {
|
||||
vm.$message.success("删除成功");
|
||||
vm.$parent.queryTagList();
|
||||
});
|
||||
}).catch(() => {
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.btn-box {
|
||||
text-align: right;
|
||||
margin-top: 25px;
|
||||
}
|
||||
|
||||
.node-box {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.node-box .title {
|
||||
font-size: 18px;
|
||||
margin-bottom: 35px;
|
||||
}
|
||||
|
||||
.form-title {
|
||||
font-size: 16px;
|
||||
margin: 15px 0;
|
||||
|
||||
}
|
||||
|
||||
.add-attribute-box {
|
||||
margin-top: 10px;
|
||||
color: #409EFF;
|
||||
cursor: pointer;
|
||||
text-align: right;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.info-content > div {
|
||||
margin-bottom: 5px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
226
web/src/components/dialog/TreeGraphInfo.vue
Normal file
@@ -0,0 +1,226 @@
|
||||
<template>
|
||||
<!-- 树形图谱 -->
|
||||
<div>
|
||||
<el-tabs v-model="activeName" @tab-click="handleTabClick">
|
||||
<el-tab-pane label="树形图谱" name="first">
|
||||
<div style=""></div>
|
||||
<el-tree
|
||||
:data="treeData"
|
||||
node-key="vid"
|
||||
:default-expanded-keys="['root']"
|
||||
:props="defaultProps"
|
||||
@node-drop="handleDrop"
|
||||
:expand-on-click-node="false"
|
||||
draggable
|
||||
:allow-drag="allowDrag"
|
||||
style="height: 650px;overflow-y: auto;">
|
||||
<span class="custom-tree-node" slot-scope="{ node, data }">
|
||||
<span>{{ node.label }}</span>
|
||||
<span class="btn-box">
|
||||
<el-button
|
||||
type="text"
|
||||
size="mini"
|
||||
@click="() => appendChild(data)">
|
||||
添加子节点
|
||||
</el-button>
|
||||
<el-button
|
||||
type="text"
|
||||
size="mini"
|
||||
@click="() => removeNode(data)">
|
||||
删除
|
||||
</el-button>
|
||||
</span>
|
||||
</span>
|
||||
</el-tree>
|
||||
</el-tab-pane>
|
||||
<!-- <el-tab-pane label="统计信息" name="second">-->
|
||||
<!-- </el-tab-pane>-->
|
||||
</el-tabs>
|
||||
<el-dialog
|
||||
title="添加子节点"
|
||||
:append-to-body="true"
|
||||
:visible.sync="cmdDialogVisible"
|
||||
width="40%">
|
||||
<el-form ref="cmd" label-width="100px" :rules="rules" :model="cmd">
|
||||
<el-form-item label="子节点类名称" prop="tagName">
|
||||
<el-input v-model="cmd.tagName"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="子节点类描述">
|
||||
<el-input v-model="cmd.label"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="cmdDialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="submitAppendChild">确 定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import request from "@/utils/request";
|
||||
import {tripletToTree} from "@/utils/common";
|
||||
|
||||
var vm;
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
defaultProps: {
|
||||
children: 'children',
|
||||
label: 'label'
|
||||
},
|
||||
activeName: 'first',
|
||||
ontologyId: '',
|
||||
treeData: [],
|
||||
cmdDialogVisible: false,
|
||||
cmd: {},
|
||||
rules: {
|
||||
tagName: [
|
||||
{required: true, message: '请输入子节点类名称'}
|
||||
],
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
vm = this;
|
||||
},
|
||||
mounted() {
|
||||
|
||||
},
|
||||
methods: {
|
||||
queryTreeData(ontologyId) {
|
||||
if (vm.ontologyId === ontologyId) {
|
||||
return;
|
||||
}
|
||||
vm.refreshTree(ontologyId);
|
||||
},
|
||||
refreshTree(ontologyId) {
|
||||
if (ontologyId) {
|
||||
vm.ontologyId = ontologyId;
|
||||
}
|
||||
request({
|
||||
url: `/nebula_model/findtreebyontologyid/${vm.ontologyId}`,
|
||||
method: 'post',
|
||||
data: {}
|
||||
}).then(res => {
|
||||
res.data.nodes.forEach(node => {
|
||||
node.label = node.properties.label || '未命名';
|
||||
});
|
||||
vm.treeData = [{
|
||||
vid: "root",
|
||||
label: '根节点',
|
||||
children: tripletToTree({
|
||||
nodes: res.data.nodes,
|
||||
relations: res.data.relations,
|
||||
idName: 'vid',
|
||||
sourceName: 'srcId',
|
||||
targetName: 'dstId'
|
||||
})
|
||||
}];
|
||||
console.log(vm.treeData);
|
||||
});
|
||||
},
|
||||
handleDrop(draggingNode, dropNode, dropType, ev) { // 树形拖拽完成时触发
|
||||
console.log("drop success");
|
||||
},
|
||||
allowDrag(draggingNode) { // judge node can be drag
|
||||
return draggingNode.data.label.indexOf('三级 3-2-2') === -1;
|
||||
},
|
||||
destroyTree() {
|
||||
},
|
||||
appendChild(parent) {
|
||||
vm.cmdDialogVisible = true;
|
||||
vm.$nextTick(() => {
|
||||
vm.cmd = {
|
||||
tagName: '',
|
||||
label: '',
|
||||
ontologyId: vm.ontologyId,
|
||||
parentId: parent.vid
|
||||
};
|
||||
vm.$refs.cmd.resetFields();
|
||||
});
|
||||
},
|
||||
submitAppendChild() {
|
||||
this.$refs.cmd.validate((valid) => {
|
||||
if (valid) {
|
||||
request({
|
||||
url: `/nebula_model/insertchildmodelvertex/${vm.cmd.parentId}`,
|
||||
method: 'post',
|
||||
data: vm.cmd
|
||||
}).then(res => {
|
||||
vm.$message.success("添加成功");
|
||||
vm.cmdDialogVisible = false;
|
||||
vm.refreshTree();
|
||||
vm.$parent.queryTagData();
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
removeNode(node) {
|
||||
this.$confirm('此操作将永久删除选中节点和关系, 是否继续?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
request({
|
||||
url: `/nebula_model/deletemodelvertex/${node.vid}`,
|
||||
method: 'get',
|
||||
data: {}
|
||||
}).then(res => {
|
||||
vm.$message.success("删除成功");
|
||||
vm.refreshTree();
|
||||
vm.$parent.queryTagData();
|
||||
});
|
||||
}).catch(() => {
|
||||
});
|
||||
},
|
||||
handleTabClick(tab, event) {
|
||||
console.log(tab, event);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
.node-box {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.form-title {
|
||||
font-size: 16px;
|
||||
margin: 15px 0;
|
||||
|
||||
}
|
||||
|
||||
.add-attribute-box {
|
||||
margin-top: 10px;
|
||||
color: #409EFF;
|
||||
cursor: pointer;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.info-content > div {
|
||||
margin-bottom: 5px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.custom-tree-node {
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-size: 14px;
|
||||
padding-right: 8px;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.el-tree-node__content .btn-box {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.el-tree-node__content:hover .btn-box {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
</style>
|
||||
244
web/src/components/dialog/TreeGraphInfo2.vue
Normal file
@@ -0,0 +1,244 @@
|
||||
<template>
|
||||
<!-- 树形图谱 -->
|
||||
<el-tabs v-model="activeName" @tab-click="handleTabClick">
|
||||
<el-tab-pane label="树形图谱" name="first">
|
||||
<div id="container"></div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="统计信息" name="second">
|
||||
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import G6 from '@antv/g6';
|
||||
import request from "@/utils/request";
|
||||
import {tripletToTree} from "@/utils/common";
|
||||
|
||||
let data;
|
||||
var vm;
|
||||
var graph;
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
activeName: 'first'
|
||||
}
|
||||
},
|
||||
created() {
|
||||
vm = this;
|
||||
},
|
||||
mounted() {
|
||||
|
||||
},
|
||||
methods: {
|
||||
queryTreeData(ontologyId) {
|
||||
if (graph) {
|
||||
return;
|
||||
}
|
||||
request({
|
||||
url: `/nebula_model/findtreebyontologyid/${ontologyId}`,
|
||||
method: 'post',
|
||||
data: {}
|
||||
}).then(res => {
|
||||
data = {
|
||||
id: "root",
|
||||
properties: {tagName: '根节点'},
|
||||
children: tripletToTree({
|
||||
nodes: res.data.nodes,
|
||||
relations: res.data.relations,
|
||||
idName: 'vid',
|
||||
sourceName: 'srcId',
|
||||
targetName: 'dstId'
|
||||
})
|
||||
};
|
||||
vm.initTree();
|
||||
});
|
||||
|
||||
},
|
||||
destroyTree() {
|
||||
if (graph) {
|
||||
graph = null;
|
||||
document.getElementById('container').innerHTML = "";
|
||||
}
|
||||
},
|
||||
initTree() { // 初始化数据
|
||||
const container = document.getElementById('container');
|
||||
const width = container.scrollWidth;
|
||||
const height = (container.scrollHeight || 800) - 20;
|
||||
graph = new G6.TreeGraph({
|
||||
container: 'container',
|
||||
width,
|
||||
height,
|
||||
modes: {
|
||||
default: [
|
||||
'drag-canvas',
|
||||
'zoom-canvas',
|
||||
{
|
||||
type: 'drag-node',
|
||||
enableDelegate: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
defaultNode: {
|
||||
size: 25,
|
||||
anchorPoints: [
|
||||
[0, 0.5],
|
||||
[1, 0.5],
|
||||
],
|
||||
style: {
|
||||
|
||||
fill: '#68BDF6',
|
||||
stroke: '#4b4b4b',
|
||||
},
|
||||
},
|
||||
defaultEdge: {
|
||||
type: 'cubic-horizontal',
|
||||
style: {
|
||||
stroke: '#A3B1BF',
|
||||
},
|
||||
},
|
||||
nodeStateStyles: {
|
||||
closest: {
|
||||
fill: '#004f80',
|
||||
},
|
||||
},
|
||||
layout: {
|
||||
type: 'compactBox',
|
||||
direction: 'LR',
|
||||
getId: function getId(d) {
|
||||
return d.id;
|
||||
},
|
||||
getHeight: function getHeight() {
|
||||
return 16;
|
||||
},
|
||||
getWidth: function getWidth() {
|
||||
return 16;
|
||||
},
|
||||
getVGap: function getVGap() {
|
||||
return 10;
|
||||
},
|
||||
getHGap: function getHGap() {
|
||||
return 100;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
graph.node(function (node) {
|
||||
node.tagName = (node.properties && node.properties.tagName) ? node.properties.tagName : '未命名';
|
||||
return {
|
||||
label: node.tagName,
|
||||
labelCfg: {
|
||||
offset: 10,
|
||||
position: node.children && node.children.length > 0 ? 'left' : 'right',
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
graph.data(data);
|
||||
graph.render();
|
||||
graph.fitView();
|
||||
|
||||
let minDisNode;
|
||||
graph.on('node:dragstart', (e) => {
|
||||
minDisNode = undefined;
|
||||
});
|
||||
graph.on('node:drag', (e) => {
|
||||
minDisNode = undefined;
|
||||
const item = e.item;
|
||||
const model = item.getModel();
|
||||
const nodes = graph.getNodes();
|
||||
let minDis = Infinity;
|
||||
nodes.forEach((inode) => {
|
||||
graph.setItemState(inode, 'closest', false);
|
||||
const node = inode.getModel();
|
||||
if (node.id === model.id) return;
|
||||
const dis = (node.x - e.x) * (node.x - e.x) + (node.y - e.y) * (node.y - e.y);
|
||||
if (dis < minDis) {
|
||||
minDis = dis;
|
||||
minDisNode = inode;
|
||||
}
|
||||
});
|
||||
// console.log('minDis', minDis, minDisNode);
|
||||
if (minDis < 2000) graph.setItemState(minDisNode, 'closest', true);
|
||||
else minDisNode = undefined;
|
||||
});
|
||||
|
||||
graph.on('node:dragend', (e) => {
|
||||
if (!minDisNode) {
|
||||
// descriptionDiv.innerHTML = '失败,拖动的节点附近没有节点';
|
||||
return;
|
||||
}
|
||||
const item = e.item;
|
||||
const id = item.getID();
|
||||
const data = graph.findDataById(id);
|
||||
// if the minDisNode is a descent of the dragged node, return
|
||||
let isDescent = false;
|
||||
const minDisNodeId = minDisNode.getID();
|
||||
console.log('dragend', minDisNodeId, isDescent, data, id);
|
||||
|
||||
G6.Util.traverseTree(data, (d) => {
|
||||
if (d.id === minDisNodeId) isDescent = true;
|
||||
});
|
||||
if (isDescent) {
|
||||
vm.$message.error("目标节点是被拖动节点的后代");
|
||||
return;
|
||||
}
|
||||
graph.removeChild(id);
|
||||
|
||||
setTimeout(() => {
|
||||
const newParentData = graph.findDataById(minDisNodeId);
|
||||
let newChildren = newParentData.children;
|
||||
if (newChildren) newChildren.push(data);
|
||||
else newChildren = [data];
|
||||
graph.updateChildren(newChildren, minDisNodeId);
|
||||
vm.$message.success("操作成功");
|
||||
}, 600);
|
||||
});
|
||||
|
||||
if (typeof window !== 'undefined')
|
||||
window.onresize = () => {
|
||||
if (!graph || graph.get('destroyed')) return;
|
||||
if (!container || !container.scrollWidth || !container.scrollHeight) return;
|
||||
graph.changeSize(container.scrollWidth, container.scrollHeight - 20);
|
||||
};
|
||||
},
|
||||
destroyTreeGraph() {
|
||||
|
||||
},
|
||||
handleTabClick(tab, event) {
|
||||
console.log(tab, event);
|
||||
},
|
||||
submitUpdate() { // 更新
|
||||
vm.$parent.submitUpdateEdge(vm.modifyCmd);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
.node-box {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.form-title {
|
||||
font-size: 16px;
|
||||
margin: 15px 0;
|
||||
|
||||
}
|
||||
|
||||
.add-attribute-box {
|
||||
margin-top: 10px;
|
||||
color: #409EFF;
|
||||
cursor: pointer;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.info-content > div {
|
||||
margin-bottom: 5px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
145
web/src/components/graph/Graph.vue
Normal file
@@ -0,0 +1,145 @@
|
||||
<template>
|
||||
<div :id="id" style="width: 100%; height: 100%"></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import request from '@/utils/request';
|
||||
import {config} from '@/components/graph/config';
|
||||
import G6 from '@antv/g6';
|
||||
|
||||
var graphObj = {};
|
||||
|
||||
/**
|
||||
* 格式约定
|
||||
* node{
|
||||
* id,
|
||||
* name,
|
||||
* label,
|
||||
* }
|
||||
* edge{
|
||||
* source,
|
||||
* target,
|
||||
* name,
|
||||
* label,
|
||||
* }
|
||||
*/
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
id: "graph" + Math.round(Math.random() * 10000000).toString(),// 随机ID的目的是为了一个页面同时存在多个画布
|
||||
graph: null,
|
||||
graphData: null
|
||||
}
|
||||
},
|
||||
created() {
|
||||
},
|
||||
mounted() {
|
||||
},
|
||||
methods: {
|
||||
initGraph: function (cmd, flag, clickFun, ifNotDestroy) {
|
||||
let graph = graphObj[this.id];
|
||||
this.$nextTick(() => {
|
||||
if (!ifNotDestroy) {
|
||||
this.destroyGraph();
|
||||
}
|
||||
|
||||
let _width = document.getElementById(this.id).clientWidth;
|
||||
let _height = document.getElementById(this.id).clientHeight;
|
||||
// 创建 G6 图实例
|
||||
if (graph == undefined || graph == null) {
|
||||
graph = new G6.Graph(config({width: _width, height: _height, id: this.id}));
|
||||
|
||||
graph.on('node:click', (e) => {
|
||||
let node = e.item._cfg.model;
|
||||
if (clickFun) {
|
||||
clickFun(node);
|
||||
}
|
||||
});
|
||||
|
||||
graphObj[this.id] = graph;
|
||||
|
||||
}
|
||||
if (flag) {
|
||||
this.importData(cmd);
|
||||
} else {
|
||||
this.queryData(cmd);
|
||||
}
|
||||
});
|
||||
},
|
||||
importData({nodes, edges}) { // 查询图空间内节点关系
|
||||
let graph = graphObj[this.id];
|
||||
this.graphData = {
|
||||
nodes: nodes,
|
||||
edges: edges
|
||||
};
|
||||
// 读取数据
|
||||
graph.data(this.graphData);
|
||||
// 渲染图
|
||||
graph.render();
|
||||
},
|
||||
queryData({path, qo}) { // 查询图空间内节点关系
|
||||
let graph = graphObj[this.id];
|
||||
request({
|
||||
url: path,
|
||||
method: 'post',
|
||||
data: qo
|
||||
}).then(res => {
|
||||
// 处理节点的属性,要适应组件的要求
|
||||
res.data.nodes.forEach(node => {
|
||||
node.id = node.vid;
|
||||
node.label = node.properties.labelName;
|
||||
node.name = node.properties.name;
|
||||
});
|
||||
res.data.relations.forEach(edge => {
|
||||
edge.source = edge.srcId;
|
||||
edge.target = edge.dstId;
|
||||
edge.name = edge.properties.name;
|
||||
edge.label = edge.properties.labelName;
|
||||
if (edge.srcId == edge.dstId) {
|
||||
edge.type = 'loop';
|
||||
}
|
||||
});
|
||||
this.graphData = {
|
||||
nodes: res.data.nodes,
|
||||
edges: res.data.relations
|
||||
};
|
||||
// 读取数据
|
||||
graph.data(this.graphData);
|
||||
// 渲染图
|
||||
graph.render();
|
||||
});
|
||||
},
|
||||
destroyGraph() {
|
||||
let graph = graphObj[this.id];
|
||||
try {
|
||||
if (graph != undefined && graph != null) {
|
||||
graph.clear();
|
||||
graph = null;
|
||||
document.getElementById(this.id).innerHTML = "";
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
function refreshDragedNodePosition(e) {
|
||||
const model = e.item.get('model');
|
||||
model.fx = e.x;
|
||||
model.fy = e.y;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.g6-tooltip {
|
||||
border: 1px solid #e2e2e2;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
color: #545454;
|
||||
background-color: rgba(255, 255, 255, 0.9);
|
||||
padding: 10px 8px;
|
||||
box-shadow: rgb(174 174 174) 0px 0px 10px;
|
||||
}
|
||||
|
||||
</style>
|
||||
314
web/src/components/graph/Graph614.vue
Normal file
@@ -0,0 +1,314 @@
|
||||
<template>
|
||||
<div class="graph-main">
|
||||
<div class="legend-box" v-show="!legendHide">
|
||||
<div class="item-row" v-for="(value, key) in legendList" :key="key">
|
||||
<div class="point" :style="'background-color:' + value.color"></div>
|
||||
<div class="label">{{ value.label }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div :id="id" style="width: 100%; height: 100%"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import request from '@/utils/request';
|
||||
import G6 from '@antv/g6';
|
||||
|
||||
var graphObj = {};
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
ontologyId: '',
|
||||
id: Math.round(Math.random() * 10000000).toString(),
|
||||
graph: null,
|
||||
graphData: null,
|
||||
legendHide: false,
|
||||
legendList: {
|
||||
"armyType": {label: '军种', color: 'rgb(76,142,218)'},
|
||||
"control": {label: '控制系统', color: 'rgb(236,181,201)'},
|
||||
"engine": {label: '发动机', color: 'rgb(241,102,103)'},
|
||||
"fault": {label: '故障信息', color: 'rgb(141,204,147)'},
|
||||
"faultCase": {label: '故障案例', color: 'rgb(156,33,234)'},
|
||||
"oriPlane": {label: '原飞机', color: 'rgb(255,196,84)'},
|
||||
"part": {label: '部件', color: 'rgb(86,148,128)'},
|
||||
"place": {label: '发生地', color: 'rgb(217,200,174)'},
|
||||
"plane": {label: '飞机', color: 'rgb(87,199,227)'}
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.ontologyId = this.$route.query.id;
|
||||
},
|
||||
mounted() {
|
||||
},
|
||||
methods: {
|
||||
initGraph: function (cmd, flag, clickNodeFun, legendHide) { // 是否隐藏图例
|
||||
if(legendHide) {
|
||||
this.legendHide = true;
|
||||
}
|
||||
let graph = graphObj[this.id];
|
||||
this.$nextTick(() => {
|
||||
this.destroyGraph();
|
||||
let _width = document.getElementById(this.id).clientWidth;
|
||||
let _height = document.getElementById(this.id).clientHeight;
|
||||
// 创建 G6 图实例
|
||||
if (graph == undefined || graph == null) {
|
||||
graph = new G6.Graph({
|
||||
container: this.id, // 指定图画布的容器 id,与第 9 行的容器对应
|
||||
// 画布宽高
|
||||
width: _width,
|
||||
height: _height,
|
||||
layout: {
|
||||
type: 'force',
|
||||
nodeStrength: -0,
|
||||
nodeSize: 80,
|
||||
preventOverlap: true,
|
||||
edgeStrength: 0.1
|
||||
},
|
||||
modes: {
|
||||
// Defualt mode
|
||||
default: ['drag-node',
|
||||
{
|
||||
type: 'drag-canvas',
|
||||
enableOptimize: true, // enable the optimize to hide the shapes beside nodes' keyShape
|
||||
},
|
||||
{
|
||||
type: 'zoom-canvas',
|
||||
enableOptimize: true, // enable the optimize to hide the shapes beside nodes' keyShape
|
||||
},
|
||||
{
|
||||
type: 'tooltip',
|
||||
formatText: function formatText(model) {
|
||||
let name = '';
|
||||
let argumentsStr = '';
|
||||
if (model.label) name = model.label + '<br/>';
|
||||
if (model.arguments && model.arguments.length > 0) {
|
||||
model.arguments.forEach(arg => {
|
||||
argumentsStr += arg.role + ":" + arg.argument + '<br/>';
|
||||
});
|
||||
}
|
||||
const text = `${name} ${argumentsStr}`;
|
||||
return text;
|
||||
},
|
||||
|
||||
shouldUpdate: function shouldUpdate() {
|
||||
return true;
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
defaultNode: {
|
||||
size: 20,
|
||||
color: '#4b4b4b',
|
||||
label: 'name',
|
||||
style: {
|
||||
lineWidth: 2,
|
||||
fill: '#68BDF6'
|
||||
},
|
||||
labelCfg: {
|
||||
position: 'bottom',
|
||||
style: {
|
||||
fontSize: 14,
|
||||
fill: '#454545'
|
||||
}
|
||||
}
|
||||
},
|
||||
defaultEdge: {
|
||||
style: {
|
||||
stroke: '#b3b3b3',
|
||||
lineAppendWidth: 10, // Enlarge the range the edge to be hitted
|
||||
},
|
||||
labelCfg: {
|
||||
autoRotate: false,
|
||||
style: {
|
||||
fontSize: 14,
|
||||
fill: '#848484'
|
||||
}
|
||||
},
|
||||
},
|
||||
nodeStateStyles: {
|
||||
yourStateName: {
|
||||
stroke: '#f00',
|
||||
lineWidth: 3,
|
||||
},
|
||||
},
|
||||
edgeStateStyles: {
|
||||
yourStateName: {
|
||||
stroke: '#f00',
|
||||
lineWidth: 3,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
/*拖动节点-start*/
|
||||
const forceLayout = graph.get('layoutController').layoutMethod;
|
||||
graph.on('node:dragstart', function (e) {
|
||||
graph.layout();
|
||||
refreshDragedNodePosition(e);
|
||||
});
|
||||
graph.on('node:drag', function (e) {
|
||||
if (forceLayout) {
|
||||
forceLayout.execute();
|
||||
}
|
||||
refreshDragedNodePosition(e);
|
||||
});
|
||||
graph.on('node:dragend', function (e) {
|
||||
e.item.get('model').fx = null;
|
||||
e.item.get('model').fy = null;
|
||||
});
|
||||
/*拖动节点-end*/
|
||||
|
||||
graph.on('node:click', (e) => {
|
||||
let node = e.item._cfg.model;
|
||||
if (clickNodeFun) {
|
||||
clickNodeFun(node);
|
||||
}
|
||||
this.clearStates();
|
||||
graph.setItemState(e.item, 'yourStateName', true);
|
||||
});
|
||||
|
||||
graph.on('canvas:click', (e) => {
|
||||
this.clearStates();
|
||||
});
|
||||
|
||||
graphObj[this.id] = graph;
|
||||
|
||||
}
|
||||
if (flag) {
|
||||
this.importData(cmd);
|
||||
} else {
|
||||
this.queryData(cmd);
|
||||
}
|
||||
});
|
||||
},
|
||||
importData({nodes, edges}) { // 查询图空间内节点关系
|
||||
let graph = graphObj[this.id];
|
||||
// 更新颜色数据
|
||||
nodes.forEach(node => {
|
||||
node.style = {
|
||||
lineWidth: 2,
|
||||
fill: this.legendList[node._label].color || "#68BDF6"
|
||||
};
|
||||
});
|
||||
|
||||
this.graphData = {
|
||||
nodes: nodes,
|
||||
edges: edges
|
||||
};
|
||||
// 读取数据
|
||||
graph.data(this.graphData);
|
||||
// 渲染图
|
||||
graph.render();
|
||||
},
|
||||
queryData({path, qo}) { // 查询图空间内节点关系
|
||||
let graph = graphObj[this.id];
|
||||
request({
|
||||
url: path,
|
||||
method: 'post',
|
||||
data: qo
|
||||
}).then(res => {
|
||||
res.data.nodes.forEach(node => {
|
||||
node.label = node.properties.name;
|
||||
node.id = node.id.toString();
|
||||
});
|
||||
res.data.relations.forEach(edge => {
|
||||
delete edge.id;
|
||||
edge.source = edge.source.toString();
|
||||
edge.target = edge.target.toString();
|
||||
if (edge.source === edge.target) {
|
||||
edge.type = 'loop';
|
||||
} else {
|
||||
delete edge.type;
|
||||
}
|
||||
});
|
||||
this.importData({
|
||||
nodes: res.data.nodes,
|
||||
edges: res.data.relations
|
||||
});
|
||||
// this.graphData = {
|
||||
// nodes: res.data.nodes,
|
||||
// edges: res.data.relations
|
||||
// };
|
||||
// // 读取数据
|
||||
// graph.data(this.graphData);
|
||||
// // 渲染图
|
||||
// graph.render();
|
||||
});
|
||||
},
|
||||
clearStates() { // 清空选中状态
|
||||
let graph = graphObj[this.id];
|
||||
graph.getNodes().forEach((node) => {
|
||||
graph.clearItemStates(node);
|
||||
});
|
||||
graph.getEdges().forEach((edge) => {
|
||||
graph.clearItemStates(edge);
|
||||
});
|
||||
},
|
||||
destroyGraph() {
|
||||
let graph = graphObj[this.id];
|
||||
try {
|
||||
if (graph != undefined && graph != null) {
|
||||
graph.clear();
|
||||
graph = null;
|
||||
document.getElementById("mountNode").innerHTML = "";
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
function refreshDragedNodePosition(e) {
|
||||
const model = e.item.get('model');
|
||||
model.fx = e.x;
|
||||
model.fy = e.y;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.g6-tooltip {
|
||||
border: 1px solid #e2e2e2;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
color: #545454;
|
||||
background-color: rgba(255, 255, 255, 0.9);
|
||||
padding: 10px 8px;
|
||||
box-shadow: rgb(174 174 174) 0px 0px 10px;
|
||||
}
|
||||
|
||||
.graph-main {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.legend-box {
|
||||
position: absolute;
|
||||
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
}
|
||||
|
||||
.item-row {
|
||||
float: left;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.item-row .point {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 40px;
|
||||
border: 2px solid #4b4b4b;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.item-row .label {
|
||||
line-height: 20px;
|
||||
height: 20px;
|
||||
float: right;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
</style>
|
||||
1105
web/src/components/graph/GraphModel.vue
Normal file
782
web/src/components/graph/GraphModel20220927.vue
Normal file
@@ -0,0 +1,782 @@
|
||||
<template>
|
||||
<div class="node-box" style="position: relative">
|
||||
<transition name="el-zoom-in-center">
|
||||
<div v-show="infoVisible" class="graph-info-box">
|
||||
<div class="graph-info-child">
|
||||
<div v-show="selectObj.type == 'edge'">
|
||||
<noumenon-edge-modify ref="noumenonEdgeModify"></noumenon-edge-modify>
|
||||
</div>
|
||||
<div v-show="selectObj.type == 'node'">
|
||||
<noumenon-modify ref="noumenonModify"></noumenon-modify>
|
||||
</div>
|
||||
<i class="el-icon-d-arrow-left" @click="infoVisible = false"></i>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
<transition name="el-zoom-in-center">
|
||||
<div v-show="treeInfoVisible" class="tree-graph-info">
|
||||
<div class="graph-info-child">
|
||||
<tree-graph-info ref="treeGraphInfo"></tree-graph-info>
|
||||
<i class="el-icon-d-arrow-right" @click="treeInfoVisible = false"></i>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
<!-- 为图谱准备一个具备大小(宽高)的Dom -->
|
||||
<div class="tree-container">
|
||||
<div class="graph-name-box">
|
||||
<label>本体名称: {{ graphName }};</label>
|
||||
<label>节点数量:{{ nodeCount }};</label>
|
||||
<label>关系属性数量:{{ edgeCount }};</label>
|
||||
<label>值属性数量:{{ valueCount }};</label>
|
||||
</div>
|
||||
<!-- <div class="tips-box">-->
|
||||
<!-- <label></label>-->
|
||||
<!-- </div>-->
|
||||
<div class="icon-box">
|
||||
<div class="icon icon-tree" @click="showTreeCom">
|
||||
<i title="树形图谱"></i>
|
||||
</div>
|
||||
<div class="icon icon-add" @click="showAddNodeDialog">
|
||||
<i title="新增概念"></i>
|
||||
</div>
|
||||
<div title="按住shift点选两节点可新增关系" :class="['icon icon-arrow', createEdgeModelFlag ? 'active' : '']" @click="changeCreateEdgeModel">
|
||||
<i title="按住shift点选两节点可新增关系"></i>
|
||||
</div>
|
||||
<div class="icon icon-remove" @click="removeNode">
|
||||
<i title="删除"></i>
|
||||
</div>
|
||||
<div class="icon icon-save" @click="backGraph">
|
||||
<i title="返回"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div id="mountNode" style="width: 100%; height: 1000px"></div>
|
||||
</div>
|
||||
<el-dialog
|
||||
title="新增概念"
|
||||
:visible.sync="addNodeDialogVisible"
|
||||
width="40%">
|
||||
<el-form ref="addNodeForm" label-width="80px" :rules="addNodeRules" :model="addNodeCmd">
|
||||
<el-form-item label="概念名" prop="tagName">
|
||||
<el-input v-model="addNodeCmd.tagName"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="概念描述">
|
||||
<el-input v-model="addNodeCmd.label"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-button @click="addNodeDialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="submitAddNode">确 定</el-button>
|
||||
</el-dialog>
|
||||
<el-dialog
|
||||
title="新增关系"
|
||||
:visible.sync="addEdgeDialogVisible"
|
||||
@close="handleAddEdgeDialogClose"
|
||||
width="40%">
|
||||
<el-form ref="addEdgeForm" :model="addEdgeCmd" label-width="100px" :rules="addEdgeRules">
|
||||
<el-form-item label="关系名称" prop="edgeName">
|
||||
<el-input v-model="addEdgeCmd.edgeName"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="关系描述">
|
||||
<el-input v-model="addEdgeCmd.label"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否显示箭头">
|
||||
<el-radio v-model="addEdgeCmd.arrow" :label="true">是</el-radio>
|
||||
<el-radio v-model="addEdgeCmd.arrow" :label="false">否</el-radio>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-button @click="addEdgeDialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="submitAddEdge">确 定</el-button>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import request from '@/utils/request';
|
||||
import {config} from '@/components/graph/config';
|
||||
import G6 from '@antv/g6';
|
||||
import noumenonModify from '@/components/dialog/NoumenonModify';
|
||||
import noumenonEdgeModify from '@/components/dialog/NoumenonEdgeModify';
|
||||
import treeGraphInfo from '@/components/dialog/TreeGraphInfo';
|
||||
|
||||
|
||||
G6.registerBehavior('click-add-edge', {
|
||||
// Set the events and the corresponding responsing function for this behavior
|
||||
getEvents() {
|
||||
return {
|
||||
'node:click': 'onClick', // The event is canvas:click, the responsing function is onClick
|
||||
mousemove: 'onMousemove', // The event is mousemove, the responsing function is onMousemove
|
||||
'edge:click': 'onEdgeClick',
|
||||
};
|
||||
},
|
||||
// The responsing function for node:click defined in getEvents
|
||||
onClick(ev) {
|
||||
const self = this;
|
||||
const node = ev.item;
|
||||
const graph = self.graph;
|
||||
// The position where the mouse clicks
|
||||
const point = {x: ev.x, y: ev.y};
|
||||
const model = node.getModel();
|
||||
if (self.addingEdge && self.edge) {
|
||||
graph.updateItem(self.edge, {
|
||||
target: model.id,
|
||||
});
|
||||
// 打开编辑新建关系的信息弹窗
|
||||
vm.showAddEdge(self.edge._cfg.model);
|
||||
self.edge = null;
|
||||
self.addingEdge = false;
|
||||
} else {
|
||||
// Add anew edge, the end node is the current node user clicks
|
||||
self.edge = graph.addItem('edge', {
|
||||
source: model.id,
|
||||
target: model.id,
|
||||
});
|
||||
self.addingEdge = true;
|
||||
}
|
||||
},
|
||||
// The responsing function for mousemove defined in getEvents
|
||||
onMousemove(ev) {
|
||||
const self = this;
|
||||
// The current position the mouse clicks
|
||||
const point = {x: ev.x, y: ev.y};
|
||||
if (self.addingEdge && self.edge) {
|
||||
// Update the end node to the current node the mouse clicks
|
||||
self.graph.updateItem(self.edge, {
|
||||
target: point,
|
||||
});
|
||||
}
|
||||
},
|
||||
// The responsing function for edge:click defined in getEvents
|
||||
onEdgeClick(ev) {
|
||||
const self = this;
|
||||
const currentEdge = ev.item;
|
||||
if (self.addingEdge && self.edge === currentEdge) {
|
||||
self.graph.removeItem(self.edge);
|
||||
self.edge = null;
|
||||
self.addingEdge = false;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
var vm;
|
||||
var graph;
|
||||
var graphData;
|
||||
var _ = require('lodash');
|
||||
var nodeProps = {
|
||||
id: 'vid',
|
||||
label: 'properties.label',
|
||||
name: 'properties.tagName',
|
||||
labelName: 'properties.label'
|
||||
};
|
||||
var edgeProps = {
|
||||
source: 'srcId',
|
||||
target: 'dstId',
|
||||
name: 'properties.edgeName',
|
||||
label: 'properties.label',
|
||||
arrow: 'properties.arrow',
|
||||
labelName: 'properties.label'
|
||||
}
|
||||
// const subjectColors = ['#5F95FF', '#61DDAA', '#65789B', '#F6BD16', '#7262FD', '#78D3F8', '#9661BC', '#F6903D', '#008685', '#F08BB4'];
|
||||
// const colorSets = G6.Util.getColorSetsBySubjectColors(subjectColors, '#fff', 'default', '#777');
|
||||
export default {
|
||||
components: {
|
||||
'noumenon-modify': noumenonModify,
|
||||
'noumenon-edge-modify': noumenonEdgeModify,
|
||||
'tree-graph-info': treeGraphInfo
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
qo: '',
|
||||
graphName: '',
|
||||
nodeCount: 0,
|
||||
edgeCount: 0,
|
||||
valueCount: 0,
|
||||
ontologyId: '',
|
||||
infoVisible: false, // 左侧信息栏显隐
|
||||
treeInfoVisible: false, // 右侧树形图谱
|
||||
clickNode: {id: '', name: ''},
|
||||
addNodeDialogVisible: false,
|
||||
addNodeCmd: {
|
||||
ontologyId: '',
|
||||
tagName: '',
|
||||
label: ''
|
||||
},
|
||||
arrowVisible: false, // 是否展示箭头方向
|
||||
createEdgeModelFlag: false, // 创建关系模式开关
|
||||
addEdgeDialogVisible: false,
|
||||
addEdgeCmd: {
|
||||
ontologyId: '',
|
||||
edgeName: '',
|
||||
label: '',
|
||||
source: '',
|
||||
target: '',
|
||||
arrow: false
|
||||
},
|
||||
selectObj: {
|
||||
type: '',
|
||||
value: {}
|
||||
},
|
||||
addNodeRules: {
|
||||
tagName: [
|
||||
{required: true, message: '请输入类名称', trigger: 'blur'},
|
||||
],
|
||||
},
|
||||
addEdgeRules: {
|
||||
edgeName: [
|
||||
{required: true, message: '请输入类名称', trigger: 'blur'},
|
||||
],
|
||||
},
|
||||
}
|
||||
},
|
||||
created() {
|
||||
vm = this;
|
||||
vm.ontologyId = this.$route.query.id;
|
||||
vm.qo = {
|
||||
pageNo: this.$route.query.pageNo,
|
||||
name: this.$route.query.name
|
||||
};
|
||||
vm.graphName = this.$route.query.graphName;
|
||||
},
|
||||
mounted() {
|
||||
vm.initGraph();
|
||||
},
|
||||
methods: {
|
||||
queryCount() {
|
||||
request({
|
||||
url: `/nebula_model/countallbyontologyid/${vm.ontologyId}`,
|
||||
method: 'get',
|
||||
data: {}
|
||||
}).then(res => {
|
||||
vm.nodeCount = res.data.gns;
|
||||
vm.edgeCount = res.data.gxs;
|
||||
vm.valueCount = res.data.zsxs;
|
||||
});
|
||||
},
|
||||
queryTagData() { // 查询图空间内节点关系
|
||||
vm.queryCount(); // 更新统计信息
|
||||
request({
|
||||
url: `/nebula_model/findrelationbyontologyid/${vm.ontologyId}`,
|
||||
method: 'post',
|
||||
data: {
|
||||
// ontologyId: vm.ontologyId
|
||||
}
|
||||
}).then(res => {
|
||||
res.data.nodes.forEach(node => {
|
||||
Reflect.ownKeys(nodeProps).forEach(key => {
|
||||
node[key] = _.get(node, nodeProps[key], '');
|
||||
});
|
||||
});
|
||||
res.data.relations.forEach(edge => {
|
||||
Reflect.ownKeys(edgeProps).forEach(key => {
|
||||
edge[key] = _.get(edge, edgeProps[key], '');
|
||||
});
|
||||
// 是否指向自己
|
||||
edge.type = edge.srcId === edge.dstId ? 'loop' : '';
|
||||
// 是否显示箭头
|
||||
edge.style = {endArrow: edge.arrow};
|
||||
});
|
||||
graphData = {
|
||||
nodes: res.data.nodes,
|
||||
edges: res.data.relations
|
||||
};
|
||||
// 读取数据
|
||||
graph.data(graphData);
|
||||
// 渲染图
|
||||
graph.render();
|
||||
});
|
||||
},
|
||||
initGraph: function () {
|
||||
this.destroyGraph();
|
||||
let mountNodeDom = document.getElementById("mountNode");
|
||||
let _width = mountNodeDom.clientWidth, _height = mountNodeDom.clientHeight;
|
||||
// 创建 G6 图实例
|
||||
if (graph == undefined || graph == null) {
|
||||
graph = new G6.Graph(config({width: _width, height: _height, id: 'mountNode'}));
|
||||
|
||||
graph.on('aftercreateedge', (e) => {
|
||||
vm.showAddEdge(e.edge._cfg.model);
|
||||
});
|
||||
|
||||
graph.on('canvas:click', (e) => {
|
||||
vm.selectObj = {
|
||||
type: '',
|
||||
value: {}
|
||||
};
|
||||
vm.clearStates();
|
||||
vm.infoVisible = false;
|
||||
});
|
||||
|
||||
/*拖动节点-start*/
|
||||
// const forceLayout = graph.get('layoutController').layoutMethod;
|
||||
// graph.on('node:dragstart', function (e) {
|
||||
// graph.layout();
|
||||
// refreshDragedNodePosition(e);
|
||||
// });
|
||||
// graph.on('node:drag', function (e) {
|
||||
// if (forceLayout) {
|
||||
// forceLayout.execute();
|
||||
// }
|
||||
// refreshDragedNodePosition(e);
|
||||
// });
|
||||
// graph.on('node:dragend', function (e) {
|
||||
// e.item.get('model').fx = null;
|
||||
// e.item.get('model').fy = null;
|
||||
// });
|
||||
/*拖动节点-end*/
|
||||
|
||||
graph.on('edge:click', function (e) { // 点击边事件
|
||||
let edge = e.item._cfg.model;
|
||||
if (!edge.name) {
|
||||
return;
|
||||
}
|
||||
let fields = [];
|
||||
if (edge.properties && edge.properties.nebulafieldsnapshot) {
|
||||
fields = edge.properties.nebulafieldsnapshot;
|
||||
}
|
||||
vm.showEdgeModifyCom({
|
||||
edgeName: edge.name,
|
||||
label: edge.labelName,
|
||||
arrow: edge.arrow,
|
||||
source: edge.srcId,
|
||||
target: edge.dstId
|
||||
}, fields);
|
||||
graph.getEdges().forEach((edge) => {
|
||||
graph.clearItemStates(edge);
|
||||
});
|
||||
graph.getNodes().forEach((node) => {
|
||||
graph.clearItemStates(node);
|
||||
});
|
||||
graph.setItemState(e.item, 'yourStateName', true);
|
||||
|
||||
});
|
||||
|
||||
graph.on('node:click', (e) => {
|
||||
if (!event.shiftKey && !vm.createEdgeModelFlag) { // 按住shift属于新增关系,不需要触发点击节点事件
|
||||
let node = e.item._cfg.model;
|
||||
vm.showNodeModifyCom({
|
||||
id: node.id,
|
||||
tagName: node.name,
|
||||
label: node.labelName
|
||||
}, _.get(node, 'properties.nebulafieldsnapshot', []));
|
||||
vm.clearStates();
|
||||
graph.setItemState(e.item, 'yourStateName', true);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
vm.queryTagData();
|
||||
},
|
||||
destroyGraph() {
|
||||
try {
|
||||
if (graph != undefined && graph != null) {
|
||||
graph.clear();
|
||||
graph = null;
|
||||
document.getElementById("mountNode").innerHTML = "";
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
},
|
||||
clearStates() { // 清空选中状态
|
||||
graph.getNodes().forEach((node) => {
|
||||
graph.clearItemStates(node);
|
||||
});
|
||||
graph.getEdges().forEach((edge) => {
|
||||
graph.clearItemStates(edge);
|
||||
});
|
||||
},
|
||||
changeCreateEdgeModel() { // 切换模式,默认和添加关系模式之间切换
|
||||
vm.createEdgeModelFlag = !vm.createEdgeModelFlag;
|
||||
if (vm.createEdgeModelFlag) {
|
||||
graph.setMode("addEdge");
|
||||
} else {
|
||||
graph.setMode("default");
|
||||
}
|
||||
},
|
||||
showAddNodeDialog() {
|
||||
vm.addNodeCmd = {
|
||||
ontologyId: vm.ontologyId,
|
||||
tagName: '',
|
||||
label: ''
|
||||
};
|
||||
vm.addNodeDialogVisible = true;
|
||||
},
|
||||
submitAddNode() {
|
||||
request({
|
||||
url: `/nebula_model/insertmodelvertex`,
|
||||
method: 'post',
|
||||
data: {
|
||||
ontologyId: vm.ontologyId,
|
||||
tagName: vm.addNodeCmd.tagName,
|
||||
label: vm.addNodeCmd.label
|
||||
}
|
||||
}).then(res => {
|
||||
graph.addItem('node', {
|
||||
id: res.data.vid,
|
||||
name: vm.addNodeCmd.tagName,
|
||||
label: vm.addNodeCmd.tagName,
|
||||
labelName: vm.addNodeCmd.label
|
||||
});
|
||||
graphData.nodes = graph.save().nodes;
|
||||
graph.layout();
|
||||
vm.$message.success("新增类成功");
|
||||
vm.addNodeDialogVisible = false;
|
||||
|
||||
vm.showNodeModifyCom(res.data.ob, []);
|
||||
});
|
||||
},
|
||||
showAddEdge(edge) {
|
||||
vm.addEdgeCmd = {
|
||||
ontologyId: vm.ontologyId,
|
||||
edgeName: '',
|
||||
label: '',
|
||||
arrow: false,
|
||||
source: edge.source,
|
||||
target: edge.target
|
||||
};
|
||||
vm.addEdgeDialogVisible = true;
|
||||
},
|
||||
handleAddEdgeDialogClose() {
|
||||
vm.queryTagData();
|
||||
},
|
||||
submitAddEdge() {
|
||||
vm.$refs['addEdgeForm'].validate((valid) => {
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
let edge = {
|
||||
srcId: vm.addEdgeCmd.source,
|
||||
ontologyId: vm.ontologyId,
|
||||
dstId: vm.addEdgeCmd.target,
|
||||
edgeName: vm.addEdgeCmd.edgeName,
|
||||
arrow: vm.addEdgeCmd.arrow,
|
||||
label: vm.addEdgeCmd.label
|
||||
};
|
||||
request({
|
||||
url: `/nebula_model/insertmodeledge`,
|
||||
method: 'post',
|
||||
data: edge
|
||||
}).then(res => {
|
||||
vm.queryTagData();
|
||||
vm.$message.success("新增关系成功");
|
||||
vm.addEdgeDialogVisible = false;
|
||||
|
||||
vm.showEdgeModifyCom(edge, []);
|
||||
});
|
||||
});
|
||||
},
|
||||
showTreeCom() { // 显示树形图谱窗口
|
||||
vm.treeInfoVisible = true;
|
||||
vm.$nextTick(() => {
|
||||
vm.$refs['treeGraphInfo'].queryTreeData(vm.ontologyId);
|
||||
});
|
||||
},
|
||||
showNodeModifyCom(node, fields) { // 显示节点编辑组件
|
||||
vm.infoVisible = true;
|
||||
vm.$nextTick(() => {
|
||||
vm.selectObj = {
|
||||
type: 'node',
|
||||
value: node
|
||||
};
|
||||
vm.$refs['noumenonModify'].updateValue(node.tagName, node.label, fields);
|
||||
});
|
||||
},
|
||||
showEdgeModifyCom(edge, fields) { // 显示关系编辑组件
|
||||
vm.infoVisible = true;
|
||||
vm.selectObj = {
|
||||
type: 'edge',
|
||||
value: edge
|
||||
};
|
||||
vm.$nextTick(() => {
|
||||
vm.$refs['noumenonEdgeModify'].updateValue(edge.edgeName, edge.label, edge.arrow, fields, vm.selectObj.value.source, vm.selectObj.value.target);
|
||||
});
|
||||
},
|
||||
backGraph() { // 返回
|
||||
if(vm.$refs['treeGraphInfo']) {
|
||||
vm.$refs['treeGraphInfo'].destroyTree();
|
||||
}
|
||||
vm.$router.push({path: "/graphModel", query: {pageNo: vm.qo.pageNo, name: vm.qo.name}})
|
||||
vm.$message.success("保存成功");
|
||||
},
|
||||
changeArrowVisible() { // 显隐箭头
|
||||
vm.arrowVisible = !vm.arrowVisible;
|
||||
vm.queryTagData();
|
||||
},
|
||||
removeNode() { // 删除节点
|
||||
if (vm.selectObj.type.length === 0) {
|
||||
vm.$message.warning("请先选中节点或关系");
|
||||
return;
|
||||
}
|
||||
this.$confirm('此操作将永久删除选中节点和关系, 是否继续?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
if (vm.selectObj.type === "node") {
|
||||
request({
|
||||
url: `/nebula_model/deletemodelvertex/${vm.selectObj.value.id}`,
|
||||
method: 'get',
|
||||
data: {
|
||||
// vid: vm.selectObj.value.id
|
||||
}
|
||||
}).then(res => {
|
||||
vm.$message.success("删除成功");
|
||||
vm.queryTagData();
|
||||
vm.infoVisible = false;
|
||||
});
|
||||
} else if (vm.selectObj.type === "edge") {
|
||||
request({
|
||||
url: `/nebula_model/deletemodeledge`,
|
||||
method: 'post',
|
||||
data: {
|
||||
srcId: vm.selectObj.value.source,
|
||||
dstId: vm.selectObj.value.target,
|
||||
}
|
||||
}).then(res => {
|
||||
vm.$message.success("删除成功");
|
||||
vm.queryTagData();
|
||||
vm.infoVisible = false;
|
||||
});
|
||||
}
|
||||
}).catch(() => {
|
||||
});
|
||||
},
|
||||
submitUpdateNode(modifyCmd) { // 更新
|
||||
request({
|
||||
url: `/nebula_model/insertmodelvertex`,
|
||||
method: 'post',
|
||||
data: {
|
||||
vid: vm.selectObj.value.id,
|
||||
tagName: modifyCmd.tagName,
|
||||
label: modifyCmd.label,
|
||||
fields: modifyCmd.fields
|
||||
}
|
||||
}).then(res => {
|
||||
vm.queryTagData();
|
||||
vm.$message.success("保存成功");
|
||||
});
|
||||
},
|
||||
submitUpdateEdge(modifyCmd) {
|
||||
request({
|
||||
url: `/nebula_model/insertmodeledge`,
|
||||
method: 'post',
|
||||
data: {
|
||||
edgeName: modifyCmd.edgeName,
|
||||
label: modifyCmd.label,
|
||||
fields: modifyCmd.fields,
|
||||
arrow: modifyCmd.arrow,
|
||||
srcId: vm.selectObj.value.source,
|
||||
dstId: vm.selectObj.value.target,
|
||||
}
|
||||
}).then(res => {
|
||||
vm.queryTagData();
|
||||
vm.$message.success("保存成功");
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
function refreshDragedNodePosition(e) {
|
||||
const model = e.item.get('model');
|
||||
model.fx = e.x;
|
||||
model.fy = e.y;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.graph-name-box {
|
||||
position: absolute;
|
||||
top: 25px;
|
||||
left: 65px;
|
||||
width: 700px;
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
.form-title {
|
||||
font-size: 16px;
|
||||
margin: 15px 0;
|
||||
|
||||
}
|
||||
|
||||
.add-attribute-box {
|
||||
margin-top: 10px;
|
||||
color: #409EFF;
|
||||
cursor: pointer;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.graph-info-box, .tree-graph-info {
|
||||
position: absolute;
|
||||
width: 500px;
|
||||
top: 0px;
|
||||
overflow: hidden;
|
||||
bottom: 0;
|
||||
background-color: #fff;
|
||||
padding: 15px;
|
||||
z-index: 999;
|
||||
border-right: 1px solid rgba(52, 100, 224, 0.15);
|
||||
box-shadow: 0px 2px 21px 0px rgba(52, 100, 224, 0.15);
|
||||
}
|
||||
|
||||
.graph-info-box {
|
||||
left: 0px;
|
||||
}
|
||||
|
||||
.tree-graph-info {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.graph-info-child {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.el-icon-d-arrow-left, .el-icon-d-arrow-right {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
margin-top: -10px;
|
||||
font-size: 20px;
|
||||
cursor: pointer;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.el-icon-d-arrow-left {
|
||||
right: 0px;
|
||||
}
|
||||
|
||||
.el-icon-d-arrow-right {
|
||||
left: 0px;
|
||||
}
|
||||
|
||||
.info-line-item {
|
||||
margin-bottom: 35px;
|
||||
}
|
||||
|
||||
.info-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.info-content > div {
|
||||
margin-bottom: 5px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
ol, ul {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.menu {
|
||||
/*这个样式不写,右键弹框会一直显示在画布的左下角*/
|
||||
position: absolute;
|
||||
background: white;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #f2f4f7;
|
||||
left: -99999px;
|
||||
top: -999999px;
|
||||
}
|
||||
|
||||
.menu div {
|
||||
list-style: none;
|
||||
padding: 5px 10px;
|
||||
color: black;
|
||||
border-bottom: 1px dashed #ffffff;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.menu div:hover {
|
||||
color: #659bc5;
|
||||
background: #f3f6fa;
|
||||
}
|
||||
|
||||
.menu div:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
ul#menuBox li {
|
||||
cursor: pointer;
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
ul#menuBox li:hover {
|
||||
color: #1c63e0;
|
||||
}
|
||||
|
||||
.tree-container {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.tips-box {
|
||||
position: absolute;
|
||||
top: 25px;
|
||||
left: 50%;
|
||||
width: 300px;
|
||||
margin-left: -150px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
div.icon-box {
|
||||
position: absolute;
|
||||
top: 25px;
|
||||
right: 75px;
|
||||
}
|
||||
|
||||
div.icon {
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
padding: 15px;
|
||||
background-color: #fff;
|
||||
border-radius: 40px;
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
div.icon i {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
margin: auto;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
|
||||
div.icon-add i {
|
||||
background: url("../../assets/image/icon/bg-add.png") no-repeat center/contain;
|
||||
}
|
||||
|
||||
|
||||
div.icon-remove i {
|
||||
background: url("../../assets/image/icon/changyonggoupiaorenshanchu.png") no-repeat center/contain;
|
||||
}
|
||||
|
||||
|
||||
div.icon-save i {
|
||||
background: url("../../assets/image/icon/fanhui.png") no-repeat center/contain;
|
||||
}
|
||||
|
||||
div.icon-arrow i {
|
||||
background: url("../../assets/image/icon/arrowTop-fill.png") no-repeat center/contain;
|
||||
}
|
||||
|
||||
|
||||
div.icon-tree i {
|
||||
background: url("../../assets/image/icon/shuxingicon.png") no-repeat center/contain;
|
||||
}
|
||||
|
||||
div.icon-arrow.active i {
|
||||
background: url("../../assets/image/icon/arrowTop-fill-active.png") no-repeat center/contain;
|
||||
}
|
||||
|
||||
div.icon-arrow.active {
|
||||
box-shadow: 0px 0px 6px #979797;
|
||||
}
|
||||
|
||||
.node-box {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
947
web/src/components/graph/GraphSpace.vue
Normal file
@@ -0,0 +1,947 @@
|
||||
<template>
|
||||
<div class="node-box" style="position:relative;" v-loading="graphLoading">
|
||||
<transition name="el-zoom-in-center">
|
||||
<div v-show="infoVisible" class="graph-info-box">
|
||||
<div class="graph-info-child">
|
||||
<div class="info-item" style="margin-bottom: 15px">
|
||||
<div class="info-item-title">
|
||||
<label>{{comment}}</label>
|
||||
<!--<div class="add-attribute-box" style="float: right" @click="showAddGraphSpaceDialog({Name:''})">新建-->
|
||||
<!--</div>-->
|
||||
<!--<div class="add-attribute-box" style="float: right;margin-right: 10px" @click="removeGraphSpace()">-->
|
||||
<!--删除-->
|
||||
<!--</div>-->
|
||||
</div>
|
||||
<div class="info-item-content">
|
||||
<!--<el-select v-model="space" filterable placeholder="请选择" @change="handleSpaceChange">-->
|
||||
<!--<el-option v-for="item in spaceList"-->
|
||||
<!--:key="item.name"-->
|
||||
<!--:label="item.comment"-->
|
||||
<!--:value="item.name">-->
|
||||
<!--</el-option>-->
|
||||
<!--</el-select>-->
|
||||
<div style="margin-top: 20px;font-size: 14px;color: #606266">本体名称:{{ontologyName}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-tabs v-model="activeTab" class="el-tabs-item">
|
||||
<el-tab-pane label="概念" name="tag">
|
||||
<el-table
|
||||
class="tab-table-item"
|
||||
@row-click="modifyTag"
|
||||
:data="tagList"
|
||||
style="width: 100%">
|
||||
<el-table-column
|
||||
prop="Name"
|
||||
label="名称">
|
||||
<template slot-scope="scope">
|
||||
<div :style="scope.row.Name === activeSelectType ? 'color: #409EFF':''">
|
||||
<label>{{ scope.row.comment }}</label>
|
||||
<label>({{ scope.row.count }})</label>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- <div class="add-attribute-box" @click="modifyTag({Name:''})">+新建TAG</div>-->
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="关系" name="edge" class="el-tabs-item">
|
||||
<el-table
|
||||
class="tab-table-item"
|
||||
@row-click="modifyEdge"
|
||||
:data="edgeList"
|
||||
style="width: 100%">
|
||||
<el-table-column
|
||||
prop="Name"
|
||||
label="名称">
|
||||
<template slot-scope="scope">
|
||||
<div :style="scope.row.Name === activeSelectType ? 'color: #409EFF':''">
|
||||
<label>{{ scope.row.comment }}</label>
|
||||
<label>({{ scope.row.count }})</label>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- <div class="add-attribute-box" @click="modifyEdge({Name:''})">+新建EDGE</div>-->
|
||||
</el-tab-pane>
|
||||
|
||||
</el-tabs>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
<transition name="el-zoom-in-center">
|
||||
<div v-show="propsInfoVisible" class="tree-graph-info">
|
||||
<div class="graph-info-child">
|
||||
<div v-show="tabModifyCmdType === 'tag'">
|
||||
<tag-modify ref="tagModify"></tag-modify>
|
||||
</div>
|
||||
<div v-show="tabModifyCmdType === 'edge'">
|
||||
<edge-type-modify ref="edgeTypeModify"></edge-type-modify>
|
||||
</div>
|
||||
<div v-show="tabModifyCmdType === 'nodeDetail'">
|
||||
<node-detail ref="nodeDetail"></node-detail>
|
||||
</div>
|
||||
<div v-show="tabModifyCmdType === 'edgeAdd'">
|
||||
<edge-add ref="edgeAdd"></edge-add>
|
||||
</div>
|
||||
<i class="el-icon-d-arrow-right" @click="propsInfoVisible = false;"></i>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
<!-- 为图谱准备一个具备大小(宽高)的Dom -->
|
||||
<div class="tree-container">
|
||||
<div class="icon-box">
|
||||
<div v-if="showFlag" style="display: inline-block;margin-right: 50px">
|
||||
<el-input placeholder="请输入关键词" v-model="keyword" style="width: 550px">
|
||||
<el-select v-model="searchTag" slot="prepend" placeholder="请选择概念" style="width: 150px" filterable>
|
||||
<el-option :label="item.comment" :value="item.Name" v-for="(item,index) in tagList" v-if="index != 0"></el-option>
|
||||
</el-select>
|
||||
<el-button slot="append" icon="el-icon-search" @click="searchBtn()"></el-button>
|
||||
</el-input>
|
||||
</div>
|
||||
<div class="icon icon-search" @click="showFlag = !showFlag">
|
||||
<i title="搜索"></i>
|
||||
</div>
|
||||
<div class="icon icon-add" @click="showAddNodeDialog">
|
||||
<i title="新增类"></i>
|
||||
</div>
|
||||
<div title="新增关系" class="icon icon-arrow"
|
||||
@click="showAddEdgeDialog">
|
||||
<i title="新增关系"></i>
|
||||
</div>
|
||||
<div class="icon icon-save" @click="backGraph">
|
||||
<i title="返回"></i>
|
||||
</div>
|
||||
<!--<div title="按住shift点选两节点可新增关系" :class="['icon icon-arrow', createEdgeModelFlag ? 'active' : '']"-->
|
||||
<!--@click="changeCreateEdgeModel">-->
|
||||
<!--<i title="按住shift点选两节点可新增关系"></i>-->
|
||||
<!--</div>-->
|
||||
<!-- <div class="icon icon-remove" @click="removeNode">-->
|
||||
<!-- <i title="删除"></i>-->
|
||||
<!-- </div>-->
|
||||
</div>
|
||||
<div id="mountNode" style="width: 100%; height: 1000px"></div>
|
||||
</div>
|
||||
<graph-space-add ref="graphSpaceAdd"></graph-space-add>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import request from '@/utils/request';
|
||||
import {config} from '@/components/graph/config';
|
||||
import G6 from '@antv/g6';
|
||||
import tagModify from '@/components/dialog/TagModify';
|
||||
import edgeTypeModify from '@/components/dialog/EdgeTypeModify';
|
||||
import nodeDetail from '@/components/dialog/NodeDetail';
|
||||
import edgeAdd from '@/components/dialog/EdgeAdd';
|
||||
import edgeDetail from '@/components/dialog/EdgeDetail';
|
||||
import {getFirstStringProperty} from '@/utils/common';
|
||||
import graphSpaceAdd from '@/components/dialog/GraphSpaceAdd';
|
||||
|
||||
G6.registerBehavior('click-add-edge', {
|
||||
// Set the events and the corresponding responsing function for this behavior
|
||||
getEvents() {
|
||||
return {
|
||||
'node:click': 'onClick', // The event is canvas:click, the responsing function is onClick
|
||||
mousemove: 'onMousemove', // The event is mousemove, the responsing function is onMousemove
|
||||
'edge:click': 'onEdgeClick',
|
||||
};
|
||||
},
|
||||
// The responsing function for node:click defined in getEvents
|
||||
onClick(ev) {
|
||||
const self = this;
|
||||
const node = ev.item;
|
||||
const graph = self.graph;
|
||||
// The position where the mouse clicks
|
||||
const point = {x: ev.x, y: ev.y};
|
||||
const model = node.getModel();
|
||||
if (self.addingEdge && self.edge) {
|
||||
graph.updateItem(self.edge, {
|
||||
target: model.id,
|
||||
});
|
||||
// 打开编辑新建关系的信息弹窗
|
||||
vm.showAddEdgeDialog(self.edge._cfg.model);
|
||||
self.edge = null;
|
||||
self.addingEdge = false;
|
||||
} else {
|
||||
// Add anew edge, the end node is the current node user clicks
|
||||
self.edge = graph.addItem('edge', {
|
||||
source: model.id,
|
||||
target: model.id,
|
||||
});
|
||||
self.addingEdge = true;
|
||||
}
|
||||
},
|
||||
// The responsing function for mousemove defined in getEvents
|
||||
onMousemove(ev) {
|
||||
const self = this;
|
||||
// The current position the mouse clicks
|
||||
const point = {x: ev.x, y: ev.y};
|
||||
if (self.addingEdge && self.edge) {
|
||||
// Update the end node to the current node the mouse clicks
|
||||
self.graph.updateItem(self.edge, {
|
||||
target: point,
|
||||
});
|
||||
}
|
||||
},
|
||||
// The responsing function for edge:click defined in getEvents
|
||||
onEdgeClick(ev) {
|
||||
const self = this;
|
||||
const currentEdge = ev.item;
|
||||
if (self.addingEdge && self.edge === currentEdge) {
|
||||
self.graph.removeItem(self.edge);
|
||||
self.edge = null;
|
||||
self.addingEdge = false;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
var vm;
|
||||
var graph;
|
||||
var graphData;
|
||||
var _ = require('lodash');
|
||||
var nodeProps = {
|
||||
id: 'vid',
|
||||
};
|
||||
var edgeProps = {
|
||||
source: 'srcId',
|
||||
target: 'dstId',
|
||||
}
|
||||
export default {
|
||||
components: {
|
||||
'tag-modify': tagModify,
|
||||
'edge-type-modify': edgeTypeModify,
|
||||
'node-detail': nodeDetail,
|
||||
'edge-detail': edgeDetail,
|
||||
'graph-space-add': graphSpaceAdd,
|
||||
'edge-add':edgeAdd
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
space: '', // 当前展示的图空间(实例)
|
||||
activeSelectType: 'All',
|
||||
spaceList: [], // 所有的图空间列表
|
||||
tagList: [], // 图空间的TAG列表
|
||||
edgeList: [], // 图空间的EDGE列表
|
||||
activeTab: 'tag',
|
||||
graphLoading: false,
|
||||
tabModifyCmdType: 'tag',
|
||||
createEdgeModelFlag: false,
|
||||
infoVisible: true, // 左侧信息栏显隐
|
||||
propsInfoVisible: false, // 右侧树形图谱
|
||||
selectObj: {
|
||||
type: '',
|
||||
value: {}
|
||||
},
|
||||
tagMap: {},
|
||||
edgeMap: {},
|
||||
ontologyName:"",
|
||||
showFlag:false,
|
||||
keyword:"",
|
||||
searchTag:"",
|
||||
ontologyId:"",
|
||||
comment:"",
|
||||
qo:{
|
||||
pageNo:"",
|
||||
name:""
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
vm = this;
|
||||
},
|
||||
mounted() {
|
||||
vm.qo = {
|
||||
pageNo: this.$route.query.pageNo,
|
||||
name: this.$route.query.name
|
||||
};
|
||||
vm.ontologyId = this.$route.query.ontologyId;
|
||||
vm.space = this.$route.query.space;
|
||||
vm.comment = this.$route.query.comment;
|
||||
vm.handleSpaceChange();
|
||||
// vm.querySpaceList();
|
||||
// vm.initGraph();
|
||||
},
|
||||
methods: {
|
||||
querySpaceList() { // 查询图空间列表,供快速选择切换
|
||||
request({
|
||||
url: '/nebula_operate/showspace',
|
||||
method: 'get',
|
||||
data: {}
|
||||
}).then(res => {
|
||||
vm.spaceList = res.data;
|
||||
if (res.data.length > 0) {
|
||||
vm.space = res.data[0].name;
|
||||
vm.handleSpaceChange();
|
||||
}else{
|
||||
vm.space = "";
|
||||
vm.tagMap = {};
|
||||
vm.edgeMap = {};
|
||||
vm.tagList = [];
|
||||
vm.edgeList = [];
|
||||
vm.ontologyName = "";
|
||||
vm.destroyGraph();
|
||||
}
|
||||
});
|
||||
},
|
||||
queryOntologyDetail(){
|
||||
var id = vm.ontologyId;
|
||||
// vm.spaceList.forEach(item => {
|
||||
// if(item.name == vm.space){
|
||||
// id = item.OntologyId;
|
||||
// }
|
||||
// })
|
||||
|
||||
if(id){
|
||||
request({
|
||||
url: `/ontology/getone/`+id,
|
||||
method: 'post',
|
||||
data: {id:id}
|
||||
}).then(res => {
|
||||
vm.ontologyName = res.data.name;
|
||||
})
|
||||
}
|
||||
},
|
||||
handleSpaceChange() {
|
||||
vm.initGraph();
|
||||
vm.queryStatistics();
|
||||
vm.queryOntologyDetail();
|
||||
},
|
||||
queryStatistics() {
|
||||
request({
|
||||
url: `/nebula_operate/censusgraphbyspace/${vm.space}`,
|
||||
method: 'get',
|
||||
data: {}
|
||||
}).then(res => {
|
||||
let row = res.data;
|
||||
let tagMap = {};
|
||||
let edgeMap = {};
|
||||
row.forEach(item => {
|
||||
if (item.type === "Space") {
|
||||
if (item.name === "vertices") {
|
||||
tagMap['All'] = item.count;
|
||||
} else if (item.name === "edges") {
|
||||
edgeMap['All'] = item.count;
|
||||
}
|
||||
} else {
|
||||
if (item.type === "Tag") {
|
||||
tagMap[item.name] = item.count;
|
||||
} else if (item.type === "Edge") {
|
||||
edgeMap[item.name] = item.count;
|
||||
}
|
||||
}
|
||||
});
|
||||
vm.tagMap = tagMap;
|
||||
vm.edgeMap = edgeMap;
|
||||
vm.queryTagList();
|
||||
vm.queryEdgeList();
|
||||
});
|
||||
},
|
||||
queryTagList() { // 查询tag列表
|
||||
vm.propsInfoVisible = false;
|
||||
request({
|
||||
url: `/nebula_operate/showtag/${vm.space}`,
|
||||
method: 'get',
|
||||
data: {}
|
||||
}).then(res => {
|
||||
res.data.unshift({
|
||||
Name: `All`,
|
||||
comment: '实体数'
|
||||
});
|
||||
res.data.forEach(row => {
|
||||
row.count = vm.tagMap[row.Name] ? vm.tagMap[row.Name] : 0;
|
||||
});
|
||||
vm.tagList = res.data;
|
||||
});
|
||||
},
|
||||
queryEdgeList() {
|
||||
vm.propsInfoVisible = false;
|
||||
request({
|
||||
url: `/nebula_operate/showedge/${vm.space}`,
|
||||
method: 'get',
|
||||
data: {}
|
||||
}).then(res => {
|
||||
res.data.unshift({
|
||||
Name: `All`,
|
||||
comment: '三元组数'
|
||||
});
|
||||
res.data.forEach(row => {
|
||||
row.count = vm.edgeMap[row.Name] ? vm.edgeMap[row.Name] : 0;
|
||||
});
|
||||
vm.edgeList = res.data;
|
||||
});
|
||||
},
|
||||
modifyTag(row) {
|
||||
vm.tabModifyCmdType = 'tag';
|
||||
if (row.Name !== "All") {
|
||||
vm.propsInfoVisible = true;
|
||||
vm.$nextTick(() => {
|
||||
vm.$refs['tagModify'].updateValue(vm.space, row.Name);
|
||||
});
|
||||
} else {
|
||||
vm.propsInfoVisible = false;
|
||||
}
|
||||
// 更新图谱
|
||||
if (row.Name.length > 0) {
|
||||
vm.activeSelectType = row.Name;
|
||||
vm.querySpaceGraphData(row.Name, 'tag');
|
||||
}
|
||||
},
|
||||
modifyEdge(row) {
|
||||
vm.tabModifyCmdType = 'edge';
|
||||
if (row.Name !== "All") {
|
||||
vm.propsInfoVisible = true;
|
||||
vm.$nextTick(() => {
|
||||
vm.$refs['edgeTypeModify'].updateValue(vm.space, row.Name);
|
||||
});
|
||||
} else {
|
||||
vm.propsInfoVisible = false;
|
||||
}
|
||||
|
||||
// 更新图谱
|
||||
if (row.Name.length > 0) {
|
||||
vm.activeSelectType = row.Name;
|
||||
vm.querySpaceGraphData(row.Name, 'edge');
|
||||
}
|
||||
},
|
||||
queryDetail(type, obj) { // type : node/edge
|
||||
vm.tabModifyCmdType = type + 'Detail';
|
||||
vm.propsInfoVisible = true;
|
||||
vm.$nextTick(() => {
|
||||
vm.$refs[type + 'Detail'].queryDetail(vm.space, obj);
|
||||
});
|
||||
},
|
||||
showAddGraphSpaceDialog() {
|
||||
vm.$refs['graphSpaceAdd'].openDialog();
|
||||
},
|
||||
removeGraphSpace() {
|
||||
this.$confirm('此操作将永久删除, 是否继续?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
request({
|
||||
url: `/nebula_operate/dropspace/${vm.space}`,
|
||||
method: 'get',
|
||||
data: {}
|
||||
}).then(res => {
|
||||
vm.$message.success("删除成功");
|
||||
vm.querySpaceList();
|
||||
});
|
||||
});
|
||||
},
|
||||
querySpaceGraphData(typeName, type) { // 查询图空间内节点关系
|
||||
if (typeName == undefined) {
|
||||
vm.activeSelectType = "All";
|
||||
typeName = "All";
|
||||
}
|
||||
// vm.propsInfoVisible = false;
|
||||
vm.graphLoading = true;
|
||||
|
||||
// 根据查询类型区分接口,分三种,固定edgeType,固定tag的和查询全部类型的
|
||||
if (typeName === 'All') {
|
||||
request({
|
||||
url: `/nebula_operate/findpathinspace/${vm.space}`,
|
||||
method: 'post',
|
||||
data: {}
|
||||
}).then(res => {
|
||||
vm.resolveGraphData(res);
|
||||
});
|
||||
} else {
|
||||
if (type === "tag") {
|
||||
request({
|
||||
url: `/nebula_operate/findnodes/${vm.space}`,
|
||||
method: 'post',
|
||||
data: {
|
||||
tag: typeName
|
||||
}
|
||||
}).then(res => {
|
||||
vm.resolveGraphData({data: {nodes: res.data, relations: []}});
|
||||
});
|
||||
} else if (type === "edge") {
|
||||
request({
|
||||
url: `/nebula_operate/findrelations/${vm.space}`,
|
||||
method: 'post',
|
||||
data: {
|
||||
edge: typeName
|
||||
}
|
||||
}).then(res => {
|
||||
vm.resolveGraphData(res);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
resolveGraphData(res) { //处理图谱数据,格式化
|
||||
if (res.data && res.data.nodes) {
|
||||
res.data.nodes.forEach(node => {
|
||||
Reflect.ownKeys(nodeProps).forEach(key => {
|
||||
node[key] = _.get(node, nodeProps[key], '');
|
||||
});
|
||||
|
||||
if (node.properties) {
|
||||
node.label = node.name = getFirstStringProperty(node.properties);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (res.data && res.data.relations) {
|
||||
res.data.relations.forEach(edge => {
|
||||
Reflect.ownKeys(edgeProps).forEach(key => {
|
||||
edge[key] = _.get(edge, edgeProps[key], '');
|
||||
});
|
||||
if (edge.properties) {
|
||||
edge.label = edge.name = getFirstStringProperty(edge.properties);
|
||||
}
|
||||
|
||||
// 是否指向自己
|
||||
edge.type = edge.srcId === edge.dstId ? 'loop' : '';
|
||||
});
|
||||
}
|
||||
|
||||
graphData = {
|
||||
nodes: res.data && res.data.nodes ? res.data.nodes : [],
|
||||
edges: res.data && res.data.relations ? res.data.relations : []
|
||||
};
|
||||
// 读取数据
|
||||
graph.data(graphData);
|
||||
// 渲染图
|
||||
graph.render();
|
||||
vm.graphLoading = false;
|
||||
},
|
||||
initGraph() {
|
||||
this.destroyGraph();
|
||||
let mountNodeDom = document.getElementById("mountNode");
|
||||
let _width = mountNodeDom.clientWidth, _height = mountNodeDom.clientHeight;
|
||||
// 创建 G6 图实例
|
||||
if (graph == undefined || graph == null) {
|
||||
graph = new G6.Graph(config({width: _width, height: _height, id: 'mountNode'}));
|
||||
|
||||
graph.on('aftercreateedge', (e) => {
|
||||
vm.showAddEdgeDialog(e.edge._cfg.model);
|
||||
});
|
||||
|
||||
graph.on('canvas:click', (e) => {
|
||||
vm.selectObj = {
|
||||
type: '',
|
||||
value: {}
|
||||
};
|
||||
vm.clearStates();
|
||||
});
|
||||
|
||||
graph.on('edge:click', function (e) { // 点击边事件
|
||||
let edge = e.item._cfg.model;
|
||||
if (!edge.name) {
|
||||
return;
|
||||
}
|
||||
vm.queryDetail('edge', {
|
||||
edgeType: edge.edgeName,
|
||||
srcVid: edge.srcId,
|
||||
dstVid: edge.dstId
|
||||
});
|
||||
graph.getEdges().forEach((edge) => {
|
||||
graph.clearItemStates(edge);
|
||||
});
|
||||
graph.getNodes().forEach((node) => {
|
||||
graph.clearItemStates(node);
|
||||
});
|
||||
graph.setItemState(e.item, 'yourStateName', true);
|
||||
|
||||
});
|
||||
|
||||
graph.on('node:click', (e) => {
|
||||
if (!event.shiftKey && !vm.createEdgeModelFlag) { // 按住shift属于新增关系,不需要触发点击节点事件
|
||||
let node = e.item._cfg.model;
|
||||
vm.queryDetail('node', {
|
||||
tag: node.labels,
|
||||
vid: node.vid,
|
||||
});
|
||||
vm.clearStates();
|
||||
graph.setItemState(e.item, 'yourStateName', true);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
vm.querySpaceGraphData('All');
|
||||
},
|
||||
destroyGraph() {
|
||||
try {
|
||||
if (graph != undefined && graph != null) {
|
||||
graph.clear();
|
||||
graph = null;
|
||||
document.getElementById("mountNode").innerHTML = "";
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
},
|
||||
clearStates() { // 清空选中状态
|
||||
graph.getNodes().forEach((node) => {
|
||||
graph.clearItemStates(node);
|
||||
});
|
||||
graph.getEdges().forEach((edge) => {
|
||||
graph.clearItemStates(edge);
|
||||
});
|
||||
},
|
||||
changeCreateEdgeModel() { // 切换模式,默认和添加关系模式之间切换
|
||||
vm.createEdgeModelFlag = !vm.createEdgeModelFlag;
|
||||
if (vm.createEdgeModelFlag) {
|
||||
graph.setMode("addEdge");
|
||||
} else {
|
||||
graph.setMode("default");
|
||||
}
|
||||
},
|
||||
showAddEdgeDialog(edge) {
|
||||
vm.tabModifyCmdType = 'edgeDetail';
|
||||
vm.propsInfoVisible = true;
|
||||
vm.$nextTick(() => {
|
||||
vm.$refs['edgeDetail'].createItem(vm.space, edge.source, edge.target);
|
||||
});
|
||||
},
|
||||
showAddNodeDialog() {
|
||||
vm.tabModifyCmdType = 'nodeDetail';
|
||||
vm.propsInfoVisible = true;
|
||||
vm.$nextTick(() => {
|
||||
vm.$refs['nodeDetail'].createItem(vm.space);
|
||||
});
|
||||
},
|
||||
showAddEdgeDialog(){
|
||||
vm.tabModifyCmdType = 'edgeAdd';
|
||||
vm.propsInfoVisible = true;
|
||||
vm.$nextTick(() => {
|
||||
vm.$refs['edgeAdd'].createItem(vm.space);
|
||||
});
|
||||
},
|
||||
//搜索
|
||||
searchBtn(){
|
||||
if(!vm.searchTag){
|
||||
vm.$message.warning("请选择概念");
|
||||
return false;
|
||||
}
|
||||
if(!vm.keyword){
|
||||
vm.$message.warning("请输入关键字");
|
||||
return false;
|
||||
}
|
||||
vm.graphLoading = true;
|
||||
request({
|
||||
url: `/nebula_operate/findnodebykeyword/${vm.space}/${vm.searchTag}`,
|
||||
method: 'post',
|
||||
data: {keyword:vm.keyword}
|
||||
}).then(res => {
|
||||
if (res.data) {
|
||||
res.data.forEach(node => {
|
||||
Reflect.ownKeys(nodeProps).forEach(key => {
|
||||
node[key] = _.get(node, nodeProps[key], '');
|
||||
});
|
||||
|
||||
if (node.properties) {
|
||||
node.label = node.name = getFirstStringProperty(node.properties);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
graphData = {
|
||||
nodes: res.data ? res.data : [],
|
||||
edges: []
|
||||
};
|
||||
// 读取数据
|
||||
graph.data(graphData);
|
||||
// 渲染图
|
||||
graph.render();
|
||||
vm.graphLoading = false;
|
||||
});
|
||||
},
|
||||
findOnePathBySrcidAndDctid(srcId, dstId){
|
||||
request({
|
||||
url: `/nebula_operate/findonepathbysrcidanddctid/${vm.space}/${srcId}/${dstId}`,
|
||||
method: 'get',
|
||||
data: {}
|
||||
}).then(res => {
|
||||
vm.resolveGraphData(res);
|
||||
});
|
||||
},
|
||||
findNodeById(tag,vid){
|
||||
request({
|
||||
url: `/nebula_operate/findnodebyid/${vm.space}/${tag}/${vid}`,
|
||||
method: 'get',
|
||||
data: {}
|
||||
}).then(res => {
|
||||
if (res.data) {
|
||||
Reflect.ownKeys(nodeProps).forEach(key => {
|
||||
res.data[key] = _.get(res.data, nodeProps[key], '');
|
||||
});
|
||||
|
||||
if (res.data.properties) {
|
||||
res.data.label = res.data.name = getFirstStringProperty(res.data.properties);
|
||||
}
|
||||
}
|
||||
|
||||
graphData = {
|
||||
nodes: res.data ? [res.data] : [],
|
||||
edges: []
|
||||
};
|
||||
// 读取数据
|
||||
graph.data(graphData);
|
||||
// 渲染图
|
||||
graph.render();
|
||||
vm.graphLoading = false;
|
||||
});
|
||||
},
|
||||
backGraph() { // 返回
|
||||
vm.$router.push({path: "/graphSpaceManage", query: {pageNo: vm.qo.pageNo, name: vm.qo.name}})
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
function refreshDragedNodePosition(e) {
|
||||
const model = e.item.get('model');
|
||||
model.fx = e.x;
|
||||
model.fy = e.y;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
.el-tabs-item {
|
||||
height: calc(100% - 200px);
|
||||
}
|
||||
|
||||
.el-tabs-item .el-tabs__content {
|
||||
height: calc(100% - 50px);
|
||||
}
|
||||
|
||||
.el-tabs-item .el-tabs__content .el-tab-pane {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.tab-table-item {
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.node-box {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.info-item-content .el-select {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
margin-bottom: 45px;
|
||||
}
|
||||
|
||||
.info-item-title {
|
||||
border-bottom: 1px solid #ccc;
|
||||
padding-bottom: 15px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.info-item-title label {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
color: #2f2f2f;
|
||||
}
|
||||
|
||||
.graph-name-box {
|
||||
position: absolute;
|
||||
top: 25px;
|
||||
left: 65px;
|
||||
width: 250px;
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
.form-title {
|
||||
font-size: 16px;
|
||||
margin: 15px 0;
|
||||
|
||||
}
|
||||
|
||||
.add-attribute-box {
|
||||
margin-top: 10px;
|
||||
color: #409EFF;
|
||||
cursor: pointer;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.graph-info-box, .tree-graph-info {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
overflow: hidden;
|
||||
bottom: 0;
|
||||
background-color: #fff;
|
||||
padding: 15px;
|
||||
z-index: 999;
|
||||
border-right: 1px solid rgba(52, 100, 224, 0.15);
|
||||
box-shadow: 0px 2px 21px 0px rgba(52, 100, 224, 0.15);
|
||||
}
|
||||
|
||||
.graph-info-box {
|
||||
left: 0;
|
||||
width: 230px;
|
||||
}
|
||||
|
||||
.tree-graph-info {
|
||||
right: 0;
|
||||
width: 500px;
|
||||
}
|
||||
|
||||
.graph-info-child {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.graph-info-child .el-table__header-wrapper {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.el-icon-d-arrow-left, .el-icon-d-arrow-right, .el-icon-d-arrow-right2 {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
margin-top: -10px;
|
||||
font-size: 20px;
|
||||
cursor: pointer;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.el-icon-d-arrow-left {
|
||||
right: 0px;
|
||||
}
|
||||
|
||||
.el-icon-d-arrow-right {
|
||||
left: 0px;
|
||||
}
|
||||
|
||||
.info-line-item {
|
||||
margin-bottom: 35px;
|
||||
}
|
||||
|
||||
.info-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.info-content > div {
|
||||
margin-bottom: 5px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
ol, ul {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.menu {
|
||||
/*这个样式不写,右键弹框会一直显示在画布的左下角*/
|
||||
position: absolute;
|
||||
background: white;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #f2f4f7;
|
||||
left: -99999px;
|
||||
top: -999999px;
|
||||
}
|
||||
|
||||
.menu div {
|
||||
list-style: none;
|
||||
padding: 5px 10px;
|
||||
color: black;
|
||||
border-bottom: 1px dashed #ffffff;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.menu div:hover {
|
||||
color: #659bc5;
|
||||
background: #f3f6fa;
|
||||
}
|
||||
|
||||
.menu div:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
ul#menuBox li {
|
||||
cursor: pointer;
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
ul#menuBox li:hover {
|
||||
color: #1c63e0;
|
||||
}
|
||||
|
||||
.tree-container {
|
||||
position: relative;
|
||||
padding-left: 300px;
|
||||
}
|
||||
|
||||
.tips-box {
|
||||
position: absolute;
|
||||
top: 25px;
|
||||
left: 50%;
|
||||
width: 300px;
|
||||
margin-left: -150px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
div.icon-box {
|
||||
position: absolute;
|
||||
top: 25px;
|
||||
right: 75px;
|
||||
}
|
||||
|
||||
div.icon {
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
padding: 15px;
|
||||
background-color: #fff;
|
||||
border-radius: 40px;
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
div.icon i {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
margin: auto;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
|
||||
div.icon-add i {
|
||||
background: url("../../assets/image/icon/bg-add.png") no-repeat center/contain;
|
||||
}
|
||||
|
||||
|
||||
div.icon-remove i {
|
||||
background: url("../../assets/image/icon/changyonggoupiaorenshanchu.png") no-repeat center/contain;
|
||||
}
|
||||
|
||||
|
||||
div.icon-save i {
|
||||
background: url("../../assets/image/icon/fanhui.png") no-repeat center/contain;
|
||||
}
|
||||
|
||||
div.icon-arrow i {
|
||||
background: url("../../assets/image/icon/arrowTop-fill.png") no-repeat center/contain;
|
||||
}
|
||||
|
||||
|
||||
div.icon-tree i {
|
||||
background: url("../../assets/image/icon/shuxingicon.png") no-repeat center/contain;
|
||||
}
|
||||
|
||||
div.icon-search i {
|
||||
background: url("../../assets/image/icon/search.png") no-repeat center/contain;
|
||||
}
|
||||
|
||||
div.icon-arrow.active i {
|
||||
background: url("../../assets/image/icon/arrowTop-fill-active.png") no-repeat center/contain;
|
||||
}
|
||||
|
||||
div.icon-arrow.active {
|
||||
box-shadow: 0px 0px 6px #979797;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
327
web/src/components/graph/Graph_x6.vue
Normal file
@@ -0,0 +1,327 @@
|
||||
<template>
|
||||
<div class="node-box">
|
||||
<transition name="el-zoom-in-center">
|
||||
<div v-show="infoVisible" class="graph-info-box">
|
||||
<div class="form-title"></div>
|
||||
<el-form ref="relationForm" label-width="80px">
|
||||
<el-form-item label="*关系名称">
|
||||
<el-input v-model="relationCmd.name"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</transition>
|
||||
<i :class="infoVisible ? 'el-icon-d-arrow-left' : 'el-icon-d-arrow-right'"
|
||||
@click="infoVisible = !infoVisible"></i>
|
||||
<!-- 为图谱准备一个具备大小(宽高)的Dom -->
|
||||
<div class="tree-container">
|
||||
<div class="icon icon-add" @click="showAddNodeDialog">
|
||||
<i title="新增节点"></i>
|
||||
</div>
|
||||
<div class="icon icon-remove">
|
||||
<i title="删除"></i>
|
||||
</div>
|
||||
<div class="icon icon-save">
|
||||
<i title="保存"></i>
|
||||
</div>
|
||||
<div id="mountNode" style="width: 100%; height: 1000px"></div>
|
||||
</div>
|
||||
<el-dialog
|
||||
title="新增节点"
|
||||
:visible.sync="addNodeDialogVisible"
|
||||
width="40%">
|
||||
<el-form ref="addNodeForm" label-width="80px">
|
||||
<el-form-item label="节点名称">
|
||||
<el-input v-model="addNodeCmd.name"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="addNodeDialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="submitAddNode">确 定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import request from '@/utils/request';
|
||||
import { Graph } from '@antv/x6';
|
||||
|
||||
var vm;
|
||||
var graph;
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
nodeNum: 0,
|
||||
linkNum: 0,
|
||||
infoVisible: false,
|
||||
clickNode: {id: '', name: ''},
|
||||
addNodeDialogVisible: false,
|
||||
addNodeCmd: {
|
||||
name: ''
|
||||
},
|
||||
relationCmd: {
|
||||
name: '',
|
||||
table: '',
|
||||
sourceId: '',
|
||||
targetId: '',
|
||||
edgeId: ''
|
||||
},
|
||||
nodeAttributes: [] // 节点属性
|
||||
}
|
||||
},
|
||||
created() {
|
||||
vm = this;
|
||||
},
|
||||
mounted() {
|
||||
const data = {
|
||||
// 节点
|
||||
nodes: [
|
||||
{
|
||||
id: 'node1', // String,可选,节点的唯一标识
|
||||
x: 40, // Number,必选,节点位置的 x 值
|
||||
y: 40, // Number,必选,节点位置的 y 值
|
||||
width: 80, // Number,可选,节点大小的 width 值
|
||||
height: 40, // Number,可选,节点大小的 height 值
|
||||
label: 'hello', // String,节点标签
|
||||
},
|
||||
{
|
||||
id: 'node2', // String,节点的唯一标识
|
||||
x: 160, // Number,必选,节点位置的 x 值
|
||||
y: 180, // Number,必选,节点位置的 y 值
|
||||
width: 80, // Number,可选,节点大小的 width 值
|
||||
height: 40, // Number,可选,节点大小的 height 值
|
||||
label: 'world', // String,节点标签
|
||||
},
|
||||
],
|
||||
// 边
|
||||
edges: [
|
||||
{
|
||||
source: 'node1', // String,必须,起始节点 id
|
||||
target: 'node2', // String,必须,目标节点 id
|
||||
},
|
||||
],
|
||||
};
|
||||
vm.initGraph(data);
|
||||
},
|
||||
methods: {
|
||||
initGraph: function (_data) {
|
||||
this.destroyGraph();
|
||||
let _width = document.getElementById("mountNode").clientWidth;
|
||||
let _height = document.getElementById("mountNode").clientHeight;
|
||||
graph = new Graph({
|
||||
container: document.getElementById('mountNode'),
|
||||
width: _width,
|
||||
height: _height,
|
||||
scroller: {
|
||||
enabled: true,
|
||||
pannable: true,
|
||||
pageVisible: false,
|
||||
pageBreak: false,
|
||||
},
|
||||
// mousewheel: {
|
||||
// enabled: true,
|
||||
// modifiers: ['ctrl', 'meta'],
|
||||
// },
|
||||
modes: {
|
||||
// Defualt mode
|
||||
default: ['drag-node',
|
||||
{
|
||||
type: 'drag-canvas',
|
||||
enableOptimize: true, // enable the optimize to hide the shapes beside nodes' keyShape
|
||||
},
|
||||
{
|
||||
type: 'zoom-canvas',
|
||||
enableOptimize: true, // enable the optimize to hide the shapes beside nodes' keyShape
|
||||
},
|
||||
{
|
||||
type: 'create-edge',
|
||||
key: 'shift', // undefined by default, options: 'shift', 'control', 'ctrl', 'meta', 'alt'
|
||||
},
|
||||
]
|
||||
},
|
||||
});
|
||||
graph.fromJSON(_data);
|
||||
|
||||
},
|
||||
destroyGraph() {
|
||||
try {
|
||||
if(graph != undefined && graph != null) {
|
||||
graph.clear();
|
||||
graph = null;
|
||||
document.getElementById("mountNode").innerHTML = "";
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
},
|
||||
clearStates() { // 清空选中状态
|
||||
graph.getNodes().forEach((node) => {
|
||||
graph.clearItemStates(node);
|
||||
});
|
||||
graph.getEdges().forEach((edge) => {
|
||||
graph.clearItemStates(edge);
|
||||
});
|
||||
},
|
||||
showAddNodeDialog() {
|
||||
vm.addNodeCmd = {
|
||||
name: ''
|
||||
};
|
||||
vm.addNodeDialogVisible = true;
|
||||
},
|
||||
submitAddNode() {
|
||||
graph.addNode({
|
||||
id: Math.ceil(Math.random()*10000).toString(),
|
||||
label: vm.addNodeCmd.name
|
||||
});
|
||||
vm.$message.success("新增节点成功");
|
||||
vm.addNodeDialogVisible = false;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
function refreshDragedNodePosition(e) {
|
||||
const model = e.item.get('model');
|
||||
model.fx = e.x;
|
||||
model.fy = e.y;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.graph-info-box {
|
||||
position: absolute;
|
||||
left: 290px;
|
||||
width: 500px;
|
||||
top: 60px;
|
||||
bottom: 0;
|
||||
background-color: #fff;
|
||||
padding: 15px 15px;
|
||||
z-index: 999;
|
||||
border-right: 1px solid rgba(52, 100, 224, 0.15);
|
||||
box-shadow: 0px 2px 21px 0px rgba(52, 100, 224, 0.15);
|
||||
}
|
||||
|
||||
.el-icon-d-arrow-left, .el-icon-d-arrow-right {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
margin-top: -10px;
|
||||
font-size: 20px;
|
||||
cursor: pointer;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.el-icon-d-arrow-left {
|
||||
left: 780px;
|
||||
}
|
||||
|
||||
.el-icon-d-arrow-right {
|
||||
left: 300px;
|
||||
}
|
||||
|
||||
.info-line-item {
|
||||
margin-bottom: 35px;
|
||||
}
|
||||
|
||||
.info-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.info-content > div {
|
||||
margin-bottom: 5px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
ol, ul {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.menu {
|
||||
/*这个样式不写,右键弹框会一直显示在画布的左下角*/
|
||||
position: absolute;
|
||||
background: white;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #f2f4f7;
|
||||
left: -99999px;
|
||||
top: -999999px;
|
||||
}
|
||||
|
||||
.menu div {
|
||||
list-style: none;
|
||||
padding: 5px 10px;
|
||||
color: black;
|
||||
border-bottom: 1px dashed #ffffff;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.menu div:hover {
|
||||
color: #659bc5;
|
||||
background: #f3f6fa;
|
||||
}
|
||||
|
||||
.menu div:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
ul#menuBox li {
|
||||
cursor: pointer;
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
ul#menuBox li:hover {
|
||||
color: #1c63e0;
|
||||
}
|
||||
|
||||
.tree-container {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
div.icon {
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
padding: 15px;
|
||||
background-color: #fff;
|
||||
border-radius: 40px;
|
||||
|
||||
position: absolute;
|
||||
top: 25px;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
div.icon i {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
margin: auto;
|
||||
display: inline-block;
|
||||
|
||||
}
|
||||
|
||||
div.icon-add {
|
||||
right: 75px;
|
||||
}
|
||||
|
||||
div.icon-add i {
|
||||
background: url("../../assets/image/icon/bg-add.png") no-repeat center/contain;
|
||||
}
|
||||
|
||||
div.icon-remove {
|
||||
right: 145px;
|
||||
}
|
||||
|
||||
div.icon-remove i {
|
||||
background: url("../../assets/image/icon/changyonggoupiaorenshanchu.png") no-repeat center/contain;
|
||||
}
|
||||
|
||||
div.icon-save {
|
||||
right: 215px;
|
||||
}
|
||||
|
||||
div.icon-save i {
|
||||
background: url("../../assets/image/icon/baocun.png") no-repeat center/contain;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
81
web/src/components/graph/config.js
Normal file
@@ -0,0 +1,81 @@
|
||||
export function config(param) {
|
||||
return {
|
||||
container: param.id, // 指定图画布的容器id
|
||||
// 画布宽高
|
||||
width: param.width,
|
||||
height: param.height,
|
||||
layout: {
|
||||
type: 'force',
|
||||
nodeStrength: -0,
|
||||
nodeSize: 80,
|
||||
preventOverlap: true,
|
||||
edgeStrength: 0.1
|
||||
},
|
||||
// layout: {
|
||||
// type: 'fruchterman',
|
||||
// gravity: 10, // 重力大小,影响紧凑性, 默认10
|
||||
// speed: 5, // 每次迭代节点移动的速度。速度太快可能会导致强烈震荡,默认1
|
||||
// workerEnabled: true, // 是否启用 web-worker 以防布局计算时间过长阻塞页面交互, 默认false
|
||||
// },
|
||||
modes: {
|
||||
// Defualt mode
|
||||
default: ['drag-node',
|
||||
{
|
||||
type: 'drag-canvas',
|
||||
enableOptimize: true, // enable the optimize to hide the shapes beside nodes' keyShape
|
||||
},
|
||||
{
|
||||
type: 'zoom-canvas',
|
||||
enableOptimize: true, // enable the optimize to hide the shapes beside nodes' keyShape
|
||||
},
|
||||
{
|
||||
type: 'create-edge',
|
||||
key: 'shift', // undefined by default, options: 'shift', 'control', 'ctrl', 'meta', 'alt'
|
||||
},
|
||||
],
|
||||
addEdge: ['click-add-edge'],
|
||||
},
|
||||
// plugins: [contextMenu], //minimap
|
||||
defaultNode: {
|
||||
size: 25,
|
||||
color: '#4b4b4b',
|
||||
label: 'name',
|
||||
style: {
|
||||
fill: '#68BDF6'
|
||||
},
|
||||
labelCfg: {
|
||||
position: 'bottom',
|
||||
style: {
|
||||
fontSize: 14,
|
||||
fill: '#4b4b4b'
|
||||
}
|
||||
}
|
||||
},
|
||||
defaultEdge: {
|
||||
style: {
|
||||
stroke: '#B3B3B3',
|
||||
lineAppendWidth: 10, // Enlarge the range the edge to be hitted
|
||||
},
|
||||
labelCfg: {
|
||||
autoRotate: false,
|
||||
style: {
|
||||
fontSize: 13,
|
||||
fill: '#989898'
|
||||
}
|
||||
},
|
||||
},
|
||||
nodeStateStyles: {
|
||||
yourStateName: {
|
||||
stroke: '#f00',
|
||||
lineWidth: 3,
|
||||
},
|
||||
},
|
||||
edgeStateStyles: {
|
||||
yourStateName: {
|
||||
stroke: '#f00',
|
||||
lineWidth: 3,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
110
web/src/components/log/index.vue
Normal file
@@ -0,0 +1,110 @@
|
||||
<template>
|
||||
<div>
|
||||
<div id="log-box" v-html="content"></div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import request from '@/utils/request2';
|
||||
|
||||
var _this;
|
||||
var socket;
|
||||
var sit;
|
||||
export default {
|
||||
name: "log",
|
||||
data() {
|
||||
return {
|
||||
modelId: '',
|
||||
type: '',
|
||||
content: ''
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
_this = this;
|
||||
},
|
||||
methods: {
|
||||
close() {
|
||||
if (sit) {
|
||||
clearInterval(sit);
|
||||
}
|
||||
_this.content = "";
|
||||
if (socket) {
|
||||
socket.close();
|
||||
}
|
||||
},
|
||||
init({modelId, type}) {
|
||||
_this.content = "";
|
||||
_this.modelId = modelId;
|
||||
_this.type = type;
|
||||
console.log(`当前modelId为${modelId},type为${type}`);
|
||||
socket = new WebSocket(`ws://47.103.128.32:10050/socket/file-tail?modelId=${modelId}&type=${type}`);
|
||||
//连接打开事件
|
||||
socket.onopen = function () {
|
||||
console.log("Socket 已打开");
|
||||
};
|
||||
//收到消息事件
|
||||
socket.onmessage = function (msg) {
|
||||
if (msg.data.indexOf('连接成功,sessionId=') != -1) {
|
||||
var sessionId = msg.data.slice(15);
|
||||
console.log(sessionId)
|
||||
} else {
|
||||
// console.log(msg);
|
||||
_this.content += '<p>' + msg.data + "</p>";
|
||||
_this.$nextTick(() => {
|
||||
document.getElementById("log-box").scrollTop = 100000;
|
||||
});
|
||||
}
|
||||
};
|
||||
//连接关闭事件
|
||||
socket.onclose = function () {
|
||||
console.log("Socket已关闭");
|
||||
};
|
||||
//发生了错误事件
|
||||
socket.onerror = function () {
|
||||
alert("Socket发生了错误");
|
||||
}
|
||||
|
||||
|
||||
//创建心跳,防止掉线
|
||||
sit = setInterval(() => {
|
||||
let op = {
|
||||
data: "heart",
|
||||
};
|
||||
sendJson(op);
|
||||
}, 5000);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function sendJson(data) {
|
||||
// 0 CONNECTING 连接尚未建立
|
||||
// 1 OPEN WebSocket的链接已经建立
|
||||
// 2 CLOSING 连接正在关闭
|
||||
// 3 CLOSED 连接已经关闭或不可用
|
||||
if (socket.readyState == 2 || socket.readyState == 3) {
|
||||
clearInterval(sit);
|
||||
sit = null;
|
||||
} else {
|
||||
socket.send(JSON.stringify(data));
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
#log-box {
|
||||
height: 800px;
|
||||
overflow-y: auto;
|
||||
background-color: #c2c2c2;
|
||||
border-radius: 5px;
|
||||
padding: 0 25px;
|
||||
}
|
||||
|
||||
#log-box p {
|
||||
line-height: 30px;
|
||||
font-size: 16px;
|
||||
text-indent: 2em;
|
||||
color: #313131;
|
||||
}
|
||||
</style>
|
||||
256
web/src/components/menus/614/AuxiliaryMaintenance.vue
Normal file
@@ -0,0 +1,256 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="menu-title">
|
||||
辅助维修
|
||||
<el-image
|
||||
class="img-item"
|
||||
:src="coverImg"
|
||||
:preview-src-list="srcList">
|
||||
</el-image>
|
||||
</div>
|
||||
<div class="menu-content">
|
||||
<div class="search-input-box">
|
||||
<el-input
|
||||
class="search-input"
|
||||
placeholder="请输入内容"
|
||||
v-model="keyword">
|
||||
<i slot="prefix" class="el-input__icon el-icon-search"></i>
|
||||
</el-input>
|
||||
<el-button type="primary" style="margin-left: 30px" @click="queryByKeyword">检 索</el-button>
|
||||
</div>
|
||||
<div class="title-label">Top5</div>
|
||||
<el-tabs v-model="activeTab">
|
||||
<el-tab-pane label="推荐案例" name="first">
|
||||
<el-table :data="list" style="width: 100%">
|
||||
<el-table-column type="index" width="50"></el-table-column>
|
||||
<el-table-column prop="number" label="案例编号"></el-table-column>
|
||||
<el-table-column prop="name" label="案例名称"></el-table-column>
|
||||
<el-table-column prop="keyContent" label="关键词"></el-table-column>
|
||||
<el-table-column prop="name" label="操作" width="120">
|
||||
<template slot-scope="scope">
|
||||
<el-button @click.native.prevent="showDetail(scope.row, 'faultCase')" type="text" size="small">
|
||||
查看说明
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="推荐维修" name="second">
|
||||
<el-table :data="repairList" style="width: 100%">
|
||||
<el-table-column type="index" width="50"></el-table-column>
|
||||
<el-table-column prop="title" label="标题"></el-table-column>
|
||||
<el-table-column prop="reason" label="原因">
|
||||
<template slot-scope="scope">
|
||||
<label>{{ scope.row.reason.substring(0, 30) + (scope.row.reason.length > 30 ? '...' : '') }}</label>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="influence" label="影响">
|
||||
<template slot-scope="scope">
|
||||
<label>{{
|
||||
scope.row.influence.substring(0, 30) + (scope.row.influence.length > 30 ? '...' : '')
|
||||
}}</label>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="program" label="程序">
|
||||
<template slot-scope="scope">
|
||||
<label>{{ scope.row.program.substring(0, 30) + (scope.row.program.length > 30 ? '...' : '') }}</label>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="name" label="操作" width="120">
|
||||
<template slot-scope="scope">
|
||||
<el-button @click.native.prevent="showDetail(scope.row, 'repair')" type="text" size="small">
|
||||
查看说明
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
<el-dialog
|
||||
title="查看说明"
|
||||
:visible.sync="detailVisible"
|
||||
width="50%">
|
||||
<el-tabs>
|
||||
<el-tab-pane label="故障描述">
|
||||
{{ cmd.description }}
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="排故过程">
|
||||
{{ cmd.checkFaultProcess }}
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="故障分析">
|
||||
{{ cmd.faultAnalysis }}
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="故障总结">
|
||||
{{ cmd.faultSummary }}
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="经验教训">
|
||||
{{ cmd.experience }}
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="detailVisible = false">关 闭</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
<el-dialog
|
||||
title="查看说明"
|
||||
:visible.sync="repairDetailVisible"
|
||||
width="50%">
|
||||
<el-tabs>
|
||||
<el-tab-pane label="标题">
|
||||
{{ cmd.title }}
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="原因">
|
||||
{{ cmd.reason }}
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="影响">
|
||||
{{ cmd.influence }}
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="程序">
|
||||
{{ cmd.program }}
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="repairDetailVisible = false">关 闭</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import request from '@/utils/request614';
|
||||
|
||||
import coverImg from "@/assets/image/icon/tupian.png";
|
||||
import aImg from "@/assets/image/614/5a.jpg";
|
||||
import bImg from "@/assets/image/614/5b.jpg";
|
||||
import cImg from "@/assets/image/614/5c.jpg";
|
||||
import dImg from "@/assets/image/614/5d.jpg";
|
||||
import eImg from "@/assets/image/614/5e.jpg";
|
||||
import fImg from "@/assets/image/614/5f.jpg";
|
||||
import gImg from "@/assets/image/614/5g.jpg";
|
||||
import hImg from "@/assets/image/614/5h.jpg";
|
||||
|
||||
|
||||
var _this;
|
||||
export default {
|
||||
name: "auxiliaryMaintenance",
|
||||
data() {
|
||||
return {
|
||||
keyword: '',
|
||||
list: [],
|
||||
repairList: [],
|
||||
cmd: {},
|
||||
rateNum: "-",
|
||||
activeTab: 'first',
|
||||
detailVisible: false,
|
||||
repairDetailVisible: false,
|
||||
coverImg: coverImg,
|
||||
srcList: [
|
||||
aImg, bImg, cImg, dImg, eImg, fImg, gImg, hImg
|
||||
]
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
_this = this;
|
||||
},
|
||||
methods: {
|
||||
queryByKeyword() {
|
||||
if (_this.keyword.length === 0) {
|
||||
_this.$message.warning("请输入内容再进行检索");
|
||||
return false;
|
||||
}
|
||||
|
||||
let sum = 0;
|
||||
for (let charStr in _this.keyword) {
|
||||
sum += charStr.charCodeAt(0);
|
||||
}
|
||||
_this.rateNum = "9" + sum.toString().substring(0, 1) + "." + sum.toString().substring(1);
|
||||
_this.queryFaultCaseList();
|
||||
_this.queryRepairList();
|
||||
},
|
||||
queryFaultCaseList() {
|
||||
let formData = new FormData();
|
||||
formData.append("keyword", _this.keyword);
|
||||
request({
|
||||
url: '/fault_case/query_like_keyword',
|
||||
method: 'post',
|
||||
data: formData
|
||||
}).then(res => {
|
||||
let list = res.data;
|
||||
let resList = [];
|
||||
// 优化排序
|
||||
for (let i = list.length - 1; i >= 0; i--) {
|
||||
let row = list[i];
|
||||
if (row.keyContent && row.keyContent.indexOf(_this.keyword) >= 0 && row.description && row.description.indexOf(_this.keyword) >= 0) {
|
||||
resList.unshift(row);
|
||||
} else {
|
||||
resList.push(row);
|
||||
}
|
||||
}
|
||||
_this.list = resList;
|
||||
_this.$message.success("检索成功");
|
||||
});
|
||||
},
|
||||
queryRepairList() {
|
||||
let formData = new FormData();
|
||||
formData.append("keyword", _this.keyword);
|
||||
request({
|
||||
url: '/repair/query_like_keyword',
|
||||
method: 'post',
|
||||
data: formData
|
||||
}).then(res => {
|
||||
let list = res.data;
|
||||
let resList = [];
|
||||
// 优化排序
|
||||
for (let i = list.length - 1; i >= 0; i--) {
|
||||
let row = list[i];
|
||||
if (row.title && row.title.indexOf(_this.keyword) >= 0 && row.reason && row.reason.indexOf(_this.keyword) >= 0) {
|
||||
resList.unshift(row);
|
||||
} else {
|
||||
resList.push(row);
|
||||
}
|
||||
}
|
||||
_this.repairList = resList;
|
||||
});
|
||||
},
|
||||
showDetail(row, type) {
|
||||
_this.cmd = row;
|
||||
if (type === 'repair') {
|
||||
_this.repairDetailVisible = true;
|
||||
} else if (type === 'faultCase') {
|
||||
_this.detailVisible = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.img-item {
|
||||
width: 95px;
|
||||
height: 25px;
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
right: 30px;
|
||||
top: 80px;
|
||||
}
|
||||
|
||||
.menu-content {
|
||||
overflow-x: hidden;
|
||||
|
||||
.search-input-box {
|
||||
display: flex;
|
||||
width: 40%;
|
||||
margin-bottom: 1.5625vw;
|
||||
}
|
||||
|
||||
.title-label {
|
||||
margin: 20px 0;
|
||||
font-size: 18px;
|
||||
line-height: 25px;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
363
web/src/components/menus/614/IndexPage.vue
Normal file
@@ -0,0 +1,363 @@
|
||||
<template>
|
||||
<div class="container-box">
|
||||
<!-- <div class="btn-box"></div>-->
|
||||
<div class="tool-box">
|
||||
<el-button size="small" type="primary" style="margin-bottom: 15px" @click="gotoInfoExtract">图谱管理</el-button>
|
||||
<el-image
|
||||
class="img-item"
|
||||
:src="coverImg"
|
||||
:preview-src-list="srcList">
|
||||
</el-image>
|
||||
</div>
|
||||
<el-row :gutter="30">
|
||||
<el-col :span="12">
|
||||
<div class="block series-box">
|
||||
<div class="block-label">实体数量</div>
|
||||
<div class="count-box">{{ count.nodeCount }}个</div>
|
||||
<!-- <div class="btn-box">管 理</div>-->
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<div class="block commodity-box">
|
||||
<div class="block-label">三元组数量</div>
|
||||
<div class="count-box">{{ count.relationCount }}个</div>
|
||||
<!-- <div class="btn-box">管 理</div>-->
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<div>
|
||||
<el-button size="small" type="primary" @click="clearAll" style="float: left;margin-right: 15px">清空数据
|
||||
</el-button>
|
||||
<el-upload
|
||||
class="upload-demo"
|
||||
action="#"
|
||||
:auto-upload="false"
|
||||
:on-change="handleFileChange"
|
||||
:limit="10"
|
||||
accept=".xls,.xlsx"
|
||||
:file-list="fileList">
|
||||
<el-button size="small" type="primary">导 入</el-button>
|
||||
<label slot="tip" class="el-upload__tip" style="margin-left: 25px">只能上传.xls/.xlsx文件</label>
|
||||
</el-upload>
|
||||
</div>
|
||||
<el-row :gutter="20" style="margin-top: 15px">
|
||||
<el-col :span="12">
|
||||
<div class="graph-box">
|
||||
<graph ref="graph"></graph>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-table :data="list" border style="width: 100%" height="500">
|
||||
<el-table-column prop="name" label="概念名称" width="130"></el-table-column>
|
||||
<el-table-column prop="properties" label="属性">
|
||||
<template slot-scope="scope">
|
||||
<el-tag v-for="tag in scope.row.properties" :key="tag" style="margin-right: 5px;margin-bottom: 5px">{{
|
||||
tag
|
||||
}}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import request from '@/utils/request614';
|
||||
import graph from "@/components/graph/Graph614";
|
||||
import coverImg from "@/assets/image/icon/tupian.png";
|
||||
import aImg from "@/assets/image/614/1a.jpg";
|
||||
import bImg from "@/assets/image/614/1b.jpg";
|
||||
|
||||
var _this;
|
||||
export default {
|
||||
components: {
|
||||
'graph': graph,
|
||||
},
|
||||
name: "indexPage",
|
||||
data() {
|
||||
return {
|
||||
count: {
|
||||
nodeCount: 0,
|
||||
relationCount: 0
|
||||
},
|
||||
fileList: [],
|
||||
list: [
|
||||
{
|
||||
name: '军种',
|
||||
properties: ['编号', '名称']
|
||||
}, {
|
||||
name: '数控系统',
|
||||
properties: ['编号', '名称', '型号', '最新交付日期', '发动机', '状态', '工作总寿命', '总工作时间', '工作时间翻修期'
|
||||
, '翻修期累积时间', '日历翻修期', '下次翻修日期']
|
||||
}, {
|
||||
name: '发动机',
|
||||
properties: ['编号', '名称', '安装时间', '安装位置', '总工作时间', '总空中工作时间', '型号']
|
||||
}, {
|
||||
name: '故障信息',
|
||||
properties: ['编号', '名称', '故障件编号', '故障件型号', '故障件名称', '环境特点', '故障原因', '故障工作时间',
|
||||
'发生时间', '发现时机', '故障场所', '处理时间', '处理方式', '故障处理措施', '是否归零', '是否重复故障',
|
||||
'是否责任故障', '是否已处理', '故障现象', '排故进度']
|
||||
}, {
|
||||
name: '故障案例',
|
||||
properties: ['编号', '名称', '关键词', '排故进程', '故障分析', '故障总结', '经验教训']
|
||||
}, {
|
||||
name: '原飞机',
|
||||
properties: ['编号', '名称']
|
||||
}, {
|
||||
name: '部件',
|
||||
properties: ['编号', '名称', '型号', '编号码', '日期']
|
||||
}, {
|
||||
name: '地点',
|
||||
properties: ['编号', '名称']
|
||||
}, {
|
||||
name: '飞机',
|
||||
properties: ['编号', '名称']
|
||||
},
|
||||
],
|
||||
coverImg: coverImg,
|
||||
srcList: [
|
||||
aImg,
|
||||
bImg
|
||||
]
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
_this = this;
|
||||
_this.queryCount();
|
||||
|
||||
_this.$refs['graph'].initGraph({
|
||||
nodes: [
|
||||
{
|
||||
id: "1",
|
||||
label: '军种',
|
||||
_label: 'armyType'
|
||||
}, {
|
||||
id: "2",
|
||||
label: '数控系统',
|
||||
_label: 'control'
|
||||
}, {
|
||||
id: "3",
|
||||
label: '发动机',
|
||||
_label: 'engine'
|
||||
}, {
|
||||
id: "4",
|
||||
label: '故障信息',
|
||||
_label: 'fault'
|
||||
}, {
|
||||
id: "5",
|
||||
label: '故障案例',
|
||||
_label: 'faultCase'
|
||||
}, {
|
||||
id: "6",
|
||||
label: '原飞机',
|
||||
_label: 'oriPlane'
|
||||
}, {
|
||||
id: "7",
|
||||
label: '部件',
|
||||
_label: 'part'
|
||||
}, {
|
||||
id: "8",
|
||||
label: '发生地',
|
||||
_label: 'place'
|
||||
}, {
|
||||
id: "9",
|
||||
label: '飞机',
|
||||
_label: 'plane'
|
||||
}
|
||||
],
|
||||
edges: [
|
||||
{
|
||||
source: '3',
|
||||
target: '8',
|
||||
label: '所在地'
|
||||
}, {
|
||||
source: '3',
|
||||
target: '6',
|
||||
label: '原装配'
|
||||
}, {
|
||||
source: '3',
|
||||
target: '9',
|
||||
label: '现装配'
|
||||
}, {
|
||||
source: '3',
|
||||
target: '1',
|
||||
label: '隶属'
|
||||
}, {
|
||||
source: '3',
|
||||
target: '2',
|
||||
label: '数控于'
|
||||
}, {
|
||||
source: '4',
|
||||
target: '9',
|
||||
label: '故障飞机'
|
||||
}, {
|
||||
source: '4',
|
||||
target: '3',
|
||||
label: '故障发动机'
|
||||
}, {
|
||||
source: '4',
|
||||
target: '8',
|
||||
label: '故障发生地'
|
||||
}, {
|
||||
source: '4',
|
||||
target: '2',
|
||||
label: '故障控制系统'
|
||||
}, {
|
||||
source: '2',
|
||||
target: '7',
|
||||
label: '配套部件'
|
||||
}, {
|
||||
source: '2',
|
||||
target: '8',
|
||||
label: '所在地'
|
||||
}, {
|
||||
source: '5',
|
||||
target: '9',
|
||||
label: '故障案例飞机'
|
||||
}
|
||||
]
|
||||
}, true, null, true);
|
||||
},
|
||||
methods: {
|
||||
gotoInfoExtract() {
|
||||
this.$router.push("/614/infoExtract");
|
||||
},
|
||||
queryCount() {
|
||||
request({
|
||||
url: '/neo4j/get_count',
|
||||
method: 'post',
|
||||
data: {}
|
||||
}).then(res => {
|
||||
_this.count.nodeCount = res.data.nodeCount;
|
||||
_this.count.relationCount = res.data.relationCount;
|
||||
});
|
||||
},
|
||||
handleFileChange(file) {
|
||||
_this.fileList = [file];
|
||||
let formData = new FormData();
|
||||
formData.append("file", file.raw);
|
||||
request({
|
||||
url: '/neo4j/read_excel',
|
||||
method: 'put',
|
||||
data: formData
|
||||
}).then(res => {
|
||||
_this.$message.success("导入成功");
|
||||
});
|
||||
},
|
||||
clearAll() {
|
||||
_this.$confirm('此操作将永久清空数据, 是否继续?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
request({
|
||||
url: '/neo4j/clear_all',
|
||||
method: 'post',
|
||||
}).then(res => {
|
||||
_this.$message.success("清空成功");
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.tool-box {
|
||||
overflow: hidden;
|
||||
|
||||
.img-item {
|
||||
float: right;
|
||||
width: 95px;
|
||||
height: 25px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.graph-box {
|
||||
border: 1px solid #dcdddf;
|
||||
width: 100%;
|
||||
height: 500px;
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
div {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.box-card .el-card__body {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.btn-box {
|
||||
width: 130px;
|
||||
height: 50px;
|
||||
text-align: center;
|
||||
line-height: 50px;
|
||||
background-color: #4da8fc;
|
||||
font-size: 21px;
|
||||
font-weight: bold;
|
||||
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.container-box {
|
||||
padding: 30px;
|
||||
|
||||
|
||||
.block {
|
||||
border: 1px solid rgb(231, 231, 231);
|
||||
padding: 25px 30px;
|
||||
background-color: #fff;
|
||||
overflow: hidden;
|
||||
margin-bottom: 15px;
|
||||
|
||||
|
||||
}
|
||||
|
||||
.series-box, .commodity-box {
|
||||
color: #fff;
|
||||
|
||||
|
||||
.block-label {
|
||||
font-size: 25px;
|
||||
float: left;
|
||||
line-height: 50px;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.count-box {
|
||||
font-size: 35px;
|
||||
float: right;
|
||||
line-height: 50px;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.btn-box:hover {
|
||||
transform: scale(1.04);
|
||||
}
|
||||
}
|
||||
|
||||
.series-box {
|
||||
background-color: rgb(108, 180, 246);
|
||||
|
||||
.btn-box {
|
||||
color: rgb(108, 180, 246);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.commodity-box {
|
||||
background-color: rgb(251, 174, 94);
|
||||
|
||||
.btn-box {
|
||||
color: rgb(251, 174, 94);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
252
web/src/components/menus/614/InfoConverge.vue
Normal file
@@ -0,0 +1,252 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="menu-title">
|
||||
信息汇聚
|
||||
<el-image
|
||||
class="img-item"
|
||||
:src="coverImg"
|
||||
:preview-src-list="srcList">
|
||||
</el-image>
|
||||
</div>
|
||||
<div class="menu-content">
|
||||
<div class="search-input-box">
|
||||
<el-input
|
||||
class="search-input"
|
||||
placeholder="请输入内容"
|
||||
v-model="keyword">
|
||||
<i slot="prefix" class="el-input__icon el-icon-search"></i>
|
||||
</el-input>
|
||||
<el-button type="primary" style="margin-left: 30px" @click="queryFaultGraph">检 索</el-button>
|
||||
</div>
|
||||
<div class="graph-box">
|
||||
<graph ref="graph"></graph>
|
||||
</div>
|
||||
</div>
|
||||
<el-drawer
|
||||
title="基础信息"
|
||||
:visible.sync="drawerVisible"
|
||||
direction="rtl">
|
||||
<div class="drawer-content">
|
||||
<el-descriptions :column="1" v-show="activeLabel === 'fault'">
|
||||
<el-descriptions-item label="故障名称">{{ nodeItem.name }}</el-descriptions-item>
|
||||
<el-descriptions-item label="环境特点">{{ nodeItem.enviChar }}</el-descriptions-item>
|
||||
<el-descriptions-item label="故障件编号">{{ nodeItem.partNumber }}</el-descriptions-item>
|
||||
<el-descriptions-item label="故障件型号">{{ nodeItem.partModel }}</el-descriptions-item>
|
||||
<el-descriptions-item label="故障件名称">{{ nodeItem.partName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="发生时间">{{ nodeItem.happenTime }}</el-descriptions-item>
|
||||
<el-descriptions-item label="故障场所">{{ nodeItem.faultPlace }}</el-descriptions-item>
|
||||
<el-descriptions-item label="处理时间">{{ nodeItem.handleTime }}</el-descriptions-item>
|
||||
<el-descriptions-item label="处理方式">{{ nodeItem.handleStyle }}</el-descriptions-item>
|
||||
<el-descriptions-item label="处理措施">{{ nodeItem.faultHandleMeasures }}</el-descriptions-item>
|
||||
<el-descriptions-item label="故障原因">{{ nodeItem.faultReason }}</el-descriptions-item>
|
||||
<el-descriptions-item label="故障现象">{{ nodeItem.faultPhenomenon }}</el-descriptions-item>
|
||||
<el-descriptions-item label="排故进度">{{ nodeItem.checkFaultProgress }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<el-descriptions :column="1" v-show="activeLabel === 'engine'">
|
||||
<el-descriptions-item label="编号">{{ nodeItem.number }}</el-descriptions-item>
|
||||
<el-descriptions-item label="名称">{{ nodeItem.name }}</el-descriptions-item>
|
||||
<el-descriptions-item label="安装时间">{{ nodeItem.installTime }}</el-descriptions-item>
|
||||
<el-descriptions-item label="安装位置">{{ nodeItem.position }}</el-descriptions-item>
|
||||
<el-descriptions-item label="总工时间">{{ nodeItem.workTime }}</el-descriptions-item>
|
||||
<el-descriptions-item label="总空中工作时间">{{ nodeItem.airWorkTime }}</el-descriptions-item>
|
||||
<el-descriptions-item label="型号">{{ nodeItem.model }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<el-descriptions :column="1" v-show="activeLabel === 'control'">
|
||||
<el-descriptions-item label="编号">{{ nodeItem.number }}</el-descriptions-item>
|
||||
<el-descriptions-item label="名称">{{ nodeItem.name }}</el-descriptions-item>
|
||||
<el-descriptions-item label="型号">{{ nodeItem.model }}</el-descriptions-item>
|
||||
<el-descriptions-item label="最新交付日期">{{ nodeItem.lastDeliverTime }}</el-descriptions-item>
|
||||
<el-descriptions-item label="发动机">{{ nodeItem.engine }}</el-descriptions-item>
|
||||
<el-descriptions-item label="状态">{{ nodeItem.status }}</el-descriptions-item>
|
||||
<el-descriptions-item label="工作总寿命">{{ nodeItem.workLife }}</el-descriptions-item>
|
||||
|
||||
<el-descriptions-item label="总工作时间">{{ nodeItem.workTime }}</el-descriptions-item>
|
||||
<el-descriptions-item label="工作时间翻修期">{{ nodeItem.renovate }}</el-descriptions-item>
|
||||
<el-descriptions-item label="翻修期累积时间">{{ nodeItem.renovateTime }}</el-descriptions-item>
|
||||
<el-descriptions-item label="日历翻修期">{{ nodeItem.renovateCalendar }}</el-descriptions-item>
|
||||
<el-descriptions-item label="下次翻修日期">{{ nodeItem.nextRenovate }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<el-descriptions :column="1" v-show="activeLabel === 'part'">
|
||||
<el-descriptions-item label="编号">{{ nodeItem.number }}</el-descriptions-item>
|
||||
<el-descriptions-item label="名称">{{ nodeItem.name }}</el-descriptions-item>
|
||||
<el-descriptions-item label="型号">{{ nodeItem.model }}</el-descriptions-item>
|
||||
<el-descriptions-item label="编号码">{{ nodeItem.numberCode }}</el-descriptions-item>
|
||||
<el-descriptions-item label="出厂日期">{{ nodeItem.dateStr }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<el-descriptions :column="1" v-show="activeLabel === 'other'">
|
||||
<el-descriptions-item label="编号">{{ nodeItem.number }}</el-descriptions-item>
|
||||
<el-descriptions-item label="名称">{{ nodeItem.name }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import request from '@/utils/request614';
|
||||
import graph from "@/components/graph/Graph614";
|
||||
|
||||
import coverImg from "@/assets/image/icon/tupian.png";
|
||||
import aImg from "@/assets/image/614/4a.jpg";
|
||||
import bImg from "@/assets/image/614/4b.jpg";
|
||||
import cImg from "@/assets/image/614/4c.jpg";
|
||||
import dImg from "@/assets/image/614/4d.jpg";
|
||||
import eImg from "@/assets/image/614/4e.jpg";
|
||||
import fImg from "@/assets/image/614/4f.jpg";
|
||||
import gImg from "@/assets/image/614/4g.jpg";
|
||||
import hImg from "@/assets/image/614/4h.jpg";
|
||||
import jImg from "@/assets/image/614/4j.jpg";
|
||||
|
||||
|
||||
var _this;
|
||||
export default {
|
||||
components: {
|
||||
'graph': graph,
|
||||
},
|
||||
name: "infoConverge",
|
||||
data() {
|
||||
return {
|
||||
keyword: '',
|
||||
nodeItem: {},
|
||||
drawerVisible: false,
|
||||
activeLabel: '',
|
||||
coverImg: coverImg,
|
||||
srcList: [
|
||||
aImg, bImg, cImg, dImg, eImg, fImg, gImg, hImg, jImg
|
||||
]
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
_this = this;
|
||||
},
|
||||
methods: {
|
||||
queryFaultGraph() {
|
||||
if (_this.keyword.length === 0) {
|
||||
_this.$message.warning("请输入内容再进行检索");
|
||||
return false;
|
||||
}
|
||||
let formData = new FormData();
|
||||
formData.append("keyword", _this.keyword);
|
||||
request({
|
||||
url: '/fault/query_for_neo4j',
|
||||
method: 'post',
|
||||
data: formData
|
||||
}).then(res => {
|
||||
res.data.nodes.forEach(node => {
|
||||
node._label = node.label;
|
||||
node.label = node.properties.name;
|
||||
node.id = node.id.toString();
|
||||
});
|
||||
res.data.relations.forEach(edge => {
|
||||
delete edge.id;
|
||||
edge.label = edge.properties ? edge.properties.name : '';
|
||||
edge.source = edge.source.toString();
|
||||
edge.target = edge.target.toString();
|
||||
if (edge.source === edge.target) {
|
||||
edge.type = 'loop';
|
||||
} else {
|
||||
delete edge.type;
|
||||
}
|
||||
});
|
||||
|
||||
_this.$refs['graph'].initGraph({
|
||||
nodes: res.data.nodes,
|
||||
edges: res.data.relations
|
||||
}, true, _this.clickNode);
|
||||
_this.$message.success("检索成功");
|
||||
});
|
||||
},
|
||||
clickNode(param) {
|
||||
_this.activeLabel = param._label;
|
||||
if (param._label === "fault") {
|
||||
request({
|
||||
url: '/fault/query_unique',
|
||||
method: 'post',
|
||||
data: {
|
||||
EQS_number: param.number
|
||||
}
|
||||
}).then(res => {
|
||||
_this.nodeItem = res.data;
|
||||
_this.drawerVisible = true;
|
||||
});
|
||||
} else if (param._label === "engine") {
|
||||
request({
|
||||
url: '/engine/query_unique',
|
||||
method: 'post',
|
||||
data: {
|
||||
EQS_number: param.number
|
||||
}
|
||||
}).then(res => {
|
||||
_this.nodeItem = res.data;
|
||||
_this.drawerVisible = true;
|
||||
});
|
||||
} else if (param._label === "control") {
|
||||
request({
|
||||
url: '/control/query_unique',
|
||||
method: 'post',
|
||||
data: {
|
||||
EQS_number: param.number
|
||||
}
|
||||
}).then(res => {
|
||||
_this.nodeItem = res.data;
|
||||
_this.drawerVisible = true;
|
||||
});
|
||||
} else if (param._label === "part") {
|
||||
request({
|
||||
url: '/part/query_unique',
|
||||
method: 'post',
|
||||
data: {
|
||||
EQS_number: param.number
|
||||
}
|
||||
}).then(res => {
|
||||
_this.nodeItem = res.data;
|
||||
_this.drawerVisible = true;
|
||||
});
|
||||
} else {
|
||||
_this.activeLabel = 'other';
|
||||
_this.nodeItem = {
|
||||
number: param.number,
|
||||
name: param.label
|
||||
};
|
||||
_this.drawerVisible = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.img-item {
|
||||
width: 95px;
|
||||
height: 25px;
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
right: 30px;
|
||||
top: 80px;
|
||||
}
|
||||
.menu-content {
|
||||
overflow-x: hidden;
|
||||
|
||||
.search-input-box {
|
||||
display: flex;
|
||||
width: 40%;
|
||||
margin-bottom: 1.5625vw;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.drawer-content {
|
||||
padding: 0 20px;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.graph-box {
|
||||
border: 1px solid #dcdddf;
|
||||
width: 100%;
|
||||
height: 500px;
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
265
web/src/components/menus/614/InfoExtract.vue
Normal file
@@ -0,0 +1,265 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="menu-title">
|
||||
知识抽取
|
||||
<el-tag
|
||||
class="tag-item"
|
||||
@click="handleTagClick(item)"
|
||||
v-for="item in tags"
|
||||
:key="item.label"
|
||||
:type="item.type"
|
||||
:effect="activeTag === item.label ? 'dark' : 'plain'">
|
||||
{{ item.name }}
|
||||
</el-tag>
|
||||
<el-image
|
||||
class="img-item"
|
||||
:src="coverImg"
|
||||
:preview-src-list="srcList">
|
||||
</el-image>
|
||||
</div>
|
||||
<div class="menu-content">
|
||||
<div class="graph-box">
|
||||
<graph ref="graph"></graph>
|
||||
</div>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<div class="title-label">实体(F1值:99.2%)</div>
|
||||
<el-table :data="nodeRecord.list" border style="width: 100%">
|
||||
<el-table-column prop="id" label="ID"></el-table-column>
|
||||
<el-table-column prop="label" label="标签" :formatter="labelFormatter"></el-table-column>
|
||||
<el-table-column prop="number" label="编号"></el-table-column>
|
||||
<el-table-column prop="properties.name" label="名称"></el-table-column>
|
||||
<el-table-column prop="flag" label="是否准确" width="80">
|
||||
<template slot-scope="scope">
|
||||
<label style="color: #00dc6b">√</label>
|
||||
<!-- <label style="color: #e02323" v-if="!scope.row.flag">×</label>-->
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination
|
||||
background
|
||||
:page-size="5"
|
||||
layout="prev, pager, next"
|
||||
@current-change="handleEntityCurrentChange"
|
||||
:current-page="nodeQo.pageNo"
|
||||
:total="nodeRecord.total">
|
||||
</el-pagination>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<div class="title-label">三元组(F1值:98.3%)</div>
|
||||
<el-table :data="relationRecord.list" border style="width: 100%">
|
||||
<el-table-column prop="properties.sourceNumber" label="起始节点编号"></el-table-column>
|
||||
<el-table-column prop="properties.targetNumber" label="终止节点编号"></el-table-column>
|
||||
<el-table-column prop="properties.name" label="名称"></el-table-column>
|
||||
<el-table-column prop="name" label="是否准确" width="80">
|
||||
<template slot-scope="scope">
|
||||
<label style="color: #00dc6b">√</label>
|
||||
<!-- <label style="color: #e02323" v-if="!scope.row.flag">×</label>-->
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination
|
||||
background
|
||||
layout="prev, pager, next"
|
||||
:page-size="5"
|
||||
@current-change="handleTripletCurrentChange"
|
||||
:current-page="relationQo.pageNo"
|
||||
:total="relationRecord.total">
|
||||
</el-pagination>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import request from '@/utils/request614';
|
||||
import graph from "@/components/graph/Graph614";
|
||||
|
||||
import coverImg from "@/assets/image/icon/tupian.png";
|
||||
import aImg from "@/assets/image/614/2a.jpg";
|
||||
import bImg from "@/assets/image/614/2b.jpg";
|
||||
import cImg from "@/assets/image/614/2c.jpg";
|
||||
import dImg from "@/assets/image/614/2d.jpg";
|
||||
import fImg from "@/assets/image/614/2f.jpg";
|
||||
|
||||
var _this;
|
||||
export default {
|
||||
components: {
|
||||
'graph': graph,
|
||||
},
|
||||
name: "infoExtract",
|
||||
data() {
|
||||
return {
|
||||
nodeQo: {
|
||||
pageNo: 1,
|
||||
pageSize: 5
|
||||
},
|
||||
relationQo: {
|
||||
pageNo: 1,
|
||||
pageSize: 5
|
||||
},
|
||||
nodeRecord: {
|
||||
list: [],
|
||||
total: 0
|
||||
},
|
||||
relationRecord: {
|
||||
list: [],
|
||||
total: 0
|
||||
},
|
||||
tags: [
|
||||
{
|
||||
name: '数控系统',
|
||||
label: 'control'
|
||||
}, {
|
||||
name: '发动机',
|
||||
label: 'engine'
|
||||
}, {
|
||||
name: '故障信息',
|
||||
label: 'fault'
|
||||
}
|
||||
],
|
||||
activeTag: '',
|
||||
legendList: {
|
||||
"armyType": {label: '军种', color: 'rgb(76,142,218)'},
|
||||
"control": {label: '控制系统', color: 'rgb(236,181,201)'},
|
||||
"engine": {label: '发动机', color: 'rgb(241,102,103)'},
|
||||
"fault": {label: '故障信息', color: 'rgb(141,204,147)'},
|
||||
"faultCase": {label: '故障案例', color: 'rgb(156,33,234)'},
|
||||
"oriPlane": {label: '原飞机', color: 'rgb(255,196,84)'},
|
||||
"part": {label: '部件', color: 'rgb(86,148,128)'},
|
||||
"place": {label: '发生地', color: 'rgb(217,200,174)'},
|
||||
"plane": {label: '飞机', color: 'rgb(87,199,227)'}
|
||||
},
|
||||
coverImg: coverImg,
|
||||
srcList: [
|
||||
aImg, bImg, cImg, dImg, fImg
|
||||
]
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
_this = this;
|
||||
_this.queryGraphData();
|
||||
_this.queryNodePage();
|
||||
_this.queryRelationPage();
|
||||
},
|
||||
methods: {
|
||||
handleTagClick(item) {
|
||||
if (item.label !== _this.activeTag) {
|
||||
_this.activeTag = item.label;
|
||||
} else {
|
||||
_this.activeTag = '';
|
||||
}
|
||||
_this.queryGraphData();
|
||||
},
|
||||
queryGraphData() {
|
||||
let formData = new FormData();
|
||||
formData.append("label", _this.activeTag);
|
||||
request({
|
||||
url: '/neo4j/query_data/70',
|
||||
method: 'post',
|
||||
data: formData
|
||||
}).then(res => {
|
||||
res.data.nodes.forEach(node => {
|
||||
node._label = node.label;
|
||||
node.label = node.properties.name;
|
||||
node.id = node.id.toString();
|
||||
});
|
||||
res.data.relations.forEach(edge => {
|
||||
delete edge.id;
|
||||
edge.source = edge.source.toString();
|
||||
edge.target = edge.target.toString();
|
||||
edge.label = edge.properties ? edge.properties.name : '';
|
||||
if (edge.source === edge.target) {
|
||||
edge.type = 'loop';
|
||||
} else {
|
||||
delete edge.type;
|
||||
}
|
||||
});
|
||||
_this.$refs['graph'].initGraph({
|
||||
nodes: res.data.nodes,
|
||||
edges: res.data.relations
|
||||
}, true);
|
||||
});
|
||||
},
|
||||
labelFormatter(row) {
|
||||
if (_this.legendList[row.label]) {
|
||||
return _this.legendList[row.label].label;
|
||||
} else {
|
||||
return '-'
|
||||
}
|
||||
},
|
||||
queryNodePage() {
|
||||
request({
|
||||
url: '/neo4j/query_node_page',
|
||||
method: 'post',
|
||||
data: _this.nodeQo
|
||||
}).then(res => {
|
||||
_this.nodeRecord.list = res.data.nodes;
|
||||
_this.nodeRecord.total = res.data.total;
|
||||
});
|
||||
},
|
||||
queryRelationPage() {
|
||||
request({
|
||||
url: '/neo4j/query_relation_page',
|
||||
method: 'post',
|
||||
data: _this.relationQo
|
||||
}).then(res => {
|
||||
_this.relationRecord.list = res.data.relations;
|
||||
_this.relationRecord.total = res.data.total;
|
||||
});
|
||||
},
|
||||
handleEntityCurrentChange(val) {
|
||||
_this.nodeQo.pageNo = val;
|
||||
_this.queryNodePage();
|
||||
},
|
||||
handleTripletCurrentChange(val) {
|
||||
_this.relationQo.pageNo = val;
|
||||
_this.queryRelationPage();
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.img-item {
|
||||
width: 95px;
|
||||
height: 25px;
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
right: 30px;
|
||||
top: 80px;
|
||||
}
|
||||
|
||||
.tag-item {
|
||||
margin-right: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.menu-content {
|
||||
overflow-x: hidden;
|
||||
|
||||
.title-label {
|
||||
margin: 20px 0;
|
||||
font-size: 18px;
|
||||
line-height: 25px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.el-pagination {
|
||||
text-align: center;
|
||||
margin-top: 25px;
|
||||
}
|
||||
}
|
||||
|
||||
.graph-box {
|
||||
border: 1px solid #dcdddf;
|
||||
width: 100%;
|
||||
height: 500px;
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
161
web/src/components/menus/614/LinkPrediction.vue
Normal file
@@ -0,0 +1,161 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="menu-title">
|
||||
链接预测
|
||||
<el-image
|
||||
class="img-item"
|
||||
:src="coverImg"
|
||||
:preview-src-list="srcList">
|
||||
</el-image>
|
||||
</div>
|
||||
<div class="menu-content">
|
||||
<div class="recommend-content">
|
||||
<div class="search-input-box">
|
||||
<el-input placeholder="请输入头实体内容" v-model="startKeyword" @change="handleStartKeywordChange"
|
||||
class="search-input" style="width: 160px;"></el-input>
|
||||
<el-select v-model="relationType" placeholder="请选择" style="width: 140px;">
|
||||
<el-option label="故障飞机" value="plane"></el-option>
|
||||
<el-option label="故障发动机" value="engine"></el-option>
|
||||
<el-option label="故障所在地" value="place"></el-option>
|
||||
<el-option label="故障控制系统" value="control"></el-option>
|
||||
</el-select>
|
||||
<el-input placeholder="请输入尾实体内容" v-model="endKeyword" @change="handleEndKeywordChange"
|
||||
class="search-input" style="width: 160px;"></el-input>
|
||||
<el-button type="primary" style="margin-left: 30px" @click="queryData">预 测</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="result-table-box">
|
||||
<el-table :data="list" border style="width: 100%">
|
||||
<el-table-column type="index" label="序号" width="80"></el-table-column>
|
||||
<el-table-column prop="label" label="标签" :formatter="labelFormatter"></el-table-column>
|
||||
<el-table-column prop="number" label="编号"></el-table-column>
|
||||
<el-table-column prop="properties.name" label="名称"></el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import request from '@/utils/request614';
|
||||
import coverImg from "@/assets/image/icon/tupian.png";
|
||||
import aImg from "@/assets/image/614/3a.jpg";
|
||||
import bImg from "@/assets/image/614/3b.jpg";
|
||||
import cImg from "@/assets/image/614/3c.jpg";
|
||||
import dImg from "@/assets/image/614/3d.jpg";
|
||||
import eImg from "@/assets/image/614/3e.jpg";
|
||||
import fImg from "@/assets/image/614/3f.jpg";
|
||||
import gImg from "@/assets/image/614/3g.jpg";
|
||||
import hImg from "@/assets/image/614/3h.jpg";
|
||||
import iImg from "@/assets/image/614/3i.jpg";
|
||||
import jImg from "@/assets/image/614/3j.jpg";
|
||||
import kImg from "@/assets/image/614/3k.jpg";
|
||||
import lImg from "@/assets/image/614/3l.jpg";
|
||||
import mImg from "@/assets/image/614/3m.jpg";
|
||||
import nImg from "@/assets/image/614/3n.jpg";
|
||||
import oImg from "@/assets/image/614/3o.jpg";
|
||||
import pImg from "@/assets/image/614/3p.jpg";
|
||||
import qImg from "@/assets/image/614/3q.jpg";
|
||||
|
||||
var _this;
|
||||
export default {
|
||||
name: "linkPrediction",
|
||||
data() {
|
||||
return {
|
||||
startKeyword: "",
|
||||
endKeyword: "",
|
||||
relationType: 'plane',
|
||||
list: [],
|
||||
legendList: {
|
||||
"armyType": {label: '军种', color: 'rgb(76,142,218)'},
|
||||
"control": {label: '控制系统', color: 'rgb(236,181,201)'},
|
||||
"engine": {label: '发动机', color: 'rgb(241,102,103)'},
|
||||
"fault": {label: '故障信息', color: 'rgb(141,204,147)'},
|
||||
"faultCase": {label: '故障案例', color: 'rgb(156,33,234)'},
|
||||
"oriPlane": {label: '原飞机', color: 'rgb(255,196,84)'},
|
||||
"part": {label: '部件', color: 'rgb(86,148,128)'},
|
||||
"place": {label: '发生地', color: 'rgb(217,200,174)'},
|
||||
"plane": {label: '飞机', color: 'rgb(87,199,227)'}
|
||||
},
|
||||
coverImg: coverImg,
|
||||
srcList: [
|
||||
aImg, bImg, cImg, dImg, eImg, fImg, gImg, hImg, iImg, jImg, kImg, lImg, mImg, nImg, oImg, pImg, qImg
|
||||
]
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
_this = this;
|
||||
},
|
||||
methods: {
|
||||
labelFormatter(row) {
|
||||
return _this.legendList[row.label].label;
|
||||
},
|
||||
handleStartKeywordChange() {
|
||||
_this.endKeyword = "";
|
||||
},
|
||||
handleEndKeywordChange() {
|
||||
_this.startKeyword = "";
|
||||
},
|
||||
queryData() {
|
||||
if (_this.startKeyword.length === 0 && _this.endKeyword.length === 0) {
|
||||
_this.$message.warning("请输入头或尾实体内容再进行预测");
|
||||
return false;
|
||||
}
|
||||
|
||||
let formData = new FormData();
|
||||
formData.append("keyword", _this.startKeyword.length > _this.endKeyword.length ? _this.startKeyword : _this.endKeyword);
|
||||
formData.append("relationType", _this.relationType);
|
||||
if (_this.startKeyword.length > 0) {
|
||||
request({
|
||||
url: '/fault/query_link_node',
|
||||
method: 'post',
|
||||
data: formData
|
||||
}).then(res => {
|
||||
_this.list = res.data;
|
||||
_this.$message.success("预测成功");
|
||||
});
|
||||
} else {
|
||||
request({
|
||||
url: '/fault/query_source_fault_node',
|
||||
method: 'post',
|
||||
data: formData
|
||||
}).then(res => {
|
||||
_this.list = res.data;
|
||||
_this.$message.success("预测成功");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.img-item {
|
||||
width: 95px;
|
||||
height: 25px;
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
right: 30px;
|
||||
top: 80px;
|
||||
}
|
||||
|
||||
.recommend-content {
|
||||
margin: 0 auto;
|
||||
|
||||
.search-input-box {
|
||||
width: 55%;
|
||||
display: flex;
|
||||
text-align: left;
|
||||
margin-bottom: 30px;
|
||||
|
||||
.search-input input {
|
||||
border-top-left-radius: 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||