Browse Source

Initial module escheduler-ui commit

pull/1/head
ligang 6 years ago
parent
commit
c7d13d2557
  1. 27
      escheduler-ui/.babelrc
  2. 21
      escheduler-ui/.editorconfig
  3. 6
      escheduler-ui/.env
  4. 6
      escheduler-ui/.eslintrc
  5. 115
      escheduler-ui/build/combo.js
  6. 208
      escheduler-ui/build/config.js
  7. 87
      escheduler-ui/build/i18n.js
  8. 112
      escheduler-ui/build/webpack.config.dev.js
  9. 132
      escheduler-ui/build/webpack.config.prod.js
  10. 88
      escheduler-ui/build/webpack.config.test.js
  11. 97
      escheduler-ui/package.json
  12. 5
      escheduler-ui/src/combo/1.0.0/3rd.css
  13. 10783
      escheduler-ui/src/combo/1.0.0/3rd.js
  14. 8
      escheduler-ui/src/combo/1.0.0/base.css
  15. 14
      escheduler-ui/src/combo/1.0.0/es5.js
  16. 1
      escheduler-ui/src/combo/1.0.0/local.js
  17. BIN
      escheduler-ui/src/font/awesome/FontAwesome.otf
  18. 2337
      escheduler-ui/src/font/awesome/font-awesome.css
  19. BIN
      escheduler-ui/src/font/awesome/fontawesome-webfont.eot
  20. 2671
      escheduler-ui/src/font/awesome/fontawesome-webfont.svg
  21. BIN
      escheduler-ui/src/font/awesome/fontawesome-webfont.ttf
  22. BIN
      escheduler-ui/src/font/awesome/fontawesome-webfont.woff
  23. BIN
      escheduler-ui/src/font/awesome/fontawesome-webfont.woff2
  24. 539
      escheduler-ui/src/font/demo.css
  25. 1964
      escheduler-ui/src/font/demo_index.html
  26. 329
      escheduler-ui/src/font/iconfont.css
  27. BIN
      escheduler-ui/src/font/iconfont.eot
  28. 1
      escheduler-ui/src/font/iconfont.js
  29. 260
      escheduler-ui/src/font/iconfont.svg
  30. BIN
      escheduler-ui/src/font/iconfont.ttf
  31. BIN
      escheduler-ui/src/font/iconfont.woff
  32. BIN
      escheduler-ui/src/font/iconfont.woff2
  33. BIN
      escheduler-ui/src/images/favicon.ico
  34. 15
      escheduler-ui/src/js/conf/home/App.vue
  35. 85
      escheduler-ui/src/js/conf/home/index.js
  36. 284
      escheduler-ui/src/js/conf/home/pages/dag/_source/config.js
  37. 119
      escheduler-ui/src/js/conf/home/pages/dag/_source/dag.js
  38. 506
      escheduler-ui/src/js/conf/home/pages/dag/_source/dag.scss
  39. 478
      escheduler-ui/src/js/conf/home/pages/dag/_source/dag.vue
  40. 101
      escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/_source/selectInput.vue
  41. 113
      escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/_source/timeoutAlarm.vue
  42. 554
      escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/formModel.vue
  43. 357
      escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/log.vue
  44. 199
      escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/_source/commcon.js
  45. 133
      escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/_source/datasource.vue
  46. 247
      escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/_source/dependItemList.vue
  47. 46
      escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/_source/listBox.vue
  48. 209
      escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/_source/localParams.vue
  49. 100
      escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/_source/resources.vue
  50. 57
      escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/_source/sqlType.vue
  51. 116
      escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/_source/udfs.vue
  52. 237
      escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/dependent.vue
  53. 264
      escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/mr.vue
  54. 134
      escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/procedure.vue
  55. 161
      escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/python.vue
  56. 165
      escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/shell.vue
  57. 400
      escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/spark.vue
  58. 267
      escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/sql.vue
  59. 102
      escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/sub_process.vue
  60. 107
      escheduler-ui/src/js/conf/home/pages/dag/_source/jumpAffirm/index.js
  61. 39
      escheduler-ui/src/js/conf/home/pages/dag/_source/jumpAffirm/jumpAffirm.vue
  62. 122
      escheduler-ui/src/js/conf/home/pages/dag/_source/plugIn/downChart.js
  63. 40
      escheduler-ui/src/js/conf/home/pages/dag/_source/plugIn/dragZoom.js
  64. 761
      escheduler-ui/src/js/conf/home/pages/dag/_source/plugIn/jsPlumbHandle.js
  65. 131
      escheduler-ui/src/js/conf/home/pages/dag/_source/plugIn/util.js
  66. 187
      escheduler-ui/src/js/conf/home/pages/dag/_source/udp/udp.vue
  67. 24
      escheduler-ui/src/js/conf/home/pages/dag/_source/variable/index.vue
  68. 141
      escheduler-ui/src/js/conf/home/pages/dag/_source/variable/variablesView.vue
  69. 82
      escheduler-ui/src/js/conf/home/pages/dag/definitionDetails.vue
  70. BIN
      escheduler-ui/src/js/conf/home/pages/dag/img/dag_bg.png
  71. BIN
      escheduler-ui/src/js/conf/home/pages/dag/img/toolbar_DEPENDENT.png
  72. BIN
      escheduler-ui/src/js/conf/home/pages/dag/img/toolbar_MR.png
  73. BIN
      escheduler-ui/src/js/conf/home/pages/dag/img/toolbar_PROCEDURE.png
  74. BIN
      escheduler-ui/src/js/conf/home/pages/dag/img/toolbar_PYTHON.png
  75. BIN
      escheduler-ui/src/js/conf/home/pages/dag/img/toolbar_SHELL.png
  76. BIN
      escheduler-ui/src/js/conf/home/pages/dag/img/toolbar_SPARK.png
  77. BIN
      escheduler-ui/src/js/conf/home/pages/dag/img/toolbar_SQL.png
  78. BIN
      escheduler-ui/src/js/conf/home/pages/dag/img/toolbar_SUB_PROCESS.png
  79. 65
      escheduler-ui/src/js/conf/home/pages/dag/index.vue
  80. 92
      escheduler-ui/src/js/conf/home/pages/dag/instanceDetails.vue
  81. 8
      escheduler-ui/src/js/conf/home/pages/datasource/index.vue
  82. 337
      escheduler-ui/src/js/conf/home/pages/datasource/pages/list/_source/createDataSource.vue
  83. 160
      escheduler-ui/src/js/conf/home/pages/datasource/pages/list/_source/list.vue
  84. 125
      escheduler-ui/src/js/conf/home/pages/datasource/pages/list/index.vue
  85. 16
      escheduler-ui/src/js/conf/home/pages/home/index.vue
  86. 40
      escheduler-ui/src/js/conf/home/pages/projects/index.vue
  87. 8
      escheduler-ui/src/js/conf/home/pages/projects/pages/definition/index.vue
  88. 14
      escheduler-ui/src/js/conf/home/pages/projects/pages/definition/pages/create/index.vue
  89. 14
      escheduler-ui/src/js/conf/home/pages/projects/pages/definition/pages/details/index.vue
  90. 338
      escheduler-ui/src/js/conf/home/pages/projects/pages/definition/pages/list/_source/email.vue
  91. 238
      escheduler-ui/src/js/conf/home/pages/projects/pages/definition/pages/list/_source/list.vue
  92. 298
      escheduler-ui/src/js/conf/home/pages/projects/pages/definition/pages/list/_source/start.vue
  93. 323
      escheduler-ui/src/js/conf/home/pages/projects/pages/definition/pages/list/_source/timing.vue
  94. 60
      escheduler-ui/src/js/conf/home/pages/projects/pages/definition/pages/list/_source/util.js
  95. 147
      escheduler-ui/src/js/conf/home/pages/projects/pages/definition/pages/list/index.vue
  96. 279
      escheduler-ui/src/js/conf/home/pages/projects/pages/definition/pages/tree/_source/tree.js
  97. 72
      escheduler-ui/src/js/conf/home/pages/projects/pages/definition/pages/tree/_source/util.js
  98. BIN
      escheduler-ui/src/js/conf/home/pages/projects/pages/definition/pages/tree/img/dag_bg.png
  99. 248
      escheduler-ui/src/js/conf/home/pages/projects/pages/definition/pages/tree/index.vue
  100. 265
      escheduler-ui/src/js/conf/home/pages/projects/pages/definition/timing/_source/list.vue
  101. Some files were not shown because too many files have changed in this diff Show More

27
escheduler-ui/.babelrc

@ -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
}

21
escheduler-ui/.editorconfig

@ -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

6
escheduler-ui/.env

@ -0,0 +1,6 @@
# 后端接口地址
API_BASE = http://192.168.xx.xx:12345
# 本地开发如需ip访问项目把"#"号去掉
#DEV_HOST = 192.168.xx.xx

6
escheduler-ui/.eslintrc

@ -0,0 +1,6 @@
globals:
$: true
expect: true
rules:
"no-new": "off"
"no-labels": [2, {"allowLoop": true}]

115
escheduler-ui/build/combo.js

@ -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' + ']下载完毕')
}
})
})

208
escheduler-ui/build/config.js

@ -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
}

87
escheduler-ui/build/i18n.js

@ -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文件成功')
}
})

112
escheduler-ui/build/webpack.config.dev.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

132
escheduler-ui/build/webpack.config.prod.js

@ -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

88
escheduler-ui/build/webpack.config.test.js

@ -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

97
escheduler-ui/package.json

@ -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"
}
}

5
escheduler-ui/src/combo/1.0.0/3rd.css

File diff suppressed because one or more lines are too long

10783
escheduler-ui/src/combo/1.0.0/3rd.js

File diff suppressed because one or more lines are too long

8
escheduler-ui/src/combo/1.0.0/base.css

File diff suppressed because one or more lines are too long

14
escheduler-ui/src/combo/1.0.0/es5.js

File diff suppressed because one or more lines are too long

1
escheduler-ui/src/combo/1.0.0/local.js

@ -0,0 +1 @@
Not found

BIN
escheduler-ui/src/font/awesome/FontAwesome.otf

Binary file not shown.

2337
escheduler-ui/src/font/awesome/font-awesome.css vendored

File diff suppressed because it is too large Load Diff

BIN
escheduler-ui/src/font/awesome/fontawesome-webfont.eot

Binary file not shown.

2671
escheduler-ui/src/font/awesome/fontawesome-webfont.svg

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 434 KiB

BIN
escheduler-ui/src/font/awesome/fontawesome-webfont.ttf

Binary file not shown.

BIN
escheduler-ui/src/font/awesome/fontawesome-webfont.woff

Binary file not shown.

BIN
escheduler-ui/src/font/awesome/fontawesome-webfont.woff2

Binary file not shown.

539
escheduler-ui/src/font/demo.css

@ -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;
}

1964
escheduler-ui/src/font/demo_index.html

File diff suppressed because it is too large Load Diff

329
escheduler-ui/src/font/iconfont.css

File diff suppressed because one or more lines are too long

BIN
escheduler-ui/src/font/iconfont.eot

Binary file not shown.

1
escheduler-ui/src/font/iconfont.js

File diff suppressed because one or more lines are too long

260
escheduler-ui/src/font/iconfont.svg

@ -0,0 +1,260 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
<!--
2013-9-30: Created.
-->
<svg>
<metadata>
Created by iconfont
</metadata>
<defs>
<font id="iconfont" horiz-adv-x="1024" >
<font-face
font-family="iconfont"
font-weight="500"
font-stretch="normal"
units-per-em="1024"
ascent="896"
descent="-128"
/>
<missing-glyph />
<glyph glyph-name="bianjixiugai" unicode="&#58881;" d="M765.27521057 436.59767761c-13.25783386 0-23.02761841-10.75946045-23.02761841-24.0173767v-293.80471875c0-31.60263977-24.42062989-58.45415955-55.95578613-58.45415955h-428.473125c-31.53515625 0-68.20112 26.85151977-68.20111999 58.45415955V548.71265625c0 31.6245575 36.66687012 65.32058716 68.20111999 65.32058716h244.91615625c13.25783386 0 23.94981079 9.81362 23.94981079 23.07153625 0 13.28065796-10.69197693 23.07153625-23.94981079 23.07153626H257.818625c-62.97918091 0-114.25388489-48.21355591-114.25388489-111.4627533v-429.93703124c0-63.22727966 51.27470398-104.59714966 114.25388489-104.59714966h428.473125c63.0247467 0 102.009375 41.36987 102.009375 104.59714966V412.58034375C788.30109864 425.83821716 778.51022034 436.59767761 765.27521057 436.59767761zM859.67559204 697.17973023l-35.09068909 35.18017272c-26.69537659 26.7856842-73.60285034 26.7856842-100.2763092 0l-66.28752136-78.0595642L304.74888 315.47909546000005v-8.262l-0.27001648-1.41748353-44.43274841-150.91984862 32.61513977-29.17100831 142.54653626 50.35160523 1.80054931-0.38224182h6.99975l337.80964966 354.35308227 77.85703125 63.69974671C887.31689148 621.43800659 887.31689148 669.42628784 859.67559204 697.17973023zM322.80084534 188.0356842l20.7528717 66.2183075 41.46100158-41.59432068L322.80084534 188.0356842zM427.19554443 237.41870727000003l-61.04366455 61.19972534 315.81727295 314.78367921 59.08441772-59.26503296L427.19554443 237.41870727000003zM826.25048523 630.10333557l-47.0651825-47.17831421-68.5158783 68.74115296 47.04326478 47.1783142c4.4558075 4.43388977 10.37647705 6.88752136 16.72314147 6.88752137 6.3475708 0 12.28925171-2.45363159 16.72396546-6.88752137l35.04602967-35.1809967C835.45658875 654.39064636 835.45658875 639.35500488 826.25048523 630.10333557z" horiz-adv-x="1024" />
<glyph glyph-name="shibai" unicode="&#58918;" d="M512.61293427 778.23780703c-217.56339229 0-393.93291357-176.36952128-393.93291357-393.93291357 0-217.56429141 176.36952128-393.93291357 393.93291357-393.93291357 217.56429141 0 393.93291357 176.36862217 393.93291358 393.93291357C906.54584786 601.86828487 730.17722568 778.23780703 512.61293427 778.23780703zM669.04837138 266.92277842c10.78009102-10.78728662 10.78009102-28.2750293 0-39.04702647-10.79538047-10.78728662-28.2750293-10.78728662-39.07041064 0l-117.17255741 117.17255742-117.18155128-117.17255742c-10.78728662-10.78728662-28.26693545-10.78728662-39.06321504 0-10.78009102 10.77199629-10.78009102 28.25973984 0 39.04702647l117.188746 117.20493545L356.56063789 501.30116953c-10.78009102 10.77199629-10.78009102 28.2750293 0 39.06231592 10.79538047 10.77199629 28.2750293 10.77199629 39.06321503 0l117.18155128-117.188746 117.17255742 117.188746c10.79538047 10.77199629 28.2750293 10.77199629 39.07041065 0 10.78009102-10.78728662 10.78009102-28.29121875 0-39.06231592L551.85962539 384.12771299 669.04837138 266.92277842z" horiz-adv-x="1024" />
<glyph glyph-name="dengdai" unicode="&#58922;" d="M511.71354424 778.23780703c-217.56429141 0-393.93291357-176.35333271-393.93291357-393.93291357 0-217.54810195 176.36862217-393.93291357 393.93291357-393.93291357s393.93291357 176.38481075 393.93291357 393.93291357C905.64645781 601.88447432 729.27783565 778.23780703 511.71354424 778.23780703zM653.12466787 181.98616522999998c-12.80641729-12.92063994-33.83685879-12.92063994-46.63698047 0L490.04363604 299.06158857c-8.6953043 8.75106651-7.90923779 20.93330742-7.9092378 39.46344346 0 18.56251494-4.20105146 233.09676035-4.20105146 233.09676035 0 18.4006248 14.72391738 33.30801739 32.88350478 33.30801739 18.1604874 0 32.88350479-14.90739258 32.88350479-33.30801738l0-233.09676036c0-0.96144785 109.68063662-109.7040208 109.68063662-109.7040208C666.18021552 215.90217041000005 665.92388955 194.93648497000004 653.12466787 181.98616522999998z" horiz-adv-x="1024" />
<glyph glyph-name="shuaxin1" unicode="&#59074;" d="M801.28338945 349.07168168c0-159.52050352-129.76288594-289.28338945-289.28338945-289.28338946s-289.28338945 129.76288594-289.28338945 289.28338946c0 154.15268994 121.28848945 280.14846328 273.40012441 288.46696728l0-87.5757252c0-2.85586963 1.53802354-5.5253127 4.017825-6.96851542 1.25516865-0.72160137 2.63730059-1.06713457 4.017825-1.06713458s2.76265635 0.3455332 4.017825 1.06713458l208.80153632 120.5347456c2.47980146 1.44320273 4.017825 4.1126458 4.017825 6.96851544s-1.53802354 5.5253127-4.017825 6.96851542l-208.80153632 120.53474561c-2.5103373 1.44320273-5.5253127 1.44320273-8.03565 0-2.47980146-1.44320273-4.017825-4.1126458-4.017825-6.96851543l0-89.20856865C308.56627724 693.442664 158.4314123 538.6631935 158.4314123 349.07168168c0-194.95932627 158.60926143-353.5685877 353.5685877-353.56858769s353.5685877 158.60926143 353.5685877 353.56858769L801.28338945 349.07168168z" horiz-adv-x="1024" />
<glyph glyph-name="qidong" unicode="&#58891;" d="M510.5072525-36.38889655000003c-56.52199781 0-111.37280906 11.07856875-163.02994594 32.92775531-49.87466531 21.0951375-94.65998063 51.28778719-133.10975156 89.73755811s-68.64242062 83.23508626-89.73755813 133.10975157c-21.84918657 51.65809594-32.92775531 106.50794719-32.92775531 163.02994594 0 56.52199781 11.07856875 111.37280906 32.92775531 163.02994593 21.0951375 49.87562438 51.28778719 94.65998063 89.73755813 133.10975157 38.44977094 38.45072999 83.23508626 68.64242062 133.10975156 89.73851718 51.65809594 21.84918657 106.50794719 32.92775531 163.02994594 32.92775532s111.37280906-11.07856875 163.02994594-32.92775532c49.87466531-21.09609657 94.65998063-51.28778719 133.10975157-89.73851718 38.44977094-38.44977094 68.64242062-83.23508626 89.73755811-133.10975157 21.84918657-51.65713687 32.92775531-106.50794719 32.92775533-163.02994594 0-56.52199781-11.07856875-111.37280906-32.92775533-163.02994593-21.0951375-49.87466531-51.28778719-94.65998063-89.73755811-133.10975157s-83.23508626-68.64242062-133.10975157-89.73755813C621.88006156-25.31032780999999 567.02925031-36.38889655000003 510.5072525-36.38889655000003zM510.5072525 741.74241094c-95.97908624 0-186.21358688-37.37625844-254.08181249-105.24448407-67.86822563-67.86822563-105.24448406-158.10272625-105.24448407-254.0818125 0-95.97908624 37.37625844-186.21454687 105.24448407-254.0818125 67.86822563-67.86726563 158.10272625-105.24448406 254.08181249-105.24448406 95.97908624 0 186.21454687 37.37625844 254.0818125 105.24448406 67.86726563 67.86822563 105.24448406 158.10272625 105.24448405 254.0818125 0 95.97908624-37.37625844 186.21358688-105.24448405 254.0818125C696.72179844 704.3661515599999 606.48729781 741.74241094 510.5072525 741.74241094zM673.64464531 381.66206531L435.54751438 199.60917657000005 435.54751438 565.22401031Z" horiz-adv-x="1024" />
<glyph glyph-name="gantt" unicode="&#59028;" d="M669.99264645 569.32132087L669.99264645 727.32366384c0 14.50182376-11.82641941 26.33245944-26.33245944 26.33245945L169.67592365 753.65612329c-14.4571355 0-26.33245944-11.83147861-26.33245944-26.33245945l0-158.00234298c0-14.50604004 11.87532312-26.33330237 26.33245943-26.33330237l473.98342044 0C658.16538413 542.9880185 669.99264645 554.81612458 669.99264645 569.32132087L669.99264645 569.32132087zM196.00501056 569.32132087L196.00501056 727.32366384l210.6681048 0 0-158.00234298L196.00501056 569.32132087 196.00501056 569.32132087zM775.32585593 305.98408254000003L775.32585593 463.98558262c0 14.50604004-11.82726232 26.33245944-26.33245945 26.33245943L169.67592365 490.31804123c-14.4571355 0-26.33245944-11.82726232-26.33245944-26.33245944l0-158.002343c0-14.50098083 11.87532312-26.33245944 26.33245943-26.33245944l579.31662992 0C763.49774985 279.65078017999997 775.32585593 291.48225795999997 775.32585593 305.98408254000003L775.32585593 305.98408254000003zM196.00501056 305.98408254000003L196.00501056 463.98558262l263.32965033 0 0-158.00234299L196.00501056 305.98323879 196.00501056 305.98408254000003zM880.65653497 42.64262796000003L880.65653497 200.64244135c0 14.51194217-11.83063486 26.3417341-26.32908609 26.3417341l-684.65236816 0c-14.4571355 0-26.33245944-11.82979192-26.33245945-26.34173411l0-157.99981338c0-14.50182376 11.87532312-26.33161569 26.33245945-26.33161569l684.64730895-1e-8C868.82505719 16.311855199999968 880.65653497 28.140803369999958 880.65653497 42.64262796000003L880.65653497 42.64262796000003zM196.00501056 42.64262796000003L196.00501056 200.64244135l315.99372464-1e-8 0-157.99981338L196.00501056 42.64262796000003 196.00501056 42.64262796000003zM196.00501056 42.64262796000003" horiz-adv-x="1024" />
<glyph glyph-name="gongzuoliuchengtu" unicode="&#58880;" d="M925.57343749 826.46624999L925.5734375 697.41281251c0-20.3634375-16.4765625-36.87187501-36.7959375-36.87187501L778.3821875 660.5409375c-20.3221875 0-36.79593748 16.5084375-36.79593751 36.87187501l0 36.87187499L575.9965625 734.2846875c-20.3240625 0-36.7978125-16.5065625-36.79781249-36.871875L539.19874999 402.43500001l202.38750002 0-2e-8 36.87375001c0 20.3634375 16.47374998 36.871875 36.79593751 36.87187497l110.39625 3e-8c20.31937499 0 36.79593748-16.5084375 36.79593751-36.87187503L925.57437501 310.25624999c0-20.3653125-16.4765625-36.87187501-36.79593751-36.87187498L778.3821875 273.384375c-20.3221875 0-36.79593748 16.5065625-36.79593751 36.87187501l0 36.87187499-202.38749998 0L539.19874999 70.58718749000002c0-20.3634375 16.47374998-36.871875 36.79781251-36.87187499l165.58968749 0 2e-8 36.87187499c0 20.3634375 16.47374998 36.871875 36.79593749 36.87187501l110.39625 0c20.31937499 0 36.79593748-16.5084375 36.79593748-36.87187501L925.57437501-58.46624999000005c0-20.3634375-16.4765625-36.87187501-36.79593751-36.87187501L778.3821875-95.33812499999999c-20.3221875 0-36.79593748 16.5084375-36.79593751 36.87187501l0 36.87187499L557.59624999-21.594375000000014c-40.6453125 0-73.595625 33.0178125-73.59562498 73.7465625L484.00062501 347.12812499999995 281.6159375 347.12812499999995l0-36.87187501c0-20.3653125-16.4765625-36.87187501-36.79968751-36.87187499L134.42374999 273.384375c-20.3240625 0-36.7978125 16.5065625-36.79781249 36.87187501l0 129.05343749c0 20.3634375 16.47374998 36.871875 36.79781251 36.871875l110.39156249 0c20.3240625 0 36.7996875-16.5084375 36.7996875-36.87187501l0-36.87375 202.38562501 1e-8 0 313.4146875c0 40.72593751 32.95031249 73.74375001 73.595625 73.74375l183.98906249 0 0 36.87187501c0 20.3634375 16.47374998 36.871875 36.79593749 36.87187499l110.39625001 0C909.0978125 863.338125 925.57343749 846.82875001 925.57343749 826.46624999z" horiz-adv-x="1024" />
<glyph glyph-name="chenggongyijiejue" unicode="&#59092;" d="M513.37022099 781.06728838c-218.23163877 0-395.1452918-176.92354599-395.14529178-395.17856895 0-218.22894053 176.91365213-395.1515874 395.14529178-395.1515874 218.21275195 0 395.18576367 176.92354599 395.18576368 395.1515874C908.55598467 604.1437423699999 731.58297295 781.06728838 513.37022099 781.06728838zM735.53939053 476.06967657L489.0776917 225.56701728999997c-0.03867364-0.03957276-0.07464902-0.0809455-0.11242354-0.12051827s-0.07914638-0.07554903-0.11782002-0.11422266l-0.66015264-0.67094472c-5.49887168-5.58971017-12.78663047-8.38951172-20.18591367-8.43538096-0.05396309-0.00089913-0.10702705-0.00089913-0.16099101-0.00179912-0.14210332 0-0.28330752-0.00359737-0.42631084-0.00179912-7.38129551-0.06025957-14.69153935 2.61902461-20.26506007 8.10170683L310.30499902 358.95827870999995c-11.4249542 11.24237724-11.22888691 29.96858145 0.43800293 41.82794033 11.67318545 11.86025888 30.39669141 12.363917 41.81534912 1.12153975l114.58231348-112.73226768 225.44564766 229.15023574c11.24777373 11.4249542 29.97127968 11.22528955 41.82884033-0.44160029C746.27720967 506.21813584 746.78176778 487.49732901 735.53939053 476.06967657z" horiz-adv-x="1024" />
<glyph glyph-name="home" unicode="&#58909;" d="M874.44031573 436.3535045L579.06438066 748.21256426c-18.35655469 19.36297177-42.88742227 30.01714805-69.18739102 30.01714805s-50.82993721-10.65507627-69.18739101-30.01714806L145.31456269 436.3535045c-30.47673691-32.18467852-26.55269737-60.01451017-21.51161542-71.62743692 3.59216455-8.24920665 15.71144766-30.91563895 50.64376377-30.91563896l43.28765068 0 0-239.9024461c0-54.47516572 38.56585254-105.75839619 93.35940205-105.75839619l49.6868124 0 76.06592755 0 0 56.37827549L436.84650372 242.04834287000006c0 27.2182456-4.07153935 42.38196503 23.34637089 42.38196504l49.68591328 0 49.68501328 0c27.41791026 0 23.3463709-15.16371943 23.3463709-42.38196504l0-197.52048105 0-56.37827549 76.05423545 0 49.69940362 0c54.79265039 0 93.35940205 51.28322959 93.35940204 105.75839619L802.02321406 333.81042862000004l43.28765068 0c34.93141612 0 47.05159922 22.66643232 50.64376378 30.91563896C900.99391221 376.33899434 904.91795177 404.1688251 874.44031573 436.3535045zM845.30906651 383.19054844000004l-37.27612706 0L783.19717842 383.19054844000004l-29.86425176 0 0-289.2825668c0-27.2182456-17.29437451-56.37737637-44.67091289-56.37737637l-77.0651499 0L631.59686299 242.04834287000006c0 54.46077539-17.21252989 91.76208574-72.03486007 91.76208575l-49.68501327 0-49.68591328 0c-54.83402227 0-72.03396094-37.30220947-72.03396094-91.76208575l0-204.51773672-77.06425078 0c-27.39092873 0-44.67091289 29.15912988-44.67091288 56.37737637L266.42195175 383.19054844000004 236.55680089 383.19054844000004l-24.83486194 0-37.27612704 0c-0.86431377 0-1.64858203 3.39789638-2.3537039 3.44646299 1.67556357 2.99137148 4.57519834 10.56153955 9.40582266 15.65028896l295.40111835 311.63691006c8.8194208 9.33387187 21.28586836 15.04589854 33.3628796 14.92717938 12.06532002 0.11871914 23.77358174-5.59330752 32.59300166-14.92717938l295.40111835-311.63691006c4.81623487-5.08964941 7.73025908-12.65891748 9.40582266-15.65028896C846.95674942 386.58844482 846.17338027 383.19054844000004 845.30906651 383.19054844000004z" horiz-adv-x="1024" />
<glyph glyph-name="fuzhi" unicode="&#58910;" d="M731.68184 135.942527 731.68184 628.676741c0 30.233582-24.512277 54.745858-54.747905 54.745858L184.216093 683.422599c-30.233582 0-54.746882-24.512277-54.746882-54.745858l0-492.734214c0-30.207999 24.5133-54.746882 54.746882-54.746882l492.717841 0C707.16854 81.195645 731.68184 105.734528 731.68184 135.942527zM622.1891 135.942527 238.962975 135.942527c-30.233582 0-54.746882 24.538883-54.746882 54.745858L184.216093 573.92986c0 30.233582 24.5133 54.746882 54.746882 54.746882l383.226125 0c30.233582 0 54.744835-24.512277 54.744835-54.746882l0-383.242498C676.933935 160.48141 652.421658 135.942527 622.1891 135.942527zM841.17458 519.182978l-54.745858 0 0-54.746882c30.232558 0 54.745858-24.5133 54.745858-54.759161l0-383.228171c0-30.206976-24.5133-54.745858-54.745858-54.745858L403.201573-28.297095c-30.233582 0-54.746882 24.538883-54.746882 54.745858l-54.746882 0 0-54.745858c0-30.207999 24.5133-54.747905 54.746882-54.747905l492.719888 0c30.234605 0 54.747905 24.539906 54.747905 54.747905L895.922485 464.436096C895.922485 494.670701 871.408161 519.182978 841.17458 519.182978z" horiz-adv-x="1024" />
<glyph glyph-name="shanchu1" unicode="&#58897;" d="M680.18372158-8.618004789999986L323.26341348-8.618004789999986c-85.74426562 0-115.16241973 15.91650879-115.16241973 114.51216094L208.10099375 491.08229795c0 13.14009141 10.65417627 23.7951668 23.7951668 23.79516679 13.14009141 0 23.7951668-10.65417627 23.79516679-23.79516679l0-385.18814267c0-62.5301042-1.58022862-66.92362559 67.57298526-66.92362559l356.9203081 0c66.84088184 0 75.19441816 1.88332295 75.19441816 66.92362559L755.37903887 491.08229795c0 13.14009141 10.65417627 23.7951668 23.7951668 23.79516679 13.14009141 0 23.79426768-10.65417627 23.79426767-23.79516679l0-385.18814267C802.96757422 14.943320210000024 772.62034942-8.618004789999986 680.18372158-8.618004789999986zM672.0973042 621.95346797c-13.14009141 0-23.79426768 10.65417627-23.79426767 23.7951668l-1e-8 7.43615859c0 68.75838193-12.8504874 75.84557695-75.19441816 75.84557695L430.33941582 729.0303694300001c-65.00522636 0-67.57298526-9.21335362-67.57298525-75.84557695l0-7.4361586c0-13.14009141-10.65417627-23.7951668-23.7951668-23.79516679-13.14099052 0-23.7951668 10.65417627-23.79516679 23.79516679l0 7.4361586c0 92.28553067 24.25925215 123.43501143 115.16241972 123.43501143l142.76830341 0c98.94371572 0 122.78475175-39.8052123 122.78475176-123.43501143l0-7.4361586C695.89247099 632.60764424 685.23829473 621.95346797 672.0973042 621.95346797zM362.76643057 110.35603096c-6.57634131 0-11.8980334 5.34327714-11.8980334 11.89803339l0 23.79336768c0 6.57634131 5.32169209 11.8980334 11.8980334 11.8980334 6.57634131 0 11.89713339-5.32079209 11.89713339-11.8980334l0-23.79336768C374.66356396 115.69930810000005 369.34187188 110.35603096 362.76643057 110.35603096zM362.76643057 193.63776561999998c-6.57634131 0-11.8980334 5.34327714-11.8980334 11.89803341L350.86839717 407.80056328c0 6.5700457 5.32169209 11.89713339 11.8980334 11.8971334 6.57634131 0 11.89713339-5.32708857 11.89713339-11.8971334l0-202.26566425C374.66356396 198.98104278000005 369.34187188 193.63776561999998 362.76643057 193.63776561999998zM505.53383398 110.35603096c-6.57634131 0-11.89713339 5.34327714-11.89713339 11.89803339l0 285.54739893c0 6.5700457 5.32079209 11.89713339 11.89713339 11.89713339s11.8980334-5.32708857 11.89803341-11.89713339l0-285.54739893C517.43186739 115.69930810000005 512.11017529 110.35603096 505.53383398 110.35603096zM648.30303653 110.35603096c-6.57634131 0-11.8980334 5.34327714-11.89803341 11.89803339l0 285.54739893c0 6.5700457 5.32169209 11.89713339 11.89803341 11.89713339s11.89713339-5.32708857 11.89713339-11.89713339l0-285.54739893C660.1992708 115.69930810000005 654.87847872 110.35603096 648.30303653 110.35603096zM898.14734229 565.44118301c0-54.20624854-43.94060859-98.15315185-98.15315186-98.15315186l-577.02177949 0c-54.21164414 0-98.15315185 43.9469042-98.15315186 98.15315186l0 5.9485667c0 54.20624854 43.94060859 98.15315185 98.15315186 98.15315185l577.02177949 0c54.21164414 0 98.15315185-43.9469042 98.15315186-98.15315185L898.14734229 565.44118301zM850.55790781 571.38885059c0 27.92516661-22.63225518 50.56371739-50.56371738 50.56371738l-577.02177949 0c-27.93056308 0-50.56371739-22.63855078-50.56371739-50.56371738l0-5.94856671c0-27.92516661 22.6331543-50.56371739 50.56371739-50.56371737l577.02177949 0c27.93146221 0 50.56371739 22.63855078 50.56371738 50.56371737L850.55790781 571.38885059z" horiz-adv-x="1024" />
<glyph glyph-name="xitongcaozuorizhi" unicode="&#59025;" d="M896.69314575 271.37297058l-101.50337219 101.73511505c-6.95228576 7.02953339-16.45374298 10.96916198-26.41868591 10.96916199L603.15219117 384.07724763c-23.01979065 0-41.7137146-18.61667633-41.71371461-41.55921937L561.43847656 31.596359249999978c0-22.94254303 18.69392395-41.55921936 41.71371461-41.55921936l262.64190673 0c23.01979065 0 41.7137146 18.61667633 41.7137146 41.55921936L907.5078125 245.26327515000003C907.5078125 254.99647521999998 903.64543152 264.42068482 896.69314575 271.37297058zM858.06933594 39.47561645999997l-247.19238281 0 0 295.08590698 152.87303925 0L858.06933594 240.08768463 858.06933594 39.47561645999997zM650.81397248 235.68457031000003l70.99056244 0c13.67282868 0 24.71923828 11.04640961 24.71923828 24.71923828s-11.04640961 24.71923828-24.71923828 24.71923829l-70.99056245 0c-13.67282868 0-24.71923828-11.04640961-24.71923827-24.71923829S637.1411438 235.68457031000003 650.81397248 235.68457031000003zM626.0947342 186.24609375c0-13.67282868 11.04640961-24.71923828 24.71923827-24.71923828l159.82532501 0c13.67282868 0 24.71923828 11.04640961 24.71923828 24.71923828s-11.04640961 24.71923828-24.71923828 24.71923828l-159.82532501 0C637.1411438 210.96533203 626.0947342 199.91892241999994 626.0947342 186.24609375zM810.63929748 136.80761718999997l-159.82532501 0c-13.67282868 0-24.71923828-11.04640961-24.71923827-24.71923828s11.04640961-24.71923828 24.71923828-24.71923829l159.825325 0c13.67282868 0 24.71923828 11.04640961 24.71923828 24.71923829S824.23487854 136.80761718999997 810.63929748 136.80761718999997zM490.37066651 235.68457031000003l-52.52838135 0 0 49.43847657 50.13370514 0c13.67282868 0 24.71923828 11.04640961 24.71923828 24.71923828s-11.04640961 24.71923828-24.71923828 24.71923828L194.35778808 334.56152344c-15.68126679 0-28.42712403 12.74585724-28.42712402 28.42712403l0 289.2923355c0 15.68126679 12.74585724 28.42712403 28.42712403 28.42712402l437.6077652 0c15.68126679 0 28.42712403-12.74585724 28.42712402-28.42712402L660.39267732 456.22652436c0-13.67282868 11.04640961-24.71923828 24.71923827-24.71923829s24.71923828 11.04640961 24.71923828 24.71923828l0 196.05445862c0 42.94967651-34.91592407 77.86560059-77.86560058 77.86560059L194.35778808 730.14658357C151.40811157 730.06933594 116.4921875 695.15341187 116.4921875 652.28098297L116.4921875 362.98864746000004c0-42.94967651 34.91592407-77.86560059 77.86560059-77.86560058L388.40380859 285.12304687000005l0-49.43847656L289.52685547 235.68457031000003c-13.67282868 0-24.71923828-11.04640961-24.71923828-24.71923828s11.04640961-24.71923828 24.71923828-24.71923828l200.84381104 0c13.67282868 0 24.71923828 11.04640961 24.71923828 24.71923828S504.04349518 235.68457031000003 490.37066651 235.68457031000003z" horiz-adv-x="1024" />
<glyph glyph-name="dingwei" unicode="&#59332;" d="M511.99955 777.48321856c-137.58151992 0-249.11220234-111.53158154-249.11220234-249.11220234 0-41.85852012 10.44911513-81.2311251 28.68425244-115.87383721l-0.09083848-0.04496924 220.5196875-421.93542745 217.79363584 417.06972686c19.9116 35.78044043 31.31856562 76.93473867 31.31856562 120.78450791C761.11175234 665.95163701 649.58106992 777.48321856 511.99955 777.48321856zM511.99955 442.18335205c-42.30731602 0-76.61995136 34.31263623-76.61995136 76.65053115 0 42.30731602 34.31263623 76.61995136 76.61995136 76.61995137 42.3369958 0 76.65053115-34.31263623 76.65053115-76.61995137C588.64918203 476.4968874 554.3365458 442.18335205 511.99955 442.18335205z" horiz-adv-x="1024" />
<glyph glyph-name="yunxingzhong" unicode="&#59067;" d="M512-11.507812489999992c-217.52929689 0-395.50781249 177.97851563-395.50781249 395.50781249s177.97851563 395.50781249 395.50781249 395.50781249 395.50781249-177.97851563 395.50781249-395.50781249S729.52929689-11.507812489999992 512-11.507812489999992zM512 735.01318359C319.18994139 735.01318359 160.98681641 576.8100586099999 160.98681641 384s158.20312501-351.01318359 351.01318359-351.01318359 351.01318359 158.20312501 351.01318359 351.01318359S704.81005861 735.01318359 512 735.01318359zM413.12304687 522.42773437L689.97851563 384 413.12304687 245.57226562999995Z" horiz-adv-x="1024" />
<glyph glyph-name="shezhishedingpeizhichilun" unicode="&#59407;" d="M896 448l-71.04 0c-8.32 40.96-24.96 78.08-46.72 111.36l50.56 50.56c24.96 24.96 24.96 65.28 0 90.24-24.96 24.96-65.28 24.96-90.24 0l-50.56-50.56C654.08 672.64 616.96 689.28 576 697.6L576 768c0 35.2-28.8 64-64 64C476.8 832 448 803.2 448 768l0-70.4C407.04 689.28 369.92 672.64 336 650.24L285.44 700.8c-24.96 24.96-65.28 24.96-90.24 0-24.96-24.96-24.96-65.28 0-90.24l50.56-50.56C224 526.0799999999999 207.36 488.96 199.04 448L128 448C92.8 448 64 419.2 64 384c0-35.2 28.8-64 64-64l71.04 0c8.32-40.96 24.96-78.08 46.72-111.36l-50.56-50.56c-24.96-24.96-24.96-65.28 0-90.24 24.96-24.96 65.28-24.96 90.24 0l50.56 50.56C369.92 95.36000000000001 407.04 78.72000000000003 448 70.39999999999998L448 0c0-35.2 28.8-64 64-64 35.2 0 64 28.8 64 64l0 70.4c40.96 8.32 78.08 24.96 112 47.36l50.56-50.56c24.96-24.96 65.28-24.96 90.24 0 24.96 24.96 24.96 65.28 0 90.24l-50.56 50.56c21.76 33.28 38.4 71.04 46.72 111.36L896 319.36c35.2 0 64 28.8 64 64C960 419.2 931.2 448 896 448zM512 256c-70.4 0-128 57.6-128 128 0 70.4 57.6 128 128 128 70.4 0 128-57.6 128-128C640 313.6 582.4 256 512 256z" horiz-adv-x="1024" />
<glyph glyph-name="zhiyuanshuaxin9" unicode="&#58931;" d="M510.73509781 805.95455437c-232.36501688 0-420.67094531-188.30592844-420.67094531-420.67094531 0-232.31513062 188.30592844-420.67094531 420.67094531-420.67094531 232.31321156 0 420.67094531 188.35581469 420.67094531 420.67094531C931.40604312 617.64862594 743.04830938 805.95455437 510.73509781 805.95455437L510.73509781 805.95455437zM510.01558531 145.26682125000002c-97.61957437 0-180.85945688 62.03250188-212.90365125 148.71357188l0.35975625 0.154455c-2.0021625 4.00528406-3.33757687 8.32043906-3.33757687 13.09416187 0 16.53534938 13.3512675 29.88661688 29.88565781 29.88661688 13.24957688 0 24.13531594-8.78092688 27.987105-20.74497469l0.46144687 0.15253687c23.05700719-64.8558675 84.88324875-111.53493937 157.54630407-111.53493937 92.32972031 0 167.40553875 75.07485937 167.40553875 167.40553875 0 92.27791594-75.07581844 167.35373437-167.40553875 167.35373437-20.2326825 0-39.48970594-3.95347969-57.46312031-10.57778812l21.05484468-40.36271438c2.46456937-2.66986969 3.95443875-6.26455219 3.95443875-10.16718656 0-8.37032531-8.31852-14.7893325-15.19993406-14.94378844l-0.30891094 0c-0.20530125 0-0.41060156 0-0.61590281 0l-149.32947469 6.41900813c-5.28889406 0.20530125-10.11634125 3.28673156-12.58186968 8.01056906-2.46456937 4.72479656-2.20746375 10.42525125 0.66770718 14.94378844l80.15941219 126.06716625c2.87613 4.46769094 7.95972375 7.08671531 13.24861781 6.880455 5.34069937-0.25614656 10.11538219-3.28673156 12.58090969-8.01056906l18.43486125-35.32996594c26.39458406 10.78308938 55.20289219 16.791495 85.39842 16.791495 125.24596313 0 227.1787725-101.881005 227.1787725-227.07612281C737.19435781 247.14878531 635.26154844 145.26682125000002 510.01558531 145.26682125000002L510.01558531 145.26682125000002zM510.01558531 145.26682125000002" horiz-adv-x="1024" />
<glyph glyph-name="tishi2" unicode="&#59027;" d="M874.02587891 536.08857422c-20.61650391 47.67011719-48.66503906 89.24150391-84.1631836 124.69130859-35.48408203 35.46035156-76.97197266 63.48867187-124.44697265 84.09023438-47.48027344 20.60683594-98.31357422 30.90761719-152.49990235 30.90761719-54.19072266 0-105.02578125-10.30166016-152.50429687-30.90761719-47.475-20.6015625-88.95234375-48.62900391-124.44697266-84.09023438-35.49462891-35.45068359-63.54228516-77.01591797-84.16933594-124.69130859-20.62177734-47.67626953-30.92695313-98.57724609-30.92695312-152.72490235 0-54.14238281 10.30517578-104.92207031 30.92695312-152.35224609 20.62529297-47.44072266 48.67470703-88.88378906 84.1631836-124.34326172 35.49462891-35.45068359 76.97197266-63.47900391 124.44609375-84.09023437 47.47939453-20.59716797 98.31357422-30.90234375 152.50429687-30.90234375 54.18720703 0 105.01962891 10.30166016 152.49990235 30.90234375 47.475 20.61123047 88.96113281 48.64042969 124.44609375 84.09023437 35.49023438 35.46035156 63.54755859 76.90341797 84.16318359 124.34326172 20.63144531 47.43017578 30.93662109 98.21513672 30.93662109 152.35224609 0.00966797 54.15292969-10.30166016 105.04951172-30.93134765 152.72490235l0 0zM512.91582031 130.48564452999995c-24.51357422 0-44.38037109 19.84746094-44.38037109 44.34169922 0 24.48369141 19.87207031 44.34169922 44.38037109 44.34169922 24.51796875 0 44.37597656-19.85712891 44.37597657-44.34169922 0-24.49863281-19.86152344-44.34169922-44.37597657-44.34169922l0 0zM557.29179688 314.82216797c0-24.48896484-19.86152344-44.35136719-44.37597657-44.35136719-24.51357422 0-44.38037109 19.86152344-44.38037109 44.35136719l0 277.80820312c0 24.49863281 19.87207031 44.35136719 44.38037109 44.35136719 24.51796875 0 44.37597656-19.85273438 44.37597657-44.35136719l0-277.80820312zM557.29179688 314.82216797z" horiz-adv-x="1024" />
<glyph glyph-name="one-line-arrow" unicode="&#58908;" d="M962.011 834.022l-150.243-40.261 39.115-39.139-788.895-788.873 31.75-31.75 788.895 788.873 39.115-39.115z" horiz-adv-x="1024" />
<glyph glyph-name="quanping" unicode="&#59104;" d="M654.74667969 487.14492187l222.61992187 221.85175782-0.76289062-125.72226563c-0.30585937-10.42734375 8.12460938-19.62333984 18.55019531-19.31748047h13.33916016c10.42734375 0.30673828 19.16367187 6.43886719 19.31748046 17.01914063l0.61435547 187.20263672c0 0.15380859 0.30585937 9.96503906 0.30585938 9.96503906 0.15380859 5.21103516-1.07402344 9.96503906-4.44726563 13.33916016-3.37324219 3.37324219-7.96904297 5.51865234-13.33916015 5.36660156l-9.50625-0.15380859c-0.15292969 0-0.30234375 0-0.45703125-0.1538086l-185.67070313 0.76904297c-10.42734375-0.30673828-19.16367187-8.89628906-19.31748047-19.47304687v-13.33916016c1.53544922-12.41806641 11.34404297-19.62509766 21.77050782-19.31748047l122.34814453-0.30673828-222.00556641-221.08798828c-10.11972656-10.11972656-10.11972656-26.52275391 0-36.64072266 10.11972656-10.27265625 26.52539063-10.27265625 36.64423828 0h-0.00351562zM374.16992187 278.01708984000004l-222.77197265-221.08974609 0.76728516 125.1140625c0.30673828 10.42294922-8.128125 19.61982422-18.55371094 19.31748047h-14.10292969c-10.42734375-0.30673828-19.16367187-6.43974609-19.31748047-17.02001953l-0.61435547-187.35644531c0-0.15380859-0.30585937-9.96503906-0.30585937-9.96503907-0.15380859-5.2171875 1.07402344-9.96503906 4.44287109-13.33916015 3.37324219-3.37324219 7.97431641-5.51865234 13.33916016-5.36660157l9.50537109 0.1538086c0.15380859 0 0.30673828 0 0.46142578 0.15380859l186.43798828-0.76816406c10.42294922 0.30673828 19.16367187 8.89189453 19.31748047 19.47304687v13.33828125c-1.53457031 12.41806641-11.34667969 19.62509766-21.77490234 19.31748047l-122.34902344 0.30673828 221.85263672 221.08271485c10.11972656 10.11972656 10.11972656 26.52626953 0 36.64423828-9.96152344 10.27265625-26.2125 10.27265625-36.33398438-0.00087891v0zM928.42490234-3.016699219999964l-0.46054687 187.35644531c-0.30673828 10.42822266-8.89628906 16.71328125-19.31835938 17.02001954h-13.33828125c-10.42822266 0.30234375-18.70576172-8.89628906-18.55458984-19.31748047l0.76816406-125.72666016-222.77285156 221.70146484c-10.11972656 10.11972656-26.52539063 10.11972656-36.64423828 0-10.11533203-10.11884766-10.11533203-26.52539063 0-36.64423828l221.85527344-221.08183593-122.34814454-0.30673829c-10.42734375 0.30673828-20.08476562-7.05234375-21.77402343-19.31748046v-13.33916016c0.30585937-10.42734375 8.89628906-19.16367187 19.31748047-19.47304688l185.67158203 0.76816407c0.15292969 0 0.30585937-0.15380859 0.46054687-0.1538086l9.50625-0.15380859c5.21015625-0.15292969 9.96503906 1.83955078 13.33828125 5.36660156 3.37324219 3.37324219 4.5984375 8.12373047 4.44375 13.33916016 0 0-0.15380859 9.81210938-0.15380859 9.96503906h0.00439453zM188.81035156 744.87275391l122.34814453 0.30673828c10.42294922-0.30673828 20.08125 7.05234375 21.77050782 19.31748047v13.34091797c-0.30673828 10.42734375-8.89189453 19.16367187-19.31748047 19.47304687l-186.58828125-0.76816406c-0.15380859 0-0.30673828 0.15380859-0.46142578 0.15380859l-9.50449219 0.1538086c-5.2171875 0.15292969-9.96503906-1.83955078-13.33916016-5.36660157-3.37324219-3.37324219-4.60283203-8.12373047-4.44287109-13.33916015 0 0 0.30585937-9.81210938 0.30585937-9.96503907l0.45703125-187.35644531c0.15380859-10.42382813 8.89628906-16.71328125 19.31748047-17.015625h14.10732422c10.42734375-0.30585937 18.70488281 8.89189453 18.54931641 19.31748047l-0.61347657 125.10878906 222.6234375-221.24267578c10.11445313-10.11972656 26.521875-10.11972656 36.63984375 0 10.11972656 10.11972656 10.11972656 26.52539063 0 36.64423828l-221.85263671 221.23476563zM188.81035156 744.87275391z" horiz-adv-x="1024" />
<glyph glyph-name="quanping1" unicode="&#58976;" d="M167.09959268 728.9179459l163.25371406-1e-8c14.12762168 0 25.73784932 11.54367334 25.73784931 25.77202648 0 14.32908458-11.52568565 25.77112734-25.73784931 25.77112734l-189.05901768 0c-7.06381084 0-13.48995411-2.88524355-18.15419179-7.55038125-4.731692-4.66513682-7.58455752-11.09128008-7.58455753-18.18836807L115.55553974 565.6642318300001c0-14.12762168 11.54367334-25.73784932 25.77112735-25.73784931 14.32908458 0 25.77202646 11.52658477 25.77202646 25.73784932L167.09869268 728.9179459zM854.34344141 728.9179459L691.08972734 728.9179459c-14.14471026 0-25.73784932 11.54367334-25.73784931 25.77202647 0 14.32908458 11.52658477 25.77112734 25.73784931 25.77112734l189.05901768 0c7.06381084 0 13.48995411-2.88524355 18.1541918-7.55038125 4.73259112-4.66513682 7.58455752-11.09128008 7.58455751-18.18836807L905.88749433 565.6642318300001c0-14.12762168-11.54367334-25.73784932-25.77112733-25.73784931-14.32908458 0-25.77202646 11.52658477-25.77202648 25.73784932L854.34434053 728.9179459zM167.09959268 41.67499627999996l163.25371406 1e-8c14.12762168 0 25.73784932-11.54277422 25.73784931-25.77112734 0-14.32908458-11.52568565-25.77112734-25.73784931-25.77112734l-189.05901768 0c-7.06381084 0-13.48995411 2.88614356-18.15419179 7.55038125-4.731692 4.6642377-7.58455752 11.09128008-7.58455753 18.18836806L115.55553974 204.92781122999997c0 14.1285208 11.54367334 25.73964844 25.77112735 25.73964844 14.32908458 0 25.77202646-11.52658477 25.77202646-25.73964844L167.09869268 41.67499627999996zM854.34344141 41.67499627999996L691.08972734 41.67499627999996c-14.14471026 0-25.73784932-11.54277422-25.73784931-25.77112733 0-14.32908458 11.52658477-25.77112734 25.73784931-25.77112734l189.05901768 0c7.06381084 0 13.48995411 2.88614356 18.1541918 7.55038125 4.73259112 4.6642377 7.58455752 11.09128008 7.58455751 18.18836806L905.88749433 204.92781122999997c0 14.1285208-11.54367334 25.73964844-25.77112733 25.73964844-14.32908458 0-25.77202646-11.52658477-25.77202648-25.73964844L854.34434053 41.67499627999996z" horiz-adv-x="1024" />
<glyph glyph-name="shanchu" unicode="&#58928;" d="M817.968553 680.102858l-169.357176 0 0 58.869782c0 25.391297-20.657482 46.048779-46.048779 46.048779l-181.125197 0c-25.391297 0-46.048779-20.657482-46.048779-46.048779l0-58.869782-169.357176 0c-25.391297 0-46.048779-20.657482-46.048779-46.048779l0-71.631434c0-25.391297 20.657482-46.048779 46.048779-46.048779l28.321022 0 0-425.947112c0-59.246359 48.200792-107.447151 107.447151-107.447151l340.40076 0c59.246359 0 107.447151 48.200792 107.447151 107.447151L789.647531 516.373867l28.321022 0c25.391297 0 46.048779 20.657482 46.048779 46.048779l0 71.631434C864.017332 659.445376 843.35985 680.102858 817.968553 680.102858zM426.553932 733.85611l170.892135 0 0-53.753251-170.892135 0L426.553932 733.85611zM738.482221 90.425731c0-31.033807-25.248034-56.281841-56.281841-56.281841L341.79962 34.14389c-31.033807 0-56.281841 25.248034-56.281841 56.281841L285.517779 516.373867l452.964442 0L738.482221 90.425731zM812.852022 567.539176l-601.704045 0 0 61.398372 203.227588 0c2.302439-0.356111 4.66116-0.542352 7.061836-0.542352l181.125197 0c2.400676 0 4.759397 0.186242 7.062859 0.542352l203.226564 0L812.852022 567.539176zM513.023306 112.679571c14.128789 0 25.582655 11.453866 25.582655 25.582655l0 288.572348c0 14.128789-11.453866 25.582655-25.582655 25.582655-14.128789 0-25.582655-11.453866-25.582655-25.582655l0-288.572348C487.440651 124.133438 498.894518 112.679571 513.023306 112.679571zM645.541459 112.679571c14.128789 0 25.582655 11.453866 25.582655 25.582655l0 288.572348c0 14.128789-11.453866 25.582655-25.582655 25.582655s-25.582655-11.453866-25.582655-25.582655l0-288.572348C619.958804 124.133438 631.41267 112.679571 645.541459 112.679571zM380.505154 112.679571c14.128789 0 25.582655 11.453866 25.582655 25.582655l0 288.572348c0 14.128789-11.453866 25.582655-25.582655 25.582655s-25.582655-11.453866-25.582655-25.582655l0-288.572348C354.922499 124.133438 366.376365 112.679571 380.505154 112.679571z" horiz-adv-x="1024" />
<glyph glyph-name="yonghu" unicode="&#58936;" d="M502.36843027 778.68930029c110.43882247 0 199.96232519-88.06199414 199.9623252-196.67775234 0-108.63734414-89.52260362-196.70383477-199.96232519-196.70383477-110.4352251 0-199.95692959 88.06559151-199.9569296 196.70383477C302.41060156 690.65248945 391.96288497 778.68930029 502.36843027 778.68930029L502.36843027 778.68930029 502.36843027 778.68930029zM502.36843027 778.68930029c110.43882247 0 199.96232519-88.06199414 199.9623252-196.67775234 0-108.63734414-89.52260362-196.70383477-199.96232519-196.70383477-110.4352251 0-199.95692959 88.06559151-199.9569296 196.70383477C302.41060156 690.65248945 391.96288497 778.68930029 502.36843027 778.68930029L502.36843027 778.68930029 502.36843027 778.68930029zM427.38806709 319.72957528999996l166.66689991 0c142.65947724 0 258.29317705-113.71979795 258.29317704-254.05435107l0-16.36710293c0-55.30260498-115.65798398-57.4044794-258.29317705-57.40447939L427.38806709-8.09635897999999c-142.66397373 0-258.29317705 0.0809455-258.29317706 57.40447939l0 16.36710293C169.09668828 206.00977734000003 284.72499248 319.72957528999996 427.38806709 319.72957528999996L427.38806709 319.72957528999996 427.38806709 319.72957528999996z" horiz-adv-x="1024" />
<glyph glyph-name="ai06" unicode="&#58999;" d="M512.23227737 786.07299584c-220.42550386 0-400.83069382-180.37841124-400.83069387-400.82836479 0-220.42666781 180.40518997-400.83069382 400.83069387-400.83069382 220.45228257 0 400.83069382 180.40402602 400.8306938 400.83069382C913.06297003 605.69342066 732.68455878 786.07299584 512.23227737 786.07299584M472.18518473 224.92702380000003l-80.1710285 0 0 320.65966421 80.1710285 0L472.18518473 224.92702380000003zM632.52840562 224.92702380000003l-80.17102848 0 0 320.65966421 80.17102848 0L632.52840562 224.92702380000003z" horiz-adv-x="1024" />
<glyph glyph-name="ai05" unicode="&#59001;" d="M391.40755797 224.11434667000003l80.57853156 0 0 322.28502072-80.57853156 0L391.40755797 224.11434667000003zM512.23344128 788.10469149c-221.54089813 0-402.86122439-181.29354638-402.86122439-402.8612244 0-221.54322717 181.31916117-402.86238834 402.86122439-402.86238834 221.56884082 0 402.86005931 181.31916117 402.86005931 402.86238834C915.09350059 606.81114397 733.8022821 788.10469149 512.23344128 788.10469149M512.23344128 62.95844637000005c-177.23947122 0-322.2826917 145.04554951-322.2826917 322.28502072 0 177.26508601 145.04322048 322.31063552 322.2826917 322.31063552 177.26508601 0 322.31063552-145.04554951 322.31063552-322.31063552C834.54407566 208.00399587000004 689.49852729 62.95844637000005 512.23344128 62.95844637000005M552.56229319 224.11434667000003l80.57853156 0 0 322.28502072-80.57853156 0L552.56229319 224.11434667000003z" horiz-adv-x="1024" />
<glyph glyph-name="yonghu1" unicode="&#58921;" d="M670.01446625 357.18713906000005c58.26993281 47.0465025 94.18606219 118.78570312 94.18606219 195.97976532 0 139.07115-113.12937844 252.20052844-252.20052844 252.20052843-139.07115 0-252.20052844-113.12937844-252.20052844-252.20052843 0-77.35523344 36.06578719-149.23449938 94.55157375-196.27524563-140.62913344-61.70056687-236.44129313-202.84007438-236.44129312-360.50341875 0-18.65743031 15.11359312-33.75375469 33.75375468-33.75375469s33.75375469 15.09728438 33.75375469 33.75375469c0 152.75051531 108.58014281 286.77836438 258.18303188 318.75252562 15.27572344 3.25986938 25.87077937 16.38760875 26.6257875 31.28055188 0.02302406 0.35495906 0.0326175 0.708 0.04413 1.062 0.00959344 0.50078062 0.01534969 1.00156125 0.00287812 1.50521906-0.17556094 13.57767469-8.56027594 26.26699125-22.057365 31.25368969C375.89515906 406.87665 327.30794094 476.36233875 327.30794094 553.16690438c0 101.85606188 82.85230594 184.69205906 184.69205906 184.69205906 101.83975219 0 184.69205906-82.83599719 184.69205906-184.69205906 0-76.8036075-48.58721812-146.29025531-120.90874406-172.92371813-4.535805-1.67598375-8.48256844-4.23360938-11.75107312-7.38987-0.08634187-0.08346375-0.16500844-0.17460187-0.25039032-0.25902469-0.66099188-0.65139844-1.30375594-1.31814656-1.90526812-2.01751219-0.26574-0.30699188-0.50461781-0.63700781-0.75884531-0.95455312-0.40388625-0.50653687-0.81544688-1.0063575-1.18863375-1.53400031-0.33481312-0.47008125-0.63412969-0.96702469-0.94591875-1.45629282-0.26574-0.41827687-0.54395156-0.82791844-0.79050375-1.25770687-0.29452031-0.51229313-0.55450406-1.04856938-0.82312219-1.57908937-0.23024344-0.45473156-0.47008125-0.90178875-0.67921969-1.36611375-0.20913844-0.46624406-0.38949563-0.94975594-0.57848812-1.42847157-0.22928438-0.57561-0.45856875-1.14930094-0.65619469-1.7373825-0.12951187-0.38853656-0.23599969-0.78762562-0.35208094-1.18287844-0.20913844-0.708-0.40676438-1.41887812-0.56985375-2.14126781-0.02686219-0.11991844-0.06811406-0.2321625-0.09401625-0.35304093-0.05180531-0.24079688-0.07003219-0.47967469-0.11608125-0.72047157-0.14198344-0.74349562-0.26861812-1.48795125-0.36167437-2.24200031-0.04988625-0.40772344-0.08250375-0.81160969-0.11704032-1.21837406-0.05852062-0.67921969-0.10360969-1.35939844-0.11991843-2.04533344-0.01247156-0.48159375-0.00575625-0.95934938 0.00287812-1.438065 0.0115125-0.59863406 0.03069937-1.19630906 0.07482938-1.79686219 0.04029281-0.55930125 0.10169062-1.11380437 0.16884562-1.66734937 0.06331687-0.51613031 0.13143094-1.03130063 0.21969094-1.54647188 0.10744687-0.63125156 0.24079688-1.25386969 0.38278031-1.87552875 0.10169062-0.44226 0.20242313-0.88356094 0.32234156-1.32390281 0.18515438-0.67730062 0.39908906-1.34212969 0.62549625-2.00408156 0.09209719-0.26957719 0.154455-0.5420325 0.25326844-0.81160969 0.05947969-0.16021125 0.13239-0.30987 0.19378875-0.46912219 0.15349594-0.39717094 0.31946344-0.78666656 0.48735-1.17712219 0.24463406-0.57081281 0.50269875-1.13107312 0.77515406-1.68078 0.16213031-0.32713781 0.32425969-0.6533175 0.49694344-0.97469906 0.35591906-0.66387 0.73486219-1.30759312 1.13011406-1.93884562 0.12567469-0.20050406 0.24079688-0.40676438 0.37126782-0.60534938 0.55546312-0.84806531 1.14162563-1.66926844 1.76424375-2.45497594 0.07578844-0.09497531 0.16021125-0.18323531 0.23599968-0.27725156 0.53435813-0.65907281 1.08982125-1.29512156 1.66830844-1.90718719 0.26478094-0.28108969 0.54107344-0.54874781 0.81544688-0.82120312 0.40100812-0.39621094 0.80873156-0.78378844 1.2279675-1.15793531 0.35975625-0.32330063 0.72334969-0.64084594 1.09749562-0.94975594 0.32809781-0.26861812 0.66770719-0.52284562 1.00539844-0.77899219 1.62705656-1.23852 3.37499156-2.33217844 5.23517062-3.26850375 0.23120344-0.11608125 0.46048781-0.23408156 0.69360938-0.34536562 0.597675-0.28396781 1.20494344-0.55162594 1.82372344-0.80105719 0.26861812-0.10840687 0.54011344-0.20530125 0.81160968-0.30699188 1.10229281-0.41252063 2.23240688-0.76843875 3.39513844-1.06967437 0.30411375-0.07866656 0.60343125-0.17268281 0.90946313-0.242715 0.16980469-0.03933375 0.33001594-0.09689438 0.50078062-0.13335 149.58658031-31.84177125 258.16672312-166.06820531 258.16672312-319.1477775 0-18.65743031 15.11359312-33.75375469 33.75375469-33.75375469s33.75375469 15.09728438 33.75375469 33.75375469C906.08928781 154.19069062999995 810.44789188 295.37912530999995 670.01446625 357.18713906000005z" horiz-adv-x="1024" />
<glyph glyph-name="wenjianjia" unicode="&#59240;" d="M841.99029541 433.4046936v0h-566.12905884c-21.02618408 0-38.80178833-13.73483276-44.92391967-32.73568725v0l-49.39398194-152.17327881v420.76263428h235.90310669c0-52.10650635 42.21139526-94.31790161 94.32119751-94.31790161v0h235.85119629v-94.31954956h47.15524292v94.31954956c0 26.02770997-21.12588501 47.16101074-47.15524292 47.16101073h-235.90722657c-26.02606201 0-47.15936279 21.13082886-47.15936279 47.15689088v0c0 26.02853393-21.07727051 47.15936279-47.15936279 47.15936279v0h-235.85119629c-26.02688599 0-47.15936279-21.13165283-47.15936279-47.15936279v-566.02194214c0-26.02853393 21.13165283-47.15524292 47.15936279-47.15524293h566.02359009c21.02618408 0 38.80178833 13.72988891 44.92391968 32.73568726h0.0519104l96.50061035 297.43341065c0.00082398 26.02688599-21.02453614 47.10580445-47.05389404 47.15936279v0zM750.01660156 103.23312378000003h-568.47161865l91.871521 283.01138305h568.46749877l-91.8682251-283.01138305z" horiz-adv-x="1024" />
<glyph glyph-name="chenggong" unicode="&#58887;" d="M512.61293427 778.23870615c-217.56429141 0-393.93291357-176.36862217-393.93291357-393.93291357 0-217.56429141 176.36862217-393.93291357 393.93291357-393.93291357 217.56429141 0 393.93291357 176.36862217 393.93291358 393.93291357C906.54584786 601.87008398 730.17722568 778.23870615 512.61293427 778.23870615zM749.87656982 494.45681016L477.29208184 215.96692645999997c-0.92906982-1.39405518-1.96336846-2.72515254-3.18204229-3.95911581-10.68385605-10.85114268-28.00341386-10.85114268-38.69446552 0L300.01777402 349.48949824c-10.67576221 10.85204268-10.67576221 28.43691943 0 39.27277265 10.68295693 10.85204268 28.00251387 10.85204268 38.6863708 0L454.35403408 271.34777783000004l256.82807022 262.39709444c10.69195078 10.85114268 28.00341386 10.85114268 38.69446552 0C760.55233115 522.89373047 760.55233115 505.30975195 749.87656982 494.45681016z" horiz-adv-x="1024" />
<glyph glyph-name="anquan" unicode="&#58993;" d="M840.58007276 688.34555391c-0.81394805 8.2294207-5.74170732 15.50278916-13.06184414 19.33059375-85.93133818 44.87867227-186.40761593 67.5576958-298.55707823 67.5576958-5.74170732 0-11.33951221-0.19156992-16.98588369-0.28690577l0-0.09533496c-5.64547237 0.19156992-11.19560977 0.38313984-16.93731621 0.38313985-112.1503623 0-212.62663916-22.77435937-298.55707822-67.5576958-7.32103594-3.82780459-12.24879521-11.10117305-13.06184415-19.42592959-1.14762217-12.34503018-28.41983174-304.96973027 23.6359749-461.23338341 1.00461885-4.40161612 40.33405371-147.26885185 304.96793204-234.25247724l0 0c264.58800908 86.98362539 303.91654482 229.85086114 304.92116367 234.25247724C868.99990449 383.28138692000005 841.72769492 675.90608789 840.58007276 688.34555391zM769.95905381 240.79729102c-0.38313984-1.24385625-35.59696523-117.89206875-257.98468623-196.07156368l0 0c-222.3382544 78.08415908-257.55297891 194.73237158-257.93611963 196.07156368-43.25257442 129.85395908-27.65445029 370.32661846-22.9659293 429.46332361 76.26649131 37.12772724 164.97244864 55.97984531 263.96473184 55.97984534 5.74080732 0 11.29094473-0.47847568 16.93731621-0.57471065l0 0 0 0 0.04766748 0 0 0c5.69403984 0.19156992 11.24507549 0.57471065 16.93821621 0.57471065 98.9922832 0 187.69913965-18.85211807 263.96473183-55.97984532C797.61440322 611.1239103600001 813.21252823 370.74658594000005 769.95905381 240.79729102zM660.6795456 551.89097021L454.03475029 345.5789499 363.41399111 436.67728477c-9.56861279 9.66484688-25.11906943 9.56951193-34.64091387 0.09623495-9.61628028-9.56951193-9.61628028-25.07230107-0.09443583-34.64091386l104.59008808-105.06946289c3.11009151-3.15775898 6.88932862-4.88009092 10.81246905-5.93327725 3.58856719-1.91300273 7.41637177-3.25309482 11.3395122-3.25309483 6.26785049 0 12.53570097 2.39237753 17.32045694 7.17623438L695.32045859 517.25005635c9.56861279 9.47327695 9.56861279 25.07140195 0 34.64091386C685.75094668 561.45958213 670.24815753 561.45958213 660.6795456 551.89097021z" horiz-adv-x="1024" />
<glyph glyph-name="shuaxin" unicode="&#58882;" d="M422.0140625 134.78437499999995c-27.7734375 9.6890625-53.015625 23.315625-75.6984375 40.9078125-22.6828125 17.578125-42.1734375 38.3625-58.4859375 62.3109375-16.3125 23.9625-28.546875 49.95-36.703125 77.99062499l79.509375 2e-8c4.078125 3.571875 6.75 7.65 8.0296875 12.23437499 1.2796875 4.584375-0.1265625 8.6625-4.2046875 12.234375l-91.74375 93.2765625c-3.571875 3.571875-8.0296875 5.3578125-13.37343749 5.3578125-5.3578125 0-10.06875001-1.7859375-14.14687501-5.3578125l-90.984375-93.2765625c-5.6109375-6.1171875-7.2703125-10.828125-4.9640625-14.146875 2.2921875-3.31875001 5.23125001-6.75 8.7890625-10.32187501l72.6328125 2e-8c8.6625-35.1703125 22.55625001-67.66875001 41.6671875-97.48125001 19.1109375-29.8125 42.1734375-55.6875 69.1875-77.596875 27.0140625-21.9234375 57.4734375-38.9953125 91.3640625-51.2296875s69.7078125-18.3515625 107.4234375-18.3515625c28.546875 0 56.0671875 3.571875 82.575 10.7015625 26.5078125 7.1296875 51.35625001 17.325 74.5453125 30.5859375 23.1890625 13.246875 44.3390625 29.1796875 63.4640625 47.78437501 19.1109375 18.6046875 35.803125 39.375 50.0765625 62.31093749l-45.871875 18.35156251c-12.234375-18.3515625-26.38125001-34.9171875-42.4265625-49.69687501-16.059375-14.7796875-33.7640625-27.39375001-53.1421875-37.8421875-19.3640625-10.4484375-39.88125001-18.6046875-61.55156251-24.46875-21.65625001-5.8640625-44.2125-8.7890625-67.66874999-8.7890625C479.234375 120.2578125 449.8015625 125.09531249999998 422.0140625 134.78437499999995zM778.68124999 320.5640625c3.571875-3.571875 9.8015625-8.1703125 15.15937501-8.17031249s8.296875 4.5984375 12.375 8.17031249l91.74375 93.2765625c3.571875 3.571875 4.7109375 7.65 3.4453125 12.234375-1.2796875 4.584375-3.6984375 8.6625-7.2703125 12.234375l-69.58125 0c-6.1171875 38.221875-18.478125 73.659375-37.0828125 106.2703125-18.6046875 32.625-41.79375001 61.03125001-69.58125 85.246875-27.7734375 24.215625-59.3859375 43.2-94.809375 56.953125C587.6703125 700.5609375 550.08125001 707.4375 510.3265625 707.4375c-30.5859375 0-60.01875001-4.2046875-88.3125-12.6140625-28.29375001-8.409375-54.534375-20.1375-78.75-35.1703125-24.215625-15.0328125-46.125-33.0046875-65.75625-53.9015625-19.6171875-20.896875-36.05625001-44.0859375-49.3171875-69.58125l45.1125-18.35156251c11.728125 20.896875 25.8609375 40.0078125 42.4265625 57.34687501 16.565625 17.325 34.9171875 32.1046875 55.0546875 44.3390625 20.1375 12.234375 42.046875 21.796875 65.75625 28.6734375 23.6953125 6.8765625 48.290625 10.321875 73.7859375 10.321875 33.13125001 0 64.4765625-5.6109375 94.0359375-16.81875001 29.559375-11.2078125 55.940625-26.634375 79.1296875-46.25156249 23.1890625-19.6171875 42.8203125-42.946875 58.865625-69.96093751 16.059375-27.0140625 26.8875-56.0671875 32.49843751-87.15937499l-83.33437501 0c-4.078125-3.571875-7.1296875-7.003125-9.16875-10.321875-2.0390625-3.31875001-0.253125-8.0296875 5.3578125-14.146875" horiz-adv-x="1024" />
<glyph glyph-name="wendangxiugai" unicode="&#59171;" d="M397.459421 58.444601000000034H190.057869c-9.394495 0-16.62103 7.949188-16.621031 16.621031V737.0162310000001c0 9.394495 7.949188 16.62103 16.621031 16.621031h581.736062c9.394495 0 16.62103-7.949188 16.62103-16.621031v-278.944248c0-13.730416 11.562456-25.292872 25.292872-25.292872s25.292872 11.562456 25.292873 25.292872V737.0162310000001c0 36.855328-30.351447 67.206775-67.206775 67.206775H190.057869c-36.855328 0-67.206775-30.351447-67.206775-67.206775v-661.950599c0-36.855328 30.351447-67.206775 67.206775-67.206775H397.459421c13.730416 0 25.292872 11.562456 25.292873 25.292872s-11.562456 25.292872-25.292873 25.292872zM880.191955 366.294989c-33.242061 33.242061-87.441073 33.242061-120.683134 0l-247.870148-247.870148c-3.613267-3.613267-5.781228-7.226535-6.503881-12.285109l-24.570219-107.675371c-2.16796-8.671842 0.722653-17.343684 6.503881-23.124911 5.058574-5.058574 11.562456-7.949188 18.066338-7.949189 1.445307 0 3.613267 0 5.058574 0.722654l109.843331 22.402258c5.058574 0.722653 9.394495 3.613267 13.007763 7.226535L880.191955 245.611856c15.898377 15.898377 25.292872 37.577982 25.292872 60.702893s-9.394495 44.081863-25.292872 59.98024z m-35.410021-85.273112l-242.088921-242.08892-64.31616-13.007763 14.453069 62.1482L794.918843 330.88496799999996c13.730416 13.730416 36.132675 13.730416 49.140437 0 6.503881-6.503881 10.117149-15.175723 10.117149-24.570219s-2.890614-18.788991-9.394495-25.292872zM698.805928 687.875794H255.096683c-13.730416 0-25.292872-11.562456-25.292872-25.292872s11.562456-25.292872 25.292872-25.292873h444.431899c13.730416 0 25.292872 11.562456 25.292872 25.292873s-11.562456 25.292872-26.015526 25.292872zM724.0988 539.731828c0 13.730416-11.562456 25.292872-25.292872 25.292872H255.096683c-13.730416 0-25.292872-11.562456-25.292872-25.292872s11.562456-25.292872 25.292872-25.292872h444.431899c13.730416 0 24.570219 11.562456 24.570218 25.292872zM257.987297 410.376853m-27.460833 0a27.460833 27.460833 0 1 1 54.921666 0 27.460833 27.460833 0 1 1-54.921666 0ZM354.100212 410.376853m-27.460833 0a27.460833 27.460833 0 1 1 54.921665 0 27.460833 27.460833 0 1 1-54.921665 0ZM450.213126 410.376853m-27.460832 0a27.460833 27.460833 0 1 1 54.921665 0 27.460833 27.460833 0 1 1-54.921665 0Z" horiz-adv-x="1024" />
<glyph glyph-name="download" unicode="&#58896;" d="M485 93v240c0 12 12 24 24 24s24-12 24-24v-240l48 36c12 6 24 6 36-6 12-18 6-30-6-36l-90-66c0-6-6-6-12-6s-12 0-12 6l-90 66c-12 6-12 24-6 36 6 12 24 12 36 6l48-36z m-192 36h-18c-108 0-192 96-192 210 0 120 90 216 198 210 36 120 138 204 252 204 126 0 234-96 264-234 84-18 144-96 144-192 0-108-78-198-174-198-30 0-90 0-156 54-12 12-12 30 0 36 12 12 24 12 36 0 48-48 90-42 114-42h6c72 0 126 66 126 150 0 78-54 144-120 150-12 0-18 12-24 18-18 120-108 210-216 210-96 0-186-78-210-186 0-12-12-18-30-18h-24c-78 0-138-72-138-162 0-90 60-162 138-162h12c24 0 54 0 96 42 12 12 24 12 36 0 12-12 12-24 0-36-48-48-90-54-120-54z" horiz-adv-x="1024" />
<glyph glyph-name="icon-xiugai" unicode="&#58893;" d="M783.78987676 441.79931221c-14.75719453 0-24.59472451-9.83663086-24.5947254-24.59562452v-314.83514179c0-34.4331545-24.59832276-63.94934268-59.03507373-63.9493418h-457.49281992c-34.43855098 0-73.7895709 29.51528906-73.78957089 63.94934179V559.86496318c0 34.43405362 39.35101991 68.87080547 73.78957089 68.87080635h260.72422911c14.75899365 0 24.59652363 9.83752998 24.59652363 24.59652276 0 14.75809365-9.83752998 24.59562451-24.59652363 24.59562452h-260.72422911c-68.86900721 0-122.98171817-49.19214815-122.98171816-118.06295363v-457.49641729c0-68.86630898 54.11361094-113.14148995 122.98171816-113.14148993h457.49371904c68.87170459 0 108.22542275 44.27518185 108.22542364 113.14148993V412.28762139c0 14.75449628-9.8393291 29.51169082-24.59652365 29.51169082m98.38699367 275.48232274l-39.35191992 39.35371817c-29.51798643 29.5170873-78.71553106 29.5170873-108.22722187 0l-68.86810725-83.62710089-373.87021639-364.02818905v-9.83752999l-49.19124815-162.33543632 34.4331545-29.51528906 152.49970547 54.11091357h9.83752998L798.54976953 540.1872049799999l83.62889912 68.87080547c29.51438906 29.51618818 29.51438906 78.70653721-0.00179824 108.22362452M311.53806318 176.15991593l24.59472452 68.87170458 44.27608095-44.27608096-68.87080547-24.59562364m113.14148994 49.19124815l-68.8672081 68.86900635L695.24580957 628.73576953 759.19515136 564.7828294999999 424.67955312 225.35116405999997m423.05876631 423.06056456l-49.19034902-49.19214728-73.79047002 73.78867089 49.1957455 49.1948464c4.91516719 0 14.75719453 4.91696633 19.67416085 4.9169663 4.92056368 0 14.75719453-4.91696633 19.6777582-4.9169663l39.35551728-39.35371816c4.91966457-9.84202734 4.91966457-24.60012099-4.92236279-34.43765185m0 0z" horiz-adv-x="1024" />
<glyph glyph-name="remove" unicode="&#58894;" d="M769.00449219 725.51308594h-137.90302735c-6.87919922 59.65224609-57.63164063 106.14287109-119.10058593 106.14287109-61.46630859 0-112.21171875-46.48798828-119.09091797-106.14287109h-137.9100586c-55.80878906 0-101.20605469-45.41044922-101.20605468-101.21748047v-5.19345703c0-42.64716797 26.55439453-79.14990234 63.96240233-94.02275391v-478.14433594c0-55.80878906 45.40341797-101.21748047 101.20781251-101.21748046h386.07890625c55.80615234 0 101.20605469 45.41308594 101.2060547 101.21748046v478.14257812c37.40537109 14.87460938 63.96240234 51.37734375 63.96240233 94.02275392v5.19345703c0 55.80878906-45.40166015 101.21923828-101.20605469 101.21923828zM512 783.65449219c34.96025391 0 64.14082031-25.05761719 70.59726562-58.14052735h-141.18134765c6.4546875 33.08466797 35.63701172 58.14052734 70.58408203 58.14052735zM758.24667969 46.93593750000002c0-29.34228516-23.87373049-53.21777344-53.20634765-53.21777344h-386.07890626c-29.33261719 0-53.20634766 23.87724609-53.20634766 53.21777344v470.94960937h492.49248047v-470.94960937zM822.20820313 619.1030273399999c0-29.34228516-23.87373049-53.21777344-53.20634766-53.21777343h-514.00371094c-29.33261719 0-53.20634766 23.87548828-53.20634766 53.21777343v5.19345703c0 29.34228516 23.87373049 53.21777344 53.20634766 53.21777344h514.00546875c29.33261719 0 53.20634766-23.87548828 53.20634766-53.21777344v-5.19345703zM383.32285156 55.10537108999995c13.25566406 0 24.00029297 10.74902345 24.00029297 23.99853516v270.23554687c0 13.25214844-10.74638672 24.00205078-24.00029297 24.00205081s-24.00029297-10.75078125-24.00029297-24.00205081v-270.23554687c-0.00175781-13.25390625 10.74462891-23.99853516 24.00029297-23.99853516zM512 55.10537108999995c13.25566406 0 24.00205078 10.74902345 24.00205078 23.99853516v270.23554687c0 13.25214844-10.75078125 24.00205078-24.00205078 24.00205081-13.25390625 0-24.00029297-10.75078125-24.00029297-24.00205081v-270.23554687c0-13.25390625 10.74462891-23.99853516 24.00029297-23.99853516zM640.67714844 55.10537108999995c13.25390625 0 23.99853516 10.74902345 23.99853515 23.99853516v270.23554687c0 13.25214844-10.74638672 24.00205078-23.99853515 24.00205081-13.25742187 0-24.00205078-10.75078125-24.00205078-24.00205081v-270.23554687c-0.00175781-13.25390625 10.74902345-23.99853516 24.00205078-23.99853516z" horiz-adv-x="1024" />
<glyph glyph-name="paibanguanli" unicode="&#58898;" d="M185.046875 51.7734375c-47.4609375 0-84.375 36.9140625-84.375 84.375V631.8515625c0 47.4609375 36.9140625 84.375 84.375 84.375h73.828125v52.734375H301.0625v-52.734375h321.6796875v52.734375h42.1875v-52.734375h73.828125c47.4609375 0 84.375-36.9140625 84.375-84.375v-168.75H142.859375v-332.2265625c0-21.09375 15.8203125-42.1875 42.1875-42.1875H459.265625c10.546875 0 21.09375-10.546875 21.09375-21.09375s-10.546875-21.09375-21.09375-21.09375l-274.21875 5.2734375z m0 622.265625c-21.09375 0-42.1875-15.8203125-42.1875-42.1875v-126.5625h632.8125V631.8515625c0 21.09375-15.8203125 42.1875-42.1875 42.1875h-73.828125V594.9375H617.46875V674.0390625H301.0625V594.9375h-42.1875V674.0390625H185.046875zM232.5078125 378.7265625h168.75v-42.1875H232.5078125v42.1875zM232.5078125 220.5234375h168.75v-42.1875H232.5078125v42.1875zM696.5703125 178.3359375V299.625h42.1875v-79.1015625h79.1015625v-42.1875h-121.2890625zM717.6640625-0.9609375c-52.734375 0-105.46875 21.09375-142.3828125 58.0078125-36.9140625 36.9140625-58.0078125 89.6484375-58.0078125 142.3828125 0 52.734375 21.09375 105.46875 58.0078125 142.3828125 36.9140625 36.9140625 89.6484375 58.0078125 142.3828125 58.0078125 52.734375 0 105.46875-21.09375 142.3828125-58.0078125 36.9140625-36.9140625 58.0078125-89.6484375 58.0078125-142.3828125 0-52.734375-21.09375-105.46875-58.0078125-142.3828125-36.9140625-36.9140625-84.375-58.0078125-142.3828125-58.0078125z m0 363.8671875c-89.6484375 0-163.4765625-73.828125-163.4765625-163.4765625 0-89.6484375 73.828125-163.4765625 163.4765625-163.4765625s163.4765625 73.828125 163.4765625 163.4765625c0 89.6484375-73.828125 163.4765625-163.4765625 163.4765625z" horiz-adv-x="1024" />
<glyph glyph-name="shezhi-xue" unicode="&#58929;" d="M845.5625 509.26875h-17.8875a312.01875 312.01875 0 0 1-17.60625 42.3l12.76875 12.7125a83.8125 83.8125 0 0 1 24.69375 59.68125 84.0375 84.0375 0 0 1-24.69375 59.625l-19.96875 19.9125c-31.95 31.8375-87.4125 31.89375-119.3625 0l-12.7125-12.7125a304.5375 304.5375 0 0 1-42.35625 17.60625v17.94375c0 46.51875-37.85625 84.375-84.31875 84.375h-28.125c-46.51875 0-84.375-37.85625-84.375-84.375v-17.94375c-14.5125-4.78125-28.63125-10.6875-42.35625-17.60625l-12.7125 12.76875c-31.95 31.8375-87.525 31.78125-119.30625 0l-19.9125-19.9125a84.4875 84.4875 0 0 1 0-119.3625l12.76875-12.76875a313.14375 313.14375 0 0 1-17.60625-42.24375h-18c-46.51875 0-84.375-37.9125-84.375-84.375v-28.125c0-46.51875 37.85625-84.375 84.375-84.375h17.94375c4.78125-14.5125 10.6875-28.63125 17.60625-42.35625l-12.76875-12.76875a84.54375 84.54375 0 0 1 0-119.30625l19.9125-19.9125c31.89375-31.89375 87.525-31.8375 119.30625 0l12.76875 12.76875c13.725-6.91875 27.84375-12.825 42.35625-17.60625v-17.94375c0-46.51875 37.85625-84.375 84.375-84.375h28.125c46.4625 0 84.31875 37.85625 84.31875 84.375v17.94375a315 315 0 0 1 42.3 17.60625l12.825-12.825c31.78125-31.78125 87.3-31.8375 119.30625 0l19.9125 19.9125a84.6 84.6 0 0 1 0 119.3625l-12.76875 12.76875c6.91875 13.725 12.88125 27.84375 17.60625 42.35625h17.94375c46.4625 0 84.31875 37.85625 84.31875 84.375v28.125a84.4875 84.4875 0 0 1-84.31875 84.375z m28.125-112.55625a28.125 28.125 0 0 0-28.06875-28.125h-38.98125a28.06875 28.06875 0 0 1-27.225-21.15c-6.01875-23.7375-15.525-46.6875-28.29375-68.00625a28.125 28.125 0 0 1 4.275-34.25625l27.61875-27.61875a28.29375 28.29375 0 0 0 0-39.825l-19.9125-19.9125a28.96875 28.96875 0 0 0-39.76875 0l-27.675 27.675a28.125 28.125 0 0 1-34.25625 4.275 256.5 256.5 0 0 0-68.00625-28.29375 28.18125 28.18125 0 0 1-21.20625-27.225v-38.98125a28.125 28.125 0 0 0-28.06875-28.125h-28.125a28.125 28.125 0 0 0-28.125 28.125v38.98125a28.06875 28.06875 0 0 1-21.15 27.225 252.9 252.9 0 0 0-67.95 28.35 28.35 28.35 0 0 1-34.3125-4.275l-27.675-27.675a28.85625 28.85625 0 0 0-39.76875 0l-19.9125 19.9125a28.125 28.125 0 0 0 0 39.76875l27.675 27.675a28.125 28.125 0 0 1 4.275 34.25625A253.35 253.35 0 0 0 280.8125 347.4375a28.2375 28.2375 0 0 1-27.28125 21.20625h-38.98125a28.125 28.125 0 0 0-28.125 28.125v28.125c0 15.46875 12.65625 28.125 28.125 28.125h38.98125a28.06875 28.06875 0 0 1 27.225 21.20625 258.1875 258.1875 0 0 0 28.29375 67.95 28.0125 28.0125 0 0 1-4.275 34.2l-27.675 27.675a28.125 28.125 0 0 0 0 39.825l19.9125 19.9125a28.85625 28.85625 0 0 0 39.76875 0l27.675-27.675a28.125 28.125 0 0 1 34.3125-4.275 255.375 255.375 0 0 0 67.95 28.29375 28.06875 28.06875 0 0 1 21.15 27.225v38.98125a28.125 28.125 0 0 0 28.125 28.125h28.125a28.125 28.125 0 0 0 28.06875-28.125v-38.98125c0-12.88125 8.71875-24.075 21.20625-27.225 23.625-6.01875 46.51875-15.525 67.95-28.29375a28.18125 28.18125 0 0 1 34.25625 4.275l27.61875 27.61875a28.74375 28.74375 0 0 0 39.825 0l19.9125-19.9125a28.0125 28.0125 0 0 0 0-39.76875l-27.675-27.675a28.125 28.125 0 0 1-4.275-34.3125c12.76875-21.31875 22.275-44.15625 28.35-67.95a28.125 28.125 0 0 1 27.225-21.15h38.925c15.46875 0 28.125-12.65625 28.125-28.125v-28.125zM530.05625 592.6875a182.1375 182.1375 0 0 1-181.9125-181.9125 182.1375 182.1375 0 0 1 181.9125-181.9125 182.1375 182.1375 0 0 1 181.96875 181.9125A182.19375 182.19375 0 0 1 530.05625 592.6875z m0-307.575c-69.3 0-125.6625 56.3625-125.6625 125.6625S460.75625 536.4375 530.05625 536.4375s125.71875-56.3625 125.71875-125.6625-56.41875-125.6625-125.71875-125.6625z" horiz-adv-x="1024" />
<glyph glyph-name="tianjia-xue" unicode="&#58934;" d="M515.54375 775.55625a393.3 393.3 0 0 1-392.85-392.85c0-216.675 176.23125-392.85 392.85-392.85s392.85 176.23125 392.85 392.85a393.3 393.3 0 0 1-392.85 392.85z m0-729.50625c-185.625 0-336.6 151.03125-336.6 336.6S329.975 719.25 515.54375 719.25s336.6-151.03125 336.6-336.6-151.03125-336.6-336.6-336.6zM677.2625 410.83125H543.66875V544.425a28.125 28.125 0 0 1-56.25 0v-133.59375H353.825a28.125 28.125 0 0 1 0-56.25h133.59375v-133.59375a28.125 28.125 0 0 1 56.25 0V354.58124999999995h133.59375a28.125 28.125 0 0 1 0 56.25z" horiz-adv-x="1024" />
<glyph glyph-name="tuichufffpx" unicode="&#58892;" d="M693.23046875 14.5078125zM145.3203125 14.5078125zM870.68164063 777.75zM493.98242187-9.75C301.4140625-9.75 145.3203125 146.34375 145.3203125 338.91210937000005c0 145.72265625 89.47265625 270.61523438 216.38671875 322.64648438v-0.08789063c3.77929688 1.31835938 7.82226563 2.02148438 12.04101563 2.02148438 19.86328125 0 36.12304688-16.171875 36.12304687-36.03515625 0-15.64453125-10.01953125-29.09179688-24.08203125-34.01367188-98.87695313-42.09960938-168.31054688-140.18554688-168.31054688-254.53124999 0-152.75390625 123.75-276.50390625 276.50390626-276.50390626S770.48632813 186.24609375 770.48632813 338.91210937000005c0 114.2578125-69.34570313 212.43164063-168.31054688 254.53125001-14.0625 4.921875-23.99414063 18.36914063-23.99414063 34.01367187 0 19.95117188 16.08398438 36.03515625 36.03515626 36.03515625 4.21875 0 8.17382813-0.703125 12.04101562-2.02148438v0.08789063c127.00195313-52.11914063 216.38671875-176.92382813 216.38671875-322.64648438 0-192.56835938-156.09375-348.66210938-348.66210938-348.66210937z m1e-8 372.65625c-19.86328125 0-36.03515625 16.171875-36.03515625 36.12304688V723.69726563c0 19.86328125 16.171875 36.03515625 36.03515625 36.03515624 19.95117188 0 36.03515625-16.171875 36.03515625-36.03515625V399.1171875c0-20.0390625-16.08398438-36.2109375-36.03515625-36.2109375z" horiz-adv-x="1024" />
<glyph glyph-name="jiazaizhong" unicode="&#59055;" d="M864 416H704c-17.6 0-32-14.4-32-32s14.4-32 32-32h160c17.6 0 32 14.4 32 32s-14.4 32-32 32z m-512-32c0 17.6-14.4 32-32 32H160c-17.6 0-32-14.4-32-32s14.4-32 32-32h160c17.6 0 32 14.4 32 32z m160-160c-17.6 0-32-14.4-32-32v-160c0-17.6 14.4-32 32-32s32 14.4 32 32V192c0 17.6-14.4 32-32 32z m0 544c-17.6 0-32-14.4-32-32v-160c0-17.6 14.4-32 32-32s32 14.4 32 32V736c0 17.6-14.4 32-32 32z m138.6-304c8.8-15.4 28.4-20.6 43.8-11.8l138.6 80c15.4 8.8 20.6 28.4 11.8 43.8s-28.4 20.6-43.8 11.8l-138.6-80c-15.4-9-20.6-28.4-11.8-43.8zM373.4 304c-8.8 15.4-28.4 20.6-43.8 11.8l-138.6-80c-15.4-8.8-20.6-28.4-11.8-43.8s28.4-20.6 43.8-11.8l138.6 80c15.4 9 20.6 28.4 11.8 43.8z m262.4-70.2c-8.8 15.4-28.4 20.6-43.8 11.8s-20.6-28.4-11.8-43.8l80-138.6c8.8-15.4 28.4-20.6 43.8-11.8 15.4 8.8 20.6 28.4 11.8 43.8l-80 138.6z m-272 471c-8.8 15.4-28.4 20.6-43.8 11.8-15.4-8.8-20.6-28.4-11.8-43.8l80-138.6c8.8-15.4 28.4-20.6 43.8-11.8s20.6 28.4 11.8 43.8l-80 138.6zM592 522.6c15.4-8.8 34.8-3.6 43.8 11.8l80 138.6c8.8 15.4 3.6 34.8-11.8 43.8-15.4 8.8-34.8 3.6-43.8-11.8l-80-138.6c-8.8-15.4-3.6-35 11.8-43.8zM432 245.4c-15.4 8.8-34.8 3.6-43.8-11.8l-80-138.6c-8.8-15.4-3.6-34.8 11.8-43.8 15.4-8.8 34.8-3.6 43.8 11.8l80 138.6c8.8 15.4 3.6 35-11.8 43.8z m400.8-9.6l-138.6 80c-15.4 8.8-34.8 3.6-43.8-11.8-8.8-15.4-3.6-34.8 11.8-43.8l138.6-80c15.4-8.8 34.8-3.6 43.8 11.8 8.8 15.4 3.6 34.8-11.8 43.8zM191.2 532.2l138.6-80c15.4-8.8 34.8-3.6 43.8 11.8s3.6 34.8-11.8 43.8l-138.6 80c-15.4 8.8-34.8 3.6-43.8-11.8-8.8-15.4-3.6-34.8 11.8-43.8z" horiz-adv-x="1024" />
<glyph glyph-name="gou1" unicode="&#58961;" d="M427.24832567 124.09486597c-11.30022289 0-16.95033472 5.65011183-28.25055758 11.30022364L127.79241038 406.60044653c-16.95033472 16.95033472-16.95033472 39.55078125 1e-8 56.50111597 16.95033472 16.95033472 39.55078125 16.95033472 56.50111672 0L427.24832567 214.49665212000002l418.10825904 418.10825827c16.95033472 16.95033472 39.55078125 16.95033472 56.50111596-1e-8 16.95033472-16.95033472 16.95033472-39.55078125 0-56.50111595L455.49888404 135.39508962000002c-11.30022289-5.65011183-16.95033472-11.30022289-28.25055837-11.30022366z" horiz-adv-x="1033" />
<glyph glyph-name="shalou" unicode="&#58926;" d="M795.35937501 753.140625H228.64062499c-11.953125 0-21.09375003 9.84375001-21.09374999 21.09375 0 11.953125 9.84375001 21.09375003 21.09375001 21.09375h566.71875c11.953125 0 21.09375003-9.84375001 21.09374999-21.09375 0.703125-11.25-9.140625-21.09375003-21.09375001-21.09375zM823.484375-38.578125H201.21874999c-12.65625001 0-23.203125 10.546875-23.20312499 23.203125 0 12.65625001 10.546875 23.203125 23.20312501 23.203125h622.26562499c12.65625001 0 23.203125-10.546875 23.203125-23.203125 0-12.65625001-10.546875-23.203125-23.203125-23.203125zM735.59375001 248.296875l-0.70312501 1.40625c-35.859375 62.578125-83.671875 103.359375-134.29687501 127.96875 50.625 25.3125 97.73437499 65.390625 134.29687501 127.96875l0.70312499 1.40625c35.859375 61.875 59.765625 146.25 63.98437501 258.75H758.09375001c-3.515625-104.0625-25.3125-181.40625001-58.359375-238.359375l-0.70312502-0.70312501C658.25 454.3125 612.546875 415.640625 553.484375 397.359375l-2.8125-0.70312499h-0.70312499c-1.40625001-0.703125-2.109375-1.40625001-3.51562501-2.10937501l-0.703125-0.70312499-1.40624999-1.40625001-1.40625001-1.40625001v-0.70312499c-0.703125-0.703125-1.40625001-2.109375-2.109375-3.515625l-0.703125-0.703125-1.40624999-4.921875v-7.734375l1.40624999-4.92187501 0.703125-0.70312499c0.703125-1.40625001 1.40625001-2.109375 2.109375-3.51562499v-0.703125l1.40625001-1.40625001V362.90624997l1.40624999-0.70312497 0.703125-0.70312501c0.703125-0.703125 2.109375-1.40625001 3.51562501-2.10937499h0.70312499l2.8125-1.40625c59.765625-18.98437499 104.765625-56.95312501 146.25000001-128.671875l0.70312499-1.40625001c17.578125-29.53125001 30.9375-65.390625 41.484375-106.875 2.109375-11.953125 9.84375001-37.96875001 11.25-71.71874999-33.046875 29.53125001-124.453125 50.625-234.14062501 52.03125002V426.1875c1.40625001 0 2.109375 0.703125 3.51562501 1.40625001v0.70312499l5.625 2.10937499h1.40625c40.078125 12.65625001 71.71875001 32.34375001 98.4375 58.35937501 28.125 28.125 49.921875 62.578125 64.6875 101.25 4.21875001 10.546875-0.703125 22.50000001-11.953125 26.71875001-10.546875 4.21875001-22.50000001-0.703125-26.71875001-11.25000001v-0.70312501c-12.65625001-32.34375001-30.9375-62.578125-54.84374999-86.48437499-21.796875-21.09375003-47.8125-37.96875001-80.859375-47.8125l-0.703125-0.70312499-2.109375-0.70312501-3.515625-0.703125-2.109375 0.703125-1.40625 0.70312501-2.109375 0.70312499c-32.34375001 10.546875-59.765625 26.71875001-80.859375 47.8125-24.609375 23.90625001-42.1875 53.4375-54.84375 86.48437501-4.21875001 10.546875-16.171875 16.171875-26.01562501 11.953125-10.546875-4.21875001-15.46875001-15.46875001-11.95312499-26.71875001 14.765625-38.671875 35.859375-73.125 64.6875-101.25 26.015625-26.015625 58.359375-45.703125 97.734375-58.35937501h0.703125l5.625-2.10937499 1.40625-0.70312501c0.703125-0.703125 1.40625001-0.703125 2.8125-1.40624999v-324.84375001c-102.65625001 0-191.953125-17.578125-234.14062499-42.18749998 1.40625001 16.875 4.921875 35.15625001 11.24999998 61.87500001 10.546875 42.1875 24.609375 77.34375001 41.484375 106.87499997l0.70312499 1.40625001c41.484375 71.71875001 86.484375 109.6875 146.95312502 128.671875l2.10937499 1.40625h0.703125c1.40625001 0.703125 2.109375 1.40625001 3.51562501 2.10937501l0.703125 0.70312499 1.40625 0.70312501v0.703125l1.40625 1.40625v0.70312498c0.703125 0.703125 1.40625001 2.109375 2.109375 3.51562501V369.9375c0.703125 1.40625001 1.40625001 3.515625 1.40625001 4.921875v7.03125c0 1.40625001-0.703125 3.515625-1.40625001 4.921875v0.703125c-0.703125 1.40625001-1.40625001 2.8125-2.109375 3.51562499v0.70312502l-1.40625 1.40624999-1.40625 1.40625-2.10937499-0.70312501c-1.40625001 0.703125-2.109375 1.40625001-3.51562501 2.10937501h-0.703125l-2.109375 0.70312501c-59.765625 18.28125001-105.46875001 56.95312501-146.953125 129.37499998l-0.703125 0.70312502c-32.34375001 56.95312501-54.140625 134.296875-58.35937499 238.359375h-41.48437501c4.21875001-112.50000001 28.125-196.171875 63.984375-258.75000002l0.703125-1.40624999C323.5625 442.359375 371.375 402.28125001 422 376.96874998c-50.625-24.609375-97.73437499-65.390625-134.296875-127.96874998l-0.703125-1.40625001c-33.75-59.0625-57.65624999-137.8125-62.578125-242.57812499h573.75c-4.921875 105.46875001-28.125 184.21875001-62.57812501 243.28125z" horiz-adv-x="1024" />
<glyph glyph-name="stop" unicode="&#59110;" d="M512 801.1875C281.56249999 801.1875 94.8125 614.43750001 94.8125 384s186.75-417.1875 417.1875-417.1875 417.1875 186.75 417.1875 417.1875S742.43750001 801.1875 512 801.1875z m261.84375002-679.03124999c-34.03125002-34.03125002-73.59375001-60.75000001-117.75000003-79.40625001-45.65625001-19.3125-94.125-29.0625-144.09374999-29.0625s-98.53125001 9.75-144.09375001 29.0625c-44.06250001 18.65625001-83.71875001 45.375-117.74999998 79.40625001-34.03125002 34.03125002-60.75000001 73.59375001-79.40625001 117.74999998-19.3125 45.65625001-29.0625 94.125-29.0625 144.09375001s9.75 98.53125001 29.0625 144.09374999c18.65625001 44.06250001 45.375 83.71875001 79.40625001 117.75 34.03125002 34.03125002 73.59375001 60.75000001 117.75 79.40625001 45.65625001 19.3125 94.125 29.0625 144.09374999 29.0625s98.53125001-9.75 144.09375001-29.0625c44.06250001-18.65625001 83.71875001-45.375 117.74999998-79.40625001 34.03125002-34.03125002 60.75000001-73.59375001 79.40625001-117.75 19.3125-45.65625001 29.0625-94.125 29.0625-144.09374999s-9.75-98.53125001-29.0625-144.09375001c-18.65625001-44.15625001-45.375-83.71875001-79.40625001-117.74999998zM362 234h300V534H362v-300z m46.875 253.125h206.25v-206.25H408.875V487.125z" horiz-adv-x="1024" />
<glyph glyph-name="timer" unicode="&#59230;" d="M535.4375 734.34375v20.53125h89.0625v46.875H399.5v-46.875h89.0625v-20.53125c-201.375-12.09375-360.9375-179.25-360.9375-383.625 0-212.25 172.125-384.375 384.375-384.375s384.375 172.125 384.375 384.375c0 204.375-159.5625 371.53125-360.9375 383.625z m215.25-622.3125c-31.03125-31.03125-67.125-55.3125-107.25-72.375-41.625-17.625-85.78125-26.53125-131.34375-26.53125s-89.8125 8.90625-131.34375 26.53125c-40.21875 16.96875-76.3125 41.34375-107.25 72.375-31.03125 31.03125-55.3125 67.125-72.375 107.25-17.625 41.625-26.53125 85.78125-26.53125 131.34375s8.90625 89.8125 26.53125 131.34375c16.96875 40.21875 41.34375 76.3125 72.375 107.25s67.125 55.3125 107.25 72.375c41.625 17.625 85.78125 26.53125 131.34375 26.53125s89.8125-8.90625 131.34375-26.53125c40.125-16.96875 76.21875-41.25 107.25-72.28125s55.3125-67.125 72.375-107.25c17.625-41.625 26.53125-85.78125 26.53125-131.34375s-8.90625-89.8125-26.53125-131.34375c-17.0625-40.21875-41.4375-76.3125-72.375-107.34375zM535.4375 623.15625h-46.875v46.875h46.875v-46.875z m-46.875-544.96875h46.875v-46.875h-46.875v46.875zM192.6875 374.0625h46.875v-46.875h-46.875v46.875z m638.625 0v-46.875h-46.875v46.875h46.875z m-312.46875-27.1875l155.53125-65.625-18.1875-43.21875-176.625 74.53125-69.46875 256.5 45.28125 12.28125 63.46875-234.46875z" horiz-adv-x="1024" />
<glyph glyph-name="jiantou-copy" unicode="&#58930;" d="M814.94826667 461.53386667l-274.65813334 274.65813333c-21.45066667 21.45066667-56.22293333 21.45066667-77.6736 0l-274.65813333-274.65813333c-21.45066667-21.45066667-21.45066667-56.22293333 0-77.6736s56.22293333-21.45066667 77.6736 0l180.89066667 180.89066666v-526.57493333c0-30.34986667 24.5824-54.93226667 54.93226666-54.93226667s54.93226667 24.5824 54.93226667 54.93226667v526.57493333l180.89066667-180.89066666c10.71146667-10.71253333 24.7744-16.09493333 38.83733333-16.09493334s28.1248 5.35573333 38.83733333 16.09493334c21.45066667 21.45066667 21.45066667 56.22293333 0 77.6736z" horiz-adv-x="1000" />
<glyph glyph-name="tingzhi" unicode="&#59054;" d="M512-42.666666549999945c-234.66666656 0-426.66666655 192-426.66666655 426.66666655s192 426.66666655 426.66666655 426.66666655 426.66666655-192 426.66666655-426.66666655-192-426.66666655-426.66666655-426.66666655z m0 53.33333343c208.00000031 0 373.33333312 165.33333375 373.33333312 373.33333312s-165.33333375 373.33333312-373.33333312 373.33333312-373.33333312-165.33333375-373.33333312-373.33333312 165.33333375-373.33333312 373.33333312-373.33333312zM351.99999969 544.00000031h320.00000062v-320.00000062H351.99999969z" horiz-adv-x="1024" />
<glyph glyph-name="yunsuan-dengyu" unicode="&#58884;" d="M984.615385 580.923077H39.384615a39.384615 39.384615 0 0 1 0-78.769231h945.23077a39.384615 39.384615 0 0 1 0 78.769231zM984.615385 265.846154H39.384615a39.384615 39.384615 0 0 1 0-78.769231h945.23077a39.384615 39.384615 0 0 1 0 78.769231z" horiz-adv-x="1024" />
<glyph glyph-name="bianji" unicode="&#58883;" d="M367.780625 344.0390625c-0.4996875-0.6375-0.999375-1.3040625-1.2225-2.1103125l-38.535-141.28125c-2.25-8.2246875 0.05625-17.086875 6.140625-23.3371875 4.55625-4.445625 10.558125-6.890625 16.948125-6.890625 2.11125 0 4.2234375 0.249375 6.3065625 0.80625l140.2790625 38.2575c0.223125 0 0.3346875-0.1940625 0.500625-0.1940625 1.610625 0 3.1959375 0.583125 4.39125 1.8075l375.106875 375.050625c11.1403125 11.154375 17.25375 26.353125 17.25375 42.8840625 0 18.7396875-7.94625 37.4653125-21.86625 51.3440625l-35.4253125 35.4796875c-13.89 13.92-32.645625 21.8803125-51.3721875 21.8803125-16.53 0-31.7278125-6.1134375-42.898125-17.240625l-375.0525-375.15c-0.3871875-0.36-0.2765625-0.88875-0.555-1.3059375m473.2115625 278.8378125l-37.258125-37.2309375-60.4021875 61.3603125 36.73125 36.73125c5.806875 5.833125 17.0578125 4.985625 23.728125-1.7090625l35.44875-35.480625c3.6975-3.6946875 5.8078125-8.611875 5.8078125-13.47375-0.0253125-3.988125-1.44375-7.6003125-4.055625-10.1971875m-406.5028125-284.728125l270.6684375 270.6834375 60.43125-61.4025-270.16875-270.15375-60.9309375 60.8728125zM385.173125 228.40312500000005l19.56 71.79375 52.1775-52.179375-71.7375-19.614375zM864.7484375 474.2475c-14.1984375 0-25.8403125-11.5434375-25.89375-25.9359375v-349.670625c0-18.3375-14.893125-33.2296875-33.25875-33.2296875H214.0821875c-18.3375 0-33.2859375 14.89125-33.2859375 33.2296875v570.73125c0 18.3534375 14.9484375 33.25875 33.2859375 33.25875h380.9690625c14.28 0 25.8684375 11.59875 25.8684375 25.880625 0 14.2528125-11.5884375 25.865625-25.8684375 25.865625H210.1371875c-44.70375 0-81.0871875-36.354375-81.0871875-81.08625v-578.596875c0-44.7309375 36.384375-81.0721875 81.0871875-81.0721875h599.375625c44.73375 0 81.103125 36.34125 81.103125 81.073125v353.784375c-0.0590625 14.2246875-11.67 25.768125-25.8675 25.768125" horiz-adv-x="1024" />
<glyph glyph-name="xiangmuguanli" unicode="&#58933;" d="M869.16209412 219.36987305000002l-21.34351731-6.72054292c0.62570572-4.54216003 1.34410858-9.0379715 1.34410859-13.81187437 0-4.70438003-0.78792573-9.31606293-1.45998002-13.78870012l21.48256302-6.7205429a19.23465729 19.23465729 0 0 0 13.07029724-24.4720459 20.43972016 20.43972016 0 0 0-25.51488876-12.4909401l-21.83017731 6.7437172c-4.54216003-8.18052293-10.19668579-15.80486298-16.70866012-22.5022316l13.25569153-17.5661087a18.86386872 18.86386872 0 0 0 3.63836287-14.50710297 18.93339158 18.93339158 0 0 0-8.15734863-12.58363724 20.74098587 20.74098587 0 0 0-28.2494545 4.28724289l-13.37156296 17.63563156a111.23657227 111.23657227 0 0 0-27.4151802-8.8757515v-21.41304016c0-10.70652008-9.06114578-19.44322586-20.25432586-19.44322585-11.17000581 0-20.27750015 8.66718293-20.27750016 19.44322585v21.41304016a112.673378 112.673378 0 0 0-27.39200592 8.8757515l-13.27886581-17.63563156a20.92638016 20.92638016 0 0 0-28.36532593-4.28724289 18.77117157 18.77117157 0 0 0-4.44946289 27.09074021l13.39473725 17.7283287a106.36997224 106.36997224 0 0 0-17.33436585 22.17779159l-21.25082016-6.62784576c-10.70652008-3.38344574-22.10826875 2.27108002-25.53806305 12.4909401a19.28100586 19.28100586 0 0 0 12.97760009 24.4488716l21.34351731 6.60467149c-0.57935715 4.61168289-1.29776001 9.17701721-1.29776001 13.90457153 0 4.75072861 0.76475144 9.29288864 1.45998001 13.85822296l-21.50573731 6.69736862c-10.6833458 3.33709717-16.43056869 14.27536011-12.97760009 24.4720459 3.40662002 10.19668579 14.83154297 15.78168869 25.53806305 12.51411438l21.71430588-6.81324004a107.29694367 107.29694367 0 0 0 16.77818298 22.52540588l-13.25569152 17.51976013a18.95656586 18.95656586 0 0 0 4.44946289 27.16026306 20.8568573 20.8568573 0 0 0 28.36532592-4.33359146l13.27886581-17.63563156a110.5413437 110.5413437 0 0 0 27.4383545 8.92210006v21.36669159c0 10.75286865 9.06114578 19.46640015 20.27750015 19.46640015 11.14683152 0 20.23115158-8.66718293 20.23115158-19.46640015v-21.34351731c9.71002579-1.69172287 18.79434585-4.9361229 27.41518021-8.92210006l13.34838868 17.63563156a20.90320587 20.90320587 0 0 0 28.29580306 4.33359147 18.91021729 18.91021729 0 0 0 4.49581146-27.16026306l-13.4642601-17.65880586c6.62784576-6.76689148 12.69950867-14.04361725 17.33436584-22.1777916l21.34351731 6.5814972a20.46289444 20.46289444 0 0 0 25.51488876-12.51411438c3.4529686-10.15033722-2.41012573-21.11177444-13.09347152-24.42569732z m-131.44454956 47.41458893c-39.14136887 0-70.93648911-30.45101167-70.93648911-67.9933548s31.77194595-67.97018051 70.93648911-67.97018052c39.11819458 0 70.89014053 30.42783738 70.89014053 67.97018052 0 37.54234314-31.7024231 67.9933548-70.89014053 67.9933548zM409.75505066 279.36809920999997c0-19.00291443 15.34137727-34.36746597 34.29794312-34.36746598h82.33823775a214.17675018 214.17675018 0 0 0 28.17993165 68.68858339h-110.5181694a34.29794312 34.29794312 0 0 1-34.29794312-34.32111741zM786.0822792 614.63049317s-286.78178787-0.30126572-271.48675918-1e-8c-16.33787155-0.30126572-24.65744018 8.64400864-24.65744018 8.64400865s-11.40174865 19.72131728-31.98051453 50.68216322c-21.45938873 32.53669739-46.44126893 27.27613449-46.44126893 27.2761345H200.35220337c-58.56142043 0-59.14077758-56.35986328-59.14077759-56.35986328v-509.20858383c0-62.77914048 47.4609375-55.08527756 47.4609375-55.08527756h367.98448563a213.82913589 213.82913589 0 0 0-21.55208588 42.91877747H219.35511779a34.9931717 34.9931717 0 0 0-35.03952026 35.10904311V521.93334961c0 19.39687729 15.6194687 35.01634598 35.03952026 35.01634597h536.67011263c19.42005157 0 35.03952026-15.6194687 35.03952026-35.01634597v-113.66987228a213.20343018 213.20343018 0 0 0 43.08099746-15.99025726V566.89146424c-0.02317429 52.74467468-48.06346894 47.73902893-48.06346894 47.73902892z m-109.63754654-165.13996125H444.07616806c-18.95656586 0-34.29794312-15.34137727-34.29794312-34.3211174s15.34137727-34.32111741 34.29794312-34.3211174h176.98202133a214.91832734 214.91832734 0 0 0 89.4990921 32.44400025c0.02317429 0.62570572 0.18539429 1.22823715 0.18539429 1.87711715 0 18.97974014-15.31820298 34.32111741-34.29794312 34.32111741zM316.61759567 315.98347091999995a36.6153717 36.6153717 0 1 1 0-73.30026627 36.66172028 36.66172028 0 0 1 0 73.30026627z m0 135.82448959a36.66172028 36.66172028 0 1 1-0.04634857-73.32344055 36.66172028 36.66172028 0 0 1 0.04634857 73.32344056z" horiz-adv-x="1025" />
<glyph glyph-name="yilaiguanxi" unicode="&#59020;" d="M561.43847656 581.75390625H907.5078125v-49.43847656H561.43847656zM116.4921875 235.68457031000003h346.06933594V186.24609375H116.4921875zM314.24609375 37.930664060000026h593.26171875v-49.43847656H314.24609375zM116.4921875 779.5078125h593.26171875v-49.43847656H116.4921875zM660.31542969 779.5078125H709.75390625v-148.31542969h-49.43847656zM314.24609375 136.80761718999997h49.43847656V-11.5078125H314.24609375zM116.4921875 779.5078125h49.43847656v-593.26171875H116.4921875zM858.06933594 581.75390625h49.43847656v-593.26171875h-49.43847656zM349.20239283 581.75390625L720.50512721 210.43798803000004l-34.95629909-34.95629832L314.24609375 546.79101563z" horiz-adv-x="1024" />
<glyph glyph-name="erji-xiaxianjilu" unicode="&#60086;" d="M649.109375 162.515625l-110.7421875-110.7421875V489.46875c0 15.8203125-10.546875 26.3671875-26.3671875 26.3671875s-26.3671875-10.546875-26.3671875-26.3671875v-437.6953125l-110.7421875 110.7421875c-10.546875 10.546875-26.3671875 10.546875-36.9140625 0-10.546875-10.546875-10.546875-26.3671875 0-36.9140625l152.9296875-158.203125s5.2734375-5.2734375 10.546875-5.2734375h26.3671875s5.2734375 0 5.2734375 5.2734375l152.9296875 158.203125c10.546875 10.546875 10.546875 26.3671875 0 36.9140625-10.546875 10.546875-26.3671875 10.546875-36.9140625 0zM512 805.875C295.7890625 805.875 116.4921875 626.578125 116.4921875 410.3671875c0-89.6484375 31.640625-179.296875 89.6484375-253.125 5.2734375-5.2734375 10.546875-10.546875 21.09375-10.546875 5.2734375 0 10.546875 0 15.8203125 5.2734375 10.546875 10.546875 10.546875 26.3671875 5.2734375 36.9140625C195.59375 252.1640625 169.2265625 331.265625 169.2265625 410.3671875 169.2265625 600.2109375 322.15625 753.140625 512 753.140625s342.7734375-152.9296875 342.7734375-342.7734375c0-79.1015625-26.3671875-158.203125-79.1015625-216.2109375-10.546875-10.546875-5.2734375-26.3671875 5.2734375-36.9140625 10.546875-10.546875 26.3671875-5.2734375 36.9140625 5.2734375 58.0078125 68.5546875 89.6484375 158.203125 89.6484375 253.125 0 210.9375-179.296875 390.234375-395.5078125 390.234375z" horiz-adv-x="1024" />
<glyph glyph-name="daima" unicode="&#58939;" d="M410.86741638 14.026870970000004h-25.36135911c-65.78600408 0-109.83742476 9.76578892-132.16367663 29.29736674-22.32335509 19.53157782-33.48684311 58.46437811-33.4868431 116.79622829v79.18363809c0 28.76870334-8.12258721 53.57894898-24.3699342 74.43146109-16.24734699 20.85251212-18.23816299 31.27804399-52.31812299 31.27804399v56.61478043c37.25049198 0 40.03357887 8.84388685 54.69565988 26.52731538 14.66280519 17.68487692 21.99239731 43.6835289 21.99239731 77.99595594V609.09183884c0 58.32967759 11.16348802 97.1973002 33.4868431 116.59707426C275.6686325 745.0879629799999 319.72294998 754.78857422 385.50533308 754.78857422h25.3620833v-56.61478043h-27.7396202c-36.98616028 0-61.09465957-5.74287772-72.32260108-17.2228396-11.22794151-11.48285866-16.84263647-35.96431911-16.84263647-73.44438135v-106.10564052c0-46.45502866-9.11473631-77.66644657-27.34565735-93.63352955-18.22657585-15.96925556-30.58571219-27.5172919-83.42525661-34.64555741 51.25427843-6.06876612 63.21727931-17.7493304 82.23829866-35.03662347 19.02174353-17.28874147 28.5326153-48.49943519 28.5326153-93.63352955v-82.74885713c0-37.74366975 5.61469495-62.29248047 16.84263647-73.6406386 11.22794151-11.34815812 35.3364408-17.02368557 72.32260108-17.02368558h27.7396202v-57.01164006z m205.0554961 0h25.36135912c65.78527987 0 109.83742476 9.76578892 132.16367662 29.29736674 22.32335509 19.53157782 33.48684311 58.46437811 33.4868431 116.79622829v79.18363809c0 28.76870334 8.12258721 53.57894898 24.36921001 74.43146109 16.24807119 20.85251212 18.2388872 31.27804399 52.31884718 31.27804399v56.61478043c-37.25049198 0-40.03357887 8.84388685-54.69565988 26.52731538-14.66280519 17.68487692-21.99239731 43.6835289-21.99239731 77.99595594V609.09183884c0 58.32967759-11.16348802 97.1973002-33.4868431 116.59707426C751.12097216 745.0879629799999 707.06955147 754.78857422 641.28499579 754.78857422H615.92218828v-56.61478043h27.73962021c36.98616028 0 61.09393537-5.74287772 72.32187688-17.2228396 11.22794151-11.48285866 16.84336066-35.96431911 16.84336066-73.44438135v-106.10564052c0-46.45502866 9.11473631-77.66644657 27.34348477-93.63352955 18.22874843-15.96925556 30.59005737-27.5172919 83.42742918-34.64555741-51.25500261-6.06876612-63.21727931-17.7493304-82.23902284-35.03662347-19.02101934-17.28874147-28.53189111-48.49943519-28.53189111-93.63352955v-82.74885713c0-37.74366975-5.61541915-62.29248047-16.84336066-73.6406386-11.22794151-11.34815812-35.33571661-17.02368557-72.32187688-17.02368558H615.92218828v-57.01164006zM351.97214138 239.33017515999995h81.33450152V158.89802241999996h-81.33450152V239.33017515999995z m121.73959315 0h81.33450151V158.89802241999996H473.71173453V239.33017515999995z m121.73886895 0h81.33450151V158.89802241999996h-81.33450151V239.33017515999995z" horiz-adv-x="1027" />
<glyph glyph-name="wendangxiazai1" unicode="&#58920;" d="M275.681468-72.553688h182.140477a27.525872 27.525872 0 0 1 27.441321 27.441321 27.516477 27.516477 0 0 1-27.441321 27.441321H275.681468c-58.997431 0-107.022092 48.024661-107.022092 107.031486V700.989064c0 58.997431 48.015266 107.022092 107.022092 107.022092h487.424c58.997431 0 107.022092-48.015266 107.022092-107.022092v-224.312367a27.525872 27.525872 0 0 1 27.441321-27.441321 27.516477 27.516477 0 0 1 27.441321 27.441321V700.989064c0 89.181945-72.713394 161.904734-161.89534 161.904734H275.681468c-89.181945 0-161.904734-72.722789-161.904734-161.904734v-611.628624c0.685798-89.181945 72.722789-161.914128 161.904734-161.914128zM290.017468 601.858349h398.23266a27.525872 27.525872 0 0 1 27.441322 27.441321 27.516477 27.516477 0 0 1-27.441322 27.441321h-398.23266a27.525872 27.525872 0 0 1-27.441321-27.441321 27.525872 27.525872 0 0 1 27.441321-27.441321zM546.928734 412.014385a27.525872 27.525872 0 0 1-27.450716 27.441321H290.017468c-15.08756 0-27.441321-12.344367-27.441321-27.441321s12.344367-27.441321 27.441321-27.441321h228.784147c15.773358 0.009394 28.127119 12.353761 28.127119 27.441321zM290.017468 222.161028c-15.08756 0-27.441321-12.344367-27.441321-27.441322s12.344367-27.441321 27.441321-27.441321h70.317798c15.08756 0 27.441321 12.344367 27.441321 27.441321s-12.344367 27.441321-27.441321 27.441322h-70.317798zM715.353248 381.106495c-119.34767 0-217.125578-97.204844-217.125578-217.125578 0-119.920734 97.214239-217.134972 217.125578-217.134972 119.338275 0 217.134972 97.223633 217.134972 217.134972 0 119.338275-97.223633 217.125578-217.134972 217.125578z m0-383.643009c-91.756037 0-165.953761 74.18833-165.953762 165.953762 0 91.756037 74.761394 165.953761 165.953762 165.953761s165.953761-74.197725 165.953761-165.953761-74.207119-165.953761-165.953761-165.953762zM704.371083 63.891963c0.685798 0 0.685798 0 0 0l1.371596-1.371596 0.685798-0.676404s0.676404 0 0.676404-0.685798c0 0 0.685798 0 0.685798-0.685798 0 0 0.685798 0 0.685798-0.676404 0 0 0.676404 0 0.676404-0.685798 0 0 0.695193 0 0.695192-0.685798h12.344367s0.676404 0 0.676404 0.685798c0 0 0.685798 0 0.685798 0.685798 0 0 0.685798 0 0.685798 0.676404 0 0 0.676404 0 0.676404 0.685798 0 0 0.685798 0 0.685798 0.685798l0.685798 0.676404 0.685799 0.695193 0.685798 0.676403 93.982532 93.306129c6.857982 6.857982 6.857982 18.525945 0 25.383926-6.848587 6.848587-18.525945 6.848587-25.383927 0l-63.11222-63.121614V251.697321c0 9.601174-8.238972 17.840147-17.830752 17.840147-9.601174 0-17.840147-8.238972-17.840147-17.840147v-132.236917L634.363303 182.582018c-6.857982 6.848587-18.525945 6.848587-25.383927 0-6.857982-6.857982-6.857982-18.525945 0-25.383926l95.391707-93.306129z" horiz-adv-x="1024" />
<glyph glyph-name="lishi" unicode="&#59118;" d="M512-4.125C297.636875-4.125 123.875 169.63687500000003 123.875 384S297.636875 772.125 512 772.125s388.125-173.761875 388.125-388.125c0-10.918125-0.455625-21.718125-1.333125-32.4l-50.45625 4.168125c0.77625 9.34875 1.164375 18.765 1.164375 28.231875 0 186.40125-151.09875 337.5-337.5 337.5S174.5 570.40125 174.5 384s151.09875-337.5 337.5-337.5v-50.625z m-25.3125 413.4375V603.375h50.625v-244.6875H343.25v50.625h143.4375z m92.8125-168.75v50.625h320.625v-50.625H579.5z m0-118.125v50.625h320.625v-50.625H579.5z m0-118.125v50.625h320.625v-50.625H579.5z" horiz-adv-x="1024" />
<glyph glyph-name="fangda" unicode="&#58890;" d="M970.14518518-29.483614819999957l-266.99851851 266.87715557c54.61333333 64.80782222 87.5026963 148.4269037 87.5026963 239.69185184 0 205.58885925-167.23816297 372.94838518-372.94838519 372.94838519S44.87395555 682.79561482 44.87395555 477.08539259s167.23816297-372.94838518 372.9483852-372.94838518c92.35721482 0 176.82583703 33.7389037 241.99774814 89.56586667l266.75579259-266.7557926c5.94678518-6.06814815 13.83537778-8.98085925 21.72397037-8.98085926s15.77718518 3.03407408 21.72397037 8.98085926c12.1362963 12.01493333 12.1362963 31.55437037 0.12136296 43.5693037zM417.82234075 165.78939259000003c-171.60722963 0-311.296 139.68877037-311.296 311.296 0 171.72859259 139.68877037 311.296 311.296 311.296s311.296-139.68877037 311.296-311.296-139.68877037-311.296-311.296-311.296zM564.18607408 497.7170963h-121.12023705v121.12023703c0 16.99081482-13.83537778 30.82619259-30.82619258 30.82619259s-30.82619259-13.83537778-30.8261926-30.82619259v-121.12023703h-121.12023703c-16.99081482 0-30.82619259-13.83537778-30.8261926-30.8261926s13.83537778-30.82619259 30.8261926-30.82619259h121.12023703v-121.12023703c0-16.99081482 13.83537778-30.82619259 30.8261926-30.8261926s30.82619259 13.83537778 30.82619258 30.8261926v121.12023703H564.18607408c16.99081482 0 30.82619259 13.83537778 30.82619259 30.82619259S581.17688889 497.7170963 564.18607408 497.7170963z" horiz-adv-x="1024" />
<glyph glyph-name="suoxiao" unicode="&#58895;" d="M970.14518518-29.483614819999957l-266.99851851 266.87715557c54.61333333 64.80782222 87.5026963 148.4269037 87.5026963 239.69185184 0 205.58885925-167.23816297 372.94838518-372.94838519 372.94838519S44.87395555 682.79561482 44.87395555 477.08539259s167.23816297-372.94838518 372.9483852-372.94838518c92.35721482 0 176.82583703 33.7389037 241.99774814 89.56586667l266.75579259-266.7557926c5.94678518-6.06814815 13.83537778-8.98085925 21.72397037-8.98085926s15.77718518 3.03407408 21.72397037 8.98085926c12.1362963 12.01493333 12.1362963 31.55437037 0.12136296 43.5693037zM417.82234075 165.78939259000003c-171.60722963 0-311.296 139.68877037-311.296 311.296 0 171.72859259 139.68877037 311.296 311.296 311.296s311.296-139.68877037 311.296-311.296-139.68877037-311.296-311.296-311.296zM564.18607408 497.7170963H260.41457778c-16.99081482 0-30.82619259-13.83537778-30.8261926-30.8261926s13.83537778-30.82619259 30.8261926-30.82619259H564.18607408c16.99081482 0 30.82619259 13.83537778 30.82619259 30.82619259S581.17688889 497.7170963 564.18607408 497.7170963z" horiz-adv-x="1024" />
<glyph glyph-name="daohang" unicode="&#58889;" d="M838.37634278 426.10510254H183.975708c-23.23608398 0-42.26989747-19.03381348-42.26989745-42.26989746 0-23.23608398 19.03381348-42.26989747 42.26989746-42.26989747h654.40063477c23.23608398 0 42.26989747 19.03381348 42.26989745 42.26989747-0.08239747 23.23608398-19.03381348 42.26989747-42.26989745 42.26989746zM838.37634278 713.83703614H183.975708c-23.23608398 0-42.26989747-19.03381348-42.26989745-42.26989747 0-23.23608398 19.03381348-42.26989747 42.26989746-42.26989746h654.40063477c23.23608398 0 42.26989747 19.03381348 42.26989745 42.26989746-0.08239747 23.31848145-19.03381348 42.26989747-42.26989745 42.26989746zM838.37634278 138.29077148H183.975708c-23.23608398 0-42.26989747-19.03381348-42.26989745-42.26989746 0-23.23608398 19.03381348-42.26989747 42.26989746-42.26989746h654.40063477c23.23608398 0 42.26989747 19.03381348 42.26989745 42.26989747-0.08239747 23.23608398-19.03381348 42.26989747-42.26989745 42.26989745z" horiz-adv-x="1024" />
<glyph glyph-name="shijianguanli" unicode="&#58906;" d="M567.03125 58.36458332999996H207.5c-54.375 0-98.625 44.25-98.625 98.625V624.61458333c0 54.375 44.25 98.625 98.625 98.625h528c54.375 0 98.625-44.25 98.625-98.625v-187.875c0-12.9375-10.5-23.4375-23.4375-23.4375s-23.4375 10.5-23.4375 23.4375V624.61458333c0 28.5-23.25 51.75-51.75 51.75H207.5c-28.5 0-51.75-23.25-51.75-51.75v-467.625c0-28.5 23.25-51.75 51.75-51.75h359.53125c12.9375 0 23.4375-10.5 23.4375-23.4375s-10.5-23.4375-23.4375-23.4375zM810.6875 549.89583333H133.90625c-12.9375 0-23.4375 10.5-23.4375 23.4375s10.5 23.4375 23.4375 23.4375h676.78125c12.9375 0 23.4375-10.5 23.4375-23.4375s-10.5-23.4375-23.4375-23.4375zM588.03125 624.70833333c-12.9375 0-23.4375 10.5-23.4375 23.4375V752.20833333c0 12.9375 10.5 23.4375 23.4375 23.4375s23.4375-10.5 23.4375-23.4375v-104.0625c0-12.9375-10.5-23.4375-23.4375-23.4375zM355.8125 624.70833333c-12.9375 0-23.4375 10.5-23.4375 23.4375V752.20833333c0 12.9375 10.5 23.4375 23.4375 23.4375s23.4375-10.5 23.4375-23.4375v-104.0625c0-12.9375-10.5-23.4375-23.4375-23.4375zM282.78125 421.64583333h-29.15625c-4.875 0-8.90625 4.03125-8.90625 8.90625V459.70833333c0 4.875 4.03125 8.90625 8.90625 8.90625h29.15625c4.875 0 8.90625-4.03125 8.90625-8.90625v-29.15625c-0.09375-4.96875-4.03125-8.90625-8.90625-8.90625zM443.5625 421.64583333h-29.0625c-4.875 0-8.90625 4.03125-8.90625 8.90625V459.70833333c0 4.875 4.03125 8.90625 8.90625 8.90625h29.0625c4.875 0 8.90625-4.03125 8.90625-8.90625v-29.15625c0-4.96875-4.03125-8.90625-8.90625-8.90625zM604.4375 421.64583333h-29.15625c-4.875 0-8.90625 4.03125-8.90625 8.90625V459.70833333c0 4.875 4.03125 8.90625 8.90625 8.90625h29.15625c4.875 0 8.90625-4.03125 8.90625-8.90625v-29.15625c0-4.96875-4.03125-8.90625-8.90625-8.90625zM282.78125 309.14583332999996h-29.15625c-4.875 0-8.90625 4.03125-8.90625 8.90625V347.20833332999996c0 4.875 4.03125 8.90625 8.90625 8.90625h29.15625c4.875 0 8.90625-4.03125 8.90625-8.90625v-29.15625c-0.09375-4.96875-4.03125-8.90625-8.90625-8.90625zM443.5625 309.14583332999996h-29.0625c-4.875 0-8.90625 4.03125-8.90625 8.90625V347.20833332999996c0 4.875 4.03125 8.90625 8.90625 8.90625h29.0625c4.875 0 8.90625-4.03125 8.90625-8.90625v-29.15625c0-4.96875-4.03125-8.90625-8.90625-8.90625zM280.90625 196.64583332999996h-29.15625c-4.875 0-8.90625 4.03125-8.90625 8.90625V234.70833332999996c0 4.875 4.03125 8.90625 8.90625 8.90625h29.15625c4.875 0 8.90625-4.03125 8.90625-8.90625v-29.15625c-0.09375-4.875-4.03125-8.90625-8.90625-8.90625zM441.6875 196.64583332999996h-29.0625c-4.875 0-8.90625 4.03125-8.90625 8.90625V234.70833332999996c0 4.875 4.03125 8.90625 8.90625 8.90625h29.0625c4.875 0 8.90625-4.03125 8.90625-8.90625v-29.15625c0-4.875-4.03125-8.90625-8.90625-8.90625zM695.9375 20.77083332999996c-62.8125 0-121.875 24.46875-166.21875 68.90625-44.4375 44.4375-68.90625 103.5-68.90625 166.21875s24.46875 121.875 68.90625 166.21875c44.4375 44.4375 103.5 68.90625 166.21875 68.90625s121.875-24.46875 166.21875-68.90625c44.4375-44.4375 68.90625-103.5 68.90625-166.21875s-24.46875-121.875-68.90625-166.21875c-44.34375-44.4375-103.40625-68.90625-166.21875-68.90625z m0 423.375c-103.78125 0-188.25-84.46875-188.25-188.25s84.46875-188.25 188.25-188.25S884.1875 152.11458332999996 884.1875 255.89583332999996s-84.46875 188.25-188.25 188.25zM787.625 177.23958332999996c-1.59375 0-3.1875 0.1875-4.78125 0.46875L695.75 195.80208332999996c-13.5 2.8125-23.25 14.8125-23.25 28.59375v86.71875c0 12.9375 10.5 23.4375 23.4375 23.4375s23.4375-10.5 23.4375-23.4375v-72.28125l73.03125-15.1875c12.65625-2.625 20.8125-15 18.1875-27.75-2.34375-11.0625-12.09375-18.65625-22.96875-18.65625z m-82.3125 64.5z" horiz-adv-x="1024" />
<glyph glyph-name="shujuku" unicode="&#61172;" d="M512 772.528125c-202.14375 0-354.58125-72.1875-354.58125-167.896875v-441.2625c0-95.71875 152.446875-167.896875 354.58125-167.896875s354.58125 72.1875 354.58125 167.896875V604.63125c0 95.71875-152.4375 167.896875-354.58125 167.896875zM512 365.25c-149.240625 0-290.353125 50.371875-290.353125 103.640625V505.875c64.940625-43.4625 172.153125-69.159375 290.353125-69.159375S737.403125 462.440625 802.353125 505.875v-37.05C802.353125 415.584375 661.240625 365.25 512 365.25z m0-152.8125c-149.240625 0-290.353125 50.371875-290.353125 103.659375V370.125c64.93125-43.4625 172.14375-69.159375 290.353125-69.159375s225.421875 25.696875 290.353125 69.159375v-54C802.353125 262.8375 661.240625 212.4375 512 212.4375z m-290.353125 4.9125C286.596875 173.91562499999998 393.8 148.21875 512 148.21875s225.403125 25.696875 290.353125 69.15v-54c0-53.2875-141.1125-103.659375-290.353125-103.659375s-290.353125 50.371875-290.353125 103.659375zM512 500.971875c-149.240625 0-290.353125 50.38125-290.353125 103.659375S362.759375 708.290625 512 708.290625s290.353125-50.38125 290.353125-103.659375S661.240625 500.971875 512 500.971875z m0 0" horiz-adv-x="1024" />
<glyph glyph-name="tiaoduzhongxin" unicode="&#59026;" d="M646.435754 661.452514H503.418994c-57.206704 0-108.692737 51.486034-108.692737 108.692737 0 57.206704 51.486034 108.692737 108.692737 108.692738h143.01676c57.206704 0 108.692737-51.486034 108.692738-108.692738 0-62.927374-51.486034-108.692737-108.692738-108.692737z m0-400.446927H503.418994c-57.206704 0-108.692737 51.486034-108.692737 108.692737 0 57.206704 51.486034 108.692737 108.692737 108.692737h143.01676c57.206704 0 108.692737-51.486034 108.692738-108.692737 0-57.206704-51.486034-108.692737-108.692738-108.692737z m0-389.005587H503.418994c-57.206704 0-108.692737 51.486034-108.692737 108.692737 0 57.206704 51.486034 108.692737 108.692737 108.692738h143.01676c57.206704 0 108.692737-51.486034 108.692738-108.692738 0-57.206704-51.486034-108.692737-108.692738-108.692737z m-411.888268 80.089385c-125.854749 0-234.547486 102.972067-234.547486 234.547487 0 125.854749 102.972067 234.547486 234.547486 234.547486h40.044693c22.882682 0 40.044693-17.162011 40.044693-40.044693 0-22.882682-17.162011-40.044693-40.044693-40.044693h-40.044693c-85.810056 0-154.458101-68.648045-154.458101-154.4581 0-85.810056 68.648045-154.458101 154.458101-154.458101 22.882682 0 40.044693-17.162011 40.044693-40.044693 0-22.882682-17.162011-40.044693-40.044693-40.044693z m0 0M343.240223-2.145251l-114.413407-120.134079v234.547486l114.413407-114.413407z m566.346369 360.402234h-40.044693c-22.882682 0-40.044693 17.162011-40.044692 40.044693 0 22.882682 17.162011 40.044693 40.044692 40.044693h40.044693c85.810056 0 154.458101 68.648045 154.458101 154.4581 0 85.810056-68.648045 154.458101-154.458101 154.458101-22.882682 0-40.044693 17.162011-40.044693 40.044693 0 22.882682 17.162011 40.044693 40.044693 40.044692C1035.441341 827.351955 1144.134078 724.379888 1144.134078 592.804469s-102.972067-234.547486-234.547486-234.547486z m0 0M800.893855 775.865922L915.307263 896v-234.547486l-114.413408 114.413408z m0 0" horiz-adv-x="1144" />
<glyph glyph-name="shubiaozhizhen" unicode="&#59265;" d="M777.06666667 303.67999999999995c9.81333333-9.49333333 12.05333333-20.48 6.72-32.85333333-5.44-12.69333333-14.72-18.98666667-28.16-18.98666667H573.65333333l95.78666667-226.66666667c3.2-7.89333333 3.2-15.68 0-23.36-3.2-7.57333333-8.64-13.22666667-16.21333333-16.64l-84.37333334-35.73333333c-7.89333333-3.2-15.68-3.2-23.36 0-7.57333333 3.2-13.22666667 8.64-16.64 16.21333333l-90.98666666 215.25333334-148.48-148.8c-5.97333333-5.97333333-13.22666667-9.06666667-21.44-9.06666667-3.84 0-7.57333333 0.85333333-11.41333334 2.45333333-12.69333333 5.44-18.98666667 14.72-18.98666666 28.16V769.81333333c0 13.33333333 6.29333333 22.72 18.98666666 28.16 3.84 1.6 7.57333333 2.45333333 11.41333334 2.45333334 8.64 0 15.68-2.98666667 21.44-9.06666667l487.68-487.68z" horiz-adv-x="1024" />
<glyph glyph-name="yuandian" unicode="&#59330;" d="M881.38666668 598.18666667C919.46666667 532.8000000100001 938.66666667 461.44 938.66666667 384s-19.09333334-148.80000001-57.28000001-214.18666667C843.20000001 104.53333333 791.46666667 52.69333332999997 726.18666667 14.613333320000038S589.44-42.66666667000004 512-42.66666667000004s-148.80000001 19.09333334-214.18666667 57.28000001c-65.28 38.08000001-117.01333334 89.81333333-155.30666666 155.30666665C104.42666666 235.19999999000004 85.33333333 306.55999999999995 85.33333333 384c0 77.33333334 19.09333334 148.69333333 57.28000001 214.18666667 38.08000001 65.28 89.81333333 117.01333334 155.30666665 155.30666666C363.19999999 791.46666667 434.56 810.66666667 512 810.66666667c77.33333334 0 148.69333333-19.09333334 214.18666667-57.28000001C791.46666667 715.2000000099999 843.20000001 663.46666667 881.38666668 598.18666667z m-217.70666668 47.36c-46.29333333 26.98666668-96.85333333 40.53333333-151.68 40.53333332s-105.38666667-13.54666668-151.68-40.53333332-82.98666667-63.68000001-109.97333334-109.97333335-40.53333333-96.85333333-40.53333332-151.67999998c0-54.82666667 13.54666668-105.38666667 40.53333332-151.68s63.68000001-82.98666667 109.97333334-109.97333334c46.29333333-26.98666668 96.85333333-40.53333333 151.68-40.53333333s105.38666667 13.54666668 151.68 40.53333333c46.29333333 26.98666668 82.98666667 63.68000001 109.97333334 109.97333334 26.98666668 46.29333333 40.53333333 96.85333333 40.53333332 151.68s-13.54666668 105.38666667-40.53333335 151.68c-27.09333333 46.29333333-63.78666667 82.98666667-109.97333331 109.97333333z m-51.09333334-161.06666667c27.84000001-27.84000001 41.70666668-61.33333334 41.70666667-100.58666668s-13.86666667-72.74666667-41.70666667-100.58666666c-27.84000001-27.84000001-61.33333334-41.70666668-100.58666666-41.70666667s-72.74666667 13.86666667-100.58666668 41.70666667c-27.84000001 27.84000001-41.70666668 61.33333334-41.70666665 100.58666668s13.86666667 72.74666667 41.70666667 100.58666666c27.84000001 27.84000001 61.33333334 41.70666668 100.58666666 41.70666668s72.74666667-13.86666667 100.58666668-41.70666668z" horiz-adv-x="1024" />
<glyph glyph-name="-Tree-Structure" unicode="&#58935;" d="M632 714v-105l-240-167.82V504H92v-240h300V326.82000000000005l240-167.82V54h300v240H632V231.17999999999995L413.57 384 632 536.8199999999999V474h300V714H632z m60-60h180v-120h-180V654zM152 444h180v-120H152v120z m540-210h180v-120h-180v120z" horiz-adv-x="1024" />
<glyph glyph-name="xia" unicode="&#58907;" d="M512 271.67999999999995l264.32 293.76a32 32 0 1 0 47.36-42.88l-288-320a32 32 0 0 0-47.36 0l-288 320a32 32 0 0 0 47.36 42.88z" horiz-adv-x="1024" />
<glyph glyph-name="zanting" unicode="&#58900;" d="M899.09375001 547.59375001c-21.09375001 49.96875001-51.375 94.875-89.90625001 133.40624999-38.53125001 38.53125001-83.4375 68.8125-133.40625001 89.90625001C624.03125001 792.75 569.09375001 803.90625001 512.46875001 803.90625001c-56.625 0-111.5625-11.0625-163.31250002-33.00000002-49.96875001-21.09375001-94.875-51.375-133.40624999-89.90624999-38.53125001-38.53125001-68.8125-83.4375-89.90625001-133.40625001-21.9375-51.75-33-106.6875-32.99999998-163.31249998s11.0625-111.5625 33-163.31250002c21.09375001-49.96875001 51.375-94.875 89.90624999-133.40624999s83.4375-68.8125 133.40625001-89.90625001c51.75-21.9375 106.6875-33 163.31249998-32.99999998 56.625 0 111.5625 11.0625 163.31250002 33 49.96875001 21.09375001 94.875 51.375 133.40624999 89.90624999s68.8125 83.4375 89.90625001 133.40625001c21.9375 51.75 33 106.6875 32.99999998 163.31249998s-11.0625 111.5625-33 163.31250002zM761.46875001 135.1875c-66.46875001-66.46875001-154.96875001-103.125-249.00000002-103.125s-182.53125001 36.65625001-248.99999998 103.125c-66.46875001 66.46875001-103.125 154.96875001-103.12500002 249 0 94.03125001 36.65625001 182.53125001 103.125 249 66.46875001 66.46875001 154.96875001 103.125 249.00000002 103.125s182.53125001-36.65625001 248.99999998-103.125c66.46875001-66.46875001 103.125-154.96875001 103.12500002-249 0-94.03125001-36.5625-182.4375-103.125-249zM582.875 532.96875001H442.0625c-43.3125 0-78.375-35.0625-78.375-78.37500002v-140.71874999c0-43.3125 35.0625-78.375 78.375-78.375h140.71875001c43.3125 0 78.375 35.0625 78.37499998 78.375V454.59375001c0 43.3125-35.0625 78.375-78.28124999 78.37499998z" horiz-adv-x="1024" />
<glyph glyph-name="yonghu3" unicode="&#58954;" d="M133.7-35.4c0 208.6 169.1 377.6 377.6 377.6s377.6-169.1 377.6-377.6h-75.5c0 166.8-135.3 302.1-302.1 302.1S209.2 131.4 209.2-35.4h-75.5z m377.6 377.7c-125.1 0-226.6 101.5-226.6 226.6s101.4 226.6 226.6 226.6S737.9 694 737.9 568.9c0-125.2-101.4-226.6-226.6-226.6z m0 75.5c83.4 0 151.1 67.6 151.1 151.1S594.8 720 511.3 720c-83.4 0-151.1-67.6-151.1-151.1s67.7-151.1 151.1-151.1z" horiz-adv-x="1024" />
<glyph glyph-name="shanchu2" unicode="&#59086;" d="M512 753.140625c49.85046387 0 98.21777344-9.72290039 143.70117188-29.00390625 43.91784668-18.62182617 83.46862793-45.23620606 117.33398437-79.1015625 33.94775391-33.94775391 60.56213379-73.4161377 79.1015625-117.33398438C871.41772461 482.21777344 881.140625 433.85046387 881.140625 384s-9.72290039-98.21777344-29.00390625-143.70117188c-18.62182617-43.91784668-45.23620606-83.46862793-79.1015625-117.33398437-33.94775391-33.94775391-73.4161377-60.56213379-117.33398438-79.1015625C610.21777344 24.58227538999995 561.85046387 14.859375 512 14.859375s-98.21777344 9.72290039-143.70117188 29.00390625c-43.91784668 18.62182617-83.46862793 45.23620606-117.33398437 79.1015625-33.94775391 33.94775391-60.56213379 73.4161377-79.1015625 117.33398438C152.58227539 285.78222656 142.859375 334.14953613 142.859375 384s9.72290039 98.21777344 29.00390625 143.70117188c18.62182617 43.91784668 45.23620606 83.46862793 79.1015625 117.33398437s73.4161377 60.56213379 117.33398438 79.1015625C413.78222656 743.41772461 462.14953613 753.140625 512 753.140625m0 52.734375C278.97998047 805.875 90.125 617.02001953 90.125 384s188.85498047-421.875 421.875-421.875 421.875 188.85498047 421.875 421.875S745.02001953 805.875 512 805.875zM719.64160156 410.3671875H304.35839844c-14.50195313 0-26.3671875-11.86523438-26.3671875-26.3671875s11.86523438-26.3671875 26.3671875-26.3671875h415.28320312c14.50195313 0 26.3671875 11.86523438 26.3671875 26.3671875s-11.86523438 26.3671875-26.3671875 26.3671875z" horiz-adv-x="1024" />
<glyph glyph-name="guanbi" unicode="&#59106;" d="M571.904 394.24L885.76 708.096c15.872 15.872 15.872 41.984 0 57.856l-1.536 1.536c-15.872 15.872-41.984 15.872-57.856 0L512 453.632 198.144 768c-15.872 15.872-41.984 15.872-57.856 0l-1.536-1.536a40.192 40.192 0 0 1 0-57.856L452.608 394.24l-313.856-313.856c-15.872-15.872-15.872-41.984 0-57.856l1.536-1.536c15.872-15.872 41.984-15.872 57.856 0l313.856 313.856 313.856-313.856c15.872-15.872 41.984-15.872 57.856 0l1.536 1.536c15.872 15.872 15.872 41.984 0 57.856L571.904 394.24z" horiz-adv-x="1024" />
<glyph glyph-name="cuowuguanbishibai" unicode="&#59229;" d="M512-36.46875001000001c-56.71875001 0-111.84375001 11.15625001-163.68749999 33.09375001-50.06250001 21.1875-95.0625 51.46875001-133.59375002 90.09375002-38.625 38.53125001-68.90625001 83.53125001-90.09374999 133.59374997C102.6875 272.15624999 91.53124999 327.28124999 91.53124999 384s11.15625001 111.84375001 33.09375001 163.68749999c21.1875 50.06250001 51.46875001 95.0625 90.09375002 133.68750001 38.625 38.625 83.53125001 68.90625001 133.68749997 90.09375001 51.75 21.84375002 106.875 33 163.59375001 32.99999998s111.84375001-11.15625001 163.68749999-33.09374999c50.06250001-21.1875 95.0625-51.46875001 133.68750001-90.09375002 38.625-38.625 68.90625001-83.53125001 90.09375001-133.68749997 21.9375-51.84375001 33.09375001-106.96875002 33.09374999-163.68750002s-11.15625001-111.84375001-33.09374999-163.68749998c-21.28125001-49.96875001-51.56250002-94.96875001-90.1875-133.50000002-38.625-38.625-83.53125001-68.90625001-133.6875-90.09374999-51.75-21.9375-106.875-33.09375001-163.59375001-33.09375001z m0 780c-198.28125001 0-359.53125001-161.25-359.53125001-359.53124999s161.25-359.53125001 359.53125001-359.53125001 359.53125001 161.25 359.53125001 359.53125001-161.25 359.53125001-359.53125001 359.53124999zM681.6875 511.3125L384.6875 214.3125c-11.625-11.625-30.75-11.625-42.46875001 0-11.625 11.625-11.625 30.75 0 42.46875001L639.3125 553.6875c11.625 11.625 30.75 11.625 42.46875001 0 11.625-11.625 11.625-30.75-0.09375001-42.375zM384.6875 553.6875L681.6875 256.6875c11.625-11.625 11.625-30.75 0-42.46875001-11.625-11.625-30.75-11.625-42.46875001 0L342.3125 511.3125c-11.625 11.625-11.625 30.75 0 42.46875001 11.625 11.625 30.75 11.625 42.375-0.09375001z" horiz-adv-x="1024" />
<glyph glyph-name="icon_paging_left" unicode="&#58962;" d="M316.28543091 384l209.75046157-209.7496891c12.87099838-12.87099838 12.87099838-33.73944282 0-46.61121369-12.87099838-12.87099838-33.7402153-12.87099838-46.61121367 0l-233.05529595 233.05606842c-12.87099838 12.87022591-12.87099838 33.73944282 0 46.61044121l233.05606841 233.05529595c12.87022591 12.87099838 33.73944282 12.87099838 46.61044121 0 12.87099838-12.87177085 12.87099838-33.7402153 0-46.61121369L316.28543091 384zM548.02828979 384l209.75046158-209.7496891c12.87099838-12.87099838 12.87099838-33.73944282 0-46.61121369-12.87099838-12.87099838-33.7402153-12.87099838-46.61121368 0l-233.05529595 233.05606842c-12.87099838 12.87022591-12.87099838 33.73944282 0 46.61044121l233.05606843 233.05529595c12.87022591 12.87099838 33.73944282 12.87099838 46.6104412 0 12.87099838-12.87177085 12.87099838-33.7402153 0-46.61121369L548.02828979 384z" horiz-adv-x="1024" />
<glyph glyph-name="icon_paging_left-copy" unicode="&#61173;" d="M707.71456909 384l-209.75046157 209.74968909c-12.87099838 12.87099838-12.87099838 33.73944282 0 46.6112137 12.87099838 12.87099838 33.7402153 12.87099838 46.61121367 0l233.05529595-233.05606842c12.87099838-12.87022591 12.87099838-33.73944282 0-46.61044121l-233.05606841-233.05529595c-12.87022591-12.87099838-33.73944282-12.87099838-46.61044121 0-12.87099838 12.87177085-12.87099838 33.7402153 0 46.6112137L707.71456909 384zM475.97171022 384l-209.75046159 209.7496891c-12.87099838 12.87099838-12.87099838 33.73944282 0 46.6112137 12.87099838 12.87099838 33.7402153 12.87099838 46.61121368-1e-8l233.05529595-233.05606842c12.87099838-12.87022591 12.87099838-33.73944282 0-46.61044121l-233.05606843-233.05529596c-12.87022591-12.87099838-33.73944282-12.87099838-46.6104412 0-12.87099838 12.87177085-12.87099838 33.7402153 0 46.6112137L475.97171022 384z" horiz-adv-x="1024" />
<glyph glyph-name="rizhishezhi" unicode="&#58899;" d="M862.18464985 213.88488819999998c-27.10318786 0-44.04079497 29.34293377-30.48920105 52.81124781a35.20247105 35.20247105 0 0 1-12.88796551 48.09043657l-47.23073611 27.26909495a35.20247105 35.20247105 0 0 1-48.09043656-12.88796551c-13.55159393-23.46831402-47.42680814-23.46831402-60.97840207 0a35.20247105 35.20247105 0 0 1-48.09043655 12.88796551l-47.23073612-27.26909495a35.20247105 35.20247105 0 0 1-12.8879655-48.09043657c13.55159393-23.46831402-3.38601318-52.81124779-30.48920105-52.81124781a35.21755351 35.21755351 0 0 1-35.21001226-35.21001229v-54.5381899a35.21755351 35.21755351 0 0 1 35.21001226-35.21001229c27.10318786 0 44.04079497-29.34293377 30.48920105-52.81124779a35.20247105 35.20247105 0 0 1 12.8879655-48.09043658l47.23073612-27.26909496a35.20247105 35.20247105 0 0 1 48.09043655 12.88796552c13.55159393 23.46831402 47.42680814 23.46831402 60.97840207 0a35.20247105 35.20247105 0 0 1 48.09043656-12.88796552l47.23073611 27.26909496a35.20247105 35.20247105 0 0 1 12.88796551 48.09043658c-13.55159393 23.46831402 3.38601318 52.81124779 30.48920105 52.81124779a35.21755351 35.21755351 0 0 1 35.21001227 35.21001229v54.5381899a35.21755351 35.21755351 0 0 1-35.21001227 35.21001229zM730.69572844 86.09871170999998c-36.06971274-20.82134158-82.19188773-8.46880354-103.01322933 27.60090918-20.82134158 36.06971274-8.46880354 82.19188773 27.60090917 103.01322934 36.06971274 20.82134158 82.19188773 8.46880354 103.01322933-27.60090921 20.82888283-36.06217149 8.46880354-82.18434651-27.60090917-103.01322931zM284.97875142 640.14548662h407.2265288v-60.32985612h-407.2265288zM284.97875142 483.37081426h407.2265288v-60.32985612h-407.2265288zM284.97875142 323.72293250999996h226.23696046v-60.32985612h-226.23696046zM790.24129642 811.96491684h-603.2985612c-33.26437441 0-60.32985613-27.0654817-60.32985613-60.32985611v-693.79334537c0-33.26437441 27.0654817-60.32985613 60.32985613-60.32985613h264.21460489a30.16492806 30.16492806 0 0 1 0 60.32985613H186.94273522v693.79334537h603.2985612v-328.59410259a30.16492806 30.16492806 0 0 1 60.32985612 0V751.63506073c0 33.26437441-27.0654817 60.32985613-60.32985612 60.32985611z" horiz-adv-x="1024" />
<glyph glyph-name="icon-test" unicode="&#58901;" d="M690.76953125 34.28320312000005h105.38085938v-43.68164062H577.56640625V209.09765625h43.68164063v-156.88476563C760.81835938 98.1796875 861.71679688 229.04882812000005 861.71679688 384c0 193.18359375-156.62109375 349.71679688-349.71679688 349.71679688-7.3828125 0-14.58984375-0.61523438-21.88476563-1.14257813V776.34375c7.29492188 0.43945313 14.50195313 1.14257813 21.88476563 1.14257813 217.265625 0 393.48632813-176.1328125 393.48632813-393.48632813 0-152.84179688-87.45117188-284.67773438-214.71679688-349.71679688zM402.6640625 715.78710938C263.18164062 669.8203125 162.28320312 538.95117188 162.28320312 384c0-193.18359375 156.62109375-349.71679688 349.71679688-349.71679688 7.3828125 0 14.58984375 0.61523438 21.88476563 1.14257813v-43.68164062c-7.29492188-0.43945313-14.50195313-1.14257813-21.88476563-1.14257813-217.265625-0.08789063-393.48632813 176.1328125-393.48632813 393.3984375 0 152.84179688 87.36328125 284.67773438 214.71679688 349.71679688H227.84960937V777.48632813h218.58398438V558.90234375h-43.68164063V715.78710938z" horiz-adv-x="1024" />
<glyph glyph-name="zanting1" unicode="&#59016;" d="M435.5 544.6800000000001c-17.1 0-31.02-11.94-31.02-26.76v-267.84c0-14.76 13.86-26.76 31.02-26.76 17.1 0 30.96 12 30.96 26.76V517.9200000000001c0 14.82-13.92 26.76-30.96 26.76z m153.96 0c-17.1 0-30.96-11.94-30.96-26.76v-267.84c0-14.76 13.8-26.76 30.96-26.76s31.02 12 31.02 26.76V517.9200000000001c0 14.82-13.92 26.76-31.02 26.76zM512.48 802.14C281.9 802.14 94.34 614.5799999999999 94.34 384S281.9-34.139999999999986 512.48-34.139999999999986 930.62 153.41999999999996 930.62 384 743.06 802.14 512.48 802.14z m0-776.28c-197.46 0-358.14 160.68-358.14 358.14s160.68 358.14 358.14 358.14S870.62 581.46 870.62 384 709.94 25.860000000000014 512.48 25.860000000000014z" horiz-adv-x="1024" />
<glyph glyph-name="shijianfenlei" unicode="&#59101;" d="M490.66666667-9.75C274.10416667-9.75 96.91666667 167.4375 96.91666667 384S274.10416667 777.75 490.66666667 777.75c88.59375 0 172.96875-29.53125 241.875-82.96875 12.65625-9.84375 14.0625-26.71875 4.21875-39.375-9.84375-12.65625-26.71875-14.0625-39.375-4.21875-59.0625 45-130.78125 70.3125-206.71875 70.3125-185.625 0-337.5-151.875-337.5-337.5s151.875-337.5 337.5-337.5c75.9375 0 147.65625 25.3125 208.125 71.71875 12.65625 9.84375 29.53125 7.03125 39.375-4.21875s7.03125-29.53125-4.21875-39.375c-70.3125-54.84375-154.6875-84.375-243.28125-84.375z m196.875 365.625H490.66666667c-15.46875 0-28.125 12.65625-28.125 28.125V637.125c0 15.46875 12.65625 28.125 28.125 28.125s28.125-12.65625 28.125-28.125v-225h168.75c15.46875 0 28.125-12.65625 28.125-28.125s-12.65625-28.125-28.125-28.125z m225 0h-56.25c-15.46875 0-28.125 12.65625-28.125 28.125s12.65625 28.125 28.125 28.125h56.25c15.46875 0 28.125-12.65625 28.125-28.125s-12.65625-28.125-28.125-28.125z m0 168.75H814.10416667c-15.46875 0-28.125 12.65625-28.125 28.125s12.65625 28.125 28.125 28.125h98.4375c15.46875 0 28.125-12.65625 28.125-28.125s-12.65625-28.125-28.125-28.125z m0-337.5H814.10416667c-15.46875 0-28.125 12.65625-28.125 28.125s12.65625 28.125 28.125 28.125h98.4375c15.46875 0 28.125-12.65625 28.125-28.125s-12.65625-28.125-28.125-28.125z" horiz-adv-x="1024" />
<glyph glyph-name="erji-xiaxianjilu-copy" unicode="&#61174;" d="M374.890625 605.484375l110.7421875 110.7421875L485.6328125 278.53125c0-15.8203125 10.546875-26.3671875 26.3671875-26.3671875s26.3671875 10.546875 26.3671875 26.3671875l0 437.6953125 110.7421875-110.7421875c10.546875-10.546875 26.3671875-10.546875 36.9140625 0 10.546875 10.546875 10.546875 26.3671875 0 36.9140625l-152.9296875 158.203125s-5.2734375 5.2734375-10.546875 5.2734375l-26.3671875 0s-5.27343751 0-5.2734375-5.2734375l-152.9296875-158.203125c-10.546875-10.546875-10.546875-26.3671875 0-36.9140625 10.546875-10.546875 26.3671875-10.546875 36.9140625 0zM512-37.875C728.2109375-37.875 907.50781251 141.421875 907.5078125 357.6328125c0 89.6484375-31.640625 179.296875-89.6484375 253.125-5.2734375 5.2734375-10.546875 10.546875-21.09375 10.54687499-5.27343751 0-10.546875 0-15.8203125-5.27343749-10.546875-10.546875-10.546875-26.3671875-5.2734375-36.9140625C828.40625 515.83593751 854.7734375 436.734375 854.7734375 357.6328125 854.7734375 167.7890625 701.84375 14.859375 512 14.859375s-342.7734375 152.9296875-342.7734375 342.7734375c0 79.10156251 26.3671875 158.203125 79.1015625 216.2109375 10.546875 10.546875 5.2734375 26.3671875-5.2734375 36.9140625-10.546875 10.546875-26.3671875 5.2734375-36.9140625-5.2734375-58.0078125-68.5546875-89.6484375-158.203125-89.6484375-253.125 0-210.9375 179.296875-390.234375 395.5078125-390.234375z" horiz-adv-x="1024" />
<glyph glyph-name="tiaoduzhongxin-copy" unicode="&#61175;" d="M615.84841989 598.32546267H505.37137712c-44.19081711 0-83.96255204 39.7717357-83.96255203 83.96255203 0 44.19081711 39.7717357 83.96255204 83.96255204 83.96255282h110.47704277c44.19081711 0 83.96255204-39.7717357 83.96255281-83.96255282 0-48.60989852-39.7717357-83.96255204-83.96255282-83.96255203z m1e-8-309.33571899H505.37137712c-44.19081711 0-83.96255204 39.7717357-83.96255203 83.96255205 0 44.19081711 39.7717357 83.96255204 83.96255204 83.96255204h110.47704277c44.19081711 0 83.96255204-39.7717357 83.96255281-83.96255204 0-44.19081711-39.7717357-83.96255204-83.96255282-83.96255205z m0-300.49755618H505.37137712c-44.19081711 0-83.96255204 39.7717357-83.96255203 83.96255204 0 44.19081711 39.7717357 83.96255204 83.96255204 83.96255281h110.47704277c44.19081711 0 83.96255204-39.7717357 83.96255281-83.96255281 0-44.19081711-39.7717357-83.96255204-83.96255282-83.96255204z m-318.17388257 61.86714349c-97.2197978 0-181.18234983 79.54347064-181.18234983 181.1823506 0 97.2197978 79.54347064 181.18234983 181.18234983 181.18234983h30.93357214c17.67632715 0 30.93357213-13.25724498 30.93357212-30.93357213 0-17.67632715-13.25724498-30.93357213-30.93357212-30.93357212h-30.93357213c-66.28622566 0-119.31520634-53.02898068-119.31520634-119.31520558 0-66.28622566 53.02898068-119.31520634 119.31520633-119.31520634 17.67632715 0 30.93357213-13.25724498 30.93357214-30.93357212 0-17.67632715-13.25724498-30.93357213-30.93357214-30.93357214z m1e-8 0M381.63708937 85.71198530000004l-88.38163344-92.8007164v181.18234983l88.38163344-88.38163343z m437.48908892 278.40214684h-30.93357213c-17.67632715 0-30.93357213 13.25724498-30.93357136 30.93357213 0 17.67632715 13.25724498 30.93357213 30.93357136 30.93357214h30.93357212c66.28622566 0 119.31520634 53.02898068 119.31520636 119.31520557 0 66.28622566-53.02898068 119.31520634-119.31520636 119.31520635-17.67632715 0-30.93357213 13.25724498-30.93357212 30.93357213 0 17.67632715 13.25724498 30.93357213 30.93357213 30.93357136C916.34597608 726.47883182 1000.30852813 646.93536118 1000.30852813 545.29648198s-79.54347064-181.18234983-181.18234984-181.18234984z m-1e-8 0M735.16362624 686.70709688L823.54526046 779.5078125v-181.18234983l-88.38163422 88.38163421z m0 0" horiz-adv-x="1144" />
<glyph glyph-name="juxingkaobei" unicode="&#59301;" d="M128.692 768.01v-191.05H319.04V768.01H128.692z m127.261-127.963h-64.169v64.169h64.169v-64.169zM511.333 191.77700000000004v-191.416h385.792V191.77700000000004H511.333zM832 64H576.112v64.198H832V64zM384.075 768.01v-191.05h512.099V768.01H384.075z m448.087-127.963H448.087v64.169h384.075v-64.169zM511.333 447.791v-191.416H896.23V447.791H511.333z m319.922-127.776H575.961v64.198h255.294v-64.198zM192.037 576.9590000000001h64.012v-512.68h-64.012zM256.05 128.19799999999998h255.284v-63.919H256.05zM256.05 384h255.284v-63.381H256.05z" horiz-adv-x="1024" />
<glyph glyph-name="LOGO-" unicode="&#58937;" d="M578.122795 640.18066301H450.21312601c-51.30839798 0-97.55822201 46.24982399-97.55822102 97.55822199S398.904728 835.297107 450.21312601 835.297107H578.122795c51.30839798 0 97.55822201-46.24982399 97.558221-97.558222 0-56.366972-46.24982399-97.55822201-97.558221-97.55822199zM578.122795 281.02187698H450.21312601c-51.30839798 0-97.55822201 46.24982399-97.55822102 97.55822202s46.24982399 97.55822201 97.55822102 97.558221H578.122795c51.30839798 0 97.55822201-46.24982399 97.558221-97.558221S629.43119299 281.02187698 578.122795 281.02187698zM578.122795-67.29710699999998H450.21312601c-51.30839798 0-97.55822201 46.24982399-97.55822102 97.558222s46.24982399 97.55822201 97.55822102 97.55822199H578.122795c51.30839798 0 97.55822201-46.24982399 97.558221-97.55822199s-46.24982399-97.55822201-97.558221-97.558222zM814.430487 414.712773c117.792519 0 210.29216699-92.499647 210.29216601-210.292166s-97.55822201-210.29216699-210.29216601-210.292167c-20.23429799 0-36.132675 15.175723-36.132675 36.132675 0 20.23429799 15.175723 36.132675 36.132675 36.13267501 76.60126997 0 138.026817 61.425547 138.026817 138.02681699 0 76.60126997-61.425547 138.026817-138.026817 138.026817h-36.132675c-20.23429799 0-36.132675 15.175723-36.13267403 36.132675 0 20.23429799 15.175723 36.132675 36.13267403 36.132674h36.132675zM819.48906101 142.99505999999997v-210.292167l-102.61679602 107.675371 102.61679602 102.616796z m-102.61679602-102.616796M210.29216699 350.396613C92.499647 350.396613 0 442.89626 0 560.6887790000001s97.55822201 210.29216699 210.29216699 210.29216699c20.23429799 0 36.132675-15.175723 36.13267401-36.13267499 0-20.23429799-15.175723-36.132675-36.13267399-36.132675-76.60126997 0-138.026817-61.425547-138.02681802-138.026817 0-76.60126997 61.425547-138.026817 138.026818-138.02681699h36.13267401c20.23429799 0 36.132675-15.175723 36.13267501-36.13267502 0-20.23429799-15.175723-36.132675-36.13267501-36.13267399h-36.13267401zM205.233592 622.11432601V832.406493l102.616796-107.67537101-102.616796-102.616796z m102.616796 102.616796" horiz-adv-x="1024" />
<glyph glyph-name="jiantou-copy-copy" unicode="&#61176;" d="M209.05173332 306.46613333000005l274.65813335-274.65813333c21.45066667-21.45066667 56.22293333-21.45066667 77.6736 0l274.65813333 274.65813333c21.45066667 21.45066667 21.45066667 56.22293333 0 77.6736s-56.22293333 21.45066667-77.6736 0l-180.89066667-180.89066666 0 526.57493333c0 30.34986667-24.5824 54.93226667-54.93226665 54.93226667s-54.93226667-24.5824-54.93226668-54.93226667l0-526.57493333-180.89066667 180.89066666c-10.71146667 10.71253333-24.7744 16.09493333-38.83733333 16.09493334s-28.1248-5.35573334-38.83733333-16.09493334c-21.45066667-21.45066667-21.45066667-56.22293333 0-77.6736z" horiz-adv-x="1000" />
</font>
</defs></svg>

After

Width:  |  Height:  |  Size: 121 KiB

BIN
escheduler-ui/src/font/iconfont.ttf

Binary file not shown.

BIN
escheduler-ui/src/font/iconfont.woff

Binary file not shown.

BIN
escheduler-ui/src/font/iconfont.woff2

Binary file not shown.

BIN
escheduler-ui/src/images/favicon.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

15
escheduler-ui/src/js/conf/home/App.vue

@ -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>

85
escheduler-ui/src/js/conf/home/index.js

@ -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()
}
})
})

284
escheduler-ui/src/js/conf/home/pages/dag/_source/config.js

@ -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: '&#xe781;',
disable: disabled,
desc: `${i18n.$t('拖动节点和选中项')}`
},
{
code: 'line',
icon: '&#xe61c;',
disable: disabled,
desc: `${i18n.$t('选择线条连接')}`
},
{
code: 'remove',
icon: '&#xe611;',
disable: disabled,
desc: `${i18n.$t('删除选中的线或节点')}`
},
{
code: 'download',
icon: '&#xe628;',
disable: !!dagThis.type,
desc: `${i18n.$t('下载')}`
},
{
code: 'screen',
icon: '&#xe6e0;',
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: '&#xe7c2;',
isSpin: false
},
'RUNNING_EXEUTION': {
id: 1,
desc: `${i18n.$t('正在执行')}`,
color: '#0097e0',
icoUnicode: '&#xe80f;',
isSpin: true
},
'READY_PAUSE': {
id: 2,
desc: `${i18n.$t('准备暂停')}`,
color: '#07b1a3',
icoUnicode: '&#xe677;',
isSpin: false
},
'PAUSE': {
id: 3,
desc: `${i18n.$t('暂停')}`,
color: '#057c72',
icoUnicode: '&#xe679;',
isSpin: false
},
'READY_STOP': {
id: 4,
desc: `${i18n.$t('准备停止')}`,
color: '#FE0402',
icoUnicode: '&#xe6e6;',
isSpin: false
},
'STOP': {
id: 5,
desc: `${i18n.$t('停止')}`,
color: '#e90101',
icoUnicode: '&#xe6ae;',
isSpin: false
},
'FAILURE': {
id: 6,
desc: `${i18n.$t('失败')}`,
color: '#000000',
icoUnicode: '&#xe75d;',
isSpin: false
},
'SUCCESS': {
id: 7,
desc: `${i18n.$t('成功')}`,
color: '#33cc00',
icoUnicode: '&#xe6d4;',
isSpin: false
},
'NEED_FAULT_TOLERANCE': {
id: 8,
desc: `${i18n.$t('需要容错')}`,
color: '#FF8C00',
icoUnicode: '&#xe60d;',
isSpin: false
},
'KILL': {
id: 9,
desc: `${i18n.$t('kill')}`,
color: '#a70202',
icoUnicode: '&#xe6ce;',
isSpin: false
},
'WAITTING_THREAD': {
id: 10,
desc: `${i18n.$t('等待线程')}`,
color: '#912eed',
icoUnicode: '&#xe62e;',
isSpin: false
},
'WAITTING_DEPEND': {
id: 11,
desc: `${i18n.$t('等待依赖')}`,
color: '#5101be',
icoUnicode: '&#xe68c;',
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
}

119
escheduler-ui/src/js/conf/home/pages/dag/_source/dag.js

@ -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()

506
escheduler-ui/src/js/conf/home/pages/dag/_source/dag.scss

@ -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;
}

478
escheduler-ui/src/js/conf/home/pages/dag/_source/dag.vue

@ -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>

101
escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/_source/selectInput.vue

@ -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>

113
escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/_source/timeoutAlarm.vue

@ -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>

554
escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/formModel.vue

@ -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">&#xe6ee;</i><em>{{$t('查看历史')}}</em></a></template>
<template slot="log"><a href="javascript:"><i class="iconfont">&#xe691;</i><em>{{$t('查看日志')}}</em></a></template>
</m-log>
<a href="javascript:" @click="_goSubProcess" v-if="_isGoSubProcess"><i class="iconfont">&#xe600;</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>

357
escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/log.vue

@ -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">&#xe610;</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">&#xe602;</i>
</a>
<a href="javascript:" @click="_screenOpen" v-show="!isScreen" data-container="body" data-toggle="tooltip" :title="$t('进入全屏')">
<i class="iconfont">&#xe6e0;</i>
</a>
<a href="javascript:" @click="_screenClose" v-show="isScreen" data-container="body" data-toggle="tooltip" :title="$t('取消全屏')">
<i class="iconfont">&#xe660;</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>

199
escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/_source/commcon.js

@ -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
}

133
escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/_source/datasource.vue

@ -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>

247
escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/_source/dependItemList.vue

@ -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('成功')">&#xe607;</i>
<i class="iconfont" :class="'icon-' + el.state" v-if="el.state === 'WAITING'" data-toggle="tooltip" data-container="body" :title="$t('等待')">&#xe62a;</i>
<i class="iconfont" :class="'icon-' + el.state" v-if="el.state === 'FAILED'" data-toggle="tooltip" data-container="body" :title="$t('失败')">&#xe626;</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('删除')" >&#xe611;</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('添加')">&#xe636;</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>

46
escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/_source/listBox.vue

@ -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>

209
escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/_source/localParams.vue

@ -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('删除')" >&#xe611;</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('添加')">&#xe636;</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('添加')">&#xe636;</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>

100
escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/_source/resources.vue

@ -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>

57
escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/_source/sqlType.vue

@ -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>

116
escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/_source/udfs.vue

@ -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>

237
escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/dependent.vue

@ -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('添加')">
&#xe636;
</i>
<i v-if="isLoading" class="iconfont fa fa-spin" data-toggle="tooltip" :title="$t('添加')">
&#xe6af;
</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('删除')" >
&#xe611;
</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>

264
escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/mr.vue

@ -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>

134
escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/procedure.vue

@ -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>

161
escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/python.vue

@ -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>

165
escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/shell.vue

@ -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>

400
escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/spark.vue

@ -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>

267
escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/sql.vue

@ -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>

102
escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/sub_process.vue

@ -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>

107
escheduler-ui/src/js/conf/home/pages/dag/_source/jumpAffirm/index.js

@ -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

39
escheduler-ui/src/js/conf/home/pages/dag/_source/jumpAffirm/jumpAffirm.vue

@ -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>

122
escheduler-ui/src/js/conf/home/pages/dag/_source/plugIn/downChart.js vendored

@ -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()

40
escheduler-ui/src/js/conf/home/pages/dag/_source/plugIn/dragZoom.js

@ -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()

761
escheduler-ui/src/js/conf/home/pages/dag/_source/plugIn/jsPlumbHandle.js

@ -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">&#xe60b;</i><span>${i18n.$t('开始运行')}</span></a>`,
`<a href="javascript:" id="editNodes" class="${isTwo ? 'disbled' : ''}"><i class="iconfont">&#xe601;</i><span>${i18n.$t('编辑节点')}</span></a>`,
`<a href="javascript:" id="copyNodes" class="${isTwo ? 'disbled' : ''}"><i class="iconfont">&#xe61e;</i><span>${i18n.$t('复制节点')}</span></a>`,
`<a href="javascript:" id="removeNodes" class="${isTwo ? 'disbled' : ''}"><i class="iconfont">&#xe611;</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 = '&#xe660;'
screenOpen = true
} else {
item.icon = '&#xe6e0;'
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()

131
escheduler-ui/src/js/conf/home/pages/dag/_source/plugIn/util.js

@ -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
}

187
escheduler-ui/src/js/conf/home/pages/dag/_source/udp/udp.vue

@ -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>

24
escheduler-ui/src/js/conf/home/pages/dag/_source/variable/index.vue

@ -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>

141
escheduler-ui/src/js/conf/home/pages/dag/_source/variable/variablesView.vue

@ -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">
&nbsp;
</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>

82
escheduler-ui/src/js/conf/home/pages/dag/definitionDetails.vue

@ -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>

BIN
escheduler-ui/src/js/conf/home/pages/dag/img/dag_bg.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

BIN
escheduler-ui/src/js/conf/home/pages/dag/img/toolbar_DEPENDENT.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

BIN
escheduler-ui/src/js/conf/home/pages/dag/img/toolbar_MR.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
escheduler-ui/src/js/conf/home/pages/dag/img/toolbar_PROCEDURE.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
escheduler-ui/src/js/conf/home/pages/dag/img/toolbar_PYTHON.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

BIN
escheduler-ui/src/js/conf/home/pages/dag/img/toolbar_SHELL.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
escheduler-ui/src/js/conf/home/pages/dag/img/toolbar_SPARK.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

BIN
escheduler-ui/src/js/conf/home/pages/dag/img/toolbar_SQL.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
escheduler-ui/src/js/conf/home/pages/dag/img/toolbar_SUB_PROCESS.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

65
escheduler-ui/src/js/conf/home/pages/dag/index.vue

@ -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>

92
escheduler-ui/src/js/conf/home/pages/dag/instanceDetails.vue

@ -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>

8
escheduler-ui/src/js/conf/home/pages/datasource/index.vue

@ -0,0 +1,8 @@
<template>
<router-view></router-view>
</template>
<script>
export default {
name: 'datasource-index'
}
</script>

337
escheduler-ui/src/js/conf/home/pages/datasource/pages/list/_source/createDataSource.vue

@ -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>

160
escheduler-ui/src/js/conf/home/pages/datasource/pages/list/_source/list.vue

@ -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>

125
escheduler-ui/src/js/conf/home/pages/datasource/pages/list/index.vue

@ -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>

16
escheduler-ui/src/js/conf/home/pages/home/index.vue

@ -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>

40
escheduler-ui/src/js/conf/home/pages/projects/index.vue

@ -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>

8
escheduler-ui/src/js/conf/home/pages/projects/pages/definition/index.vue

@ -0,0 +1,8 @@
<template>
<router-view></router-view>
</template>
<script>
export default {
name: 'process-definition-index'
}
</script>

14
escheduler-ui/src/js/conf/home/pages/projects/pages/definition/pages/create/index.vue

@ -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>

14
escheduler-ui/src/js/conf/home/pages/projects/pages/definition/pages/details/index.vue

@ -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>

338
escheduler-ui/src/js/conf/home/pages/projects/pages/definition/pages/list/_source/email.vue

@ -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>

238
escheduler-ui/src/js/conf/home/pages/projects/pages/definition/pages/list/_source/list.vue

@ -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>

298
escheduler-ui/src/js/conf/home/pages/projects/pages/definition/pages/list/_source/start.vue

@ -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>

323
escheduler-ui/src/js/conf/home/pages/projects/pages/definition/pages/list/_source/timing.vue

@ -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>

60
escheduler-ui/src/js/conf/home/pages/projects/pages/definition/pages/list/_source/util.js

@ -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
}

147
escheduler-ui/src/js/conf/home/pages/projects/pages/definition/pages/list/index.vue

@ -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>

279
escheduler-ui/src/js/conf/home/pages/projects/pages/definition/pages/tree/_source/tree.js

@ -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()

72
escheduler-ui/src/js/conf/home/pages/projects/pages/definition/pages/tree/_source/util.js

@ -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
}

BIN
escheduler-ui/src/js/conf/home/pages/projects/pages/definition/pages/tree/img/dag_bg.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

248
escheduler-ui/src/js/conf/home/pages/projects/pages/definition/pages/tree/index.vue

@ -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>

265
escheduler-ui/src/js/conf/home/pages/projects/pages/definition/timing/_source/list.vue

@ -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>

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

Loading…
Cancel
Save