allen 2 anos atrás
pai
commit
b7053138f4

+ 1 - 1
src/api/graph/attrClass.js

@@ -40,7 +40,7 @@ function getAttrClassById(entClsID, data) {
 function getAttrClassById2(entClsID, data) {
 	return request({
 		method: 'get',
-		url: `/attrcls/notnull/${entClsID}/list`,
+		url: `/knowledge/classAttribute/attrcls/notnull/${entClsID}/list`,
 		params: {
 			id: entClsID
 		}

+ 13 - 24
src/api/graph/entity.js

@@ -46,14 +46,10 @@ function getEntityListByEntityClassId(id, data) {
 // 	})
 // }
 //新的delEntityById函数
-function delEntityById(id, isModel) {
+function delEntityById(id) {
 	return request({
-		method: 'post',
-		url: `/ent/del/ids`,
-		data: {
-			ids: id,
-			isModel,
-		},
+		method: 'delete',
+		url: `/knowledge/entity/ent/del/${id}`
 	})
 }
 
@@ -86,11 +82,8 @@ function delEntityById(id, isModel) {
 //新的delEntityByIds函数
 function delEntityByIds(ids) {
 	return request({
-		method: 'post',
-		url: `/ent/del/ids`,
-		data: {
-			ids: ids,
-		},
+		method: 'delete',
+		url: `/knowledge/entity/ent/del/${ids}`,
 	})
 }
 
@@ -137,10 +130,7 @@ function addEntity(
 ) {
 	return request({
 		method: 'post',
-		url: `/ent/add`,
-		headers: {
-			'Content-Type': 'application/json;charset=UTF-8'
-		},
+		url: `/knowledge/entity/ent/add`,
 		data: {
 			entClsID: entClsID,
 			entMemo: entMemo,
@@ -148,8 +138,7 @@ function addEntity(
 			entIcon: entIcon,
 			notNullAttrVOList: notNullAttrVOList, // 必填属性列表
 			isModel,
-		},
-		json: true,
+		}
 	})
 }
 
@@ -175,7 +164,7 @@ function addEntity(
 function getEntityDetailById(id, isModel) {
 	return request({
 		method: 'get',
-		url: `/ent/${id}`,
+		url: `/knowledge/entity/ent/${id}`,
 		params: {
 			id: id,
 			isModel
@@ -204,12 +193,12 @@ function getEntityDetailById(id, isModel) {
 // 	})
 // }
 //新的updateEntityName函数
-function updateEntityName(entID, entName, entMemo, entIcon, isModel) {
+function updateEntityName(entId, entName, entMemo, entIcon, isModel) {
 	return request({
 		method: 'post',
-		url: `/ent/update`,
+		url: `/knowledge/entity/ent/update`,
 		data: {
-			entID: entID,
+			entId: entId,
 			entMemo: entMemo, // 可选择传不传
 			entName: entName,
 			entIcon: entIcon,
@@ -558,7 +547,7 @@ function getChart(data) {
 function getRelationClsByEntCls(id) {
 	return request({
 		method: 'get',
-		url: `/relcls/all/list/${id}`,
+		url: `/knowledge/classRelation/relcls/all/list/${id}`,
 		params: {
 			id,
 		}
@@ -620,7 +609,7 @@ function getRelationAttr(entId, relClsId, direction, isModel, current, size) {
 function saveEntAttr(data) {
 	return request({
 		method: 'post',
-		url: `/ent/update/batch`,
+		url: `/knowledge/entityAttribute/ent/update/batch`,
 		data: data,
 	})
 }

+ 1 - 1
src/api/graph/entityAttrEditor.js

@@ -24,7 +24,7 @@ import request from '@/utils/request'
 function getEntityAttrById(id, data, isModel) {
 	return request({
 		method: 'get',
-		url: `/ent/${id}/attrs`,
+		url: `/knowledge/entityAttribute/ent/${id}/attrs`,
 		params: {
 			id: id,
 			attrType: data.attrType,

+ 5 - 5
src/api/graph/search.js

@@ -26,15 +26,15 @@ import request from '@/utils/request'
     })
 } */
 //新的entSearch函数
-function entSearch(searchStr, entClsIDs, pagenum, pagesize, isModel, isIcon, searchType) {
+function entSearch(searchStr, entClsIDs, pageNum, pageSize, isModel, isIcon, searchType) {
 	return request({
 		method: 'get',
-		url: `/ent/entquery`,
-		data: {
+		url: `/knowledge/entity/ent/entquery`,
+		params: {
 			searchStr: (searchType === 'name' || searchType == null) ? searchStr : null,
 			entClsIDs,
-			pagenum,
-			pagesize,
+			pageNum,
+			pageSize,
 			isModel,
 			isIcon,
 			unionID: searchType === 'id' ? searchStr : null

+ 228 - 0
src/api/graph/statisticalMap.js

@@ -0,0 +1,228 @@
+import request from '@/utils/request'
+
+/*
+* 根据输入的字符搜索实体列表
+* @param str
+* @returns []
+* */
+function getEntityListByStr(str) {
+    return request({
+        method: 'get',
+        url: '/show/entlist',
+        data: {
+            name: str
+        }
+    })
+}
+
+/**
+ * 根据ID、度数获取实体,关系列表,实体类列表,关系类列表
+ * @param id
+ * @returns {*}
+ */
+function getEntityListByEntityId(id, degree, entClsIDs, relClsIDs, direction, entName) {
+    let url = id ? `/knowledge/statisticalMap/all/${id}/list` : '/all/list'
+    return request({
+        method: 'get',
+        url: url,
+        path: {
+            id: id
+        },
+        data: {
+            degree: degree,
+            entClsIDs: entClsIDs,
+            relClsIDs: relClsIDs,
+            direction: direction,
+            entName: entName
+        }
+    })
+}
+
+/**
+ * bf版本:根据ID、度数获取实体,关系列表,实体类列表,关系类列表
+ * @param id
+ * @returns {*}
+ */
+function getBfEntityListByEntityId(id, degree, entClsIDs, relClsIDs, direction) {
+    return request({
+        method: 'get',
+        url: '/bf/all/{id}/list',
+        path: {
+            id: id
+        },
+        data: {
+            degree: degree,
+            entClsIDs: entClsIDs,
+            relClsIDs: relClsIDs,
+            direction: direction
+        }
+    })
+}
+
+/*
+* 根据ID获取实体的详情
+* @param id
+* @return {}
+* */
+function getEntityInfoByEntityId(id) {
+    return request({
+        method: 'get',
+        url: '/ent/{id}',
+        path: {
+            id: id
+        }
+    })
+}
+
+/*
+* 根据ID获取实体属性的列表
+* @param id
+* @return {}
+* */
+function getEntityAttrsByEntityId(id, type) {
+    return request({
+        method: 'get',
+        url: '/ent/{id}/attrs',
+        path: {
+            id: id
+        },
+        data: {
+            attrType: type
+        }
+    })
+}
+
+/*
+* 根据ID获取关系详情
+* @param id
+* @return {}
+* */
+function getRelationInfoByRelationId(id) {
+    return request({
+        method: 'get',
+        url: '/show/{id}',
+        path: {
+            id: id
+        }
+    })
+}
+
+/*
+* 根据ID获取关系属性的列表
+* @param id
+* @return {}
+* */
+function getRelationAttrsByRelationId(id) {
+    return request({
+        method: 'get',
+        url: '/show/{id}/attrs',
+        path: {
+            id: id
+        }
+    })
+}
+
+/**
+ * 显示图数据统计 实体类的信息以及实例化实体的个数
+ * @param id
+ * @returns {*}
+ */
+function getGraphEntClsTree(id) {
+    return request({
+        method: 'get',
+        url: '/statistic/entclslist',
+        path: {
+            id: id
+        }
+    })
+}
+
+/**
+ * 实体类下关系类以及该关系类下实体数量
+ * @param id
+ * @returns {*}
+ */
+function getRelclsentByEntClsId(entClsID) {
+    return request({
+        method: 'get',
+        url: '/statistic/relclsent',
+        data: {
+            entClsID: entClsID
+        }
+    })
+}
+
+/**
+ * 实体类ID获取属性类列表接口s
+ * @param entClsID
+ * @returns {*}
+ */
+function getAttrClsListByEntClsId(attrType, entClsID) {
+    return request({
+        method: 'get',
+        url: '/attrcls/{id}/list',
+        path: {
+            id: entClsID
+        },
+        data: {
+            attrType: attrType,
+            id: entClsID
+        }
+    })
+}
+
+/**
+ * 实体类下属性信息以及该属性所连实体数量
+ * @param attrClsID
+ * @param entClsID
+ * @returns {*}
+ */
+function getAllAttrAndEntity(attrClsID, entClsID) {
+    return request({
+        method: 'get',
+        url: '/statistic/attrent',
+        data: {
+            attrClsID: attrClsID,
+            entClsID: entClsID
+        }
+    })
+}
+
+/**
+ * 所有关系类以及关系类下实体数量(默认显示最大为100条关系类 按每个关系类下实体数量从大到小排列)
+ * @returns {*}
+ */
+function getAllRelClsEnt() {
+    return request({
+        method: 'get',
+        url: '/statistic/allrelclsent',
+        data: {}
+    })
+}
+
+
+function compare(data) {
+    return request({
+        method: 'post',
+        url: '/show/graph/compare',
+        data: data,
+        headers: {'Content-Type': 'application/json;charset=UTF-8'},
+        json: true
+    })
+}
+
+export {
+    getAllRelClsEnt,
+    getAllAttrAndEntity,
+    getAttrClsListByEntClsId,
+    getRelclsentByEntClsId,
+    getGraphEntClsTree,
+    getEntityListByStr,
+    getEntityListByEntityId,
+    getBfEntityListByEntityId,
+    getEntityInfoByEntityId,
+    getEntityAttrsByEntityId,
+    getRelationInfoByRelationId,
+    getRelationAttrsByRelationId,
+    compare
+}

Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 0
src/assets/zc.css


+ 2 - 0
src/main.js

@@ -50,6 +50,7 @@ import modalList from "@/views/knowledge/modal/index";
 import contentmenu from "v-contextmenu";
 import "v-contextmenu/dist/index.css";
 import '@/assets/knowledge/config/config'
+import moment from "moment";
 Vue.prototype.$const = window.global.const;
 // knowledge 知识图谱新增 end
 
@@ -101,6 +102,7 @@ Vue.use(Antd);
 Vue.config.productionTip = false
 
 // knowledge add start
+Vue.prototype.$moment = moment;
 Vue.prototype.$checkSpecialChar = function (value) {
   const pattern = /[`~!@#$^&*()=|{}':;',[\].<>《》/?~!@#¥……&*()——|{}【】‘;:”“'。,、? ]/g
   const matchList = value.match(pattern)

Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 0
src/plugins/knowledge/zc.css


Diferenças do arquivo suprimidas por serem muito extensas
+ 32 - 0
src/plugins/knowledge/zoomChart.js


+ 24 - 67
src/router/knowledge/index.js

@@ -2,6 +2,8 @@ import Knowledge from '@/views/knowledge/index.vue' //管理器(实体类/实体
 import ManagerPage from '@/views/knowledge/graphEntity/manager.vue' //管理器(实体类/实体)框架页面
 
 //实体管理器
+import EntityTemplateManagerPageBak from '@/views/knowledge/graphEntity/entityTemplateList.vue'
+import Relationship_class_blank from '@/views/knowledge/common/Relationship_class_blank.vue'
 import EntityManagerPage from '@/views/knowledge/graphEntity/entity.vue' //管理器 -> 实体主页面
 import EntityList from '@/views/knowledge/graphEntity/entityList.vue' //管理器 -> 实体列表(实体类页面不存在)
 import EM_AttrEditor from '@/views/knowledge/graphEntity/attrEditor.vue' //管理器 -> 实体 -> 基本属性
@@ -123,89 +125,44 @@ export default [
             ]
           },
           {
-            path: 'class/unknow/entity',
+            path: 'class/unknow/entity_v2',
             meta: {
-              msg: '请选中关系类'
+              code: 'ent'
             },
             components: {
-              main: BlankPage,
-              // entityList: BlankPage,
+              main: () => import('@/views/knowledge/common/Relationship_class_blank.vue') // 实体类新增空白页面
             }
           },
           {
-            path: 'class/:classId/entity',
-            name: 'class_entity',
+            path: 'class/:classId/entity_v2',
+            name: 'class_entity_v2',
             meta: {
-              msg: '请选中实体'
+              msg: '请选中实体',
+              code: 'ent'
             },
             components: {
-              main: EntityManagerPage,
-              entityList: EntityList,
-            }
-          },
-          /**
-           * manager -> entity -> :id
-           */
-          {
-            path: 'class/:classId/entity/:entityId',
-            components: {
-              main: EntityManagerPage,
-              entityList: EntityList
+              // 如果是带实体模板的版本 EntityTemplateManagerPageBak
+              main: EntityTemplateManagerPageBak,//管理器 -> 实体主页面
+              entityList: () => import('@/views/knowledge/graphEntity/entityList.vue')//管理器 -> 实体列表(实体类页面不存在)
             },
-            children: [
-              {
-                path: '',
-                name: 'e_base',
-                component: EM_AttrEditor,
-                meta: {
-                  type: 'ELEM'
-                }
-              }, {
-                path: 'relation',
-                name: 'e_relation',
-                component: EM_RelationEditor,
-                meta: {}
-              }, {
-                path: 'notype',
-                name: 'e_notype',
-                component: EM_AttrEditor,
-                meta: {
-                  type: 'NONE'
-                }
-              },
-              {
-                path: 'media',
-                name: 'e_media',
-                component: EM_AttrEditor,
-                meta: {
-                  type: '尚未开放'
-                }
-              },
-            //   {
-            //     path: 'tag',
-            //     name: 'e_tag',
-            //     component: EM_ECM_TagEditor,
-            //     meta: {
-            //       type:'entity'
-            //       // type: '尚未开放'
-            //     }
-            //   },
-              {
-                path: 'ability',
-                name: 'e_ability',
-                component: EM_AttrEditor,
-                meta: {
-                  type: 'CIDX'
-                }
-              }]
-          }],
+          },
+        ],
       },
       {
           path: '/entityListnew',
           name: 'entityListnew',
           hidden: true,
           component: entityListnew
-      }
+      },
+      {
+        path: '/model/:classId/entity_model/:entityId', // 模板实体详情
+        name: 'model_edit',
+        meta: {
+          code: 'ent'
+        },
+        hidden: true,
+        component: () => import('@/views/knowledge/graphEntity/attrModelEditor.vue')
+      },
     ]
   }
 ]

+ 0 - 345
src/views/knowledge/class/index.vue

@@ -1,345 +0,0 @@
-<template>
-  <div class="app-container">
-    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
-      <el-form-item label="实体类父节点ID" prop="pid">
-        <el-input
-          v-model="queryParams.pid"
-          placeholder="请输入实体类父节点ID"
-          clearable
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="实体类名称" prop="entClsName">
-        <el-input
-          v-model="queryParams.entClsName"
-          placeholder="请输入实体类名称"
-          clearable
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="图标id" prop="entClsIconId">
-        <el-input
-          v-model="queryParams.entClsIconId"
-          placeholder="请输入图标id"
-          clearable
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="实体类背景颜色" prop="backGroundColor">
-        <el-input
-          v-model="queryParams.backGroundColor"
-          placeholder="请输入实体类背景颜色"
-          clearable
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="是否存在子类" prop="childCount">
-        <el-input
-          v-model="queryParams.childCount"
-          placeholder="请输入是否存在子类"
-          clearable
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="待审属性节点个数" prop="noneCount">
-        <el-input
-          v-model="queryParams.noneCount"
-          placeholder="请输入待审属性节点个数"
-          clearable
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="是否根节点" prop="isRoot">
-        <el-input
-          v-model="queryParams.isRoot"
-          placeholder="请输入是否根节点"
-          clearable
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item>
-        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
-        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
-      </el-form-item>
-    </el-form>
-
-    <el-row :gutter="10" class="mb8">
-      <el-col :span="1.5">
-        <el-button
-          type="primary"
-          plain
-          icon="el-icon-plus"
-          size="mini"
-          @click="handleAdd"
-          v-hasPermi="['knowledge:class:add']"
-        >新增</el-button>
-      </el-col>
-      <el-col :span="1.5">
-        <el-button
-          type="success"
-          plain
-          icon="el-icon-edit"
-          size="mini"
-          :disabled="single"
-          @click="handleUpdate"
-          v-hasPermi="['knowledge:class:edit']"
-        >修改</el-button>
-      </el-col>
-      <el-col :span="1.5">
-        <el-button
-          type="danger"
-          plain
-          icon="el-icon-delete"
-          size="mini"
-          :disabled="multiple"
-          @click="handleDelete"
-          v-hasPermi="['knowledge:class:remove']"
-        >删除</el-button>
-      </el-col>
-      <el-col :span="1.5">
-        <el-button
-          type="warning"
-          plain
-          icon="el-icon-download"
-          size="mini"
-          @click="handleExport"
-          v-hasPermi="['knowledge:class:export']"
-        >导出</el-button>
-      </el-col>
-      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
-    </el-row>
-
-    <el-table v-loading="loading" :data="classList" @selection-change="handleSelectionChange">
-      <el-table-column type="selection" width="55" align="center" />
-      <el-table-column label="实体类ID" align="center" prop="entClsID" />
-      <el-table-column label="实体类父节点ID" align="center" prop="pid" />
-      <el-table-column label="实体类名称" align="center" prop="entClsName" />
-      <el-table-column label="实体类描述" align="center" prop="entClsMemo" />
-      <el-table-column label="图标id" align="center" prop="entClsIconId" />
-      <el-table-column label="实体类背景颜色" align="center" prop="backGroundColor" />
-      <el-table-column label="实体类类型" align="center" prop="clsType" />
-      <el-table-column label="是否存在子类" align="center" prop="childCount" />
-      <el-table-column label="待审属性节点个数" align="center" prop="noneCount" />
-      <el-table-column label="允许的属性类型" align="center" prop="entClsAllowAttrType" />
-      <el-table-column label="是否根节点" align="center" prop="isRoot" />
-      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
-        <template slot-scope="scope">
-          <el-button
-            size="mini"
-            type="text"
-            icon="el-icon-edit"
-            @click="handleUpdate(scope.row)"
-            v-hasPermi="['knowledge:class:edit']"
-          >修改</el-button>
-          <el-button
-            size="mini"
-            type="text"
-            icon="el-icon-delete"
-            @click="handleDelete(scope.row)"
-            v-hasPermi="['knowledge:class:remove']"
-          >删除</el-button>
-        </template>
-      </el-table-column>
-    </el-table>
-    
-    <pagination
-      v-show="total>0"
-      :total="total"
-      :page.sync="queryParams.pageNum"
-      :limit.sync="queryParams.pageSize"
-      @pagination="getList"
-    />
-
-    <!-- 添加或修改实体类对话框 -->
-    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
-      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
-        <el-form-item label="实体类父节点ID" prop="pid">
-          <el-input v-model="form.pid" placeholder="请输入实体类父节点ID" />
-        </el-form-item>
-        <el-form-item label="实体类名称" prop="entClsName">
-          <el-input v-model="form.entClsName" placeholder="请输入实体类名称" />
-        </el-form-item>
-        <el-form-item label="实体类描述" prop="entClsMemo">
-          <el-input v-model="form.entClsMemo" type="textarea" placeholder="请输入内容" />
-        </el-form-item>
-        <el-form-item label="图标id" prop="entClsIconId">
-          <el-input v-model="form.entClsIconId" placeholder="请输入图标id" />
-        </el-form-item>
-        <el-form-item label="实体类背景颜色" prop="backGroundColor">
-          <el-input v-model="form.backGroundColor" placeholder="请输入实体类背景颜色" />
-        </el-form-item>
-        <el-form-item label="是否存在子类" prop="childCount">
-          <el-input v-model="form.childCount" placeholder="请输入是否存在子类" />
-        </el-form-item>
-        <el-form-item label="待审属性节点个数" prop="noneCount">
-          <el-input v-model="form.noneCount" placeholder="请输入待审属性节点个数" />
-        </el-form-item>
-        <el-form-item label="是否根节点" prop="isRoot">
-          <el-input v-model="form.isRoot" placeholder="请输入是否根节点" />
-        </el-form-item>
-      </el-form>
-      <div slot="footer" class="dialog-footer">
-        <el-button type="primary" @click="submitForm">确 定</el-button>
-        <el-button @click="cancel">取 消</el-button>
-      </div>
-    </el-dialog>
-  </div>
-</template>
-
-<script>
-import { listClass, getClass, delClass, addClass, updateClass } from "@/api/knowledge/class";
-
-export default {
-  name: "Class",
-  data() {
-    return {
-      // 遮罩层
-      loading: true,
-      // 选中数组
-      ids: [],
-      // 非单个禁用
-      single: true,
-      // 非多个禁用
-      multiple: true,
-      // 显示搜索条件
-      showSearch: true,
-      // 总条数
-      total: 0,
-      // 实体类表格数据
-      classList: [],
-      // 弹出层标题
-      title: "",
-      // 是否显示弹出层
-      open: false,
-      // 查询参数
-      queryParams: {
-        pageNum: 1,
-        pageSize: 10,
-        pid: null,
-        entClsName: null,
-        entClsMemo: null,
-        entClsIconId: null,
-        backGroundColor: null,
-        clsType: null,
-        childCount: null,
-        noneCount: null,
-        entClsAllowAttrType: null,
-        isRoot: null
-      },
-      // 表单参数
-      form: {},
-      // 表单校验
-      rules: {
-      }
-    };
-  },
-  created() {
-    this.getList();
-  },
-  methods: {
-    /** 查询实体类列表 */
-    getList() {
-      this.loading = true;
-      listClass(this.queryParams).then(response => {
-        this.classList = response.rows;
-        this.total = response.total;
-        this.loading = false;
-      });
-    },
-    // 取消按钮
-    cancel() {
-      this.open = false;
-      this.reset();
-    },
-    // 表单重置
-    reset() {
-      this.form = {
-        entClsID: null,
-        pid: null,
-        entClsName: null,
-        entClsMemo: null,
-        entClsIconId: null,
-        backGroundColor: null,
-        clsType: null,
-        childCount: null,
-        noneCount: null,
-        createBy: null,
-        createTime: null,
-        updateBy: null,
-        updateTime: null,
-        entClsAllowAttrType: null,
-        isRoot: null
-      };
-      this.resetForm("form");
-    },
-    /** 搜索按钮操作 */
-    handleQuery() {
-      this.queryParams.pageNum = 1;
-      this.getList();
-    },
-    /** 重置按钮操作 */
-    resetQuery() {
-      this.resetForm("queryForm");
-      this.handleQuery();
-    },
-    // 多选框选中数据
-    handleSelectionChange(selection) {
-      this.ids = selection.map(item => item.entClsID)
-      this.single = selection.length!==1
-      this.multiple = !selection.length
-    },
-    /** 新增按钮操作 */
-    handleAdd() {
-      this.reset();
-      this.open = true;
-      this.title = "添加实体类";
-    },
-    /** 修改按钮操作 */
-    handleUpdate(row) {
-      this.reset();
-      const entClsID = row.entClsID || this.ids
-      getClass(entClsID).then(response => {
-        this.form = response.data;
-        this.open = true;
-        this.title = "修改实体类";
-      });
-    },
-    /** 提交按钮 */
-    submitForm() {
-      this.$refs["form"].validate(valid => {
-        if (valid) {
-          if (this.form.entClsID != null) {
-            updateClass(this.form).then(response => {
-              this.$modal.msgSuccess("修改成功");
-              this.open = false;
-              this.getList();
-            });
-          } else {
-            addClass(this.form).then(response => {
-              this.$modal.msgSuccess("新增成功");
-              this.open = false;
-              this.getList();
-            });
-          }
-        }
-      });
-    },
-    /** 删除按钮操作 */
-    handleDelete(row) {
-      const entClsIDs = row.entClsID || this.ids;
-      this.$modal.confirm('是否确认删除实体类编号为"' + entClsIDs + '"的数据项?').then(function() {
-        return delClass(entClsIDs);
-      }).then(() => {
-        this.getList();
-        this.$modal.msgSuccess("删除成功");
-      }).catch(() => {});
-    },
-    /** 导出按钮操作 */
-    handleExport() {
-      this.download('knowledge/class/export', {
-        ...this.queryParams
-      }, `class_${new Date().getTime()}.xlsx`)
-    }
-  }
-};
-</script>

+ 0 - 415
src/views/knowledge/classAttribute/index.vue

@@ -1,415 +0,0 @@
-<template>
-  <div class="app-container">
-    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
-      <el-form-item label="属性类名称" prop="attrClsName">
-        <el-input
-          v-model="queryParams.attrClsName"
-          placeholder="请输入属性类名称"
-          clearable
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="属性单位" prop="attrUnit">
-        <el-input
-          v-model="queryParams.attrUnit"
-          placeholder="请输入属性单位"
-          clearable
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="实体类id" prop="entClsID">
-        <el-input
-          v-model="queryParams.entClsID"
-          placeholder="请输入实体类id"
-          clearable
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="属性类描述" prop="attrClsMemo">
-        <el-input
-          v-model="queryParams.attrClsMemo"
-          placeholder="请输入属性类描述"
-          clearable
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="domainKey" prop="domainKey">
-        <el-input
-          v-model="queryParams.domainKey"
-          placeholder="请输入domainKey"
-          clearable
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="domain" prop="domain">
-        <el-input
-          v-model="queryParams.domain"
-          placeholder="请输入domain"
-          clearable
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="isPublic" prop="isPublic">
-        <el-input
-          v-model="queryParams.isPublic"
-          placeholder="请输入isPublic"
-          clearable
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="最大值" prop="maxValue">
-        <el-input
-          v-model="queryParams.maxValue"
-          placeholder="请输入最大值"
-          clearable
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="最小值" prop="minValue">
-        <el-input
-          v-model="queryParams.minValue"
-          placeholder="请输入最小值"
-          clearable
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="是否可以为空" prop="notNull">
-        <el-input
-          v-model="queryParams.notNull"
-          placeholder="请输入是否可以为空"
-          clearable
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="entUseCount" prop="entUseCount">
-        <el-input
-          v-model="queryParams.entUseCount"
-          placeholder="请输入entUseCount"
-          clearable
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="isEdit" prop="isEdit">
-        <el-input
-          v-model="queryParams.isEdit"
-          placeholder="请输入isEdit"
-          clearable
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item>
-        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
-        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
-      </el-form-item>
-    </el-form>
-
-    <el-row :gutter="10" class="mb8">
-      <el-col :span="1.5">
-        <el-button
-          type="primary"
-          plain
-          icon="el-icon-plus"
-          size="mini"
-          @click="handleAdd"
-          v-hasPermi="['knowledge:classAttribute:add']"
-        >新增</el-button>
-      </el-col>
-      <el-col :span="1.5">
-        <el-button
-          type="success"
-          plain
-          icon="el-icon-edit"
-          size="mini"
-          :disabled="single"
-          @click="handleUpdate"
-          v-hasPermi="['knowledge:classAttribute:edit']"
-        >修改</el-button>
-      </el-col>
-      <el-col :span="1.5">
-        <el-button
-          type="danger"
-          plain
-          icon="el-icon-delete"
-          size="mini"
-          :disabled="multiple"
-          @click="handleDelete"
-          v-hasPermi="['knowledge:classAttribute:remove']"
-        >删除</el-button>
-      </el-col>
-      <el-col :span="1.5">
-        <el-button
-          type="warning"
-          plain
-          icon="el-icon-download"
-          size="mini"
-          @click="handleExport"
-          v-hasPermi="['knowledge:classAttribute:export']"
-        >导出</el-button>
-      </el-col>
-      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
-    </el-row>
-
-    <el-table v-loading="loading" :data="classAttributeList" @selection-change="handleSelectionChange">
-      <el-table-column type="selection" width="55" align="center" />
-      <el-table-column label="关系id" align="center" prop="attrClsID" />
-      <el-table-column label="属性类名称" align="center" prop="attrClsName" />
-      <el-table-column label="属性单位" align="center" prop="attrUnit" />
-      <el-table-column label="属性类型" align="center" prop="entAndAttrType" />
-      <el-table-column label="属性类型" align="center" prop="attrType" />
-      <el-table-column label="实体类id" align="center" prop="entClsID" />
-      <el-table-column label="属性类描述" align="center" prop="attrClsMemo" />
-      <el-table-column label="值类型 (TEXT) " align="center" prop="valueType" />
-      <el-table-column label="值类型 (TEXT) " align="center" prop="attrValueType" />
-      <el-table-column label="domainKey" align="center" prop="domainKey" />
-      <el-table-column label="domain" align="center" prop="domain" />
-      <el-table-column label="isPublic" align="center" prop="isPublic" />
-      <el-table-column label="最大值" align="center" prop="maxValue" />
-      <el-table-column label="最小值" align="center" prop="minValue" />
-      <el-table-column label="是否可以为空" align="center" prop="notNull" />
-      <el-table-column label="entUseCount" align="center" prop="entUseCount" />
-      <el-table-column label="isEdit" align="center" prop="isEdit" />
-      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
-        <template slot-scope="scope">
-          <el-button
-            size="mini"
-            type="text"
-            icon="el-icon-edit"
-            @click="handleUpdate(scope.row)"
-            v-hasPermi="['knowledge:classAttribute:edit']"
-          >修改</el-button>
-          <el-button
-            size="mini"
-            type="text"
-            icon="el-icon-delete"
-            @click="handleDelete(scope.row)"
-            v-hasPermi="['knowledge:classAttribute:remove']"
-          >删除</el-button>
-        </template>
-      </el-table-column>
-    </el-table>
-    
-    <pagination
-      v-show="total>0"
-      :total="total"
-      :page.sync="queryParams.pageNum"
-      :limit.sync="queryParams.pageSize"
-      @pagination="getList"
-    />
-
-    <!-- 添加或修改实体类属性对话框 -->
-    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
-      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
-        <el-form-item label="属性类名称" prop="attrClsName">
-          <el-input v-model="form.attrClsName" placeholder="请输入属性类名称" />
-        </el-form-item>
-        <el-form-item label="属性单位" prop="attrUnit">
-          <el-input v-model="form.attrUnit" placeholder="请输入属性单位" />
-        </el-form-item>
-        <el-form-item label="实体类id" prop="entClsID">
-          <el-input v-model="form.entClsID" placeholder="请输入实体类id" />
-        </el-form-item>
-        <el-form-item label="属性类描述" prop="attrClsMemo">
-          <el-input v-model="form.attrClsMemo" placeholder="请输入属性类描述" />
-        </el-form-item>
-        <el-form-item label="domainKey" prop="domainKey">
-          <el-input v-model="form.domainKey" placeholder="请输入domainKey" />
-        </el-form-item>
-        <el-form-item label="domain" prop="domain">
-          <el-input v-model="form.domain" placeholder="请输入domain" />
-        </el-form-item>
-        <el-form-item label="isPublic" prop="isPublic">
-          <el-input v-model="form.isPublic" placeholder="请输入isPublic" />
-        </el-form-item>
-        <el-form-item label="最大值" prop="maxValue">
-          <el-input v-model="form.maxValue" placeholder="请输入最大值" />
-        </el-form-item>
-        <el-form-item label="最小值" prop="minValue">
-          <el-input v-model="form.minValue" placeholder="请输入最小值" />
-        </el-form-item>
-        <el-form-item label="是否可以为空" prop="notNull">
-          <el-input v-model="form.notNull" placeholder="请输入是否可以为空" />
-        </el-form-item>
-        <el-form-item label="entUseCount" prop="entUseCount">
-          <el-input v-model="form.entUseCount" placeholder="请输入entUseCount" />
-        </el-form-item>
-        <el-form-item label="isEdit" prop="isEdit">
-          <el-input v-model="form.isEdit" placeholder="请输入isEdit" />
-        </el-form-item>
-      </el-form>
-      <div slot="footer" class="dialog-footer">
-        <el-button type="primary" @click="submitForm">确 定</el-button>
-        <el-button @click="cancel">取 消</el-button>
-      </div>
-    </el-dialog>
-  </div>
-</template>
-
-<script>
-import { listClassAttribute, getClassAttribute, delClassAttribute, addClassAttribute, updateClassAttribute } from "@/api/knowledge/classAttribute";
-
-export default {
-  name: "ClassAttribute",
-  data() {
-    return {
-      // 遮罩层
-      loading: true,
-      // 选中数组
-      ids: [],
-      // 非单个禁用
-      single: true,
-      // 非多个禁用
-      multiple: true,
-      // 显示搜索条件
-      showSearch: true,
-      // 总条数
-      total: 0,
-      // 实体类属性表格数据
-      classAttributeList: [],
-      // 弹出层标题
-      title: "",
-      // 是否显示弹出层
-      open: false,
-      // 查询参数
-      queryParams: {
-        pageNum: 1,
-        pageSize: 10,
-        attrClsName: null,
-        attrUnit: null,
-        entAndAttrType: null,
-        attrType: null,
-        entClsID: null,
-        attrClsMemo: null,
-        valueType: null,
-        attrValueType: null,
-        domainKey: null,
-        domain: null,
-        isPublic: null,
-        maxValue: null,
-        minValue: null,
-        notNull: null,
-        entUseCount: null,
-        isEdit: null,
-      },
-      // 表单参数
-      form: {},
-      // 表单校验
-      rules: {
-      }
-    };
-  },
-  created() {
-    this.getList();
-  },
-  methods: {
-    /** 查询实体类属性列表 */
-    getList() {
-      this.loading = true;
-      listClassAttribute(this.queryParams).then(response => {
-        this.classAttributeList = response.rows;
-        this.total = response.total;
-        this.loading = false;
-      });
-    },
-    // 取消按钮
-    cancel() {
-      this.open = false;
-      this.reset();
-    },
-    // 表单重置
-    reset() {
-      this.form = {
-        attrClsID: null,
-        attrClsName: null,
-        attrUnit: null,
-        entAndAttrType: null,
-        attrType: null,
-        entClsID: null,
-        attrClsMemo: null,
-        valueType: null,
-        attrValueType: null,
-        domainKey: null,
-        domain: null,
-        isPublic: null,
-        maxValue: null,
-        minValue: null,
-        notNull: null,
-        entUseCount: null,
-        isEdit: null,
-        createBy: null,
-        createTime: null,
-        updateBy: null,
-        updateTime: null
-      };
-      this.resetForm("form");
-    },
-    /** 搜索按钮操作 */
-    handleQuery() {
-      this.queryParams.pageNum = 1;
-      this.getList();
-    },
-    /** 重置按钮操作 */
-    resetQuery() {
-      this.resetForm("queryForm");
-      this.handleQuery();
-    },
-    // 多选框选中数据
-    handleSelectionChange(selection) {
-      this.ids = selection.map(item => item.attrClsID)
-      this.single = selection.length!==1
-      this.multiple = !selection.length
-    },
-    /** 新增按钮操作 */
-    handleAdd() {
-      this.reset();
-      this.open = true;
-      this.title = "添加实体类属性";
-    },
-    /** 修改按钮操作 */
-    handleUpdate(row) {
-      this.reset();
-      const attrClsID = row.attrClsID || this.ids
-      getClassAttribute(attrClsID).then(response => {
-        this.form = response.data;
-        this.open = true;
-        this.title = "修改实体类属性";
-      });
-    },
-    /** 提交按钮 */
-    submitForm() {
-      this.$refs["form"].validate(valid => {
-        if (valid) {
-          if (this.form.attrClsID != null) {
-            updateClassAttribute(this.form).then(response => {
-              this.$modal.msgSuccess("修改成功");
-              this.open = false;
-              this.getList();
-            });
-          } else {
-            addClassAttribute(this.form).then(response => {
-              this.$modal.msgSuccess("新增成功");
-              this.open = false;
-              this.getList();
-            });
-          }
-        }
-      });
-    },
-    /** 删除按钮操作 */
-    handleDelete(row) {
-      const attrClsIDs = row.attrClsID || this.ids;
-      this.$modal.confirm('是否确认删除实体类属性编号为"' + attrClsIDs + '"的数据项?').then(function() {
-        return delClassAttribute(attrClsIDs);
-      }).then(() => {
-        this.getList();
-        this.$modal.msgSuccess("删除成功");
-      }).catch(() => {});
-    },
-    /** 导出按钮操作 */
-    handleExport() {
-      this.download('knowledge/classAttribute/export', {
-        ...this.queryParams
-      }, `classAttribute_${new Date().getTime()}.xlsx`)
-    }
-  }
-};
-</script>

+ 0 - 328
src/views/knowledge/classRelation/index.vue

@@ -1,328 +0,0 @@
-<template>
-  <div class="app-container">
-    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
-      <el-form-item label="关系类名称" prop="relClsName">
-        <el-input
-          v-model="queryParams.relClsName"
-          placeholder="请输入关系类名称"
-          clearable
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="关系类描述" prop="relClsMemo">
-        <el-input
-          v-model="queryParams.relClsMemo"
-          placeholder="请输入关系类描述"
-          clearable
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="关系类背景颜色" prop="backGroundColor">
-        <el-input
-          v-model="queryParams.backGroundColor"
-          placeholder="请输入关系类背景颜色"
-          clearable
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="是否模板" prop="isModel">
-        <el-input
-          v-model="queryParams.isModel"
-          placeholder="请输入是否模板"
-          clearable
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="起点实体类ID" prop="startID">
-        <el-input
-          v-model="queryParams.startID"
-          placeholder="请输入起点实体类ID"
-          clearable
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="终点实体类ID" prop="endID">
-        <el-input
-          v-model="queryParams.endID"
-          placeholder="请输入终点实体类ID"
-          clearable
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item>
-        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
-        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
-      </el-form-item>
-    </el-form>
-
-    <el-row :gutter="10" class="mb8">
-      <el-col :span="1.5">
-        <el-button
-          type="primary"
-          plain
-          icon="el-icon-plus"
-          size="mini"
-          @click="handleAdd"
-          v-hasPermi="['knowledge:classRelation:add']"
-        >新增</el-button>
-      </el-col>
-      <el-col :span="1.5">
-        <el-button
-          type="success"
-          plain
-          icon="el-icon-edit"
-          size="mini"
-          :disabled="single"
-          @click="handleUpdate"
-          v-hasPermi="['knowledge:classRelation:edit']"
-        >修改</el-button>
-      </el-col>
-      <el-col :span="1.5">
-        <el-button
-          type="danger"
-          plain
-          icon="el-icon-delete"
-          size="mini"
-          :disabled="multiple"
-          @click="handleDelete"
-          v-hasPermi="['knowledge:classRelation:remove']"
-        >删除</el-button>
-      </el-col>
-      <el-col :span="1.5">
-        <el-button
-          type="warning"
-          plain
-          icon="el-icon-download"
-          size="mini"
-          @click="handleExport"
-          v-hasPermi="['knowledge:classRelation:export']"
-        >导出</el-button>
-      </el-col>
-      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
-    </el-row>
-
-    <el-table v-loading="loading" :data="classRelationList" @selection-change="handleSelectionChange">
-      <el-table-column type="selection" width="55" align="center" />
-      <el-table-column label="关系id" align="center" prop="relClsID" />
-      <el-table-column label="关系类名称" align="center" prop="relClsName" />
-      <el-table-column label="关系类描述" align="center" prop="relClsMemo" />
-      <el-table-column label="关系类背景颜色" align="center" prop="backGroundColor" />
-      <el-table-column label="关系类类型" align="center" prop="clsType" />
-      <el-table-column label="是否模板" align="center" prop="isModel" />
-      <el-table-column label="起点实体类ID" align="center" prop="startID" />
-      <el-table-column label="终点实体类ID" align="center" prop="endID" />
-      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
-        <template slot-scope="scope">
-          <el-button
-            size="mini"
-            type="text"
-            icon="el-icon-edit"
-            @click="handleUpdate(scope.row)"
-            v-hasPermi="['knowledge:classRelation:edit']"
-          >修改</el-button>
-          <el-button
-            size="mini"
-            type="text"
-            icon="el-icon-delete"
-            @click="handleDelete(scope.row)"
-            v-hasPermi="['knowledge:classRelation:remove']"
-          >删除</el-button>
-        </template>
-      </el-table-column>
-    </el-table>
-    
-    <pagination
-      v-show="total>0"
-      :total="total"
-      :page.sync="queryParams.pageNum"
-      :limit.sync="queryParams.pageSize"
-      @pagination="getList"
-    />
-
-    <!-- 添加或修改实体类关系对话框 -->
-    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
-      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
-        <el-form-item label="关系类名称" prop="relClsName">
-          <el-input v-model="form.relClsName" placeholder="请输入关系类名称" />
-        </el-form-item>
-        <el-form-item label="关系类描述" prop="relClsMemo">
-          <el-input v-model="form.relClsMemo" placeholder="请输入关系类描述" />
-        </el-form-item>
-        <el-form-item label="关系类背景颜色" prop="backGroundColor">
-          <el-input v-model="form.backGroundColor" placeholder="请输入关系类背景颜色" />
-        </el-form-item>
-        <el-form-item label="是否模板" prop="isModel">
-          <el-input v-model="form.isModel" placeholder="请输入是否模板" />
-        </el-form-item>
-        <el-form-item label="起点实体类ID" prop="startID">
-          <el-input v-model="form.startID" placeholder="请输入起点实体类ID" />
-        </el-form-item>
-        <el-form-item label="终点实体类ID" prop="endID">
-          <el-input v-model="form.endID" placeholder="请输入终点实体类ID" />
-        </el-form-item>
-      </el-form>
-      <div slot="footer" class="dialog-footer">
-        <el-button type="primary" @click="submitForm">确 定</el-button>
-        <el-button @click="cancel">取 消</el-button>
-      </div>
-    </el-dialog>
-  </div>
-</template>
-
-<script>
-import { listClassRelation, getClassRelation, delClassRelation, addClassRelation, updateClassRelation } from "@/api/knowledge/classRelation";
-
-export default {
-  name: "ClassRelation",
-  data() {
-    return {
-      // 遮罩层
-      loading: true,
-      // 选中数组
-      ids: [],
-      // 非单个禁用
-      single: true,
-      // 非多个禁用
-      multiple: true,
-      // 显示搜索条件
-      showSearch: true,
-      // 总条数
-      total: 0,
-      // 实体类关系表格数据
-      classRelationList: [],
-      // 弹出层标题
-      title: "",
-      // 是否显示弹出层
-      open: false,
-      // 查询参数
-      queryParams: {
-        pageNum: 1,
-        pageSize: 10,
-        relClsName: null,
-        relClsMemo: null,
-        backGroundColor: null,
-        clsType: null,
-        isModel: null,
-        startID: null,
-        endID: null,
-      },
-      // 表单参数
-      form: {},
-      // 表单校验
-      rules: {
-        startID: [
-          { required: true, message: "起点实体类ID不能为空", trigger: "blur" }
-        ],
-        endID: [
-          { required: true, message: "终点实体类ID不能为空", trigger: "blur" }
-        ],
-      }
-    };
-  },
-  created() {
-    this.getList();
-  },
-  methods: {
-    /** 查询实体类关系列表 */
-    getList() {
-      this.loading = true;
-      listClassRelation(this.queryParams).then(response => {
-        this.classRelationList = response.rows;
-        this.total = response.total;
-        this.loading = false;
-      });
-    },
-    // 取消按钮
-    cancel() {
-      this.open = false;
-      this.reset();
-    },
-    // 表单重置
-    reset() {
-      this.form = {
-        relClsID: null,
-        relClsName: null,
-        relClsMemo: null,
-        backGroundColor: null,
-        clsType: null,
-        isModel: null,
-        startID: null,
-        endID: null,
-        createBy: null,
-        createTime: null,
-        updateBy: null,
-        updateTime: null
-      };
-      this.resetForm("form");
-    },
-    /** 搜索按钮操作 */
-    handleQuery() {
-      this.queryParams.pageNum = 1;
-      this.getList();
-    },
-    /** 重置按钮操作 */
-    resetQuery() {
-      this.resetForm("queryForm");
-      this.handleQuery();
-    },
-    // 多选框选中数据
-    handleSelectionChange(selection) {
-      this.ids = selection.map(item => item.relClsID)
-      this.single = selection.length!==1
-      this.multiple = !selection.length
-    },
-    /** 新增按钮操作 */
-    handleAdd() {
-      this.reset();
-      this.open = true;
-      this.title = "添加实体类关系";
-    },
-    /** 修改按钮操作 */
-    handleUpdate(row) {
-      this.reset();
-      const relClsID = row.relClsID || this.ids
-      getClassRelation(relClsID).then(response => {
-        this.form = response.data;
-        this.open = true;
-        this.title = "修改实体类关系";
-      });
-    },
-    /** 提交按钮 */
-    submitForm() {
-      this.$refs["form"].validate(valid => {
-        if (valid) {
-          if (this.form.relClsID != null) {
-            updateClassRelation(this.form).then(response => {
-              this.$modal.msgSuccess("修改成功");
-              this.open = false;
-              this.getList();
-            });
-          } else {
-            addClassRelation(this.form).then(response => {
-              this.$modal.msgSuccess("新增成功");
-              this.open = false;
-              this.getList();
-            });
-          }
-        }
-      });
-    },
-    /** 删除按钮操作 */
-    handleDelete(row) {
-      const relClsIDs = row.relClsID || this.ids;
-      this.$modal.confirm('是否确认删除实体类关系编号为"' + relClsIDs + '"的数据项?').then(function() {
-        return delClassRelation(relClsIDs);
-      }).then(() => {
-        this.getList();
-        this.$modal.msgSuccess("删除成功");
-      }).catch(() => {});
-    },
-    /** 导出按钮操作 */
-    handleExport() {
-      this.download('knowledge/classRelation/export', {
-        ...this.queryParams
-      }, `classRelation_${new Date().getTime()}.xlsx`)
-    }
-  }
-};
-</script>

+ 76 - 0
src/views/knowledge/common/Relationship_class_blank.vue

@@ -0,0 +1,76 @@
+<template>
+    <div style="text-align:center">
+        <h1><b>{{names}}</b></h1>
+        <div class="h1_span"><b>{{introduce}}</b></div>
+        <div class="flex-center" :class="[$const.version === 'base' ? 'Entity_class_blank_base' : 'Entity_class_blank_bf']"></div>
+    </div>
+</template>
+
+<script>
+  export default {
+    name: "Relationship_class_blank",
+    data() {
+      return {
+        names: `-知识图谱数据管理子系统-`,
+        introduce: `-Knowledge Graph-`
+      }
+    }
+  }
+</script>
+
+
+<style scoped>
+    .flex-center {
+        position: relative;
+    }
+
+    .Entity_class_blank_base {
+        height: 100%;
+        /* height: 660px; */
+        width: auto;
+        border-radius: 4px;
+        background-size: cover;
+        /*background-attachment:fixed;*/
+        margin-top: auto;
+        position: relative;
+        /* background-image: url("../../assets/20201207/entBlank_base.png"); */
+    }
+
+    .Entity_class_blank_bf {
+        height: 100%;
+        /* height: 660px; */
+        width: auto;
+        border-radius: 4px;
+        background-size: cover;
+        /*background-attachment:fixed;*/
+        margin-top: auto;
+        position: relative;
+        /* background-image: url("../../assets/20201207/entBlank_bf.png"); */
+    }
+
+    h1 {
+        font-size: 50px;
+        color: #38383a;
+        letter-spacing: 2px;
+        margin-top: 60px;
+    }
+
+    .h1_span {
+        color: #c6cacb;
+    }
+
+    .logo_caiji {
+        position: absolute;
+        height: 65px;
+        bottom: 30%;
+        left: 10%;
+
+    }
+
+    .flot_box {
+        bottom: 55%;
+        left: 10%;
+        position: absolute;
+    }
+</style>
+

+ 230 - 0
src/views/knowledge/common/attrEditInput.vue

@@ -0,0 +1,230 @@
+<template>
+    <div class="editable-cell">
+    <span v-if="record.attrValueType === 'TEXT' || !record.attrValueType">
+      <a-select
+              v-if="record.domain && isShow"
+              showSearch
+              :value="value"
+              placeholder="请输入关键词"
+              :defaultActiveFirstOption="false"
+              :showArrow="false"
+              @focus="handleFocus"
+              @change="handleChangeSelect"
+              style="width: 100%"
+              :notFoundContent="fetching ? undefined : notFoundContent"
+      >
+        <a-spin v-if="fetching" slot="notFoundContent" size="small"/>
+        <a-select-option
+                v-for="(d, $index) in searchResult"
+                :value="d"
+                :key="$index"
+        >{{ d }}</a-select-option
+        >
+      </a-select>
+      <a-input
+              v-else
+              v-model="value"
+              @change="handleChange"
+              :suffix="record.attrUnit"
+              @pressEnter="check"
+      />
+    </span>
+    <span class="number-input-box" v-if="record.attrValueType === 'LONG'">
+      <a-input-number
+              style="width:100%"
+              v-model="value"
+              @change="numChange"
+              :precision="0"
+              :formatter="value => `${value}`"
+              :step="1"/>
+              <div class="num-unit">{{record.attrUnit ? record.attrUnit : ''}}</div>
+    </span>
+        <span v-if="record.attrValueType === 'DATE'">
+      <a-date-picker
+              style="width: 100%"
+              @change="dataChange"
+              :defaultValue="value ?moment(value, dateFormat):moment().isAfter(moment(null,dateFormat))"
+      />
+    </span>
+    <span class="number-input-box" v-if="record.attrValueType === 'DOUBLE'">
+      <a-input-number
+              style="width:100%"
+              v-model="value"
+              @change="doubleChange"
+              :formatter="value => `${value}`"
+              :step="1"
+      />
+      <div class="num-unit">{{record.attrUnit ? record.attrUnit : ''}}</div>
+    </span>
+        <span v-if="record.attrValueType === 'BOOLEAN'">
+      <a-select
+              v-model="value"
+              style="width: 100%"
+              @change="booleanChange"
+              :allowClear="true"
+      >
+        <a-select-option value="true">{{
+          booleanText["true"]
+        }}</a-select-option>
+        <a-select-option value="false">{{
+          booleanText["false"]
+        }}</a-select-option>
+      </a-select>
+    </span>
+    </div>
+</template>
+
+<script>
+  import moment from "moment";
+  import { getDomainValue } from '@/api/graph/domain'
+
+  export default {
+    name: "attrEditInput",
+    props: {
+      record: null,
+      pValue: String
+    },
+    data() {
+      return {
+        isShow: true,
+        notFoundContent: "",
+        fetching: false,
+        searchResult: [],
+        value: this.pValue ? this.pValue : '',
+        dateFormat: this.$const.dateFormat,
+        booleanText: this.$const.booleanText,
+        editing: false // 当前是否有过修改
+      };
+    },
+    methods: {
+      moment,
+      handleFocus() {
+        const vm = this;
+        vm.fetching = true;
+        try {
+          if (this.record.domain) {
+            const domainKey = JSON.parse(this.record.domain).domainKey;
+            if (!domainKey) {
+              this.$message.error("枚举类型获取出错,请联系管理员");
+              return false;
+            }
+            getDomainValue(domainKey).then(data => {
+              if (data) {
+                vm.fetching = false;
+                vm.searchResult = data;
+              } else {
+                vm.isShow = false;
+              }
+            });
+          } else {
+            vm.fetching = false;
+          }
+        } catch (e) {
+          this.$message.error("枚举类型获取出错,请联系管理员");
+        }
+      },
+      check() {
+        // 这个if的判断,是判断整形和浮点型时,输入的值的范围是否正确
+        if ((!this.value || this.value.length === 0) && this.record.notNull) {
+          this.$message.error(this.record.attrClsName + "请选择或输入值");
+          return false;
+        }
+        try {
+          if (
+            (this.record.attrValueType === "LONG" ||
+            this.record.attrValueType === "DOUBLE")
+          ) {
+            if (!this.record.domain) {
+              this.$emit("change", this.record, this.value);
+              return true
+            }
+            const rule = JSON.parse(this.record.domain);
+            if (!rule.minValue && !rule.maxValue) {
+              // 既没有最大限制,也没有最小限制
+              if (this.editing) {
+                this.$emit("change", this.record, this.value);
+              }
+              return true;
+            }
+            if (rule.minValue && !rule.maxValue) {
+              // 有最小限制,没有最大限制
+              if (this.value < rule.minValue) {
+                this.$message.error(this.record.attrClsName + "不能比最小值还小");
+                return false;
+              }
+            }
+            if (!rule.minValue && rule.maxValue) {
+              // 没有最小限制,有最大限制
+              if (this.value > rule.maxValue) {
+                this.$message.error(this.record.attrClsName + "不能比最大值还大");
+                return false;
+              }
+            }
+            if (rule.minValue && rule.maxValue) {
+              // 有最小限制,也有最大限制
+              if (this.value < rule.minValue || this.value > rule.maxValue) {
+                //  既有最大限制,也有最小限制
+                this.$message.error(this.record.attrClsName + "值超出范围,请修改");
+                return false;
+              }
+            }
+            this.value = this.value.toString().replace(/[^\d.]/g, "") // 去除除了数字之外的值
+          }
+        } catch (e) {
+          this.$message.error(this.record.attrClsName + "枚举类型获取出错,请联系管理员");
+        }
+        if (this.editing) {
+          this.$emit('change', this.record, this.value)
+        }
+        return true
+      },
+      dataChange(moment, data) {
+        this.value = data
+        this.editing = true
+      },
+      booleanChange(data) {
+        this.value = data
+        this.editing = true
+      },
+      numChange(num) {
+        let Reg=/^[-+]?\d+$|^\d*$/;
+        Reg.test(num)
+        if(Reg.test(num)){
+          this.value = num
+          this.editing = true
+        }else{
+          this.value = 0
+          this.$message.error('请输入整数')
+        }
+      },
+      doubleChange(num) {
+        let Reg=/^(-|\+)?(\d{1,8})?([.]\d*)?$/;
+        Reg.test(num)
+        if(Reg.test(num)){
+          this.value = num
+          this.editing = true
+        }else{
+          this.value = 0
+          this.$message.error('请输入整数')
+        }
+      },
+      handleChangeSelect(value) {
+        this.value = value
+        this.editing = true
+      },
+      handleChange(e) {
+        this.value = e.target.value
+        this.editing = true
+      },
+    }
+  };
+</script>
+
+<style scoped>
+.ant-input-number{ position: relative; }
+</style>
+<style>
+.number-input-box .num-unit{ position: absolute; right: 30px; top: 1px; background: #fff; height: 30px; line-height: 30px; }
+.number-input-box .ant-input-number .ant-input-number-input-wrap .ant-input-number-input{ padding-right: 55px; }
+.number-input-box .ant-input-number-handler-wrap{ opacity: 1 !important; }
+</style>

+ 696 - 0
src/views/knowledge/common/chart.vue

@@ -0,0 +1,696 @@
+<template>
+	<div
+		id="chartContent"
+		style="position:relative;height:100%"
+		:style="{ 'min-width': minWid + 'px', 'min-height': minHei + 'px' }"
+	>
+		<div
+			style="display: flex;justify-content: flex-end;height: 30px; margin-top:10px"
+		>
+			<a-button @click="switchOPen" v-if="enable" style="display: none;"
+				>{{ isShow ? '隐藏图标' : '显示图标' }}
+			</a-button>
+			<a-button
+				type="primary"
+				@click="exportChartData"
+				style="margin-left: 10px;"
+				v-if="showExportBtn"
+				>导出数据到控制台
+			</a-button>
+			<a-button
+				type="default"
+				@click="resetChart"
+				v-if="showReset"
+				style="width: 150px;"
+				>重置
+			</a-button>
+		</div>
+		<div
+			:id="domUuid"
+			style="height: calc(100% - 40px);width: 100%"
+			v-if="isShowChart"
+		></div>
+		<div
+			class="flex-center"
+			:class="isRoad ? 'road_computed_blank' : 'relevance_blank'"
+			style="height: 100%;width: 100%;"
+			v-else
+		></div>
+		<a-dropdown
+			:visible="dropdown.show && isShowContextMenu === true"
+			:getPopupContainer="getPopupContainer"
+			:trigger="['click']"
+			style="position: absolute;z-index: 1"
+			:style="{ left: dropdown.x, top: dropdown.y }"
+		>
+			<a class="ant-dropdown-link" href="#" />
+			<a-menu slot="overlay">
+				<a-menu-item
+					v-if="!contextMenu && clickTarget.type === 'node'"
+					key="1"
+					@click="handleRemoveEntCls"
+					>隐藏选中
+				</a-menu-item>
+				<a-menu-item
+					v-if="contextMenu && contextMenu.indexOf('delete') > -1"
+					key="2"
+					@click="contextMenuDelete"
+					>排除
+				</a-menu-item>
+				<!--<a-menu-item v-if="clickTarget.type === 'node'" key="2" @click="movePosition">移动位置</a-menu-item>-->
+			</a-menu>
+		</a-dropdown>
+	</div>
+</template>
+
+<script>
+import uuid from 'uuid'
+import { NetChart } from '@/plugins/knowledge/zoomChart'
+
+// const NetChart = window.NetChart
+// const NetChart = null;
+const colors = ['rgba(111,82,184,1)',
+			'rgba(255,214,24,1)',
+			'rgba(47,195,47,1)',
+			'rgba(86,185,247,1)',
+			'rgba(234,180,4,1)',
+			'rgba(222,103,44,1)',
+			'#FEDD00',
+			'#00843D',
+			'#009A44',
+			'#4A7729',
+			'#78BE20',
+			'#007A33',
+			'#BFB800',
+			'#64A70B',
+			'#006341',
+			'#FDDA24',
+			'#009639',
+			'#43B02A',
+			'#00205B',
+			'#00629B',
+			'#64CCC9',
+			'#0093B2',
+			'#004F71',
+			'#006BA6',
+			'#003DA5',
+			'#003B5C',
+			'#008578',
+			'#0033A0',
+			'#002855',
+			'#003087',
+			'#00778B',
+			'#0082BA',
+			'#00A9CE',
+			'#002D72',
+			'#001871',
+			'#672146',
+			'#AD1AAC',
+			'#A9431E',
+			'#D57800',
+			'#643335',
+			'#FFCD00',
+			'#3E2B2E',
+			'#BE6A14',
+			'#A50034',
+			'#F9423A',
+			'#C8102E',
+			'#E4002B',
+			'#C5003E',
+			'#EF3340',
+			'#CB333B',
+			'#FC4C02',
+			'#FE5000',
+			'#FF671F',
+			'#2C2A29',
+			'#FFA300',
+			'#FBD872',
+			'#333F48',
+			'#C99700',
+			'#ABCAE9',
+			'#F4364C',
+			'#7A7D81',
+			'#C5299B',
+			'#DB3EB1',
+			'#B9975B',
+		]
+
+let g_root,
+	chart,
+	node_colors = {},
+	link_colors = {}
+let highLightCache = {}
+let isShow = true
+let _vue
+
+let isDivisionColor = false
+export default {
+	props: {
+		nodes: {
+			type: Array,
+			default: () => [],
+		},
+		links: {
+			type: Array,
+			default: () => [],
+		},
+		enable: {
+			type: Boolean,
+			default: false,
+		},
+		isDivisionColor: {
+			type: Boolean,
+			default: false,
+		},
+		isShowChart: {
+			type: Boolean,
+			default: false,
+		},
+		isShowContextMenu: {
+			type: Boolean,
+			default: false,
+		},
+		contextMenu: {
+			type: Array,
+			default: () => [],
+		},
+		isRoad: {
+			type: Boolean,
+			default: false,
+		},
+		isShowTree: {
+			type: Boolean,
+			default: false,
+		},
+		minWid: {
+			type: Number,
+			default: null,
+		},
+		minHei: {
+			type: Number,
+			default: null,
+		},
+		showExportBtn: {
+			type: Boolean,
+			default: false,
+		},
+		showRelKey: {
+			// 默认关系之间的名称显示,默认显示true:relClsName [true:'relClsName', false:'relName']
+			type: Boolean,
+			default: true,
+		},
+		isEntChart: {
+			type: Boolean,
+			default: false,
+		},
+	},
+	data() {
+		_vue = this
+		return {
+			domUuid: uuid(),
+			useNavigation: false,
+			showReset: false,
+			isShow,
+			dropdown: {
+				// 下拉菜单的样式配置
+				show: false,
+				x: null,
+				y: null,
+			},
+			chartNodes: null,
+			chartLinks: null,
+			clickTarget: {},
+			//moveid:'', // 要移动的id
+			selectedEntClsIds: [], // 选中的实体类ids
+		}
+	},
+	watch: {
+		nodes: function() {
+			this.chartNodes = this.nodes
+		},
+		links: function() {
+			this.chartLinks = this.links
+		},
+		contextMenu: function() {
+			console.log(this.contextMenu)
+		},
+	},
+	methods: {
+		getPopupContainer() {
+			return document.getElementById('chartContent')
+		},
+		// 导出图表的数据(json格式)
+		exportChartData() {
+			const nodes = chart.nodes()
+			const links = chart.links()
+			const json = {
+				nodes: [],
+				links: [],
+			}
+			for (let i = 0; i < nodes.length; i++) {
+				const node = nodes[i].data
+				node.x = nodes[i].x
+				node.y = nodes[i].y
+				json.nodes.push(node)
+			}
+			for (let l = 0; l < links.length; l++) {
+				json.links.push(links[l].data)
+			}
+			// 这里显示导出的数据,不要删
+			console.log(JSON.stringify(json))
+		},
+		// 切换图标显示和隐藏
+		switchOPen() {
+			this.isShow = isShow = !isShow
+			this.$emit('reloadChart', this.chartNodes, this.chartLinks)
+			// this.$emit('reloadChart')
+		},
+		hidePopup() {
+			this.dropdown.show = false
+		},
+		movePosition() {
+			chart.reloadData({ nodes: [{ id: this.moveid, x: 300, y: 300 }] })
+			// chart.replaceData({ nodes: [{id: this.moveid,x: 300, y: 300}] });
+		},
+		// 右键菜单删除
+		contextMenuDelete() {
+			this.dropdown.show = false
+			this.$emit('delete', this.selectedEntClsIds)
+		},
+		// 批量隐藏 实体类
+		handleRemoveEntCls() {
+			this.dropdown.show = false
+			chart.removeData({ nodes: this.selectedEntClsIds })
+			this.selectedEntClsIds = [] // 清空上次删除的ids
+		},
+		/**
+		 * 高亮时图表的样式
+		 * */
+		highLightStyle(start, end, nodes) {
+			let nodeIds = []
+			nodes.forEach((v) => {
+				if (nodeIds.indexOf(v.endEntVOS.entID) === -1) {
+					nodeIds.push(v.endEntVOS.entID)
+				}
+				if (nodeIds.indexOf(v.startEntVo.entID) === -1) {
+					nodeIds.push(v.startEntVo.entID)
+				}
+			})
+			highLightCache.nodeIds = nodeIds
+			highLightCache.linkIds = computePath(nodes)
+			chart.updateStyle()
+		},
+		/**
+		 * 取消高亮
+		 * */
+		unhighLightStyle() {
+			highLightCache = {}
+			chart.updateStyle()
+		},
+		/**
+		 * 重绘
+		 * */
+		reDraw(root, nodes, links) {
+			g_root = root
+			if (chart) {
+				chart.replaceData({
+					nodes: getNodes(nodes),
+					links: getLinks(links),
+				})
+			} else {
+				this.drawChart(root, nodes, links)
+			}
+		},
+		addDraw(root, nodes, links) {
+			if (chart) {
+				chart.addData({
+					nodes: getNodes(nodes),
+					links: getLinks(links),
+				})
+			} else {
+				this.drawChart(root, nodes, links)
+			}
+		},
+		/*
+		 * 画zoomchart
+		 * */
+		drawChart(root, nodes, links) {
+			console.log(root, nodes, links)
+			const vm = this
+
+			g_root = root
+			highLightCache = {}
+			chart = new NetChart({
+				container: document.getElementById(this.domUuid),
+				area: {},
+				legend: {
+					enabled: true,
+					margin: 20,
+				},
+				layout: this.isShowTree
+					? {
+							mode: 'hierarchy',
+							nodeSpacing: 45,
+							rowSpacing: 80,
+					  }
+					: {},
+				navigation: this.useNavigation
+					? {
+							mode: 'focusnodes',
+							autoZoomOnFocus: true,
+							// initialNodes: g_root,
+							initialNodes: nodes[0].entClsID,
+							focusNodeExpansionRadius: 1,
+							numberOfFocusNodes: 2,
+							focusNodeTailExpansionRadius: 0.5,
+					  }
+					: {},
+				style: {
+					link: { fillColor: 'rgba(0,0,0,0.4)' },
+					node: {
+						lineWidth: 2,
+						lineColor: '#09c',
+						imageCropping: true,
+					},
+					nodeLabel: {
+						// 节点label的显示样式
+						padding: 0,
+						borderRadius: 4,
+						textStyle: { font: '16px Arial', fillColor: 'black' },
+						backgroundStyle: { fillColor: 'rgba(255,255,255,0.7)' },
+					}, // 节点label的显示样式,
+					linkLabel: {
+						// 线的label显示样式
+						padding: 0,
+						borderRadius: 20, //make as round as possible
+						textStyle: { font: '20px Arial', fillColor: '#aaa' },
+						backgroundStyle: {
+							fillColor: 'rgba(255,255,255,0.6)',
+							lineColor: 'rgba(0,0,0,0)',
+						},
+						rotateWithLink: true,
+						scaleWithSize: true,
+					}, // 线的label显示样式
+					nodeStyleFunction: vm.nodeStyle, // 节点样式与配置的回调
+					linkStyleFunction: linkStyle, // 关系样式与配置的回调
+				},
+				info: {
+					enabled: true,
+					nodeContentsFunction: function(data, item) {
+						let html
+						if (data.entName) {
+							// 实体
+							html =
+								'<div class="chart_tooltip"><h3>实体名称:' +
+								data.entName +
+								'</h3>'
+						} else if (data.entClsName) {
+							// 实体类
+							html =
+								'<div class="chart_tooltip"><h3>实体类名称:' +
+								data.entClsName +
+								'</h3>'
+						}
+						if (
+							data.entName === undefined &&
+							data.entClsName === undefined
+						)
+							html = ''
+						return html
+					},
+					linkContentsFunction: function(data, item) {
+						let html =
+							'<div class="chart_tooltip"><h3>关系名称:' +
+							data.relClsName +
+							'</h3>'
+						if (data.relClsName === undefined) html = ''
+						return html
+					},
+				},
+				events: {
+					onClick: function(event, args) {
+						if (
+							!event.ctrlKey &&
+							!event.shiftKey &&
+							args.clickNode &&
+							vm.useNavigation
+						) {
+							chart.addFocusNode(args.clickNode)
+						}
+						vm.dropdown.show = false
+						vm.$emit('c_click', event, args)
+						event.preventDefault()
+					},
+					onSelectionChange: function(event, args) {
+						// 选中的实体类事件
+						vm.selectedEntClsIds = [] // 清空上一次选中
+						for (let i = 0; i < event.selection.length; i++) {
+							const item = {}
+							item.id = event.selection[i].id
+							item.label = event.selection[i].label
+							vm.selectedEntClsIds.push(item)
+						}
+					},
+					onDoubleClick: function(event, args) {
+						// 双击事件
+						vm.dropdown.show = false
+						if (args.clickNode) {
+							vm.$emit('changeRoot', args.clickNode.data.id, 1)
+						}
+						event.preventDefault()
+					},
+					onRightClick: function(event, args) {
+						// 右键
+						// vm.moveid = event.clickNode.id
+						vm.dropdown.show = true
+						vm.dropdown.x = event.x + 20 + 'px'
+						vm.dropdown.y = event.y + 50 + 'px'
+						if (args.clickNode) {
+							vm.clickTarget.type = 'node'
+							// vm.clickTarget.data = args.clickNode.data
+							this.selectedEntClsIds = [
+								{
+									id: event.clickNode.id,
+									label: event.clickNode.label,
+								},
+							]
+						} else if (args.clickLink) {
+							vm.clickTarget.type = 'link'
+						} else {
+							vm.hidePopup()
+						}
+						event.preventDefault()
+					},
+				},
+			})
+			document.oncontextmenu = function() {
+				return false
+			}
+			this.reDraw(root, nodes, links)
+		},
+		// 重定义变量
+		reloadData(obj) {
+			this.useNavigation = obj.useNavigation
+			this.showReset = obj.showReset
+		},
+		resetChart() {
+			this.$emit('resetChart')
+		},
+		/**
+		 * 销毁chart实例
+		 * */
+		destroyChart() {
+			chart = undefined
+		},
+		nodeStyle(node) {
+			// 定义节点的样式
+			const vm = this
+			let data = node.data.data ? node.data.data : node.data
+			if (vm.isEntChart) {
+				node.label = data.label
+				let r = 90
+				let g = 150
+				let b = 220
+				r -= (data.relNum - 1) * 5
+				g -= (data.relNum - 1) * 5
+				b -= (data.relNum - 1) * 5
+				node.fillColor = 'rgba(' + r + ',' + g + ',' + b + ',1)'
+				node.radius = 50 + (data.relNum - 1) * 10
+			} else {
+				if (data.entClsIcon && isShow) {
+					node.image = data.entClsIcon
+				}
+				if (data.entIcon && isShow) {
+					node.image = data.entIcon
+				}
+				node.label = data.label
+				if (data.id === g_root) {
+					if (!node.data.backGroundColor) {
+						node.fillColor = 'orange'
+					} else {
+						node.fillColor = data.backGroundColor
+					}
+				} else {
+					let lineColor = node_colors[data.entClsID]
+					if (lineColor === undefined) {
+						lineColor = getColor()
+					}
+					node.lineColor = lineColor
+					node.fillColor = 'white'
+					if (isDivisionColor) {
+						// 根据创建和修改的时间,标记颜色
+						if (data.createTime && !data.updateTime) {
+							node.lineColor = '#f5222d'
+						} else if (data.createTime == data.updateTime) {
+							node.lineColor = '#1890ff'
+						} else if (data.createTime != data.updateTime) {
+							node.lineColor = '#52c41a'
+						}
+						node.lineWidth = 3
+					} else {
+						if (!!node.data.backGroundColor) {
+							node.fillColor = data.backGroundColor
+						}
+					}
+				}
+			}
+
+			// 如果当前节点在高亮节点集合中
+			if (
+				highLightCache.nodeIds &&
+				highLightCache.nodeIds.indexOf(data.id) > -1
+			) {
+				node.fillColor = 'orange'
+			}
+		},
+	},
+	created() {
+		window.isEntChart = this.isEntChart
+		isDivisionColor = this.isDivisionColor
+	},
+	destroyed() {
+		this.destroyChart()
+	},
+}
+
+// 定义线的样式
+function linkStyle(link) {
+	// debugger
+	let data = link.data.data ? link.data.data : link.data
+	// link.label = data.label ? data.label : data.relName
+	getLinkClass(link)
+
+	if (
+		highLightCache.linkIds &&
+		highLightCache.linkIds.indexOf(data.id) > -1
+	) {
+		if (!link.data.backGroundColor) {
+			link.fillColor = 'orange'
+		} else {
+			link.fillColor = data.backGroundColor
+		}
+		link.radius = 4
+		link.label = ''
+	}
+}
+
+// 格式化成zoomchart需要的nodes
+function getNodes(nodes) {
+	nodes.forEach((node, index) => {
+		if (node.entID) node.id = node.entID
+		if (node.label === undefined) node.label = node.entName
+		if (!node_colors[node.entClsID]) {
+			node_colors[node.entClsID] = colors[index % nodes.length]
+		}
+	})
+	return nodes
+}
+
+// 格式化成zoomchart需要的links
+function getLinks(links) {
+	links.forEach((link, index) => {
+		if (link.relID) link.id = link.relID
+		if (link.from === undefined) link.from = link.startEntID
+		if (link.to === undefined) link.to = link.endEntID
+		if (!link_colors[link.relClsID]) {
+			link_colors[link.relClsID] = colors[index % links.length]
+		}
+	})
+	return links
+}
+
+// 生成随机颜色
+function getColor() {
+	let r = Math.floor(Math.random() * 255)
+	let g = Math.floor(Math.random() * 255)
+	let b = Math.floor(Math.random() * 255)
+	return 'rgba(' + r + ',' + g + ',' + b + ',0.8)'
+}
+
+// 根据关系的classType生成不同的线的样式
+function getLinkClass(link) {
+	let data = link.data.data ? link.data.data : link.data
+	if (data.classType === 'dashed') {
+		link.toDecoration = 'arrow'
+		link.lineDash = [10, 10, 2, 2]
+	} else {
+		link.toDecoration = 'arrow'
+		link.items = [
+			{
+				text: _vue.showRelKey ? data.relClsName : data.relName,
+				padding: 2,
+				backgroundStyle: {
+					fillColor: 'white',
+					// lineColor: link_colors[data.relClsID]
+					lineColor: 'black',
+				},
+				textStyle: {
+					fillColor: 'black',
+				},
+			},
+		]
+	}
+	return link
+}
+
+function computePath(nodes) {
+	let linkIds = []
+	const currentLinks = chart.links()
+	nodes.forEach((v) => {
+		let startId = v.startEntVo.entID,
+			endId = v.endEntVOS.entID
+		currentLinks.forEach((_v) => {
+			if (startId === _v.from.id && endId === _v.to.id) {
+				linkIds.push(_v.id)
+			}
+		})
+	})
+	return linkIds
+}
+</script>
+
+<style>
+.DVSL-menu-container.DVSL-menu-workaround {
+	display: none;
+}
+
+.flex-center {
+	position: relative;
+}
+
+.road_computed_blank,
+.relevance_blank {
+	width: auto;
+	border-radius: 4px;
+	background-size: cover;
+}
+
+.road_computed_blank {
+	/* background-image: url('../../assets/banner (1).png'); */
+}
+
+.relevance_blank {
+	background-size: 100% 100%;
+	/* background-image: url('../../assets/banner (2).png'); */
+}
+</style>

+ 98 - 0
src/views/knowledge/common/entityDetails.vue

@@ -0,0 +1,98 @@
+<template>
+    <a-card :title="title" class="entCls">
+        <a href="javascript:;" @click="openEntityDetail(info)" slot="extra">详情</a>
+        <ul class="chart-tooltip">
+            <li v-if="info.entClsName" class="infos">
+                <p>实体类名称:
+                    <a v-if="GOTO_ENTCLS" href="javascript:;"
+                                         @click="openEntityClsDetail(info.entClsID,info.entID)"
+                                         slot="extra">{{info.entClsName}}</a>
+                    <span v-else>{{info.entClsName}}</span>
+                </p>
+            </li>
+            <li v-if="info.entMemo" class="infos">
+                <p>实体描述:<span>{{info.entMemo}}</span></p>
+            </li>
+            <template v-for="attrs in attrList">
+                <li :key='attrs' v-if="attrs.entAttrValueVO&&attrs.entAttrValueVO.attrValue" class="attrs-list">
+                    <p>
+						<span v-if="attrs.entAttrValueVO&&attrs.entAttrValueVO.attrValue">{{attrs.attrClsName}}:{{attrs.entAttrValueVO
+                          ? attrs.entAttrValueVO.attrValue
+                          : ''}} </span>
+                        <span v-if="attrs.attrUnit"> {{attrs.attrUnit}}</span>
+                    </p>
+                </li>
+            </template>
+        </ul>
+    </a-card>
+</template>
+
+<script>
+  import { getEntityInfoByEntityId, getEntityAttrsByEntityId } from '@/api/graph/statisticalMap'
+  var isBF = false
+  export default {
+    name: 'entityDetails',
+    props: ['id', 'throwClickDetail'],
+    data() {
+      return {
+        GOTO_ENTCLS: true,
+
+        isBF,
+        title: null,
+        info: {},
+        attrList: []
+      }
+    },
+    created() {
+      const vm = this
+      getEntityInfoByEntityId(vm.id).then((response) => {
+        vm.$set(vm, 'info', response)
+        vm.$set(vm, 'title', response.entName)
+        if (response.entClsAllowAttrType.indexOf('ELEM') > -1) {
+          getEntityAttrsByEntityId(vm.id, 'ELEM').then((_response) => {
+            vm.attrList = _response
+          })
+        }
+      })
+    },
+    mounted() {
+      if (this.$const.authorityControl) {
+        this.GOTO_ENTCLS = !!this.authMap["GOTO_ENTCLS"];
+      }
+    },
+    methods: {
+      openEntityClsDetail(entClsId) {
+        const baseUrl = this.$getBaseUrl()
+        window.open(`${baseUrl}/mng/class/${entClsId}`)
+      },
+      openEntityDetail(ent) { // 跳转实体详情
+        // 通过传图参数决定是否将 “详情”事件弹出
+        if (this.throwClickDetail) {
+          this.$emit('clickDetail', this.info)
+          return
+        }
+        let eitityStr = ''
+        if (this.isBF) {
+          eitityStr = 'entity_v2'
+        } else {
+          eitityStr = 'entity'
+        }
+        const baseUrl = this.$getBaseUrl()
+        // window.open(baseUrl + '/mng/class/' + entClsID + '/' + eitityStr + '/' + entID + '/')
+        // window.open(baseUrl + '/mng/class/' + entClsID + '/entity_v2/' + entID + '/')
+        window.open(`${baseUrl}/model/${ent.entClsID}/entity_model/${ent.entID}?page=1&clsName=${ent.entClsName}&isModel=${ent.isModel}`)
+      }
+    }
+  }
+</script>
+
+<style>
+    .entCls .ant-card-extra {
+        /*border-bottom: 1px solid #e8e8e8;*/
+        /*margin-top: -2px !important;*/
+    }
+
+    .entCls .ant-card-extra {
+        padding: 10px 0;
+    }
+</style>

+ 74 - 0
src/views/knowledge/common/linkDetails.vue

@@ -0,0 +1,74 @@
+<template>
+    <a-card :title="title">
+        <!--<a href="javascript:;" @click="openEntityDetail(info.entClsID,info.entID)" slot="extra">详情</a>-->
+        <ul v-if="entCls">
+            <template v-for="(attr,k) in attrList" >
+                <li class="attrs-list">
+                    <p>
+                        属性:<span> {{attr.attrClsName}}</span>
+                    </p>
+                </li>
+            </template>
+        </ul>
+        <ul v-else>
+            <li v-if="info.startEnt" class="infos">
+                <p>起点:<span>{{info.startEnt ? info.startEnt.entName : ''}}</span></p>
+            </li>
+            <li v-if="info.endEnt" class="infos">
+                <p>终点:<span>{{info.endEnt ? info.endEnt.entName : ''}}</span></p>
+            </li>
+            <template v-for="attrs in attrList">
+                <li :key="attrs" v-if="attrs.attrValueVO&&attrs.attrValueVO.attrValue" class="attrs-list">
+                    <p>
+                        <span v-if="attrs.attrValueVO&&attrs.attrValueVO.attrValue">{{attrs.attrClsName}}:{{attrs.attrValueVO
+                          ? attrs.attrValueVO.attrValue
+                          : ''}} </span>
+                        <span v-if="attrs.attrUnit"> {{attrs.attrUnit}}</span>
+                    </p>
+                </li>
+            </template>
+        </ul>
+    </a-card>
+</template>
+
+<script>
+  import { getRelationAttr } from '@/api/graph/relationEditor'
+  import { getRelationInfoByRelationId, getRelationAttrsByRelationId } from '@/api/graph/statisticalMap'
+
+  export default {
+    name: 'linkDetails',
+    props: ['id','entCls'],
+    data () {
+      return {
+        title: null,
+        info: {},
+        attrList: []
+      }
+    },
+    created () {
+      const vm = this
+      if(vm.entCls){ // 实体类可视化点击关系
+        vm.title = vm.entCls
+        getRelationAttr(vm.id).then(data => {
+          vm.attrList = data
+        })
+      }else{ // 实体可视化点击关系
+        Promise.all([
+          getRelationInfoByRelationId(vm.id),
+          getRelationAttrsByRelationId(vm.id)]).then((response) => {
+          vm.title = response[0].relName
+          vm.info = response[0]
+          vm.attrList = response[1]
+        })
+      }
+
+    },
+    methods : {
+      openEntityDetail(entClsID,entID) {
+        // window.open('/#/mng/class/' + entClsID + '/entity/' + entID + '/relation')
+      }
+    }
+  }
+</script>
+
+<style></style>

+ 125 - 0
src/views/knowledge/common/tagEditor.vue

@@ -0,0 +1,125 @@
+
+<template>
+  <div>
+    <h3 class="attr-title">
+      标签属性
+    </h3>
+    <template v-for="(tag, index) in tags">
+      <a-tooltip v-if="tag.length > 20" :key="tag" :title="tag">
+        <a-tag
+          :key="tag"
+          :closable="true"
+          :afterClose="() => handleClose(tag)"
+        >{{`${tag.slice(0, 20)}...`}}</a-tag>
+      </a-tooltip>
+      <a-tag v-else :key="tag" :closable="true" :afterClose="() => handleClose(tag)">{{tag}}</a-tag>
+    </template>
+    <a-input
+      v-if="inputVisible"
+      ref="input"
+      type="text"
+      size="small"
+      :style="{width: '78px'}"
+      style="margin-top: 10px;"
+      :value="inputValue"
+      @change="handleInputChange"
+      @blur="handleInputConfirm"
+      @keyup.enter="handleInputConfirm"
+    />
+    <a-tag v-else @click="showInput" style="background: #fff; borderStyle: dashed;">
+      <a-icon type="plus" />新建标签
+    </a-tag>
+  </div>
+</template>
+
+<script>
+import { getTagList, deleteTag, addTag } from '@/api/graph/tag'
+export default {
+  name: "tagEditor",
+  data() {
+    return {
+      vertexId: null,
+      tags: [],
+      inputVisible: false,
+      inputValue: ""
+    };
+  },
+  props: [
+    "entid", 
+    "classid"
+  ],
+  created() {
+    this.vertexId = this.entid;
+    // this.vertexId = this.classid
+    if (this.vertexId) {
+      this.refreshTagList();
+    }
+  },
+  methods: {
+    /**
+     * 刷新tag列表
+     */
+    refreshTagList() {
+      getTagList(this.vertexId).then(data => {
+        const tags = [];
+        for (var i = 0; i < data.length; i++) {
+          tags.push(data[i].tagName);
+        }
+        this.tags = tags;
+      });
+    },
+    /**
+     * 删除标签
+     **/
+    handleClose(removedTag) {
+      deleteTag(this.vertexId, removedTag).then(data => {
+        if (data) {
+          const tags = this.tags.filter(tag => tag !== removedTag);
+          this.tags = tags;
+        }
+      });
+    },
+    /**
+     * 点击新建标签按钮
+     * */
+    showInput() {
+      this.inputVisible = true;
+      this.$nextTick(function() {
+        this.$refs.input.focus();
+      });
+    },
+    /**
+     * 输入框变化触发
+     * */
+    handleInputChange(e) {
+      this.inputValue = e.target.value;
+    },
+    /**
+     * 新建提交
+     */
+    handleInputConfirm() {
+      const inputValue = this.inputValue;
+      let tags = this.tags;
+      if (inputValue && tags.indexOf(inputValue) === -1) {
+        addTag(this.vertexId, inputValue).then(data => {
+          if (data) {
+            tags = [...tags, inputValue];
+            Object.assign(this, {
+              tags,
+              inputVisible: false,
+              inputValue: ""
+            });
+          }
+        });
+      } else if (inputValue && tags.indexOf(inputValue) > -1) {
+        this.$message.error("不可以有重名标签");
+      }
+    }
+  }
+};
+</script>
+
+<style scoped>
+.attr-title{ padding-bottom: 10px; font-weight: bold; border-bottom: 1px solid #ddd; }
+.ant-tag{ margin-top: 10px; }
+</style>

+ 0 - 297
src/views/knowledge/entity/index.vue

@@ -1,297 +0,0 @@
-<template>
-  <div class="app-container">
-    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
-      <el-form-item label="实体名称" prop="entName">
-        <el-input
-          v-model="queryParams.entName"
-          placeholder="请输入实体名称"
-          clearable
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="实体类id" prop="entClsId">
-        <el-input
-          v-model="queryParams.entClsId"
-          placeholder="请输入实体类id"
-          clearable
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="是否模板" prop="model">
-        <el-input
-          v-model="queryParams.model"
-          placeholder="请输入是否模板"
-          clearable
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="是否可以为空" prop="notNull">
-        <el-input
-          v-model="queryParams.notNull"
-          placeholder="请输入是否可以为空"
-          clearable
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item>
-        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
-        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
-      </el-form-item>
-    </el-form>
-
-    <el-row :gutter="10" class="mb8">
-      <el-col :span="1.5">
-        <el-button
-          type="primary"
-          plain
-          icon="el-icon-plus"
-          size="mini"
-          @click="handleAdd"
-          v-hasPermi="['knowledge:entity:add']"
-        >新增</el-button>
-      </el-col>
-      <el-col :span="1.5">
-        <el-button
-          type="success"
-          plain
-          icon="el-icon-edit"
-          size="mini"
-          :disabled="single"
-          @click="handleUpdate"
-          v-hasPermi="['knowledge:entity:edit']"
-        >修改</el-button>
-      </el-col>
-      <el-col :span="1.5">
-        <el-button
-          type="danger"
-          plain
-          icon="el-icon-delete"
-          size="mini"
-          :disabled="multiple"
-          @click="handleDelete"
-          v-hasPermi="['knowledge:entity:remove']"
-        >删除</el-button>
-      </el-col>
-      <el-col :span="1.5">
-        <el-button
-          type="warning"
-          plain
-          icon="el-icon-download"
-          size="mini"
-          @click="handleExport"
-          v-hasPermi="['knowledge:entity:export']"
-        >导出</el-button>
-      </el-col>
-      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
-    </el-row>
-
-    <el-table v-loading="loading" :data="entityList" @selection-change="handleSelectionChange">
-      <el-table-column type="selection" width="55" align="center" />
-      <el-table-column label="实体id" align="center" prop="entId" />
-      <el-table-column label="实体名称" align="center" prop="entName" />
-      <el-table-column label="实体描述" align="center" prop="entMemo" />
-      <el-table-column label="实体类id" align="center" prop="entClsId" />
-      <el-table-column label="是否模板" align="center" prop="model" />
-      <el-table-column label="是否可以为空" align="center" prop="notNull" />
-      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
-        <template slot-scope="scope">
-          <el-button
-            size="mini"
-            type="text"
-            icon="el-icon-edit"
-            @click="handleUpdate(scope.row)"
-            v-hasPermi="['knowledge:entity:edit']"
-          >修改</el-button>
-          <el-button
-            size="mini"
-            type="text"
-            icon="el-icon-delete"
-            @click="handleDelete(scope.row)"
-            v-hasPermi="['knowledge:entity:remove']"
-          >删除</el-button>
-        </template>
-      </el-table-column>
-    </el-table>
-    
-    <pagination
-      v-show="total>0"
-      :total="total"
-      :page.sync="queryParams.pageNum"
-      :limit.sync="queryParams.pageSize"
-      @pagination="getList"
-    />
-
-    <!-- 添加或修改实体对话框 -->
-    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
-      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
-        <el-form-item label="实体名称" prop="entName">
-          <el-input v-model="form.entName" placeholder="请输入实体名称" />
-        </el-form-item>
-        <el-form-item label="实体描述" prop="entMemo">
-          <el-input v-model="form.entMemo" type="textarea" placeholder="请输入内容" />
-        </el-form-item>
-        <el-form-item label="实体类id" prop="entClsId">
-          <el-input v-model="form.entClsId" placeholder="请输入实体类id" />
-        </el-form-item>
-        <el-form-item label="是否模板" prop="model">
-          <el-input v-model="form.model" placeholder="请输入是否模板" />
-        </el-form-item>
-        <el-form-item label="是否可以为空" prop="notNull">
-          <el-input v-model="form.notNull" placeholder="请输入是否可以为空" />
-        </el-form-item>
-      </el-form>
-      <div slot="footer" class="dialog-footer">
-        <el-button type="primary" @click="submitForm">确 定</el-button>
-        <el-button @click="cancel">取 消</el-button>
-      </div>
-    </el-dialog>
-  </div>
-</template>
-
-<script>
-import { listEntity, getEntity, delEntity, addEntity, updateEntity } from "@/api/knowledge/entity";
-
-export default {
-  name: "Entity",
-  data() {
-    return {
-      // 遮罩层
-      loading: true,
-      // 选中数组
-      ids: [],
-      // 非单个禁用
-      single: true,
-      // 非多个禁用
-      multiple: true,
-      // 显示搜索条件
-      showSearch: true,
-      // 总条数
-      total: 0,
-      // 实体表格数据
-      entityList: [],
-      // 弹出层标题
-      title: "",
-      // 是否显示弹出层
-      open: false,
-      // 查询参数
-      queryParams: {
-        pageNum: 1,
-        pageSize: 10,
-        entName: null,
-        entMemo: null,
-        entClsId: null,
-        model: null,
-        notNull: null,
-      },
-      // 表单参数
-      form: {},
-      // 表单校验
-      rules: {
-      }
-    };
-  },
-  created() {
-    this.getList();
-  },
-  methods: {
-    /** 查询实体列表 */
-    getList() {
-      this.loading = true;
-      listEntity(this.queryParams).then(response => {
-        this.entityList = response.rows;
-        this.total = response.total;
-        this.loading = false;
-      });
-    },
-    // 取消按钮
-    cancel() {
-      this.open = false;
-      this.reset();
-    },
-    // 表单重置
-    reset() {
-      this.form = {
-        entId: null,
-        entName: null,
-        entMemo: null,
-        entClsId: null,
-        model: null,
-        notNull: null,
-        createBy: null,
-        createTime: null,
-        updateBy: null,
-        updateTime: null
-      };
-      this.resetForm("form");
-    },
-    /** 搜索按钮操作 */
-    handleQuery() {
-      this.queryParams.pageNum = 1;
-      this.getList();
-    },
-    /** 重置按钮操作 */
-    resetQuery() {
-      this.resetForm("queryForm");
-      this.handleQuery();
-    },
-    // 多选框选中数据
-    handleSelectionChange(selection) {
-      this.ids = selection.map(item => item.entId)
-      this.single = selection.length!==1
-      this.multiple = !selection.length
-    },
-    /** 新增按钮操作 */
-    handleAdd() {
-      this.reset();
-      this.open = true;
-      this.title = "添加实体";
-    },
-    /** 修改按钮操作 */
-    handleUpdate(row) {
-      this.reset();
-      const entId = row.entId || this.ids
-      getEntity(entId).then(response => {
-        this.form = response.data;
-        this.open = true;
-        this.title = "修改实体";
-      });
-    },
-    /** 提交按钮 */
-    submitForm() {
-      this.$refs["form"].validate(valid => {
-        if (valid) {
-          if (this.form.entId != null) {
-            updateEntity(this.form).then(response => {
-              this.$modal.msgSuccess("修改成功");
-              this.open = false;
-              this.getList();
-            });
-          } else {
-            addEntity(this.form).then(response => {
-              this.$modal.msgSuccess("新增成功");
-              this.open = false;
-              this.getList();
-            });
-          }
-        }
-      });
-    },
-    /** 删除按钮操作 */
-    handleDelete(row) {
-      const entIds = row.entId || this.ids;
-      this.$modal.confirm('是否确认删除实体编号为"' + entIds + '"的数据项?').then(function() {
-        return delEntity(entIds);
-      }).then(() => {
-        this.getList();
-        this.$modal.msgSuccess("删除成功");
-      }).catch(() => {});
-    },
-    /** 导出按钮操作 */
-    handleExport() {
-      this.download('knowledge/entity/export', {
-        ...this.queryParams
-      }, `entity_${new Date().getTime()}.xlsx`)
-    }
-  }
-};
-</script>

+ 0 - 252
src/views/knowledge/entityAttribute/index.vue

@@ -1,252 +0,0 @@
-<template>
-  <div class="app-container">
-    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
-      <el-form-item label="属性值" prop="attrValue">
-        <el-input
-          v-model="queryParams.attrValue"
-          placeholder="请输入属性值"
-          clearable
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item>
-        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
-        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
-      </el-form-item>
-    </el-form>
-
-    <el-row :gutter="10" class="mb8">
-      <el-col :span="1.5">
-        <el-button
-          type="primary"
-          plain
-          icon="el-icon-plus"
-          size="mini"
-          @click="handleAdd"
-          v-hasPermi="['knowledge:attribute:add']"
-        >新增</el-button>
-      </el-col>
-      <el-col :span="1.5">
-        <el-button
-          type="success"
-          plain
-          icon="el-icon-edit"
-          size="mini"
-          :disabled="single"
-          @click="handleUpdate"
-          v-hasPermi="['knowledge:attribute:edit']"
-        >修改</el-button>
-      </el-col>
-      <el-col :span="1.5">
-        <el-button
-          type="danger"
-          plain
-          icon="el-icon-delete"
-          size="mini"
-          :disabled="multiple"
-          @click="handleDelete"
-          v-hasPermi="['knowledge:attribute:remove']"
-        >删除</el-button>
-      </el-col>
-      <el-col :span="1.5">
-        <el-button
-          type="warning"
-          plain
-          icon="el-icon-download"
-          size="mini"
-          @click="handleExport"
-          v-hasPermi="['knowledge:attribute:export']"
-        >导出</el-button>
-      </el-col>
-      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
-    </el-row>
-
-    <el-table v-loading="loading" :data="attributeList" @selection-change="handleSelectionChange">
-      <el-table-column type="selection" width="55" align="center" />
-      <el-table-column label="属性id" align="center" prop="attrClsId" />
-      <el-table-column label="属性值" align="center" prop="attrValue" />
-      <el-table-column label="属性描述" align="center" prop="entAndAttrType" />
-      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
-        <template slot-scope="scope">
-          <el-button
-            size="mini"
-            type="text"
-            icon="el-icon-edit"
-            @click="handleUpdate(scope.row)"
-            v-hasPermi="['knowledge:attribute:edit']"
-          >修改</el-button>
-          <el-button
-            size="mini"
-            type="text"
-            icon="el-icon-delete"
-            @click="handleDelete(scope.row)"
-            v-hasPermi="['knowledge:attribute:remove']"
-          >删除</el-button>
-        </template>
-      </el-table-column>
-    </el-table>
-
-    <pagination
-      v-show="total>0"
-      :total="total"
-      :page.sync="queryParams.pageNum"
-      :limit.sync="queryParams.pageSize"
-      @pagination="getList"
-    />
-
-    <!-- 添加或修改实体属性对话框 -->
-    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
-      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
-        <el-form-item label="属性值" prop="attrValue">
-          <el-input v-model="form.attrValue" placeholder="请输入属性值" />
-        </el-form-item>
-      </el-form>
-      <div slot="footer" class="dialog-footer">
-        <el-button type="primary" @click="submitForm">确 定</el-button>
-        <el-button @click="cancel">取 消</el-button>
-      </div>
-    </el-dialog>
-  </div>
-</template>
-
-<script>
-import { listAttribute, getAttribute, delAttribute, addAttribute, updateAttribute } from "@/api/knowledge/entityAttribute";
-
-export default {
-  name: "EntityAttribute",
-  data() {
-    return {
-      // 遮罩层
-      loading: true,
-      // 选中数组
-      ids: [],
-      // 非单个禁用
-      single: true,
-      // 非多个禁用
-      multiple: true,
-      // 显示搜索条件
-      showSearch: true,
-      // 总条数
-      total: 0,
-      // 实体属性表格数据
-      attributeList: [],
-      // 弹出层标题
-      title: "",
-      // 是否显示弹出层
-      open: false,
-      // 查询参数
-      queryParams: {
-        pageNum: 1,
-        pageSize: 10,
-        attrValue: null,
-        entAndAttrType: null,
-      },
-      // 表单参数
-      form: {},
-      // 表单校验
-      rules: {
-      }
-    };
-  },
-  created() {
-    this.getList();
-  },
-  methods: {
-    /** 查询实体属性列表 */
-    getList() {
-      this.loading = true;
-      listAttribute(this.queryParams).then(response => {
-        this.attributeList = response.rows;
-        this.total = response.total;
-        this.loading = false;
-      });
-    },
-    // 取消按钮
-    cancel() {
-      this.open = false;
-      this.reset();
-    },
-    // 表单重置
-    reset() {
-      this.form = {
-        attrClsId: null,
-        attrValue: null,
-        entAndAttrType: null,
-        createBy: null,
-        createTime: null,
-        updateBy: null,
-        updateTime: null
-      };
-      this.resetForm("form");
-    },
-    /** 搜索按钮操作 */
-    handleQuery() {
-      this.queryParams.pageNum = 1;
-      this.getList();
-    },
-    /** 重置按钮操作 */
-    resetQuery() {
-      this.resetForm("queryForm");
-      this.handleQuery();
-    },
-    // 多选框选中数据
-    handleSelectionChange(selection) {
-      this.ids = selection.map(item => item.attrClsId)
-      this.single = selection.length!==1
-      this.multiple = !selection.length
-    },
-    /** 新增按钮操作 */
-    handleAdd() {
-      this.reset();
-      this.open = true;
-      this.title = "添加实体属性";
-    },
-    /** 修改按钮操作 */
-    handleUpdate(row) {
-      this.reset();
-      const attrClsId = row.attrClsId || this.ids
-      getAttribute(attrClsId).then(response => {
-        this.form = response.data;
-        this.open = true;
-        this.title = "修改实体属性";
-      });
-    },
-    /** 提交按钮 */
-    submitForm() {
-      this.$refs["form"].validate(valid => {
-        if (valid) {
-          if (this.form.attrClsId != null) {
-            updateAttribute(this.form).then(response => {
-              this.$modal.msgSuccess("修改成功");
-              this.open = false;
-              this.getList();
-            });
-          } else {
-            addAttribute(this.form).then(response => {
-              this.$modal.msgSuccess("新增成功");
-              this.open = false;
-              this.getList();
-            });
-          }
-        }
-      });
-    },
-    /** 删除按钮操作 */
-    handleDelete(row) {
-      const attrClsIds = row.attrClsId || this.ids;
-      this.$modal.confirm('是否确认删除实体属性编号为"' + attrClsIds + '"的数据项?').then(function() {
-        return delAttribute(attrClsIds);
-      }).then(() => {
-        this.getList();
-        this.$modal.msgSuccess("删除成功");
-      }).catch(() => {});
-    },
-    /** 导出按钮操作 */
-    handleExport() {
-      this.download('knowledge/attribute/export', {
-        ...this.queryParams
-      }, `attribute_${new Date().getTime()}.xlsx`)
-    }
-  }
-};
-</script>

+ 0 - 283
src/views/knowledge/entityRelation/index.vue

@@ -1,283 +0,0 @@
-<template>
-  <div class="app-container">
-    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
-      <el-form-item label="是否模板" prop="model">
-        <el-input
-          v-model="queryParams.model"
-          placeholder="请输入是否模板"
-          clearable
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="起始实体id" prop="startEntId">
-        <el-input
-          v-model="queryParams.startEntId"
-          placeholder="请输入起始实体id"
-          clearable
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="结束实体id" prop="endEntId">
-        <el-input
-          v-model="queryParams.endEntId"
-          placeholder="请输入结束实体id"
-          clearable
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item>
-        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
-        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
-      </el-form-item>
-    </el-form>
-
-    <el-row :gutter="10" class="mb8">
-      <el-col :span="1.5">
-        <el-button
-          type="primary"
-          plain
-          icon="el-icon-plus"
-          size="mini"
-          @click="handleAdd"
-          v-hasPermi="['knowledge:entityRelation:add']"
-        >新增</el-button>
-      </el-col>
-      <el-col :span="1.5">
-        <el-button
-          type="success"
-          plain
-          icon="el-icon-edit"
-          size="mini"
-          :disabled="single"
-          @click="handleUpdate"
-          v-hasPermi="['knowledge:entityRelation:edit']"
-        >修改</el-button>
-      </el-col>
-      <el-col :span="1.5">
-        <el-button
-          type="danger"
-          plain
-          icon="el-icon-delete"
-          size="mini"
-          :disabled="multiple"
-          @click="handleDelete"
-          v-hasPermi="['knowledge:entityRelation:remove']"
-        >删除</el-button>
-      </el-col>
-      <el-col :span="1.5">
-        <el-button
-          type="warning"
-          plain
-          icon="el-icon-download"
-          size="mini"
-          @click="handleExport"
-          v-hasPermi="['knowledge:entityRelation:export']"
-        >导出</el-button>
-      </el-col>
-      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
-    </el-row>
-
-    <el-table v-loading="loading" :data="entityRelationList" @selection-change="handleSelectionChange">
-      <el-table-column type="selection" width="55" align="center" />
-      <el-table-column label="实体关系id" align="center" prop="relClsId" />
-      <el-table-column label="是否模板" align="center" prop="model" />
-      <el-table-column label="起始实体id" align="center" prop="startEntId" />
-      <el-table-column label="结束实体id" align="center" prop="endEntId" />
-      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
-        <template slot-scope="scope">
-          <el-button
-            size="mini"
-            type="text"
-            icon="el-icon-edit"
-            @click="handleUpdate(scope.row)"
-            v-hasPermi="['knowledge:entityRelation:edit']"
-          >修改</el-button>
-          <el-button
-            size="mini"
-            type="text"
-            icon="el-icon-delete"
-            @click="handleDelete(scope.row)"
-            v-hasPermi="['knowledge:entityRelation:remove']"
-          >删除</el-button>
-        </template>
-      </el-table-column>
-    </el-table>
-    
-    <pagination
-      v-show="total>0"
-      :total="total"
-      :page.sync="queryParams.pageNum"
-      :limit.sync="queryParams.pageSize"
-      @pagination="getList"
-    />
-
-    <!-- 添加或修改实体关系对话框 -->
-    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
-      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
-        <el-form-item label="是否模板" prop="model">
-          <el-input v-model="form.model" placeholder="请输入是否模板" />
-        </el-form-item>
-        <el-form-item label="起始实体id" prop="startEntId">
-          <el-input v-model="form.startEntId" placeholder="请输入起始实体id" />
-        </el-form-item>
-        <el-form-item label="结束实体id" prop="endEntId">
-          <el-input v-model="form.endEntId" placeholder="请输入结束实体id" />
-        </el-form-item>
-      </el-form>
-      <div slot="footer" class="dialog-footer">
-        <el-button type="primary" @click="submitForm">确 定</el-button>
-        <el-button @click="cancel">取 消</el-button>
-      </div>
-    </el-dialog>
-  </div>
-</template>
-
-<script>
-import { listEntityRelation, getEntityRelation, delEntityRelation, addEntityRelation, updateEntityRelation } from "@/api/knowledge/entityRelation";
-
-export default {
-  name: "EntityRelation",
-  data() {
-    return {
-      // 遮罩层
-      loading: true,
-      // 选中数组
-      ids: [],
-      // 非单个禁用
-      single: true,
-      // 非多个禁用
-      multiple: true,
-      // 显示搜索条件
-      showSearch: true,
-      // 总条数
-      total: 0,
-      // 实体关系表格数据
-      entityRelationList: [],
-      // 弹出层标题
-      title: "",
-      // 是否显示弹出层
-      open: false,
-      // 查询参数
-      queryParams: {
-        pageNum: 1,
-        pageSize: 10,
-        model: null,
-        startEntId: null,
-        endEntId: null,
-      },
-      // 表单参数
-      form: {},
-      // 表单校验
-      rules: {
-        startEntId: [
-          { required: true, message: "起始实体id不能为空", trigger: "blur" }
-        ],
-        endEntId: [
-          { required: true, message: "结束实体id不能为空", trigger: "blur" }
-        ],
-      }
-    };
-  },
-  created() {
-    this.getList();
-  },
-  methods: {
-    /** 查询实体关系列表 */
-    getList() {
-      this.loading = true;
-      listEntityRelation(this.queryParams).then(response => {
-        this.entityRelationList = response.rows;
-        this.total = response.total;
-        this.loading = false;
-      });
-    },
-    // 取消按钮
-    cancel() {
-      this.open = false;
-      this.reset();
-    },
-    // 表单重置
-    reset() {
-      this.form = {
-        relClsId: null,
-        model: null,
-        startEntId: null,
-        endEntId: null,
-        createBy: null,
-        createTime: null,
-        updateBy: null,
-        updateTime: null
-      };
-      this.resetForm("form");
-    },
-    /** 搜索按钮操作 */
-    handleQuery() {
-      this.queryParams.pageNum = 1;
-      this.getList();
-    },
-    /** 重置按钮操作 */
-    resetQuery() {
-      this.resetForm("queryForm");
-      this.handleQuery();
-    },
-    // 多选框选中数据
-    handleSelectionChange(selection) {
-      this.ids = selection.map(item => item.relClsId)
-      this.single = selection.length!==1
-      this.multiple = !selection.length
-    },
-    /** 新增按钮操作 */
-    handleAdd() {
-      this.reset();
-      this.open = true;
-      this.title = "添加实体关系";
-    },
-    /** 修改按钮操作 */
-    handleUpdate(row) {
-      this.reset();
-      const relClsId = row.relClsId || this.ids
-      getEntityRelation(relClsId).then(response => {
-        this.form = response.data;
-        this.open = true;
-        this.title = "修改实体关系";
-      });
-    },
-    /** 提交按钮 */
-    submitForm() {
-      this.$refs["form"].validate(valid => {
-        if (valid) {
-          if (this.form.relClsId != null) {
-            updateEntityRelation(this.form).then(response => {
-              this.$modal.msgSuccess("修改成功");
-              this.open = false;
-              this.getList();
-            });
-          } else {
-            addEntityRelation(this.form).then(response => {
-              this.$modal.msgSuccess("新增成功");
-              this.open = false;
-              this.getList();
-            });
-          }
-        }
-      });
-    },
-    /** 删除按钮操作 */
-    handleDelete(row) {
-      const relClsIds = row.relClsId || this.ids;
-      this.$modal.confirm('是否确认删除实体关系编号为"' + relClsIds + '"的数据项?').then(function() {
-        return delEntityRelation(relClsIds);
-      }).then(() => {
-        this.getList();
-        this.$modal.msgSuccess("删除成功");
-      }).catch(() => {});
-    },
-    /** 导出按钮操作 */
-    handleExport() {
-      this.download('knowledge/entityRelation/export', {
-        ...this.queryParams
-      }, `entityRelation_${new Date().getTime()}.xlsx`)
-    }
-  }
-};
-</script>

+ 1190 - 0
src/views/knowledge/graphEntity/attrModelEditor.vue

@@ -0,0 +1,1190 @@
+<template>
+	<div id="attrModelEditorContainer"
+			 class="container panel panel-ulli">
+		<div class="container-header"
+				 style="height: 90px;">
+			<div>
+				<a-col :span="2"
+							 class="shiti-img">
+					<div v-if="entIcon">
+						<img :src="entIcon"
+								 alt="" />
+					</div>
+					<div v-else><img :src="blankPicture"
+								 alt="" /></div>
+					<!-- ../../../assets/kong-01.png -->
+				</a-col>
+			</div>
+			<div class="panel-header shiti_panel-header"
+					 style="padding-top: 0px;display: flex;    top: 10px;position: relative;">
+				<a-icon type="dropbox" />
+				<div style="margin-right:40px;"
+						 :style="{ 'color': !entity ? '#f5222d' : ''}">
+					{{ entity ? entity : '无名称' }}
+					<h5 style="color: #8c8c8c;">
+						<!-- <ellipsis :length="50"
+											tooltip>
+							{{ entMemo }}
+						</ellipsis> -->
+					</h5>
+				</div>
+				<a-icon type="slack" />
+				<div style="">
+					{{ entityClass }}
+				</div>
+
+				<a-button @click="edit"
+									style="margin-right: 10px;margin-left: 10px">基础信息更新</a-button>
+				<a-button v-if="false"
+									style="float: right;margin-right: 10px">运行</a-button>
+				<!--                <a-button v-if="!isModel" @click="goSta" style="float: right;margin-right: 10px">可视化统计</a-button>-->
+			</div>
+		</div>
+		<!-- <a-divider /> -->
+		<a-row :gutter="10"
+					 style="    display: flex;height: calc(100% - 90px);">
+			<!-- 左侧菜单 -->
+			<a-col :span="4"
+						 class="left-menu"
+						 style="height:100%;background:#f5f7fa;padding:0px">
+				<div @click="tabsChange('ELEM')"
+						 class="left-menu-item"
+						 :class="{ active: activePanel === 'ELEM' }">
+					基本属性
+				</div>
+				<div @click="tabsChange('OTHER')"
+						 class="left-menu-item"
+						 :class="{ active: activePanel === 'OTHER' }">
+					其他属性
+				</div>
+				<a-collapse v-model="activeColl"
+										:expandIconPosition="'right'"
+										class="left-menu-coll"
+										ref="collapse"
+										style="height: calc(100% - 90px);">
+					<a-collapse-panel key="relation"
+														header="关联关系"
+														:style="{ border: 'none' }">
+						<a-collapse v-model="activerelclsColl"
+												:expandIconPosition="'right'"
+												class="left-menu-coll"
+												ref="collapse">
+							<a-collapse-panel v-for="item in relclsLists"
+																:key="item.name"
+																:header="item.name"
+																:style="{ border: 'none' }">
+								<div class="menu-panel">
+									<p v-for="tab in item.children"
+										 :key="tab.relClsId"
+										 class="left-menu-item"
+										 :class="{ active: activePanel === tab.relClsId }"
+										 @click="tabsChange(tab.relClsId)">
+										<a-icon v-if="tab.direction === 'START'"
+														type="left-square" />
+										<a-icon v-if="tab.direction !== 'START'"
+														type="right-square" />
+										<!-- <ellipsis :length="50"
+															tooltip>
+											{{ tab.otherVName }}
+											<span slot="tooltipTitle"
+														v-if="tab.direction === 'START'">
+												{{ entityClass }}->{{ tab.relClsName }}->{{
+                          tab.otherVName
+                        }}
+											</span>
+											<span slot="tooltipTitle"
+														v-else>
+												{{ tab.otherVName }}->{{ tab.relClsName }}->{{
+                          entityClass
+                        }}
+											</span>
+										</ellipsis> -->
+									</p>
+								</div>
+							</a-collapse-panel>
+						</a-collapse>
+						<div class="menu-panel">
+							<p v-for="tab in relclsList"
+								 :key="tab.relClsId"
+								 class="left-menu-item"
+								 :class="{ active: activePanel === tab.relClsId }"
+								 @click="tabsChange(tab.relClsId)">
+								<a-icon v-if="tab.direction === 'START'"
+												type="left-square" />
+								<a-icon v-if="tab.direction !== 'START'"
+												type="right-square" />
+								<!-- <ellipsis :length="50"
+													tooltip>
+									{{ tab.relClsName }}
+									<span slot="tooltipTitle"
+												v-if="tab.direction === 'START'">
+										{{ entityClass }}->{{ tab.relClsName }}->{{
+                      tab.otherVName
+                    }}
+									</span>
+									<span slot="tooltipTitle"
+												v-else>
+										{{ tab.otherVName }}->{{ tab.relClsName }}->{{
+                      entityClass
+                    }}
+									</span>
+								</ellipsis> -->
+							</p>
+						</div>
+					</a-collapse-panel>
+
+					<a-collapse-panel v-if="ATTRCLS_GROUP_TAB"
+														key="attrcls"
+														header="复合属性"
+														:style="{ border: 'none' }">
+						<div class="menu-panel">
+							<p v-for="tab in attrcls"
+								 :key="tab.relClsId"
+								 class="left-menu-item"
+								 :class="{ active: activePanel === tab.relClsId }"
+								 @click="tabsChange(tab.relClsId)">
+								<a-icon v-if="tab.direction === 'START'"
+												type="left-square" />
+								<a-icon v-if="tab.direction !== 'START'"
+												type="right-square" />
+								<!-- <ellipsis :length="50"
+													tooltip>
+									{{ tab.relClsName }}
+									<span slot="tooltipTitle"
+												v-if="tab.direction === 'START'">
+										{{ entityClass }}->{{ tab.relClsName }}->{{
+                      tab.otherVName
+                    }}
+									</span>
+									<span slot="tooltipTitle"
+												v-else>
+										{{ tab.otherVName }}->{{ tab.relClsName }}->{{
+                      entityClass
+                    }}
+									</span>
+								</ellipsis> -->
+							</p>
+						</div>
+					</a-collapse-panel>
+				</a-collapse>
+			</a-col>
+			<!-- 中间内容 -->
+			<a-col :span="10"
+						 class="center-box">
+				<div v-if="activePanel === 'ELEM'"
+						 style="height: 100%; overflow-y: auto;">
+					<!-- 基础属性 -->
+					<div class="card-content">
+						<h3 style="font-weight: 400;color: #1f2f3d;    margin: 0px 0 20px;">
+							<a-icon type="info-circle"
+											class="warnIcons"
+											theme="filled" />
+							基础属性
+						</h3>
+						<div class="card_elem">
+							<a-row v-for="item in ELEMAttr"
+										 :key="item.attrClsId" :gutter="16">
+								<a-col :span="8">
+									<span v-if="item.notNull"
+												style="color: #f5222d">*</span>
+									{{ item.attrClsName }}:
+								</a-col>
+								<a-col :span="16">
+									<attr-edit-input :record="item"
+																	 ref="editorRef"
+																	 :pValue="item.attrValue"
+																	 @change="handleChange"></attr-edit-input>
+								</a-col>
+							</a-row>
+						</div>
+					</div>
+					<!-- 能力属性 -->
+					<div class="card-content">
+						<h3 style="font-weight: 400;color: #1f2f3d;margin: 0 0 20px;">
+							<a-icon type="info-circle"
+											class="warnIcons"
+											theme="filled" />
+							能力属性
+						</h3>
+						<div class="card_elem">
+							<a-row v-if="version=='bf'" v-for="item in CIDXAttr"
+										 :key="item.attrClsId" :gutter="16">
+								<a-col :span="8">
+									<span v-if="item.notNull"
+												style="color: #f5222d">*</span>
+									{{ item.attrClsName }}:
+								</a-col>
+								<a-col :span="12">
+									<attr-edit-input :record="item" ref="editorRef" :pValue="item.attrValue" @change="handleChange"></attr-edit-input>
+								</a-col>
+								<a-col :span="4">
+									<a-button @click="handlerRunFlow(item)">运行</a-button>
+								</a-col>
+							</a-row>
+							<a-row v-else v-for="item in CIDXAttr"
+										 :key="item.attrClsId" :gutter="16">
+								<a-col :span="8">
+									<span v-if="item.notNull"
+												style="color: #f5222d">*</span>
+									{{ item.attrClsName }}:
+								</a-col>
+								<a-col :span="16">
+									<attr-edit-input :record="item" ref="editorRef" :pValue="item.attrValue" @change="handleChange"></attr-edit-input>
+								</a-col>
+							</a-row>
+						</div>
+					</div>
+					<!-- 多媒体属性 -->
+					<div class="card-content"
+							 style="margin-bottom: 40px">
+						<h3 style="font-weight: 400;color: #1f2f3d;margin: 0 0 20px;">
+							<a-icon type="info-circle"
+											class="warnIcons"
+											theme="filled" />
+							多媒体属性
+						</h3>
+						<div class="card_elem">
+							<a-row v-for="mime in MIMEAttr"
+										 :key="mime.attrClsId">
+								<a-col :span="10"> {{ mime.attrClsName }}: </a-col>
+								<a-col :span="14">
+									<p v-if="mime.attrID">
+										<a :href="
+                        `${baseUrl}/attr/media/download/${mime.attrID}`
+                      ">{{ mime.attrValue }}</a>
+									</p>
+									<p>
+										<a-button size="small"
+															type="primary"
+															style="margin-right:5px"
+															@click="uploadFile(mime)">上传</a-button>
+										<a-button v-if="mime.attrID"
+															@click="downloadFile(mime)"
+															size="small">下载</a-button>
+									</p>
+								</a-col>
+							</a-row>
+						</div>
+					</div>
+					<div style="position: absolute; bottom: 10px;right: 10px">
+						<a-button @click="goBak"
+											style="float: right">完成</a-button>
+						<a-button type="primary"
+											@click="saveElem"
+											style="float: right;margin-right: 10px;">下一步</a-button>
+						<a-button @click="goBakNoSubmit"
+											style="float: right;margin-right: 10px;">取消</a-button>
+					</div>
+				</div>
+				<div v-if="activePanel === 'OTHER'"
+						 style="padding: 15px 20px 0 20px">
+					<h3>
+						<a-icon type="info-circle"
+										class="warnIcons"
+										theme="filled" />
+						待审属性
+					</h3>
+					<div class="card_elem">
+						<none-attr-editor :entId="entId"
+															:clsId="clsId"
+															:tType="'NONE'"
+															:isModel="isModel"></none-attr-editor>
+					</div>
+					<h3>
+						<a-icon type="info-circle"
+										class="warnIcons"
+										theme="filled" />
+						标签属性
+					</h3>
+					<div class="card_elem">
+						<tag-attr-editor :entId="entId"
+														 :isModel="isModel"></tag-attr-editor>
+					</div>
+					<a-button @click="goBak"
+										style="float: right">完成</a-button>
+					<a-button type="primary"
+										@click="next"
+										style="float: right;margin-right: 10px;">下一步</a-button>
+					<a-button type="primary"
+										@click="prev"
+										style="float: right;margin-right: 10px;">上一步</a-button>
+				</div>
+				<div v-for="(tab, $index) in rlsList"
+						 :key="tab.relClsId">
+					<div v-if="activePanel === tab.relClsId"
+							 style="padding: 15px 20px 0 20px;">
+						<attr-table ref="attrTableRef"
+												:entId="entId"
+												:clsId="clsId"
+												:otherVID="tab.otherVID"
+												:relClsId="tab.relClsId"
+												:direction="tab.direction"
+												:isModel="isModel"></attr-table>
+						<a-button type="primary"
+											@click="goBak"
+											style="float: right">完成</a-button>
+						<a-button v-if="$index < rlsList.length - 1"
+											type="primary"
+											@click="next"
+											style="float: right;margin-right: 10px;">下一步
+						</a-button>
+						<a-button type="primary"
+											@click="prev"
+											style="float: right;margin-right: 10px;">上一步</a-button>
+					</div>
+				</div>
+			</a-col>
+			<!-- 右侧可视化图谱 -->
+			<a-col :span="10"
+						 style="text-align: right;">
+				<a-button @click="openRightMenu"
+									style="margin-right: 5px;">筛选</a-button>
+				<a-button v-if="isModel === false || isModel === 'false'"
+									@click="goSta">可视化统计</a-button>
+				<chart-comp ref="chart"
+										style="max-height: 730px;"
+										@c_click="getInfoTooltip"
+										:isShowChart="true"
+										:enable="true"
+										:nodes="nodes"
+										:links="links"
+										:isDivisionColor="version=='bf'"
+										@reloadChart="reloadChart"></chart-comp>
+			</a-col>
+		</a-row>
+		<entity-details-tooltip class="chart_tooltip"
+														ref="entityRef"
+														:id="tooltip.entID"
+														:key="tooltip.entID"
+														v-if="tooltip.entID"
+														:throwClickDetail="true"
+														@clickDetail="onClickDetail"
+														style="position: absolute;z-index: 1;border-radius: 3px"
+														:style="{'left': tooltip.x, 'top': tooltip.y}"></entity-details-tooltip>
+		<link-details-tooltip class="chart_tooltip"
+													:id="tooltip.relID"
+													:key="tooltip.relID"
+													v-if="tooltip.relID"
+													style="position: absolute;z-index: 1;border-radius: 3px"
+													:style="{'left': tooltip.x, 'top': tooltip.y}">
+		</link-details-tooltip>
+	</div>
+</template>
+
+<script>
+	import entityDetailsTooltip from '@/views/knowledge/common/entityDetails'
+	import linkDetailsTooltip from '@/views/knowledge/common/linkDetails'
+	import attrTable from "@/views/knowledge/graphEntity/relationClsAttrEditor";
+	import tagAttrEditor from "@/views/knowledge/common/tagEditor";
+	import noneAttrEditor from "@/views/knowledge/graphEntity/attrEditor";
+	// import Ellipsis from "@/components/Ellipsis";
+	import attrEditInput from "@/views/knowledge/common/attrEditInput";
+	import chartComp from "@/views/knowledge/common/chart";
+	
+	import { getEntityListByEntityId } from '@/api/graph/statisticalMap'
+	import { getRelationClsByEntCls, getEntityDetailById, saveEntAttr, getRelationEnt, getChart } from '@/api/graph/entity'
+	import { getEntityAttrById, runFlow } from '@/api/graph/entityAttrEditor'
+
+	const version = 'base' // 版本控制
+	const directionsList = [
+		{ label: "出度", value: "OUT", checked: true },
+		{ label: "入度", value: "IN", checked: true },
+	];
+	import eventBus from "@/plugins/knowledge/eventBus";
+	export default {
+		name: "attrModelEditor",
+		components: {
+			attrTable,
+			tagAttrEditor,
+			noneAttrEditor,
+			attrEditInput,
+			chartComp,
+			entityDetailsTooltip,
+			linkDetailsTooltip
+		},
+		events: {
+		},
+		data () {
+			return {
+				version: version,
+				//  权限控制
+				ATTRCLS_GROUP_TAB: false,
+				baseUrl: window.global.baseUrl(),
+				entity: "",
+				entityClass: "",
+				clsId: "",
+				entId: "",
+				entIcon: "",
+				entMemo: "",
+				isModel: false, // 是否是模板,默认为实体
+				rlsList: [],
+				attrcls: [], // 复合属性列表
+				relclsList: [], // 含有多个关系类的关系列表
+				activerelclsColl: "",
+				relclsLists: [], // 含有单个关系类的关系列表
+				ELEMAttr: [],
+				CIDXAttr: [],
+				MIMEAttr: [],
+				tabs: ["ELEM", "OTHER"],
+				tabCount: 0,
+				activePanel: "ELEM",
+				activeColl: "",
+				searchLeftMenu: "",
+				//  以下是画可视化图需要的变量
+				nodes: [],
+				links: [],
+				entityClassList: [],
+				linkClassList: [],
+				degreeCache: 1,
+				entityClassCache: undefined,
+				linkClassCache: undefined,
+				directionCache: undefined,
+				directionsList,
+				tooltip: { entID: false, relID: false },// 点击的实体或关系的悬浮层
+
+                entName: '',
+                ruleList: {},
+				blankPicture: require('@/assets/knowledge/kong-01.png')
+			};
+		},
+		computed: {
+			leftMenuList: function () {
+				return this.rlsList.filter((item) => {
+					return item.relClsName.indexOf(this.searchLeftMenu) > -1;
+				});
+			},
+		},
+		mounted () {
+
+			this.clsId = this.$route.params.classId;
+			this.entId = this.$route.params.entityId;
+			this.isModel = this.$route.query.isModel;
+			this.getRelList(); // 获取关系类列表(复合属性)
+			this.getEntityInfo(); // 获取实体信息
+			this.getELEMAttr(); // 获取基础属性
+			this.getCIDXAttr(); // 获取能力属性
+			this.getMIMEAttr(); // 获取多媒体属性
+			this.$nextTick(() => {
+				this.drawChart();
+			});
+			const vm = this
+			eventBus.eventBus.$on('graph:exportData', function () {
+				vm.$refs.chart.exportChartData()
+			})
+		},
+		destroyed () {
+			eventBus.eventBus.$off('graph:exportData')
+		},
+		methods: {
+			/**
+			 * 根据ID获取实力列表和关系列表
+			 * @params id: 实体ID _string,
+			 * @params degree: 度数(跳) _string,
+			 *     entityClassList: 实体类ID列表 _string,linkClassList:关系类ID列表 _string
+			 * */
+			getEntityList (id, degree, entityClassList, linkClassList, direction) {
+				// 根据搜索记录获取实力列表,以及实体类、关系类列表
+				return getEntityListByEntityId(
+					id,
+					degree,
+					entityClassList,
+					linkClassList,
+					direction
+				);
+			},
+			getRelList () {
+				const vm = this;
+				const relclsCache = {};
+				getRelationClsByEntCls(this.clsId).then((res) => {
+					res.data.forEach((item) => {
+						if (vm.ATTRCLS_GROUP_TAB) {
+							// 如果有权限控制
+							if (item.relClsName.slice(item.relClsName.length - 2) !== "关系" && item.relClsName.slice(item.relClsName.length - 2) !== "GX") {
+								//从关系类中拆分复合属性
+								// 这个是复合属性
+								this.attrcls.push(item);
+							} else {
+								// 这些是关系类
+								if (typeof relclsCache[item.relClsName] === "undefined") {
+									relclsCache[item.relClsName] = [];
+								}
+								relclsCache[item.relClsName].push(item);
+							}
+						} else {
+							// 如果没有权限控制或者没有权限(默认的就是没有权限,因为咱们自己用不上这个复合属性)
+							if (typeof relclsCache[item.relClsName] === "undefined") {
+								relclsCache[item.relClsName] = [];
+							}
+							relclsCache[item.relClsName].push(item);
+						}
+					});
+					for (const key in relclsCache) {
+						// 拆分关系类里的中只有一个关系类和有多个关系类的情况
+						const value = relclsCache[key];
+						if (value.length > 1) {
+							this.relclsLists.push({
+								name: key,
+								children: value,
+							});
+						} else {
+							this.relclsList.push(value[0]);
+						}
+					}
+
+					this.relclsLists.forEach((item) => {
+						item.children.forEach((_item) => {
+							vm.tabs.push(_item.relClsId);
+							vm.rlsList.push(_item);
+						});
+					});
+					this.relclsList.forEach((item) => {
+						vm.tabs.push(item.relClsId);
+					});
+					this.attrcls.forEach((item) => {
+						vm.tabs.push(item.relClsId);
+					});
+					vm.rlsList = this.rlsList.concat(this.relclsList.concat(this.attrcls));
+				});
+			},
+			edit () {
+				this.$open(
+					"addEntityModal",
+					{
+						title: this.isModel ? "编辑模板" : "编辑实体",
+						isLink: true, // 添加路由后改变路由
+						isModel: this.isModel,
+						entityName: this.entity, // 实体名字
+						entityMemo: this.entMemo,
+						entClsIcon: this.entIcon,
+						entityId: this.entId, // 实体id
+					},
+					function (data) {
+						if (data) {
+							this.getEntityInfo();
+						}
+					}
+				);
+			},
+			// 悬浮框内点击详情
+			onClickDetail (info) {
+				const baseUrl = this.$getBaseUrl()
+				if (info) window.open(baseUrl + '/model/quota/entity_model/' + info.entID + '?page=1&clsName=' + info.entClsName + '&isModel=false')
+			},
+			/**
+			 * 获取实体或关系的悬浮框
+			 * @params event:zoomchart返回的event,args:zoomchart返回的变量,包含了当前点击的实体或关系的数据
+			 * */
+			getInfoTooltip (event, args) {
+				const vm = this
+				this.$set(this.tooltip, 'x', event.pageX + 'px')
+				this.$set(this.tooltip, 'y', event.pageY + 'px')
+				if (args.clickNode) {
+					vm.tooltip.entID = args.clickNode.data.entID
+					vm.tooltip.relID = false
+				} else if (args.clickLink) {
+					vm.tooltip.entID = false
+					vm.tooltip.relID = args.clickLink.data.relID
+				} else {
+					vm.tooltip.entID = false
+					vm.tooltip.relID = false
+				}
+			},
+			goSta () {
+				window.location.href = `#/sta?entId=${this.entId}&entName=${this.entity}`;
+			},
+			async goBak () {
+				let saveStatus = true;
+				if (this.activePanel === "ELEM") {
+					saveStatus = await this.saveElem(true);
+				}
+				if (saveStatus) {
+					this.goBakNoSubmit();
+				}
+			},
+			goBakNoSubmit () {
+				this.$router.push({
+					name: "class_entity_v2",
+					params: { classId: this.clsId },
+					query: {
+						...this.$route.query,
+						clsName: this.entityClass,
+					},
+				});
+			},
+			getEntityInfo () {
+				const vm = this;
+				getEntityDetailById(this.entId, this.isModel).then((res) => {
+					vm.entity = res.data.entName;
+					vm.entityClass = res.data.entClsName;
+					vm.entMemo = res.data.entMemo;
+					vm.entIcon = res.data.entIcon || res.data.entClsIcon;
+				});
+			},
+			// 获取基础和高级的属性
+			getELEMAttr () {
+				getEntityAttrById(this.entId, { attrType: "ELEM" }, this.isModel)
+					.then((res) => {
+						res.data.forEach((item) => {
+							const rule = item.domain;
+							if (rule) {
+								const jsonRule = JSON.parse(rule);
+								item.required =
+									jsonRule.domainKey !== null ||
+									(jsonRule.minValue !== null && jsonRule.maxValue !== null);
+							} else {
+								item.required = false;
+							}
+						});
+						this.ELEMAttr = res.data;
+					});
+			},
+			// 获取基础和高级的属性
+			getCIDXAttr () {
+				getEntityAttrById(this.entId, { attrType: "CIDX" }, this.isModel)
+					.then((res) => {
+						this.CIDXAttr = res.data;
+					});
+			},
+			getMIMEAttr () {
+				getEntityAttrById(this.entId, { attrType: "MIME" }, this.isModel)
+					.then((res) => {
+						this.MIMEAttr = res.data;
+					});
+			},
+			// 属性中切换下一项
+			next () {
+				this.tabCount++;
+				this.activePanel = this.tabs[this.tabCount];
+				const count = this.tabCount;
+				const varLength = 2; // 基础属性+能力属性的长度
+				const relclsLength2 = this.relclsList.length; // 单个关系类的长度
+				const attrclsLength = this.attrcls.length; // 复合属性的长度
+				let relclsLength = 0; // 多个关系类的长度
+				this.relclsLists.forEach((item) => {
+					relclsLength += item.children.length;
+				});
+				// 如果当前在关系类中
+				if (
+					count >= varLength &&
+					this.tabCount <= relclsLength + relclsLength2 + varLength
+				) {
+					this.activeColl = "relation";
+					// 当前在多个关系类中
+					if (count >= varLength && count < relclsLength + varLength) {
+						let childLength = 0;
+						let relclsIndex = 0;
+						this.relclsLists.forEach((relcls, index) => { });
+						for (let i = 0; i < this.relclsLists.length; i++) {
+							const relcls = this.relclsLists[i];
+							childLength += relcls.children.length;
+							if (count > childLength + varLength - 1) {
+								relclsIndex = i + 1;
+								break;
+							}
+						}
+						this.activerelclsColl = this.relclsLists[relclsIndex].name;
+					} else if (count >= relclsLength + varLength) {
+						// 当前在单个关系类中
+						this.activerelclsColl = "";
+					}
+				} else if (count >= relclsLength + relclsLength2 + varLength) {
+					// 当前在复合属性中
+					this.activeColl = "attrcls";
+				}
+			},
+			// 属性中切换上一项
+			prev () {
+				this.tabCount--;
+				this.activePanel = this.tabs[this.tabCount];
+				const count = this.tabCount;
+				const varLength = 2; // 基础属性+能力属性的长度
+				const relclsLength2 = this.relclsList.length; // 单个关系类的长度
+				const attrclsLength = this.attrcls.length; // 复合属性的长度
+				let relclsLength = 0; // 多个关系类的长度
+				this.relclsLists.forEach((item) => {
+					relclsLength += item.children.length;
+				});
+				if (count < varLength) {
+					this.activeColl = "";
+				} else if (
+					count >= varLength &&
+					count < relclsLength + varLength + relclsLength2
+				) {
+					this.activeColl = "relation";
+					// 当前在多个关系类中
+					if (count >= varLength && count < relclsLength + varLength) {
+						let childLength = 0;
+						let relclsIndex = 0;
+						this.relclsLists.forEach((relcls, index) => { });
+						for (let i = 0; i < this.relclsLists.length; i++) {
+							const relcls = this.relclsLists[i];
+							childLength += relcls.children.length;
+							if (count > childLength + varLength - 1) {
+								relclsIndex = i + 1;
+								break;
+							}
+						}
+						this.activerelclsColl = this.relclsLists[relclsIndex].name;
+					} else if (count >= relclsLength + varLength) {
+						// 当前在单个关系类中
+						this.activerelclsColl = "";
+					}
+				} else if (count >= relclsLength + relclsLength2 + varLength) {
+					// 当前在复合属性中
+					this.activeColl = "attrcls";
+				}
+			},
+			// tab标签切换时的回调
+			tabsChange (key) {
+				this.tabCount = this.tabs.indexOf(key);
+				this.activePanel = key;
+				if (key === "ELEM") {
+					this.getELEMAttr();
+					this.getCIDXAttr();
+				} else if (key === "OTHER") {
+				} else {
+					if (
+						this.$refs.attrTableRef &&
+						this.$refs.attrTableRef[this.tabs.indexOf(key) - 2]
+					) {
+						this.$refs.attrTableRef[this.tabs.indexOf(key) - 2].getAttr();
+					}
+				}
+			},
+			uploadFile (mime) {
+				this.$open(
+					"uploadMIMEFileModal",
+					{
+						entId: this.entId,
+						attrClsId: mime.attrClsId,
+					},
+					function (data) {
+						if (data) {
+							this.getMIMEAttr();
+						}
+					}
+				);
+			},
+			downloadFile (mime) {
+				window.location = `${window.global.baseUrl()}/attr/media/download/${mime.attrID
+					}`;
+			},
+			// 保存能力属性/基础属性
+			async saveElem (back) {
+				let check = true;
+				const editorRefs = this.$refs.editorRef;
+				if (editorRefs) {
+					editorRefs.forEach((ref) => {
+						const checkResult = ref.check();
+						if (!checkResult) {
+							check = checkResult;
+						}
+					});
+				}
+				if (!check) {
+					return false;
+				}
+				let count = 0;
+				// const content = {
+				// 	entId: this.entId,
+				// 	isModel: this.isModel,
+				// };
+				// this.CIDXAttr.forEach((item) => {
+				// 	if (item.attrValue_z) {
+				// 		content["list[" + count + "].attrClsId"] = item.attrClsId;
+				// 		content["list[" + count + "].attrId"] = item.attrID;
+				// 		content["list[" + count + "].attrValue"] = item.attrValue_z;
+				// 		content["list[" + count + "].entAndAttrType"] = "CIDX";
+				// 		count++;
+				// 	}
+				// });
+				// this.ELEMAttr.forEach((item) => {
+				// 	if (item.attrValue_z) {
+				// 		content["list[" + count + "].attrClsId"] = item.attrClsId;
+				// 		content["list[" + count + "].attrId"] = item.attrID;
+				// 		content["list[" + count + "].attrValue"] = item.attrValue_z;
+				// 		content["list[" + count + "].entAndAttrType"] = "ELEM";
+				// 		count++;
+				// 	}
+				// });
+				let attrs = [];
+				this.CIDXAttr.forEach((item) => {
+					if (item.attrValue_z) {
+						let attr = {
+							attrID: item.attrID,
+							attrValue: item.attrValue_z,
+							entId: this.entId,
+							attrClsId: item.attrClsId,
+							entAndAttrType: "CIDX"
+						}
+						attrs.push(attr)
+					}
+				});
+				this.ELEMAttr.forEach((item) => {
+					if (item.attrValue_z) {
+						let attr = {
+							attrID: item.attrID,
+							attrValue: item.attrValue_z,
+							entId: this.entId,
+							attrClsId: item.attrClsId,
+							entAndAttrType: "ELEM"
+						}
+						attrs.push(attr)
+					}
+				});
+				if (attrs.length > 0) {
+					return saveEntAttr(attrs).then((res) => {
+						if (res) {
+							this.$notification["success"]({
+								message: "属性保存成功",
+							});
+							if (back === true) {
+								return true;
+							}
+							this.next();
+						}
+					});
+				} else {
+					if (back === true) {
+						return true;
+					}
+					this.next();
+				}
+			},
+			// 表单输入框改变的方法
+			handleChange (item, value) {
+				item.attrValue_z = value;
+			},
+			reloadChart (nodes, links) {
+				this.$refs.chart.drawChart(this.entId, nodes, links);
+			},
+			drawChart () {
+				if (this.isModel === "false" || this.isModel === false) {
+					this.getEntityList(this.entId, 1).then((resp) => {
+						this.$refs.chart.drawChart(
+							this.entId,
+							resp.data.entListVO,
+							resp.data.relListVO
+						);
+						this.nodes = data.entListVO;
+						this.links = data.relListVO;
+						this.entityClassList = resp.data.entClsListVO;
+						this.linkClassList = resp.data.relClsListVO;
+					});
+				} else {
+					this.showChart = true;
+					getRelationEnt(this.entId, 1, "", "BOTH", true).then((res) => {
+						this.$refs.chart.drawChart(this.entId, res.entListVO, res.relListVO);
+					});
+				}
+			},
+			/**
+			 * 调用右侧菜单,传入实体类列表_entityClassList、关系类列表_relationClassList
+			 * */
+			// openRightMenu () {
+			// 	if (this.entityClassCache !== undefined) {
+			// 		this.entityClassList.forEach((v) => {
+			// 			if (this.entityClassCache.indexOf(v.entClsID) > -1) {
+			// 				v.checked = true;
+			// 			} else {
+			// 				v.checked = false;
+			// 			}
+			// 		});
+			// 	}
+			// 	if (this.linkClassCache !== undefined) {
+			// 		this.linkClassList.forEach((v) => {
+			// 			if (this.linkClassCache.indexOf(v.relClsID) > -1) {
+			// 				v.checked = true;
+			// 			} else {
+			// 				v.checked = false;
+			// 			}
+			// 		});
+			// 	}
+			// 	if (this.directionCache !== undefined) {
+			// 		this.directionsList.forEach((v) => {
+			// 			if (this.directionCache.indexOf(v.value) > -1) {
+			// 				v.checked = true;
+			// 			} else {
+			// 				v.checked = false;
+			// 			}
+			// 		});
+			// 	}
+			// 	this.$open(
+			// 		"rightMenuDrawer",
+			// 		{
+			// 			entityClassList: this.entityClassList,
+			// 			linkClassList: this.linkClassList,
+			// 			degreeCache: this.degreeCache,
+			// 			directionList: this.directionsList,
+			// 		},
+			// 		function (response) {
+			// 			if (response !== false) {
+			// 				let _data = response.data ? response.data : {};
+			// 				this.entityClassCache = _data.entityIds;
+			// 				this.linkClassCache = _data.linkIds;
+			// 				this.degreeCache = _data.degree;
+			// 				this.directionCache = _data.direction;
+			// 				this.getEntityList(
+			// 					this.entId,
+			// 					_data.degree,
+			// 					_data.entityIds,
+			// 					_data.linkIds,
+			// 					_data.direction
+			// 				).then((__data) => {
+			// 					this.entityClassList = __data.entClsListVO;
+			// 					this.linkClassList = __data.relClsListVO;
+			// 					this.nodes = __data.entListVO;
+			// 					this.links = __data.relListVO;
+			// 					this.directionsList.forEach((v) => {
+			// 						v.checked = true;
+			// 					});
+			// 					this.$refs.chart.reDraw(
+			// 						this.entId,
+			// 						__data.entListVO,
+			// 						__data.relListVO
+			// 					);
+			// 				});
+			// 			}
+			// 		}
+			// 	);
+			// },
+
+
+            openRightMenu() {
+                if (this.entityClassCache !== undefined) {
+                    this.entityClassList.forEach((v) => {
+                        if (this.entityClassCache.indexOf(v.entClsID) > -1) {
+                            v.checked = true
+                        } else {
+                            v.checked = false
+                        }
+                    })
+                }
+                if (this.linkClassCache !== undefined) {
+                    this.linkClassList.forEach((v) => {
+                        if (this.linkClassCache.indexOf(v.relClsID) > -1) {
+                            v.checked = true
+                        } else {
+                            v.checked = false
+                        }
+                    })
+                }
+                if (this.directionCache !== undefined) {
+                    this.directionsList.forEach((v) => {
+                        if (this.directionCache.indexOf(v.value) > -1) {
+                            v.checked = true
+                        } else {
+                            v.checked = false
+                        }
+                    })
+                }
+            
+                this.$open(
+                    'rightMenuDrawer',
+                    {
+                        entityClassList: this.entityClassList,
+                        linkClassList: this.linkClassList,
+                        degreeCache: this.degreeCache,
+                        directionList: this.directionsList,
+                        ruleList: this.ruleList,
+                        delEntityList: this.delEntIds
+                    },
+                    function(response) {
+                        if (response !== false) {
+                            this.spinning = true
+                            let _data = response.data ? response.data : {}
+                            this.entityClassCache = _data.entityIds  //参数
+                            this.linkClassCache = _data.linkIds  //参数
+                            this.degreeCache = _data.degree      //参数
+                            this.directionCache = _data.direction//方向参数
+                            this.ruleList = _data.ruleList       //高级筛选
+                            let entConditionQueries = []         //高级筛选-参数
+                            let delEntIds = _data.delEntityIds   //被删除的id-参数
+
+                            this.delEntIds = _data.delEntList
+                            //高级筛选参数拼接
+                            if(!!this.ruleList && JSON.stringify(this.ruleList)!='{}'){
+                                for(let k in this.ruleList){
+                                    let item={}
+                                    item.entClsID = k;
+                                    // item.entName = decodeURI(getQueryVariable('entName'));
+                                    let arr = this.ruleList[k]
+                                    let attrFilters = []
+                                    arr.forEach((v,i) => {
+                                        let innerItem = {
+                                            attrClsId: v.attrClsId,
+                                            attrValue: v.attrValue,
+                                            conditionType: v.conditionType,
+                                            operatorType: v.operatorType,
+                                            valueType: v.valueType
+                                        }
+                                        attrFilters.push(innerItem)
+                                    })
+                                    item['attrFilters']=attrFilters
+                                    entConditionQueries.push(item)
+                                }
+                            }else{
+                                if(!this.entityClassCache){
+                                    entConditionQueries=[]
+                                }else{
+                                    this.entityClassCache.split(',').forEach(item => {
+                                        let innerItem = {
+                                            entClsID: item,
+                                            attrFilters: []
+                                        }
+                                        entConditionQueries.push(innerItem)
+                                    })
+                                }
+                            }
+
+                            //方向参数拼接,如果为 in,out,则为both
+                            let direction = ''
+                            if(!!this.directionCache && this.directionCache.split(',').length==2){
+                                direction = 'BOTH'
+                            }else{
+                                direction = this.directionCache;
+                            }
+
+                            //高级搜索-----所有参数拼接
+                            let data = {
+                                degree: this.degreeCache,
+                                delEntIds: delEntIds,
+                                direction: direction,
+                                entId: this.entId,
+                                entName: this.entName,
+                                relClsIDs: this.linkClassCache,
+                                limitNum: 3,
+                                isModel: false,
+                                entConditionQueries: entConditionQueries
+                            }
+                        
+                            getChart(data).then(__data => {
+                                this.entityClassList = __data.entClsListVO
+                                this.linkClassList = __data.relClsListVO
+                                this.nodes = __data.entListVO
+                                this.links = __data.relListVO
+                                this.directionsList.forEach((v) => {
+                                    v.checked = true
+                                })
+                                this.$refs.chart.reDraw(
+                                    this.entId,
+                                    __data.entListVO,
+                                    __data.relListVO
+                                )
+                                this.spinning = false
+                            })
+                        }
+                    }
+                )
+            },
+			// 运行测试按钮
+			handlerRunFlow(data) {
+				const vm = this
+				let attrClsId = data.attrClsId
+				runFlow(this.entId, attrClsId, this.isModel).then((data) => {
+					vm.$message.success('计算流程启动成功');
+					this.getCIDXAttr(); // 获取能力属性
+				})
+			},
+		},
+	};
+</script>
+
+<style>
+	.ant-collapse-content > .ant-collapse-content-box {
+		padding: 0px !important;
+	}
+
+	.ant-collapse-content > .ant-collapse-content-box > .menu-panel {
+		max-height: 300px;
+		overflow-y: auto;
+	}
+
+	.shu-xing {
+		text-align: center;
+	}
+	#attrModelEditorContainer {
+		height: 100%;
+	}
+	#attrModelEditorContainer .left-menu {
+		padding-right: 0;
+		/* border-right: 1px solid #ddd; */
+		/* background: #f5f7fa; */
+	}
+
+	.left-menu-item {
+		padding: 12px 16px;
+		/* margin: 0 0 16px 0; */
+		cursor: pointer;
+	}
+
+	.ant-collapse-header:hover {
+		background: #0aa67985;
+	}
+
+	.left-menu-item:hover {
+		color: #fff;
+		background: #0aa67985;
+	}
+
+	.left-menu-item {
+		margin-bottom: 0px;
+	}
+
+	.left-menu-item.active {
+		background: #0aa679;
+		color: #fff;
+	}
+
+	.left-menu .left-menu-coll {
+		background-color: transparent;
+		border: none;
+	}
+
+	.left-menu .left-menu-coll .ant-collapse-content {
+		border: none;
+	}
+
+	#attrModelEditorContainer .ant-tabs .ant-tabs-left-bar .ant-tabs-tab {
+		text-align: left;
+	}
+
+	.card-content {
+		margin: 15px 20px 0 20px;
+	}
+
+	.card_elem {
+		border: 1px solid #e8e8e8;
+		padding: 10px;
+		border-radius: 4px;
+		margin-bottom: 20px;
+		max-height: 255px;
+		overflow-y: auto;
+	}
+
+	.let_elem {
+		text-align: right;
+		color: #999;
+		height: 32px;
+		line-height: 32px;
+	}
+
+	.warnIcons {
+		margin-right: 5px;
+		color: #0aa679 !important;
+	}
+
+	.panel-ulli .ant-tabs-nav .ant-tabs-tab-active {
+		background: #0aa679;
+		color: #fff;
+	}
+
+	.panel-ulli .ant-tabs-tab {
+		transition: color 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
+	}
+
+	.center-box {
+		border: 1px solid #e8e8e8;
+		padding: 0 !important;
+	}
+</style>

+ 51 - 30
src/views/knowledge/graphEntity/entity.vue

@@ -33,8 +33,8 @@
           v-for="item in filterEntity"
           :pagination="pagination"
           :span="8"
-          :key="item.entID"
-          @click.stop="goDeail(item.entID)"
+          :key="item.entId"
+          @click.stop="goDeail(item.entId)"
         >
           <a-card hoverable>
             <a-card-meta :title="item.entName" description>
@@ -42,8 +42,8 @@
             </a-card-meta>
             <template class="ant-card-actions" slot="actions">
               <div class="ent-link1">查看详情</div>
-              <!-- <div class="ent-link1" @click="goSta(item.entID)">图形化</div> -->
-              <div class="ent-link2" @click.stop="handleDelEntity(item.entID)">
+              <!-- <div class="ent-link1" @click="goSta(item.entId)">图形化</div> -->
+              <div class="ent-link2" @click.stop="handleDelEntity(item.entId)">
                 删除
               </div>
             </template>
@@ -149,9 +149,9 @@ export default {
     // 搜索实体
     searchEnt(searchStr, entClsIDs, current, pageSize) {
       entSearch(searchStr, entClsIDs, current, pageSize)
-        .then((data) => {
-          this.pagelist = data.entList;
-          this.pagination.total = data.count;
+        .then((resp) => {
+          this.pagelist = resp.rows;
+          this.pagination.total = resp.count;
           // this.onChange(this.pagination.current)
         });
     },
@@ -212,34 +212,55 @@ export default {
      * @param id
      */
     handleDelEntity(id) {
-      const vm = this;
-      this.$confirm({
-        title: "你确定要删除吗?",
-        onOk() {
-          delEntityById(id).then((res) => {
-            if (vm.entityClassId != "uknow") {
-              vm.searchEnt(
-                vm.entClsName,
-                vm.entityClassId,
-                vm.pagination.current,
-                vm.pagination.pageSize
+      // const vm = this;
+      // this.$confirm({
+      //   title: "你确定要删除吗?",
+      //   onOk() {
+      //     delEntityById(id).then((res) => {
+      //       if (vm.entityClassId != "uknow") {
+      //         vm.searchEnt(
+      //           vm.entClsName,
+      //           vm.entityClassId,
+      //           vm.pagination.current,
+      //           vm.pagination.pageSize
+      //         );
+      //       } else {
+      //         vm.searchEnt(
+      //           vm.entClsName,
+      //           "",
+      //           vm.pagination.current,
+      //           vm.pagination.pageSize
+      //         );
+      //       }
+      //       vm.$trigger("entity:nodeDestroyed", id);
+      //       vm.$message.success("实体删除成功");
+      //     });
+      //   },
+      //   onCancel() {
+      //     console.log("取消删除");
+      //   },
+      // });
+      this.$modal.confirm('你确定要删除吗?').then(function() {
+        return delEntityById(id);
+      }).then((resp) => {
+            if (this.entityClassId != "uknow") {
+              this.searchEnt(
+                this.entClsName,
+                this.entityClassId,
+                this.pagination.current,
+                this.pagination.pageSize
               );
             } else {
-              vm.searchEnt(
-                vm.entClsName,
+              this.searchEnt(
+                this.entClsName,
                 "",
-                vm.pagination.current,
-                vm.pagination.pageSize
+                this.pagination.current,
+                this.pagination.pageSize
               );
             }
-            vm.$trigger("entity:nodeDestroyed", id);
-            vm.$message.success("实体删除成功");
-          });
-        },
-        onCancel() {
-          console.log("取消删除");
-        },
-      });
+            this.$trigger("entity:nodeDestroyed", id);
+            this.$message.success("实体删除成功");
+      }).catch(() => {});
     },
     /**
      * 添加实体

+ 614 - 0
src/views/knowledge/graphEntity/entityTemplateList.vue

@@ -0,0 +1,614 @@
+<template>
+    <div class="flex1 flex-col ant-card-dis">
+        <a-spin :spinning="spinning">
+            <div class="container-header">
+                <a-row>
+                    <a-breadcrumb class="miao-shu">
+                        <a-breadcrumb-item>
+                            <span>来源: <span v-if="!breadcrumbList || breadcrumbList.length === 0">/</span> </span>
+                        </a-breadcrumb-item>
+                        <a-breadcrumb-item
+                                v-for="item in breadcrumbList"
+                                :key="item.entClsID"
+                        >
+                            {{ item.entClsName }}
+                        </a-breadcrumb-item>
+                    </a-breadcrumb>
+                </a-row>
+                <a-row :gutter="10">
+                    <a-col :span="2" class="shiti-img">
+                        <div v-if="entityClassTreeNode.entClsIcon">
+                            <img :src="entityClassTreeNode.entClsIcon" alt=""/>
+                        </div>
+                        <div v-else><img :src="blankPicture" alt=""/></div>
+                    </a-col>
+                    <a-col :span="22">
+                        <h2 style="margin-top: 0em">
+                            <b>{{ entityClassTreeNode.entClsName }}</b>
+                        </h2>
+                        <span class="miao-shu">
+            {{
+              entityClassTreeNode.entClsMemo
+                ? entityClassTreeNode.entClsMemo
+                : "无相关描述"
+            }}</span
+                        >
+                    </a-col>
+                </a-row>
+            </div>
+            <div class="flex1 flex-col">
+                <a-divider/>
+                <div style="margin-bottom:20px">
+                    <button
+                            style="margin-right: 5px;"
+                            class="ant-btn ant-btn-primary"
+                            @click="handleAddEntity(true)"
+                            v-if="entityClassId !== 'uknow' && ADD_ENT_MODE_BTN"
+                    >
+                        <a-icon type="plus"/>
+                        新增模板
+                    </button>
+                    <button
+                            class="ant-btn ant-btn-primary"
+                            style="margin-right: 5px;"
+                            @click="handleAddEntity"
+                            v-if="entityClassId !== 'uknow'"
+                    >
+                        <a-icon type="plus"/>
+                        新增实体
+                    </button>
+                    <button
+                            class="ant-btn ant-btn-default"
+                            @click="goEntCls"
+                            v-if="entityClassId !== 'uknow' && GOTO_ENTCLS"
+                    >
+                        <a-icon type="profile"/>
+                        实体类信息
+                    </button>
+                </div>
+                <a-tabs type="card" @change="tabChange" default-active-key="entity">
+                    <a-tab-pane key="model" v-if="ENT_MODE_LIST">
+                        <span slot="tab"> <a-icon type="home"/> 模板 </span>
+                    </a-tab-pane>
+                    <a-tab-pane key="entity">
+                        <span slot="tab"> <a-icon type="home"/> 实体 </span>
+                    </a-tab-pane>
+                </a-tabs>
+                <a-row>
+                    <a-select v-model="searchType" style="width: 120px">
+                        <a-select-option value="name">
+                            名称
+                        </a-select-option>
+                        <a-select-option value="id">
+                            大ID
+                        </a-select-option>
+                    </a-select>
+                    <a-input
+                            v-model="searchEntStr"
+                            style="width: 300px;margin-left: 5px"
+                            @keyup.enter="searchEntByName"
+                    />
+                    <a-button
+                            type="primary"
+                            @click="searchEntByName"
+                            style="margin-left: 5px"
+                    >搜索
+                    </a-button
+                    >
+                </a-row>
+                <a-row :gutter="16" style="min-height: 500px;">
+                    <a-col
+                            class="ant-card-body-flex no-arrow ent-content-card"
+                            v-for="(item, $index) in entList"
+                            :pagination="pagination"
+                            :span="8"
+                            :key="item.entId"
+                            @click.stop="goDetail(item.entId, item)"
+                    >
+                        <a-popover
+                                :title="`图谱预览:${item.entName}`"
+                                :placement="'right'"
+                                :destroyTooltipOnHide="true"
+                                @visibleChange="drawChart($event, item.entId, isModel)"
+                                :get-popup-container="getPopupContainer"
+                        >
+                            <template
+                                    slot="content"
+                                    style="min-width: 400px; min-height: 150px"
+                            >
+                                <chart-comp
+                                        :ref="`chart_${item.entId}`"
+                                        style="background: #f1f1f1;"
+                                        :minWid="400"
+                                        :minHie="200"
+                                        :isShowContextMenu="false"
+                                        :isShowChart="true"
+                                        :isRoad="false"
+                                ></chart-comp>
+                            </template>
+                            <a-card hoverable>
+                                <a-card-meta>
+                                    <template slot="title">
+                                      <span :style="{ color: !item.entName ? '#f5222d' : '' }">
+                                        {{ item.entName ? item.entName : "无名称" }}
+                                      </span>
+                                    </template>
+                                    <!-- <template slot="description">
+                                      <span>
+                                        {{ item.entMemo }}
+                                      </span>
+                                    </template> -->
+                                    <a-avatar
+                                            slot="avatar"
+                                            :src="item.entIcon ? item.entIcon : blankPicture"
+                                    />
+                                </a-card-meta>
+                                <div class="card-flex1">
+                                    {{ $moment(item.lastTime).format("YYYY-MM-DD") }}
+                                </div>
+                                <template class="ant-card-actions" slot="actions">
+                                    <div class="ent-link1">查看/编辑</div>
+                                    <!-- <div class="ent-link1" @click="goSta(item.entId)">图形化</div> -->
+                                    <div class="ent-link1" @click.stop="createByTemplate(item)">
+                                        参照创建
+                                    </div>
+                                    <div
+                                            v-if="!isModel"
+                                            class="ent-link1"
+                                            @click.stop="showQRCode(item)"
+                                    >
+                                        <a-popover
+                                                v-if="$const.version === 'bf'"
+                                                v-model="item.QRCodeCard"
+                                                :title="`二维码:${item.entName}`"
+                                                placement="top"
+                                                :destroyTooltipOnHide="true"
+                                                trigger="click"
+                                                :get-popup-container="getPopupContainer"
+                                                @visibleChange="showHideQRCode(item, $event)"
+                                        >
+                                            <template
+                                                    slot="content"
+                                                    style="min-width: 200px; min-height: 200px"
+                                            >
+                                                <div :id="'qrcode' + item.entId"></div>
+                                            </template
+                                            >
+                                            二维码
+                                        </a-popover
+                                        >
+                                    </div>
+                                    <div
+                                            class="ent-link2"
+                                            @click.stop="handleDelEntity(item.entId)"
+                                    >
+                                        删除
+                                    </div>
+                                </template>
+                            </a-card>
+                        </a-popover>
+                    </a-col>
+                </a-row>
+                <a-row style="margin-top: 30px;">
+                    <a-col>
+                        <a-pagination
+                                v-model="pagination.current"
+                                :total="pagination.total"
+                                :pageSize="pagination.pageSize"
+                                @change="onChangePagination"
+                        />
+                    </a-col>
+                </a-row>
+            </div>
+        </a-spin>
+    </div>
+</template>
+
+<script>
+  import chartComp from "@/views/knowledge/common/chart";
+  import { getRelationEnt,delEntityById } from '@/api/graph/entity'
+  import { getEntityClass } from '@/api/graph/entityClass'
+  import { entSearch } from '@/api/graph/search'
+
+  export default {
+    name: "entityTemplateList",
+    components: {
+      chartComp,
+    },
+    data() {
+      return {
+        // 功能权限控制
+        GOTO_ENTCLS: true,
+        ADD_ENT_MODE_BTN: true,
+        ENT_MODE_LIST: true,
+
+        QRCodeCard: false,
+        entityClassId: this.$route.params.classId === "uknow" ? "" : this.$route.params.classId,
+        entClsName: this.$route.query.entClsName,
+        editable: true,
+        searchType: 'name',
+        searchValue: "",
+        searchEntStr: "",
+        pagination: {
+          pageSize: 9,
+          total: 100,
+          current: this.$route.query.page ? parseInt(this.$route.query.page) : 1,
+        },
+        entList: [],
+        isModel: false,
+        breadcrumbList: [],
+        entityClassTreeNode: {
+          // 选中的实体类节点信息
+          entClsName: "",
+          entClsID: "",
+          entClsIcon: "",
+        },
+        spinning: false,
+        blankPicture: require('@/assets/knowledge/kong-01.png')
+      };
+    },
+    created() {
+      this.init();
+    },
+    mounted() {
+      if (this.$const.authorityControl) {
+        // this.GOTO_ENTCLS = !!this.authMap["GOTO_ENTCLS"];
+        // this.ADD_ENT_MODE_BTN = !!this.authMap["ADD_ENT_MODE_BTN"];
+        // this.ENT_MODE_LIST = !!this.authMap["ENT_MODE_LIST"];
+      }
+
+      const classId = this.entityClassId === "uknow" ? "" : this.entityClassId;
+      this.clsName = this.$route.query.clsName || this.$route.query.searchValue;
+      this.searchValue = this.$route.query.searchValue || "";
+      this.spinning = true
+      this.searchEnt(
+        this.searchValue,
+        classId,
+        this.pagination.current,
+        this.pagination.pageSize,
+        this.isModel
+      );
+    },
+    methods: {
+      //
+      getPopupContainer(trigger) {
+        return trigger.parentElement;
+      },
+      showQRCode(ent) {
+        if (!ent.qrcode) {
+          ent.QRCodeCard = true;
+          const qrcode = new QRCode(document.getElementById("qrcode" + ent.entId), {
+            width: 200,
+            height: 200,
+          });
+          const code = `实体类名称:${ent.entClsName}||实体名称:${ent.entName}||实体ID:${ent.entId}`;
+          ent.qrcode = qrcode
+          qrcode.makeCode(code);
+        }
+      },
+      showHideQRCode(ent, value) {
+        if (!value) {
+          ent.qrcode = undefined
+        }
+      },
+      drawChart(isShow, entId, isModel) {
+        if (isShow) {
+          getRelationEnt(entId, 2, "", "BOTH", isModel).then((res) => {
+            this.$refs[`chart_${entId}`][0].drawChart(
+              entId,
+              res.data.entListVO,
+              res.data.relListVO
+            );
+          });
+        }
+      },
+      goEntCls() {
+        this.$router.push(`/mng/class/${this.entityClassId}`);
+      },
+      init() {
+        const classId = this.$route.params.classId;
+        const _vm = this;
+        if (classId !== "uknow") {
+          getEntityClass(classId).then((data) => {
+            _vm.entityClassTreeNode.entClsName = data.entClsName;
+            _vm.entityClassTreeNode.entClsID = data.entClsID;
+            _vm.entityClassTreeNode.entClsMemo = data.entClsMemo;
+            _vm.entityClassTreeNode.entClsIcon = data.entClsIcon;
+            _vm.breadcrumbList = data.parents;
+          });
+        }
+      },
+      goDetail(entId, ent) {
+        this.$router.push({
+          name: "model_edit",
+          params: {classId: ent.entClsID, entityId: entId},
+          query: {
+            page: this.pagination.current,
+            clsName: ent.entClsName,
+            isModel: this.isModel,
+            searchValue: this.searchValue ? this.searchValue : undefined,
+          },
+        });
+      },
+      searchEntByName() {
+        this.$trigger('entityClass:clearSearch')
+        this.pagination.current = 1
+        this.spinning = true
+        this.searchEnt(
+          this.searchEntStr,
+          this.entityClassId,
+          this.pagination.current,
+          this.pagination.pageSize,
+          this.isModel,
+          this.searchType
+        );
+      },
+      // 搜索实体
+      searchEnt(searchStr, entClsIDs, current, pageSize, isModel, searchType) {
+        entSearch(searchStr, entClsIDs, current, pageSize, isModel, true, searchType)
+          .then((resp) => {
+            this.entList = resp.rows;
+            this.pagination.total = resp.total;
+            this.spinning = false
+          });
+      },
+      handleRemoveClick(e) {
+        this.$open(
+          "entityDeleteMulModal",
+          {
+            paramsId: this.entityClassId, // 实体类id
+            pagelist: this.entList,
+          },
+          function (data) {
+            if (data) {
+              const classId =
+                this.entityClassId === "uknow" ? "" : this.entityClassId;
+              this.spinning = true
+              this.searchEnt(
+                this.searchEnt,
+                classId,
+                this.pagination.current,
+                this.pagination.pageSize,
+                this.isModel
+              );
+              this.$message.success("删除成功");
+            }
+          }
+        );
+      },
+      /**
+       * 删除实体
+       * @param id
+       */
+      handleDelEntity(id) {
+        const vm = this;
+        // this.$confirm({
+        //   title: "你确定要删除吗?",
+        //   onOk() {
+        //     delEntityById(id, vm.isModel).then((res) => {
+        //       const classId =
+        //         vm.entityClassId === "uknow" ? "" : vm.entityClassId;
+        //       vm.spinning = true
+        //       vm.searchEnt(
+        //         vm.entClsName,
+        //         classId,
+        //         vm.pagination.current,
+        //         vm.pagination.pageSize,
+        //         vm.isModel
+        //       );
+        //       vm.$trigger("entity:nodeDestroyed", id);
+        //       vm.$message.success("实体删除成功");
+        //     });
+        //   },
+        //   onCancel() {
+        //     console.log("取消删除");
+        //   },
+        // });
+        this.$modal.confirm('你确定要删除吗?').then(function() {
+          return delEntityById(id, vm.isModel)
+        }).then((resp) => {
+              const classId = vm.entityClassId === "uknow" ? "" : vm.entityClassId;
+              vm.spinning = true
+              vm.searchEnt(
+                vm.entClsName,
+                classId,
+                vm.pagination.current,
+                vm.pagination.pageSize,
+                vm.isModel
+              );
+              vm.$trigger("entity:nodeDestroyed", id);
+              vm.$message.success("实体删除成功");
+        }).catch(() => {});
+      },
+      /**
+       * 添加实体
+       */
+      handleAddEntity(bool) {
+        this.$open(
+          "addEntityModal",
+          {
+            title: bool === true ? "新增模板" : "新增实体",
+            paramsId: this.entityClassId, // 实体类id
+            isModel: bool === true,
+            className: this.clsName,
+          },
+          function (data) {
+            if (data) {
+              this.isModel = bool === true;
+              this.goDetail(data, {
+                entClsName: this.clsName,
+                entClsID: this.entityClassId
+              });
+            }
+          }
+        );
+      },
+      // 参照创建按钮
+      handleAddModelEntity() {
+        this.$open(
+          "addTemplateEntityModal",
+          {
+            title: this.isModel ? "新增模板" : "新增实体",
+            paramsId: this.entityClassId, // 实体类id
+            isModel: this.isModel,
+            className: this.clsName,
+          },
+          function (data) {
+            if (data) {
+              this.goDetail(data, {
+                entClsName: this.clsName,
+                entClsID: this.entityClassId
+              });
+            }
+          }
+        );
+      },
+      onChangePagination(current) {
+        const searchValue = this.searchValue || this.searchEntStr
+        this.spinning = true
+        this.searchEnt(
+          searchValue,
+          this.entityClassId,
+          current,
+          this.pagination.pageSize,
+          this.isModel
+        );
+      },
+      // tab标签切换的回调
+      tabChange(key) {
+        this.isModel = key === "model";
+        const classId = this.entityClassId === "uknow" ? "" : this.entityClassId;
+        this.spinning = true
+        this.searchEnt(
+          this.entClsName,
+          classId,
+          this.pagination.current,
+          this.pagination.pageSize,
+          this.isModel
+        );
+      },
+      // 模板参照创建
+      createByTemplate(item) {
+        this.$open(
+          "addTemplateEntityModal",
+          {
+            title: "创建模板",
+            paramsId: this.entityClassId, // 实体类id
+            isModel: this.isModel,
+            entityId: item.entId,
+            entityName: item.entName,
+            className: this.clsName,
+            startIsModel: false
+          },
+          function (data) {
+            if (data) {
+              this.spinning = true
+              this.searchEnt(
+                "",
+                this.entityClassId,
+                this.pagination.current,
+                this.pagination.pageSize,
+                this.isModel
+              );
+            }
+          }
+        );
+      },
+    },
+  };
+</script>
+<style lang="less">
+    .ant-card-body-flex .ant-card-bordered .ant-card-body {
+        display: flex !important;
+        box-shadow: none;
+    }
+
+    .ant-card-dis .ant-card-meta-detail {
+        width: 190px;
+    }
+
+    .ant-card-body-flex .ant-card-meta-title,
+    .ant-card-meta-description {
+        overflow: hidden;
+        text-overflow: ellipsis;
+        white-space: nowrap;
+    }
+</style>
+
+<style scoped>
+    .ant-avatar {
+        border-radius: 4px;
+    }
+
+    .panel-header {
+        display: block;
+    }
+
+    .ant-card {
+        margin-top: 20px;
+        border: 1px solid #ddd;
+        border-radius: 6px;
+        cursor: pointer;
+    }
+
+    .ant-card:hover {
+        border: 1px solid #0aa679;
+    }
+
+    .ant-card:hover .ant-card-body {
+        color: #0aa679;
+    }
+
+    .ant-btn-add {
+        position: absolute;
+        right: 0;
+        top: 50%;
+        margin-top: -21px;
+        height: 32px;
+    }
+
+    .ent-link1,
+    .ent-link2 {
+        width: 100%;
+        text-align: center;
+    }
+
+    .ent-link1 {
+        color: #0aa679;
+    }
+
+    .ent-link2 {
+        color: #999;
+    }
+
+    .ent-link1:hover {
+        color: #27b386;
+    }
+
+    .ent-link2:hover {
+        color: #0aa679;
+    }
+
+    .ant-card-body {
+        background: #eee;
+    }
+
+    .ant-card-actions > li > span {
+        display: block;
+        width: 100%;
+        height: 100%;
+    }
+
+    .ant-avatar {
+        width: 40px;
+        height: 40px;
+        background: require('@/assets/knowledge/kong-01.png') no-repeat;
+        background-size: 40px 40px;
+    }
+
+    .card-flex1 {
+        flex: 1;
+        text-align: right;
+    }
+
+</style>

+ 251 - 0
src/views/knowledge/graphEntity/relationClsAttrEditor.vue

@@ -0,0 +1,251 @@
+<template>
+    <div class="flex-col">
+        <h3 style="font-weight: 400;color: #1f2f3d;    margin: 0px 0 20px;">
+            <a-icon type="info-circle" class="warnIcons" theme="filled" />
+            关联关系
+        </h3>
+        <div style="margin-bottom: 10px">
+            <a-button type="primary" @click="addEnt" style="margin-right: 10px">新增关联实体</a-button>
+            <a-button type="primary" @click="selectEnt" style="margin-right: 10px">选择关联实体</a-button>
+            <a-button type="primary" @click="dels">删除</a-button>
+        </div>
+        <a-table :pagination="false" :loading="loading" :columns="columns" :data-source="data" :row-selection="{ onChange: onTableSelect }">
+            <span slot="entName" slot-scope="text, record">
+                <a @click="openNewPage(record)">{{text}}</a>
+            </span>
+            <span slot="action" slot-scope="text, record">
+                <a @click="edit(record)" style="margin-right: 5px">编辑</a>
+                <a-popconfirm title="此操作无法恢复,请确认是否删除?"
+                              @confirm="() => del(record)">
+                  <a href="javascript:;" class="spanMarginl">删除</a>
+                </a-popconfirm>
+            </span>
+        </a-table>
+        <a-row style="margin-top: 30px;">
+            <a-col>
+                <a-pagination
+                        v-model="pagination.current"
+                        :total="pagination.total"
+                        :pageSize="pagination.pageSize"
+                        @change="onChangePagination"/>
+            </a-col>
+        </a-row>
+    </div>
+</template>
+
+<script>
+  import { getRelationAttr } from '@/api/graph/entity'
+  import { addRelBatch, deleteEntityRelation } from '@/api/graph/relationClass'
+
+  export default {
+    name: "relationClsAttrEditor",
+    props: ['entId', 'relClsId', 'direction', 'isModel', 'clsId', 'otherVID'],
+    data() {
+      return {
+        data: [],
+        columns: [
+          {
+            title: '实体名称',
+            dataIndex: 'entName',
+            key: 'entName',
+            scopedSlots: {customRender: 'entName'},
+          },
+          {
+            title: '操作',
+            key: 'action',
+            scopedSlots: {customRender: 'action'},
+          },
+        ],
+        loading: false,
+        selectRows: [],
+        columnsIdCache: [],
+        columnsCache: [],
+        pagination: {
+          pageSize: 9,
+          total: 100,
+          current: 1
+        }
+      }
+    },
+    mounted() {
+      this.getAttr()
+    },
+    methods: {
+      // 获取属性
+      getAttr() {
+        const vm = this
+        this.loading = true
+        getRelationAttr(this.entId, this.relClsId, this.direction, this.isModel, this.pagination.current, this.pagination.pageSize).then(res => {
+          const attrClsNameList = {}
+          this.pagination.total = res.total
+          // 组装表格columns
+          res.headers.reverse().forEach(item => {
+            if (vm.columnsIdCache.indexOf(item.attrClsId) === -1) {
+              attrClsNameList[item.attrClsId] = item.attrClsName
+              vm.columnsIdCache.push(item.attrClsId)
+              vm.columnsCache.push({
+                attrClsId: item.attrClsId,
+                attrClsName: item.attrClsName
+              })
+              vm.columns.splice(1, 0, {
+                dataIndex: item.attrClsId,
+                key: item.attrClsId,
+                title: item.attrClsName
+              })
+            }
+          })
+          res.records.forEach(item => {
+            item.key = item.entID
+            // 新建的关系类没有属性,给一个空的属性列表,方便后面操作
+            item.attrList ? item.attrList.forEach(attr => {
+              item[attr.attrClsId] = attr.attrValue
+              item[attr.attrClsId + '_name'] = attrClsNameList[attr.attrClsId]
+            }) : item.attrList = []
+          })
+          vm.data = res.records
+          vm.loading = false
+        })
+      },
+      openNewPage(record) {
+        const params = this.$route.params
+        const query = this.$route.query
+        const location = window.location
+        const url = location.origin + location.pathname + '#/model/' + params.classId + '/entity_model/' + record.entID + '?page=' + query.page + '&clsName=' + query.clsName + '&entName=' + record.entName + '&isModel=' + query.isModel
+        window.open(url)
+      },
+      // 表格选中行后的回调
+      onTableSelect(selectedRowKeys, selectedRows) {
+        this.selectRows = selectedRows
+      },
+      // 分页变更
+      onChangePagination(current) {
+        this.pagination.current = current
+        this.getAttr()
+      },
+      // 新增实体
+      addEnt() {
+        this.$open(
+          'addEntityModal',
+          {
+            title: '新增实体',
+            paramsId: this.otherVID, // 实体类id
+            isModel: this.isModel
+          },
+          function (data) {
+            if (data) {
+              this.addRelEnt(data)
+            }
+          }
+        )
+      },
+      // 新增关系类实体
+      addRelEnt(data) {
+        const entityContent = {
+          isModel: this.isModel,
+          relClsId: this.relClsId,
+          'list[0].startEntId': '',
+          'list[0].endEntId': '',
+        }
+        if (this.direction === 'START') {
+          entityContent['list[0].startEntId'] = this.entId
+          entityContent['list[0].endEntId'] = data
+        } else {
+          entityContent['list[0].startEntId'] = data
+          entityContent['list[0].endEntId'] = this.entId
+        }
+        addRelBatch(entityContent).then(res => {
+          if (res) {
+            this.getAttr()
+          }
+        })
+      },
+      // 选择实体
+      selectEnt() {
+        this.$open(
+          'addRelBatchModal',
+          {
+            relClsId: this.relClsId, // 实体类id
+            isModel: this.isModel,
+            direction: this.direction,
+            entId: this.entId
+          },
+          function (data) {
+            if (data) {
+              this.getAttr()
+            }
+          }
+        )
+      },
+      // 编辑
+      edit(record) {
+        // 如果新增实体,没有属性类
+        if (record.attrList.length === 0) {
+          this.columnsCache.forEach(cls => {
+            record.attrList.push({
+              attrClsId: cls.attrClsId,
+              attrValue: ''
+            })
+            record[cls.attrClsId] = ''
+            record[cls.attrClsId + '_name'] = cls.attrClsName
+          })
+        }
+        this.columnsCache.forEach(cls => {
+          let hasCls = false;
+          record.attrList.forEach(attr => {
+            if (attr.attrClsId === cls.attrClsId) hasCls = true
+          })
+          if (!hasCls) {
+            record.attrList.push({
+              attrClsId: cls.attrClsId,
+              attrValue: ''
+            })
+            record[cls.attrClsId] = ''
+            record[cls.attrClsId + '_name'] = cls.attrClsName
+          }
+        })
+        this.$open(
+          'editTemplateRelAttrbatchModal',
+          {
+            record: record, // 实体类id
+            isModel: this.isModel
+          },
+          function (data) {
+            if (data) {
+              this.getAttr()
+            }
+          }
+        )
+      },
+      // 批量删除
+      dels() {
+        const ids = []
+        this.selectRows.forEach(row => {
+          ids.push(row.relId)
+        })
+        deleteEntityRelation(ids.join(','), this.isModel).then(res => {
+          if (res) {
+            this.$notification["success"]({
+              message: "删除成功"
+            });
+            this.getAttr()
+          }
+        })
+      },
+      // 表格删除
+      del(record) {
+        deleteEntityRelation(record.relId, this.isModel).then(res => {
+          if (res) {
+            this.$notification["success"]({
+              message: "删除成功"
+            });
+            this.getAttr()
+          }
+        })
+      }
+    }
+  }
+</script>
+
+<style scoped>
+
+</style>

+ 254 - 0
src/views/knowledge/modal/addEntityModal.vue

@@ -0,0 +1,254 @@
+<template>
+    <a-modal
+            :title="headTitle"
+            :visible="show"
+            :maskClosable="false"
+            @ok="handleOk"
+            @cancel="handleClose"
+    >
+        <div style="display: flex">
+            <div style="width:130px;">
+                <div style="width:100px;height:100px;overflow:hidden;border:1px solid #ddd">
+                    <img style="width:100px;height:100px;" :src="headImg" alt="头像" v-if="headImg">
+                </div>
+                <label class="btn btn-orange" for="uploads"
+                       style="display:inline-block;width: 100px;padding: 0;text-align: center;line-height: 28px;border:1px solid #ccc;margin-top: 20px;">选择图片</label>
+                <input type="file" id="uploads" :value="imgFile"
+                       style="position:absolute; clip:rect(0 0 0 0);display: none"
+                       accept="image/png, image/jpeg, image/gif, image/jpg" @change="uploadImg($event, 1)">
+            </div>
+            <a-form :form="form" style="flex: 1">
+                <a-form-item label="实体名称:">
+                    <a-input v-decorator="formRules.name"/>
+                </a-form-item>
+                <a-form-item label="实体描述:">
+                    <a-input type="textarea" v-decorator="formRules.memo"/>
+                </a-form-item>
+            </a-form>
+        </div>
+        <div v-if="!entityId">
+            <a-table :columns="columns"
+                     :dataSource="resultList"
+                     :pagination="false"
+                     size="small"
+                     rowKey="attrClsID"
+                     bordered
+            >
+                <template slot="attrValueType" slot-scope="text">
+                    {{attrClsType[text]}}
+                </template>
+                <template slot="attrValue" slot-scope="text,record">
+                    <!--{{record}}-->
+                    <editable-cell :record="record" :text="text" :editable="record.edit"
+                                   @change="onCellChange(record,'attrValue', $event)"  @close="closeCell(record)"></editable-cell>
+                    <!--<a-input placeholder="请输入属性值" v-model="record.attrValue" style="width: 120px;"/>-->
+                </template>
+            </a-table>
+        </div>
+    </a-modal>
+</template>
+
+<script>
+  import EditableCell from '@/components/knowledge/editableCell'
+  import { getAttrClassById2 } from '@/api/graph/attrClass'
+  import { addEntity, updateEntityName } from '@/api/graph/entity'
+  const formItemLayout = {
+    labelCol: {
+      xs: {span: 24},
+      sm: {span: 6}
+    },
+    wrapperCol: {
+      xs: {span: 24},
+      sm: {span: 16}
+    }
+  }
+  const columns = [
+    {
+      rowClassName: 'name',
+      title: '名称',
+      dataIndex: 'attrClsName',
+      align: 'center'
+    },
+    {
+      title: '数据类型',
+      dataIndex: 'attrValueType',
+      align: 'center',
+      scopedSlots: {customRender: 'attrValueType'}
+    },
+    {
+      title: '单位',
+      dataIndex: 'attrUnit',
+      align: 'center'
+    },
+    {
+      title: '属性值',
+      dataIndex: 'attrValue',
+      width: '30%',
+      scopedSlots: {customRender: 'attrValue'}
+    }
+  ]
+  export default {
+    name: 'add-entity-modal',
+    components: {
+      EditableCell
+    },
+    // paramsId 实体类id  title:标题   entityName: 实体名字  entityId:实体id isLink:改变路由 entClsIcon: 实体图标
+    props: ['paramsId', 'title', 'entityName', 'entityId', 'entityMemo', 'isLink', 'entClsIcon', 'isModel'],
+    data () {
+      return {
+        columns,
+        attrClsType: this.$const.attrClsType,
+        resultList: [], // 必填列表
+        fileName: '',  //本机文件地址
+        headImg: '',
+        imgFile: '',
+        formItemLayout,
+        headTitle: '',
+        form: this.$form.createForm(this),
+        show: true,
+        formRules: {        // 所有验证规则
+          name: [       // 用作标识,我们统一写成和表单提交字段一样
+            'name',     // 表单提交的字段
+            {
+              rules: [{required: true, message: '此选项必填', whitespace: true}],
+              initialValue: this.entityName
+            }
+          ],
+          memo: [       // 用作标识,我们统一写成和表单提交字段一样
+            'memo',     // 表单提交的字段
+            {
+              rules: [{required: false, message: '可以选择填'}],
+              initialValue: this.entityMemo
+            }
+          ]
+        }
+      }
+    },
+    created () {
+      const vm = this
+      this.headTitle = this.title
+      if (this.paramsId) { // 新增
+        getAttrClassById2(this.paramsId, 'ELEM').then(function (resp) {
+          const data = resp.data
+          let resultList = []
+          data.forEach(v => {
+            if (v.notNull) {
+              v.edit = {
+                abled: false
+              }
+              v.attrValue =''
+              resultList.push(v)
+
+            }
+          })
+          vm.resultList = resultList
+        })
+      }
+
+    },
+    mounted () {
+      //  判断是新增还是添加
+      if (this.entityName) {
+        this.headImg = this.entClsIcon
+      }
+    },
+    methods: {
+      //选择本地图片
+      uploadImg (e, num) {
+        var max_size = 80// 20k
+        var _this = this
+        //上传图片
+        var file = e.target.files[0]
+        _this.fileName = file.name
+        var size = file.size
+        if (size > max_size * 1024) {
+          this.$message.warning('建议上传图标不要超过80KB')
+        }
+        if (!/\.(gif|jpg|jpeg|png|bmp|GIF|JPG|PNG|JPEG|BMP)$/.test(e.target.value)) {
+          alert('图片类型必须是.gif,jpeg,jpg,png,bmp中的一种')
+          return false
+        }
+        var reader = new FileReader()
+        reader.onload = (e) => {
+          let data
+          data = e.target.result
+          this.$open('cropperImgModal', {
+            paramImgUrl: data
+          }, function (data) {
+            this.headImg = data.data
+          })
+        }
+        // 转化为base64
+        reader.readAsDataURL(file)
+        // 转化为blob
+        // reader.readAsArrayBuffer(file)
+
+      },
+      async getFormData () {
+        var result = await this.$formValidateFields('form')    //form的字符串
+        // 在这里对form返回数据进行处理
+        return result
+      },
+      async handleOk (e) {
+        var result = await this.getFormData()     // this是当前组件的this,  'form'此表单的名称,一定要是字符串
+        const entClsID = this.paramsId  // 实体类id
+        const entId = this.entityId    //实体id
+        const entName = result.name.trim()  // 实体名字
+        const uniqueMatchList = this.$checkSpecialChar(entName)
+        if (uniqueMatchList.length > 0) {
+          this.$message.error(`${this.isModel ? '模板' : '实体'}名称不能包含特殊字符【${uniqueMatchList.join('、')}】!`)
+          return false
+        }
+        if (!result.memo) result.memo = ''
+        const entMemo = result.memo.trim()
+        const entIcon = (this.headImg && this.headImg != 'null') ? encodeURIComponent(this.headImg) : '',
+          notNullAttrVOList = []
+        this.resultList.forEach(v => {
+          notNullAttrVOList.push({attrClsID: v.attrClsID, attrValue: v.attrValue})
+        })
+        if (entClsID) {
+          // 新增实体
+          if (notNullAttrVOList.some(v => {return !v.attrValue})) {
+            this.$message.error('属性值必填')
+            return false
+          } else {
+            addEntity(entClsID, entName, entMemo, entIcon, notNullAttrVOList, this.isModel).then((resp) => {
+              if (resp !== false) {
+                if (this.isLink) {
+                  this.$trigger('entity:nodeCreated', resp.data.entId)
+                }
+                this.$close(resp.data.entId)
+              }
+            })
+          }
+        }
+        if (entId) {
+          //修改实体
+          updateEntityName(entId, entName, entMemo, entIcon, this.isModel).then((data) => {
+            if (data !== false) {
+              if (this.isLink) {
+                this.$trigger('entity:nodeUpdated', data)
+              }
+              this.$close(data)
+            }
+          })
+        }
+      },
+      // 关闭模态窗
+      handleClose (e) {
+        this.$close(false)
+      },
+      closeCell (record) {
+        record.edit.abled = false
+      },
+      onCellChange (target, data, value) {
+        target.attrValue = value.toString()
+        target.edit.abled = false
+      }
+    }
+  }
+</script>
+
+<style scoped>
+
+</style>

+ 2 - 2
src/views/knowledge/modal/index.js

@@ -7,7 +7,7 @@ import AddRelationAttrModal from './addRelationAttrModal'
 // import AddEntityClass from './addEntityClassModal.vue' // 添加实体类modal
 import editEntityClassTreeNameModal from './editEntityClassTreeNameModal' // 编辑实体类树的名字modal
 import createRelationClassModal from './createRelationClassModal' // 新建关系类modal
-// import addEntityModal from './addEntityModal' // 添加实体modal
+import addEntityModal from './addEntityModal' // 添加实体modal
 
 // import createRelationModal from './createRelationModal' // 新建关系
 import editRelationClassNameModal from './editRelationClassNameModal' // 修改关系类名
@@ -115,7 +115,7 @@ export default {
 	editEntityClassTreeNameModal,
 	AddRelationAttrModal,
 	createRelationClassModal,
-	// addEntityModal,
+	addEntityModal,
 	// createRelationModal,
 	// rightMenuDrawer,
 	// checkTargetModal,

Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff