推荐系统初始化

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

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>

View File

@@ -0,0 +1,340 @@
<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>
<el-row :gutter="20">
<el-col :span="12">
<el-tabs v-model="activeTab">
<el-tab-pane label="故障案例" name="first">
<el-table :data="faultCaseList" 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="third">
<el-table :data="faultList" 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="happenTime" label="发生时间"></el-table-column>
<el-table-column prop="name" label="操作" width="120">
<template slot-scope="scope">
<el-button @click.native.prevent="showDetail(scope.row, 'fault')" 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>
</el-col>
<el-col :span="12">
<div class="graph-box">
<graph ref="graph"></graph>
</div>
<div class="result-label">
<label>风险预测指标{{ riskNum }};</label><br/>
<label>风险预测原因{{ riskLabel }};</label>
</div>
</el-col>
</el-row>
</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>
<el-dialog
title="查看说明"
:visible.sync="faultDetailVisible"
width="50%">
<el-descriptions :column="2">
<el-descriptions-item label="故障名称">{{ cmd.name }}</el-descriptions-item>
<el-descriptions-item label="环境特点">{{ cmd.enviChar }}</el-descriptions-item>
<el-descriptions-item label="故障件编号">{{ cmd.partNumber }}</el-descriptions-item>
<el-descriptions-item label="故障件型号">{{ cmd.partModel }}</el-descriptions-item>
<el-descriptions-item label="故障件名称">{{ cmd.partName }}</el-descriptions-item>
<el-descriptions-item label="发生时间">{{ cmd.happenTime }}</el-descriptions-item>
<el-descriptions-item label="故障场所">{{ cmd.faultPlace }}</el-descriptions-item>
<el-descriptions-item label="处理时间">{{ cmd.handleTime }}</el-descriptions-item>
<el-descriptions-item label="处理方式">{{ cmd.handleStyle }}</el-descriptions-item>
<el-descriptions-item label="处理措施">{{ cmd.faultHandleMeasures }}</el-descriptions-item>
<el-descriptions-item label="故障原因">{{ cmd.faultReason }}</el-descriptions-item>
<el-descriptions-item label="故障现象">{{ cmd.faultPhenomenon }}</el-descriptions-item>
<el-descriptions-item label="排故进度">{{ cmd.checkFaultProgress }}</el-descriptions-item>
</el-descriptions>
<span slot="footer" class="dialog-footer">
<el-button @click="faultDetailVisible = false"> </el-button>
</span>
</el-dialog>
</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/6a.jpg";
import bImg from "@/assets/image/614/6b.jpg";
import cImg from "@/assets/image/614/6c.jpg";
import dImg from "@/assets/image/614/6d.jpg";
import eImg from "@/assets/image/614/6e.jpg";
import fImg from "@/assets/image/614/6f.jpg";
import gImg from "@/assets/image/614/6g.jpg";
var _this;
export default {
components: {
'graph': graph,
},
name: "riskPrediction",
data() {
return {
keyword: '',
activeTab: 'first',
faultCaseList: [],
repairList: [],
faultList: [],
cmd: {},
riskNum: 0,
riskLabel: '',
faultDetailVisible: false,
detailVisible: false,
repairDetailVisible: false,
coverImg: coverImg,
srcList: [
aImg, bImg, cImg, dImg, eImg, fImg, gImg
]
}
},
mounted() {
_this = this;
},
methods: {
calcRisk(faultNum, repairNum) {// 计算风险
_this.riskNum = (Math.log(faultNum + 1) / Math.log(faultNum + 2 * (repairNum + 1))).toFixed(3);
if (_this.riskNum <= 0.7) {
_this.riskLabel = "风险等级低,故障关联少";
} else if (_this.riskNum <= 0.9 && _this.riskNum > 0.7) {
_this.riskLabel = "风险等级中,有一定数量故障关联和维修方法";
} else if (_this.riskNum > 0.9) {
_this.riskLabel = "风险等级高,故障关联多,维修方法内容不足";
}
},
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);
let formData = new FormData();
formData.append("keyword", _this.keyword);
_this.queryFaultCaseListTogether(formData);
_this.queryFaultGraph(formData);
},
queryFaultCaseListTogether(formData) {
request({
url: '/fault_case/query_like_keyword_together',
method: 'post',
data: formData
}).then(res => {
let item = res.data;
_this.faultCaseList = item.faultCaseList;
_this.faultList = item.faultList;
_this.repairList = item.repairList;
_this.calcRisk(_this.faultCaseList.length + _this.faultList.length, _this.repairList.length);
_this.$message.success("检索成功");
});
},
queryFaultGraph(formData) {
request({
url: '/fault_case/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.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);
});
},
showDetail(row, type) {
_this.cmd = row;
if (type === 'repair') {
_this.repairDetailVisible = true;
} else if (type === 'faultCase') {
_this.detailVisible = true;
} else if (type === "fault") {
_this.faultDetailVisible = true;
}
}
}
}
</script>
<style lang="scss">
.img-item {
width: 95px;
height: 25px;
cursor: pointer;
position: absolute;
right: 30px;
top: 80px;
}
.result-label {
text-align: center;
margin-top: 15px;
font-size: 18px;
}
.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,355 @@
<template>
<div>
<div class="menu-title">
算法发布
</div>
<div class="menu-content">
<div>
<el-form :inline="true" :model="qo" class="demo-form-inline">
<el-form-item>
<el-input v-model="qo.LIKES_name" placeholder="请输入算法名称"></el-input>
</el-form-item>
<!-- <el-form-item>
<el-input v-model="qo.LIKES_name" placeholder="请输入版本"></el-input>
</el-form-item> -->
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="qo.pageNo=1;queryData()"> </el-button>
</el-form-item>
</el-form>
</div>
<div style="margin: 0px 0 20px 0">
<el-button type="primary" @click="createRow()">发布算法</el-button>
</div>
<div>
<el-table :data="result.records" style="width: 100%" ref="table">
<el-table-column type="index" label="行号" width="100"></el-table-column>
<el-table-column prop="name" label="算法名称"></el-table-column>
<!-- <el-table-column prop="version" label="版本"></el-table-column> -->
<el-table-column prop="buildRemark" label="介绍"></el-table-column>
<el-table-column prop="modifyTimeMillis" label="修改时间">
<template slot-scope="scope">
{{ scope.row.modifyTimeMillis | timeFilter }}
</template>
</el-table-column>
<el-table-column prop="createTimeMillis" label="创建时间">
<template slot-scope="scope">
{{ scope.row.createTimeMillis | timeFilter }}
</template>
</el-table-column>
<el-table-column label="操作" width="120">
<template slot-scope="scope">
<el-button @click.native.prevent="modifyRow(scope.row)" type="text" size="small">
编辑
</el-button>
<el-button @click.native.prevent="removeRow(scope.row)" type="text" size="small">
删除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div class="page-box">
<el-pagination background
@current-change="handleCurrentChange"
:current-page="qo.pageNo"
:page-size="qo.pageSize"
layout="total, prev, pager, next"
:total="result.total">
</el-pagination>
</div>
</div>
<el-dialog
:title="dialogName"
:visible.sync="cmdDialogVisible"
width="40%">
<div v-show="step == 1">
<el-form ref="cmd" label-width="100px" :rules="rules" :model="cmd" v-loading="stepLoading1" element-loading-text="代码pull中...">
<el-form-item label="算法名称" prop="name">
<el-input v-model="cmd.name" placeholder="请输入算法名称"></el-input>
</el-form-item>
<el-form-item label="算法介绍" prop="buildRemark">
<el-input type="textarea" v-model="cmd.buildRemark" placeholder="请输入算法介绍"></el-input>
</el-form-item>
<el-form-item label="代码仓库" prop="repositoryId" >
<el-select v-model="cmd.repositoryId" placeholder="请选择代码仓库" @change="handleRepositoryChange">
<el-option :label="item.name" :value="item.id" v-for="item in codeWarehouseList"
:key="item.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="仓库分支" prop="branchName">
<el-select v-model="cmd.branchName" placeholder="请选择分支">
<el-option :label="item" :value="item" v-for="(item,index) in branchList" :key="index"></el-option>
</el-select>
<!-- <el-input v-model="cmd.branchName" placeholder="请输入分支"></el-input>-->
</el-form-item>
<el-form-item label="依赖方式" prop="relyOnType">
<el-radio-group v-model="cmd.relyOnType">
<el-radio :label="1">克隆Conda环境</el-radio>
<el-radio :label="2">文件安装</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="环境名称" prop="condaName" v-if="cmd.relyOnType==1">
<el-input v-model="cmd.condaName" placeholder="请输入环境名称"></el-input>
</el-form-item>
<!-- <el-form-item label="标签(TAG)" prop="branchTagName">-->
<!-- <el-input v-model="cmd.branchTagName" placeholder="请输入标签(TAG)"></el-input>-->
<!-- &lt;!&ndash; <el-select v-model="cmd.name" placeholder="请选择发布的标签,不选为最新提交">&ndash;&gt;-->
<!-- &lt;!&ndash; <el-option label="" value=""></el-option>&ndash;&gt;-->
<!-- &lt;!&ndash; </el-select>&ndash;&gt;-->
<!-- </el-form-item>-->
<!-- <el-form-item label="启动命令" prop="script">-->
<!-- <el-input v-model="cmd.script" placeholder="请输入启动命令" type="textarea"></el-input>-->
<!-- </el-form-item>-->
<!-- <el-form-item label="日志文件" prop="logFileName">-->
<!-- <el-input v-model="cmd.logFileName" placeholder="请输入日志文件名称或目录(相对目录)"></el-input>-->
<!-- </el-form-item>-->
</el-form>
</div>
<div v-show="step == 2">
<el-form ref="cmd2" label-width="100px" :model="cmd">
<div class="title-form-box">公共配置</div>
<el-form-item :label="item.name" v-for="item in cmd2.publicPropert" :key="item.key">
<el-input v-model="item.value" :placeholder="'请输入' + item.name"></el-input>
</el-form-item>
<div class="title-form-box">私有配置</div>
<el-form-item :label="item.name" v-for="item in cmd2.privatePropert" :key="item.key">
<el-input v-model="item.value" :placeholder="'请输入' + item.name"></el-input>
</el-form-item>
</el-form>
</div>
<div v-show="step == 3">
<i class="el-icon-loading" v-show="stepPercent < 100"></i>
<!-- <el-progress :text-inside="true" :stroke-width="26" :percentage="stepPercent" v-show="stepPercent < 100"></el-progress>-->
<label v-show="stepPercent >= 100">依赖校验成功</label>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="cmdDialogVisible = false"> </el-button>
<el-button type="primary" @click="nextStep" v-show="step == 1" :disabled="stepLoading1">下一步</el-button>
<el-button type="primary" @click="nextStep" v-show="step == 2">下一步</el-button>
<el-button type="primary" @click="submitModify" v-show="step == 3" :disabled="stepPercent < 100">发布</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import request from '@/utils/request2';
var _this;
export default {
name: "codeWarehouse",
data() {
return {
qo: {
pageNo: 1,
pageSize: 10,
LIKES_name: '',
},
result: {
records: [],
total: 0
},
codeWarehouseList: [],
step: 1,
stepPercent: 0,
dialogName: '发布算法',
cmdDialogVisible: false,
cmd: {},
cmd2: {},
rules: {
name: [
{required: true, message: '请输入算法名称'}
],
repositoryId: [
{required: true, message: '请选择代码仓库'}
],
branchName: [
{required: true, message: '请输入分支'}
],
branchTagName: [
{required: true, message: '请输入标签(TAG)'}
],
logFileName: [
{required: true, message: '请输入启动命令'}
],
script: [
{required: true, message: '请输入日志文件'}
],
relyOnType: [
{required: true, message: '请选择依赖方式'}
],
condaName: [
{required: true, message: '请输入虚拟环境名称'}
],
},
stepLoading1: false,
branchList: []
}
},
mounted() {
_this = this;
_this.queryData();
_this.queryCodeWarehouseList();
},
filters: {
timeFilter(val) {
if (val > 0) {
let dt = new Date(val);
let year = dt.getFullYear();
let month = dt.getMonth() + 1;
let date = dt.getDate();
let hour = dt.getHours();
let minute = dt.getMinutes();
let second = dt.getSeconds();
return `${year}-${month}-${date} ${hour}:${minute}:${second}`;
} else {
return "-";
}
}
},
methods: {
handleRepositoryChange(id) {
_this.queryBranchList(id);
_this.cmd.branchName = "";
},
queryBranchList(id) {
request({
url: '/repository/branch-list',
method: 'post',
data: {repositoryId: id}
}).then(res => {
_this.branchList = res.list[0];
});
},
queryCodeWarehouseList() {
request({
url: '/repository/list',
method: 'post',
data: {pageNo: 1, pageSize: 1000}
}).then(res => {
_this.codeWarehouseList = res.list;
});
},
queryData() {
request({
url: '/algorithm/list',
method: 'post',
data: _this.qo
}).then(res => {
_this.result.records = res.list;
console.log(res.list);
_this.result.total = res.total;
});
},
handleCurrentChange(val) {
_this.qo.pageNo = val;
_this.queryData();
},
removeRow(item) {
_this.$confirm('此操作将永久删除记录, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
let id = item.id
request({
url: `/algorithm/delete/${id}`,
method: 'get',
}).then(res => {
_this.$message.success("删除成功");
_this.queryData();
_this.queryOntologyList();
});
}).catch(() => {
});
},
createRow() {
_this.step = 1;
_this.cmdDialogVisible = true;
_this.stepLoading1 = false;
_this.$nextTick(() => {
_this.cmd = {
name: '',
repositoryId: '',
branchName: '',
branchTagName: '',
logFileName: '',
script: ''
};
_this.$refs.cmd.resetFields();
});
},
modifyRow(item) {
_this.cmd = JSON.parse(JSON.stringify(item));
_this.cmd.modifyTimeMillis = null;
_this.stepLoading1 = false;
if (_this.cmd.repositoryId != null && _this.cmd.repositoryId.toString().length > 0) {
_this.queryBranchList(_this.cmd.repositoryId);
}
_this.cmdDialogVisible = true;
},
nextStep() {
if (_this.step == 1) {
this.$refs.cmd.validate((valid) => {
if (valid) {
_this.stepLoading1 = true;
request({
url: '/algorithm/pull',
method: 'post',
data: _this.cmd
}).then(res => {
_this.stepLoading1 = false;
_this.step = 2;
_this.dialogName = "配置文件预览";
_this.cmd2 = res.data;
});
}
});
} else if (_this.step == 2) {
let id = _this.cmd2.id;
_this.dialogName = "依赖下载中.........";
_this.step = 3;
request({
url: `/algorithm/verification_rely/${id}`,
method: 'get',
data: _this.cmd
}).then(res => {
_this.stepPercent = 100;
});
// let si = setInterval(function() {
// let percent = _this.stepPercent;
// percent += 10;
// if(percent >= 100) {
// percent = 100;
// clearInterval(si);
// }
//
// }, 2000);
}
},
submitModify() {
let id = _this.cmd2.id;
request({
url: `/algorithm/release/${id}`,
method: 'get',
data: _this.cmd
}).then(res => {
_this.$message.success("发布成功");
_this.queryData();
_this.cmdDialogVisible = false;
});
},
}
}
</script>
<style lang="scss">
.title-form-box {
font-size: 16px;
padding-left: 5px;
margin-bottom: 25px;
font-weight: 600;
}
</style>

View File

@@ -0,0 +1,242 @@
<template>
<div>
<div class="menu-title">
三元组高速抽取
</div>
<div class="menu-content">
<div style="margin: 0px 0 20px 0">
<el-upload
style="float: left;margin-right: 10px"
class="upload-demo"
:auto-upload="false"
:show-file-list="false"
action="#"
multiple
:limit="3"
:on-change="handleFileChange"
:file-list="fileList">
<el-button type="primary" title='上传高速抽取测试数据'>上传数据</el-button>
</el-upload>
<el-button type="primary" title='开始三元组的高速抽取' :disabled="!uploadFlag" @click="validateData">开始抽取
</el-button>
</div>
<el-row :gutter="20">
<el-col :span="12">
<el-table :data="tableData" style="width: 100%" border class="text-table" id="text-table-id">
<el-table-column type="index" label="行号" width="60"></el-table-column>
<el-table-column prop="text" label="文本" width="200">
<template slot-scope="scope" :title="scope.row.text">{{
scope.row.text.substring(0, 120)
}}{{ scope.row.text.length > 120 ? '...' : '' }}
</template>
</el-table-column>
<el-table-column prop="groupStrCut" label="三元组">
<template slot-scope="scope">
<div class="tag-item" v-for="(tag,index) in scope.row.sro_list" :key="index">
{{ tag.object }}-{{ tag.relation }}-{{ tag.subject }}
</div>
</template>
</el-table-column>
</el-table>
</el-col>
<el-col :span="12">
<el-descriptions class="margin-top desc2" :column="2" border>
<el-descriptions-item>
<template slot="label">准确率</template>
<label>{{ correctRate }}%</label>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">耗时</template>
<div>{{ time }}s</div>
</el-descriptions-item>
</el-descriptions>
<div class="graph-box">
<graph ref="graph"></graph>
</div>
</el-col>
</el-row>
<div class="label-result" v-show="resultFlag">每千条文本知识抽取耗时{{ qths }}</div>
</div>
</div>
</template>
<script>
import request from '@/utils/request';
import graph from "@/components/graph/Graph";
var _this;
export default {
components: {
'graph': graph,
},
name: "algorithmSpeedVerification",
data() {
return {
uploadFlag: false,
correctRate: 0,
time: 0,
fileList: [],
jsonObj: {},
tableData: [],
resultFlag: false,
everyThousandTime: 0,
rateAll: [],
timeAll:[],
qths:0
}
},
mounted() {
_this = this;
},
methods: {
validateData() {
_this.$message.info("开始验证");
let pageNo = 1, pageSize = 5;
let _index = 0;
let _time = 0;
// let timeSt = setInterval(function () {
// _this.time = _time++ / 10;
// }, 100);
_this.tableData = [];
let st = setInterval(function () {
_this.correctRate = (parseFloat(_this.rateAll[_index]) * 100).toFixed(2);
_this.time = _this.timeAll[_index];
_index += 5;
_this.tableData = _this.tableData.concat(_this.jsonObj.items.slice((pageNo - 1) * pageSize, pageNo * pageSize));
_this.$nextTick(() => {
var div = document.getElementById('text-table-id');
div.scrollTop = div.scrollHeight;
})
pageNo++;
if (_index >= _this.jsonObj.items.length) {
clearInterval(st);
// clearInterval(timeSt);
_this.startInitGraph();
_this.$message.success("验证完毕");
_this.resultFlag = true;
// _this.everyThousandTime = (_this.time / 1.2).toFixed(2);
}
}, 40);
},
handleFileChange(file) {
_this.fileList = [file];
_this.correctRate = 0;
_this.time = 0;
_this.resultFlag = false;
_this.everyThousandTime = 0;
_this.tableData = [];
_this.$refs['graph'].initGraph({
nodes: [],
edges: []
}, true, null, true);
_this.queryData(file.raw);
},
queryData(fileItem) {
let formData = new FormData();
formData.append("file", fileItem);
let _msg = _this.$message({
message: '文件正在上传,请耐心等待',
type: 'info',
duration: 0
});
request({
url: '/indicator/indicator10',
method: 'put',
data: formData
}).then(res => {
_msg.close();
_this.$message.success("上传成功");
_this.rateAll = [];
_this.timeAll = [];
res.data.items.forEach(item => {
_this.rateAll.push(item.precision);
_this.timeAll.push(item.hshi)
})
_this.qths = res.data.qths
/**
* nodes:[],
* relations: [],
* items: []
*/
res.data.relations = res.data.relations.slice(0, 100);
_this.jsonObj = res.data;
_this.uploadFlag = true;
});
},
startInitGraph() {
let _nodes = [], _edges = [];
let ids = [];
_this.jsonObj.relations.forEach(edge => {
ids.push(edge.srcId);
ids.push(edge.dstId);
_edges.push({
source: edge.srcId,
target: edge.dstId,
label: edge.edgeName
});
});
_this.jsonObj.nodes.forEach(node => {
if (ids.indexOf(node.vid) >= 0) {
_nodes.push({
label: node.properties.name,
id: node.vid
});
}
});
_this.$refs['graph'].initGraph({
nodes: _nodes,
edges: _edges
}, true, null, true);
}
}
}
</script>
<style scoped lang="scss">
.label-result {
padding: 15px 0;
font-size: 15px;
text-align: center;
}
.tag-item {
word-break: break-all;
float: left;
background-color: #ecf5ff;
border-color: #d9ecff;
padding: 0 5px;
line-height: 40px;
font-size: 14px;
border-width: 1px;
border-style: solid;
border-radius: 5px;
margin: 0 4px 4px 0;
max-width: 430px;
min-width: 50px;
}
.result {
text-align: center;
margin-top: 25px;
font-size: 16px;
color: #5c5c5c;
}
.text-table {
height: 600px;
margin-top: 0;
overflow-y: auto;
}
.graph-box {
margin-top: 20px;
width: 100%;
height: 530px;
background: rgba(0, 0, 0, 0.1);
border-radius: 5px;
position: relative;
}
</style>

View File

@@ -0,0 +1,232 @@
<template>
<div>
<div class="menu-title">
代码仓库
</div>
<div class="menu-content">
<div>
<el-form :inline="true" :model="qo" class="demo-form-inline">
<el-form-item>
<el-input v-model="qo.LIKES_name" placeholder="请输入仓库名称"></el-input>
</el-form-item>
<el-form-item>
<el-input v-model="qo.LIKES_name" placeholder="请输入仓库地址"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="qo.pageNo=1;queryData()"> </el-button>
</el-form-item>
</el-form>
</div>
<div style="margin: 0px 0 20px 0">
<el-button type="primary" @click="createRow()">新增</el-button>
</div>
<div>
<el-table :data="result.records" style="width: 100%" ref="table" >
<el-table-column type="index" label="行号" width="100"></el-table-column>
<el-table-column prop="name" label="算法仓库名称"></el-table-column>
<el-table-column prop="gitUrl" label="仓库地址"></el-table-column>
<el-table-column prop="modifyTimeMillis" label="修改时间">
<template slot-scope="scope">
{{ scope.row.modifyTimeMillis | timeFilter }}
</template>
</el-table-column>
<el-table-column prop="createTimeMillis" label="创建时间">
<template slot-scope="scope">
{{ scope.row.createTimeMillis | timeFilter }}
</template>
</el-table-column>
<el-table-column label="操作" width="120">
<template slot-scope="scope">
<el-button @click.native.prevent="modifyRow(scope.row)" type="text" size="small">
编辑
</el-button>
<el-button @click.native.prevent="removeRow(scope.row)" type="text" size="small">
删除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div class="page-box">
<el-pagination background
@current-change="handleCurrentChange"
:current-page="qo.pageNo"
:page-size="qo.pageSize"
layout="total, prev, pager, next"
:total="result.total">
</el-pagination>
</div>
</div>
<el-dialog
:title="dialogName"
:visible.sync="cmdDialogVisible"
width="40%">
<el-form ref="cmd" label-width="100px" :rules="rules" :model="cmd">
<el-form-item label="算法名称" prop="name">
<el-input v-model="cmd.name" placeholder="请输入算法名称"></el-input>
</el-form-item>
<el-form-item label="仓库地址" prop="gitUrl">
<el-input v-model="cmd.gitUrl" placeholder="请输入仓库地址"></el-input>
</el-form-item>
<el-form-item label="账号" prop="userName">
<el-input v-model="cmd.userName" placeholder="请输入账号"></el-input>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input v-model="cmd.password" placeholder="请输入密码"></el-input>
</el-form-item>
<el-form-item label="描述">
<el-input v-model="cmd.remarks" placeholder="请输入描述" type="textarea"></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="submitModify"> </el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import request from '@/utils/request2';
var _this;
export default {
name: "codeWarehouse",
data() {
return {
qo: {
pageNo: 1,
pageSize: 10,
LIKES_name: '',
},
result: {
records: [],
total: 0
},
dialogName: '编辑',
cmdDialogVisible: false,
cmd: {},
rules: {
name: [
{required: true, message: '请输入算法名称'}
],
gitUrl: [
{required: true, message: '请输入仓库地址'}
],
userName: [
{required: true, message: '请输入账号'}
],
password: [
{required: true, message: '请输入密码'}
],
},
}
},
mounted() {
_this = this;
_this.queryData();
},
filters: {
timeFilter(val) {
if (val > 0) {
let dt = new Date(val);
let year = dt.getFullYear();
let month = dt.getMonth() + 1;
let date = dt.getDate();
let hour = dt.getHours();
let minute = dt.getMinutes();
let second = dt.getSeconds();
return `${year}-${month}-${date} ${hour}:${minute}:${second}`;
} else {
return "-";
}
}
},
methods: {
queryData() {
request({
url: '/repository/list',
method: 'post',
data: _this.qo
}).then(res => {
_this.result.records = res.list;
_this.result.total = res.total;
});
},
handleCurrentChange(val) {
_this.qo.pageNo = val;
_this.queryData();
},
removeRow(item) {
_this.$confirm('此操作将永久删除记录, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
let id = item.id;
request({
url: `/repository/delete/${id}`,
method: 'get',
}).then(res => {
_this.$message.success("删除成功");
_this.queryData();
});
}).catch(() => {
});
},
createRow() {
_this.cmdDialogVisible = true;
_this.$nextTick(() => {
_this.dialogName = "新增";
_this.cmd = {
name: '',
gitUrl: '',
userName: '',
password: '',
remarks: ''
};
_this.$refs.cmd.resetFields();
});
},
modifyRow(item) {
_this.cmdDialogVisible = true;
_this.$nextTick(() => {
_this.dialogName = "编辑";
_this.cmd = JSON.parse(JSON.stringify(item));
_this.cmd.modifyTimeMillis = null;
_this.$refs.cmd.resetFields();
});
},
submitModify() {
this.$refs.cmd.validate((valid) => {
if (valid) {
if (_this.cmd.id) {
request({
url: '/repository/update',
method: 'post',
data: _this.cmd
}).then(res => {
_this.$message.success("编辑成功");
_this.queryData();
_this.cmdDialogVisible = false;
});
} else { // 新建
request({
url: '/repository/save',
method: 'post',
data: _this.cmd
}).then(res => {
_this.$message.success("新增成功");
_this.queryData();
_this.cmdDialogVisible = false;
});
}
}
});
},
}
}
</script>
<style lang="scss">
</style>

View File

@@ -0,0 +1,357 @@
<template>
<div>
<div class="menu-title">
离散知识补充
</div>
<div class="menu-content">
<div>
<span>图谱选择</span>
<el-select v-model="activeSpace" placeholder="请选择要进行补充的图谱" @change="changeSpace">
<el-option
v-for="(item, index) in spaceList"
:key="item.name"
:label="item.name"
:value="index">
</el-option>
</el-select>
<el-upload
style="display: inline-block;margin-left: 20px"
class="upload-demo"
:auto-upload="false"
:show-file-list="false"
action="#"
multiple
:limit="3"
:on-change="handleFileChange"
:file-list="fileList">
<el-button type="primary" title='上传离散知识文件'>上传数据</el-button>
</el-upload>
<el-button type="primary" style="margin-left: 20px" @click="showResult" :disabled="!uploadSuccess">执行补充</el-button>
</div>
<el-row :gutter="20" style="margin-top: 20px">
<el-col :span="10">
<el-descriptions class="margin-top" title="补充结果" :column="1" border>
<el-descriptions-item label="补充时间">{{ resultCmd.time }}</el-descriptions-item>
<el-descriptions-item label="目标图谱">{{ resultCmd.space }}</el-descriptions-item>
<el-descriptions-item label="文件名">{{ resultCmd.fileName }}</el-descriptions-item>
<el-descriptions-item label="包含知识数量">{{ resultCmd.allCounts }}</el-descriptions-item>
<el-descriptions-item label="成功知识占比">{{ resultCmd.cgzb }}</el-descriptions-item>
<el-descriptions-item label="补充成功率">{{ resultCmd.cgl }}</el-descriptions-item>
<el-descriptions-item label="重叠知识占比">{{ resultCmd.cdzb }}</el-descriptions-item>
<el-descriptions-item label="重叠识别准确率">{{ resultCmd.cdl }}</el-descriptions-item>
<el-descriptions-item label="冲突知识占比">{{ resultCmd.ctzb }}</el-descriptions-item>
<el-descriptions-item label="冲突识别准确率">{{ resultCmd.ctl }}</el-descriptions-item>
</el-descriptions>
</el-col>
<el-col :span="14">
<el-descriptions class="margin-top" title="详细结果" :column="1" border>
</el-descriptions>
<el-table :data="resultList" style="width: 100%" height="500">
<el-table-column prop="zyz" :label="tableTitle[0]"></el-table-column>
<el-table-column prop="wyz" :label="tableTitle[1]"></el-table-column>
<el-table-column prop="byz" :label="tableTitle[2]"></el-table-column>
<el-table-column prop="bq" label="标签" width="100">
<template slot-scope="scope">
<label :style="{color:scope.row.bq=='成功'?'#67c23a':scope.row.bq=='冲突'?'#f56c6c':'#e6a23c'}">{{scope.row.bq}}</label>
</template>
</el-table-column>
<el-table-column prop="bq" label="状态" width="100">
<template slot-scope="scope">
<label :style="{color:scope.row.bq=='成功'?'#67c23a':scope.row.bq=='冲突'?'#f56c6c':'#e6a23c'}">{{scope.row.bq}}</label>
</template>
</el-table-column>
</el-table>
</el-col>
</el-row>
<!--
<div class="menu-content-tab">
<div>
<div>手动添加</div>
</div>
<div>
<div>
<span>主语类型</span>
<el-select v-model="activeTag" placeholder="请选择主语类型">
<el-option
v-for="item in tagList"
:key="item.name"
:label="item.name"
:value="item.name">
</el-option>
</el-select>
</div>
<div>
<span>主语取值</span>
<el-input v-model="tagValue" placeholder="请输入主语取值"></el-input>
</div>
<div>
<span>谓语类型</span>
<el-radio v-model="edgeType" label="1" @change="radioChange">关系属性</el-radio>
<el-radio v-model="edgeType" label="2" @change="radioChange">数值属性</el-radio>
</div>
<div v-show="edgeType === '1'">
<span>谓语取值</span>
<el-select v-model="activeEdge" placeholder="请选择谓语取值">
<el-option
v-for="item in edgeList"
:key="item.name"
:label="item.name"
:value="item.name">
</el-option>
</el-select>
</div>
<div v-show="edgeType === '2'">
<span>谓语取值</span>
<el-select v-model="activeEdge" placeholder="请选择谓语取值">
<el-option
v-for="item in tagField"
:key="item.name"
:label="item.name"
:value="item.name">
</el-option>
</el-select>
</div>
<div>
<span>宾语类型</span>
<el-select v-model="activeDataType" placeholder="请选择宾语类型">
<el-option
v-for="item in dataTypeList"
:key="item.name"
:label="item.name"
:value="item.name">
</el-option>
</el-select>
</div>
<div>
<span>宾语取值</span>
<el-input v-model="dataTypeValue" placeholder="请输入宾语取值"></el-input>
</div>
</div>
</div>
<div class="menu-content2">
<div style="margin: 0px 0 20px 0">
<p>
<span>补充时间</span>
<span>{{ resultCmd.time }}</span>
</p>
<p>
<span>目标图谱</span>
<span>{{ resultCmd.space }}</span>
</p>
<p>
<span>重叠识别准确率</span>
<span>{{ resultCmd.repeatRate }}%</span>
</p>
<p>
<span>冲突识别准确率</span>
<span>{{ resultCmd.conflictRate }}%</span>
</p>
</div>
<div>
</div>
</div>
-->
</div>
</div>
</template>
<script>
import request from '@/utils/request';
import {formatTime} from '@/utils/common';
var _this;
export default {
name: "dataRepeatRate",
data() {
return {
spaceList: [],
activeSpace: '',
dataTypeList: [],
activeDataType: '',
dataTypeValue: '',
tagList: [],
activeTag: '',
tagValue: '',
edgeType: '1',
tagField: [],
edgeList: [],
activeEdge: '',
edgeValue: '',
resultCmd1: {},
resultCmd: {
repeatRate: '0',
conflictRate: '0',
space: '',
time: ''
},
list: [],
resultList: [],
ontologyList: [],
AtlasSelection: '',
fileList: [],
edges: [],
radio: "1",
uploadSuccess: false,
tableTitle:["头实体","关系","尾实体"]
}
},
mounted() {
_this = this;
_this.queryData();
},
methods: {
radioChange() {
_this.activeEdge = '';
},
queryData() {
request({
url: '/indicator/indicator3_1',
method: 'get',
data: {}
}).then(res => {
if (res.data.space.length > 0) {
_this.activeSpace = 0;
}
_this.spaceList = res.data.space;
_this.dataTypeList = res.data.datatype;
_this.tagList = res.data.tag;
_this.tagField = res.data.tag_field;
_this.edgeList = res.data.edge;
});
},
changeSpace(){
if(_this.spaceList[_this.activeSpace].name.indexOf("实例") != -1){
_this.tableTitle = ["头实体","关系","尾实体"]
}else{
_this.tableTitle = ["概念","属性","概念"]
}
},
handleFileChange(file) {
_this.fileList = [file];
let fileName = file.name;
let activeSpace = _this.spaceList[_this.activeSpace];
if (activeSpace.id !== fileName) {
_this.$message.warning("上传文件与" + activeSpace.name + "不符");
return false;
}
_this.uploadFile(file);
},
showResult() {
_this.$message.info("开始执行补充");
setTimeout(() => {
_this.resultCmd = _this.resultCmd1;
_this.resultList = _this.list;
_this.$message.success("补充成功");
}, 1233);
},
uploadFile(fileItem) {
_this.uploadSuccess = false;
_this.$message.info("开始上传");
let formData = new FormData();
formData.append("file", fileItem.raw);
request({
url: '/indicator/indicator3',
method: 'put',
data: formData
}).then(res => {
_this.resultCmd1 = res.data;
_this.resultCmd1.space = _this.spaceList[_this.activeSpace].name;
_this.resultCmd1.fileName = fileItem.name;
_this.resultCmd1.time = formatTime(new Date());
_this.list = res.data.items;
_this.$message.success("上传成功");
_this.uploadSuccess = true;
});
},
}
}
</script>
<style lang="scss">
.result {
text-align: center;
margin-top: 25px;
font-size: 16px;
color: #5c5c5c;
}
.menu-content {
//overflow: hidden;
//display: flex;
//justify-content: space-between;
}
.menu-content2 {
float: left;
width: 50%;
}
.menu-content-tab > div:nth-of-type(1) {
width: 80%;
display: flex;
margin-top: 30px;
}
.menu-content-tab > div:nth-of-type(1) > div {
width: 100%;
height: 40px;
border: 1px solid #EBEEF5;
display: flex;
align-items: center;
justify-content: center;
border-radius: 0.20833vw 0.20833vw 0 0;
cursor: pointer;
font-weight: 500;
font-size: 0.72917vw;
}
.menu-content-tab > div:nth-of-type(1) > div:nth-of-type(2) {
background: #409EFF;
color: white;
}
.menu-content-tab > div:nth-of-type(1) > div:nth-of-type(2) .el-upload {
width: 100%;
height: 100%;
}
.menu-content-tab > div:nth-of-type(1) > div:nth-of-type(2) button {
width: 100%;
height: 100%;
}
.menu-content-tab > div:nth-of-type(2) {
width: 80%;
border: 1px solid #EBEEF5;
box-sizing: border-box;
border-top: none;
padding: 30px;
}
.menu-content-tab > div:nth-of-type(2) > div > .el-select, .menu-content-tab > div:nth-of-type(2) > div > .el-input {
width: 50%;
}
.menu-content-tab > div:nth-of-type(2) > div {
margin-top: 30px;
}
.menu-content2 > div:nth-of-type(1) {
font-size: 0.72917vw;
}
.menu-content2 > div:nth-of-type(1) > p {
display: flex;
margin-top: 20px;
}
.menu-content2 > div:nth-of-type(1) > p > span:nth-of-type(1) {
width: 150px;
}
</style>

View File

@@ -0,0 +1,174 @@
<template>
<div>
<div class="menu-title">
低资源场景知识抽取
</div>
<div class="menu-content">
<div style="margin: 0px 0 20px 0;overflow: hidden">
<el-upload
style="float: left;margin-right: 10px"
class="upload-demo"
action="#"
multiple
:auto-upload="false"
:limit="3"
:show-file-list="false"
:on-change="handleFileChange"
:file-list="fileList">
<el-button type="primary" title='上传“低资源”场景测试数据'>上传数据</el-button>
</el-upload>
</div>
<div class="menu-table">
<el-table :data="resultCmd.items" style="width: 60%" height="350">
<el-table-column prop="text" align="center" label="文本"></el-table-column>
<el-table-column prop="spo[0]" align="center" label="头实体"></el-table-column>
<el-table-column prop="spo[1]" align="center" label="关系"></el-table-column>
<el-table-column prop="spo[2]" align="center" label="尾实体"></el-table-column>
</el-table>
<div id="echart"></div>
</div>
<div style="margin: 20px 0 20px 0">
<el-button type="primary" title='开始“低资源”场景知识抽取' @click="validateData">开始验证</el-button>
</div>
<div>
<el-table :data="resultCmd1.items" style="width: 100%" height="350">
<el-table-column prop="text" align="center" label="文本"></el-table-column>
<el-table-column prop="spo[0]" align="center" label="头实体"></el-table-column>
<el-table-column prop="spo[1]" align="center" label="关系"></el-table-column>
<el-table-column prop="spo[2]" align="center" label="尾实体"></el-table-column>
<el-table-column align="center" label="预测结果">
<template slot-scope="scope">
<label
:style="scope.row.ycspoflag?'':'color:red'">({{ scope.row.ycspo[0] }},{{ scope.row.ycspo[1] }},{{ scope.row.ycspo[2] }})</label>
</template>
</el-table-column>
</el-table>
</div>
<div class="result" v-if="resultCmd1.zql ">低资源场景知识抽取结果 准确率{{
resultCmd1.zql
}}正确条数{{ resultCmd1.trueTotal }}总条数{{ resultCmd1.total }}
</div>
</div>
</div>
</template>
<script>
import request from '@/utils/request';
var _this;
export default {
name: "company",
data() {
return {
fileList: [],
resultCmd: {},
resultCmd1: {}
}
},
mounted() {
_this = this;
_this.queryData();
},
methods: {
handleFileChange(file) {
_this.fileList = [file];
_this.uploadFile(file.raw);
},
queryData() {
request({
url: '/indicator/indicator1_1',
method: 'get',
data: {}
}).then(res => {
_this.resultCmd = res.data;
_this.initEchart();
_this.validateData();
});
},
uploadFile(fileItem) {
let formData = new FormData();
formData.append("file", fileItem);
request({
url: '/indicator/indicator1',
method: 'put',
data: formData
}).then(res => {
_this.resultCmd = res.data;
_this.resultCmd1 = {};
_this.initEchart();
});
},
validateData() {
_this.resultCmd1 = _this.resultCmd
_this.resultCmd1.total = _this.resultCmd1.items.length;
_this.resultCmd1.trueTotal = 0
_this.resultCmd1.items.forEach(item => {
if (item.ycspoflag) {
_this.resultCmd1.trueTotal++;
}
})
},
initEchart() {
var xAxis = [];
var data = []
for (var key in _this.resultCmd.relations) {
xAxis.push(key);
data.push(_this.resultCmd.relations[key])
}
var chart = this.$echarts.init(document.getElementById("echart"));
var option = {
tooltip: {
trigger: 'axis'
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: {
type: 'category',
data: xAxis,
axisLabel: {interval: 0, rotate: 30}
},
yAxis: {
type: 'value'
},
series: [
{
data: data,
type: 'bar'
}
]
};
chart.setOption(option);
}
}
}
</script>
<style scoped lang="scss">
.result {
text-align: center;
margin-top: 25px;
font-size: 16px;
color: #5c5c5c;
}
#echart {
width: 40%;
height: 350px;
margin-left: 30px;
}
.menu-table {
width: 100%;
display: flex;
justify-content: space-between;
}
.menu-table th div, .menu-table td div {
text-align: center;
}
</style>

View File

@@ -0,0 +1,585 @@
<template>
<div>
<div class="menu-title">
数据集管理
</div>
<div class="menu-content">
<div>
<el-form :inline="true" :model="qo" class="demo-form-inline">
<el-form-item>
<el-input v-model="qo.LIKES_name" placeholder="请输入任务名称"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="qo.pageNo=1;queryData()"> </el-button>
</el-form-item>
</el-form>
</div>
<div style="margin: 0px 0 20px 0">
<el-button type="primary" @click="createRow()">新建任务</el-button>
</div>
<div>
<el-table :data="result.records" style="width: 100%" ref="table" @expand-change="showDataSetListByTaskId">
<el-table-column type="expand">
<template slot-scope="scope">
<el-row>
<el-col :span="8" v-for="item in scope.row.tasks" :key="item.id">
<el-form label-position="left" inline class="demo-table-expand" label-width="85px">
<el-form-item label="数据集类型">
<span>{{ item.taskTypeName }}</span>
<span v-if="item.taskId == null">暂无数据</span>
</el-form-item>
<el-form-item label="总记录数">
<span>{{ item.icount }}</span>
</el-form-item>
<el-form-item label="实体数量">
<span>{{ item.ecount }}</span>
</el-form-item>
<el-form-item label="关系数量">
<span>{{ item.rcount }}</span>
</el-form-item>
<el-form-item label="操作">
<el-button type="text" size="small" @click="showImportDialog(item, scope.row)">
导入
</el-button>
<el-button type="text" size="small" @click="showDataSetViewDialog(item, scope.row)"
v-if="item.taskId != null">
查看
</el-button>
<el-button type="text" size="small" @click="markTxt(item, scope.row)"
v-if="item.taskId != null">
标注
</el-button>
<el-button type="text" size="small" @click="downloadFile(item, scope.row)"
v-if="item.taskId != null">
导出
</el-button>
<el-button type="text" size="small" @click="removeDataSet(item, scope.row)"
v-if="item.taskId != null">
删除
</el-button>
</el-form-item>
</el-form>
</el-col>
</el-row>
</template>
</el-table-column>
<el-table-column type="index" label="行号" width="100"></el-table-column>
<el-table-column prop="name" label="任务名称"></el-table-column>
<el-table-column prop="createTime" label="创建时间"></el-table-column>
<el-table-column label="操作">
<template slot-scope="scope">
<el-button title="将其他知识图谱本体三元组导入当前数据集中"
@click.native.prevent="showImportNodeDialog(scope.row)"
type="text" size="small">
导入知识图谱本体
</el-button>
<el-button @click.native.prevent="removeRow(scope.row)" type="text" size="small">
删除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div class="page-box">
<el-pagination background
@current-change="handleCurrentChange"
:current-page="qo.pageNo"
:page-size="qo.pageSize"
layout="total, prev, pager, next"
:total="result.total">
</el-pagination>
</div>
</div>
<el-dialog
title="新建"
:visible.sync="cmdDialogVisible"
width="40%">
<el-form ref="cmd" label-width="100px" :rules="rules" :model="cmd">
<el-form-item label="任务名称" prop="name">
<el-input v-model="cmd.name" placeholder="请输入任务名称"></el-input>
</el-form-item>
<!-- <el-form-item label="相关描述" prop="name">-->
<!-- <el-input v-model="cmd.description" placeholder="请输入相关描述" type="textarea"></el-input>-->
<!-- </el-form-item>-->
<el-form-item label="验证集文件">
<el-upload
class="upload-demo"
ref="upload2"
action="#"
:on-change="handleValidationFileChange"
:auto-upload="false"
accept=".txt"
:limit="10"
:file-list="fileList2">
<el-button size="small" type="primary">点击上传</el-button>
<div slot="tip" class="el-upload__tip">请选择一个格式为.txt的文本文件进行上传</div>
</el-upload>
</el-form-item>
<el-form-item label="训练集文件">
<el-upload
class="upload-demo"
ref="upload3"
action="#"
:on-change="handleTrainingFileChange"
:auto-upload="false"
accept=".txt"
:limit="10"
:file-list="fileList3">
<el-button size="small" type="primary">点击上传</el-button>
<div slot="tip" class="el-upload__tip">请选择一个格式为.txt的文本文件进行上传</div>
</el-upload>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="cmdDialogVisible = false"> </el-button>
<el-button type="primary" @click="submitModify"> </el-button>
</span>
</el-dialog>
<el-dialog
title="导入知识图谱本体"
:visible.sync="importNodeDialogVisible"
width="40%">
<el-table :data="ontologyList" style="width: 100%">
<el-table-column type="index" label="行号" width="100"></el-table-column>
<el-table-column prop="name" label="模型名称"></el-table-column>
<el-table-column prop="createTime" label="创建时间"></el-table-column>
<el-table-column label="操作" width="80">
<template slot-scope="scope">
<el-button @click.native.prevent="submitImportNode(scope.row)" type="text" size="small"
v-if="cmd.srcOntologyId != scope.row.id">
导入
</el-button>
<label v-else>自身</label>
</template>
</el-table-column>
</el-table>
<span slot="footer" class="dialog-footer">
<el-button type="primary" @click="importNodeDialogVisible = false"> </el-button>
</span>
</el-dialog>
<el-dialog
title="导入"
:visible.sync="importDialogVisible"
width="40%">
<el-form ref="cmd" label-width="100px" :model="cmd">
<el-form-item label="数据集类型" prop="name">
<el-select v-model="cmd.taskType" disabled>
<el-option :label="item.name" :value="item.code" v-for="item in taskTypeList" :key="item.code"></el-option>
</el-select>
</el-form-item>
<el-form-item label="选择文件" prop="name">
<el-upload
class="upload-demo"
ref="upload"
action="#"
:on-change="handleFileChange"
:auto-upload="false"
accept=".txt"
:limit="10"
:file-list="fileList">
<el-button size="small" type="primary">点击上传</el-button>
<div slot="tip" class="el-upload__tip">请选择一个格式为.txt的文本文件进行上传</div>
</el-upload>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="importDialogVisible = false"> </el-button>
<el-button type="primary" @click="submitImport"> </el-button>
</span>
</el-dialog>
<el-dialog
title="查看"
:visible.sync="viewDialogVisible"
width="60%">
<div>
<el-table :data="dataSetResult.records" style="width: 100%">
<el-table-column type="index" label="行号" width="80"></el-table-column>
<el-table-column prop="content" label="文本内容">
<template slot-scope="scope">
<label
:title="scope.row.content">{{
scope.row.content.length > 45 ? (scope.row.content.substring(0, 45) + '...') : scope.row.content
}}</label>
</template>
</el-table-column>
<el-table-column label="操作" width="120">
<template slot-scope="scope">
<el-button @click.native.prevent="remarkText(scope.row, scope.$index)" type="text" size="small">
标注
</el-button>
<el-button @click.native.prevent="removeDataSetView(scope.row)" type="text" size="small">
删除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div class="page-box">
<el-pagination background
@current-change="handleDataSetCurrentChange"
:current-page="dataSetQo.pageNo"
:page-size="dataSetQo.pageSize"
layout="total, prev, pager, next"
:total="dataSetResult.total">
</el-pagination>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="viewDialogVisible = false"> </el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import request, {getBaseUrl} from '@/utils/request';
var _this;
export default {
name: "company",
data() {
return {
qo: {
pageNo: 1,
pageSize: 10,
LIKES_name: '',
},
result: {
records: [],
total: 0
},
dataSetQo: {
pageNo: 1,
pageSize: 10,
taskId: '',
taskType: ''
},
dataSetResult: {
records: [],
total: 0
},
ontologyList: [],
taskTypeList: [{
name: "测试集",
code: 1,
eName: "test"
}, {
name: "验证集",
code: 2,
eName: "validation"
}, {
name: "训练集",
code: 3,
eName: "training"
}],
dialogName: '编辑',
cmdDialogVisible: false,
viewDialogVisible: false,
importDialogVisible: false,
importNodeDialogVisible: false,
cmd: {},
rules: {
name: [
{required: true, message: '请输入任务名称'}
],
ontologyId: [
{required: true, message: '本体标签库'}
],
},
fileList: [],
fileList2: [],
fileList3: []
}
},
mounted() {
_this = this;
_this.queryOntologyList();
_this.queryData();
},
methods: {
queryData() {
request({
url: '/remark_task/query_pages',
method: 'post',
data: _this.qo
}).then(res => {
_this.result.records = res.data.records;
_this.result.total = res.data.total;
if (res.data.records.length > 0) {
_this.$nextTick(() => {
_this.$refs['table'].toggleRowExpansion(res.data.records[0], true);
});
}
});
},
handleCurrentChange(val) {
_this.qo.pageNo = val;
_this.queryData();
},
downloadFile(item, row) { // 导出
window.open(getBaseUrl() + `/es_remark_task/export/${row.id}/${item.taskTypeCode}`);
},
showImportNodeDialog(item) { // 打开复制图模型的列表弹窗
_this.queryOntologyList();
_this.cmd = {
srcOntologyId: item.ontologyId,
dictOntologyId: ''
};
_this.importNodeDialogVisible = true;
},
submitImportNode(item) {
_this.cmd.dictOntologyId = item.id;
request({
url: '/noumenon/copy_by_ontologyid',
method: 'post',
data: _this.cmd
}).then(res => {
_this.$message.success("导入成功");
});
},
queryOntologyList() {
request({
url: '/ontology/query_list',
method: 'post',
data: {}
}).then(res => {
_this.ontologyList = res.data;
});
},
removeRow(item) {
_this.$confirm('此操作将永久删除记录, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
request({
url: '/remark_task/removeremarktask',
method: 'post',
data: {
remarkId: item.id,
ontologyId: item.ontologyId
}
}).then(res => {
_this.$message.success("删除成功");
_this.queryData();
_this.queryOntologyList();
});
}).catch(() => {
});
},
createRow() {
_this.cmd = {
name: '',
};
_this.cmdDialogVisible = true;
},
modifyRow(item) {
_this.cmd = JSON.parse(JSON.stringify(item));
_this.cmdDialogVisible = true;
},
showImportDialog(dataSet, task) {
_this.cmd = {
taskId: task.id,
taskType: dataSet.taskTypeCode
}
_this.fileList = [];
_this.importDialogVisible = true;
},
handleFileChange(file) {
_this.$refs['upload'].clearFiles();
_this.fileList = [file];
},
handleValidationFileChange(file) {
_this.$refs['upload2'].clearFiles();
_this.fileList2 = [file];
},
handleTrainingFileChange(file) {
_this.$refs['upload3'].clearFiles();
_this.fileList3 = [file];
},
submitModify() {
this.$refs.cmd.validate((valid) => {
if (valid) {
let formData = new FormData();
formData.append("name", _this.cmd.name);
formData.append("validationFile", _this.fileList2[0].raw);
formData.append("trainingFile", _this.fileList3[0].raw);
// if (_this.cmd.id) {
// request({
// url: '/remark_task/modify',
// method: 'post',
// data: _this.cmd
// }).then(res => {
// _this.$message.success("编辑成功");
// _this.queryData();
// _this.cmdDialogVisible = false;
// });
// } else { // 新建
request({
url: '/remark_task/create_with_file',
method: 'post',
data: formData
}).then(res => {
_this.$message.success("添加成功");
_this.queryData();
_this.cmdDialogVisible = false;
});
// }
}
});
},
showDataSetListByTaskId(row, expanded) {
if (row.tasks) {
return;
}
request({
url: '/es_remark_task/findesremarkinfosticdto/' + row.id,
method: 'post',
data: _this.qo
}).then(res => {
let tasks = [];
for (let i = 0; i < 3; i++) {
tasks.push({
ecount: 0,
icount: 0,
rcount: 0,
taskTypeName: _this.taskTypeList[i].name,
taskTypeEName: _this.taskTypeList[i].eName,
taskTypeCode: i + 1
});
}
res.data.forEach(item => {
let index = tasks.findIndex(row => {
return row.taskTypeEName == item.type;
});
if (tasks[index]) {
tasks[index].ecount = item.ecount;
tasks[index].icount = item.icount;
tasks[index].rcount = item.rcount;
tasks[index].taskId = item.taskId;
}
});
row.tasks = tasks;
});
},
submitImport() {
if (_this.fileList.length == 0) {
_this.$message.warning("请选择一个文本文件进行上传");
return;
}
let formData = new FormData();
formData.append("taskId", _this.cmd.taskId);
formData.append("file", _this.fileList[0].raw);
formData.append("taskType", _this.cmd.taskType);
request({
url: '/es_remark_task/upload_task',
method: 'post',
data: formData
}).then(res => {
_this.$message.success("导入成功");
_this.reloadDataSet(_this.cmd.taskId);
_this.importDialogVisible = false;
});
},
reloadDataSet(taskId) {
let index = _this.result.records.findIndex(row => {
return row.id == taskId;
});
_this.result.records[index].tasks = null;
_this.showDataSetListByTaskId(_this.result.records[index]);
},
showDataSetViewDialog(dataSet, task) { // 打开查看弹窗,保存一些父级数据集信息
_this.dataSetQo = {
pageNo: 1,
pageSize: 10,
taskId: task.id,
taskType: dataSet.taskTypeCode,
ontologyId: task.ontologyId
}
_this.queryDataSetViewData();
},
queryDataSetViewData() {
request({
url: '/es_remark_task/findbytaskidandtasktype',
method: 'post',
data: _this.dataSetQo
}).then(res => {
_this.dataSetResult.records = res.data.content;
_this.dataSetResult.total = res.data.totalElements;
_this.viewDialogVisible = true;
});
},
handleDataSetCurrentChange(val) {
_this.dataSetQo.pageNo = val;
_this.queryDataSetViewData();
},
removeDataSet(item, task) {
_this.$confirm('此操作将永久删除记录, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
request({
url: '/es_remark_task/deletebyqo',
method: 'post',
data: {
taskId: task.id,
taskType: item.taskTypeCode
}
}).then(res => {
_this.$message.success("删除成功");
_this.reloadDataSet(task.id);
});
}).catch(() => {
});
},
removeDataSetView(item) {
_this.$confirm('此操作将永久删除记录, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
request({
url: '/es_remark_task/delete/' + item.id,
method: 'post'
}).then(res => {
_this.$message.success("删除成功");
_this.queryDataSetViewData();
});
}).catch(() => {
});
},
markTxt(item, task) {
this.$router.push({
path: '/textTag',
query: {taskId: task.id, taskTypeCode: item.taskTypeCode, ontologyId: task.ontologyId}
});
},
remarkText(row, index) { // 跳转到标注页,根据序号
let sort = (_this.dataSetQo.pageNo - 1) * _this.dataSetQo.pageSize + index + 1;
this.$router.push({
path: '/textTag',
query: {sort: sort, taskId: _this.dataSetQo.taskId, taskTypeCode: _this.dataSetQo.taskType, ontologyId: _this.dataSetQo.ontologyId}
});
}
}
}
</script>
<style lang="scss">
.demo-table-expand {
font-size: 0;
margin-left: 10%;
}
.demo-table-expand label {
width: 90px;
color: #99a9bf;
}
.demo-table-expand .el-form-item {
margin-right: 0;
margin-bottom: 0;
width: 80%;
}
</style>

View File

@@ -0,0 +1,515 @@
<template>
<div>
<div class="menu-title">
知识图谱质量评估
</div>
<div class="menu-content">
<div>
<el-form :inline="true" :model="qo" class="demo-form-inline">
<el-form-item label="选择待评估图谱:">
<el-select v-model="value" placeholder="选择待评估图谱" @change="handleSelectChange">
<el-option
v-for="item in spaceList"
:key="item.name"
:label="item.name"
:value="item.name">
</el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="indicator5(1)">开始采样</el-button>
<el-button type="primary" icon="el-icon-search" @click="indicator5(2)">开始质量评估</el-button>
</el-form-item>
</el-form>
</div>
<div v-if="tableShow == 1">
<div class="result1">评估结果:</div>
<el-table :data="indicator5Data.zb1" style="width: 60%">
<el-table-column prop="sign1" label="指标">
<template slot-scope="scope">
{{ scope.row[0] }}
</template>
</el-table-column>
<el-table-column prop="sign2" label="采样后的知识图谱">
<template slot-scope="scope">
{{ scope.row[1] }}
</template>
</el-table-column>
<el-table-column prop="sign3" label="原始的知识图谱">
<template slot-scope="scope">
{{ scope.row[2] }}
</template>
</el-table-column>
</el-table>
<el-table :data="indicator5Data.zb2" style="width: 60%;margin-top: 40px">
<el-table-column prop="sign1" label="指标">
<template slot-scope="scope">
{{ scope.row[0] }}
</template>
</el-table-column>
<el-table-column prop="sign2" label="采样后的知识图谱">
<template slot-scope="scope">
{{ scope.row[1] }}
</template>
</el-table-column>
<el-table-column prop="sign3" label="原始的知识图谱">
<template slot-scope="scope">
{{ scope.row[2] }}
</template>
</el-table-column>
</el-table>
<div class="result1" style="margin-top: 20px" v-if="cai.length > 0">
<!-- 使用采样数据集 预估评估误差{{indicator5Data.wc}}-->
温馨小贴士<br/><br/>
{{ cai }}
</div>
</div>
<div v-if="tableShow == 2">
<div class="ping-box" v-if="ping.length > 0">
温馨小贴士<br/><br/>
{{ ping }}
</div>
<el-row :gutter="20" style="margin-top: 30px">
<el-col :span="15">
<p>知识图谱评估结果整体展示</p>
<div id="echart"></div>
</el-col>
<el-col :span="9">
<div>
<img :src="fileUrl+'/'+indicator5Data.rlt" style="width: 100%;margin-top: 30px" alt="">
</div>
</el-col>
</el-row>
<div style="margin-top: 30px;overflow: hidden">
<el-table :data="indicator5Data.tjxx" style="width: 100%" border :span-method="objectSpanMethod">
<el-table-column prop="weidu" label="维度" align="center"></el-table-column>
<el-table-column prop="csbs" label="标识符" align="center">
<template slot-scope="scope">
<label v-if="scope.row.csbs">{{ scope.row.csbs }}</label>
<label :style="scope.row.zhibiao.indexOf('总得分') != -1?'font-weight: bold;':''"
v-else>{{ scope.row.zhibiao }}</label>
</template>
</el-table-column>
<el-table-column prop="zhibiao" label="指标" align="center">
<template slot-scope="scope">
<label v-if="scope.row.zhibiao.indexOf('总得分') == -1">{{ scope.row.zhibiao }}</label>
</template>
</el-table-column>
<el-table-column prop="val" label="评估值" align="center"></el-table-column>
</el-table>
</div>
<!--<el-row :gutter="20" style="margin-top: 30px;overflow: hidden">-->
<!--<div style="float: left;width: 30%">-->
<!--<p>时效性维度</p>-->
<!--<el-table :data="indicator5Data.arr1" style="width: 100%">-->
<!--<el-table-column prop="sign1" label="时效性评估指标">-->
<!--<template slot-scope="scope">-->
<!--<span>{{scope.row.zhibiao}}</span>-->
<!--</template>-->
<!--</el-table-column>-->
<!--<el-table-column prop="sign2" label="评估值">-->
<!--<template slot-scope="scope">-->
<!--<span>{{scope.row.val}}</span>-->
<!--</template>-->
<!--</el-table-column>-->
<!--</el-table>-->
<!--</div>-->
<!--<div style="float: left;width: 30%;margin: 0 5%">-->
<!--<p>语法有效性维度</p>-->
<!--<el-table :data="indicator5Data.arr2" style="width: 100%">-->
<!--<el-table-column prop="sign1" label="语法有效性评估指标">-->
<!--<template slot-scope="scope">-->
<!--<span>{{scope.row.zhibiao}}</span>-->
<!--</template>-->
<!--</el-table-column>-->
<!--<el-table-column prop="sign2" label="评估值">-->
<!--<template slot-scope="scope">-->
<!--<span>{{scope.row.val}}</span>-->
<!--</template>-->
<!--</el-table-column>-->
<!--</el-table>-->
<!--</div>-->
<!--<div style="float: left;width: 30%">-->
<!--<p>一致性维度</p>-->
<!--<el-table :data="indicator5Data.arr3" style="width: 100%">-->
<!--<el-table-column prop="sign1" label="一致性评估指标">-->
<!--<template slot-scope="scope">-->
<!--<span>{{scope.row.zhibiao}}</span>-->
<!--</template>-->
<!--</el-table-column>-->
<!--<el-table-column prop="sign2" label="评估值">-->
<!--<template slot-scope="scope">-->
<!--<span>{{scope.row.val}}</span>-->
<!--</template>-->
<!--</el-table-column>-->
<!--</el-table>-->
<!--</div>-->
<!--</el-row>-->
<!--<el-row :gutter="20" style="margin-top: 30px;overflow: hidden">-->
<!--<div style="float: left;width: 30%">-->
<!--<p>简洁性维度</p>-->
<!--<el-table :data="indicator5Data.arr4" style="width: 100%">-->
<!--<el-table-column prop="sign1" label="简洁性评估指标">-->
<!--<template slot-scope="scope">-->
<!--<span>{{scope.row.zhibiao}}</span>-->
<!--</template>-->
<!--</el-table-column>-->
<!--<el-table-column prop="sign2" label="评估值">-->
<!--<template slot-scope="scope">-->
<!--<span>{{scope.row.val}}</span>-->
<!--</template>-->
<!--</el-table-column>-->
<!--</el-table>-->
<!--</div>-->
<!--<div style="float: left;width: 30%;margin: 0 5%">-->
<!--<p>完整性维度</p>-->
<!--<el-table :data="indicator5Data.arr5" style="width: 100%">-->
<!--<el-table-column prop="sign1" label="完整性评估指标">-->
<!--<template slot-scope="scope">-->
<!--<span>{{scope.row.zhibiao}}</span>-->
<!--</template>-->
<!--</el-table-column>-->
<!--<el-table-column prop="sign2" label="评估值">-->
<!--<template slot-scope="scope">-->
<!--<span>{{scope.row.val}}</span>-->
<!--</template>-->
<!--</el-table-column>-->
<!--</el-table>-->
<!--</div>-->
<!--</el-row>-->
</div>
</div>
</div>
</template>
<script>
import request, {getFileUrl} from '@/utils/request';
var _this;
export default {
name: "graphAssessment",
data() {
return {
spaceList: [],
fileUrl: getFileUrl(),
value: '',
qo: {
pageNo: 1,
pageSize: 10,
LIKES_name: '',
EQI_sourceType: 1
},
result: {
records: [],
total: 1
},
indicator5Data: {},
tableShow: '',
spanArr: [],
liArr: [],
cai: '',
ping: ''
}
},
mounted() {
_this = this;
_this.queryData();
},
methods: {
queryData() {
request({
url: '/indicator/indicator5_1',
method: 'get',
data: {}
}).then(res => {
_this.spaceList = res.data;
_this.value = _this.spaceList[0].name;
_this.indicator5(1);
});
},
handleSelectChange() {
_this.cai = "";
_this.ping = "";
},
indicator5(type) {
_this.tableShow = type;
request({
url: '/indicator/indicator5/' + _this.value,
method: 'get',
data: {}
}).then(res => {
if (type === 1) {
if (_this.value === "DBPedia") {
_this.cai = "从原始DBPedia知识图谱中抽样了6,067,531条知识得到采样后的DBPedia知识图谱评估工作量降低了99.6%。";
} else if (_this.value === "WikiData") {
_this.cai = "从原始WikiData知识图谱中抽样了1,771,981条知识得到采样后的WikiData知识图谱评估工作量降低了90.9%。";
} else {
_this.cai = "";
}
} else if (type === 2) {
if (_this.value === "DBPedia") {
_this.ping = "对抽样后的DBPedia知识图谱进行评估其知识准确率为94.6%知识准确率评估误差为0.04%。";
} else if (_this.value === "WikiData") {
_this.ping = "对抽样后的WikiData知识图谱进行评估其知识准确率为85.7%知识准确率评估误差为0.07%。";
} else {
_this.ping = "";
}
}
let arr1 = [];
let arr2 = [];
let arr3 = [];
let arr4 = [];
let arr5 = [];
res.data.tjxx.map(data1 => {
if (data1.weidu == "时效性") {
arr1.push(data1);
} else if (data1.weidu == "语法有效性") {
arr2.push(data1);
} else if (data1.weidu == "一致性") {
arr3.push(data1);
} else if (data1.weidu == "简洁性") {
arr4.push(data1);
} else if (data1.weidu == "完整性") {
arr5.push(data1);
}
})
_this.indicator5Data = res.data;
_this.indicator5Data.arr1 = arr1;
_this.indicator5Data.arr2 = arr2;
_this.indicator5Data.arr3 = arr3;
_this.indicator5Data.arr4 = arr4;
_this.indicator5Data.arr5 = arr5;
_this.getSpanId(res.data.tjxx);
if (type == 2) {
_this.initEchart();
}
});
},
getSpanId(data) {
this.spanArr = []
this.liArr = []
// data就是我们从后台拿到的数据
for (var i = 0; i < data.length; i++) {
if (i === 0) {
//spanArr 用于存放没一行记录的合并数
this.spanArr.push(1);
//pos是spanArr的索引
this.pos = 0;
} else {
// 判断当前元素与上一个元素是否相同
if (data[i].weidu === data[i - 1].weidu) {
this.spanArr[this.pos] += 1;
this.spanArr.push(0);
} else {
this.spanArr.push(1);
this.pos = i;
}
}
if (data[i].zhibiao.indexOf('总得分') != -1) {
this.liArr.push(i)
}
}
console.log(this.liArr)
},
objectSpanMethod({row, column, rowIndex, columnIndex}) {
if (columnIndex === 0) {
const _row = this.spanArr[rowIndex];
//如果行号大于0 合并
const _col = _row > 0 ? 1 : 0;
// console.log(`rowspan:${_row} colspan:${_col}`);
return {
// [0,0] 表示这一行不显示,
rowspan: _row,
colspan: _col
};
}
if (this.liArr.indexOf(rowIndex) != -1) {
if (columnIndex === 1) {
return [1, 2];
} else if (columnIndex === 2) {
return [0, 0];
}
}
},
handleFileChange(file) {
_this.fileList = [file];
},
// queryData() {
//
// if(_this.value == 1) {
// _this.result.records = [ {
// sign1: '93%',
// sign2: '45%',
// sign3: '81%',
// }]
// } else {
// _this.result.records = [ {
// sign1: '90%',
// sign2: '40%',
// sign3: '88%',
// }]
// }
// },
initEchart() {
let chart = _this.$echarts.init(document.getElementById("echart"));
let echartArr1 = [];
let echartArr2 = [];
let echartArr3 = [];
let echartArr4 = [];
if (_this.indicator5Data.ld1) {
_this.indicator5Data.ld1.map(data => {
echartArr1.push({text: data.name, max: 1});
echartArr2.push(data.val);
})
}
if (_this.indicator5Data.ld2) {
_this.indicator5Data.ld2.map(data => {
echartArr3.push({text: data.name});
echartArr4.push(data.val);
})
}
var option = {
// color: ['#67F9D8', '#FFE434', '#56A3F1', '#FF917C'],
// title: {
// text: 'Customized Radar Chart'
// },
// legend: {},
radar: [
{
indicator: echartArr3,
center: ['75%', '50%'],
radius: 120,
startAngle: 90,
splitNumber: 4,
shape: 'circle',
axisName: {
formatter: '【{value}】',
color: '#428BD4'
},
splitArea: {
areaStyle: {
// color: ['#77EADF', '#26C3BE', '#64AFE9', '#428BD4'],
shadowColor: 'rgba(0, 0, 0, 0.2)',
shadowBlur: 10
}
},
axisLine: {
lineStyle: {
// color: 'rgba(211, 253, 250, 0.8)'
}
},
splitLine: {
lineStyle: {
// color: 'rgba(211, 253, 250, 0.8)'
}
}
},
{
indicator: echartArr1,
center: ['25%', '50%'],
radius: 120,
axisName: {
color: '#fff',
backgroundColor: '#666',
borderRadius: 3,
padding: [3, 5]
}
}
],
series: [
{
type: 'radar',
emphasis: {
lineStyle: {
width: 4
}
},
data: [
{
value: echartArr4,
name: 'Data A'
},
// {
// value: [60, 5, 0.3, -100, 1500],
// name: 'Data B',
// // areaStyle: {
// // color: 'rgba(255, 228, 52, 0.6)'
// // }
// }
]
},
{
type: 'radar',
radarIndex: 1,
data: [
{
value: echartArr2,
name: 'Data C',
// symbol: 'rect',
// symbolSize: 12,
// lineStyle: {
// type: 'dashed'
// },
// label: {
// show: true,
// formatter: function (params) {
// return params.value;
// }
// }
},
// {
// value: [100, 93, 50, 90, 70, 60],
// name: 'Data D',
// // areaStyle: {
// // color: new echarts.graphic.RadialGradient(0.1, 0.6, 1, [
// // {
// // color: 'rgba(255, 145, 124, 0.1)',
// // offset: 0
// // },
// // {
// // color: 'rgba(255, 145, 124, 0.9)',
// // offset: 1
// // }
// // ])
// // }
// }
]
}
]
};
chart.resize()
chart.setOption(option);
}
}
}
</script>
<style lang="scss">
.ping-box {
position: absolute;
right: 200px;
top: 25px;
width: 650px;
}
.result1 {
text-align: left;
margin-top: 5px;
margin-bottom: 15px;
font-size: 16px;
color: #5c5c5c;
}
#echart {
width: 100%;
height: 500px;
margin-left: 30px;
}
</style>

View File

@@ -0,0 +1,133 @@
<template>
<div>
<div class="menu-title">
武器装备维修保障知识抽取
</div>
<!--<div class="menu-content">-->
<!--<div style="height: 40px">-->
<!--<el-upload-->
<!--ref="upload"-->
<!--class="upload-btn"-->
<!--:auto-upload="false"-->
<!--action="#"-->
<!--:on-change="handleFileChange"-->
<!--:limit="2"-->
<!--:show-file-list="false">-->
<!--<el-button type="primary">导入测试文件</el-button>-->
<!--</el-upload>-->
<!--<el-button type="primary" style="margin-left: 20px">开始测试</el-button>-->
<!--<el-button style="float: right">三元组F1</el-button>-->
<!--<el-button style="float: right">实体F1</el-button>-->
<!--</div>-->
<!--<div style="margin-top: 30px;height: calc(100% - 80px)">-->
<!--<el-table :data="questionData" style="width: 100%;">-->
<!--<el-table-column prop="question" label="句子"></el-table-column>-->
<!--<el-table-column prop="answer" label="实体"></el-table-column>-->
<!--<el-table-column prop="index" label="三元组"></el-table-column>-->
<!--</el-table>-->
<!--</div>-->
<!--</div>-->
<div class="menu-content">
<div style="height: 40px">
<el-input
placeholder="请输入内容"
v-model="keyword" style="width: 50%">
<i slot="prefix" class="el-input__icon el-icon-search"></i>
</el-input>
<el-button type="primary" style="float: right">故障原因推荐Top5准确率</el-button>
</div>
<div style="margin-top: 30px;height: calc(100% - 80px)">
<el-table :data="questionData" style="width: 100%;">
<el-table-column prop="question" label="故障原因"></el-table-column>
</el-table>
</div>
</div>
</div>
</template>
<script>
import request from '@/utils/request';
var _this;
export default {
name: "graphExhibition",
data() {
return {
keyword: "",
fileName: "",
questionData: [{question: "问题1", answer: "答案1", index: 1},
{question: "问题1", answer: "答案1", index: 1},
{question: "问题1", answer: "答案1", index: 1},
{question: "问题1", answer: "答案1", index: 1}
],
}
},
mounted() {
_this = this;
},
methods: {
handleFileChange(item) {
this.$refs.upload.clearFiles();
let formData = new FormData();
formData.append("file", item.raw);
_this.fileName = item.raw.name;
// request({
// url: '/sys-file/create',
// method: 'put',
// data: formData
// }).then(res => {
// _this.$message.success("上传成功");
// _this.queryData();
// });
},
}
}
</script>
<style scoped lang="scss">
.upload-btn {
display: inline-block;
margin-left: 20px;
}
.text-box {
border: 1px solid #dcdddf;
width: calc(100% - 40px);
height: 550px;
overflow-y: auto;
margin-top: 40px;
padding: 20px;
line-height: 25px;
font-size: 14px;
color: #333333;
border-radius: 3px;
}
.text-title {
width: calc(100% - 40px);
padding: 20px;
text-align: center;
}
.left-box {
width: 50%;
float: left;
.text-box-item {
width: calc(90% - 1px);
padding-right: 10%;
border-right: 1px solid #c1c2c4;
}
}
.right-box {
width: 50%;
float: right;
.text-box-item {
width: 90%;
padding-left: 10%;
}
}
</style>

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