推荐系统初始化

This commit is contained in:
2023-05-09 17:53:58 +08:00
commit 9f8c374ac2
406 changed files with 68905 additions and 0 deletions

3
web/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
node_modules
.idea
dist

24
web/README.md Normal file
View 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
View File

@@ -0,0 +1,5 @@
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
]
}

15578
web/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

72
web/package.json Normal file
View 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
View 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
View 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

Binary file not shown.

Binary file not shown.

73
web/src/App.vue Normal file
View 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
View 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',
})
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 234 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 212 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 249 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 277 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

854
web/src/assets/index.css Normal file
View 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;
}

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

File diff suppressed because it is too large Load Diff

View 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>

View 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>

View 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>

View 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,
},
},
};
}

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

Some files were not shown because too many files have changed in this diff Show More