├── .eslintignore
├── tests
└── unit
│ ├── .eslintrc.js
│ ├── components
│ ├── Hamburger.spec.js
│ └── SvgIcon.spec.js
│ └── utils
│ ├── validate.spec.js
│ ├── parseTime.spec.js
│ └── formatTime.spec.js
├── babel.config.js
├── doc
└── images
│ ├── dept.png
│ ├── role.png
│ ├── user.png
│ ├── dictionary.png
│ ├── fileStore.png
│ ├── monitorSql.png
│ ├── permission.png
│ ├── personal.png
│ └── schedule.png
├── public
├── favicon.ico
└── index.html
├── .travis.yml
├── src
├── assets
│ ├── logo
│ │ └── logo.png
│ ├── 404_images
│ │ ├── 404.png
│ │ └── 404_cloud.png
│ └── avatar
│ │ └── avatar.png
├── layout
│ ├── components
│ │ ├── Empty.vue
│ │ ├── index.js
│ │ ├── Sidebar
│ │ │ ├── Link.vue
│ │ │ ├── FixiOSBug.js
│ │ │ ├── Item.vue
│ │ │ ├── index.vue
│ │ │ └── Logo.vue
│ │ └── AppMain.vue
│ ├── mixin
│ │ └── ResizeHandler.js
│ └── index.vue
├── App.vue
├── api
│ ├── table.js
│ ├── queryHistory.js
│ ├── auth.js
│ ├── userCenter.js
│ ├── actModel.js
│ ├── dictionary.js
│ ├── flowHistory.js
│ ├── dictionaryItem.js
│ ├── dept.js
│ ├── location.js
│ ├── flowLeave.js
│ ├── permission.js
│ ├── user.js
│ ├── actProcess.js
│ ├── role.js
│ ├── actTask.js
│ ├── quartzJob.js
│ └── fileStore.js
├── icons
│ ├── svg
│ │ ├── link.svg
│ │ ├── example.svg
│ │ ├── save.svg
│ │ ├── dictionary.svg
│ │ ├── table.svg
│ │ ├── password.svg
│ │ ├── user.svg
│ │ ├── permission.svg
│ │ ├── system.svg
│ │ ├── workflowLaunch.svg
│ │ ├── systemTool.svg
│ │ ├── nested.svg
│ │ ├── workflowApply.svg
│ │ ├── menu.svg
│ │ ├── eye.svg
│ │ ├── workflowTodo.svg
│ │ ├── monitorSql.svg
│ │ ├── workflowModel.svg
│ │ ├── workflowDone.svg
│ │ ├── workflow.svg
│ │ ├── eye-open.svg
│ │ ├── workflowProcess.svg
│ │ ├── location.svg
│ │ ├── schedule.svg
│ │ ├── tree.svg
│ │ ├── fileStore.svg
│ │ ├── redis.svg
│ │ ├── dashboard.svg
│ │ ├── form.svg
│ │ └── role.svg
│ ├── index.js
│ └── svgo.yml
├── utils
│ ├── get-page-title.js
│ ├── auth.js
│ ├── validate.js
│ ├── tree.js
│ ├── rules.js
│ └── dic.js
├── settings.js
├── directive
│ └── permission
│ │ ├── index.js
│ │ └── permission.js
├── store
│ ├── modules
│ │ ├── api.js
│ │ ├── settings.js
│ │ ├── dic.js
│ │ ├── socket.js
│ │ ├── app.js
│ │ └── permission.js
│ ├── getters.js
│ └── index.js
├── styles
│ ├── mixin.scss
│ ├── variables.scss
│ ├── element-ui.scss
│ ├── transition.scss
│ └── index.scss
├── views
│ ├── dashboard
│ │ └── index.vue
│ └── system
│ │ ├── tool
│ │ └── monitorSql
│ │ │ └── index.vue
│ │ ├── workflow
│ │ ├── components
│ │ │ ├── util.js
│ │ │ ├── approveForm.vue
│ │ │ └── editHistory.vue
│ │ ├── launch
│ │ │ └── index.vue
│ │ └── apply
│ │ │ └── reason.vue
│ │ └── manage
│ │ └── dictionary
│ │ └── index.vue
├── mixin
│ ├── commonMsg.js
│ └── permission.js
├── main.js
├── components
│ ├── Hamburger
│ │ └── index.vue
│ ├── SvgIcon
│ │ └── index.vue
│ └── Breadcrumb
│ │ └── index.vue
└── router
│ └── modules
│ ├── systemManage.js
│ ├── systemTool.js
│ └── systemWorkflow.js
├── wfd-vue
├── src
│ ├── locales
│ │ ├── index.js
│ │ └── zh-CN.js
│ ├── assets
│ │ ├── iconfont
│ │ │ ├── iconfont.eot
│ │ │ ├── iconfont.ttf
│ │ │ ├── iconfont.woff
│ │ │ └── iconfont.woff2
│ │ ├── icons
│ │ │ └── flow
│ │ │ │ ├── icon_timer.svg
│ │ │ │ ├── icon_signal.svg
│ │ │ │ ├── icon_mail.svg
│ │ │ │ ├── icon_script.svg
│ │ │ │ ├── icon_user.svg
│ │ │ │ ├── icon_java.svg
│ │ │ │ ├── icon_message.svg
│ │ │ │ └── icon_receive.svg
│ │ └── flow
│ │ │ ├── end.svg
│ │ │ ├── start.svg
│ │ │ ├── timer-catch.svg
│ │ │ ├── inclusive-gateway.svg
│ │ │ ├── mail-task.svg
│ │ │ ├── signal-catch.svg
│ │ │ ├── message-catch.svg
│ │ │ ├── script-task.svg
│ │ │ ├── parallel-gateway.svg
│ │ │ ├── gateway.svg
│ │ │ ├── exclusive-gateway.svg
│ │ │ ├── timer-start.svg
│ │ │ ├── user-task.svg
│ │ │ ├── signal-start.svg
│ │ │ ├── receive-task.svg
│ │ │ ├── message-start.svg
│ │ │ └── java-task.svg
│ ├── index.js
│ ├── shape
│ │ ├── index.js
│ │ └── anchor.js
│ ├── behavior
│ │ ├── index.js
│ │ ├── hoverAnchorActived.js
│ │ ├── hoverNodeActived.js
│ │ ├── deleteItem.js
│ │ └── clickSelected.js
│ ├── components
│ │ └── DetailPanel
│ │ │ ├── EndEventDetail.vue
│ │ │ ├── StartEventDetail.vue
│ │ │ ├── GatewayDetail.vue
│ │ │ ├── DefaultDetail.vue
│ │ │ ├── JavaTaskDetail.vue
│ │ │ ├── ScriptTaskDetail.vue
│ │ │ ├── SignalEventDetail.vue
│ │ │ ├── MessageEventDetail.vue
│ │ │ ├── ReceiveTaskDetail.vue
│ │ │ ├── TimerEventDetail.vue
│ │ │ ├── FlowDetail.vue
│ │ │ └── MailTaskDetail.vue
│ ├── plugins
│ │ ├── canvasPanel.js
│ │ ├── addItemPanel.js
│ │ └── detailPanel.js
│ ├── util
│ │ └── clazz.js
│ └── item
│ │ └── anchor.js
└── example
│ ├── snapshots
│ └── 1.jpg
│ └── main.js
├── .env.staging
├── .env.production
├── jsconfig.json
├── postcss.config.js
├── .gitignore
├── .gitattributes
├── .editorconfig
├── .vscode
└── settings.json
├── templates
├── mapStruct.ejs
├── mapper.ejs
├── api.ejs
└── service.ejs
├── .env.development
├── mock
├── table.js
├── user.js
├── index.js
└── mock-server.js
├── xcrud.config.js
├── jest.config.js
├── LICENSE
├── test.js
└── package.json
/.eslintignore:
--------------------------------------------------------------------------------
1 | build/*.js
2 | src/assets
3 | public
4 | dist
5 | package
6 | wfd-vue
7 |
--------------------------------------------------------------------------------
/tests/unit/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | env: {
3 | jest: true
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/cli-plugin-babel/preset'
4 | ]
5 | }
--------------------------------------------------------------------------------
/doc/images/dept.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nayacco/submarine-admin-frontend/HEAD/doc/images/dept.png
--------------------------------------------------------------------------------
/doc/images/role.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nayacco/submarine-admin-frontend/HEAD/doc/images/role.png
--------------------------------------------------------------------------------
/doc/images/user.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nayacco/submarine-admin-frontend/HEAD/doc/images/user.png
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nayacco/submarine-admin-frontend/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js: 10
3 | script: npm run test
4 | notifications:
5 | email: false
6 |
--------------------------------------------------------------------------------
/doc/images/dictionary.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nayacco/submarine-admin-frontend/HEAD/doc/images/dictionary.png
--------------------------------------------------------------------------------
/doc/images/fileStore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nayacco/submarine-admin-frontend/HEAD/doc/images/fileStore.png
--------------------------------------------------------------------------------
/doc/images/monitorSql.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nayacco/submarine-admin-frontend/HEAD/doc/images/monitorSql.png
--------------------------------------------------------------------------------
/doc/images/permission.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nayacco/submarine-admin-frontend/HEAD/doc/images/permission.png
--------------------------------------------------------------------------------
/doc/images/personal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nayacco/submarine-admin-frontend/HEAD/doc/images/personal.png
--------------------------------------------------------------------------------
/doc/images/schedule.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nayacco/submarine-admin-frontend/HEAD/doc/images/schedule.png
--------------------------------------------------------------------------------
/src/assets/logo/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nayacco/submarine-admin-frontend/HEAD/src/assets/logo/logo.png
--------------------------------------------------------------------------------
/src/assets/404_images/404.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nayacco/submarine-admin-frontend/HEAD/src/assets/404_images/404.png
--------------------------------------------------------------------------------
/src/assets/avatar/avatar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nayacco/submarine-admin-frontend/HEAD/src/assets/avatar/avatar.png
--------------------------------------------------------------------------------
/wfd-vue/src/locales/index.js:
--------------------------------------------------------------------------------
1 | import en from './en-US'
2 | import zh from './zh-CN'
3 | export default {
4 | en,
5 | zh,
6 | }
--------------------------------------------------------------------------------
/wfd-vue/example/snapshots/1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nayacco/submarine-admin-frontend/HEAD/wfd-vue/example/snapshots/1.jpg
--------------------------------------------------------------------------------
/src/assets/404_images/404_cloud.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nayacco/submarine-admin-frontend/HEAD/src/assets/404_images/404_cloud.png
--------------------------------------------------------------------------------
/.env.staging:
--------------------------------------------------------------------------------
1 | NODE_ENV = production
2 |
3 | # just a flag
4 | ENV = 'staging'
5 |
6 | # base api
7 | VUE_APP_BASE_API = '/stage-api'
8 |
9 |
--------------------------------------------------------------------------------
/wfd-vue/src/assets/iconfont/iconfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nayacco/submarine-admin-frontend/HEAD/wfd-vue/src/assets/iconfont/iconfont.eot
--------------------------------------------------------------------------------
/wfd-vue/src/assets/iconfont/iconfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nayacco/submarine-admin-frontend/HEAD/wfd-vue/src/assets/iconfont/iconfont.ttf
--------------------------------------------------------------------------------
/.env.production:
--------------------------------------------------------------------------------
1 | # just a flag
2 | ENV = 'production'
3 |
4 | # base api
5 | VUE_APP_BASE_API = '/prod-api'
6 |
7 | VUE_APP_SOCKET_PORT = '443'
8 |
9 |
--------------------------------------------------------------------------------
/wfd-vue/src/assets/iconfont/iconfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nayacco/submarine-admin-frontend/HEAD/wfd-vue/src/assets/iconfont/iconfont.woff
--------------------------------------------------------------------------------
/wfd-vue/src/assets/iconfont/iconfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nayacco/submarine-admin-frontend/HEAD/wfd-vue/src/assets/iconfont/iconfont.woff2
--------------------------------------------------------------------------------
/src/layout/components/Empty.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
10 |
--------------------------------------------------------------------------------
/src/layout/components/index.js:
--------------------------------------------------------------------------------
1 | export { default as Navbar } from './Navbar'
2 | export { default as Sidebar } from './Sidebar'
3 | export { default as AppMain } from './AppMain'
4 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
--------------------------------------------------------------------------------
/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": "./",
4 | "paths": {
5 | "@/*": ["src/*"]
6 | }
7 | },
8 | "exclude": ["node_modules", "dist"]
9 | }
10 |
--------------------------------------------------------------------------------
/src/api/table.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request'
2 |
3 | export function getList(params) {
4 | return request({
5 | url: '/table/list',
6 | method: 'get',
7 | params
8 | })
9 | }
10 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | // https://github.com/michael-ciniawsky/postcss-load-config
2 |
3 | module.exports = {
4 | 'plugins': {
5 | // to edit target browsers: use "browserslist" field in package.json
6 | 'autoprefixer': {}
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/wfd-vue/src/index.js:
--------------------------------------------------------------------------------
1 | import Wfd from './components/Wfd';
2 |
3 | const install = (Vue) => {
4 | Vue.component(Wfd.name, Wfd);
5 | };
6 |
7 | if (typeof window !== 'undefined' && window.Vue) {
8 | install(window.Vue);
9 | }
10 |
11 |
12 | export default Wfd;
13 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules/
3 | dist/
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | package-lock.json
8 | tests/**/coverage/
9 |
10 | # Editor directories and files
11 | .history
12 | .idea
13 | # .vscode
14 | *.suo
15 | *.ntvs*
16 | *.njsproj
17 | *.sln
18 |
--------------------------------------------------------------------------------
/src/icons/svg/link.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/utils/get-page-title.js:
--------------------------------------------------------------------------------
1 | import defaultSettings from '@/settings'
2 |
3 | const title = defaultSettings.title || 'Vue Admin Template'
4 |
5 | export default function getPageTitle(pageTitle) {
6 | if (pageTitle) {
7 | return `${pageTitle} - ${title}`
8 | }
9 | return `${title}`
10 | }
11 |
--------------------------------------------------------------------------------
/wfd-vue/example/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import App from './App.vue'
3 | import ElementUI from 'element-ui'
4 | import 'element-ui/lib/theme-chalk/index.css'
5 |
6 | Vue.use(ElementUI);
7 |
8 | Vue.config.productionTip = false;
9 | new Vue({
10 | render: h => h(App),
11 | }).$mount('#app');
12 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # 防止不设置 core.autocrlf 导致混合 crlf 和 lf 提交的情况.建议执行下列 3 行命令
2 | # git config --global core.autocrlf input
3 | # git config --global core.safecrlf true
4 | # git config --global core.eol lf
5 |
6 | * text eol=lf
7 | *.jar binary
8 | *.png binary
9 | *.jpg binary
10 | *.eot binary
11 | *.ttf binary
12 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # http://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 2
8 | end_of_line = lf
9 | insert_final_newline = true
10 | trim_trailing_whitespace = true
11 |
12 | [*.md]
13 | insert_final_newline = false
14 | trim_trailing_whitespace = false
15 |
--------------------------------------------------------------------------------
/wfd-vue/src/shape/index.js:
--------------------------------------------------------------------------------
1 | import registerAnchor from './anchor'
2 | import registerNode from './node'
3 | import registerFlowNode from './flowNode'
4 | import registerEdge from './edge'
5 |
6 | export default function(G6){
7 | registerAnchor(G6);
8 | registerNode(G6);
9 | registerFlowNode(G6);
10 | registerEdge(G6);
11 | }
12 |
--------------------------------------------------------------------------------
/src/api/queryHistory.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request'
2 |
3 | /**
4 | * 查询历史记录
5 | * @param value: value 有值时进行模糊查询,无值时查出所有的历史
6 | */
7 | export function queryHistory(table, field, value) {
8 | return request({
9 | url: '/query/history',
10 | method: 'get',
11 | params: { table, field, value }
12 | })
13 | }
14 |
--------------------------------------------------------------------------------
/src/icons/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import SvgIcon from '@/components/SvgIcon'// svg component
3 |
4 | // register globally
5 | Vue.component('svg-icon', SvgIcon)
6 |
7 | const req = require.context('./svg', false, /\.svg$/)
8 | const requireAll = requireContext => requireContext.keys().map(requireContext)
9 | requireAll(req)
10 |
--------------------------------------------------------------------------------
/src/settings.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 |
3 | title: 'Submarine',
4 |
5 | /**
6 | * @type {boolean} true | false
7 | * @description Whether fix the header
8 | */
9 | fixedHeader: false,
10 |
11 | /**
12 | * @type {boolean} true | false
13 | * @description Whether show the logo in sidebar
14 | */
15 | sidebarLogo: true
16 | }
17 |
--------------------------------------------------------------------------------
/src/directive/permission/index.js:
--------------------------------------------------------------------------------
1 | import permission from './permission'
2 |
3 | const install = function(Vue) {
4 | Vue.directive('permission', permission)
5 | }
6 |
7 | if (window.Vue) {
8 | window['permission'] = permission
9 | Vue.use(install); // eslint-disable-line
10 | }
11 |
12 | permission.install = install
13 | export default permission
14 |
--------------------------------------------------------------------------------
/src/icons/svgo.yml:
--------------------------------------------------------------------------------
1 | # replace default config
2 |
3 | # multipass: true
4 | # full: true
5 |
6 | plugins:
7 |
8 | # - name
9 | #
10 | # or:
11 | # - name: false
12 | # - name: true
13 | #
14 | # or:
15 | # - name:
16 | # param1: 1
17 | # param2: 2
18 |
19 | - removeAttrs:
20 | attrs:
21 | - 'fill'
22 | - 'fill-rule'
23 |
--------------------------------------------------------------------------------
/src/utils/auth.js:
--------------------------------------------------------------------------------
1 | import Cookies from 'js-cookie'
2 |
3 | const TokenKey = 'vue_admin_template_token'
4 |
5 | export function getToken() {
6 | return Cookies.get(TokenKey)
7 | }
8 |
9 | export function setToken(token) {
10 | return Cookies.set(TokenKey, token)
11 | }
12 |
13 | export function removeToken() {
14 | return Cookies.remove(TokenKey)
15 | }
16 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "files.autoSave": "off",
3 | "eslint.validate": [
4 | "javascript",
5 | "javascriptreact",
6 | "vue-html",
7 | {
8 | "language": "vue",
9 | "autoFix": true
10 | }
11 | ],
12 | "eslint.run": "onSave",
13 | "eslint.autoFixOnSave": true,
14 | "editor.codeActionsOnSave": {
15 | "source.fixAll.eslint": true
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/store/modules/api.js:
--------------------------------------------------------------------------------
1 | const baseUrl = process.env.VUE_APP_BASE_API
2 | const socketPort = process.env.VUE_APP_SOCKET_PORT
3 | const api = {
4 | state: {
5 | // Sql 监控
6 | sqlApi: baseUrl + '/druid',
7 | // socket
8 | socketPort: socketPort,
9 | // 文件上传
10 | fileUploadApi: baseUrl + '/file/upload',
11 | // baseUrl,
12 | baseApi: baseUrl
13 | }
14 | }
15 |
16 | export default api
17 |
--------------------------------------------------------------------------------
/src/utils/validate.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by PanJiaChen on 16/11/18.
3 | */
4 |
5 | /**
6 | * @param {string} path
7 | * @returns {Boolean}
8 | */
9 | export function isExternal(path) {
10 | return /^(https?:|mailto:|tel:)/.test(path)
11 | }
12 |
13 | /**
14 | * @param {string} str
15 | * @returns {Boolean}
16 | */
17 | export function validUsername(str) {
18 | const valid_map = ['admin', 'editor']
19 | return valid_map.indexOf(str.trim()) >= 0
20 | }
21 |
--------------------------------------------------------------------------------
/src/icons/svg/example.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/store/getters.js:
--------------------------------------------------------------------------------
1 | const getters = {
2 | sidebar: state => state.app.sidebar,
3 | user: state => state.user,
4 | device: state => state.app.device,
5 | // token: state => state.user.token,
6 | avatar: state => state.user.avatar,
7 | name: state => state.user.name,
8 | roles: state => state.user.roles,
9 | permissions: state => state.user.permissions,
10 | routes: state => state.permission.routes,
11 | api: state => state.api,
12 | dic: state => state.dic.dic
13 | }
14 | export default getters
15 |
--------------------------------------------------------------------------------
/templates/mapStruct.ejs:
--------------------------------------------------------------------------------
1 | package com.htnova.<%= module %>.mapstruct;
2 |
3 | import com.htnova.common.base.BaseMapStruct;
4 | import com.htnova.<%= module %>.dto.<%= Entity %>Dto;
5 | import com.htnova.<%= module %>.entity.<%= Entity %>;
6 | import org.mapstruct.Mapper;
7 | import org.mapstruct.factory.Mappers;
8 |
9 | @Mapper
10 | public interface <%= Entity %>MapStruct extends BaseMapStruct<<%= Entity %>Dto, <%= Entity %>> {
11 | <%= Entity %>MapStruct INSTANCE = Mappers.getMapper(<%= Entity %>MapStruct.class);
12 | }
13 |
--------------------------------------------------------------------------------
/src/styles/mixin.scss:
--------------------------------------------------------------------------------
1 | @mixin clearfix {
2 | &:after {
3 | content: "";
4 | display: table;
5 | clear: both;
6 | }
7 | }
8 |
9 | @mixin scrollBar {
10 | &::-webkit-scrollbar-track-piece {
11 | background: #d3dce6;
12 | }
13 |
14 | &::-webkit-scrollbar {
15 | width: 6px;
16 | }
17 |
18 | &::-webkit-scrollbar-thumb {
19 | background: #99a9bf;
20 | border-radius: 20px;
21 | }
22 | }
23 |
24 | @mixin relative {
25 | position: relative;
26 | width: 100%;
27 | height: 100%;
28 | }
29 |
--------------------------------------------------------------------------------
/src/icons/svg/save.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/icons/svg/dictionary.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/views/dashboard/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
19 |
20 |
31 |
--------------------------------------------------------------------------------
/src/api/auth.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request'
2 | import qs from 'qs'
3 |
4 | export function login(data) {
5 | return request({
6 | url: '/auth/login',
7 | method: 'post',
8 | headers: {
9 | 'Content-Type': 'application/x-www-form-urlencoded'
10 | },
11 | data: qs.stringify(data)
12 | })
13 | }
14 |
15 | export function getInfo() {
16 | return request({
17 | url: '/auth/info',
18 | method: 'get'
19 | })
20 | }
21 |
22 | export function logout() {
23 | return request({
24 | url: '/auth/logout',
25 | method: 'post'
26 | })
27 | }
28 |
--------------------------------------------------------------------------------
/src/icons/svg/table.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/api/userCenter.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request'
2 |
3 | /**
4 | * 获取详情
5 | */
6 | export function getUserDetail(id) {
7 | return request({
8 | url: '/user-center/detail',
9 | method: 'get'
10 | })
11 | }
12 |
13 | /**
14 | * 保存
15 | */
16 | export function saveUser(data) {
17 | return request({
18 | url: '/user-center/save',
19 | method: 'post',
20 | data
21 | })
22 | }
23 |
24 | /**
25 | * 修改密码
26 | */
27 | export function changePass(data) {
28 | return request({
29 | url: '/user-center/changePass',
30 | method: 'post',
31 | data
32 | })
33 | }
34 |
--------------------------------------------------------------------------------
/src/icons/svg/password.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/store/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Vuex from 'vuex'
3 | import getters from './getters'
4 | import app from './modules/app'
5 | import settings from './modules/settings'
6 | import user from './modules/user'
7 | import permission from './modules/permission'
8 | import api from './modules/api'
9 | import dic from './modules/dic'
10 | import socket from './modules/socket'
11 |
12 | Vue.use(Vuex)
13 |
14 | const store = new Vuex.Store({
15 | modules: {
16 | app,
17 | settings,
18 | user,
19 | permission,
20 | api,
21 | dic,
22 | socket
23 | },
24 | getters
25 | })
26 |
27 | export default store
28 |
--------------------------------------------------------------------------------
/wfd-vue/src/behavior/index.js:
--------------------------------------------------------------------------------
1 | import clickSelected from './clickSelected'
2 | import deleteItem from './deleteItem'
3 | import dragNode from './dragNode'
4 | import dragEdge from './dragEdge'
5 | import dragPanelItemAddNode from './dragPanelItemAddNode'
6 | import hoverAnchorActived from './hoverAnchorActived'
7 | import hoverNodeActived from './hoverNodeActived'
8 | import itemAlign from './itemAlign'
9 | export default function(G6){
10 | clickSelected(G6);
11 | deleteItem(G6);
12 | dragNode(G6);
13 | dragEdge(G6);
14 | dragPanelItemAddNode(G6);
15 | hoverAnchorActived(G6);
16 | hoverNodeActived(G6);
17 | itemAlign(G6);
18 | }
19 |
--------------------------------------------------------------------------------
/.env.development:
--------------------------------------------------------------------------------
1 | # just a flag
2 | ENV = 'development'
3 |
4 | # base api
5 | VUE_APP_BASE_API = '/api'
6 | # socket api
7 | VUE_APP_SOCKET_PORT = '19688'
8 |
9 | # vue-cli uses the VUE_CLI_BABEL_TRANSPILE_MODULES environment variable,
10 | # to control whether the babel-plugin-dynamic-import-node plugin is enabled.
11 | # It only does one thing by converting all import() to require().
12 | # This configuration can significantly increase the speed of hot updates,
13 | # when you have a large number of pages.
14 | # Detail: https://github.com/vuejs/vue-cli/blob/dev/packages/@vue/babel-preset-app/index.js
15 |
16 | VUE_CLI_BABEL_TRANSPILE_MODULES = true
17 |
--------------------------------------------------------------------------------
/mock/table.js:
--------------------------------------------------------------------------------
1 | import Mock from 'mockjs'
2 |
3 | const data = Mock.mock({
4 | 'items|30': [{
5 | id: '@id',
6 | title: '@sentence(10, 20)',
7 | 'status|1': ['published', 'draft', 'deleted'],
8 | author: 'name',
9 | display_time: '@datetime',
10 | pageviews: '@integer(300, 5000)'
11 | }]
12 | })
13 |
14 | export default [
15 | {
16 | url: '/table/list',
17 | type: 'get',
18 | response: config => {
19 | const items = data.items
20 | return {
21 | code: 20000,
22 | data: {
23 | total: items.length,
24 | items: items
25 | }
26 | }
27 | }
28 | }
29 | ]
30 |
--------------------------------------------------------------------------------
/src/views/system/tool/monitorSql/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
11 |
12 |
27 |
--------------------------------------------------------------------------------
/src/mixin/commonMsg.js:
--------------------------------------------------------------------------------
1 | import { MessageBox } from 'element-ui'
2 |
3 | export default {
4 | install: function(Vue, options) {
5 | Vue.mixin({
6 | methods: {
7 | delConfirm() {
8 | return MessageBox.confirm('此操作将永久删除该记录, 是否继续?', '提示', {
9 | confirmButtonText: '确定',
10 | cancelButtonText: '取消',
11 | type: 'warning'
12 | })
13 | },
14 | commonConfirm(msg) {
15 | return MessageBox.confirm(msg, '提示', {
16 | confirmButtonText: '确定',
17 | cancelButtonText: '取消',
18 | type: 'warning'
19 | })
20 | }
21 | }
22 | })
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/directive/permission/permission.js:
--------------------------------------------------------------------------------
1 | import store from '@/store'
2 |
3 | export default {
4 | inserted(el, binding, vnode) {
5 | const { value } = binding
6 | const roles = store.getters && store.getters.roles
7 |
8 | if (value && value instanceof Array && value.length > 0) {
9 | const permissionRoles = value
10 |
11 | const hasPermission = roles.some(role => {
12 | return permissionRoles.includes(role)
13 | })
14 |
15 | if (!hasPermission) {
16 | el.parentNode && el.parentNode.removeChild(el)
17 | }
18 | } else {
19 | throw new Error(`need roles! Like v-permission="['admin','editor']"`)
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | <%= webpackConfig.name %>
9 |
10 |
11 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/xcrud.config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | input: {
3 | placeholder: '请输入'
4 | },
5 | datePicker: {
6 | valueFormat: 'yyyy-MM-dd HH:mm:ss'
7 | },
8 | xtable: {
9 | table: {
10 | stripe: true,
11 | border: true
12 | },
13 | column: {
14 | showOverflowTooltip: true
15 | },
16 | operate: {
17 | btn: {
18 | show: true,
19 | size: 'medium',
20 | type: 'text',
21 | plain: false,
22 | round: false,
23 | circle: false,
24 | loading: false,
25 | disabled: false,
26 | icon: null,
27 | autofocus: false,
28 | nativeType: 'button'
29 | }
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/templates/mapper.ejs:
--------------------------------------------------------------------------------
1 | package com.htnova.<%= module %>.mapper;
2 |
3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper;
4 | import com.baomidou.mybatisplus.core.metadata.IPage;
5 | import com.htnova.<%= module %>.entity.<%= Entity %>;
6 | import com.htnova.<%= module %>.dto.<%= Entity %>Dto;
7 | import org.apache.ibatis.annotations.Param;
8 |
9 | import java.util.List;
10 |
11 | public interface <%= Entity %>Mapper extends BaseMapper<<%= Entity %>> {
12 |
13 | IPage<<%= Entity %>> findPage(IPage xPage, @Param("<%= entity %>Dto") <%= Entity %>Dto <%= entity %>Dto);
14 |
15 | List<<%= Entity %>> findList(@Param("<%= entity %>Dto") <%= Entity %>Dto <%= entity %>Dto);
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/src/store/modules/settings.js:
--------------------------------------------------------------------------------
1 | import defaultSettings from '@/settings'
2 |
3 | const { showSettings, fixedHeader, sidebarLogo } = defaultSettings
4 |
5 | const state = {
6 | showSettings: showSettings,
7 | fixedHeader: fixedHeader,
8 | sidebarLogo: sidebarLogo
9 | }
10 |
11 | const mutations = {
12 | CHANGE_SETTING: (state, { key, value }) => {
13 | if (Object.prototype.hasOwnProperty.call(state, key)) {
14 | state[key] = value
15 | }
16 | }
17 | }
18 |
19 | const actions = {
20 | changeSetting({ commit }, data) {
21 | commit('CHANGE_SETTING', data)
22 | }
23 | }
24 |
25 | export default {
26 | namespaced: true,
27 | state,
28 | mutations,
29 | actions
30 | }
31 |
32 |
--------------------------------------------------------------------------------
/src/icons/svg/user.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/store/modules/dic.js:
--------------------------------------------------------------------------------
1 | import { getDictionaryList } from '@/api/dictionary'
2 |
3 | const state = {
4 | dic: {}
5 | }
6 |
7 | const mutations = {
8 | SET_DIC: (state, dic) => {
9 | state.dic = dic
10 | }
11 | }
12 |
13 | const actions = {
14 | loadDic({ commit }) {
15 | return new Promise(resolve => {
16 | getDictionaryList().then(res => {
17 | const obj = {}
18 | res.forEach(item => {
19 | obj[item.name] = item.dictionaryItemList
20 | })
21 | commit('SET_DIC', obj)
22 | resolve(obj)
23 | }).catch(e => console.log(e))
24 | })
25 | }
26 | }
27 |
28 | export default {
29 | namespaced: true,
30 | state,
31 | mutations,
32 | actions
33 | }
34 |
--------------------------------------------------------------------------------
/src/styles/variables.scss:
--------------------------------------------------------------------------------
1 | // sidebar
2 | $menuText:#bfcbd9;
3 | $menuActiveText:#409EFF;
4 | $subMenuActiveText:#f4f4f5; //https://github.com/ElemeFE/element/issues/12951
5 |
6 | $menuBg:#304156;
7 | $menuHover:#263445;
8 |
9 | $subMenuBg:#1f2d3d;
10 | $subMenuHover:#001528;
11 |
12 | $sideBarWidth: 210px;
13 |
14 | // the :export directive is the magic sauce for webpack
15 | // https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
16 | :export {
17 | menuText: $menuText;
18 | menuActiveText: $menuActiveText;
19 | subMenuActiveText: $subMenuActiveText;
20 | menuBg: $menuBg;
21 | menuHover: $menuHover;
22 | subMenuBg: $subMenuBg;
23 | subMenuHover: $subMenuHover;
24 | sideBarWidth: $sideBarWidth;
25 | }
26 |
--------------------------------------------------------------------------------
/src/icons/svg/permission.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/tests/unit/components/Hamburger.spec.js:
--------------------------------------------------------------------------------
1 | import { shallowMount } from '@vue/test-utils'
2 | import Hamburger from '@/components/Hamburger/index.vue'
3 | describe('Hamburger.vue', () => {
4 | it('toggle click', () => {
5 | const wrapper = shallowMount(Hamburger)
6 | const mockFn = jest.fn()
7 | wrapper.vm.$on('toggleClick', mockFn)
8 | wrapper.find('.hamburger').trigger('click')
9 | expect(mockFn).toBeCalled()
10 | })
11 | it('prop isActive', () => {
12 | const wrapper = shallowMount(Hamburger)
13 | wrapper.setProps({ isActive: true })
14 | expect(wrapper.contains('.is-active')).toBe(true)
15 | wrapper.setProps({ isActive: false })
16 | expect(wrapper.contains('.is-active')).toBe(false)
17 | })
18 | })
19 |
--------------------------------------------------------------------------------
/tests/unit/components/SvgIcon.spec.js:
--------------------------------------------------------------------------------
1 | import { shallowMount } from '@vue/test-utils'
2 | import SvgIcon from '@/components/SvgIcon/index.vue'
3 | describe('SvgIcon.vue', () => {
4 | it('iconClass', () => {
5 | const wrapper = shallowMount(SvgIcon, {
6 | propsData: {
7 | iconClass: 'test'
8 | }
9 | })
10 | expect(wrapper.find('use').attributes().href).toBe('#icon-test')
11 | })
12 | it('className', () => {
13 | const wrapper = shallowMount(SvgIcon, {
14 | propsData: {
15 | iconClass: 'test'
16 | }
17 | })
18 | expect(wrapper.classes().length).toBe(1)
19 | wrapper.setProps({ className: 'test' })
20 | expect(wrapper.classes().includes('test')).toBe(true)
21 | })
22 | })
23 |
--------------------------------------------------------------------------------
/wfd-vue/src/behavior/hoverAnchorActived.js:
--------------------------------------------------------------------------------
1 | export default function(G6){
2 | G6.registerBehavior('hoverAnchorActived', {
3 | getEvents() {
4 | return {
5 | 'anchor:mouseenter': 'onAnchorEnter',
6 | 'anchor:mousemove': 'onAnchorEnter',
7 | 'anchor:mouseleave': 'onAnchorLeave',
8 | }
9 | },
10 | onAnchorEnter(e){
11 | if(!this.graph.get('onDragEdge'))
12 | this.graph.setItemState(e.item, 'active-anchor', true);
13 | },
14 | onAnchorLeave(e){
15 | if(!this.graph.get('onDragEdge')) {
16 | let node = e.item.getContainer().getParent();
17 | if(node) {
18 | this.graph.setItemState(e.item, 'active-anchor', false);
19 | }
20 | }
21 | }
22 | });
23 | }
--------------------------------------------------------------------------------
/src/layout/components/Sidebar/Link.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
37 |
--------------------------------------------------------------------------------
/wfd-vue/src/assets/icons/flow/icon_timer.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/layout/components/Sidebar/FixiOSBug.js:
--------------------------------------------------------------------------------
1 | export default {
2 | computed: {
3 | device() {
4 | return this.$store.state.app.device
5 | }
6 | },
7 | mounted() {
8 | // In order to fix the click on menu on the ios device will trigger the mouseleave bug
9 | // https://github.com/PanJiaChen/vue-element-admin/issues/1135
10 | this.fixBugIniOS()
11 | },
12 | methods: {
13 | fixBugIniOS() {
14 | const $subMenu = this.$refs.subMenu
15 | if ($subMenu) {
16 | const handleMouseleave = $subMenu.handleMouseleave
17 | $subMenu.handleMouseleave = (e) => {
18 | if (this.device === 'mobile') {
19 | return
20 | }
21 | handleMouseleave(e)
22 | }
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/tests/unit/utils/validate.spec.js:
--------------------------------------------------------------------------------
1 | import { validUsername, isExternal } from '@/utils/validate.js'
2 |
3 | describe('Utils:validate', () => {
4 | it('validUsername', () => {
5 | expect(validUsername('admin')).toBe(true)
6 | expect(validUsername('editor')).toBe(true)
7 | expect(validUsername('xxxx')).toBe(false)
8 | })
9 | it('isExternal', () => {
10 | expect(isExternal('https://github.com/PanJiaChen/vue-element-admin')).toBe(true)
11 | expect(isExternal('http://github.com/PanJiaChen/vue-element-admin')).toBe(true)
12 | expect(isExternal('github.com/PanJiaChen/vue-element-admin')).toBe(false)
13 | expect(isExternal('/dashboard')).toBe(false)
14 | expect(isExternal('./dashboard')).toBe(false)
15 | expect(isExternal('dashboard')).toBe(false)
16 | })
17 | })
18 |
--------------------------------------------------------------------------------
/src/icons/svg/system.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/icons/svg/workflowLaunch.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/icons/svg/systemTool.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/nested.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/wfd-vue/src/components/DetailPanel/EndEventDetail.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{i18n['endEvent']}}
4 |
5 |
6 |
7 |
8 |
9 |
32 |
--------------------------------------------------------------------------------
/src/layout/components/AppMain.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
19 |
20 |
32 |
33 |
41 |
--------------------------------------------------------------------------------
/src/views/system/workflow/components/util.js:
--------------------------------------------------------------------------------
1 | import html2canvas from 'html2canvas'
2 |
3 | export async function getScreenshot(oldVal, newVal) {
4 | if (!isEdited(oldVal, newVal)) {
5 | return null
6 | }
7 | const dom = window.document.querySelector('.js-screenshot')
8 | const imgData = await html2canvas(dom, {
9 | useCORS: true,
10 | type: 'dataURL',
11 | backgroundColor: null,
12 | scale: window.devicePixelRatio,
13 | width: dom.offsetWidth,
14 | height: dom.offsetHeight
15 | })
16 | return imgData.toDataURL()
17 | }
18 |
19 | /**
20 | * 是否修改过
21 | */
22 | function isEdited(oldVal, newVal) {
23 | // 首次需要保存图片
24 | if (!oldVal || JSON.stringify(oldVal) === '{}') return true
25 | for (const key in oldVal) {
26 | if (newVal[key] !== oldVal[key]) return true
27 | }
28 | return false
29 | }
30 |
--------------------------------------------------------------------------------
/wfd-vue/src/components/DetailPanel/StartEventDetail.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{i18n['startEvent']}}
4 |
5 |
6 |
7 |
8 |
9 |
32 |
--------------------------------------------------------------------------------
/src/icons/svg/workflowApply.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | moduleFileExtensions: ['js', 'jsx', 'json', 'vue'],
3 | transform: {
4 | '^.+\\.vue$': 'vue-jest',
5 | '.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$':
6 | 'jest-transform-stub',
7 | '^.+\\.jsx?$': 'babel-jest'
8 | },
9 | moduleNameMapper: {
10 | '^@/(.*)$': '/src/$1'
11 | },
12 | snapshotSerializers: ['jest-serializer-vue'],
13 | testMatch: [
14 | '**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'
15 | ],
16 | collectCoverageFrom: ['src/utils/**/*.{js,vue}', '!src/utils/auth.js', '!src/utils/request.js', 'src/components/**/*.{js,vue}'],
17 | coverageDirectory: '/tests/unit/coverage',
18 | // 'collectCoverage': true,
19 | 'coverageReporters': [
20 | 'lcov',
21 | 'text-summary'
22 | ],
23 | testURL: 'http://localhost/'
24 | }
25 |
--------------------------------------------------------------------------------
/src/layout/components/Sidebar/Item.vue:
--------------------------------------------------------------------------------
1 |
34 |
35 |
42 |
--------------------------------------------------------------------------------
/src/styles/element-ui.scss:
--------------------------------------------------------------------------------
1 | // cover some element-ui styles
2 |
3 | .el-breadcrumb__inner,
4 | .el-breadcrumb__inner a {
5 | font-weight: 400 !important;
6 | }
7 |
8 | .el-upload {
9 | input[type="file"] {
10 | display: none !important;
11 | }
12 | }
13 |
14 | .el-upload__input {
15 | display: none;
16 | }
17 |
18 |
19 | // to fixed https://github.com/ElemeFE/element/issues/2461
20 | .el-dialog {
21 | transform: none;
22 | left: 0;
23 | position: relative;
24 | margin: 0 auto;
25 | }
26 |
27 | // refine element ui upload
28 | .upload-container {
29 | .el-upload {
30 | width: 100%;
31 |
32 | .el-upload-dragger {
33 | width: 100%;
34 | height: 200px;
35 | }
36 | }
37 | }
38 |
39 | // dropdown
40 | .el-dropdown-menu {
41 | a {
42 | display: block
43 | }
44 | }
45 |
46 | // to fix el-date-picker css style
47 | .el-range-separator {
48 | box-sizing: content-box;
49 | }
--------------------------------------------------------------------------------
/src/icons/svg/menu.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/icons/svg/eye.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/wfd-vue/src/assets/flow/end.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
20 |
--------------------------------------------------------------------------------
/wfd-vue/src/assets/icons/flow/icon_signal.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/wfd-vue/src/plugins/canvasPanel.js:
--------------------------------------------------------------------------------
1 | const deepMix = require('@antv/util/lib/deep-mix');
2 |
3 | class CanvasPanel {
4 |
5 | constructor(cfgs) {
6 | this._cfgs = deepMix(this.getDefaultCfg(), cfgs);
7 | }
8 | getDefaultCfg() {
9 | return { container: null };
10 | }
11 |
12 | get(key) {
13 | return this._cfgs[key];
14 | }
15 | set(key, val) {
16 | this._cfgs[key] = val;
17 | }
18 |
19 | initPlugin(graph) {
20 | const parentNode = this.get('container');
21 | parentNode.addEventListener('dragover', e => {
22 | graph.emit('canvas:mousemove',e);
23 | });
24 | parentNode.addEventListener('dragleave', e => {
25 | graph.emit('canvas:mouseleave',e);
26 | });
27 | }
28 |
29 | destroy() {
30 | this.get('canvas').destroy();
31 | const container = this.get('container');
32 | container.parentNode.removeChild(container);
33 | }
34 | }
35 |
36 | export default CanvasPanel;
37 |
--------------------------------------------------------------------------------
/src/mixin/permission.js:
--------------------------------------------------------------------------------
1 | import store from '@/store'
2 |
3 | /**
4 | * @param {Array} value
5 | * @returns {Boolean}
6 | * @example see @/views/permission/directive.vue
7 | */
8 |
9 | function checkPermission(value) {
10 | if (value && value instanceof Array && value.length > 0) {
11 | const permissions = store.getters && store.getters.permissions
12 | const permissionRoles = value
13 |
14 | const hasPermission = permissions.some(role => {
15 | return permissionRoles.includes(role)
16 | })
17 |
18 | if (!hasPermission) {
19 | return false
20 | }
21 | return true
22 | } else {
23 | console.error(`need roles! Like v-permission="['admin','editor']"`)
24 | return false
25 | }
26 | }
27 |
28 | export default {
29 | install: function(Vue, options) {
30 | Vue.mixin({
31 | methods: {
32 | checkPermission
33 | }
34 | })
35 | }
36 | }
37 |
38 | export { checkPermission }
39 |
--------------------------------------------------------------------------------
/src/styles/transition.scss:
--------------------------------------------------------------------------------
1 | // global transition css
2 |
3 | /* fade */
4 | .fade-enter-active,
5 | .fade-leave-active {
6 | transition: opacity 0.28s;
7 | }
8 |
9 | .fade-enter,
10 | .fade-leave-active {
11 | opacity: 0;
12 | }
13 |
14 | /* fade-transform */
15 | .fade-transform-leave-active,
16 | .fade-transform-enter-active {
17 | transition: all .5s;
18 | }
19 |
20 | .fade-transform-enter {
21 | opacity: 0;
22 | transform: translateX(-30px);
23 | }
24 |
25 | .fade-transform-leave-to {
26 | opacity: 0;
27 | transform: translateX(30px);
28 | }
29 |
30 | /* breadcrumb transition */
31 | .breadcrumb-enter-active,
32 | .breadcrumb-leave-active {
33 | transition: all .5s;
34 | }
35 |
36 | .breadcrumb-enter,
37 | .breadcrumb-leave-active {
38 | opacity: 0;
39 | transform: translateX(20px);
40 | }
41 |
42 | .breadcrumb-move {
43 | transition: all .5s;
44 | }
45 |
46 | .breadcrumb-leave-active {
47 | position: absolute;
48 | }
49 |
--------------------------------------------------------------------------------
/src/icons/svg/workflowTodo.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/wfd-vue/src/assets/flow/start.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
20 |
--------------------------------------------------------------------------------
/wfd-vue/src/assets/flow/timer-catch.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
14 |
--------------------------------------------------------------------------------
/wfd-vue/src/behavior/hoverNodeActived.js:
--------------------------------------------------------------------------------
1 | export default function(G6){
2 | G6.registerBehavior('hoverNodeActived', {
3 | getEvents() {
4 | return {
5 | 'node:mouseenter': 'onNodeEnter',
6 | 'node:mouseleave': 'onNodeLeave',
7 | 'anchor:mouseleave': 'onAnchorLeave',
8 | }
9 | },
10 | onAnchorLeave(e){
11 | let node = e.item.getContainer().getParent();
12 | if(node && !this.graph.get('onDragEdge')) {
13 | this.graph.setItemState(node.get('item'), 'show-anchor', false);
14 | }
15 | },
16 | onNodeEnter(e){
17 | const clazz = e.item.getModel().clazz;
18 | if(clazz !== 'endEvent' && !this.graph.get('onDragEdge'))
19 | this.graph.setItemState(e.item, 'show-anchor', true);
20 | },
21 | onNodeLeave(e){
22 | if(e.target.type !== 'marker' && !this.graph.get('onDragEdge')) {
23 | this.graph.setItemState(e.item, 'show-anchor', false);
24 | }
25 | },
26 | });
27 | }
--------------------------------------------------------------------------------
/wfd-vue/src/assets/flow/inclusive-gateway.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
20 |
--------------------------------------------------------------------------------
/wfd-vue/src/behavior/deleteItem.js:
--------------------------------------------------------------------------------
1 | export default function(G6){
2 | G6.registerBehavior('deleteItem', {
3 | getEvents() {
4 | return {
5 | 'keydown': 'onKeydown',
6 | 'canvas:mouseleave': 'onCanvasLeave',
7 | 'canvas:mouseenter': 'onCanvasFocus',
8 | }
9 | },
10 | onKeydown(e){
11 | const items = this.graph.get('selectedItems');
12 | const focus = this.graph.get('focusGraphWrapper');
13 | if(e.keyCode === 8 && items && items.length > 0 && focus){
14 | if(this.graph.executeCommand) {
15 | this.graph.executeCommand('delete', {});
16 | }else{
17 | this.graph.remove(items[0]);
18 | }
19 | this.graph.set('selectedItems',[]);
20 | this.graph.emit('afteritemselected',[]);
21 | }
22 | },
23 | onCanvasLeave(e){
24 | this.graph.set('focusGraphWrapper',false);
25 | },
26 | onCanvasFocus(){
27 | this.graph.set('focusGraphWrapper',true);
28 | }
29 | });
30 | }
--------------------------------------------------------------------------------
/wfd-vue/src/components/DetailPanel/GatewayDetail.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{model.clazz === 'exclusiveGateway' || model.clazz === 'gateway' ? i18n['exclusiveGateway']
4 | : model.clazz === 'parallelGateway' ? i18n['parallelGateway'] : i18n['inclusiveGateway']}}
5 |
6 |
7 |
8 |
9 |
10 |
33 |
--------------------------------------------------------------------------------
/wfd-vue/src/util/clazz.js:
--------------------------------------------------------------------------------
1 | export function getShapeName(clazz) {
2 | switch (clazz) {
3 | case 'start': return 'start-node';
4 | case 'end': return 'end-node';
5 | case 'gateway': return 'gateway-node';
6 | case 'exclusiveGateway': return 'exclusive-gateway-node';
7 | case 'parallelGateway': return 'parallel-gateway-node';
8 | case 'inclusiveGateway': return 'inclusive-gateway-node';
9 | case 'timerStart': return 'timer-start-node';
10 | case 'messageStart': return 'message-start-node';
11 | case 'signalStart': return 'signal-start-node';
12 | case 'userTask': return 'user-task-node';
13 | case 'scriptTask': return 'script-task-node';
14 | case 'mailTask': return 'mail-task-node';
15 | case 'javaTask': return 'java-task-node';
16 | case 'receiveTask': return 'receive-task-node';
17 | case 'timerCatch': return 'timer-catch-node';
18 | case 'messageCatch': return 'message-catch-node';
19 | case 'signalCatch': return 'signal-catch-node';
20 | default: return 'task-node';
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/wfd-vue/src/shape/anchor.js:
--------------------------------------------------------------------------------
1 | import editorStyle from "../util/defaultStyle";
2 | const SingleShapeMixin = require('@antv/g6/src/shape/single-shape-mixin');
3 | export default function(G6){
4 | G6.Shape.registerFactory('anchor', {
5 | defaultShapeType: 'marker'
6 | });
7 | G6.Shape.registerAnchor('single-anchor', G6.Util.mix({}, SingleShapeMixin, {
8 | itemType: 'anchor',
9 |
10 | drawShape(cfg, group) {
11 | const shapeType = this.shapeType;
12 | const style = this.getShapeStyle(cfg);
13 | const shape = group.addShape(shapeType, {
14 | attrs: style
15 | });
16 | return shape;
17 | },
18 |
19 | setState(name, value, item) {
20 | if(name === 'active-anchor') {
21 | if(value) {
22 | this.update({style: {...editorStyle.anchorPointHoverStyle}}, item);
23 | }else{
24 | this.update({style: {...editorStyle.anchorPointStyle}}, item);
25 | }
26 | }
27 | }
28 | }));
29 | G6.Shape.registerAnchor('marker',{ shapeType:'marker' },'single-anchor');
30 | }
31 |
--------------------------------------------------------------------------------
/wfd-vue/src/assets/flow/mail-task.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
18 |
--------------------------------------------------------------------------------
/src/api/actModel.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request'
2 |
3 | /**
4 | * 分页获取
5 | */
6 | export function getActModelPage(params, pageNum, pageSize) {
7 | return request({
8 | url: '/workflow/model/list/page',
9 | method: 'get',
10 | params: {
11 | ...params,
12 | pageNum,
13 | pageSize
14 | }
15 | })
16 | }
17 |
18 | /**
19 | * 获取详情
20 | */
21 | export function getActModelDetail(id) {
22 | return request({
23 | url: '/workflow/model/detail/' + id,
24 | method: 'get'
25 | })
26 | }
27 |
28 | /**
29 | * 保存
30 | */
31 | export function saveActModel(data) {
32 | return request({
33 | url: '/workflow/model/save',
34 | method: 'post',
35 | data
36 | })
37 | }
38 |
39 | /**
40 | * 部署
41 | */
42 | export function deployActModel(id) {
43 | return request({
44 | url: '/workflow/model/deploy/' + id,
45 | method: 'post'
46 | })
47 | }
48 |
49 | /**
50 | * 删除
51 | */
52 | export function deleteActModel(id) {
53 | return request({
54 | url: '/workflow/model/del/' + id,
55 | method: 'delete'
56 | })
57 | }
58 |
--------------------------------------------------------------------------------
/wfd-vue/src/components/DetailPanel/DefaultDetail.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
{{i18n['label']}}:
5 |
{onChange('label', value)}" />
9 |
10 |
11 | onChange('hideIcon', value)"
12 | :disabled="readOnly"
13 | :value="!!model.hideIcon">{{i18n['hideIcon']}}
14 |
15 |
16 |
17 |
36 |
--------------------------------------------------------------------------------
/src/api/dictionary.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request'
2 |
3 | /**
4 | * 分页获取
5 | */
6 | export function getDictionaryPage(params, pageNum, pageSize) {
7 | return request({
8 | url: '/dictionary/list/page',
9 | method: 'get',
10 | params: {
11 | ...params,
12 | pageNum,
13 | pageSize
14 | }
15 | })
16 | }
17 |
18 | /**
19 | * 不分页获取
20 | */
21 | export function getDictionaryList(params) {
22 | return request({
23 | url: '/dictionary/list/all',
24 | method: 'get',
25 | params
26 | })
27 | }
28 |
29 | /**
30 | * 获取详情
31 | */
32 | export function getDictionaryDetail(id) {
33 | return request({
34 | url: '/dictionary/detail/' + id,
35 | method: 'get'
36 | })
37 | }
38 |
39 | /**
40 | * 保存
41 | */
42 | export function saveDictionary(data) {
43 | return request({
44 | url: '/dictionary/save',
45 | method: 'post',
46 | data
47 | })
48 | }
49 |
50 | /**
51 | * 删除
52 | */
53 | export function deleteDictionary(id) {
54 | return request({
55 | url: '/dictionary/del/' + id,
56 | method: 'delete'
57 | })
58 | }
59 |
--------------------------------------------------------------------------------
/tests/unit/utils/parseTime.spec.js:
--------------------------------------------------------------------------------
1 | import { parseTime } from '@/utils/index.js'
2 |
3 | describe('Utils:parseTime', () => {
4 | const d = new Date('2018-07-13 17:54:01') // "2018-07-13 17:54:01"
5 | it('timestamp', () => {
6 | expect(parseTime(d)).toBe('2018-07-13 17:54:01')
7 | })
8 | it('ten digits timestamp', () => {
9 | expect(parseTime((d / 1000).toFixed(0))).toBe('2018-07-13 17:54:01')
10 | })
11 | it('new Date', () => {
12 | expect(parseTime(new Date(d))).toBe('2018-07-13 17:54:01')
13 | })
14 | it('format', () => {
15 | expect(parseTime(d, '{y}-{m}-{d} {h}:{i}')).toBe('2018-07-13 17:54')
16 | expect(parseTime(d, '{y}-{m}-{d}')).toBe('2018-07-13')
17 | expect(parseTime(d, '{y}/{m}/{d} {h}-{i}')).toBe('2018/07/13 17-54')
18 | })
19 | it('get the day of the week', () => {
20 | expect(parseTime(d, '{a}')).toBe('五') // 星期五
21 | })
22 | it('get the day of the week', () => {
23 | expect(parseTime(+d + 1000 * 60 * 60 * 24 * 2, '{a}')).toBe('日') // 星期日
24 | })
25 | it('empty argument', () => {
26 | expect(parseTime()).toBeNull()
27 | })
28 | })
29 |
--------------------------------------------------------------------------------
/wfd-vue/src/assets/flow/signal-catch.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
15 |
--------------------------------------------------------------------------------
/src/icons/svg/monitorSql.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/api/flowHistory.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request'
2 |
3 | /**
4 | * 分页获取
5 | */
6 | export function getFlowHistoryPage(params, pageNum, pageSize) {
7 | return request({
8 | url: '/flow-history/list/page',
9 | method: 'get',
10 | params: {
11 | ...params,
12 | pageNum,
13 | pageSize
14 | }
15 | })
16 | }
17 |
18 | /**
19 | * 不分页获取
20 | */
21 | export function getFlowHistoryList(params) {
22 | return request({
23 | url: '/flow-history/list/all',
24 | method: 'get',
25 | params
26 | })
27 | }
28 |
29 | /**
30 | * 获取详情
31 | */
32 | export function getFlowHistoryDetail(id) {
33 | return request({
34 | url: '/flow-history/detail/' + id,
35 | method: 'get'
36 | })
37 | }
38 |
39 | /**
40 | * 保存
41 | */
42 | export function saveFlowHistory(data) {
43 | return request({
44 | url: '/flow-history/save',
45 | method: 'post',
46 | data
47 | })
48 | }
49 |
50 | /**
51 | * 删除
52 | */
53 | export function deleteFlowHistory(id) {
54 | return request({
55 | url: '/flow-history/del/' + id,
56 | method: 'delete'
57 | })
58 | }
59 |
--------------------------------------------------------------------------------
/src/icons/svg/workflowModel.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/utils/tree.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 根据list获取到叶子节点
3 | */
4 | export function getLeafFromList(list) {
5 | const pidSet = new Set()
6 | list.forEach(item => pidSet.add(item.pid))
7 | return list.filter(item => !pidSet.has(item.id))
8 | }
9 |
10 | /**
11 | * list 转 tree
12 | */
13 | export function listToTree(data) {
14 | const idSet = new Set()
15 | const pidSet = new Set()
16 | const map = new Map()
17 | data.forEach(item => {
18 | idSet.add(item.id)
19 | pidSet.add(item.pid)
20 | map.get(item.pid) ? map.get(item.pid).push(item) : map.set(item.pid, [item])
21 | })
22 | return data.filter(item => {
23 | if (map.get(item.id)) item.children = map.get(item.id)
24 | return (!idSet.has(item.pid)) && pidSet.has(item.pid)
25 | })
26 | }
27 |
28 | /**
29 | * tree 转 list
30 | */
31 | export function treeToList(tree) {
32 | const result = []
33 | recursive(tree)
34 | return result
35 | function recursive(data) {
36 | data.forEach(item => {
37 | result.push(item)
38 | if (item.children && item.children.length > 0) {
39 | recursive(item.children)
40 | }
41 | })
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/wfd-vue/src/assets/flow/message-catch.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
16 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017-present PanJiaChen
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/wfd-vue/src/assets/icons/flow/icon_mail.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/api/dictionaryItem.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request'
2 |
3 | /**
4 | * 分页获取
5 | */
6 | export function getDictionaryItemPage(params, pageNum, pageSize) {
7 | return request({
8 | url: '/dictionary-item/list/page',
9 | method: 'get',
10 | params: {
11 | ...params,
12 | pageNum,
13 | pageSize
14 | }
15 | })
16 | }
17 |
18 | /**
19 | * 不分页获取
20 | */
21 | export function getDictionaryItemList(params) {
22 | return request({
23 | url: '/dictionary-item/list/all',
24 | method: 'get',
25 | params
26 | })
27 | }
28 |
29 | /**
30 | * 获取详情
31 | */
32 | export function getDictionaryItemDetail(id) {
33 | return request({
34 | url: '/dictionary-item/detail/' + id,
35 | method: 'get'
36 | })
37 | }
38 |
39 | /**
40 | * 保存
41 | */
42 | export function saveDictionaryItem(data) {
43 | return request({
44 | url: '/dictionary-item/save',
45 | method: 'post',
46 | data
47 | })
48 | }
49 |
50 | /**
51 | * 删除
52 | */
53 | export function deleteDictionaryItem(id) {
54 | return request({
55 | url: '/dictionary-item/del/' + id,
56 | method: 'delete'
57 | })
58 | }
59 |
--------------------------------------------------------------------------------
/src/store/modules/socket.js:
--------------------------------------------------------------------------------
1 |
2 | import Vue from 'vue'
3 | import VueSocketIO from 'vue-socket.io'
4 | // import store from '../index'
5 | import api from './api'
6 |
7 | const state = {
8 | vueSocketIO: null
9 | }
10 |
11 | const mutations = {
12 | SET_VUE_SOCKET_IO: (state, vueSocketIO) => {
13 | state.vueSocketIO = vueSocketIO
14 | }
15 | }
16 |
17 | const actions = {
18 | register({ commit }) {
19 | const vueSocketIO = new VueSocketIO({
20 | debug: process.env.NODE_ENV === 'development',
21 | connection: `${window.location.protocol}//${window.location.hostname}:${api.state.socketPort}`,
22 | // vuex: {
23 | // store,
24 | // actionPrefix: 'SOCKET_',
25 | // mutationPrefix: 'SOCKET_'
26 | // },
27 | options: {
28 | path: api.state.baseUrl + '/socket.io',
29 | transports: ['websocket']
30 | }
31 | })
32 | Vue.use(vueSocketIO)
33 | commit('SET_VUE_SOCKET_IO', vueSocketIO)
34 | },
35 | logout() {
36 | state.vueSocketIO?.io.close()
37 | }
38 | }
39 |
40 | export default {
41 | namespaced: true,
42 | state,
43 | mutations,
44 | actions
45 | }
46 |
--------------------------------------------------------------------------------
/src/icons/svg/workflowDone.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/tests/unit/utils/formatTime.spec.js:
--------------------------------------------------------------------------------
1 | import { formatTime } from '@/utils/index.js'
2 |
3 | describe('Utils:formatTime', () => {
4 | const d = new Date('2018-07-13 17:54:01') // "2018-07-13 17:54:01"
5 | const retrofit = 5 * 1000
6 |
7 | it('ten digits timestamp', () => {
8 | expect(formatTime((d / 1000).toFixed(0))).toBe('7月13日17时54分')
9 | })
10 | it('test now', () => {
11 | expect(formatTime(+new Date() - 1)).toBe('刚刚')
12 | })
13 | it('less two minute', () => {
14 | expect(formatTime(+new Date() - 60 * 2 * 1000 + retrofit)).toBe('2分钟前')
15 | })
16 | it('less two hour', () => {
17 | expect(formatTime(+new Date() - 60 * 60 * 2 * 1000 + retrofit)).toBe('2小时前')
18 | })
19 | it('less one day', () => {
20 | expect(formatTime(+new Date() - 60 * 60 * 24 * 1 * 1000)).toBe('1天前')
21 | })
22 | it('more than one day', () => {
23 | expect(formatTime(d)).toBe('7月13日17时54分')
24 | })
25 | it('format', () => {
26 | expect(formatTime(d, '{y}-{m}-{d} {h}:{i}')).toBe('2018-07-13 17:54')
27 | expect(formatTime(d, '{y}-{m}-{d}')).toBe('2018-07-13')
28 | expect(formatTime(d, '{y}/{m}/{d} {h}-{i}')).toBe('2018/07/13 17-54')
29 | })
30 | })
31 |
--------------------------------------------------------------------------------
/wfd-vue/src/assets/flow/script-task.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
19 |
--------------------------------------------------------------------------------
/templates/api.ejs:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request'
2 |
3 | <%_ var entityKebab = StrUtil.camelToKebab(entity) -%>
4 | /**
5 | * 分页获取
6 | */
7 | export function get<%= Entity %>Page(params, pageNum, pageSize) {
8 | return request({
9 | url: '/<%= entityKebab %>/list/page',
10 | method: 'get',
11 | params: {
12 | ...params,
13 | pageNum,
14 | pageSize
15 | }
16 | })
17 | }
18 |
19 | /**
20 | * 不分页获取
21 | */
22 | export function get<%= Entity %>List(params) {
23 | return request({
24 | url: '/<%= entityKebab %>/list/all',
25 | method: 'get',
26 | params
27 | })
28 | }
29 |
30 | /**
31 | * 获取详情
32 | */
33 | export function get<%= Entity %>Detail(id) {
34 | return request({
35 | url: '/<%= entityKebab %>/detail/' + id,
36 | method: 'get'
37 | })
38 | }
39 |
40 | /**
41 | * 保存
42 | */
43 | export function save<%= Entity %>(data) {
44 | return request({
45 | url: '/<%= entityKebab %>/save',
46 | method: 'post',
47 | data
48 | })
49 | }
50 |
51 | /**
52 | * 删除
53 | */
54 | export function delete<%= Entity %>(id) {
55 | return request({
56 | url: '/<%= entityKebab %>/del/' + id,
57 | method: 'delete'
58 | })
59 | }
60 |
--------------------------------------------------------------------------------
/wfd-vue/src/components/DetailPanel/JavaTaskDetail.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{i18n['javaTask']}}
4 |
5 |
6 |
7 |
{{i18n['javaTask.javaClass']}}:
8 |
{onChange('javaClass', value)}" />
12 |
13 |
14 |
15 |
16 |
39 |
--------------------------------------------------------------------------------
/src/styles/index.scss:
--------------------------------------------------------------------------------
1 | @import './variables.scss';
2 | @import './mixin.scss';
3 | @import './transition.scss';
4 | @import './element-ui.scss';
5 | @import './sidebar.scss';
6 |
7 | body {
8 | height: 100%;
9 | -moz-osx-font-smoothing: grayscale;
10 | -webkit-font-smoothing: antialiased;
11 | text-rendering: optimizeLegibility;
12 | font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif;
13 | }
14 |
15 | label {
16 | font-weight: 700;
17 | }
18 |
19 | html {
20 | height: 100%;
21 | box-sizing: border-box;
22 | }
23 |
24 | #app {
25 | height: 100%;
26 | }
27 |
28 | *,
29 | *:before,
30 | *:after {
31 | box-sizing: inherit;
32 | }
33 |
34 | a:focus,
35 | a:active {
36 | outline: none;
37 | }
38 |
39 | a,
40 | a:focus,
41 | a:hover {
42 | cursor: pointer;
43 | color: inherit;
44 | text-decoration: none;
45 | }
46 |
47 | div:focus {
48 | outline: none;
49 | }
50 |
51 | .clearfix {
52 | &:after {
53 | visibility: hidden;
54 | display: block;
55 | font-size: 0;
56 | content: " ";
57 | clear: both;
58 | height: 0;
59 | }
60 | }
61 |
62 | // main-container global css
63 | .app-container {
64 | padding: 20px;
65 | }
66 |
--------------------------------------------------------------------------------
/wfd-vue/src/assets/flow/parallel-gateway.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
23 |
--------------------------------------------------------------------------------
/src/icons/svg/workflow.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/wfd-vue/src/assets/flow/gateway.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
23 |
--------------------------------------------------------------------------------
/src/api/dept.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request'
2 |
3 | /**
4 | * 分页获取部门
5 | */
6 | export function getDeptPage(params, pageNum, pageSize) {
7 | return request({
8 | url: '/dept/list/page',
9 | method: 'get',
10 | params: {
11 | ...params,
12 | pageNum,
13 | pageSize
14 | }
15 | })
16 | }
17 |
18 | /**
19 | * 不分页获取部门
20 | */
21 | export function getDeptList(params) {
22 | return request({
23 | url: '/dept/list/all',
24 | method: 'get',
25 | params
26 | })
27 | }
28 |
29 | /**
30 | * 获取部门详情
31 | */
32 | export function getDeptDetail(id) {
33 | return request({
34 | url: '/dept/detail/' + id,
35 | method: 'get'
36 | })
37 | }
38 |
39 | /**
40 | * 获取部门的 tree
41 | */
42 | export function getDeptTree(params) {
43 | return request({
44 | url: '/dept/tree/list',
45 | method: 'get',
46 | params
47 | })
48 | }
49 |
50 | /**
51 | * 保存部门
52 | */
53 | export function saveDept(data) {
54 | return request({
55 | url: '/dept/save',
56 | method: 'post',
57 | data
58 | })
59 | }
60 |
61 | /**
62 | * 删除部门
63 | */
64 | export function deleteDept(id) {
65 | return request({
66 | url: '/dept/del/' + id,
67 | method: 'delete'
68 | })
69 | }
70 |
--------------------------------------------------------------------------------
/wfd-vue/src/assets/flow/exclusive-gateway.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
23 |
--------------------------------------------------------------------------------
/wfd-vue/src/assets/flow/timer-start.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
22 |
--------------------------------------------------------------------------------
/wfd-vue/src/assets/flow/user-task.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
21 |
--------------------------------------------------------------------------------
/src/icons/svg/eye-open.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/store/modules/app.js:
--------------------------------------------------------------------------------
1 | import Cookies from 'js-cookie'
2 |
3 | const state = {
4 | sidebar: {
5 | opened: Cookies.get('sidebarStatus') ? !!+Cookies.get('sidebarStatus') : true,
6 | withoutAnimation: false
7 | },
8 | device: 'desktop'
9 | }
10 |
11 | const mutations = {
12 | TOGGLE_SIDEBAR: state => {
13 | state.sidebar.opened = !state.sidebar.opened
14 | state.sidebar.withoutAnimation = false
15 | if (state.sidebar.opened) {
16 | Cookies.set('sidebarStatus', 1)
17 | } else {
18 | Cookies.set('sidebarStatus', 0)
19 | }
20 | },
21 | CLOSE_SIDEBAR: (state, withoutAnimation) => {
22 | Cookies.set('sidebarStatus', 0)
23 | state.sidebar.opened = false
24 | state.sidebar.withoutAnimation = withoutAnimation
25 | },
26 | TOGGLE_DEVICE: (state, device) => {
27 | state.device = device
28 | }
29 | }
30 |
31 | const actions = {
32 | toggleSideBar({ commit }) {
33 | commit('TOGGLE_SIDEBAR')
34 | },
35 | closeSideBar({ commit }, { withoutAnimation }) {
36 | commit('CLOSE_SIDEBAR', withoutAnimation)
37 | },
38 | toggleDevice({ commit }, device) {
39 | commit('TOGGLE_DEVICE', device)
40 | }
41 | }
42 |
43 | export default {
44 | namespaced: true,
45 | state,
46 | mutations,
47 | actions
48 | }
49 |
--------------------------------------------------------------------------------
/src/views/system/workflow/components/approveForm.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | 通过
7 | 驳回
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
47 |
--------------------------------------------------------------------------------
/src/views/system/manage/dictionary/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | 字典列表
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | 字典详情
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
50 |
51 |
54 |
--------------------------------------------------------------------------------
/wfd-vue/src/assets/icons/flow/icon_script.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/wfd-vue/src/components/DetailPanel/ScriptTaskDetail.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{i18n['scriptTask']}}
4 |
5 |
6 |
7 |
{{i18n['scriptTask.script']}}:
8 |
{onChange('script', value)}" />
14 |
15 |
16 |
17 |
18 |
41 |
--------------------------------------------------------------------------------
/src/icons/svg/workflowProcess.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/api/location.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request'
2 |
3 | /**
4 | * 分页获取
5 | */
6 | export function getLocationPage(params, pageNum, pageSize) {
7 | return request({
8 | url: '/location/list/page',
9 | method: 'get',
10 | params: {
11 | ...params,
12 | pageNum,
13 | pageSize
14 | }
15 | })
16 | }
17 |
18 | /**
19 | * 获取tree
20 | */
21 | export function getLocationTree(params) {
22 | return request({
23 | url: '/location/tree',
24 | method: 'get',
25 | params: {
26 | ...params
27 | }
28 | })
29 | }
30 |
31 | /**
32 | * 不分页获取
33 | */
34 | export function getLocationList(params) {
35 | return request({
36 | url: '/location/list/all',
37 | method: 'get',
38 | params
39 | })
40 | }
41 |
42 | /**
43 | * 获取详情
44 | */
45 | export function getLocationDetail(id) {
46 | return request({
47 | url: '/location/detail/' + id,
48 | method: 'get'
49 | })
50 | }
51 |
52 | /**
53 | * 保存
54 | */
55 | export function saveLocation(data) {
56 | return request({
57 | url: '/location/save',
58 | method: 'post',
59 | data
60 | })
61 | }
62 |
63 | /**
64 | * 删除
65 | */
66 | export function deleteLocation(id) {
67 | return request({
68 | url: '/location/del/' + id,
69 | method: 'delete'
70 | })
71 | }
72 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 |
3 | import 'normalize.css/normalize.css' // A modern alternative to CSS resets
4 |
5 | import ElementUI from 'element-ui'
6 | import 'element-ui/lib/theme-chalk/index.css'
7 |
8 | import '@/styles/index.scss' // global css
9 |
10 | import App from './App'
11 | import store from './store'
12 | import router from './router'
13 |
14 | import '@/icons' // icon
15 | import '@/permission' // permission control
16 |
17 | import checkPermission from '@/mixin/permission' // 全局加载校验
18 | import commonMsg from '@/mixin/commonMsg' // 全局加载校验
19 | import Xcrud from 'xcrud' // 增删改查的包
20 | import XcrudConfig from '../xcrud.config.js' // 全局加载数据字典
21 |
22 | /**
23 | * If you don't want to use mock-server
24 | * you want to use MockJs for mock api
25 | * you can execute: mockXHR()
26 | *
27 | * Currently MockJs will be used in the production environment,
28 | * please remove it before going online! ! !
29 | */
30 | // import { mockXHR } from '../mock'
31 | // if (process.env.NODE_ENV === 'production') {
32 | // mockXHR()
33 | // }
34 |
35 | Vue.use(ElementUI)
36 | Vue.use(checkPermission)
37 | Vue.use(commonMsg)
38 | Vue.use(Xcrud, XcrudConfig)
39 |
40 | Vue.config.productionTip = false
41 |
42 | new Vue({
43 | el: '#app',
44 | router,
45 | store,
46 | render: h => h(App)
47 | })
48 |
--------------------------------------------------------------------------------
/src/views/system/workflow/components/editHistory.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
47 |
48 |
51 |
--------------------------------------------------------------------------------
/wfd-vue/src/assets/flow/signal-start.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
23 |
--------------------------------------------------------------------------------
/src/components/Hamburger/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
16 |
32 |
33 |
45 |
--------------------------------------------------------------------------------
/src/icons/svg/location.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/icons/svg/schedule.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/layout/mixin/ResizeHandler.js:
--------------------------------------------------------------------------------
1 | import store from '@/store'
2 |
3 | const { body } = document
4 | const WIDTH = 992 // refer to Bootstrap's responsive design
5 |
6 | export default {
7 | watch: {
8 | $route(route) {
9 | if (this.device === 'mobile' && this.sidebar.opened) {
10 | store.dispatch('app/closeSideBar', { withoutAnimation: false })
11 | }
12 | }
13 | },
14 | beforeMount() {
15 | window.addEventListener('resize', this.$_resizeHandler)
16 | },
17 | beforeDestroy() {
18 | window.removeEventListener('resize', this.$_resizeHandler)
19 | },
20 | mounted() {
21 | const isMobile = this.$_isMobile()
22 | if (isMobile) {
23 | store.dispatch('app/toggleDevice', 'mobile')
24 | store.dispatch('app/closeSideBar', { withoutAnimation: true })
25 | }
26 | },
27 | methods: {
28 | // use $_ for mixins properties
29 | // https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential
30 | $_isMobile() {
31 | const rect = body.getBoundingClientRect()
32 | return rect.width - 1 < WIDTH
33 | },
34 | $_resizeHandler() {
35 | if (!document.hidden) {
36 | const isMobile = this.$_isMobile()
37 | store.dispatch('app/toggleDevice', isMobile ? 'mobile' : 'desktop')
38 |
39 | if (isMobile) {
40 | store.dispatch('app/closeSideBar', { withoutAnimation: true })
41 | }
42 | }
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/wfd-vue/src/item/anchor.js:
--------------------------------------------------------------------------------
1 | import editorStyle from '../util/defaultStyle';
2 | const Item = require('@antv/g6/src/item/item');
3 |
4 | const createAnchor = (index,style,group) => {
5 | const anchorContainer = group.addGroup();
6 | const anchor = new Item({
7 | type: 'anchor',
8 | group: anchorContainer,
9 | capture: false,
10 | index,
11 | isActived: false,
12 | model: {
13 | style: {
14 | ...style,
15 | ...editorStyle.anchorPointStyle,
16 | cursor: editorStyle.cursor.hoverEffectiveAnchor,
17 | }
18 | },
19 | });
20 | anchor.isAnchor = true;
21 | anchor.toFront();
22 | let hotpot;
23 | anchor.showHotpot = function () {
24 | hotpot = anchorContainer.addShape('marker', {
25 | attrs: {
26 | ...style,
27 | ...editorStyle.anchorHotsoptStyle
28 | }
29 | });
30 | hotpot.toFront();
31 | anchor.getKeyShape().toFront();
32 | };
33 | anchor.setActived = function () {
34 | anchor.update({style: {...editorStyle.anchorPointHoverStyle}});
35 | };
36 | anchor.clearActived = function () {
37 | anchor.update({style: {...editorStyle.anchorPointStyle}});
38 | };
39 | anchor.setHotspotActived = function (act) {
40 | hotpot &&
41 | (act ?
42 | hotpot.attr(editorStyle.anchorHotsoptActivedStyle)
43 | : hotpot.attr(editorStyle.anchorHotsoptStyle))
44 | };
45 | return anchorContainer;
46 | };
47 |
48 | export default createAnchor;
49 |
--------------------------------------------------------------------------------
/wfd-vue/src/assets/flow/receive-task.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
22 |
--------------------------------------------------------------------------------
/src/router/modules/systemManage.js:
--------------------------------------------------------------------------------
1 | import Layout from '@/layout'
2 |
3 | const systemManageRouter = {
4 | path: '/system/manage',
5 | component: Layout,
6 | redirect: '/system/manage/permission',
7 | name: 'System',
8 | meta: {
9 | title: '系统设置',
10 | icon: 'system',
11 | permission: ['systemManage']
12 | },
13 | children: [
14 | {
15 | path: 'permission',
16 | component: () => import('@/views/system/manage/permission/index'),
17 | name: 'Permission',
18 | meta: { title: '权限管理', icon: 'permission', permission: ['permission'] }
19 | },
20 | {
21 | path: 'dept',
22 | component: () => import('@/views/system/manage/dept/index'),
23 | name: 'dept',
24 | meta: { title: '部门管理', icon: 'tree', permission: ['dept'] }
25 | },
26 | {
27 | path: 'role',
28 | component: () => import('@/views/system/manage/role/index'),
29 | name: 'role',
30 | meta: { title: '角色管理', icon: 'role', permission: ['role'] }
31 | },
32 | {
33 | path: 'user',
34 | component: () => import('@/views/system/manage/user/index'),
35 | name: 'user',
36 | meta: { title: '用户管理', icon: 'user', permission: ['user'] }
37 | },
38 | {
39 | path: 'dictionary',
40 | component: () => import('@/views/system/manage/dictionary/index'),
41 | name: 'dictionary',
42 | meta: { title: '字典管理', icon: 'dictionary', permission: ['dictionary'] }
43 | }
44 | ]
45 | }
46 | export default systemManageRouter
47 |
--------------------------------------------------------------------------------
/src/api/flowLeave.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request'
2 |
3 | /**
4 | * 分页获取
5 | */
6 | export function getFlowLeavePage(params, pageNum, pageSize) {
7 | return request({
8 | url: '/flow-leave/list/page',
9 | method: 'get',
10 | params: {
11 | ...params,
12 | pageNum,
13 | pageSize
14 | }
15 | })
16 | }
17 |
18 | /**
19 | * 不分页获取
20 | */
21 | export function getFlowLeaveList(params) {
22 | return request({
23 | url: '/flow-leave/list/all',
24 | method: 'get',
25 | params
26 | })
27 | }
28 |
29 | /**
30 | * 获取详情
31 | */
32 | export function getFlowLeaveDetail(id) {
33 | return request({
34 | url: '/flow-leave/detail/' + id,
35 | method: 'get'
36 | })
37 | }
38 |
39 | /**
40 | * 获取详情
41 | */
42 | export function getFlowLeaveDetailByProcessInstanceId(id) {
43 | return request({
44 | url: '/flow-leave/detail/by-process-instance-id/' + id,
45 | method: 'get'
46 | })
47 | }
48 |
49 | /**
50 | * 保存
51 | */
52 | export function saveFlowLeave(data) {
53 | return request({
54 | url: '/flow-leave/save',
55 | method: 'post',
56 | data
57 | })
58 | }
59 |
60 | /**
61 | * 审批完成
62 | */
63 | export function approveFlowLeave(data) {
64 | return request({
65 | url: '/flow-leave/approve',
66 | method: 'post',
67 | data
68 | })
69 | }
70 |
71 | /**
72 | * 删除
73 | */
74 | export function deleteFlowLeave(id) {
75 | return request({
76 | url: '/flow-leave/del/' + id,
77 | method: 'delete'
78 | })
79 | }
80 |
--------------------------------------------------------------------------------
/src/api/permission.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request'
2 |
3 | /**
4 | * 分页获取权限
5 | */
6 | export function getPermissionPage(params, pageNum, pageSize) {
7 | return request({
8 | url: '/permission/list/page',
9 | method: 'get',
10 | params: {
11 | ...params,
12 | pageNum,
13 | pageSize
14 | }
15 | })
16 | }
17 |
18 | /**
19 | * 不分页获取权限
20 | */
21 | export function getPermissionList(params) {
22 | return request({
23 | url: '/permission/list/all',
24 | method: 'get',
25 | params
26 | })
27 | }
28 |
29 | /**
30 | * 获取权限详情
31 | */
32 | export function getPermissionDetail(id) {
33 | return request({
34 | url: '/permission/detail/' + id,
35 | method: 'get'
36 | })
37 | }
38 |
39 | /**
40 | * 获取权限的 tree
41 | */
42 | export function getPermissionTree(params) {
43 | return request({
44 | url: '/permission/tree/list',
45 | method: 'get',
46 | params
47 | })
48 | }
49 |
50 | /**
51 | * 保存权限
52 | */
53 | export function savePermission(data) {
54 | return request({
55 | url: '/permission/save',
56 | method: 'post',
57 | data
58 | })
59 | }
60 |
61 | /**
62 | * 模块保存权限
63 | */
64 | export function saveModulePermission(data) {
65 | return request({
66 | url: '/permission/save/module',
67 | method: 'post',
68 | data
69 | })
70 | }
71 |
72 | /**
73 | * 删除权限
74 | */
75 | export function deletePermission(id) {
76 | return request({
77 | url: '/permission/del/' + id,
78 | method: 'delete'
79 | })
80 | }
81 |
--------------------------------------------------------------------------------
/wfd-vue/src/assets/flow/message-start.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
25 |
--------------------------------------------------------------------------------
/wfd-vue/src/components/DetailPanel/SignalEventDetail.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{i18n['signalEvent']}}
4 |
5 |
6 |
7 |
{{i18n['signalEvent.signal']}}:
8 |
{ onChange('signal', e) }">
13 |
14 |
15 |
16 |
17 |
18 |
19 |
46 |
--------------------------------------------------------------------------------
/wfd-vue/src/components/DetailPanel/MessageEventDetail.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{i18n['messageEvent']}}
4 |
5 |
6 |
7 |
{{i18n['messageEvent.message']}}:
8 |
{ onChange('message', e) }">
13 |
14 |
15 |
16 |
17 |
18 |
19 |
46 |
--------------------------------------------------------------------------------
/src/router/modules/systemTool.js:
--------------------------------------------------------------------------------
1 | import Layout from '@/layout'
2 |
3 | const systemToolRouter = {
4 | path: '/system/tool',
5 | component: Layout,
6 | redirect: '/system/tool/file-store',
7 | name: 'SystemTool',
8 | meta: {
9 | title: '系统工具',
10 | icon: 'systemTool',
11 | permission: ['systemTool']
12 | },
13 | children: [
14 | {
15 | path: 'file-store',
16 | component: () => import('@/views/system/tool/fileStore/index'),
17 | name: 'FileStore',
18 | meta: { title: '存储管理', icon: 'fileStore', permission: ['fileStore'] }
19 | },
20 | {
21 | path: 'quartz-job',
22 | component: () => import('@/views/system/tool/quartzJob/index'),
23 | name: 'quartzJob',
24 | meta: { title: '定时任务', icon: 'schedule', permission: ['quartzJob'] }
25 | },
26 | {
27 | path: 'monitor-sql',
28 | component: () => import('@/views/system/tool/monitorSql/index'),
29 | name: 'monitorSql',
30 | meta: { title: 'SQL监控', icon: 'monitorSql', permission: ['fileStore'] }
31 | },
32 | // {
33 | // path: 'redis',
34 | // component: () => import('@/views/system/tool/redis/index'),
35 | // name: 'redis',
36 | // meta: { title: 'redis', icon: 'redis', permission: ['fileStore'] }
37 | // },
38 | {
39 | path: 'location',
40 | component: () => import('@/views/system/tool/location/index'),
41 | name: 'location',
42 | meta: { title: '省市区', icon: 'location', permission: ['location'] }
43 | }
44 | ]
45 | }
46 | export default systemToolRouter
47 |
--------------------------------------------------------------------------------
/wfd-vue/src/assets/flow/java-task.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
22 |
--------------------------------------------------------------------------------
/src/api/user.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request'
2 |
3 | /**
4 | * 分页获取
5 | */
6 | export function getUserPage(params, pageNum, pageSize) {
7 | return request({
8 | url: '/user/list/page',
9 | method: 'get',
10 | params: {
11 | ...params,
12 | pageNum,
13 | pageSize
14 | }
15 | })
16 | }
17 |
18 | /**
19 | * 不分页获取
20 | */
21 | export function getUserList(params) {
22 | return request({
23 | url: '/user/list/all',
24 | method: 'get',
25 | params
26 | })
27 | }
28 |
29 | /**
30 | * 获取详情
31 | */
32 | export function getUserDetail(id) {
33 | return request({
34 | url: '/user/detail/' + id,
35 | method: 'get'
36 | })
37 | }
38 |
39 | /**
40 | * 保存
41 | */
42 | export function saveUser(data) {
43 | return request({
44 | url: '/user/save',
45 | method: 'post',
46 | data
47 | })
48 | }
49 |
50 | /**
51 | * 绑定角色
52 | */
53 | export function bindRole(data) {
54 | return request({
55 | url: '/user/bind-role',
56 | method: 'post',
57 | data
58 | })
59 | }
60 |
61 | /**
62 | * 删除
63 | */
64 | export function deleteUser(id) {
65 | return request({
66 | url: '/user/del/' + id,
67 | method: 'delete'
68 | })
69 | }
70 |
71 | /**
72 | * 修改密码
73 | */
74 | export function changePass(data) {
75 | return request({
76 | url: '/user/changePass',
77 | method: 'post',
78 | data
79 | })
80 | }
81 |
82 | /**
83 | * 重置密码
84 | */
85 | export function resetPass(id) {
86 | return request({
87 | url: '/user/resetPass',
88 | method: 'post',
89 | data: { id }
90 | })
91 | }
92 |
--------------------------------------------------------------------------------
/src/components/SvgIcon/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
47 |
48 |
63 |
--------------------------------------------------------------------------------
/wfd-vue/src/components/DetailPanel/ReceiveTaskDetail.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{i18n['receiveTask']}}
4 |
5 |
6 |
7 |
{{i18n['receiveTask.waitState']}}:
8 |
{onChange('waitState', value)}" />
12 |
13 |
14 |
{{i18n['receiveTask.stateValue']}}:
15 |
{onChange('stateValue', value)}" />
19 |
20 |
21 |
22 |
23 |
46 |
--------------------------------------------------------------------------------
/src/api/actProcess.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request'
2 |
3 | /**
4 | * 分页获取
5 | */
6 | export function getActProcessPage(params, pageNum, pageSize) {
7 | return request({
8 | url: '/workflow/process/list/page',
9 | method: 'get',
10 | params: {
11 | ...params,
12 | pageNum,
13 | pageSize
14 | }
15 | })
16 | }
17 |
18 | /**
19 | * 不分页获取
20 | */
21 | export function getActProcessList(params) {
22 | return request({
23 | url: '/workflow/process/list/all',
24 | method: 'get',
25 | params
26 | })
27 | }
28 |
29 | /**
30 | * 获取详情
31 | */
32 | export function getActProcessDetail(id) {
33 | return request({
34 | url: '/workflow/process/detail/' + id,
35 | method: 'get'
36 | })
37 | }
38 |
39 | /**
40 | * 获取资源
41 | */
42 | export function getActProcessResource(id, name) {
43 | return request({
44 | url: '/workflow/process/resource/' + id,
45 | method: 'get',
46 | params: { name }
47 | })
48 | }
49 |
50 | /**
51 | * 保存
52 | */
53 | export function saveActProcess(data) {
54 | return request({
55 | url: '/workflow/process/save',
56 | method: 'post',
57 | data
58 | })
59 | }
60 |
61 | /**
62 | * 激活/挂起
63 | */
64 | export function changeProcessStatus({ id, suspensionState }) {
65 | return request({
66 | url: '/workflow/process/status/' + id,
67 | method: 'post',
68 | data: { suspensionState }
69 | })
70 | }
71 |
72 | /**
73 | * 删除
74 | */
75 | export function deleteActDeployment(id) {
76 | return request({
77 | url: '/workflow/process/del/' + id,
78 | method: 'delete'
79 | })
80 | }
81 |
--------------------------------------------------------------------------------
/wfd-vue/src/assets/icons/flow/icon_user.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/wfd-vue/src/assets/icons/flow/icon_java.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/api/role.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request'
2 |
3 | /**
4 | * 分页获取
5 | */
6 | export function getRolePage(params, pageNum, pageSize) {
7 | return request({
8 | url: '/role/list/page',
9 | method: 'get',
10 | params: {
11 | ...params,
12 | pageNum,
13 | pageSize
14 | }
15 | })
16 | }
17 |
18 | /**
19 | * 不分页获取
20 | */
21 | export function getRoleList(params) {
22 | return request({
23 | url: '/role/list/all',
24 | method: 'get',
25 | params
26 | })
27 | }
28 |
29 | /**
30 | * 获取详情
31 | */
32 | export function getRoleDetail(id) {
33 | return request({
34 | url: '/role/detail/' + id,
35 | method: 'get'
36 | })
37 | }
38 |
39 | /**
40 | * 保存
41 | */
42 | export function saveRole(data) {
43 | return request({
44 | url: '/role/save',
45 | method: 'post',
46 | data
47 | })
48 | }
49 |
50 | /**
51 | * 权限保存
52 | */
53 | export function saveRolePermission(roleId, permissionList) {
54 | return request({
55 | url: '/role/permission/save',
56 | method: 'post',
57 | data: {
58 | roleId,
59 | permissionList
60 | }
61 | })
62 | }
63 |
64 | /**
65 | * 批量权限保存
66 | */
67 | export function saveRolePermissionBatch(batchAuthType, roleIds, permissionList) {
68 | return request({
69 | url: '/role/permission/batch-save',
70 | method: 'post',
71 | data: {
72 | batchAuthType,
73 | roleIds,
74 | permissionList
75 | }
76 | })
77 | }
78 |
79 | /**
80 | * 删除
81 | */
82 | export function deleteRole(id) {
83 | return request({
84 | url: '/role/del/' + id,
85 | method: 'delete'
86 | })
87 | }
88 |
--------------------------------------------------------------------------------
/wfd-vue/src/plugins/addItemPanel.js:
--------------------------------------------------------------------------------
1 | const deepMix = require('@antv/util/lib/deep-mix');
2 | const each = require('@antv/util/lib/each');
3 | const createDOM = require('@antv/util/lib/dom/create-dom');
4 |
5 | class AddItemPanel {
6 |
7 | constructor(cfgs) {
8 | this._cfgs = deepMix(this.getDefaultCfg(), cfgs);
9 | }
10 | getDefaultCfg() {
11 | return { container: null };
12 | }
13 |
14 | get(key) {
15 | return this._cfgs[key];
16 | }
17 | set(key, val) {
18 | this._cfgs[key] = val;
19 | }
20 |
21 | initPlugin(graph) {
22 | const parentNode = this.get('container');
23 | const ghost = createDOM('
');
24 | const children = parentNode.querySelectorAll('div > .el-collapse-item > .el-collapse-item__wrap > .el-collapse-item__content > img[data-item]');
25 | each(children,(child,i)=>{
26 | const addModel = (new Function("return " + child.getAttribute('data-item')))();
27 | child.addEventListener('dragstart', e => {
28 | e.dataTransfer.setDragImage(ghost, 0, 0);
29 | graph.set('onDragAddNode',true);
30 | graph.set('addModel',addModel);
31 | });
32 | child.addEventListener('dragend', e => {
33 | graph.emit('canvas:mouseup',e);
34 | graph.set('onDragAddNode',false);
35 | graph.set('addModel',null);
36 | });
37 | })
38 | }
39 |
40 | destroy() {
41 | this.get('canvas').destroy();
42 | const container = this.get('container');
43 | container.parentNode.removeChild(container);
44 | }
45 | }
46 |
47 | export default AddItemPanel;
48 |
--------------------------------------------------------------------------------
/src/utils/rules.js:
--------------------------------------------------------------------------------
1 | // 输入框必填
2 | export const inputRequired = [
3 | { required: true, message: '请输入', trigger: ['blur', 'change'] }
4 | ]
5 |
6 | // 选择框必填
7 | export const selectRequired = [
8 | { required: true, message: '请选择', trigger: ['blur', 'change'] }
9 | ]
10 |
11 | // 邮箱校验
12 | export const email = [
13 | { type: 'email', message: '请输入正确的邮箱地址', trigger: ['blur', 'change'] }
14 | ]
15 |
16 | // 电话校验
17 | export const phone = [
18 | { required: true, pattern: /^1[3-9][0-9]{9}$/, message: '请输入正确的手机号', trigger: 'blur' }
19 | ]
20 |
21 | // 是否是英文逗号分隔
22 | export const segment = [
23 | { required: true, pattern: /^[\d,]+$/, message: '请用英文逗号分隔数字', trigger: 'blur' }
24 | ]
25 |
26 | // 是否是整数
27 | export const integer = [
28 | { pattern: /^\d+$/, message: '必须为整数值', trigger: 'blur' }
29 | ]
30 |
31 | // 是否是整数(大于0)
32 | export const integerGtZero = [
33 | { pattern: /^[1-9]\d*$/, message: '必须为大于 0 的整数', trigger: 'blur' }
34 | ]
35 |
36 | // 是否是整数(大于等于0)
37 | export const integerGtEqZero = [
38 | { pattern: /^\d+$/, message: '必须为大于等于 0 的整数', trigger: 'blur' }
39 | ]
40 |
41 | // 是否是小数(大于0)
42 | export const floatGtZero = [
43 | { pattern: /^(?!(0[0-9]{0,}$))[0-9]{1,}[.]{0,}[0-9]{0,}$/, message: '必须为大于 0 的数', trigger: 'blur' }
44 | ]
45 |
46 | // 是否是小数(大于等于0)
47 | export const floatGtEqZero = [
48 | { pattern: /^\d+(\.\d+)?$/, message: '必须为大于等于 0 的数', trigger: 'blur' }
49 | ]
50 |
51 | // 是否是数字,包含小数
52 | export const number = [
53 | { pattern: /^\d+(\.\d+)?$/, message: '必须为数字值', trigger: 'blur' }
54 | ]
55 |
56 | // 是否是 ip
57 | export const ip = [
58 | { pattern: /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/, message: '请输入正确的 IP', trigger: 'blur' }
59 | ]
60 |
--------------------------------------------------------------------------------
/templates/service.ejs:
--------------------------------------------------------------------------------
1 | package com.htnova.<%= module %>.service;
2 |
3 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
4 | import com.baomidou.mybatisplus.core.metadata.IPage;
5 | import com.htnova.<%= module %>.entity.<%= Entity %>;
6 | import com.htnova.<%= module %>.dto.<%= Entity %>Dto;
7 | import com.htnova.<%= module %>.mapper.<%= Entity %>Mapper;
8 | import org.springframework.stereotype.Service;
9 | import org.springframework.transaction.annotation.Transactional;
10 |
11 | import javax.annotation.Resource;
12 | import java.util.List;
13 |
14 | @Service
15 | public class <%= Entity %>Service extends ServiceImpl<<%= Entity %>Mapper, <%= Entity %>> {
16 |
17 | @Resource
18 | private <%= Entity %>Mapper <%= entity %>Mapper;
19 |
20 | @Transactional(readOnly = true)
21 | public IPage<<%= Entity %>> find<%= Entity %>List(<%= Entity %>Dto <%= entity %>Dto, IPage xPage) {
22 | return <%= entity %>Mapper.findPage(xPage, <%= entity %>Dto);
23 | }
24 |
25 | @Transactional(readOnly = true)
26 | public List<<%= Entity %>> find<%= Entity %>List(<%= Entity %>Dto <%= entity %>Dto) {
27 | return <%= entity %>Mapper.findList(<%= entity %>Dto);
28 | }
29 |
30 | @Transactional
31 | public void save<%= Entity %>(<%= Entity %> <%= entity %>) {
32 | super.saveOrUpdate(<%= entity %>);
33 | }
34 |
35 | @Transactional(readOnly = true)
36 | public <%= Entity %> get<%= Entity %>ById(long id) {
37 | return <%= entity %>Mapper.selectById(id);
38 | }
39 |
40 | @Transactional
41 | public void delete<%= Entity %>(Long id) {
42 | super.removeById(id);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/wfd-vue/src/assets/icons/flow/icon_message.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/layout/components/Sidebar/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
58 |
--------------------------------------------------------------------------------
/src/store/modules/permission.js:
--------------------------------------------------------------------------------
1 | import { asyncRoutes, constantRoutes } from '@/router'
2 |
3 | /**
4 | * Use meta.menu to determine if the current user has permission
5 | * @param menus
6 | * @param route
7 | */
8 | function hasPermission(menus, route) {
9 | if (route.meta && route.meta.permission) {
10 | return menus.some(menu => route.meta.permission.includes(menu))
11 | } else {
12 | return true
13 | }
14 | }
15 |
16 | /**
17 | * Filter asynchronous routing tables by recursion
18 | * @param routes asyncRoutes
19 | * @param menus
20 | */
21 | export function filterAsyncRoutes(routes, menus) {
22 | // debugger
23 | const res = []
24 |
25 | routes.forEach(route => {
26 | const tmp = { ...route }
27 | if (hasPermission(menus, tmp)) {
28 | if (tmp.children) {
29 | tmp.children = filterAsyncRoutes(tmp.children, menus)
30 | }
31 | res.push(tmp)
32 | }
33 | })
34 |
35 | return res
36 | }
37 |
38 | const state = {
39 | routes: [],
40 | addRoutes: []
41 | }
42 |
43 | const mutations = {
44 | SET_ROUTES: (state, routes) => {
45 | state.addRoutes = routes
46 | state.routes = constantRoutes.concat(routes)
47 | }
48 | }
49 |
50 | const actions = {
51 | generateRoutes({ commit }, menus) {
52 | return new Promise(resolve => {
53 | let accessedRoutes
54 | if (menus.includes('admin')) {
55 | accessedRoutes = asyncRoutes || []
56 | } else {
57 | accessedRoutes = filterAsyncRoutes(asyncRoutes, menus)
58 | }
59 | commit('SET_ROUTES', accessedRoutes)
60 | resolve(accessedRoutes)
61 | })
62 | }
63 | }
64 |
65 | export default {
66 | namespaced: true,
67 | state,
68 | mutations,
69 | actions
70 | }
71 |
--------------------------------------------------------------------------------
/wfd-vue/src/components/DetailPanel/TimerEventDetail.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{i18n['timerEvent']}}
4 |
5 |
6 |
7 |
{{i18n['timerEvent.cycle']}}:
8 |
{onChange('cycle', value)}" />
14 |
15 |
16 |
{{i18n['timerEvent.duration']}}:
17 |
{onChange('duration', value)}" />
23 |
24 |
25 |
26 |
27 |
50 |
--------------------------------------------------------------------------------
/src/api/actTask.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request'
2 |
3 | /**
4 | * 获取待办
5 | */
6 | export function getTodoPage(data, pageNum, pageSize) {
7 | return request({
8 | url: '/workflow/task/todo/page',
9 | method: 'get',
10 | params: { ...data, pageNum, pageSize }
11 | })
12 | }
13 |
14 | /**
15 | * 获取已办任务
16 | */
17 | export function getDonePage(data, pageNum, pageSize) {
18 | return request({
19 | url: '/workflow/task/done/page',
20 | method: 'get',
21 | params: { ...data, pageNum, pageSize }
22 | })
23 | }
24 |
25 | /**
26 | * 获取我的申请
27 | */
28 | export function getApplyPage(data, pageNum, pageSize) {
29 | return request({
30 | url: '/workflow/task/apply/page',
31 | method: 'get',
32 | params: { ...data, pageNum, pageSize }
33 | })
34 | }
35 |
36 | /**
37 | * 签收任务
38 | */
39 | export function claimTask(taskId) {
40 | return request({
41 | url: '/workflow/task/claim/' + taskId,
42 | method: 'post'
43 | })
44 | }
45 |
46 | /**
47 | * 委托任务
48 | */
49 | export function delegateTask(taskId, assigneeId) {
50 | return request({
51 | url: '/workflow/task/delegate/' + taskId,
52 | method: 'post',
53 | data: { assigneeId }
54 | })
55 | }
56 |
57 | /**
58 | * 撤销申请
59 | */
60 | export function deleteApply(processInstanceId, deleteReason) {
61 | return request({
62 | url: '/workflow/task/apply/delete',
63 | method: 'post',
64 | data: { processInstanceId, deleteReason }
65 | })
66 | }
67 |
68 | /**
69 | * 获取历史操作记录
70 | */
71 | export function getHistoryOperate(processInstanceId, taskDefinitionKey) {
72 | return request({
73 | url: '/workflow/task/history/operate',
74 | method: 'get',
75 | params: { processInstanceId, taskDefinitionKey }
76 | })
77 | }
78 |
--------------------------------------------------------------------------------
/src/icons/svg/tree.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/api/quartzJob.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request'
2 |
3 | /**
4 | * 分页获取
5 | */
6 | export function getQuartzJobPage(params, pageNum, pageSize) {
7 | return request({
8 | url: '/quartz-job/list/page',
9 | method: 'get',
10 | params: {
11 | ...params,
12 | pageNum,
13 | pageSize
14 | }
15 | })
16 | }
17 |
18 | /**
19 | * 不分页获取
20 | */
21 | export function getQuartzJobList(params) {
22 | return request({
23 | url: '/quartz-job/list/all',
24 | method: 'get',
25 | params
26 | })
27 | }
28 |
29 | /**
30 | * 获取详情
31 | */
32 | export function getQuartzJobDetail(id) {
33 | return request({
34 | url: '/quartz-job/detail/' + id,
35 | method: 'get'
36 | })
37 | }
38 |
39 | /**
40 | * 保存
41 | */
42 | export function saveQuartzJob(data) {
43 | return request({
44 | url: '/quartz-job/save',
45 | method: 'post',
46 | data
47 | })
48 | }
49 |
50 | /**
51 | * 删除
52 | */
53 | export function deleteQuartzJob(id) {
54 | return request({
55 | url: '/quartz-job/del/' + id,
56 | method: 'delete'
57 | })
58 | }
59 |
60 | /**
61 | * 执行一次
62 | */
63 | export function runQuartzJob(id) {
64 | return request({
65 | url: '/quartz-job/run',
66 | method: 'post',
67 | data: { id }
68 | })
69 | }
70 |
71 | /**
72 | * 停用
73 | */
74 | export function changeQuartzJobStatus(id, status) {
75 | return request({
76 | url: '/quartz-job/status',
77 | method: 'post',
78 | data: { id, status }
79 | })
80 | }
81 |
82 | /**
83 | * 查询日志
84 | */
85 | export function findLogByPage(params, pageNum, pageSize) {
86 | return request({
87 | url: '/quartz-job/log/page',
88 | method: 'get',
89 | params: {
90 | ...params,
91 | pageNum,
92 | pageSize
93 | }
94 | })
95 | }
96 |
--------------------------------------------------------------------------------
/src/router/modules/systemWorkflow.js:
--------------------------------------------------------------------------------
1 | import Layout from '@/layout'
2 |
3 | const systemWorkflowRouter = {
4 | path: '/workflow',
5 | component: Layout,
6 | redirect: '/workflow/model',
7 | name: 'Workflow',
8 | meta: {
9 | title: '工作流程',
10 | icon: 'workflow',
11 | permission: ['workflow']
12 | },
13 | children: [
14 | {
15 | path: 'model',
16 | component: () => import('@/views/system/workflow/model/index'),
17 | name: 'WorkflowModel',
18 | meta: { title: '模型管理', icon: 'workflowModel', permission: ['workflowModel'] }
19 | },
20 | {
21 | path: 'process',
22 | component: () => import('@/views/system/workflow/process/index'),
23 | name: 'WorkflowProcess',
24 | meta: { title: '流程管理', icon: 'workflowProcess', permission: ['workflowProcess'] }
25 | },
26 | {
27 | path: 'launch',
28 | component: () => import('@/views/system/workflow/launch/index'),
29 | name: 'WorkflowLaunch',
30 | meta: { title: '发起申请', icon: 'workflowLaunch', permission: ['workflowLaunch'] }
31 | },
32 | {
33 | path: 'apply',
34 | component: () => import('@/views/system/workflow/apply/index'),
35 | name: 'WorkflowApply',
36 | meta: { title: '我的申请', icon: 'workflowApply', permission: ['workflowApply'] }
37 | },
38 | {
39 | path: 'todo',
40 | component: () => import('@/views/system/workflow/todo/index'),
41 | name: 'WorkflowTodo',
42 | meta: { title: '我的待办', icon: 'workflowTodo', permission: ['workflowTodo'] }
43 | },
44 | {
45 | path: 'done',
46 | component: () => import('@/views/system/workflow/done/index'),
47 | name: 'WorkflowDone',
48 | meta: { title: '我的已办', icon: 'workflowDone', permission: ['workflowDone'] }
49 | }
50 | ]
51 | }
52 | export default systemWorkflowRouter
53 |
--------------------------------------------------------------------------------
/mock/user.js:
--------------------------------------------------------------------------------
1 |
2 | const tokens = {
3 | admin: {
4 | token: 'admin-token'
5 | },
6 | editor: {
7 | token: 'editor-token'
8 | }
9 | }
10 |
11 | const users = {
12 | 'admin-token': {
13 | roles: ['admin'],
14 | introduction: 'I am a super administrator',
15 | avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
16 | name: 'Super Admin'
17 | },
18 | 'editor-token': {
19 | roles: ['editor'],
20 | introduction: 'I am an editor',
21 | avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
22 | name: 'Normal Editor'
23 | }
24 | }
25 |
26 | export default [
27 | // user login
28 | {
29 | url: '/user/login',
30 | type: 'post',
31 | response: config => {
32 | const { username } = config.body
33 | const token = tokens[username]
34 |
35 | // mock error
36 | if (!token) {
37 | return {
38 | code: 60204,
39 | message: 'Account and password are incorrect.'
40 | }
41 | }
42 |
43 | return {
44 | code: 20000,
45 | data: token
46 | }
47 | }
48 | },
49 |
50 | // get user info
51 | {
52 | url: '/user/info\.*',
53 | type: 'get',
54 | response: config => {
55 | const { token } = config.query
56 | const info = users[token]
57 |
58 | // mock error
59 | if (!info) {
60 | return {
61 | code: 50008,
62 | message: 'Login failed, unable to get user details.'
63 | }
64 | }
65 |
66 | return {
67 | code: 20000,
68 | data: info
69 | }
70 | }
71 | },
72 |
73 | // user logout
74 | {
75 | url: '/user/logout',
76 | type: 'post',
77 | response: _ => {
78 | return {
79 | code: 20000,
80 | data: 'success'
81 | }
82 | }
83 | }
84 | ]
85 |
--------------------------------------------------------------------------------
/src/views/system/workflow/launch/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 | {{ launch.name }}
11 |
12 |
13 |
20 |
21 |
22 |
23 |
65 |
66 |
74 |
--------------------------------------------------------------------------------
/wfd-vue/src/assets/icons/flow/icon_receive.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/api/fileStore.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request'
2 | import store from '@/store'
3 |
4 | /**
5 | * 分页获取
6 | */
7 | export function getFileStorePage(params, pageNum, pageSize) {
8 | return request({
9 | url: '/file/list/page',
10 | method: 'get',
11 | params: {
12 | ...params,
13 | pageNum,
14 | pageSize
15 | }
16 | })
17 | }
18 |
19 | /**
20 | * 不分页获取
21 | */
22 | export function getFileStoreList(params) {
23 | return request({
24 | url: '/file/list/all',
25 | method: 'get',
26 | params
27 | })
28 | }
29 |
30 | /**
31 | * 获取详情
32 | */
33 | export function getFileStoreDetail(id) {
34 | return request({
35 | url: '/file/detail/' + id,
36 | method: 'get'
37 | })
38 | }
39 |
40 | /**
41 | * 获取详情
42 | */
43 | export function findListByIds(ids) {
44 | return request({
45 | url: '/file/list/ids',
46 | method: 'get',
47 | params: { ids }
48 | })
49 | }
50 |
51 | /**
52 | * 保存
53 | */
54 | export function saveFileStore(data) {
55 | return request({
56 | url: '/file/save',
57 | method: 'post',
58 | data
59 | })
60 | }
61 |
62 | /**
63 | * 删除
64 | */
65 | export function deleteFileStore(id) {
66 | return request({
67 | url: '/file/del/' + id,
68 | method: 'delete'
69 | })
70 | }
71 |
72 | /**
73 | * 文件上传
74 | */
75 | export function uploadFileStore(data) {
76 | return request({
77 | url: '/file/upload',
78 | method: 'post',
79 | headers: {
80 | 'Content-Type': 'multipart/form-data;charset=UTF-8'
81 | },
82 | data
83 | })
84 | }
85 |
86 | /**
87 | * 获取文件的二进制数据
88 | */
89 | export function getFileStoreBinary(url, responseType = 'blob') {
90 | if (url.indexOf(store.getters.api.baseUrl) === 0) {
91 | url = url.substring(store.getters.api.baseUrl.length)
92 | }
93 | return request({
94 | url: url,
95 | method: 'get',
96 | responseType: responseType // arraybuffer, blob
97 | })
98 | }
99 |
--------------------------------------------------------------------------------
/mock/index.js:
--------------------------------------------------------------------------------
1 | import Mock from 'mockjs'
2 | import { param2Obj } from '../src/utils'
3 |
4 | import user from './user'
5 | import table from './table'
6 |
7 | const mocks = [
8 | ...user,
9 | ...table
10 | ]
11 |
12 | // for front mock
13 | // please use it cautiously, it will redefine XMLHttpRequest,
14 | // which will cause many of your third-party libraries to be invalidated(like progress event).
15 | export function mockXHR() {
16 | // mock patch
17 | // https://github.com/nuysoft/Mock/issues/300
18 | Mock.XHR.prototype.proxy_send = Mock.XHR.prototype.send
19 | Mock.XHR.prototype.send = function() {
20 | if (this.custom.xhr) {
21 | this.custom.xhr.withCredentials = this.withCredentials || false
22 |
23 | if (this.responseType) {
24 | this.custom.xhr.responseType = this.responseType
25 | }
26 | }
27 | this.proxy_send(...arguments)
28 | }
29 |
30 | function XHR2ExpressReqWrap(respond) {
31 | return function(options) {
32 | let result = null
33 | if (respond instanceof Function) {
34 | const { body, type, url } = options
35 | // https://expressjs.com/en/4x/api.html#req
36 | result = respond({
37 | method: type,
38 | body: JSON.parse(body),
39 | query: param2Obj(url)
40 | })
41 | } else {
42 | result = respond
43 | }
44 | return Mock.mock(result)
45 | }
46 | }
47 |
48 | for (const i of mocks) {
49 | Mock.mock(new RegExp(i.url), i.type || 'get', XHR2ExpressReqWrap(i.response))
50 | }
51 | }
52 |
53 | // for mock server
54 | const responseFake = (url, type, respond) => {
55 | return {
56 | url: new RegExp(`/mock${url}`),
57 | type: type || 'get',
58 | response(req, res) {
59 | res.json(Mock.mock(respond instanceof Function ? respond(req, res) : respond))
60 | }
61 | }
62 | }
63 |
64 | export default mocks.map(route => {
65 | return responseFake(route.url, route.type, route.response)
66 | })
67 |
--------------------------------------------------------------------------------
/wfd-vue/src/components/DetailPanel/FlowDetail.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{i18n['sequenceFlow']}}
4 |
5 |
6 |
7 |
{{i18n['sequenceFlow.expression']}}:
8 |
{onChange('conditionExpression', value)}" />
14 |
15 |
16 |
{{i18n['sequenceFlow.seq']}}:
17 |
{onChange('seq', value)}" />
21 |
22 |
23 | onChange('reverse', value)"
24 | :disabled="readOnly"
25 | :value="!!model.reverse">{{i18n['sequenceFlow.reverse']}}
26 |
27 |
28 |
29 |
30 |
53 |
--------------------------------------------------------------------------------
/wfd-vue/src/components/DetailPanel/MailTaskDetail.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{i18n['mailTask']}}
4 |
5 |
6 |
7 |
{{i18n['mailTask.to']}}:
8 |
{onChange('to', value)}" />
12 |
13 |
14 |
{{i18n['mailTask.subject']}}:
15 |
{onChange('subject', value)}" />
19 |
20 |
21 |
{{i18n['mailTask.content']}}:
22 |
{onChange('content', value)}" />
28 |
29 |
30 |
31 |
32 |
55 |
--------------------------------------------------------------------------------
/src/icons/svg/fileStore.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test.js:
--------------------------------------------------------------------------------
1 | const xml = `↵↵ ↵ 描述↵ ↵ Flow_0n1hrs5↵ ↵ ↵ Flow_0n1hrs5↵ ↵ ↵ ↵ ↵ ↵ ↵ ↵ ↵ ↵ ↵ ↵ ↵ ↵ ↵ ↵ ↵ ↵ ↵ ↵ ↵↵`
2 | const nodeTag = 'bpmn2:process'
3 | const attr = 'name'
4 | const start = xml.indexOf(nodeTag)
5 | let attrValue = xml.substr(start, xml.indexOf('>', start))
6 | attrValue = attrValue.substr(attrValue.indexOf(attr) + attr.length + 2)
7 | attrValue = attrValue.substr(0, attrValue.indexOf('"'))
8 | console.log(attrValue)
9 | console.log(xml.indexOf('>'))
10 |
--------------------------------------------------------------------------------
/src/views/system/workflow/apply/reason.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
73 |
74 |
77 |
--------------------------------------------------------------------------------
/src/layout/components/Sidebar/Logo.vue:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
16 |
34 |
35 |
84 |
--------------------------------------------------------------------------------
/wfd-vue/src/behavior/clickSelected.js:
--------------------------------------------------------------------------------
1 | export default function(G6){
2 | G6.registerBehavior('clickSelected', {
3 | getDefaultCfg() {
4 | return {
5 | multiple: false,
6 | }
7 | },
8 | getEvents() {
9 | return {
10 | 'node:click': 'onClick',
11 | 'edge:click': 'onClick',
12 | 'edge:mouseover': 'onEdgeMouseOver',
13 | 'edge:mouseleave': 'onEdgeMouseLeave',
14 | 'canvas:click': 'onCanvasClick',
15 | 'node:mouseover': 'onNodeMouseOver',
16 | }
17 | },
18 | onClick(e) {
19 | this._clearSelected();
20 | this.graph.setItemState(e.item, 'selected', true);
21 | let selectedItems = this.graph.get('selectedItems');
22 | if(!selectedItems)
23 | selectedItems = [];
24 | selectedItems = [e.item.get('id')];
25 | this.graph.set('selectedItems',selectedItems);
26 | this.graph.emit('afteritemselected',selectedItems);
27 | },
28 | onNodeMouseOver(e){
29 | if(this.graph.getCurrentMode() === 'edit')
30 | this.graph.setItemState(e.item, 'hover', true);
31 | else
32 | this.graph.setItemState(e.item, 'hover', false);
33 | },
34 | onEdgeMouseOver(e){
35 | if(this.graph.getCurrentMode() === 'edit' && !e.item.hasState('selected'))
36 | this.graph.setItemState(e.item, 'hover', true);
37 | },
38 | onEdgeMouseLeave(e){
39 | if(this.graph.getCurrentMode() === 'edit' && !e.item.hasState('selected'))
40 | this.graph.setItemState(e.item, 'hover', false);
41 | },
42 | onCanvasClick(){
43 | this._clearSelected();
44 | },
45 | _clearSelected(){
46 | let selected = this.graph.findAllByState('node', 'selected');
47 | selected.forEach(node => {
48 | this.graph.setItemState(node, 'selected', false);
49 | });
50 | selected = this.graph.findAllByState('edge', 'selected');
51 | selected.forEach(edge => {
52 | this.graph.setItemState(edge, 'selected', false);
53 | });
54 | this.graph.set('selectedItems',[]);
55 | this.graph.emit('afteritemselected',[]);
56 | }
57 | });
58 | }
--------------------------------------------------------------------------------
/wfd-vue/src/plugins/detailPanel.js:
--------------------------------------------------------------------------------
1 | const deepMix = require('@antv/util/lib/deep-mix');
2 | const each = require('@antv/util/lib/each');
3 | const wrapBehavior = require('@antv/util/lib/event/wrap-behavior');
4 | const modifyCSS = require('@antv/util/lib/dom/modify-css');
5 |
6 | class DetailPanel {
7 |
8 | constructor(cfgs) {
9 | this._cfgs = deepMix(this.getDefaultCfg(), cfgs);
10 | }
11 | getDefaultCfg() {
12 | return { container: null };
13 | }
14 |
15 | get(key) {
16 | return this._cfgs[key];
17 | }
18 | set(key, val) {
19 | this._cfgs[key] = val;
20 | }
21 |
22 | initPlugin(graph) {
23 | const self = this;
24 | this.set('graph', graph);
25 | const events = self.getEvents();
26 | const bindEvents = {};
27 | each(events, (v, k) => {
28 | const event = wrapBehavior(self, v);
29 | bindEvents[k] = event;
30 | graph.on(k, event);
31 | });
32 | this._events = bindEvents;
33 | this.updatePanel();
34 | }
35 |
36 | updatePanel(){
37 | const graph = this.get('graph');
38 | const parentNode = this.get('container');
39 | const selectedItems = graph.get('selectedItems');
40 | let selectedItem = null;
41 | let clazz = null;
42 | if(selectedItems && selectedItems.length > 0){
43 | selectedItem = graph.findById(selectedItems[0]);
44 | clazz = selectedItem.getModel().clazz;
45 | }
46 | each(parentNode.children,(child,i)=>{
47 | if(child.hasAttribute('data-clazz')){
48 | const clazzName = child.getAttribute('data-clazz');
49 | if(clazz && clazz === clazzName){
50 | modifyCSS(child,{
51 | display: 'inline'
52 | });
53 | }else{
54 | modifyCSS(child,{
55 | display: 'none'
56 | });
57 | }
58 | }
59 | })
60 | }
61 |
62 | getEvents() {
63 | return { afteritemselected: 'updatePanel' };
64 | }
65 |
66 | destroy() {
67 | this.get('canvas').destroy();
68 | const container = this.get('container');
69 | container.parentNode.removeChild(container);
70 | }
71 | }
72 |
73 | export default DetailPanel;
74 |
--------------------------------------------------------------------------------
/mock/mock-server.js:
--------------------------------------------------------------------------------
1 | const chokidar = require('chokidar')
2 | const bodyParser = require('body-parser')
3 | const chalk = require('chalk')
4 | const path = require('path')
5 |
6 | const mockDir = path.join(process.cwd(), 'mock')
7 |
8 | function registerRoutes(app) {
9 | let mockLastIndex
10 | const { default: mocks } = require('./index.js')
11 | for (const mock of mocks) {
12 | app[mock.type](mock.url, mock.response)
13 | mockLastIndex = app._router.stack.length
14 | }
15 | const mockRoutesLength = Object.keys(mocks).length
16 | return {
17 | mockRoutesLength: mockRoutesLength,
18 | mockStartIndex: mockLastIndex - mockRoutesLength
19 | }
20 | }
21 |
22 | function unregisterRoutes() {
23 | Object.keys(require.cache).forEach(i => {
24 | if (i.includes(mockDir)) {
25 | delete require.cache[require.resolve(i)]
26 | }
27 | })
28 | }
29 |
30 | module.exports = app => {
31 | // es6 polyfill
32 | require('@babel/register')
33 |
34 | // parse app.body
35 | // https://expressjs.com/en/4x/api.html#req.body
36 | app.use(bodyParser.json())
37 | app.use(bodyParser.urlencoded({
38 | extended: true
39 | }))
40 |
41 | const mockRoutes = registerRoutes(app)
42 | var mockRoutesLength = mockRoutes.mockRoutesLength
43 | var mockStartIndex = mockRoutes.mockStartIndex
44 |
45 | // watch files, hot reload mock server
46 | chokidar.watch(mockDir, {
47 | ignored: /mock-server/,
48 | ignoreInitial: true
49 | }).on('all', (event, path) => {
50 | if (event === 'change' || event === 'add') {
51 | try {
52 | // remove mock routes stack
53 | app._router.stack.splice(mockStartIndex, mockRoutesLength)
54 |
55 | // clear routes cache
56 | unregisterRoutes()
57 |
58 | const mockRoutes = registerRoutes(app)
59 | mockRoutesLength = mockRoutes.mockRoutesLength
60 | mockStartIndex = mockRoutes.mockStartIndex
61 |
62 | console.log(chalk.magentaBright(`\n > Mock Server hot reload success! changed ${path}`))
63 | } catch (error) {
64 | console.log(chalk.redBright(error))
65 | }
66 | }
67 | })
68 | }
69 |
--------------------------------------------------------------------------------
/src/utils/dic.js:
--------------------------------------------------------------------------------
1 |
2 | // 全部
3 | export const all = [
4 | { label: '全部', value: '' }
5 | ]
6 |
7 | // 无
8 | export const none = [
9 | { label: '无', value: '' }
10 | ]
11 |
12 | // 性别
13 | export const sex = [
14 | { label: '男', value: 'male' },
15 | { label: '女', value: 'female' }
16 | ]
17 |
18 | // 权限新增方式
19 | export const permissionAddType = [
20 | { label: '单个', value: false },
21 | { label: '模块', value: true }
22 | ]
23 |
24 | // 权限类型
25 | export const permissionType = [
26 | { label: '菜单', value: 'menu' },
27 | { label: '按钮', value: 'button' }
28 | ]
29 |
30 | // 部门状态
31 | export const deptStatus = [
32 | { label: '正常', value: 'enable' },
33 | { label: '停用', value: 'disable' }
34 | ]
35 |
36 | // 用户状态
37 | export const userStatus = [
38 | { label: '激活', value: 'enable' },
39 | { label: '锁定', value: 'disable' }
40 | ]
41 |
42 | // 证件类型
43 | export const credentialType = [
44 | { label: '身份证', value: 'idCard' },
45 | { label: '护照', value: 'passport' },
46 | { label: '港澳台通行证', value: 'HMTpasses' },
47 | { label: '其他', value: 'other' }
48 | ]
49 |
50 | // 机构管理员是否可见
51 | export const displayType = [
52 | { label: '可见', value: 'visible' },
53 | { label: '隐藏', value: 'hidden' }
54 | ]
55 |
56 | // 文件存储方式
57 | export const fileStoreType = [
58 | { label: '本地', value: 'local' },
59 | { label: 'OSS', value: 'OSS' }
60 | ]
61 |
62 | // 定时任务状态
63 | export const QuartzJobStatusType = [
64 | { label: '启用', value: 'enable' },
65 | { label: '停用', value: 'disable' }
66 | ]
67 |
68 | // 定时任务状态
69 | export const QuartzLogStatusType = [
70 | { label: '成功', value: 'success' },
71 | { label: '失败', value: 'fail' }
72 | ]
73 |
74 | // 流程状态
75 | export const ProcessSuspensionState = [
76 | { label: '激活', value: 'active' },
77 | { label: '挂起', value: 'suspended' }
78 | ]
79 |
80 | // 我的申请状态
81 | export const ApplyStatus = [
82 | { label: '进行中', value: 'unfinish' },
83 | { label: '已完成', value: 'finish' },
84 | { label: '已撤销', value: 'delete' }
85 | ]
86 |
87 | // 任务的状态
88 | export const TaskApplyStatus = [
89 | { label: '通过', value: 'approve' },
90 | { label: '驳回', value: 'reject' }
91 | ]
92 |
93 |
--------------------------------------------------------------------------------
/src/icons/svg/redis.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/icons/svg/dashboard.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/layout/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
14 |
52 |
53 |
94 |
--------------------------------------------------------------------------------
/src/components/Breadcrumb/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {{ item.meta.title }}
6 | {{ item.meta.title }}
7 |
8 |
9 |
10 |
11 |
12 |
65 |
66 |
79 |
--------------------------------------------------------------------------------
/src/icons/svg/form.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/role.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue-admin-template",
3 | "version": "4.2.1",
4 | "description": "A vue admin template with Element UI & axios & iconfont & permission control & lint",
5 | "author": "Pan ",
6 | "license": "MIT",
7 | "scripts": {
8 | "dev": "vue-cli-service serve",
9 | "build:prod": "vue-cli-service build",
10 | "build:stage": "vue-cli-service build --mode staging",
11 | "preview": "node build/index.js --preview",
12 | "lint": "eslint --ext .js,.vue src",
13 | "test:unit": "jest --clearCache && vue-cli-service test:unit",
14 | "test:ci": "npm run lint && npm run test:unit",
15 | "svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml"
16 | },
17 | "gitHooks": {
18 | "pre-commit": "lint-staged"
19 | },
20 | "lint-staged": {
21 | "src/**/*.{js,vue}": [
22 | "eslint --fix",
23 | "git add"
24 | ]
25 | },
26 | "dependencies": {
27 | "@antv/g6": "~3.1.3",
28 | "@antv/util": "~1.3.1",
29 | "axios": "0.19.1",
30 | "compressorjs": "^1.0.6",
31 | "element-ui": "2.13.2",
32 | "file-saver": "^2.0.2",
33 | "html2canvas": "^1.0.0-rc.5",
34 | "js-cookie": "2.2.1",
35 | "normalize.css": "8.0.1",
36 | "nprogress": "0.2.0",
37 | "numericjs": "^1.2.6",
38 | "path-to-regexp": "6.1.0",
39 | "qs": "^6.8.0",
40 | "sprintf-js": "^1.1.2",
41 | "vue": "2.6.11",
42 | "vue-router": "3.1.3",
43 | "vue-socket.io": "^3.0.10",
44 | "vuex": "3.1.2",
45 | "xcrud": "0.3.15"
46 | },
47 | "devDependencies": {
48 | "@vue/cli-plugin-babel": "^4.1.0",
49 | "@vue/cli-plugin-eslint": "^4.1.0",
50 | "@vue/cli-plugin-unit-jest": "^4.1.2",
51 | "@vue/cli-service": "^4.1.0",
52 | "@vue/test-utils": "^1.0.3",
53 | "autoprefixer": "^9.5.1",
54 | "babel-eslint": "^10.0.3",
55 | "babel-jest": "23.6.0",
56 | "chalk": "2.4.2",
57 | "connect": "3.7.0",
58 | "eslint": "^6.8.0",
59 | "eslint-plugin-vue": "^6.1.2",
60 | "html-webpack-plugin": "3.2.0",
61 | "lint-staged": "^9.4.2",
62 | "mockjs": "1.1.0",
63 | "runjs": "^4.3.2",
64 | "sass": "^1.26.8",
65 | "sass-loader": "^8.0.0",
66 | "script-ext-html-webpack-plugin": "2.1.4",
67 | "serve-static": "^1.13.2",
68 | "svg-sprite-loader": "4.1.6",
69 | "svgo": "1.2.2",
70 | "vue-template-compiler": "2.6.11"
71 | },
72 | "engines": {
73 | "node": ">=8.9",
74 | "npm": ">= 3.0.0"
75 | },
76 | "browserslist": [
77 | "> 1%",
78 | "last 2 versions"
79 | ]
80 | }
81 |
--------------------------------------------------------------------------------
/wfd-vue/src/locales/zh-CN.js:
--------------------------------------------------------------------------------
1 | export default {
2 | 'label': '标题',
3 | 'hideIcon': '隐藏图标',
4 | 'userTask': '审批节点',
5 | 'userTask.assignType': '指派类型',
6 | 'userTask.assignType.placeholder': '选择一个类型',
7 | 'userTask.assignType.assignee': '受理人',
8 | 'userTask.assignType.assignee.title': '受理人',
9 | 'userTask.assignType.assignee.placeholder': '选择受理人',
10 | 'userTask.assignType.person': '候选人',
11 | 'userTask.assignType.person.title': '候选人',
12 | 'userTask.assignType.person.placeholder': '选择候选人',
13 | 'userTask.assignType.persongroup': '候选组',
14 | 'userTask.assignType.persongroup.title': '候选组',
15 | 'userTask.assignType.persongroup.placeholder': '选择候选组',
16 | 'userTask.dueDate': '到期时间',
17 | 'userTask.dueDate.placeholder': '请选择日期',
18 | 'userTask.counterSign': '会签',
19 | 'scriptTask': '脚本节点',
20 | 'scriptTask.script': '脚本',
21 | 'javaTask': '自定义类节点',
22 | 'javaTask.javaClass': '类名',
23 | 'mailTask': '邮件节点',
24 | 'mailTask.to': '收件人',
25 | 'mailTask.subject': '标题',
26 | 'mailTask.content': '内容',
27 | 'receiveTask': '接收节点',
28 | 'receiveTask.waitState': '等待属性',
29 | 'receiveTask.stateValue': '等待值',
30 | 'timerEvent': '定时节点',
31 | 'timerEvent.cycle': '循环时间',
32 | 'timerEvent.cycle.placeholder': '请选择时间',
33 | 'timerEvent.duration': '持续时间',
34 | 'messageEvent': '消息节点',
35 | 'messageEvent.message': '消息名',
36 | 'signalEvent': '信号节点',
37 | 'signalEvent.signal': '信号名',
38 | 'sequenceFlow': '连接线',
39 | 'sequenceFlow.expression': '条件表达式',
40 | 'sequenceFlow.seq': '序号',
41 | 'sequenceFlow.reverse': '反向',
42 | 'startEvent': '开始节点',
43 | 'endEvent': '结束节点',
44 | 'start': '开始事件',
45 | 'end': '结束事件',
46 | 'gateway': '网关',
47 | 'exclusiveGateway': '排他网关',
48 | 'parallelGateway': '并行网关',
49 | 'inclusiveGateway': '包容网关',
50 | 'task': '活动',
51 | 'catch': '捕获事件',
52 | 'tooltip.undo': '撤销',
53 | 'tooltip.redo': '重复',
54 | 'tooltip.copy': '复制',
55 | 'tooltip.paste': '粘贴',
56 | 'tooltip.delete': '删除',
57 | 'tooltip.zoomIn': '放大',
58 | 'tooltip.zoomOut': '缩小',
59 | 'tooltip.zoomReset': '实际大小',
60 | 'tooltip.autoFit': '适应屏幕',
61 | 'tooltip.toFront': '移到上一层',
62 | 'tooltip.toBack': '移到下一层',
63 | 'tooltip.edit': '编辑',
64 | 'process': '流程',
65 | 'process.category': '分类',
66 | 'process.id': '流程标识',
67 | 'process.name': '流程名称',
68 | 'process.dataObjs': '数据对象',
69 | 'process.signalDefs': '信号定义',
70 | 'process.messageDefs': '消息定义',
71 | 'process.dataObjs.id': 'Id',
72 | 'process.dataObjs.name': '名称',
73 | 'process.dataObjs.type': '类型',
74 | 'process.dataObjs.defaultValue': '默认值',
75 | 'process.signalDef.scope': '作用域',
76 | };
77 |
--------------------------------------------------------------------------------