推荐系统初始化

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

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>

View File

@@ -0,0 +1,326 @@
<template>
<div>
<div class="menu-title">
知识图谱导入
</div>
<div class="menu-content">
<el-tabs v-model="activeName" @tab-click="handleClick">
<el-tab-pane label="本体导入" name="first">
<el-row :gutter="5" style="margin: 20px 0">
<el-col :span="7">
<div>
<label>请选择本体</label>
<el-select v-model="ontologyId" placeholder="请选择本体">
<el-option v-for="item in ontologyList" :key="item.id" :label="item.name" :value="item.id"></el-option>
</el-select>
</div>
</el-col>
<el-col :span="10">
<div>
<label>请选择文件</label>
<el-input v-model="fileName" readonly style="width: 300px;margin-right: 20px" disabled></el-input>
<el-upload
ref="upload" style="display: inline-block"
:auto-upload="false"
action="#" accept=".xls, .xlsx"
:on-change="handleFileChange"
:limit="2"
:show-file-list="false">
<el-button type="primary">上传文件</el-button>
</el-upload>
</div>
</el-col>
<el-col :span="2">
<el-button type="primary" style="float:right;" @click="queryData" :loading="btLoading">执行</el-button>
</el-col>
</el-row>
<div><a :href="path+'武器装备-本体模型.xlsx'" download="武器装备-本体模型.xlsx" style="text-decoration:underline;color: #0D6DFF">下载模板</a></div>
<div class="result" style="width: 100%;margin-top: 20px;color: #5c5c5c;" v-if="showFlag && activeName == 'first'">成功导入</div>
<div style="margin-top: 20px;height:20px;border: 1px solid rgba(0, 0, 0, 0.1);padding: 20px" v-if="showFlag && activeName == 'first'">
<el-descriptions title="" :column="3" >
<el-descriptions-item label="概念数量">{{resultCmd.gncount.toString().replace(/(\d)(?=(?:\d{3})+$)/g,'$1,')}}</el-descriptions-item>
<el-descriptions-item label="对象属性数量">{{resultCmd.gxscount.toString().replace(/(\d)(?=(?:\d{3})+$)/g,'$1,')}}</el-descriptions-item>
<el-descriptions-item label="值属性数量">{{resultCmd.zsxcount.toString().replace(/(\d)(?=(?:\d{3})+$)/g,'$1,')}}</el-descriptions-item>
</el-descriptions>
</div>
</el-tab-pane>
<el-tab-pane label="图谱数据导入" name="second">
<el-row :gutter="5" style="margin: 20px 0">
<el-col :span="7">
<div>
<label>请选择图谱</label>
<el-select v-model="spaceName" placeholder="请选择图谱" style="width: calc(100% - 204px)">
<el-option v-for="item in spaceList" :label="item.comment" :value="item.name"></el-option>
</el-select>
<!--<el-button type="primary" style="margin-left: 20px;" @click="addCmd">新建图谱</el-button>-->
</div>
</el-col>
<el-col :span="10">
<div >
<label>请选择文件</label>
<el-input v-model="fileName" readonly style="margin-right: 20px;width: calc(100% - 204px)" disabled></el-input>
<el-upload
ref="upload" style="display: inline-block"
:auto-upload="false"
action="#" accept=".zip"
:on-change="handleFileChange"
:limit="2"
:show-file-list="false">
<el-button type="primary">上传文件</el-button>
</el-upload>
</div>
<div style="color: red;margin-top: 10px">* zip文件必须包含vertex.jsonedge.json</div>
</el-col>
<el-col :span="2">
<el-button type="primary" style="float:right;" @click="startSpace">执行</el-button>
</el-col>
</el-row>
<div><a :href="path+'图谱数据.zip'" download="图谱数据.zip" style="text-decoration:underline;color: #0D6DFF">下载模板</a></div>
<div class="result" style="width: 100%;margin-top: 20px;color: #5c5c5c;" v-if="showFlag && activeName == 'second'">{{message}}</div>
<div style="margin-top: 20px;" v-if="showFlag && activeName == 'second'">
<el-table :data="resultCmd1" border style="width: 100%" >
<el-table-column prop="title" label="标题"></el-table-column>
<el-table-column prop="gf_name" label="文件名"></el-table-column>
<el-table-column prop="flag" label="状态">
<template slot-scope="scope">
<label :style="{color:scope.row.flag?'#67c23a':'#f56c6c'}">{{scope.row.flag?"成功":"失败"}}</label>
</template>
</el-table-column>
</el-table>
</div>
</el-tab-pane>
</el-tabs>
</div>
<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>
</div>
</template>
<script>
import request,{getFileUrl} from '@/utils/request';
var _this;
export default {
name: "codeWarehouse",
data() {
return {
activeName: 'first',
ontologyId:"",
fileName:"",
file:"",
ontologyList:[],
resultCmd:{
gncount:"",
gxscount:"",
zsxcount:""
},
resultCmd1:{},
showFlag:false,
cmd:{},
cmdDialogVisible:false,
spaceList:[],
active:0,
spaceName:"",
loading:false,
path:getFileUrl(),
message:"",
btLoading:false
}
},
mounted() {
_this = this;
_this.queryOntology();
_this.querySpaceList();
},
methods: {
handleClick(tab, event) {
_this.fileName = "";
_this.file = "";
_this.resultCmd = {};
_this.showFlag = false;
_this.btLoading = false;
},
handleFileChange(file) {
this.$refs.upload.clearFiles();
_this.fileName = file.raw.name;
_this.file = file.raw;
},
queryOntology() {
request({
url: `/ontology/query_list`,
method: 'post',
data: {EQI_sourceType: 1}
}).then(res => {
_this.ontologyList = res.data;
});
},
querySpaceList() {
request({
url: '/nebula_operate/showspace',
method: 'get'
}).then(res => {
_this.spaceList = res.data;
});
},
queryData() {
_this.resultCmd = {};
_this.showFlag = false;
if(!_this.ontologyId){
_this.$message.warning("请选择本体");
return false;
}
if(!_this.file){
_this.$message.warning("请选择文件");
return false;
}
_this.btLoading = true;
_this.$message.info("数据在执行中。。");
let formData = new FormData();
formData.append("file", _this.file);
formData.append("ontologyId", _this.ontologyId);
request({
url: '/nebula_model/importmodel/'+_this.ontologyId,
method: 'post',
data: formData
}).then(res => {
_this.resultCmd = res.data;
_this.showFlag = true;
_this.btLoading = false;
});
},
addCmd(){
_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.querySpaceList();
});
},20000)
});
},
startSpace(){
_this.resultCmd = {};
_this.showFlag = false;
if(!_this.spaceName){
_this.$message.warning("请选择图谱");
return false;
}
if(!_this.file){
_this.$message.warning("请选择文件");
return false;
}
request({
url: '/graph-task/query_list/'+_this.spaceName,
method: 'get',
data: {}
}).then(res => {
if(res.data.length <= 0){
let formData = new FormData();
formData.append("file", _this.file);
request({
url: '/nebula_graph_import/uploadfile/'+_this.spaceName,
method: 'put',
data: formData
}).then(res => {
_this.resultCmd1 = res.data;
var flag = true;
res.data.forEach(item => {
if(!item.flag){
_this.message = "导入失败";
flag = false;
}
})
if(flag){
_this.message = "导入成功";
}
_this.showFlag = true;
});
}else{
_this.$message.warning("该图谱在执行中。。");
}
});
}
}
}
</script>
<style lang="scss">
.upload-btn {
display: inline-block;
margin-left: 20px;
}
</style>

View File

@@ -0,0 +1,429 @@
<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">
<el-table-column type="index" label="行号" width="100"></el-table-column>
<el-table-column prop="space" label="实例名称"></el-table-column>
<el-table-column prop="name" label="任务名称"></el-table-column>
<el-table-column prop="totle" label="文件个数"></el-table-column>
<el-table-column prop="over" label="已导入个数"></el-table-column>
<el-table-column label="操作">
<template slot-scope="scope">
<el-button @click.native.prevent="modifyRow(scope.row)" type="text" size="small">
编辑
</el-button>
<el-button @click.native.prevent="showRow(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="'查看-' + showTaskName"
:visible.sync="showDialogVisible"
width="60%">
<!-- createTime: "2022-08-03 08:19:29"-->
<!-- headerRow: null-->
<!-- id: 1-->
<!-- over: false-->
<!-- originalFilename: "dn_graph_one_tag"-->
<!-- path: "2022-08-03\\64e790821d872af8db27e781b6becc0e.xlsx"-->
<!-- suffix: ".xlsx"-->
<!-- taskId: 4-->
<el-tabs v-model="activeTab">
<el-tab-pane label="未导入" name="first">
<el-table :data="cmd.records" style="width: 100%" ref="fileListTable"
@selection-change="handleSelectionChange" default-expand-all>
<el-table-column type="expand">
<template slot-scope="scope">
<el-form label-position="left" class="demo-table-expand">
<el-form-item label="类型">
<el-select v-model="scope.row.type" @change="val => {handleTypeChange(val, scope.row)}">
<el-option label="TAG" value="TAG"></el-option>
<el-option label="EDGE" value="EDGE"></el-option>
</el-select>
</el-form-item>
<el-form-item label="TAG名称" v-show="scope.row.type == 'TAG'">
<el-select v-model="scope.row.name" placeholder="请选择TAG名称" @change="val => {handleTagNameChange(val, scope.row)}">
<el-option :label="item.Name" :value="item.Name" v-for="item in tagList"
:key="item.Name"></el-option>
</el-select>
</el-form-item>
<el-form-item label="EDGE名称" v-show="scope.row.type == 'EDGE'">
<el-select v-model="scope.row.name" placeholder="请选择EDGE名称" @change="val => {handleEdgeNameChange(val, scope.row)}">
<el-option :label="item.Name" :value="item.Name" v-for="item in edgeList"
:key="item.Name"></el-option>
</el-select>
</el-form-item>
<template v-show="scope.row.name">
<el-form-item :label="field.field" v-for="field in scope.row.fieldList" :key="field.field">
<el-select v-model="field.value" placeholder="请选择TAG名称">
<el-option :label="row" :value="row" v-for="row in scope.row.headerRowList"
:key="row"></el-option>
</el-select>
</el-form-item>
</template>
</el-form>
</template>
</el-table-column>
<el-table-column
type="selection"
width="55">
</el-table-column>
<el-table-column type="index" label="行号" width="80"></el-table-column>
<el-table-column prop="originalFilename" label="源文件名称">
<template slot-scope="scope">{{scope.row.originalFilename}}{{scope.row.suffix}}</template>
</el-table-column>
<el-table-column prop="type" label="类型" ></el-table-column>
<el-table-column prop="typename" label="名称" ></el-table-column>
<!-- <el-table-column prop="path" label="路径" width="450"></el-table-column>-->
<el-table-column prop="createTime" label="创建时间" width="180"></el-table-column>
</el-table>
</el-tab-pane>
<el-tab-pane label="已导入" name="second">
<el-table :data="cmd.records2" style="width: 100%" ref="fileListTable">
<el-table-column type="index" label="行号" width="80"></el-table-column>
<el-table-column prop="originalFilename" label="源文件名称"></el-table-column>
<el-table-column prop="path" label="路径" width="450"></el-table-column>
<el-table-column prop="createTime" label="创建时间" width="180"></el-table-column>
</el-table>
</el-tab-pane>
</el-tabs>
<span slot="footer" class="dialog-footer">
<el-button @click="showDialogVisible = false"> </el-button>
<el-button type="primary" @click="importRow" v-show="activeTab == 'first'"> </el-button>
</span>
</el-dialog>
<el-dialog
title="创建任务"
:visible.sync="createDialogVisible"
width="40%">
<el-form ref="createCmd" label-width="100px" :rules="rules" :model="cmd">
<el-form-item label="实例名称" prop="space">
<el-select v-model="cmd.space" placeholder="请选择实例名称">
<el-option v-for="space in spaceList" :key="space.Name" :label="space.Name" :value="space.Name"></el-option>
</el-select>
</el-form-item>
<el-form-item label="任务名称" prop="name">
<el-input v-model="cmd.name" placeholder="请输入名称"></el-input>
</el-form-item>
<el-form-item label="文件选择" prop="file">
<el-upload
class="upload-demo"
:auto-upload="false"
accept=".xls,.xlsx"
action="#"
:limit="10"
:on-change="handleFileChange"
:file-list="fileList">
<el-button size="small" type="primary">点击上传</el-button>
<div slot="tip" class="el-upload__tip">只能上传xls/xlsx文件</div>
</el-upload>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="createDialogVisible = false"> </el-button>
<el-button type="primary" @click="submitCreate"> </el-button>
</span>
</el-dialog>
<el-dialog
title="编辑"
:visible.sync="cmdDialogVisible"
width="40%">
<el-form ref="cmd" label-width="100px" :rules="rules" :model="cmd">
<el-form-item label="实例名称">
<el-input v-model="cmd.space" disabled></el-input>
</el-form-item>
<el-form-item label="任务名称" prop="name">
<el-input v-model="cmd.name" placeholder="请输入名称"></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/request';
var _this;
export default {
name: "codeWarehouse",
data() {
return {
qo: {
pageNo: 1,
pageSize: 10,
LIKES_name: '',
},
spaceList: [], // 实例列表
result: {
records: [],
total: 0
},
showTaskName: '',
createDialogVisible: false,
cmdDialogVisible: false,
showDialogVisible: false,
cmd: {},
rules: {
name: [
{required: true, message: '请输入任务名称'}
],
space: [
{required: true, message: '请选择实例名称'}
]
},
fileList: [], // 创建任务导入的文件列表
importSelection: [], // 选中的需要执行导入的文件
activeTab: 'first',
tagList: [], // 任务space下的所有tag
edgeList: [], // 任务space下的所有edge
}
},
mounted() {
_this = this;
_this.queryData();
_this.querySpaceList();
},
methods: {
querySpaceList() { // 查询实例列表
request({
url: '/nebula_operate/showspace',
method: 'get',
data: {}
}).then(res => {
_this.spaceList = res.data;
});
},
queryData() {
request({
url: '/graph-task/query_pages',
method: 'post',
data: _this.qo
}).then(res => {
res.data.records.forEach(item => {
item.totle = item.totle || 0;
item.over = item.over || 0;
});
_this.result.records = res.data.records;
_this.result.total = res.data.total;
});
},
handleCurrentChange(val) {
_this.qo.pageNo = val;
_this.queryData();
},
removeRow(item) {
_this.$confirm('此操作将永久删除记录, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
request({
url: `/graph-task/remove/${item.id}`,
method: 'post',
}).then(res => {
_this.$message.success("删除成功");
_this.queryData();
});
}).catch(() => {
});
},
createRow() {
_this.createDialogVisible = true;
_this.$nextTick(() => {
_this.cmd = {
"space": "",
"name": "",
"file": null
};
_this.fileList = [];
_this.$refs.createCmd.resetFields();
});
},
handleFileChange(file, fileList) {
_this.cmd.file = file.raw;
_this.fileList = [fileList.at(-1)];
},
modifyRow(item) {
_this.cmdDialogVisible = true;
_this.$nextTick(() => {
_this.cmd = JSON.parse(JSON.stringify(item));
_this.$refs.cmd.resetFields();
});
},
submitCreate() {
this.$refs.createCmd.validate((valid) => {
if (valid) {
let formData = new FormData();
formData.append("file", _this.cmd.file);
formData.append("name", _this.cmd.name);
request({
url: `/nebula_graph_import/createtask/${_this.cmd.space}`,
method: 'put',
data: formData
}).then(res => {
_this.$message.success("创建成功");
_this.queryData();
_this.createDialogVisible = false;
});
}
});
},
submitModify() {
this.$refs.cmd.validate((valid) => {
if (valid) {
request({
url: '/graph-task/modify',
method: 'post',
data: _this.cmd
}).then(res => {
_this.$message.success("编辑成功");
_this.queryData();
_this.cmdDialogVisible = false;
});
}
});
},
showRow(item) { // 打开查看
_this.showTaskName = item.name;
_this.importSelection = [];
request({
url: `/nebula_graph_import/findtaskbyid/${item.id}`,
method: 'get',
data: _this.cmd
}).then(res => {
let _records = [], _records2 = [];
_this.tagList = res.data.tags;
_this.edgeList = res.data.edges;
res.data.tfs.forEach(row => {
if (row.over) {
_records2.push(row);
} else {
row.headerRowList = JSON.parse(row.headerRow) || [];
row.fieldList = [];
row.type = row.type || "TAG"; // 默认TAG类型
row.name = row.typename || "";
if(row.name && row.type) {
if(row.type === 'TAG') {
_this.handleTagNameChange(row.typename, row);
} else if(row.type === 'EDGE') {
_this.handleEdgeNameChange(row.typename, row);
}
}
_records.push(row);
}
});
_this.cmd = {
records: _records,
records2: _records2
};
_this.showDialogVisible = true;
});
},
handleTypeChange(val, row) {
row.name = "";
row.fieldList = [];
},
handleTagNameChange(val, row) {
row.typename = val;
let index = _this.tagList.findIndex(tag => {
return tag.Name == val;
});
if(index >= 0) {
row.fieldList = _this.resolveFieldList(_this.tagList[index].fields, row.headerRowList);
}
},
handleEdgeNameChange(val, row) {
row.typename = val;
let index = _this.edgeList.findIndex(edge => {
return edge.Name == val;
});
if(index >= 0) {
row.fieldList = _this.resolveFieldList(_this.edgeList[index].fields, row.headerRowList);
}
},
resolveFieldList(fieldList, headerRowList) { // solve fieldList, field.value auto assignment rowHeader's value
fieldList.forEach(field => {
if(headerRowList.indexOf(field.field) >= 0) {
field.value = field.field;
}
});
return fieldList;
},
handleSelectionChange(val) {
_this.importSelection = val;
},
importRow() { // 执行批量导入,导入选择的
if (_this.importSelection.length == 0) {
_this.$message.warning("请选择文件再执行导入!");
return;
}
let cmd = {
taskId: _this.importSelection[0].taskId,
taskFiles: []
};
_this.importSelection.forEach(item => {
let _correspond = {};
item.fieldList.forEach(field => {
_correspond[field.field] = field.value;
});
cmd.taskFiles.push({
taskFileId: item.id,
type: item.type,
name: item.name,
correspond: _correspond
});
});
console.log(cmd);
request({
url: '/nebula_graph_import/graphtaskexecute',
method: 'post',
data: cmd
}).then(res => {
_this.$message.success("导入成功");
_this.queryData();
_this.showDialogVisible = false;
});
}
}
}
</script>
<style lang="scss">
</style>

View File

@@ -0,0 +1,208 @@
<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%">
<el-table-column type="index" label="行号" width="100"></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-column label="操作">
<template slot-scope="scope">
<el-button @click.native.prevent="modifyRow(scope.row)" type="text" size="small">
本体描述
</el-button>
<el-button @click.native.prevent="updateModel(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="name">-->
<!-- <el-select v-model="cmd.sourceType">-->
<!-- <el-option v-for="item in sourceTypeList" :key="item.value" :label="item.name" :value="item.value"></el-option>-->
<!-- </el-select>-->
<!-- </el-form-item>-->
<el-form-item label="本体描述">
<el-input v-model="cmd.description" 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/request';
var _this;
export default {
name: "company",
data() {
return {
qo: {
pageNo: 1,
pageSize: 10,
LIKES_name: '',
EQI_sourceType: 1
},
result: {
records: [],
total: 0
},
sourceTypeList: [
{name: '自定义本体', value: 1},
{name: '标注系统', value: 2}
],
dialogName: '编辑',
cmdDialogVisible: false,
cmd: {},
rules: {
name: [
{required: true, message: '请输入模型名称'}
],
}
}
},
mounted() {
_this = this;
let _pageNo = this.$route.query.pageNo;
let _name = this.$route.query.name;
if (_pageNo) {
_this.qo.pageNo = parseInt(_pageNo);
}
if (_name) {
_this.qo.LIKES_name = _name;
}
_this.queryData();
},
methods: {
queryData() {
request({
url: '/ontology/query_pages',
method: 'post',
data: _this.qo
}).then(res => {
_this.result.records = res.data.records;
_this.result.total = res.data.total;
});
},
handleCurrentChange(val) {
_this.qo.pageNo = val;
_this.queryData();
},
removeRow(item) {
_this.$confirm('此操作将永久删除记录, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
request({
url: '/ontology/remove/' + item.id,
method: 'post'
}).then(res => {
_this.$message.success("删除成功");
_this.queryData();
});
}).catch(() => {
});
},
updateModel(item) {
this.$router.push({
path: "/graphModel_g",
query: {id: item.id, pageNo: _this.qo.pageNo, name: _this.qo.LIKES_name, graphName: item.name}
})
},
createRow() {
_this.cmd = {
name: '',
sourceType: 1,
description: ''
};
_this.dialogName = '新建';
_this.cmdDialogVisible = true;
},
modifyRow(item) {
_this.cmd = JSON.parse(JSON.stringify(item));
_this.dialogName = '编辑';
_this.cmdDialogVisible = true;
},
submitModify() {
this.$refs.cmd.validate((valid) => {
if (valid) {
if (_this.cmd.id) {
request({
url: '/ontology/modify',
method: 'post',
data: _this.cmd
}).then(res => {
_this.$message.success("编辑成功");
_this.queryData();
_this.cmdDialogVisible = false;
});
} else { // 新建
request({
url: '/ontology/create',
method: 'post',
data: _this.cmd
}).then(res => {
_this.$message.success("添加成功");
// _this.queryData();
_this.cmdDialogVisible = false;
_this.updateModel(res.data);
});
}
}
});
},
}
}
</script>
<style lang="scss">
.ca {
color: rgb(51, 51, 51);
}
</style>

View File

@@ -0,0 +1,297 @@
<template>
<div>
<div class="menu-title">
知识图谱推理
</div>
<div class="menu-content">
<el-row :gutter="5" style="padding-bottom: 20px">
<el-col :span="7">
<div>
<label>请选择知识图谱</label>
<el-select v-model="qo.select" placeholder="选择图谱">
<el-option label="装备知识图谱" value="1"></el-option>
</el-select>
</div>
</el-col>
<el-col :span="4">
<div>
<label>请选择文件</label>
<el-upload
ref="upload1" style="display: inline-block"
:auto-upload="false"
action="#"
:on-change="handleFileChange"
:limit="2"
:show-file-list="false">
<el-button type="primary">上传文件</el-button>
</el-upload>
</div>
</el-col>
<el-col :span="13">
<el-button :type="items.length > 0 ?'primary':'info'" style="float:right;" @click="startReason">开始推理</el-button>
</el-col>
</el-row>
<el-row :gutter="5">
<el-col :span="12">
<el-table :data="items" style="width: 100%" height="495" border>
<el-table-column type="index" label="行号" width="70"></el-table-column>
<el-table-column prop="qu" label="问题"></el-table-column>
<el-table-column prop="an" label="正确答案"></el-table-column>
</el-table>
</el-col>
<el-col :span="12">
<div class="path-right-box">
<div id="echart"></div>
<div style="width: calc(100% - 30px);margin: 30px">
<el-table :data="tableData" style="width: 100%;">
<el-table-column prop="tl_len" label="推理路径长度"></el-table-column>
<el-table-column prop="hits1" label="hits@1"></el-table-column>
<el-table-column prop="hits2" label="hits@5"></el-table-column>
<el-table-column prop="hits3" label="hits@10"></el-table-column>
</el-table>
</div>
</div>
</el-col>
</el-row>
<el-descriptions class="margin-top" :column="1" border v-show="predictFlag">
<el-descriptions-item label="问题">
<el-select v-model="activeQuestionIndex" style="width: 100%" @change="handleQuestionSelect">
<el-option v-for="(item,index) in items" :key="index" :value="index" :label="item.qu"></el-option>
</el-select>
</el-descriptions-item>
<el-descriptions-item label="正确答案">
<label v-for="answer in predictAnswers" :key="answer">{{ answer }}</label>
</el-descriptions-item>
<el-descriptions-item label="正确答案排序">
{{ sort }}
</el-descriptions-item>
<el-descriptions-item label="正确答案推理路径" :span="2">
<div class="graph-box">
<graph ref="graph"></graph>
</div>
</el-descriptions-item>
</el-descriptions>
</div>
</div>
</template>
<script>
import request from '@/utils/request';
import graph from "@/components/graph/Graph";
var _this;
var chart = null;
export default {
components: {
'graph': graph,
},
name: "graphPath",
data() {
return {
qo: {
select: "1",
pageNo: 1,
pageSize: 1
},
questions: [],
answers: [],
resultList: [],
items: [],
tableData: [],
predictAnswers: [],
activeQuestionIndex: null,
predictFlag: false,
sort: ''
}
},
mounted() {
_this = this;
},
methods: {
handleFileChange(file) {
this.$refs.upload1.clearFiles();
_this.predictFlag = false;
_this.predictAnswers = [];
_this.sort = '';
_this.items = [];
_this.queryData(file.raw);
},
startReason() {
if(_this.items.length <= 0){
_this.$message.error("显示数据存在问题导致推理失败");
return false;
}
_this.$message.info("开始推理");
setTimeout(() => {
_this.tableData = _this.resultList;
_this.initRchart();
_this.predictFlag = true;
_this.$message.success("推理成功");
}, 1520);
},
handleQuestionSelect(row) {
_this.predictAnswers = [_this.items[_this.activeQuestionIndex].an];
_this.sort = _this.items[_this.activeQuestionIndex].sort;
_this.initGraph();
},
initGraph() {
_this.$nextTick(() => {
let cmd = {
nodes: [],
edges: []
};
_this.items[_this.activeQuestionIndex].model.nodes.forEach(node => {
cmd.nodes.push({
id: node.vid,
label: node.properties.name,
});
});
_this.items[_this.activeQuestionIndex].model.relations.forEach(edge => {
cmd.edges.push({
source: edge.srcId,
target: edge.dstId,
label: edge.edgeName
});
});
_this.$refs['graph'].initGraph(cmd, true, null, true);
});
},
queryData(fileItem) {
let formData = new FormData();
formData.append("file", fileItem);
request({
url: '/indicator/indicator8',
method: 'put',
data: formData
}).then(res => {
let _questions = [];
let _answers = [];
if(res.data && res.data.items){
res.data.items.forEach(item => {
_questions.push({
text: item.qu
});
_answers.push({
text: item.an
});
});
}
_this.questions = _questions;
_this.answers = _answers;
_this.items = res.data && res.data.items ? res.data.items : [];
_this.resultList = res.data && res.data.tj_result ? res.data.tj_result : [];
});
},
initRchart() {
if (chart == null) {
chart = this.$echarts.init(document.getElementById("echart"));
}
let hits1 = [], hits2 = [], hits3 = [];
_this.resultList.forEach(item => {
hits1.push(item.hits1);
hits2.push(item.hits2);
hits3.push(item.hits3);
});
console.log(hits1, hits2, hits3);
var option = {
legend: {},
xAxis: {
type: 'category',
data: ['一跳', '二跳']
},
yAxis: {
type: 'value'
},
series: [
{
name: 'hits@1',
data: hits1,
type: 'bar'
}, {
name: 'hits@5',
type: 'bar',
data: hits2,
}, {
name: 'hits@10',
type: 'bar',
data: hits3,
},
]
};
chart.setOption(option);
}
}
}
</script>
<style scoped lang="scss">
.file-content {
border: 1px solid #dcdddf;
border-radius: 3px;
overflow-y: auto;
margin-top: 20px;
padding: 10px;
line-height: 25px;
font-size: 14px;
color: #333333;
width: calc(100% - 20px);
height: 80px;
}
.path-bottom-box {
height: calc(100% - 95px);
width: 100%;
display: flex;
}
.path-left-box {
width: 50%;
border-right: 1px solid #c1c2c4;
.question-item {
margin: 15px 25px;
line-height: 30px;
font-size: 15px;
color: #333333;
.question-item-div {
display: flex;
padding: 8px 0;
.question-item-title {
width: 80px;
text-align: right;
}
.question-item-answer {
flex: 1;
color: #666666;
}
}
}
}
.path-right-box {
flex: 1;
margin: 30px 0;
height: 100%;
overflow-y: auto;
overflow-x: hidden;
#echart {
height: 350px;
}
}
.graph-box {
flex: 1;
height: 500px;
background: rgba(0, 0, 0, 0.1);
border-radius: 8px;
position: relative;
}
</style>

View File

@@ -0,0 +1,185 @@
<template>
<div>
<div class="menu-title">
辅助维修决策
</div>
<div class="menu-content">
<div class="recommend-content">
<div class="recommend-title">装备维修信息检索主界面</div>
<div class="recommed-tab">
<label :class="active == 0?'tab-active':''" @click="selectTab(0)">信息汇聚</label>
<label :class="active == 1?'tab-active':''" @click="selectTab(1)">知识检索</label>
<label :class="active == 2?'tab-active':''" @click="selectTab(2)">故障定位</label>
<label :class="active == 3?'tab-active':''" @click="selectTab(3)">维修推荐</label>
</div>
<div style="display: flex;width: 100%;margin-bottom: 30px">
<el-input
placeholder="请输入内容"
v-model="keyword" style="flex: 1">
<i slot="prefix" class="el-input__icon el-icon-search"></i>
</el-input>
<el-button type="primary" style="margin-left: 30px">图谱一下</el-button>
</div>
<div v-if="active == 0">
<div class="graph-box">
<graph ref="graph"></graph>
</div>
<div style="margin-top: 15px;text-align: center">信息汇聚子图</div>
</div>
<div v-if="active == 1" class="search-box">
<div class="search-box-item" style="flex: 1"></div>
<div class="search-box-item" style="width: 300px;margin-left: 20px">
{h1,r1,t1}
{h2,r2,t2}
{h3,r3,t3}
</div>
</div>
<div v-if="active == 2">
<div class="graph-table-title">故障定位描述</div>
<div class="graph-table-content">
发动机故障标志亮灯的原因有<br>
1水温曲轴位置空气流量进气温度氧传感器等这些传感器受损接触不良或信号<br>
中断时ECU就不能准确获得发动机的数据此时会引起发动机故障灯亮<br>
2发动机保养不良<br>
3没有按要求添加汽油和机油造成发动机磨损等<br>
根据查询的描
</div>
</div>
<div v-if="active == 3">
<div class="graph-table-title">维修推荐</div>
<div class="graph-table-content">
发动机故障灯亮的维修方法是<br>
1更换氧气传感器2更换三元催化器3紧固或更换油箱盖4更换恒温器5
换点火线圈6更换空气流量传感器7按期保养跟据车辆保养卡的时间周期按期
进行保养发动机的作用是将汽油柴油的热能通过在密封气缸内燃烧后膨胀气体推动
活塞做功转变为机械能发动机的保养方法是1定期更换机油及滤芯2使用合适质
量等级的润滑油3定期清理水箱4定期空气滤清器机油滤清器及汽油滤清器5
保持曲轴箱通风良好定期清洗6定期清洗燃油系统
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import request from '@/utils/request';
import graph from "@/components/graph/Graph";
var _this;
export default {
components: {
'graph': graph,
},
name: "graphRecommend",
data() {
return {
keyword: "",
active: 0
}
},
mounted() {
_this = this;
let cmd = {
path: '/noumenon/query_relation_by_ontologyid',
qo: {
ontologyId: 2
}
};
_this.$refs['graph'].initGraph({
nodes: [
{id: "1", name: "type1", label: "节点1"},
{id: "2", name: "type1", label: "节点2"}
],
edges: [
{source: "1", target: "2", name: "type2", label: "关系1"}
]
}, true);
},
methods: {
selectTab(index) {
_this.active = index;
}
}
}
</script>
<style scoped lang="scss">
.recommend-content {
width: 65%;
margin: 40px auto 0 auto;
.recommend-title {
font-size: 30px;
width: 100%;
text-align: center;
}
.recommed-tab {
margin-top: 50px;
label {
height: 35px;
line-height: 35px;
display: inline-block;
padding: 0px 20px;
margin-right: 10px;
border-left: 1px solid #dcdddf;
border-right: 1px solid #dcdddf;
border-top: 1px solid #dcdddf;
border-top-left-radius: 5px;
border-top-right-radius: 5px;
color: #303133;
cursor: pointer;
}
.tab-active {
color: #ffffff;
border-color: #409eff;
background-color: #409eff;
}
}
.graph-box {
border: 1px solid #dcdddf;
width: 100%;
height: 500px;
background: rgba(0, 0, 0, 0.1);
border-radius: 25px;
}
.search-box {
display: flex;
align-content: space-between;
.search-box-item {
height: 450px;
border: 1px solid #dcdddf;
overflow-y: auto;
padding: 20px;
line-height: 25px;
}
}
.graph-table-title {
width: calc(100% - 42px);
background: rgba(250, 250, 250, 1);
border: 1px solid #dcdddf;
height: 40px;
line-height: 40px;
padding: 0px 20px;
}
.graph-table-content {
border-left: 1px solid #dcdddf;
border-right: 1px solid #dcdddf;
border-bottom: 1px solid #dcdddf;
padding: 20px 20px;
line-height: 25px;
max-height: 450px;
overflow-y: auto;
}
}
</style>

View File

@@ -0,0 +1,279 @@
<template>
<div>
<div class="menu-title">
知识图谱关联
</div>
<div class="menu-content" style="display: inline-block">
<el-row :gutter="5">
<el-col :span="12">
<div>
<label>请选择知识图谱</label>
<el-select v-model="activeSpaceName" placeholder="选择图谱">
<el-option :label="item.name" :value="item.name" v-for="item in spaceList"></el-option>
</el-select>
</div>
</el-col>
<el-col :span="12">
<el-descriptions class="margin-top desc2" :column="2" border>
<el-descriptions-item>
<template slot="label">实体数量</template>
<label>{{ activeSpace.nodes }}</label>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">关系数量</template>
<label>{{ activeSpace.relations }}</label>
</el-descriptions-item>
</el-descriptions>
</el-col>
</el-row>
<el-upload
style="float: right;margin: 15px 0;"
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-table :data="items" border class="text-table" height="300">
<el-table-column type="index" width="50" label="序号"></el-table-column>
<el-table-column prop="text" label="文本"></el-table-column>
<el-table-column prop="el1Str" label="实体" width="200"></el-table-column>
</el-table>
<el-button type="primary" style="float:right;margin: 15px 0;" @click="startPredict">知识图谱关联</el-button>
<el-table :data="tableData" border class="text-table" height="300" @row-click="handleTableDataRowClick">
<el-table-column type="index" width="50" label="序号"></el-table-column>
<el-table-column prop="text" label="文本"></el-table-column>
<el-table-column prop="el1Str" label="实体" width="200"></el-table-column>
<el-table-column prop="el2Str" label="链接结果" width="200"></el-table-column>
</el-table>
<div class="result-label">准确率{{ rate }}</div>
<el-descriptions title="" direction="vertical" :column="2" border id="menuContent">
<el-descriptions-item label="实体链接结果" :span="2">
<div class="result-el2-box">
<el-tag v-for="tag in tags" style="margin-right: 5px;">{{ tag }}</el-tag>
</div>
</el-descriptions-item>
<el-descriptions-item label="模式关联结果" :span="1" labelClassName="handle-des">
<div class="graph-box" id="graph1">
<graph ref="graph"></graph>
</div>
</el-descriptions-item>
<el-descriptions-item label="信息汇聚结果" :span="1" labelClassName="handle-des2">
<div class="graph-box" id="graph2">
<graph ref="graph2"></graph>
</div>
</el-descriptions-item>
</el-descriptions>
</div>
</div>
</template>
<script>
import request from '@/utils/request';
import graph from "@/components/graph/Graph";
var menuContentWidth;
var _this;
export default {
components: {
'graph': graph,
},
name: "graphRelation",
data() {
return {
spaceList: [],
activeSpace: '',
activeSpaceName: '',
items: [],
tableData: [],
tags: [],
rateLabel: '',
rate: '0%'
}
},
mounted() {
_this = this;
_this.queryPrepareData();
menuContentWidth = document.getElementById("menuContent").offsetWidth;
},
methods: {
handleTableDataRowClick(row) {
_this.tags = row.el2;
_this.initGraphData(_this.resolveData(row.model1));
_this.initGraphData2(_this.resolveData(row.model2));
},
queryPrepareData() {
request({
url: '/indicator/indicator7_1',
method: 'get',
data: {}
}).then(res => {
if (res.data.length > 0) {
_this.activeSpace = res.data[0]
_this.activeSpaceName = res.data[0].name;
}
_this.spaceList = res.data;
});
},
handleFileChange(item) {
this.$refs.upload.clearFiles();
_this.uploadFile(item.raw);
},
uploadFile(fileItem) {
let formData = new FormData();
formData.append("file", fileItem);
request({
url: '/indicator/indicator7',
method: 'put',
data: formData
}).then(res => {
res.data.items.forEach(item => {
item.el1Str = item.el1.toString();
item.el2Str = item.el2.toString();
});
_this.items = res.data.items;
_this.rateLabel = res.data.zql;
});
},
startPredict() {
if (_this.items.length == 0) {
_this.$message.warning("请先上传待关联文本数据集");
return false;
}
_this.$message.info("知识图谱关联开始");
setTimeout(() => {
_this.tableData = _this.items;
_this.rate = _this.rateLabel;
_this.$message.success("知识图谱关联成功");
}, 1560);
},
resolveData({nodes, relations}) {
let cmd = {
nodes: [],
edges: []
};
nodes.forEach(node => {
cmd.nodes.push({
id: node.vid,
label: node.properties.name
});
});
relations.forEach(edge => {
cmd.edges.push({
label: edge.edgeName,
source: edge.srcId,
target: edge.dstId,
});
});
return cmd;
},
initGraphData(cmd) {
_this.$nextTick(() => {
document.getElementById("graph1").style.width = menuContentWidth / 2 - 20 + "px";
_this.$refs['graph'].initGraph(cmd, true, null, true);
});
},
initGraphData2(cmd) {
_this.$nextTick(() => {
document.getElementById("graph2").style.width = menuContentWidth / 2 - 20 + "px";
_this.$refs['graph2'].initGraph(cmd, true, null, true);
});
}
}
}
</script>
<style scoped lang="scss">
.result-label {
padding: 15px 0;
text-align: center;
}
.bottom-title {
padding-top: 25px;
text-align: center;
font-weight: bold;
padding-bottom: 10px;
}
.tool-box {
margin-bottom: 20px;
overflow: hidden;
}
.upload-btn {
display: inline-block;
margin-top: 150px;
}
.text-table {
margin-top: 20px;
.el-table th.is-leaf {
border-top: 0;
}
.el-table__header {
th {
background-color: #fafafa;
}
}
}
.text-box {
border: 1px solid #dcdddf;
width: calc(100% - 40px);
height: 350px;
overflow-y: auto;
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%;
}
}
.graph-box {
height: 400px;
background: rgba(0, 0, 0, 0.1);
border-radius: 5px;
position: relative;
margin: 0 auto;
}
</style>

View File

@@ -0,0 +1,243 @@
<template>
<div>
<div class="menu-title">
航发控制装备维修知识补全
</div>
<div class="menu-content">
<el-row :gutter="40" style="border-bottom: 1px solid #c1c2c4;padding-bottom: 40px">
<el-col :span="6">
<div>
<label>请选择模式</label>
<el-select v-model="qo.select" placeholder="选择模式">
<el-option label="评估模式" value="1"></el-option>
<el-option label="应用模式" value="2"></el-option>
</el-select>
</div>
</el-col>
<el-col :span="6">
<div>
<label>请选择知识图谱</label>
<el-select v-model="qo.graph" placeholder="选择知识图谱">
<el-option label="图谱1" value="1"></el-option>
<el-option label="图谱2" value="2"></el-option>
</el-select>
</div>
<div class="file-graph-content" v-if="qo.graph">
</div>
</el-col>
<el-col :span="6" v-if="qo.select == '1'">
<div>
<label>请选择待补全三元组文件</label>
<el-upload
ref="upload" style="display: inline-block"
:auto-upload="false"
action="#"
:on-change="handleFileChange"
:limit="2"
:show-file-list="false">
<el-button type="primary">上传文件</el-button>
</el-upload>
</div>
<div v-if="file">
<el-table :data="ralationData" style="width: 100%;margin-top: 20px;" height="150">
<el-table-column prop="source" label="头实体"></el-table-column>
<el-table-column prop="relation" label="关系"></el-table-column>
<el-table-column prop="target" label="尾实体"></el-table-column>
</el-table>
</div>
</el-col>
<el-col :span="6">
<el-button type="primary">开始链接预测</el-button>
</el-col>
</el-row>
<div class="path-bottom-box">
<div class="path-left-box">
<div style="height: calc(100% - 50px);overflow-y: auto;margin-right: 20px">
<el-table :data="tableData" style="width: 100%;margin-top: 20px;">
<el-table-column prop="len" label="待测试三元组"></el-table-column>
<el-table-column prop="hits@1" label="预测答案"></el-table-column>
<el-table-column prop="hits@5" label="真实答案"></el-table-column>
<el-table-column prop="hits@10" label="真实答案排名"></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>
<div class="path-right-box">
<div id="echart"></div>
<div style="width: calc(100% - 70px);margin: 30px">
<el-table :data="tableData" style="width: 100%;">
<el-table-column prop="len" label="推理路径长度"></el-table-column>
<el-table-column prop="hits@1" label="hits@1"></el-table-column>
<el-table-column prop="hits@5" label="hits@5"></el-table-column>
<el-table-column prop="hits@10" label="hits@10"></el-table-column>
</el-table>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import request from '@/utils/request';
var _this;
export default {
name: "graphShow",
data() {
return {
qo: {
select: "",
graph: "",
pageNo: 1,
pageSize: 10
},
file: "",
result: {
total: 100
},
tableData: [
{len: "1-hop", "hits@1": "hits@1", "hits@5": "hits@5", "hits@10": "hits@10"},
{len: "2-hop", "hits@1": "hits@1", "hits@5": "hits@5", "hits@10": "hits@10"},
{len: "3-hop", "hits@1": "hits@1", "hits@5": "hits@5", "hits@10": "hits@10"},
{len: "4-hop", "hits@1": "hits@1", "hits@5": "hits@5", "hits@10": "hits@10"}
],
ralationData: [
{source: "头实体", relation: "关系", target: "尾实体"},
{source: "头实体", relation: "关系", target: "尾实体"},
{source: "头实体", relation: "关系", target: "尾实体"},
{source: "头实体", relation: "关系", target: "尾实体"},
{source: "头实体", relation: "关系", target: "尾实体"}
]
}
},
mounted() {
_this = this;
_this.initRchart();
},
methods: {
handleFileChange(item) {
this.$refs.upload.clearFiles();
let formData = new FormData();
formData.append("file", item.raw);
_this.file = item.raw.name;
// request({
// url: '/sys-file/create',
// method: 'put',
// data: formData
// }).then(res => {
// _this.$message.success("上传成功");
// _this.queryData();
// });
},
handleCurrentChange(val) {
_this.qo.pageNo = val;
},
initRchart() {
var chart = this.$echarts.init(document.getElementById("echart"));
var option = {
title: {
text: '链接预测Hits@1、Hits@5、Hits@10以及其他占比',
left: 'center'
},
tooltip: {
trigger: 'item'
},
legend: {
top: 'bottom'
},
series: [
{
name: 'Access From',
type: 'pie',
radius: '50%',
data: [
{value: 1048, name: 'Search Engine'},
{value: 735, name: 'Direct'},
{value: 580, name: 'Email'},
{value: 484, name: 'Union Ads'},
{value: 300, name: 'Video Ads'}
],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
};
chart.setOption(option);
}
}
}
</script>
<style scoped lang="scss">
.file-graph-content {
border: 1px solid #dcdddf;
border-radius: 3px;
overflow-y: auto;
margin-top: 20px;
line-height: 25px;
font-size: 14px;
color: #333333;
width: calc(100% - 20px);
height: 150px;
}
.path-bottom-box {
height: calc(100% - 95px);
width: 100%;
display: flex;
}
.path-left-box {
width: 50%;
border-right: 1px solid #c1c2c4;
.question-item {
margin: 15px 10%;
line-height: 30px;
font-size: 15px;
color: #333333;
.question-item-div {
display: flex;
padding: 8px 0;
.question-item-title {
width: 80px;
text-align: right;
}
.question-item-answer {
flex: 1;
color: #666666;
}
}
}
}
.path-right-box {
flex: 1;
margin: 30px 0;
height: 100%;
overflow-y: auto;
overflow-x: hidden;
#echart {
height: 400px;
}
}
</style>

View File

@@ -0,0 +1,264 @@
<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%">
<el-table-column type="index" label="行号" width="100"></el-table-column>
<el-table-column prop="name" label="图谱名称"></el-table-column>
<el-table-column prop="comment" label="图谱描述"></el-table-column>
<el-table-column prop="createTime" label="创建时间"></el-table-column>
<el-table-column label="操作" width="250">
<template slot-scope="scope">
<el-button @click.native.prevent="detailRow(scope.row)" type="text" size="small">
查看图谱
</el-button>
<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>
<el-button @click.native.prevent="importRow(scope.row)" type="text" size="small" v-if="!scope.row.ontologyId">
导入本体
</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" v-if="dialogName == '新建'">
<el-input v-model="cmd.name" placeholder="请输入图谱名称"></el-input>
</el-form-item>
<el-form-item label="图谱名称" prop="name" v-if="dialogName == '编辑'">
<el-input v-model="cmd.name" placeholder="请输入图谱名称" :disabled="true"></el-input>
</el-form-item>
<el-form-item label="图谱描述" prop="comment">
<el-input v-model="cmd.comment" 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>
<el-dialog title="导入本体"
:visible.sync="importDialogVisible"
width="40%">
<el-form ref="cmd" label-width="100px" :rules="rules" :model="cmd">
<el-form-item label="选择本体:" prop="ontologyId">
<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">
<el-button @click="importDialogVisible = false"> </el-button>
<el-button type="primary" @click="submitImport" :loading="loading"> </el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import request from '@/utils/request';
var _this;
export default {
name: "company",
data() {
return {
qo: {
pageNo: 1,
pageSize: 10,
LIKES_name: ''},
result: {
records: [],
total: 0
},
dialogName: '编辑',
cmdDialogVisible: false,
cmd: {},
rules: {
name: [
{required: true, message: '请输入图谱名称'}
],
comment: [
{required: true, message: '请输入图谱描述'}
],
ontologyId: [
{required: true, message: '请选择本体'}
],
},
ontologyList:[],
importDialogVisible:false,
loading:false
}
},
mounted() {
_this = this;
let _pageNo = this.$route.query.pageNo;
let _name = this.$route.query.name;
if (_pageNo) {
_this.qo.pageNo = parseInt(_pageNo);
}
if (_name) {
_this.qo.LIKES_name = _name;
}
_this.queryData();
_this.queryOntology();
},
methods: {
queryData() {
request({
url: '/graph-case/query_pages',
method: 'post',
data: _this.qo
}).then(res => {
_this.result.records = res.data.records;
_this.result.total = res.data.total;
});
},
queryOntology() {
request({
url: `/ontology/query_list`,
method: 'post',
data: {EQI_sourceType: 1}
}).then(res => {
_this.ontologyList = res.data;
});
},
handleCurrentChange(val) {
_this.qo.pageNo = val;
_this.queryData();
},
removeRow(item) {
_this.$confirm('此操作将永久删除记录, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
request({
url: '/graph-case/remove/' + item.id,
method: 'post'
}).then(res => {
_this.$message.success("删除成功");
_this.queryData();
});
}).catch(() => {
});
},
detailRow(item) {
this.$router.push({
path: "/graphSpace_g",
query: {pageNo: _this.qo.pageNo, name: _this.qo.LIKES_name, space: item.name,ontologyId:item.ontologyId,comment:item.comment}
})
},
createRow() {
_this.cmd = {
name: '',
comment: ''
};
_this.dialogName = '新建';
_this.cmdDialogVisible = true;
},
modifyRow(item) {
_this.cmd = JSON.parse(JSON.stringify(item));
_this.dialogName = '编辑';
_this.cmdDialogVisible = true;
},
submitModify() {
this.$refs.cmd.validate((valid) => {
if (valid) {
if (_this.cmd.id) {
request({
url: '/graph-case/modify',
method: 'post',
data: _this.cmd
}).then(res => {
_this.$message.success("编辑成功");
_this.queryData();
_this.cmdDialogVisible = false;
});
} else { // 新建
request({
url: '/graph-case/create',
method: 'post',
data: _this.cmd
}).then(res => {
_this.$message.success("添加成功");
_this.queryData();
_this.cmdDialogVisible = false;
});
}
}
});
},
importRow(item){
_this.cmd = item;
_this.cmd.ontologyId = "";
_this.importDialogVisible = true
},
submitImport(){
this.$refs.cmd.validate((valid) => {
if (valid) {
_this.loading = true;
request({
url: '/graph-case/modify',
method: 'post',
data: _this.cmd
}).then(res => {
request({
url: '/nebula_model/initgraphdatabase/' + _this.cmd.ontologyId + '/' + _this.cmd.name,
method: 'get',
data: {}
}).then(res => {
_this.$message.success("导入本体成功");
_this.loading = false;
_this.importDialogVisible = false;
_this.queryData();
});
});
}
})
}
}
}
</script>
<style lang="scss">
.ca {
color: rgb(51, 51, 51);
}
</style>

View File

@@ -0,0 +1,291 @@
<template>
<!-- 弃用留档20220805功能迁移至/graph/graphSpace.vue -->
<div>
<div class="menu-title">
知识图谱实例管理
</div>
<div class="menu-content">
<div>
<el-form :inline="true" class="demo-form-inline">
<el-form-item label="当前知识图谱实例:">
<el-select v-model="space" @change="querySpaceDescribe">
<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 style="float:right;">
<el-button type="primary" icon="el-icon-back" @click="backToSpaceList">知识图谱实例列表</el-button>
</el-form-item>
</el-form>
</div>
<div class="tab-box">
<el-tabs tab-position="left">
<el-tab-pane label="类">
<div style="margin: 0px 0 20px 0">
<el-button type="primary" @click="createTag()">新建类</el-button>
</div>
<div>
<el-table :data="tagList" 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 label="操作">
<template slot-scope="scope">
<el-button @click.native.prevent="modifyTag(scope.row)" type="text" size="small">
编辑
</el-button>
<el-button @click.native.prevent="removeTag(scope.row)" type="text" size="small">
删除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
</el-tab-pane>
<el-tab-pane label="关系">
<div style="margin: 0px 0 20px 0">
<el-button type="primary" @click="createEdge()">新建关系</el-button>
</div>
<div>
<el-table :data="edgeList" 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 label="操作">
<template slot-scope="scope">
<el-button @click.native.prevent="modifyEdge(scope.row)" type="text" size="small">
编辑
</el-button>
<el-button @click.native.prevent="removeEdge(scope.row)" type="text" size="small">
删除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
</el-tab-pane>
<el-tab-pane label="索引">
<div>
<el-form :inline="true" class="demo-form-inline">
<el-form-item>
<el-select v-model="activeIndexType" placeholder="请选择索引类型" @change="queryIndexList">
<el-option label="TAG" value="TAG"></el-option>
<el-option label="EDGE" value="EDGE"></el-option>
</el-select>
</el-form-item>
</el-form>
</div>
<div style="margin: 0px 0 20px 0">
<el-button type="primary" @click="createIndex()">新建索引</el-button>
</div>
<div>
<el-table :data="indexList" 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="type" label="标签" v-if="activeIndexType == 'TAG'"></el-table-column>
<el-table-column prop="type" label="边类型" v-if="activeIndexType == 'EDGE'"></el-table-column>
<el-table-column prop="columns" label="属性"></el-table-column>
<el-table-column label="操作">
<template slot-scope="scope">
<el-button @click.native.prevent="removeIndex(scope.row)" type="text" size="small">
删除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
</el-tab-pane>
</el-tabs>
</div>
</div>
<tag-modify ref="tagModify"></tag-modify>
<edge-type-modify ref="edgeTypeModify"></edge-type-modify>
<index-add ref="indexAdd"></index-add>
</div>
</template>
<script>
import request from '@/utils/request';
import tagModify from '@/components/dialog/TagModify';
import edgeTypeModify from '@/components/dialog/EdgeTypeModify';
import indexAdd from '@/components/dialog/IndexAdd';
var _this;
export default {
name: "spaceSet",
components: {
'tag-modify': tagModify,
'edge-type-modify': edgeTypeModify,
'index-add': indexAdd
},
data() {
return {
space: '',
spaceList: [],
spaceDescribe: {},
cmd: {},
tagList: [],
addTagDialogVisible: false,
edgeList: [],
activeIndexType: 'TAG',
indexList: [],
}
},
mounted() {
_this = this;
_this.space = this.$route.query.space;
_this.querySpaceList();
_this.querySpaceDescribe();
},
methods: {
backToSpaceList() {
this.$router.push({path: "/graphSpace"})
},
querySpaceList() {
request({
url: '/nebula_operate/showspace',
method: 'get'
}).then(res => {
_this.spaceList = res.data;
});
},
querySpaceDescribe() {
request({
url: `/nebula_operate/descspace/${_this.space}` ,
method: 'get',
data: {}
}).then(res => {
let spaceDescribe = {};
// 处理返回数据
res.data.forEach(row => {
for (let key in row) {
spaceDescribe[key] = row[key];
}
});
_this.spaceDescribe = spaceDescribe;
_this.queryTagList();
_this.queryEdgeList();
_this.queryIndexList();
});
},
queryTagList() {
request({
url: `/nebula_operate/showtag/${_this.space}`,
method: 'get',
data: {}
}).then(res => {
_this.tagList = res.data;
});
},
queryEdgeList() {
request({
url: `/nebula_operate/showedge/${_this.space}`,
method: 'get',
data: {}
}).then(res => {
_this.edgeList = res.data;
});
},
queryIndexList() {
request({
url: `/nebula_operate/showindex/${_this.space}/${_this.activeIndexType}`,
method: 'get',
data: {}
}).then(res => {
let _indexList = [];
for (let i = 0; i < res.data.length / 3; i++) {
let j = i * 3;
_indexList.push({
name: res.data[j]['Index Name'],
type: _this.activeIndexType == 'TAG' ? res.data[j + 1]['By Tag'] : res.data[j + 1]['By Edge'],
columns: JSON.stringify(res.data[j + 2]['Columns']),
});
}
_this.indexList = _indexList;
});
},
createTag() {
_this.$refs['tagModify'].updateValue(_this.space, '', true);
},
modifyTag(item) {
_this.$refs['tagModify'].updateValue(_this.space, item.Name);
},
removeTag(item) {
_this.$confirm('此操作将永久删除记录, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
request({
url: `/nebula_operate/droptag/${_this.space}/${item.Name}`,
method: 'get',
data: {}
}).then(res => {
_this.$message.success("删除成功");
_this.querySpaceList();
});
}).catch(() => {
});
},
createEdge() {
_this.$refs['edgeTypeModify'].updateValue(_this.space, '', true);
},
modifyEdge(item) {
_this.$refs['edgeTypeModify'].updateValue(_this.space, item.Name);
},
removeEdge(item) {
_this.$confirm('此操作将永久删除记录, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
request({
url: `/nebula_operate/dropedge/${_this.space}/${item.Name}`,
method: 'get',
data: {}
}).then(res => {
_this.$message.success("删除成功");
_this.querySpaceList();
});
}).catch(() => {
});
},
createIndex() {
_this.$refs['indexAdd'].showAddIndexDialog(_this.space);
},
removeIndex(item) {
console.log(item);
_this.$confirm('此操作将永久删除记录, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
request({
url: `/nebula_operate/dropindex/${_this.space}`,
method: 'post',
data: {
name: item.Name,
type: _this.activeIndexType
}
}).then(res => {
_this.$message.success("删除成功");
_this.querySpaceList();
});
}).catch(() => {
});
}
}
}
</script>
<style lang="scss">
.tab-box {
margin-top: 20px;
}
.el-tabs--left .el-tabs__header.is-left {
margin-right: 25px;
}
.el-tabs__content {
margin: 0 auto;
}
</style>

View File

@@ -0,0 +1,266 @@
<template>
<div>
<div class="menu-title">
知识图谱融合
</div>
<div class="menu-content">
<el-row :gutter="20">
<el-col :span="8">
<div class="result" style="margin-bottom: 20px">待融合的图谱1</div>
<el-select v-model="sourceGraph.name" placeholder="请选择要融合的知识图谱1" @change="handleSourceGraphChange">
<el-option v-for="item in resultCmd.graphs" :label="item.name" :value="item.name">
</el-option>
</el-select>
<div style="margin-top: 20px;height: 138px;border: 1px solid rgba(0, 0, 0, 0.1);padding: 20px">
<el-descriptions title="" :column="1" v-if="sourceGraph.name">
<el-descriptions-item label="概念数量">{{sourceGraph.gn_count.toString().replace(/(\d)(?=(?:\d{3})+$)/g,'$1,')}}</el-descriptions-item>
<el-descriptions-item label="属性数量">{{sourceGraph.sx_count.toString().replace(/(\d)(?=(?:\d{3})+$)/g,'$1,')}}</el-descriptions-item>
<el-descriptions-item label="实体数量">{{sourceGraph.sl_count.toString().replace(/(\d)(?=(?:\d{3})+$)/g,'$1,')}}</el-descriptions-item>
<el-descriptions-item label="三元组数量">{{sourceGraph.saz_count.toString().replace(/(\d)(?=(?:\d{3})+$)/g,'$1,')}}</el-descriptions-item>
</el-descriptions>
</div>
<div class="result">待融合的图谱2</div>
<el-select v-model="targetGraph.name" placeholder="请选择要融合的知识图谱2"
@change="handleTargetGraphChange" style="margin-top: 25px">
<el-option
v-for="item in resultCmd.graphs"
:label="item.name"
:value="item.name">
</el-option>
</el-select>
<div style="margin-top: 20px;height: 138px;border: 1px solid rgba(0, 0, 0, 0.1);padding: 20px">
<el-descriptions class="margin-top" title="" :column="1" v-if="targetGraph.name">
<el-descriptions-item label="概念数量">{{targetGraph.gn_count.toString().replace(/(\d)(?=(?:\d{3})+$)/g,'$1,')}}</el-descriptions-item>
<el-descriptions-item label="属性数量">{{targetGraph.sx_count.toString().replace(/(\d)(?=(?:\d{3})+$)/g,'$1,')}}</el-descriptions-item>
<el-descriptions-item label="实体数量">{{targetGraph.sl_count.toString().replace(/(\d)(?=(?:\d{3})+$)/g,'$1,')}}</el-descriptions-item>
<el-descriptions-item label="三元组数量">{{targetGraph.saz_count.toString().replace(/(\d)(?=(?:\d{3})+$)/g,'$1,')}}</el-descriptions-item>
</el-descriptions>
</div>
<div style="margin: 0 auto;margin-top: 25px;display: flex;justify-content: center">
<el-button type="primary" @click="fusionData" :loading="loading">开始融合</el-button>
</div>
</el-col>
<el-col :span="16" v-if="showFlag">
<el-row :gutter="50">
<el-col :span="12" >
<div class="result" style="text-align: center;width: 100%;margin-bottom: 20px;color: #5c5c5c;">本体匹配结果展示</div>
<el-table :data="btResults" style="width: 100%" height="350px" @current-change="handleCurrentChange1" highlight-current-row>
<el-table-column prop="srcNode" label="本体1"></el-table-column>
<el-table-column prop="dctNode" label="本体2"></el-table-column>
<el-table-column prop="type" label="类型"></el-table-column>
<el-table-column prop="reliability" label="匹配置信度"></el-table-column>
<el-table-column prop="result" label="匹配结果"></el-table-column>
</el-table>
<div class="page-box">
<el-pagination background
@current-change="handleChange1"
:current-page="qo1.pageNo"
:page-size="qo1.pageSize"
layout="total, prev, pager, next"
:total="resultCmd1.btResults.length">
</el-pagination>
</div>
<div style="display: flex;width: 100%;margin-top: 20px">
<el-button type="primary" size="small" style="flex: 1" @click="clickStr('currentRow1','srcNode')">验证本体1</el-button>
<el-button type="primary" size="small" style="flex: 1" @click="clickStr('currentRow1','dctNode')">验证本体2</el-button>
</div>
<div class="result">本体匹配结果 {{resultCmd1.bfb.bt_result}}</div>
</el-col>
<el-col :span="12">
<div class="result" style="text-align: center;width: 100%;margin-bottom: 20px;color: #5c5c5c;">实例匹配结果展示</div>
<el-table :data="slResults" style="width: 100%" height="350px" @current-change="handleCurrentChange2" highlight-current-row>
<el-table-column prop="srcNode" label="本体1"></el-table-column>
<el-table-column prop="dctNode" label="本体2"></el-table-column>
<el-table-column prop="type" label="类型"></el-table-column>
<el-table-column prop="reliability" label="匹配置信度"></el-table-column>
<el-table-column prop="result" label="匹配结果"></el-table-column>
</el-table>
<div class="page-box">
<el-pagination background
@current-change="handleChange2"
:current-page="qo2.pageNo"
:page-size="qo2.pageSize"
layout="total, prev, pager, next"
:total="resultCmd1.slResults.length">
</el-pagination>
</div>
<div style="display: flex;width: 100%;margin-top: 20px">
<el-button type="primary" size="small" style="flex: 1" @click="clickStr('currentRow2','srcNode')">验证本体1</el-button>
<el-button type="primary" size="small" style="flex: 1" @click="clickStr('currentRow2','dctNode')">验证本体2</el-button>
</div>
<div class="result">实例匹配结果 {{resultCmd1.bfb.sl_result}}</div>
</el-col>
</el-row>
<div class="result" style="text-align: center;width: 100%;margin-top: 20px;color: #5c5c5c;">融合后知识图谱统计信息</div>
<div style="margin-top: 20px;height:20px;border: 1px solid rgba(0, 0, 0, 0.1);padding: 20px">
<el-descriptions title="" :column="4">
<el-descriptions-item label="概念数量">{{resultCmd1.rhGraph.gn_count.toString().replace(/(\d)(?=(?:\d{3})+$)/g,'$1,')}}</el-descriptions-item>
<el-descriptions-item label="属性数量">{{resultCmd1.rhGraph.sx_count.toString().replace(/(\d)(?=(?:\d{3})+$)/g,'$1,')}}</el-descriptions-item>
<el-descriptions-item label="实体数量">{{resultCmd1.rhGraph.sl_count.toString().replace(/(\d)(?=(?:\d{3})+$)/g,'$1,')}}</el-descriptions-item>
<el-descriptions-item label="三元组数量">{{resultCmd1.rhGraph.saz_count.toString().replace(/(\d)(?=(?:\d{3})+$)/g,'$1,')}}</el-descriptions-item>
</el-descriptions>
</div>
</el-col>
</el-row>
</div>
</div>
</template>
<script>
import request from '@/utils/request';
var _this;
export default {
name: "knowledgeFusion",
data() {
return {
sourceGraph: {
"name": "",
"gn_count": "",
"sx_count": "",
"sl_count": "",
"saz_count": ""
},
targetGraph: {
"name": "",
"gn_count": "",
"sx_count": "",
"sl_count": "",
"saz_count": ""
},
resultCmd: {},
resultCmd1: {
bfb:{
bt_result:"",
sl_result:""
},
rhGraph: {
"gn_count": "",
"sx_count": "",
"sl_count": "",
"saz_count": ""
},
btResults:[],
slResults:[]
},
currentRow1:{},
currentRow2:{},
qo1:{
pageNo:1,
pageSize:10
},
qo2:{
pageNo:1,
pageSize:10
},
btResults:[],
slResults:[],
showFlag: false,
loading:false
}
},
mounted() {
_this = this;
_this.queryData();
},
methods: {
handleSourceGraphChange() {
_this.resultCmd.graphs.forEach(item => {
if(item.name == _this.sourceGraph.name){
_this.sourceGraph = JSON.parse(JSON.stringify(item))
}
})
console.log(_this.resultCmd.graphs)
},
handleTargetGraphChange() {
_this.resultCmd.graphs.forEach(item => {
if(item.name == _this.targetGraph.name){
_this.targetGraph = JSON.parse(JSON.stringify(item))
}
})
},
handleChange1(val) {
_this.qo1.pageNo = val;
_this.btResults = _this.resultCmd1.btResults.slice((_this.qo1.pageNo - 1) * 10, _this.qo1.pageNo * 10);
},
handleChange2(val) {
_this.qo2.pageNo = val;
_this.slResults = _this.resultCmd1.slResults.slice((_this.qo2.pageNo - 1) * 10, _this.qo2.pageNo * 10);
},
fusionData(){
if(_this.targetGraph.name == _this.sourceGraph.name){
_this.$message.warning("待融合图谱1和待融合图谱2不可相同");
return false;
}
_this.queryResult();
},
queryData() {
request({
url: '/indicator/indicator4/1',
method: 'get',
}).then(res => {
_this.resultCmd = res.data;
if(_this.resultCmd.graphs.length >= 2){
_this.sourceGraph = JSON.parse(JSON.stringify(_this.resultCmd.graphs[0]))
_this.targetGraph = JSON.parse(JSON.stringify(_this.resultCmd.graphs[1]))
}
});
},
queryResult() {
_this.loading = true
request({
url: '/indicator/indicator4/2',
method: 'get',
}).then(res => {
_this.loading = false
_this.resultCmd1 = res.data;
_this.$nextTick(()=>{
_this.showFlag = true;
_this.handleChange1(1);
_this.handleChange2(1);
})
});
},
handleCurrentChange1(val) {
this.currentRow1 = val;
},
handleCurrentChange2(val) {
this.currentRow2 = val;
},
clickStr(name,value){
if(!this[name][value]){
_this.$message.warning("请选中行");
return false;
}
var srcNode = this[name][value];
if(srcNode.substring(0,1) == '<'){
srcNode = srcNode.substring(1)
}
if(srcNode.substring(srcNode.length-3) == '> .'){
srcNode = srcNode.substring(0,srcNode.length-3)
}
if(srcNode.substring(srcNode.length-1) == '>'){
srcNode = srcNode.substring(0,srcNode.length-1)
}
window.open(srcNode, "_blank")
}
}
}
</script>
<style scoped lang="scss">
.result {
text-align: center;
margin-top: 25px;
font-size: 16px;
color: #5c5c5c;
}
</style>

View File

@@ -0,0 +1,216 @@
<template>
<div>
<div class="menu-title">
知识检索和问答
</div>
<div class="menu-content" style="display: inline-block;display: flex">
<div style="width:30%;min-width:500px;">
<div>
<el-form :inline="true" :model="qo" class="demo-form-inline">
<el-form-item label="">
<el-select v-model="value" style="width: 300px" placeholder="选择图谱名">
<el-option
v-for="item in options"
:key="item.name"
:label="item.name"
:value="item.name">
</el-option>
</el-select>
</el-form-item>
<!-- <el-form-item>-->
<!-- <el-button type="primary" style="margin-left: 14px">选择图谱</el-button>-->
<!-- </el-form-item>-->
</el-form>
</div>
<div >
<el-input v-model="fileName" readonly style="width: 300px" disabled></el-input>
<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>
</div>
<div>
<el-button type="primary" style="margin-left: 150px;margin-top: 100px" @click="queryData()">开始测试</el-button>
</div>
<br><br>
<!--<el-input v-model="resultStr" readonly style="width: 80%" disabled></el-input>-->
<div v-if="resultStr">{{resultStr}}</div>
<!-- <div class="right-box" style="padding-left: 5%;width: 45%">-->
<!-- <el-input v-model="keyword" placeholder="检索或问答内容" style="width: 300px"></el-input>-->
<!-- <el-button type="primary" style="margin-left: 20px">开始检索</el-button>-->
<!-- </div>-->
</div>
<div style="width:70%;height: calc(100% - 80px)">
<div class="left-box" style="width: 100%">
<div style="width: 96%;">
<el-table :data="questions" style="width: 100%;" @row-click="handleTableRowClick">
<el-table-column prop="qu" label="问题"></el-table-column>
<el-table-column prop="hxan" label="知识检索或问答结果Top-5">
<template slot-scope="scope">
<!-- {{scope.row.hxan}}-->
<p v-for="items in scope.row.hxan" :style=" items == scope.row.an ? 'color: red' : ''">{{items}}</p>
</template>
</el-table-column>
<el-table-column prop="an" label="正确答案"></el-table-column>
<el-table-column prop="loc" label="正确答案位置序号"></el-table-column>
</el-table>
<div class="page-box">
<el-pagination background
@current-change="handleCurrentChange"
:current-page="qo.pageNo"
:page-size="qo.pageSize"
layout="total, prev, pager, next"
:total="questionsAll.length">
</el-pagination>
</div>
</div>
</div>
<!-- <div class="right-box">-->
<!-- <div style="width: 90%;margin-left: 10%">-->
<!-- <el-table :data="answerData" style="width: 100%;">-->
<!-- <el-table-column prop="result" label="检索结果">-->
<!-- <template slot-scope="scope">-->
<!-- <label :style=" scope.row.result == activeRow.qa.Answer ? 'color: red' : ''">{{ scope.row.result }}</label>-->
<!-- </template>-->
<!-- </el-table-column>-->
<!-- </el-table>-->
<!-- </div>-->
<!-- </div>-->
</div>
</div>
</div>
</template>
<script>
import request from '@/utils/request';
var _this;
export default {
name: "graphQuestion",
data() {
return {
options: [
{name: "装备知识图谱"},
],
value: '',
keyword: "",
fileName: "",
resultStr: "",
qo: {
pageNo: 1,
pageSize: 10
},
file:"",
questionsAll: [],
questions: [],
answerData: [],
activeRow: {
qa: {
}
}
}
},
mounted() {
_this = this;
},
methods: {
handleFileChange(file) {
this.$refs.upload.clearFiles();
_this.fileName = file.raw.name;
_this.file = file.raw;
},
handleCurrentChange(val) {
_this.qo.pageNo = val;
_this.questions = _this.questionsAll.slice((_this.qo.pageNo - 1) * 10, _this.qo.pageNo * 10);
},
handleTableRowClick(row, column, event) {
let _answerData = [];
row.entity.forEach(item => {
_answerData.push({
result: item
});
});
_this.activeRow = row;
_this.answerData = _answerData;
},
queryData() {
let formData = new FormData();
formData.append("file", _this.file);
request({
url: '/indicator/indicator9/dn_graph_one',
method: 'put',
data: formData
}).then(res => {
var trueTotal = 0;
res.data.items.map(data1 => {
data1.hxan = JSON.parse(data1.hxan);
if(data1.hxan.indexOf(data1.an) != -1){
trueTotal ++;
}
})
_this.resultStr = "知识检索或问答结果 Top-5 准确率:" + res.data.zql.toFixed(2) + "%,正确条数:"+trueTotal+",总条数:"+res.data.items.length;
_this.questionsAll = res.data.items;
_this.handleCurrentChange(1);
});
},
}
}
</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>

View File

@@ -0,0 +1,567 @@
<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="algorithmId" label="算法名称" :formatter="algorithmIdFormatter"></el-table-column>
<!-- <el-table-column prop="version" label="版本"></el-table-column> -->
<el-table-column prop="status" label="训练状态" :formatter="statusFormatter"></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="220">
<template slot-scope="scope">
<el-button @click.native.prevent="trainRow(scope.row)" type="text" size="small" v-if="scope.row.status != 8">
训练
</el-button>
<el-button type="text" size="small" v-if="scope.row.status == 8" style="color: #ccc;cursor: default" title="训练中">
训练
</el-button>
<el-button @click.native.prevent="modifyRow(scope.row)" type="text" size="small" v-if="scope.row.status == 1">
编辑
</el-button>
<el-button @click.native.prevent="removeRow(scope.row)" type="text" size="small" >
删除
</el-button>
<br>
<el-button @click.native.prevent="showLogDialog(scope.row)" type="text" size="small" v-if="scope.row.status == 8 || scope.row.status == 9">
日志
</el-button>
<el-button @click.native.prevent="updateStatus(scope.row, 'stop')" type="text" size="small" v-if="scope.row.status == 8">
停止
</el-button>
<!-- <el-button @click.native.prevent="updateStatus(scope.row, 'start')" type="text" size="small">
重启
</el-button> -->
<el-button @click.native.prevent="publishService(scope.row)" type="text" size="small" v-if="scope.row.status == 9">
发布服务
</el-button>
<el-button @click.native.prevent="testRow(scope.row)" type="text" size="small" v-if="scope.row.status == 9">
测试
</el-button>
<!-- <template v-show="scope.row.status == 0">
</template> -->
</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="algorithmId">
<el-select v-model="cmd.algorithmId" placeholder="请选择算法">
<el-option :label="item.name" :value="item.id" :key="item.id" v-for="item in algorithmList"></el-option>
</el-select>
</el-form-item>
<!-- <el-form-item label="数据集" prop="name">-->
<!-- <el-select v-model="cmd.name" placeholder="请选择数据集">-->
<!-- <el-option label="" value=""></el-option>-->
<!-- </el-select>-->
<!-- </el-form-item>-->
<el-form-item label="描述">
<el-input v-model="cmd.modelRemark" 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>
<el-dialog
title="训练模型"
:visible.sync="trainCmdDialogVisible"
width="75%">
<el-form ref="cmd" label-width="120px" :rules="rules" :model="cmd" v-loading="trainLoading" element-loading-text="程序启动中" :inline="true">
<div class="title-form-box">公共配置</div>
<el-form-item :label="item.name" v-for="item in cmd.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 cmd.privatePropert" :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="指定显卡" prop="gpuId">
<el-select v-model="cmd.gpuId" placeholder="请选择显卡">
<el-option :label="item.name" :value="item.id" :key="item.id" v-for="item in cmd.gpuInfoList"></el-option>
</el-select>
</el-form-item>
<el-form-item label="数据集" prop="dataSetId1">
<el-select v-model="cmd.dataSetId1" placeholder="请选择数据集">
<el-option :label="item.name" :value="item.id" :key="item.id" v-for="item in dataSetList"></el-option>
</el-select>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="trainCmdDialogVisible = false"> </el-button>
<el-button type="primary" :disabled="trainLoading" @click="submitTrain"> </el-button>
</span>
</el-dialog>
<el-dialog
title="发布服务"
:visible.sync="serverCmdDialogVisible"
width="75%">
<el-form ref="cmd" label-width="120px" :rules="rules" :model="cmd">
<el-form-item :label="item.name" v-for="item in cmd.privatePropert" :key="item.key">
<el-input v-model="item.value" :placeholder="'请输入' + item.name" ></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="serverCmdDialogVisible = false"> </el-button>
<el-button type="primary" @click="submitPublishService"> </el-button>
</span>
</el-dialog>
<el-dialog
title="测试"
:visible.sync="testCmdDialogVisible"
destroy-on-close
@close="handleTestDialogClose"
width="40%">
<el-form ref="cmd" label-width="100px" :rules="rules" :model="cmd" v-loading="testLoading">
<el-form-item label="测试类型" prop="testType">
<el-select v-model="cmd.testType" placeholder="请选择测试类型">
<el-option label="单文本测试" value="text"></el-option>
<el-option label="数据集测试" value="database"></el-option>
</el-select>
</el-form-item>
<el-form-item label="单文本测试" prop="text" v-if="cmd.testType == 'text'">
<el-input v-model="cmd.text" placeholder="请输入所要测试的单文本"></el-input>
</el-form-item>
<el-form-item label="数据集测试" prop="dataSetId" v-if="cmd.testType == 'database'">
<el-select v-model="cmd.dataSetId" placeholder="请选择数据集">
<el-option :label="item.name" :value="item.id" :key="item.id" v-for="item in dataSetList"></el-option>
</el-select>
</el-form-item>
<div class="log-title-box">服务日志</div>
<log ref="log-item2" v-if="testSuccess"></log>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="testCmdDialogVisible = false"> </el-button>
<el-button type="primary" @click="submitTest" :disabled="testLoading">开始测试</el-button>
</span>
</el-dialog>
<el-dialog
title="日志"
:visible.sync="logDialogVisible"
destroy-on-close
@close="handleLogDialogClose"
width="60%">
<log ref="log-item"></log>
</el-dialog>
</div>
</template>
<script>
import request from '@/utils/request2';
import request1, {getBaseUrl} from '@/utils/request';
import log from '@/components/log/index';
var _this;
export default {
name: "modelManage",
components: {
log
},
data() {
return {
qo: {
pageNo: 1,
pageSize: 10,
LIKES_name: '',
},
result: {
records: [],
total: 0
},
algorithmList: [],
dialogName: '编辑',
cmdDialogVisible: false,
trainCmdDialogVisible: false,
serverCmdDialogVisible: false,
cmd: {
dataSetId: '',
dataSetId1: ''
},
testSuccess: false,
testLoading: false,
rules: {
name: [
{required: true, message: '请输入模型名称'}
],
algorithmId: [
{required: true, message: '请选择算法'}
],
gpuId: [
{required: true, message: '请选择显卡'}
],
testType: [
{required: true, message: '请选择测试类型'}
],
text: [
{required: true, message: '请输入所要测试的单文本'}
],
dataSetId: [
{required: true, message: '请选择数据集'}
],
dataSetId1: [
{required: true, message: '请选择数据集'}
],
},
testCmdDialogVisible: false,
dataSetList: [],
logDialogVisible: false,
statusList: {
1: '保存状态',
2: '开始',
3: '运行中',
4: '等待中',
5: '结束',
6: '发布失败',
7: '取消',
8: '训练中',
9: '训练完成'
},
trainLoading: false,
modelId: ''
}
},
mounted() {
_this = this;
_this.queryData();
_this.queryAlgorithmList();
_this.queryDataSetList();
},
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: {
algorithmIdFormatter(row) {
let index = _this.algorithmList.findIndex(dataSet => {
return row.algorithmId == dataSet.id;
});
return index >= 0 ? _this.algorithmList[index].name : '-';
},
statusFormatter(row) {
return _this.statusList[row.status] || '-';
},
queryDataSetList() {
request1({
url: '/remark_task/query_list',
method: 'post',
data: {}
}).then(res => {
_this.dataSetList = res.data;
});
},
showLogDialog(row) {
_this.logDialogVisible = true;
_this.$nextTick(() => {
_this.$refs['log-item'].init({modelId: row.id, type: 'log_train'});
});
},
handleLogDialogClose() {
_this.$refs['log-item'].close();
},
handleTestDialogClose() {
_this.$refs['log-item2'].close();
},
queryAlgorithmList() {
request({
url: '/algorithm/list',
method: 'post',
data: {pageNo: 1, pageSize: 1000}
}).then(res => {
_this.algorithmList = res.list;
});
},
queryData() {
request({
url: '/model/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(() => {
request({
url: '/model/remove',
method: 'post',
data: {
id: item.id,
}
}).then(res => {
_this.$message.success("删除成功");
_this.queryData();
});
}).catch(() => {
});
},
createRow() {
_this.cmdDialogVisible = true;
_this.$nextTick(() => {
_this.dialogName = "新增";
_this.cmd = {
name: '',
algorithmId: '',
modelRemark: ''
};
_this.$refs.cmd.resetFields();
});
},
trainRow(item) {
let id = item.id;
request({
url: `/model/editTrainParameter/${id}`,
method: 'post',
}).then(res => {
_this.cmd = res.data;
_this.cmd.dataSetId = "";
_this.trainLoading = false;
_this.trainCmdDialogVisible = true;
});
},
testRow(item) {
_this.testSuccess = false;
_this.testCmdDialogVisible = true;
_this.$nextTick(() => {
_this.cmd = {
testType: '',
text: '',
dataSetId: '',
modelId: item.id
};
_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) {
request({
url: '/model/save',
method: 'post',
data: _this.cmd
}).then(res => {
_this.$message.success("新增成功");
_this.queryData();
_this.cmdDialogVisible = false;
});
}
});
},
submitTrain() { // 提交训练
if(_this.trainLoading) {
return
}
this.$refs.cmd.validate((valid) => {
if (valid) {
_this.trainLoading = true;
_this.cmd.dataSetUrl = getBaseUrl() + "/es_remark_task/findbytaskidandtasktypeall/" + _this.cmd.dataSetId1 + "/";
request({
url: '/model/startTrain',
method: 'post',
data: _this.cmd
}).then(res => {
_this.$message.success("训练成功");
_this.trainLoading = false;
_this.queryData();
_this.trainCmdDialogVisible = false;
});
}
});
},
submitTest() { // 提交测试
this.$refs.cmd.validate((valid) => {
if (valid) {
_this.testLoading = true;
if (_this.cmd.testType == 'text') {
request({
url: '/model/singleTextTest',
method: 'post',
data: _this.cmd
}).then(res => {
_this.$message.success("测试成功");
_this.testSuccess = true;
_this.$nextTick(() => {
_this.$refs['log-item2'].init({modelId: _this.cmd.modelId, type: 'test_single'});
_this.testLoading = false;
});
});
} else if (_this.cmd.testType == 'database') {
let _cmd = JSON.parse(JSON.stringify(_this.cmd))
_cmd.dataSetId = getBaseUrl() + "/es_remark_task/findbytaskidandtasktypeall/" + _cmd.dataSetId + "/";
console.log(_cmd);
request({
url: '/model/dataSetTest',
method: 'post',
data: _cmd
}).then(res => {
_this.$message.success("测试成功");
_this.testSuccess = true;
_this.$nextTick(() => {
_this.$refs['log-item2'].init({modelId: _this.cmd.modelId, type: 'log_test'});
_this.testLoading = false;
});
});
}
}
});
},
updateStatus(item, action) { // 修改状态重启start停止stop
let text = action === 'start' ? '重启' : '停止';
_this.$confirm(`此操作将执行${text}操作, 是否继续?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
request({
url: '/model/update/status',
method: 'post',
data: {
modelId: item.id,
action: action
}
}).then(res => {
_this.$message.success(`${text}成功`);
_this.queryData();
});
}).catch(() => {
});
},
publishService(item) { // 发布服务
let id = item.id;
_this.modelId = id;
request({
url: `/model/getServerPropert/${id}`,
method: 'post',
}).then(res => {
_this.cmd.privatePropert = res.data;
_this.serverCmdDialogVisible = true;
});
},
submitPublishService(item) { // 发布服务
const loading = this.$loading({
lock: true,
text: '服务发布中',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
});
request({
url: '/model/publishService',
method: 'post',
data: {
modelId: _this.modelId,
serverPropert: _this.cmd.privatePropert
}
}).then(res => {
_this.$message.success(`发布成功`);
loading.close();
_this.serverCmdDialogVisible = false;
_this.queryData();
});
}
}
}
</script>
<style lang="scss">
.log-title-box {
font-size: 16px;
font-weight: 600;
margin-bottom: 10px;
}
.log-box {
background-color: #c2c2c2;
border-radius: 3px;
min-height: 300px;
}
.title-form-box {
font-weight: bold;
font-size: 16px;
padding-left: 5px;
margin-bottom: 25px;
}
</style>

View File

@@ -0,0 +1,284 @@
<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 label="节点地址">
<template slot-scope="scope">
{{ scope.row.host }}:{{ scope.row.port }}
</template>
</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="操作">
<template slot-scope="scope">
<el-button @click.native.prevent="showXtermDialog(scope.row)" type="text" size="small">
终端
</el-button>
<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="节点IP" prop="host">
<el-input v-model="cmd.host" placeholder="请输入节点IP"></el-input>
</el-form-item>
<el-form-item label="节点端口" prop="port">
<el-input v-model="cmd.port" placeholder="请输入节点端口"></el-input>
</el-form-item>
<el-form-item label="SSH账号" prop="user">
<el-input v-model="cmd.user" placeholder="请输入SSH账号"></el-input>
</el-form-item>
<el-form-item label="SSH密码" prop="password">
<el-input v-model="cmd.password" placeholder="请输入SSH密码"></el-input>
</el-form-item>
<!-- <el-form-item label="Host密码" prop="name">-->
<!-- <el-input v-model="cmd.name" placeholder="请输入Host密码"></el-input>-->
<!-- </el-form-item>-->
<el-form-item label="数据目录" prop="dataPath">
<el-input v-model="cmd.dataPath" placeholder="请输入数据目录"></el-input>
</el-form-item>
<!-- <el-form-item label="超时时间">-->
<!-- <el-date-picker-->
<!-- v-model="cmd.time"-->
<!-- type="datetime"-->
<!-- placeholder="请选择超时时间">-->
<!-- </el-date-picker>-->
<!-- </el-form-item>-->
<!-- <el-form-item label="描述">-->
<!-- <el-input v-model="cmd.description" 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>
<el-dialog
title="终端"
:visible.sync="xtermDialogVisible"
destroy-on-close
@close="handleXtermDialogClose"
width="60%">
<xterm ref="xterm-item"></xterm>
</el-dialog>
</div>
</template>
<script>
import request from '@/utils/request2';
import xterm from '@/components/xterm/index';
var _this;
export default {
name: "codeWarehouse",
components: {
xterm
},
data() {
return {
qo: {
pageNo: 1,
pageSize: 10,
LIKES_name: '',
},
result: {
records: [],
total: 0
},
dialogName: '编辑',
cmdDialogVisible: false,
cmd: {},
rules: {
name: [
{required: true, message: '请输入节点名称'}
],
host: [
{required: true, message: '请输入节点IP'}
],
port: [
{required: true, message: '请输入节点端口'}
],
user: [
{required: true, message: '请输入SSH账号'}
],
password: [
{required: true, message: '请输入SSH密码'}
],
},
xtermDialogVisible: false,
}
},
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: '/server/node/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: `/server/node/delete/${id}`,
method: 'post',
}).then(res => {
_this.$message.success("删除成功");
_this.queryData();
});
}).catch(() => {
});
},
createRow() {
_this.cmdDialogVisible = true;
_this.$nextTick(() => {
_this.dialogName = "新增";
_this.cmd = {
"charset": "",
"dataPath": "",
"fileDirs": "",
"host": "",
"name": "",
"notAllowedCommand": "",
"password": "",
"port": "",
"user": ""
};
_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();
});
},
showXtermDialog(row) {
_this.xtermDialogVisible = true;
_this.$nextTick(() => {
_this.$refs['xterm-item'].init(row.id);
});
},
handleXtermDialogClose() {
_this.$refs['xterm-item'].close();
},
submitModify() {
this.$refs.cmd.validate((valid) => {
if (valid) {
if (_this.cmd.id) {
request({
url: '/server/node/update',
method: 'post',
data: _this.cmd
}).then(res => {
_this.$message.success("编辑成功");
_this.queryData();
_this.cmdDialogVisible = false;
});
} else { // 新建
request({
url: '/server/node/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,385 @@
<template>
<div>
<div class="menu-title">
装备维修本体构建
</div>
<div class="menu-content">
<el-row :gutter="20">
<el-col :span="15">
<el-descriptions class="margin-top" title="本体信息统计" :column="2" border style="position: relative">
<template slot="extra">
<el-select v-model="ontologyId" placeholder="请选择图谱" @change="handleSelectChange"
style="position: absolute;left:120px;top:-10px;">
<el-option
v-for="item in ontologyList"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
</template>
<el-descriptions-item>
<template slot="label">本体名称</template>
<label>{{ ontology.name }}</label>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">概念数量</template>
<label>{{ ontologyCount.conceptc }}</label>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">本体版本</template>
<label>1.0</label>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">对象属性数量</template>
<label>{{ newNum.relationc }}</label>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">本体描述</template>
<label>构建了关于{{ontology.name}}的本体包括{{ontologyCount.conceptc}}个概念和{{newNum.fieldc+newNum.relationc}}个属性</label>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">值属性数量</template>
<label>{{ newNum.fieldc }}</label>
</el-descriptions-item>
</el-descriptions>
<div class="graph-box1">
<graph ref="graph"></graph>
</div>
</el-col>
<el-col :span="9">
<el-descriptions class="margin-top desc2" title="本体元素浏览" :column="2" border>
</el-descriptions>
<el-tabs type="border-card">
<el-tab-pane label="概念">
<div class="tree-box">
<el-tree :data="treeData" :props="defaultProps"
@node-click="handlePopShow"
:expand-on-click-node="false">
</el-tree>
</div>
</el-tab-pane>
<el-tab-pane label="对象属性">
<el-table :data="edgeData" style="width: 100%" class="right-table">
<el-table-column type="index" label="行号" width="80"></el-table-column>
<el-table-column prop="relation" label="属性名"></el-table-column>
<el-table-column prop="srccount" label="起点概念数量"></el-table-column>
<el-table-column prop="dstcount" label="终点概念数量"></el-table-column>
</el-table>
</el-tab-pane>
<el-tab-pane label="值属性">
<el-table :data="valueData" style="width: 100%" class="right-table">
<el-table-column type="index" label="行号" width="80"></el-table-column>
<el-table-column prop="comment" label="属性名"></el-table-column>
<el-table-column prop="count" label="所属概念数量"></el-table-column>
<el-table-column prop="type" label="值类型"></el-table-column>
</el-table>
</el-tab-pane>
</el-tabs>
</el-col>
</el-row>
</div>
<el-dialog
title="提示"
:visible.sync="dialogVisible"
@close="handlePopHide"
width="400">
<el-descriptions class="margin-top" :column="2" border style="margin-bottom: 15px">
<el-descriptions-item label="概念名">{{ infoCmd.tagName }}</el-descriptions-item>
<el-descriptions-item label="概念描述">{{ infoCmd.label }}</el-descriptions-item>
<el-descriptions-item label="次级概念数量">{{ edgeFieldCount }}</el-descriptions-item>
<el-descriptions-item label="值属性数量">{{ fieldCount.length }}</el-descriptions-item>
</el-descriptions>
<el-table
:data="fieldCount"
height="300"
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>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"> </el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import request from '@/utils/request';
import {listToTree} from '@/utils/common';
import graph from "@/components/graph/Graph";
var _ = require('lodash');
var _this;
export default {
components: {
'graph': graph,
},
name: "noumenonModelImport",
data() {
return {
dialogVisible: false,
fileList: [],
edgeCount: 0,
vertexCount: 0,
qo: {
pageNo: 1,
pageSize: 10,
LIKES_name: '',
EQI_sourceType: 1
},
nodes: [],
edges: [],
treeData: [], // 概念树形
defaultProps: {
children: 'children',
label: 'label'
},
edgeData: [],
valueData: [],
nodeInfo: {},
fieldCount: [],
edgeFieldCount: 0,
ontologyList: [],
ontologyId: '',
ontology: {},
ontologyCount: {
"conceptc": "0",
"relationc": "0",
"fieldc": "0"
},
infoCmd: {
tagName: '',
label: ''
},
newNum:{
"relationc": 0,
"fieldc": 0,
}
}
},
mounted() {
_this = this;
_this.queryOntology();
},
methods: {
handlePopHide() {
_this.fieldCount = [];
_this.edgeFieldCount = 0;
},
handlePopShow(row) {
// console.log(row);
_this.dialogVisible = true;
request({
url: `/ontology-concept/countchildbyid/${row.id}`,
method: 'get',
data: {}
}).then(res => {
_this.edgeFieldCount = res.data;
});
request({
url: `/nebula_model/findnodebyid/${_this.ontologyId}/${row.ownId}`,
method: 'get',
data: {}
}).then(res => {
_this.infoCmd.tagName = _.get(res.data, "properties.tagName", '');
_this.infoCmd.label = _.get(res.data, "properties.label", '');
// _this.fieldCount = _.get(res.data, "properties.nebulafieldsnapshot", '');
});
request({
url: `/nebula_model/findnebulafieldwithparents/${row.ownId}`,
method: 'get',
data: {}
}).then(res => {
_this.fieldCount = res.data;
});
},
queryOntology() {
request({
url: `/ontology/query_list`,
method: 'post',
data: {EQI_sourceType: 1}
}).then(res => {
_this.ontologyList = res.data;
if (_this.ontologyList.length > 0) {
_this.handleSelectChange(_this.ontologyList[0].id);
}
});
},
handleSelectChange(ontologyId) {
_this.ontologyId = ontologyId;
let index = _this.ontologyList.findIndex(row => {
return row.id === ontologyId;
});
if(index >= 0) {
_this.ontology = _this.ontologyList[index];
_this.queryCount();
_this.queryIndicator2();
_this.queryVertexTree();
_this.queryGroupVertexEdgeCount();
_this.queryData();
} else {
_this.$message.warning("数据异常");
}
},
queryCount() {
request({
url: '/ontology-concept/countallbyontologyid/' + _this.ontologyId,
method: 'get',
data: {}
}).then(res => {
_this.ontologyCount = res.data;
});
},
queryGroupVertexEdgeCount() {
request({
url: '/nebula_model/groupcountvexbyedgebyontologyid/' + _this.ontologyId,
method: 'get',
data: {}
}).then(res => {
_this.edgeData = res.data;
request({
url: '/indicator/indicator2_kcrelation',
method: 'get',
data: {}
}).then(res => {
_this.edgeData = _this.edgeData.concat(res.data);
_this.newNum.relationc = _this.edgeData.length;
});
});
},
queryIndicator2() {
request({
url: '/nebula_model/groupfieldbyontologyid/' + _this.ontologyId,
method: 'get',
data: {}
}).then(res => {
_this.valueData = res.data;
request({
url: '/indicator/indicator2_kcvalues',
method: 'get',
data: {}
}).then(res => {
_this.valueData = _this.valueData.concat(res.data);
_this.newNum.fieldc = _this.valueData.length;
});
});
// request({
// url: '/indicator/indicator2',
// method: 'get',
// data: {}
// }).then(res => {
// _this.valueData = res.data;
// });
},
queryVertexTree() {
request({
url: '/ontology-concept/query_list/' + _this.ontologyId,
method: 'post',
data: {}
}).then(res => {
_this.treeData = listToTree(res.data, 'ownId');
});
// request({
// url: '/nebula_model/findtreebyontologyid/' + _this.ontologyId,
// method: 'post',
// data: {}
// }).then(res => {
// res.data.nodes.forEach(node => {
// node.label = node.properties.label || "-";
// node.fieldCount = node.properties.nebulafieldsnapshot ? node.properties.nebulafieldsnapshot.length : 0;
// });
// _this.treeData = tripletToTree({
// nodes: res.data.nodes,
// relations: res.data.relations,
// idName: 'vid',
// sourceName: 'srcId',
// targetName: 'dstId'
// });
// });
},
queryEdgeCount() { // 概念数量
request({
url: '/nebula_model/countedgesbyontologyid/' + _this.ontologyId,
method: 'get',
data: {}
}).then(res => {
_this.edgeCount = res.data;
});
},
queryVertexCount() { // 值属性数量
request({
url: '/nebula_model/countvertexsbyontologyid/' + _this.ontologyId,
method: 'get',
data: {}
}).then(res => {
_this.vertexCount = res.data;
});
},
queryData(fileItem) {
request({
url: '/nebula_model/findrelationbyontologyid/' + _this.ontologyId,
method: 'post',
data: {}
}).then(res => {
let cmd = {
nodes: [],
edges: []
};
res.data.nodes.forEach(node => {
cmd.nodes.push({
id: node.vid,
label: node.properties.label
});
});
res.data.relations.forEach(edge => {
cmd.edges.push({
source: edge.srcId,
target: edge.dstId,
label: edge.properties.label
});
});
_this.$refs['graph'].initGraph(cmd, true, null, true);
});
},
}
}
</script>
<style scoped lang="scss">
.desc2 {
.el-descriptions__title {
height: 40px;
line-height: 40px;
}
}
.result {
text-align: center;
margin-top: 25px;
font-size: 16px;
color: #5c5c5c;
}
.tree-box {
height: 615px;
overflow-y: auto;
}
.right-table {
height: 615px;
overflow-y: auto;
}
.graph-box1 {
width: 100%;
height: 500px;
background: rgba(0, 0, 0, 0.1);
border-radius: 5px;
margin-top: 50px;
}
</style>

View File

@@ -0,0 +1,351 @@
<template>
<div>
<div class="menu-title">
事理图谱构建
</div>
<div class="menu-content">
<el-row :gutter="20">
<el-col :span="10">
<el-table :data="fileList" style="width: 100%" class="right-table">
<el-table-column prop="name" label="文件名"></el-table-column>
<el-table-column prop="size" label="文件大小"></el-table-column>
<el-table-column prop="time" label="上传时间" width="150"></el-table-column>
<el-table-column label="操作">
<template slot-scope="scope">
<el-button type="text" style="float: left;margin-right: 5px" @click="clearData">清空数据</el-button>
<el-upload
style="float: left"
class="upload-demo"
action="#"
multiple
:auto-upload="false"
:limit="3"
:show-file-list="false"
:on-change="handleFileChange"
:file-list="fileList">
<el-button type="text">上传数据</el-button>
</el-upload>
</template>
</el-table-column>
</el-table>
<div class="pie-box">
<el-row :gutter="5">
<el-col :span="12">
<div id="pie1" class="pie-item"></div>
</el-col>
<el-col :span="12">
<div id="pie2" class="pie-item"></div>
</el-col>
</el-row>
</div>
<el-table :data="resultList" style="width: 100%">
<el-table-column prop="trigger" label="事件触发词识别"></el-table-column>
<el-table-column prop="event_type" label="事件分类"></el-table-column>
<el-table-column prop="relation" label="事件元素角色识别"></el-table-column>
<!-- <el-table-column label="操作">-->
<!-- <template slot-scope="scope">-->
<!-- <el-button type="text" style="float: left;margin-right: 5px">抽取</el-button>-->
<!-- </template>-->
<!-- </el-table-column>-->
</el-table>
</el-col>
<el-col :span="14" class="graph-pa">
<div class="graph-box">
<graph ref="graph"></graph>
</div>
<el-card class="box-card-2" v-show="nodeInfoVisible">
<div slot="header" class="clearfix">
<span>事理图谱节点属性</span>
<el-button style="float: right; padding: 3px 0" type="text" @click="nodeInfoVisible = false">关闭</el-button>
</div>
<el-descriptions class="margin-top" :column="2" border style="margin-bottom: 15px">
<el-descriptions-item>
<template slot="label">事件类型</template>
{{ nodeInfo._label }}
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">触发词</template>
{{ nodeInfo.label }}
</el-descriptions-item>
</el-descriptions>
<el-table :data="nodeInfo.arguments" border style="width: 100%">
<el-table-column prop="text" label="事件论元" ></el-table-column>
<el-table-column prop="role" label="论元角色" ></el-table-column>
</el-table>
</el-card>
</el-col>
</el-row>
</div>
</div>
</template>
<script>
import request from '@/utils/request';
import graph from "@/components/graph/Graph";
import {formatTime} from "@/utils/common";
var _this;
export default {
components: {
'graph': graph,
},
name: "reasonGraph",
data() {
return {
originText: '',
fileList: [
{
name: '暂无文件',
size: '0',
time: '-'
}
],
resultList: [
// {
// trigger: '',
// event_type: '',
// relation: ''
// }
],
nodeArguments: {},
nodes: [],
edges: [],
nodeInfo: {
arguments: [],
label: '',
_label: ''
},
nodeInfoVisible: false
}
},
mounted() {
_this = this;
_this.queryData();
},
methods: {
initRchart1(data) {
let _data = [];
data.forEach(item => {
_data.push({
name: item.name,
value: item.count
});
});
var chart = this.$echarts.init(document.getElementById("pie1"));
var option = {
title: {
text: '事件类型',
left: 'center',
top: 30
},
tooltip: {
trigger: 'item'
},
series: [
{
name: '事件类型',
type: 'pie',
radius: '60%',
data: _data,
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
};
chart.setOption(option);
},
initRchart2(data) {
let _data = [];
data.forEach(item => {
_data.push({
name: item.name,
value: item.count
});
});
var chart = this.$echarts.init(document.getElementById("pie2"));
var option = {
title: {
text: '事理关系',
left: 'center',
top: 30
},
tooltip: {
trigger: 'item'
},
series: [
{
name: '事理关系',
type: 'pie',
radius: '60%',
data: _data,
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
};
chart.setOption(option);
},
handleFileChange(file) {
if(file.name != 'event_graph.json'){
_this.$message.warning("上传文件不正确");
return false;
}
_this.fileList = [file];
_this.uploadFile(file);
},
uploadFile(file) {
console.log(file);
let formData = new FormData();
formData.append("file", file.raw);
request({
url: '/indicator/indicator6',
method: 'put',
data: formData
}).then(res => {
_this.fileList = [
{
name: file.name,
size: file.size + "kb",
time: formatTime(new Date())
}
];
_this.initRchart1(res.data.listmap1);
_this.initRchart2(res.data.listmap2);
let _map3 = res.data.map3;
_this.resultList = [
{
trigger: _map3.sjcfclb,
event_type: _map3.sjfl,
relation: _map3.sjyslb
}
];
_this.nodes = res.data.nodes;
_this.edges = res.data.relations;
_this.initGraphData();
});
},
queryData(){
request({
url: '/indicator/indicator6_1',
method: 'get',
data: {}
}).then(res => {
_this.initRchart1(res.data.listmap1);
_this.initRchart2(res.data.listmap2);
let _map3 = res.data.map3;
_this.resultList = [
{
trigger: _map3.sjcfclb,
event_type: _map3.sjfl,
relation: _map3.sjyslb
}
];
_this.nodes = res.data.nodes;
_this.edges = res.data.relations;
_this.initGraphData();
});
},
clearData() {
_this.fileList = [
{
name: '暂无文件',
size: '0',
time: '-'
}
];
_this.initRchart1([]);
_this.initRchart2([]);
_this.resultList = [];
_this.nodes = [];
_this.edges = [];
_this.initGraphData();
},
clickNode(node) {
let _arguments = _this.nodeArguments[node.id];
_this.nodeInfo = {
arguments: _arguments,
label: node.label,
_label: node._label
};
_this.nodeInfoVisible = true;
},
initGraphData() {
let cmd = {
nodes: [],
edges: []
};
let nodeArguments = {};
_this.nodes.forEach(node => {
cmd.nodes.push({
id: node.vid,
label: node.properties.name,
_label: node.labels
});
nodeArguments[node.vid] = node.properties.arguments;
});
_this.nodeArguments = nodeArguments;
_this.edges.forEach(edge => {
cmd.edges.push({
source: edge.dstId,
target: edge.srcId,
label: edge.edgeName
});
});
_this.$refs['graph'].initGraph(cmd, true, _this.clickNode ,true);
}
}
}
</script>
<style scoped lang="scss">
.result {
text-align: center;
margin-top: 25px;
font-size: 16px;
color: #5c5c5c;
}
.pie-box {
height: 490px;
.pie-item {
height: 480px;
width: 100%;
}
}
.graph-box {
width: 100%;
height: 700px;
background: rgba(0, 0, 0, 0.1);
border-radius: 5px;
position: relative;
}
.graph-pa {
position: relative;
.box-card-2 {
position: absolute;
right: 10px;
top: 15%;
bottom: 15%;
overflow-y: auto;
width: 40%;
}
}
</style>

View File

@@ -0,0 +1,425 @@
<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>
<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="algorithmId" label="算法名称" :formatter="algorithmIdFormatter"></el-table-column>
<!-- <el-table-column prop="version" label="版本"></el-table-column> -->
<el-table-column prop="status" label="服务状态" :formatter="statusFormatter"></el-table-column>
<el-table-column prop="url" 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="操作">
<template slot-scope="scope">
<el-button type="text" size="small"
@click.native.prevent="updateStatus(scope.row, 'start')" v-if="scope.row.status != 3">
启动
</el-button>
<el-button @click.native.prevent="detailRow(scope.row)" type="text" size="small">
详情
</el-button>
<el-button @click.native.prevent="updateStatus(scope.row, 'stop')" type="text" size="small" v-if="scope.row.status == 3">
停止
</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"
@close="handleLogDialogClose"
width="60%">
<el-form ref="cmd" label-width="80px" :rules="rules" :model="cmd">
<el-form-item label="请求地址" prop="address">
<el-input placeholder="请输入请求地址" v-model="cmd.address"
disabled
class="input-with-select" @input="change($event)">
<el-select v-model="cmd.requestType" slot="prepend" placeholder="请选择" style="width: 100px;">
<el-option label="POST" value="post"></el-option>
<el-option label="GET" value="get"></el-option>
<el-option label="PUT" value="put"></el-option>
</el-select>
<el-button slot="append" icon="el-icon-s-promotion" @click="submitHttp"> </el-button>
</el-input>
</el-form-item>
<el-form-item label="参数">
<el-table
:data="params"
ref="paramsTable"
border
@selection-change="handleSelectionChange"
style="width: 100%">
<el-table-column
type="selection"
width="55">
</el-table-column>
<el-table-column
prop="type"
label="参数类型">
<template slot-scope="scope">
<el-select v-model="scope.row.type" placeholder="请选择参数类型" :disabled="scope.row.isDisabled">
<el-option label="Int" value="int"></el-option>
<el-option label="Long" value="long"></el-option>
<el-option label="Double" value="double"></el-option>
<el-option label="String" value="string"></el-option>
<el-option label="Boolean" value="boolean"></el-option>
<el-option label="Float" value="float"></el-option>
<el-option label="Date" value="date"></el-option>
</el-select>
</template>
</el-table-column>
<el-table-column
prop="key"
label="参数名">
<template slot-scope="scope">
<el-input v-model="scope.row.key" placeholder="请输入参数名" :disabled="scope.row.isDisabled"
@change="(val) => handleParamKeyChange(scope.row, val)"></el-input>
</template>
</el-table-column>
<el-table-column
prop="value"
label="参数值">
<template slot-scope="scope">
<template v-if="scope.row.index == 1">
<el-select v-model="scope.row.value" placeholder="请选择数据集">
<el-option :label="item.name" :value="item.id" :key="item.id"
v-for="item in dataSetList"></el-option>
</el-select>
</template>
<template v-if="scope.row.index != 1">
<template v-if="scope.row.type == 'boolean'">
<el-select v-model="scope.row.value" placeholder="请选择参数值">
<el-option label="True" value="true"></el-option>
<el-option label="False" value="false"></el-option>
</el-select>
</template>
<template v-if="scope.row.type == 'date'">
<el-date-picker
v-model="scope.row.value"
type="datetime"
placeholder="选择日期时间">
</el-date-picker>
</template>
<template v-if="scope.row.type != 'date' && scope.row.type != 'boolean'">
<el-input v-model="scope.row.value" placeholder="请输入参数值"></el-input>
</template>
</template>
</template>
</el-table-column>
</el-table>
</el-form-item>
<el-form-item label="响应示例">
<vue-json-editor
v-model="resultJson"
:mode="'code'"
lang="zh"
:show-btns="false"
@json-change="onJsonChange"
@json-save="onJsonSave"
@has-error="onError"></vue-json-editor>
</el-form-item>
<div class="log-title-box">服务日志</div>
<!-- <div class="log-box"></div>-->
<log ref="log-item"></log>
</el-form>
</el-dialog>
</div>
</template>
<script>
import request from '@/utils/request2';
import request3 from '@/utils/request3';
import vueJsonEditor from 'vue-json-editor';
import log from '@/components/log/index';
import request1, {getBaseUrl} from "@/utils/request";
var _this;
export default {
name: "serviceManage",
components: {
vueJsonEditor,
log
},
data() {
return {
qo: {
pageNo: 1,
pageSize: 10,
LIKES_name: '',
},
result: {
records: [],
total: 0
},
cmdDialogVisible: false,
cmd: {
address: ''
},
params: [],
paramsSelection: [],
resultJson: {
msg: 'success of test',
},
rules: {
address: [
{required: true, message: '请输入请求地址'}
],
},
algorithmList: [],
statusList: {
1: '保存状态',
2: '开始',
3: '运行中',
4: '等待中',
5: '结束',
6: '发布失败',
7: '取消',
8: '训练中',
9: '训练完成',
10: '停止'
},
dataSetList: []
}
},
mounted() {
_this = this;
_this.queryData();
_this.queryAlgorithmList();
_this.queryDataSetList();
},
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: {
queryDataSetList() {
request1({
url: '/remark_task/query_list',
method: 'post',
data: {}
}).then(res => {
_this.dataSetList = res.data;
});
},
statusFormatter(row) {
return _this.statusList[row.status] || '-';
},
algorithmIdFormatter(row) {
let index = _this.algorithmList.findIndex(dataSet => {
return row.algorithmId == dataSet.id;
});
return index >= 0 ? _this.algorithmList[index].name : '-';
},
queryAlgorithmList() {
request({
url: '/algorithm/list',
method: 'post',
data: {pageNo: 1, pageSize: 1000}
}).then(res => {
_this.algorithmList = res.list;
});
},
// 数据改变是触发
onJsonChange(value) {
// console.log('value:', value)
},
// 点击保存时触发
onJsonSave(value) {
// console.log('value:', value)
},
onError(value) {
// console.log('value:', value)
},
handleSelectionChange(val) {
_this.paramsSelection = val;
},
handleParamKeyChange(row) {
if (_this.params.length == row.index) {
_this.params.push({
index: _this.params.length + 1,
type: 'string',
key: '',
value: ''
});
_this.$refs.paramsTable.toggleRowSelection(_this.params[_this.params.length - 1]);
}
},
queryData() {
request({
url: '/model/serviceList',
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();
},
handleLogDialogClose() {
_this.$refs['log-item'].close();
},
detailRow(item) {
_this.cmdDialogVisible = true;
_this.$nextTick(() => {
_this.$refs['log-item'].init({modelId: item.id, type: 'log_service'});
_this.cmd = JSON.parse(JSON.stringify(item));
if (!_this.cmd.requestType) {
_this.cmd.requestType = "post";
}
_this.$refs.cmd.resetFields();
_this.cmd.address = item.url;
_this.params = [
{
index: 1,
type: 'string',
key: 'dataSetUrl',
value: '',
isDisabled: true
}, {
index: 2,
type: 'string',
key: '',
value: ''
}
];
_this.$nextTick(() => {
_this.$refs.paramsTable.toggleRowSelection(_this.params[0]);
_this.$refs.paramsTable.toggleRowSelection(_this.params[1]);
});
});
},
change(e) {
_this.$forceUpdate(e);
},
submitHttp() {
let params = "";
for (let i = 0; i < _this.paramsSelection.length; i++) {
let pa = _this.paramsSelection[i];
if (pa.key.toString().length > 0 && pa.value.toString().length > 0) {
params += i == 0 ? '?' : '&';
if (pa.isDisabled) {
params += (pa.key + "=" + getBaseUrl() + "/es_remark_task/findbytaskidandtasktypeall/" + pa.value + "/1");
} else {
params += (pa.key + "=" + pa.value);
}
}
}
request3({
url: _this.cmd.address + params,
method: _this.cmd.requestType,
data: {}
}).then(res => {
_this.$message.success('发送成功');
_this.resultJson = res;
});
// console.log(_this.cmd);
},
updateStatus(item, action) { // 修改状态重启start停止stop
let text = action === 'start' ? '启动' : '停止';
_this.$confirm(`此操作将执行${text}操作, 是否继续?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
const loading = this.$loading({
lock: true,
text: text+'中...',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
});
request({
url: '/server/update/status',
method: 'post',
data: {
modelId: item.id,
action: action
}
}).then(res => {
_this.$message.success(`${text}成功`);
loading.close();
_this.queryData();
});
}).catch(() => {
});
},
}
}
</script>
<style lang="scss">
.jsoneditor-vue {
height: 400px;
}
.jsoneditor-poweredBy {
display: none;
}
.log-title-box {
font-size: 16px;
font-weight: 600;
margin-bottom: 10px;
}
.log-box {
background-color: #c2c2c2;
border-radius: 3px;
min-height: 300px;
}
</style>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,171 @@
<template>
<div>
<div id="xterm"></div>
</div>
</template>
<script>
import request from '@/utils/request2';
import {Terminal} from '../../utils/xterm/lib/xterm.js' //注意路径
var _this;
var commandKey = [];
var term;
var socket;
var sit;
export default {
name: "xterm",
data() {
return {
id: ''
}
},
// created() {
// let arr = ['../../utils/xterm/lib/xterm.js',
// '../../utils/xterm-addon/lib/xterm-addon-attach.js'];
// arr.map((item) => {
// let script = document.createElement('script');
// script.type = 'text/javascript';
// script.src = item;
// document.getElementsByTagName('body')[0].appendChild(script);
// });
// },
mounted() {
_this = this;
// _this.init();
},
methods: {
close() {
if(sit) {
clearInterval(sit);
}
if(socket) {
socket.close();
}
},
init(id) {
_this.id = id;
console.log(`当前节点ID为${id}`);
socket = new WebSocket(`ws://47.103.128.32:10050/socket/ssh?id=${id}&nodeId=${id}&type=ssh`);
//连接打开事件
socket.onopen = function () {
console.log("Socket 已打开");
};
//收到消息事件
socket.onmessage = function (msg) {
term.write(msg.data);//把接收的数据写到这个插件的屏幕上
if (msg.data.indexOf('连接成功sessionId=') != -1) {
var sessionId = msg.data.slice(15);
console.log(sessionId)
} else {
console.log("常规数据:" + msg.data);
}
};
//连接关闭事件
socket.onclose = function () {
console.log("Socket已关闭");
};
//发生了错误事件
socket.onerror = function () {
alert("Socket发生了错误");
}
term = new Terminal({
rendererType: "canvas", //渲染类型
rows: parseInt(24), //行数
cols: parseInt(100), // 不指定行数,自动回车后光标从下一行开始
convertEol: true, //启用时,光标将设置为下一行的开头
scrollback: 10, //终端中的回滚量
disableStdin: false, //是否应禁用输入
cursorStyle: "underline", //光标样式
cursorBlink: true, //光标闪烁
theme: {
foreground: "yellow", //字体
background: "#060101", //背景色
cursor: "help" //设置光标
}
});
// const attachAddon = new AttachAddon(socket);
// term.loadAddon(attachAddon);
term.open(document.getElementById("xterm"));
// 支持输入与粘贴方法
term.onData(function (key) {
// console.log("|"+key+"|");
// commandKey.push(key);
// console.log(commandKey);
// term.write(key);
socket.send(key); //转换为字符串
});
term.onLineFeed(function () {
console.log("执行换行" + JSON.stringify(commandKey))
});
term.onTitleChange(function (key) {
console.log("onTitleChange:" + key);
});
//创建心跳,防止掉线
sit = setInterval(() => {
let op = {
data: "heart",
};
sendJson(op);
}, 5000);
runFakeTerminal();
}
}
}
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));
}
}
function runFakeTerminal() {
if (term._initialized) {
return;
}
term._initialized = true;
term.prompt = () => {
term.write('\r\n~$ ');
};
term.writeln('Welcome to xterm.js');
prompt(term);
term.onKey(e => {
const printable = !e.domEvent.altKey && !e.domEvent.altGraphKey && !e.domEvent.ctrlKey && !e.domEvent.metaKey;
if (e.domEvent.keyCode === 13) {
prompt(term);
} else if (e.domEvent.keyCode === 8) {
// Do not delete the prompt
if (term._core.buffer.x > 2) {
// term.write('\b \b')
}
} else if (printable) {
// term.write(e.key);
}
console.log(commandKey);
console.log("key::" + e.domEvent.keyCode);
});
}
function prompt(term) {
// term.write('\r\n~$ ');
// term.focus();
}
</script>
<style lang="scss">
@import '../../utils/xterm/css/xterm.css';
</style>