@ -0,0 +1,27 @@ |
|||||||
|
{ |
||||||
|
"presets": [ |
||||||
|
["env", { |
||||||
|
"loose": true, |
||||||
|
"debug": false, |
||||||
|
"useBuiltIns": true, |
||||||
|
"targets": { |
||||||
|
"browsers": [ "ie > 8", "last 2 version", "safari >= 9" ] |
||||||
|
}, |
||||||
|
"production": { |
||||||
|
"plugins": ["transform-remove-console"] |
||||||
|
} |
||||||
|
}] |
||||||
|
], |
||||||
|
"plugins": [ |
||||||
|
[ "transform-runtime", { |
||||||
|
"helpers": false, |
||||||
|
"polyfill": false, |
||||||
|
"regenerator": true } ], |
||||||
|
[ "transform-class-properties", { "spec": true } ], |
||||||
|
[ "transform-object-rest-spread", { "useBuiltIns": true } ], |
||||||
|
[ "transform-vue-jsx" ], |
||||||
|
[ "syntax-dynamic-import" ] |
||||||
|
], |
||||||
|
"comments": false |
||||||
|
} |
||||||
|
|
@ -0,0 +1,21 @@ |
|||||||
|
# editorconfig.org |
||||||
|
# author: axin |
||||||
|
root = true |
||||||
|
|
||||||
|
[*] |
||||||
|
indent_style = space |
||||||
|
indent_size = 2 |
||||||
|
end_of_line = lf |
||||||
|
charset = utf-8 |
||||||
|
trim_trailing_whitespace = true |
||||||
|
insert_final_newline = true |
||||||
|
|
||||||
|
[*.py] |
||||||
|
indent_style = space |
||||||
|
indent_size = 4 |
||||||
|
|
||||||
|
[*.md] |
||||||
|
trim_trailing_whitespace = false |
||||||
|
|
||||||
|
[COMMIT_EDITMSG] |
||||||
|
max_line_length = 80 |
@ -0,0 +1,6 @@ |
|||||||
|
|
||||||
|
# 后端接口地址 |
||||||
|
API_BASE = http://192.168.xx.xx:12345 |
||||||
|
|
||||||
|
# 本地开发如需ip访问项目把"#"号去掉 |
||||||
|
#DEV_HOST = 192.168.xx.xx |
@ -0,0 +1,6 @@ |
|||||||
|
globals: |
||||||
|
$: true |
||||||
|
expect: true |
||||||
|
rules: |
||||||
|
"no-new": "off" |
||||||
|
"no-labels": [2, {"allowLoop": true}] |
@ -0,0 +1,115 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
var fs = require('fs') |
||||||
|
var path = require('path') |
||||||
|
var request = require('request') |
||||||
|
var cdnUrl = 'https://s1.analysys.cn/libs/??' |
||||||
|
var version = '1.0.0' |
||||||
|
|
||||||
|
// js集合
|
||||||
|
var jslibs = { |
||||||
|
'es5': [ |
||||||
|
'es5-shim/4.5.7/es5-shim.min.js', |
||||||
|
'es5-shim/4.5.7/es5-sham.min.js' |
||||||
|
], |
||||||
|
'3rd': [ |
||||||
|
'vue/2.5.2/vue.js', |
||||||
|
'vue-router/2.7.0/vue-router.min.js', |
||||||
|
'vuex/3.0.0/vuex.min.js', |
||||||
|
'jquery/3.3.1/jquery.min.js', |
||||||
|
'lodash.js/4.17.5/lodash.min.js', |
||||||
|
'jqueryui/1.12.1/jquery-ui.min.js', |
||||||
|
'twitter-bootstrap/3.3.7/js/bootstrap.min.js', |
||||||
|
'jsPlumb/2.8.5/js/jsplumb.min.js', |
||||||
|
'clipboard.js/2.0.1/clipboard.min.js', |
||||||
|
'd3/3.3.6/d3.min.js', |
||||||
|
'echarts/4.1.0/echarts.min.js', |
||||||
|
'dayjs/1.7.8/dayjs.min.js', |
||||||
|
'codemirror/5.43.0/codemirror.min.js', |
||||||
|
'codemirror/5.43.0/mode/sql/sql.min.js', |
||||||
|
'codemirror/5.43.0/addon/hint/show-hint.min.js', |
||||||
|
'codemirror/5.43.0/addon/hint/sql-hint.min.js', |
||||||
|
'codemirror/5.43.0/mode/textile/textile.min.js', |
||||||
|
'codemirror/5.43.0/mode/shell/shell.min.js', |
||||||
|
'codemirror/5.43.0/mode/python/python.min.js', |
||||||
|
'codemirror/5.43.0/addon/hint/xml-hint.min.js', |
||||||
|
'codemirror/5.43.0/mode/xml/xml.min.js', |
||||||
|
'html2canvas/0.5.0-beta4/html2canvas.min.js', |
||||||
|
'canvg/1.5/canvg.min.js' |
||||||
|
], |
||||||
|
'local': [] |
||||||
|
} |
||||||
|
|
||||||
|
// css集合
|
||||||
|
csslibs = { |
||||||
|
'base': [ |
||||||
|
'normalize/7.0.0/normalize.min.css', |
||||||
|
'twitter-bootstrap/3.3.7/css/bootstrap.min.css', |
||||||
|
'-/@analysys/reset.css@1.0.1', |
||||||
|
'-/@vue/animate.css@' |
||||||
|
], |
||||||
|
'3rd': [ |
||||||
|
'highlight.js/9.13.1/styles/vs.min.css', |
||||||
|
'jsPlumb/2.8.5/css/jsplumbtoolkit-defaults.min.css', |
||||||
|
'codemirror/5.43.0/codemirror.min.css', |
||||||
|
'codemirror/5.20.0/theme/mdn-like.min.css', |
||||||
|
'codemirror/5.43.0/addon/hint/show-hint.min.css' |
||||||
|
] |
||||||
|
} |
||||||
|
|
||||||
|
// 创建文件夹目录
|
||||||
|
var dirPath = path.resolve(__dirname, '..', 'src/combo/' + version) |
||||||
|
|
||||||
|
if (!fs.existsSync(dirPath)) { |
||||||
|
fs.mkdirSync(dirPath) |
||||||
|
console.log('文件夹创建成功') |
||||||
|
} else { |
||||||
|
console.log('文件夹已存在') |
||||||
|
} |
||||||
|
|
||||||
|
var jsKeys = Object.keys(jslibs) |
||||||
|
var jsUrl = jsKeys.map(v => { |
||||||
|
return jslibs[v].join() |
||||||
|
}) |
||||||
|
|
||||||
|
jsUrl.forEach((v, i) => { |
||||||
|
var url = cdnUrl + v |
||||||
|
console.log(url) |
||||||
|
var stream = fs.createWriteStream(path.join(dirPath, jsKeys[i] + '.js'), { encoding: 'utf-8' }) |
||||||
|
request(url).pipe(stream).on('close', function (err) { |
||||||
|
if (!err) { |
||||||
|
console.log('文件[' + version + '/' + jsKeys[i] + '.js' + ']下载完毕') |
||||||
|
} |
||||||
|
}) |
||||||
|
}) |
||||||
|
|
||||||
|
var cssKeys = Object.keys(csslibs) |
||||||
|
var cssUrl = cssKeys.map(v => { |
||||||
|
return csslibs[v].join() |
||||||
|
}) |
||||||
|
|
||||||
|
cssUrl.forEach((v, i) => { |
||||||
|
var url = cdnUrl + v |
||||||
|
console.log(url) |
||||||
|
var stream = fs.createWriteStream(path.join(dirPath, cssKeys[i] + '.css'), { encoding: 'utf-8' }) |
||||||
|
request(url).pipe(stream).on('close', function (err) { |
||||||
|
if (!err) { |
||||||
|
console.log('文件[' + version + '/' + cssKeys[i] + '.css' + ']下载完毕') |
||||||
|
} |
||||||
|
}) |
||||||
|
}) |
@ -0,0 +1,208 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
const path = require('path') |
||||||
|
const glob = require('globby') |
||||||
|
const webpack = require('webpack') |
||||||
|
const HtmlWebpackPlugin = require('html-webpack-plugin') |
||||||
|
const HtmlWebpackExtPlugin = require('html-webpack-ext-plugin') |
||||||
|
const isProduction = process.env.NODE_ENV !== 'development' |
||||||
|
|
||||||
|
const resolve = dir => path.join(__dirname, '..', dir) |
||||||
|
|
||||||
|
const assetsDir = resolve('src') |
||||||
|
const distDir = resolve('dist') |
||||||
|
const viewDir = resolve('src/view') |
||||||
|
|
||||||
|
|
||||||
|
function moduleName (modules) { |
||||||
|
let filename = path.basename(modules) |
||||||
|
let parts = filename.split('.') |
||||||
|
parts.pop() |
||||||
|
filename = parts.join('.') |
||||||
|
return path.dirname(modules) + '/' + filename |
||||||
|
} |
||||||
|
|
||||||
|
const jsEntry = (() => { |
||||||
|
const obj = {} |
||||||
|
const files = glob.sync(['js/conf/*/!(_*).js'], { cwd: assetsDir }) |
||||||
|
files.forEach(val => { |
||||||
|
let parts = val.split(/[\\/]/) |
||||||
|
parts.shift() |
||||||
|
parts.shift() |
||||||
|
let modules = parts.join('/') |
||||||
|
let entry = moduleName(modules) |
||||||
|
obj[entry] = val |
||||||
|
}) |
||||||
|
return obj |
||||||
|
})() |
||||||
|
|
||||||
|
const minifierConfig = isProduction ? { |
||||||
|
removeComments: true, |
||||||
|
removeCommentsFromCDATA: true, |
||||||
|
collapseWhitespace: true, |
||||||
|
collapseBooleanAttributes: true, |
||||||
|
removeRedundantAttributes: true, |
||||||
|
useShortDoctype: true, |
||||||
|
minifyJS: true, |
||||||
|
removeScriptTypeAttributes: true, |
||||||
|
maxLineLength: 1024 |
||||||
|
} : false |
||||||
|
|
||||||
|
const getPageEntry = view => jsEntry[view] ? view : '' |
||||||
|
|
||||||
|
// 重新定向输出页面
|
||||||
|
const pageRewriter = { |
||||||
|
'view/home/index.*': 'index.html' |
||||||
|
} |
||||||
|
|
||||||
|
const isEmpty = o => { |
||||||
|
for (let k in o) { |
||||||
|
if (o.hasOwnProperty(k)) { |
||||||
|
return |
||||||
|
} |
||||||
|
} |
||||||
|
return true |
||||||
|
} |
||||||
|
|
||||||
|
const unixPath = v => v.replace(/\\/g, '/') |
||||||
|
|
||||||
|
const rewriterPath = p => { |
||||||
|
if (isEmpty(pageRewriter)) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
for (let k in pageRewriter) { |
||||||
|
let regx = new RegExp(k) |
||||||
|
|
||||||
|
if (regx.test(unixPath(p))) { |
||||||
|
return pageRewriter[k] |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const pages = glob.sync(['*/!(_*).html'], { cwd: viewDir }).map(p => { |
||||||
|
let pagePath = `${path.join(viewDir, p)}` |
||||||
|
let newPagePath = rewriterPath(pagePath) |
||||||
|
|
||||||
|
let entry = getPageEntry(p.replace('.html', '')) |
||||||
|
let chunks = ['common'] |
||||||
|
if (entry) { |
||||||
|
chunks.push(entry) |
||||||
|
} |
||||||
|
return new HtmlWebpackPlugin({ |
||||||
|
filename: newPagePath || path.join('view', p), |
||||||
|
template: `html-loader?min=false!${path.join(viewDir, p)}`, |
||||||
|
cache: true, |
||||||
|
inject: true, |
||||||
|
chunks: chunks, |
||||||
|
minify: minifierConfig |
||||||
|
}) |
||||||
|
}) |
||||||
|
|
||||||
|
const baseConfig = { |
||||||
|
entry: jsEntry, |
||||||
|
output: { |
||||||
|
path: distDir, |
||||||
|
publicPath: '/', |
||||||
|
filename: 'js/[name].[chunkhash:7].js' |
||||||
|
}, |
||||||
|
devServer: { |
||||||
|
historyApiFallback: true, |
||||||
|
hot: true, |
||||||
|
inline: true, |
||||||
|
progress: true |
||||||
|
}, |
||||||
|
module: { |
||||||
|
rules: [ |
||||||
|
{ |
||||||
|
test: /\.js$/, |
||||||
|
exclude: /(node_modules|bower_components)/, |
||||||
|
use: [ |
||||||
|
{ |
||||||
|
loader: 'babel-loader', |
||||||
|
options: { |
||||||
|
cacheDirectory: true, |
||||||
|
cacheIdentifier: true |
||||||
|
} |
||||||
|
} |
||||||
|
] |
||||||
|
}, |
||||||
|
{ |
||||||
|
test: /\.(png|jpe?g|gif|svg|cur)(\?.*)?$/, |
||||||
|
loader: 'file-loader', |
||||||
|
options: { |
||||||
|
name: 'images/[name].[ext]?[hash]' |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, |
||||||
|
loader: 'url-loader', |
||||||
|
options: { |
||||||
|
limit: 10000, |
||||||
|
// publicPath: distDir,
|
||||||
|
name: 'font/[name].[hash:7].[ext]' |
||||||
|
} |
||||||
|
} |
||||||
|
] |
||||||
|
}, |
||||||
|
resolve: { |
||||||
|
modules: [ |
||||||
|
resolve('node_modules'), |
||||||
|
resolve('src'), |
||||||
|
resolve('src/js') |
||||||
|
], |
||||||
|
alias: { |
||||||
|
'@': resolve('src/js'), |
||||||
|
'~': resolve('src/lib') |
||||||
|
}, |
||||||
|
extensions: ['.js', 'json', '.vue', '.scss'] |
||||||
|
}, |
||||||
|
externals: { |
||||||
|
'vue': 'Vue', |
||||||
|
'vuex': 'Vuex', |
||||||
|
'vue-router': 'VueRouter', |
||||||
|
'jquery': '$', |
||||||
|
'lodash': '_', |
||||||
|
'bootstrap': 'bootstrap', |
||||||
|
'd3': 'd3', |
||||||
|
'canvg': 'canvg', |
||||||
|
'html2canvas': 'html2canvas', |
||||||
|
'./jsplumb': 'jsPlumb', |
||||||
|
'./highlight.js': 'highlight.js', |
||||||
|
'./clipboard': 'clipboard', |
||||||
|
'./codemirror': 'CodeMirror' |
||||||
|
}, |
||||||
|
plugins: [ |
||||||
|
new webpack.ProvidePlugin({ vue: 'Vue', _: 'lodash' }), |
||||||
|
new HtmlWebpackExtPlugin({ |
||||||
|
cache: true, |
||||||
|
delimiter: '$', |
||||||
|
locals: { |
||||||
|
NODE_ENV:isProduction |
||||||
|
} |
||||||
|
}), |
||||||
|
...pages |
||||||
|
] |
||||||
|
} |
||||||
|
|
||||||
|
module.exports = { |
||||||
|
isProduction, |
||||||
|
assetsDir, |
||||||
|
distDir, |
||||||
|
baseConfig |
||||||
|
} |
@ -0,0 +1,87 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
const fs = require('fs'); |
||||||
|
const path = require('path') |
||||||
|
const glob = require('globby') |
||||||
|
|
||||||
|
function moduleName (modules) { |
||||||
|
let filename = path.basename(modules) |
||||||
|
let parts = filename.split('.') |
||||||
|
parts.pop() |
||||||
|
filename = parts.join('.') |
||||||
|
return path.dirname(modules) + '/' + filename |
||||||
|
} |
||||||
|
|
||||||
|
const jsEntry = () => { |
||||||
|
const obj = {} |
||||||
|
const files = glob.sync([ |
||||||
|
'./src/js/conf/login/**/*.vue', |
||||||
|
'./src/js/conf/login/**/*.js', |
||||||
|
'./src/js/conf/home/**/**/**/**/**/**/**/**/*.vue', |
||||||
|
'./src/js/conf/home/**/**/**/**/**/**/**/**/*.js', |
||||||
|
'./src/js/module/**/**/**/**/**/*.vue', |
||||||
|
'./src/js/module/**/**/**/**/**/*.js' |
||||||
|
]) |
||||||
|
files.forEach(val => { |
||||||
|
let parts = val.split(/[\\/]/) |
||||||
|
parts.shift() |
||||||
|
parts.shift() |
||||||
|
let modules = parts.join('/') |
||||||
|
let entry = moduleName(modules) |
||||||
|
obj[entry] = val |
||||||
|
}) |
||||||
|
return obj |
||||||
|
} |
||||||
|
/* eslint-disable */ |
||||||
|
let reg = /\$t\([\w,""''“”~\-\s.?!,。:;《》、\+\/<>()?!\u4e00-\u9fa5]*\)/g |
||||||
|
let map = {} |
||||||
|
let entryPathList = '' |
||||||
|
let matchPathList = '' |
||||||
|
let jsEntryObj = jsEntry() |
||||||
|
|
||||||
|
for (let i in jsEntryObj) { |
||||||
|
entryPathList += jsEntryObj[i] + '\n' |
||||||
|
let data = fs.readFileSync(path.join(jsEntryObj[i]), 'utf-8') |
||||||
|
if (reg.test(data)) { |
||||||
|
matchPathList += jsEntryObj[i] + '\n' |
||||||
|
let str = data.replace(/[""'']/g, '') |
||||||
|
str.replace(reg, function () { |
||||||
|
if (arguments && arguments[0]) { |
||||||
|
let key = arguments[0] |
||||||
|
key = key.substring(3, key.length - 1) |
||||||
|
map[key] = key |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
let outPath = path.join(__dirname, '../src/js/module/i18n/locale/zh_CN.js') |
||||||
|
fs.unlink(outPath, (err) => { |
||||||
|
if (err) { |
||||||
|
console.error('删除zh_CN.js文件出错 -- \n', err) |
||||||
|
} else { |
||||||
|
console.log('删除zh_CN.js文件成功') |
||||||
|
} |
||||||
|
}) |
||||||
|
fs.writeFile(outPath, 'export default ' + JSON.stringify(map, null, 2), function (err) { |
||||||
|
if (err) { |
||||||
|
console.error('写入zh_CN.js文件出错 -- \n', err) |
||||||
|
} else { |
||||||
|
console.log('写入zh_CN.js文件成功') |
||||||
|
} |
||||||
|
}) |
@ -0,0 +1,112 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
const webpack = require('webpack') |
||||||
|
const merge = require('webpack-merge') |
||||||
|
const { assetsDir, baseConfig } = require('./config') |
||||||
|
const ExtractTextPlugin = require('extract-text-webpack-plugin') |
||||||
|
const ProgressPlugin = require('./../src/lib/@fedor/progress-webpack-plugin') |
||||||
|
const getEnv = require('env-parse').getEnv |
||||||
|
|
||||||
|
const config = merge.smart(baseConfig, { |
||||||
|
devtool: 'eval-source-map', |
||||||
|
output: { |
||||||
|
filename: 'js/[name].js' |
||||||
|
}, |
||||||
|
module: { |
||||||
|
rules: [ |
||||||
|
{ |
||||||
|
test: /\.vue$/, |
||||||
|
loader: 'vue-loader', |
||||||
|
options: { |
||||||
|
hotReload: true // 开启热重载
|
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
test: /\.css$/, |
||||||
|
loader: ExtractTextPlugin.extract({ |
||||||
|
use: [ |
||||||
|
'css-loader', |
||||||
|
{ |
||||||
|
loader: 'postcss-loader', |
||||||
|
options: { |
||||||
|
plugins: (loader) => [ |
||||||
|
require('autoprefixer')({ |
||||||
|
'browsers': [ '> 1%', 'last 3 versions', 'ie >= 9' ] |
||||||
|
}), |
||||||
|
require('cssnano') |
||||||
|
] |
||||||
|
} |
||||||
|
} |
||||||
|
], |
||||||
|
fallback: ['vue-style-loader'] |
||||||
|
}) |
||||||
|
}, |
||||||
|
{ |
||||||
|
test: /\.scss$/, |
||||||
|
loader: ExtractTextPlugin.extract({ |
||||||
|
use: [ |
||||||
|
'css-loader', |
||||||
|
'sass-loader', |
||||||
|
{ |
||||||
|
loader: 'postcss-loader', |
||||||
|
options: { |
||||||
|
plugins: (loader) => [ |
||||||
|
require('autoprefixer')({ |
||||||
|
'browsers': [ '> 1%', 'last 3 versions', 'ie >= 9' ] |
||||||
|
}), |
||||||
|
require('cssnano') |
||||||
|
] |
||||||
|
} |
||||||
|
} |
||||||
|
], |
||||||
|
fallback: ['vue-style-loader'] |
||||||
|
}) |
||||||
|
} |
||||||
|
] |
||||||
|
}, |
||||||
|
devServer: { |
||||||
|
hot: true, |
||||||
|
contentBase: assetsDir, |
||||||
|
publicPath: baseConfig.output.publicPath, |
||||||
|
port: getEnv('DEV_PORT', 8888), |
||||||
|
host: getEnv('DEV_HOST', 'localhost'), |
||||||
|
noInfo: false, |
||||||
|
historyApiFallback: true, |
||||||
|
disableHostCheck: true, |
||||||
|
proxy: { |
||||||
|
'/escheduler': { |
||||||
|
target: getEnv('API_BASE', 'http://local.dev:8080/backend'), |
||||||
|
changeOrigin: true |
||||||
|
} |
||||||
|
}, |
||||||
|
progress: false, |
||||||
|
quiet: false, |
||||||
|
stats: { |
||||||
|
colors: true |
||||||
|
}, |
||||||
|
clientLogLevel: 'none' |
||||||
|
}, |
||||||
|
plugins: [ |
||||||
|
new ProgressPlugin(), |
||||||
|
new webpack.HotModuleReplacementPlugin(), |
||||||
|
new ExtractTextPlugin({ filename: 'css/[name].css', allChunks: true }), |
||||||
|
new webpack.optimize.CommonsChunkPlugin({ name: 'common', filename: 'js/[name].js' }), |
||||||
|
new webpack.optimize.OccurrenceOrderPlugin() |
||||||
|
] |
||||||
|
}) |
||||||
|
|
||||||
|
module.exports = config |
@ -0,0 +1,132 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
const path = require('path') |
||||||
|
const webpack = require('webpack') |
||||||
|
const merge = require('webpack-merge') |
||||||
|
const CopyWebpackPlugin = require('copy-webpack-plugin') |
||||||
|
const { baseConfig } = require('./config') |
||||||
|
const ExtractTextPlugin = require('extract-text-webpack-plugin') |
||||||
|
const UglifyJSPlugin = require('uglifyjs-webpack-plugin') |
||||||
|
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin') |
||||||
|
const ProgressPlugin = require('./../src/lib/@fedor/progress-webpack-plugin') |
||||||
|
|
||||||
|
const resolve = dir => |
||||||
|
path.resolve(__dirname, '..', dir) |
||||||
|
|
||||||
|
const config = merge.smart(baseConfig, { |
||||||
|
devtool: 'source-map', |
||||||
|
output: { |
||||||
|
filename: 'js/[name].[chunkhash:7].js' |
||||||
|
}, |
||||||
|
module: { |
||||||
|
rules: [ |
||||||
|
{ |
||||||
|
test: /\.vue$/, |
||||||
|
loader: 'vue-loader', |
||||||
|
options: { |
||||||
|
hotReload: false // 开启热重载
|
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
test: /\.css$/, |
||||||
|
loader: ExtractTextPlugin.extract({ |
||||||
|
use: [ |
||||||
|
'css-loader', |
||||||
|
{ |
||||||
|
loader: 'postcss-loader', |
||||||
|
options: { |
||||||
|
plugins: (loader) => [ |
||||||
|
require('autoprefixer')({ |
||||||
|
'browsers': [ '> 1%', 'last 3 versions', 'ie >= 9' ] |
||||||
|
}), |
||||||
|
require('cssnano') |
||||||
|
] |
||||||
|
} |
||||||
|
} |
||||||
|
], |
||||||
|
fallback: ['vue-style-loader'] |
||||||
|
}) |
||||||
|
}, |
||||||
|
{ |
||||||
|
test: /\.scss$/, |
||||||
|
loader: ExtractTextPlugin.extract({ |
||||||
|
use: [ |
||||||
|
'css-loader', |
||||||
|
'sass-loader', |
||||||
|
{ |
||||||
|
loader: 'postcss-loader', |
||||||
|
options: { |
||||||
|
plugins: (loader) => [ |
||||||
|
require('autoprefixer')({ |
||||||
|
'browsers': [ '> 1%', 'last 3 versions', 'ie >= 9' ] |
||||||
|
}), |
||||||
|
require('cssnano') |
||||||
|
] |
||||||
|
} |
||||||
|
} |
||||||
|
], |
||||||
|
fallback: ['vue-style-loader'] |
||||||
|
}) |
||||||
|
} |
||||||
|
] |
||||||
|
}, |
||||||
|
plugins: [ |
||||||
|
new ProgressPlugin(), |
||||||
|
new ExtractTextPlugin({ filename: 'css/[name].[contenthash:7].css', allChunks: true }), |
||||||
|
new webpack.optimize.CommonsChunkPlugin({ name: 'common', filename: 'js/[name].[hash:7].js' }), |
||||||
|
new webpack.optimize.OccurrenceOrderPlugin(), |
||||||
|
new OptimizeCssAssetsPlugin({ |
||||||
|
assetNameRegExp: /\.css$/g, |
||||||
|
cssProcessor: require('cssnano'), |
||||||
|
cssProcessorOptions: { discardComments: { removeAll: true } }, |
||||||
|
canPrint: true |
||||||
|
}), |
||||||
|
new UglifyJSPlugin({ |
||||||
|
parallel: true, |
||||||
|
sourceMap: true, |
||||||
|
uglifyOptions: { |
||||||
|
compress: { |
||||||
|
drop_console: true, |
||||||
|
drop_debugger: true |
||||||
|
}, |
||||||
|
comments: function (n, c) { |
||||||
|
/*! IMPORTANT: Please preserve 3rd-party library license info, inspired from @allex/amd-build-worker/config/jsplumb.js */ |
||||||
|
var text = c.value, type = c.type |
||||||
|
if (type === 'comment2') { |
||||||
|
return /^!|@preserve|@license|@cc_on|MIT/i.test(text) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
}), |
||||||
|
new CopyWebpackPlugin([ |
||||||
|
{ |
||||||
|
from: resolve('src/combo'), |
||||||
|
to: resolve('dist/combo') |
||||||
|
}, |
||||||
|
{ |
||||||
|
from: resolve('src/lib'), |
||||||
|
to: resolve('dist/lib') |
||||||
|
}, |
||||||
|
{ |
||||||
|
from: resolve('src/images'), |
||||||
|
to: resolve('dist/images') |
||||||
|
}, |
||||||
|
]), |
||||||
|
] |
||||||
|
}) |
||||||
|
|
||||||
|
module.exports = config |
@ -0,0 +1,88 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
const webpack = require('webpack') |
||||||
|
const merge = require('webpack-merge') |
||||||
|
const { baseConfig } = require('./config') |
||||||
|
const ExtractTextPlugin = require('extract-text-webpack-plugin') |
||||||
|
|
||||||
|
const config = merge.smart(baseConfig, { |
||||||
|
devtool: 'inline-source-map', |
||||||
|
output: { |
||||||
|
filename: 'js/[name].js' |
||||||
|
}, |
||||||
|
module: { |
||||||
|
rules: [ |
||||||
|
{ |
||||||
|
test: /\.vue$/, |
||||||
|
loader: 'vue-loader', |
||||||
|
options: { |
||||||
|
hotReload: true // 开启热重载
|
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
test: /\.css$/, |
||||||
|
loader: ExtractTextPlugin.extract({ |
||||||
|
use: [ |
||||||
|
'css-loader', |
||||||
|
{ |
||||||
|
loader: 'postcss-loader', |
||||||
|
options: { |
||||||
|
plugins: (loader) => [ |
||||||
|
require('autoprefixer')({ |
||||||
|
'browsers': [ '> 1%', 'last 3 versions', 'ie >= 9' ] |
||||||
|
}), |
||||||
|
require('cssnano') |
||||||
|
] |
||||||
|
} |
||||||
|
} |
||||||
|
], |
||||||
|
fallback: ['vue-style-loader'] |
||||||
|
}) |
||||||
|
}, |
||||||
|
{ |
||||||
|
test: /\.scss$/, |
||||||
|
loader: ExtractTextPlugin.extract({ |
||||||
|
use: [ |
||||||
|
'css-loader', |
||||||
|
'sass-loader', |
||||||
|
{ |
||||||
|
loader: 'postcss-loader', |
||||||
|
options: { |
||||||
|
plugins: (loader) => [ |
||||||
|
require('autoprefixer')({ |
||||||
|
'browsers': [ '> 1%', 'last 3 versions', 'ie >= 9' ] |
||||||
|
}), |
||||||
|
require('cssnano') |
||||||
|
] |
||||||
|
} |
||||||
|
} |
||||||
|
], |
||||||
|
fallback: ['vue-style-loader'] |
||||||
|
}) |
||||||
|
} |
||||||
|
] |
||||||
|
}, |
||||||
|
externals: '', |
||||||
|
plugins: [ |
||||||
|
new webpack.HotModuleReplacementPlugin(), |
||||||
|
new ExtractTextPlugin({ filename: 'css/[name].css', allChunks: true }), |
||||||
|
new webpack.optimize.OccurrenceOrderPlugin() |
||||||
|
] |
||||||
|
}) |
||||||
|
|
||||||
|
module.exports = config |
@ -0,0 +1,97 @@ |
|||||||
|
{ |
||||||
|
"name": "escheduler", |
||||||
|
"version": "1.0.0", |
||||||
|
"description": "调度平台前端项目", |
||||||
|
"author": "gongzijian <gongzijian@analysys.com.cn>", |
||||||
|
"scripts": { |
||||||
|
"build": "npm run clean && cross-env NODE_ENV=production webpack --config ./build/webpack.config.prod.js", |
||||||
|
"dev": "cross-env NODE_ENV=development webpack-dev-server --config ./build/webpack.config.dev.js", |
||||||
|
"clean": "rimraf dist", |
||||||
|
"lint": "standard \"**/*.{js,vue}\"", |
||||||
|
"lint:fix": "standard \"**/*.{js,vue}\" --fix", |
||||||
|
"start": "npm run dev", |
||||||
|
"combo": "node ./build/combo.js" |
||||||
|
}, |
||||||
|
"dependencies": { |
||||||
|
"autoprefixer": "^9.1.0", |
||||||
|
"babel-core": "^6.25.0", |
||||||
|
"babel-eslint": "^8.2.2", |
||||||
|
"babel-helper-vue-jsx-merge-props": "^2.0.2", |
||||||
|
"babel-loader": "^7.1.1", |
||||||
|
"babel-plugin-syntax-dynamic-import": "^6.18.0", |
||||||
|
"babel-plugin-syntax-jsx": "^6.18.0", |
||||||
|
"babel-plugin-transform-class-properties": "^6.24.1", |
||||||
|
"babel-plugin-transform-object-rest-spread": "^6.26.0", |
||||||
|
"babel-plugin-transform-remove-console": "^6.9.4", |
||||||
|
"babel-plugin-transform-runtime": "^6.23.0", |
||||||
|
"babel-plugin-transform-vue-jsx": "^3.5.0", |
||||||
|
"babel-preset-env": "^1.6.1", |
||||||
|
"babel-runtime": "^6.26.0", |
||||||
|
"bootstrap": "3.3.7", |
||||||
|
"canvg": "1.5", |
||||||
|
"clipboard": "^2.0.1", |
||||||
|
"codemirror": "^5.43.0", |
||||||
|
"copy-webpack-plugin": "^4.5.2", |
||||||
|
"cross-env": "^5.2.0", |
||||||
|
"css-loader": "^0.28.8", |
||||||
|
"cssnano": "4.1.10", |
||||||
|
"d3": "^3.5.17", |
||||||
|
"dayjs": "^1.7.8", |
||||||
|
"echarts": "^4.1.0", |
||||||
|
"env-parse": "^1.0.5", |
||||||
|
"extract-text-webpack-plugin": "^3.0.2", |
||||||
|
"file-loader": "^1.1.11", |
||||||
|
"ghooks": "^2.0.4", |
||||||
|
"globby": "^8.0.1", |
||||||
|
"html-loader": "^0.5.5", |
||||||
|
"html-webpack-ext-plugin": "^1.0.0", |
||||||
|
"html-webpack-plugin": "^3.2.0", |
||||||
|
"html2canvas": "^0.5.0-beta4", |
||||||
|
"jsplumb": "^2.8.6", |
||||||
|
"lodash": "^4.17.11", |
||||||
|
"node-sass": "^4.9.2", |
||||||
|
"optimize-css-assets-webpack-plugin": "3.2.0", |
||||||
|
"postcss-loader": "^2.1.6", |
||||||
|
"rimraf": "^2.6.2", |
||||||
|
"sass-loader": "^7.1.0", |
||||||
|
"uglifyjs-webpack-plugin": "^1.2.7", |
||||||
|
"url-loader": "^0.5.9", |
||||||
|
"vue-loader": "^13.7.0", |
||||||
|
"vue-style-loader": "^4.1.1", |
||||||
|
"vue-template-compiler": "^2.5.16", |
||||||
|
"vuex-router-sync": "^4.1.2", |
||||||
|
"webpack": "^3.12.0", |
||||||
|
"webpack-dev-server": "^2.11.2", |
||||||
|
"webpack-merge": "^4.1.4" |
||||||
|
}, |
||||||
|
"standard": { |
||||||
|
"parser": "babel-eslint", |
||||||
|
"ignore": [ |
||||||
|
"src/~/**", |
||||||
|
"src/view/docs/**", |
||||||
|
"src/font/*", |
||||||
|
"src/combo/**", |
||||||
|
"dist/**", |
||||||
|
"src/lib/**", |
||||||
|
"build/**" |
||||||
|
] |
||||||
|
}, |
||||||
|
"config": { |
||||||
|
"ghooks": {} |
||||||
|
}, |
||||||
|
"devDependencies": { |
||||||
|
"jasmine-core": "^3.2.1", |
||||||
|
"jquery": "1.12.4", |
||||||
|
"karma": "^3.0.0", |
||||||
|
"karma-browserstack-launcher": "^1.3.0", |
||||||
|
"karma-chrome-launcher": "^2.2.0", |
||||||
|
"karma-coverage": "^1.1.2", |
||||||
|
"karma-jasmine": "^1.1.2", |
||||||
|
"karma-sourcemap-loader": "^0.3.7", |
||||||
|
"karma-spec-reporter": "^0.0.32", |
||||||
|
"karma-webpack": "^3.0.0", |
||||||
|
"vue": "^2.5.17", |
||||||
|
"vue-router": "2.7.0", |
||||||
|
"vuex": "^3.0.0" |
||||||
|
} |
||||||
|
} |
After Width: | Height: | Size: 434 KiB |
@ -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: 160px; |
||||||
|
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; |
||||||
|
} |
After Width: | Height: | Size: 4.2 KiB |
@ -0,0 +1,15 @@ |
|||||||
|
<template> |
||||||
|
<m-layout> |
||||||
|
<m-nav slot="top"></m-nav> |
||||||
|
<router-view slot="bottom"></router-view> |
||||||
|
</m-layout> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
import mLayout from '@/module/components/layout/layout' |
||||||
|
import mNav from '@/module/components/nav/nav' |
||||||
|
export default { |
||||||
|
name: 'app', |
||||||
|
components: { mLayout, mNav } |
||||||
|
} |
||||||
|
</script> |
@ -0,0 +1,85 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
// The Vue build version to load with the `import` command
|
||||||
|
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
|
||||||
|
import $ from 'jquery' |
||||||
|
import Vue from 'vue' |
||||||
|
import App from './App' |
||||||
|
import router from './router' |
||||||
|
import store from './store' |
||||||
|
import i18n from '@/module/i18n' |
||||||
|
import { sync } from 'vuex-router-sync' |
||||||
|
import Chart from '~/@analysys/ana-charts' |
||||||
|
import themeData from '@/module/echarts/themeData.json' |
||||||
|
import Permissions from '@/module/permissions' |
||||||
|
import '~/@analysys/ans-ui/lib/ans-ui.min.css' |
||||||
|
import ans from '~/@analysys/ans-ui/lib/ans-ui.min' |
||||||
|
import en_US from '~/@analysys/ans-ui/lib/locale/en' // eslint-disable-line
|
||||||
|
import 'sass/conf/home/index.scss' |
||||||
|
|
||||||
|
// Component internationalization
|
||||||
|
let useOpt = i18n.globalScope.LOCALE === 'en_US' ? { locale: en_US } : {} |
||||||
|
|
||||||
|
// Vue.use(ans)
|
||||||
|
Vue.use(ans, useOpt) |
||||||
|
|
||||||
|
sync(store, router) |
||||||
|
|
||||||
|
Vue.config.devtools = true |
||||||
|
Vue.config.productionTip = true |
||||||
|
Vue.config.silent = true |
||||||
|
|
||||||
|
Chart.config({ |
||||||
|
theme: { |
||||||
|
name: 'themeName', |
||||||
|
data: themeData, |
||||||
|
default: true |
||||||
|
} |
||||||
|
}) |
||||||
|
|
||||||
|
/* eslint-disable no-new */ |
||||||
|
Permissions.request().then(res => { |
||||||
|
// instance
|
||||||
|
new Vue({ |
||||||
|
el: '#app', |
||||||
|
router, |
||||||
|
store, |
||||||
|
render: h => h(App), |
||||||
|
mounted () { |
||||||
|
document.addEventListener('click', (e) => { |
||||||
|
$('#contextmenu').css('visibility', 'hidden') |
||||||
|
}) |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
initApp () { |
||||||
|
$('.global-loading').hide() |
||||||
|
let bootstrapTooltip = $.fn.tooltip.noConflict() |
||||||
|
$.fn.tooltip = bootstrapTooltip |
||||||
|
$('body').tooltip({ |
||||||
|
selector: '[data-toggle="tooltip"]', |
||||||
|
trigger: 'hover' |
||||||
|
}) |
||||||
|
// init
|
||||||
|
i18n.init() |
||||||
|
} |
||||||
|
}, |
||||||
|
created () { |
||||||
|
this.initApp() |
||||||
|
} |
||||||
|
}) |
||||||
|
}) |
@ -0,0 +1,284 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
import i18n from '@/module/i18n' |
||||||
|
import Permissions from '@/module/permissions' |
||||||
|
|
||||||
|
/** |
||||||
|
* Operation bar config |
||||||
|
* @code code |
||||||
|
* @icon icon |
||||||
|
* @disable disable |
||||||
|
* @desc tooltip |
||||||
|
*/ |
||||||
|
const toolOper = (dagThis) => { |
||||||
|
let disabled = Permissions.getAuth() === false ? false : !dagThis.$store.state.dag.isDetails |
||||||
|
return [ |
||||||
|
{ |
||||||
|
code: 'pointer', |
||||||
|
icon: '', |
||||||
|
disable: disabled, |
||||||
|
desc: `${i18n.$t('拖动节点和选中项')}` |
||||||
|
}, |
||||||
|
{ |
||||||
|
code: 'line', |
||||||
|
icon: '', |
||||||
|
disable: disabled, |
||||||
|
desc: `${i18n.$t('选择线条连接')}` |
||||||
|
}, |
||||||
|
{ |
||||||
|
code: 'remove', |
||||||
|
icon: '', |
||||||
|
disable: disabled, |
||||||
|
desc: `${i18n.$t('删除选中的线或节点')}` |
||||||
|
}, |
||||||
|
{ |
||||||
|
code: 'download', |
||||||
|
icon: '', |
||||||
|
disable: !!dagThis.type, |
||||||
|
desc: `${i18n.$t('下载')}` |
||||||
|
}, |
||||||
|
{ |
||||||
|
code: 'screen', |
||||||
|
icon: '', |
||||||
|
disable: disabled, |
||||||
|
desc: `${i18n.$t('全屏')}` |
||||||
|
} |
||||||
|
] |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Post status |
||||||
|
* @id Front end definition id |
||||||
|
* @desc tooltip |
||||||
|
* @code Backend definition identifier |
||||||
|
*/ |
||||||
|
let publishStatus = [ |
||||||
|
{ |
||||||
|
id: 0, |
||||||
|
desc: `${i18n.$t('未发布')}`, |
||||||
|
code: 'NOT_RELEASE' |
||||||
|
}, |
||||||
|
{ |
||||||
|
id: 1, |
||||||
|
desc: `${i18n.$t('上线')}`, |
||||||
|
code: 'ONLINE' |
||||||
|
}, |
||||||
|
{ |
||||||
|
id: 2, |
||||||
|
desc: `${i18n.$t('下线')}`, |
||||||
|
code: 'OFFLINE' |
||||||
|
} |
||||||
|
] |
||||||
|
|
||||||
|
/** |
||||||
|
* Operation type |
||||||
|
* @desc tooltip |
||||||
|
* @code identifier |
||||||
|
*/ |
||||||
|
let runningType = [ |
||||||
|
{ |
||||||
|
desc: `${i18n.$t('启动工作流')}`, |
||||||
|
code: 'START_PROCESS' |
||||||
|
}, |
||||||
|
{ |
||||||
|
desc: `${i18n.$t('从当前节点开始执行')}`, |
||||||
|
code: 'START_CURRENT_TASK_PROCESS' |
||||||
|
}, |
||||||
|
{ |
||||||
|
desc: `${i18n.$t('恢复被容错的工作流')}`, |
||||||
|
code: 'RECOVER_TOLERANCE_FAULT_PROCESS' |
||||||
|
}, |
||||||
|
{ |
||||||
|
desc: `${i18n.$t('恢复暂停流程')}`, |
||||||
|
code: 'RECOVER_SUSPENDED_PROCESS' |
||||||
|
}, |
||||||
|
{ |
||||||
|
desc: `${i18n.$t('从失败节点开始执行')}`, |
||||||
|
code: 'START_FAILURE_TASK_PROCESS' |
||||||
|
}, |
||||||
|
{ |
||||||
|
desc: `${i18n.$t('补数')}`, |
||||||
|
code: 'COMPLEMENT_DATA' |
||||||
|
}, |
||||||
|
{ |
||||||
|
desc: `${i18n.$t('调度执行')}`, |
||||||
|
code: 'SCHEDULER' |
||||||
|
}, |
||||||
|
{ |
||||||
|
desc: `${i18n.$t('重跑')}`, |
||||||
|
code: 'REPEAT_RUNNING' |
||||||
|
}, |
||||||
|
{ |
||||||
|
desc: `${i18n.$t('暂停')}`, |
||||||
|
code: 'PAUSE' |
||||||
|
}, |
||||||
|
{ |
||||||
|
desc: `${i18n.$t('停止')}`, |
||||||
|
code: 'STOP' |
||||||
|
}, |
||||||
|
{ |
||||||
|
desc: `${i18n.$t('恢复等待线程')}`, |
||||||
|
code: 'RECOVER_WAITTING_THREAD' |
||||||
|
} |
||||||
|
] |
||||||
|
|
||||||
|
/** |
||||||
|
* Task status |
||||||
|
* @key key |
||||||
|
* @id id |
||||||
|
* @desc tooltip |
||||||
|
* @color color |
||||||
|
* @icoUnicode iconfont |
||||||
|
* @isSpin is loading (Need to execute the code block to write if judgment) |
||||||
|
*/ |
||||||
|
let tasksState = { |
||||||
|
'SUBMITTED_SUCCESS': { |
||||||
|
id: 0, |
||||||
|
desc: `${i18n.$t('提交成功')}`, |
||||||
|
color: '#A9A9A9', |
||||||
|
icoUnicode: '', |
||||||
|
isSpin: false |
||||||
|
}, |
||||||
|
'RUNNING_EXEUTION': { |
||||||
|
id: 1, |
||||||
|
desc: `${i18n.$t('正在执行')}`, |
||||||
|
color: '#0097e0', |
||||||
|
icoUnicode: '', |
||||||
|
isSpin: true |
||||||
|
}, |
||||||
|
'READY_PAUSE': { |
||||||
|
id: 2, |
||||||
|
desc: `${i18n.$t('准备暂停')}`, |
||||||
|
color: '#07b1a3', |
||||||
|
icoUnicode: '', |
||||||
|
isSpin: false |
||||||
|
}, |
||||||
|
'PAUSE': { |
||||||
|
id: 3, |
||||||
|
desc: `${i18n.$t('暂停')}`, |
||||||
|
color: '#057c72', |
||||||
|
icoUnicode: '', |
||||||
|
isSpin: false |
||||||
|
}, |
||||||
|
'READY_STOP': { |
||||||
|
id: 4, |
||||||
|
desc: `${i18n.$t('准备停止')}`, |
||||||
|
color: '#FE0402', |
||||||
|
icoUnicode: '', |
||||||
|
isSpin: false |
||||||
|
}, |
||||||
|
'STOP': { |
||||||
|
id: 5, |
||||||
|
desc: `${i18n.$t('停止')}`, |
||||||
|
color: '#e90101', |
||||||
|
icoUnicode: '', |
||||||
|
isSpin: false |
||||||
|
}, |
||||||
|
'FAILURE': { |
||||||
|
id: 6, |
||||||
|
desc: `${i18n.$t('失败')}`, |
||||||
|
color: '#000000', |
||||||
|
icoUnicode: '', |
||||||
|
isSpin: false |
||||||
|
}, |
||||||
|
'SUCCESS': { |
||||||
|
id: 7, |
||||||
|
desc: `${i18n.$t('成功')}`, |
||||||
|
color: '#33cc00', |
||||||
|
icoUnicode: '', |
||||||
|
isSpin: false |
||||||
|
}, |
||||||
|
'NEED_FAULT_TOLERANCE': { |
||||||
|
id: 8, |
||||||
|
desc: `${i18n.$t('需要容错')}`, |
||||||
|
color: '#FF8C00', |
||||||
|
icoUnicode: '', |
||||||
|
isSpin: false |
||||||
|
}, |
||||||
|
'KILL': { |
||||||
|
id: 9, |
||||||
|
desc: `${i18n.$t('kill')}`, |
||||||
|
color: '#a70202', |
||||||
|
icoUnicode: '', |
||||||
|
isSpin: false |
||||||
|
}, |
||||||
|
'WAITTING_THREAD': { |
||||||
|
id: 10, |
||||||
|
desc: `${i18n.$t('等待线程')}`, |
||||||
|
color: '#912eed', |
||||||
|
icoUnicode: '', |
||||||
|
isSpin: false |
||||||
|
}, |
||||||
|
'WAITTING_DEPEND': { |
||||||
|
id: 11, |
||||||
|
desc: `${i18n.$t('等待依赖')}`, |
||||||
|
color: '#5101be', |
||||||
|
icoUnicode: '', |
||||||
|
isSpin: false |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Node type |
||||||
|
* @key key |
||||||
|
* @desc tooltip |
||||||
|
* @color color (tree and gantt) |
||||||
|
*/ |
||||||
|
let tasksType = { |
||||||
|
'SHELL': { |
||||||
|
desc: 'SHELL', |
||||||
|
color: '#646464' |
||||||
|
}, |
||||||
|
'SUB_PROCESS': { |
||||||
|
desc: 'SUB_PROCESS', |
||||||
|
color: '#0097e0' |
||||||
|
}, |
||||||
|
'PROCEDURE': { |
||||||
|
desc: 'PROCEDURE', |
||||||
|
color: '#525CCD' |
||||||
|
}, |
||||||
|
'SQL': { |
||||||
|
desc: 'SQL', |
||||||
|
color: '#7A98A1' |
||||||
|
}, |
||||||
|
'SPARK': { |
||||||
|
desc: 'SPARK', |
||||||
|
color: '#E46F13' |
||||||
|
}, |
||||||
|
'MR': { |
||||||
|
desc: 'MapReduce', |
||||||
|
color: '#A0A5CC' |
||||||
|
}, |
||||||
|
'PYTHON': { |
||||||
|
desc: 'PYTHON', |
||||||
|
color: '#FED52D' |
||||||
|
}, |
||||||
|
'DEPENDENT': { |
||||||
|
desc: 'DEPENDENT', |
||||||
|
color: '#2FBFD8' |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
export { |
||||||
|
toolOper, |
||||||
|
publishStatus, |
||||||
|
runningType, |
||||||
|
tasksState, |
||||||
|
tasksType |
||||||
|
} |
@ -0,0 +1,119 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
import _ from 'lodash' |
||||||
|
import { jsPlumb } from 'jsplumb' |
||||||
|
import JSP from './plugIn/jsPlumbHandle' |
||||||
|
import DownChart from './plugIn/downChart' |
||||||
|
import store from '@/conf/home/store' |
||||||
|
|
||||||
|
/** |
||||||
|
* Prototype method |
||||||
|
*/ |
||||||
|
let Dag = function () { |
||||||
|
this.dag = {} |
||||||
|
this.instance = {} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* init |
||||||
|
* @dag dag vue instance |
||||||
|
*/ |
||||||
|
Dag.prototype.init = function ({ dag, instance }) { |
||||||
|
this.dag = dag |
||||||
|
this.instance = instance |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* set init config |
||||||
|
*/ |
||||||
|
Dag.prototype.setConfig = function (o) { |
||||||
|
JSP.setConfig(o) |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* create dag |
||||||
|
*/ |
||||||
|
Dag.prototype.create = function () { |
||||||
|
jsPlumb.ready(() => { |
||||||
|
JSP.init({ |
||||||
|
dag: this.dag, |
||||||
|
instance: this.instance |
||||||
|
}) |
||||||
|
|
||||||
|
// init event
|
||||||
|
JSP.handleEvent() |
||||||
|
|
||||||
|
// init draggable
|
||||||
|
JSP.draggable() |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Action event on the right side of the toolbar |
||||||
|
*/ |
||||||
|
Dag.prototype.toolbarEvent = function ({ item, code, is }) { |
||||||
|
switch (code) { |
||||||
|
case 'pointer': |
||||||
|
JSP.handleEventPointer(is) |
||||||
|
break |
||||||
|
case 'line': |
||||||
|
JSP.handleEventLine(is) |
||||||
|
break |
||||||
|
case 'remove': |
||||||
|
JSP.handleEventRemove() |
||||||
|
break |
||||||
|
case 'screen': |
||||||
|
JSP.handleEventScreen({ item, is }) |
||||||
|
break |
||||||
|
case 'download': |
||||||
|
DownChart.download({ |
||||||
|
dagThis: this.dag |
||||||
|
}) |
||||||
|
break |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Echo data display |
||||||
|
*/ |
||||||
|
Dag.prototype.backfill = function () { |
||||||
|
jsPlumb.ready(() => { |
||||||
|
JSP.init({ |
||||||
|
dag: this.dag, |
||||||
|
instance: this.instance |
||||||
|
}) |
||||||
|
// Backfill
|
||||||
|
JSP.jspBackfill({ |
||||||
|
// connects
|
||||||
|
connects: _.cloneDeep(store.state.dag.connects), |
||||||
|
// Node location information
|
||||||
|
locations: _.cloneDeep(store.state.dag.locations), |
||||||
|
// Node data
|
||||||
|
largeJson: _.cloneDeep(store.state.dag.tasks) |
||||||
|
}) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get dag storage format data |
||||||
|
*/ |
||||||
|
Dag.prototype.saveStore = function () { |
||||||
|
return JSP.saveStore() |
||||||
|
} |
||||||
|
|
||||||
|
export default new Dag() |
@ -0,0 +1,506 @@ |
|||||||
|
|
||||||
|
.dag-model { |
||||||
|
background: url("../img/dag_bg.png"); |
||||||
|
height: calc(100vh - 100px); |
||||||
|
::selection { |
||||||
|
background:transparent; |
||||||
|
} |
||||||
|
::-moz-selection { |
||||||
|
background:transparent; |
||||||
|
} |
||||||
|
::-webkit-selection { |
||||||
|
background:transparent; |
||||||
|
} |
||||||
|
.jsplumb-connector { |
||||||
|
z-index: 1; |
||||||
|
} |
||||||
|
.endpoint-tasks { |
||||||
|
margin-top:22px; |
||||||
|
} |
||||||
|
.draggable { |
||||||
|
> span { |
||||||
|
text-align: center; |
||||||
|
display: block; |
||||||
|
margin-top: -4px; |
||||||
|
padding: 0 4px; |
||||||
|
width: 200px; |
||||||
|
margin-left: -81px; |
||||||
|
position: absolute; |
||||||
|
left: 0; |
||||||
|
bottom: -12px; |
||||||
|
} |
||||||
|
.fa { |
||||||
|
display: inline-block; |
||||||
|
position: absolute; |
||||||
|
right: -8px; |
||||||
|
top: -8px; |
||||||
|
z-index: 2; |
||||||
|
cursor: pointer; |
||||||
|
} |
||||||
|
.icos { |
||||||
|
display: inline-block; |
||||||
|
cursor: pointer; |
||||||
|
} |
||||||
|
&.active-tasks { |
||||||
|
span { |
||||||
|
color: #0296DF; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.icos { |
||||||
|
width: 32px; |
||||||
|
height: 32px; |
||||||
|
margin: 2px; |
||||||
|
border-radius: 3px; |
||||||
|
position: relative; |
||||||
|
z-index: 9; |
||||||
|
} |
||||||
|
.icos-SHELL { |
||||||
|
background: url("../img/toolbar_SHELL.png") no-repeat 50% 50%; |
||||||
|
} |
||||||
|
.icos-SUB_PROCESS { |
||||||
|
background: url("../img/toolbar_SUB_PROCESS.png") no-repeat 50% 50%; |
||||||
|
} |
||||||
|
.icos-PROCEDURE { |
||||||
|
background: url("../img/toolbar_PROCEDURE.png") no-repeat 50% 50%; |
||||||
|
} |
||||||
|
.icos-SQL { |
||||||
|
background: url("../img/toolbar_SQL.png") no-repeat 50% 50%; |
||||||
|
} |
||||||
|
.icos-SPARK { |
||||||
|
background: url("../img/toolbar_SPARK.png") no-repeat 50% 50%; |
||||||
|
} |
||||||
|
.icos-MR { |
||||||
|
background: url("../img/toolbar_MR.png") no-repeat 50% 50%; |
||||||
|
} |
||||||
|
.icos-PYTHON { |
||||||
|
background: url("../img/toolbar_PYTHON.png") no-repeat 50% 50%; |
||||||
|
} |
||||||
|
.icos-DEPENDENT { |
||||||
|
background: url("../img/toolbar_DEPENDENT.png") no-repeat 50% 50%; |
||||||
|
} |
||||||
|
.toolbar { |
||||||
|
width: 60px; |
||||||
|
height: 100%; |
||||||
|
background: #F2F3F7; |
||||||
|
float: left; |
||||||
|
border-radius: 0 0 0 3px; |
||||||
|
.title { |
||||||
|
height: 40px; |
||||||
|
line-height: 40px; |
||||||
|
background: #40434C; |
||||||
|
text-align: center; |
||||||
|
border-radius: 3px 0 0 0; |
||||||
|
span { |
||||||
|
font-size: 14px; |
||||||
|
color: #fff; |
||||||
|
font-weight: bold; |
||||||
|
} |
||||||
|
} |
||||||
|
.toolbar-btn { |
||||||
|
overflow: hidden; |
||||||
|
padding: 11px 11px 0 11px; |
||||||
|
.bar-box { |
||||||
|
width: 36px; |
||||||
|
height: 36px; |
||||||
|
float: left; |
||||||
|
margin-bottom: 11px; |
||||||
|
border-radius: 3px; |
||||||
|
.disabled { |
||||||
|
.icos { |
||||||
|
opacity: .6; |
||||||
|
-webkit-filter: grayscale(100%); |
||||||
|
-moz-filter: grayscale(100%); |
||||||
|
-ms-filter: grayscale(100%); |
||||||
|
-o-filter: grayscale(100%); |
||||||
|
filter: grayscale(100%); |
||||||
|
filter: gray; |
||||||
|
} |
||||||
|
} |
||||||
|
&:nth-child(odd) { |
||||||
|
margin-right: 6px; |
||||||
|
} |
||||||
|
&.active { |
||||||
|
background: #e1e2e3; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.dag-contect { |
||||||
|
float: left; |
||||||
|
width: calc(100% - 60px); |
||||||
|
height: 100%; |
||||||
|
.dag-toolbar { |
||||||
|
height: 40px; |
||||||
|
background: #F2F3F7; |
||||||
|
position: relative; |
||||||
|
border-radius: 0 3px 0 0; |
||||||
|
.assist-btn { |
||||||
|
position: absolute; |
||||||
|
left: 10px; |
||||||
|
top: 8px; |
||||||
|
>.name { |
||||||
|
padding-left: 6px; |
||||||
|
vertical-align: middle; |
||||||
|
} |
||||||
|
} |
||||||
|
.save-btn { |
||||||
|
position: absolute; |
||||||
|
right: 8px; |
||||||
|
top: 6px; |
||||||
|
.operation { |
||||||
|
overflow: hidden; |
||||||
|
display: inline-block; |
||||||
|
margin-right: 10px; |
||||||
|
a { |
||||||
|
float: left; |
||||||
|
width: 28px; |
||||||
|
height: 28px; |
||||||
|
text-align: center; |
||||||
|
line-height: 28px; |
||||||
|
margin-left: 6px; |
||||||
|
border-radius: 3px; |
||||||
|
vertical-align: middle; |
||||||
|
i { |
||||||
|
color: #333; |
||||||
|
} |
||||||
|
&.active { |
||||||
|
background: #e1e2e3; |
||||||
|
i { |
||||||
|
color: #2d8cf0; |
||||||
|
} |
||||||
|
} |
||||||
|
&.disable { |
||||||
|
i { |
||||||
|
color: #bbb; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.dag-container { |
||||||
|
height: calc(100% - 40px); |
||||||
|
overflow-x: auto; |
||||||
|
&::-webkit-scrollbar{ |
||||||
|
width: 9px; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.tools-model { |
||||||
|
height: 60px; |
||||||
|
background: #F4F5F4; |
||||||
|
border-radius: 3px 3px 0px 0px; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.v-modal-custom-log { |
||||||
|
z-index: 101; |
||||||
|
} |
||||||
|
|
||||||
|
svg path:hover { |
||||||
|
cursor: pointer; |
||||||
|
} |
||||||
|
|
||||||
|
#chart-container .ui-selecting { |
||||||
|
span { |
||||||
|
color: #0296DF; |
||||||
|
} |
||||||
|
} |
||||||
|
#chart-container .ui-selected { |
||||||
|
span { |
||||||
|
color: #0296DF; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.contextmenu { |
||||||
|
position: fixed; |
||||||
|
width: 90px; |
||||||
|
background: #fff; |
||||||
|
border-radius: 3px; |
||||||
|
box-shadow: 0 2px 4px 1px rgba(0, 0, 0, 0.1); |
||||||
|
padding: 4px 0; |
||||||
|
visibility:hidden; |
||||||
|
a { |
||||||
|
height: 30px; |
||||||
|
line-height: 28px; |
||||||
|
display: block; |
||||||
|
i { |
||||||
|
font-size: 16px; |
||||||
|
vertical-align: middle; |
||||||
|
margin-left: 10px; |
||||||
|
} |
||||||
|
span { |
||||||
|
vertical-align: middle; |
||||||
|
font-size: 12px; |
||||||
|
color: #666; |
||||||
|
padding-left: 2px; |
||||||
|
} |
||||||
|
&:hover { |
||||||
|
background: #f6faff; |
||||||
|
} |
||||||
|
&#startRunning { |
||||||
|
i { |
||||||
|
color: #35cd75; |
||||||
|
} |
||||||
|
} |
||||||
|
&#editNodes { |
||||||
|
i { |
||||||
|
color: #0097e0; |
||||||
|
} |
||||||
|
} |
||||||
|
&#removeNodes { |
||||||
|
i { |
||||||
|
color: #f04d4e; |
||||||
|
} |
||||||
|
} |
||||||
|
&#copyNodes { |
||||||
|
i { |
||||||
|
color: #FABC05; |
||||||
|
} |
||||||
|
} |
||||||
|
&.disbled { |
||||||
|
i,span { |
||||||
|
color: #aaa !important; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.jtk-demo { |
||||||
|
//min-width: calc(100% - 220px); |
||||||
|
width: 8000px; |
||||||
|
height: 5000px; |
||||||
|
position: relative; |
||||||
|
svg:not(:root){ |
||||||
|
z-index: 11; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.jtk-demo-canvas { |
||||||
|
height: 100%; |
||||||
|
} |
||||||
|
|
||||||
|
.jtk-bootstrap { |
||||||
|
min-height: 100vh; |
||||||
|
display: flex; |
||||||
|
flex-direction: column; |
||||||
|
} |
||||||
|
|
||||||
|
.jtk-bootstrap .jtk-page-container { |
||||||
|
display: flex; |
||||||
|
width: 100vw; |
||||||
|
justify-content: center; |
||||||
|
flex: 1; |
||||||
|
} |
||||||
|
|
||||||
|
.jtk-bootstrap .jtk-container { |
||||||
|
width: 60%; |
||||||
|
max-width: 800px; |
||||||
|
} |
||||||
|
|
||||||
|
.jtk-bootstrap-wide .jtk-container { |
||||||
|
width: 80%; |
||||||
|
max-width: 1187px; |
||||||
|
} |
||||||
|
|
||||||
|
.jtk-demo-main { |
||||||
|
position: relative; |
||||||
|
margin-top: 98px; |
||||||
|
} |
||||||
|
|
||||||
|
.jtk-demo-main .description { |
||||||
|
font-size: 13px; |
||||||
|
margin-top: 25px; |
||||||
|
padding: 13px; |
||||||
|
margin-bottom: 22px; |
||||||
|
background-color: #f4f5ef; |
||||||
|
} |
||||||
|
|
||||||
|
.jtk-demo-main .description li { |
||||||
|
list-style-type: disc !important; |
||||||
|
} |
||||||
|
|
||||||
|
.jtk-demo-canvas { |
||||||
|
display: flex; |
||||||
|
} |
||||||
|
|
||||||
|
.canvas-wide { |
||||||
|
padding-top: 10px; |
||||||
|
margin-left: 0; |
||||||
|
-ms-transition: all .1s ease-out; |
||||||
|
-moz-transition: all .1s ease-out; |
||||||
|
-webkit-transition: all .1s ease-out; |
||||||
|
-o-transition: all .1s ease-out; |
||||||
|
} |
||||||
|
|
||||||
|
.jtk-demo-dataset { |
||||||
|
text-align: left; |
||||||
|
max-height: 600px; |
||||||
|
overflow: auto; |
||||||
|
} |
||||||
|
|
||||||
|
.demo-title { |
||||||
|
float: left; |
||||||
|
font-size: 18px; |
||||||
|
} |
||||||
|
|
||||||
|
.controls { |
||||||
|
top: 25px; |
||||||
|
color: #FFF; |
||||||
|
margin-right: 10px; |
||||||
|
position: absolute; |
||||||
|
left: 25px; |
||||||
|
z-index: 1; |
||||||
|
} |
||||||
|
|
||||||
|
.controls i { |
||||||
|
background-color: #3E7E9C; |
||||||
|
border-radius: 4px; |
||||||
|
cursor: pointer; |
||||||
|
margin-right: 0; |
||||||
|
padding: 4px; |
||||||
|
} |
||||||
|
.w { |
||||||
|
position: absolute; |
||||||
|
z-index: 4; |
||||||
|
font-size: 11px; |
||||||
|
-webkit-transition: background-color 0.25s ease-in; |
||||||
|
-moz-transition: background-color 0.25s ease-in; |
||||||
|
transition: background-color 0.25s ease-in; |
||||||
|
border: 7px solid transparent; |
||||||
|
border-bottom: 30px solid transparent; |
||||||
|
.icos { |
||||||
|
width: 50px; |
||||||
|
height: 50px; |
||||||
|
box-shadow: 2px 2px 19px #e0e0e0; |
||||||
|
-o-box-shadow: 2px 2px 19px #e0e0e0; |
||||||
|
-webkit-box-shadow: 2px 2px 19px #e0e0e0; |
||||||
|
-moz-box-shadow: 2px 2px 19px #e0e0e0; |
||||||
|
-moz-border-radius: 8px; |
||||||
|
border-radius: 8px; |
||||||
|
opacity: 0.8; |
||||||
|
cursor: move; |
||||||
|
background-color: #fff; |
||||||
|
} |
||||||
|
.name-p { |
||||||
|
position: absolute; |
||||||
|
left: 50%; |
||||||
|
bottom: -24px; |
||||||
|
width: 200px; |
||||||
|
text-align: center; |
||||||
|
margin-left: -100px; |
||||||
|
} |
||||||
|
.state-p { |
||||||
|
width: 20px; |
||||||
|
height: 20px; |
||||||
|
position: absolute; |
||||||
|
top: -20px; |
||||||
|
left: 18px; |
||||||
|
text-align: center; |
||||||
|
cursor: pointer; |
||||||
|
b { |
||||||
|
font-weight: normal; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.aLabel { |
||||||
|
-webkit-transition: background-color 0.25s ease-in; |
||||||
|
-moz-transition: background-color 0.25s ease-in; |
||||||
|
transition: background-color 0.25s ease-in; |
||||||
|
} |
||||||
|
|
||||||
|
.aLabel.jtk-hover, |
||||||
|
.jtk-source-hover, |
||||||
|
.jtk-target-hover { |
||||||
|
.icos { |
||||||
|
background-color: #333; |
||||||
|
color: #333; |
||||||
|
-ms-transition: all 0.6s ease-out; |
||||||
|
-moz-transition: all 0.6s ease-out; |
||||||
|
-webkit-transition: all 0.6s ease-out; |
||||||
|
-o-transition: all 0.6s ease-out; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.jtk-tasks-active { |
||||||
|
.icos { |
||||||
|
background-color: #2db7f5; |
||||||
|
color: #0097e0; |
||||||
|
-ms-transition: all 0.6s ease-out; |
||||||
|
-moz-transition: all 0.6s ease-out; |
||||||
|
-webkit-transition: all 0.6s ease-out; |
||||||
|
-o-transition: all 0.6s ease-out; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.aLabel { |
||||||
|
background-color: white; |
||||||
|
opacity: 0.8; |
||||||
|
padding: 0.3em; |
||||||
|
border-radius: 0.5em; |
||||||
|
border: 1px solid #346789; |
||||||
|
cursor: pointer; |
||||||
|
} |
||||||
|
|
||||||
|
.jtk-ep { |
||||||
|
.ep { |
||||||
|
display: block; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.ep { |
||||||
|
position: absolute; |
||||||
|
top: -4%; |
||||||
|
right: -1px; |
||||||
|
width: 1em; |
||||||
|
height: 1em; |
||||||
|
z-index: 12; |
||||||
|
background-color: orange; |
||||||
|
cursor: pointer; |
||||||
|
box-shadow: 0 0 2px black; |
||||||
|
-webkit-transition: -webkit-box-shadow 0.25s ease-in; |
||||||
|
-moz-transition: -moz-box-shadow 0.25s ease-in; |
||||||
|
transition: box-shadow 0.25s ease-in; |
||||||
|
border-radius:100%; |
||||||
|
display: none; |
||||||
|
} |
||||||
|
|
||||||
|
.ep:hover { |
||||||
|
box-shadow: 0 0 6px black; |
||||||
|
} |
||||||
|
|
||||||
|
.statemachine-demo .jtk-endpoint { |
||||||
|
z-index: 3; |
||||||
|
} |
||||||
|
|
||||||
|
#canvas { |
||||||
|
.dot-style { |
||||||
|
opacity: 0; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.from-mirror { |
||||||
|
width: 100%; |
||||||
|
position: relative; |
||||||
|
z-index: 0; |
||||||
|
.CodeMirror { |
||||||
|
height:auto; |
||||||
|
min-height: 72px; |
||||||
|
} |
||||||
|
|
||||||
|
.CodeMirror-scroll { |
||||||
|
height:auto; |
||||||
|
min-height: 72px; |
||||||
|
overflow-y: hidden; |
||||||
|
overflow-x: auto; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.ans-drawer.ans-drawer-right { |
||||||
|
width: 628px; |
||||||
|
left: auto; |
||||||
|
} |
||||||
|
|
||||||
|
|
@ -0,0 +1,478 @@ |
|||||||
|
<template> |
||||||
|
<div class="clearfix dag-model" > |
||||||
|
<div class="toolbar"> |
||||||
|
<div class="title"><span>{{$t('工具栏')}}</span></div> |
||||||
|
<div class="toolbar-btn"> |
||||||
|
<div class="bar-box roundedRect jtk-draggable jtk-droppable jtk-endpoint-anchor jtk-connected" |
||||||
|
:class="v === dagBarId ? 'active' : ''" |
||||||
|
:id="v" |
||||||
|
v-for="(item,v) in tasksTypeList" |
||||||
|
@mousedown="_getDagId(v)"> |
||||||
|
<div data-toggle="tooltip" :title="item.desc" :class="_isDetails"> |
||||||
|
<div class="icos" :class="'icos-' + v" ></div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="dag-contect"> |
||||||
|
<div class="dag-toolbar"> |
||||||
|
<div class="assist-btn"> |
||||||
|
<x-button |
||||||
|
style="vertical-align: middle;" |
||||||
|
data-toggle="tooltip" |
||||||
|
:title="$t('查看变量')" |
||||||
|
data-container="body" |
||||||
|
type="primary" |
||||||
|
size="xsmall" |
||||||
|
:disabled="$route.name !== 'projects-instance-details'" |
||||||
|
@click="_toggleView" |
||||||
|
icon="fa fa-code"> |
||||||
|
</x-button> |
||||||
|
<span class="name">{{name}}</span> |
||||||
|
</div> |
||||||
|
<div class="save-btn"> |
||||||
|
<div class="operation" style="vertical-align: middle;"> |
||||||
|
<a href="javascript:" |
||||||
|
v-for="(item,$index) in toolOperList" |
||||||
|
:class="_operationClass(item)" |
||||||
|
:id="item.code" |
||||||
|
@click="_ckOperation(item,$event)"> |
||||||
|
<i class="iconfont" v-html="item.icon" data-toggle="tooltip" :title="item.desc" ></i> |
||||||
|
</a> |
||||||
|
</div> |
||||||
|
<x-button |
||||||
|
data-toggle="tooltip" |
||||||
|
:title="$t('刷新DAG状态')" |
||||||
|
data-container="body" |
||||||
|
style="vertical-align: middle;" |
||||||
|
icon="fa fa-refresh" |
||||||
|
type="primary" |
||||||
|
:loading="isRefresh" |
||||||
|
v-if="type === 'instance'" |
||||||
|
@click="!isRefresh && _refresh()" |
||||||
|
size="xsmall" > |
||||||
|
</x-button> |
||||||
|
<x-button |
||||||
|
v-if="isRtTasks" |
||||||
|
style="vertical-align: middle;" |
||||||
|
type="primary" |
||||||
|
size="xsmall" |
||||||
|
icon="fa fa-reply" |
||||||
|
@click="_rtNodesDag" > |
||||||
|
{{$t('返回上一节点')}} |
||||||
|
</x-button> |
||||||
|
<x-button |
||||||
|
style="vertical-align: middle;" |
||||||
|
type="primary" |
||||||
|
size="xsmall" |
||||||
|
:loading="spinnerLoading" |
||||||
|
v-ps="['GENERAL_USER']" |
||||||
|
@click="_saveChart" |
||||||
|
icon="fa fa-save" |
||||||
|
:disabled="isDetails"> |
||||||
|
{{spinnerLoading ? 'Loading...' : $t('保存')}} |
||||||
|
</x-button> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="scrollbar dag-container"> |
||||||
|
<div class="jtk-demo" id="jtk-demo"> |
||||||
|
<div class="jtk-demo-canvas canvas-wide statemachine-demo jtk-surface jtk-surface-nopan jtk-draggable" id="canvas" ></div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<script> |
||||||
|
import _ from 'lodash' |
||||||
|
import Dag from './dag' |
||||||
|
import mUdp from './udp/udp' |
||||||
|
import i18n from '@/module/i18n' |
||||||
|
import { jsPlumb } from 'jsplumb' |
||||||
|
import { allNodesId } from './plugIn/util' |
||||||
|
import { toolOper, tasksType } from './config' |
||||||
|
import mFormModel from './formModel/formModel' |
||||||
|
import { formatDate } from '@/module/filter/filter' |
||||||
|
import { findComponentDownward } from '@/module/util/' |
||||||
|
import disabledState from '@/module/mixin/disabledState' |
||||||
|
import { mapActions, mapState, mapMutations } from 'vuex' |
||||||
|
|
||||||
|
let eventModel |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'dag-chart', |
||||||
|
data () { |
||||||
|
return { |
||||||
|
tasksTypeList: tasksType, |
||||||
|
toolOperList: toolOper(this), |
||||||
|
dagBarId: null, |
||||||
|
toolOperCode: '', |
||||||
|
spinnerLoading: false, |
||||||
|
urlParam: { |
||||||
|
id: this.$route.params.id || null |
||||||
|
}, |
||||||
|
isRtTasks: false, |
||||||
|
isRefresh: false, |
||||||
|
isLoading: false, |
||||||
|
taskId: null |
||||||
|
} |
||||||
|
}, |
||||||
|
mixins: [disabledState], |
||||||
|
props: { |
||||||
|
type: String, |
||||||
|
releaseState: String |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
...mapActions('dag', ['saveDAGchart', 'updateInstance', 'updateDefinition', 'getTaskState']), |
||||||
|
...mapMutations('dag', ['addTasks', 'resetParams', 'setIsEditDag', 'setName']), |
||||||
|
init () { |
||||||
|
if (this.tasks.length) { |
||||||
|
Dag.backfill() |
||||||
|
// Process instances can view status |
||||||
|
if (this.type === 'instance') { |
||||||
|
this._getTaskState(false).then(res => {}) |
||||||
|
// Round robin acquisition status |
||||||
|
this.setIntervalP = setInterval(() => { |
||||||
|
this._getTaskState(true).then(res => {}) |
||||||
|
}, 90000) |
||||||
|
} |
||||||
|
} else { |
||||||
|
Dag.create() |
||||||
|
} |
||||||
|
}, |
||||||
|
/** |
||||||
|
* Get state interface |
||||||
|
* @param isReset Whether to manually refresh |
||||||
|
*/ |
||||||
|
_getTaskState (isReset) { |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
this.getTaskState(this.urlParam.id).then(res => { |
||||||
|
let data = res.list |
||||||
|
let state = res.processInstanceState |
||||||
|
let taskList = res.taskList |
||||||
|
let idArr = allNodesId() |
||||||
|
const titleTpl = (item, desc) => { |
||||||
|
let $item = _.filter(taskList, v => v.name === item.name)[0] |
||||||
|
return `<div style="text-align: left">${i18n.$t('名称')}:${$item.name}</br>${i18n.$t('状态')}:${desc}</br>${i18n.$t('类型')}:${$item.taskType}</br>${i18n.$t('host')}:${$item.host || '-'}</br>${i18n.$t('重试次数')}:${$item.retryTimes}</br>${i18n.$t('提交时间')}:${formatDate($item.submitTime)}</br>${i18n.$t('开始时间')}:${formatDate($item.startTime)}</br>${i18n.$t('结束时间')}:${$item.endTime ? formatDate($item.endTime) : '-'}</br></div>` |
||||||
|
} |
||||||
|
data.forEach(v1 => { |
||||||
|
idArr.forEach(v2 => { |
||||||
|
if (v2.name === v1.name) { |
||||||
|
let dom = $(`#${v2.id}`) |
||||||
|
let state = dom.find('.state-p') |
||||||
|
dom.attr('data-state-id', v1.stateId) |
||||||
|
dom.attr('data-dependent-result', v1.dependentResult || '') |
||||||
|
state.html('') |
||||||
|
state.append(`<b class="iconfont ${v1.isSpin ? 'fa fa-spin' : ''}" style="color:${v1.color}" data-toggle="tooltip" data-html="true" data-container="body">${v1.icoUnicode}</b>`) |
||||||
|
state.find('b').attr('title', titleTpl(v2, v1.desc)) |
||||||
|
} |
||||||
|
}) |
||||||
|
}) |
||||||
|
if (state === 'PAUSE' || state === 'STOP' || state === 'FAILURE' || this.state === 'SUCCESS') { |
||||||
|
// Manual refresh does not regain large json |
||||||
|
if (isReset) { |
||||||
|
findComponentDownward(this.$root, `${this.type}-details`)._reset() |
||||||
|
} |
||||||
|
} |
||||||
|
resolve() |
||||||
|
}) |
||||||
|
}) |
||||||
|
}, |
||||||
|
/** |
||||||
|
* Get the action bar id |
||||||
|
* @param item |
||||||
|
*/ |
||||||
|
_getDagId (v) { |
||||||
|
if (this.isDetails) { |
||||||
|
return |
||||||
|
} |
||||||
|
this.dagBarId = v |
||||||
|
}, |
||||||
|
/** |
||||||
|
* operating |
||||||
|
*/ |
||||||
|
_ckOperation (item) { |
||||||
|
let is = true |
||||||
|
let code = '' |
||||||
|
|
||||||
|
if (!item.disable) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
if (this.toolOperCode === item.code) { |
||||||
|
this.toolOperCode = '' |
||||||
|
code = item.code |
||||||
|
is = false |
||||||
|
} else { |
||||||
|
this.toolOperCode = item.code |
||||||
|
code = this.toolOperCode |
||||||
|
is = true |
||||||
|
} |
||||||
|
|
||||||
|
// event type |
||||||
|
Dag.toolbarEvent({ |
||||||
|
item: item, |
||||||
|
code: code, |
||||||
|
is: is |
||||||
|
}) |
||||||
|
}, |
||||||
|
_operationClass (item) { |
||||||
|
if (item.disable) { |
||||||
|
return this.toolOperCode === item.code ? 'active' : '' |
||||||
|
} else { |
||||||
|
return 'disable' |
||||||
|
} |
||||||
|
}, |
||||||
|
/** |
||||||
|
* Storage interface |
||||||
|
*/ |
||||||
|
_save (sourceType) { |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
this.spinnerLoading = true |
||||||
|
// Storage store |
||||||
|
Dag.saveStore().then(res => { |
||||||
|
if (this.urlParam.id) { |
||||||
|
/** |
||||||
|
* 编辑 |
||||||
|
* @param saveInstanceEditDAGChart => Process instance editing |
||||||
|
* @param saveEditDAGChart => Process definition editing |
||||||
|
*/ |
||||||
|
this[this.type === 'instance' ? 'updateInstance' : 'updateDefinition'](this.urlParam.id).then(res => { |
||||||
|
this.$message.success(res.msg) |
||||||
|
this.spinnerLoading = false |
||||||
|
resolve() |
||||||
|
}).catch(e => { |
||||||
|
this.$message.error(e.msg || '') |
||||||
|
this.spinnerLoading = false |
||||||
|
reject(e) |
||||||
|
}) |
||||||
|
} else { |
||||||
|
// New |
||||||
|
this.saveDAGchart().then(res => { |
||||||
|
this.$message.success(res.msg) |
||||||
|
this.spinnerLoading = false |
||||||
|
// source @/conf/home/pages/dag/_source/editAffirmModel/index.js |
||||||
|
if (sourceType !== 'affirm') { |
||||||
|
// Jump process definition |
||||||
|
this.$router.push({ name: 'projects-definition-list' }) |
||||||
|
} |
||||||
|
resolve() |
||||||
|
}).catch(e => { |
||||||
|
this.$message.error(e.msg || '') |
||||||
|
this.setName('') |
||||||
|
this.spinnerLoading = false |
||||||
|
reject(e) |
||||||
|
}) |
||||||
|
} |
||||||
|
}) |
||||||
|
}) |
||||||
|
}, |
||||||
|
/** |
||||||
|
* Global parameter |
||||||
|
* @param Promise |
||||||
|
*/ |
||||||
|
_udpTopFloorPop () { |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
let modal = this.$modal.dialog({ |
||||||
|
closable: false, |
||||||
|
showMask: true, |
||||||
|
escClose: true, |
||||||
|
className: 'v-modal-custom', |
||||||
|
transitionName: 'opacityp', |
||||||
|
render (h) { |
||||||
|
return h(mUdp, { |
||||||
|
on: { |
||||||
|
onUdp () { |
||||||
|
modal.remove() |
||||||
|
resolve() |
||||||
|
}, |
||||||
|
close () { |
||||||
|
modal.remove() |
||||||
|
} |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
}) |
||||||
|
}) |
||||||
|
}, |
||||||
|
/** |
||||||
|
* Save chart |
||||||
|
*/ |
||||||
|
_saveChart () { |
||||||
|
// Verify node |
||||||
|
if (!this.tasks.length) { |
||||||
|
this.$message.warning(`${i18n.$t('未创建节点保存失败')}`) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// Global parameters (optional) |
||||||
|
this._udpTopFloorPop().then(() => { |
||||||
|
return this._save() |
||||||
|
}) |
||||||
|
}, |
||||||
|
/** |
||||||
|
* Return to the previous child node |
||||||
|
*/ |
||||||
|
_rtNodesDag () { |
||||||
|
let getIds = this.$route.query.subProcessIds |
||||||
|
let idsArr = getIds.split(',') |
||||||
|
let ids = idsArr.slice(0, idsArr.length - 1) |
||||||
|
let id = idsArr[idsArr.length - 1] |
||||||
|
let query = {} |
||||||
|
|
||||||
|
if (id !== idsArr[0]) { |
||||||
|
query = { subProcessIds: ids.join(',') } |
||||||
|
} |
||||||
|
let $name = this.$route.name.split('-') |
||||||
|
this.$router.push({ path: `/${$name[0]}/${$name[1]}/list/${id}`, query: query }) |
||||||
|
}, |
||||||
|
/** |
||||||
|
* Subprocess processing |
||||||
|
* @param subProcessId Subprocess ID |
||||||
|
*/ |
||||||
|
_subProcessHandle (subProcessId) { |
||||||
|
let subProcessIds = [] |
||||||
|
let getIds = this.$route.query.subProcessIds |
||||||
|
if (getIds) { |
||||||
|
let newId = getIds.split(',') |
||||||
|
newId.push(this.urlParam.id) |
||||||
|
subProcessIds = newId |
||||||
|
} else { |
||||||
|
subProcessIds.push(this.urlParam.id) |
||||||
|
} |
||||||
|
let $name = this.$route.name.split('-') |
||||||
|
this.$router.push({ path: `/${$name[0]}/${$name[1]}/list/${subProcessId}`, query: { subProcessIds: subProcessIds.join(',') } }) |
||||||
|
}, |
||||||
|
/** |
||||||
|
* Refresh data |
||||||
|
*/ |
||||||
|
_refresh () { |
||||||
|
this.isRefresh = true |
||||||
|
this._getTaskState(false).then(res => { |
||||||
|
setTimeout(() => { |
||||||
|
this.isRefresh = false |
||||||
|
this.$message.success(`${i18n.$t('刷新状态成功')}`) |
||||||
|
}, 2200) |
||||||
|
}) |
||||||
|
}, |
||||||
|
/** |
||||||
|
* View variables |
||||||
|
*/ |
||||||
|
_toggleView () { |
||||||
|
findComponentDownward(this.$root, `assist-dag-index`)._toggleView() |
||||||
|
}, |
||||||
|
/** |
||||||
|
* Create a node popup layer |
||||||
|
* @param Object id |
||||||
|
*/ |
||||||
|
_createNodes ({ id, type }) { |
||||||
|
let self = this |
||||||
|
|
||||||
|
if (eventModel) { |
||||||
|
eventModel.remove() |
||||||
|
} |
||||||
|
|
||||||
|
const removeNodesEvent = (fromThis) => { |
||||||
|
// Manually destroy events inside the component |
||||||
|
fromThis.$destroy() |
||||||
|
// Close the popup |
||||||
|
eventModel.remove() |
||||||
|
} |
||||||
|
|
||||||
|
this.taskId = id |
||||||
|
|
||||||
|
eventModel = this.$drawer({ |
||||||
|
closable: false, |
||||||
|
direction: 'right', |
||||||
|
escClose: true, |
||||||
|
render: h => h(mFormModel, { |
||||||
|
on: { |
||||||
|
addTaskInfo ({ item, fromThis }) { |
||||||
|
self.addTasks(item) |
||||||
|
setTimeout(() => { |
||||||
|
removeNodesEvent(fromThis) |
||||||
|
}, 100) |
||||||
|
}, |
||||||
|
close ({ flag, fromThis }) { |
||||||
|
// Edit status does not allow deletion of nodes |
||||||
|
if (flag) { |
||||||
|
jsPlumb.remove(id) |
||||||
|
} |
||||||
|
|
||||||
|
removeNodesEvent(fromThis) |
||||||
|
}, |
||||||
|
onSubProcess ({ subProcessId, fromThis }) { |
||||||
|
removeNodesEvent(fromThis) |
||||||
|
self._subProcessHandle(subProcessId) |
||||||
|
} |
||||||
|
}, |
||||||
|
props: { |
||||||
|
id: id, |
||||||
|
taskType: type || self.dagBarId, |
||||||
|
self: self |
||||||
|
} |
||||||
|
}) |
||||||
|
}) |
||||||
|
} |
||||||
|
}, |
||||||
|
watch: { |
||||||
|
'tasks': { |
||||||
|
deep: true, |
||||||
|
handler () { |
||||||
|
console.log('+++++ save dag params +++++') |
||||||
|
// Edit state does not allow deletion of node a... |
||||||
|
this.setIsEditDag(true) |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
created () { |
||||||
|
// Edit state does not allow deletion of node a... |
||||||
|
this.setIsEditDag(false) |
||||||
|
|
||||||
|
if (this.$route.query.subProcessIds) { |
||||||
|
this.isRtTasks = true |
||||||
|
} |
||||||
|
|
||||||
|
Dag.init({ |
||||||
|
dag: this, |
||||||
|
instance: jsPlumb.getInstance({ |
||||||
|
Endpoint: [ |
||||||
|
'Dot', { radius: 1, cssClass: 'dot-style' } |
||||||
|
], |
||||||
|
Connector: 'Straight', |
||||||
|
PaintStyle: { lineWidth: 2, stroke: '#456' }, // Connection style |
||||||
|
ConnectionOverlays: [ |
||||||
|
[ |
||||||
|
'Arrow', |
||||||
|
{ |
||||||
|
location: 1, |
||||||
|
id: 'arrow', |
||||||
|
length: 12, |
||||||
|
foldback: 0.8 |
||||||
|
} |
||||||
|
] |
||||||
|
], |
||||||
|
Container: 'canvas' |
||||||
|
}) |
||||||
|
}) |
||||||
|
}, |
||||||
|
mounted () { |
||||||
|
this.init() |
||||||
|
}, |
||||||
|
beforeDestroy () { |
||||||
|
this.resetParams() |
||||||
|
|
||||||
|
// Destroy round robin |
||||||
|
clearInterval(this.setIntervalP) |
||||||
|
}, |
||||||
|
destroyed () { |
||||||
|
}, |
||||||
|
computed: { |
||||||
|
...mapState('dag', ['tasks', 'locations', 'connects', 'isEditDag', 'name']) |
||||||
|
}, |
||||||
|
components: {} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style lang="scss" rel="stylesheet/scss"> |
||||||
|
@import "dag"; |
||||||
|
</style> |
@ -0,0 +1,101 @@ |
|||||||
|
<template> |
||||||
|
<x-select |
||||||
|
style="width: 170px;" |
||||||
|
:disabled="isDetails" |
||||||
|
@on-change="_onChange" |
||||||
|
v-model="value"> |
||||||
|
<x-input |
||||||
|
ref="input" |
||||||
|
slot="trigger" |
||||||
|
v-if="isInput" |
||||||
|
:disabled="isDetails" |
||||||
|
slot-scope="{ selectedModel }" |
||||||
|
maxlength="4" |
||||||
|
@on-blur="_onBlur" |
||||||
|
:placeholder="$t('请选择')" |
||||||
|
:value="selectedModel === null ? '0' : selectedModel.value" |
||||||
|
style="width: 100%;" |
||||||
|
@on-click-icon.stop="_ckIcon"> |
||||||
|
<i slot="suffix" class="fa fa-times-circle" style="font-size: 15px;cursor: pointer;" v-show="!isIconState"></i> |
||||||
|
<i slot="suffix" class="ans-icon-arrow-down" style="font-size: 12px;" v-show="isIconState"></i> |
||||||
|
</x-input> |
||||||
|
<x-option |
||||||
|
v-for="city in list" |
||||||
|
:key="city" |
||||||
|
:value="city" |
||||||
|
:label="city"> |
||||||
|
</x-option> |
||||||
|
</x-select> |
||||||
|
</template> |
||||||
|
<script> |
||||||
|
import _ from 'lodash' |
||||||
|
import i18n from '@/module/i18n' |
||||||
|
import disabledState from '@/module/mixin/disabledState' |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'select-input', |
||||||
|
data () { |
||||||
|
return { |
||||||
|
isIconState: false, |
||||||
|
isInput: true |
||||||
|
} |
||||||
|
}, |
||||||
|
mixins: [disabledState], |
||||||
|
props: { |
||||||
|
value: String, |
||||||
|
list: Array |
||||||
|
}, |
||||||
|
model: { |
||||||
|
prop: 'value', |
||||||
|
event: 'valueEvent' |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
_onChange (o) { |
||||||
|
this.$emit('valueEvent', +o.value) |
||||||
|
this._setIconState(+o.value) |
||||||
|
}, |
||||||
|
_setIconState (value) { |
||||||
|
// Whether there is a list |
||||||
|
this.isIconState = _.includes(this.list, parseInt(value)) |
||||||
|
}, |
||||||
|
_ckIcon () { |
||||||
|
if (this.isDetails) { |
||||||
|
return |
||||||
|
} |
||||||
|
this.isInput = false |
||||||
|
this.$emit('valueEvent', +this.list[0]) |
||||||
|
this.isIconState = true |
||||||
|
// Refresh instance |
||||||
|
setTimeout(() => { |
||||||
|
this.isInput = true |
||||||
|
}, 1) |
||||||
|
}, |
||||||
|
_onBlur () { |
||||||
|
let val = $(this.$refs['input'].$el).find('input')[0].value |
||||||
|
if (this._validation(val)) { |
||||||
|
this.$emit('valueEvent', val) |
||||||
|
this._setIconState(val) |
||||||
|
} |
||||||
|
}, |
||||||
|
_validation (val) { |
||||||
|
if (val === '0') return true |
||||||
|
|
||||||
|
if (!(/(^[0-9]*[1-9][0-9]*$)/.test(val))) { |
||||||
|
this.$message.warning(`${i18n.$t('请输入正整数')}`) |
||||||
|
// init |
||||||
|
this._ckIcon() |
||||||
|
return false |
||||||
|
} |
||||||
|
return true |
||||||
|
} |
||||||
|
}, |
||||||
|
watch: { |
||||||
|
}, |
||||||
|
created () { |
||||||
|
this._setIconState(this.value) |
||||||
|
}, |
||||||
|
mounted () { |
||||||
|
}, |
||||||
|
components: {} |
||||||
|
} |
||||||
|
</script> |
@ -0,0 +1,113 @@ |
|||||||
|
<template> |
||||||
|
<div class="timeout-alarm-model"> |
||||||
|
<div class="clearfix list"> |
||||||
|
<div class="text-box"> |
||||||
|
<span>{{$t('任务超时告警')}}</span> |
||||||
|
</div> |
||||||
|
<div class="cont-box"> |
||||||
|
<label class="label-box"> |
||||||
|
<div style="padding-top: 5px;"> |
||||||
|
<x-switch v-model="enable" @on-click="_onSwitch" :disabled="isDetails"></x-switch> |
||||||
|
</div> |
||||||
|
</label> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="clearfix list" v-if="enable"> |
||||||
|
<div class="text-box"> |
||||||
|
<span>{{$t('超时策略')}}</span> |
||||||
|
</div> |
||||||
|
<div class="cont-box"> |
||||||
|
<label class="label-box"> |
||||||
|
<div style="padding-top: 6px;"> |
||||||
|
<x-checkbox-group v-model="strategy"> |
||||||
|
<x-checkbox label="WARN" :disabled="isDetails">{{$t('超时告警')}}</x-checkbox> |
||||||
|
<x-checkbox label="FAILED" :disabled="isDetails">{{$t('超时失败')}}</x-checkbox> |
||||||
|
</x-checkbox-group> |
||||||
|
</div> |
||||||
|
</label> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="clearfix list" v-if="enable"> |
||||||
|
<div class="text-box"> |
||||||
|
<span>{{$t('超时时长')}}</span> |
||||||
|
</div> |
||||||
|
<div class="cont-box"> |
||||||
|
<label class="label-box"> |
||||||
|
<x-input v-model="interval" style="width: 128px;" :disabled="isDetails"> |
||||||
|
<span slot="append">{{$t('分')}}</span> |
||||||
|
</x-input> |
||||||
|
</label> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<script> |
||||||
|
import _ from 'lodash' |
||||||
|
import disabledState from '@/module/mixin/disabledState' |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'timeout-alarm', |
||||||
|
data () { |
||||||
|
return { |
||||||
|
// Timeout display hiding |
||||||
|
enable: false, |
||||||
|
// Timeout strategy |
||||||
|
strategy: [], |
||||||
|
// Timeout period |
||||||
|
interval: null |
||||||
|
} |
||||||
|
}, |
||||||
|
mixins: [disabledState], |
||||||
|
props: { |
||||||
|
backfillItem: Object |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
_onSwitch (is) { |
||||||
|
// Timeout strategy |
||||||
|
this.strategy = is ? ['WARN'] : [] |
||||||
|
// Timeout period |
||||||
|
this.interval = is ? 30 : null |
||||||
|
}, |
||||||
|
_verification () { |
||||||
|
// Verification timeout policy |
||||||
|
if (this.enable && !this.strategy.length) { |
||||||
|
this.$message.warning(`${this.$t('超时策略必须选一个')}`) |
||||||
|
return false |
||||||
|
} |
||||||
|
// Verify timeout duration Non 0 positive integer |
||||||
|
if (this.enable && !parseInt(this.interval) && !_.isInteger(this.interval)) { |
||||||
|
this.$message.warning(`${this.$t('超时时长必须为正整数')}`) |
||||||
|
return false |
||||||
|
} |
||||||
|
this.$emit('on-timeout', { |
||||||
|
strategy: (() => { |
||||||
|
// Handling checkout sequence |
||||||
|
let strategy = this.strategy |
||||||
|
if (strategy.length === 2 && strategy[0] === 'FAILED') { |
||||||
|
return [strategy[1], strategy[0]].join(',') |
||||||
|
} else { |
||||||
|
return strategy.join(',') |
||||||
|
} |
||||||
|
})(), |
||||||
|
interval: parseInt(this.interval), |
||||||
|
enable: this.enable |
||||||
|
}) |
||||||
|
return true |
||||||
|
} |
||||||
|
}, |
||||||
|
watch: { |
||||||
|
}, |
||||||
|
created () { |
||||||
|
let o = this.backfillItem |
||||||
|
// Non-null objects represent backfill |
||||||
|
if (!_.isEmpty(o) && o.timeout) { |
||||||
|
this.enable = o.timeout.enable || false |
||||||
|
this.strategy = _.split(o.timeout.strategy, ',') || ['WARN'] |
||||||
|
this.interval = o.timeout.interval || null |
||||||
|
} |
||||||
|
}, |
||||||
|
mounted () { |
||||||
|
}, |
||||||
|
components: {} |
||||||
|
} |
||||||
|
</script> |
@ -0,0 +1,554 @@ |
|||||||
|
<template> |
||||||
|
<div class="form-model-model" v-clickoutside="_handleClose"> |
||||||
|
<div class="title-box"> |
||||||
|
<span class="name">{{$t('当前节点设置')}}</span> |
||||||
|
<span class="go-subtask"> |
||||||
|
<!-- Component can't pop up box to do component processing --> |
||||||
|
<m-log :item="backfillItem"> |
||||||
|
<template slot="history"><a href="javascript:" @click="_seeHistory" ><i class="iconfont"></i><em>{{$t('查看历史')}}</em></a></template> |
||||||
|
<template slot="log"><a href="javascript:"><i class="iconfont"></i><em>{{$t('查看日志')}}</em></a></template> |
||||||
|
</m-log> |
||||||
|
<a href="javascript:" @click="_goSubProcess" v-if="_isGoSubProcess"><i class="iconfont"></i><em>{{$t('进入该子节点')}}</em></a> |
||||||
|
</span> |
||||||
|
</div> |
||||||
|
<div class="content-box" v-if="isContentBox"> |
||||||
|
<div class="from-model"> |
||||||
|
|
||||||
|
<!-- Node name --> |
||||||
|
<div class="clearfix list"> |
||||||
|
<div class="text-box"><span>{{$t('节点名称')}}</span></div> |
||||||
|
<div class="cont-box"> |
||||||
|
<label class="label-box"> |
||||||
|
<x-input |
||||||
|
type="text" |
||||||
|
v-model="name" |
||||||
|
:disabled="isDetails" |
||||||
|
:placeholder="$t('请输入name(必填)')" |
||||||
|
maxlength="100" |
||||||
|
@on-blur="_verifName()" |
||||||
|
autocomplete="off"> |
||||||
|
</x-input> |
||||||
|
</label> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<!-- Running sign --> |
||||||
|
<div class="clearfix list"> |
||||||
|
<div class="text-box"><span>{{$t('运行标志')}}</span></div> |
||||||
|
<div class="cont-box"> |
||||||
|
<label class="label-box"> |
||||||
|
<x-radio-group v-model="runFlag" > |
||||||
|
<x-radio :label="'NORMAL'" :disabled="isDetails">{{$t('正常')}}</x-radio> |
||||||
|
<x-radio :label="'FORBIDDEN'" :disabled="isDetails">{{$t('禁止执行')}}</x-radio> |
||||||
|
</x-radio-group> |
||||||
|
</label> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<!-- desc --> |
||||||
|
<div class="clearfix list"> |
||||||
|
<div class="text-box"> |
||||||
|
<span>{{$t('描述')}}</span> |
||||||
|
</div> |
||||||
|
<div class="cont-box"> |
||||||
|
|
||||||
|
<label class="label-box"> |
||||||
|
<x-input |
||||||
|
resize |
||||||
|
:autosize="{minRows:2}" |
||||||
|
type="textarea" |
||||||
|
:disabled="isDetails" |
||||||
|
v-model="desc" |
||||||
|
:placeholder="$t('请输入desc')" |
||||||
|
autocomplete="off"> |
||||||
|
</x-input> |
||||||
|
</label> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<!-- Task priority --> |
||||||
|
<div class="clearfix list"> |
||||||
|
<div class="text-box"> |
||||||
|
<span>{{$t('任务优先级')}}</span> |
||||||
|
</div> |
||||||
|
<div class="cont-box"> |
||||||
|
<label class="label-box"> |
||||||
|
<m-priority v-model="taskInstancePriority" style="width: 180px;"></m-priority> |
||||||
|
</label> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<!-- Number of failed retries --> |
||||||
|
<div class="clearfix list" v-if="taskType !== 'SUB_PROCESS'"> |
||||||
|
<div class="text-box"> |
||||||
|
<span>{{$t('失败重试次数')}}</span> |
||||||
|
</div> |
||||||
|
<div class="cont-box"> |
||||||
|
<m-select-input v-model="maxRetryTimes" :list="[0,1,2,3,4]"> |
||||||
|
</m-select-input> |
||||||
|
<span>({{$t('次')}})</span> |
||||||
|
<span class="text-b">{{$t('失败重试间隔')}}</span> |
||||||
|
<m-select-input v-model="retryInterval" :list="[1,10,30,60,120]"> |
||||||
|
</m-select-input> |
||||||
|
<span>({{$t('分')}})</span> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<!-- Task timeout alarm --> |
||||||
|
<m-timeout-alarm |
||||||
|
ref="timeout" |
||||||
|
:backfill-item="backfillItem" |
||||||
|
@on-timeout="_onTimeout"> |
||||||
|
</m-timeout-alarm> |
||||||
|
|
||||||
|
<!-- shell node --> |
||||||
|
<m-shell |
||||||
|
v-if="taskType === 'SHELL'" |
||||||
|
@on-params="_onParams" |
||||||
|
ref="SHELL" |
||||||
|
:backfill-item="backfillItem"> |
||||||
|
</m-shell> |
||||||
|
<!-- sub_process node --> |
||||||
|
<m-sub-process |
||||||
|
v-if="taskType === 'SUB_PROCESS'" |
||||||
|
@on-params="_onParams" |
||||||
|
@on-set-process-name="_onSetProcessName" |
||||||
|
ref="SUB_PROCESS" |
||||||
|
:backfill-item="backfillItem"> |
||||||
|
</m-sub-process> |
||||||
|
<!-- procedure node --> |
||||||
|
<m-procedure |
||||||
|
v-if="taskType === 'PROCEDURE'" |
||||||
|
@on-params="_onParams" |
||||||
|
ref="PROCEDURE" |
||||||
|
:backfill-item="backfillItem"> |
||||||
|
</m-procedure> |
||||||
|
<!-- sql node --> |
||||||
|
<m-sql |
||||||
|
v-if="taskType === 'SQL'" |
||||||
|
@on-params="_onParams" |
||||||
|
ref="SQL" |
||||||
|
:backfill-item="backfillItem"> |
||||||
|
</m-sql> |
||||||
|
<!-- spark node --> |
||||||
|
<m-spark |
||||||
|
v-if="taskType === 'SPARK'" |
||||||
|
@on-params="_onParams" |
||||||
|
ref="SPARK" |
||||||
|
:backfill-item="backfillItem"> |
||||||
|
</m-spark> |
||||||
|
<!-- mr node --> |
||||||
|
<m-mr |
||||||
|
v-if="taskType === 'MR'" |
||||||
|
@on-params="_onParams" |
||||||
|
ref="MR" |
||||||
|
:backfill-item="backfillItem"> |
||||||
|
</m-mr> |
||||||
|
<!-- python node --> |
||||||
|
<m-python |
||||||
|
v-if="taskType === 'PYTHON'" |
||||||
|
@on-params="_onParams" |
||||||
|
ref="PYTHON" |
||||||
|
:backfill-item="backfillItem"> |
||||||
|
</m-python> |
||||||
|
<!-- dependent node --> |
||||||
|
<m-dependent |
||||||
|
v-if="taskType === 'DEPENDENT'" |
||||||
|
@on-dependent="_onDependent" |
||||||
|
ref="DEPENDENT" |
||||||
|
:backfill-item="backfillItem"> |
||||||
|
</m-dependent> |
||||||
|
|
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="bottom-box"> |
||||||
|
<div class="submit" style="background: #fff;"> |
||||||
|
<x-button type="text" @click="close()"> {{$t('取消')}} </x-button> |
||||||
|
<x-button type="primary" shape="circle" :loading="spinnerLoading" @click="ok()" :disabled="isDetails" v-ps="['GENERAL_USER']">{{spinnerLoading ? 'Loading...' : $t('确认添加')}} </x-button> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<script> |
||||||
|
import _ from 'lodash' |
||||||
|
import mLog from './log' |
||||||
|
import mMr from './tasks/mr' |
||||||
|
import mSql from './tasks/sql' |
||||||
|
import i18n from '@/module/i18n' |
||||||
|
import mShell from './tasks/shell' |
||||||
|
import mSpark from './tasks/spark' |
||||||
|
import mPython from './tasks/python' |
||||||
|
import { isNameExDag } from './../plugIn/util' |
||||||
|
import JSP from './../plugIn/jsPlumbHandle' |
||||||
|
import mProcedure from './tasks/procedure' |
||||||
|
import mDependent from './tasks/dependent' |
||||||
|
import mSubProcess from './tasks/sub_process' |
||||||
|
import mSelectInput from './_source/selectInput' |
||||||
|
import mTimeoutAlarm from './_source/timeoutAlarm' |
||||||
|
import clickoutside from '@/module/util/clickoutside' |
||||||
|
import disabledState from '@/module/mixin/disabledState' |
||||||
|
import mPriority from '@/module/components/priority/priority' |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'form-model', |
||||||
|
data () { |
||||||
|
return { |
||||||
|
// loading |
||||||
|
spinnerLoading: false, |
||||||
|
// node name |
||||||
|
name: ``, |
||||||
|
// desc |
||||||
|
desc: '', |
||||||
|
// Node echo data |
||||||
|
backfillItem: {}, |
||||||
|
// Resource(list) |
||||||
|
resourcesList: [], |
||||||
|
// dependence |
||||||
|
dependence: {}, |
||||||
|
// Current node params data |
||||||
|
params: {}, |
||||||
|
// Running sign |
||||||
|
runFlag: 'NORMAL', |
||||||
|
// The second echo problem caused by the node data is specifically which node hook caused the unfinished special treatment |
||||||
|
isContentBox: false, |
||||||
|
// Number of failed retries |
||||||
|
maxRetryTimes: '0', |
||||||
|
// Failure retry interval |
||||||
|
retryInterval: '1', |
||||||
|
// Task timeout alarm |
||||||
|
timeout: {}, |
||||||
|
// Task priority |
||||||
|
taskInstancePriority: 'MEDIUM' |
||||||
|
} |
||||||
|
}, |
||||||
|
/** |
||||||
|
* Click on events that are not generated internally by the component |
||||||
|
*/ |
||||||
|
directives: { clickoutside }, |
||||||
|
mixins: [disabledState], |
||||||
|
props: { |
||||||
|
id: Number, |
||||||
|
taskType: String, |
||||||
|
self: Object |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
/** |
||||||
|
* depend |
||||||
|
*/ |
||||||
|
_onDependent (o) { |
||||||
|
this.dependence = Object.assign(this.dependence, {}, o) |
||||||
|
}, |
||||||
|
/** |
||||||
|
* Task timeout alarm |
||||||
|
*/ |
||||||
|
_onTimeout (o) { |
||||||
|
this.timeout = Object.assign(this.timeout, {}, o) |
||||||
|
}, |
||||||
|
/** |
||||||
|
* Click external to close the current component |
||||||
|
*/ |
||||||
|
_handleClose () { |
||||||
|
this.close() |
||||||
|
}, |
||||||
|
/** |
||||||
|
* Jump to task instance |
||||||
|
*/ |
||||||
|
_seeHistory () { |
||||||
|
this.self.$router.push({ |
||||||
|
name: 'task-instance-list', |
||||||
|
query: { |
||||||
|
processInstanceId: this.self.$route.params.id, |
||||||
|
taskName: this.backfillItem.name |
||||||
|
} |
||||||
|
}) |
||||||
|
this.$modal.destroy() |
||||||
|
}, |
||||||
|
/** |
||||||
|
* Enter the child node to judge the process instance or the process definition |
||||||
|
* @param type = instance |
||||||
|
*/ |
||||||
|
_goSubProcess () { |
||||||
|
if (_.isEmpty(this.backfillItem)) { |
||||||
|
this.$message.warning(`${i18n.$t('新创建子工作流还未执行,不能进入子工作流')}`) |
||||||
|
return |
||||||
|
} |
||||||
|
if (this.router.history.current.name === 'projects-instance-details') { |
||||||
|
let stateId = $(`#${this.id}`).attr('data-state-id') || null |
||||||
|
if (!stateId) { |
||||||
|
this.$message.warning(`${i18n.$t('该任务还未执行,不能进入子工作流')}`) |
||||||
|
return |
||||||
|
} |
||||||
|
this.store.dispatch('dag/getSubProcessId', { taskId: stateId }).then(res => { |
||||||
|
this.$emit('onSubProcess', { |
||||||
|
subProcessId: res.data.subProcessInstanceId, |
||||||
|
fromThis: this |
||||||
|
}) |
||||||
|
}).catch(e => { |
||||||
|
this.$message.error(e.msg || '') |
||||||
|
}) |
||||||
|
} else { |
||||||
|
this.$emit('onSubProcess', { |
||||||
|
subProcessId: this.backfillItem.params.processDefinitionId, |
||||||
|
fromThis: this |
||||||
|
}) |
||||||
|
} |
||||||
|
}, |
||||||
|
/** |
||||||
|
* return params |
||||||
|
*/ |
||||||
|
_onParams (o) { |
||||||
|
this.params = Object.assign(this.params, {}, o) |
||||||
|
}, |
||||||
|
/** |
||||||
|
* verification name |
||||||
|
*/ |
||||||
|
_verifName () { |
||||||
|
if (!_.trim(this.name)) { |
||||||
|
this.$message.warning(`${i18n.$t('请输入名称(必填)')}`) |
||||||
|
return false |
||||||
|
} |
||||||
|
if (this.name === this.backfillItem.name) { |
||||||
|
return true |
||||||
|
} |
||||||
|
// Name repeat depends on dom backfill dependent store |
||||||
|
if (isNameExDag(this.name, _.isEmpty(this.backfillItem) ? 'dom' : 'backfill')) { |
||||||
|
this.$message.warning(`${i18n.$t('名称已存在请重新输入')}`) |
||||||
|
return false |
||||||
|
} |
||||||
|
return true |
||||||
|
}, |
||||||
|
/** |
||||||
|
* Global verification procedure |
||||||
|
*/ |
||||||
|
_verification () { |
||||||
|
// Verify name |
||||||
|
if (!this._verifName()) { |
||||||
|
return |
||||||
|
} |
||||||
|
// Verify task alarm parameters |
||||||
|
if (!this.$refs['timeout']._verification()) { |
||||||
|
return |
||||||
|
} |
||||||
|
// Verify node parameters |
||||||
|
if (!this.$refs[this.taskType]._verification()) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
$(`#${this.id}`).find('span').text(this.name) |
||||||
|
|
||||||
|
// Store the corresponding node data structure |
||||||
|
this.$emit('addTaskInfo', { |
||||||
|
item: { |
||||||
|
type: this.taskType, |
||||||
|
id: this.id, |
||||||
|
name: this.name, |
||||||
|
params: this.params, |
||||||
|
desc: this.desc, |
||||||
|
runFlag: this.runFlag, |
||||||
|
dependence: this.dependence, |
||||||
|
maxRetryTimes: this.maxRetryTimes, |
||||||
|
retryInterval: this.retryInterval, |
||||||
|
timeout: this.timeout, |
||||||
|
taskInstancePriority: this.taskInstancePriority |
||||||
|
}, |
||||||
|
fromThis: this |
||||||
|
}) |
||||||
|
}, |
||||||
|
/** |
||||||
|
* Sub-workflow selected node echo name |
||||||
|
*/ |
||||||
|
_onSetProcessName (name) { |
||||||
|
this.name = name |
||||||
|
}, |
||||||
|
/** |
||||||
|
* Submit verification |
||||||
|
*/ |
||||||
|
ok () { |
||||||
|
this._verification() |
||||||
|
}, |
||||||
|
/** |
||||||
|
* Close and destroy component and component internal events |
||||||
|
*/ |
||||||
|
close () { |
||||||
|
let flag = false |
||||||
|
// Delete node without storage |
||||||
|
if (!this.backfillItem.name) { |
||||||
|
flag = true |
||||||
|
} |
||||||
|
this.isContentBox = false |
||||||
|
// flag Whether to delete a node this.$destroy() |
||||||
|
this.$emit('close', { |
||||||
|
flag: flag, |
||||||
|
fromThis: this |
||||||
|
}) |
||||||
|
} |
||||||
|
}, |
||||||
|
watch: {}, |
||||||
|
created () { |
||||||
|
// Unbind copy and paste events |
||||||
|
JSP.removePaste() |
||||||
|
// Backfill data |
||||||
|
let taskList = this.store.state.dag.tasks |
||||||
|
let o = {} |
||||||
|
if (taskList.length) { |
||||||
|
taskList.forEach(v => { |
||||||
|
if (v.id === this.id) { |
||||||
|
o = v |
||||||
|
this.backfillItem = v |
||||||
|
} |
||||||
|
}) |
||||||
|
// Non-null objects represent backfill |
||||||
|
if (!_.isEmpty(o)) { |
||||||
|
this.name = o.name |
||||||
|
this.taskInstancePriority = o.taskInstancePriority |
||||||
|
this.runFlag = o.runFlag || 'NORMAL' |
||||||
|
this.desc = o.desc |
||||||
|
this.maxRetryTimes = o.maxRetryTimes |
||||||
|
this.retryInterval = o.retryInterval |
||||||
|
} |
||||||
|
} |
||||||
|
this.isContentBox = true |
||||||
|
}, |
||||||
|
mounted () {}, |
||||||
|
updated () { |
||||||
|
}, |
||||||
|
beforeDestroy () { |
||||||
|
}, |
||||||
|
destroyed () { |
||||||
|
}, |
||||||
|
computed: { |
||||||
|
/** |
||||||
|
* Child workflow entry show/hide |
||||||
|
*/ |
||||||
|
_isGoSubProcess () { |
||||||
|
return this.taskType === 'SUB_PROCESS' && this.name |
||||||
|
} |
||||||
|
}, |
||||||
|
components: { |
||||||
|
mMr, |
||||||
|
mShell, |
||||||
|
mSubProcess, |
||||||
|
mProcedure, |
||||||
|
mSql, |
||||||
|
mLog, |
||||||
|
mSpark, |
||||||
|
mPython, |
||||||
|
mDependent, |
||||||
|
mSelectInput, |
||||||
|
mTimeoutAlarm, |
||||||
|
mPriority |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style lang="scss" rel="stylesheet/scss"> |
||||||
|
.form-model-model { |
||||||
|
width: 720px; |
||||||
|
position: relative; |
||||||
|
.title-box { |
||||||
|
height: 61px; |
||||||
|
border-bottom: 1px solid #DCDEDC; |
||||||
|
position: relative; |
||||||
|
.name { |
||||||
|
position: absolute; |
||||||
|
left: 24px; |
||||||
|
top: 18px; |
||||||
|
font-size: 16px; |
||||||
|
} |
||||||
|
.go-subtask { |
||||||
|
position: absolute; |
||||||
|
right: 30px; |
||||||
|
top: 17px; |
||||||
|
a { |
||||||
|
font-size: 14px; |
||||||
|
color: #0097e0; |
||||||
|
margin-left: 10px; |
||||||
|
i.iconfont { |
||||||
|
font-size: 18px; |
||||||
|
vertical-align: middle; |
||||||
|
} |
||||||
|
em { |
||||||
|
color: #333; |
||||||
|
vertical-align: middle; |
||||||
|
font-style: normal; |
||||||
|
vertical-align: middle; |
||||||
|
padding-left: 2px; |
||||||
|
} |
||||||
|
&:hover { |
||||||
|
em { |
||||||
|
text-decoration: underline; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.bottom-box { |
||||||
|
position: absolute; |
||||||
|
bottom: 0; |
||||||
|
left: 0; |
||||||
|
width: 100%; |
||||||
|
text-align: right; |
||||||
|
height: 60px; |
||||||
|
line-height: 60px; |
||||||
|
border-top: 1px solid #DCDEDC; |
||||||
|
background: #fff; |
||||||
|
.submit { |
||||||
|
padding-right: 20px; |
||||||
|
position: relative; |
||||||
|
z-index: 9; |
||||||
|
} |
||||||
|
} |
||||||
|
.content-box { |
||||||
|
overflow-y: scroll; |
||||||
|
height: calc(100vh - 61px); |
||||||
|
padding-bottom: 60px; |
||||||
|
} |
||||||
|
} |
||||||
|
.from-model { |
||||||
|
padding-top: 26px; |
||||||
|
>div { |
||||||
|
clear: both; |
||||||
|
} |
||||||
|
.list { |
||||||
|
position: relative; |
||||||
|
margin-bottom: 10px; |
||||||
|
.text-box { |
||||||
|
width: 110px; |
||||||
|
float: left; |
||||||
|
text-align: right; |
||||||
|
margin-right: 10px; |
||||||
|
>span { |
||||||
|
font-size: 14px; |
||||||
|
color: #777; |
||||||
|
display: inline-block; |
||||||
|
padding-top: 6px; |
||||||
|
} |
||||||
|
} |
||||||
|
.cont-box { |
||||||
|
width: 580px; |
||||||
|
float: left; |
||||||
|
.label-box { |
||||||
|
width: 100%; |
||||||
|
} |
||||||
|
.text-b { |
||||||
|
font-size: 14px; |
||||||
|
color: #777; |
||||||
|
display: inline-block; |
||||||
|
padding:0 6px 0 20px; |
||||||
|
} |
||||||
|
} |
||||||
|
.add { |
||||||
|
line-height: 32px; |
||||||
|
a { |
||||||
|
color: #0097e0; |
||||||
|
} |
||||||
|
} |
||||||
|
&:hover { |
||||||
|
} |
||||||
|
.list-t { |
||||||
|
width: 50%; |
||||||
|
float: left; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,357 @@ |
|||||||
|
<template> |
||||||
|
<span class="log-model"> |
||||||
|
<span v-if="stateId && item.type !== 'SUB_PROCESS'"> |
||||||
|
<slot name="history"></slot> |
||||||
|
<span @click="_ckLog"> |
||||||
|
<slot name="log" ></slot> |
||||||
|
</span> |
||||||
|
</span> |
||||||
|
<transition name="fade"> |
||||||
|
<div v-show="isLog || source === 'list'" class="log-pop"> |
||||||
|
<div class="log-box" > |
||||||
|
<div class="title"> |
||||||
|
<span>{{$t('查看日志')}}</span> |
||||||
|
<div class="full-screen"> |
||||||
|
<a href="javascript:" @click="_downloadLog" data-container="body" data-toggle="tooltip" :title="$t('下载日志')"> |
||||||
|
<i class="iconfont" style="font-size: 20px"></i> |
||||||
|
</a> |
||||||
|
<a href="javascript:" class="refresh-log" :class="loading ? 'active' :''" @click="!loading && _refreshLog()" data-container="body" data-toggle="tooltip" :title="$t('刷新日志')"> |
||||||
|
<i class="fa iconfont"></i> |
||||||
|
</a> |
||||||
|
<a href="javascript:" @click="_screenOpen" v-show="!isScreen" data-container="body" data-toggle="tooltip" :title="$t('进入全屏')"> |
||||||
|
<i class="iconfont"></i> |
||||||
|
</a> |
||||||
|
<a href="javascript:" @click="_screenClose" v-show="isScreen" data-container="body" data-toggle="tooltip" :title="$t('取消全屏')"> |
||||||
|
<i class="iconfont"></i> |
||||||
|
</a> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="content"> |
||||||
|
<div class="content-log-box" > |
||||||
|
<textarea class="textarea-ft" id="textarea-log" style="width: 100%" spellcheck="false" ></textarea> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="operation"> |
||||||
|
<x-button type="primary" shape="circle" @click="close"> {{$t('关闭')}} </x-button> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</transition> |
||||||
|
</span> |
||||||
|
</template> |
||||||
|
<script> |
||||||
|
import _ from 'lodash' |
||||||
|
import i18n from '@/module/i18n' |
||||||
|
import store from '@/conf/home/store' |
||||||
|
import router from '@/conf/home/router' |
||||||
|
import { downloadFile } from '@/module/download' |
||||||
|
|
||||||
|
/** |
||||||
|
* Calculate text size |
||||||
|
*/ |
||||||
|
const handerTextareaSize = (isH = 0) => { |
||||||
|
$('body').find('.tooltip.fade.top.in').remove() |
||||||
|
return $('.textarea-ft').css({ 'height': `${$('.content-log-box').height() - isH}px` }) |
||||||
|
} |
||||||
|
|
||||||
|
let content = '' |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'log', |
||||||
|
data () { |
||||||
|
return { |
||||||
|
store, |
||||||
|
router, |
||||||
|
isLog: false, |
||||||
|
stateId: $(`#${this.item.id}`).attr('data-state-id') || null, |
||||||
|
isScreen: false, |
||||||
|
loadingIndex: 0, |
||||||
|
isData: true, |
||||||
|
loading: false |
||||||
|
} |
||||||
|
}, |
||||||
|
props: { |
||||||
|
item: { |
||||||
|
type: Object, |
||||||
|
default: {} |
||||||
|
}, |
||||||
|
source: { |
||||||
|
type: String, |
||||||
|
default: 'from' |
||||||
|
}, |
||||||
|
logId: Number |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
_refreshLog () { |
||||||
|
this.loading = true |
||||||
|
this.store.dispatch('dag/getLog', this._rtParam).then(res => { |
||||||
|
setTimeout(() => { |
||||||
|
this.loading = false |
||||||
|
if (res.data) { |
||||||
|
this.$message.success(`${i18n.$t('更新日志成功')}`) |
||||||
|
} else { |
||||||
|
this.$message.warning(`${i18n.$t('暂无更多日志')}`) |
||||||
|
} |
||||||
|
}, 1500) |
||||||
|
// Handling text field size |
||||||
|
handerTextareaSize().html('').text(res.data || `${i18n.$t('暂无日志')}`) |
||||||
|
}).catch(e => { |
||||||
|
this.$message.error(e.msg || '') |
||||||
|
this.loading = false |
||||||
|
}) |
||||||
|
}, |
||||||
|
_ckLog () { |
||||||
|
this.isLog = true |
||||||
|
this.store.dispatch('dag/getLog', this._rtParam).then(res => { |
||||||
|
this.$message.destroy() |
||||||
|
|
||||||
|
if (!res.data) { |
||||||
|
this.isData = false |
||||||
|
setTimeout(() => { |
||||||
|
this.$message.warning(`${i18n.$t('暂无更多日志')}`) |
||||||
|
}, 1000) |
||||||
|
// Handling text field size |
||||||
|
handerTextareaSize().html('').text(content || `${i18n.$t('暂无日志')}`) |
||||||
|
} else { |
||||||
|
this.isData = true |
||||||
|
content = res.data |
||||||
|
// Handling text field size |
||||||
|
handerTextareaSize().html('').text(content || `${i18n.$t('暂无日志')}`) |
||||||
|
|
||||||
|
setTimeout(() => { |
||||||
|
$('#textarea').scrollTop(2) |
||||||
|
}, 800) |
||||||
|
} |
||||||
|
}).catch(e => { |
||||||
|
this.$message.error(e.msg || '') |
||||||
|
this.$message.destroy() |
||||||
|
}) |
||||||
|
}, |
||||||
|
_screenOpen () { |
||||||
|
this.isScreen = true |
||||||
|
let $logBox = $('.log-box') |
||||||
|
let winW = $(window).width() - 40 |
||||||
|
let winH = $(window).height() - 40 |
||||||
|
$logBox.css({ |
||||||
|
width: winW, |
||||||
|
height: winH, |
||||||
|
marginLeft: `-${parseInt(winW / 2)}px`, |
||||||
|
marginTop: `-${parseInt(winH / 2)}px` |
||||||
|
}) |
||||||
|
$logBox.find('.content').animate({ scrollTop: 0 }, 0) |
||||||
|
// Handling text field size |
||||||
|
handerTextareaSize().html('').text(content) |
||||||
|
}, |
||||||
|
_screenClose () { |
||||||
|
this.isScreen = false |
||||||
|
let $logBox = $('.log-box') |
||||||
|
$logBox.attr('style', '') |
||||||
|
$logBox.find('.content').animate({ scrollTop: 0 }, 0) |
||||||
|
// Handling text field size |
||||||
|
handerTextareaSize().html('').text(content) |
||||||
|
}, |
||||||
|
/** |
||||||
|
* Download log |
||||||
|
*/ |
||||||
|
_downloadLog () { |
||||||
|
downloadFile('/escheduler/log/download-log', { |
||||||
|
taskInstId: this.stateId || this.logId |
||||||
|
}) |
||||||
|
}, |
||||||
|
/** |
||||||
|
* up |
||||||
|
*/ |
||||||
|
_onUp: _.debounce(function () { |
||||||
|
this.loadingIndex = this.loadingIndex - 1 |
||||||
|
this._ckLog() |
||||||
|
}, 1000, { |
||||||
|
'leading': false, |
||||||
|
'trailing': true |
||||||
|
}), |
||||||
|
/** |
||||||
|
* down |
||||||
|
*/ |
||||||
|
_onDown: _.debounce(function () { |
||||||
|
this.loadingIndex = this.loadingIndex + 1 |
||||||
|
this._ckLog() |
||||||
|
}, 1000, { |
||||||
|
'leading': false, |
||||||
|
'trailing': true |
||||||
|
}), |
||||||
|
/** |
||||||
|
* Monitor scroll bar |
||||||
|
*/ |
||||||
|
_onTextareaScroll () { |
||||||
|
let self = this |
||||||
|
$('#textarea-log').scroll(function () { |
||||||
|
let $this = $(this) |
||||||
|
// Listen for scrollbar events |
||||||
|
if (($this.scrollTop() + $this.height()) === $this.height()) { |
||||||
|
if (self.loadingIndex > 0) { |
||||||
|
self.$message.loading({ |
||||||
|
content: `${i18n.$t('正在努力请求日志中...')}`, |
||||||
|
duration: 0, |
||||||
|
closable: false |
||||||
|
}) |
||||||
|
self._onUp() |
||||||
|
} |
||||||
|
} |
||||||
|
// Listen for scrollbar events |
||||||
|
if ($this.get(0).scrollHeight === ($this.height() + $this.scrollTop())) { |
||||||
|
// No data is not requested |
||||||
|
if (self.isData) { |
||||||
|
self.$message.loading({ |
||||||
|
content: `${i18n.$t('正在努力请求日志中...')}`, |
||||||
|
duration: 0, |
||||||
|
closable: false |
||||||
|
}) |
||||||
|
self._onDown() |
||||||
|
} |
||||||
|
} |
||||||
|
}) |
||||||
|
}, |
||||||
|
/** |
||||||
|
* close |
||||||
|
*/ |
||||||
|
close () { |
||||||
|
$('body').find('.tooltip.fade.top.in').remove() |
||||||
|
this.isScreen = false |
||||||
|
this.isLog = false |
||||||
|
content = '' |
||||||
|
this.$emit('close') |
||||||
|
} |
||||||
|
}, |
||||||
|
watch: {}, |
||||||
|
created () { |
||||||
|
// Source is a task instance |
||||||
|
if (this.source === 'list') { |
||||||
|
this.$message.loading({ |
||||||
|
content: `${i18n.$t('正在努力请求日志中...')}`, |
||||||
|
duration: 0, |
||||||
|
closable: false |
||||||
|
}) |
||||||
|
this._ckLog() |
||||||
|
} |
||||||
|
}, |
||||||
|
mounted () { |
||||||
|
this._onTextareaScroll() |
||||||
|
}, |
||||||
|
updated () { |
||||||
|
}, |
||||||
|
computed: { |
||||||
|
_rtParam () { |
||||||
|
return { |
||||||
|
taskInstId: this.stateId || this.logId, |
||||||
|
skipLineNum: parseInt(`${this.loadingIndex ? this.loadingIndex + '0000' : 0}`), |
||||||
|
limit: parseInt(`${this.loadingIndex ? this.loadingIndex + 1 : 1}0000`) |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
components: { } |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style lang="scss" rel="stylesheet/scss"> |
||||||
|
.log-pop { |
||||||
|
position: fixed; |
||||||
|
left: 0; |
||||||
|
top: 0; |
||||||
|
width: 100%; |
||||||
|
height: 100%; |
||||||
|
background: rgba(0,0,0,.4); |
||||||
|
z-index: 10; |
||||||
|
.log-box { |
||||||
|
width: 660px; |
||||||
|
height: 520px; |
||||||
|
background: #fff; |
||||||
|
border-radius: 3px; |
||||||
|
position: absolute; |
||||||
|
left:50%; |
||||||
|
top: 50%; |
||||||
|
margin-left: -340px; |
||||||
|
margin-top: -250px; |
||||||
|
.title { |
||||||
|
height: 50px; |
||||||
|
border-bottom: 1px solid #dcdedc; |
||||||
|
span { |
||||||
|
font-size: 16px; |
||||||
|
color: #333; |
||||||
|
padding-left: 20px; |
||||||
|
display: inline-block; |
||||||
|
padding-top: 16px; |
||||||
|
} |
||||||
|
.full-screen { |
||||||
|
position: absolute; |
||||||
|
right: 20px; |
||||||
|
top: 12px; |
||||||
|
a{ |
||||||
|
color: #0097e0; |
||||||
|
font-size: 12px; |
||||||
|
margin-left: 10px; |
||||||
|
i { |
||||||
|
vertical-align: middle; |
||||||
|
} |
||||||
|
} |
||||||
|
.clock { |
||||||
|
>i { |
||||||
|
font-size: 20px; |
||||||
|
vertical-align: middle; |
||||||
|
transform: scale(1); |
||||||
|
} |
||||||
|
} |
||||||
|
.refresh-log { |
||||||
|
>i { |
||||||
|
font-size: 24px; |
||||||
|
vertical-align: middle; |
||||||
|
transform: scale(1); |
||||||
|
} |
||||||
|
&.active { |
||||||
|
>i { |
||||||
|
-webkit-transition-property: -webkit-transform; |
||||||
|
-webkit-transition-duration: 1s; |
||||||
|
-moz-transition-property: -moz-transform; |
||||||
|
-moz-transition-duration: 1s; |
||||||
|
-webkit-animation: rotateloading .4s linear infinite; |
||||||
|
-moz-animation: rotateloading .4s linear infinite; |
||||||
|
-o-animation: rotateloading .4s linear infinite; |
||||||
|
animation: rotateloading .4s linear infinite; |
||||||
|
transform: scale(.4); |
||||||
|
color: #999; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.content { |
||||||
|
height: calc(100% - 100px); |
||||||
|
background: #002A35; |
||||||
|
padding:6px 2px; |
||||||
|
.content-log-box { |
||||||
|
width: 100%; |
||||||
|
height: 100%; |
||||||
|
word-break:break-all; |
||||||
|
textarea { |
||||||
|
background: none; |
||||||
|
color: #9CABAF; |
||||||
|
border: 0; |
||||||
|
font-family: 'Microsoft Yahei,Arial,Hiragino Sans GB,tahoma,SimSun,sans-serif'; |
||||||
|
font-weight: bold; |
||||||
|
resize:none; |
||||||
|
line-height: 1.6; |
||||||
|
padding: 6px; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.operation { |
||||||
|
text-align: right; |
||||||
|
height: 50px; |
||||||
|
line-height: 44px; |
||||||
|
border-top: 1px solid #dcdedc; |
||||||
|
padding-right: 20px; |
||||||
|
background: #fff; |
||||||
|
position: relative; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
</style> |
@ -0,0 +1,199 @@ |
|||||||
|
|
||||||
|
import i18n from '@/module/i18n' |
||||||
|
|
||||||
|
/** |
||||||
|
* cycle |
||||||
|
*/ |
||||||
|
const cycleList = [ |
||||||
|
{ |
||||||
|
value: 'month', |
||||||
|
label: `${i18n.$t('月')}` |
||||||
|
}, |
||||||
|
{ |
||||||
|
value: 'week', |
||||||
|
label: `${i18n.$t('周')}` |
||||||
|
}, |
||||||
|
{ |
||||||
|
value: 'day', |
||||||
|
label: `${i18n.$t('日')}` |
||||||
|
}, |
||||||
|
{ |
||||||
|
value: 'hour', |
||||||
|
label: `${i18n.$t('时')}` |
||||||
|
} |
||||||
|
] |
||||||
|
|
||||||
|
/** |
||||||
|
* cycle value |
||||||
|
*/ |
||||||
|
const dateValueList = { |
||||||
|
'hour': [ |
||||||
|
{ |
||||||
|
value: 'last1Hour', |
||||||
|
label: `${i18n.$t('前1小时')}` |
||||||
|
}, |
||||||
|
{ |
||||||
|
value: 'last2Hours', |
||||||
|
label: `${i18n.$t('前2小时')}` |
||||||
|
}, |
||||||
|
{ |
||||||
|
value: 'last3Hours', |
||||||
|
label: `${i18n.$t('前3小时')}` |
||||||
|
} |
||||||
|
], |
||||||
|
'day': [ |
||||||
|
{ |
||||||
|
value: 'last1Days', |
||||||
|
label: `${i18n.$t('昨天')}` |
||||||
|
}, |
||||||
|
{ |
||||||
|
value: 'last2Days', |
||||||
|
label: `${i18n.$t('前两天')}` |
||||||
|
}, |
||||||
|
{ |
||||||
|
value: 'last3Days', |
||||||
|
label: `${i18n.$t('前三天')}` |
||||||
|
}, |
||||||
|
{ |
||||||
|
value: 'last7Days', |
||||||
|
label: `${i18n.$t('前七天')}` |
||||||
|
} |
||||||
|
], |
||||||
|
'week': [ |
||||||
|
{ |
||||||
|
value: 'lastWeek', |
||||||
|
label: `${i18n.$t('上周')}` |
||||||
|
}, |
||||||
|
{ |
||||||
|
value: 'lastMonday', |
||||||
|
label: `${i18n.$t('上周一')}` |
||||||
|
}, |
||||||
|
{ |
||||||
|
value: 'lastTuesday', |
||||||
|
label: `${i18n.$t('上周二')}` |
||||||
|
}, |
||||||
|
{ |
||||||
|
value: 'lastWednesday', |
||||||
|
label: `${i18n.$t('上周三')}` |
||||||
|
}, |
||||||
|
{ |
||||||
|
value: 'lastThursday', |
||||||
|
label: `${i18n.$t('上周四')}` |
||||||
|
}, |
||||||
|
{ |
||||||
|
value: 'lastFriday', |
||||||
|
label: `${i18n.$t('上周五')}` |
||||||
|
}, |
||||||
|
{ |
||||||
|
value: 'lastSaturday', |
||||||
|
label: `${i18n.$t('上周六')}` |
||||||
|
}, |
||||||
|
{ |
||||||
|
value: 'lastSunday', |
||||||
|
label: `${i18n.$t('上周日')}` |
||||||
|
} |
||||||
|
], |
||||||
|
'month': [ |
||||||
|
{ |
||||||
|
value: 'lastMonth', |
||||||
|
label: `${i18n.$t('上月')}` |
||||||
|
}, |
||||||
|
{ |
||||||
|
value: 'lastMonthBegin', |
||||||
|
label: `${i18n.$t('上月初')}` |
||||||
|
}, |
||||||
|
{ |
||||||
|
value: 'lastMonthEnd', |
||||||
|
label: `${i18n.$t('上月末')}` |
||||||
|
} |
||||||
|
] |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* direct |
||||||
|
*/ |
||||||
|
const directList = [ |
||||||
|
{ |
||||||
|
id: 1, |
||||||
|
code: 'IN', |
||||||
|
disabled: false |
||||||
|
}, |
||||||
|
{ |
||||||
|
id: 2, |
||||||
|
code: 'OUT', |
||||||
|
disabled: false |
||||||
|
} |
||||||
|
] |
||||||
|
|
||||||
|
/** |
||||||
|
* type |
||||||
|
*/ |
||||||
|
const typeList = [ |
||||||
|
{ |
||||||
|
id: 1, |
||||||
|
code: 'VARCHAR', |
||||||
|
disabled: false |
||||||
|
}, |
||||||
|
{ |
||||||
|
id: 2, |
||||||
|
code: 'INTEGER', |
||||||
|
disabled: false |
||||||
|
}, |
||||||
|
{ |
||||||
|
id: 3, |
||||||
|
code: 'LONG', |
||||||
|
disabled: false |
||||||
|
}, |
||||||
|
{ |
||||||
|
id: 4, |
||||||
|
code: 'FLOAT', |
||||||
|
disabled: false |
||||||
|
}, |
||||||
|
{ |
||||||
|
id: 5, |
||||||
|
code: 'DOUBLE', |
||||||
|
disabled: false |
||||||
|
}, |
||||||
|
{ |
||||||
|
id: 6, |
||||||
|
code: 'DATE', |
||||||
|
disabled: false |
||||||
|
}, |
||||||
|
{ |
||||||
|
id: 7, |
||||||
|
code: 'TIME', |
||||||
|
disabled: false |
||||||
|
}, |
||||||
|
{ |
||||||
|
id: 8, |
||||||
|
code: 'TIMESTAMP', |
||||||
|
disabled: false |
||||||
|
}, |
||||||
|
{ |
||||||
|
id: 9, |
||||||
|
code: 'BOOLEAN', |
||||||
|
disabled: false |
||||||
|
} |
||||||
|
] |
||||||
|
|
||||||
|
/** |
||||||
|
* sqlType |
||||||
|
*/ |
||||||
|
const sqlTypeList = [ |
||||||
|
{ |
||||||
|
id: 0, |
||||||
|
code: `${i18n.$t('查询')}` |
||||||
|
}, |
||||||
|
{ |
||||||
|
id: 1, |
||||||
|
code: `${i18n.$t('非查询')}` |
||||||
|
} |
||||||
|
] |
||||||
|
|
||||||
|
export { |
||||||
|
cycleList, |
||||||
|
dateValueList, |
||||||
|
typeList, |
||||||
|
directList, |
||||||
|
sqlTypeList |
||||||
|
} |
@ -0,0 +1,133 @@ |
|||||||
|
<template> |
||||||
|
<div class="datasource-model"> |
||||||
|
<div class="select-listpp"> |
||||||
|
<x-select v-model="type" |
||||||
|
style="width: 160px;" |
||||||
|
@on-change="_handleTypeChanged" |
||||||
|
:disabled="isDetails"> |
||||||
|
<x-option |
||||||
|
v-for="city in typeList" |
||||||
|
:key="city.code" |
||||||
|
:value="city.code" |
||||||
|
:label="city.code"> |
||||||
|
</x-option> |
||||||
|
</x-select> |
||||||
|
<x-select :placeholder="$t('请选择数据源')" |
||||||
|
v-model="datasource" |
||||||
|
style="width: 288px;" |
||||||
|
:disabled="isDetails"> |
||||||
|
<x-option |
||||||
|
v-for="city in datasourceList" |
||||||
|
:key="city.id" |
||||||
|
:value="city" |
||||||
|
:label="city.code"> |
||||||
|
</x-option> |
||||||
|
</x-select> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<script> |
||||||
|
import _ from 'lodash' |
||||||
|
import i18n from '@/module/i18n' |
||||||
|
import disabledState from '@/module/mixin/disabledState' |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'datasource', |
||||||
|
data () { |
||||||
|
return { |
||||||
|
// Data source type |
||||||
|
type: '', |
||||||
|
// Data source type(List) |
||||||
|
typeList: [], |
||||||
|
// data source |
||||||
|
datasource: {}, |
||||||
|
// data source(List) |
||||||
|
datasourceList: [] |
||||||
|
} |
||||||
|
}, |
||||||
|
mixins: [disabledState], |
||||||
|
props: { |
||||||
|
data: Object, |
||||||
|
supportType: Array |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
/** |
||||||
|
* Verify data source |
||||||
|
*/ |
||||||
|
_verifDatasource () { |
||||||
|
if (!this.datasource) { |
||||||
|
this.$message.warning(`${i18n.$t('请选择数据源')}`) |
||||||
|
return false |
||||||
|
} |
||||||
|
this.$emit('on-dsData', { |
||||||
|
type: this.type, |
||||||
|
datasource: this.datasource.id |
||||||
|
}) |
||||||
|
return true |
||||||
|
}, |
||||||
|
/** |
||||||
|
* Get the corresponding datasource data according to type |
||||||
|
*/ |
||||||
|
_getDatasourceData () { |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
this.store.dispatch('dag/getDatasourceList', this.type).then(res => { |
||||||
|
this.datasourceList = _.map(res.data, v => { |
||||||
|
return { |
||||||
|
id: v.id, |
||||||
|
code: v.name, |
||||||
|
disabled: false |
||||||
|
} |
||||||
|
}) |
||||||
|
resolve() |
||||||
|
}) |
||||||
|
}) |
||||||
|
}, |
||||||
|
/** |
||||||
|
* Brush type |
||||||
|
*/ |
||||||
|
_handleTypeChanged ({ value }) { |
||||||
|
this.type = value |
||||||
|
this._getDatasourceData().then(res => { |
||||||
|
this.datasource = this.datasourceList.length && this.datasourceList[0] || {} |
||||||
|
this.$emit('on-dsData', { |
||||||
|
type: this.type, |
||||||
|
datasource: this.datasource.id |
||||||
|
}) |
||||||
|
}) |
||||||
|
} |
||||||
|
}, |
||||||
|
watch: {}, |
||||||
|
created () { |
||||||
|
let supportType = this.supportType || [] |
||||||
|
this.typeList = _.cloneDeep(this.store.state.dag.dsTypeListS) |
||||||
|
// Have a specified data source |
||||||
|
if (supportType.length) { |
||||||
|
let is = (type) => { |
||||||
|
return !!_.filter(supportType, v => v === type).length |
||||||
|
} |
||||||
|
this.typeList = _.filter(this.typeList, v => is(v.code)) |
||||||
|
} |
||||||
|
|
||||||
|
this.type = _.cloneDeep(this.data.type) || this.typeList[0].code |
||||||
|
// init data |
||||||
|
this._getDatasourceData().then(res => { |
||||||
|
if (_.isEmpty(this.data)) { |
||||||
|
this.$nextTick(() => { |
||||||
|
this.datasource = this.datasourceList[0] |
||||||
|
}) |
||||||
|
} else { |
||||||
|
this.$nextTick(() => { |
||||||
|
this.datasource = _.filter(this.datasourceList, v => v.id === this.data.datasource)[0] |
||||||
|
}) |
||||||
|
} |
||||||
|
this.$emit('on-dsData', { |
||||||
|
type: this.type |
||||||
|
}) |
||||||
|
}) |
||||||
|
}, |
||||||
|
mounted () { |
||||||
|
|
||||||
|
}, |
||||||
|
components: { } |
||||||
|
} |
||||||
|
</script> |
@ -0,0 +1,247 @@ |
|||||||
|
<template> |
||||||
|
<div class="dep-list-model"> |
||||||
|
<div v-for="(el,$index) in dependItemList" class="list" @click="itemIndex = $index"> |
||||||
|
<x-select filterable :style="{width:isInstance ? '140px' : '162px'}" :disabled="isDetails" v-model="el.definitionId" @on-change="_onChangeDefinitionId"> |
||||||
|
<x-option v-for="item in definitionList" :key="item.value" :value="item.value" :label="item.label"> |
||||||
|
</x-option> |
||||||
|
</x-select> |
||||||
|
<x-select filterable :style="{width:isInstance ? '144px' : '156px'}" :disabled="isDetails" v-model="el.depTasks"> |
||||||
|
<x-option v-for="item in el.depTasksList || []" :key="item" :value="item" :label="item"> |
||||||
|
</x-option> |
||||||
|
</x-select> |
||||||
|
<x-select style="width: 80px;" v-model="el.cycle" :disabled="isDetails" @on-change="_onChangeCycle"> |
||||||
|
<x-option v-for="item in cycleList" :key="item.value" :value="item.value" :label="item.label"> |
||||||
|
</x-option> |
||||||
|
</x-select> |
||||||
|
<x-select style="width: 116px;" v-model="el.dateValue" :disabled="isDetails"> |
||||||
|
<x-option v-for="item in el.dateValueList || []" :key="item.value" :value="item.value" :label="item.label"> |
||||||
|
</x-option> |
||||||
|
</x-select> |
||||||
|
<template v-if="isInstance"> |
||||||
|
<span class="instance-state"> |
||||||
|
<i class="iconfont" :class="'icon-' + el.state" v-if="el.state === 'SUCCESS'" data-toggle="tooltip" data-container="body" :title="$t('成功')"></i> |
||||||
|
<i class="iconfont" :class="'icon-' + el.state" v-if="el.state === 'WAITING'" data-toggle="tooltip" data-container="body" :title="$t('等待')"></i> |
||||||
|
<i class="iconfont" :class="'icon-' + el.state" v-if="el.state === 'FAILED'" data-toggle="tooltip" data-container="body" :title="$t('失败')"></i> |
||||||
|
</span> |
||||||
|
</template> |
||||||
|
<span class="operation"> |
||||||
|
<a href="javascript:" class="delete" @click="!isDetails && _remove($index)"> |
||||||
|
<i class="iconfont" :class="_isDetails" data-toggle="tooltip" data-container="body" :title="$t('删除')" ></i> |
||||||
|
</a> |
||||||
|
<a href="javascript:" class="add" @click="!isDetails && _add()" v-if="$index === (dependItemList.length - 1)"> |
||||||
|
<i class="iconfont" :class="_isDetails" data-toggle="tooltip" data-container="body" :title="$t('添加')"></i> |
||||||
|
</a> |
||||||
|
</span> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<script> |
||||||
|
import _ from 'lodash' |
||||||
|
import { cycleList, dateValueList } from './commcon' |
||||||
|
import disabledState from '@/module/mixin/disabledState' |
||||||
|
export default { |
||||||
|
name: 'dep-list', |
||||||
|
data () { |
||||||
|
return { |
||||||
|
list: [], |
||||||
|
definitionList: [], |
||||||
|
cycleList: cycleList, |
||||||
|
isInstance: false, |
||||||
|
itemIndex: null |
||||||
|
} |
||||||
|
}, |
||||||
|
mixins: [disabledState], |
||||||
|
props: { |
||||||
|
dependItemList: Array, |
||||||
|
index: Number |
||||||
|
}, |
||||||
|
model: { |
||||||
|
prop: 'dependItemList', |
||||||
|
event: 'dependItemListEvent' |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
/** |
||||||
|
* add task |
||||||
|
*/ |
||||||
|
_add () { |
||||||
|
// btn loading |
||||||
|
this.isLoading = true |
||||||
|
// dependItemList index |
||||||
|
let is = (value) => _.some(this.dependItemList, { definitionId: value }) |
||||||
|
let noArr = _.filter(this.definitionList, v => !is(v.value)) |
||||||
|
let value = noArr[0] && noArr[0].value || null |
||||||
|
let val = value || this.definitionList[0].value |
||||||
|
// add task list |
||||||
|
this._getDependItemList(val).then(depTasksList => { |
||||||
|
this.$nextTick(() => { |
||||||
|
this.$emit('dependItemListEvent', _.concat(this.dependItemList, this._rtNewParams(val, depTasksList))) |
||||||
|
}) |
||||||
|
}) |
||||||
|
// remove tooltip |
||||||
|
this._removeTip() |
||||||
|
}, |
||||||
|
/** |
||||||
|
* remove task |
||||||
|
*/ |
||||||
|
_remove (i) { |
||||||
|
this.dependItemList.splice(i, 1) |
||||||
|
this._removeTip() |
||||||
|
|
||||||
|
if (!this.dependItemList.length) { |
||||||
|
this.$emit('on-delete-all', { |
||||||
|
index: this.index |
||||||
|
}) |
||||||
|
} |
||||||
|
}, |
||||||
|
/** |
||||||
|
* get processlist |
||||||
|
*/ |
||||||
|
_getProcessList () { |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
this.definitionList = _.map(_.cloneDeep(this.store.state.dag.processListS), v => { |
||||||
|
return { |
||||||
|
value: v.id, |
||||||
|
label: v.name |
||||||
|
} |
||||||
|
}) |
||||||
|
resolve() |
||||||
|
}) |
||||||
|
}, |
||||||
|
/** |
||||||
|
* get dependItemList |
||||||
|
*/ |
||||||
|
_getDependItemList (ids, is = true) { |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
if (is) { |
||||||
|
this.store.dispatch('dag/getProcessTasksList', { processDefinitionId: ids }).then(res => { |
||||||
|
resolve(['ALL'].concat(_.map(res, v => v.name))) |
||||||
|
}) |
||||||
|
} else { |
||||||
|
this.store.dispatch('dag/getTaskListDefIdAll', { processDefinitionIdList: ids }).then(res => { |
||||||
|
resolve(res) |
||||||
|
}) |
||||||
|
} |
||||||
|
}) |
||||||
|
}, |
||||||
|
/** |
||||||
|
* change process get dependItemList |
||||||
|
*/ |
||||||
|
_onChangeDefinitionId ({ value }) { |
||||||
|
// get depItem list data |
||||||
|
this._getDependItemList(value).then(depTasksList => { |
||||||
|
let item = this.dependItemList[this.itemIndex] |
||||||
|
// init set depTasks All |
||||||
|
item.depTasks = 'ALL' |
||||||
|
// set dependItemList item data |
||||||
|
this.$set(this.dependItemList, this.itemIndex, this._rtOldParams(value, depTasksList, item)) |
||||||
|
}) |
||||||
|
}, |
||||||
|
_onChangeCycle ({ value }) { |
||||||
|
let list = _.cloneDeep(dateValueList[value]) |
||||||
|
this.$set(this.dependItemList[this.itemIndex], 'dateValue', list[0].value) |
||||||
|
this.$set(this.dependItemList[this.itemIndex], 'dateValueList', list) |
||||||
|
}, |
||||||
|
_rtNewParams (value, depTasksList) { |
||||||
|
return { |
||||||
|
definitionId: value, |
||||||
|
depTasks: 'ALL', |
||||||
|
depTasksList: depTasksList, |
||||||
|
cycle: 'day', |
||||||
|
dateValue: 'last1Days', |
||||||
|
dateValueList: _.cloneDeep(dateValueList['day']), |
||||||
|
state: '' |
||||||
|
} |
||||||
|
}, |
||||||
|
_rtOldParams (value, depTasksList, item) { |
||||||
|
return { |
||||||
|
definitionId: value, |
||||||
|
depTasks: item.depTasks || 'ALL', |
||||||
|
depTasksList: depTasksList, |
||||||
|
cycle: item.cycle, |
||||||
|
dateValue: item.dateValue, |
||||||
|
dateValueList: _.cloneDeep(dateValueList[item.cycle]), |
||||||
|
state: item.state |
||||||
|
} |
||||||
|
}, |
||||||
|
/** |
||||||
|
* remove tip |
||||||
|
*/ |
||||||
|
_removeTip () { |
||||||
|
$('body').find('.tooltip.fade.top.in').remove() |
||||||
|
} |
||||||
|
}, |
||||||
|
watch: { |
||||||
|
}, |
||||||
|
beforeCreate () { |
||||||
|
}, |
||||||
|
created () { |
||||||
|
// is type projects-instance-details |
||||||
|
this.isInstance = this.router.history.current.name === 'projects-instance-details' |
||||||
|
// get processlist |
||||||
|
this._getProcessList().then(() => { |
||||||
|
if (!this.dependItemList.length) { |
||||||
|
let value = this.definitionList[0].value |
||||||
|
this._getDependItemList(value).then(depTasksList => { |
||||||
|
this.$emit('dependItemListEvent', _.concat(this.dependItemList, this._rtNewParams(value, depTasksList))) |
||||||
|
}) |
||||||
|
} else { |
||||||
|
// get definitionId ids |
||||||
|
let ids = _.map(this.dependItemList, v => v.definitionId).join(',') |
||||||
|
// get item list |
||||||
|
this._getDependItemList(ids, false).then(res => { |
||||||
|
_.map(this.dependItemList, (v, i) => { |
||||||
|
this.$set(this.dependItemList, i, this._rtOldParams(v.definitionId, ['ALL'].concat(_.map(res[v.definitionId] || [], v => v.name)), v)) |
||||||
|
}) |
||||||
|
}) |
||||||
|
} |
||||||
|
}) |
||||||
|
}, |
||||||
|
mounted () { |
||||||
|
}, |
||||||
|
components: {} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style lang="scss" rel="stylesheet/scss"> |
||||||
|
.dep-list-model { |
||||||
|
position: relative; |
||||||
|
min-height: 32px; |
||||||
|
.list { |
||||||
|
margin-bottom: 6px; |
||||||
|
.operation { |
||||||
|
padding-left: 4px; |
||||||
|
a { |
||||||
|
i { |
||||||
|
font-size: 18px; |
||||||
|
vertical-align: middle; |
||||||
|
} |
||||||
|
} |
||||||
|
.delete { |
||||||
|
color: #ff0000; |
||||||
|
} |
||||||
|
.add { |
||||||
|
color: #0097e0; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.instance-state { |
||||||
|
display: inline-block; |
||||||
|
width: 24px; |
||||||
|
.iconfont { |
||||||
|
font-size: 20px; |
||||||
|
vertical-align: middle; |
||||||
|
cursor: pointer; |
||||||
|
margin-left: 6px; |
||||||
|
&.icon-SUCCESS { |
||||||
|
color: #33cc00; |
||||||
|
} |
||||||
|
&.icon-WAITING { |
||||||
|
color: #888888; |
||||||
|
} |
||||||
|
&.icon-FAILED { |
||||||
|
color: #F31322; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,46 @@ |
|||||||
|
<template> |
||||||
|
<div class="clearfix list"> |
||||||
|
<div class="text-box"> |
||||||
|
<span><slot name="text"></slot></span> |
||||||
|
</div> |
||||||
|
<div class="cont-box"> |
||||||
|
<div class="label-box"> |
||||||
|
<slot name="content"></slot> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<script> |
||||||
|
export default { |
||||||
|
name: 'list-box' |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style lang="scss" rel="stylesheet/scss"> |
||||||
|
.cont-box { |
||||||
|
.label-box { |
||||||
|
.ans-radio-group { |
||||||
|
margin-top: 7px; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.v-checkbox-wrapper { |
||||||
|
&.v-checkbox-wrapper-disabled { |
||||||
|
color: #999 ; |
||||||
|
.v-checkbox { |
||||||
|
.v-checkbox-inner{ |
||||||
|
border-color:#dddee1; |
||||||
|
background: #f7f7f7; |
||||||
|
color: #bbbec4 ; |
||||||
|
&:after{ |
||||||
|
border: 2px solid #ddd; |
||||||
|
border-top: 0; |
||||||
|
border-left: 0; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
</style> |
@ -0,0 +1,209 @@ |
|||||||
|
<template> |
||||||
|
<div class="user-def-params-model"> |
||||||
|
<div class="select-listpp" |
||||||
|
v-for="(item,$index) in localParamsList" |
||||||
|
:key="item.id" |
||||||
|
@click="_getIndex($index)"> |
||||||
|
<x-input |
||||||
|
:disabled="isDetails" |
||||||
|
type="text" |
||||||
|
v-model="localParamsList[$index].prop" |
||||||
|
:placeholder="$t('prop(必填)')" |
||||||
|
maxlength="64" |
||||||
|
@on-blur="_verifProp()" |
||||||
|
style="width: 164px;"> |
||||||
|
</x-input> |
||||||
|
<x-select |
||||||
|
style="width: 80px;" |
||||||
|
@change="_handleDirectChanged" |
||||||
|
v-model="localParamsList[$index].direct" |
||||||
|
:disabled="isDetails || !hide"> |
||||||
|
<x-option |
||||||
|
v-for="city in directList" |
||||||
|
:key="city.code" |
||||||
|
:value="city.code" |
||||||
|
:label="city.code"> |
||||||
|
</x-option> |
||||||
|
</x-select> |
||||||
|
<x-select |
||||||
|
style="width: 118px;" |
||||||
|
@change="_handleTypeChanged" |
||||||
|
v-model="localParamsList[$index].type" |
||||||
|
:disabled="isDetails || !hide"> |
||||||
|
<x-option |
||||||
|
v-for="city in typeList" |
||||||
|
:key="city.code" |
||||||
|
:value="city.code" |
||||||
|
:label="city.code"> |
||||||
|
</x-option> |
||||||
|
</x-select> |
||||||
|
<x-input |
||||||
|
:disabled="isDetails" |
||||||
|
type="text" |
||||||
|
v-model="localParamsList[$index].value" |
||||||
|
:placeholder="$t('value(选填)')" |
||||||
|
maxlength="64" |
||||||
|
@on-blur="_handleValue()" |
||||||
|
style="width: 150px;position: relative;margin-bottom: -2px;"> |
||||||
|
</x-input> |
||||||
|
<span class="lt-add"> |
||||||
|
<a href="javascript:" style="color:red;" @click="!isDetails && _removeUdp($index)" > |
||||||
|
<i class="iconfont" :class="_isDetails" data-toggle="tooltip" :title="$t('删除')" ></i> |
||||||
|
</a> |
||||||
|
</span> |
||||||
|
<span class="add" v-if="$index === (localParamsList.length - 1)"> |
||||||
|
<a href="javascript:" @click="!isDetails && _addUdp()" > |
||||||
|
<i class="iconfont" :class="_isDetails" data-toggle="tooltip" :title="$t('添加')"></i> |
||||||
|
</a> |
||||||
|
</span> |
||||||
|
</div> |
||||||
|
<span class="add" v-if="!localParamsList.length"> |
||||||
|
<a href="javascript:" @click="!isDetails && _addUdp()" > |
||||||
|
<i class="iconfont" :class="_isDetails" data-toggle="tooltip" :title="$t('添加')"></i> |
||||||
|
</a> |
||||||
|
</span> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<script> |
||||||
|
import _ from 'lodash' |
||||||
|
import i18n from '@/module/i18n' |
||||||
|
import { directList, typeList } from './commcon' |
||||||
|
import disabledState from '@/module/mixin/disabledState' |
||||||
|
export default { |
||||||
|
name: 'user-def-params', |
||||||
|
data () { |
||||||
|
return { |
||||||
|
// Direct data Custom parameter type support IN |
||||||
|
directList: directList, |
||||||
|
// Type data Custom parameter type support OUT |
||||||
|
typeList: typeList, |
||||||
|
// Increased data |
||||||
|
localParamsList: [], |
||||||
|
// Current execution index |
||||||
|
localParamsIndex: null |
||||||
|
} |
||||||
|
}, |
||||||
|
mixins: [disabledState], |
||||||
|
props: { |
||||||
|
udpList: Array, |
||||||
|
// hide direct/type |
||||||
|
hide: { |
||||||
|
type: Boolean, |
||||||
|
default: true |
||||||
|
} |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
/** |
||||||
|
* Current index |
||||||
|
*/ |
||||||
|
_getIndex (index) { |
||||||
|
this.localParamsIndex = index |
||||||
|
}, |
||||||
|
/** |
||||||
|
* handle direct |
||||||
|
*/ |
||||||
|
_handleDirectChanged () { |
||||||
|
this._verifProp('value') |
||||||
|
}, |
||||||
|
/** |
||||||
|
* handle type |
||||||
|
*/ |
||||||
|
_handleTypeChanged () { |
||||||
|
this._verifProp('value') |
||||||
|
}, |
||||||
|
/** |
||||||
|
* delete item |
||||||
|
*/ |
||||||
|
_removeUdp (index) { |
||||||
|
this.localParamsList.splice(index, 1) |
||||||
|
this._verifProp('value') |
||||||
|
}, |
||||||
|
/** |
||||||
|
* add |
||||||
|
*/ |
||||||
|
_addUdp () { |
||||||
|
this.localParamsList.push({ |
||||||
|
prop: '', |
||||||
|
direct: 'IN', |
||||||
|
type: 'VARCHAR', |
||||||
|
value: '' |
||||||
|
}) |
||||||
|
}, |
||||||
|
/** |
||||||
|
* blur verification |
||||||
|
*/ |
||||||
|
_handleValue () { |
||||||
|
this._verifProp('value') |
||||||
|
}, |
||||||
|
/** |
||||||
|
* Verify that the value exists or is empty |
||||||
|
*/ |
||||||
|
_verifProp (type) { |
||||||
|
let arr = [] |
||||||
|
let flag = true |
||||||
|
_.map(this.localParamsList, v => { |
||||||
|
arr.push(v.prop) |
||||||
|
if (!v.prop) { |
||||||
|
flag = false |
||||||
|
} |
||||||
|
}) |
||||||
|
if (!flag) { |
||||||
|
if (!type) { |
||||||
|
this.$message.warning(`${i18n.$t('prop不能为空')}`) |
||||||
|
} |
||||||
|
return false |
||||||
|
} |
||||||
|
let newArr = _.cloneDeep(_.uniqWith(arr, _.isEqual)) |
||||||
|
if (newArr.length !== arr.length) { |
||||||
|
if (!type) { |
||||||
|
this.$message.warning(`${i18n.$t('prop中有重复')}`) |
||||||
|
} |
||||||
|
return false |
||||||
|
} |
||||||
|
this.$emit('on-local-params', _.cloneDeep(this.localParamsList)) |
||||||
|
return true |
||||||
|
} |
||||||
|
}, |
||||||
|
watch: { |
||||||
|
// Monitor data changes |
||||||
|
udpList () { |
||||||
|
this.localParamsList = this.udpList |
||||||
|
} |
||||||
|
}, |
||||||
|
created () { |
||||||
|
this.localParamsList = this.udpList |
||||||
|
}, |
||||||
|
mounted () { |
||||||
|
}, |
||||||
|
components: { } |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style lang="scss" rel="stylesheet/scss"> |
||||||
|
.user-def-params-model { |
||||||
|
.select-listpp { |
||||||
|
margin-bottom: 6px; |
||||||
|
.lt-add { |
||||||
|
padding-left: 4px; |
||||||
|
a { |
||||||
|
.iconfont { |
||||||
|
font-size: 18px; |
||||||
|
vertical-align: middle; |
||||||
|
margin-bottom: -2px; |
||||||
|
display: inline-block; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.add { |
||||||
|
a { |
||||||
|
.iconfont { |
||||||
|
font-size: 18px; |
||||||
|
vertical-align: middle; |
||||||
|
display: inline-block; |
||||||
|
margin-top: 1px; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,100 @@ |
|||||||
|
<template> |
||||||
|
<div class="resource-list-model"> |
||||||
|
<x-select multiple |
||||||
|
v-model="value" |
||||||
|
filterable |
||||||
|
:disabled="isDetails" |
||||||
|
:placeholder="$t('请选择资源')" |
||||||
|
style="width: 100%;"> |
||||||
|
<x-option |
||||||
|
v-for="city in resList" |
||||||
|
:key="city.code" |
||||||
|
:value="city.code" |
||||||
|
:label="city.code"> |
||||||
|
</x-option> |
||||||
|
</x-select> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<script> |
||||||
|
import _ from 'lodash' |
||||||
|
import disabledState from '@/module/mixin/disabledState' |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'resourceList', |
||||||
|
data () { |
||||||
|
return { |
||||||
|
// Resource(List) |
||||||
|
resList: [], |
||||||
|
// Resource |
||||||
|
value: [] |
||||||
|
} |
||||||
|
}, |
||||||
|
mixins: [disabledState], |
||||||
|
props: { |
||||||
|
resourceList: Array |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
/** |
||||||
|
* Verify data source |
||||||
|
*/ |
||||||
|
_verifResources () { |
||||||
|
this.$emit('on-resourcesData', _.map(this.value, v => { |
||||||
|
return { |
||||||
|
res: v |
||||||
|
} |
||||||
|
})) |
||||||
|
return true |
||||||
|
} |
||||||
|
}, |
||||||
|
watch: { |
||||||
|
// Listening data source |
||||||
|
resourceList (a) { |
||||||
|
this.value = _.map(_.cloneDeep(a), v => v.res) |
||||||
|
} |
||||||
|
}, |
||||||
|
created () { |
||||||
|
this.resList = _.map(_.cloneDeep(this.store.state.dag.resourcesListS), v => { |
||||||
|
return { |
||||||
|
code: v.alias |
||||||
|
} |
||||||
|
}) |
||||||
|
|
||||||
|
if (this.resourceList.length) { |
||||||
|
this.value = _.map(_.cloneDeep(this.resourceList), v => v.res) |
||||||
|
} |
||||||
|
}, |
||||||
|
mounted () { |
||||||
|
|
||||||
|
}, |
||||||
|
components: { } |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style lang="scss" rel="stylesheet/scss"> |
||||||
|
.resource-list-model { |
||||||
|
.select-listpp { |
||||||
|
margin-bottom: 6px; |
||||||
|
.lt-add { |
||||||
|
padding-left: 4px; |
||||||
|
a { |
||||||
|
.iconfont { |
||||||
|
font-size: 18px; |
||||||
|
vertical-align: middle; |
||||||
|
margin-bottom: -2px; |
||||||
|
display: inline-block; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
>.add { |
||||||
|
a { |
||||||
|
.iconfont { |
||||||
|
font-size: 18px; |
||||||
|
vertical-align: middle; |
||||||
|
display: inline-block; |
||||||
|
margin-top: 1px; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,57 @@ |
|||||||
|
<template> |
||||||
|
<div class="sql-type-model"> |
||||||
|
<x-select |
||||||
|
v-model="sqlTypeId" |
||||||
|
:disabled="isDetails" |
||||||
|
@on-change="_handleSqlTypeChanged" |
||||||
|
style="width: 90px;"> |
||||||
|
<x-option |
||||||
|
v-for="city in sqlTypeList" |
||||||
|
:key="city.id" |
||||||
|
:value="city" |
||||||
|
:label="city.code"> |
||||||
|
</x-option> |
||||||
|
</x-select> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<script> |
||||||
|
import _ from 'lodash' |
||||||
|
import { sqlTypeList } from './commcon' |
||||||
|
import disabledState from '@/module/mixin/disabledState' |
||||||
|
export default { |
||||||
|
name: 'sql-type', |
||||||
|
data () { |
||||||
|
return { |
||||||
|
// sql(List) |
||||||
|
sqlTypeList: sqlTypeList, |
||||||
|
// sql |
||||||
|
sqlTypeId: {} |
||||||
|
} |
||||||
|
}, |
||||||
|
mixins: [disabledState], |
||||||
|
props: { |
||||||
|
sqlType: Number |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
/** |
||||||
|
* return sqlType |
||||||
|
*/ |
||||||
|
_handleSqlTypeChanged (val) { |
||||||
|
this.$emit('on-sqlType', val.value.id) |
||||||
|
} |
||||||
|
}, |
||||||
|
watch: { |
||||||
|
}, |
||||||
|
created () { |
||||||
|
this.$nextTick(() => { |
||||||
|
if (this.sqlType !== null) { |
||||||
|
this.sqlTypeId = _.filter(this.sqlTypeList, v => v.id === this.sqlType)[0] |
||||||
|
} else { |
||||||
|
this.sqlTypeId = this.sqlTypeList[0] |
||||||
|
} |
||||||
|
}) |
||||||
|
}, |
||||||
|
mounted () { |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
@ -0,0 +1,116 @@ |
|||||||
|
<template> |
||||||
|
<div class="udfs-model"> |
||||||
|
<x-select multiple |
||||||
|
v-model="udfsStr" |
||||||
|
:disabled="isDetails" |
||||||
|
style="width: 100%;"> |
||||||
|
<x-option |
||||||
|
v-for="city in udfsList" |
||||||
|
:key="city.id" |
||||||
|
:value="city" |
||||||
|
:label="city.code"> |
||||||
|
</x-option> |
||||||
|
</x-select> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<script> |
||||||
|
import _ from 'lodash' |
||||||
|
import disabledState from '@/module/mixin/disabledState' |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'udfs', |
||||||
|
data () { |
||||||
|
return { |
||||||
|
// UDFS Function |
||||||
|
udfsStr: [], |
||||||
|
// UDFS Function(List) |
||||||
|
udfsList: [] |
||||||
|
} |
||||||
|
}, |
||||||
|
mixins: [disabledState], |
||||||
|
props: { |
||||||
|
udfs: String, |
||||||
|
type: String |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
/** |
||||||
|
* verification |
||||||
|
*/ |
||||||
|
_verifUdfs () { |
||||||
|
this.$emit('on-udfsData', _.map(this.udfsStr, v => v.id).join(',')) |
||||||
|
return true |
||||||
|
}, |
||||||
|
/** |
||||||
|
* Get UDFS function data |
||||||
|
*/ |
||||||
|
_getUdfList () { |
||||||
|
this.udfsList = [] |
||||||
|
this.store.dispatch('dag/getUdfList', { type: this.type }).then(res => { |
||||||
|
this.udfsList = _.map(res.data, v => { |
||||||
|
return { |
||||||
|
id: v.id, |
||||||
|
code: v.funcName |
||||||
|
} |
||||||
|
}) |
||||||
|
|
||||||
|
let udfs = _.cloneDeep(this.udfs.split(',')) |
||||||
|
if (udfs.length) { |
||||||
|
let arr = [] |
||||||
|
_.map(udfs, v => { |
||||||
|
_.map(this.udfsList, v1 => { |
||||||
|
if (parseInt(v) === v1.id) { |
||||||
|
arr.push(v1) |
||||||
|
} |
||||||
|
}) |
||||||
|
}) |
||||||
|
this.$nextTick(() => { |
||||||
|
this.udfsStr = arr |
||||||
|
}) |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
}, |
||||||
|
watch: { |
||||||
|
type (a) { |
||||||
|
// The props parameter needs to be changed due to the scene. |
||||||
|
this.udfs = '' |
||||||
|
if (a === 'HIVE') { |
||||||
|
this._getUdfList() |
||||||
|
} else { |
||||||
|
this.udfsList = [] |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
created () { |
||||||
|
this._getUdfList() |
||||||
|
}, |
||||||
|
mounted () { |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style lang="scss" rel="stylesheet/scss"> |
||||||
|
.udfs-model { |
||||||
|
.add-udfs { |
||||||
|
color: #0097e0; |
||||||
|
} |
||||||
|
.t-list { |
||||||
|
margin-bottom: 14px; |
||||||
|
.v-btn { |
||||||
|
width: 208px; |
||||||
|
} |
||||||
|
&:hover { |
||||||
|
} |
||||||
|
.delect-btn { |
||||||
|
display: inline-block; |
||||||
|
width: 54px !important; |
||||||
|
vertical-align: middle; |
||||||
|
background: #ff0000; |
||||||
|
border-color: #ff0000; |
||||||
|
span { |
||||||
|
vertical-align: middle !important; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,237 @@ |
|||||||
|
<template> |
||||||
|
<div class="dependence-model"> |
||||||
|
<m-list-box> |
||||||
|
<div slot="text">{{$t('添加依赖')}}</div> |
||||||
|
<div slot="content"> |
||||||
|
<div class="dep-opt"> |
||||||
|
<a href="javascript:" |
||||||
|
@click="!isDetails && _addDep()" |
||||||
|
class="add-dep"> |
||||||
|
<i v-if="!isLoading" class="iconfont" :class="_isDetails" data-toggle="tooltip" :title="$t('添加')"> |
||||||
|
 |
||||||
|
</i> |
||||||
|
<i v-if="isLoading" class="iconfont fa fa-spin" data-toggle="tooltip" :title="$t('添加')"> |
||||||
|
 |
||||||
|
</i> |
||||||
|
</a> |
||||||
|
</div> |
||||||
|
<div class="dep-box"> |
||||||
|
<span |
||||||
|
class="dep-relation" |
||||||
|
@click="!isDetails && _setGlobalRelation()" |
||||||
|
v-if="dependTaskList.length"> |
||||||
|
{{relation === 'AND' ? $t('且') : $t('或')}} |
||||||
|
</span> |
||||||
|
<div class="dep-list" v-for="(el,$index) in dependTaskList"> |
||||||
|
<span class="dep-line-pie" |
||||||
|
v-if="el.dependItemList.length" |
||||||
|
@click="!isDetails && _setRelation($index)"> |
||||||
|
{{el.relation === 'AND' ? $t('且') : $t('或')}} |
||||||
|
</span> |
||||||
|
<i class="iconfont dep-delete" |
||||||
|
data-toggle="tooltip" |
||||||
|
data-container="body" |
||||||
|
:class="_isDetails" |
||||||
|
@click="!isDetails && _deleteDep($index)" |
||||||
|
:title="$t('删除')" > |
||||||
|
 |
||||||
|
</i> |
||||||
|
<m-depend-item-list |
||||||
|
v-model="el.dependItemList" |
||||||
|
@on-delete-all="_onDeleteAll" |
||||||
|
:index="$index"> |
||||||
|
</m-depend-item-list> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</m-list-box> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<script> |
||||||
|
import _ from 'lodash' |
||||||
|
import mListBox from './_source/listBox' |
||||||
|
import mDependItemList from './_source/dependItemList' |
||||||
|
import disabledState from '@/module/mixin/disabledState' |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'dependence', |
||||||
|
data () { |
||||||
|
return { |
||||||
|
relation: 'AND', |
||||||
|
dependTaskList: [], |
||||||
|
isLoading: false |
||||||
|
} |
||||||
|
}, |
||||||
|
mixins: [disabledState], |
||||||
|
props: { |
||||||
|
backfillItem: Object |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
_addDep () { |
||||||
|
if (!this.isLoading) { |
||||||
|
this.isLoading = true |
||||||
|
this.dependTaskList.push({ |
||||||
|
dependItemList: [], |
||||||
|
relation: 'AND' |
||||||
|
}) |
||||||
|
} |
||||||
|
}, |
||||||
|
_deleteDep (i) { |
||||||
|
// remove index dependent |
||||||
|
this.dependTaskList.splice(i, 1) |
||||||
|
|
||||||
|
// remove tootip |
||||||
|
$('body').find('.tooltip.fade.top.in').remove() |
||||||
|
}, |
||||||
|
_onDeleteAll (i) { |
||||||
|
this._deleteDep(i) |
||||||
|
}, |
||||||
|
_setGlobalRelation () { |
||||||
|
this.relation = this.relation === 'AND' ? 'OR' : 'AND' |
||||||
|
}, |
||||||
|
_setRelation (i) { |
||||||
|
this.dependTaskList[i].relation = this.dependTaskList[i].relation === 'AND' ? 'OR' : 'AND' |
||||||
|
}, |
||||||
|
_verification () { |
||||||
|
this.$emit('on-dependent', { |
||||||
|
relation: this.relation, |
||||||
|
dependTaskList: _.map(this.dependTaskList, v => { |
||||||
|
return { |
||||||
|
relation: v.relation, |
||||||
|
dependItemList: _.map(v.dependItemList, v1 => _.omit(v1, ['depTasksList', 'state', 'dateValueList'])) |
||||||
|
} |
||||||
|
}) |
||||||
|
}) |
||||||
|
return true |
||||||
|
} |
||||||
|
}, |
||||||
|
watch: { |
||||||
|
dependTaskList () { |
||||||
|
setTimeout(() => { |
||||||
|
this.isLoading = false |
||||||
|
}, 600) |
||||||
|
} |
||||||
|
}, |
||||||
|
beforeCreate () { |
||||||
|
}, |
||||||
|
created () { |
||||||
|
let o = this.backfillItem |
||||||
|
let dependentResult = $(`#${o.id}`).data('dependent-result') || {} |
||||||
|
// Does not represent an empty object backfill |
||||||
|
if (!_.isEmpty(o)) { |
||||||
|
this.relation = _.cloneDeep(o.dependence.relation) || 'AND' |
||||||
|
this.dependTaskList = _.cloneDeep(o.dependence.dependTaskList) || [] |
||||||
|
let defaultState = this.isDetails ? 'WAITING' : '' |
||||||
|
// Process instance return status display matches by key |
||||||
|
_.map(this.dependTaskList, v => _.map(v.dependItemList, v1 => v1.state = dependentResult[`${v1.definitionId}-${v1.depTasks}-${v1.cycle}-${v1.dateValue}`] || defaultState)) |
||||||
|
} |
||||||
|
}, |
||||||
|
mounted () { |
||||||
|
}, |
||||||
|
destroyed () { |
||||||
|
}, |
||||||
|
computed: {}, |
||||||
|
components: { mListBox, mDependItemList } |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style lang="scss" rel="stylesheet/scss"> |
||||||
|
.dependence-model { |
||||||
|
margin-top: -10px; |
||||||
|
.dep-opt { |
||||||
|
margin-bottom: 10px; |
||||||
|
padding-top: 3px; |
||||||
|
line-height: 24px; |
||||||
|
.add-dep { |
||||||
|
color: #0097e0; |
||||||
|
margin-right: 10px; |
||||||
|
i { |
||||||
|
font-size: 18px; |
||||||
|
vertical-align: middle; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.dep-list { |
||||||
|
margin-bottom: 16px; |
||||||
|
position: relative; |
||||||
|
border-left: 1px solid #eee; |
||||||
|
padding-left: 16px; |
||||||
|
margin-left: -16px; |
||||||
|
transition: all 0.2s ease-out; |
||||||
|
padding-bottom: 20px; |
||||||
|
&:hover{ |
||||||
|
border-left: 1px solid #0097e0; |
||||||
|
transition: all 0.2s ease-out; |
||||||
|
.dep-line-pie { |
||||||
|
transition: all 0.2s ease-out; |
||||||
|
border: 1px solid #0097e0; |
||||||
|
background: #0097e0; |
||||||
|
color: #fff; |
||||||
|
} |
||||||
|
} |
||||||
|
.dep-line-pie { |
||||||
|
transition: all 0.2s ease-out; |
||||||
|
position: absolute; |
||||||
|
width: 20px; |
||||||
|
height: 20px; |
||||||
|
border: 1px solid #e2e2e2; |
||||||
|
text-align: center; |
||||||
|
top: 50%; |
||||||
|
margin-top: -20px; |
||||||
|
z-index: 1; |
||||||
|
left: -10px; |
||||||
|
border-radius: 10px; |
||||||
|
background: #fff; |
||||||
|
font-size: 12px; |
||||||
|
cursor: pointer; |
||||||
|
&::selection { |
||||||
|
background:transparent; |
||||||
|
} |
||||||
|
&::-moz-selection { |
||||||
|
background:transparent; |
||||||
|
} |
||||||
|
&::-webkit-selection { |
||||||
|
background:transparent; |
||||||
|
} |
||||||
|
} |
||||||
|
.dep-delete { |
||||||
|
position: absolute; |
||||||
|
bottom: -6px; |
||||||
|
left: 14px; |
||||||
|
font-size: 18px; |
||||||
|
color: #ff0000; |
||||||
|
cursor: pointer; |
||||||
|
} |
||||||
|
} |
||||||
|
.dep-box { |
||||||
|
border-left: 4px solid #eee; |
||||||
|
margin-left: -46px; |
||||||
|
padding-left: 42px; |
||||||
|
position: relative; |
||||||
|
.dep-relation { |
||||||
|
position: absolute; |
||||||
|
width: 20px; |
||||||
|
height: 20px; |
||||||
|
border: 1px solid #e2e2e2; |
||||||
|
text-align: center; |
||||||
|
top: 50%; |
||||||
|
margin-top: -10px; |
||||||
|
z-index: 1; |
||||||
|
left: -12px; |
||||||
|
border-radius: 10px; |
||||||
|
background: #fff; |
||||||
|
font-size: 12px; |
||||||
|
cursor: pointer; |
||||||
|
&::selection { |
||||||
|
background:transparent; |
||||||
|
} |
||||||
|
&::-moz-selection { |
||||||
|
background:transparent; |
||||||
|
} |
||||||
|
&::-webkit-selection { |
||||||
|
background:transparent; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,264 @@ |
|||||||
|
<template> |
||||||
|
<div class="spark-model"> |
||||||
|
<m-list-box> |
||||||
|
<div slot="text">{{$t('程序类型')}}</div> |
||||||
|
<div slot="content"> |
||||||
|
<x-select v-model="programType" :disabled="isDetails" style="width: 100px;"> |
||||||
|
<x-option |
||||||
|
v-for="city in programTypeList" |
||||||
|
:key="city.code" |
||||||
|
:value="city.code" |
||||||
|
:label="city.code"> |
||||||
|
</x-option> |
||||||
|
</x-select> |
||||||
|
</div> |
||||||
|
</m-list-box> |
||||||
|
<m-list-box v-if="programType !== 'PYTHON'"> |
||||||
|
<div slot="text">{{$t('主函数的class')}}</div> |
||||||
|
<div slot="content"> |
||||||
|
<x-input |
||||||
|
:disabled="isDetails" |
||||||
|
type="input" |
||||||
|
v-model="mainClass" |
||||||
|
:placeholder="$t('请输入mainClass')" |
||||||
|
autocomplete="off"> |
||||||
|
</x-input> |
||||||
|
</div> |
||||||
|
</m-list-box> |
||||||
|
<m-list-box> |
||||||
|
<div slot="text">{{$t('主jar包')}}</div> |
||||||
|
<div slot="content"> |
||||||
|
<x-select |
||||||
|
style="width: 100%;" |
||||||
|
:placeholder="$t('请选择主jar包')" |
||||||
|
v-model="mainJar" |
||||||
|
filterable |
||||||
|
:disabled="isDetails"> |
||||||
|
<x-option |
||||||
|
v-for="city in mainJarList" |
||||||
|
:key="city.code" |
||||||
|
:value="city.code" |
||||||
|
:label="city.code"> |
||||||
|
</x-option> |
||||||
|
</x-select> |
||||||
|
</div> |
||||||
|
</m-list-box> |
||||||
|
<m-list-box> |
||||||
|
<div slot="text">{{$t('命令行参数')}}</div> |
||||||
|
<div slot="content"> |
||||||
|
<x-input |
||||||
|
:autosize="{minRows:2}" |
||||||
|
:disabled="isDetails" |
||||||
|
type="textarea" |
||||||
|
v-model="mainArgs" |
||||||
|
:placeholder="$t('请输入命令行参数')" |
||||||
|
autocomplete="off"> |
||||||
|
</x-input> |
||||||
|
</div> |
||||||
|
</m-list-box> |
||||||
|
<m-list-box> |
||||||
|
<div slot="text">{{$t('其他参数')}}</div> |
||||||
|
<div slot="content"> |
||||||
|
<x-input |
||||||
|
:disabled="isDetails" |
||||||
|
:autosize="{minRows:2}" |
||||||
|
type="textarea" |
||||||
|
v-model="others" |
||||||
|
:placeholder="$t('请输入其他参数')" |
||||||
|
autocomplete="off"> |
||||||
|
</x-input> |
||||||
|
</div> |
||||||
|
</m-list-box> |
||||||
|
<m-list-box> |
||||||
|
<div slot="text">{{$t('资源')}}</div> |
||||||
|
<div slot="content"> |
||||||
|
<m-resources |
||||||
|
ref="refResources" |
||||||
|
@on-resourcesData="_onResourcesData" |
||||||
|
:resource-list="resourceList"> |
||||||
|
</m-resources> |
||||||
|
</div> |
||||||
|
</m-list-box> |
||||||
|
<m-list-box> |
||||||
|
<div slot="text">{{$t('自定义参数')}}</div> |
||||||
|
<div slot="content"> |
||||||
|
<m-local-params |
||||||
|
ref="refLocalParams" |
||||||
|
@on-local-params="_onLocalParams" |
||||||
|
:udp-list="localParams" |
||||||
|
:hide="false"> |
||||||
|
</m-local-params> |
||||||
|
</div> |
||||||
|
</m-list-box> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<script> |
||||||
|
import _ from 'lodash' |
||||||
|
import i18n from '@/module/i18n' |
||||||
|
import mListBox from './_source/listBox' |
||||||
|
import mResources from './_source/resources' |
||||||
|
import mLocalParams from './_source/localParams' |
||||||
|
import disabledState from '@/module/mixin/disabledState' |
||||||
|
export default { |
||||||
|
name: 'mr', |
||||||
|
data () { |
||||||
|
return { |
||||||
|
// Main function class |
||||||
|
mainClass: '', |
||||||
|
// Master jar package |
||||||
|
mainJar: null, |
||||||
|
// Main jar package (List) |
||||||
|
mainJarList: [], |
||||||
|
// Resource(list) |
||||||
|
resourceList: [], |
||||||
|
// Custom parameter |
||||||
|
localParams: [], |
||||||
|
// Command line argument |
||||||
|
mainArgs: '', |
||||||
|
// Other parameters |
||||||
|
others: '', |
||||||
|
// Program type |
||||||
|
programType: 'JAVA', |
||||||
|
// Program type(List) |
||||||
|
programTypeList: [{ code: 'JAVA' }, { code: 'PYTHON' }] |
||||||
|
} |
||||||
|
}, |
||||||
|
props: { |
||||||
|
backfillItem: Object |
||||||
|
}, |
||||||
|
mixins: [disabledState], |
||||||
|
methods: { |
||||||
|
/** |
||||||
|
* return localParams |
||||||
|
*/ |
||||||
|
_onLocalParams (a) { |
||||||
|
this.localParams = a |
||||||
|
}, |
||||||
|
/** |
||||||
|
* return resourceList |
||||||
|
*/ |
||||||
|
_onResourcesData (a) { |
||||||
|
this.resourceList = a |
||||||
|
}, |
||||||
|
/** |
||||||
|
* verification |
||||||
|
*/ |
||||||
|
_verification () { |
||||||
|
if (this.programType !== 'PYTHON' && !this.mainClass) { |
||||||
|
this.$message.warning(`${i18n.$t('请填写主函数的class')}`) |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
if (!this.mainJar) { |
||||||
|
this.$message.warning(`${i18n.$t('请选择主jar包')}`) |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
if (!this.$refs.refResources._verifResources()) { |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
// localParams Subcomponent verification |
||||||
|
if (!this.$refs.refLocalParams._verifProp()) { |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
// storage |
||||||
|
this.$emit('on-params', { |
||||||
|
mainClass: this.mainClass, |
||||||
|
mainJar: { |
||||||
|
res: this.mainJar |
||||||
|
}, |
||||||
|
resourceList: this.resourceList, |
||||||
|
localParams: this.localParams, |
||||||
|
mainArgs: this.mainArgs, |
||||||
|
others: this.others, |
||||||
|
programType: this.programType |
||||||
|
}) |
||||||
|
return true |
||||||
|
}, |
||||||
|
/** |
||||||
|
* Get resource data |
||||||
|
*/ |
||||||
|
_getResourcesList () { |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
let isJar = (alias) => { |
||||||
|
return alias.substring(alias.lastIndexOf('.') + 1, alias.length) !== 'jar' |
||||||
|
} |
||||||
|
this.mainJarList = _.map(_.cloneDeep(this.store.state.dag.resourcesListS), v => { |
||||||
|
return { |
||||||
|
id: v.id, |
||||||
|
code: v.alias, |
||||||
|
disabled: isJar(v.alias) |
||||||
|
} |
||||||
|
}) |
||||||
|
resolve() |
||||||
|
}) |
||||||
|
} |
||||||
|
}, |
||||||
|
watch: { |
||||||
|
/** |
||||||
|
* monitor |
||||||
|
*/ |
||||||
|
programType (type) { |
||||||
|
if (type === 'PYTHON') { |
||||||
|
this.mainClass = '' |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
created () { |
||||||
|
this._getResourcesList().then(() => { |
||||||
|
let o = this.backfillItem |
||||||
|
|
||||||
|
// Non-null objects represent backfill |
||||||
|
if (!_.isEmpty(o)) { |
||||||
|
this.mainClass = o.params.mainClass || '' |
||||||
|
this.mainJar = o.params.mainJar.res || '' |
||||||
|
this.mainArgs = o.params.mainArgs || '' |
||||||
|
this.others = o.params.others |
||||||
|
this.programType = o.params.programType || 'JAVA' |
||||||
|
|
||||||
|
// backfill resourceList |
||||||
|
let resourceList = o.params.resourceList || [] |
||||||
|
if (resourceList.length) { |
||||||
|
this.resourceList = resourceList |
||||||
|
} |
||||||
|
|
||||||
|
// backfill localParams |
||||||
|
let localParams = o.params.localParams || [] |
||||||
|
if (localParams.length) { |
||||||
|
this.localParams = localParams |
||||||
|
} |
||||||
|
} |
||||||
|
}) |
||||||
|
}, |
||||||
|
mounted () { |
||||||
|
|
||||||
|
}, |
||||||
|
components: { mLocalParams, mListBox, mResources } |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style lang="scss" rel="stylesheet/scss"> |
||||||
|
.spark-model { |
||||||
|
.list-box-4p { |
||||||
|
.list { |
||||||
|
margin-bottom: 14px; |
||||||
|
.sp1 { |
||||||
|
float: left; |
||||||
|
width: 112px; |
||||||
|
text-align: right; |
||||||
|
margin-right: 10px; |
||||||
|
font-size: 14px; |
||||||
|
color: #777; |
||||||
|
display: inline-block; |
||||||
|
padding-top: 6px; |
||||||
|
} |
||||||
|
.sp2 { |
||||||
|
float: left; |
||||||
|
margin-right: 4px; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,134 @@ |
|||||||
|
<template> |
||||||
|
<div class="procedure-model"> |
||||||
|
<m-list-box> |
||||||
|
<div slot="text">{{$t('数据源')}}</div> |
||||||
|
<div slot="content"> |
||||||
|
<m-datasource |
||||||
|
ref="refDs" |
||||||
|
@on-dsData="_onDsData" |
||||||
|
:supportType="['MYSQL','POSTGRESQL']" |
||||||
|
:data="{ type:type,datasource:datasource }"> |
||||||
|
</m-datasource> |
||||||
|
</div> |
||||||
|
</m-list-box> |
||||||
|
<m-list-box> |
||||||
|
<div slot="text">{{$t('方法')}}</div> |
||||||
|
<div slot="content"> |
||||||
|
<x-input |
||||||
|
type="input" |
||||||
|
:disabled="isDetails" |
||||||
|
v-model="method" |
||||||
|
:placeholder="$t('请输入method(选填)')" |
||||||
|
autocomplete="off"> |
||||||
|
</x-input> |
||||||
|
</div> |
||||||
|
</m-list-box> |
||||||
|
<m-list-box> |
||||||
|
<div slot="text">{{$t('自定义参数')}}</div> |
||||||
|
<div slot="content"> |
||||||
|
<m-local-params |
||||||
|
ref="refLocalParams" |
||||||
|
@on-local-params="_onLocalParams" |
||||||
|
:udp-list="localParams"> |
||||||
|
</m-local-params> |
||||||
|
</div> |
||||||
|
</m-list-box> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<script> |
||||||
|
import _ from 'lodash' |
||||||
|
import i18n from '@/module/i18n' |
||||||
|
import mListBox from './_source/listBox' |
||||||
|
import mDatasource from './_source/datasource' |
||||||
|
import mLocalParams from './_source/localParams' |
||||||
|
import disabledState from '@/module/mixin/disabledState' |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'procedure', |
||||||
|
data () { |
||||||
|
return { |
||||||
|
// method |
||||||
|
method: '', |
||||||
|
// Custom parameter |
||||||
|
localParams: [], |
||||||
|
// Data source type |
||||||
|
type: '', |
||||||
|
// data source |
||||||
|
datasource: '' |
||||||
|
} |
||||||
|
}, |
||||||
|
mixins: [disabledState], |
||||||
|
props: { |
||||||
|
backfillItem: Object |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
/** |
||||||
|
* return type or datasource |
||||||
|
*/ |
||||||
|
_onDsData (o) { |
||||||
|
this.type = o.type |
||||||
|
this.datasource = o.datasource |
||||||
|
}, |
||||||
|
/** |
||||||
|
* return udp |
||||||
|
*/ |
||||||
|
_onLocalParams (a) { |
||||||
|
}, |
||||||
|
/** |
||||||
|
* verification |
||||||
|
*/ |
||||||
|
_verification () { |
||||||
|
// datasource Subcomponent verification |
||||||
|
if (!this.$refs.refDs._verifDatasource()) { |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
// Verification function |
||||||
|
if (!this.method) { |
||||||
|
this.$message.warning(`${i18n.$t('请输入方法')}`) |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
// localParams Subcomponent verification |
||||||
|
if (!this.$refs.refLocalParams._verifProp()) { |
||||||
|
return false |
||||||
|
} |
||||||
|
// storage |
||||||
|
this.$emit('on-params', { |
||||||
|
type: this.type, |
||||||
|
datasource: this.datasource, |
||||||
|
method: this.method, |
||||||
|
localParams: this.localParams |
||||||
|
}) |
||||||
|
return true |
||||||
|
} |
||||||
|
}, |
||||||
|
watch: {}, |
||||||
|
created () { |
||||||
|
let o = this.backfillItem |
||||||
|
|
||||||
|
// Non-null objects represent backfill |
||||||
|
if (!_.isEmpty(o)) { |
||||||
|
this.name = o.name |
||||||
|
this.desc = o.desc |
||||||
|
|
||||||
|
// backfill |
||||||
|
this.type = o.params.type || '' |
||||||
|
this.datasource = o.params.datasource || '' |
||||||
|
this.method = o.params.method || '' |
||||||
|
|
||||||
|
// backfill localParams |
||||||
|
let localParams = o.params.localParams || [] |
||||||
|
if (localParams.length) { |
||||||
|
this.localParams = localParams |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
mounted () { |
||||||
|
}, |
||||||
|
components: { mListBox, mDatasource, mLocalParams } |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style lang="scss" rel="stylesheet/scss"> |
||||||
|
</style> |
@ -0,0 +1,161 @@ |
|||||||
|
<template> |
||||||
|
<div class="shell-model"> |
||||||
|
<m-list-box> |
||||||
|
<div slot="text">{{$t('脚本')}}</div> |
||||||
|
<div slot="content"> |
||||||
|
<div class="from-mirror"> |
||||||
|
<textarea id="code-python-mirror" name="code-python-mirror" style="opacity: 0;"> |
||||||
|
</textarea> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</m-list-box> |
||||||
|
<m-list-box> |
||||||
|
<div slot="text">{{$t('资源')}}</div> |
||||||
|
<div slot="content"> |
||||||
|
<m-resources |
||||||
|
ref="refResources" |
||||||
|
@on-resourcesData="_onResourcesData" |
||||||
|
:resource-list="resourceList"> |
||||||
|
</m-resources> |
||||||
|
</div> |
||||||
|
</m-list-box> |
||||||
|
|
||||||
|
<m-list-box> |
||||||
|
<div slot="text">{{$t('自定义参数')}}</div> |
||||||
|
<div slot="content"> |
||||||
|
<m-local-params |
||||||
|
ref="refLocalParams" |
||||||
|
@on-local-params="_onLocalParams" |
||||||
|
:udp-list="localParams" |
||||||
|
:hide="false"> |
||||||
|
</m-local-params> |
||||||
|
</div> |
||||||
|
</m-list-box> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<script> |
||||||
|
import _ from 'lodash' |
||||||
|
import i18n from '@/module/i18n' |
||||||
|
import mListBox from './_source/listBox' |
||||||
|
import mResources from './_source/resources' |
||||||
|
import mLocalParams from './_source/localParams' |
||||||
|
import disabledState from '@/module/mixin/disabledState' |
||||||
|
import codemirror from '@/conf/home/pages/resource/pages/file/pages/_source/codemirror' |
||||||
|
|
||||||
|
let editor |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'python', |
||||||
|
data () { |
||||||
|
return { |
||||||
|
// script |
||||||
|
rawScript: '', |
||||||
|
// Custom parameter |
||||||
|
localParams: [], |
||||||
|
// resource(list) |
||||||
|
resourceList: [] |
||||||
|
} |
||||||
|
}, |
||||||
|
mixins: [disabledState], |
||||||
|
props: { |
||||||
|
backfillItem: Object |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
/** |
||||||
|
* return localParams |
||||||
|
*/ |
||||||
|
_onLocalParams (a) { |
||||||
|
this.localParams = a |
||||||
|
}, |
||||||
|
/** |
||||||
|
* return resourceList |
||||||
|
*/ |
||||||
|
_onResourcesData (a) { |
||||||
|
this.resourceList = a |
||||||
|
}, |
||||||
|
/** |
||||||
|
* verification |
||||||
|
*/ |
||||||
|
_verification () { |
||||||
|
// rawScript 验证 |
||||||
|
if (!editor.getValue()) { |
||||||
|
this.$message.warning(`${i18n.$t('请输入rawScript(必填)')}`) |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
if (!this.$refs.refResources._verifResources()) { |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
// localParams Subcomponent verification |
||||||
|
if (!this.$refs.refLocalParams._verifProp()) { |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
// storage |
||||||
|
this.$emit('on-params', { |
||||||
|
resourceList: this.resourceList, |
||||||
|
localParams: this.localParams, |
||||||
|
rawScript: editor.getValue() |
||||||
|
}) |
||||||
|
return true |
||||||
|
}, |
||||||
|
/** |
||||||
|
* Processing code highlighting |
||||||
|
*/ |
||||||
|
_handlerEditor () { |
||||||
|
// editor |
||||||
|
editor = codemirror('code-python-mirror', { |
||||||
|
mode: 'python', |
||||||
|
readOnly: this.isDetails |
||||||
|
}) |
||||||
|
|
||||||
|
this.keypress = () => { |
||||||
|
if (!editor.getOption('readOnly')) { |
||||||
|
editor.showHint({ |
||||||
|
completeSingle: false |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Monitor keyboard |
||||||
|
editor.on('keypress', this.keypress) |
||||||
|
|
||||||
|
editor.setValue(this.rawScript) |
||||||
|
|
||||||
|
return editor |
||||||
|
} |
||||||
|
}, |
||||||
|
watch: {}, |
||||||
|
created () { |
||||||
|
let o = this.backfillItem |
||||||
|
|
||||||
|
// Non-null objects represent backfill |
||||||
|
if (!_.isEmpty(o)) { |
||||||
|
this.rawScript = o.params.rawScript |
||||||
|
|
||||||
|
// backfill resourceList |
||||||
|
let resourceList = o.params.resourceList || [] |
||||||
|
if (resourceList.length) { |
||||||
|
this.resourceList = resourceList |
||||||
|
} |
||||||
|
|
||||||
|
// backfill localParams |
||||||
|
let localParams = o.params.localParams || [] |
||||||
|
if (localParams.length) { |
||||||
|
this.localParams = localParams |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
mounted () { |
||||||
|
setTimeout(() => { |
||||||
|
this._handlerEditor() |
||||||
|
}, 200) |
||||||
|
}, |
||||||
|
destroyed () { |
||||||
|
editor.toTextArea() // Uninstall |
||||||
|
editor.off($('.code-python-mirror'), 'keypress', this.keypress) |
||||||
|
}, |
||||||
|
components: { mLocalParams, mListBox, mResources } |
||||||
|
} |
||||||
|
</script> |
@ -0,0 +1,165 @@ |
|||||||
|
<template> |
||||||
|
<div class="shell-model"> |
||||||
|
<m-list-box> |
||||||
|
<div slot="text">{{$t('脚本')}}</div> |
||||||
|
<div slot="content"> |
||||||
|
<div class="from-mirror"> |
||||||
|
<textarea |
||||||
|
id="code-shell-mirror" |
||||||
|
name="code-shell-mirror" |
||||||
|
style="opacity: 0"> |
||||||
|
</textarea> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</m-list-box> |
||||||
|
<m-list-box> |
||||||
|
<div slot="text">{{$t('资源')}}</div> |
||||||
|
<div slot="content"> |
||||||
|
<m-resources |
||||||
|
ref="refResources" |
||||||
|
@on-resourcesData="_onResourcesData" |
||||||
|
:resource-list="resourceList"> |
||||||
|
</m-resources> |
||||||
|
</div> |
||||||
|
</m-list-box> |
||||||
|
<m-list-box> |
||||||
|
<div slot="text">{{$t('自定义参数')}}</div> |
||||||
|
<div slot="content"> |
||||||
|
<m-local-params |
||||||
|
ref="refLocalParams" |
||||||
|
@on-local-params="_onLocalParams" |
||||||
|
:udp-list="localParams" |
||||||
|
:hide="false"> |
||||||
|
</m-local-params> |
||||||
|
</div> |
||||||
|
</m-list-box> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<script> |
||||||
|
import _ from 'lodash' |
||||||
|
import i18n from '@/module/i18n' |
||||||
|
import mListBox from './_source/listBox' |
||||||
|
import mResources from './_source/resources' |
||||||
|
import mLocalParams from './_source/localParams' |
||||||
|
import disabledState from '@/module/mixin/disabledState' |
||||||
|
import codemirror from '@/conf/home/pages/resource/pages/file/pages/_source/codemirror' |
||||||
|
|
||||||
|
let editor |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'shell', |
||||||
|
data () { |
||||||
|
return { |
||||||
|
// script |
||||||
|
rawScript: '', |
||||||
|
// Custom parameter |
||||||
|
localParams: [], |
||||||
|
// resource(list) |
||||||
|
resourceList: [] |
||||||
|
} |
||||||
|
}, |
||||||
|
mixins: [disabledState], |
||||||
|
props: { |
||||||
|
backfillItem: Object |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
/** |
||||||
|
* return localParams |
||||||
|
*/ |
||||||
|
_onLocalParams (a) { |
||||||
|
this.localParams = a |
||||||
|
}, |
||||||
|
/** |
||||||
|
* return resourceList |
||||||
|
*/ |
||||||
|
_onResourcesData (a) { |
||||||
|
this.resourceList = a |
||||||
|
}, |
||||||
|
/** |
||||||
|
* verification |
||||||
|
*/ |
||||||
|
_verification () { |
||||||
|
// rawScript verification |
||||||
|
if (!editor.getValue()) { |
||||||
|
this.$message.warning(`${i18n.$t('请输入rawScript(必填)')}`) |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
if (!this.$refs.refResources._verifResources()) { |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
// localParams Subcomponent verification |
||||||
|
if (!this.$refs.refLocalParams._verifProp()) { |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
// storage |
||||||
|
this.$emit('on-params', { |
||||||
|
resourceList: this.resourceList, |
||||||
|
localParams: this.localParams, |
||||||
|
rawScript: editor.getValue() |
||||||
|
}) |
||||||
|
return true |
||||||
|
}, |
||||||
|
/** |
||||||
|
* Processing code highlighting |
||||||
|
*/ |
||||||
|
_handlerEditor () { |
||||||
|
// editor |
||||||
|
editor = codemirror('code-shell-mirror', { |
||||||
|
mode: 'shell', |
||||||
|
readOnly: this.isDetails |
||||||
|
}) |
||||||
|
|
||||||
|
this.keypress = () => { |
||||||
|
if (!editor.getOption('readOnly')) { |
||||||
|
editor.showHint({ |
||||||
|
completeSingle: false |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Monitor keyboard |
||||||
|
editor.on('keypress', this.keypress) |
||||||
|
|
||||||
|
editor.setValue(this.rawScript) |
||||||
|
|
||||||
|
return editor |
||||||
|
} |
||||||
|
}, |
||||||
|
watch: {}, |
||||||
|
created () { |
||||||
|
let o = this.backfillItem |
||||||
|
|
||||||
|
// Non-null objects represent backfill |
||||||
|
if (!_.isEmpty(o)) { |
||||||
|
this.rawScript = o.params.rawScript |
||||||
|
|
||||||
|
// backfill resourceList |
||||||
|
let resourceList = o.params.resourceList || [] |
||||||
|
if (resourceList.length) { |
||||||
|
this.resourceList = resourceList |
||||||
|
} |
||||||
|
|
||||||
|
// backfill localParams |
||||||
|
let localParams = o.params.localParams || [] |
||||||
|
if (localParams.length) { |
||||||
|
this.localParams = localParams |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
mounted () { |
||||||
|
setTimeout(() => { |
||||||
|
this._handlerEditor() |
||||||
|
}, 200) |
||||||
|
}, |
||||||
|
destroyed () { |
||||||
|
if (editor) { |
||||||
|
editor.toTextArea() // Uninstall |
||||||
|
editor.off($('.code-shell-mirror'), 'keypress', this.keypress) |
||||||
|
} |
||||||
|
}, |
||||||
|
components: { mLocalParams, mListBox, mResources } |
||||||
|
} |
||||||
|
</script> |
@ -0,0 +1,400 @@ |
|||||||
|
<template> |
||||||
|
<div class="spark-model"> |
||||||
|
<m-list-box> |
||||||
|
<div slot="text">{{$t('程序类型')}}</div> |
||||||
|
<div slot="content"> |
||||||
|
<x-select |
||||||
|
style="width: 130px;" |
||||||
|
v-model="programType" |
||||||
|
:disabled="isDetails"> |
||||||
|
<x-option |
||||||
|
v-for="city in programTypeList" |
||||||
|
:key="city.code" |
||||||
|
:value="city.code" |
||||||
|
:label="city.code"> |
||||||
|
</x-option> |
||||||
|
</x-select> |
||||||
|
</div> |
||||||
|
</m-list-box> |
||||||
|
<m-list-box v-if="programType !== 'PYTHON'"> |
||||||
|
<div slot="text">{{$t('主函数的class')}}</div> |
||||||
|
<div slot="content"> |
||||||
|
<x-input |
||||||
|
:disabled="isDetails" |
||||||
|
type="input" |
||||||
|
v-model="mainClass" |
||||||
|
:placeholder="$t('请输入mainClass')" |
||||||
|
autocomplete="off"> |
||||||
|
</x-input> |
||||||
|
</div> |
||||||
|
</m-list-box> |
||||||
|
<m-list-box> |
||||||
|
<div slot="text">{{$t('主jar包')}}</div> |
||||||
|
<div slot="content"> |
||||||
|
<x-select |
||||||
|
style="width: 100%;" |
||||||
|
:placeholder="$t('请选择主jar包')" |
||||||
|
v-model="mainJar" |
||||||
|
filterable |
||||||
|
:disabled="isDetails"> |
||||||
|
<x-option |
||||||
|
v-for="city in mainJarList" |
||||||
|
:key="city.code" |
||||||
|
:value="city.code" |
||||||
|
:label="city.code"> |
||||||
|
</x-option> |
||||||
|
</x-select> |
||||||
|
</div> |
||||||
|
</m-list-box> |
||||||
|
<m-list-box> |
||||||
|
<div slot="text">{{$t('部署方式')}}</div> |
||||||
|
<div slot="content"> |
||||||
|
<x-radio-group v-model="deployMode"> |
||||||
|
<x-radio :label="'cluster'" :disabled="isDetails"></x-radio> |
||||||
|
<x-radio :label="'client'" :disabled="isDetails"></x-radio> |
||||||
|
<x-radio :label="'local'" :disabled="isDetails"></x-radio> |
||||||
|
</x-radio-group> |
||||||
|
</div> |
||||||
|
</m-list-box> |
||||||
|
<div class="list-box-4p"> |
||||||
|
<div class="clearfix list"> |
||||||
|
<span class="sp1">{{$t('Driver内核数')}}</span> |
||||||
|
<span class="sp2"> |
||||||
|
<x-input |
||||||
|
:disabled="isDetails" |
||||||
|
type="input" |
||||||
|
v-model="driverCores" |
||||||
|
:placeholder="$t('请输入Driver内核数')" |
||||||
|
style="width: 200px;" |
||||||
|
autocomplete="off"> |
||||||
|
</x-input> |
||||||
|
</span> |
||||||
|
<span class="sp1 sp3">{{$t('Driver内存数')}}</span> |
||||||
|
<span class="sp2"> |
||||||
|
<x-input |
||||||
|
:disabled="isDetails" |
||||||
|
type="input" |
||||||
|
v-model="driverMemory" |
||||||
|
:placeholder="$t('请输入Driver内存数')" |
||||||
|
style="width: 186px;" |
||||||
|
autocomplete="off"> |
||||||
|
</x-input> |
||||||
|
</span> |
||||||
|
</div> |
||||||
|
<div class="clearfix list"> |
||||||
|
<span class="sp1">{{$t('Executor数量')}}</span> |
||||||
|
<span class="sp2"> |
||||||
|
<x-input |
||||||
|
:disabled="isDetails" |
||||||
|
type="input" |
||||||
|
v-model="numExecutors" |
||||||
|
:placeholder="$t('请输入Executor数量')" |
||||||
|
style="width: 200px;" |
||||||
|
autocomplete="off"> |
||||||
|
</x-input> |
||||||
|
</span> |
||||||
|
<span class="sp1 sp3">{{$t('Executor内存数')}}</span> |
||||||
|
<span class="sp2"> |
||||||
|
<x-input |
||||||
|
:disabled="isDetails" |
||||||
|
type="input" |
||||||
|
v-model="executorMemory" |
||||||
|
:placeholder="$t('请输入Executor内存数')" |
||||||
|
style="width: 186px;" |
||||||
|
autocomplete="off"> |
||||||
|
</x-input> |
||||||
|
</span> |
||||||
|
</div> |
||||||
|
<div class="clearfix list"> |
||||||
|
<span class="sp1">{{$t('Executor内核数')}}</span> |
||||||
|
<span class="sp2"> |
||||||
|
<x-input |
||||||
|
:disabled="isDetails" |
||||||
|
type="input" |
||||||
|
v-model="executorCores" |
||||||
|
:placeholder="$t('请输入Executor内核数')" |
||||||
|
style="width: 200px;" |
||||||
|
autocomplete="off"> |
||||||
|
</x-input> |
||||||
|
</span> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<m-list-box> |
||||||
|
<div slot="text">{{$t('命令行参数')}}</div> |
||||||
|
<div slot="content"> |
||||||
|
<x-input |
||||||
|
:autosize="{minRows:2}" |
||||||
|
:disabled="isDetails" |
||||||
|
type="textarea" |
||||||
|
v-model="mainArgs" |
||||||
|
:placeholder="$t('请输入命令行参数')" |
||||||
|
autocomplete="off"> |
||||||
|
</x-input> |
||||||
|
</div> |
||||||
|
</m-list-box> |
||||||
|
<m-list-box> |
||||||
|
<div slot="text">{{$t('其他参数')}}</div> |
||||||
|
<div slot="content"> |
||||||
|
<x-input |
||||||
|
:disabled="isDetails" |
||||||
|
:autosize="{minRows:2}" |
||||||
|
type="textarea" |
||||||
|
v-model="others" |
||||||
|
:placeholder="$t('请输入其他参数')"> |
||||||
|
</x-input> |
||||||
|
</div> |
||||||
|
</m-list-box> |
||||||
|
<m-list-box> |
||||||
|
<div slot="text">{{$t('资源')}}</div> |
||||||
|
<div slot="content"> |
||||||
|
<m-resources |
||||||
|
ref="refResources" |
||||||
|
@on-resourcesData="_onResourcesData" |
||||||
|
:resource-list="resourceList"> |
||||||
|
</m-resources> |
||||||
|
</div> |
||||||
|
</m-list-box> |
||||||
|
<m-list-box> |
||||||
|
<div slot="text">{{$t('自定义参数')}}</div> |
||||||
|
<div slot="content"> |
||||||
|
<m-local-params |
||||||
|
ref="refLocalParams" |
||||||
|
@on-local-params="_onLocalParams" |
||||||
|
:udp-list="localParams" |
||||||
|
:hide="false"> |
||||||
|
</m-local-params> |
||||||
|
</div> |
||||||
|
</m-list-box> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<script> |
||||||
|
import _ from 'lodash' |
||||||
|
import i18n from '@/module/i18n' |
||||||
|
import mLocalParams from './_source/localParams' |
||||||
|
import mListBox from './_source/listBox' |
||||||
|
import mResources from './_source/resources' |
||||||
|
import disabledState from '@/module/mixin/disabledState' |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'spark', |
||||||
|
data () { |
||||||
|
return { |
||||||
|
// Main function class |
||||||
|
mainClass: '', |
||||||
|
// Master jar package |
||||||
|
mainJar: null, |
||||||
|
// Master jar package(List) |
||||||
|
mainJarList: [], |
||||||
|
// Deployment method |
||||||
|
deployMode: 'cluster', |
||||||
|
// Resource(list) |
||||||
|
resourceList: [], |
||||||
|
// Custom function |
||||||
|
localParams: [], |
||||||
|
// Driver Number of cores |
||||||
|
driverCores: 1, |
||||||
|
// Driver Number of memory |
||||||
|
driverMemory: '512M', |
||||||
|
// Executor Number |
||||||
|
numExecutors: 2, |
||||||
|
// Executor Number of memory |
||||||
|
executorMemory: '2G', |
||||||
|
// Executor Number of cores |
||||||
|
executorCores: 2, |
||||||
|
// Command line argument |
||||||
|
mainArgs: '', |
||||||
|
// Other parameters |
||||||
|
others: '', |
||||||
|
// Program type |
||||||
|
programType: 'SCALA', |
||||||
|
// Program type(List) |
||||||
|
programTypeList: [{ code: 'JAVA' }, { code: 'SCALA' }, { code: 'PYTHON' }] |
||||||
|
} |
||||||
|
}, |
||||||
|
props: { |
||||||
|
backfillItem: Object |
||||||
|
}, |
||||||
|
mixins: [disabledState], |
||||||
|
methods: { |
||||||
|
/** |
||||||
|
* return localParams |
||||||
|
*/ |
||||||
|
_onLocalParams (a) { |
||||||
|
this.localParams = a |
||||||
|
}, |
||||||
|
/** |
||||||
|
* return resourceList |
||||||
|
*/ |
||||||
|
_onResourcesData (a) { |
||||||
|
this.resourceList = a |
||||||
|
}, |
||||||
|
/** |
||||||
|
* verification |
||||||
|
*/ |
||||||
|
_verification () { |
||||||
|
if (this.programType !== 'PYTHON' && !this.mainClass) { |
||||||
|
this.$message.warning(`${i18n.$t('请填写主函数的class')}`) |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
if (!this.mainJar) { |
||||||
|
this.$message.warning(`${i18n.$t('请选择主jar包')}`) |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
if (!this.numExecutors) { |
||||||
|
this.$message.warning(`${i18n.$t('请填写Executor数量')}`) |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
if (!Number.isInteger(parseInt(this.numExecutors))) { |
||||||
|
this.$message.warning(`${i18n.$t('Executor数量为正整数')}`) |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
if (!this.executorMemory) { |
||||||
|
this.$message.warning(`${i18n.$t('请填写Executor内存数')}`) |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
if (!this.executorMemory) { |
||||||
|
this.$message.warning(`${i18n.$t('请填写Executor内存数')}`) |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
if (!_.isNumber(parseInt(this.executorMemory))) { |
||||||
|
this.$message.warning(`${i18n.$t('内存数为数字')}`) |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
if (!this.executorCores) { |
||||||
|
this.$message.warning(`${i18n.$t('请填写Executor内核数')}`) |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
if (!Number.isInteger(parseInt(this.executorCores))) { |
||||||
|
this.$message.warning(`${i18n.$t('内核数为正整数')}`) |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
if (!this.$refs.refResources._verifResources()) { |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
// localParams Subcomponent verification |
||||||
|
if (!this.$refs.refLocalParams._verifProp()) { |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
// storage |
||||||
|
this.$emit('on-params', { |
||||||
|
mainClass: this.mainClass, |
||||||
|
mainJar: { |
||||||
|
res: this.mainJar |
||||||
|
}, |
||||||
|
deployMode: this.deployMode, |
||||||
|
resourceList: this.resourceList, |
||||||
|
localParams: this.localParams, |
||||||
|
driverCores: this.driverCores, |
||||||
|
driverMemory: this.driverMemory, |
||||||
|
numExecutors: this.numExecutors, |
||||||
|
executorMemory: this.executorMemory, |
||||||
|
executorCores: this.executorCores, |
||||||
|
mainArgs: this.mainArgs, |
||||||
|
others: this.others, |
||||||
|
programType: this.programType |
||||||
|
}) |
||||||
|
return true |
||||||
|
}, |
||||||
|
/** |
||||||
|
* get resources list |
||||||
|
*/ |
||||||
|
_getResourcesList () { |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
let isJar = (alias) => { |
||||||
|
return alias.substring(alias.lastIndexOf('.') + 1, alias.length) !== 'jar' |
||||||
|
} |
||||||
|
this.mainJarList = _.map(_.cloneDeep(this.store.state.dag.resourcesListS), v => { |
||||||
|
return { |
||||||
|
id: v.id, |
||||||
|
code: v.alias, |
||||||
|
disabled: isJar(v.alias) |
||||||
|
} |
||||||
|
}) |
||||||
|
resolve() |
||||||
|
}) |
||||||
|
} |
||||||
|
}, |
||||||
|
watch: { |
||||||
|
// Listening type |
||||||
|
programType (type) { |
||||||
|
if (type === 'PYTHON') { |
||||||
|
this.mainClass = '' |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
created () { |
||||||
|
this._getResourcesList().then(() => { |
||||||
|
let o = this.backfillItem |
||||||
|
|
||||||
|
// Non-null objects represent backfill |
||||||
|
if (!_.isEmpty(o)) { |
||||||
|
this.mainClass = o.params.mainClass || '' |
||||||
|
this.mainJar = o.params.mainJar.res || '' |
||||||
|
this.deployMode = o.params.deployMode || '' |
||||||
|
this.driverCores = o.params.driverCores || 1 |
||||||
|
this.driverMemory = o.params.driverMemory || '512M' |
||||||
|
this.numExecutors = o.params.numExecutors || 2 |
||||||
|
this.executorMemory = o.params.executorMemory || '2G' |
||||||
|
this.executorCores = o.params.executorCores || 2 |
||||||
|
this.mainArgs = o.params.mainArgs || '' |
||||||
|
this.others = o.params.others |
||||||
|
this.programType = o.params.programType || 'SCALA' |
||||||
|
|
||||||
|
// backfill resourceList |
||||||
|
let resourceList = o.params.resourceList || [] |
||||||
|
if (resourceList.length) { |
||||||
|
this.resourceList = resourceList |
||||||
|
} |
||||||
|
|
||||||
|
// backfill localParams |
||||||
|
let localParams = o.params.localParams || [] |
||||||
|
if (localParams.length) { |
||||||
|
this.localParams = localParams |
||||||
|
} |
||||||
|
} |
||||||
|
}) |
||||||
|
}, |
||||||
|
mounted () { |
||||||
|
|
||||||
|
}, |
||||||
|
components: { mLocalParams, mListBox, mResources } |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style lang="scss" rel="stylesheet/scss"> |
||||||
|
.spark-model { |
||||||
|
.list-box-4p { |
||||||
|
.list { |
||||||
|
margin-bottom: 14px; |
||||||
|
.sp1 { |
||||||
|
float: left; |
||||||
|
width: 112px; |
||||||
|
text-align: right; |
||||||
|
margin-right: 10px; |
||||||
|
font-size: 14px; |
||||||
|
color: #777; |
||||||
|
display: inline-block; |
||||||
|
padding-top: 6px; |
||||||
|
} |
||||||
|
.sp2 { |
||||||
|
float: left; |
||||||
|
margin-right: 4px; |
||||||
|
} |
||||||
|
.sp3 { |
||||||
|
width: 176px; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,267 @@ |
|||||||
|
<template> |
||||||
|
<div class="sql-model"> |
||||||
|
<m-list-box> |
||||||
|
<div slot="text">{{$t('数据源')}}</div> |
||||||
|
<div slot="content"> |
||||||
|
<m-datasource |
||||||
|
ref="refDs" |
||||||
|
@on-dsData="_onDsData" |
||||||
|
:data="{ type:type,datasource:datasource }"> |
||||||
|
</m-datasource> |
||||||
|
</div> |
||||||
|
</m-list-box> |
||||||
|
<m-list-box> |
||||||
|
<div slot="text">{{$t('sql类型')}}</div> |
||||||
|
<div slot="content"> |
||||||
|
<div style="display: inline-block;"> |
||||||
|
<m-sql-type |
||||||
|
@on-sqlType="_onSqlType" |
||||||
|
:sql-type="sqlType"> |
||||||
|
</m-sql-type> |
||||||
|
</div> |
||||||
|
<div v-if="!sqlType" style="display: inline-block;padding-left: 10px;margin-top: 2px;"> |
||||||
|
<x-checkbox-group v-model="showType"> |
||||||
|
<x-checkbox :label="'TABLE'" :disabled="isDetails">{{$t('表格')}}</x-checkbox> |
||||||
|
<x-checkbox :label="'ATTACHMENT'" :disabled="isDetails">{{$t('附件')}}</x-checkbox> |
||||||
|
</x-checkbox-group> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</m-list-box> |
||||||
|
<m-list-box v-show="type === 'HIVE'"> |
||||||
|
<div slot="text">{{$t('sql参数')}}</div> |
||||||
|
<div slot="content"> |
||||||
|
<x-input |
||||||
|
:disabled="isDetails" |
||||||
|
type="input" |
||||||
|
v-model="connParams" |
||||||
|
:placeholder="$t('请输入格式为') + ' key1=value1;key2=value2...'" |
||||||
|
autocomplete="off"> |
||||||
|
</x-input> |
||||||
|
</div> |
||||||
|
</m-list-box> |
||||||
|
<m-list-box> |
||||||
|
<div slot="text">{{$t('sql语句')}}</div> |
||||||
|
<div slot="content"> |
||||||
|
<div class="from-mirror"> |
||||||
|
<textarea |
||||||
|
id="code-sql-mirror" |
||||||
|
name="code-sql-mirror" |
||||||
|
style="opacity: 0;"> |
||||||
|
</textarea> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</m-list-box> |
||||||
|
<m-list-box v-if="type === 'HIVE'"> |
||||||
|
<div slot="text">{{$t('UDF函数')}}</div> |
||||||
|
<div slot="content"> |
||||||
|
<m-udfs |
||||||
|
ref="refUdfs" |
||||||
|
@on-udfsData="_onUdfsData" |
||||||
|
:udfs="udfs" |
||||||
|
:type="type"> |
||||||
|
</m-udfs> |
||||||
|
</div> |
||||||
|
</m-list-box> |
||||||
|
<m-list-box> |
||||||
|
<div slot="text">{{$t('自定义参数')}}</div> |
||||||
|
<div slot="content"> |
||||||
|
<m-local-params |
||||||
|
ref="refLocalParams" |
||||||
|
@on-udpData="_onUdpData" |
||||||
|
:udp-list="localParams"> |
||||||
|
</m-local-params> |
||||||
|
</div> |
||||||
|
</m-list-box> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<script> |
||||||
|
import _ from 'lodash' |
||||||
|
import i18n from '@/module/i18n' |
||||||
|
import mUdfs from './_source/udfs' |
||||||
|
import mListBox from './_source/listBox' |
||||||
|
import mSqlType from './_source/sqlType' |
||||||
|
import mDatasource from './_source/datasource' |
||||||
|
import mLocalParams from './_source/localParams' |
||||||
|
import disabledState from '@/module/mixin/disabledState' |
||||||
|
import codemirror from '@/conf/home/pages/resource/pages/file/pages/_source/codemirror' |
||||||
|
|
||||||
|
let editor |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'sql', |
||||||
|
data () { |
||||||
|
return { |
||||||
|
// Data source type |
||||||
|
type: '', |
||||||
|
// data source |
||||||
|
datasource: '', |
||||||
|
// Return to the selected data source |
||||||
|
rtDatasource: '', |
||||||
|
// Sql statement |
||||||
|
sql: '', |
||||||
|
// Custom parameter |
||||||
|
localParams: [], |
||||||
|
// UDF function |
||||||
|
udfs: '', |
||||||
|
// Sql type |
||||||
|
sqlType: 0, |
||||||
|
// Form/attachment |
||||||
|
showType: ['TABLE'], |
||||||
|
// Sql parameter |
||||||
|
connParams: '' |
||||||
|
} |
||||||
|
}, |
||||||
|
mixins: [disabledState], |
||||||
|
props: { |
||||||
|
backfillItem: Object |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
/** |
||||||
|
* return sqlType |
||||||
|
*/ |
||||||
|
_onSqlType (a) { |
||||||
|
this.sqlType = a |
||||||
|
}, |
||||||
|
/** |
||||||
|
* return udfs |
||||||
|
*/ |
||||||
|
_onUdfsData (a) { |
||||||
|
this.udfs = a |
||||||
|
}, |
||||||
|
/** |
||||||
|
* return Custom parameter |
||||||
|
*/ |
||||||
|
_onUdpData (a) { |
||||||
|
this.localParams = a |
||||||
|
}, |
||||||
|
/** |
||||||
|
* return data source |
||||||
|
*/ |
||||||
|
_onDsData (o) { |
||||||
|
this.type = o.type |
||||||
|
this.rtDatasource = o.datasource |
||||||
|
}, |
||||||
|
/** |
||||||
|
* verification |
||||||
|
*/ |
||||||
|
_verification () { |
||||||
|
if (!editor.getValue()) { |
||||||
|
this.$message.warning(`${i18n.$t('请输入sql语句(必填)')}`) |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
// datasource Subcomponent verification |
||||||
|
if (!this.$refs.refDs._verifDatasource()) { |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
// udfs Subcomponent verification Verification only if the data type is HIVE |
||||||
|
if (this.type === 'HIVE') { |
||||||
|
if (!this.$refs.refUdfs._verifUdfs()) { |
||||||
|
return false |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// localParams Subcomponent verification |
||||||
|
if (!this.$refs.refLocalParams._verifProp()) { |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
// storage |
||||||
|
this.$emit('on-params', { |
||||||
|
type: this.type, |
||||||
|
datasource: this.rtDatasource, |
||||||
|
sql: editor.getValue(), |
||||||
|
udfs: this.udfs, |
||||||
|
sqlType: this.sqlType, |
||||||
|
showType: (() => { |
||||||
|
/** |
||||||
|
* Special processing return order TABLE,ATTACHMENT |
||||||
|
* Handling checkout sequence |
||||||
|
*/ |
||||||
|
let showType = this.showType |
||||||
|
if (showType.length === 2 && showType[0] === 'ATTACHMENT') { |
||||||
|
return [showType[1], showType[0]].join(',') |
||||||
|
} else { |
||||||
|
return showType.join(',') |
||||||
|
} |
||||||
|
})(), |
||||||
|
localParams: this.localParams, |
||||||
|
connParams: this.connParams |
||||||
|
}) |
||||||
|
return true |
||||||
|
}, |
||||||
|
/** |
||||||
|
* Processing code highlighting |
||||||
|
*/ |
||||||
|
_handlerEditor () { |
||||||
|
// editor |
||||||
|
editor = codemirror('code-sql-mirror', { |
||||||
|
mode: 'sql', |
||||||
|
readOnly: this.isDetails |
||||||
|
}) |
||||||
|
|
||||||
|
this.keypress = () => { |
||||||
|
if (!editor.getOption('readOnly')) { |
||||||
|
editor.showHint({ |
||||||
|
completeSingle: false |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Monitor keyboard |
||||||
|
editor.on('keypress', this.keypress) |
||||||
|
|
||||||
|
editor.setValue(this.sql) |
||||||
|
|
||||||
|
return editor |
||||||
|
} |
||||||
|
}, |
||||||
|
watch: { |
||||||
|
// Listening to sqlType |
||||||
|
sqlType (val) { |
||||||
|
if (val) { |
||||||
|
this.showType = [] |
||||||
|
} |
||||||
|
}, |
||||||
|
// Listening data source |
||||||
|
type (val) { |
||||||
|
if (val !== 'HIVE') { |
||||||
|
this.connParams = '' |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
created () { |
||||||
|
let o = this.backfillItem |
||||||
|
|
||||||
|
// Non-null objects represent backfill |
||||||
|
if (!_.isEmpty(o)) { |
||||||
|
// backfill |
||||||
|
this.type = o.params.type || '' |
||||||
|
this.datasource = o.params.datasource || '' |
||||||
|
this.sql = o.params.sql || '' |
||||||
|
this.udfs = o.params.udfs || '' |
||||||
|
this.sqlType = o.params.sqlType |
||||||
|
this.connParams = o.params.connParams || '' |
||||||
|
this.localParams = o.params.localParams || [] |
||||||
|
this.showType = o.params.showType.split(',') || [] |
||||||
|
} |
||||||
|
}, |
||||||
|
mounted () { |
||||||
|
setTimeout(() => { |
||||||
|
this._handlerEditor() |
||||||
|
}, 200) |
||||||
|
}, |
||||||
|
destroyed () { |
||||||
|
/** |
||||||
|
* Destroy the editor instance |
||||||
|
*/ |
||||||
|
if (editor) { |
||||||
|
editor.toTextArea() // Uninstall |
||||||
|
editor.off($('.code-sql-mirror'), 'keypress', this.keypress) |
||||||
|
} |
||||||
|
}, |
||||||
|
computed: {}, |
||||||
|
components: { mListBox, mDatasource, mLocalParams, mUdfs, mSqlType } |
||||||
|
} |
||||||
|
</script> |
@ -0,0 +1,102 @@ |
|||||||
|
<template> |
||||||
|
<div class="sub_process-model"> |
||||||
|
<div class="clearfix list"> |
||||||
|
<div class="text-box"> |
||||||
|
<span>{{$t('子节点')}}</span> |
||||||
|
</div> |
||||||
|
<div class="cont-box"> |
||||||
|
<div class="label-box"> |
||||||
|
<x-select |
||||||
|
style="width: 100%;" |
||||||
|
filterable |
||||||
|
v-model="wdiCurr" |
||||||
|
:disabled="isDetails" |
||||||
|
@on-change="_handleWdiChanged"> |
||||||
|
<x-option |
||||||
|
v-for="city in processDefinitionList" |
||||||
|
:key="city.code" |
||||||
|
:value="city.id" |
||||||
|
:label="city.code"> |
||||||
|
</x-option> |
||||||
|
</x-select> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<script> |
||||||
|
import _ from 'lodash' |
||||||
|
import i18n from '@/module/i18n' |
||||||
|
import disabledState from '@/module/mixin/disabledState' |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'sub_process', |
||||||
|
data () { |
||||||
|
return { |
||||||
|
// Process definition(List) |
||||||
|
processDefinitionList: [], |
||||||
|
// Process definition |
||||||
|
wdiCurr: null |
||||||
|
} |
||||||
|
}, |
||||||
|
mixins: [disabledState], |
||||||
|
props: { |
||||||
|
backfillItem: Object |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
/** |
||||||
|
* Node unified authentication parameters |
||||||
|
*/ |
||||||
|
_verification () { |
||||||
|
if (!this.wdiCurr) { |
||||||
|
this.$message.warning(`${i18n.$t('请选择子工作流')}`) |
||||||
|
return false |
||||||
|
} |
||||||
|
this.$emit('on-params', { |
||||||
|
processDefinitionId: this.wdiCurr |
||||||
|
}) |
||||||
|
return true |
||||||
|
}, |
||||||
|
/** |
||||||
|
* The selected process defines the upper component name padding |
||||||
|
*/ |
||||||
|
_handleWdiChanged (o) { |
||||||
|
this.$emit('on-set-process-name', this._handleName(o.value)) |
||||||
|
}, |
||||||
|
/** |
||||||
|
* Return the name according to the process definition id |
||||||
|
*/ |
||||||
|
_handleName (id) { |
||||||
|
return _.filter(this.processDefinitionList, v => id === v.id)[0].code |
||||||
|
} |
||||||
|
}, |
||||||
|
watch: {}, |
||||||
|
created () { |
||||||
|
let processListS = _.cloneDeep(this.store.state.dag.processListS) |
||||||
|
let id = this.router.history.current.params.id || null |
||||||
|
this.processDefinitionList = (() => { |
||||||
|
let a = _.map(processListS, v => { |
||||||
|
return { |
||||||
|
id: v.id, |
||||||
|
code: v.name, |
||||||
|
disabled: false |
||||||
|
} |
||||||
|
}) |
||||||
|
return _.filter(a, v => +v.id !== +id) |
||||||
|
})() |
||||||
|
|
||||||
|
let o = this.backfillItem |
||||||
|
// Non-null objects represent backfill |
||||||
|
if (!_.isEmpty(o)) { |
||||||
|
this.wdiCurr = o.params.processDefinitionId |
||||||
|
} else { |
||||||
|
if (this.processDefinitionList.length) { |
||||||
|
this.wdiCurr = this.processDefinitionList[0]['id'] |
||||||
|
this.$emit('on-set-process-name', this._handleName(this.wdiCurr)) |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
mounted () { |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
@ -0,0 +1,107 @@ |
|||||||
|
|
||||||
|
import Vue from 'vue' |
||||||
|
import mAffirm from './jumpAffirm' |
||||||
|
import store from '@/conf/home/store' |
||||||
|
import router from '@/conf/home/router' |
||||||
|
import { uuid, findComponentDownward } from '@/module/util/' |
||||||
|
|
||||||
|
let Affirm = {} |
||||||
|
let $root = {} |
||||||
|
let $routerType = '' |
||||||
|
let $isPop = true |
||||||
|
|
||||||
|
/** |
||||||
|
* Listen for route changes |
||||||
|
*/ |
||||||
|
router.beforeEach((to, from, next) => { |
||||||
|
if (from.name === 'projects-definition-details' || from.name === 'projects-instance-details' || from.name === 'definition-create') { |
||||||
|
if (!Affirm.paramVerification(from.name)) { |
||||||
|
Affirm.isPop(() => { |
||||||
|
next() |
||||||
|
}) |
||||||
|
} else { |
||||||
|
next() |
||||||
|
} |
||||||
|
} else { |
||||||
|
next() |
||||||
|
} |
||||||
|
}) |
||||||
|
|
||||||
|
/** |
||||||
|
* Get judgment initialization data |
||||||
|
*/ |
||||||
|
Affirm.init = (root) => { |
||||||
|
$isPop = true |
||||||
|
$root = root |
||||||
|
$routerType = router.history.current.name |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Parameter verification |
||||||
|
*/ |
||||||
|
Affirm.paramVerification = (name) => { |
||||||
|
if (!$isPop) { |
||||||
|
return true |
||||||
|
} |
||||||
|
let dagStore = store.state.dag |
||||||
|
let flag = false |
||||||
|
if ($routerType === 'definition-create') { |
||||||
|
// No nodes jump out directly
|
||||||
|
if (dagStore.tasks.length) { |
||||||
|
if (!dagStore.name) { |
||||||
|
store.commit('dag/setName', `${uuid('dag_')}${uuid() + uuid()}`) |
||||||
|
} |
||||||
|
flag = false |
||||||
|
} else { |
||||||
|
flag = true |
||||||
|
} |
||||||
|
} else { |
||||||
|
// View history direct jump
|
||||||
|
flag = name === 'projects-instance-details' ? true : !dagStore.isEditDag |
||||||
|
} |
||||||
|
return flag |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Pop-up judgment |
||||||
|
*/ |
||||||
|
Affirm.isPop = (fn) => { |
||||||
|
Vue.$modal.dialog({ |
||||||
|
closable: false, |
||||||
|
showMask: true, |
||||||
|
escClose: true, |
||||||
|
className: 'v-modal-custom', |
||||||
|
transitionName: 'opacityp', |
||||||
|
render (h) { |
||||||
|
return h(mAffirm, { |
||||||
|
on: { |
||||||
|
ok () { |
||||||
|
// save
|
||||||
|
findComponentDownward($root, 'dag-chart')._save('affirm').then(() => { |
||||||
|
fn() |
||||||
|
Vue.$modal.destroy() |
||||||
|
}).catch(() => { |
||||||
|
fn() |
||||||
|
Vue.$modal.destroy() |
||||||
|
}) |
||||||
|
}, |
||||||
|
close () { |
||||||
|
fn() |
||||||
|
Vue.$modal.destroy() |
||||||
|
} |
||||||
|
}, |
||||||
|
props: { |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Whether the external setting pops up |
||||||
|
*/ |
||||||
|
Affirm.setIsPop = (is) => { |
||||||
|
$isPop = is |
||||||
|
} |
||||||
|
|
||||||
|
export default Affirm |
@ -0,0 +1,39 @@ |
|||||||
|
<template> |
||||||
|
<div class="affirm-model"> |
||||||
|
<m-popup :ok-text="$t('确认保存')" |
||||||
|
:nameText="$t('是否保存DAG图')" |
||||||
|
@close="_close" |
||||||
|
@ok="_ok"> |
||||||
|
</m-popup> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<script> |
||||||
|
import mPopup from '@/module/components/popup/popup' |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'affirm', |
||||||
|
methods: { |
||||||
|
_ok () { |
||||||
|
this.$emit('ok') |
||||||
|
}, |
||||||
|
_close () { |
||||||
|
this.$emit('close') |
||||||
|
} |
||||||
|
}, |
||||||
|
components: { mPopup } |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style lang="scss" rel="stylesheet/scss"> |
||||||
|
.affirm-model { |
||||||
|
.popup-model { |
||||||
|
.top-p { |
||||||
|
height: 50px; |
||||||
|
} |
||||||
|
.content-p { |
||||||
|
min-height: 0px; |
||||||
|
min-width: 250px; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,122 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
import _ from 'lodash' |
||||||
|
import canvg from 'canvg' |
||||||
|
import { tasksAll } from './util' |
||||||
|
import html2canvas from 'html2canvas' |
||||||
|
import { findComponentDownward } from '@/module/util/' |
||||||
|
|
||||||
|
let DownChart = function () { |
||||||
|
this.dag = {} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get interception location information |
||||||
|
*/ |
||||||
|
DownChart.prototype.maxVal = function () { |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
// All nodes
|
||||||
|
let tasksAllList = tasksAll() |
||||||
|
let dom = $('.dag-container') |
||||||
|
let y = parseInt(_.maxBy(tasksAllList, 'y').y + 60) |
||||||
|
let x = parseInt(_.maxBy(tasksAllList, 'x').x + 100) |
||||||
|
|
||||||
|
resolve({ |
||||||
|
width: x > 600 ? x : dom.width(), |
||||||
|
height: (y > 500 ? y : dom.height()) + 100 |
||||||
|
}) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Download to image |
||||||
|
*/ |
||||||
|
DownChart.prototype.download = function ({ dagThis }) { |
||||||
|
this.dag = dagThis |
||||||
|
|
||||||
|
this.maxVal().then(({ width, height }) => { |
||||||
|
// Dom to save
|
||||||
|
const copyDom = $('#canvas') |
||||||
|
// gain
|
||||||
|
const scale = 1 |
||||||
|
// svg handle
|
||||||
|
const nodesToRecover = [] |
||||||
|
const nodesToRemove = [] |
||||||
|
// divReport is the id of the dom that needs to be intercepted into a picture
|
||||||
|
const svgElem = copyDom.find('svg') |
||||||
|
svgElem.each((index, node) => { |
||||||
|
let parentNode = node.parentNode |
||||||
|
let svg = node.outerHTML.trim() |
||||||
|
let canvas = document.createElement('canvas') |
||||||
|
canvg(canvas, svg) |
||||||
|
if (node.style.position) { |
||||||
|
canvas.style.position += node.style.position |
||||||
|
canvas.style.left += node.style.left |
||||||
|
canvas.style.top += node.style.top |
||||||
|
} |
||||||
|
nodesToRecover.push({ |
||||||
|
parent: parentNode, |
||||||
|
child: node |
||||||
|
}) |
||||||
|
parentNode.removeChild(node) |
||||||
|
nodesToRemove.push({ |
||||||
|
parent: parentNode, |
||||||
|
child: canvas |
||||||
|
}) |
||||||
|
parentNode.appendChild(canvas) |
||||||
|
}) |
||||||
|
|
||||||
|
const canvas = document.createElement('canvas') |
||||||
|
// canvas width
|
||||||
|
canvas.width = width * scale |
||||||
|
// canvas height
|
||||||
|
canvas.height = height * scale |
||||||
|
|
||||||
|
const content = canvas.getContext('2d') |
||||||
|
content.scale(scale, scale) |
||||||
|
// Get the offset of the element relative to the inspection
|
||||||
|
const rect = copyDom.get(0).getBoundingClientRect() |
||||||
|
// Set the context position, the value is a negative value relative to the window offset, let the picture reset
|
||||||
|
content.translate(-rect.left, -rect.top) |
||||||
|
|
||||||
|
html2canvas(copyDom[0], { |
||||||
|
dpi: window.devicePixelRatio * 2, |
||||||
|
scale: scale, |
||||||
|
width: width, |
||||||
|
canvas: canvas, |
||||||
|
heigth: height, |
||||||
|
useCORS: true // Enable cross-domain configuration
|
||||||
|
}).then((canvas) => { |
||||||
|
let name = `${this.dag.name}.png` |
||||||
|
let url = canvas.toDataURL('image/png', 1) |
||||||
|
setTimeout(() => { |
||||||
|
let triggerDownload = $('<a>').attr('href', url).attr('download', name).appendTo('body') |
||||||
|
triggerDownload[0].click() |
||||||
|
triggerDownload.remove() |
||||||
|
}, 100) |
||||||
|
|
||||||
|
// To refresh the dag instance, otherwise you can't re-plot
|
||||||
|
setTimeout(() => { |
||||||
|
// Refresh current dag
|
||||||
|
findComponentDownward(this.dag.$root, `${this.dag.type}-details`).init() |
||||||
|
}, 500) |
||||||
|
}) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
export default new DownChart() |
@ -0,0 +1,40 @@ |
|||||||
|
import $ from 'jquery' |
||||||
|
import d3 from 'd3' |
||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
const DragZoom = function () { |
||||||
|
this.element = {} |
||||||
|
this.zoom = {} |
||||||
|
this.scale = 1 |
||||||
|
} |
||||||
|
|
||||||
|
DragZoom.prototype.init = function () { |
||||||
|
let $canvas = $('#canvas') |
||||||
|
this.element = d3.select('#canvas') |
||||||
|
this.zoom = d3.behavior.zoom() |
||||||
|
.scaleExtent([0.5, 2]) |
||||||
|
.on('zoom', () => { |
||||||
|
this.scale = d3.event.scale |
||||||
|
$canvas.css('transform', 'translate(' + d3.event.translate[0] + 'px,' + d3.event.translate[1] + 'px) scale(' + this.scale + ')') |
||||||
|
$canvas.css('transform-origin', '0 0') |
||||||
|
}) |
||||||
|
this.element.call(this.zoom).on('dblclick.zoom', null) |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
export default new DragZoom() |
@ -0,0 +1,761 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
import Vue from 'vue' |
||||||
|
import $ from 'jquery' |
||||||
|
import _ from 'lodash' |
||||||
|
import i18n from '@/module/i18n' |
||||||
|
import { jsPlumb } from 'jsplumb' |
||||||
|
import DragZoom from './dragZoom' |
||||||
|
import store from '@/conf/home/store' |
||||||
|
import router from '@/conf/home/router' |
||||||
|
import Permissions from '@/module/permissions' |
||||||
|
import { uuid, findComponentDownward } from '@/module/util/' |
||||||
|
import { |
||||||
|
tasksAll, |
||||||
|
rtTasksTpl, |
||||||
|
setSvgColor, |
||||||
|
saveTargetarr, |
||||||
|
rtTargetarrArr } from './util' |
||||||
|
import mStart from '@/conf/home/pages/projects/pages/definition/pages/list/_source/start' |
||||||
|
|
||||||
|
let JSP = function () { |
||||||
|
this.dag = {} |
||||||
|
this.selectedElement = {} |
||||||
|
|
||||||
|
this.config = { |
||||||
|
// Whether to drag
|
||||||
|
isDrag: true, |
||||||
|
// Whether to allow connection
|
||||||
|
isAttachment: false, |
||||||
|
// Whether to drag a new node
|
||||||
|
isNewNodes: true, |
||||||
|
// Whether to support double-click node events
|
||||||
|
isDblclick: true, |
||||||
|
// Whether to support right-click menu events
|
||||||
|
isContextmenu: true, |
||||||
|
// Whether to allow click events
|
||||||
|
isClick: false |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* dag init |
||||||
|
*/ |
||||||
|
JSP.prototype.init = function ({ dag, instance }) { |
||||||
|
// Get the dag component instance
|
||||||
|
this.dag = dag |
||||||
|
// Get jsplumb instance
|
||||||
|
this.JspInstance = instance |
||||||
|
// Register jsplumb connection type and configuration
|
||||||
|
this.JspInstance.registerConnectionType('basic', { |
||||||
|
anchor: 'Continuous', |
||||||
|
connector: 'Straight' // Line type
|
||||||
|
}) |
||||||
|
|
||||||
|
// Initial configuration
|
||||||
|
this.setConfig({ |
||||||
|
isDrag: !store.state.dag.isDetails, |
||||||
|
isAttachment: false, |
||||||
|
isNewNodes: Permissions.getAuth() === false ? false : !store.state.dag.isDetails, |
||||||
|
isDblclick: true, |
||||||
|
isContextmenu: true, |
||||||
|
isClick: false |
||||||
|
}) |
||||||
|
|
||||||
|
// Monitor line click
|
||||||
|
this.JspInstance.bind('click', e => { |
||||||
|
if (this.config.isClick) { |
||||||
|
this.connectClick(e) |
||||||
|
} |
||||||
|
}) |
||||||
|
|
||||||
|
// Drag and drop
|
||||||
|
if (this.config.isNewNodes) { |
||||||
|
DragZoom.init() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* set config attribute |
||||||
|
*/ |
||||||
|
JSP.prototype.setConfig = function (o) { |
||||||
|
this.config = Object.assign(this.config, {}, o) |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Node binding event |
||||||
|
*/ |
||||||
|
JSP.prototype.tasksEvent = function (selfId) { |
||||||
|
let tasks = $(`#${selfId}`) |
||||||
|
// Bind right event
|
||||||
|
tasks.on('contextmenu', e => { |
||||||
|
this.tasksContextmenu(e) |
||||||
|
return false |
||||||
|
}) |
||||||
|
|
||||||
|
// Binding double click event
|
||||||
|
tasks.find('.icos').bind('dblclick', e => { |
||||||
|
this.tasksDblclick(e) |
||||||
|
}) |
||||||
|
|
||||||
|
// Binding click event
|
||||||
|
tasks.on('click', e => { |
||||||
|
this.tasksClick(e) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Dag node drag and drop processing |
||||||
|
*/ |
||||||
|
JSP.prototype.draggable = function () { |
||||||
|
if (this.config.isNewNodes) { |
||||||
|
let selfId |
||||||
|
let self = this |
||||||
|
$('.toolbar-btn .roundedRect').draggable({ |
||||||
|
scope: 'plant', |
||||||
|
helper: 'clone', |
||||||
|
containment: $('.dag-model'), |
||||||
|
stop: function (e, ui) { |
||||||
|
self.tasksEvent(selfId) |
||||||
|
|
||||||
|
// Dom structure is not generated without pop-up form form
|
||||||
|
if ($(`#${selfId}`).html()) { |
||||||
|
// dag event
|
||||||
|
findComponentDownward(self.dag.$root, 'dag-chart')._createNodes({ |
||||||
|
id: selfId |
||||||
|
}) |
||||||
|
} |
||||||
|
}, |
||||||
|
drag: function () { |
||||||
|
$('body').find('.tooltip.fade.top.in').remove() |
||||||
|
} |
||||||
|
}) |
||||||
|
|
||||||
|
$('#canvas').droppable({ |
||||||
|
scope: 'plant', |
||||||
|
drop: function (ev, ui) { |
||||||
|
let id = 'tasks-' + Math.ceil(Math.random() * 100000) // eslint-disable-line
|
||||||
|
// Get mouse coordinates
|
||||||
|
let left = parseInt(ui.offset.left - $(this).offset().left) |
||||||
|
let top = parseInt(ui.offset.top - $(this).offset().top) - 10 |
||||||
|
if (top < 25) { |
||||||
|
top = 25 |
||||||
|
} |
||||||
|
// Generate template node
|
||||||
|
$('#canvas').append(rtTasksTpl({ |
||||||
|
id: id, |
||||||
|
name: id, |
||||||
|
x: left, |
||||||
|
y: top, |
||||||
|
isAttachment: self.config.isAttachment, |
||||||
|
taskType: findComponentDownward(self.dag.$root, 'dag-chart').dagBarId |
||||||
|
})) |
||||||
|
|
||||||
|
// Get the generated node
|
||||||
|
let thisDom = jsPlumb.getSelector('.statemachine-demo .w') |
||||||
|
|
||||||
|
// Generating a connection node
|
||||||
|
self.JspInstance.batch(() => { |
||||||
|
self.initNode(thisDom[thisDom.length - 1]) |
||||||
|
}) |
||||||
|
selfId = id |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Echo json processing and old data structure processing |
||||||
|
*/ |
||||||
|
JSP.prototype.jsonHandle = function ({ largeJson, locations }) { |
||||||
|
_.map(largeJson, v => { |
||||||
|
// Generate template
|
||||||
|
$('#canvas').append(rtTasksTpl({ |
||||||
|
id: v.id, |
||||||
|
name: v.name, |
||||||
|
x: locations[v.id]['x'], |
||||||
|
y: locations[v.id]['y'], |
||||||
|
targetarr: locations[v.id]['targetarr'], |
||||||
|
isAttachment: this.config.isAttachment, |
||||||
|
taskType: v.type |
||||||
|
})) |
||||||
|
|
||||||
|
// contextmenu event
|
||||||
|
$(`#${v.id}`).on('contextmenu', e => { |
||||||
|
this.tasksContextmenu(e) |
||||||
|
return false |
||||||
|
}) |
||||||
|
|
||||||
|
// dblclick event
|
||||||
|
$(`#${v.id}`).find('.icos').bind('dblclick', e => { |
||||||
|
this.tasksDblclick(e) |
||||||
|
}) |
||||||
|
|
||||||
|
// click event
|
||||||
|
$(`#${v.id}`).bind('click', e => { |
||||||
|
this.tasksClick(e) |
||||||
|
}) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Initialize a single node |
||||||
|
*/ |
||||||
|
JSP.prototype.initNode = function (el) { |
||||||
|
// Whether to drag
|
||||||
|
if (this.config.isDrag) { |
||||||
|
this.JspInstance.draggable(el, { |
||||||
|
containment: 'dag-container' |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
// Node attribute configuration
|
||||||
|
this.JspInstance.makeSource(el, { |
||||||
|
filter: '.ep', |
||||||
|
anchor: 'Continuous', |
||||||
|
connectorStyle: { |
||||||
|
stroke: '#555', |
||||||
|
strokeWidth: 2, |
||||||
|
outlineStroke: 'transparent', |
||||||
|
outlineWidth: 4 |
||||||
|
}, |
||||||
|
// This place is leaking
|
||||||
|
// connectionType: "basic",
|
||||||
|
extract: { |
||||||
|
action: 'the-action' |
||||||
|
}, |
||||||
|
maxConnections: -1 |
||||||
|
}) |
||||||
|
|
||||||
|
// Node connection property configuration
|
||||||
|
this.JspInstance.makeTarget(el, { |
||||||
|
dropOptions: { hoverClass: 'dragHover' }, |
||||||
|
anchor: 'Continuous', |
||||||
|
allowLoopback: false // Forbid yourself to connect yourself
|
||||||
|
}) |
||||||
|
this.JspInstance.fire('jsPlumbDemoNodeAdded', el) |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Node right click menu |
||||||
|
*/ |
||||||
|
JSP.prototype.tasksContextmenu = function (event) { |
||||||
|
if (this.config.isContextmenu) { |
||||||
|
let routerName = router.history.current.name |
||||||
|
// state
|
||||||
|
let isOne = routerName === 'projects-definition-details' && this.dag.releaseState !== 'NOT_RELEASE' |
||||||
|
// hide
|
||||||
|
let isTwo = store.state.dag.isDetails |
||||||
|
|
||||||
|
let html = [ |
||||||
|
`<a href="javascript:" id="startRunning" class="${isOne ? '' : 'disbled'}"><i class="iconfont"></i><span>${i18n.$t('开始运行')}</span></a>`, |
||||||
|
`<a href="javascript:" id="editNodes" class="${isTwo ? 'disbled' : ''}"><i class="iconfont"></i><span>${i18n.$t('编辑节点')}</span></a>`, |
||||||
|
`<a href="javascript:" id="copyNodes" class="${isTwo ? 'disbled' : ''}"><i class="iconfont"></i><span>${i18n.$t('复制节点')}</span></a>`, |
||||||
|
`<a href="javascript:" id="removeNodes" class="${isTwo ? 'disbled' : ''}"><i class="iconfont"></i><span>${i18n.$t('删除节点')}</span></a>` |
||||||
|
] |
||||||
|
|
||||||
|
let operationHtml = () => { |
||||||
|
return html.splice(',') |
||||||
|
} |
||||||
|
|
||||||
|
let e = event |
||||||
|
let $id = e.currentTarget.id |
||||||
|
let $contextmenu = $('#contextmenu') |
||||||
|
let $name = $(`#${$id}`).find('.name-p').text() |
||||||
|
let $left = e.pageX + document.body.scrollLeft - 5 |
||||||
|
let $top = e.pageY + document.body.scrollTop - 5 |
||||||
|
$contextmenu.css({ |
||||||
|
left: $left, |
||||||
|
top: $top, |
||||||
|
visibility: 'visible' |
||||||
|
}) |
||||||
|
// Action bar
|
||||||
|
$contextmenu.html('').append(operationHtml) |
||||||
|
|
||||||
|
if (isOne) { |
||||||
|
// start run
|
||||||
|
$('#startRunning').on('click', () => { |
||||||
|
let id = router.history.current.params.id |
||||||
|
store.dispatch('dag/getStartCheck', { processDefinitionId: id }).then(res => { |
||||||
|
let modal = Vue.$modal.dialog({ |
||||||
|
closable: false, |
||||||
|
showMask: true, |
||||||
|
escClose: true, |
||||||
|
className: 'v-modal-custom', |
||||||
|
transitionName: 'opacityp', |
||||||
|
render (h) { |
||||||
|
return h(mStart, { |
||||||
|
on: { |
||||||
|
onUpdate () { |
||||||
|
modal.remove() |
||||||
|
}, |
||||||
|
close () { |
||||||
|
modal.remove() |
||||||
|
} |
||||||
|
}, |
||||||
|
props: { |
||||||
|
item: { |
||||||
|
id: id |
||||||
|
}, |
||||||
|
startNodeList: $name, |
||||||
|
sourceType: 'contextmenu' |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
}) |
||||||
|
}).catch(e => { |
||||||
|
Vue.$message.error(e.msg || '') |
||||||
|
}) |
||||||
|
}) |
||||||
|
} |
||||||
|
if (!isTwo) { |
||||||
|
// edit node
|
||||||
|
$(`#editNodes`).click(ev => { |
||||||
|
findComponentDownward(this.dag.$root, 'dag-chart')._createNodes({ |
||||||
|
id: $id, |
||||||
|
type: $(`#${$id}`).attr('data-tasks-type') |
||||||
|
}) |
||||||
|
}) |
||||||
|
// delete node
|
||||||
|
$('#removeNodes').click(ev => { |
||||||
|
this.removeNodes($id) |
||||||
|
}) |
||||||
|
|
||||||
|
// copy node
|
||||||
|
$('#copyNodes').click(res => { |
||||||
|
this.copyNodes($id) |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Node double click event |
||||||
|
*/ |
||||||
|
JSP.prototype.tasksDblclick = function (e) { |
||||||
|
// Untie event
|
||||||
|
if (this.config.isDblclick) { |
||||||
|
let id = $(e.currentTarget.offsetParent).attr('id') |
||||||
|
|
||||||
|
findComponentDownward(this.dag.$root, 'dag-chart')._createNodes({ |
||||||
|
id: id, |
||||||
|
type: $(`#${id}`).attr('data-tasks-type') |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Node click event |
||||||
|
*/ |
||||||
|
JSP.prototype.tasksClick = function (e) { |
||||||
|
let $id |
||||||
|
let self = this |
||||||
|
let $body = $(`body`) |
||||||
|
if (this.config.isClick) { |
||||||
|
let $connect = this.selectedElement.connect |
||||||
|
$('.w').removeClass('jtk-tasks-active') |
||||||
|
$(e.currentTarget).addClass('jtk-tasks-active') |
||||||
|
if ($connect) { |
||||||
|
setSvgColor($connect, '#555') |
||||||
|
this.selectedElement.connect = null |
||||||
|
} |
||||||
|
this.selectedElement.id = $(e.currentTarget).attr('id') |
||||||
|
|
||||||
|
// Unbind copy and paste events
|
||||||
|
$body.unbind('copy').unbind('paste') |
||||||
|
// Copy binding id
|
||||||
|
$id = self.selectedElement.id |
||||||
|
|
||||||
|
$body.bind({ |
||||||
|
copy: function () { |
||||||
|
$id = self.selectedElement.id |
||||||
|
}, |
||||||
|
paste: function () { |
||||||
|
$id && self.copyNodes($id) |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Remove binding events |
||||||
|
* paste |
||||||
|
*/ |
||||||
|
JSP.prototype.removePaste = function () { |
||||||
|
let $body = $(`body`) |
||||||
|
// Unbind copy and paste events
|
||||||
|
$body.unbind('copy').unbind('paste') |
||||||
|
// Remove selected node parameters
|
||||||
|
this.selectedElement.id = null |
||||||
|
// Remove node selection effect
|
||||||
|
$('.w').removeClass('jtk-tasks-active') |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Line click event |
||||||
|
*/ |
||||||
|
JSP.prototype.connectClick = function (e) { |
||||||
|
// Set svg color
|
||||||
|
setSvgColor(e, '#0097e0') |
||||||
|
let $id = this.selectedElement.id |
||||||
|
if ($id) { |
||||||
|
$(`#${$id}`).removeClass('jtk-tasks-active') |
||||||
|
this.selectedElement.id = null |
||||||
|
} |
||||||
|
this.selectedElement.connect = e |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* toolbarEvent |
||||||
|
* @param {Pointer} |
||||||
|
*/ |
||||||
|
JSP.prototype.handleEventPointer = function (is) { |
||||||
|
let wDom = $('.w') |
||||||
|
this.setConfig({ |
||||||
|
isClick: is, |
||||||
|
isAttachment: false |
||||||
|
}) |
||||||
|
wDom.removeClass('jtk-ep') |
||||||
|
if (!is) { |
||||||
|
wDom.removeClass('jtk-tasks-active') |
||||||
|
this.selectedElement = {} |
||||||
|
_.map($('#canvas svg'), v => { |
||||||
|
if ($(v).attr('class')) { |
||||||
|
_.map($(v).find('path'), v1 => { |
||||||
|
$(v1).attr('fill', '#555') |
||||||
|
$(v1).attr('stroke', '#555') |
||||||
|
}) |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* toolbarEvent |
||||||
|
* @param {Line} |
||||||
|
*/ |
||||||
|
JSP.prototype.handleEventLine = function (is) { |
||||||
|
let wDom = $('.w') |
||||||
|
this.setConfig({ |
||||||
|
isAttachment: is |
||||||
|
}) |
||||||
|
is ? wDom.addClass('jtk-ep') : wDom.removeClass('jtk-ep') |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* toolbarEvent |
||||||
|
* @param {Remove} |
||||||
|
*/ |
||||||
|
JSP.prototype.handleEventRemove = function () { |
||||||
|
let $id = this.selectedElement.id || null |
||||||
|
let $connect = this.selectedElement.connect || null |
||||||
|
if ($id) { |
||||||
|
this.removeNodes(this.selectedElement.id) |
||||||
|
} else { |
||||||
|
this.removeConnect($connect) |
||||||
|
} |
||||||
|
|
||||||
|
// Monitor whether to edit DAG
|
||||||
|
store.commit('dag/setIsEditDag', true) |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Delete node |
||||||
|
*/ |
||||||
|
JSP.prototype.removeNodes = function ($id) { |
||||||
|
// Delete node processing(data-targetarr)
|
||||||
|
_.map(tasksAll(), v => { |
||||||
|
let targetarr = v.targetarr.split(',') |
||||||
|
if (targetarr.length) { |
||||||
|
let newArr = _.filter(targetarr, v1 => v1 !== $id) |
||||||
|
$(`#${v.id}`).attr('data-targetarr', newArr.toString()) |
||||||
|
} |
||||||
|
}) |
||||||
|
// delete node
|
||||||
|
this.JspInstance.remove($id) |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Delete connection |
||||||
|
*/ |
||||||
|
JSP.prototype.removeConnect = function ($connect) { |
||||||
|
if (!$connect) { |
||||||
|
return |
||||||
|
} |
||||||
|
// Remove connections and remove node and node dependencies
|
||||||
|
let targetId = $connect.targetId |
||||||
|
let sourceId = $connect.sourceId |
||||||
|
let targetarr = rtTargetarrArr(targetId) |
||||||
|
if (targetarr.length) { |
||||||
|
targetarr = _.filter(targetarr, v => v !== sourceId) |
||||||
|
$(`#${targetId}`).attr('data-targetarr', targetarr.toString()) |
||||||
|
} |
||||||
|
this.JspInstance.deleteConnection($connect) |
||||||
|
|
||||||
|
this.selectedElement = {} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Copy node |
||||||
|
*/ |
||||||
|
JSP.prototype.copyNodes = function ($id) { |
||||||
|
let newNodeInfo = _.cloneDeep(_.find(store.state.dag.tasks, v => v.id === $id)) |
||||||
|
let newNodePors = store.state.dag.locations[$id] |
||||||
|
// Unstored nodes do not allow replication
|
||||||
|
if (!newNodePors) { |
||||||
|
return |
||||||
|
} |
||||||
|
// Generate random id
|
||||||
|
let newUuId = `${uuid() + uuid()}` |
||||||
|
let id = newNodeInfo.id.length > 8 ? newNodeInfo.id.substr(0, 7) : newNodeInfo.id |
||||||
|
let name = newNodeInfo.name.length > 8 ? newNodeInfo.name.substr(0, 7) : newNodeInfo.name |
||||||
|
|
||||||
|
// new id
|
||||||
|
let newId = `${id || ''}-${newUuId}` |
||||||
|
// new name
|
||||||
|
let newName = `${name || ''}-${newUuId}` |
||||||
|
// coordinate x
|
||||||
|
let newX = newNodePors.x + 100 |
||||||
|
// coordinate y
|
||||||
|
let newY = newNodePors.y + 40 |
||||||
|
|
||||||
|
// Generate template node
|
||||||
|
$('#canvas').append(rtTasksTpl({ |
||||||
|
id: newId, |
||||||
|
name: newName, |
||||||
|
x: newX, |
||||||
|
y: newY, |
||||||
|
isAttachment: this.config.isAttachment, |
||||||
|
taskType: newNodeInfo.type |
||||||
|
})) |
||||||
|
|
||||||
|
// Get the generated node
|
||||||
|
let thisDom = jsPlumb.getSelector('.statemachine-demo .w') |
||||||
|
|
||||||
|
// Copy node information
|
||||||
|
newNodeInfo = Object.assign(newNodeInfo, { |
||||||
|
id: newId, |
||||||
|
name: newName |
||||||
|
}) |
||||||
|
|
||||||
|
// Add new node
|
||||||
|
store.commit('dag/addTasks', newNodeInfo) |
||||||
|
// Add node location information
|
||||||
|
store.commit('dag/setLocations', { |
||||||
|
[newId]: { |
||||||
|
name: newName, |
||||||
|
targetarr: '', |
||||||
|
x: newX, |
||||||
|
y: newY |
||||||
|
} |
||||||
|
}) |
||||||
|
|
||||||
|
// Generating a connection node
|
||||||
|
this.JspInstance.batch(() => { |
||||||
|
this.initNode(thisDom[thisDom.length - 1]) |
||||||
|
// Add events to nodes
|
||||||
|
this.tasksEvent(newId) |
||||||
|
}) |
||||||
|
} |
||||||
|
/** |
||||||
|
* toolbarEvent |
||||||
|
* @param {Screen} |
||||||
|
*/ |
||||||
|
JSP.prototype.handleEventScreen = function ({ item, is }) { |
||||||
|
let screenOpen = true |
||||||
|
if (is) { |
||||||
|
item.icon = '' |
||||||
|
screenOpen = true |
||||||
|
} else { |
||||||
|
item.icon = '' |
||||||
|
screenOpen = false |
||||||
|
} |
||||||
|
let $mainLayoutModel = $('.main-layout-model') |
||||||
|
if (screenOpen) { |
||||||
|
$mainLayoutModel.addClass('dag-screen') |
||||||
|
} else { |
||||||
|
$mainLayoutModel.removeClass('dag-screen') |
||||||
|
} |
||||||
|
} |
||||||
|
/** |
||||||
|
* save task |
||||||
|
* @param tasks |
||||||
|
* @param locations |
||||||
|
* @param connects |
||||||
|
*/ |
||||||
|
JSP.prototype.saveStore = function () { |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
let connects = [] |
||||||
|
let locations = {} |
||||||
|
let tasks = [] |
||||||
|
|
||||||
|
let is = (id) => { |
||||||
|
return !!_.filter(tasksAll(), v => v.id === id).length |
||||||
|
} |
||||||
|
|
||||||
|
// task
|
||||||
|
_.map(_.cloneDeep(store.state.dag.tasks), v => { |
||||||
|
if (is(v.id)) { |
||||||
|
let preTasks = [] |
||||||
|
let id = $(`#${v.id}`) |
||||||
|
let tar = id.attr('data-targetarr') |
||||||
|
let idDep = tar ? id.attr('data-targetarr').split(',') : [] |
||||||
|
if (idDep.length) { |
||||||
|
_.map(idDep, v1 => { |
||||||
|
preTasks.push($(`#${v1}`).find('.name-p').text()) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
let tasksParam = _.assign(v, { |
||||||
|
preTasks: preTasks |
||||||
|
}) |
||||||
|
|
||||||
|
// Sub-workflow has no retries and interval
|
||||||
|
if (v.type === 'SUB_PROCESS') { |
||||||
|
tasksParam = _.omit(tasksParam, ['maxRetryTimes', 'retryInterval']) |
||||||
|
} |
||||||
|
|
||||||
|
tasks.push(tasksParam) |
||||||
|
} |
||||||
|
}) |
||||||
|
|
||||||
|
_.map(this.JspInstance.getConnections(), v => { |
||||||
|
connects.push({ |
||||||
|
'endPointSourceId': v.sourceId, |
||||||
|
'endPointTargetId': v.targetId |
||||||
|
}) |
||||||
|
}) |
||||||
|
|
||||||
|
_.map(tasksAll(), v => { |
||||||
|
locations[v.id] = { |
||||||
|
name: v.name, |
||||||
|
targetarr: v.targetarr, |
||||||
|
x: v.x, |
||||||
|
y: v.y |
||||||
|
} |
||||||
|
}) |
||||||
|
|
||||||
|
// Storage node
|
||||||
|
store.commit('dag/setTasks', tasks) |
||||||
|
// Store coordinate information
|
||||||
|
store.commit('dag/setLocations', locations) |
||||||
|
// Storage line dependence
|
||||||
|
store.commit('dag/setConnects', connects) |
||||||
|
|
||||||
|
resolve({ |
||||||
|
connects: connects, |
||||||
|
tasks: tasks, |
||||||
|
locations: locations |
||||||
|
}) |
||||||
|
}) |
||||||
|
} |
||||||
|
/** |
||||||
|
* Event processing |
||||||
|
*/ |
||||||
|
JSP.prototype.handleEvent = function () { |
||||||
|
this.JspInstance.bind('beforeDrop', function (info) { |
||||||
|
let sourceId = info['sourceId']// 出
|
||||||
|
let targetId = info['targetId']// 入
|
||||||
|
|
||||||
|
/** |
||||||
|
* Recursive search for nodes |
||||||
|
*/ |
||||||
|
let recursiveVal |
||||||
|
const recursiveTargetarr = (arr, targetId) => { |
||||||
|
for (var i in arr) { |
||||||
|
if (arr[i] === targetId) { |
||||||
|
recursiveVal = targetId |
||||||
|
} else { |
||||||
|
let recTargetarrArr = rtTargetarrArr(arr[i]) |
||||||
|
if (recTargetarrArr.length) { |
||||||
|
recursiveTargetarr(recTargetarrArr, targetId) |
||||||
|
} else { |
||||||
|
return recursiveTargetarr(targetId) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return recursiveVal |
||||||
|
} |
||||||
|
|
||||||
|
// Connection to connected nodes is not allowed
|
||||||
|
if (_.findIndex(rtTargetarrArr(targetId), v => v === sourceId) !== -1) { |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
// Recursive form to find if the target Targetarr has a sourceId
|
||||||
|
if (recursiveTargetarr(rtTargetarrArr(sourceId), targetId)) { |
||||||
|
// setRecursiveVal(null)
|
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
// Storage node dependency information
|
||||||
|
saveTargetarr(sourceId, targetId) |
||||||
|
|
||||||
|
// Monitor whether to edit DAG
|
||||||
|
store.commit('dag/setIsEditDag', true) |
||||||
|
|
||||||
|
return true |
||||||
|
}) |
||||||
|
} |
||||||
|
/** |
||||||
|
* Backfill data processing |
||||||
|
*/ |
||||||
|
JSP.prototype.jspBackfill = function ({ connects, locations, largeJson }) { |
||||||
|
// Backfill nodes
|
||||||
|
this.jsonHandle({ |
||||||
|
largeJson: largeJson, |
||||||
|
locations: locations |
||||||
|
}) |
||||||
|
|
||||||
|
let wNodes = jsPlumb.getSelector('.statemachine-demo .w') |
||||||
|
|
||||||
|
// Backfill line
|
||||||
|
this.JspInstance.batch(() => { |
||||||
|
for (let i = 0; i < wNodes.length; i++) { |
||||||
|
this.initNode(wNodes[i]) |
||||||
|
} |
||||||
|
_.map(connects, v => { |
||||||
|
let sourceId = v.endPointSourceId.split('-') |
||||||
|
let targetId = v.endPointTargetId.split('-') |
||||||
|
if (sourceId.length === 4 && targetId.length === 4) { |
||||||
|
sourceId = `${sourceId[0]}-${sourceId[1]}-${sourceId[2]}` |
||||||
|
targetId = `${targetId[0]}-${targetId[1]}-${targetId[2]}` |
||||||
|
} else { |
||||||
|
sourceId = v.endPointSourceId |
||||||
|
targetId = v.endPointTargetId |
||||||
|
} |
||||||
|
|
||||||
|
this.JspInstance.connect({ |
||||||
|
source: sourceId, |
||||||
|
target: targetId, |
||||||
|
type: 'basic', |
||||||
|
paintStyle: { strokeWidth: 2, stroke: '#555' } |
||||||
|
}) |
||||||
|
}) |
||||||
|
}) |
||||||
|
|
||||||
|
jsPlumb.fire('jsPlumbDemoLoaded', this.JspInstance) |
||||||
|
|
||||||
|
// Connection monitoring
|
||||||
|
this.handleEvent() |
||||||
|
|
||||||
|
// Drag and drop new nodes
|
||||||
|
this.draggable() |
||||||
|
} |
||||||
|
|
||||||
|
export default new JSP() |
@ -0,0 +1,131 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
import _ from 'lodash' |
||||||
|
import $ from 'jquery' |
||||||
|
import store from '@/conf/home/store' |
||||||
|
|
||||||
|
/** |
||||||
|
* 节点,转数组 |
||||||
|
*/ |
||||||
|
const rtTargetarrArr = (id) => { |
||||||
|
let a = $(`#${id}`).attr('data-targetarr') |
||||||
|
return a ? a.split(',') : [] |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 存储节点id到targetarr |
||||||
|
*/ |
||||||
|
const saveTargetarr = (valId, domId) => { |
||||||
|
let $target = $(`#${domId}`) |
||||||
|
let targetStr = $target.attr('data-targetarr') ? $target.attr('data-targetarr') + `,${valId}` : `${valId}` |
||||||
|
$target.attr('data-targetarr', targetStr) |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 返回节点html |
||||||
|
*/ |
||||||
|
const rtTasksTpl = ({ id, name, x, y, targetarr, isAttachment, taskType }) => { |
||||||
|
let tpl = `` |
||||||
|
tpl += `<div class="w jtk-draggable jtk-droppable jtk-endpoint-anchor jtk-connected ${isAttachment ? 'jtk-ep' : ''}" data-targetarr="${targetarr || ''}" data-tasks-type="${taskType}" id="${id}" style="left: ${x}px; top: ${y}px;">` |
||||||
|
tpl += `<div>` |
||||||
|
tpl += `<div class="state-p"></div>` |
||||||
|
tpl += `<div class="icos icos-${taskType}"></div>` |
||||||
|
tpl += `<span class="name-p">${name}</span>` |
||||||
|
tpl += `</div>` |
||||||
|
tpl += `<div class="ep"></div>` |
||||||
|
tpl += `</div>` |
||||||
|
return tpl |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 获取所有tasks节点 |
||||||
|
*/ |
||||||
|
const tasksAll = () => { |
||||||
|
let a = [] |
||||||
|
$('#canvas .w').each(function (idx, elem) { |
||||||
|
let e = $(elem) |
||||||
|
a.push({ |
||||||
|
id: e.attr('id'), |
||||||
|
name: e.find('.name-p').text(), |
||||||
|
targetarr: e.attr('data-targetarr') || '', |
||||||
|
x: parseInt(e.css('left'), 10), |
||||||
|
y: parseInt(e.css('top'), 10) |
||||||
|
}) |
||||||
|
}) |
||||||
|
return a |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 判断 name 是否在当前的dag图中 |
||||||
|
* rely dom / backfill dom元素 回填 |
||||||
|
*/ |
||||||
|
const isNameExDag = (name, rely) => { |
||||||
|
if (rely === 'dom') { |
||||||
|
return _.findIndex(tasksAll(), v => v.name === name) !== -1 |
||||||
|
} else { |
||||||
|
return _.findIndex(store.state.dag.tasks, v => v.name === name) !== -1 |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 更改svg线条颜色 |
||||||
|
*/ |
||||||
|
const setSvgColor = (e, color) => { |
||||||
|
// 遍历 清除所有颜色
|
||||||
|
$('.jtk-connector').each((i, o) => { |
||||||
|
_.map($(o)[0].childNodes, v => { |
||||||
|
$(v).attr('fill', '#555').attr('stroke', '#555').attr('stroke-width', 2) |
||||||
|
}) |
||||||
|
}) |
||||||
|
|
||||||
|
// 给选择的添加颜色
|
||||||
|
_.map($(e.canvas)[0].childNodes, (v, i) => { |
||||||
|
$(v).attr('fill', color).attr('stroke', color) |
||||||
|
if ($(v).attr('class')) { |
||||||
|
$(v).attr('stroke-width', 2) |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 获取所有节点id |
||||||
|
*/ |
||||||
|
const allNodesId = () => { |
||||||
|
let idArr = [] |
||||||
|
$('.w').each((i, o) => { |
||||||
|
let $obj = $(o) |
||||||
|
let $span = $obj.find('.name-p').text() |
||||||
|
if ($span) { |
||||||
|
idArr.push({ |
||||||
|
id: $obj.attr('id'), |
||||||
|
name: $span |
||||||
|
}) |
||||||
|
} |
||||||
|
}) |
||||||
|
return idArr |
||||||
|
} |
||||||
|
|
||||||
|
export { |
||||||
|
rtTargetarrArr, |
||||||
|
saveTargetarr, |
||||||
|
rtTasksTpl, |
||||||
|
tasksAll, |
||||||
|
isNameExDag, |
||||||
|
setSvgColor, |
||||||
|
allNodesId |
||||||
|
} |
@ -0,0 +1,187 @@ |
|||||||
|
<template> |
||||||
|
<div class="udp-model"> |
||||||
|
<div class="scrollbar contpi-boxt"> |
||||||
|
<div class="title"> |
||||||
|
<span>{{$t('设置DAG图名称')}}</span> |
||||||
|
</div> |
||||||
|
<div> |
||||||
|
<x-input |
||||||
|
type="text" |
||||||
|
v-model="name" |
||||||
|
:disabled="router.history.current.name === 'projects-instance-details'" |
||||||
|
:placeholder="$t('请输入name(必填)')"> |
||||||
|
</x-input> |
||||||
|
</div> |
||||||
|
<template v-if="router.history.current.name !== 'projects-instance-details'"> |
||||||
|
<div style="padding-top: 12px;"> |
||||||
|
<x-input |
||||||
|
type="textarea" |
||||||
|
v-model="desc" |
||||||
|
:autosize="{minRows:2}" |
||||||
|
:placeholder="$t('请输入desc(选填)')" |
||||||
|
autocomplete="off"> |
||||||
|
</x-input> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<div class="title" style="padding-top: 6px;"> |
||||||
|
<span>{{$t('设置全局')}}</span> |
||||||
|
</div> |
||||||
|
<div class="content"> |
||||||
|
<div> |
||||||
|
<m-local-params |
||||||
|
ref="refLocalParams" |
||||||
|
@on-local-params="_onLocalParams" |
||||||
|
:udp-list="udpList" |
||||||
|
:hide="false"> |
||||||
|
</m-local-params> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="bottom"> |
||||||
|
<div class="submit"> |
||||||
|
<template v-if="router.history.current.name === 'projects-instance-details'"> |
||||||
|
<div class="lint-pt"> |
||||||
|
<x-checkbox v-model="syncDefine">{{$t('是否更新流程定义')}}</x-checkbox> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<x-button type="text" @click="close()"> {{$t('取消')}} </x-button> |
||||||
|
<x-button type="primary" shape="circle" @click="ok()" v-ps="['GENERAL_USER']" >{{$t('添加')}}</x-button> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<script> |
||||||
|
import _ from 'lodash' |
||||||
|
import i18n from '@/module/i18n' |
||||||
|
import mLocalParams from '../formModel/tasks/_source/localParams' |
||||||
|
import disabledState from '@/module/mixin/disabledState' |
||||||
|
import Affirm from '../jumpAffirm' |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'udp', |
||||||
|
data () { |
||||||
|
return { |
||||||
|
// dag name |
||||||
|
name: '', |
||||||
|
// dag desc |
||||||
|
desc: '', |
||||||
|
// Global custom parameters |
||||||
|
udpList: [], |
||||||
|
// Whether to update the process definition |
||||||
|
syncDefine: true |
||||||
|
} |
||||||
|
}, |
||||||
|
mixins: [disabledState], |
||||||
|
props: { |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
/** |
||||||
|
* udp data |
||||||
|
*/ |
||||||
|
_onLocalParams (a) { |
||||||
|
this.udpList = a |
||||||
|
}, |
||||||
|
/** |
||||||
|
* submit |
||||||
|
*/ |
||||||
|
ok () { |
||||||
|
if (!this.name) { |
||||||
|
this.$message.warning(`${i18n.$t('DAG图名称不能为空')}`) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
let _verif = () => { |
||||||
|
// verification udf |
||||||
|
if (!this.$refs.refLocalParams._verifProp()) { |
||||||
|
return |
||||||
|
} |
||||||
|
// Storage global globalParams |
||||||
|
this.store.commit('dag/setGlobalParams', _.cloneDeep(this.udpList)) |
||||||
|
this.store.commit('dag/setName', _.cloneDeep(this.name)) |
||||||
|
this.store.commit('dag/setDesc', _.cloneDeep(this.desc)) |
||||||
|
this.store.commit('dag/setSyncDefine', this.syncDefine) |
||||||
|
Affirm.setIsPop(false) |
||||||
|
this.$emit('onUdp') |
||||||
|
} |
||||||
|
|
||||||
|
// Edit => direct storage |
||||||
|
if (this.store.state.dag.name) { |
||||||
|
_verif() |
||||||
|
} else { |
||||||
|
// New First verify that the name exists |
||||||
|
this.store.dispatch('dag/verifDAGName', this.name).then(res => { |
||||||
|
_verif() |
||||||
|
}).catch(e => { |
||||||
|
this.$message.error(e.msg || '') |
||||||
|
}) |
||||||
|
} |
||||||
|
}, |
||||||
|
/** |
||||||
|
* Close the popup |
||||||
|
*/ |
||||||
|
close () { |
||||||
|
this.$emit('close') |
||||||
|
} |
||||||
|
}, |
||||||
|
watch: { |
||||||
|
}, |
||||||
|
created () { |
||||||
|
this.udpList = this.store.state.dag.globalParams |
||||||
|
this.name = this.store.state.dag.name |
||||||
|
this.desc = this.store.state.dag.desc |
||||||
|
this.syncDefine = this.store.state.dag.syncDefine |
||||||
|
}, |
||||||
|
mounted () {}, |
||||||
|
components: { mLocalParams } |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style lang="scss" rel="stylesheet/scss"> |
||||||
|
.udp-model { |
||||||
|
width: 616px; |
||||||
|
min-height: 326px; |
||||||
|
background: #fff; |
||||||
|
border-radius: 3px; |
||||||
|
padding:20px 0 ; |
||||||
|
position: relative; |
||||||
|
.contpi-boxt { |
||||||
|
max-height: 600px; |
||||||
|
overflow-y: scroll; |
||||||
|
padding:0 20px; |
||||||
|
} |
||||||
|
.title { |
||||||
|
line-height: 36px; |
||||||
|
padding-bottom: 10px; |
||||||
|
span { |
||||||
|
font-size: 16px; |
||||||
|
color: #333; |
||||||
|
} |
||||||
|
} |
||||||
|
.bottom{ |
||||||
|
position: absolute; |
||||||
|
bottom: 0; |
||||||
|
left: 0; |
||||||
|
width: 100%; |
||||||
|
text-align: right; |
||||||
|
height: 56px; |
||||||
|
line-height: 56px; |
||||||
|
border-top: 1px solid #DCDEDC; |
||||||
|
background: #fff; |
||||||
|
.submit { |
||||||
|
padding-right: 20px; |
||||||
|
margin-top: -4px; |
||||||
|
} |
||||||
|
.lint-pt { |
||||||
|
position: absolute; |
||||||
|
left: 20px; |
||||||
|
top: -2px; |
||||||
|
>label { |
||||||
|
font-weight: normal; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.content { |
||||||
|
padding-bottom: 50px; |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,24 @@ |
|||||||
|
<template> |
||||||
|
<div class="assist-dag-model"> |
||||||
|
<template v-if="isView"> |
||||||
|
<m-variables-view></m-variables-view> |
||||||
|
</template> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<script> |
||||||
|
import mVariablesView from './variablesView' |
||||||
|
export default { |
||||||
|
name: 'assist-dag-index', |
||||||
|
data () { |
||||||
|
return { |
||||||
|
isView: false |
||||||
|
} |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
_toggleView () { |
||||||
|
this.isView = !this.isView |
||||||
|
} |
||||||
|
}, |
||||||
|
components: { mVariablesView } |
||||||
|
} |
||||||
|
</script> |
@ -0,0 +1,141 @@ |
|||||||
|
<template> |
||||||
|
<div class="variable-model"> |
||||||
|
<div class="list"> |
||||||
|
<div class="name"><i class="fa fa-code"></i><b style="padding-top: 3px;display: inline-block">{{$t('全局参数')}}</b></div> |
||||||
|
<div class="var-cont"> |
||||||
|
<x-button size="xsmall" type="ghost" v-for="(item,$index) in list.globalParams" @click="_copy('gbudp-' + $index)" :data-clipboard-text="item.prop + ' = ' +item.value" :class="'gbudp-' + $index"><b style="color: #2A455B;">{{item.prop}}</b> = {{item.value}}</x-button> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="list" style="height: 30px;"> |
||||||
|
<div class="name"><i class="fa fa-code"></i><b style="padding-top: 3px;display: inline-block">{{$t('局部参数')}}</b></div> |
||||||
|
<div class="var-cont"> |
||||||
|
|
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="list list-t" v-for="(item,key,$index) in list.localParams"> |
||||||
|
<div class="task-name">Task({{$index}}):{{key}}</div> |
||||||
|
<div class="var-cont" v-if="item.length"> |
||||||
|
<template v-for="(el,index) in item"> |
||||||
|
<x-button size="xsmall" type="ghost" @click="_copy('copy-part-' + index)" :data-clipboard-text="_rtClipboard(el)" :class="'copy-part-' + index"> |
||||||
|
<span v-for="(e,k,i) in el"><b style="color: #2A455B;">{{k}}</b> = {{e}} </span> |
||||||
|
</x-button> |
||||||
|
</template> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<script> |
||||||
|
import i18n from '@/module/i18n' |
||||||
|
import { mapActions } from 'vuex' |
||||||
|
import Clipboard from 'clipboard' |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'variables-view', |
||||||
|
data () { |
||||||
|
return { |
||||||
|
list: {} |
||||||
|
} |
||||||
|
}, |
||||||
|
props: {}, |
||||||
|
methods: { |
||||||
|
...mapActions('dag', ['getViewvariables']), |
||||||
|
/** |
||||||
|
* Get variable data |
||||||
|
*/ |
||||||
|
_getViewvariables () { |
||||||
|
this.getViewvariables({ |
||||||
|
processInstanceId: this.$route.params.id |
||||||
|
}).then(res => { |
||||||
|
this.list = res.data |
||||||
|
}).catch(e => { |
||||||
|
this.$message.error(e.msg || '') |
||||||
|
}) |
||||||
|
}, |
||||||
|
/** |
||||||
|
* Click to copy |
||||||
|
*/ |
||||||
|
_copy (className) { |
||||||
|
let clipboard = new Clipboard(`.${className}`) |
||||||
|
clipboard.on('success', e => { |
||||||
|
this.$message.success(`${i18n.$t('复制成功')}`) |
||||||
|
// Free memory |
||||||
|
clipboard.destroy() |
||||||
|
}) |
||||||
|
clipboard.on('error', e => { |
||||||
|
// Copy is not supported |
||||||
|
this.$message.warning(`${i18n.$t('该浏览器不支持自动复制')}`) |
||||||
|
// Free memory |
||||||
|
clipboard.destroy() |
||||||
|
}) |
||||||
|
}, |
||||||
|
/** |
||||||
|
* Copyed text processing |
||||||
|
*/ |
||||||
|
_rtClipboard (el) { |
||||||
|
let arr = [] |
||||||
|
Object.keys(el).forEach((key) => { |
||||||
|
arr.push(`${key}=${el[key]}`) |
||||||
|
}) |
||||||
|
return arr.join(' ') |
||||||
|
} |
||||||
|
}, |
||||||
|
watch: {}, |
||||||
|
created () { |
||||||
|
this._getViewvariables() |
||||||
|
}, |
||||||
|
mounted () { |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style lang="scss" rel="stylesheet/scss"> |
||||||
|
.variable-model { |
||||||
|
padding: 10px; |
||||||
|
padding-bottom: 5px; |
||||||
|
.list { |
||||||
|
position: relative; |
||||||
|
min-height: 30px; |
||||||
|
.var-cont { |
||||||
|
padding-left: 19px; |
||||||
|
>button { |
||||||
|
margin-bottom: 6px; |
||||||
|
margin-right: 6px; |
||||||
|
} |
||||||
|
} |
||||||
|
.name { |
||||||
|
padding-bottom: 10px; |
||||||
|
font-size: 16px; |
||||||
|
>.fa { |
||||||
|
font-size: 16px; |
||||||
|
color: #0097e0; |
||||||
|
margin-right: 4px; |
||||||
|
vertical-align: middle; |
||||||
|
font-weight: bold; |
||||||
|
} |
||||||
|
>b { |
||||||
|
vertical-align: middle; |
||||||
|
} |
||||||
|
} |
||||||
|
>span{ |
||||||
|
height: 28px; |
||||||
|
line-height: 28px; |
||||||
|
padding: 0 8px; |
||||||
|
background: #2d8cf0; |
||||||
|
display: inline-block; |
||||||
|
margin-bottom: 8px; |
||||||
|
color: #fff; |
||||||
|
} |
||||||
|
} |
||||||
|
.list-t { |
||||||
|
padding-left: 0px; |
||||||
|
margin-bottom: 10px; |
||||||
|
.task-name { |
||||||
|
padding-left: 19px; |
||||||
|
padding-bottom: 8px; |
||||||
|
font-size: 12px; |
||||||
|
font-weight: bold; |
||||||
|
color: #0097e0; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,82 @@ |
|||||||
|
<template> |
||||||
|
<div class="home-main index-model"> |
||||||
|
<m-dag v-if="!isLoading" :type="'definition'" :release-state="releaseState"></m-dag> |
||||||
|
<m-spin :is-spin="isLoading" ></m-spin> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<script> |
||||||
|
import mDag from './_source/dag.vue' |
||||||
|
import mSpin from '@/module/components/spin/spin' |
||||||
|
import Affirm from './_source/jumpAffirm' |
||||||
|
import disabledState from '@/module/mixin/disabledState' |
||||||
|
import { mapActions, mapMutations } from 'vuex' |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'definition-details', |
||||||
|
data () { |
||||||
|
return { |
||||||
|
// loading |
||||||
|
isLoading: true, |
||||||
|
// state |
||||||
|
releaseState: '' |
||||||
|
} |
||||||
|
}, |
||||||
|
mixins: [disabledState], |
||||||
|
props: {}, |
||||||
|
methods: { |
||||||
|
...mapMutations('dag', ['resetParams', 'setIsDetails']), |
||||||
|
...mapActions('dag', ['getProcessList', 'getResourcesList', 'getProcessDetails']), |
||||||
|
/** |
||||||
|
* init |
||||||
|
*/ |
||||||
|
init () { |
||||||
|
this.isLoading = true |
||||||
|
// Initialization parameters |
||||||
|
this.resetParams() |
||||||
|
// Promise Get node needs data |
||||||
|
Promise.all([ |
||||||
|
// Node details |
||||||
|
this.getProcessDetails(this.$route.params.id), |
||||||
|
// get process definition |
||||||
|
this.getProcessList(), |
||||||
|
// get resource |
||||||
|
this.getResourcesList() |
||||||
|
]).then((data) => { |
||||||
|
let item = data[0] |
||||||
|
this.setIsDetails(item.releaseState === 'ONLINE') |
||||||
|
this.releaseState = item.releaseState |
||||||
|
this.isLoading = false |
||||||
|
// Whether to pop up the box? |
||||||
|
Affirm.init(this.$root) |
||||||
|
}).catch(() => { |
||||||
|
this.isLoading = false |
||||||
|
}) |
||||||
|
}, |
||||||
|
/** |
||||||
|
* Redraw (refresh operation) |
||||||
|
*/ |
||||||
|
_reset () { |
||||||
|
this.getProcessDetails(this.$route.params.id).then(res => { |
||||||
|
let item = res |
||||||
|
this.setIsDetails(item.releaseState === 'ONLINE') |
||||||
|
this.releaseState = item.releaseState |
||||||
|
}) |
||||||
|
} |
||||||
|
}, |
||||||
|
watch: { |
||||||
|
// Listening for routing changes |
||||||
|
'$route': { |
||||||
|
deep: true, |
||||||
|
handler () { |
||||||
|
this.init() |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
created () { |
||||||
|
this.init() |
||||||
|
}, |
||||||
|
mounted () { |
||||||
|
}, |
||||||
|
components: { mDag, mSpin } |
||||||
|
} |
||||||
|
</script> |
After Width: | Height: | Size: 5.0 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 3.4 KiB |
After Width: | Height: | Size: 3.5 KiB |
After Width: | Height: | Size: 3.2 KiB |
After Width: | Height: | Size: 4.1 KiB |
After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 2.3 KiB |
@ -0,0 +1,65 @@ |
|||||||
|
<template> |
||||||
|
<div class="home-main index-model"> |
||||||
|
<m-dag v-if="!isLoading"></m-dag> |
||||||
|
<m-spin :is-spin="isLoading"></m-spin> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<script> |
||||||
|
import mDag from './_source/dag.vue' |
||||||
|
import { mapActions, mapMutations } from 'vuex' |
||||||
|
import mSpin from '@/module/components/spin/spin' |
||||||
|
import Affirm from './_source/jumpAffirm' |
||||||
|
import disabledState from '@/module/mixin/disabledState' |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'create-index', |
||||||
|
data () { |
||||||
|
return { |
||||||
|
// loading |
||||||
|
isLoading: true |
||||||
|
} |
||||||
|
}, |
||||||
|
// mixins |
||||||
|
mixins: [disabledState], |
||||||
|
props: {}, |
||||||
|
methods: { |
||||||
|
...mapMutations('dag', ['resetParams']), |
||||||
|
...mapActions('dag', ['getProcessList', 'getResourcesList']), |
||||||
|
/** |
||||||
|
* init |
||||||
|
*/ |
||||||
|
init () { |
||||||
|
this.isLoading = true |
||||||
|
// Initialization parameters |
||||||
|
this.resetParams() |
||||||
|
// Promise Get node needs data |
||||||
|
Promise.all([ |
||||||
|
// get process definition |
||||||
|
this.getProcessList(), |
||||||
|
// get resource |
||||||
|
this.getResourcesList() |
||||||
|
]).then((data) => { |
||||||
|
this.isLoading = false |
||||||
|
// Whether to pop up the box? |
||||||
|
Affirm.init(this.$root) |
||||||
|
}).catch(() => { |
||||||
|
this.isLoading = false |
||||||
|
}) |
||||||
|
} |
||||||
|
}, |
||||||
|
watch: { |
||||||
|
'$route': { |
||||||
|
deep: true, |
||||||
|
handler () { |
||||||
|
this.init() |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
created () { |
||||||
|
this.init() |
||||||
|
}, |
||||||
|
mounted () { |
||||||
|
}, |
||||||
|
components: { mDag, mSpin } |
||||||
|
} |
||||||
|
</script> |
@ -0,0 +1,92 @@ |
|||||||
|
<template> |
||||||
|
<div class="home-main index-model"> |
||||||
|
<m-variable></m-variable> |
||||||
|
<m-dag v-if="!isLoading" :type="'instance'"></m-dag> |
||||||
|
<m-spin :is-spin="isLoading"></m-spin> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<script> |
||||||
|
import mDag from './_source/dag.vue' |
||||||
|
import { mapActions, mapMutations } from 'vuex' |
||||||
|
import mSpin from '@/module/components/spin/spin' |
||||||
|
import mVariable from './_source/variable' |
||||||
|
import Affirm from './_source/jumpAffirm' |
||||||
|
import disabledState from '@/module/mixin/disabledState' |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'instance-details', |
||||||
|
data () { |
||||||
|
return { |
||||||
|
// loading |
||||||
|
isLoading: true |
||||||
|
} |
||||||
|
}, |
||||||
|
mixins: [disabledState], |
||||||
|
props: {}, |
||||||
|
methods: { |
||||||
|
...mapMutations('dag', ['setIsDetails', 'resetParams']), |
||||||
|
...mapActions('dag', ['getProcessList', 'getResourcesList', 'getInstancedetail']), |
||||||
|
/** |
||||||
|
* init |
||||||
|
*/ |
||||||
|
init () { |
||||||
|
this.isLoading = true |
||||||
|
// Initialization parameters |
||||||
|
this.resetParams() |
||||||
|
// Promise Get node needs data |
||||||
|
Promise.all([ |
||||||
|
// Process instance details |
||||||
|
this.getInstancedetail(this.$route.params.id), |
||||||
|
// get process definition |
||||||
|
this.getProcessList(), |
||||||
|
// get resources |
||||||
|
this.getResourcesList() |
||||||
|
]).then((data) => { |
||||||
|
let item = data[0] |
||||||
|
let flag = false |
||||||
|
if (item.state !== 'WAITTING_THREAD' && item.state !== 'SUCCESS' && item.state !== 'PAUSE' && item.state !== 'FAILURE' && item.state !== 'STOP') { |
||||||
|
flag = true |
||||||
|
} else { |
||||||
|
flag = false |
||||||
|
} |
||||||
|
this.setIsDetails(flag) |
||||||
|
this.isLoading = false |
||||||
|
|
||||||
|
// Whether to pop up the box? |
||||||
|
Affirm.init(this.$root) |
||||||
|
}).catch(() => { |
||||||
|
this.isLoading = false |
||||||
|
}) |
||||||
|
}, |
||||||
|
/** |
||||||
|
* Redraw (refresh operation) |
||||||
|
*/ |
||||||
|
_reset () { |
||||||
|
this.getInstancedetail(this.$route.params.id).then(res => { |
||||||
|
let item = res |
||||||
|
let flag = false |
||||||
|
if (item.state !== 'WAITTING_THREAD' && item.state !== 'SUCCESS' && item.state !== 'PAUSE' && item.state !== 'FAILURE' && item.state !== 'STOP') { |
||||||
|
flag = true |
||||||
|
} else { |
||||||
|
flag = false |
||||||
|
} |
||||||
|
this.setIsDetails(flag) |
||||||
|
}) |
||||||
|
} |
||||||
|
}, |
||||||
|
watch: { |
||||||
|
'$route': { |
||||||
|
deep: true, |
||||||
|
handler () { |
||||||
|
this.init() |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
created () { |
||||||
|
this.init() |
||||||
|
}, |
||||||
|
mounted () { |
||||||
|
}, |
||||||
|
components: { mDag, mSpin, mVariable } |
||||||
|
} |
||||||
|
</script> |
@ -0,0 +1,8 @@ |
|||||||
|
<template> |
||||||
|
<router-view></router-view> |
||||||
|
</template> |
||||||
|
<script> |
||||||
|
export default { |
||||||
|
name: 'datasource-index' |
||||||
|
} |
||||||
|
</script> |
@ -0,0 +1,337 @@ |
|||||||
|
<template> |
||||||
|
<div class="datasource-popup-model"> |
||||||
|
<div class="top-p"> |
||||||
|
<span>{{item ? `${$t('编辑')}` : `${$t('创建')}`}}{{`${$t('数据源')}`}}</span> |
||||||
|
</div> |
||||||
|
<div class="content-p"> |
||||||
|
<div class="create-datasource-model"> |
||||||
|
<m-list-box-f> |
||||||
|
<template slot="name"><b>*</b>{{$t('数据源')}}</template> |
||||||
|
<template slot="content"> |
||||||
|
<x-radio-group v-model="type" size="small"> |
||||||
|
<x-radio :label="'MYSQL'">MYSQL</x-radio> |
||||||
|
<x-radio :label="'POSTGRESQL'">POSTGRESQL</x-radio> |
||||||
|
<x-radio :label="'HIVE'">HVIE</x-radio> |
||||||
|
<x-radio :label="'SPARK'">SPARK</x-radio> |
||||||
|
</x-radio-group> |
||||||
|
</template> |
||||||
|
</m-list-box-f> |
||||||
|
<m-list-box-f> |
||||||
|
<template slot="name"><b>*</b>{{$t('数据源名称')}}</template> |
||||||
|
<template slot="content"> |
||||||
|
<x-input |
||||||
|
type="input" |
||||||
|
v-model="name" |
||||||
|
:placeholder="$t('请输入数据源名称')" |
||||||
|
autocomplete="off"> |
||||||
|
</x-input> |
||||||
|
</template> |
||||||
|
</m-list-box-f> |
||||||
|
<m-list-box-f> |
||||||
|
<template slot="name">{{$t('描述')}}</template> |
||||||
|
<template slot="content"> |
||||||
|
<x-input |
||||||
|
type="textarea" |
||||||
|
v-model="note" |
||||||
|
:placeholder="$t('请输入描述')" |
||||||
|
autocomplete="off"> |
||||||
|
</x-input> |
||||||
|
</template> |
||||||
|
</m-list-box-f> |
||||||
|
<m-list-box-f> |
||||||
|
<template slot="name"><b>*</b>{{$t('IP主机名')}}</template> |
||||||
|
<template slot="content"> |
||||||
|
<x-input |
||||||
|
type="input" |
||||||
|
v-model="host" |
||||||
|
:placeholder="$t('请输入IP主机名')" |
||||||
|
autocomplete="off"> |
||||||
|
</x-input> |
||||||
|
</template> |
||||||
|
</m-list-box-f> |
||||||
|
<m-list-box-f> |
||||||
|
<template slot="name"><b>*</b>{{$t('端口')}}</template> |
||||||
|
<template slot="content"> |
||||||
|
<x-input |
||||||
|
type="input" |
||||||
|
v-model="port" |
||||||
|
:placeholder="$t('请输入端口')" |
||||||
|
autocomplete="off"> |
||||||
|
</x-input> |
||||||
|
</template> |
||||||
|
</m-list-box-f> |
||||||
|
<m-list-box-f> |
||||||
|
<template slot="name"><b>*</b>{{$t('用户名')}}</template> |
||||||
|
<template slot="content"> |
||||||
|
<x-input |
||||||
|
type="input" |
||||||
|
v-model="userName" |
||||||
|
:placeholder="$t('请输入用户名')" |
||||||
|
autocomplete="off"> |
||||||
|
</x-input> |
||||||
|
</template> |
||||||
|
</m-list-box-f> |
||||||
|
<m-list-box-f> |
||||||
|
<template slot="name">{{$t('密码')}}</template> |
||||||
|
<template slot="content"> |
||||||
|
<x-input |
||||||
|
type="password" |
||||||
|
v-model="password" |
||||||
|
:placeholder="$t('请输入密码')" |
||||||
|
autocomplete="off"> |
||||||
|
</x-input> |
||||||
|
</template> |
||||||
|
</m-list-box-f> |
||||||
|
<m-list-box-f> |
||||||
|
<template slot="name"><b>*</b>{{$t('数据库名')}}</template> |
||||||
|
<template slot="content"> |
||||||
|
<x-input |
||||||
|
type="input" |
||||||
|
v-model="database" |
||||||
|
:placeholder="$t('请输入数据库名')" |
||||||
|
autocomplete="off"> |
||||||
|
</x-input> |
||||||
|
</template> |
||||||
|
</m-list-box-f> |
||||||
|
<m-list-box-f> |
||||||
|
<template slot="name">{{$t('jdbc连接参数')}}</template> |
||||||
|
<template slot="content"> |
||||||
|
<x-input |
||||||
|
type="textarea" |
||||||
|
v-model="other" |
||||||
|
:autosize="{minRows:2}" |
||||||
|
:placeholder="_rtOtherPlaceholder()" |
||||||
|
autocomplete="off"> |
||||||
|
</x-input> |
||||||
|
</template> |
||||||
|
</m-list-box-f> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="bottom-p"> |
||||||
|
<x-button type="text" @click="_close()"> {{$t('取消')}} </x-button> |
||||||
|
<x-button type="success" shape="circle" @click="_testConnect()" :loading="testLoading">{{testLoading ? 'Loading...' : $t('测试连接')}}</x-button> |
||||||
|
<x-button type="primary" shape="circle" :loading="spinnerLoading" @click="_ok()">{{spinnerLoading ? 'Loading...' :item ? `${$t('确认编辑')}` : `${$t('确认提交')}`}} </x-button> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<script> |
||||||
|
import i18n from '@/module/i18n' |
||||||
|
import store from '@/conf/home/store' |
||||||
|
import { isJson } from '@/module/util/util' |
||||||
|
import mPopup from '@/module/components/popup/popup' |
||||||
|
import mListBoxF from '@/module/components/listBoxF/listBoxF' |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'create-datasource', |
||||||
|
data () { |
||||||
|
return { |
||||||
|
store, |
||||||
|
// btn loading |
||||||
|
spinnerLoading: false, |
||||||
|
// Data source type |
||||||
|
type: 'MYSQL', |
||||||
|
// name |
||||||
|
name: '', |
||||||
|
// desc |
||||||
|
note: '', |
||||||
|
// host |
||||||
|
host: '', |
||||||
|
// port |
||||||
|
port: '', |
||||||
|
// data storage name |
||||||
|
database: '', |
||||||
|
// database username |
||||||
|
userName: '', |
||||||
|
// Database password |
||||||
|
password: '', |
||||||
|
// Jdbc connection parameter |
||||||
|
other: '', |
||||||
|
// btn test loading |
||||||
|
testLoading: false |
||||||
|
} |
||||||
|
}, |
||||||
|
props: { |
||||||
|
item: Object |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
_rtOtherPlaceholder () { |
||||||
|
return `${i18n.$t('请输入格式为')} {"key1":"value1","key2":"value2"...} ${i18n.$t('连接参数')}` |
||||||
|
}, |
||||||
|
/** |
||||||
|
* submit |
||||||
|
*/ |
||||||
|
_ok () { |
||||||
|
if (this._verification()) { |
||||||
|
this._verifName().then(res => { |
||||||
|
this._submit() |
||||||
|
}) |
||||||
|
} |
||||||
|
}, |
||||||
|
/** |
||||||
|
* close |
||||||
|
*/ |
||||||
|
_close () { |
||||||
|
this.$emit('close') |
||||||
|
}, |
||||||
|
/** |
||||||
|
* return param |
||||||
|
*/ |
||||||
|
_rtParam () { |
||||||
|
return { |
||||||
|
type: this.type, |
||||||
|
name: this.name, |
||||||
|
note: this.note, |
||||||
|
host: this.host, |
||||||
|
port: this.port, |
||||||
|
database: this.database, |
||||||
|
userName: this.userName, |
||||||
|
password: this.password, |
||||||
|
other: this.other |
||||||
|
} |
||||||
|
}, |
||||||
|
/** |
||||||
|
* test connect |
||||||
|
*/ |
||||||
|
_testConnect () { |
||||||
|
if (this._verification()) { |
||||||
|
this.testLoading = true |
||||||
|
this.store.dispatch('datasource/connectDatasources', this._rtParam()).then(res => { |
||||||
|
setTimeout(() => { |
||||||
|
this.$message.success(res.msg) |
||||||
|
this.testLoading = false |
||||||
|
}, 800) |
||||||
|
}).catch(e => { |
||||||
|
this.$message.error(e.msg || '') |
||||||
|
this.testLoading = false |
||||||
|
}) |
||||||
|
} |
||||||
|
}, |
||||||
|
/** |
||||||
|
* Verify that the data source name exists |
||||||
|
*/ |
||||||
|
_verifName () { |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
if (this.name === this.item.name) { |
||||||
|
resolve() |
||||||
|
return |
||||||
|
} |
||||||
|
this.store.dispatch('datasource/verifyName', { name: this.name }).then(res => { |
||||||
|
resolve() |
||||||
|
}).catch(e => { |
||||||
|
this.$message.error(e.msg || '') |
||||||
|
reject(e) |
||||||
|
}) |
||||||
|
}) |
||||||
|
}, |
||||||
|
/** |
||||||
|
* verification |
||||||
|
*/ |
||||||
|
_verification () { |
||||||
|
if (!this.name) { |
||||||
|
this.$message.warning(`${i18n.$t('请输入资源名称')}`) |
||||||
|
return false |
||||||
|
} |
||||||
|
if (!this.host) { |
||||||
|
this.$message.warning(`${i18n.$t('请输入IP/主机名')}`) |
||||||
|
return false |
||||||
|
} |
||||||
|
if (!this.port) { |
||||||
|
this.$message.warning(`${i18n.$t('请输入端口')}`) |
||||||
|
return false |
||||||
|
} |
||||||
|
if (!this.userName) { |
||||||
|
this.$message.warning(`${i18n.$t('请输入用户名')}`) |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
if (!this.database) { |
||||||
|
this.$message.warning(`${i18n.$t('请输入数据库名')}`) |
||||||
|
return false |
||||||
|
} |
||||||
|
if (this.other) { |
||||||
|
if (!isJson(this.other)) { |
||||||
|
this.$message.warning(`${i18n.$t('jdbc连接参数不是一个正确的JSON格式')}`) |
||||||
|
return false |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return true |
||||||
|
}, |
||||||
|
/** |
||||||
|
* submit => add/update |
||||||
|
*/ |
||||||
|
_submit () { |
||||||
|
this.spinnerLoading = true |
||||||
|
let param = this._rtParam() |
||||||
|
// edit |
||||||
|
if (this.item) { |
||||||
|
param.id = this.item.id |
||||||
|
} |
||||||
|
this.store.dispatch(`datasource/${this.item ? `updateDatasource` : `createDatasources`}`, param).then(res => { |
||||||
|
this.$message.success(res.msg) |
||||||
|
this.spinnerLoading = false |
||||||
|
this.$emit('onUpdate') |
||||||
|
}).catch(e => { |
||||||
|
this.$message.error(e.msg || '') |
||||||
|
this.spinnerLoading = false |
||||||
|
}) |
||||||
|
}, |
||||||
|
/** |
||||||
|
* Get modified data |
||||||
|
*/ |
||||||
|
_getEditDatasource () { |
||||||
|
this.store.dispatch('datasource/getEditDatasource', { id: this.item.id }).then(res => { |
||||||
|
this.type = res.type |
||||||
|
this.name = res.name |
||||||
|
this.note = res.note |
||||||
|
this.host = res.host |
||||||
|
this.port = res.port |
||||||
|
this.database = res.database |
||||||
|
this.userName = res.userName |
||||||
|
this.password = res.password |
||||||
|
this.other = JSON.stringify(res.other) === '{}' ? '' : JSON.stringify(res.other) |
||||||
|
}).catch(e => { |
||||||
|
this.$message.error(e.msg || '') |
||||||
|
}) |
||||||
|
} |
||||||
|
}, |
||||||
|
watch: {}, |
||||||
|
created () { |
||||||
|
// Backfill |
||||||
|
if (this.item.id) { |
||||||
|
this._getEditDatasource() |
||||||
|
} |
||||||
|
}, |
||||||
|
mounted () { |
||||||
|
}, |
||||||
|
components: { mPopup, mListBoxF } |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style lang="scss" rel="stylesheet/scss"> |
||||||
|
.datasource-popup-model { |
||||||
|
background: #fff; |
||||||
|
border-radius: 3px; |
||||||
|
|
||||||
|
.top-p { |
||||||
|
height: 70px; |
||||||
|
line-height: 70px; |
||||||
|
border-radius: 3px 3px 0 0; |
||||||
|
padding: 0 20px; |
||||||
|
>span { |
||||||
|
font-size: 20px; |
||||||
|
} |
||||||
|
} |
||||||
|
.bottom-p { |
||||||
|
text-align: right; |
||||||
|
height: 72px; |
||||||
|
line-height: 72px; |
||||||
|
border-radius: 0 0 3px 3px; |
||||||
|
padding: 0 20px; |
||||||
|
} |
||||||
|
.content-p { |
||||||
|
min-width: 500px; |
||||||
|
min-height: 100px; |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,160 @@ |
|||||||
|
<template> |
||||||
|
<div class="list-model"> |
||||||
|
<div class="table-box"> |
||||||
|
<table class="fixed"> |
||||||
|
<tr> |
||||||
|
<th> |
||||||
|
<span>{{$t('编号')}}</span> |
||||||
|
</th> |
||||||
|
<th> |
||||||
|
<span>{{$t('数据源名称')}}</span> |
||||||
|
</th> |
||||||
|
<th width="120"> |
||||||
|
<span>{{$t('数据源类型')}}</span> |
||||||
|
</th> |
||||||
|
<th width="100"> |
||||||
|
<span>{{$t('数据源参数')}}</span> |
||||||
|
</th> |
||||||
|
<th> |
||||||
|
<span>{{$t('描述')}}</span> |
||||||
|
</th> |
||||||
|
<th width="150"> |
||||||
|
<span>{{$t('创建时间')}}</span> |
||||||
|
</th> |
||||||
|
<th width="150"> |
||||||
|
<span>{{$t('更新时间')}}</span> |
||||||
|
</th> |
||||||
|
<th width="80"> |
||||||
|
<span>{{$t('操作')}}</span> |
||||||
|
</th> |
||||||
|
</tr> |
||||||
|
<tr v-for="(item, $index) in list" :key="$index"> |
||||||
|
<td> |
||||||
|
<span>{{parseInt(pageNo === 1 ? ($index + 1) : (($index + 1) + (pageSize * (pageNo - 1))))}}</span> |
||||||
|
</td> |
||||||
|
<td> |
||||||
|
<span class="ellipsis"> |
||||||
|
<a href="javascript:" class="links">{{item.name}}</a> |
||||||
|
</span> |
||||||
|
</td> |
||||||
|
<td> |
||||||
|
<span>{{item.type}}</span> |
||||||
|
</td> |
||||||
|
<td> |
||||||
|
<m-tooltips-JSON :JSON="JSON.parse(item.connectionParams)" :id="item.id"> |
||||||
|
<span slot="reference"> |
||||||
|
<a href="javascript:" class="links" style="font-size: 12px;">{{$t('点击查看')}}</a> |
||||||
|
</span> |
||||||
|
</m-tooltips-JSON> |
||||||
|
</td> |
||||||
|
<td><span class="ellipsis">{{item.note}}</span></td> |
||||||
|
<td><span>{{item.createTime | formatDate}}</span></td> |
||||||
|
<td><span>{{item.updateTime | formatDate}}</span></td> |
||||||
|
<td> |
||||||
|
<x-button |
||||||
|
type="info" |
||||||
|
shape="circle" |
||||||
|
size="xsmall" |
||||||
|
data-toggle="tooltip" |
||||||
|
v-ps="['GENERAL_USER']" |
||||||
|
:title="$t('编辑')" |
||||||
|
icon="iconfont icon-bianjixiugai" |
||||||
|
@click="_edit(item)"> |
||||||
|
</x-button> |
||||||
|
<x-poptip |
||||||
|
:ref="'poptip-delete-' + $index" |
||||||
|
placement="bottom-end" |
||||||
|
width="90"> |
||||||
|
<p>{{$t('确定删除吗?')}}</p> |
||||||
|
<div style="text-align: right; margin: 0;padding-top: 4px;"> |
||||||
|
<x-button type="text" size="xsmall" shape="circle" @click="_closeDelete($index)">{{$t('取消')}}</x-button> |
||||||
|
<x-button type="primary" size="xsmall" shape="circle" @click="_delete(item,$index)">{{$t('确定')}}</x-button> |
||||||
|
</div> |
||||||
|
<template slot="reference"> |
||||||
|
<x-button |
||||||
|
type="error" |
||||||
|
shape="circle" |
||||||
|
size="xsmall" |
||||||
|
icon="iconfont icon-shanchu" |
||||||
|
data-toggle="tooltip" |
||||||
|
:title="$t('删除')" |
||||||
|
v-ps="['GENERAL_USER']"> |
||||||
|
</x-button> |
||||||
|
</template> |
||||||
|
</x-poptip> |
||||||
|
</td> |
||||||
|
</tr> |
||||||
|
</table> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<script> |
||||||
|
import { mapActions } from 'vuex' |
||||||
|
import '@/module/filter/formatDate' |
||||||
|
import { findComponentDownward } from '@/module/util/' |
||||||
|
import mTooltipsJSON from '@/module/components/tooltipsJSON/tooltipsJSON' |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'datasource-list', |
||||||
|
data () { |
||||||
|
return { |
||||||
|
// list |
||||||
|
list: [] |
||||||
|
} |
||||||
|
}, |
||||||
|
props: { |
||||||
|
// External incoming data |
||||||
|
datasourcesList: Array, |
||||||
|
// current page number |
||||||
|
pageNo: Number, |
||||||
|
// Total number of articles |
||||||
|
pageSize: Number |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
...mapActions('datasource', ['deleteDatasource']), |
||||||
|
/** |
||||||
|
* Close delete popup layer |
||||||
|
*/ |
||||||
|
_closeDelete (i) { |
||||||
|
this.$refs[`poptip-delete-${i}`][0].doClose() |
||||||
|
}, |
||||||
|
/** |
||||||
|
* Delete current line |
||||||
|
*/ |
||||||
|
_delete (item, i) { |
||||||
|
this.$refs[`poptip-delete-${i}`][0].doClose() |
||||||
|
this.deleteDatasource({ |
||||||
|
id: item.id |
||||||
|
}).then(res => { |
||||||
|
this.list.splice(i, 1) |
||||||
|
this.$message.success(res.msg) |
||||||
|
}).catch(e => { |
||||||
|
this.$message.error(e.msg || '') |
||||||
|
}) |
||||||
|
}, |
||||||
|
/** |
||||||
|
* edit |
||||||
|
*/ |
||||||
|
_edit (item) { |
||||||
|
findComponentDownward(this.$root, 'datasource-indexP')._create(item) |
||||||
|
} |
||||||
|
}, |
||||||
|
watch: { |
||||||
|
/** |
||||||
|
* Monitor external data changes |
||||||
|
*/ |
||||||
|
datasourcesList (a) { |
||||||
|
this.list = [] |
||||||
|
setTimeout(() => { |
||||||
|
this.list = a |
||||||
|
}) |
||||||
|
} |
||||||
|
}, |
||||||
|
created () { |
||||||
|
this.list = this.datasourcesList |
||||||
|
}, |
||||||
|
mounted () { |
||||||
|
}, |
||||||
|
components: { mTooltipsJSON } |
||||||
|
} |
||||||
|
</script> |
@ -0,0 +1,125 @@ |
|||||||
|
<template> |
||||||
|
<m-list-construction :title="$t('数据源中心')"> |
||||||
|
<template slot="conditions"> |
||||||
|
<m-conditions @on-conditions="_onConditions"> |
||||||
|
<template slot="button-group"> |
||||||
|
<x-button type="ghost" size="small" @click="_create('')" v-ps="['GENERAL_USER']">{{$t('创建数据源')}}</x-button> |
||||||
|
</template> |
||||||
|
</m-conditions> |
||||||
|
</template> |
||||||
|
<template slot="content"> |
||||||
|
<template v-if="datasourcesList.length"> |
||||||
|
<m-list :datasources-list="datasourcesList" :page-no="pageNo" :page-size="pageSize"></m-list> |
||||||
|
<div class="page-box"> |
||||||
|
<x-page :current="pageNo" :total="total" show-elevator @on-change="_page"></x-page> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<template v-if="!datasourcesList.length"> |
||||||
|
<m-no-data></m-no-data> |
||||||
|
</template> |
||||||
|
<m-spin :is-spin="isLoading" :is-left="false"> |
||||||
|
</m-spin> |
||||||
|
</template> |
||||||
|
</m-list-construction> |
||||||
|
</template> |
||||||
|
<script> |
||||||
|
import { mapActions } from 'vuex' |
||||||
|
import mList from './_source/list' |
||||||
|
import mSpin from '@/module/components/spin/spin' |
||||||
|
import mNoData from '@/module/components/noData/noData' |
||||||
|
import mCreateDataSource from './_source/createDataSource' |
||||||
|
import mConditions from '@/module/components/conditions/conditions' |
||||||
|
import mListConstruction from '@/module/components/listConstruction/listConstruction' |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'datasource-indexP', |
||||||
|
data () { |
||||||
|
return { |
||||||
|
// loading |
||||||
|
isLoading: true, |
||||||
|
// Number of pages per page |
||||||
|
pageSize: 10, |
||||||
|
// Number of pages |
||||||
|
pageNo: 1, |
||||||
|
// Total number of articles |
||||||
|
total: 20, |
||||||
|
// Search value |
||||||
|
searchVal: '', |
||||||
|
// data sources(List) |
||||||
|
datasourcesList: [] |
||||||
|
} |
||||||
|
}, |
||||||
|
props: {}, |
||||||
|
methods: { |
||||||
|
...mapActions('datasource', ['getDatasourcesListP']), |
||||||
|
/** |
||||||
|
* create data source |
||||||
|
*/ |
||||||
|
_create (item) { |
||||||
|
let self = this |
||||||
|
let modal = this.$modal.dialog({ |
||||||
|
closable: false, |
||||||
|
showMask: true, |
||||||
|
escClose: true, |
||||||
|
className: 'v-modal-custom', |
||||||
|
transitionName: 'opacityp', |
||||||
|
render (h) { |
||||||
|
return h(mCreateDataSource, { |
||||||
|
on: { |
||||||
|
onUpdate () { |
||||||
|
self._getDatasourcesListP('false') |
||||||
|
modal.remove() |
||||||
|
}, |
||||||
|
close () { |
||||||
|
modal.remove() |
||||||
|
} |
||||||
|
}, |
||||||
|
props: { |
||||||
|
item: item |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
}) |
||||||
|
}, |
||||||
|
/** |
||||||
|
* page |
||||||
|
*/ |
||||||
|
_page (val) { |
||||||
|
this.pageNo = val |
||||||
|
this._getDatasourcesListP() |
||||||
|
}, |
||||||
|
/** |
||||||
|
* conditions event |
||||||
|
*/ |
||||||
|
_onConditions (o) { |
||||||
|
this.searchVal = o.searchVal |
||||||
|
this.pageNo = 1 |
||||||
|
this._getDatasourcesListP('false') |
||||||
|
}, |
||||||
|
/** |
||||||
|
* get data(List) |
||||||
|
*/ |
||||||
|
_getDatasourcesListP (flag) { |
||||||
|
this.isLoading = !flag |
||||||
|
this.getDatasourcesListP({ |
||||||
|
pageSize: this.pageSize, |
||||||
|
pageNo: this.pageNo, |
||||||
|
searchVal: this.searchVal |
||||||
|
}).then(res => { |
||||||
|
this.datasourcesList = res.totalList |
||||||
|
this.total = res.total |
||||||
|
this.isLoading = false |
||||||
|
}).catch(e => { |
||||||
|
this.isLoading = false |
||||||
|
}) |
||||||
|
} |
||||||
|
}, |
||||||
|
watch: {}, |
||||||
|
created () { |
||||||
|
this._getDatasourcesListP() |
||||||
|
}, |
||||||
|
mounted () { |
||||||
|
}, |
||||||
|
components: { mList, mConditions, mSpin, mListConstruction, mNoData } |
||||||
|
} |
||||||
|
</script> |
@ -0,0 +1,16 @@ |
|||||||
|
<template> |
||||||
|
<m-list-construction :title="$t('首页')"> |
||||||
|
<template slot="content"> |
||||||
|
<m-project-chart :id="0"></m-project-chart> |
||||||
|
</template> |
||||||
|
</m-list-construction> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
import mProjectChart from '@/conf/home/pages/projects/pages/index/_source/projectChart' |
||||||
|
import mListConstruction from '@/module/components/listConstruction/listConstruction' |
||||||
|
export default { |
||||||
|
name: 'home', |
||||||
|
components: { mProjectChart, mListConstruction } |
||||||
|
} |
||||||
|
</script> |
@ -0,0 +1,40 @@ |
|||||||
|
<template> |
||||||
|
<router-view></router-view> |
||||||
|
</template> |
||||||
|
<script> |
||||||
|
export default { |
||||||
|
name: 'projects-index' |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style lang="scss" rel="stylesheet/scss"> |
||||||
|
.toolbar-color-sp,.state-tasks-color-sp { |
||||||
|
>a { |
||||||
|
display: inline-block; |
||||||
|
margin-right: 10px; |
||||||
|
cursor:default; |
||||||
|
&:hover { |
||||||
|
span { |
||||||
|
color: #333; |
||||||
|
} |
||||||
|
} |
||||||
|
>i { |
||||||
|
border-radius: 10px; |
||||||
|
display: inline-block; |
||||||
|
vertical-align: middle; |
||||||
|
font-size: 14px; |
||||||
|
} |
||||||
|
span { |
||||||
|
vertical-align: middle; |
||||||
|
font-size: 12px; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.toolbar-color-sp { |
||||||
|
>a { |
||||||
|
>i { |
||||||
|
font-size: 15px; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,8 @@ |
|||||||
|
<template> |
||||||
|
<router-view></router-view> |
||||||
|
</template> |
||||||
|
<script> |
||||||
|
export default { |
||||||
|
name: 'process-definition-index' |
||||||
|
} |
||||||
|
</script> |
@ -0,0 +1,14 @@ |
|||||||
|
<template> |
||||||
|
<div class="main-layout-box"> |
||||||
|
<m-secondary-menu :type="'projects'"></m-secondary-menu> |
||||||
|
<m-create-dag></m-create-dag> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<script> |
||||||
|
import mCreateDag from '@/conf/home/pages/dag/index' |
||||||
|
import mSecondaryMenu from '@/module/components/secondaryMenu/secondaryMenu' |
||||||
|
export default { |
||||||
|
name: 'definition-create-index', |
||||||
|
components: { mCreateDag, mSecondaryMenu } |
||||||
|
} |
||||||
|
</script> |
@ -0,0 +1,14 @@ |
|||||||
|
<template> |
||||||
|
<div class="main-layout-box"> |
||||||
|
<m-secondary-menu :type="'projects'"></m-secondary-menu> |
||||||
|
<m-definition-details></m-definition-details> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<script> |
||||||
|
import mSecondaryMenu from '@/module/components/secondaryMenu/secondaryMenu' |
||||||
|
import mDefinitionDetails from '@/conf/home/pages/dag/definitionDetails.vue' |
||||||
|
export default { |
||||||
|
name: 'definition-details-index', |
||||||
|
components: { mDefinitionDetails, mSecondaryMenu } |
||||||
|
} |
||||||
|
</script> |
@ -0,0 +1,338 @@ |
|||||||
|
<template> |
||||||
|
<div class="ans-input email-model"> |
||||||
|
<div class="clearfix input-element"> |
||||||
|
<span class="tag-wrapper" v-for="(item,$index) in activeList" :class="activeIndex === $index ? 'active' : ''"> |
||||||
|
<span class="tag-text">{{item}}</span> |
||||||
|
<i class="remove-tag ans-icon-close" @click="_del($index)"></i> |
||||||
|
</span> |
||||||
|
<x-poptip |
||||||
|
placement="bottom-start" |
||||||
|
:append-to-body="true" |
||||||
|
:visible-arrow="false" |
||||||
|
v-model="isEmail" |
||||||
|
trigger="manual"> |
||||||
|
<div class="email-list-model"> |
||||||
|
<div class="ans-scroller" style=" max-height: 300px;"> |
||||||
|
<div class="scroll-area-wrapper scroll-transition"> |
||||||
|
<ul class="dropdown-container"> |
||||||
|
<li class="ans-option" v-for="(item,$index) in emailList" @click="_selectEmail($index + 1)"> |
||||||
|
<span class="default-option-class" :class="index === ($index + 1) ? 'active' : ''">{{item}}</span> |
||||||
|
</li> |
||||||
|
</ul> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<span class="label-wrapper" slot="reference" > |
||||||
|
<!--@keydown.tab="_emailTab"--> |
||||||
|
<input |
||||||
|
class="email-input" |
||||||
|
ref="emailInput" |
||||||
|
:style="{width:emailWidth + 'px'}" |
||||||
|
type="text" |
||||||
|
v-model="email" |
||||||
|
:placeholder="$t('请输入邮箱')" |
||||||
|
@keydown.tab="_emailTab" |
||||||
|
@keyup.delete="_emailDelete" |
||||||
|
@keyup.enter="_emailEnter" |
||||||
|
@keyup.up="_emailKeyup('up')" |
||||||
|
@keyup.down="_emailKeyup('down')"> |
||||||
|
</span> |
||||||
|
</x-poptip> |
||||||
|
|
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<script> |
||||||
|
import _ from 'lodash' |
||||||
|
import i18n from '@/module/i18n' |
||||||
|
import emailList from '~/localData/email' |
||||||
|
import { isEmial, fuzzyQuery } from './util' |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'email', |
||||||
|
data () { |
||||||
|
return { |
||||||
|
tagModel: false, |
||||||
|
email: '', |
||||||
|
activeIndex: null, |
||||||
|
emailList: [], |
||||||
|
index: 0, |
||||||
|
emailWidth: 100, |
||||||
|
isCn: false |
||||||
|
} |
||||||
|
}, |
||||||
|
props: { |
||||||
|
activeList: Array, |
||||||
|
repeatData: Array |
||||||
|
}, |
||||||
|
model: { |
||||||
|
prop: 'activeList', |
||||||
|
event: 'valueEvent' |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
/** |
||||||
|
* Manually add a mailbox |
||||||
|
*/ |
||||||
|
_manualEmail () { |
||||||
|
let email = this.email |
||||||
|
|
||||||
|
let is = (n) => { |
||||||
|
return _.some(_.cloneDeep(this.repeatData).concat(_.cloneDeep(this.activeList)), v => v === n) |
||||||
|
} |
||||||
|
|
||||||
|
if (isEmial(email)) { |
||||||
|
if (!is(email)) { |
||||||
|
this.emailWidth = 0 |
||||||
|
this.activeList.push(email) |
||||||
|
this.email = '' |
||||||
|
this._handlerEmailWitch() |
||||||
|
} else { |
||||||
|
this.$message.warning(`${i18n.$t('邮箱已存在!收件人和抄送人不能重复')}`) |
||||||
|
} |
||||||
|
} else { |
||||||
|
this.$message.warning(`${i18n.$t('邮箱输入不合法')}`) |
||||||
|
} |
||||||
|
}, |
||||||
|
/** |
||||||
|
* Processing mailbox |
||||||
|
*/ |
||||||
|
_handlerEmail (val) { |
||||||
|
if (!val) { |
||||||
|
this.emailList = [] |
||||||
|
this.isEmail = false |
||||||
|
} else { |
||||||
|
let a = _.cloneDeep(this.repeatData).concat(_.cloneDeep(this.activeList)) |
||||||
|
let b = a.concat(emailList) |
||||||
|
let list = fuzzyQuery(b, val) |
||||||
|
this.emailList = _.uniqWith(list.length && list, _.isEqual) |
||||||
|
this.isEmail = !!list.length |
||||||
|
if (this.emailList.length) { |
||||||
|
this.index = 1 |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
/** |
||||||
|
* Carriage return |
||||||
|
*/ |
||||||
|
_emailEnter () { |
||||||
|
// 没有list 手填 |
||||||
|
if (!this.emailList.length) { |
||||||
|
this._manualEmail() |
||||||
|
return |
||||||
|
} |
||||||
|
this._selectEmail(this.index) |
||||||
|
}, |
||||||
|
/** |
||||||
|
* delete email |
||||||
|
*/ |
||||||
|
_emailDelete () { |
||||||
|
// 输入法中文情况下禁止删除 |
||||||
|
if (!this.isCn) { |
||||||
|
this.emailWidth = 0 |
||||||
|
if (_.isInteger(this.activeIndex)) { |
||||||
|
this.activeList.pop() |
||||||
|
this.activeIndex = null |
||||||
|
} else { |
||||||
|
if (!this.email) { |
||||||
|
this.activeIndex = this.activeList.length - 1 |
||||||
|
} |
||||||
|
} |
||||||
|
this._handlerEmailWitch() |
||||||
|
} |
||||||
|
}, |
||||||
|
/** |
||||||
|
* click delete |
||||||
|
*/ |
||||||
|
_del (i) { |
||||||
|
this.emailWidth = 0 |
||||||
|
this.activeList.splice(i, 1) |
||||||
|
this._handlerEmailWitch() |
||||||
|
}, |
||||||
|
/** |
||||||
|
* keyup Up/down event processing |
||||||
|
*/ |
||||||
|
_emailKeyup (type) { |
||||||
|
let emailList = this.emailList.length |
||||||
|
if (emailList === 1) { |
||||||
|
this.index = 1 |
||||||
|
return |
||||||
|
} |
||||||
|
if (emailList) { |
||||||
|
if (type === 'up') { |
||||||
|
this.index = ((i) => { |
||||||
|
let num |
||||||
|
if (i === 0 || i === 1) { |
||||||
|
num = emailList |
||||||
|
} else { |
||||||
|
num = i - 1 |
||||||
|
} |
||||||
|
return num |
||||||
|
})(this.index) |
||||||
|
} else { |
||||||
|
this.index = ((i) => { |
||||||
|
let num |
||||||
|
if (i === 0 || i === emailList) { |
||||||
|
num = 1 |
||||||
|
} else { |
||||||
|
num = i + 1 |
||||||
|
} |
||||||
|
return num |
||||||
|
})(this.index) |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
/** |
||||||
|
* Check mailbox processing |
||||||
|
*/ |
||||||
|
_selectEmail (i) { |
||||||
|
let item = this.emailList[i - 1] |
||||||
|
this.isEmail = false |
||||||
|
this.email = '' |
||||||
|
|
||||||
|
// Non-existing data |
||||||
|
if (_.filter(_.cloneDeep(this.repeatData).concat(_.cloneDeep(this.activeList)), v => v === item).length) { |
||||||
|
this.$message.warning(`${i18n.$t('邮箱已存在!收件人和抄送人不能重复')}`) |
||||||
|
return |
||||||
|
} |
||||||
|
// Width initialization |
||||||
|
this.emailWidth = 0 |
||||||
|
// Insert data |
||||||
|
this.activeList.push(item) |
||||||
|
// Calculated width |
||||||
|
this._handlerEmailWitch() |
||||||
|
// Check mailbox index initialization |
||||||
|
this.activeIndex = null |
||||||
|
setTimeout(() => { |
||||||
|
// Focus position |
||||||
|
this.$refs.emailInput.focus() |
||||||
|
}, 100) |
||||||
|
}, |
||||||
|
/** |
||||||
|
* Processing width |
||||||
|
*/ |
||||||
|
_handlerEmailWitch () { |
||||||
|
setTimeout(() => { |
||||||
|
this.emailWidth = parseInt(688 - $(this.$refs.emailInput).position().left - 20) |
||||||
|
if (this.emailWidth < 80) { |
||||||
|
this.emailWidth = 200 |
||||||
|
} |
||||||
|
}, 100) |
||||||
|
}, |
||||||
|
/** |
||||||
|
* Tab event processing |
||||||
|
*/ |
||||||
|
_emailTab () { |
||||||
|
// Data processing |
||||||
|
this._emailEnter() |
||||||
|
// Focus acquisition |
||||||
|
setTimeout(() => { |
||||||
|
// Focus position |
||||||
|
this.$refs.emailInput.focus() |
||||||
|
}, 100) |
||||||
|
} |
||||||
|
}, |
||||||
|
watch: { |
||||||
|
email (val) { |
||||||
|
this._handlerEmail(val) |
||||||
|
// Check mailbox index initialization |
||||||
|
this.activeIndex = null |
||||||
|
}, |
||||||
|
activeList (val) { |
||||||
|
this.$emit('valueEvent', val) |
||||||
|
} |
||||||
|
}, |
||||||
|
created () { |
||||||
|
|
||||||
|
}, |
||||||
|
mounted () { |
||||||
|
setTimeout(() => { |
||||||
|
// Processing width |
||||||
|
this._handlerEmailWitch() |
||||||
|
}, 500) |
||||||
|
|
||||||
|
// Input method judgment |
||||||
|
$('.email-input').on('input', function () { |
||||||
|
// Chinese input is not truncated |
||||||
|
if ($(this).prop('comStart')) return |
||||||
|
this.isCn = false |
||||||
|
}).on('compositionstart', () => { |
||||||
|
$(this).prop('comStart', true) |
||||||
|
// Check mailbox index initialization |
||||||
|
this.activeIndex = null |
||||||
|
// console.log('中文输入:开始'); |
||||||
|
this.isCn = true |
||||||
|
}).on('compositionend', () => { |
||||||
|
$(this).prop('comStart', false) |
||||||
|
// Check mailbox index initialization |
||||||
|
this.activeIndex = null |
||||||
|
// console.log('中文输入:结束'); |
||||||
|
this.isCn = false |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style lang="scss" rel="stylesheet/scss"> |
||||||
|
.email-model { |
||||||
|
width: 688px; |
||||||
|
.input-element { |
||||||
|
min-height: 32px; |
||||||
|
padding: 1px 8px; |
||||||
|
.tag-wrapper { |
||||||
|
display: inline-block; |
||||||
|
height: 22px; |
||||||
|
margin: 3px 8px 3px 0px; |
||||||
|
padding: 0 10px; |
||||||
|
background: #ebf8ff; |
||||||
|
border-radius: 2px; |
||||||
|
cursor: default; |
||||||
|
&.active { |
||||||
|
background: #E2EFF9 |
||||||
|
} |
||||||
|
.tag-text { |
||||||
|
margin-right: 8px; |
||||||
|
font-size: 12px; |
||||||
|
line-height: 22px; |
||||||
|
color: #666; |
||||||
|
cursor: text; |
||||||
|
} |
||||||
|
.remove-tag { |
||||||
|
font-size: 12px; |
||||||
|
-webkit-transform: scale(.8); |
||||||
|
-ms-transform: scale(.8); |
||||||
|
transform: scale(.8); |
||||||
|
color: #666; |
||||||
|
cursor: pointer; |
||||||
|
&:hover { |
||||||
|
color: #000; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.label-wrapper { |
||||||
|
margin-left: -6px; |
||||||
|
input { |
||||||
|
height: 29px; |
||||||
|
line-height: 29px; |
||||||
|
border: 0; |
||||||
|
padding-left: 4px; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.email-list-model { |
||||||
|
margin: -10px -13px; |
||||||
|
.ans-scroller { |
||||||
|
width: 230px; |
||||||
|
overflow-y: scroll; |
||||||
|
.default-option-class { |
||||||
|
width: 230px; |
||||||
|
overflow: hidden; |
||||||
|
text-overflow:ellipsis; |
||||||
|
white-space: nowrap; |
||||||
|
} |
||||||
|
} |
||||||
|
.ans-option .default-option-class.active { |
||||||
|
background: #ebf8ff; |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,238 @@ |
|||||||
|
<template> |
||||||
|
<div class="list-model"> |
||||||
|
<div class="table-box"> |
||||||
|
<table class="fixed"> |
||||||
|
<tr> |
||||||
|
<th> |
||||||
|
<span>{{$t('编号')}}</span> |
||||||
|
</th> |
||||||
|
<th> |
||||||
|
<span>{{$t('工作流名称')}}</span> |
||||||
|
</th> |
||||||
|
<th width="50"> |
||||||
|
<span>{{$t('状态')}}</span> |
||||||
|
</th> |
||||||
|
<th width="140"> |
||||||
|
<span>{{$t('创建时间')}}</span> |
||||||
|
</th> |
||||||
|
<th width="140"> |
||||||
|
<span>{{$t('更新时间')}}</span> |
||||||
|
</th> |
||||||
|
<th> |
||||||
|
<span>{{$t('描述')}}</span> |
||||||
|
</th> |
||||||
|
<th width="90"> |
||||||
|
<span>{{$t('定时状态')}}</span> |
||||||
|
</th> |
||||||
|
<th width="220"> |
||||||
|
<span>{{$t('操作')}}</span> |
||||||
|
</th> |
||||||
|
</tr> |
||||||
|
<tr v-for="(item, $index) in list" :key="item.id"> |
||||||
|
<td> |
||||||
|
<span>{{parseInt(pageNo === 1 ? ($index + 1) : (($index + 1) + (pageSize * (pageNo - 1))))}}</span> |
||||||
|
</td> |
||||||
|
<td> |
||||||
|
<span class="ellipsis"> |
||||||
|
<router-link :to="{ path: '/projects/definition/list/' + item.id}" tag="a" class="links"> |
||||||
|
{{item.name}} |
||||||
|
</router-link> |
||||||
|
</span> |
||||||
|
</td> |
||||||
|
<td><span>{{_rtPublishStatus(item.releaseState)}}</span></td> |
||||||
|
<td> |
||||||
|
<span v-if="item.createTime">{{item.createTime | formatDate}}</span> |
||||||
|
<span v-if="!item.createTime">-</span> |
||||||
|
</td> |
||||||
|
<td> |
||||||
|
<span>{{item.updateTime | formatDate}}</span> |
||||||
|
</td> |
||||||
|
<td><span class="ellipsis">{{item.desc}}</span></td> |
||||||
|
<td> |
||||||
|
<span v-if="item.scheduleReleaseState === 'OFFLINE'">{{$t('下线')}}</span> |
||||||
|
<span v-if="item.scheduleReleaseState === 'ONLINE'">{{$t('上线')}}</span> |
||||||
|
<span v-if="!item.scheduleReleaseState">-</span> |
||||||
|
</td> |
||||||
|
<td> |
||||||
|
<x-button type="info" shape="circle" size="xsmall" data-toggle="tooltip" :title="$t('编辑')" @click="_edit(item)" :disabled="item.releaseState === 'ONLINE'" v-ps="['GENERAL_USER']" icon="iconfont icon-bianji"><!--{{$t('编辑')}}--></x-button> |
||||||
|
<x-button type="success" shape="circle" size="xsmall" data-toggle="tooltip" :title="$t('启动')" @click="_start(item)" :disabled="item.releaseState !== 'ONLINE'" v-ps="['GENERAL_USER']" icon="iconfont icon-qidong"><!--{{$t('启动')}}--></x-button> |
||||||
|
<x-button type="info" shape="circle" size="xsmall" data-toggle="tooltip" :title="$t('定时')" @click="_timing(item)" :disabled="item.releaseState !== 'ONLINE' || item.scheduleReleaseState !== null" v-ps="['GENERAL_USER']" icon="iconfont icon-timer"><!--{{$t('定时')}}--></x-button> |
||||||
|
<x-button type="error" shape="circle" size="xsmall" data-toggle="tooltip" :title="$t('下线')" @click="_downline(item)" v-if="item.releaseState === 'ONLINE'" v-ps="['GENERAL_USER']" icon="iconfont icon-erji-xiaxianjilu"><!--{{$t('下线')}}--></x-button> |
||||||
|
<x-button type="warning" shape="circle" size="xsmall" data-toggle="tooltip" :title="$t('上线')" @click="_poponline(item)" v-if="item.releaseState === 'OFFLINE'" v-ps="['GENERAL_USER']" icon="iconfont icon-erji-xiaxianjilu-copy"><!--{{$t('上线')}}--></x-button> |
||||||
|
<x-button type="info" shape="circle" size="xsmall" data-toggle="tooltip" :title="$t('定时管理')" @click="_timingManage(item)" :disabled="item.releaseState !== 'ONLINE'" v-ps="['GENERAL_USER']" icon="iconfont icon-paibanguanli"><!--{{$t('定时管理')}}--></x-button> |
||||||
|
<x-button type="info" shape="circle" size="xsmall" data-toggle="tooltip" :title="$t('树形图')" @click="_treeView(item)" icon="iconfont icon-juxingkaobei"><!--{{$t('树形图')}}--></x-button> |
||||||
|
</td> |
||||||
|
</tr> |
||||||
|
</table> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<script> |
||||||
|
import _ from 'lodash' |
||||||
|
import mStart from './start' |
||||||
|
import mTiming from './timing' |
||||||
|
import { mapActions } from 'vuex' |
||||||
|
import '@/module/filter/formatDate' |
||||||
|
import { publishStatus } from '@/conf/home/pages/dag/_source/config' |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'definition-list', |
||||||
|
data () { |
||||||
|
return { |
||||||
|
list: [] |
||||||
|
} |
||||||
|
}, |
||||||
|
props: { |
||||||
|
processList: Array, |
||||||
|
pageNo: Number, |
||||||
|
pageSize: Number |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
...mapActions('dag', ['editProcessState', 'getStartCheck', 'getReceiver']), |
||||||
|
_rtPublishStatus (code) { |
||||||
|
return _.filter(publishStatus, v => v.code === code)[0].desc |
||||||
|
}, |
||||||
|
_treeView (item) { |
||||||
|
this.$router.push({ path: `/projects/definition/tree/${item.id}` }) |
||||||
|
}, |
||||||
|
/** |
||||||
|
* Start |
||||||
|
*/ |
||||||
|
_start (item) { |
||||||
|
this.getStartCheck({ processDefinitionId: item.id }).then(res => { |
||||||
|
let self = this |
||||||
|
let modal = this.$modal.dialog({ |
||||||
|
closable: false, |
||||||
|
showMask: true, |
||||||
|
escClose: true, |
||||||
|
className: 'v-modal-custom', |
||||||
|
transitionName: 'opacityp', |
||||||
|
render (h) { |
||||||
|
return h(mStart, { |
||||||
|
on: { |
||||||
|
onUpdate () { |
||||||
|
self._onUpdate() |
||||||
|
modal.remove() |
||||||
|
}, |
||||||
|
close () { |
||||||
|
modal.remove() |
||||||
|
} |
||||||
|
}, |
||||||
|
props: { |
||||||
|
item: item |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
}) |
||||||
|
}).catch(e => { |
||||||
|
this.$message.error(e.msg || '') |
||||||
|
}) |
||||||
|
}, |
||||||
|
/** |
||||||
|
* get emial |
||||||
|
*/ |
||||||
|
_getReceiver (id) { |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
this.getReceiver({ processDefinitionId: id }).then(res => { |
||||||
|
resolve({ |
||||||
|
receivers: res.receivers && res.receivers.split(',') || [], |
||||||
|
receiversCc: res.receiversCc && res.receiversCc.split(',') || [] |
||||||
|
}) |
||||||
|
}) |
||||||
|
}) |
||||||
|
}, |
||||||
|
/** |
||||||
|
* timing |
||||||
|
*/ |
||||||
|
_timing (item) { |
||||||
|
let self = this |
||||||
|
this._getReceiver(item.id).then(res => { |
||||||
|
let modal = this.$modal.dialog({ |
||||||
|
closable: false, |
||||||
|
showMask: true, |
||||||
|
escClose: true, |
||||||
|
className: 'v-modal-custom', |
||||||
|
transitionName: 'opacityp', |
||||||
|
render (h) { |
||||||
|
return h(mTiming, { |
||||||
|
on: { |
||||||
|
onUpdate () { |
||||||
|
self._onUpdate() |
||||||
|
modal.remove() |
||||||
|
}, |
||||||
|
close () { |
||||||
|
modal.remove() |
||||||
|
} |
||||||
|
}, |
||||||
|
props: { |
||||||
|
item: item, |
||||||
|
receiversD: res.receivers, |
||||||
|
receiversCcD: res.receiversCc |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
}) |
||||||
|
}) |
||||||
|
}, |
||||||
|
/** |
||||||
|
* Timing manage |
||||||
|
*/ |
||||||
|
_timingManage (item) { |
||||||
|
this.$router.push({ path: `/projects/definition/list/timing/${item.id}` }) |
||||||
|
}, |
||||||
|
/** |
||||||
|
* edit |
||||||
|
*/ |
||||||
|
_edit (item) { |
||||||
|
this.$router.push({ path: `/projects/definition/list/${item.id}` }) |
||||||
|
}, |
||||||
|
/** |
||||||
|
* Offline |
||||||
|
*/ |
||||||
|
_downline (item) { |
||||||
|
this._upProcessState({ |
||||||
|
processId: item.id, |
||||||
|
releaseState: 0 |
||||||
|
}) |
||||||
|
}, |
||||||
|
/** |
||||||
|
* online |
||||||
|
*/ |
||||||
|
_poponline (item) { |
||||||
|
this._upProcessState({ |
||||||
|
processId: item.id, |
||||||
|
releaseState: 1 |
||||||
|
}) |
||||||
|
}, |
||||||
|
/** |
||||||
|
* Edit state |
||||||
|
*/ |
||||||
|
_upProcessState (o) { |
||||||
|
this.editProcessState(o).then(res => { |
||||||
|
this.$message.success(res.msg) |
||||||
|
$('body').find('.tooltip.fade.top.in').remove() |
||||||
|
this._onUpdate() |
||||||
|
}).catch(e => { |
||||||
|
this.$message.error(e.msg || '') |
||||||
|
}) |
||||||
|
}, |
||||||
|
_onUpdate () { |
||||||
|
this.$emit('on-update') |
||||||
|
} |
||||||
|
}, |
||||||
|
watch: { |
||||||
|
processList (a) { |
||||||
|
this.list = [] |
||||||
|
setTimeout(() => { |
||||||
|
this.list = a |
||||||
|
}) |
||||||
|
} |
||||||
|
}, |
||||||
|
created () { |
||||||
|
}, |
||||||
|
mounted () { |
||||||
|
this.list = this.processList |
||||||
|
}, |
||||||
|
components: { } |
||||||
|
} |
||||||
|
</script> |
@ -0,0 +1,298 @@ |
|||||||
|
<template> |
||||||
|
<div class="start-process-model"> |
||||||
|
<div class="title-box"> |
||||||
|
<span>{{$t('启动前请先设置参数')}}</span> |
||||||
|
</div> |
||||||
|
<div class="clearfix list"> |
||||||
|
<div class="text"> |
||||||
|
{{$t('失败策略')}} |
||||||
|
</div> |
||||||
|
<div class="cont"> |
||||||
|
<x-radio-group v-model="failureStrategy" style="margin-top: 7px;"> |
||||||
|
<x-radio :label="'CONTINUE'">{{$t('继续')}}</x-radio> |
||||||
|
<x-radio :label="'END'">{{$t('结束')}}</x-radio> |
||||||
|
</x-radio-group> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="clearfix list" v-if="sourceType === 'contextmenu'"> |
||||||
|
<div class="text"> |
||||||
|
{{$t('节点执行')}} |
||||||
|
</div> |
||||||
|
<div class="cont"> |
||||||
|
<x-radio-group v-model="taskDependType"> |
||||||
|
<x-radio :label="'TASK_POST'">{{$t('向后执行')}}</x-radio> |
||||||
|
<x-radio :label="'TASK_PRE'">{{$t('向前执行')}}</x-radio> |
||||||
|
<x-radio :label="'TASK_ONLY'">{{$t('仅执行当前节点')}}</x-radio> |
||||||
|
</x-radio-group> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="clearfix list"> |
||||||
|
<div class="text"> |
||||||
|
{{$t('通知策略')}} |
||||||
|
</div> |
||||||
|
<div class="cont"> |
||||||
|
<x-select style="width: 200px;" v-model="warningType"> |
||||||
|
<x-option |
||||||
|
v-for="city in warningTypeList" |
||||||
|
:key="city.id" |
||||||
|
:value="city" |
||||||
|
:label="city.code"> |
||||||
|
</x-option> |
||||||
|
</x-select> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="clearfix list"> |
||||||
|
<div class="text"> |
||||||
|
{{$t('流程优先级')}} |
||||||
|
</div> |
||||||
|
<div class="cont"> |
||||||
|
<m-priority v-model="processInstancePriority"></m-priority> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="clearfix list"> |
||||||
|
<div class="text"> |
||||||
|
{{$t('通知组')}} |
||||||
|
</div> |
||||||
|
<div class="cont"> |
||||||
|
<x-select |
||||||
|
style="width: 200px;" |
||||||
|
v-model="warningGroupId" |
||||||
|
:disabled="!notifyGroupList.length"> |
||||||
|
<x-input slot="trigger" slot-scope="{ selectedModel }" readonly :placeholder="$t('请选择通知组')" :value="selectedModel ? selectedModel.label : ''" style="width: 200px;" @on-click-icon.stop="warningGroupId = {}"> |
||||||
|
<i slot="suffix" class="fa fa-times-circle" style="font-size: 15px;cursor: pointer;" v-show="warningGroupId.id"></i> |
||||||
|
<i slot="suffix" class="ans-icon-arrow-down" style="font-size: 12px;" v-show="!warningGroupId.id"></i> |
||||||
|
</x-input> |
||||||
|
<x-option |
||||||
|
v-for="city in notifyGroupList" |
||||||
|
:key="city.id" |
||||||
|
:value="city" |
||||||
|
:label="city.code"> |
||||||
|
</x-option> |
||||||
|
</x-select> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="clearfix list"> |
||||||
|
<div class="text"> |
||||||
|
{{$t('收件人')}} |
||||||
|
</div> |
||||||
|
<div class="cont"> |
||||||
|
<m-email v-model="receivers" :repeat-data="receiversCc"></m-email> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="clearfix list"> |
||||||
|
<div class="text"> |
||||||
|
{{$t('抄送人')}} |
||||||
|
</div> |
||||||
|
<div class="cont"> |
||||||
|
<m-email v-model="receiversCc" :repeat-data="receivers"></m-email> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="clearfix list"> |
||||||
|
<div class="text"> |
||||||
|
{{$t('补数')}} |
||||||
|
</div> |
||||||
|
<div class="cont"> |
||||||
|
<div style="padding-top: 6px;"> |
||||||
|
<x-checkbox v-model="execType">{{$t('是否补数')}}</x-checkbox> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<template v-if="execType"> |
||||||
|
<div class="clearfix list" style="margin:-6px 0 16px 0"> |
||||||
|
<div class="text"> |
||||||
|
{{$t('执行方式')}} |
||||||
|
</div> |
||||||
|
<div class="cont"> |
||||||
|
<x-radio-group v-model="runMode" style="margin-top: 7px;"> |
||||||
|
<x-radio :label="'RUN_MODE_SERIAL'">{{$t('串行执行')}}</x-radio> |
||||||
|
<x-radio :label="'RUN_MODE_PARALLEL'">{{$t('并行执行')}}</x-radio> |
||||||
|
</x-radio-group> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="clearfix list"> |
||||||
|
<div class="text"> |
||||||
|
{{$t('时间')}} |
||||||
|
</div> |
||||||
|
<div class="cont"> |
||||||
|
<x-datepicker |
||||||
|
style="width: 360px;" |
||||||
|
:panel-num="2" |
||||||
|
placement="bottom-start" |
||||||
|
@on-change="_datepicker" |
||||||
|
:value="scheduleTime" |
||||||
|
type="daterange" |
||||||
|
:placeholder="$t('选择日期区间')" |
||||||
|
format="YYYY-MM-DD HH:mm:ss"> |
||||||
|
</x-datepicker> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<div class="submit"> |
||||||
|
<x-button type="text" @click="close()"> {{$t('取消')}} </x-button> |
||||||
|
<x-button type="primary" shape="circle" :loading="spinnerLoading" @click="ok()" v-ps="['GENERAL_USER']">{{spinnerLoading ? 'Loading...' : $t('启动')}} </x-button> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<script> |
||||||
|
import _ from 'lodash' |
||||||
|
import dayjs from 'dayjs' |
||||||
|
import mEmail from './email.vue' |
||||||
|
import store from '@/conf/home/store' |
||||||
|
import { warningTypeList } from './util' |
||||||
|
import mPriority from '@/module/components/priority/priority' |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'start-process', |
||||||
|
data () { |
||||||
|
return { |
||||||
|
store, |
||||||
|
processDefinitionId: 0, |
||||||
|
failureStrategy: 'CONTINUE', |
||||||
|
warningTypeList: warningTypeList, |
||||||
|
warningType: {}, |
||||||
|
notifyGroupList: [], |
||||||
|
warningGroupId: {}, |
||||||
|
scheduleTime: '', |
||||||
|
spinnerLoading: false, |
||||||
|
execType: false, |
||||||
|
taskDependType: 'TASK_POST', |
||||||
|
receivers: [], |
||||||
|
receiversCc: [], |
||||||
|
runMode: 'RUN_MODE_SERIAL', |
||||||
|
processInstancePriority: 'MEDIUM' |
||||||
|
} |
||||||
|
}, |
||||||
|
props: { |
||||||
|
item: Object, |
||||||
|
startNodeList: { |
||||||
|
type: String, |
||||||
|
default: '' |
||||||
|
}, |
||||||
|
sourceType: String |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
_datepicker (val) { |
||||||
|
this.scheduleTime = val |
||||||
|
}, |
||||||
|
_start () { |
||||||
|
this.spinnerLoading = true |
||||||
|
let param = { |
||||||
|
processDefinitionId: this.item.id, |
||||||
|
scheduleTime: this.scheduleTime.length && this.scheduleTime.join(',') || '', |
||||||
|
failureStrategy: this.failureStrategy, |
||||||
|
warningType: this.warningType.id, |
||||||
|
warningGroupId: _.isEmpty(this.warningGroupId) ? 0 : this.warningGroupId.id, |
||||||
|
execType: this.execType ? 'COMPLEMENT_DATA' : null, |
||||||
|
startNodeList: this.startNodeList, |
||||||
|
taskDependType: this.taskDependType, |
||||||
|
runMode: this.runMode, |
||||||
|
processInstancePriority: this.processInstancePriority, |
||||||
|
receivers: this.receivers.join(',') || '', |
||||||
|
receiversCc: this.receiversCc.join(',') || '' |
||||||
|
} |
||||||
|
// Executed from the specified node |
||||||
|
if (this.sourceType === 'contextmenu') { |
||||||
|
param.taskDependType = this.taskDependType |
||||||
|
} |
||||||
|
this.store.dispatch('dag/processStart', param).then(res => { |
||||||
|
this.$message.success(res.msg) |
||||||
|
this.$emit('onUpdate') |
||||||
|
setTimeout(() => { |
||||||
|
this.spinnerLoading = false |
||||||
|
this.close() |
||||||
|
}, 500) |
||||||
|
}).catch(e => { |
||||||
|
this.$message.error(e.msg || '') |
||||||
|
this.spinnerLoading = false |
||||||
|
}) |
||||||
|
}, |
||||||
|
_getNotifyGroupList () { |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
let notifyGroupListS = _.cloneDeep(this.store.state.dag.notifyGroupListS) || [] |
||||||
|
if (!notifyGroupListS.length) { |
||||||
|
this.store.dispatch('dag/getNotifyGroupList').then(res => { |
||||||
|
this.notifyGroupList = res |
||||||
|
resolve() |
||||||
|
}) |
||||||
|
} else { |
||||||
|
this.notifyGroupList = notifyGroupListS |
||||||
|
resolve() |
||||||
|
} |
||||||
|
}) |
||||||
|
}, |
||||||
|
_getReceiver () { |
||||||
|
this.store.dispatch('dag/getReceiver', { processDefinitionId: this.item.id }).then(res => { |
||||||
|
this.receivers = res.receivers && res.receivers.split(',') || [] |
||||||
|
this.receiversCc = res.receiversCc && res.receiversCc.split(',') || [] |
||||||
|
}) |
||||||
|
}, |
||||||
|
ok () { |
||||||
|
this._start() |
||||||
|
}, |
||||||
|
close () { |
||||||
|
this.$emit('close') |
||||||
|
} |
||||||
|
}, |
||||||
|
watch: { |
||||||
|
execType (a) { |
||||||
|
this.scheduleTime = a ? [dayjs().format('YYYY-MM-DD 00:00:00'), dayjs().format('YYYY-MM-DD 00:00:00')] : '' |
||||||
|
} |
||||||
|
}, |
||||||
|
created () { |
||||||
|
this.warningType = this.warningTypeList[0] |
||||||
|
|
||||||
|
this._getReceiver() |
||||||
|
}, |
||||||
|
mounted () { |
||||||
|
this._getNotifyGroupList().then(() => { |
||||||
|
this.$nextTick(() => { |
||||||
|
this.warningGroupId = { id: 0 } |
||||||
|
}) |
||||||
|
}) |
||||||
|
}, |
||||||
|
computed: {}, |
||||||
|
components: { mEmail, mPriority } |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style lang="scss" rel="stylesheet/scss"> |
||||||
|
.start-process-model { |
||||||
|
width: 860px; |
||||||
|
min-height: 300px; |
||||||
|
background: #fff; |
||||||
|
border-radius: 3px; |
||||||
|
.title-box { |
||||||
|
margin-bottom: 18px; |
||||||
|
span { |
||||||
|
padding-left: 30px; |
||||||
|
font-size: 16px; |
||||||
|
padding-top: 29px; |
||||||
|
display: block; |
||||||
|
} |
||||||
|
} |
||||||
|
.list { |
||||||
|
margin-bottom: 14px; |
||||||
|
.text { |
||||||
|
width: 140px; |
||||||
|
float: left; |
||||||
|
text-align: right; |
||||||
|
line-height: 32px; |
||||||
|
padding-right: 8px; |
||||||
|
} |
||||||
|
.cont { |
||||||
|
width: 350px; |
||||||
|
float: left; |
||||||
|
.add-email-model { |
||||||
|
padding: 20px; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
.submit { |
||||||
|
text-align: right; |
||||||
|
padding-right: 30px; |
||||||
|
padding-top: 10px; |
||||||
|
padding-bottom: 30px; |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,323 @@ |
|||||||
|
<template> |
||||||
|
<div class="timing-process-model"> |
||||||
|
<div class="title-box"> |
||||||
|
<span>{{$t('定时前请先设置参数')}}</span> |
||||||
|
</div> |
||||||
|
<div class="clearfix list"> |
||||||
|
<div class="text"> |
||||||
|
{{$t('起止时间')}} |
||||||
|
</div> |
||||||
|
<div class="cont"> |
||||||
|
<x-datepicker |
||||||
|
style="width: 300px;" |
||||||
|
:panel-num="2" |
||||||
|
placement="bottom-start" |
||||||
|
@on-change="_datepicker" |
||||||
|
:value="scheduleTime" |
||||||
|
type="daterange" |
||||||
|
:placeholder="$t('选择日期区间')" |
||||||
|
format="YYYY-MM-DD HH:mm:ss"> |
||||||
|
</x-datepicker> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="clearfix list"> |
||||||
|
<div class="text"> |
||||||
|
{{$t('定时')}} |
||||||
|
</div> |
||||||
|
<div class="cont"> |
||||||
|
<template> |
||||||
|
<x-poptip :ref="'poptip'" placement="bottom-start"> |
||||||
|
<div class="crontab-box"> |
||||||
|
<v-crontab v-model="crontab" :locale="i18n"></v-crontab> |
||||||
|
</div> |
||||||
|
<template slot="reference"> |
||||||
|
<x-input |
||||||
|
style="width: 300px;" |
||||||
|
type="text" |
||||||
|
readonly |
||||||
|
:value="crontab" |
||||||
|
autocomplete="off"> |
||||||
|
</x-input> |
||||||
|
</template> |
||||||
|
</x-poptip> |
||||||
|
</template> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="clearfix list"> |
||||||
|
<div class="text"> |
||||||
|
{{$t('失败策略')}} |
||||||
|
</div> |
||||||
|
<div class="cont"> |
||||||
|
<x-radio-group v-model="failureStrategy" style="margin-top: 7px;"> |
||||||
|
<x-radio :label="'CONTINUE'">{{$t('继续')}}</x-radio> |
||||||
|
<x-radio :label="'END'">{{$t('结束')}}</x-radio> |
||||||
|
</x-radio-group> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="clearfix list"> |
||||||
|
<div class="text"> |
||||||
|
{{$t('通知策略')}} |
||||||
|
</div> |
||||||
|
<div class="cont"> |
||||||
|
<x-select |
||||||
|
style="width: 200px;" |
||||||
|
v-model="warningType"> |
||||||
|
<x-option |
||||||
|
v-for="city in warningTypeList" |
||||||
|
:key="city.id" |
||||||
|
:value="city.id" |
||||||
|
:label="city.code"> |
||||||
|
</x-option> |
||||||
|
</x-select> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="clearfix list"> |
||||||
|
<div class="text"> |
||||||
|
{{$t('流程优先级')}} |
||||||
|
</div> |
||||||
|
<div class="cont"> |
||||||
|
<m-priority v-model="processInstancePriority"></m-priority> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="clearfix list"> |
||||||
|
<div class="text"> |
||||||
|
{{$t('通知组')}} |
||||||
|
</div> |
||||||
|
<div class="cont"> |
||||||
|
<x-select |
||||||
|
style="width: 200px;" |
||||||
|
:disabled="!notifyGroupList.length" |
||||||
|
v-model="warningGroupId"> |
||||||
|
<x-input slot="trigger" readonly slot-scope="{ selectedModel }" :placeholder="$t('请选择通知组')" :value="selectedModel ? selectedModel.label : ''" style="width: 200px;" @on-click-icon.stop="warningGroupId = {}"> |
||||||
|
<i slot="suffix" class="fa fa-times-circle" style="font-size: 15px;cursor: pointer;" v-show="warningGroupId.id"></i> |
||||||
|
<i slot="suffix" class="ans-icon-arrow-down" style="font-size: 12px;" v-show="!warningGroupId.id"></i> |
||||||
|
</x-input> |
||||||
|
<x-option |
||||||
|
v-for="city in notifyGroupList" |
||||||
|
:key="city.id" |
||||||
|
:value="city" |
||||||
|
:label="city.code"> |
||||||
|
</x-option> |
||||||
|
</x-select> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="clearfix list"> |
||||||
|
<div class="text"> |
||||||
|
{{$t('收件人')}} |
||||||
|
</div> |
||||||
|
<div class="cont" style="width: 680px;"> |
||||||
|
<m-email v-model="receivers" :repeat-data="receiversCc"></m-email> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="clearfix list"> |
||||||
|
<div class="text"> |
||||||
|
{{$t('抄送人')}} |
||||||
|
</div> |
||||||
|
<div class="cont" style="width: 680px;"> |
||||||
|
<m-email v-model="receiversCc" :repeat-data="receivers"></m-email> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="submit"> |
||||||
|
<x-button type="text" @click="close()"> {{$t('取消')}} </x-button> |
||||||
|
<x-button type="primary" shape="circle" :loading="spinnerLoading" @click="ok()" v-ps="['GENERAL_USER']">{{spinnerLoading ? 'Loading...' : (item.crontab ? $t('编辑') : $t('创建'))}} </x-button> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<script> |
||||||
|
import _ from 'lodash' |
||||||
|
import i18n from '@/module/i18n' |
||||||
|
import mEmail from './email.vue' |
||||||
|
import '~/@vue/crontab/dist/index.css' |
||||||
|
import store from '@/conf/home/store' |
||||||
|
import { warningTypeList } from './util' |
||||||
|
import { vCrontab } from '~/@vue/crontab/dist' |
||||||
|
import { formatDate } from '@/module/filter/filter' |
||||||
|
import mPriority from '@/module/components/priority/priority' |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'timing-process', |
||||||
|
data () { |
||||||
|
return { |
||||||
|
store, |
||||||
|
processDefinitionId: 0, |
||||||
|
failureStrategy: 'CONTINUE', |
||||||
|
warningTypeList: warningTypeList, |
||||||
|
warningType: 'NONE', |
||||||
|
notifyGroupList: [], |
||||||
|
warningGroupId: {}, |
||||||
|
spinnerLoading: false, |
||||||
|
scheduleTime: '', |
||||||
|
crontab: '* * * * * ? *', |
||||||
|
cronPopover: false, |
||||||
|
receivers: [], |
||||||
|
receiversCc: [], |
||||||
|
i18n: i18n.globalScope.LOCALE, |
||||||
|
processInstancePriority: 'MEDIUM' |
||||||
|
} |
||||||
|
}, |
||||||
|
props: { |
||||||
|
item: Object, |
||||||
|
receiversD: Array, |
||||||
|
receiversCcD: Array |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
_datepicker (val) { |
||||||
|
this.scheduleTime = val |
||||||
|
}, |
||||||
|
_verification () { |
||||||
|
if (!this.scheduleTime) { |
||||||
|
this.$message.warning(`${i18n.$t('请选择时间')}`) |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
if (!this.crontab) { |
||||||
|
this.$message.warning(`${i18n.$t('请填写 crontab')}`) |
||||||
|
return false |
||||||
|
} |
||||||
|
return true |
||||||
|
}, |
||||||
|
_timing () { |
||||||
|
if (this._verification()) { |
||||||
|
let api = '' |
||||||
|
let searchParams = { |
||||||
|
schedule: JSON.stringify({ |
||||||
|
startTime: this.scheduleTime[0], |
||||||
|
endTime: this.scheduleTime[1], |
||||||
|
crontab: this.crontab |
||||||
|
}), |
||||||
|
failureStrategy: this.failureStrategy, |
||||||
|
warningType: this.warningType, |
||||||
|
processInstancePriority: this.processInstancePriority, |
||||||
|
warningGroupId: _.isEmpty(this.warningGroupId) ? 0 : this.warningGroupId.id, |
||||||
|
receivers: this.receivers.join(',') || '', |
||||||
|
receiversCc: this.receiversCc.join(',') || '' |
||||||
|
} |
||||||
|
|
||||||
|
// edit |
||||||
|
if (this.item.crontab) { |
||||||
|
api = 'dag/updateSchedule' |
||||||
|
searchParams.id = this.item.id |
||||||
|
} else { |
||||||
|
api = 'dag/createSchedule' |
||||||
|
searchParams.processDefinitionId = this.item.id |
||||||
|
} |
||||||
|
|
||||||
|
this.store.dispatch(api, searchParams).then(res => { |
||||||
|
this.$message.success(res.msg) |
||||||
|
this.$emit('onUpdate') |
||||||
|
}).catch(e => { |
||||||
|
this.$message.error(e.msg || '') |
||||||
|
}) |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
_getNotifyGroupList () { |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
let notifyGroupListS = _.cloneDeep(this.store.state.dag.notifyGroupListS) || [] |
||||||
|
if (!notifyGroupListS.length) { |
||||||
|
this.store.dispatch('dag/getNotifyGroupList').then(res => { |
||||||
|
this.notifyGroupList = res |
||||||
|
if (this.notifyGroupList.length) { |
||||||
|
resolve() |
||||||
|
} else { |
||||||
|
reject(new Error(0)) |
||||||
|
} |
||||||
|
}) |
||||||
|
} else { |
||||||
|
this.notifyGroupList = notifyGroupListS |
||||||
|
resolve() |
||||||
|
} |
||||||
|
}) |
||||||
|
}, |
||||||
|
ok () { |
||||||
|
this._timing() |
||||||
|
}, |
||||||
|
close () { |
||||||
|
this.$emit('close') |
||||||
|
} |
||||||
|
}, |
||||||
|
watch: { |
||||||
|
}, |
||||||
|
created () { |
||||||
|
this.receivers = _.cloneDeep(this.receiversD) |
||||||
|
this.receiversCc = _.cloneDeep(this.receiversCcD) |
||||||
|
}, |
||||||
|
mounted () { |
||||||
|
let item = this.item |
||||||
|
|
||||||
|
// Determine whether to echo |
||||||
|
if (this.item.crontab) { |
||||||
|
this.crontab = item.crontab |
||||||
|
this.scheduleTime = [formatDate(item.startTime), formatDate(item.endTime)] |
||||||
|
this.failureStrategy = item.failureStrategy |
||||||
|
this.warningType = item.warningType |
||||||
|
this.processInstancePriority = item.processInstancePriority |
||||||
|
this._getNotifyGroupList().then(() => { |
||||||
|
this.$nextTick(() => { |
||||||
|
let list = _.filter(this.notifyGroupList, v => v.id === item.warningGroupId) |
||||||
|
this.warningGroupId = list.length && list[0] || { id: 0 } |
||||||
|
}) |
||||||
|
}).catch(() => this.warningGroupId = { id: 0 }) |
||||||
|
} else { |
||||||
|
this._getNotifyGroupList().then(() => { |
||||||
|
this.$nextTick(() => { |
||||||
|
this.warningGroupId = { id: 0 } |
||||||
|
}) |
||||||
|
}).catch(() => this.warningGroupId = { id: 0 }) |
||||||
|
} |
||||||
|
}, |
||||||
|
components: { vCrontab, mEmail, mPriority } |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style lang="scss" rel="stylesheet/scss"> |
||||||
|
.timing-process-model { |
||||||
|
width: 860px; |
||||||
|
min-height: 300px; |
||||||
|
background: #fff; |
||||||
|
border-radius: 3px; |
||||||
|
margin-top: -24%; |
||||||
|
.crontab-box { |
||||||
|
margin: -6px; |
||||||
|
.v-crontab { |
||||||
|
} |
||||||
|
} |
||||||
|
.from-model { |
||||||
|
padding-top: 0; |
||||||
|
} |
||||||
|
.title-box { |
||||||
|
margin-bottom: 18px; |
||||||
|
span { |
||||||
|
padding-left: 30px; |
||||||
|
font-size: 16px; |
||||||
|
padding-top: 29px; |
||||||
|
display: block; |
||||||
|
} |
||||||
|
} |
||||||
|
.list { |
||||||
|
margin-bottom: 14px; |
||||||
|
>.text { |
||||||
|
width: 140px; |
||||||
|
float: left; |
||||||
|
text-align: right; |
||||||
|
line-height: 32px; |
||||||
|
padding-right: 8px; |
||||||
|
} |
||||||
|
.cont { |
||||||
|
width: 350px; |
||||||
|
float: left; |
||||||
|
} |
||||||
|
} |
||||||
|
.submit { |
||||||
|
text-align: right; |
||||||
|
padding-right: 30px; |
||||||
|
padding-top: 10px; |
||||||
|
padding-bottom: 30px; |
||||||
|
} |
||||||
|
} |
||||||
|
.v-crontab-from-model { |
||||||
|
.list-box { |
||||||
|
padding: 0; |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,60 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
import i18n from '@/module/i18n' |
||||||
|
|
||||||
|
let warningTypeList = [ |
||||||
|
{ |
||||||
|
id: 'NONE', |
||||||
|
code: `${i18n.$t('都不发')}` |
||||||
|
}, |
||||||
|
{ |
||||||
|
id: 'SUCCESS', |
||||||
|
code: `${i18n.$t('成功发')}` |
||||||
|
}, |
||||||
|
{ |
||||||
|
id: 'FAILURE', |
||||||
|
code: `${i18n.$t('失败发')}` |
||||||
|
}, |
||||||
|
{ |
||||||
|
id: 'ALL', |
||||||
|
code: `${i18n.$t('成功或失败都发')}` |
||||||
|
} |
||||||
|
] |
||||||
|
|
||||||
|
const isEmial = (val) => { |
||||||
|
let regEmail = /^([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+@([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+\.[a-zA-Z]{2,3}$/ // eslint-disable-line
|
||||||
|
return regEmail.test(val) |
||||||
|
} |
||||||
|
|
||||||
|
const fuzzyQuery = (list, keyWord) => { |
||||||
|
let len = list.length |
||||||
|
let arr = [] |
||||||
|
let reg = new RegExp(keyWord) |
||||||
|
for (let i = 0; i < len; i++) { |
||||||
|
if (list[i].match(reg)) { |
||||||
|
arr.push(list[i]) |
||||||
|
} |
||||||
|
} |
||||||
|
return arr |
||||||
|
} |
||||||
|
|
||||||
|
export { |
||||||
|
warningTypeList, |
||||||
|
isEmial, |
||||||
|
fuzzyQuery |
||||||
|
} |
@ -0,0 +1,147 @@ |
|||||||
|
<template> |
||||||
|
<div class="main-layout-box"> |
||||||
|
<m-secondary-menu :type="'projects'"></m-secondary-menu> |
||||||
|
<m-list-construction :title="$t('工作流定义')"> |
||||||
|
<template slot="conditions"> |
||||||
|
<m-conditions @on-conditions="_onConditions"> |
||||||
|
<template slot="button-group"> |
||||||
|
<x-button type="ghost" size="small" v-ps="['GENERAL_USER']" @click="() => this.$router.push({name: 'definition-create'})">{{$t('创建工作流')}}</x-button> |
||||||
|
</template> |
||||||
|
</m-conditions> |
||||||
|
</template> |
||||||
|
<template slot="content"> |
||||||
|
<template v-if="processListP.length"> |
||||||
|
<m-list :process-list="processListP" @on-update="_onUpdate" :page-no="searchParams.pageNo" :page-size="searchParams.pageSize"></m-list> |
||||||
|
<div class="page-box"> |
||||||
|
<x-page :current="parseInt(searchParams.pageNo)" :total="total" show-elevator @on-change="_page"></x-page> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<template v-if="!processListP.length"> |
||||||
|
<m-no-data></m-no-data> |
||||||
|
</template> |
||||||
|
<m-spin :is-spin="isLoading"></m-spin> |
||||||
|
</template> |
||||||
|
</m-list-construction> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<script> |
||||||
|
import _ from 'lodash' |
||||||
|
import { mapActions } from 'vuex' |
||||||
|
import mList from './_source/list' |
||||||
|
import mSpin from '@/module/components/spin/spin' |
||||||
|
import localStore from '@/module/util/localStorage' |
||||||
|
import { setUrlParams } from '@/module/util/routerUtil' |
||||||
|
import mNoData from '@/module/components/noData/noData' |
||||||
|
import mConditions from '@/module/components/conditions/conditions' |
||||||
|
import mSecondaryMenu from '@/module/components/secondaryMenu/secondaryMenu' |
||||||
|
import mListConstruction from '@/module/components/listConstruction/listConstruction' |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'definition-list-index', |
||||||
|
data () { |
||||||
|
return { |
||||||
|
total: null, |
||||||
|
processListP: [], |
||||||
|
isLoading: true, |
||||||
|
searchParams: { |
||||||
|
// 分页条数 |
||||||
|
pageSize: 10, |
||||||
|
// 分页 |
||||||
|
pageNo: 1, |
||||||
|
// 查询名称 |
||||||
|
searchVal: '' |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
props: { |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
...mapActions('dag', ['getProcessListP']), |
||||||
|
/** |
||||||
|
* page |
||||||
|
*/ |
||||||
|
_page (val) { |
||||||
|
this.searchParams.pageNo = val |
||||||
|
setUrlParams({ |
||||||
|
pageNo: this.searchParams.pageNo |
||||||
|
}) |
||||||
|
this._debounceGET() |
||||||
|
}, |
||||||
|
/** |
||||||
|
* conditions |
||||||
|
*/ |
||||||
|
_onConditions (o) { |
||||||
|
this.searchParams.searchVal = o.searchVal |
||||||
|
this.searchParams.pageNo = 1 |
||||||
|
setUrlParams({ |
||||||
|
pageNo: this.searchParams.pageNo |
||||||
|
}) |
||||||
|
this._debounceGET() |
||||||
|
}, |
||||||
|
/** |
||||||
|
* get data list |
||||||
|
*/ |
||||||
|
_getProcessListP (flag) { |
||||||
|
this.isLoading = !flag |
||||||
|
this.getProcessListP({ |
||||||
|
pageSize: this.searchParams.pageSize, |
||||||
|
pageNo: this.searchParams.pageNo, |
||||||
|
searchVal: this.searchParams.searchVal, |
||||||
|
userId: this.$route.query.userId || '' |
||||||
|
}).then(res => { |
||||||
|
setUrlParams({ pageNo: this.pageNo }) |
||||||
|
this.processListP = [] |
||||||
|
this.processListP = res.totalList |
||||||
|
this.total = res.total |
||||||
|
this.isLoading = false |
||||||
|
}).catch(e => { |
||||||
|
this.isLoading = false |
||||||
|
}) |
||||||
|
}, |
||||||
|
_onUpdate () { |
||||||
|
this._debounceGET('false') |
||||||
|
}, |
||||||
|
/** |
||||||
|
* Anti-shake request interface |
||||||
|
* @desc Prevent function from being called multiple times |
||||||
|
*/ |
||||||
|
_debounceGET: _.debounce(function (flag) { |
||||||
|
this._getProcessListP(flag) |
||||||
|
}, 100, { |
||||||
|
'leading': false, |
||||||
|
'trailing': true |
||||||
|
}) |
||||||
|
}, |
||||||
|
watch: { |
||||||
|
'$route' (a) { |
||||||
|
// url no params get instance list |
||||||
|
if (_.isEmpty(a.query)) { |
||||||
|
this.searchParams.pageNo = 1 |
||||||
|
} else { |
||||||
|
this.searchParams.pageNo = a.query.pageNo || 1 |
||||||
|
} |
||||||
|
}, |
||||||
|
'searchParams': { |
||||||
|
deep: true, |
||||||
|
handler () { |
||||||
|
this._debounceGET() |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
created () { |
||||||
|
localStore.removeItem('subProcessId') |
||||||
|
|
||||||
|
// Routing parameter merging |
||||||
|
if (!_.isEmpty(this.$route.query)) { |
||||||
|
this.searchParams = _.assign(this.searchParams, this.$route.query) |
||||||
|
} |
||||||
|
}, |
||||||
|
mounted () { |
||||||
|
this._debounceGET() |
||||||
|
}, |
||||||
|
components: { mList, mConditions, mSpin, mListConstruction, mSecondaryMenu, mNoData } |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style lang="scss" rel="stylesheet/scss"> |
||||||
|
</style> |
@ -0,0 +1,279 @@ |
|||||||
|
|
||||||
|
import $ from 'jquery' |
||||||
|
import * as d3 from 'd3' |
||||||
|
import { rtInstancesTooltip, rtCountMethod } from './util' |
||||||
|
import { tasksType, tasksState } from '@/conf/home/pages/dag/_source/config' |
||||||
|
|
||||||
|
let self = this |
||||||
|
|
||||||
|
let Tree = function () { |
||||||
|
self = this |
||||||
|
this.selfTree = {} |
||||||
|
this.tree = function () {} |
||||||
|
// basic configuration
|
||||||
|
this.config = { |
||||||
|
barHeight: 26, |
||||||
|
axisHeight: 40, |
||||||
|
squareSize: 10, |
||||||
|
squarePading: 4, |
||||||
|
taskNum: 25, |
||||||
|
nodesMax: 0 |
||||||
|
} |
||||||
|
// Margin configuration
|
||||||
|
this.config.margin = { |
||||||
|
top: this.config.barHeight / 2 + this.config.axisHeight, |
||||||
|
right: 0, |
||||||
|
bottom: 0, |
||||||
|
left: this.config.barHeight / 2 |
||||||
|
} |
||||||
|
// width
|
||||||
|
this.config.margin.width = 960 - this.config.margin.left - this.config.margin.right |
||||||
|
// bar width
|
||||||
|
this.config.barWidth = parseInt(this.config.margin.width * 0.9) |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* init |
||||||
|
*/ |
||||||
|
Tree.prototype.init = function ({ data, limit, selfTree }) { |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
this.selfTree = selfTree |
||||||
|
this.config.taskNum = limit |
||||||
|
this.duration = 400 |
||||||
|
this.i = 0 |
||||||
|
this.tree = d3.layout.tree().nodeSize([0, 46]) |
||||||
|
let tasks = this.tree.nodes(data) |
||||||
|
|
||||||
|
this.diagonal = d3.svg |
||||||
|
.diagonal() |
||||||
|
.projection(d => [d.y, d.x]) |
||||||
|
|
||||||
|
this.svg = d3.select('svg') |
||||||
|
.append('g') |
||||||
|
.attr('class', 'level') |
||||||
|
.attr('transform', 'translate(' + this.config.margin.left + ',' + this.config.margin.top + ')') |
||||||
|
|
||||||
|
data.x0 = 0 |
||||||
|
data.y0 = 0 |
||||||
|
|
||||||
|
this.squareNum = tasks[tasks.length === 1 ? 0 : 1].instances.length |
||||||
|
|
||||||
|
// Calculate the maximum node length
|
||||||
|
this.config.nodesMax = rtCountMethod(data.children) |
||||||
|
|
||||||
|
this.treeUpdate(this.root = data).then(() => { |
||||||
|
this.treeTooltip() |
||||||
|
selfTree.isLoading = false |
||||||
|
resolve() |
||||||
|
}) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* tasks |
||||||
|
*/ |
||||||
|
Tree.prototype.nodesClass = function (d) { |
||||||
|
let sclass = 'node' |
||||||
|
if (d.children === undefined && d._children === undefined) { |
||||||
|
sclass += ' leaf' |
||||||
|
} else { |
||||||
|
sclass += ' parent' |
||||||
|
if (d.children === undefined) { sclass += ' collapsed' } else { sclass += ' expanded' } |
||||||
|
} |
||||||
|
return sclass |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* toottip handle |
||||||
|
*/ |
||||||
|
Tree.prototype.treeTooltip = function () { |
||||||
|
$('rect.state').tooltip({ |
||||||
|
html: true, |
||||||
|
container: 'body' |
||||||
|
}) |
||||||
|
$('circle.task').tooltip({ |
||||||
|
html: true, |
||||||
|
container: 'body' |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* tree Expand hidden |
||||||
|
*/ |
||||||
|
Tree.prototype.treeToggles = function (clicked_d) { // eslint-disable-line
|
||||||
|
|
||||||
|
self.removeTooltip() |
||||||
|
|
||||||
|
d3.selectAll("[task_id='" + clicked_d.uuid + "']").each((d) => { |
||||||
|
if (clicked_d !== d && d.children) { // eslint-disable-line
|
||||||
|
d._children = d.children |
||||||
|
d.children = null |
||||||
|
self.treeUpdate(d) |
||||||
|
} |
||||||
|
}) |
||||||
|
if (clicked_d._children) { |
||||||
|
clicked_d.children = clicked_d._children |
||||||
|
clicked_d._children = null |
||||||
|
} else { |
||||||
|
clicked_d._children = clicked_d.children |
||||||
|
clicked_d.children = null |
||||||
|
} |
||||||
|
self.treeUpdate(clicked_d) |
||||||
|
self.treeTooltip() |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* update tree |
||||||
|
*/ |
||||||
|
Tree.prototype.treeUpdate = function (source) { |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
let tasks = this.tree.nodes(this.root) |
||||||
|
let height = Math.max(500, tasks.length * this.config.barHeight + this.config.margin.top + this.config.margin.bottom) |
||||||
|
let width = (this.config.nodesMax * 70) + (this.squareNum * (this.config.squareSize + this.config.squarePading)) + this.config.margin.left + this.config.margin.right + 50 |
||||||
|
|
||||||
|
d3.select('svg') |
||||||
|
.transition() |
||||||
|
.duration(this.duration) |
||||||
|
.attr('height', height) |
||||||
|
.attr('width', width) |
||||||
|
|
||||||
|
tasks.forEach((n, i) => { |
||||||
|
n.x = i * this.config.barHeight |
||||||
|
}) |
||||||
|
|
||||||
|
let task = this.svg.selectAll('g.node') |
||||||
|
.data(tasks, (d) => { |
||||||
|
return d.id || (d.id = ++this.i) |
||||||
|
}) |
||||||
|
|
||||||
|
let nodeEnter = task.enter() |
||||||
|
.append('g') |
||||||
|
.attr('class', this.nodesClass) |
||||||
|
.attr('transform', () => 'translate(' + source.y0 + ',' + source.x0 + ')') |
||||||
|
.style('opacity', 1e-6) |
||||||
|
|
||||||
|
// Node circle
|
||||||
|
nodeEnter.append('circle') |
||||||
|
.attr('r', (this.config.barHeight / 3)) |
||||||
|
.attr('class', 'task') |
||||||
|
.attr('data-toggle', 'tooltip') |
||||||
|
.attr('title', d => d.type ? d.type : '') |
||||||
|
.attr('height', this.config.barHeight) |
||||||
|
.attr('width', d => this.config.barWidth - d.y) |
||||||
|
.style('fill', d => d.type ? tasksType[d.type].color : '#fff') |
||||||
|
.attr('task_id', d => d.name) |
||||||
|
.on('click', this.treeToggles) |
||||||
|
|
||||||
|
// Node text
|
||||||
|
nodeEnter.append('text') |
||||||
|
.attr('dy', 3.5) |
||||||
|
.attr('dx', this.config.barHeight / 2) |
||||||
|
.text((d) => { |
||||||
|
return d.name |
||||||
|
}) |
||||||
|
|
||||||
|
// Right node information
|
||||||
|
nodeEnter.append('g') |
||||||
|
.attr('class', 'stateboxes') |
||||||
|
.attr('transform', (d, i) => 'translate(' + ((this.config.nodesMax * 60) - d.y) + ',0)') |
||||||
|
.selectAll('rect').data((d) => d.instances) |
||||||
|
.enter() |
||||||
|
.append('rect') |
||||||
|
.on('click', d => { |
||||||
|
this.removeTooltip() |
||||||
|
if (d.type === 'SUB_PROCESS') { |
||||||
|
this.selfTree._subProcessHandle(d.subflowId) |
||||||
|
} |
||||||
|
}) |
||||||
|
.attr('class', 'state') |
||||||
|
.style('fill', d => d.state && tasksState[d.state].color || '#ffffff') |
||||||
|
.attr('data-toggle', 'tooltip') |
||||||
|
.attr('rx', d => d.type ? 0 : 12) |
||||||
|
.attr('ry', d => d.type ? 0 : 12) |
||||||
|
.style('shape-rendering', d => d.type ? 'crispEdges' : 'auto') |
||||||
|
.attr('title', data => rtInstancesTooltip(data)) |
||||||
|
.attr('x', (d, i) => (i * (this.config.squareSize + this.config.squarePading))) |
||||||
|
.attr('y', -(this.config.squareSize / 2)) |
||||||
|
.attr('width', 10) |
||||||
|
.attr('height', 10) |
||||||
|
.on('mouseover', () => { |
||||||
|
d3.select(this).transition() |
||||||
|
}) |
||||||
|
.on('mouseout', () => { |
||||||
|
d3.select(this).transition() |
||||||
|
}) |
||||||
|
|
||||||
|
// Convert nodes to their new location。
|
||||||
|
nodeEnter.transition() |
||||||
|
.duration(this.duration) |
||||||
|
.attr('transform', d => 'translate(' + d.y + ',' + d.x + ')') |
||||||
|
.style('opacity', 1) |
||||||
|
|
||||||
|
// Node line
|
||||||
|
task.transition() |
||||||
|
.duration(this.duration) |
||||||
|
.attr('class', this.nodesClass) |
||||||
|
.attr('transform', d => 'translate(' + d.y + ',' + d.x + ')') |
||||||
|
.style('opacity', 1) |
||||||
|
|
||||||
|
|
||||||
|
// Convert the exit node to the new location of the parent node。
|
||||||
|
task.exit().transition() |
||||||
|
.duration(this.duration) |
||||||
|
.attr('transform', d => 'translate(' + source.y + ',' + source.x + ')') |
||||||
|
.style('opacity', 1e-6) |
||||||
|
.remove() |
||||||
|
|
||||||
|
// Update link
|
||||||
|
let link = this.svg.selectAll('path.link') |
||||||
|
.data(this.tree.links(tasks), d => d.target.id) |
||||||
|
|
||||||
|
// Enter any new links in the previous location of the parent node。
|
||||||
|
link.enter().insert('path', 'g') |
||||||
|
.attr('class', 'link') |
||||||
|
.attr('d', (d) => { |
||||||
|
let o = { x: source.x0, y: source.y0 } |
||||||
|
return this.diagonal({ source: o, target: o }) |
||||||
|
}) |
||||||
|
.transition() |
||||||
|
.duration(this.duration) |
||||||
|
.attr('d', this.diagonal) |
||||||
|
|
||||||
|
// Transition link
|
||||||
|
link.transition() |
||||||
|
.duration(this.duration) |
||||||
|
.attr('d', this.diagonal) |
||||||
|
|
||||||
|
// Convert the exit node to the new location of the parent node
|
||||||
|
link.exit().transition() |
||||||
|
.duration(this.duration) |
||||||
|
.attr('d', (d) => { |
||||||
|
let o = { x: source.x, y: source.y } |
||||||
|
return this.diagonal({ source: o, target: o }) |
||||||
|
}) |
||||||
|
.remove() |
||||||
|
|
||||||
|
// Hide the old position for a transition.
|
||||||
|
tasks.forEach((d) => { |
||||||
|
d.x0 = d.x |
||||||
|
d.y0 = d.y |
||||||
|
}) |
||||||
|
resolve() |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* reset |
||||||
|
*/ |
||||||
|
Tree.prototype.reset = function () { |
||||||
|
$('.d3-tree .tree').html('') |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Manually clear tooltip |
||||||
|
*/ |
||||||
|
Tree.prototype.removeTooltip = function () { |
||||||
|
$('body').find('.tooltip.fade.top.in').remove() |
||||||
|
} |
||||||
|
|
||||||
|
export default new Tree() |
@ -0,0 +1,72 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
import { formatDate } from '@/module/filter/filter' |
||||||
|
import { tasksState } from '@/conf/home/pages/dag/_source/config' |
||||||
|
|
||||||
|
/** |
||||||
|
* Node prompt dom |
||||||
|
*/ |
||||||
|
const rtInstancesTooltip = (data) => { |
||||||
|
let str = `<div style="text-align: left;">` |
||||||
|
str += `id : ${data.id}</br>` |
||||||
|
str += `host : ${data.host}</br>` |
||||||
|
str += `name : ${data.name}</br>` |
||||||
|
str += `state : ${data.state ? tasksState[data.state].desc : '-'}(${data.state})</br>` |
||||||
|
if (data.type) { |
||||||
|
str += `type : ${data.type}</br>` |
||||||
|
} |
||||||
|
str += `startTime : ${data.startTime ? formatDate(data.startTime) : 'null'}</br>` |
||||||
|
str += `endTime : ${data.endTime ? formatDate(data.endTime) : 'null'}</br>` |
||||||
|
str += `duration : ${data.duration}</br>` |
||||||
|
str += `</div>` |
||||||
|
return str |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Calculate the maximum node length |
||||||
|
* Easy to calculate the width dynamically |
||||||
|
*/ |
||||||
|
const rtCountMethod = list => { |
||||||
|
let arr = [] |
||||||
|
function count (list, t) { |
||||||
|
let toggle = false |
||||||
|
list.forEach(v => { |
||||||
|
if (v.children && v.children.length > 0) { |
||||||
|
if (!toggle) { |
||||||
|
toggle = true |
||||||
|
t += '*' |
||||||
|
arr.push(t) |
||||||
|
} |
||||||
|
count(v.children, t) |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
count(list, '*') |
||||||
|
let num = 6 |
||||||
|
arr.forEach(v => { |
||||||
|
if (v.length > num) { |
||||||
|
num = v.length |
||||||
|
} |
||||||
|
}) |
||||||
|
return num |
||||||
|
} |
||||||
|
|
||||||
|
export { |
||||||
|
rtInstancesTooltip, |
||||||
|
rtCountMethod |
||||||
|
} |
After Width: | Height: | Size: 5.0 KiB |
@ -0,0 +1,248 @@ |
|||||||
|
<template> |
||||||
|
<div class="main-layout-box"> |
||||||
|
<m-secondary-menu :type="'projects'"></m-secondary-menu> |
||||||
|
<m-list-construction :title="$t('树形图')"> |
||||||
|
<template slot="conditions"></template> |
||||||
|
<template slot="content"> |
||||||
|
<div class="tree-view-index-model"> |
||||||
|
<div class="tree-limit-select"> |
||||||
|
<x-select v-model="limit" style="width: 70px;" @on-change="_onChangeSelect"> |
||||||
|
<x-option |
||||||
|
v-for="city in [{value:25},{value:50},{value:75},{value:100}]" |
||||||
|
:key="city.value" |
||||||
|
:value="city.value" |
||||||
|
:label="city.value"> |
||||||
|
</x-option> |
||||||
|
</x-select> |
||||||
|
<x-button |
||||||
|
@click="_rtTasksDag" |
||||||
|
v-if="$route.query.subProcessIds" |
||||||
|
type="primary" |
||||||
|
size="default" |
||||||
|
icon="fa fa-reply"> |
||||||
|
返回上一节点 |
||||||
|
</x-button> |
||||||
|
</div> |
||||||
|
<div class="tasks-color"> |
||||||
|
<div class="toolbar-color-sp"> |
||||||
|
<a href="javascript:"> |
||||||
|
<span>节点类型</span> |
||||||
|
</a> |
||||||
|
<a href="javascript:" v-for="(k,v) in tasksType"> |
||||||
|
<i class="fa fa-circle" :style="{color:k.color}"></i> |
||||||
|
<span>{{v}}</span> |
||||||
|
</a> |
||||||
|
</div> |
||||||
|
<div class="state-tasks-color-sp"> |
||||||
|
<a href="javascript:"> |
||||||
|
<span>任务状态</span> |
||||||
|
</a> |
||||||
|
<a href="javascript:" v-for="(item) in tasksState"> |
||||||
|
<i class="fa fa-square" :style="{color:item.color}"></i> |
||||||
|
<span>{{item.desc}}</span> |
||||||
|
</a> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="tree-model" v-show="!isNodata"> |
||||||
|
<div class="d3-tree"> |
||||||
|
<svg class='tree' width="100%"></svg> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<m-no-data v-if="isNodata"></m-no-data> |
||||||
|
</div> |
||||||
|
<m-spin :is-spin="isLoading"></m-spin> |
||||||
|
</template> |
||||||
|
</m-list-construction> |
||||||
|
</div> |
||||||
|
|
||||||
|
</template> |
||||||
|
<script> |
||||||
|
import _ from 'lodash' |
||||||
|
import { mapActions } from 'vuex' |
||||||
|
import Tree from './_source/tree' |
||||||
|
import { uuid } from '@/module/util' |
||||||
|
import mSpin from '@/module/components/spin/spin' |
||||||
|
import mNoData from '@/module/components/noData/noData' |
||||||
|
import { tasksType, tasksState } from '@/conf/home/pages/dag/_source/config' |
||||||
|
import mSecondaryMenu from '@/module/components/secondaryMenu/secondaryMenu' |
||||||
|
import mListConstruction from '@/module/components/listConstruction/listConstruction' |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'tree-view-index-index', |
||||||
|
data () { |
||||||
|
return { |
||||||
|
// limit |
||||||
|
limit: 25, |
||||||
|
// loading |
||||||
|
isLoading: true, |
||||||
|
// node type |
||||||
|
tasksType: tasksType, |
||||||
|
// node state |
||||||
|
tasksState: tasksState, |
||||||
|
// tree data |
||||||
|
treeData: {}, |
||||||
|
// is data |
||||||
|
isNodata: false |
||||||
|
} |
||||||
|
}, |
||||||
|
props: {}, |
||||||
|
methods: { |
||||||
|
...mapActions('dag', ['getViewTree']), |
||||||
|
/** |
||||||
|
* get tree data |
||||||
|
*/ |
||||||
|
_getViewTree () { |
||||||
|
this.isLoading = true |
||||||
|
|
||||||
|
Tree.reset() |
||||||
|
|
||||||
|
this.getViewTree({ |
||||||
|
processId: this.$route.params.id, |
||||||
|
limit: this.limit |
||||||
|
}).then(res => { |
||||||
|
let data = _.cloneDeep(res) |
||||||
|
this.treeData = data |
||||||
|
if (!this.treeData.children) { |
||||||
|
this.isLoading = false |
||||||
|
this.isNodata = true |
||||||
|
return |
||||||
|
} |
||||||
|
let recursiveChildren = (children) => { |
||||||
|
if (children.length) { |
||||||
|
_.map(children, v => { |
||||||
|
v.uuid = `${uuid('uuid_')}${uuid() + uuid()}` |
||||||
|
if (v.children.length) { |
||||||
|
recursiveChildren(v.children) |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
recursiveChildren(data.children) |
||||||
|
// init tree |
||||||
|
Tree.init({ |
||||||
|
data: _.cloneDeep(data), |
||||||
|
limit: this.limit, |
||||||
|
selfTree: this |
||||||
|
}).then(() => { |
||||||
|
setTimeout(() => { |
||||||
|
// this.isLoading = false |
||||||
|
}, 100) |
||||||
|
}) |
||||||
|
}).catch(e => { |
||||||
|
this.isLoading = false |
||||||
|
if (!e.data) { |
||||||
|
this.isNodata = true |
||||||
|
} |
||||||
|
}) |
||||||
|
}, |
||||||
|
|
||||||
|
/** |
||||||
|
* Return to the previous child node |
||||||
|
*/ |
||||||
|
_rtTasksDag () { |
||||||
|
let getIds = this.$route.query.subProcessIds |
||||||
|
let idsArr = getIds.split(',') |
||||||
|
let ids = idsArr.slice(0, idsArr.length - 1) |
||||||
|
let id = idsArr[idsArr.length - 1] |
||||||
|
let query = {} |
||||||
|
|
||||||
|
if (id !== idsArr[0]) { |
||||||
|
query = { subProcessIds: ids.join(',') } |
||||||
|
} |
||||||
|
this.$router.push({ path: `/projects/definition/tree/${id}`, query: query }) |
||||||
|
}, |
||||||
|
/** |
||||||
|
* Subprocess processing |
||||||
|
* @param subProcessId 子流程Id |
||||||
|
*/ |
||||||
|
_subProcessHandle (subProcessId) { |
||||||
|
let subProcessIds = [] |
||||||
|
let getIds = this.$route.query.subProcessIds |
||||||
|
if (getIds) { |
||||||
|
let newId = getIds.split(',') |
||||||
|
newId.push(this.$route.params.id) |
||||||
|
subProcessIds = newId |
||||||
|
} else { |
||||||
|
subProcessIds.push(this.$route.params.id) |
||||||
|
} |
||||||
|
this.$router.push({ path: `/projects/definition/tree/${subProcessId}`, query: { subProcessIds: subProcessIds.join(',') } }) |
||||||
|
}, |
||||||
|
_onChangeSelect (o) { |
||||||
|
this.limit = o.value |
||||||
|
this._getViewTree() |
||||||
|
} |
||||||
|
}, |
||||||
|
watch: { |
||||||
|
'$route.params.id' () { |
||||||
|
this._getViewTree() |
||||||
|
} |
||||||
|
}, |
||||||
|
created () { |
||||||
|
this._getViewTree() |
||||||
|
}, |
||||||
|
mounted () { |
||||||
|
}, |
||||||
|
components: { mSpin, mSecondaryMenu, mListConstruction, mNoData } |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style lang="scss" rel="stylesheet/scss"> |
||||||
|
|
||||||
|
.tree-view-index-model { |
||||||
|
background: url('img/dag_bg.png'); |
||||||
|
position: relative; |
||||||
|
.tree-limit-select { |
||||||
|
position: absolute; |
||||||
|
right: 20px; |
||||||
|
top: 22px; |
||||||
|
z-index: 1; |
||||||
|
} |
||||||
|
.tasks-color { |
||||||
|
min-height: 76px; |
||||||
|
background: #fff; |
||||||
|
padding-left: 20px; |
||||||
|
position: relative; |
||||||
|
padding-bottom: 10px; |
||||||
|
.toolbar-color-sp { |
||||||
|
padding: 12px 0; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
.tree-model { |
||||||
|
width: calc(100%); |
||||||
|
height: calc(100vh - 224px); |
||||||
|
overflow-x: scroll; |
||||||
|
} |
||||||
|
.d3-tree { |
||||||
|
padding-left: 30px; |
||||||
|
.node { |
||||||
|
text { |
||||||
|
font: 11px sans-serif; |
||||||
|
pointer-events: none; |
||||||
|
} |
||||||
|
} |
||||||
|
rect { |
||||||
|
cursor: pointer; |
||||||
|
&.state { |
||||||
|
stroke: #666; |
||||||
|
shape-rendering: crispEdges; |
||||||
|
} |
||||||
|
} |
||||||
|
path { |
||||||
|
&.link{ |
||||||
|
fill: none; |
||||||
|
stroke: #666; |
||||||
|
stroke-width: 2px; |
||||||
|
} |
||||||
|
} |
||||||
|
circle { |
||||||
|
stroke: #666; |
||||||
|
fill: #0097e0; |
||||||
|
stroke-width: 1.5px; |
||||||
|
cursor: pointer; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
</style> |
@ -0,0 +1,265 @@ |
|||||||
|
<template> |
||||||
|
<div> |
||||||
|
<div class="conditions-box"> |
||||||
|
<!--<m-conditions @on-conditions="_onConditions"></m-conditions>--> |
||||||
|
</div> |
||||||
|
<div class="list-model" v-if="!isLoading"> |
||||||
|
<template v-if="list.length"> |
||||||
|
<div class="table-box"> |
||||||
|
<table> |
||||||
|
<tr> |
||||||
|
<th> |
||||||
|
<span>{{$t('编号')}}</span> |
||||||
|
</th> |
||||||
|
<th> |
||||||
|
<span>{{$t('流程名称')}}</span> |
||||||
|
</th> |
||||||
|
<th> |
||||||
|
<span>{{$t('开始时间')}}</span> |
||||||
|
</th> |
||||||
|
<th> |
||||||
|
<span>{{$t('结束时间')}}</span> |
||||||
|
</th> |
||||||
|
<th> |
||||||
|
<span>{{$t('crontab')}}</span> |
||||||
|
</th> |
||||||
|
<th> |
||||||
|
<span>{{$t('失败策略')}}</span> |
||||||
|
</th> |
||||||
|
<th> |
||||||
|
<span>{{$t('状态')}}</span> |
||||||
|
</th> |
||||||
|
<th> |
||||||
|
<span>{{$t('创建时间')}}</span> |
||||||
|
</th> |
||||||
|
<th> |
||||||
|
<span>{{$t('更新时间')}}</span> |
||||||
|
</th> |
||||||
|
<th width="80"> |
||||||
|
<span>{{$t('操作')}}</span> |
||||||
|
</th> |
||||||
|
</tr> |
||||||
|
<tr v-for="(item, $index) in list" :key="item.id"> |
||||||
|
<td> |
||||||
|
<span>{{parseInt(pageNo === 1 ? ($index + 1) : (($index + 1) + (pageSize * (pageNo - 1))))}}</span> |
||||||
|
</td> |
||||||
|
<td> |
||||||
|
<span><a href="javascript:">{{item.processDefinitionName}}</a></span> |
||||||
|
</td> |
||||||
|
<td> |
||||||
|
<span>{{item.startTime | formatDate}}</span> |
||||||
|
</td> |
||||||
|
<td> |
||||||
|
<span>{{item.endTime | formatDate}}</span> |
||||||
|
</td> |
||||||
|
<td> |
||||||
|
<span>{{item.crontab}}</span> |
||||||
|
</td> |
||||||
|
<td> |
||||||
|
<span>{{item.failureStrategy}}</span> |
||||||
|
</td> |
||||||
|
<td> |
||||||
|
<span>{{_rtReleaseState(item.releaseState)}}</span> |
||||||
|
</td> |
||||||
|
<td> |
||||||
|
<span>{{item.createTime | formatDate}}</span> |
||||||
|
</td> |
||||||
|
<td> |
||||||
|
<span>{{item.updateTime | formatDate}}</span> |
||||||
|
</td> |
||||||
|
<td> |
||||||
|
<x-button |
||||||
|
type="info" |
||||||
|
shape="circle" |
||||||
|
size="xsmall" |
||||||
|
data-toggle="tooltip" |
||||||
|
:title="$t('编辑')" |
||||||
|
@click="_editTiming(item)" |
||||||
|
icon="iconfont icon-bianji" |
||||||
|
:disabled="item.releaseState === 'ONLINE'" > |
||||||
|
</x-button> |
||||||
|
<x-button |
||||||
|
type="success" |
||||||
|
shape="circle" |
||||||
|
size="xsmall" |
||||||
|
data-toggle="tooltip" |
||||||
|
:title="$t('上线')" |
||||||
|
@click="_online(item)" |
||||||
|
icon="iconfont icon-erji-xiaxianjilu-copy" |
||||||
|
v-if="item.releaseState === 'OFFLINE'"> |
||||||
|
</x-button> |
||||||
|
<x-button |
||||||
|
type="warning" |
||||||
|
shape="circle" |
||||||
|
size="xsmall" |
||||||
|
data-toggle="tooltip" |
||||||
|
:title="$t('下线')" |
||||||
|
icon="iconfont icon-erji-xiaxianjilu" |
||||||
|
@click="_offline(item)" |
||||||
|
v-if="item.releaseState === 'ONLINE'"> |
||||||
|
</x-button> |
||||||
|
</td> |
||||||
|
</tr> |
||||||
|
</table> |
||||||
|
</div> |
||||||
|
<div class="page-box"> |
||||||
|
<x-page :current="pageNo" :total="total" show-elevator @on-change="_page"></x-page> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<template v-if="!list.length"> |
||||||
|
<m-no-data></m-no-data> |
||||||
|
</template> |
||||||
|
</div> |
||||||
|
<m-spin :is-spin="isLoading"></m-spin> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<script> |
||||||
|
import _ from 'lodash' |
||||||
|
import { mapActions } from 'vuex' |
||||||
|
import '@/module/filter/formatDate' |
||||||
|
import mSpin from '@/module/components/spin/spin' |
||||||
|
import mTiming from '../../pages/list/_source/timing' |
||||||
|
import mNoData from '@/module/components/noData/noData' |
||||||
|
import { publishStatus } from '@/conf/home/pages/dag/_source/config' |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'list', |
||||||
|
data () { |
||||||
|
return { |
||||||
|
isLoading: false, |
||||||
|
total: null, |
||||||
|
pageNo: 1, |
||||||
|
pageSize: 10, |
||||||
|
list: [] |
||||||
|
} |
||||||
|
}, |
||||||
|
props: { |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
...mapActions('dag', ['getScheduleList', 'scheduleOffline', 'scheduleOnline', 'getReceiver']), |
||||||
|
/** |
||||||
|
* return state |
||||||
|
*/ |
||||||
|
_rtReleaseState (code) { |
||||||
|
return _.filter(publishStatus, v => v.code === code)[0].desc |
||||||
|
}, |
||||||
|
/** |
||||||
|
* page |
||||||
|
*/ |
||||||
|
_page (val) { |
||||||
|
this.pageNo = val |
||||||
|
this._getScheduleList() |
||||||
|
}, |
||||||
|
/** |
||||||
|
* Inquire list |
||||||
|
*/ |
||||||
|
_getScheduleList (flag) { |
||||||
|
this.isLoading = !flag |
||||||
|
this.getScheduleList({ |
||||||
|
processDefinitionId: this.$route.params.id, |
||||||
|
searchVal: '', |
||||||
|
pageNo: this.pageNo, |
||||||
|
pageSize: this.pageSize |
||||||
|
}).then(res => { |
||||||
|
this.list = res.data.totalList |
||||||
|
this.total = res.data.total |
||||||
|
this.isLoading = false |
||||||
|
}).catch(e => { |
||||||
|
this.isLoading = false |
||||||
|
}) |
||||||
|
}, |
||||||
|
/** |
||||||
|
* search |
||||||
|
*/ |
||||||
|
_onConditions (o) { |
||||||
|
this.searchVal = o.searchVal |
||||||
|
this.pageNo = 1 |
||||||
|
this._getScheduleList('false') |
||||||
|
}, |
||||||
|
/** |
||||||
|
* online |
||||||
|
*/ |
||||||
|
_online (item) { |
||||||
|
this.pageNo = 1 |
||||||
|
this.scheduleOnline({ |
||||||
|
id: item.id |
||||||
|
}).then(res => { |
||||||
|
this.$message.success(res.msg) |
||||||
|
this._getScheduleList('false') |
||||||
|
}).catch(e => { |
||||||
|
this.$message.error(e.msg || '') |
||||||
|
}) |
||||||
|
}, |
||||||
|
/** |
||||||
|
* offline |
||||||
|
*/ |
||||||
|
_offline (item) { |
||||||
|
this.pageNo = 1 |
||||||
|
this.scheduleOffline({ |
||||||
|
id: item.id |
||||||
|
}).then(res => { |
||||||
|
this.$message.success(res.msg) |
||||||
|
this._getScheduleList('false') |
||||||
|
}).catch(e => { |
||||||
|
this.$message.error(e.msg || '') |
||||||
|
}) |
||||||
|
}, |
||||||
|
/** |
||||||
|
* get email |
||||||
|
*/ |
||||||
|
_getReceiver (id) { |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
this.getReceiver({ processDefinitionId: id }).then(res => { |
||||||
|
resolve({ |
||||||
|
receivers: res.receivers && res.receivers.split(',') || [], |
||||||
|
receiversCc: res.receiversCc && res.receiversCc.split(',') || [] |
||||||
|
}) |
||||||
|
}) |
||||||
|
}) |
||||||
|
}, |
||||||
|
/** |
||||||
|
* timing |
||||||
|
*/ |
||||||
|
_editTiming (item) { |
||||||
|
let self = this |
||||||
|
this._getReceiver(item.processDefinitionId).then(res => { |
||||||
|
let modal = this.$modal.dialog({ |
||||||
|
closable: false, |
||||||
|
showMask: true, |
||||||
|
escClose: true, |
||||||
|
className: 'v-modal-custom', |
||||||
|
transitionName: 'opacityp', |
||||||
|
render (h) { |
||||||
|
return h(mTiming, { |
||||||
|
on: { |
||||||
|
onUpdate () { |
||||||
|
self.pageNo = 1 |
||||||
|
self._getScheduleList('false') |
||||||
|
modal.remove() |
||||||
|
}, |
||||||
|
close () { |
||||||
|
modal.remove() |
||||||
|
} |
||||||
|
}, |
||||||
|
props: { |
||||||
|
item: item, |
||||||
|
receiversD: res.receivers, |
||||||
|
receiversCcD: res.receiversCc |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
}) |
||||||
|
}) |
||||||
|
} |
||||||
|
}, |
||||||
|
watch: {}, |
||||||
|
created () { |
||||||
|
this._getScheduleList() |
||||||
|
}, |
||||||
|
mounted () {}, |
||||||
|
components: { mSpin, mNoData } |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style lang="scss" rel="stylesheet/scss"> |
||||||
|
</style> |