init
22
.editorconfig
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
# 告诉EditorConfig插件,这是根文件,不用继续往上查找
|
||||||
|
root = true
|
||||||
|
|
||||||
|
# 匹配全部文件
|
||||||
|
[*]
|
||||||
|
# 设置字符集
|
||||||
|
charset = utf-8
|
||||||
|
# 缩进风格,可选space、tab
|
||||||
|
indent_style = space
|
||||||
|
# 缩进的空格数
|
||||||
|
indent_size = 2
|
||||||
|
# 结尾换行符,可选lf、cr、crlf
|
||||||
|
end_of_line = lf
|
||||||
|
# 在文件结尾插入新行
|
||||||
|
insert_final_newline = true
|
||||||
|
# 删除一行中的前后空格
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
# 匹配md结尾的文件
|
||||||
|
[*.md]
|
||||||
|
insert_final_newline = false
|
||||||
|
trim_trailing_whitespace = false
|
||||||
8
.env.development
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# 开发环境配置
|
||||||
|
ENV = 'development'
|
||||||
|
|
||||||
|
# 开发环境
|
||||||
|
VUE_APP_BASE_API = '/kg-api'
|
||||||
|
|
||||||
|
# 路由懒加载
|
||||||
|
VUE_CLI_BABEL_TRANSPILE_MODULES = true
|
||||||
6
.env.production
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# 生产环境配置
|
||||||
|
ENV = 'production'
|
||||||
|
|
||||||
|
# 生产环境
|
||||||
|
VUE_APP_BASE_API = '/kg-api'
|
||||||
|
|
||||||
7
.env.staging
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
NODE_ENV = production
|
||||||
|
|
||||||
|
# 测试环境配置
|
||||||
|
ENV = 'staging'
|
||||||
|
|
||||||
|
# 测试环境
|
||||||
|
VUE_APP_BASE_API = '/stage-api'
|
||||||
10
.eslintignore
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# 忽略build目录下类型为js的文件的语法检查
|
||||||
|
build/*.js
|
||||||
|
# 忽略src/assets目录下文件的语法检查
|
||||||
|
src/assets
|
||||||
|
# 忽略public目录下文件的语法检查
|
||||||
|
public
|
||||||
|
# 忽略当前目录下为js的文件的语法检查
|
||||||
|
*.js
|
||||||
|
# 忽略当前目录下为vue的文件的语法检查
|
||||||
|
*.vue
|
||||||
23
.gitignore
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
.DS_Store
|
||||||
|
node_modules
|
||||||
|
/dist
|
||||||
|
|
||||||
|
|
||||||
|
# local env files
|
||||||
|
.env.local
|
||||||
|
.env.*.local
|
||||||
|
|
||||||
|
# Log files
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.idea
|
||||||
|
.vscode
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
||||||
24
README.md
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# kg-builder
|
||||||
|
|
||||||
|
## Project setup
|
||||||
|
```
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
### Compiles and hot-reloads for development
|
||||||
|
```
|
||||||
|
npm run serve
|
||||||
|
```
|
||||||
|
|
||||||
|
### Compiles and minifies for production
|
||||||
|
```
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
### Lints and fixes files
|
||||||
|
```
|
||||||
|
npm run lint
|
||||||
|
```
|
||||||
|
|
||||||
|
### Customize configuration
|
||||||
|
See [Configuration Reference](https://cli.vuejs.org/config/).
|
||||||
3
babel.config.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
module.exports = {
|
||||||
|
presets: ["@vue/cli-plugin-babel/preset"]
|
||||||
|
};
|
||||||
15178
package-lock.json
generated
Normal file
72
package.json
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
{
|
||||||
|
"name": "kg-builder",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"serve": "cross-env NODE_OPTIONS=--openssl-legacy-provider vue-cli-service serve",
|
||||||
|
"build": "cross-env NODE_OPTIONS=--openssl-legacy-provider vue-cli-service build",
|
||||||
|
"lint": "vue-cli-service lint"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@antv/x6": "^1.28.1",
|
||||||
|
"axios": "^0.24.0",
|
||||||
|
"core-js": "^3.6.5",
|
||||||
|
"element-ui": "^2.13.2",
|
||||||
|
"html2canvas": "^1.4.0",
|
||||||
|
"jquery": "^3.5.1",
|
||||||
|
"js-cookie": "^3.0.1",
|
||||||
|
"jsplumb": "^2.15.6",
|
||||||
|
"less": "^3.9.0",
|
||||||
|
"less-loader": "^5.0.0",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
|
"qs": "^6.10.2",
|
||||||
|
"script-ext-html-webpack-plugin": "^2.1.5",
|
||||||
|
"vue": "^2.6.11",
|
||||||
|
"vue-axios": "^2.1.5",
|
||||||
|
"vue-codemirror": "^4.0.6",
|
||||||
|
"vue-router": "^3.2.0",
|
||||||
|
"vuedraggable": "^2.24.3",
|
||||||
|
"vuex": "^3.4.0",
|
||||||
|
"wangeditor": "^4.7.11"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@vue/cli-plugin-babel": "~4.5.0",
|
||||||
|
"@vue/cli-plugin-eslint": "~4.5.0",
|
||||||
|
"@vue/cli-plugin-router": "~4.5.0",
|
||||||
|
"@vue/cli-plugin-vuex": "~4.5.0",
|
||||||
|
"@vue/cli-service": "~4.5.0",
|
||||||
|
"@vue/eslint-config-prettier": "^6.0.0",
|
||||||
|
"babel-eslint": "^10.1.0",
|
||||||
|
"cross-env": "^10.1.0",
|
||||||
|
"d3": "5.0.0",
|
||||||
|
"eslint": "^6.7.2",
|
||||||
|
"eslint-plugin-prettier": "^3.1.3",
|
||||||
|
"eslint-plugin-vue": "^6.2.2",
|
||||||
|
"prettier": "^1.19.1",
|
||||||
|
"sass": "^1.26.5",
|
||||||
|
"sass-loader": "^8.0.2",
|
||||||
|
"vue-template-compiler": "^2.6.11"
|
||||||
|
},
|
||||||
|
"eslintConfig": {
|
||||||
|
"root": true,
|
||||||
|
"env": {
|
||||||
|
"node": true
|
||||||
|
},
|
||||||
|
"extends": [
|
||||||
|
"plugin:vue/essential",
|
||||||
|
"eslint:recommended",
|
||||||
|
"@vue/prettier"
|
||||||
|
],
|
||||||
|
"parserOptions": {
|
||||||
|
"parser": "babel-eslint"
|
||||||
|
},
|
||||||
|
"rules": {
|
||||||
|
"no-unused-vars": "off"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"browserslist": [
|
||||||
|
"> 1%",
|
||||||
|
"last 2 versions",
|
||||||
|
"not dead"
|
||||||
|
]
|
||||||
|
}
|
||||||
BIN
public/favicon.ico
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
18
public/index.html
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||||
|
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||||
|
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<noscript>
|
||||||
|
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||||
|
</noscript>
|
||||||
|
<div id="app"></div>
|
||||||
|
<!-- built files will be auto injected -->
|
||||||
|
<script src="<%= BASE_URL %>static/icon/iconfont.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
2
public/robots.txt
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
User-agent: *
|
||||||
|
Disallow: /
|
||||||
539
public/static/icon/demo.css
Normal file
@ -0,0 +1,539 @@
|
|||||||
|
/* Logo 字体 */
|
||||||
|
@font-face {
|
||||||
|
font-family: "iconfont logo";
|
||||||
|
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834');
|
||||||
|
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'),
|
||||||
|
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'),
|
||||||
|
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'),
|
||||||
|
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg');
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
font-family: "iconfont logo";
|
||||||
|
font-size: 40px;
|
||||||
|
font-style: normal;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tabs */
|
||||||
|
.nav-tabs {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tabs .nav-more {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
height: 42px;
|
||||||
|
line-height: 42px;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tabs {
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tabs li {
|
||||||
|
cursor: pointer;
|
||||||
|
width: 100px;
|
||||||
|
height: 40px;
|
||||||
|
line-height: 40px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 16px;
|
||||||
|
border-bottom: 2px solid transparent;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
margin-bottom: -1px;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#tabs .active {
|
||||||
|
border-bottom-color: #f00;
|
||||||
|
color: #222;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-container .content {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 页面布局 */
|
||||||
|
.main {
|
||||||
|
padding: 30px 100px;
|
||||||
|
width: 960px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main .logo {
|
||||||
|
color: #333;
|
||||||
|
text-align: left;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
line-height: 1;
|
||||||
|
height: 110px;
|
||||||
|
margin-top: -50px;
|
||||||
|
overflow: hidden;
|
||||||
|
*zoom: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main .logo a {
|
||||||
|
font-size: 160px;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.helps {
|
||||||
|
margin-top: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.helps pre {
|
||||||
|
padding: 20px;
|
||||||
|
margin: 10px 0;
|
||||||
|
border: solid 1px #e7e1cd;
|
||||||
|
background-color: #fffdef;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon_lists {
|
||||||
|
width: 100% !important;
|
||||||
|
overflow: hidden;
|
||||||
|
*zoom: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon_lists li {
|
||||||
|
width: 100px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
margin-right: 20px;
|
||||||
|
text-align: center;
|
||||||
|
list-style: none !important;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon_lists li .code-name {
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon_lists .icon {
|
||||||
|
display: block;
|
||||||
|
height: 100px;
|
||||||
|
line-height: 100px;
|
||||||
|
font-size: 42px;
|
||||||
|
margin: 10px auto;
|
||||||
|
color: #333;
|
||||||
|
-webkit-transition: font-size 0.25s linear, width 0.25s linear;
|
||||||
|
-moz-transition: font-size 0.25s linear, width 0.25s linear;
|
||||||
|
transition: font-size 0.25s linear, width 0.25s linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon_lists .icon:hover {
|
||||||
|
font-size: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon_lists .svg-icon {
|
||||||
|
/* 通过设置 font-size 来改变图标大小 */
|
||||||
|
width: 1em;
|
||||||
|
/* 图标和文字相邻时,垂直对齐 */
|
||||||
|
vertical-align: -0.15em;
|
||||||
|
/* 通过设置 color 来改变 SVG 的颜色/fill */
|
||||||
|
fill: currentColor;
|
||||||
|
/* path 和 stroke 溢出 viewBox 部分在 IE 下会显示
|
||||||
|
normalize.css 中也包含这行 */
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon_lists li .name,
|
||||||
|
.icon_lists li .code-name {
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* markdown 样式 */
|
||||||
|
.markdown {
|
||||||
|
color: #666;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.highlight {
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown img {
|
||||||
|
vertical-align: middle;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown h1 {
|
||||||
|
color: #404040;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 40px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown h2,
|
||||||
|
.markdown h3,
|
||||||
|
.markdown h4,
|
||||||
|
.markdown h5,
|
||||||
|
.markdown h6 {
|
||||||
|
color: #404040;
|
||||||
|
margin: 1.6em 0 0.6em 0;
|
||||||
|
font-weight: 500;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown h1 {
|
||||||
|
font-size: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown h2 {
|
||||||
|
font-size: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown h3 {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown h4 {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown h5 {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown h6 {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown hr {
|
||||||
|
height: 1px;
|
||||||
|
border: 0;
|
||||||
|
background: #e9e9e9;
|
||||||
|
margin: 16px 0;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown p {
|
||||||
|
margin: 1em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown>p,
|
||||||
|
.markdown>blockquote,
|
||||||
|
.markdown>.highlight,
|
||||||
|
.markdown>ol,
|
||||||
|
.markdown>ul {
|
||||||
|
width: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown ul>li {
|
||||||
|
list-style: circle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown>ul li,
|
||||||
|
.markdown blockquote ul>li {
|
||||||
|
margin-left: 20px;
|
||||||
|
padding-left: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown>ul li p,
|
||||||
|
.markdown>ol li p {
|
||||||
|
margin: 0.6em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown ol>li {
|
||||||
|
list-style: decimal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown>ol li,
|
||||||
|
.markdown blockquote ol>li {
|
||||||
|
margin-left: 20px;
|
||||||
|
padding-left: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown code {
|
||||||
|
margin: 0 3px;
|
||||||
|
padding: 0 5px;
|
||||||
|
background: #eee;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown strong,
|
||||||
|
.markdown b {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown>table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
border-spacing: 0px;
|
||||||
|
empty-cells: show;
|
||||||
|
border: 1px solid #e9e9e9;
|
||||||
|
width: 95%;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown>table th {
|
||||||
|
white-space: nowrap;
|
||||||
|
color: #333;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown>table th,
|
||||||
|
.markdown>table td {
|
||||||
|
border: 1px solid #e9e9e9;
|
||||||
|
padding: 8px 16px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown>table th {
|
||||||
|
background: #F7F7F7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown blockquote {
|
||||||
|
font-size: 90%;
|
||||||
|
color: #999;
|
||||||
|
border-left: 4px solid #e9e9e9;
|
||||||
|
padding-left: 0.8em;
|
||||||
|
margin: 1em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown blockquote p {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown .anchor {
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown .waiting {
|
||||||
|
color: #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown h1:hover .anchor,
|
||||||
|
.markdown h2:hover .anchor,
|
||||||
|
.markdown h3:hover .anchor,
|
||||||
|
.markdown h4:hover .anchor,
|
||||||
|
.markdown h5:hover .anchor,
|
||||||
|
.markdown h6:hover .anchor {
|
||||||
|
opacity: 1;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown>br,
|
||||||
|
.markdown>p>br {
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.hljs {
|
||||||
|
display: block;
|
||||||
|
background: white;
|
||||||
|
padding: 0.5em;
|
||||||
|
color: #333333;
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-comment,
|
||||||
|
.hljs-meta {
|
||||||
|
color: #969896;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-string,
|
||||||
|
.hljs-variable,
|
||||||
|
.hljs-template-variable,
|
||||||
|
.hljs-strong,
|
||||||
|
.hljs-emphasis,
|
||||||
|
.hljs-quote {
|
||||||
|
color: #df5000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-keyword,
|
||||||
|
.hljs-selector-tag,
|
||||||
|
.hljs-type {
|
||||||
|
color: #a71d5d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-literal,
|
||||||
|
.hljs-symbol,
|
||||||
|
.hljs-bullet,
|
||||||
|
.hljs-attribute {
|
||||||
|
color: #0086b3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-section,
|
||||||
|
.hljs-name {
|
||||||
|
color: #63a35c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-tag {
|
||||||
|
color: #333333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-title,
|
||||||
|
.hljs-attr,
|
||||||
|
.hljs-selector-id,
|
||||||
|
.hljs-selector-class,
|
||||||
|
.hljs-selector-attr,
|
||||||
|
.hljs-selector-pseudo {
|
||||||
|
color: #795da3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-addition {
|
||||||
|
color: #55a532;
|
||||||
|
background-color: #eaffea;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-deletion {
|
||||||
|
color: #bd2c00;
|
||||||
|
background-color: #ffecec;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-link {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 代码高亮 */
|
||||||
|
/* PrismJS 1.15.0
|
||||||
|
https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */
|
||||||
|
/**
|
||||||
|
* prism.js default theme for JavaScript, CSS and HTML
|
||||||
|
* Based on dabblet (http://dabblet.com)
|
||||||
|
* @author Lea Verou
|
||||||
|
*/
|
||||||
|
code[class*="language-"],
|
||||||
|
pre[class*="language-"] {
|
||||||
|
color: black;
|
||||||
|
background: none;
|
||||||
|
text-shadow: 0 1px white;
|
||||||
|
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
|
||||||
|
text-align: left;
|
||||||
|
white-space: pre;
|
||||||
|
word-spacing: normal;
|
||||||
|
word-break: normal;
|
||||||
|
word-wrap: normal;
|
||||||
|
line-height: 1.5;
|
||||||
|
|
||||||
|
-moz-tab-size: 4;
|
||||||
|
-o-tab-size: 4;
|
||||||
|
tab-size: 4;
|
||||||
|
|
||||||
|
-webkit-hyphens: none;
|
||||||
|
-moz-hyphens: none;
|
||||||
|
-ms-hyphens: none;
|
||||||
|
hyphens: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre[class*="language-"]::-moz-selection,
|
||||||
|
pre[class*="language-"] ::-moz-selection,
|
||||||
|
code[class*="language-"]::-moz-selection,
|
||||||
|
code[class*="language-"] ::-moz-selection {
|
||||||
|
text-shadow: none;
|
||||||
|
background: #b3d4fc;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre[class*="language-"]::selection,
|
||||||
|
pre[class*="language-"] ::selection,
|
||||||
|
code[class*="language-"]::selection,
|
||||||
|
code[class*="language-"] ::selection {
|
||||||
|
text-shadow: none;
|
||||||
|
background: #b3d4fc;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media print {
|
||||||
|
|
||||||
|
code[class*="language-"],
|
||||||
|
pre[class*="language-"] {
|
||||||
|
text-shadow: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Code blocks */
|
||||||
|
pre[class*="language-"] {
|
||||||
|
padding: 1em;
|
||||||
|
margin: .5em 0;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
:not(pre)>code[class*="language-"],
|
||||||
|
pre[class*="language-"] {
|
||||||
|
background: #f5f2f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Inline code */
|
||||||
|
:not(pre)>code[class*="language-"] {
|
||||||
|
padding: .1em;
|
||||||
|
border-radius: .3em;
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.comment,
|
||||||
|
.token.prolog,
|
||||||
|
.token.doctype,
|
||||||
|
.token.cdata {
|
||||||
|
color: slategray;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.punctuation {
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.namespace {
|
||||||
|
opacity: .7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.property,
|
||||||
|
.token.tag,
|
||||||
|
.token.boolean,
|
||||||
|
.token.number,
|
||||||
|
.token.constant,
|
||||||
|
.token.symbol,
|
||||||
|
.token.deleted {
|
||||||
|
color: #905;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.selector,
|
||||||
|
.token.attr-name,
|
||||||
|
.token.string,
|
||||||
|
.token.char,
|
||||||
|
.token.builtin,
|
||||||
|
.token.inserted {
|
||||||
|
color: #690;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.operator,
|
||||||
|
.token.entity,
|
||||||
|
.token.url,
|
||||||
|
.language-css .token.string,
|
||||||
|
.style .token.string {
|
||||||
|
color: #9a6e3a;
|
||||||
|
background: hsla(0, 0%, 100%, .5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.atrule,
|
||||||
|
.token.attr-value,
|
||||||
|
.token.keyword {
|
||||||
|
color: #07a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.function,
|
||||||
|
.token.class-name {
|
||||||
|
color: #DD4A68;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.regex,
|
||||||
|
.token.important,
|
||||||
|
.token.variable {
|
||||||
|
color: #e90;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.important,
|
||||||
|
.token.bold {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.italic {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.entity {
|
||||||
|
cursor: help;
|
||||||
|
}
|
||||||
11228
public/static/icon/demo_index.html
Normal file
1935
public/static/icon/iconfont.css
Normal file
1
public/static/icon/iconfont.js
Normal file
3369
public/static/icon/iconfont.json
Normal file
BIN
public/static/icon/iconfont.ttf
Normal file
BIN
public/static/icon/iconfont.woff
Normal file
BIN
public/static/icon/iconfont.woff2
Normal file
168
public/static/kgData.json
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
{
|
||||||
|
"node": [
|
||||||
|
{
|
||||||
|
"flag": "1",
|
||||||
|
"code": "2730103",
|
||||||
|
"parentCode": "27301",
|
||||||
|
"grade": "2",
|
||||||
|
"name": "儒家",
|
||||||
|
"uuid": "26365002",
|
||||||
|
"imgsrc": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "273010308",
|
||||||
|
"flag": "0",
|
||||||
|
"parentCode": "2730103",
|
||||||
|
"grade": "4",
|
||||||
|
"name": "王守仁",
|
||||||
|
"uuid": "46178689",
|
||||||
|
"imgsrc": "http://h.bytravel.cn/ren/0/head/2057.gif"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "273010307",
|
||||||
|
"flag": "0",
|
||||||
|
"parentCode": "2730103",
|
||||||
|
"grade": "4",
|
||||||
|
"name": "陆九渊",
|
||||||
|
"uuid": "46178686",
|
||||||
|
"imgsrc": "https://bkimg.cdn.bcebos.com/pic/dcc451da81cb39dbde12202dd0160924aa1830fe?x-bce-process=image/resize,m_lfit,w_268,limit_1/format,f_jpg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "273010306",
|
||||||
|
"flag": "0",
|
||||||
|
"parentCode": "2730103",
|
||||||
|
"grade": "4",
|
||||||
|
"name": "朱熹",
|
||||||
|
"uuid": "46178681",
|
||||||
|
"imgsrc": "https://bkimg.cdn.bcebos.com/pic/f31fbe096b63f624da9384678944ebf81b4ca38c?x-bce-process=image/resize,m_lfit,w_268,limit_1/format,f_jpg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "273010305",
|
||||||
|
"flag": "0",
|
||||||
|
"parentCode": "2730103",
|
||||||
|
"grade": "4",
|
||||||
|
"name": "程颐",
|
||||||
|
"uuid": "46178676",
|
||||||
|
"imgsrc": "https://bkimg.cdn.bcebos.com/pic/060828381f30e92489594e3b4f086e061d95f73f?x-bce-process=image/resize,m_lfit,w_268,limit_1/format,f_jpg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "273010304",
|
||||||
|
"flag": "0",
|
||||||
|
"parentCode": "2730103",
|
||||||
|
"grade": "4",
|
||||||
|
"name": "董仲舒",
|
||||||
|
"uuid": "46178671",
|
||||||
|
"imgsrc": "https://bkimg.cdn.bcebos.com/pic/b17eca8065380cd7bbccaaf5a344ad34588281d3?x-bce-process=image/resize,m_lfit,w_268,limit_1/format,f_jpg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "273010309",
|
||||||
|
"flag": "0",
|
||||||
|
"parentCode": "2730103",
|
||||||
|
"grade": "4",
|
||||||
|
"name": "曾子",
|
||||||
|
"uuid": "46178665",
|
||||||
|
"imgsrc": "https://bkimg.cdn.bcebos.com/pic/838ba61ea8d3fd1fa226566e3f4e251f95ca5fb3?x-bce-process=image/resize,m_lfit,w_268,limit_1/format,f_jpg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "273010303",
|
||||||
|
"flag": "0",
|
||||||
|
"parentCode": "2730103",
|
||||||
|
"grade": "4",
|
||||||
|
"name": "荀子",
|
||||||
|
"uuid": "46178660",
|
||||||
|
"imgsrc": "https://bkimg.cdn.bcebos.com/pic/37d3d539b6003af36cf611c53b2ac65c1138b6c3?x-bce-process=image/resize,m_lfit,w_268,limit_1/format,f_jpg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "273010302",
|
||||||
|
"flag": "0",
|
||||||
|
"parentCode": "2730103",
|
||||||
|
"grade": "4",
|
||||||
|
"name": "孟子",
|
||||||
|
"uuid": "46178654",
|
||||||
|
"imgsrc": "http://img.duoziwang.com/2018/19/07051620110108.jpg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "273010301",
|
||||||
|
"flag": "0",
|
||||||
|
"parentCode": "2730103",
|
||||||
|
"grade": "4",
|
||||||
|
"name": "孔子",
|
||||||
|
"uuid": "46178648",
|
||||||
|
"imgsrc": "http://img.duoziwang.com/2018/17/05142055603532.jpg"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"relationship": [
|
||||||
|
{
|
||||||
|
"sourceId": "26365002",
|
||||||
|
"targetId": "46178689",
|
||||||
|
"name": "代表人物",
|
||||||
|
"targetcode": "273010308",
|
||||||
|
"uuid": "91804311",
|
||||||
|
"sourcecode": "2730103"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"sourceId": "26365002",
|
||||||
|
"targetId": "46178686",
|
||||||
|
"name": "代表人物",
|
||||||
|
"targetcode": "273010307",
|
||||||
|
"uuid": "91804310",
|
||||||
|
"sourcecode": "2730103"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"sourceId": "26365002",
|
||||||
|
"targetId": "46178681",
|
||||||
|
"name": "代表人物",
|
||||||
|
"targetcode": "273010306",
|
||||||
|
"uuid": "91804309",
|
||||||
|
"sourcecode": "2730103"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"sourceId": "26365002",
|
||||||
|
"targetId": "46178676",
|
||||||
|
"name": "代表人物",
|
||||||
|
"targetcode": "273010305",
|
||||||
|
"uuid": "91804308",
|
||||||
|
"sourcecode": "2730103"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"sourceId": "26365002",
|
||||||
|
"targetId": "46178671",
|
||||||
|
"name": "代表人物",
|
||||||
|
"targetcode": "273010304",
|
||||||
|
"uuid": "91804307",
|
||||||
|
"sourcecode": "2730103"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"sourceId": "26365002",
|
||||||
|
"targetId": "46178665",
|
||||||
|
"name": "代表人物",
|
||||||
|
"targetcode": "273010309",
|
||||||
|
"uuid": "91804306",
|
||||||
|
"sourcecode": "2730103"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"sourceId": "26365002",
|
||||||
|
"targetId": "46178660",
|
||||||
|
"name": "代表人物",
|
||||||
|
"targetcode": "273010303",
|
||||||
|
"uuid": "91804305",
|
||||||
|
"sourcecode": "2730103"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"sourceId": "26365002",
|
||||||
|
"targetId": "46178654",
|
||||||
|
"name": "代表人物",
|
||||||
|
"targetcode": "273010302",
|
||||||
|
"uuid": "91804295",
|
||||||
|
"sourcecode": "2730103"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"sourceId": "26365002",
|
||||||
|
"targetId": "46178648",
|
||||||
|
"name": "代表人物",
|
||||||
|
"targetcode": "273010301",
|
||||||
|
"uuid": "91804294",
|
||||||
|
"sourcecode": "2730103"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
37
src/App.vue
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<template>
|
||||||
|
<div id="app">
|
||||||
|
<kg-header ref="header"></kg-header>
|
||||||
|
<router-view />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import KgHeader from "@/components/KGHeader";
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
KgHeader,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss">
|
||||||
|
#app {
|
||||||
|
font-family: Avenir, Helvetica, Arial, sans-serif;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
// text-align: center;
|
||||||
|
color: #2c3e50;
|
||||||
|
}
|
||||||
|
|
||||||
|
#nav {
|
||||||
|
//padding: 30px;
|
||||||
|
|
||||||
|
a {
|
||||||
|
font-weight: bold;
|
||||||
|
color: #2c3e50;
|
||||||
|
|
||||||
|
&.router-link-exact-active {
|
||||||
|
color: #42b983;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
body{ margin: 0px; }
|
||||||
|
</style>
|
||||||
2
src/api/index.js
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export { default as kgBuilderApi } from "./modules/kgBuilderApi";
|
||||||
|
export { default as datasourceApi } from "./modules/datasourceApi";
|
||||||
82
src/api/modules/datasourceApi.js
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
import request from "@/utils/request";
|
||||||
|
import BaseAPI from '@/utils/BaseAPI'
|
||||||
|
|
||||||
|
class datasourceApi extends BaseAPI{
|
||||||
|
// 获取数据源
|
||||||
|
getDatasource() {
|
||||||
|
return request({
|
||||||
|
url: "/datasource/getDataSource",
|
||||||
|
method: "get"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 获取数据表
|
||||||
|
getTableInfo(datasourceId) {
|
||||||
|
return request({
|
||||||
|
url: "/datasource/getDataTable?datasourceId=" + datasourceId,
|
||||||
|
method: "get"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 获取数据列
|
||||||
|
getTableColumn(tableId) {
|
||||||
|
return request({
|
||||||
|
url: "/datasource/getDataColumn?dataTableId=" + tableId,
|
||||||
|
method: "get"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
//获取表及列
|
||||||
|
getDataTableInfo(tableId) {
|
||||||
|
return request({
|
||||||
|
url: "/datasource/getDataTableInfo?dataTableId=" + tableId,
|
||||||
|
method: "get"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
//获取预览数据
|
||||||
|
getPreviewData(data) {
|
||||||
|
return this.post("/datasource/getTableRecords",data,{
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}});
|
||||||
|
// return request({
|
||||||
|
// url: "/datasource/getTableRecords",
|
||||||
|
// method: "post",
|
||||||
|
// data: data
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
//保存数据源
|
||||||
|
saveDatasource(data) {
|
||||||
|
return this.post("/datasource/saveDataSource",data,{
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}});
|
||||||
|
// return request({
|
||||||
|
// url: "/datasource/saveDataSource",
|
||||||
|
// method: "post",
|
||||||
|
// data: data
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
//保存数据表
|
||||||
|
saveDataTable(data) {
|
||||||
|
return this.post("/datasource/saveDataTable",data,{
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}});
|
||||||
|
// return request({
|
||||||
|
// url: "/datasource/saveDataTable",
|
||||||
|
// method: "post",
|
||||||
|
// data: data
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
//获取数据表记录
|
||||||
|
getDataRecord(data) {
|
||||||
|
return this.post("/datasource/getTableRecords",data,{
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}});
|
||||||
|
// return request({
|
||||||
|
// url: "/datasource/getTableRecords",
|
||||||
|
// method: "post",
|
||||||
|
// data: data
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export default new datasourceApi();
|
||||||
186
src/api/modules/kgBuilderApi.js
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
import BaseAPI from '@/utils/BaseAPI'
|
||||||
|
|
||||||
|
class kgBuilderApi extends BaseAPI{
|
||||||
|
// 获取图谱数据
|
||||||
|
getKgData() {
|
||||||
|
return this.get("/static/kgData.json");
|
||||||
|
}
|
||||||
|
feedBack(data) {
|
||||||
|
return this.post("/feedBack",data);
|
||||||
|
}
|
||||||
|
saveData(data) {
|
||||||
|
return this.post("/er/saveData",data,{
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
getDomainNode(domainId) {
|
||||||
|
return this.get('/er/getDomainNode', {
|
||||||
|
domainId
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
execute(domainId) {
|
||||||
|
return this.get('/er/execute', {
|
||||||
|
domainId
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
getDomains(data) {
|
||||||
|
return this.post("/getGraph",data,{
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
createDomain(data) {
|
||||||
|
return this.get("/createDomain",data);
|
||||||
|
// return request({
|
||||||
|
// url: "/createDomain?domain=" + data.domain + "&type=" + data.type,
|
||||||
|
// method: "get"
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
getCypherResult(data) {
|
||||||
|
return this.get("/getCypherResult",data);
|
||||||
|
}
|
||||||
|
getNodeContent(data) {
|
||||||
|
return this.post("/getNodeContent",data);
|
||||||
|
}
|
||||||
|
getNodeImage(data) {
|
||||||
|
return this.post("/getNodeImage",data);
|
||||||
|
}
|
||||||
|
getNodeDetail(data) {
|
||||||
|
return this.post("/getNodeDetail",data);
|
||||||
|
}
|
||||||
|
saveNodeImage(data) {
|
||||||
|
return this.post("/saveNodeImage",data,{
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
saveNodeContent(data) {
|
||||||
|
return this.post("/saveNodeContent",data,{
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
getDomainGraph(data) {
|
||||||
|
return this.post("/queryGraphResult",data,{
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
getRelationNodeCount(data) {
|
||||||
|
return this.post("/getRelationNodeCount",data);
|
||||||
|
}
|
||||||
|
getMoreRelationNode(data) {
|
||||||
|
return this.get("/getMoreRelationNode",data);
|
||||||
|
}
|
||||||
|
deleteDomain(data) {
|
||||||
|
return this.post("/deleteDomain",data);
|
||||||
|
}
|
||||||
|
renameDomain(data) {
|
||||||
|
return this.put("/kg/domain/rename", data);
|
||||||
|
}
|
||||||
|
renameDomain(data) {
|
||||||
|
return this.put("/kg/domain/rename", data, {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
getRecommendGraph(data) {
|
||||||
|
return this.post("/getRecommendGraph",data,{
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
createNode(data) {
|
||||||
|
return this.post("/createNode",data,{
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
deleteNode(data) {
|
||||||
|
return this.post("/deleteNode",data);
|
||||||
|
}
|
||||||
|
deleteLink(data) {
|
||||||
|
return this.post("/deleteLink",data);
|
||||||
|
}
|
||||||
|
createLink(data) {
|
||||||
|
return this.post("/createLink",data,{
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
updateLink(data) {
|
||||||
|
return this.post("/updateLink",data);
|
||||||
|
}
|
||||||
|
updateNodeName(data) {
|
||||||
|
return this.post("/updateNodeName",data,{
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
batchCreateNode(data) {
|
||||||
|
return this.post("/batchCreateNode",data,{
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
batchCreateChildNode(data) {
|
||||||
|
return this.post("/batchCreateChildNode",data,{
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
batchCreateSameNode(data) {
|
||||||
|
return this.post("/batchCreateSameNode",data,{
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exportGraph(data) {
|
||||||
|
return this.post("/exportGraph",data);
|
||||||
|
}
|
||||||
|
download(data) {
|
||||||
|
return this.get("/download/"+data,);
|
||||||
|
}
|
||||||
|
intelligentSearch(data) {
|
||||||
|
return this.post("/intelligent/search", data, {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getSearchSuggestions(query, domain) {
|
||||||
|
return this.get("/intelligent/suggestions", {
|
||||||
|
query,
|
||||||
|
domain
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
updateCoordinateOfNode(data) {
|
||||||
|
return this.post("/updateCoordinateOfNode",data,{
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
export default new kgBuilderApi();
|
||||||
31
src/api/token.js
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/**
|
||||||
|
* @description: token操作
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const TOKENKEY = "authtoken";
|
||||||
|
|
||||||
|
// 存储token
|
||||||
|
export const setToken = (token, key) => {
|
||||||
|
localStorage.setItem(key || TOKENKEY, token);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取token
|
||||||
|
export const getToken = key => localStorage.getItem(key || TOKENKEY) || null;
|
||||||
|
|
||||||
|
// 删除token
|
||||||
|
export const removeToken = key => {
|
||||||
|
localStorage.removeItem(key || TOKENKEY);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取cookie
|
||||||
|
export const getCookie = name => {
|
||||||
|
var arr;
|
||||||
|
var reg = new RegExp("(^| )" + name + "=([^;]*)(;|$)");
|
||||||
|
if ((arr = document.cookie.match(reg))) return +unescape(arr[2]);
|
||||||
|
else return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 移除所有
|
||||||
|
export const removeAll = () => {
|
||||||
|
localStorage.clear();
|
||||||
|
};
|
||||||
BIN
src/assets/3yuanzuimport.png
Normal file
|
After Width: | Height: | Size: 61 KiB |
BIN
src/assets/logo.png
Normal file
|
After Width: | Height: | Size: 6.7 KiB |
BIN
src/assets/sanyuanzuimport1.png
Normal file
|
After Width: | Height: | Size: 7.6 KiB |
BIN
src/assets/sanyuanzuimport2.png
Normal file
|
After Width: | Height: | Size: 41 KiB |
BIN
src/assets/treeimport1.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
src/assets/treeimport2.png
Normal file
|
After Width: | Height: | Size: 68 KiB |
BIN
src/assets/中国一重.png
Normal file
|
After Width: | Height: | Size: 513 KiB |
837
src/components/KGBuilder.vue
Normal file
@ -0,0 +1,837 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div id="gid_tc" style="float:left;">
|
||||||
|
<div id="gid"></div>
|
||||||
|
<div class="mengceng"></div>
|
||||||
|
</div>
|
||||||
|
<div class="svg-set-box clearfix">
|
||||||
|
<div class="ctwh-dibmr">
|
||||||
|
<span>显示范围:</span>
|
||||||
|
<a
|
||||||
|
:key="index"
|
||||||
|
v-for="(m, index) in pageSizeList"
|
||||||
|
@click="setMatchSize(m, this)"
|
||||||
|
href="javascript:void(0)"
|
||||||
|
:class="[m.isActive ? 'sd-active' : '', 'ss-d sd' + (index + 1)]"
|
||||||
|
>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="ctwh-dibmr" style="float: right">
|
||||||
|
<ul class="toolbar">
|
||||||
|
<li>
|
||||||
|
<a href="javascript:;" @click="zoomIn"
|
||||||
|
><span><i class="el-icon-zoom-in"></i>放大</span></a
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="javascript:;" @click="zoomOut"
|
||||||
|
><span><i class="el-icon-zoom-out"></i>缩小</span></a
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="javascript:;" @click="refresh"
|
||||||
|
><span><i class="el-icon-refresh-right"></i>还原</span></a
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
v-if="!isFullscreen"
|
||||||
|
id="fullscreenbtn"
|
||||||
|
href="javascript:;"
|
||||||
|
@click="showFull"
|
||||||
|
>
|
||||||
|
<span><i class="el-icon-full-screen"></i>全屏</span>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
v-else
|
||||||
|
id="fullscreenbtn"
|
||||||
|
href="javascript:;"
|
||||||
|
@click="exitFullScreen"
|
||||||
|
>
|
||||||
|
<span><i class="el-icon-full-screen"></i>退出全屏</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import axios from 'axios'
|
||||||
|
import * as d3 from 'd3'
|
||||||
|
import $ from 'jquery'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: ['pid'],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
theme: 0,
|
||||||
|
loading: false,
|
||||||
|
width: 1000,
|
||||||
|
height: 800,
|
||||||
|
gcontainer: {},
|
||||||
|
svg: {},
|
||||||
|
zoom: null,
|
||||||
|
arrowMarker: {},
|
||||||
|
simulation: {},
|
||||||
|
isFullscreen: false,
|
||||||
|
qaGraphNode: {},
|
||||||
|
qaButtonGroup: {},
|
||||||
|
qaGraphNodeText: {},
|
||||||
|
qaGraphLink: {},
|
||||||
|
qaGraphLinkText: {},
|
||||||
|
graph: {
|
||||||
|
nodes: [],
|
||||||
|
links: [],
|
||||||
|
},
|
||||||
|
defaultR: 30,
|
||||||
|
colorList: [
|
||||||
|
'#ff8373',
|
||||||
|
'#f9c62c',
|
||||||
|
'#a5ca34',
|
||||||
|
'#6fce7a',
|
||||||
|
'#70d3bd',
|
||||||
|
'#ea91b0',
|
||||||
|
],
|
||||||
|
pageSizeList: [
|
||||||
|
{ size: 100, isActive: false },
|
||||||
|
{ size: 300, isActive: false },
|
||||||
|
{ size: 500, isActive: true },
|
||||||
|
{ size: 1000, isActive: false },
|
||||||
|
],
|
||||||
|
toolbarData: [
|
||||||
|
{ name: '编辑', value: 1, code: 'edit' },
|
||||||
|
{ name: '展开', value: 1, code: 'more' },
|
||||||
|
{ name: '追加', value: 1, code: 'append' },
|
||||||
|
{ name: '连线', value: 1, code: 'link' },
|
||||||
|
{ name: '删除', value: 1, code: 'delete' },
|
||||||
|
],
|
||||||
|
selectUuid: 0,
|
||||||
|
nodeRecordList: [],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
components: {},
|
||||||
|
mounted() {
|
||||||
|
this.initGraphContainer()
|
||||||
|
this.addMaker()
|
||||||
|
this.initGraph()
|
||||||
|
},
|
||||||
|
created() {},
|
||||||
|
watch: {},
|
||||||
|
methods: {
|
||||||
|
initGraphContainer() {
|
||||||
|
this.gcontainer = d3.select('#gid')
|
||||||
|
if (this.isFullscreen) {
|
||||||
|
this.width = window.screen.width
|
||||||
|
this.height = window.screen.height
|
||||||
|
} else {
|
||||||
|
this.width = $('#' + this.pid).width()
|
||||||
|
this.height = $('#' + this.pid).height()
|
||||||
|
}
|
||||||
|
this.svg = this.gcontainer.append('svg')
|
||||||
|
var sWidth = this.width
|
||||||
|
var sHeight = this.height
|
||||||
|
this.svg.attr('width', sWidth)
|
||||||
|
this.svg.attr('height', sHeight)
|
||||||
|
// this.svg.attr("viewBox", "0 0 " + sWidth / 2 + " " + sHeight / 2);
|
||||||
|
this.svg.attr('id', 'svg_idx')
|
||||||
|
this.svg.attr('preserveAspectRatio', 'xMidYMidmeet')
|
||||||
|
this.simulation = d3
|
||||||
|
.forceSimulation()
|
||||||
|
.force('charge', d3.forceManyBody().strength(-1500))
|
||||||
|
.force(
|
||||||
|
'link',
|
||||||
|
d3
|
||||||
|
.forceLink()
|
||||||
|
.distance(60)
|
||||||
|
.id(function (d) {
|
||||||
|
return d.uuid
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.force('collide', d3.forceCollide().strength(-30))
|
||||||
|
.force('center', d3.forceCenter(this.width / 2, this.height / 2))
|
||||||
|
this.qaGraphLink = this.svg.append('g').attr('class', 'line')
|
||||||
|
this.qaGraphLinkText = this.svg.append('g').attr('class', 'lineText')
|
||||||
|
this.qaGraphNode = this.svg.append('g').attr('class', 'node')
|
||||||
|
this.qaGraphNodeText = this.svg.append('g').attr('class', 'nodeText')
|
||||||
|
this.nodeButtonGroup = this.svg.append('g').attr('class', 'nodeButton')
|
||||||
|
this.svg.on(
|
||||||
|
'click',
|
||||||
|
function () {
|
||||||
|
d3.selectAll('.buttongroup').classed('notshow', true)
|
||||||
|
},
|
||||||
|
false
|
||||||
|
)
|
||||||
|
},
|
||||||
|
initGraph() {
|
||||||
|
var _this = this
|
||||||
|
axios.get('/static/kgData.json', {}).then(function (response) {
|
||||||
|
var data = response.data
|
||||||
|
_this.graph.nodes = data.node
|
||||||
|
_this.graph.links = data.relationship
|
||||||
|
_this.updateGraph()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
addMaker() {
|
||||||
|
var arrowMarker = this.svg
|
||||||
|
.append('marker')
|
||||||
|
.attr('id', 'arrow')
|
||||||
|
.attr('markerUnits', 'strokeWidth')
|
||||||
|
.attr('markerWidth', '12') //
|
||||||
|
.attr('markerHeight', '12')
|
||||||
|
.attr('viewBox', '0 0 12 12')
|
||||||
|
.attr('refX', '30')
|
||||||
|
.attr('refY', '6')
|
||||||
|
.attr('orient', 'auto')
|
||||||
|
var arrowPath = 'M2,2 L10,6 L2,10 L6,6 L2,2' // 定义箭头形状
|
||||||
|
arrowMarker.append('path').attr('d', arrowPath).attr('fill', '#ccc')
|
||||||
|
},
|
||||||
|
openNode() {
|
||||||
|
var _this = this
|
||||||
|
var noddd = [
|
||||||
|
{
|
||||||
|
flag: '1',
|
||||||
|
code: '27301111',
|
||||||
|
parentCode: '273',
|
||||||
|
grade: '2',
|
||||||
|
name: '儒家2',
|
||||||
|
uuid: '4617858011',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: '273012222',
|
||||||
|
flag: '1',
|
||||||
|
parentCode: '273',
|
||||||
|
grade: '3',
|
||||||
|
name: '故事轶闻2',
|
||||||
|
uuid: '2636501111',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
var newships = [
|
||||||
|
{
|
||||||
|
sourceId: '273',
|
||||||
|
targetId: '2636501111',
|
||||||
|
name: '',
|
||||||
|
targetcode: '2730107',
|
||||||
|
uuid: '91804213',
|
||||||
|
sourcecode: '27301',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sourceId: '273',
|
||||||
|
targetId: '4617858011',
|
||||||
|
name: '',
|
||||||
|
targetcode: '273010723',
|
||||||
|
uuid: '91804389',
|
||||||
|
sourcecode: '2730107',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
_this.graph.nodes = _this.graph.nodes.concat(noddd)
|
||||||
|
_this.graph.links = _this.graph.links.concat(newships)
|
||||||
|
_this.updateGraph()
|
||||||
|
},
|
||||||
|
drawNode(nodes) {
|
||||||
|
var _this = this
|
||||||
|
var node = this.qaGraphNode.selectAll('circle').data(nodes, function (d) {
|
||||||
|
return d.uuid
|
||||||
|
})
|
||||||
|
node.exit().remove()
|
||||||
|
var nodeEnter = node.enter().append('circle')
|
||||||
|
nodeEnter.on('click', function (d) {
|
||||||
|
console.log('触发单击')
|
||||||
|
_this.selectUuid = d.uuid
|
||||||
|
var out_buttongroup_id = '.out_buttongroup_' + d.uuid
|
||||||
|
var selectItem = d3.select(out_buttongroup_id)._groups[0][0]
|
||||||
|
if (selectItem.classList.contains('notshow')) {
|
||||||
|
_this.svg.selectAll('.buttongroup').classed('notshow', true)
|
||||||
|
d3.select(out_buttongroup_id).classed('notshow', false)
|
||||||
|
} else {
|
||||||
|
d3.select(out_buttongroup_id).classed('notshow', true)
|
||||||
|
}
|
||||||
|
event.stopPropagation()
|
||||||
|
})
|
||||||
|
nodeEnter.on('dblclick', function (d) {
|
||||||
|
console.log('触发双击:' + d)
|
||||||
|
event.preventDefault()
|
||||||
|
})
|
||||||
|
nodeEnter.on('mouseenter', function () {
|
||||||
|
console.log('鼠标移入')
|
||||||
|
d3.select(this).style('stroke-width', '6')
|
||||||
|
})
|
||||||
|
nodeEnter.on('mouseleave', function () {
|
||||||
|
console.log('鼠标移出')
|
||||||
|
d3.select(this).style('stroke-width', 2)
|
||||||
|
//todo其他节点和连线一并显示
|
||||||
|
d3.select('.node').style('fill-opacity', 1)
|
||||||
|
d3.select('.nodeText').style('fill-opacity', 1)
|
||||||
|
d3.selectAll('.line').style('stroke-opacity', 1)
|
||||||
|
d3.selectAll('.lineText').style('fill-opacity', 1)
|
||||||
|
})
|
||||||
|
nodeEnter.on('mouseover', function (d) {
|
||||||
|
//todo鼠标放上去只显示相关节点,其他节点和连线隐藏
|
||||||
|
d3.selectAll('.node').style('fill-opacity', 0.1)
|
||||||
|
var relvantNodeIds = []
|
||||||
|
var relvantNodes = _this.graph.links.filter(function (n) {
|
||||||
|
return n.sourceId == d.uuid || n.targetId == d.uuid
|
||||||
|
})
|
||||||
|
relvantNodes.forEach(function (item) {
|
||||||
|
relvantNodeIds.push(item.sourceId)
|
||||||
|
relvantNodeIds.push(item.targetId)
|
||||||
|
})
|
||||||
|
//显示相关的节点
|
||||||
|
_this.qaGraphNode
|
||||||
|
.selectAll('circle')
|
||||||
|
.style('fill-opacity', function (c) {
|
||||||
|
if (relvantNodeIds.indexOf(c.uuid) > -1) {
|
||||||
|
return 1.0
|
||||||
|
}
|
||||||
|
})
|
||||||
|
//透明所有节点文字
|
||||||
|
d3.selectAll('.nodeText').style('fill-opacity', 0.1)
|
||||||
|
//显示相关的节点文字
|
||||||
|
_this.qaGraphNodeText
|
||||||
|
.selectAll('text')
|
||||||
|
.style('fill-opacity', function (c) {
|
||||||
|
if (relvantNodeIds.indexOf(c.uuid) > -1) {
|
||||||
|
return 1.0
|
||||||
|
}
|
||||||
|
})
|
||||||
|
//透明所有连线
|
||||||
|
d3.selectAll('.line').style('stroke-opacity', 0.1)
|
||||||
|
//显示相关的连线
|
||||||
|
_this.qaGraphLink
|
||||||
|
.selectAll('line')
|
||||||
|
.style('stroke-opacity', function (c) {
|
||||||
|
if (c.lk.targetId === d.uuid) {
|
||||||
|
console.log(c)
|
||||||
|
return 1.0
|
||||||
|
}
|
||||||
|
})
|
||||||
|
//透明所有连线文字
|
||||||
|
d3.selectAll('.lineText').style('fill-opacity', 0.1)
|
||||||
|
//显示相关的连线文字
|
||||||
|
_this.qaGraphLinkText
|
||||||
|
.selectAll('.lineText')
|
||||||
|
.style('fill-opacity', function (c) {
|
||||||
|
if (c.lk.targetId === d.uuid) {
|
||||||
|
return 1.0
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
nodeEnter.call(
|
||||||
|
d3
|
||||||
|
.drag()
|
||||||
|
.on('start', _this.dragStarted)
|
||||||
|
.on('drag', _this.dragged)
|
||||||
|
.on('end', _this.dragEnded)
|
||||||
|
)
|
||||||
|
node = nodeEnter.merge(node).text(function (d) {
|
||||||
|
return d.name
|
||||||
|
})
|
||||||
|
node.style('stroke', function (d) {
|
||||||
|
if (d.color) {
|
||||||
|
return d.color
|
||||||
|
}
|
||||||
|
return '#A4ED6C'
|
||||||
|
})
|
||||||
|
node.style('stroke-opacity', 0.6)
|
||||||
|
node.attr('r', function (d) {
|
||||||
|
if (d.r) {
|
||||||
|
return d.r
|
||||||
|
}
|
||||||
|
return d.index === 0 ? 28 : 20
|
||||||
|
})
|
||||||
|
node.attr('fill', function (d, i) {
|
||||||
|
//创建圆形图像
|
||||||
|
if (d.imgsrc) {
|
||||||
|
var img_w = 77,
|
||||||
|
img_h = 80
|
||||||
|
var defs = d3.selectAll('svg >defs')
|
||||||
|
var catpattern = defs
|
||||||
|
.append('pattern')
|
||||||
|
.attr('id', 'catpattern' + i)
|
||||||
|
.attr('height', 1)
|
||||||
|
.attr('width', 1)
|
||||||
|
catpattern
|
||||||
|
.append('image')
|
||||||
|
.attr('x', -(img_w / 2 - d.r))
|
||||||
|
.attr('y', -(img_h / 2 - d.r))
|
||||||
|
.attr('width', img_w)
|
||||||
|
.attr('height', img_h)
|
||||||
|
.attr('xlink:href', d.imgsrc)
|
||||||
|
return 'url(#catpattern' + i + ')'
|
||||||
|
} else {
|
||||||
|
if (d.cur === '1') {
|
||||||
|
return _this.colorList[0]
|
||||||
|
} else {
|
||||||
|
return _this.colorList[2]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
node
|
||||||
|
.append('title') // 为每个节点设置title
|
||||||
|
.text(function (d) {
|
||||||
|
if (d.name) {
|
||||||
|
return d.name
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
})
|
||||||
|
return node
|
||||||
|
},
|
||||||
|
drawNodeText(nodes) {
|
||||||
|
var _this = this
|
||||||
|
var nodeText = this.qaGraphNodeText
|
||||||
|
.selectAll('text')
|
||||||
|
.data(nodes, function (d) {
|
||||||
|
return d.uuid
|
||||||
|
})
|
||||||
|
nodeText.exit().remove()
|
||||||
|
var nodeTextEnter = nodeText.enter().append('text')
|
||||||
|
nodeTextEnter.call(
|
||||||
|
d3
|
||||||
|
.drag()
|
||||||
|
.on('start', _this.dragStarted)
|
||||||
|
.on('drag', _this.dragged)
|
||||||
|
.on('end', _this.dragEnded)
|
||||||
|
)
|
||||||
|
nodeText = nodeTextEnter.merge(nodeText).text(function (d) {
|
||||||
|
return d.name
|
||||||
|
})
|
||||||
|
nodeText
|
||||||
|
.style('fill', function () {
|
||||||
|
return '#333'
|
||||||
|
})
|
||||||
|
.attr('class', 'nodeText')
|
||||||
|
.attr('dy', '3.6em')
|
||||||
|
.attr('font-family', '宋体')
|
||||||
|
.attr('font-size', 16)
|
||||||
|
.attr('text-anchor', 'middle')
|
||||||
|
.text(function (d) {
|
||||||
|
return d.name
|
||||||
|
})
|
||||||
|
nodeText
|
||||||
|
.append('title') // 为每个节点设置title
|
||||||
|
.text(function (d) {
|
||||||
|
if (d.name) {
|
||||||
|
return d.name
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
})
|
||||||
|
return nodeText
|
||||||
|
},
|
||||||
|
drawLink(links) {
|
||||||
|
var _this = this
|
||||||
|
var link = this.qaGraphLink.selectAll('line').data(links, function (d) {
|
||||||
|
return d.uuid
|
||||||
|
})
|
||||||
|
link.exit().remove()
|
||||||
|
var linkEnter = link
|
||||||
|
.enter()
|
||||||
|
.append('line')
|
||||||
|
.attr('class', 'link')
|
||||||
|
.attr('stroke-width', 1)
|
||||||
|
.attr('stroke', function () {
|
||||||
|
return _this.colorList[2]
|
||||||
|
})
|
||||||
|
.attr('fill', function () {
|
||||||
|
return _this.colorList[2]
|
||||||
|
})
|
||||||
|
.attr('marker-end', 'url(#arrow)') // 箭头
|
||||||
|
link = linkEnter.merge(link)
|
||||||
|
return link
|
||||||
|
},
|
||||||
|
drawLinkText(links) {
|
||||||
|
var _this = this
|
||||||
|
var linktext = _this.qaGraphLinkText
|
||||||
|
.selectAll('text')
|
||||||
|
.data(links, function (d) {
|
||||||
|
return d.uuid
|
||||||
|
})
|
||||||
|
linktext.exit().remove()
|
||||||
|
var linkTextEnter = linktext
|
||||||
|
.enter()
|
||||||
|
.append('text')
|
||||||
|
.attr('class', 'lineText')
|
||||||
|
.style('fill', '#875034')
|
||||||
|
.style('font-size', '16px')
|
||||||
|
.text(function (d) {
|
||||||
|
return d.lk.name
|
||||||
|
})
|
||||||
|
linktext = linkTextEnter.merge(linktext).text(function (d) {
|
||||||
|
return d.lk.name
|
||||||
|
})
|
||||||
|
return linktext
|
||||||
|
},
|
||||||
|
drawButtonGroup(nodes) {
|
||||||
|
var _this = this
|
||||||
|
d3.selectAll('.nodeButton >g').remove()
|
||||||
|
var nodeButton = _this.nodeButtonGroup
|
||||||
|
.selectAll('.nodeButton')
|
||||||
|
.data(nodes, function (d) {
|
||||||
|
return d.uuid
|
||||||
|
})
|
||||||
|
nodeButton.exit().remove()
|
||||||
|
var nodeButtonEnter = nodeButton
|
||||||
|
.enter()
|
||||||
|
.append('use') // 为每个节点组添加一个 use 子元素
|
||||||
|
.attr('r', function (d) {
|
||||||
|
if (!d.r) {
|
||||||
|
return _this.defaultR
|
||||||
|
}
|
||||||
|
return d.r
|
||||||
|
})
|
||||||
|
.attr('uuid', function (d) {
|
||||||
|
return d.uuid
|
||||||
|
})
|
||||||
|
.attr('xlink:href', function (d) {
|
||||||
|
if (!d.r) {
|
||||||
|
return '#out_circle_' + _this.defaultR
|
||||||
|
}
|
||||||
|
return '#out_circle_' + d.r
|
||||||
|
}) // 指定 use 引用的内容
|
||||||
|
.attr('class', function (d) {
|
||||||
|
return 'buttongroup out_buttongroup_' + d.uuid
|
||||||
|
})
|
||||||
|
.classed('notshow', true)
|
||||||
|
nodeButton = nodeButtonEnter.merge(nodeButton)
|
||||||
|
return nodeButton
|
||||||
|
},
|
||||||
|
drawToolButton() {
|
||||||
|
var _this = this
|
||||||
|
//先删除所有为节点自定义的按钮组
|
||||||
|
d3.selectAll('svg >defs').remove()
|
||||||
|
var nodes = _this.graph.nodes
|
||||||
|
var pie = d3.pie().value(function (d) {
|
||||||
|
return d.value //处理数据,指定value作为计算比例的字段
|
||||||
|
})
|
||||||
|
var piedata = pie(_this.toolbarData)
|
||||||
|
var nodeButtonGroup = this.svg.append('defs')
|
||||||
|
var nodeRArr = []
|
||||||
|
nodes.forEach(function (m) {
|
||||||
|
if (!m.r) {
|
||||||
|
m.r = _this.defaultR
|
||||||
|
}
|
||||||
|
//按半径分别定义每种按钮组的图标
|
||||||
|
if (nodeRArr.indexOf(m.r) == -1) {
|
||||||
|
nodeRArr.push(m.r)
|
||||||
|
var nbtng = nodeButtonGroup
|
||||||
|
.append('g')
|
||||||
|
.attr('id', 'out_circle_' + m.r) //为每一个节点定制一个按钮组,在画按钮组的时候为其指定该id
|
||||||
|
var buttonGroupEnter = nbtng
|
||||||
|
.selectAll('.buttongroup')
|
||||||
|
.data(piedata)
|
||||||
|
.enter()
|
||||||
|
.append('g')
|
||||||
|
.attr('class', function (d) {
|
||||||
|
return 'action_' + d.data.code
|
||||||
|
})
|
||||||
|
var arc = d3
|
||||||
|
.arc()
|
||||||
|
.innerRadius(m.r)
|
||||||
|
.outerRadius(m.r + 30)
|
||||||
|
buttonGroupEnter
|
||||||
|
.append('path')
|
||||||
|
.attr('d', function (d) {
|
||||||
|
return arc(d)
|
||||||
|
})
|
||||||
|
.attr('fill', '#E6A23C')
|
||||||
|
.style('opacity', 0.6)
|
||||||
|
.attr('stroke', '#6CB7ED')
|
||||||
|
.attr('stroke-width', 1)
|
||||||
|
buttonGroupEnter
|
||||||
|
.append('text')
|
||||||
|
.attr('transform', function (d) {
|
||||||
|
return 'translate(' + arc.centroid(d) + ')'
|
||||||
|
})
|
||||||
|
.attr('text-anchor', 'middle')
|
||||||
|
.text(function (d) {
|
||||||
|
return d.data.name
|
||||||
|
})
|
||||||
|
.style('fill', function () {
|
||||||
|
return '#fff'
|
||||||
|
})
|
||||||
|
.attr('font-size', 10)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
bindEventButtonGroup() {
|
||||||
|
var _this = this
|
||||||
|
//按钮组事件绑定
|
||||||
|
_this.toolbarData.forEach(function (m) {
|
||||||
|
var btnClass = '.action_' + m.code
|
||||||
|
_this.svg.selectAll(btnClass).on('click', function (d) {
|
||||||
|
console.log(
|
||||||
|
d.data.name + ':' + d.data.code + ':uuid:' + _this.selectUuid
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
formatData() {
|
||||||
|
var _this = this
|
||||||
|
var lks = _this.graph.links
|
||||||
|
var nodes = _this.graph.nodes
|
||||||
|
nodes.forEach(function (n) {
|
||||||
|
if (n.center === 1 || n.center === '1') {
|
||||||
|
n.fx = _this.width / 2
|
||||||
|
n.fy = _this.height / 2
|
||||||
|
}
|
||||||
|
if (typeof n.fx === 'undefined' || n.fx === '') {
|
||||||
|
n.fx = null
|
||||||
|
}
|
||||||
|
if (typeof n.fy === 'undefined' || n.fy === '') {
|
||||||
|
n.fy = null
|
||||||
|
}
|
||||||
|
})
|
||||||
|
var links = []
|
||||||
|
lks.forEach(function (m) {
|
||||||
|
var sourceNode = nodes.filter(function (n) {
|
||||||
|
return n.uuid === m.sourceId
|
||||||
|
})[0]
|
||||||
|
if (!sourceNode) return
|
||||||
|
var targetNode = nodes.filter(function (n) {
|
||||||
|
return n.uuid === m.targetId
|
||||||
|
})[0]
|
||||||
|
if (!targetNode) return
|
||||||
|
links.push({ source: sourceNode.uuid, target: targetNode.uuid, lk: m })
|
||||||
|
})
|
||||||
|
var data = {}
|
||||||
|
data.nodes = nodes
|
||||||
|
data.links = links
|
||||||
|
return data
|
||||||
|
},
|
||||||
|
updateGraph() {
|
||||||
|
var _this = this
|
||||||
|
var data = _this.formatData()
|
||||||
|
var nodes = data.nodes
|
||||||
|
var links = data.links
|
||||||
|
//定义按钮组引用的use元素
|
||||||
|
_this.drawToolButton(nodes)
|
||||||
|
// 更新节点
|
||||||
|
var graphNode = _this.drawNode(nodes)
|
||||||
|
// 更新节点文字
|
||||||
|
var graphNodeText = _this.drawNodeText(nodes)
|
||||||
|
// 更新按钮组
|
||||||
|
var graphNodeButtonGroup = _this.drawButtonGroup(nodes)
|
||||||
|
// 更新连线 links
|
||||||
|
var graphLink = _this.drawLink(links)
|
||||||
|
// 更新连线文字
|
||||||
|
var graphLinkText = _this.drawLinkText(links)
|
||||||
|
_this.simulation
|
||||||
|
.nodes(nodes)
|
||||||
|
.alphaTarget(0)
|
||||||
|
.alphaDecay(0.05)
|
||||||
|
.on('tick', ticked)
|
||||||
|
function ticked() {
|
||||||
|
// 更新连线坐标
|
||||||
|
graphLink
|
||||||
|
.attr('x1', function (d) {addNodeButton
|
||||||
|
return d.source.x
|
||||||
|
})
|
||||||
|
.attr('y1', function (d) {
|
||||||
|
return d.source.y
|
||||||
|
})
|
||||||
|
.attr('x2', function (d) {
|
||||||
|
return d.target.x
|
||||||
|
})
|
||||||
|
.attr('y2', function (d) {
|
||||||
|
return d.target.y
|
||||||
|
})
|
||||||
|
// 刷新连接线上的文字位置
|
||||||
|
graphLinkText
|
||||||
|
.attr('x', function (d) {
|
||||||
|
if (!d.source.x || !d.target.x) return 0
|
||||||
|
var x = (parseFloat(d.source.x) + parseFloat(d.target.x)) / 2
|
||||||
|
return x
|
||||||
|
})
|
||||||
|
.attr('y', function (d) {
|
||||||
|
if (!d.source.y || !d.target.y) return 0
|
||||||
|
var y = (parseFloat(d.source.y) + parseFloat(d.target.y)) / 2
|
||||||
|
return y
|
||||||
|
})
|
||||||
|
// 更新节点坐标
|
||||||
|
graphNode
|
||||||
|
.attr('cx', function (d) {
|
||||||
|
return d.x
|
||||||
|
})
|
||||||
|
.attr('cy', function (d) {
|
||||||
|
return d.y
|
||||||
|
})
|
||||||
|
// 更新节点操作按钮组坐标
|
||||||
|
graphNodeButtonGroup
|
||||||
|
.attr('cx', function (d) {
|
||||||
|
return d.x
|
||||||
|
})
|
||||||
|
.attr('cy', function (d) {
|
||||||
|
return d.y
|
||||||
|
})
|
||||||
|
.attr('transform', function (d) {
|
||||||
|
return 'translate(' + d.x + ',' + d.y + ') scale(1)'
|
||||||
|
})
|
||||||
|
// 更新文字坐标
|
||||||
|
graphNodeText
|
||||||
|
.attr('x', function (d) {
|
||||||
|
return d.x
|
||||||
|
})
|
||||||
|
.attr('y', function (d) {
|
||||||
|
return d.y
|
||||||
|
})
|
||||||
|
}
|
||||||
|
_this.simulation.force('link').links(links)
|
||||||
|
_this.simulation.force(
|
||||||
|
'center',
|
||||||
|
d3.forceCenter(_this.width / 2, _this.height / 2)
|
||||||
|
)
|
||||||
|
_this.simulation.alpha(1).restart()
|
||||||
|
// 鼠标滚轮缩放
|
||||||
|
_this.zoom = d3.zoom().scaleExtent([0.1, 4]).on('zoom', _this.zoomed)
|
||||||
|
_this.svg.call(_this.zoom)
|
||||||
|
// 静止双击缩放
|
||||||
|
_this.svg.on('dblclick.zoom', null)
|
||||||
|
//为按钮组绑定事件
|
||||||
|
_this.bindEventButtonGroup()
|
||||||
|
},
|
||||||
|
dragStarted(d) {
|
||||||
|
if (!d3.event.active) this.simulation.alphaTarget(0.8).restart()
|
||||||
|
d.x = d3.event.x
|
||||||
|
d.y = d3.event.y
|
||||||
|
d.fx = d.x
|
||||||
|
d.fy = d.y
|
||||||
|
},
|
||||||
|
dragged(d) {
|
||||||
|
d.x = d3.event.x
|
||||||
|
d.y = d3.event.y
|
||||||
|
d.fx = d3.event.x
|
||||||
|
d.fy = d3.event.y
|
||||||
|
},
|
||||||
|
dragEnded(d) {
|
||||||
|
if (!d3.event.active) this.simulation.alphaTarget(0)
|
||||||
|
d.x = d3.event.x
|
||||||
|
d.y = d3.event.y
|
||||||
|
d.fx = d3.event.x
|
||||||
|
d.fy = d3.event.y
|
||||||
|
},
|
||||||
|
zoomed() {
|
||||||
|
d3.selectAll('.node').attr('transform', d3.event.transform)
|
||||||
|
d3.selectAll('.nodeText text').attr('transform', d3.event.transform)
|
||||||
|
d3.selectAll('.line').attr('transform', d3.event.transform)
|
||||||
|
d3.selectAll('.lineText text').attr('transform', d3.event.transform)
|
||||||
|
d3.selectAll('.nodeButton').attr('transform', d3.event.transform)
|
||||||
|
//_this.svg.selectAll("g").attr("transform", d3.event.transform);
|
||||||
|
},
|
||||||
|
zoomClick(direction) {
|
||||||
|
var self = this
|
||||||
|
var factor = 0.2
|
||||||
|
var targetZoom = 1
|
||||||
|
var extent = self.zoom.scaleExtent()
|
||||||
|
targetZoom = 1 + factor * direction
|
||||||
|
if (targetZoom < extent[0] || targetZoom > extent[1]) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
self.zoom.scaleBy(self.svg, targetZoom) // 执行该方法后 会触发zoom事件
|
||||||
|
},
|
||||||
|
zoomIn() {
|
||||||
|
this.zoomClick(1)
|
||||||
|
},
|
||||||
|
zoomOut() {
|
||||||
|
this.zoomClick(-1)
|
||||||
|
},
|
||||||
|
refresh() {
|
||||||
|
this.svg.call(this.zoom.transform, d3.zoomIdentity)
|
||||||
|
},
|
||||||
|
showFull() {
|
||||||
|
this.isFullscreen = !this.isFullscreen
|
||||||
|
var full = document.getElementById('kg_container')
|
||||||
|
this.fullScreen(full)
|
||||||
|
},
|
||||||
|
fullScreen(element) {
|
||||||
|
if (element.requestFullscreen) {
|
||||||
|
element.requestFullscreen()
|
||||||
|
} else if (element.mozRequestFullScreen) {
|
||||||
|
element.mozRequestFullScreen()
|
||||||
|
} else if (element.webkitRequestFullscreen) {
|
||||||
|
element.webkitRequestFullscreen()
|
||||||
|
} else if (element.msRequestFullscreen) {
|
||||||
|
element.msRequestFullscreen()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
exitFullScreen() {
|
||||||
|
this.isFullscreen = !this.isFullscreen
|
||||||
|
if (document.exitFullscreen) {
|
||||||
|
document.exitFullscreen()
|
||||||
|
} else if (document.mozCancelFullScreen) {
|
||||||
|
document.mozCancelFullScreen()
|
||||||
|
} else if (document.webkitExitFullscreen) {
|
||||||
|
document.webkitExitFullscreen()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
btnCollapseNode() {},
|
||||||
|
btnOpenNode() {},
|
||||||
|
close() {},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
.svg-set-box {
|
||||||
|
height: 46px;
|
||||||
|
line-height: 46px;
|
||||||
|
padding-left: 15px;
|
||||||
|
color: #7f7f7f;
|
||||||
|
/* background: #f7f7f7; */
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
.ctwh-dibmr {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
.ss-d {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
margin-right: 10px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: #dedede;
|
||||||
|
}
|
||||||
|
.sd1 {
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
}
|
||||||
|
.sd2 {
|
||||||
|
width: 26px;
|
||||||
|
height: 26px;
|
||||||
|
}
|
||||||
|
.sd3 {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
.sd4 {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
|
.sd-active {
|
||||||
|
background: #08aefc !important;
|
||||||
|
}
|
||||||
|
.toolbar {
|
||||||
|
margin-left: 150px;
|
||||||
|
margin-right: 15px;
|
||||||
|
line-height: 18px;
|
||||||
|
}
|
||||||
|
ul,
|
||||||
|
li {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
.toolbar li {
|
||||||
|
float: left;
|
||||||
|
width: 60px;
|
||||||
|
}
|
||||||
|
.notshow {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.nodeText {
|
||||||
|
pointer-events: all;
|
||||||
|
cursor: pointer;
|
||||||
|
stroke-dasharray: 0 0 0 0;
|
||||||
|
stroke-dashoffset: 10;
|
||||||
|
transition: all ease 0.1s;
|
||||||
|
}
|
||||||
|
.nodeText:hover {
|
||||||
|
stroke-dashoffset: 0;
|
||||||
|
stroke-dasharray: 100;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
70
src/components/KGBuilderMenuBlank.vue
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
<template>
|
||||||
|
<!-- 空白处右键 -->
|
||||||
|
<ul
|
||||||
|
class="el-dropdown-menu el-popper blankmenubar"
|
||||||
|
@click="menuBarClick"
|
||||||
|
:style="blankMenuStyle"
|
||||||
|
@mouseleave="menuBarLeave"
|
||||||
|
id="blank_menubar"
|
||||||
|
v-show="menuBarShow"
|
||||||
|
>
|
||||||
|
<li class="el-dropdown-menu__item" @click="btnAddSingle">
|
||||||
|
<svg class="icon" aria-hidden="true">
|
||||||
|
<use xlink:href="#icon-jiedian"></use>
|
||||||
|
</svg>
|
||||||
|
<span class="pl-15">添加节点</span>
|
||||||
|
</li>
|
||||||
|
<li class="el-dropdown-menu__item" @click="btnQuickAddNode">
|
||||||
|
<svg class="icon" aria-hidden="true">
|
||||||
|
<use xlink:href="#icon-add-rd"></use>
|
||||||
|
</svg>
|
||||||
|
<span class="pl-15">快速添加</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
data: Object
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
top: "0px",
|
||||||
|
left: "0px",
|
||||||
|
menuBarShow: false
|
||||||
|
};
|
||||||
|
},
|
||||||
|
inject: ['quickAddNodes'],
|
||||||
|
components: {},
|
||||||
|
computed: {
|
||||||
|
blankMenuStyle() {
|
||||||
|
return {
|
||||||
|
position: "absolute",
|
||||||
|
top: this.top+'px',
|
||||||
|
left: this.left+'px'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
init(data) {
|
||||||
|
this.top = data.top;
|
||||||
|
this.left = data.left;
|
||||||
|
this.menuBarShow = data.show;
|
||||||
|
},
|
||||||
|
btnAddSingle() {
|
||||||
|
this.$emit('changeCursor')
|
||||||
|
},
|
||||||
|
btnQuickAddNode() {
|
||||||
|
this.quickAddNodes(this)
|
||||||
|
},
|
||||||
|
menuBarClick() {
|
||||||
|
this.menuBarShow=false;
|
||||||
|
},
|
||||||
|
menuBarLeave() {
|
||||||
|
this.menuBarShow=false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style></style>
|
||||||
63
src/components/KGBuilderMenuLink.vue
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
<template>
|
||||||
|
<!-- 连线按钮组 -->
|
||||||
|
<ul
|
||||||
|
v-show="linkMenuShow"
|
||||||
|
id="link_menubar2"
|
||||||
|
class="el-dropdown-menu el-popper linkmenubar"
|
||||||
|
:style="linuMenuStyle"
|
||||||
|
@mouseleave="linkMenuBarLeave"
|
||||||
|
>
|
||||||
|
<li class="el-dropdown-menu__item" @click="updateLink">
|
||||||
|
<span class="pl-15">编辑</span>
|
||||||
|
</li>
|
||||||
|
<li class="el-dropdown-menu__item" @click="deleteLink">
|
||||||
|
<span class="pl-15">删除</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// import * as d3 from "d3";
|
||||||
|
export default {
|
||||||
|
inject: ['deleteLinkName', 'updateLinkName'],
|
||||||
|
components: {},
|
||||||
|
props: {},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
top: '0px',
|
||||||
|
left: '0px',
|
||||||
|
linkMenuShow: false,
|
||||||
|
clike: false,
|
||||||
|
data:null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
linuMenuStyle() {
|
||||||
|
return {
|
||||||
|
position: 'absolute',
|
||||||
|
top: this.top + 'px',
|
||||||
|
left: this.left + 'px'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
init(data) {
|
||||||
|
this.top = data.top
|
||||||
|
this.left = data.left
|
||||||
|
this.linkMenuShow = data.show
|
||||||
|
this.data = data.sdata
|
||||||
|
},
|
||||||
|
updateLink() {
|
||||||
|
this.updateLinkName(this.data)
|
||||||
|
},
|
||||||
|
deleteLink() {
|
||||||
|
this.deleteLinkName(this.data)
|
||||||
|
},
|
||||||
|
linkMenuBarLeave() {
|
||||||
|
// d3.select(this).style("display", "none");
|
||||||
|
this.linkMenuShow = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style></style>
|
||||||
628
src/components/KGBuilderSimple.vue
Normal file
@ -0,0 +1,628 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div id="gid_tc" style="float:left;">
|
||||||
|
<div id="gid"></div>
|
||||||
|
<ul
|
||||||
|
class="el-dropdown-menu el-popper"
|
||||||
|
id="my_custom_menu"
|
||||||
|
style="display: none;"
|
||||||
|
>
|
||||||
|
<li class="el-dropdown-menu__item" @click="btnOpenNode">
|
||||||
|
<svg class="ctwh_icon" aria-hidden="true">
|
||||||
|
<use xlink:href="#icon-zk-all"></use>
|
||||||
|
</svg>
|
||||||
|
<span class="pl-15">展开</span>
|
||||||
|
</li>
|
||||||
|
<li class="el-dropdown-menu__item" @click="btnCollapseNode">
|
||||||
|
<svg class="ctwh_icon" aria-hidden="true">
|
||||||
|
<use xlink:href="#icon-shouqi"></use>
|
||||||
|
</svg>
|
||||||
|
<span class="pl-15">收起</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<div
|
||||||
|
class="el-dropdown-menu el-popper"
|
||||||
|
id="richContainer"
|
||||||
|
style="display: none;width: 420px;height: 300px;position: absolute; left: 222px; top: 75px;"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
@click="close"
|
||||||
|
class="close-x"
|
||||||
|
style="
|
||||||
|
float: right;
|
||||||
|
padding: 4px 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
color: rgb(236, 105, 65);font-size: 16px;margin: -20px -33px 0 0;background: #fff;border-radius: 50%;border: 1px solid #ddd;z-index: 999;font-family: '微软雅黑';"
|
||||||
|
>X</span
|
||||||
|
>
|
||||||
|
<div class="search_result_list_min">
|
||||||
|
<div
|
||||||
|
:key="'m_' + index"
|
||||||
|
v-for="(item, index) in nodeRecordList"
|
||||||
|
class="search_result_item_min"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<div class="datatitle">
|
||||||
|
<a href="javascript:;" @click="linkto(item)"
|
||||||
|
>{{ index + 1 }}.{{ item.条目名称 }}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="datasource">
|
||||||
|
<span>{{ item.工具书名称 }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<span class="datacontent" @click="linkto(item)" v-html="item.快照"></span>
|
||||||
|
{{ item.快照 }}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mengceng"></div>
|
||||||
|
</div>
|
||||||
|
<div class="svg-set-box clearfix">
|
||||||
|
<div class="ctwh-dibmr">
|
||||||
|
<span>显示范围:</span>
|
||||||
|
<a
|
||||||
|
:key="index"
|
||||||
|
v-for="(m, index) in pageSizeList"
|
||||||
|
@click="setMatchSize(m, this)"
|
||||||
|
href="javascript:void(0)"
|
||||||
|
:class="[m.isActive ? 'sd-active' : '', 'ss-d sd' + (index + 1)]"
|
||||||
|
>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="ctwh-dibmr" style="float: right">
|
||||||
|
<ul class="toolbar">
|
||||||
|
<li>
|
||||||
|
<a href="javascript:;" @click="zoomin"
|
||||||
|
><span><i class="el-icon-zoom-in"></i>放大</span></a
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="javascript:;" @click="zoomout"
|
||||||
|
><span><i class="el-icon-zoom-out"></i>缩小</span></a
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="javascript:;" @click="refresh"
|
||||||
|
><span><i class="el-icon-refresh-right"></i>还原</span></a
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
v-if="!isFullscreen"
|
||||||
|
id="fullscreenbtn"
|
||||||
|
href="javascript:;"
|
||||||
|
@click="showFull"
|
||||||
|
>
|
||||||
|
<span><i class="el-icon-full-screen"></i>全屏</span>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
v-else
|
||||||
|
id="fullscreenbtn"
|
||||||
|
href="javascript:;"
|
||||||
|
@click="exitfullscreen"
|
||||||
|
>
|
||||||
|
<span><i class="el-icon-full-screen"></i>退出全屏</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import axios from "axios";
|
||||||
|
import * as d3 from "d3";
|
||||||
|
import $ from "jquery";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: ["pid"],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
qaGraphNode: {},
|
||||||
|
qaGraphNodeText: {},
|
||||||
|
qaGraphLink: {},
|
||||||
|
qaGraphLinkText: {},
|
||||||
|
theme: 0,
|
||||||
|
loading: false,
|
||||||
|
width: 1000,
|
||||||
|
height: 800,
|
||||||
|
gcontainer: {},
|
||||||
|
svg: {},
|
||||||
|
zoom: null,
|
||||||
|
arrowMarker: {},
|
||||||
|
simulation: {},
|
||||||
|
isFullscreen: false,
|
||||||
|
graph: {
|
||||||
|
nodes: [],
|
||||||
|
links: []
|
||||||
|
},
|
||||||
|
colorList: [
|
||||||
|
"#ff8373",
|
||||||
|
"#f9c62c",
|
||||||
|
"#a5ca34",
|
||||||
|
"#6fce7a",
|
||||||
|
"#70d3bd",
|
||||||
|
"#ea91b0"
|
||||||
|
],
|
||||||
|
pageSizeList: [
|
||||||
|
{ size: 100, isActive: false },
|
||||||
|
{ size: 300, isActive: false },
|
||||||
|
{ size: 500, isActive: true },
|
||||||
|
{ size: 1000, isActive: false }
|
||||||
|
],
|
||||||
|
nodeRecordList: []
|
||||||
|
};
|
||||||
|
},
|
||||||
|
components: {},
|
||||||
|
mounted() {
|
||||||
|
this.initGraphContainer();
|
||||||
|
this.addMaker();
|
||||||
|
this.initGraph();
|
||||||
|
},
|
||||||
|
created() {},
|
||||||
|
watch: {},
|
||||||
|
methods: {
|
||||||
|
initGraphContainer() {
|
||||||
|
this.gcontainer = d3.select("#gid");
|
||||||
|
if (this.isFullscreen) {
|
||||||
|
this.width = window.screen.width;
|
||||||
|
this.height = window.screen.height;
|
||||||
|
} else {
|
||||||
|
this.width = $("#" + this.pid).width();
|
||||||
|
this.height = $("#" + this.pid).height();
|
||||||
|
}
|
||||||
|
this.svg = this.gcontainer.append("svg");
|
||||||
|
var sWidth = this.width;
|
||||||
|
var sHeight = this.height;
|
||||||
|
this.svg.attr("width", sWidth);
|
||||||
|
this.svg.attr("height", sHeight);
|
||||||
|
// this.svg.attr("viewBox", "0 0 " + sWidth / 2 + " " + sHeight / 2);
|
||||||
|
this.svg.attr("id", "svg_idx");
|
||||||
|
this.svg.attr("preserveAspectRatio", "xMidYMidmeet");
|
||||||
|
this.simulation = d3
|
||||||
|
.forceSimulation()
|
||||||
|
.force("charge", d3.forceManyBody().strength(-1500))
|
||||||
|
.force(
|
||||||
|
"link",
|
||||||
|
d3
|
||||||
|
.forceLink()
|
||||||
|
.distance(60)
|
||||||
|
.id(function(d) {
|
||||||
|
return d.uuid;
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.force("collide", d3.forceCollide().strength(-30))
|
||||||
|
.force("center", d3.forceCenter(this.width / 2, this.height / 2));
|
||||||
|
this.qaGraphLink = this.svg.append("g").attr("class", "line");
|
||||||
|
this.qaGraphLinkText = this.svg.append("g").attr("class", "lineText");
|
||||||
|
this.qaGraphNode = this.svg.append("g").attr("class", "node");
|
||||||
|
this.qaGraphNodeText = this.svg.append("g").attr("class", "nodeText");
|
||||||
|
},
|
||||||
|
initGraph() {
|
||||||
|
var _this = this;
|
||||||
|
axios.get("/static/kgData.json", {}).then(function(response) {
|
||||||
|
var data = response.data;
|
||||||
|
_this.graph.nodes = data.node;
|
||||||
|
_this.graph.links = data.relationship;
|
||||||
|
_this.updateGraph();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
addMaker() {
|
||||||
|
var arrowMarker = this.svg
|
||||||
|
.append("marker")
|
||||||
|
.attr("id", "arrow")
|
||||||
|
.attr("markerUnits", "strokeWidth")
|
||||||
|
.attr("markerWidth", "12") //
|
||||||
|
.attr("markerHeight", "12")
|
||||||
|
.attr("viewBox", "0 0 12 12")
|
||||||
|
.attr("refX", "30")
|
||||||
|
.attr("refY", "6")
|
||||||
|
.attr("orient", "auto");
|
||||||
|
var arrowPath = "M2,2 L10,6 L2,10 L6,6 L2,2"; // 定义箭头形状
|
||||||
|
arrowMarker
|
||||||
|
.append("path")
|
||||||
|
.attr("d", arrowPath)
|
||||||
|
.attr("fill", "#ccc");
|
||||||
|
},
|
||||||
|
drawnode(node) {
|
||||||
|
var _this = this;
|
||||||
|
var nodeEnter = node.enter().append("circle");
|
||||||
|
nodeEnter.on("click", function(d) {
|
||||||
|
console.log("触发单击:" + d);
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-debugger
|
||||||
|
debugger;
|
||||||
|
_this.opennode();
|
||||||
|
console.log("ddd");
|
||||||
|
//
|
||||||
|
});
|
||||||
|
nodeEnter.on("dblclick", function(d) {
|
||||||
|
event.preventDefault();
|
||||||
|
console.log("触发双击:" + d);
|
||||||
|
});
|
||||||
|
nodeEnter.call(
|
||||||
|
d3
|
||||||
|
.drag()
|
||||||
|
.on("start", _this.dragstarted)
|
||||||
|
.on("drag", _this.dragged)
|
||||||
|
.on("end", _this.dragended)
|
||||||
|
);
|
||||||
|
return nodeEnter;
|
||||||
|
},
|
||||||
|
opennode() {
|
||||||
|
var _this = this;
|
||||||
|
var noddd = [
|
||||||
|
{
|
||||||
|
flag: "1",
|
||||||
|
code: "27301",
|
||||||
|
parentCode: "273",
|
||||||
|
grade: "2",
|
||||||
|
name: "儒家2",
|
||||||
|
uuid: "4617858011"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: "2730107",
|
||||||
|
flag: "1",
|
||||||
|
parentCode: "27301",
|
||||||
|
grade: "3",
|
||||||
|
name: "故事轶闻2",
|
||||||
|
uuid: "2636501111"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
var newships = [
|
||||||
|
{
|
||||||
|
sourceid: "46178580",
|
||||||
|
targetid: "2636501111",
|
||||||
|
name: "",
|
||||||
|
targetcode: "2730107",
|
||||||
|
uuid: "91804213",
|
||||||
|
sourcecode: "27301"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sourceid: "46178580",
|
||||||
|
targetid: "4617858011",
|
||||||
|
name: "",
|
||||||
|
targetcode: "273010723",
|
||||||
|
uuid: "91804389",
|
||||||
|
sourcecode: "2730107"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
_this.graph.nodes = _this.graph.nodes.concat(noddd);
|
||||||
|
_this.graph.links = _this.graph.links.concat(newships);
|
||||||
|
_this.updateGraph();
|
||||||
|
},
|
||||||
|
drawNodeText(nodeText) {
|
||||||
|
var _this = this;
|
||||||
|
var nodeTextEnter = nodeText.enter().append("text");
|
||||||
|
nodeTextEnter.call(
|
||||||
|
d3
|
||||||
|
.drag()
|
||||||
|
.on("start", _this.dragstarted)
|
||||||
|
.on("drag", _this.dragged)
|
||||||
|
.on("end", _this.dragended)
|
||||||
|
);
|
||||||
|
return nodeTextEnter;
|
||||||
|
},
|
||||||
|
drawLink(link) {
|
||||||
|
var _this = this;
|
||||||
|
var linkEnter = link
|
||||||
|
.enter()
|
||||||
|
.append("line")
|
||||||
|
.attr("stroke-width", 1)
|
||||||
|
.attr("stroke", function() {
|
||||||
|
return _this.colorList[2];
|
||||||
|
})
|
||||||
|
.attr("marker-end", "url(#arrow)"); // 箭头
|
||||||
|
return linkEnter;
|
||||||
|
},
|
||||||
|
drawLinkText(linktext) {
|
||||||
|
var linkTextEnter = linktext
|
||||||
|
.enter()
|
||||||
|
.append("text")
|
||||||
|
.attr("class", "lineText")
|
||||||
|
.style("fill", "#875034")
|
||||||
|
.style("font-size", "16px")
|
||||||
|
.text(function(d) {
|
||||||
|
return d.lk.name;
|
||||||
|
});
|
||||||
|
return linkTextEnter;
|
||||||
|
},
|
||||||
|
updateGraph() {
|
||||||
|
var _this = this;
|
||||||
|
var lks = _this.graph.links;
|
||||||
|
var nodes = _this.graph.nodes;
|
||||||
|
nodes.forEach(function(n) {
|
||||||
|
if (n.center === 1 || n.center === "1") {
|
||||||
|
n.fx = _this.width / 2;
|
||||||
|
n.fy = _this.height / 2;
|
||||||
|
}
|
||||||
|
if (typeof n.fx === "undefined" || n.fx === "") {
|
||||||
|
n.fx = null;
|
||||||
|
}
|
||||||
|
if (typeof n.fy === "undefined" || n.fy === "") {
|
||||||
|
n.fy = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var links = [];
|
||||||
|
// eslint-disable-next-line no-debugger
|
||||||
|
debugger;
|
||||||
|
lks.forEach(function(m) {
|
||||||
|
var sourceNode = nodes.filter(function(n) {
|
||||||
|
return n.uuid === m.sourceid;
|
||||||
|
})[0];
|
||||||
|
if (typeof sourceNode === "undefined") return;
|
||||||
|
var targetNode = nodes.filter(function(n) {
|
||||||
|
return n.uuid === m.targetid;
|
||||||
|
})[0];
|
||||||
|
if (typeof targetNode === "undefined") return;
|
||||||
|
links.push({ source: sourceNode.uuid, target: targetNode.uuid, lk: m });
|
||||||
|
});
|
||||||
|
// 更新节点
|
||||||
|
//_this.qaGraphNode = _this.drawnode(nodes);
|
||||||
|
var node = _this.qaGraphNode.selectAll("circle").data(nodes, function(d) {
|
||||||
|
return d.uuid;
|
||||||
|
});
|
||||||
|
node.exit().remove();
|
||||||
|
var nodeEnter = _this.drawnode(node);
|
||||||
|
node = nodeEnter.merge(node).text(function(d) {
|
||||||
|
return d.name;
|
||||||
|
});
|
||||||
|
node.attr("r", 25);
|
||||||
|
node.attr("fill", "red");
|
||||||
|
node
|
||||||
|
.append("title") // 为每个节点设置title
|
||||||
|
.text(function(d) {
|
||||||
|
return d.name;
|
||||||
|
});
|
||||||
|
// 更新节点文字
|
||||||
|
//_this.qaGraphNodeText = _this.drawNodeText(nodes);
|
||||||
|
var nodeText = _this.qaGraphNodeText
|
||||||
|
.selectAll("text")
|
||||||
|
.data(nodes, function(d) {
|
||||||
|
return d.uuid;
|
||||||
|
});
|
||||||
|
nodeText.exit().remove();
|
||||||
|
var nodeTextEnter = _this.drawNodeText(nodeText);
|
||||||
|
nodeText = nodeTextEnter.merge(nodeText).text(function(d) {
|
||||||
|
return d.name;
|
||||||
|
});
|
||||||
|
nodeText
|
||||||
|
.style("fill", function() {
|
||||||
|
if (_this.theme === 0) {
|
||||||
|
return "#333";
|
||||||
|
} else {
|
||||||
|
return "#fff";
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.attr("class", "nodeText")
|
||||||
|
.attr("dy", "3.6em")
|
||||||
|
.attr("font-family", "宋体")
|
||||||
|
.attr("font-size", 16)
|
||||||
|
.attr("text-anchor", "middle")
|
||||||
|
.text(function(d) {
|
||||||
|
return d.name;
|
||||||
|
});
|
||||||
|
nodeText
|
||||||
|
.append("title") // 为每个节点设置title
|
||||||
|
.text(function(d) {
|
||||||
|
if (typeof d.name !== "undefined") {
|
||||||
|
return d.name;
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
});
|
||||||
|
// 更新连线 links
|
||||||
|
// _this.qaGraphLink = _this.drawLink(links);
|
||||||
|
var link = _this.qaGraphLink.selectAll("line").data(links, function(d) {
|
||||||
|
return d.uuid;
|
||||||
|
});
|
||||||
|
link.exit().remove();
|
||||||
|
var linkEnter = _this.drawLink(link);
|
||||||
|
link = linkEnter.merge(link);
|
||||||
|
// 更新连线文字
|
||||||
|
//_this.qaGraphLinkText = _this.drawLinkText(links);
|
||||||
|
var linktext = _this.qaGraphLinkText
|
||||||
|
.selectAll("text")
|
||||||
|
.data(links, function(d) {
|
||||||
|
return d.uuid;
|
||||||
|
});
|
||||||
|
linktext.exit().remove();
|
||||||
|
var linkTextEnter = _this.drawLinkText(linktext);
|
||||||
|
linktext = linkTextEnter.merge(linktext).text(function(d) {
|
||||||
|
return d.lk.name;
|
||||||
|
});
|
||||||
|
_this.simulation
|
||||||
|
.nodes(nodes)
|
||||||
|
.alphaTarget(0)
|
||||||
|
.alphaDecay(0.05)
|
||||||
|
.on("tick", ticked);
|
||||||
|
function ticked() {
|
||||||
|
// 更新连线坐标
|
||||||
|
link
|
||||||
|
.attr("x1", function(d) {
|
||||||
|
return d.source.x;
|
||||||
|
})
|
||||||
|
.attr("y1", function(d) {
|
||||||
|
return d.source.y;
|
||||||
|
})
|
||||||
|
.attr("x2", function(d) {
|
||||||
|
return d.target.x;
|
||||||
|
})
|
||||||
|
.attr("y2", function(d) {
|
||||||
|
return d.target.y;
|
||||||
|
});
|
||||||
|
// 刷新连接线上的文字位置
|
||||||
|
linktext
|
||||||
|
.attr("x", function(d) {
|
||||||
|
if (
|
||||||
|
typeof d.source.x === "undefined" ||
|
||||||
|
typeof d.target.x === "undefined"
|
||||||
|
)
|
||||||
|
return 0;
|
||||||
|
var x = (parseFloat(d.source.x) + parseFloat(d.target.x)) / 2;
|
||||||
|
return x;
|
||||||
|
})
|
||||||
|
.attr("y", function(d) {
|
||||||
|
if (
|
||||||
|
typeof d.source.y === "undefined" ||
|
||||||
|
typeof d.target.y === "undefined"
|
||||||
|
)
|
||||||
|
return 0;
|
||||||
|
var y = (parseFloat(d.source.y) + parseFloat(d.target.y)) / 2;
|
||||||
|
return y;
|
||||||
|
});
|
||||||
|
// 更新节点坐标
|
||||||
|
node
|
||||||
|
.attr("cx", function(d) {
|
||||||
|
return d.x;
|
||||||
|
})
|
||||||
|
.attr("cy", function(d) {
|
||||||
|
return d.y;
|
||||||
|
});
|
||||||
|
// 更新文字坐标
|
||||||
|
nodeText
|
||||||
|
.attr("x", function(d) {
|
||||||
|
return d.x;
|
||||||
|
})
|
||||||
|
.attr("y", function(d) {
|
||||||
|
return d.y;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_this.simulation.force("link").links(links);
|
||||||
|
_this.simulation.force(
|
||||||
|
"center",
|
||||||
|
d3.forceCenter(_this.width / 2, _this.height / 2)
|
||||||
|
);
|
||||||
|
_this.simulation.alpha(1).restart();
|
||||||
|
// 鼠标滚轮缩放
|
||||||
|
_this.zoom = d3
|
||||||
|
.zoom()
|
||||||
|
.scaleExtent([0.1, 4])
|
||||||
|
.on("zoom", _this.zoomed);
|
||||||
|
_this.svg.call(_this.zoom);
|
||||||
|
_this.svg.on("dblclick.zoom", null); // 静止双击缩放
|
||||||
|
},
|
||||||
|
dragstarted(d) {
|
||||||
|
if (!d3.event.active) this.simulation.alphaTarget(0.3).restart();
|
||||||
|
d.fx = d.x;
|
||||||
|
d.fy = d.y;
|
||||||
|
},
|
||||||
|
dragged(d) {
|
||||||
|
d.fx = d3.event.x;
|
||||||
|
d.fy = d3.event.y;
|
||||||
|
},
|
||||||
|
dragended(d) {
|
||||||
|
if (!d3.event.active) this.simulation.alphaTarget(0);
|
||||||
|
d.fx = d3.event.x;
|
||||||
|
d.fy = d3.event.y;
|
||||||
|
},
|
||||||
|
zoomed() {
|
||||||
|
this.svg.selectAll("g").attr("transform", d3.event.transform);
|
||||||
|
},
|
||||||
|
zoomClick(direction) {
|
||||||
|
var self = this;
|
||||||
|
var factor = 0.2;
|
||||||
|
var targetZoom = 1;
|
||||||
|
var extent = self.zoom.scaleExtent();
|
||||||
|
targetZoom = 1 + factor * direction;
|
||||||
|
if (targetZoom < extent[0] || targetZoom > extent[1]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
self.zoom.scaleBy(self.svg, targetZoom); // 执行该方法后 会触发zoom事件
|
||||||
|
},
|
||||||
|
zoomin() {
|
||||||
|
this.zoomClick(1);
|
||||||
|
},
|
||||||
|
zoomout() {
|
||||||
|
this.zoomClick(-1);
|
||||||
|
},
|
||||||
|
refresh() {
|
||||||
|
this.svg.call(this.zoom.transform, d3.zoomIdentity);
|
||||||
|
},
|
||||||
|
showFull() {
|
||||||
|
this.isFullscreen = !this.isFullscreen;
|
||||||
|
var full = document.getElementById("kg_container");
|
||||||
|
this.fullscreen(full);
|
||||||
|
},
|
||||||
|
fullscreen(element) {
|
||||||
|
if (element.requestFullscreen) {
|
||||||
|
element.requestFullscreen();
|
||||||
|
} else if (element.mozRequestFullScreen) {
|
||||||
|
element.mozRequestFullScreen();
|
||||||
|
} else if (element.webkitRequestFullscreen) {
|
||||||
|
element.webkitRequestFullscreen();
|
||||||
|
} else if (element.msRequestFullscreen) {
|
||||||
|
element.msRequestFullscreen();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
exitfullscreen() {
|
||||||
|
this.isFullscreen = !this.isFullscreen;
|
||||||
|
if (document.exitFullscreen) {
|
||||||
|
document.exitFullscreen();
|
||||||
|
} else if (document.mozCancelFullScreen) {
|
||||||
|
document.mozCancelFullScreen();
|
||||||
|
} else if (document.webkitExitFullscreen) {
|
||||||
|
document.webkitExitFullscreen();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
btnCollapseNode() {},
|
||||||
|
btnOpenNode() {},
|
||||||
|
close() {}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
.svg-set-box {
|
||||||
|
height: 46px;
|
||||||
|
line-height: 46px;
|
||||||
|
padding-left: 15px;
|
||||||
|
color: #7f7f7f;
|
||||||
|
/* background: #f7f7f7; */
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
.ctwh-dibmr {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
.ss-d {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
margin-right: 10px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: #dedede;
|
||||||
|
}
|
||||||
|
.sd1 {
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
}
|
||||||
|
.sd2 {
|
||||||
|
width: 26px;
|
||||||
|
height: 26px;
|
||||||
|
}
|
||||||
|
.sd3 {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
.sd4 {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
|
.sd-active {
|
||||||
|
background: #08aefc !important;
|
||||||
|
}
|
||||||
|
.toolbar {
|
||||||
|
margin-left: 150px;
|
||||||
|
margin-right: 15px;
|
||||||
|
line-height: 18px;
|
||||||
|
}
|
||||||
|
ul,
|
||||||
|
li {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
.toolbar li {
|
||||||
|
float: left;
|
||||||
|
width: 60px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
1481
src/components/KGBuilder_v1.vue
Normal file
56
src/components/KGFocus.vue
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
<!--
|
||||||
|
* @Description: file content
|
||||||
|
* @Author: tc
|
||||||
|
* @Date: 2022-01-01 12:53:00
|
||||||
|
* @LastEditors: your name
|
||||||
|
* @LastEditTime: 2022-01-01 14:06:07
|
||||||
|
-->
|
||||||
|
<template>
|
||||||
|
<div id="follow-us" class="guanzhu" style="padding: 20px;">
|
||||||
|
<h2 class="hometitle"></h2>
|
||||||
|
<ul>
|
||||||
|
<li class="wx">
|
||||||
|
<img
|
||||||
|
src="@/assets/中国一重.png" style="width: 100%;" />
|
||||||
|
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
data: Object
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
|
||||||
|
};
|
||||||
|
},
|
||||||
|
mounted() {},
|
||||||
|
components: {},
|
||||||
|
methods: {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
.guanzhu ul li {
|
||||||
|
font-size: 12px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
background: #fff;
|
||||||
|
color: #525252;
|
||||||
|
line-height: 40px;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 2px;
|
||||||
|
position: relative;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.guanzhu .wx img {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
107
src/components/KGHeader.vue
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
<!--
|
||||||
|
* @Description: file content
|
||||||
|
* @Author: your name
|
||||||
|
* @Date: 2022-01-01 12:53:00
|
||||||
|
* @LastEditors: your name
|
||||||
|
* @LastEditTime: 2022-01-01 13:43:38
|
||||||
|
-->
|
||||||
|
<template>
|
||||||
|
<div class="menu">
|
||||||
|
<nav class="nav" id="topnav">
|
||||||
|
<h1 class="logo"><a href="/">中国一重</a></h1>
|
||||||
|
<ul style="float: left;margin-left: 60px;padding: 10px;">
|
||||||
|
<template v-for="nav in navList">
|
||||||
|
<li @mouseover="selectStyle(nav)" >
|
||||||
|
<a
|
||||||
|
:href="nav.linkUrl"
|
||||||
|
>{{ nav.title }}</a
|
||||||
|
>
|
||||||
|
<ul class="sub-nav" v-if="nav.childrens" v-show="nav.active" @mouseout="outStyle(nav)">
|
||||||
|
<li v-for="children in nav.childrens">
|
||||||
|
<a :href="children.linkUrl">{{ children.title }}</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</template>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
data: Object
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
navList: []
|
||||||
|
};
|
||||||
|
},
|
||||||
|
mounted() {},
|
||||||
|
components: {},
|
||||||
|
methods: {
|
||||||
|
selectStyle(nav) {
|
||||||
|
var _this = this;
|
||||||
|
this.$nextTick(function() {
|
||||||
|
_this.navList.forEach(function(item) {
|
||||||
|
item.active = false;
|
||||||
|
});
|
||||||
|
nav.active = true;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
outStyle(nav) {
|
||||||
|
nav.active = false;
|
||||||
|
},
|
||||||
|
changeIcon() {
|
||||||
|
this.isOpen = !this.isOpen;
|
||||||
|
},
|
||||||
|
searchActive() {
|
||||||
|
this.search_active = !this.search_active;
|
||||||
|
},
|
||||||
|
clickNav(nav) {
|
||||||
|
nav.active = !nav.active;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
#topnav_current { color: #00A7EB; }
|
||||||
|
.menu { height: 76px; width: 100%; background-color: #000; }
|
||||||
|
.nav { height: 80px; width: 100%; margin: 0 auto; }
|
||||||
|
.nav li { float: left; position: relative; }
|
||||||
|
.nav li a { color: #bdbdbd; padding: 0 10px; display: inline-block; text-decoration:none}
|
||||||
|
.nav li a:hover { color: #fff; }
|
||||||
|
.nav li .sub-nav { position: absolute; top: 30px; width: 120px; background: #FFF; left: -20px; /* display: none; */z-index: 9999}
|
||||||
|
.nav li .sub-nav li { clear: left; height: 20px; line-height: 35px; position: relative; width: 200px; padding: 5px 20px }
|
||||||
|
.nav li .sub-nav li a { font-size: 15px; font-weight: 400; color: #404040; line-height: 28px; }
|
||||||
|
.nav li .sub-nav li a:hover { color: #000; border-left: 2px solid #000; }
|
||||||
|
.a_active { color: #00A7EB !important; }
|
||||||
|
.logo { float: left;margin-left: 70px;width: 260px;font-size: 26px;}
|
||||||
|
.logo a { color: #00A7EB;text-decoration: none; }
|
||||||
|
.hometitle {
|
||||||
|
font-size: 18px;
|
||||||
|
color: #282828;
|
||||||
|
font-weight: 600;
|
||||||
|
margin: 0;
|
||||||
|
text-transform: uppercase;
|
||||||
|
padding-bottom: 15px;
|
||||||
|
margin-bottom: 25px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.hometitle:after {
|
||||||
|
content: "";
|
||||||
|
background-color: #282828;
|
||||||
|
left: 0;
|
||||||
|
width: 50px;
|
||||||
|
height: 2px;
|
||||||
|
bottom: 0;
|
||||||
|
position: absolute;
|
||||||
|
-webkit-transition: 0.5s;
|
||||||
|
-moz-transition: 0.5s;
|
||||||
|
-ms-transition: 0.5s;
|
||||||
|
-o-transition: 0.5s;
|
||||||
|
transition: 0.5s;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
283
src/components/KGTable.vue
Normal file
@ -0,0 +1,283 @@
|
|||||||
|
<template>
|
||||||
|
<div class="kg-table" ref="kgTable">
|
||||||
|
<div
|
||||||
|
ref="tableOperate"
|
||||||
|
v-show="buttonGroup"
|
||||||
|
class="table-operate button-group"
|
||||||
|
>
|
||||||
|
<slot name="button-group"></slot>
|
||||||
|
</div>
|
||||||
|
<div class="pagi-table" ref="pagiTable">
|
||||||
|
<p
|
||||||
|
class="notice mt10"
|
||||||
|
v-show="
|
||||||
|
multipleSelection.length > 0 && config.selection && !config.notShowNum
|
||||||
|
"
|
||||||
|
>
|
||||||
|
|
||||||
|
已选择<span>{{ multipleSelection.length }}</span
|
||||||
|
>项
|
||||||
|
</p>
|
||||||
|
<el-table
|
||||||
|
ref="table"
|
||||||
|
stripe
|
||||||
|
size="medium"
|
||||||
|
v-loading="loading"
|
||||||
|
class="tableStyle"
|
||||||
|
:data="pageObj.list"
|
||||||
|
style="width: 100%"
|
||||||
|
v-bind="tableBind"
|
||||||
|
:row-key="config.rowKey || 'id'"
|
||||||
|
@selection-change="onSelectionChange"
|
||||||
|
@select="onSelectChange"
|
||||||
|
@select-all="onSelectAllChange"
|
||||||
|
>
|
||||||
|
<el-table-column v-if="config.selection" type="selection" width="55">
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
<template v-for="item in columns">
|
||||||
|
<!-- 自定义 header -->
|
||||||
|
<el-table-column
|
||||||
|
:key="item.prop"
|
||||||
|
v-if="item.type === 'slotHeader'"
|
||||||
|
v-bind="item"
|
||||||
|
:show-overflow-tooltip="item.tooltip"
|
||||||
|
>
|
||||||
|
<template slot="header">
|
||||||
|
<slot :name="'header' + item.prop">
|
||||||
|
{{ item.label }}
|
||||||
|
</slot>
|
||||||
|
</template>
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<span>{{ scope.row[item.prop] }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<!-- slot渲染 -->
|
||||||
|
<el-table-column
|
||||||
|
:key="'slot-' + item.prop"
|
||||||
|
v-else-if="item.type === 'slot'"
|
||||||
|
:label="item.label"
|
||||||
|
:prop="item.prop"
|
||||||
|
:width="item.width"
|
||||||
|
>
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<slot :name="item.slotName" :row="scope.row"></slot>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<!-- 正常渲染 -->
|
||||||
|
<el-table-column
|
||||||
|
v-else
|
||||||
|
:key="'normal-' + item.prop"
|
||||||
|
:label="item.label"
|
||||||
|
:prop="item.prop"
|
||||||
|
:align="item.align ? item.align : 'left'"
|
||||||
|
:width="item.width"
|
||||||
|
:show-overflow-tooltip="true"
|
||||||
|
>
|
||||||
|
</el-table-column>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<el-table-column
|
||||||
|
v-if="operation && operation.label"
|
||||||
|
:label="operation.label"
|
||||||
|
:width="operation.width"
|
||||||
|
>
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<span v-if="operation.type !== 'link'">
|
||||||
|
<template v-for="(item, index) in operation.options">
|
||||||
|
<el-button
|
||||||
|
:key="'operation' + index"
|
||||||
|
:icon="item.icon"
|
||||||
|
:size="item.size"
|
||||||
|
:type="item.type"
|
||||||
|
:disabled="
|
||||||
|
item.disabled &&
|
||||||
|
scope.row[item.disabled.field] === item.disabled.value
|
||||||
|
"
|
||||||
|
@click="handleClick(item.method, scope.row)"
|
||||||
|
v-if="
|
||||||
|
!item.hide ||
|
||||||
|
!item.hide.value.includes(scope.row[item.hide.field])
|
||||||
|
"
|
||||||
|
><svg-icon :icon="item.icon"></svg-icon
|
||||||
|
>{{ item.label }}</el-button
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
v-else-if="operation.doubleTitle && operation.type === 'link'"
|
||||||
|
>
|
||||||
|
<el-link
|
||||||
|
class="btn-a"
|
||||||
|
v-for="(item, index) in operation.options"
|
||||||
|
:key="'operation' + index"
|
||||||
|
v-bind="item"
|
||||||
|
@click="handleClick(item.method, scope.row)"
|
||||||
|
>
|
||||||
|
<svg-icon :icon="item.icon"></svg-icon>
|
||||||
|
{{
|
||||||
|
scope.row[item.flag] === item.realValue
|
||||||
|
? item.values.real
|
||||||
|
: item.values.unde
|
||||||
|
}}</el-link
|
||||||
|
>
|
||||||
|
</span>
|
||||||
|
<span v-else>
|
||||||
|
<el-link
|
||||||
|
class="btn-a"
|
||||||
|
v-for="(item, index) in operation.options"
|
||||||
|
:key="'operation' + index"
|
||||||
|
v-bind="item"
|
||||||
|
@click="handleClick(item.method, scope.row)"
|
||||||
|
>
|
||||||
|
<svg-icon :icon="item.icon"></svg-icon>
|
||||||
|
{{ item.label }}</el-link
|
||||||
|
>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<Pagination
|
||||||
|
v-if="config.pagination"
|
||||||
|
:total="pageObj.totalCount"
|
||||||
|
layout="sizes, prev, pager, next, jumper"
|
||||||
|
:page.sync="pageObj.currentPage"
|
||||||
|
:totalPage="pageObj.totalPage"
|
||||||
|
:limit.sync="pageObj.pageSize"
|
||||||
|
@pagination="getPage"
|
||||||
|
></Pagination>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'kgTable',
|
||||||
|
props: {
|
||||||
|
buttonGroup: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
loading: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
columns: {
|
||||||
|
type: Array,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
pageObj: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
default: () => ({
|
||||||
|
currentPage: 1,
|
||||||
|
pageSize: 15,
|
||||||
|
list: [],
|
||||||
|
totalCount: 0
|
||||||
|
})
|
||||||
|
},
|
||||||
|
operation: {
|
||||||
|
type: Object
|
||||||
|
},
|
||||||
|
config: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({
|
||||||
|
pagination: true, // 是否显示分页
|
||||||
|
selection: true, // 多选
|
||||||
|
rowKey: 'id', // table row-key配置参数
|
||||||
|
notUseMaxHeight: false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
components: {},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
multipleSelection: [],
|
||||||
|
maxHeight: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
tableBind() {
|
||||||
|
const obj = {}
|
||||||
|
if (!this.config.notUseMaxHeight) {
|
||||||
|
obj['max-height'] = this.maxHeight
|
||||||
|
}
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
'pageObj.list': {
|
||||||
|
deep: true,
|
||||||
|
handler() {
|
||||||
|
this.multipleSelection.length = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {},
|
||||||
|
mounted() {
|
||||||
|
this.$nextTick(function () {
|
||||||
|
const operateHeight = this.$refs.tableOperate.clientHeight
|
||||||
|
this.maxHeight =
|
||||||
|
this.$refs.kgTable.clientHeight -
|
||||||
|
108 -
|
||||||
|
operateHeight -
|
||||||
|
10 +
|
||||||
|
(this.config.pagination ? 0 : 64) +
|
||||||
|
'px'
|
||||||
|
})
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onSelectionChange(selection) {
|
||||||
|
this.multipleSelection = selection
|
||||||
|
this.$emit('selection-change', this.multipleSelection)
|
||||||
|
},
|
||||||
|
onSelectChange(selection, row) {
|
||||||
|
this.$emit('select', selection, row)
|
||||||
|
},
|
||||||
|
onSelectAllChange(selection) {
|
||||||
|
this.$emit('select-all', selection)
|
||||||
|
},
|
||||||
|
getPage({ page, limit }) {
|
||||||
|
this.$emit('pagination', { page, limit })
|
||||||
|
},
|
||||||
|
handleClick(method, row) {
|
||||||
|
this.$emit('handleClick', { method, row })
|
||||||
|
},
|
||||||
|
toggleRowSelection(row, selected) {
|
||||||
|
this.$refs.table.toggleRowSelection(row, selected)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
beforeDestroy() {}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.kg-table {
|
||||||
|
height: 100%;
|
||||||
|
.btn-a {
|
||||||
|
font-size: 14px;
|
||||||
|
padding: 3px 10px;
|
||||||
|
text-decoration: none;
|
||||||
|
border: 1px solid #dcdfe6;
|
||||||
|
border-radius: 4px;
|
||||||
|
.icon {
|
||||||
|
margin-right: 3px;
|
||||||
|
vertical-align: -3px;
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
color: #105aac;
|
||||||
|
background-color: #f3f5f7;
|
||||||
|
border-color: #d3deeb;
|
||||||
|
}
|
||||||
|
&:focus {
|
||||||
|
color: #fff;
|
||||||
|
background-color: #1264bf;
|
||||||
|
border-color: #1264bf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/deep/ .el-link.is-underline:hover:after {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
</style>
|
||||||
80
src/components/KGWanted.vue
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog
|
||||||
|
title="反馈"
|
||||||
|
:visible.sync="dialogVisible"
|
||||||
|
width="70%"
|
||||||
|
customClass="flowHelp"
|
||||||
|
>
|
||||||
|
<el-alert
|
||||||
|
style="margin:10px"
|
||||||
|
title="有点迫不及待了吧"
|
||||||
|
type="success"
|
||||||
|
description="不听不听,王八念经,黑灰化肥会挥发发灰黑化肥挥发;灰黑化肥会挥发发黑灰化肥发挥。 黑灰化肥会挥发发灰黑化肥黑灰挥发化为灰……"
|
||||||
|
>
|
||||||
|
</el-alert>
|
||||||
|
<el-form ref="form" :model="form" label-width="80px">
|
||||||
|
<el-form-item label="反馈主题">
|
||||||
|
<el-input v-model="form.name"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="反馈类型">
|
||||||
|
<el-select v-model="form.type" placeholder="请选择反馈类型">
|
||||||
|
<el-option label="需求" value="0"></el-option>
|
||||||
|
<el-option label="bug" value="1"></el-option>
|
||||||
|
<el-option label="表扬" value="2"></el-option>
|
||||||
|
<el-option label="加入" value="3"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="内容">
|
||||||
|
<el-input type="textarea" v-model="form.desc" rows="6" :autosize="{ minRows: 6, maxRows: 10}" placeholder="简短描述一下吧,我应该会选择性看到,看到了我也不见得做,O(∩_∩)O哈哈~"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="联系方式">
|
||||||
|
<el-input v-model="form.email"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" @click="onSubmit">立即创建</el-button>
|
||||||
|
<el-button @click="dialogVisible=!dialogVisible">取消</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { kgBuilderApi } from "@/api";
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
dialogVisible: false,
|
||||||
|
form:{
|
||||||
|
name:"",
|
||||||
|
type:"0",
|
||||||
|
desc:"",
|
||||||
|
email:""
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
components: {},
|
||||||
|
methods: {
|
||||||
|
init() {
|
||||||
|
this.dialogVisible = true;
|
||||||
|
},
|
||||||
|
onSubmit(){
|
||||||
|
let data = this.form;
|
||||||
|
kgBuilderApi.feedBack(data).then(result => {
|
||||||
|
if (result.code == 200) {
|
||||||
|
this.dialogVisible=false;
|
||||||
|
this.$message({
|
||||||
|
message: "操作成功",
|
||||||
|
type: "success"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.flowHelp {
|
||||||
|
height: 80%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
36
src/components/SvgIcon.vue
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<template>
|
||||||
|
<svg class="icon svg-icon" aria-hidden="true" :style="ClassStyle">
|
||||||
|
<use :xlink:href="IconName"></use>
|
||||||
|
</svg>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'svg-icon',
|
||||||
|
props: {
|
||||||
|
size: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 16
|
||||||
|
},
|
||||||
|
icon: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
fill: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
ClassStyle () {
|
||||||
|
return `width:${parseInt(this.size)};height:${parseInt(this.size)};fill:${this.fill};`
|
||||||
|
},
|
||||||
|
IconName () {
|
||||||
|
return `#${this.icon}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
10
src/components/index.js
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
/*
|
||||||
|
* 动态注册全局组件
|
||||||
|
*/
|
||||||
|
const allComponents = require.context('./', true, /\.vue$/)
|
||||||
|
|
||||||
|
export default Vue => {
|
||||||
|
allComponents.keys().forEach(item => {
|
||||||
|
Vue.component(item.replace(/\.\//, '').replace(/\.vue$/, ''), allComponents(item).default)
|
||||||
|
})
|
||||||
|
}
|
||||||
4
src/config/index.js
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
// base url
|
||||||
|
const BASE_URL = process.env.VUE_APP_BASE_URL;
|
||||||
|
|
||||||
|
export { BASE_URL };
|
||||||
18
src/main.js
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import Vue from "vue";
|
||||||
|
import App from "./App.vue";
|
||||||
|
import router from "./router";
|
||||||
|
import store from "./store";
|
||||||
|
import ElementUI from "element-ui";
|
||||||
|
import "element-ui/lib/theme-chalk/index.css";
|
||||||
|
import axios from "axios";
|
||||||
|
import components from './components/index'
|
||||||
|
|
||||||
|
Vue.prototype.$http = axios; //正确的使用
|
||||||
|
Vue.config.productionTip = false;
|
||||||
|
Vue.use(ElementUI);
|
||||||
|
Vue.use(components)
|
||||||
|
new Vue({
|
||||||
|
router,
|
||||||
|
store,
|
||||||
|
render: h => h(App)
|
||||||
|
}).$mount("#app");
|
||||||
55
src/router/index.js
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import Vue from "vue";
|
||||||
|
import VueRouter from "vue-router";
|
||||||
|
import Home from "../views/Home.vue";
|
||||||
|
|
||||||
|
Vue.use(VueRouter);
|
||||||
|
|
||||||
|
const routes = [
|
||||||
|
{
|
||||||
|
path: "/",
|
||||||
|
name: "Home",
|
||||||
|
component: () => import("../views/kgbuilder/index_v1.vue")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/builder",
|
||||||
|
name: "builder",
|
||||||
|
component: () => import("../views/kgbuilder/index.vue")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/kg",
|
||||||
|
name: "kg",
|
||||||
|
component: () => import("../views/kgbuilder/index_v1.vue")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/er",
|
||||||
|
name: "er",
|
||||||
|
component: () => import("../views/erbuilder/index.vue")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/ds",
|
||||||
|
name: "ds",
|
||||||
|
component: () => import("../views/datasource/index.vue")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/icon",
|
||||||
|
name: "icon",
|
||||||
|
component: () => import("../views/icon/index.vue")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/about",
|
||||||
|
name: "About",
|
||||||
|
// route level code-splitting
|
||||||
|
// this generates a separate chunk (about.[hash].js) for this route
|
||||||
|
// which is lazy-loaded when the route is visited.
|
||||||
|
component: () =>
|
||||||
|
import(/* webpackChunkName: "about" */ "../views/About.vue")
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const router = new VueRouter({
|
||||||
|
mode: "history",
|
||||||
|
base: process.env.BASE_URL,
|
||||||
|
routes
|
||||||
|
});
|
||||||
|
|
||||||
|
export default router;
|
||||||
31
src/settings.js
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
module.exports = {
|
||||||
|
title: "Dream it possible",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否系统布局配置
|
||||||
|
*/
|
||||||
|
showSettings: false,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否显示 tagsView
|
||||||
|
*/
|
||||||
|
tagsView: true,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否固定头部
|
||||||
|
*/
|
||||||
|
fixedHeader: false,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否显示logo
|
||||||
|
*/
|
||||||
|
sidebarLogo: true,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {string | array} 'production' | ['production', 'development']
|
||||||
|
* @description Need show err logs component.
|
||||||
|
* The default is only used in the production env
|
||||||
|
* If you want to also use it in dev, you can pass ['production', 'development']
|
||||||
|
*/
|
||||||
|
errorLog: "production",
|
||||||
|
};
|
||||||
11
src/store/index.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import Vue from "vue";
|
||||||
|
import Vuex from "vuex";
|
||||||
|
|
||||||
|
Vue.use(Vuex);
|
||||||
|
|
||||||
|
export default new Vuex.Store({
|
||||||
|
state: {},
|
||||||
|
mutations: {},
|
||||||
|
actions: {},
|
||||||
|
modules: {}
|
||||||
|
});
|
||||||
39
src/utils/BaseAPI.js
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
import qs from 'qs'
|
||||||
|
|
||||||
|
export default class BaseAPI {
|
||||||
|
get (url, params) {
|
||||||
|
return request({ url, method: 'GET', params })
|
||||||
|
}
|
||||||
|
|
||||||
|
post (url, data, config) {
|
||||||
|
let temp
|
||||||
|
|
||||||
|
if (
|
||||||
|
config &&
|
||||||
|
config?.headers &&
|
||||||
|
(config?.headers['Content-Type'].indexOf('application/json') !== -1 ||
|
||||||
|
config?.headers['Content-Type'].indexOf('multipart/form-data') !== -1)
|
||||||
|
) {
|
||||||
|
temp = data
|
||||||
|
} else {
|
||||||
|
temp = qs.stringify(data)
|
||||||
|
}
|
||||||
|
return request(Object.assign({ url, method: 'POST', data: temp }, config))
|
||||||
|
}
|
||||||
|
|
||||||
|
put(url, data, config) {
|
||||||
|
let temp
|
||||||
|
if (
|
||||||
|
config &&
|
||||||
|
config?.headers &&
|
||||||
|
(config?.headers['Content-Type'].indexOf('application/json') !== -1 ||
|
||||||
|
config?.headers['Content-Type'].indexOf('multipart/form-data') !== -1)
|
||||||
|
) {
|
||||||
|
temp = data
|
||||||
|
} else {
|
||||||
|
temp = qs.stringify(data)
|
||||||
|
}
|
||||||
|
return request(Object.assign({ url, method: 'PUT', data: temp }, config))
|
||||||
|
}
|
||||||
|
}
|
||||||
15
src/utils/auth.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import Cookies from "js-cookie";
|
||||||
|
|
||||||
|
const TokenKey = "Admin-Token";
|
||||||
|
|
||||||
|
export function getToken() {
|
||||||
|
return Cookies.get(TokenKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setToken(token) {
|
||||||
|
return Cookies.set(TokenKey, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function removeToken() {
|
||||||
|
return Cookies.remove(TokenKey);
|
||||||
|
}
|
||||||
6
src/utils/errorCode.js
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
export default {
|
||||||
|
"401": "认证失败,无法访问系统资源",
|
||||||
|
"403": "当前操作没有权限",
|
||||||
|
"404": "访问资源不存在",
|
||||||
|
default: "系统未知错误,请反馈给管理员"
|
||||||
|
};
|
||||||
39
src/utils/event-bus.js
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
|
||||||
|
class EventPublic {
|
||||||
|
constructor() {
|
||||||
|
this.event = {}
|
||||||
|
}
|
||||||
|
$on(type, callback) {
|
||||||
|
if (!this.event[type]) {
|
||||||
|
this.event[type] = [callback]
|
||||||
|
} else {
|
||||||
|
this.event[type].push(callback)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$emit(type, ...args) {
|
||||||
|
if (!this.event[type]) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.event[type].forEach(res => {
|
||||||
|
res.apply(this, args)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
$off(type, callback) {
|
||||||
|
if (!this.event[type]) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.event[type] = this.event[type].filter(res => {
|
||||||
|
return res != callback
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 执行一次
|
||||||
|
$once(type, callback) {
|
||||||
|
function f() {
|
||||||
|
callback()
|
||||||
|
this.$off(type, f)
|
||||||
|
}
|
||||||
|
this.$on(type, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export const EventBus = new EventPublic()
|
||||||
|
|
||||||
107
src/utils/request.js
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
import axios from "axios";
|
||||||
|
import { Notification, MessageBox, Message } from "element-ui";
|
||||||
|
import store from "@/store";
|
||||||
|
import { getToken } from "@/utils/auth";
|
||||||
|
import errorCode from "@/utils/errorCode";
|
||||||
|
|
||||||
|
const queue = [] // 请求队列
|
||||||
|
// 创建axios实例
|
||||||
|
const service = axios.create({
|
||||||
|
// axios中请求配置有baseURL选项,表示请求URL公共部分
|
||||||
|
baseURL: process.env.VUE_APP_BASE_API,
|
||||||
|
// 超时
|
||||||
|
timeout: 10 * 60 * 1000,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// 取消重复请求
|
||||||
|
const removeRepeatRequest = config => {
|
||||||
|
for (const key in queue) {
|
||||||
|
const index = +key
|
||||||
|
const item = queue[key]
|
||||||
|
|
||||||
|
if (
|
||||||
|
item.url === config.url &&
|
||||||
|
item.method === config.method &&
|
||||||
|
JSON.stringify(item.params) === JSON.stringify(config.params) &&
|
||||||
|
JSON.stringify(item.data) === JSON.stringify(config.data)
|
||||||
|
) {
|
||||||
|
// 执行取消操作
|
||||||
|
item.cancel('操作太频繁,请稍后再试')
|
||||||
|
queue.splice(index, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// request拦截器
|
||||||
|
service.interceptors.request.use(
|
||||||
|
config => {
|
||||||
|
// 是否需要设置 token
|
||||||
|
const isToken = (config.headers || {}).isToken === false;
|
||||||
|
if (getToken() && !isToken) {
|
||||||
|
config.headers["Authorization"] = "Bearer " + getToken(); // 让每个请求携带自定义token 请根据实际情况自行修改
|
||||||
|
}
|
||||||
|
return config;
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
console.log(error);
|
||||||
|
Promise.reject(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// 响应拦截器
|
||||||
|
service.interceptors.response.use(
|
||||||
|
res => {
|
||||||
|
// 未设置状态码则默认成功状态
|
||||||
|
const code = res.data.code || 200;
|
||||||
|
// 获取错误信息
|
||||||
|
const msg = errorCode[code] || res.data.msg || errorCode["default"];
|
||||||
|
if (code === 401) {
|
||||||
|
MessageBox.confirm(
|
||||||
|
"登录状态已过期,您可以继续留在该页面,或者重新登录",
|
||||||
|
"系统提示",
|
||||||
|
{
|
||||||
|
confirmButtonText: "重新登录",
|
||||||
|
cancelButtonText: "取消",
|
||||||
|
type: "warning"
|
||||||
|
}
|
||||||
|
).then(() => {
|
||||||
|
store.dispatch("LogOut").then(() => {
|
||||||
|
location.href = "/index";
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else if (code === 500) {
|
||||||
|
Message({
|
||||||
|
message: msg,
|
||||||
|
type: "error"
|
||||||
|
});
|
||||||
|
return Promise.reject(new Error(msg));
|
||||||
|
} else if (code !== 200) {
|
||||||
|
Notification.error({
|
||||||
|
title: msg
|
||||||
|
});
|
||||||
|
return Promise.reject("error");
|
||||||
|
} else {
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
console.log("err" + error);
|
||||||
|
let { message } = error;
|
||||||
|
if (message == "Network Error") {
|
||||||
|
message = "后端接口连接异常";
|
||||||
|
} else if (message.includes("timeout")) {
|
||||||
|
message = "系统接口请求超时";
|
||||||
|
} else if (message.includes("Request failed with status code")) {
|
||||||
|
message = "系统接口" + message.substr(message.length - 3) + "异常";
|
||||||
|
}
|
||||||
|
Message({
|
||||||
|
message: message,
|
||||||
|
type: "error",
|
||||||
|
duration: 5 * 1000
|
||||||
|
});
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export default service;
|
||||||
13
src/views/About.vue
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<template>
|
||||||
|
<div class="about">
|
||||||
|
about
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
22
src/views/Home.vue
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<template>
|
||||||
|
<div id="kg_container" class="home">
|
||||||
|
<KGBuilder pid="kg_container" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// @ is an alias to /src
|
||||||
|
import KGBuilder from "@/components/KGBuilder.vue";
|
||||||
|
export default {
|
||||||
|
name: "Home",
|
||||||
|
components: {
|
||||||
|
KGBuilder
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
#kg_container {
|
||||||
|
height: 100vh;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
568
src/views/datasource/index.vue
Normal file
@ -0,0 +1,568 @@
|
|||||||
|
<template>
|
||||||
|
<div class="mind-box">
|
||||||
|
<!-- 左侧 -->
|
||||||
|
<el-scrollbar class="mind-l">
|
||||||
|
<div class="ml-m">
|
||||||
|
<h2 class="ml-ht">数据源列表</h2>
|
||||||
|
<div class="ml-a-box">
|
||||||
|
<div class="block">
|
||||||
|
<el-button
|
||||||
|
@click="addWStatus = true"
|
||||||
|
size="mini"
|
||||||
|
type="primary"
|
||||||
|
plain
|
||||||
|
>新增</el-button
|
||||||
|
>
|
||||||
|
<el-aside
|
||||||
|
v-if="dataSourceList.length > 0"
|
||||||
|
|
||||||
|
>
|
||||||
|
<el-menu :router="false">
|
||||||
|
<el-submenu
|
||||||
|
:index="dIndex + ''"
|
||||||
|
:key="dIndex + ''"
|
||||||
|
v-for="(d, dIndex) in dataSourceList"
|
||||||
|
@click.native="clickDataSource(d, dIndex)"
|
||||||
|
>
|
||||||
|
<template slot="title"
|
||||||
|
><i class="el-icon-message"></i>{{ d.datasourceType
|
||||||
|
}}{{ d.datasourceAlia }}</template
|
||||||
|
>
|
||||||
|
<el-menu-item-group
|
||||||
|
v-if="d.tableList.length > 0"
|
||||||
|
v-for="(t, tIndex) in d.tableList"
|
||||||
|
:key="tIndex + ''"
|
||||||
|
@click.native="getFields(t.dataTableId)"
|
||||||
|
>
|
||||||
|
<!-- <template slot="title">分组一</template> -->
|
||||||
|
<el-menu-item :index="dIndex + '_' + tIndex"
|
||||||
|
>[{{ t.dataTableName }}]
|
||||||
|
<el-dropdown @command="getTableOperate" class="ds-down">
|
||||||
|
<span class="el-dropdown-link">...</span>
|
||||||
|
<el-dropdown-menu slot="dropdown">
|
||||||
|
<el-dropdown-item
|
||||||
|
:command="{ action: 'viewData', db: d, tb: t }"
|
||||||
|
>预览数据</el-dropdown-item
|
||||||
|
>
|
||||||
|
<el-dropdown-item
|
||||||
|
:command="{
|
||||||
|
action: 'rename',
|
||||||
|
t: t,
|
||||||
|
tIndex: tIndex,
|
||||||
|
dIndex: dIndex
|
||||||
|
}"
|
||||||
|
>重命名</el-dropdown-item
|
||||||
|
>
|
||||||
|
<el-dropdown-item
|
||||||
|
:command="{ action: 'delete', db: d, tb: t }"
|
||||||
|
>删除</el-dropdown-item
|
||||||
|
>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</el-dropdown>
|
||||||
|
</el-menu-item>
|
||||||
|
</el-menu-item-group>
|
||||||
|
</el-submenu>
|
||||||
|
</el-menu>
|
||||||
|
</el-aside>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-scrollbar>
|
||||||
|
<div class="mind-con">
|
||||||
|
<!-- 头部 -->
|
||||||
|
<div class="mind-top clearfix"></div>
|
||||||
|
<el-scrollbar class="mind-cen">
|
||||||
|
<el-dialog title="数据源编辑" :visible.sync="addWStatus">
|
||||||
|
<el-form :model="form">
|
||||||
|
<el-form-item label="数据库类型">
|
||||||
|
<el-select
|
||||||
|
v-model="form.dbType"
|
||||||
|
placeholder="请选择数据库"
|
||||||
|
@change="dbTypeChange"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="t in dataTypeList"
|
||||||
|
:key="t.type"
|
||||||
|
:label="t.type"
|
||||||
|
:value="t"
|
||||||
|
></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="ip及端口">
|
||||||
|
<el-input v-model="form.ipAndPort"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="数据库别名">
|
||||||
|
<el-input v-model="form.dbName"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="数据库名称">
|
||||||
|
<el-input v-model="form.dbCode"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="用户名">
|
||||||
|
<el-input v-model="form.dbUserName"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="密码">
|
||||||
|
<el-input v-model="form.dbPassWord"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<div slot="footer" class="dialog-footer">
|
||||||
|
<!--<el-button type="primary" @click="testDataSource">测试连接</el-button>-->
|
||||||
|
<el-button type="primary" @click="addDataSource">确 定</el-button>
|
||||||
|
<el-button @click="addWStatus = false">取 消</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
<el-dialog title="选择数据表" :visible.sync="selectTableStatus">
|
||||||
|
<el-form :model="tableForm">
|
||||||
|
<el-checkbox
|
||||||
|
:indeterminate="isIndeterminate"
|
||||||
|
v-model="checkAll"
|
||||||
|
@change="handleCheckAllChange"
|
||||||
|
>全选</el-checkbox
|
||||||
|
>
|
||||||
|
<div style="margin: 15px 0;"></div>
|
||||||
|
<el-checkbox-group
|
||||||
|
v-model="tableForm.dataTables"
|
||||||
|
@change="handleCheckedChange"
|
||||||
|
>
|
||||||
|
<el-checkbox
|
||||||
|
v-for="table in dataTableList"
|
||||||
|
:label="table"
|
||||||
|
:key="table"
|
||||||
|
>{{ table }}</el-checkbox
|
||||||
|
>
|
||||||
|
</el-checkbox-group>
|
||||||
|
</el-form>
|
||||||
|
<div slot="footer" class="dialog-footer">
|
||||||
|
<el-button type="primary" @click="saveDataTable">确 定</el-button>
|
||||||
|
<el-button @click="selectTableStatus = false">取 消</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
<el-table
|
||||||
|
v-show="dataFieldList.length > 0"
|
||||||
|
:data="dataFieldList"
|
||||||
|
stripe
|
||||||
|
style="width: 100%"
|
||||||
|
>
|
||||||
|
<el-table-column prop="dataColumnName" label="列名" width="180">
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="dataColumnAlia" label="列别名" width="180">
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="dataColumnType" label="类型">
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="isPrimary" label="是否主键">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-tag v-if="scope.row.isPrimary == 1" type="success">是</el-tag>
|
||||||
|
<el-tag v-else type="info">否</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<div v-show="pageRecord.beanList.length > 0" class="ds-table-wrap">
|
||||||
|
<div class="line-choose">
|
||||||
|
<span>共 {{ pageRecord.totalCount }}条结果</span>
|
||||||
|
</div>
|
||||||
|
<el-table
|
||||||
|
style="width: 100%"
|
||||||
|
v-loading="listLoading"
|
||||||
|
element-loading-text="给我一点时间"
|
||||||
|
fit
|
||||||
|
highlight-current-row
|
||||||
|
:data="pageRecord.beanList"
|
||||||
|
class="x-table"
|
||||||
|
>
|
||||||
|
<el-table-column
|
||||||
|
width="200"
|
||||||
|
:label="value"
|
||||||
|
v-for="(value, key) in pageRecord.headerFields"
|
||||||
|
:key="key"
|
||||||
|
>
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-popover
|
||||||
|
placement="top"
|
||||||
|
:title="value"
|
||||||
|
popper-class="table-item-popover"
|
||||||
|
trigger="hover"
|
||||||
|
>
|
||||||
|
<div>{{ scope.row[value] }}</div>
|
||||||
|
<span slot="reference" class="table-item-span"
|
||||||
|
>{{ scope.row[value] }}
|
||||||
|
</span>
|
||||||
|
</el-popover>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<el-pagination
|
||||||
|
@size-change="handleSizeChange"
|
||||||
|
class="txtCenter"
|
||||||
|
@current-change="handleCurrentChange"
|
||||||
|
:current-page="pageRecord.currentPage"
|
||||||
|
:page-sizes="[10, 20, 30]"
|
||||||
|
:page-size="pageRecord.pageSize"
|
||||||
|
layout=" sizes, prev, pager, next"
|
||||||
|
:total="pageRecord.totalCount"
|
||||||
|
></el-pagination>
|
||||||
|
</div>
|
||||||
|
</el-scrollbar>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { datasourceApi } from "@/api";
|
||||||
|
export default {
|
||||||
|
name: "ds",
|
||||||
|
components: {},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
listLoading: false,
|
||||||
|
isIndeterminate: true,
|
||||||
|
checkAll: false,
|
||||||
|
tableQueryForm: {
|
||||||
|
dataSourceId: 0,
|
||||||
|
dataTableName: "",
|
||||||
|
currentPage: 1,
|
||||||
|
pageSize: 10
|
||||||
|
},
|
||||||
|
form: {
|
||||||
|
dbType: "mysql",
|
||||||
|
driverName: "com.mysql.cj.jdbc.Driver",
|
||||||
|
ipAndPort: "rm-uf649ipw0c2fdok97xo.mysql.rds.aliyuncs.com:3306",
|
||||||
|
dbName: "zst",
|
||||||
|
dbCode: "kg",
|
||||||
|
dbUserName: "tan",
|
||||||
|
dbPassWord: "Miracletan2021"
|
||||||
|
},
|
||||||
|
tableForm: {
|
||||||
|
dataSourceId: 0,
|
||||||
|
dataTables: []
|
||||||
|
},
|
||||||
|
addWStatus: false,
|
||||||
|
selectTableStatus: false,
|
||||||
|
checkAll: false,
|
||||||
|
dataTypeList: [
|
||||||
|
{ type: "mysql", driver: "com.mysql.cj.jdbc.Driver" },
|
||||||
|
{ type: "postgresql", driver: "org.postgresql.Driver" },
|
||||||
|
{ type: "mariadb", driver: "org.mariadb.jdbc.Driver" },
|
||||||
|
{
|
||||||
|
type: "sqlserver",
|
||||||
|
driver: "com.microsoft.sqlserver.jdbc.SQLServerDriver"
|
||||||
|
},
|
||||||
|
{ type: "oracle", driver: "oracle.jdbc.driver.OracleDriver" },
|
||||||
|
{ type: "hive", driver: "org.apache.hive.jdbc.HiveDriver" }
|
||||||
|
],
|
||||||
|
dataSourceList: [],
|
||||||
|
dataTableList: [],
|
||||||
|
dataFieldList: [],
|
||||||
|
pageRecord: {
|
||||||
|
headerFields: [],
|
||||||
|
beanList: [],
|
||||||
|
currentPage: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
totalCount: 0,
|
||||||
|
totalPage: 0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.initDataSource();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleCheckedChange(value) {
|
||||||
|
let checkedCount = value.length;
|
||||||
|
this.checkAll = checkedCount === this.dataTableList.length;
|
||||||
|
this.isIndeterminate =
|
||||||
|
checkedCount > 0 && checkedCount < this.tableForm.dataTables.length;
|
||||||
|
},
|
||||||
|
handleCheckAllChange(val) {
|
||||||
|
this.tableForm.dataTables = val ? this.dataTableList : [];
|
||||||
|
this.isIndeterminate = false;
|
||||||
|
},
|
||||||
|
clickDataSource(item, index) {
|
||||||
|
this.getTableList(item.datasourceId, index);
|
||||||
|
},
|
||||||
|
initDataSource() {
|
||||||
|
let _this = this;
|
||||||
|
datasourceApi.getDatasource().then(result => {
|
||||||
|
if (result.code == 200) {
|
||||||
|
let list = result.data;
|
||||||
|
_this.dataSourceList = [];
|
||||||
|
if (list) {
|
||||||
|
for (let i = 0; i < list.length; i++) {
|
||||||
|
let m = list[i];
|
||||||
|
m.openState = 0;
|
||||||
|
m.selected = 0;
|
||||||
|
_this.dataSourceList.push(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
testDataSource() {},
|
||||||
|
saveDataTable() {
|
||||||
|
let data = this.tableForm;
|
||||||
|
let _this = this;
|
||||||
|
datasourceApi.saveDataTable(JSON.stringify(data)).then(result => {
|
||||||
|
if (result.code == 200) {
|
||||||
|
_this.selectTableStatus = false;
|
||||||
|
_this.initDataSource();
|
||||||
|
_this.$message.success(result.msg);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
getTableList(datasourceId, index) {
|
||||||
|
let _this = this;
|
||||||
|
_this.pageRecord.beanList = [];
|
||||||
|
datasourceApi.getTableInfo(datasourceId).then(result => {
|
||||||
|
if (result.code == 200) {
|
||||||
|
let list = result.data;
|
||||||
|
if (list) {
|
||||||
|
for (let i = 0; i < _this.dataSourceList.length; i++) {
|
||||||
|
if (i == index) {
|
||||||
|
_this.dataSourceList[index].openState = !_this.dataSourceList[
|
||||||
|
index
|
||||||
|
].openState;
|
||||||
|
_this.dataSourceList[index].selected = !_this.dataSourceList[
|
||||||
|
index
|
||||||
|
].selected;
|
||||||
|
_this.dataSourceList[index].tableList = list;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
getFields(dataTableId) {
|
||||||
|
let _this = this;
|
||||||
|
_this.pageRecord.beanList = [];
|
||||||
|
datasourceApi.getTableColumn(dataTableId).then(result => {
|
||||||
|
if (result.code == 200) {
|
||||||
|
_this.dataFieldList = result.data;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
dbTypeChange(value) {
|
||||||
|
this.form.driverName = value.driver;
|
||||||
|
this.form.dbType = value.type;
|
||||||
|
},
|
||||||
|
addDataSource() {
|
||||||
|
let data = this.form;
|
||||||
|
let _this = this;
|
||||||
|
datasourceApi.saveDatasource(data).then(result => {
|
||||||
|
if (result.code == 200) {
|
||||||
|
_this.addWStatus = false;
|
||||||
|
_this.selectTableStatus = true;
|
||||||
|
_this.dataTableList = result.data.tables;
|
||||||
|
_this.tableForm.dataSourceId = result.data.sourceId;
|
||||||
|
_this.initDataSource();
|
||||||
|
_this.$message.success(result.msg);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
deleteTable() {},
|
||||||
|
getTableRecord() {
|
||||||
|
let _this = this;
|
||||||
|
let query = JSON.stringify(_this.tableQueryForm);
|
||||||
|
_this.pageRecord.beanList = [];
|
||||||
|
_this.pageRecord.headerFields = [];
|
||||||
|
_this.listLoading = true;
|
||||||
|
datasourceApi.getDataRecord(query).then(result => {
|
||||||
|
if (result.code == 200) {
|
||||||
|
_this.pageRecord.headerFields = result.data.heads;
|
||||||
|
_this.pageRecord.beanList = result.data.data;
|
||||||
|
_this.pageRecord.currentPage = result.data.pageIndex;
|
||||||
|
_this.pageRecord.pageSize = result.data.pageSize;
|
||||||
|
_this.pageRecord.totalCount = result.data.totalCount;
|
||||||
|
_this.pageRecord.totalPage = result.data.totalPage;
|
||||||
|
_this.listLoading = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
getTableOperate(command) {
|
||||||
|
var _this = this;
|
||||||
|
_this.dataFieldList = [];
|
||||||
|
if (command.action === "viewData") {
|
||||||
|
_this.tableQueryForm.dataSourceId = command.db.datasourceId;
|
||||||
|
_this.tableQueryForm.dataTableName = command.tb.dataTableName;
|
||||||
|
_this.getTableRecord();
|
||||||
|
}
|
||||||
|
if (command.action === "rename") {
|
||||||
|
_this.$message.error("暂不支持");
|
||||||
|
}
|
||||||
|
if (command.action === "delete") {
|
||||||
|
_this.$message.error("暂不支持");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleCurrentChange(val) {
|
||||||
|
this.pageRecord.currentPage = val;
|
||||||
|
this.getTableRecord();
|
||||||
|
},
|
||||||
|
handleSizeChange(val) {
|
||||||
|
this.pageRecord.currentPage = 1;
|
||||||
|
this.pageRecord.pageSize = val;
|
||||||
|
this.getTableRecord();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
.ds-tree {
|
||||||
|
border-bottom: solid 1px gray;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
.el-dropdown {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
.el-pagination {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.el-table {
|
||||||
|
padding: 35px;
|
||||||
|
}
|
||||||
|
.mind-box {
|
||||||
|
height: calc(100vh - 85px);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.mind-l {
|
||||||
|
width: 300px;
|
||||||
|
float: left;
|
||||||
|
background: #f7f9fc;
|
||||||
|
height: 100%;
|
||||||
|
border-right: 1px solid #d3e2ec;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
.ml-ht {
|
||||||
|
padding-top: 20px;
|
||||||
|
line-height: 50px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 400;
|
||||||
|
text-align: center;
|
||||||
|
color: #333;
|
||||||
|
border-bottom: 1px solid #d3e2ec;
|
||||||
|
}
|
||||||
|
.ml-a-box {
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
|
.ml-a {
|
||||||
|
display: inline-block;
|
||||||
|
min-width: 46px;
|
||||||
|
line-height: 1;
|
||||||
|
padding: 6px 8px 6px 8px;
|
||||||
|
margin: 0 4px 5px 0;
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid #e3e3e3;
|
||||||
|
box-sizing: border-box;
|
||||||
|
transition: 0.3s;
|
||||||
|
}
|
||||||
|
.ml-a span {
|
||||||
|
max-width: 190px;
|
||||||
|
display: inline-block;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
.ml-a-all {
|
||||||
|
display: block;
|
||||||
|
margin: 10px 10px 0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.ml-a span:empty:before {
|
||||||
|
content: "閺堫亜鎳¢崥锟<E5B4A5>";
|
||||||
|
color: #adadad;
|
||||||
|
}
|
||||||
|
.ml-a small {
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
.ml-a:hover {
|
||||||
|
background: #f4f4f4;
|
||||||
|
}
|
||||||
|
.ml-a.cur,
|
||||||
|
.ml-a.cur small {
|
||||||
|
background: #156498;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
.ml-btn-box {
|
||||||
|
text-align: right;
|
||||||
|
padding: 0 10px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.ml-btn {
|
||||||
|
padding: 0 5px;
|
||||||
|
color: #156498;
|
||||||
|
}
|
||||||
|
.mind-con {
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
background: #fff;
|
||||||
|
display: -webkit-flex;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.mind-top {
|
||||||
|
line-height: 70px;
|
||||||
|
height: 70px;
|
||||||
|
padding: 0 22px;
|
||||||
|
border-bottom: 1px solid #ededed;
|
||||||
|
}
|
||||||
|
.mt-m {
|
||||||
|
color: #666;
|
||||||
|
margin-right: 30px;
|
||||||
|
}
|
||||||
|
.mt-m i {
|
||||||
|
font-size: 18px;
|
||||||
|
color: #333;
|
||||||
|
font-weight: 700;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
.mb-con .search,
|
||||||
|
.mind-top .search {
|
||||||
|
border: 1px solid #e2e2e2;
|
||||||
|
}
|
||||||
|
.svg-a-sm {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #156498;
|
||||||
|
margin-right: 30px;
|
||||||
|
}
|
||||||
|
.mind-cen {
|
||||||
|
height: calc(100% - 70px);
|
||||||
|
}
|
||||||
|
.half-auto {
|
||||||
|
height: 40%;
|
||||||
|
}
|
||||||
|
.mind-bottom {
|
||||||
|
height: 490px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-top: 1px solid #ededed;
|
||||||
|
}
|
||||||
|
.ss-d {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
margin-right: 10px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: #dedede;
|
||||||
|
}
|
||||||
|
.sd {
|
||||||
|
margin: 2px;
|
||||||
|
}
|
||||||
|
.sd-active {
|
||||||
|
color: red !important;
|
||||||
|
}
|
||||||
|
.btn-line + .btn-line {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
.co {
|
||||||
|
color: #ee8407 !important;
|
||||||
|
}
|
||||||
|
.a {
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
.fl {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
.fr {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
.tl {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
61
src/views/erbuilder/components/help.vue
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog
|
||||||
|
title="帮助"
|
||||||
|
:visible.sync="dialogVisible"
|
||||||
|
width="70%"
|
||||||
|
customClass="flowHelp"
|
||||||
|
>
|
||||||
|
<el-tabs tab-position="left">
|
||||||
|
<el-tab-pane label="如何新增">
|
||||||
|
<el-divider content-position="left">如何新增</el-divider>
|
||||||
|
<div>按住鼠标拖拽左侧组件到中间画布中松开鼠标即可</div>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane label="如何删除">
|
||||||
|
<el-divider content-position="left">页面删除</el-divider>
|
||||||
|
<div>
|
||||||
|
鼠标点中需要删除的节点,点击左上角的删除图标
|
||||||
|
</div>
|
||||||
|
<el-divider content-position="left">通过代码删除</el-divider>
|
||||||
|
<pre>this.deleteNode(nodeId)</pre>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane label="如何移动">
|
||||||
|
<el-divider content-position="left">如何移动</el-divider>
|
||||||
|
<div>鼠标移动到节点中,当鼠标变为可拖拽的图标时按下鼠标移动到新的位置松开鼠标</div>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane label="如何连线">
|
||||||
|
<el-divider content-position="left">如何连线</el-divider>
|
||||||
|
<div>鼠标移动到节点中左侧的图标上,当鼠标变为+时按下鼠标移动到另一个节点中松开鼠标</div>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane label="如何添加条件">
|
||||||
|
<el-divider content-position="left">如何添加条件</el-divider>
|
||||||
|
<div>点击画布中的连线,在页面右侧会出现一个表单,输入新的条件,点击【保存】</div>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane label="如何进行后端交互存储">
|
||||||
|
<el-divider content-position="left">如何进行后端交互存储</el-divider>
|
||||||
|
<div>参考: https://gitee.com/xiaoka2017/easy-flow-sdk</div>
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
dialogVisible: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
components: {},
|
||||||
|
methods: {
|
||||||
|
init() {
|
||||||
|
this.dialogVisible = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.flowHelp {
|
||||||
|
height: 80%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
164
src/views/erbuilder/components/initData.js
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
let dataB = {
|
||||||
|
"domainName": "测试知识图谱领域",
|
||||||
|
"domainId":"xxxxx",
|
||||||
|
"nodeList": [
|
||||||
|
{
|
||||||
|
"nodeKey": "table-11",
|
||||||
|
"nodeName": "kg_domain",
|
||||||
|
"type": "task",
|
||||||
|
"left": "256px",
|
||||||
|
"top": "74px",
|
||||||
|
"ico": "el-icon-menu",
|
||||||
|
"state": "success",
|
||||||
|
"viewOnly": 1,
|
||||||
|
"alia": "kg_domain",
|
||||||
|
"sourceId": 4,
|
||||||
|
"startNode":1,
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"columnId": 120,
|
||||||
|
"ico": "el-icon-film",
|
||||||
|
"isPrimary": 0,
|
||||||
|
"itemId": "table-11-120",
|
||||||
|
"itemCode": "commend",
|
||||||
|
"itemName": "commend",
|
||||||
|
"itemType": "int(11)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"columnId": 121,
|
||||||
|
"ico": "el-icon-film",
|
||||||
|
"isPrimary": 0,
|
||||||
|
"itemId": "table-11-121",
|
||||||
|
"itemCode": "createuser",
|
||||||
|
"itemName": "createuser",
|
||||||
|
"itemType": "varchar(255)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"columnId": 122,
|
||||||
|
"ico": "el-icon-film",
|
||||||
|
"isPrimary": 0,
|
||||||
|
"itemId": "table-11-122",
|
||||||
|
"itemCode": "nodeKey",
|
||||||
|
"itemName": "nodeKey",
|
||||||
|
"itemType": "int(11)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"columnId": 123,
|
||||||
|
"ico": "el-icon-film",
|
||||||
|
"isPrimary": 0,
|
||||||
|
"itemId": "table-11-123",
|
||||||
|
"itemCode": "nodeName",
|
||||||
|
"itemName": "nodeName",
|
||||||
|
"itemType": "varchar(255)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nodeKey": "table-13",
|
||||||
|
"nodeName": "kg_category",
|
||||||
|
"type": "task",
|
||||||
|
"left": "675px",
|
||||||
|
"top": "197px",
|
||||||
|
"ico": "el-icon-menu",
|
||||||
|
"state": "success",
|
||||||
|
"viewOnly": 1,
|
||||||
|
"alia": "kg_category",
|
||||||
|
"sourceId": 4,
|
||||||
|
"startNode":0,
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"columnId": 137,
|
||||||
|
"ico": "el-icon-film",
|
||||||
|
"isPrimary": 0,
|
||||||
|
"itemId": "table-13-137",
|
||||||
|
"itemCode": "CategoryId",
|
||||||
|
"itemName": "CategoryId",
|
||||||
|
"itemType": "bigint(11)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"columnId": 138,
|
||||||
|
"ico": "el-icon-film",
|
||||||
|
"isPrimary": 0,
|
||||||
|
"itemId": "table-13-138",
|
||||||
|
"itemCode": "CategoryNodeCode",
|
||||||
|
"itemName": "CategoryNodeCode",
|
||||||
|
"itemType": "varchar(255)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"columnId": 139,
|
||||||
|
"ico": "el-icon-film",
|
||||||
|
"isPrimary": 0,
|
||||||
|
"itemId": "table-13-139",
|
||||||
|
"itemCode": "CategoryNodeId",
|
||||||
|
"itemName": "CategoryNodeId",
|
||||||
|
"itemType": "int(11)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"columnId": 140,
|
||||||
|
"ico": "el-icon-film",
|
||||||
|
"isPrimary": 0,
|
||||||
|
"itemId": "table-13-140",
|
||||||
|
"itemCode": "CategoryNodeName",
|
||||||
|
"itemName": "CategoryNodeName",
|
||||||
|
"itemType": "varchar(255)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"columnId": 141,
|
||||||
|
"ico": "el-icon-film",
|
||||||
|
"isPrimary": 0,
|
||||||
|
"itemId": "table-13-141",
|
||||||
|
"itemCode": "Color",
|
||||||
|
"itemName": "Color",
|
||||||
|
"itemType": "varchar(255)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"columnId": 142,
|
||||||
|
"ico": "el-icon-film",
|
||||||
|
"isPrimary": 0,
|
||||||
|
"itemId": "table-13-142",
|
||||||
|
"itemCode": "CreateTime",
|
||||||
|
"itemName": "CreateTime",
|
||||||
|
"itemType": "datetime"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"columnId": 151,
|
||||||
|
"ico": "el-icon-film",
|
||||||
|
"isPrimary": 0,
|
||||||
|
"itemId": "table-13-151",
|
||||||
|
"itemCode": "TreeLevel",
|
||||||
|
"itemName": "TreeLevel",
|
||||||
|
"itemType": "int(11)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"columnId": 152,
|
||||||
|
"ico": "el-icon-film",
|
||||||
|
"isPrimary": 0,
|
||||||
|
"itemId": "table-13-152",
|
||||||
|
"itemCode": "UpdateTime",
|
||||||
|
"itemName": "UpdateTime",
|
||||||
|
"itemType": "datetime"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"columnId": 153,
|
||||||
|
"ico": "el-icon-film",
|
||||||
|
"isPrimary": 0,
|
||||||
|
"itemId": "table-13-153",
|
||||||
|
"itemCode": "UpdateUser",
|
||||||
|
"itemName": "UpdateUser",
|
||||||
|
"itemType": "varchar(64)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"lineList": [
|
||||||
|
{
|
||||||
|
"from": "table-11-122",
|
||||||
|
"to": "table-13-137",
|
||||||
|
"label":"AAA"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
export function getDataB() {
|
||||||
|
return dataB;
|
||||||
|
}
|
||||||
160
src/views/erbuilder/components/mixins.js
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
export const easyFlowMixin = {
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
jsplumbSetting: {
|
||||||
|
// 动态锚点、位置自适应
|
||||||
|
//Anchor: ['Top', 'TopCenter', 'TopRight', 'TopLeft', 'Right', 'RightMiddle', 'Bottom', 'BottomCenter', 'BottomRight', 'BottomLeft', 'Left', 'LeftMiddle'],
|
||||||
|
Anchor: ['RightMiddle', 'LeftMiddle'],
|
||||||
|
Anchors: ["Right", "Left"],
|
||||||
|
// 容器ID
|
||||||
|
Container: 'efContainer',
|
||||||
|
// 连线的样式,直线或者曲线等,可选值: StateMachine、Flowchart,Bezier、Straight
|
||||||
|
//Connector: ['Bezier', {curviness: 100}],
|
||||||
|
Connector: ['Straight', {stub: 20, gap: 1}],
|
||||||
|
//Connector: ['Flowchart', {stub: 30, gap: 1, alwaysRespectStubs: false, midpoint: 0.5, cornerRadius: 10}],
|
||||||
|
// Connector: ['StateMachine', {margin: 5, curviness: 10, proximityLimit: 80}],
|
||||||
|
// 鼠标不能拖动删除线
|
||||||
|
ConnectionsDetachable: false,
|
||||||
|
// 删除线的时候节点不删除
|
||||||
|
DeleteEndpointsOnDetach: false,
|
||||||
|
/**
|
||||||
|
* 连线的两端端点类型:圆形
|
||||||
|
* radius: 圆的半径,越大圆越大
|
||||||
|
*/
|
||||||
|
Endpoint: ['Dot', {radius: 5, cssClass: 'ef-dot', hoverClass: 'ef-dot-hover'}],
|
||||||
|
/**
|
||||||
|
* 连线的两端端点类型:矩形
|
||||||
|
* height: 矩形的高
|
||||||
|
* width: 矩形的宽
|
||||||
|
*/
|
||||||
|
// Endpoint: ['Rectangle', {height: 20, width: 20, cssClass: 'ef-rectangle', hoverClass: 'ef-rectangle-hover'}],
|
||||||
|
/**
|
||||||
|
* 图像端点
|
||||||
|
*/
|
||||||
|
// Endpoint: ['Image', {src: 'https://www.easyicon.net/api/resizeApi.php?id=1181776&size=32', cssClass: 'ef-img', hoverClass: 'ef-img-hover'}],
|
||||||
|
/**
|
||||||
|
* 空白端点
|
||||||
|
*/
|
||||||
|
//Endpoint: ['Blank', {Overlays: ''}],
|
||||||
|
//Endpoint: "Dot", // 端点类型
|
||||||
|
//Endpoints: [['Dot', {radius: 5, cssClass: 'ef-dot', hoverClass: 'ef-dot-hover'}], ['Rectangle', {height: 20, width: 20, cssClass: 'ef-rectangle', hoverClass: 'ef-rectangle-hover'}]],
|
||||||
|
/**
|
||||||
|
* 连线的两端端点样式
|
||||||
|
* fill: 颜色值,如:#12aabb,为空不显示
|
||||||
|
* outlineWidth: 外边线宽度
|
||||||
|
*/
|
||||||
|
EndpointStyle: {fill: '#1879ffa1', outlineWidth: 1},
|
||||||
|
// 是否打开jsPlumb的内部日志记录
|
||||||
|
LogEnabled: false,
|
||||||
|
/**
|
||||||
|
* 连线的样式
|
||||||
|
*/
|
||||||
|
PaintStyle: {
|
||||||
|
// 线的颜色
|
||||||
|
stroke: '#E0E3E7',
|
||||||
|
// 线的粗细,值越大线越粗
|
||||||
|
strokeWidth: 1,
|
||||||
|
// 设置外边线的颜色,默认设置透明,这样别人就看不见了,点击线的时候可以不用精确点击,参考 https://blog.csdn.net/roymno2/article/details/72717101
|
||||||
|
outlineStroke: 'transparent',
|
||||||
|
// 线外边的宽,值越大,线的点击范围越大
|
||||||
|
outlineWidth: 10
|
||||||
|
},
|
||||||
|
DragOptions: {cursor: 'pointer', zIndex: 2000},
|
||||||
|
/**
|
||||||
|
* 叠加 参考: https://www.jianshu.com/p/d9e9918fd928
|
||||||
|
*/
|
||||||
|
Overlays: [
|
||||||
|
// 箭头叠加
|
||||||
|
['Arrow', {
|
||||||
|
width: 10, // 箭头尾部的宽度
|
||||||
|
length: 8, // 从箭头的尾部到头部的距离
|
||||||
|
location: 1, // 位置,建议使用0~1之间
|
||||||
|
direction: 1, // 方向,默认值为1(表示向前),可选-1(表示向后)
|
||||||
|
foldback: 0.623 // 折回,也就是尾翼的角度,默认0.623,当为1时,为正三角
|
||||||
|
}],
|
||||||
|
// ['Diamond', {
|
||||||
|
// events: {
|
||||||
|
// dblclick: function (diamondOverlay, originalEvent) {
|
||||||
|
// console.log('double click on diamond overlay for : ' + diamondOverlay.component)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }],
|
||||||
|
['Label', {
|
||||||
|
label: '',
|
||||||
|
location: 0.1,
|
||||||
|
cssClass: 'aLabel'
|
||||||
|
}]
|
||||||
|
],
|
||||||
|
// 绘制图的模式 svg、canvas
|
||||||
|
RenderMode: 'svg',
|
||||||
|
// 鼠标滑过线的样式
|
||||||
|
HoverPaintStyle: {stroke: '#b0b2b5', strokeWidth: 1},
|
||||||
|
// 滑过锚点效果
|
||||||
|
EndpointHoverStyle: {fill: 'orange'},
|
||||||
|
Scope: 'jsPlumb_DefaultScope' // 范围,具有相同scope的点才可连接
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 连线参数
|
||||||
|
*/
|
||||||
|
jsplumbConnectOptions: {
|
||||||
|
isSource: false,
|
||||||
|
isTarget: false,
|
||||||
|
// 动态锚点、提供了4个方向 Continuous、AutoDefault
|
||||||
|
anchor: 'Continuous',
|
||||||
|
// 设置连线上面的label样式
|
||||||
|
labelStyle: {
|
||||||
|
cssClass: 'flowLabel'
|
||||||
|
},
|
||||||
|
// 修改了jsplumb 源码,支持label 为空传入自定义style
|
||||||
|
emptyLabelStyle: {
|
||||||
|
cssClass: 'emptyFlowLabel'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 源点配置参数
|
||||||
|
*/
|
||||||
|
jsplumbSourceOptions: {
|
||||||
|
// 设置可以拖拽的类名,只要鼠标移动到该类名上的DOM,就可以拖拽连线
|
||||||
|
filter: '.flow-node-drag',
|
||||||
|
filterExclude: false,
|
||||||
|
anchor: ['RightMiddle', 'LeftMiddle'],
|
||||||
|
// 是否允许自己连接自己
|
||||||
|
allowLoopback: false,
|
||||||
|
maxConnections: 1,
|
||||||
|
onMaxConnections: function (info, e) {
|
||||||
|
console.log(`超过了最大值连线: ${info.maxConnections}`)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 参考 https://www.cnblogs.com/mq0036/p/7942139.html
|
||||||
|
jsplumbSourceOptions2: {
|
||||||
|
// 设置可以拖拽的类名,只要鼠标移动到该类名上的DOM,就可以拖拽连线
|
||||||
|
filter: '.flow-node-drag',
|
||||||
|
filterExclude: false,
|
||||||
|
anchor: 'Continuous',
|
||||||
|
// 是否允许自己连接自己
|
||||||
|
allowLoopback: false,
|
||||||
|
connector: ['Flowchart', {curviness: 50}],
|
||||||
|
connectorStyle: {
|
||||||
|
// 线的颜色
|
||||||
|
stroke: 'red',
|
||||||
|
// 线的粗细,值越大线越粗
|
||||||
|
strokeWidth: 1,
|
||||||
|
// 设置外边线的颜色,默认设置透明,这样别人就看不见了,点击线的时候可以不用精确点击,参考 https://blog.csdn.net/roymno2/article/details/72717101
|
||||||
|
outlineStroke: 'transparent',
|
||||||
|
// 线外边的宽,值越大,线的点击范围越大
|
||||||
|
outlineWidth: 10
|
||||||
|
},
|
||||||
|
connectorHoverStyle: {stroke: 'orange', strokeWidth: 2}
|
||||||
|
},
|
||||||
|
jsplumbTargetOptions: {
|
||||||
|
// 设置可以拖拽的类名,只要鼠标移动到该类名上的DOM,就可以拖拽连线
|
||||||
|
filter: '.flow-node-drag',
|
||||||
|
filterExclude: false,
|
||||||
|
// 是否允许自己连接自己
|
||||||
|
anchor: 'Continuous',
|
||||||
|
allowLoopback: false,
|
||||||
|
dropOptions: {hoverClass: 'ef-drop-hover'}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
241
src/views/erbuilder/components/node.vue
Normal file
@ -0,0 +1,241 @@
|
|||||||
|
<template>
|
||||||
|
<div
|
||||||
|
ref="node"
|
||||||
|
:style="nodeContainerStyle"
|
||||||
|
:class="nodeContainerClass"
|
||||||
|
>
|
||||||
|
<!-- 最左侧的那条竖线 -->
|
||||||
|
<div class="ef-node-left"></div>
|
||||||
|
<!-- 节点类型的图标 -->
|
||||||
|
<div class="ef-node-left-ico flow-node-drag">
|
||||||
|
<i :class="nodeIcoClass"></i>
|
||||||
|
</div>
|
||||||
|
<!-- 节点名称 -->
|
||||||
|
<div class="ef-node-text" :show-overflow-tooltip="true">
|
||||||
|
<div class="table node">
|
||||||
|
<div class="name">
|
||||||
|
<span>{{ node.nodeName }}</span>
|
||||||
|
<i class="node-ico-edit el-icon-edit-outline" @click="clickNode"></i>
|
||||||
|
<i class="node-ico-delete el-icon-delete" @click="deleteNode"></i>
|
||||||
|
</div>
|
||||||
|
<div class="table-columns">
|
||||||
|
<ul>
|
||||||
|
<li
|
||||||
|
class="flow-node-drag node"
|
||||||
|
:show-overflow-tooltip="true"
|
||||||
|
v-for="it in node.items"
|
||||||
|
:id="it.itemId"
|
||||||
|
>
|
||||||
|
<span class="column-span">{{ it.itemName }}</span>
|
||||||
|
<el-divider direction="vertical"></el-divider>
|
||||||
|
<span class="column-span">{{ it.itemType }}</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 节点状态图标 -->
|
||||||
|
<div class="ef-node-right-ico">
|
||||||
|
<i
|
||||||
|
class="el-icon-circle-check el-node-state-success"
|
||||||
|
v-show="node.state === 'success'"
|
||||||
|
></i>
|
||||||
|
<i
|
||||||
|
class="el-icon-circle-close el-node-state-error"
|
||||||
|
v-show="node.state === 'error'"
|
||||||
|
></i>
|
||||||
|
<i
|
||||||
|
class="el-icon-warning-outline el-node-state-warning"
|
||||||
|
v-show="node.state === 'warning'"
|
||||||
|
></i>
|
||||||
|
<i
|
||||||
|
class="el-icon-loading el-node-state-running"
|
||||||
|
v-show="node.state === 'running'"
|
||||||
|
></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
node: Object,
|
||||||
|
activeElement: Object
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
nodeContainerClass() {
|
||||||
|
return {
|
||||||
|
"ef-node-container": true,
|
||||||
|
"ef-node-active":
|
||||||
|
this.activeElement.type === "node"
|
||||||
|
? this.activeElement.nodeId === this.node.nodeKey
|
||||||
|
: false
|
||||||
|
};
|
||||||
|
},
|
||||||
|
// 节点容器样式
|
||||||
|
nodeContainerStyle() {
|
||||||
|
return {
|
||||||
|
top: this.node.top,
|
||||||
|
left: this.node.left
|
||||||
|
};
|
||||||
|
},
|
||||||
|
nodeIcoClass() {
|
||||||
|
var nodeIcoClass = {};
|
||||||
|
nodeIcoClass[this.node.ico] = true;
|
||||||
|
// 添加该class可以推拽连线出来,viewOnly 可以控制节点是否运行编辑
|
||||||
|
nodeIcoClass["flow-node-drag"] = this.node.viewOnly>0;
|
||||||
|
return nodeIcoClass;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 点击节点
|
||||||
|
clickNode() {
|
||||||
|
this.$emit("clickNode", this.node);
|
||||||
|
},
|
||||||
|
deleteNode(e) {
|
||||||
|
this.$emit("deleteNode", this.node.nodeKey);
|
||||||
|
e.stopPropagation(); //阻止冒泡
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
.table-columns ul {
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
|
.table-columns li {
|
||||||
|
list-style: none;
|
||||||
|
border: 1px dashed lightblue;
|
||||||
|
margin: 1px;
|
||||||
|
z-index: 10;
|
||||||
|
text-align: left;
|
||||||
|
padding: 0 5px;
|
||||||
|
}
|
||||||
|
.column-span {
|
||||||
|
margin: 0 5px;
|
||||||
|
}
|
||||||
|
.node-ico-edit {
|
||||||
|
margin-right: 30px;
|
||||||
|
line-height: 32px;
|
||||||
|
position: absolute;
|
||||||
|
right: 25px;
|
||||||
|
color: #153df0;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.node-ico-delete {
|
||||||
|
margin-right: 30px;
|
||||||
|
line-height: 32px;
|
||||||
|
position: absolute;
|
||||||
|
right: 5px;
|
||||||
|
color: #f56c6c;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
/*节点的最外层容器*/
|
||||||
|
.ef-node-container {
|
||||||
|
position: absolute;
|
||||||
|
display: -webkit-box;
|
||||||
|
display: -ms-flexbox;
|
||||||
|
display: flex;
|
||||||
|
width: 230px;
|
||||||
|
height: auto;
|
||||||
|
border: 1px solid #e0e3e7;
|
||||||
|
border-radius: 5px;
|
||||||
|
background-color: #fff;
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
.ef-node-container:hover {
|
||||||
|
/* 设置移动样式*/
|
||||||
|
cursor: move;
|
||||||
|
background-color: #f0f7ff;
|
||||||
|
/*box-shadow: #1879FF 0px 0px 12px 0px;*/
|
||||||
|
background-color: #f0f7ff;
|
||||||
|
border: 1px dashed #1879ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*节点激活样式*/
|
||||||
|
.ef-node-active {
|
||||||
|
background-color: #f0f7ff;
|
||||||
|
/*box-shadow: #1879FF 0px 0px 12px 0px;*/
|
||||||
|
background-color: #f0f7ff;
|
||||||
|
border: 1px solid #1879ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*节点左侧的竖线*/
|
||||||
|
.ef-node-left {
|
||||||
|
width: 4px;
|
||||||
|
background-color: #1879ff;
|
||||||
|
border-radius: 4px 0 0 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*节点左侧的图标*/
|
||||||
|
.ef-node-left-ico {
|
||||||
|
line-height: 32px;
|
||||||
|
margin-left: 8px;
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ef-node-left-ico:hover {
|
||||||
|
/* 设置拖拽的样式 */
|
||||||
|
/* cursor: crosshair; */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*节点显示的文字*/
|
||||||
|
.ef-node-text {
|
||||||
|
color: #565758;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 32px;
|
||||||
|
margin-left: 8px;
|
||||||
|
width: 210px;
|
||||||
|
/* 设置超出宽度文本显示方式*/
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*节点右侧的图标*/
|
||||||
|
.ef-node-right-ico {
|
||||||
|
line-height: 32px;
|
||||||
|
position: absolute;
|
||||||
|
right: 5px;
|
||||||
|
color: #84cf65;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*节点的几种状态样式*/
|
||||||
|
.el-node-state-success {
|
||||||
|
line-height: 32px;
|
||||||
|
position: absolute;
|
||||||
|
right: 5px;
|
||||||
|
color: #84cf65;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-node-state-error {
|
||||||
|
line-height: 32px;
|
||||||
|
position: absolute;
|
||||||
|
right: 5px;
|
||||||
|
color: #f56c6c;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-node-state-warning {
|
||||||
|
line-height: 32px;
|
||||||
|
position: absolute;
|
||||||
|
right: 5px;
|
||||||
|
color: #e6a23c;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-node-state-running {
|
||||||
|
line-height: 32px;
|
||||||
|
position: absolute;
|
||||||
|
right: 5px;
|
||||||
|
color: #84cf65;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
309
src/views/erbuilder/components/node_form.vue
Normal file
@ -0,0 +1,309 @@
|
|||||||
|
<template>
|
||||||
|
<el-drawer
|
||||||
|
ref="drawer"
|
||||||
|
title="编辑"
|
||||||
|
:with-header="false"
|
||||||
|
:visible.sync="drawer"
|
||||||
|
:direction="direction"
|
||||||
|
:append-to-body="true"
|
||||||
|
>
|
||||||
|
<div class="ef-node-form">
|
||||||
|
<div class="ef-node-form-header">
|
||||||
|
编辑
|
||||||
|
</div>
|
||||||
|
<div class="ef-node-form-body">
|
||||||
|
<el-form
|
||||||
|
:model="node"
|
||||||
|
ref="dataForm"
|
||||||
|
label-width="80px"
|
||||||
|
v-show="type === 'node'"
|
||||||
|
>
|
||||||
|
<el-form-item label="类型">
|
||||||
|
<el-input v-model="node.type" :disabled="true"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="名称">
|
||||||
|
<el-input v-model="node.nodeName"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="left坐标">
|
||||||
|
<el-input v-model="node.left" :disabled="true"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="top坐标">
|
||||||
|
<el-input v-model="node.top" :disabled="true"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="ico图标">
|
||||||
|
<el-input v-model="node.ico"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="状态">
|
||||||
|
<el-select v-model="node.state" placeholder="请选择">
|
||||||
|
<el-option
|
||||||
|
v-for="item in stateList"
|
||||||
|
:key="item.state"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.state"
|
||||||
|
>
|
||||||
|
</el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="字段">
|
||||||
|
<el-checkbox
|
||||||
|
:indeterminate="isIndeterminate"
|
||||||
|
v-model="checkAll"
|
||||||
|
@change="handleCheckAllChange"
|
||||||
|
>全选
|
||||||
|
</el-checkbox>
|
||||||
|
<el-checkbox-group
|
||||||
|
v-model="checkedColumns"
|
||||||
|
@change="handlecheckedColumnsChange"
|
||||||
|
>
|
||||||
|
<kg-table
|
||||||
|
:columns="insidetableColumns"
|
||||||
|
:pageObj="pageObj"
|
||||||
|
:config="tableConfig"
|
||||||
|
>
|
||||||
|
<template v-for="item in insidetableColumns">
|
||||||
|
<el-tooltip
|
||||||
|
:slot="'header' + item.prop"
|
||||||
|
class="item"
|
||||||
|
effect="dark"
|
||||||
|
:content="item.label"
|
||||||
|
placement="top"
|
||||||
|
:key="item.prop"
|
||||||
|
>
|
||||||
|
<el-checkbox :label="item.label">
|
||||||
|
{{ item.label }}
|
||||||
|
</el-checkbox>
|
||||||
|
</el-tooltip>
|
||||||
|
</template>
|
||||||
|
</kg-table>
|
||||||
|
</el-checkbox-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button icon="el-icon-close" @click="drawer = false"
|
||||||
|
>重置</el-button
|
||||||
|
>
|
||||||
|
<el-button type="primary" icon="el-icon-check" @click="save"
|
||||||
|
>保存</el-button
|
||||||
|
>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<el-form
|
||||||
|
:model="line"
|
||||||
|
ref="dataForm"
|
||||||
|
label-width="80px"
|
||||||
|
v-show="type === 'line'"
|
||||||
|
>
|
||||||
|
<el-form-item label="条件">
|
||||||
|
<el-input v-model="line.label"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button icon="el-icon-close" @click="drawer = false"
|
||||||
|
>重置</el-button
|
||||||
|
>
|
||||||
|
<el-button type="primary" icon="el-icon-check" @click="saveLine"
|
||||||
|
>保存</el-button
|
||||||
|
>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-drawer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { cloneDeep } from "lodash";
|
||||||
|
import { datasourceApi } from "@/api";
|
||||||
|
import kgTable from "@/components/KGTable.vue";
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
kgTable
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
// 内部表格
|
||||||
|
insidetableColumns() {
|
||||||
|
const columns = [];
|
||||||
|
this.columns &&
|
||||||
|
this.columns.forEach(item => {
|
||||||
|
columns.push({
|
||||||
|
prop: item.dataColumnName,
|
||||||
|
type: "slotHeader",
|
||||||
|
tooltip: true,
|
||||||
|
label: item.dataColumnName,
|
||||||
|
minWidth: 120
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return columns;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
visible: true,
|
||||||
|
// node 或 line
|
||||||
|
type: "node",
|
||||||
|
checkModel: false,
|
||||||
|
node: {},
|
||||||
|
line: {},
|
||||||
|
data: {},
|
||||||
|
drawer: false,
|
||||||
|
direction: "rtl",
|
||||||
|
checkAll: false,
|
||||||
|
isIndeterminate: true,
|
||||||
|
columns: [],
|
||||||
|
checkedColumns: [],
|
||||||
|
stateList: [
|
||||||
|
{
|
||||||
|
state: "success",
|
||||||
|
label: "成功"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
state: "warning",
|
||||||
|
label: "警告"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
state: "error",
|
||||||
|
label: "错误"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
state: "running",
|
||||||
|
label: "运行中"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
// 内部表格
|
||||||
|
tableConfig: {
|
||||||
|
pagination: false, // 是否显示分页
|
||||||
|
selection: false, // 多选
|
||||||
|
rowKey: "id", // table row-key配置参数
|
||||||
|
notUseMaxHeight: true
|
||||||
|
},
|
||||||
|
pageObj: {
|
||||||
|
currentPage: 1,
|
||||||
|
pageSize: 15,
|
||||||
|
list: [],
|
||||||
|
totalCount: 0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleCheckAllChange(val) {
|
||||||
|
let arr = this.columns.map(function(col) {
|
||||||
|
return col.dataColumnName;
|
||||||
|
});
|
||||||
|
this.checkedColumns = val ? arr : [];
|
||||||
|
this.isIndeterminate = false;
|
||||||
|
},
|
||||||
|
handlecheckedColumnsChange(value) {
|
||||||
|
let checkedCount = value.length;
|
||||||
|
this.checkAll = checkedCount === this.columns.length;
|
||||||
|
this.isIndeterminate =
|
||||||
|
checkedCount > 0 && checkedCount < this.columns.length;
|
||||||
|
this.checkedColumns = value;
|
||||||
|
},
|
||||||
|
changeColumns() {
|
||||||
|
this.data.nodeList.filter(node => {
|
||||||
|
if (node.nodeKey === this.node.nodeKey) {
|
||||||
|
node.nodeName = this.node.nodeName;
|
||||||
|
node.left = this.node.left;
|
||||||
|
node.top = this.node.top;
|
||||||
|
node.ico = this.node.ico;
|
||||||
|
node.state = this.node.state;
|
||||||
|
let nodeItems = this.columns.filter(c => {
|
||||||
|
if (this.checkedColumns.indexOf(c.dataColumnName) > -1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
node.items = [];
|
||||||
|
for (var j = 0; j < nodeItems.length; j++) {
|
||||||
|
let tr = {
|
||||||
|
columnId: nodeItems[j].dataColumnId,
|
||||||
|
ico: "el-icon-film",
|
||||||
|
isPrimary: 0,
|
||||||
|
itemId: node.id + "-" + nodeItems[j].dataColumnId,
|
||||||
|
itemCode: nodeItems[j].dataColumnName,
|
||||||
|
itemName: nodeItems[j].dataColumnName,
|
||||||
|
itemType: nodeItems[j].dataColumnType
|
||||||
|
};
|
||||||
|
node.items.push(tr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 表单修改
|
||||||
|
* @param data
|
||||||
|
* @param node
|
||||||
|
*/
|
||||||
|
nodeInit(data, node) {
|
||||||
|
this.drawer = true;
|
||||||
|
this.type = "node";
|
||||||
|
this.data = data;
|
||||||
|
this.node = cloneDeep(node);
|
||||||
|
let arr=node.items.map(function(col) {
|
||||||
|
return col.itemCode;
|
||||||
|
});
|
||||||
|
this.checkedColumns = arr ? arr : [];
|
||||||
|
let param = {
|
||||||
|
dataSourceId: node.sourceId,
|
||||||
|
dataTableName: node.nodeName,
|
||||||
|
currentPage: 1,
|
||||||
|
pageSize: 5
|
||||||
|
};
|
||||||
|
datasourceApi.getPreviewData(param).then(response => {
|
||||||
|
if (response.code == 200) {
|
||||||
|
this.pageObj.list = response.data.data;
|
||||||
|
this.columns = response.data.heads;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
lineInit(line) {
|
||||||
|
this.drawer = true;
|
||||||
|
this.type = "line";
|
||||||
|
this.line = line;
|
||||||
|
},
|
||||||
|
// 修改连线
|
||||||
|
saveLine() {
|
||||||
|
this.drawer = false;
|
||||||
|
this.$emit("setLineLabel", this.line.from, this.line.to, this.line.label);
|
||||||
|
},
|
||||||
|
save() {
|
||||||
|
this.drawer = false;
|
||||||
|
this.changeColumns();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.el-node-form-tag {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
margin-left: -15px;
|
||||||
|
height: 40px;
|
||||||
|
width: 15px;
|
||||||
|
background-color: #fbfbfb;
|
||||||
|
border: 1px solid rgb(220, 227, 232);
|
||||||
|
border-right: none;
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
/*node-form*/
|
||||||
|
.ef-node-form-header {
|
||||||
|
height: 32px;
|
||||||
|
border-top: 1px solid #dce3e8;
|
||||||
|
border-bottom: 1px solid #dce3e8;
|
||||||
|
background: #f1f3f4;
|
||||||
|
color: #000;
|
||||||
|
line-height: 32px;
|
||||||
|
padding-left: 12px;
|
||||||
|
font-size: 14px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ef-node-form-body {
|
||||||
|
margin-top: 10px;
|
||||||
|
padding-right: 10px;
|
||||||
|
padding-bottom: 20px;
|
||||||
|
}
|
||||||
|
.ef-node-form-body {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
60
src/views/erbuilder/components/node_info.vue
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog title="数据信息" :visible.sync="dialogVisible" width="70%">
|
||||||
|
<el-alert
|
||||||
|
title="使用说明"
|
||||||
|
type="warning"
|
||||||
|
description="以下流程信息可以被存储起来,方便下一次流程加载"
|
||||||
|
show-icon
|
||||||
|
close-text="知道了"
|
||||||
|
>
|
||||||
|
</el-alert>
|
||||||
|
<br />
|
||||||
|
<!--一个高亮显示的插件-->
|
||||||
|
<codemirror
|
||||||
|
:value="flowJsonData"
|
||||||
|
:options="options"
|
||||||
|
class="code"
|
||||||
|
></codemirror>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import "codemirror/lib/codemirror.css";
|
||||||
|
import { codemirror } from "vue-codemirror";
|
||||||
|
|
||||||
|
require("codemirror/mode/javascript/javascript.js");
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
data: Object
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
dialogVisible: false,
|
||||||
|
flowJsonData: {},
|
||||||
|
options: {
|
||||||
|
mode: { name: "javascript", json: true },
|
||||||
|
lineNumbers: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
codemirror
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
init() {
|
||||||
|
this.dialogVisible = true;
|
||||||
|
this.flowJsonData = JSON.stringify(this.data, null, 4).toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
.el-dialog__body {
|
||||||
|
padding: 30px 20px;
|
||||||
|
color: #606266;
|
||||||
|
font-size: 14px;
|
||||||
|
word-break: break-all;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
263
src/views/erbuilder/components/node_tree.vue
Normal file
@ -0,0 +1,263 @@
|
|||||||
|
<template>
|
||||||
|
<div class="flow-menu" ref="tool">
|
||||||
|
<div v-for="menu in menuList" :key="menu.id">
|
||||||
|
<span class="ef-node-pmenu" @click="menuClick(menu)"
|
||||||
|
><i
|
||||||
|
:class="{
|
||||||
|
'el-icon-caret-bottom': menu.open,
|
||||||
|
'el-icon-caret-right': !menu.open
|
||||||
|
}"
|
||||||
|
></i
|
||||||
|
> {{ menu.name }}</span
|
||||||
|
>
|
||||||
|
<ul v-show="menu.open" class="ef-node-menu-ul">
|
||||||
|
<draggable
|
||||||
|
@end="end"
|
||||||
|
@start="move"
|
||||||
|
v-model="menu.children"
|
||||||
|
:options="draggableOptions"
|
||||||
|
>
|
||||||
|
<li
|
||||||
|
v-for="subMenu in menu.children"
|
||||||
|
class="ef-node-menu-li"
|
||||||
|
:id="subMenu.id"
|
||||||
|
:key="subMenu.id"
|
||||||
|
:type="subMenu.type"
|
||||||
|
>
|
||||||
|
<i :class="subMenu.ico"></i> {{ subMenu.name }}
|
||||||
|
</li>
|
||||||
|
</draggable>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import draggable from "vuedraggable";
|
||||||
|
import { datasourceApi } from "@/api";
|
||||||
|
var mousePosition = {
|
||||||
|
left: -1,
|
||||||
|
top: -1
|
||||||
|
};
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
activeNames: "1",
|
||||||
|
// draggable配置参数参考 https://www.cnblogs.com/weixin186/p/10108679.html
|
||||||
|
draggableOptions: {
|
||||||
|
preventOnFilter: false,
|
||||||
|
sort: true,
|
||||||
|
disabled: false,
|
||||||
|
ghostClass: "tt",
|
||||||
|
//
|
||||||
|
|
||||||
|
scroll: true,
|
||||||
|
animation: "300",
|
||||||
|
// 不使用H5原生的配置
|
||||||
|
forceFallback: true
|
||||||
|
// 拖拽的时候样式
|
||||||
|
// fallbackClass: 'flow-node-draggable'
|
||||||
|
},
|
||||||
|
// 默认打开的左侧菜单的id
|
||||||
|
defaultOpeneds: ["1", "2"],
|
||||||
|
menuList: [
|
||||||
|
{
|
||||||
|
id: "1",
|
||||||
|
type: "group",
|
||||||
|
name: "开始节点",
|
||||||
|
ico: "el-icon-video-play",
|
||||||
|
open: true,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
id: "11",
|
||||||
|
type: "timer",
|
||||||
|
name: "数据接入",
|
||||||
|
ico: "el-icon-time",
|
||||||
|
// 自定义覆盖样式
|
||||||
|
style: {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "12",
|
||||||
|
type: "task",
|
||||||
|
name: "接口调用",
|
||||||
|
ico: "el-icon-odometer",
|
||||||
|
// 自定义覆盖样式
|
||||||
|
style: {}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
datasourceList: [],
|
||||||
|
nodeMenu: {
|
||||||
|
table: {},
|
||||||
|
columns: []
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
draggable
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
/**
|
||||||
|
* 以下是为了解决在火狐浏览器上推拽时弹出tab页到搜索问题
|
||||||
|
* @param event
|
||||||
|
*/
|
||||||
|
if (this.isFirefox()) {
|
||||||
|
document.body.ondrop = function(event) {
|
||||||
|
// 解决火狐浏览器无法获取鼠标拖拽结束的坐标问题
|
||||||
|
mousePosition.left = event.layerX;
|
||||||
|
mousePosition.top = event.clientY - 50;
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
//加载数据源列表
|
||||||
|
this.getDatasourceList();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
menuClick(menu) {
|
||||||
|
menu.open = !menu.open;
|
||||||
|
if (menu.open && menu.children.length == 0) {
|
||||||
|
this.getDataTableList(menu.id);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
//加载数据源
|
||||||
|
getDatasourceList() {
|
||||||
|
datasourceApi.getDatasource().then(response => {
|
||||||
|
this.datasourceList = response.data;
|
||||||
|
this.menuList = [];
|
||||||
|
for (let i = 0; i < this.datasourceList.length; i++) {
|
||||||
|
let data = this.datasourceList[i];
|
||||||
|
let item = {
|
||||||
|
id: data.datasourceId,
|
||||||
|
type: "group",
|
||||||
|
name: data.datasourceName,
|
||||||
|
ico: "el-icon-video-play",
|
||||||
|
open: false,
|
||||||
|
children: []
|
||||||
|
};
|
||||||
|
this.menuList.push(item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
//加载数据表
|
||||||
|
getDataTableList(sourceId) {
|
||||||
|
datasourceApi.getTableInfo(sourceId).then(response => {
|
||||||
|
for (let i = 0; i < this.menuList.length; i++) {
|
||||||
|
if (this.menuList[i].id == sourceId) {
|
||||||
|
this.menuList[i].children = [];
|
||||||
|
for (let j = 0; j < response.data.length; j++) {
|
||||||
|
let tableItem = response.data[j];
|
||||||
|
let submitItem = {
|
||||||
|
id: tableItem.dataTableId,
|
||||||
|
type: "timer",
|
||||||
|
name: tableItem.dataTableName,
|
||||||
|
ico: "el-icon-menu",
|
||||||
|
// 自定义覆盖样式
|
||||||
|
style: {}
|
||||||
|
};
|
||||||
|
this.menuList[i].children.push(submitItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
//获取数据表字段
|
||||||
|
getDataTableInfo(tableId, evt) {
|
||||||
|
datasourceApi.getDataTableInfo(tableId).then(response => {
|
||||||
|
let columns = [];
|
||||||
|
let tableItem = response.data;
|
||||||
|
let item = {
|
||||||
|
nodeKey: "table-" + tableItem.table.dataTableId,
|
||||||
|
tableId: tableItem.table.dataTableId,
|
||||||
|
type: "timer",
|
||||||
|
nodeName: tableItem.table.dataTableName,
|
||||||
|
alia: tableItem.table.dataTableAlia,
|
||||||
|
sourceId: tableItem.table.datasourceId,
|
||||||
|
startNode:0,
|
||||||
|
ico: "el-icon-menu",
|
||||||
|
// 自定义覆盖样式
|
||||||
|
style: {},
|
||||||
|
state: "success",
|
||||||
|
viewOnly: 1 //0 不可拖拽
|
||||||
|
};
|
||||||
|
for (let i = 0; i < tableItem.column.length; i++) {
|
||||||
|
let columnItem = tableItem.column[i];
|
||||||
|
let data = {
|
||||||
|
itemId: item.nodeKey + "-" + columnItem.dataColumnId,
|
||||||
|
columnId: columnItem.dataColumnId,
|
||||||
|
itemCode: columnItem.dataColumnName,
|
||||||
|
itemName:
|
||||||
|
columnItem.dataColumnName + "[" + columnItem.dataColumnAlia + "]",
|
||||||
|
itemType: columnItem.dataColumnType,
|
||||||
|
isPrimary: columnItem.isPrimary,
|
||||||
|
ico: "el-icon-film"
|
||||||
|
};
|
||||||
|
columns.push(data);
|
||||||
|
}
|
||||||
|
this.nodeMenu.table = item;
|
||||||
|
this.nodeMenu.columns = columns;
|
||||||
|
this.$emit("addNode", evt, this.nodeMenu, mousePosition);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// 拖拽开始时触发
|
||||||
|
move(evt) {},
|
||||||
|
// 拖拽结束时触发
|
||||||
|
end(evt, e) {
|
||||||
|
let tableId = evt.item.attributes.id.nodeValue;
|
||||||
|
this.getDataTableInfo(tableId, evt);
|
||||||
|
},
|
||||||
|
// 是否是火狐浏览器
|
||||||
|
isFirefox() {
|
||||||
|
var userAgent = navigator.userAgent;
|
||||||
|
if (userAgent.indexOf("Firefox") > -1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
/*节点菜单*/
|
||||||
|
.ef-node-pmenu {
|
||||||
|
cursor: pointer;
|
||||||
|
height: 32px;
|
||||||
|
line-height: 32px;
|
||||||
|
width: 255px;
|
||||||
|
display: block;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #4a4a4a;
|
||||||
|
text-align: left;
|
||||||
|
padding-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ef-node-pmenu:hover {
|
||||||
|
background-color: #e0e0e0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ef-node-menu-li {
|
||||||
|
color: #565758;
|
||||||
|
width: 180px;
|
||||||
|
border: 1px dashed #e0e3e7;
|
||||||
|
margin: 5px 0 5px 0;
|
||||||
|
padding: 5px;
|
||||||
|
border-radius: 5px;
|
||||||
|
padding-left: 8px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ef-node-menu-li:hover {
|
||||||
|
/* 设置移动样式*/
|
||||||
|
cursor: move;
|
||||||
|
background-color: #f0f7ff;
|
||||||
|
border: 1px dashed #1879ff;
|
||||||
|
border-left: 4px solid #1879ff;
|
||||||
|
padding-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ef-node-menu-ul {
|
||||||
|
list-style: none;
|
||||||
|
padding-left: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
888
src/views/erbuilder/index.vue
Normal file
@ -0,0 +1,888 @@
|
|||||||
|
<template>
|
||||||
|
<div
|
||||||
|
v-if="easyFlowVisible"
|
||||||
|
style="height: calc(100vh)"
|
||||||
|
@contextmenu="hiddenLinkMenu"
|
||||||
|
@click="hiddenLinkMenu"
|
||||||
|
>
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="24">
|
||||||
|
<div class="ef-tooltar">
|
||||||
|
<el-tag
|
||||||
|
:key="tag.id"
|
||||||
|
v-for="tag in domainList"
|
||||||
|
@click="initERData(tag.id)"
|
||||||
|
closable
|
||||||
|
:disable-transitions="false"
|
||||||
|
@close="deleteEr(tag.id)"
|
||||||
|
>
|
||||||
|
{{ tag.name }}
|
||||||
|
</el-tag>
|
||||||
|
<el-input
|
||||||
|
class="input-new-tag"
|
||||||
|
v-if="inputVisible"
|
||||||
|
v-model="inputValue"
|
||||||
|
ref="saveTagInput"
|
||||||
|
size="small"
|
||||||
|
@keyup.enter.native="createDomain"
|
||||||
|
@blur="createDomain"
|
||||||
|
>
|
||||||
|
</el-input>
|
||||||
|
<el-button
|
||||||
|
v-else
|
||||||
|
class="button-new-tag"
|
||||||
|
size="small"
|
||||||
|
@click="showAddDomain"
|
||||||
|
>+ 添加领域</el-button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
<!--顶部工具菜单-->
|
||||||
|
<el-col :span="24">
|
||||||
|
<div class="ef-tooltar">
|
||||||
|
<el-link type="primary" :underline="false">
|
||||||
|
当前领域 【{{ data.domainName }}】</el-link
|
||||||
|
>
|
||||||
|
<el-divider direction="vertical"></el-divider>
|
||||||
|
<el-button
|
||||||
|
type="text"
|
||||||
|
@click="refreshData"
|
||||||
|
icon="el-icon-refresh"
|
||||||
|
size="large"
|
||||||
|
>刷新</el-button
|
||||||
|
>
|
||||||
|
<el-divider direction="vertical"></el-divider>
|
||||||
|
<el-button
|
||||||
|
type="text"
|
||||||
|
icon="el-icon-download"
|
||||||
|
size="large"
|
||||||
|
@click="downloadData"
|
||||||
|
></el-button>
|
||||||
|
|
||||||
|
<div style="float: right; margin-right: 5px">
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
icon="el-icon-document"
|
||||||
|
@click="saveERdata"
|
||||||
|
size="mini"
|
||||||
|
>保存</el-button
|
||||||
|
>
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
icon="el-icon-document"
|
||||||
|
@click="executeERdata"
|
||||||
|
size="mini"
|
||||||
|
>生成图谱</el-button
|
||||||
|
>
|
||||||
|
<el-button
|
||||||
|
type="info"
|
||||||
|
plain
|
||||||
|
round
|
||||||
|
icon="el-icon-document"
|
||||||
|
@click="dataInfo"
|
||||||
|
size="mini"
|
||||||
|
>预览数据</el-button
|
||||||
|
>
|
||||||
|
|
||||||
|
<el-button
|
||||||
|
type="info"
|
||||||
|
plain
|
||||||
|
round
|
||||||
|
icon="el-icon-document"
|
||||||
|
@click="openHelp"
|
||||||
|
size="mini"
|
||||||
|
>帮助</el-button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<div style="display: flex; height: calc(100% - 47px)">
|
||||||
|
<div style="width: 230px; border-right: 1px solid #dce3e8">
|
||||||
|
<node-menu @addNode="addNode" ref="nodeMenu"></node-menu>
|
||||||
|
</div>
|
||||||
|
<div id="efContainer" ref="efContainer" class="container" v-flowDrag>
|
||||||
|
<template v-for="node in data.nodeList">
|
||||||
|
<flow-node
|
||||||
|
:key="node.nodeKey"
|
||||||
|
:id="node.nodeKey"
|
||||||
|
:node="node"
|
||||||
|
:activeElement="activeElement"
|
||||||
|
@clickNode="clickNode"
|
||||||
|
@nodeRightMenu="nodeRightMenu"
|
||||||
|
@deleteNode="deleteNode"
|
||||||
|
>
|
||||||
|
</flow-node>
|
||||||
|
</template>
|
||||||
|
<!-- 给画布一个默认的宽度和高度 -->
|
||||||
|
<div style="position: absolute; top: 2000px; left: 2000px"> </div>
|
||||||
|
</div>
|
||||||
|
<ul
|
||||||
|
v-show="showLineMenu"
|
||||||
|
:style="linkmenubarStyle"
|
||||||
|
class="el-dropdown-menu el-popper linkmenubar"
|
||||||
|
>
|
||||||
|
<li class="el-dropdown-menu__item">
|
||||||
|
<span class="pl-15 el-icon-reading" @click="editActiveElement"
|
||||||
|
>编辑</span
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
<li class="el-dropdown-menu__item">
|
||||||
|
<span class="pl-15 el-icon-delete" @click="deleteElement">删除</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<!-- 右侧表单 -->
|
||||||
|
<div>
|
||||||
|
<flow-node-form
|
||||||
|
ref="nodeForm"
|
||||||
|
@setLineLabel="setLineLabel"
|
||||||
|
@repaintEverything="repaintEverything"
|
||||||
|
></flow-node-form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 流程数据详情 -->
|
||||||
|
<flow-info v-if="flowInfoVisible" ref="flowInfo" :data="data"></flow-info>
|
||||||
|
<flow-help v-if="flowHelpVisible" ref="flowHelp"></flow-help>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { jsPlumb } from "jsplumb";
|
||||||
|
import lodash from "lodash";
|
||||||
|
import { easyFlowMixin } from "@/views/erbuilder/components/mixins";
|
||||||
|
import flowNode from "@/views/erbuilder/components/node";
|
||||||
|
import nodeMenu from "@/views/erbuilder/components/node_tree";
|
||||||
|
import FlowInfo from "@/views/erbuilder/components/node_info";
|
||||||
|
import FlowHelp from "@/views/erbuilder/components/help";
|
||||||
|
import FlowNodeForm from "@/views/erbuilder/components/node_form";
|
||||||
|
import { kgBuilderApi } from "@/api";
|
||||||
|
export default {
|
||||||
|
name: "er",
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
// jsPlumb 实例
|
||||||
|
jsPlumb: null,
|
||||||
|
// 控制画布销毁
|
||||||
|
easyFlowVisible: true,
|
||||||
|
// 控制流程数据显示与隐藏
|
||||||
|
flowInfoVisible: false,
|
||||||
|
// 是否加载完毕标志位
|
||||||
|
loadEasyFlowFinish: false,
|
||||||
|
flowHelpVisible: false,
|
||||||
|
// 数据
|
||||||
|
data: {},
|
||||||
|
// 激活的元素、可能是节点、可能是连线
|
||||||
|
activeElement: {
|
||||||
|
// 可选值 node 、line
|
||||||
|
type: undefined,
|
||||||
|
// 节点ID
|
||||||
|
nodeId: undefined,
|
||||||
|
// 连线ID
|
||||||
|
sourceId: undefined,
|
||||||
|
targetId: undefined,
|
||||||
|
label: undefined
|
||||||
|
},
|
||||||
|
zoom: 0.5,
|
||||||
|
showLineMenu: false,
|
||||||
|
linkmenubar: {
|
||||||
|
top: "-1000px",
|
||||||
|
left: "-1000px"
|
||||||
|
},
|
||||||
|
domainQuery: {
|
||||||
|
domainId: 0,
|
||||||
|
type: 3,
|
||||||
|
pageSize: 10,
|
||||||
|
pageIndex: 1
|
||||||
|
},
|
||||||
|
inputVisible: false,
|
||||||
|
inputValue: "",
|
||||||
|
domainList: []
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
linkmenubarStyle: function() {
|
||||||
|
return {
|
||||||
|
top: this.linkmenubar.top + "px",
|
||||||
|
left: this.linkmenubar.left + "px"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 一些基础配置移动该文件中
|
||||||
|
mixins: [easyFlowMixin],
|
||||||
|
components: {
|
||||||
|
flowNode,
|
||||||
|
nodeMenu,
|
||||||
|
FlowInfo,
|
||||||
|
FlowNodeForm,
|
||||||
|
FlowHelp
|
||||||
|
},
|
||||||
|
directives: {
|
||||||
|
flowDrag: {
|
||||||
|
bind(el, binding, vnode, oldNode) {
|
||||||
|
if (!binding) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
el.onmousedown = e => {
|
||||||
|
if (e.button === 2) {
|
||||||
|
// 右键不管
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 鼠标按下,计算当前原始距离可视区的高度
|
||||||
|
let disX = e.clientX;
|
||||||
|
let disY = e.clientY;
|
||||||
|
el.style.cursor = "move";
|
||||||
|
|
||||||
|
document.onmousemove = function(e) {
|
||||||
|
// 移动时禁止默认事件
|
||||||
|
e.preventDefault();
|
||||||
|
const left = e.clientX - disX;
|
||||||
|
disX = e.clientX;
|
||||||
|
el.scrollLeft += -left;
|
||||||
|
|
||||||
|
const top = e.clientY - disY;
|
||||||
|
disY = e.clientY;
|
||||||
|
el.scrollTop += -top;
|
||||||
|
};
|
||||||
|
|
||||||
|
document.onmouseup = function(e) {
|
||||||
|
el.style.cursor = "auto";
|
||||||
|
document.onmousemove = null;
|
||||||
|
document.onmouseup = null;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.initDomain();
|
||||||
|
this.jsPlumb = jsPlumb.getInstance();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
showAddDomain() {
|
||||||
|
this.inputVisible = true;
|
||||||
|
this.$nextTick(_ => {
|
||||||
|
this.$refs.saveTagInput.$refs.input.focus();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
deleteEr(domainId) {
|
||||||
|
this.$message.success("计划中");
|
||||||
|
},
|
||||||
|
initDomain() {
|
||||||
|
let data = JSON.stringify(this.domainQuery);
|
||||||
|
kgBuilderApi.getDomains(data).then(response => {
|
||||||
|
if (response.code == 200) {
|
||||||
|
this.domainList = response.data.nodeList;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
createDomain() {
|
||||||
|
let inputValue = this.inputValue;
|
||||||
|
if (inputValue) {
|
||||||
|
let data = {
|
||||||
|
domain: inputValue,
|
||||||
|
type: 3
|
||||||
|
};
|
||||||
|
kgBuilderApi.createDomain(data).then(response => {
|
||||||
|
if (response.code == 200) {
|
||||||
|
this.data.domainName = inputValue;
|
||||||
|
this.data.domainId = response.data;
|
||||||
|
this.domainList.push({ id: response.data, name: inputValue });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.inputVisible = false;
|
||||||
|
this.inputValue = "";
|
||||||
|
},
|
||||||
|
saveERdata() {
|
||||||
|
let data = JSON.stringify(this.data);
|
||||||
|
kgBuilderApi.saveData(data).then(response => {
|
||||||
|
if (response.code == 200) {
|
||||||
|
if (response.data) {
|
||||||
|
this.$message.success("保存成功");
|
||||||
|
} else {
|
||||||
|
this.$message.error("暂时没有更多数据");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
executeERdata() {
|
||||||
|
kgBuilderApi.execute(this.data.domainId).then(response => {
|
||||||
|
if (response.code == 200) {
|
||||||
|
if (response.data) {
|
||||||
|
this.$message.success("保存成功");
|
||||||
|
} else {
|
||||||
|
this.$message.error("暂时没有更多数据");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// 初始化数据
|
||||||
|
initERData(domainId) {
|
||||||
|
kgBuilderApi.getDomainNode(domainId).then(response => {
|
||||||
|
if (response.code == 200) {
|
||||||
|
if (response.data) {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
// 默认加载流程A的数据、在这里可以根据具体的业务返回符合流程数据格式的数据即可
|
||||||
|
this.dataReload(response.data);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.$message.error("暂时没有更多数据");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
hiddenLinkMenu(e) {
|
||||||
|
//e.preventDefault();
|
||||||
|
this.showLineMenu = false;
|
||||||
|
},
|
||||||
|
jsPlumbInit() {
|
||||||
|
this.jsPlumb.ready(() => {
|
||||||
|
// 导入默认配置
|
||||||
|
this.jsPlumb.importDefaults(this.jsplumbSetting);
|
||||||
|
// 会使整个jsPlumb立即重绘。
|
||||||
|
this.jsPlumb.setSuspendDrawing(false, true);
|
||||||
|
// 初始化节点
|
||||||
|
this.loadEasyFlow();
|
||||||
|
// 单点击了连接线, https://www.cnblogs.com/ysx215/p/7615677.html
|
||||||
|
this.jsPlumb.bind("click", conn => {
|
||||||
|
this.activeElement.type = "line";
|
||||||
|
this.activeElement.sourceId = conn.sourceId;
|
||||||
|
this.activeElement.targetId = conn.targetId;
|
||||||
|
this.$refs.nodeForm.lineInit({
|
||||||
|
from: conn.sourceId,
|
||||||
|
to: conn.targetId,
|
||||||
|
label: conn.getLabel()
|
||||||
|
});
|
||||||
|
});
|
||||||
|
// 连线
|
||||||
|
this.jsPlumb.bind("connection", evt => {
|
||||||
|
let from = evt.source.id;
|
||||||
|
let to = evt.target.id;
|
||||||
|
if (this.loadEasyFlowFinish) {
|
||||||
|
this.data.lineList.push({ from: from, to: to });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 删除连线回调
|
||||||
|
this.jsPlumb.bind("connectionDetached", evt => {
|
||||||
|
this.deleteLine(evt.sourceId, evt.targetId);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 改变线的连接节点
|
||||||
|
this.jsPlumb.bind("connectionMoved", evt => {
|
||||||
|
this.changeLine(evt.originalSourceId, evt.originalTargetId);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 连线右击
|
||||||
|
this.jsPlumb.bind("contextmenu", (evt, e) => {
|
||||||
|
let left = e.clientX;
|
||||||
|
let top = e.clientY;
|
||||||
|
this.showLineMenu = true;
|
||||||
|
//console.log("contextmenu", evt);
|
||||||
|
this.linkmenubar.top = top;
|
||||||
|
this.linkmenubar.left = left;
|
||||||
|
this.activeElement.type = "line";
|
||||||
|
this.activeElement.sourceId = evt.sourceId;
|
||||||
|
this.activeElement.targetId = evt.targetId;
|
||||||
|
this.activeElement.label = evt.getLabel();
|
||||||
|
e.preventDefault(); //禁止浏览器右键
|
||||||
|
e.stopPropagation(); //阻止冒泡
|
||||||
|
});
|
||||||
|
// 连线
|
||||||
|
this.jsPlumb.bind("beforeDrop", evt => {
|
||||||
|
console.log(evt);
|
||||||
|
let from = evt.sourceId;
|
||||||
|
let to = evt.targetId;
|
||||||
|
if (from === to) {
|
||||||
|
this.$message.error("节点不支持连接自己");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this.hasLine(from, to)) {
|
||||||
|
this.$message.error("该关系已存在,不允许重复创建");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this.hashOppositeLine(from, to)) {
|
||||||
|
this.$message.error("不支持两个节点之间连线回环");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.isSameTableLine(from, to)) {
|
||||||
|
//this.$message.error("同一个表之间无需连线");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this.isMutilLine(from, to)) {
|
||||||
|
this.$message.error("两个表之间只能存在一根连线");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
this.$message.success("连接成功");
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
// beforeDetach
|
||||||
|
this.jsPlumb.bind("beforeDetach", evt => {
|
||||||
|
console.log("beforeDetach", evt);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.jsPlumb.setContainer(this.$refs.efContainer);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// 加载流程图
|
||||||
|
loadEasyFlow() {
|
||||||
|
// 初始化节点
|
||||||
|
for (var i = 0; i < this.data.nodeList.length; i++) {
|
||||||
|
let node = this.data.nodeList[i];
|
||||||
|
if (node.viewOnly > 0) {
|
||||||
|
this.jsPlumb.draggable(node.nodeKey, {
|
||||||
|
containment: "parent",
|
||||||
|
stop: function(el, e) {
|
||||||
|
//debugger;
|
||||||
|
let posArr = el.pos;
|
||||||
|
node.left = posArr[0] + "px";
|
||||||
|
node.top = posArr[1] + "px";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let nodeItems = node.items;
|
||||||
|
for (var j = 0; j < nodeItems.length; j++) {
|
||||||
|
// 设置源点,可以拖出线连接其他节点
|
||||||
|
//let obj = lodash.merge(this.jsplumbSourceOptions, {});
|
||||||
|
this.jsPlumb.makeSource(nodeItems[j].itemId);
|
||||||
|
// // 设置目标点,其他源点拖出的线可以连接该节点
|
||||||
|
this.jsPlumb.makeTarget(
|
||||||
|
nodeItems[j].itemId,
|
||||||
|
this.jsplumbSourceOptions
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 初始化连线
|
||||||
|
for (var m = 0; m < this.data.lineList.length; m++) {
|
||||||
|
let line = this.data.lineList[m];
|
||||||
|
var connParam = {
|
||||||
|
source: line.from,
|
||||||
|
target: line.to,
|
||||||
|
label: line.label ? line.label : "",
|
||||||
|
connector: line.connector ? line.connector : "",
|
||||||
|
anchors: line.anchors ? line.anchors : undefined,
|
||||||
|
paintStyle: line.paintStyle ? line.paintStyle : undefined
|
||||||
|
};
|
||||||
|
this.jsPlumb.connect(connParam, this.jsplumbConnectOptions);
|
||||||
|
}
|
||||||
|
this.$nextTick(function() {
|
||||||
|
this.loadEasyFlowFinish = true;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// 设置连线条件
|
||||||
|
setLineLabel(from, to, label) {
|
||||||
|
var conn = this.jsPlumb.getConnections({
|
||||||
|
source: from,
|
||||||
|
target: to
|
||||||
|
})[0];
|
||||||
|
if (!label || label === "") {
|
||||||
|
conn.removeClass("flowLabel");
|
||||||
|
conn.addClass("emptyFlowLabel");
|
||||||
|
} else {
|
||||||
|
conn.addClass("flowLabel");
|
||||||
|
}
|
||||||
|
conn.setLabel({
|
||||||
|
label: label
|
||||||
|
});
|
||||||
|
this.data.lineList.forEach(function(line) {
|
||||||
|
if (line.from === from && line.to === to) {
|
||||||
|
line.label = label;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
//编辑激活的连线
|
||||||
|
editActiveElement() {
|
||||||
|
this.activeElement.type = "line";
|
||||||
|
let sourceId = this.activeElement.sourceId;
|
||||||
|
let targetId = this.activeElement.targetId;
|
||||||
|
let label = this.activeElement.label;
|
||||||
|
this.$refs.nodeForm.lineInit({
|
||||||
|
from: sourceId,
|
||||||
|
to: targetId,
|
||||||
|
label: label
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// 删除激活的元素
|
||||||
|
deleteElement() {
|
||||||
|
if (this.activeElement.type === "node") {
|
||||||
|
this.deleteNode(this.activeElement.nodeId);
|
||||||
|
} else if (this.activeElement.type === "line") {
|
||||||
|
this.$confirm("确定删除所点击的线吗?", "提示", {
|
||||||
|
confirmButtonText: "确定",
|
||||||
|
cancelButtonText: "取消",
|
||||||
|
type: "warning"
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
var conn = this.jsPlumb.getConnections({
|
||||||
|
source: this.activeElement.sourceId,
|
||||||
|
target: this.activeElement.targetId
|
||||||
|
})[0];
|
||||||
|
this.jsPlumb.deleteConnection(conn);
|
||||||
|
})
|
||||||
|
.catch(() => {});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 删除线
|
||||||
|
deleteLine(from, to) {
|
||||||
|
this.data.lineList = this.data.lineList.filter(function(line) {
|
||||||
|
if (line.from === from && line.to === to) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// 改变连线
|
||||||
|
changeLine(oldFrom, oldTo) {
|
||||||
|
this.deleteLine(oldFrom, oldTo);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 拖拽结束后添加新的节点
|
||||||
|
* @param evt
|
||||||
|
* @param nodeMenu 被添加的节点对象
|
||||||
|
* @param mousePosition 鼠标拖拽结束的坐标
|
||||||
|
*/
|
||||||
|
addNode(evt, nodeMenu, mousePosition) {
|
||||||
|
if (!this.data.domainId) {
|
||||||
|
this.$message.warning("请先选择或者创建领域");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let screenX = evt.originalEvent.clientX;
|
||||||
|
let screenY = evt.originalEvent.clientY;
|
||||||
|
let efContainer = this.$refs.efContainer;
|
||||||
|
let containerRect = efContainer.getBoundingClientRect();
|
||||||
|
let left = screenX;
|
||||||
|
let top = screenY;
|
||||||
|
// 计算是否拖入到容器中
|
||||||
|
if (
|
||||||
|
left < containerRect.x ||
|
||||||
|
left > containerRect.width + containerRect.x ||
|
||||||
|
top < containerRect.y ||
|
||||||
|
containerRect.y > containerRect.y + containerRect.height
|
||||||
|
) {
|
||||||
|
this.$message.warning("请把节点拖入到中间画布里");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
left = left - containerRect.x + efContainer.scrollLeft;
|
||||||
|
top = top - containerRect.y + efContainer.scrollTop;
|
||||||
|
// 居中
|
||||||
|
left -= 85;
|
||||||
|
top -= 16;
|
||||||
|
var nodeId = nodeMenu.table.nodeKey;
|
||||||
|
var nodeName = nodeMenu.table.nodeName;
|
||||||
|
let nodeExists =
|
||||||
|
_.findIndex(this.data.nodeList, function(o) {
|
||||||
|
return o.id == nodeId;
|
||||||
|
}) > -1;
|
||||||
|
if (nodeExists) {
|
||||||
|
this.$message.warning("当前表节点[" + nodeName + "]已经存在于画布中");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var node = {
|
||||||
|
nodeKey: nodeId,
|
||||||
|
nodeName: nodeName,
|
||||||
|
type: "task",
|
||||||
|
left: left + "px",
|
||||||
|
top: top + "px",
|
||||||
|
ico: nodeMenu.table.ico,
|
||||||
|
state: "success",
|
||||||
|
viewOnly: 1,
|
||||||
|
startNode: 0,
|
||||||
|
alia: nodeMenu.table.alia,
|
||||||
|
sourceId: nodeMenu.table.sourceId,
|
||||||
|
tableId: nodeMenu.table.tableId,
|
||||||
|
items: nodeMenu.columns
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* 这里可以进行业务判断、是否能够添加该节点
|
||||||
|
*/
|
||||||
|
//console.log(this.data)
|
||||||
|
this.data.nodeList.push(node);
|
||||||
|
this.$nextTick(function() {
|
||||||
|
let nodeItems = node.items;
|
||||||
|
if (node.viewOnly > 0) {
|
||||||
|
this.jsPlumb.draggable(node.nodeKey, {
|
||||||
|
containment: "parent",
|
||||||
|
stop: function(el) {
|
||||||
|
// 拖拽节点结束后的对调
|
||||||
|
//console.log("拖拽结束: ", el);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
for (var j = 0; j < nodeItems.length; j++) {
|
||||||
|
// 设置源点,可以拖出线连接其他节点
|
||||||
|
//let obj = lodash.merge(this.jsplumbSourceOptions, {});
|
||||||
|
this.jsPlumb.makeSource(nodeItems[j].itemId);
|
||||||
|
// 设置目标点,其他源点拖出的线可以连接该节点
|
||||||
|
this.jsPlumb.makeTarget(
|
||||||
|
nodeItems[j].itemId,
|
||||||
|
this.jsplumbTargetOptions
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 删除节点
|
||||||
|
* @param nodeId 被删除节点的ID
|
||||||
|
*/
|
||||||
|
deleteNode(nodeId) {
|
||||||
|
this.$confirm("确定要删除节点及有关的所有连线" + nodeId + "?", "提示", {
|
||||||
|
confirmButtonText: "确定",
|
||||||
|
cancelButtonText: "取消",
|
||||||
|
type: "warning",
|
||||||
|
closeOnClickModal: false
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
/**
|
||||||
|
* 这里需要进行业务判断,是否可以删除
|
||||||
|
*/
|
||||||
|
this.data.nodeList = this.data.nodeList.filter(function(node) {
|
||||||
|
if (node.nodeKey === nodeId) {
|
||||||
|
// 伪删除,将节点隐藏,否则会导致位置错位
|
||||||
|
// node.show = false
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
//删除和该节点有关的所有连线
|
||||||
|
let deleteArr = [];
|
||||||
|
this.data.lineList = this.data.lineList.filter(function(line) {
|
||||||
|
let fromArr = line.from.split("-");
|
||||||
|
let fromTablePrex = fromArr[0] + "-" + fromArr[1];
|
||||||
|
let toArr = line.to.split("-");
|
||||||
|
let toTablePrex = toArr[0] + "-" + toArr[1];
|
||||||
|
if (fromTablePrex === nodeId) {
|
||||||
|
deleteArr.push({ sourceId: line.from, targetId: line.to });
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (toTablePrex === nodeId) {
|
||||||
|
deleteArr.push({ sourceId: line.to, targetId: line.from });
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
this.$nextTick(function() {
|
||||||
|
for (let i = 0; i < deleteArr.length; i++) {
|
||||||
|
var conn = this.jsPlumb.getConnections({
|
||||||
|
source: deleteArr[i].sourceId,
|
||||||
|
target: deleteArr[i].targetId
|
||||||
|
})[0];
|
||||||
|
this.jsPlumb.deleteConnection(conn);
|
||||||
|
}
|
||||||
|
this.jsPlumb.removeAllEndpoints(nodeId);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(() => {});
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
clickNode(node) {
|
||||||
|
let nodeId = node.nodeKey;
|
||||||
|
this.activeElement.type = "node";
|
||||||
|
this.activeElement.nodeId = nodeId;
|
||||||
|
this.$refs.nodeForm.nodeInit(this.data, node);
|
||||||
|
},
|
||||||
|
// 是否具有该线
|
||||||
|
hasLine(from, to) {
|
||||||
|
for (var i = 0; i < this.data.lineList.length; i++) {
|
||||||
|
var line = this.data.lineList[i];
|
||||||
|
if (line.from === from && line.to === to) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
// 是否含有相反的线
|
||||||
|
hashOppositeLine(from, to) {
|
||||||
|
return this.hasLine(to, from);
|
||||||
|
},
|
||||||
|
// 是否是同表之间列连线
|
||||||
|
isSameTableLine(from, to) {
|
||||||
|
let fromArr = from.split("-");
|
||||||
|
let fromTablePrex = fromArr[0] + "-" + fromArr[1];
|
||||||
|
let toArr = to.split("-");
|
||||||
|
let toTablePrex = toArr[0] + "-" + toArr[1];
|
||||||
|
if (fromTablePrex === toTablePrex) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
// 两个表间只能连一根线
|
||||||
|
isMutilLine(from, to) {
|
||||||
|
let fromArr = from.split("-");
|
||||||
|
let fromTablePrex = fromArr[0] + "-" + fromArr[1];
|
||||||
|
let toArr = to.split("-");
|
||||||
|
let toTablePrex = toArr[0] + "-" + toArr[1];
|
||||||
|
let newLine = fromTablePrex + "_" + toTablePrex;
|
||||||
|
let newLine2 = toTablePrex + "_" + fromTablePrex;
|
||||||
|
for (var i = 0; i < this.data.lineList.length; i++) {
|
||||||
|
var line = this.data.lineList[i];
|
||||||
|
let existFromArr = line.from.split("-");
|
||||||
|
let existFromTablePrex = existFromArr[0] + "-" + existFromArr[1];
|
||||||
|
let existToArr = line.to.split("-");
|
||||||
|
let existToTablePrex = existToArr[0] + "-" + existToArr[1];
|
||||||
|
let oldLine = existFromTablePrex + "_" + existToTablePrex;
|
||||||
|
let oldLine2 = existToTablePrex + "_" + existFromTablePrex;
|
||||||
|
if (
|
||||||
|
oldLine === newLine ||
|
||||||
|
oldLine === newLine2 ||
|
||||||
|
oldLine2 === newLine ||
|
||||||
|
oldLine2 === newLine2
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
nodeRightMenu(nodeId, evt) {
|
||||||
|
this.menu.show = true;
|
||||||
|
this.menu.curNodeId = nodeId;
|
||||||
|
this.menu.left = evt.x + "px";
|
||||||
|
this.menu.top = evt.y + "px";
|
||||||
|
},
|
||||||
|
repaintEverything() {
|
||||||
|
this.jsPlumb.repaint();
|
||||||
|
},
|
||||||
|
// 流程数据信息
|
||||||
|
dataInfo() {
|
||||||
|
this.flowInfoVisible = true;
|
||||||
|
this.$nextTick(function() {
|
||||||
|
this.$refs.flowInfo.init();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// 加载流程图
|
||||||
|
dataReload(data) {
|
||||||
|
this.easyFlowVisible = false;
|
||||||
|
this.data.nodeList = [];
|
||||||
|
this.data.lineList = [];
|
||||||
|
this.$nextTick(() => {
|
||||||
|
data = lodash.cloneDeep(data);
|
||||||
|
this.easyFlowVisible = true;
|
||||||
|
this.data = data;
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.jsPlumb = jsPlumb.getInstance();
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.jsPlumbInit();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// 刷新数据
|
||||||
|
refreshData() {
|
||||||
|
//this.dataReload(getDataB());
|
||||||
|
},
|
||||||
|
zoomAdd() {
|
||||||
|
if (this.zoom >= 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.zoom = this.zoom + 0.1;
|
||||||
|
this.$refs.efContainer.style.transform = `scale(${this.zoom})`;
|
||||||
|
this.jsPlumb.setZoom(this.zoom);
|
||||||
|
},
|
||||||
|
zoomSub() {
|
||||||
|
if (this.zoom <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.zoom = this.zoom - 0.1;
|
||||||
|
this.$refs.efContainer.style.transform = `scale(${this.zoom})`;
|
||||||
|
this.jsPlumb.setZoom(this.zoom);
|
||||||
|
},
|
||||||
|
// 下载数据
|
||||||
|
downloadData() {
|
||||||
|
this.$confirm("确定要下载该流程数据吗?", "提示", {
|
||||||
|
confirmButtonText: "确定",
|
||||||
|
cancelButtonText: "取消",
|
||||||
|
type: "warning",
|
||||||
|
closeOnClickModal: false
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
var datastr =
|
||||||
|
"data:text/json;charset=utf-8," +
|
||||||
|
encodeURIComponent(JSON.stringify(this.data, null, "\t"));
|
||||||
|
var downloadAnchorNode = document.createElement("a");
|
||||||
|
downloadAnchorNode.setAttribute("href", datastr);
|
||||||
|
downloadAnchorNode.setAttribute("download", "data.json");
|
||||||
|
downloadAnchorNode.click();
|
||||||
|
downloadAnchorNode.remove();
|
||||||
|
this.$message.success("正在下载中,请稍后...");
|
||||||
|
})
|
||||||
|
.catch(() => {});
|
||||||
|
},
|
||||||
|
openHelp() {
|
||||||
|
this.flowHelpVisible = true;
|
||||||
|
this.$nextTick(function() {
|
||||||
|
this.$refs.flowHelp.init();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
/*画布容器*/
|
||||||
|
#efContainer {
|
||||||
|
position: relative;
|
||||||
|
overflow: scroll;
|
||||||
|
flex: 1;
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*顶部工具栏*/
|
||||||
|
.ef-tooltar {
|
||||||
|
padding-left: 10px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
height: 42px;
|
||||||
|
line-height: 42px;
|
||||||
|
z-index: 3;
|
||||||
|
border-bottom: 1px solid #dadce0;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.jtk-overlay {
|
||||||
|
cursor: pointer;
|
||||||
|
color: #4a4a4a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 连线中的label 样式*/
|
||||||
|
.jtk-overlay.flowLabel:not(.aLabel) {
|
||||||
|
padding: 4px 10px;
|
||||||
|
background-color: white;
|
||||||
|
color: #565758 !important;
|
||||||
|
border: 1px solid #e0e3e7;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
.ef-dot {
|
||||||
|
background-color: #1879ff;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ef-dot-hover {
|
||||||
|
background-color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ef-rectangle {
|
||||||
|
background-color: #1879ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ef-rectangle-hover {
|
||||||
|
background-color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ef-drop-hover {
|
||||||
|
border: 1px dashed #1879ff;
|
||||||
|
}
|
||||||
|
.el-tag + .el-tag {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
.button-new-tag {
|
||||||
|
margin-left: 10px;
|
||||||
|
height: 32px;
|
||||||
|
line-height: 30px;
|
||||||
|
padding-top: 0;
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
|
.input-new-tag {
|
||||||
|
width: 90px;
|
||||||
|
margin-left: 10px;
|
||||||
|
vertical-align: bottom;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
11252
src/views/icon/index.vue
Normal file
525
src/views/kgbuilder/components/kg_form.vue
Normal file
@ -0,0 +1,525 @@
|
|||||||
|
<template>
|
||||||
|
<el-drawer
|
||||||
|
ref="drawer"
|
||||||
|
title="编辑"
|
||||||
|
:with-header="false"
|
||||||
|
:visible.sync="drawerShow"
|
||||||
|
:direction="direction"
|
||||||
|
:append-to-body="true"
|
||||||
|
>
|
||||||
|
<!--导入-->
|
||||||
|
<div v-show="operate == 'import'" class="pd-20">
|
||||||
|
<el-form>
|
||||||
|
<el-form-item label="类型" label-width="120px">
|
||||||
|
<el-radio-group v-model="uploadParam.type">
|
||||||
|
<el-radio key="index-1" label="1">三元组</el-radio>
|
||||||
|
<el-radio key="index-2" label="2">单元格树</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<div v-if="uploadParam.type==1">
|
||||||
|
<div>导入csv或者excel,三元组结构:节点-节点-关系如果是csv,注意字符集为utf-8无bom格式<br/>【不会的用记事本打开,然后另存为,选择utf-8 无bom】)</div>
|
||||||
|
<el-carousel >
|
||||||
|
<el-carousel-item v-for="item in [require('@/assets/sanyuanzuimport1.png'),require('@/assets/sanyuanzuimport2.png')]" :key="item">
|
||||||
|
<img :src="item" />
|
||||||
|
</el-carousel-item>
|
||||||
|
</el-carousel>
|
||||||
|
</div>
|
||||||
|
<div v-else style="max-height:calc(100vh - 80px);over-flow-y:scroll">
|
||||||
|
<div>支持合并单元格,设置颜色,设置关系需在节点后以###拼接,只识别一组关系</div>
|
||||||
|
<el-carousel height="450px">
|
||||||
|
<el-carousel-item v-for="item in [require('@/assets/treeimport1.png'),require('@/assets/treeimport2.png')]" :key="item">
|
||||||
|
<img :src="item" style="height: 500px;"/>
|
||||||
|
</el-carousel-item>
|
||||||
|
</el-carousel>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="图谱领域" label-width="120px">
|
||||||
|
<el-input
|
||||||
|
style="width:100%"
|
||||||
|
v-model="uploadParam.domain"
|
||||||
|
placeholder="请输入内容"
|
||||||
|
>
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="选择文件" label-width="120px">
|
||||||
|
<el-upload
|
||||||
|
class=""
|
||||||
|
ref="uploadExcel"
|
||||||
|
:action="uploadGraphUrl"
|
||||||
|
accept=".csv,.xls,.xlsx"
|
||||||
|
:show-file-list="true"
|
||||||
|
:data="uploadParam"
|
||||||
|
:on-success="uploadExcelSuccess"
|
||||||
|
:auto-upload="false"
|
||||||
|
>
|
||||||
|
<el-button
|
||||||
|
slot="trigger"
|
||||||
|
class="btn-bo"
|
||||||
|
>
|
||||||
|
<i class="el-icon-upload"></i>
|
||||||
|
选择文件
|
||||||
|
</el-button>
|
||||||
|
</el-upload>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label-width="120px">
|
||||||
|
<el-button @click="resetSubmit">取 消</el-button>
|
||||||
|
<el-button type="primary" @click="submitUpload">确 定</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
<!--导出-->
|
||||||
|
<div v-show="operate == 'export'" class="pd-20">
|
||||||
|
<el-form>
|
||||||
|
<el-form-item label="图谱领域" label-width="120px">
|
||||||
|
<el-autocomplete
|
||||||
|
style="width:100%"
|
||||||
|
v-model="uploadParam.domain"
|
||||||
|
placeholder="请输入内容"
|
||||||
|
><!--:fetch-suggestions="querySearch"-->
|
||||||
|
</el-autocomplete>
|
||||||
|
</el-form-item>
|
||||||
|
<el-button type="primary" @click="exportCsv">确 定</el-button>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
<!--节点编辑-->
|
||||||
|
<div v-show="operate == 'nodeEdit'" class="pd-20">
|
||||||
|
<el-tabs
|
||||||
|
type="card"
|
||||||
|
tab-position="top"
|
||||||
|
v-model="propActiveName"
|
||||||
|
@tab-click="propHandleClick"
|
||||||
|
style="margin: 10px"
|
||||||
|
>
|
||||||
|
<el-tab-pane label="属性编辑" name="propEdit">
|
||||||
|
<el-form :model="graphData">
|
||||||
|
<el-form-item label="节点名称" label-width="120px">
|
||||||
|
<el-input v-model="graphData.name" style="width:324px"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="选择颜色" label-width="120px">
|
||||||
|
<el-color-picker
|
||||||
|
id="colorpicker"
|
||||||
|
v-model="graphData.color"
|
||||||
|
:predefine="predefineColors"
|
||||||
|
>
|
||||||
|
</el-color-picker>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="节点半径" label-width="120px">
|
||||||
|
<el-slider :min="25" v-model="graphData.r" style="width:324px"></el-slider>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane label="添加图片" name="propImage">
|
||||||
|
<el-form>
|
||||||
|
<el-form-item label="本地上传" label-width="120px">
|
||||||
|
<el-upload
|
||||||
|
class=""
|
||||||
|
name="file"
|
||||||
|
ref="upload"
|
||||||
|
:headers="uploadHeader"
|
||||||
|
:action="uploadFileUrl"
|
||||||
|
accept=".jpg,.png"
|
||||||
|
:multiple="false"
|
||||||
|
:show-file-list="false"
|
||||||
|
:data="uploadImageParam"
|
||||||
|
:before-upload="beforeUpload"
|
||||||
|
:on-success="uploadSuccess"
|
||||||
|
:auto-upload="true"
|
||||||
|
:limit="1"
|
||||||
|
>
|
||||||
|
<el-button slot="trigger" size="small" type="primary"
|
||||||
|
>选择</el-button
|
||||||
|
>
|
||||||
|
</el-upload>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="网络地址" label-width="120px">
|
||||||
|
<el-input v-model="netImageUrl" style="width: 60%"></el-input>
|
||||||
|
<a href="javascript:void(0)" @click="addNetImage" class="cg">
|
||||||
|
<i class="el-icon-plus"></i>
|
||||||
|
</a>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="已选图片" label-width="120px">
|
||||||
|
<ul class="el-upload-list el-upload-list--picture-card">
|
||||||
|
<li
|
||||||
|
v-for="item in nodeImageList"
|
||||||
|
class="el-upload-list__item is-success"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
:src="imageUrlFormat(item)"
|
||||||
|
alt=""
|
||||||
|
class="el-upload-list__item-thumbnail"
|
||||||
|
/>
|
||||||
|
<label class="el-upload-list__item-status-label">
|
||||||
|
<i class="el-icon-upload-success el-icon-check"></i>
|
||||||
|
</label>
|
||||||
|
<i class="el-icon-close" @click="imageHandleRemove(item)"></i>
|
||||||
|
<span class="el-upload-list__item-actions">
|
||||||
|
<span class="el-upload-list__item-preview">
|
||||||
|
<i
|
||||||
|
class="el-icon-zoom-in"
|
||||||
|
@click="handlePictureCardPreview(item)"
|
||||||
|
></i>
|
||||||
|
</span>
|
||||||
|
<span class="el-upload-list__item-delete">
|
||||||
|
<i
|
||||||
|
class="el-icon-delete"
|
||||||
|
@click="imageHandleRemove(item)"
|
||||||
|
></i>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane label="添加描述" name="richTextEdit">
|
||||||
|
<div
|
||||||
|
ref="editorToolbar"
|
||||||
|
class="wange-toolbar"
|
||||||
|
></div>
|
||||||
|
<div
|
||||||
|
ref="editorContent"
|
||||||
|
class="wangeditor-form"
|
||||||
|
></div>
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
<div slot="footer" class="dialog-footer">
|
||||||
|
<el-button
|
||||||
|
v-show="propActiveName == 'propImage'"
|
||||||
|
type="primary"
|
||||||
|
@click="saveNodeImage"
|
||||||
|
class="btn-line cur"
|
||||||
|
>保存</el-button
|
||||||
|
>
|
||||||
|
<el-button
|
||||||
|
v-show="propActiveName == 'richTextEdit'"
|
||||||
|
@click="saveNodeContent"
|
||||||
|
type="primary"
|
||||||
|
class="btn-line cur"
|
||||||
|
>保存</el-button
|
||||||
|
>
|
||||||
|
<el-button
|
||||||
|
v-show="propActiveName == 'propEdit' && graphData.uuid != 0"
|
||||||
|
type="primary"
|
||||||
|
@click="createNode"
|
||||||
|
>更新</el-button
|
||||||
|
>
|
||||||
|
<el-button
|
||||||
|
v-show="propActiveName == 'propEdit' && graphData.uuid == 0"
|
||||||
|
type="primary"
|
||||||
|
@click="createNode"
|
||||||
|
>创建</el-button
|
||||||
|
>
|
||||||
|
<el-button @click="resetSubmit">取消</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!--段落识别-->
|
||||||
|
<div v-show="operate == 'recognition'" class="pd-20">
|
||||||
|
<div class="mb-l">段落识别</div>
|
||||||
|
开发中。。。
|
||||||
|
</div>
|
||||||
|
<!--添加下级-->
|
||||||
|
<div v-show="operate == 'batchAddChild'" class="pd-20">
|
||||||
|
<div class="mb-l">添加下级</div>
|
||||||
|
<el-form ref="form" label-width="120px">
|
||||||
|
<el-form-item label="关系">
|
||||||
|
<el-input v-model="batchCreateData.relation"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="子节点名称">
|
||||||
|
<el-input v-model="batchCreateData.targetNodeNames"></el-input>
|
||||||
|
<span class="mb-label">(多个以英文逗号隔开)</span>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label-width="120px">
|
||||||
|
<el-button type="primary" @click="batchCreateChildNode">确定</el-button>
|
||||||
|
<el-button @click="resetSubmit">取消</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<!--批量添加-->
|
||||||
|
<div v-show="operate == 'batchAdd'">
|
||||||
|
<div class="mb-l">批量添加</div>
|
||||||
|
<el-form ref="form" label-width="120px">
|
||||||
|
<el-form-item label="源节点名称">
|
||||||
|
<el-input v-model="batchCreateData.sourceNodeName"></el-input>
|
||||||
|
<span class="mb-label">(只能添加一个)</span>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="关系">
|
||||||
|
<el-input v-model="batchCreateData.relation"></el-input>
|
||||||
|
<span class="mb-label">(只能添加一个)</span>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="子节点名称">
|
||||||
|
<el-input v-model="batchCreateData.targetNodeNames"></el-input>
|
||||||
|
<span class="mb-label">(多个以英文逗号隔开,可不填)</span>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label-width="120px">
|
||||||
|
<el-button type="primary" @click="batchCreateNode">确定</el-button>
|
||||||
|
<el-button @click="resetSubmit">取消</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!--添加同级-->
|
||||||
|
<div v-show="operate == 'batchAddSame'" class="pd-20">
|
||||||
|
<div class="mb-l">添加同级</div>
|
||||||
|
<el-form ref="form" label-width="120px">
|
||||||
|
<el-form-item label="源节点名称">
|
||||||
|
<el-input v-model="batchCreateData.sourceNodeName"></el-input>
|
||||||
|
<span class="mb-label">(多个以英文逗号隔开)</span>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label-width="120px">
|
||||||
|
<el-button type="primary" @click="batchCreateSameNode">确定</el-button>
|
||||||
|
<el-button @click="resetSubmit">取消</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</el-drawer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import wangEditor from 'wangeditor'
|
||||||
|
import { kgBuilderApi } from "@/api";
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
data: Object
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
domainId:0,
|
||||||
|
uploadHeader:{
|
||||||
|
// 'Content-Type': 'multipart/form-data'
|
||||||
|
},
|
||||||
|
uploadGraphUrl: process.env.VUE_APP_BASE_API+"/importGraph",
|
||||||
|
direction: "rtl",
|
||||||
|
drawerShow: false,
|
||||||
|
operate: "",
|
||||||
|
batchCreateData:{
|
||||||
|
sourceUuid:'',
|
||||||
|
sourceName: '',
|
||||||
|
targetNames: '',
|
||||||
|
relation: ''
|
||||||
|
},
|
||||||
|
propActiveName: "propEdit",
|
||||||
|
contentActiveName: "propImage",
|
||||||
|
uploadFileUrl: process.env.VUE_APP_BASE_API+"/file/upload",
|
||||||
|
graphData:{
|
||||||
|
uuid: '0',
|
||||||
|
color: "ff4500",
|
||||||
|
name: "",
|
||||||
|
r: 30,
|
||||||
|
x: "",
|
||||||
|
y: ""
|
||||||
|
},
|
||||||
|
predefineColors: [
|
||||||
|
"#ff4500",
|
||||||
|
"#ff8c00",
|
||||||
|
"#90ee90",
|
||||||
|
"#00ced1",
|
||||||
|
"#1e90ff",
|
||||||
|
"#c71585"
|
||||||
|
],
|
||||||
|
editorContent:"",
|
||||||
|
uploadImageParam: {},
|
||||||
|
nodeImageList: [],
|
||||||
|
netImageUrl: "",
|
||||||
|
uploadParam: { domain: "", type: '1' },
|
||||||
|
};
|
||||||
|
},
|
||||||
|
components: {},
|
||||||
|
methods: {
|
||||||
|
init(drawerShow,operate,domain) {
|
||||||
|
this.operate = operate;
|
||||||
|
this.drawerShow = drawerShow;
|
||||||
|
this.uploadParam.domain=domain;
|
||||||
|
this.propActiveName="propEdit";
|
||||||
|
},
|
||||||
|
initNode(drawerShow,operate,node,domainId) {
|
||||||
|
this.operate = operate;
|
||||||
|
this.drawerShow = drawerShow;
|
||||||
|
this.domainId=domainId;
|
||||||
|
this.graphData=node;
|
||||||
|
this.propActiveName="propEdit";
|
||||||
|
},
|
||||||
|
initBatchAddChild(drawerShow,operate,node,domain) {
|
||||||
|
this.operate = operate;
|
||||||
|
this.drawerShow = drawerShow;
|
||||||
|
this.domain=domain;
|
||||||
|
this.batchCreateData.sourceUuid=node.uuid;
|
||||||
|
this.propActiveName="propEdit";
|
||||||
|
},
|
||||||
|
batchCreateNode(){
|
||||||
|
this.init(false,"");
|
||||||
|
this.$emit("batchCreateNode",this.batchCreateData);
|
||||||
|
},
|
||||||
|
batchCreateChildNode(){
|
||||||
|
this.init(false,"");
|
||||||
|
this.$emit("batchCreateChildNode",this.batchCreateData);
|
||||||
|
},
|
||||||
|
batchCreateSameNode(){
|
||||||
|
this.init(false,"");
|
||||||
|
this.$emit("batchCreateSameNode",this.batchCreateData);
|
||||||
|
},
|
||||||
|
createNode(){
|
||||||
|
this.init(false,"");
|
||||||
|
this.$emit("createNode",this.graphData);
|
||||||
|
},
|
||||||
|
initImage(imageList){
|
||||||
|
this.nodeImageList=imageList;
|
||||||
|
},
|
||||||
|
initContent(content){
|
||||||
|
this.editorContent=content;
|
||||||
|
},
|
||||||
|
bthRecognition(){
|
||||||
|
|
||||||
|
},
|
||||||
|
resetSubmit() {
|
||||||
|
this.drawerShow=false;
|
||||||
|
this.propActiveName="propEdit"
|
||||||
|
},
|
||||||
|
//节点上传图片
|
||||||
|
saveNodeImage() {
|
||||||
|
let data = {
|
||||||
|
domainId: this.domainId,
|
||||||
|
nodeId: this.graphData.uuid,
|
||||||
|
//imageList: JSON.stringify(this.nodeImageList)
|
||||||
|
imagePath: this.nodeImageList[0].file
|
||||||
|
};
|
||||||
|
this.init(false,"");
|
||||||
|
this.$emit("saveNodeImage",data);
|
||||||
|
},
|
||||||
|
//上传富文本
|
||||||
|
saveNodeContent() {
|
||||||
|
let data = {
|
||||||
|
domainId: this.domainId,
|
||||||
|
nodeId: this.graphData.uuid,
|
||||||
|
content: this.editorContent
|
||||||
|
};
|
||||||
|
this.init(false,"");
|
||||||
|
this.$emit("saveNodeContent",data);
|
||||||
|
},
|
||||||
|
//预览图片
|
||||||
|
handlePictureCardPreview(item) {
|
||||||
|
this.dialogImageUrl = this.imageUrlFormat(item);
|
||||||
|
this.dialogImageVisible = true;
|
||||||
|
},
|
||||||
|
//添加网络图片
|
||||||
|
addNetImage() {
|
||||||
|
if (this.netImageUrl != "") {
|
||||||
|
if(this.nodeImageList.length==0){
|
||||||
|
this.nodeImageList.push({ file: this.netImageUrl, imageType: 1 });
|
||||||
|
this.netImageUrl = "";
|
||||||
|
}else{
|
||||||
|
this.$message({
|
||||||
|
message: '一个节点只能使用一张图片,如果有多张图片,可以添加到富文本中',
|
||||||
|
type: 'warning'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
//移除图片
|
||||||
|
imageHandleRemove(url) {
|
||||||
|
this.nodeImageList.splice(this.nodeImageList.indexOf(url), 1);
|
||||||
|
},
|
||||||
|
//图片格式化
|
||||||
|
imageUrlFormat(item) {
|
||||||
|
if(item.file.indexOf("http")===0){
|
||||||
|
return item.file;
|
||||||
|
}else{
|
||||||
|
return process.env.VUE_APP_BASE_API+item.file;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
beforeUpload(){
|
||||||
|
if(this.nodeImageList.length>0){
|
||||||
|
this.$message({
|
||||||
|
message: '一个节点只能使用一张图片,如果有多张图片,可以添加到富文本中',
|
||||||
|
type: 'warning'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
uploadSuccess(res, file) {
|
||||||
|
if (res.success == 1) {
|
||||||
|
for (let i = 0; i < res.results.length; i++) {
|
||||||
|
let fileItem = res.results[i];
|
||||||
|
if(this.nodeImageList.length==0){
|
||||||
|
this.nodeImageList.push({ file: fileItem.url, imageType: 0 });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.$message.error(res.msg);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
initEditor() {
|
||||||
|
if (this.editor != null) return;
|
||||||
|
let _this=this;
|
||||||
|
this.editor = new wangEditor(this.$refs.editorToolbar, this.$refs.editorContent)
|
||||||
|
this.editor.config.onchange = function(html) {
|
||||||
|
_this.editorContent = html;
|
||||||
|
};
|
||||||
|
this.editor.config.uploadFileName = "file";
|
||||||
|
//this.editor.config.uploadImgHeaders = headers;
|
||||||
|
this.editor.config.uploadImgServer = process.env.VUE_APP_BASE_API+"/file/upload"; // 上传图片到服务器
|
||||||
|
this.editor.config.uploadImgHooks = {
|
||||||
|
// 如果服务器端返回的不是 {errno:0, data: [...]} 这种格式,可使用该配置
|
||||||
|
// (但是,服务器端返回的必须是一个 JSON 格式字符串!!!否则会报错)
|
||||||
|
customInsert: function(insertImg, res, editor) {
|
||||||
|
// 图片上传并返回结果,自定义插入图片的事件(而不是编辑器自动插入图片!!!)
|
||||||
|
// insertImg 是插入图片的函数,editor 是编辑器对象,result 是服务器端返回的结果
|
||||||
|
for (let i = 0; i < res.results.length; i++) {
|
||||||
|
let fileItem = res.results[i];
|
||||||
|
insertImg(process.env.VUE_APP_BASE_API+fileItem.url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.editor.create();
|
||||||
|
},
|
||||||
|
propHandleClick(tab) {
|
||||||
|
if (tab.name == "richTextEdit") {
|
||||||
|
this.initEditor();
|
||||||
|
this.editorContent = "";
|
||||||
|
this.$emit("initNodeContent",{domainId:this.domainId,nodeId:this.graphData.uuid});
|
||||||
|
|
||||||
|
}
|
||||||
|
if (tab.name == "propImage") {
|
||||||
|
this.nodeImageList = [];
|
||||||
|
this.$emit("initNodeImage",{domainId:this.domainId,nodeId:this.graphData.uuid});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
exportCsv() {
|
||||||
|
let data = { domain: this.uploadParam.domain };
|
||||||
|
kgBuilderApi.exportGraph(data).then(result => {
|
||||||
|
if (result.code == 200) {
|
||||||
|
this.exportFormVisible = false;
|
||||||
|
window.open(process.env.VUE_APP_BASE_API+result.csvUrl);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
submitUpload() {
|
||||||
|
this.$refs.uploadExcel.submit();
|
||||||
|
//关闭窗口
|
||||||
|
this.init(false,"");
|
||||||
|
//刷新领域标签
|
||||||
|
this.$emit("getDomain",1);
|
||||||
|
},
|
||||||
|
uploadExcelSuccess() {
|
||||||
|
this.$refs.uploadExcel.clearFiles();
|
||||||
|
this.uploadParam.domain = "";
|
||||||
|
this.$message({
|
||||||
|
message: "操作成功",
|
||||||
|
type: "success"
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
.pd-20{
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
.el-drawer__body {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
131
src/views/kgbuilder/components/kg_help.vue
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog
|
||||||
|
title="帮助"
|
||||||
|
:visible.sync="dialogVisible"
|
||||||
|
width="70%"
|
||||||
|
customClass="flowHelp"
|
||||||
|
>
|
||||||
|
<el-tabs tab-position="left">
|
||||||
|
<el-tab-pane label="基本功能">
|
||||||
|
<el-divider content-position="left">基本功能</el-divider>
|
||||||
|
<div>1. 新增节点,添加连线,快速添加节点和关系</div>
|
||||||
|
<div>2. 节点的颜色和大小可修改</div>
|
||||||
|
<div>3. 节点和关系的编辑,删除</div>
|
||||||
|
<div>4. 导出成图片</div>
|
||||||
|
<div>5. csv导入三元组、excel导入单元格树</div>
|
||||||
|
<div>6. 导出csv</div>
|
||||||
|
<div>7. 添加图片和富文本</div>
|
||||||
|
<div>8. 节点之间多个关系</div>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane label="运行与启动">
|
||||||
|
<el-divider content-position="left">安装jdk</el-divider>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
可参考:https://blog.csdn.net/qq_42003566/article/details/82629570
|
||||||
|
</div>
|
||||||
|
<el-divider content-position="left">安装Neo4j</el-divider>
|
||||||
|
<div>
|
||||||
|
可参考:[https://www.cnblogs.com/ljhdo/p/5521577.html](https://www.cnblogs.com/ljhdo/p/5521577.html),注意开放外网访问
|
||||||
|
0.0.0.0
|
||||||
|
</div>
|
||||||
|
<el-divider content-position="left">IDEA 导入项目</el-divider>
|
||||||
|
<div>
|
||||||
|
导入成功后对着项目根目录,右键->maven->reimport,等待其执行完成
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
倘若下载jar包太慢,自己配置外部maven仓库https://blog.csdn.net/liu_shi_jun/article/details/78733633
|
||||||
|
以上配置在linux下配置自行百度
|
||||||
|
</div>
|
||||||
|
<el-divider content-position="left">配置参数</el-divider>
|
||||||
|
<div>找到目录 src/main/resources</div>
|
||||||
|
<div>
|
||||||
|
修改application.yml,neo4j配置url,password,改成自己的,同理修改mysql(mysql脚本在根目录下,kg_builder.sql)
|
||||||
|
</div>
|
||||||
|
<el-divider content-position="left">后台打包发布</el-divider>
|
||||||
|
<div>
|
||||||
|
在idea 右侧 有 maven project
|
||||||
|
工具栏,点击展开lifecycle-clean,然后install,等待完成后在控制台可以看见打包的目录,
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
例如:[INFO] Installing
|
||||||
|
F:\git\Neo4j\kgmaker\target\kgmaker-0.0.1-SNAPSHOT.jar
|
||||||
|
复制jar包,去windows 或者linux下 切换到jar包目录执行 jar包 java -jar
|
||||||
|
xxx.jar 即可启动,想部署到tomcat自行百度,springboot配置外部tomcat
|
||||||
|
</div>
|
||||||
|
<el-divider content-position="left">启动前端</el-divider>
|
||||||
|
<div>没有前端基础的小伙伴,先自行百度安装nodejs,npm等环境</div>
|
||||||
|
<div>1.npm install // 安装依赖</div>
|
||||||
|
<div>2.npm run serve //启动</div>
|
||||||
|
<div>3.npm run build //发布</div>
|
||||||
|
<div>启动后访问http://localhost</div>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane label="注意事项">
|
||||||
|
<el-divider content-position="left">图谱三元组导入</el-divider>
|
||||||
|
<div>
|
||||||
|
支持,.xlsx,.xls,.csv,编码格式一定要是utf-8
|
||||||
|
无bom格式的,格式:节点-节点-关系,在本地测试时上传下载的文件要和neo4j在同一台电脑,当然如果能传到七牛或者hdfs上也是一样的,必须确认neo4j能访问到,否则load不成功
|
||||||
|
</div>
|
||||||
|
<el-divider content-position="left">图数据库版本与驱动</el-divider>
|
||||||
|
<div>本项目适用Neo4j版本3.x版本,对应驱动是1.7.5</div>
|
||||||
|
<div>4.x版本,需要升级驱动,对应的utils也需要升级,自行扩展</div>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane label="推荐">
|
||||||
|
<el-divider content-position="left">图数据库</el-divider>
|
||||||
|
<div>
|
||||||
|
由于neo4j集群等功能需要付费使用,囊中羞涩的可以换成Nebula,国产的,性能贼棒,集群开源版也开放
|
||||||
|
<a href="https://docs.nebula-graph.com.cn"
|
||||||
|
>Nebula https://docs.nebula-graph.com.cn</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<el-divider content-position="left">前端可视化</el-divider>
|
||||||
|
<div>
|
||||||
|
由于d3.js的文档和api开放度足够高,推荐组件化做的比较好的前端库G6
|
||||||
|
<a href="https://docs.nebula-graph.com.cn"
|
||||||
|
>G6 https://g6.antv.vision/zh/examples/gallery</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane label="源码下载">
|
||||||
|
<el-divider content-position="left">github</el-divider>
|
||||||
|
<div>
|
||||||
|
<a href="https://github.com/MiracleTanC/Neo4j-KGBuilder"
|
||||||
|
>https://github.com/MiracleTanC/Neo4j-KGBuilder</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<el-divider content-position="left">gitee</el-divider>
|
||||||
|
<div>
|
||||||
|
<a href="https://gitee.com/MiraculousWarmHeart/Neo4j"
|
||||||
|
>https://gitee.com/MiraculousWarmHeart/Neo4j</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<el-divider content-position="left">分支差异</el-divider>
|
||||||
|
<div>
|
||||||
|
master分支不是前后端分离版本,springboot+thymleaf+vue,嵌入式太深
|
||||||
|
</div>
|
||||||
|
<div>dev分支是前后端分离版本springboot+vue,前端组件化</div>
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
dialogVisible: false
|
||||||
|
};
|
||||||
|
},
|
||||||
|
components: {},
|
||||||
|
methods: {
|
||||||
|
init() {
|
||||||
|
this.dialogVisible = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.flowHelp {
|
||||||
|
height: 80%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
60
src/views/kgbuilder/components/kg_json.vue
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog title="数据信息" :visible.sync="dialogVisible" width="70%">
|
||||||
|
<el-alert
|
||||||
|
title="使用说明"
|
||||||
|
type="warning"
|
||||||
|
description="以下图谱信息可以被存储起来,方便下一次数据加载"
|
||||||
|
show-icon
|
||||||
|
close-text="知道了"
|
||||||
|
>
|
||||||
|
</el-alert>
|
||||||
|
<br />
|
||||||
|
<!--一个高亮显示的插件-->
|
||||||
|
<codemirror
|
||||||
|
:value="flowJsonData"
|
||||||
|
:options="options"
|
||||||
|
class="code"
|
||||||
|
></codemirror>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import "codemirror/lib/codemirror.css";
|
||||||
|
import { codemirror } from "vue-codemirror";
|
||||||
|
|
||||||
|
require("codemirror/mode/javascript/javascript.js");
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
data: Object
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
dialogVisible: false,
|
||||||
|
flowJsonData: {},
|
||||||
|
options: {
|
||||||
|
mode: { name: "javascript", json: true },
|
||||||
|
lineNumbers: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
codemirror
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
init() {
|
||||||
|
this.dialogVisible = true;
|
||||||
|
this.flowJsonData = JSON.stringify(this.data, null, 4).toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
.el-dialog__body {
|
||||||
|
padding: 30px 20px;
|
||||||
|
color: #606266;
|
||||||
|
font-size: 14px;
|
||||||
|
word-break: break-all;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
69
src/views/kgbuilder/components/menu_blank.vue
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
<template>
|
||||||
|
<!-- 空白处右键 -->
|
||||||
|
<ul
|
||||||
|
class="el-dropdown-menu el-popper blankmenubar"
|
||||||
|
@click="menuBarClick"
|
||||||
|
:style="blankMenuStyle"
|
||||||
|
@mouseleave="menuBarLeave"
|
||||||
|
id="blank_menubar"
|
||||||
|
v-show="menuBarShow"
|
||||||
|
>
|
||||||
|
<li class="el-dropdown-menu__item" @click="btnAddSingle">
|
||||||
|
<svg class="icon" aria-hidden="true">
|
||||||
|
<use xlink:href="#icon-jiedian"></use>
|
||||||
|
</svg>
|
||||||
|
<span class="pl-15">添加节点</span>
|
||||||
|
</li>
|
||||||
|
<li class="el-dropdown-menu__item" @click="btnQuickAddNode">
|
||||||
|
<svg class="icon" aria-hidden="true">
|
||||||
|
<use xlink:href="#icon-add-rd"></use>
|
||||||
|
</svg>
|
||||||
|
<span class="pl-15">快速添加</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
data: Object
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
top: "0px",
|
||||||
|
left: "0px",
|
||||||
|
menuBarShow: false
|
||||||
|
};
|
||||||
|
},
|
||||||
|
components: {},
|
||||||
|
computed: {
|
||||||
|
blankMenuStyle() {
|
||||||
|
return {
|
||||||
|
position: "absolute",
|
||||||
|
top: this.top+'px',
|
||||||
|
left: this.left+'px'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
init(data) {
|
||||||
|
this.top = data.top;
|
||||||
|
this.left = data.left;
|
||||||
|
this.menuBarShow = data.show;
|
||||||
|
},
|
||||||
|
btnAddSingle() {
|
||||||
|
this.$emit("btnAddSingle");
|
||||||
|
},
|
||||||
|
btnQuickAddNode() {
|
||||||
|
this.$emit("btnQuickAddNode");
|
||||||
|
},
|
||||||
|
menuBarClick() {
|
||||||
|
this.menuBarShow=false;
|
||||||
|
},
|
||||||
|
menuBarLeave() {
|
||||||
|
this.menuBarShow=false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style></style>
|
||||||
74
src/views/kgbuilder/components/menu_link.vue
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
<template>
|
||||||
|
<!-- 连线按钮组 -->
|
||||||
|
<ul
|
||||||
|
class="el-dropdown-menu el-popper linkmenubar"
|
||||||
|
id="link_menubar2"
|
||||||
|
:style="linuMenuStyle"
|
||||||
|
@mouseleave="linkMenuBarLeave"
|
||||||
|
v-show="linkMenuShow"
|
||||||
|
>
|
||||||
|
<li class="el-dropdown-menu__item" @click="updateLinkName">
|
||||||
|
<svg class="icon" aria-hidden="true">
|
||||||
|
<use xlink:href="#icon-editor"></use>
|
||||||
|
</svg>
|
||||||
|
<span class="pl-15">编辑</span>
|
||||||
|
</li>
|
||||||
|
<li class="el-dropdown-menu__item" @click="deleteLink">
|
||||||
|
<svg class="icon" aria-hidden="true">
|
||||||
|
<use xlink:href="#icon-shanchu"></use>
|
||||||
|
</svg>
|
||||||
|
<span class="pl-15">删除</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// import * as d3 from "d3";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
top: '0px',
|
||||||
|
left: '0px',
|
||||||
|
linkMenuShow: false
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
linuMenuStyle() {
|
||||||
|
return {
|
||||||
|
position:'absolute',
|
||||||
|
top: this.top+ "px",
|
||||||
|
left: this.left+ "px"
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
init(data) {
|
||||||
|
//debugger
|
||||||
|
this.top=data.top;
|
||||||
|
this.left=data.left;
|
||||||
|
this.linkMenuShow=data.show;
|
||||||
|
|
||||||
|
},
|
||||||
|
updateLinkName(){
|
||||||
|
this.$emit("updateLinkName");
|
||||||
|
},
|
||||||
|
deleteLink(){
|
||||||
|
this.$emit("deleteLink");
|
||||||
|
},
|
||||||
|
linkMenuBarLeave() {
|
||||||
|
//d3.select(this).style("display", "none");
|
||||||
|
this.linkMenuShow=false;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
|
||||||
|
</style>
|
||||||
60
src/views/kgbuilder/components/node_info.vue
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog title="数据信息" :visible.sync="dialogVisible" width="70%">
|
||||||
|
<el-alert
|
||||||
|
title="使用说明"
|
||||||
|
type="warning"
|
||||||
|
description="以下流程信息可以被存储起来,方便下一次流程加载"
|
||||||
|
show-icon
|
||||||
|
close-text="知道了"
|
||||||
|
>
|
||||||
|
</el-alert>
|
||||||
|
<br />
|
||||||
|
<!--一个高亮显示的插件-->
|
||||||
|
<codemirror
|
||||||
|
:value="flowJsonData"
|
||||||
|
:options="options"
|
||||||
|
class="code"
|
||||||
|
></codemirror>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import "codemirror/lib/codemirror.css";
|
||||||
|
import { codemirror } from "vue-codemirror";
|
||||||
|
|
||||||
|
require("codemirror/mode/javascript/javascript.js");
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
data: Object
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
dialogVisible: false,
|
||||||
|
flowJsonData: {},
|
||||||
|
options: {
|
||||||
|
mode: { name: "javascript", json: true },
|
||||||
|
lineNumbers: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
codemirror
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
init() {
|
||||||
|
this.dialogVisible = true;
|
||||||
|
this.flowJsonData = JSON.stringify(this.data, null, 4).toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
.el-dialog__body {
|
||||||
|
padding: 30px 20px;
|
||||||
|
color: #606266;
|
||||||
|
font-size: 14px;
|
||||||
|
word-break: break-all;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
73
src/views/kgbuilder/components/node_richer.vue
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
<template>
|
||||||
|
<div id="richContainer" :style="richerStyle" v-show="richerShow">
|
||||||
|
<!-- <div
|
||||||
|
class="mind-fj-box"
|
||||||
|
v-show="showImageList.length > 0 || editorContent != ''"
|
||||||
|
>
|
||||||
|
<div class="mind-carousel" v-show="showImageList.length > 0">
|
||||||
|
<el-carousel height="197px" :interval="2000" arrow="always">
|
||||||
|
<el-carousel-item v-for="item in showImageList" :key="item.ID">
|
||||||
|
<div class="carous-img">
|
||||||
|
<img :src="item.fileName" alt="" />
|
||||||
|
</div>
|
||||||
|
</el-carousel-item>
|
||||||
|
</el-carousel>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div> -->
|
||||||
|
<el-scrollbar v-show="editorContent != ''" class="mind-fj-p">
|
||||||
|
<p v-html="editorContent"></p>
|
||||||
|
</el-scrollbar>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import E from "wangeditor"
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
data: Object
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
richerShow:false,
|
||||||
|
left:'-1000px',
|
||||||
|
top:'-1000px',
|
||||||
|
editor: null,
|
||||||
|
editorContent:'',
|
||||||
|
showImageList:[],
|
||||||
|
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
richerStyle() {
|
||||||
|
return {
|
||||||
|
width: '400px',
|
||||||
|
position: "absolute",
|
||||||
|
top: this.top+'px',
|
||||||
|
left: this.left+'px'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted(){
|
||||||
|
|
||||||
|
} ,
|
||||||
|
components: {
|
||||||
|
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
init(content,imageList,left,top){
|
||||||
|
this.richerShow=true;
|
||||||
|
this.left=left;
|
||||||
|
this.top=top;
|
||||||
|
this.editorContent=content;
|
||||||
|
this.showImageList=imageList;
|
||||||
|
},
|
||||||
|
close(){
|
||||||
|
this.richerShow=false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
|
||||||
|
</style>
|
||||||
2046
src/views/kgbuilder/index.vue
Normal file
1677
src/views/kgbuilder/index_v1.vue
Normal file
125
vue.config.js
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
"use strict";
|
||||||
|
const path = require("path");
|
||||||
|
const webpack = require("webpack");
|
||||||
|
const defaultSettings = require("./src/settings.js");
|
||||||
|
|
||||||
|
function resolve(dir) {
|
||||||
|
return path.join(__dirname, dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
const name = defaultSettings.title || "暖暖动听"; // 标题
|
||||||
|
|
||||||
|
const port = process.env.port || process.env.npm_config_port || 80; // 端口
|
||||||
|
|
||||||
|
// vue.config.js 配置说明
|
||||||
|
//官方vue.config.js 参考文档 https://cli.vuejs.org/zh/config/#css-loaderoptions
|
||||||
|
// 这里只列一部分,具体配置参考文档
|
||||||
|
module.exports = {
|
||||||
|
// 部署生产环境和开发环境下的URL。
|
||||||
|
// 默认情况下,Vue CLI 会假设你的应用是被部署在一个域名的根路径上
|
||||||
|
// 例如 https://www.dream.vip/。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 https://www.dream.vip/admin/,则设置 baseUrl 为 /admin/。
|
||||||
|
publicPath: process.env.NODE_ENV === "production" ? "/" : "/",
|
||||||
|
// 在npm run build 或 yarn build 时 ,生成文件的目录名称(要和baseUrl的生产环境路径一致)(默认dist)
|
||||||
|
outputDir: "dist",
|
||||||
|
// 用于放置生成的静态资源 (js、css、img、fonts) 的;(项目打包之后,静态资源会放在这个文件夹下)
|
||||||
|
assetsDir: "static",
|
||||||
|
// 是否开启eslint保存检测,有效值:ture | false | 'error'
|
||||||
|
lintOnSave: process.env.NODE_ENV === "development",
|
||||||
|
// 如果你不需要生产环境的 source map,可以将其设置为 false 以加速生产环境构建。
|
||||||
|
productionSourceMap: false,
|
||||||
|
// webpack-dev-server 相关配置
|
||||||
|
devServer: {
|
||||||
|
host: "0.0.0.0",
|
||||||
|
port: port,
|
||||||
|
open: true,
|
||||||
|
proxy: {
|
||||||
|
// detail: https://cli.vuejs.org/config/#devserver-proxy
|
||||||
|
[process.env.VUE_APP_BASE_API]: {
|
||||||
|
target: `http://localhost:8080`,
|
||||||
|
changeOrigin: true,
|
||||||
|
pathRewrite: {
|
||||||
|
["^" + process.env.VUE_APP_BASE_API]: ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
disableHostCheck: true
|
||||||
|
},
|
||||||
|
configureWebpack: {
|
||||||
|
name: name,
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
"@": resolve("src")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
chainWebpack(config) {
|
||||||
|
config.plugin("provide").use(webpack.ProvidePlugin, [
|
||||||
|
{
|
||||||
|
$: "jquery",
|
||||||
|
jQuery: "jquery",
|
||||||
|
jquery: "jquery",
|
||||||
|
"window.jQuery": "jquery"
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
config.plugins.delete("preload"); // TODO: need test
|
||||||
|
config.plugins.delete("prefetch"); // TODO: need test
|
||||||
|
|
||||||
|
// set svg-sprite-loader
|
||||||
|
config.module
|
||||||
|
.rule("svg")
|
||||||
|
.exclude.add(resolve("src/assets/icons"))
|
||||||
|
.end();
|
||||||
|
config.module
|
||||||
|
.rule("icons")
|
||||||
|
.test(/\.svg$/)
|
||||||
|
.include.add(resolve("src/assets/icons"))
|
||||||
|
.end()
|
||||||
|
.use("svg-sprite-loader")
|
||||||
|
.loader("svg-sprite-loader")
|
||||||
|
.options({
|
||||||
|
symbolId: "icon-[name]"
|
||||||
|
})
|
||||||
|
.end();
|
||||||
|
|
||||||
|
config.when(process.env.NODE_ENV !== "development", config => {
|
||||||
|
config
|
||||||
|
.plugin("ScriptExtHtmlWebpackPlugin")
|
||||||
|
.after("html")
|
||||||
|
.use("script-ext-html-webpack-plugin", [
|
||||||
|
{
|
||||||
|
// `runtime` must same as runtimeChunk name. default is `runtime`
|
||||||
|
inline: /runtime\..*\.js$/
|
||||||
|
}
|
||||||
|
])
|
||||||
|
.end();
|
||||||
|
config.optimization.splitChunks({
|
||||||
|
chunks: "all",
|
||||||
|
cacheGroups: {
|
||||||
|
libs: {
|
||||||
|
name: "chunk-libs",
|
||||||
|
test: /[\\/]node_modules[\\/]/,
|
||||||
|
priority: 10,
|
||||||
|
chunks: "initial" // only package third parties that are initially dependent
|
||||||
|
},
|
||||||
|
elementUI: {
|
||||||
|
name: "chunk-elementUI", // split elementUI into a single package
|
||||||
|
priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
|
||||||
|
test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm
|
||||||
|
},
|
||||||
|
commons: {
|
||||||
|
name: "chunk-commons",
|
||||||
|
test: resolve("src/components"), // can customize your rules
|
||||||
|
minChunks: 3, // minimum common number
|
||||||
|
priority: 5,
|
||||||
|
reuseExistingChunk: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
config.optimization.runtimeChunk("single"),
|
||||||
|
{
|
||||||
|
from: path.resolve(__dirname, "./public/robots.txt"), //防爬虫文件
|
||||||
|
to: "./" //到根目录下
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||