├── typings.d.ts
├── .fatherrc.ts
├── .prettierignore
├── src
├── Flow
│ ├── context
│ │ └── OperatorContext.js
│ ├── components
│ │ ├── End.js
│ │ ├── TitleElement.js
│ │ ├── Render.js
│ │ ├── Node.js
│ │ ├── Start.js
│ │ ├── MyDrawer.js
│ │ ├── Wrap.js
│ │ ├── Add.js
│ │ ├── Approver.js
│ │ ├── Notifier.js
│ │ ├── SetApprover.js
│ │ ├── ZoomLayout.js
│ │ ├── Constants.js
│ │ ├── AddOptionList.js
│ │ ├── SetCondition.js
│ │ └── Condition.js
│ ├── index.md
│ ├── init.json
│ ├── index.jsx
│ └── index.less
├── index.ts
├── UserList
│ ├── index.md
│ └── index.jsx
└── ConditionList
│ ├── index.md
│ ├── util.js
│ └── index.jsx
├── .prettierrc
├── .editorconfig
├── README.md
├── .gitignore
├── .umirc.ts
├── tsconfig.json
└── package.json
/typings.d.ts:
--------------------------------------------------------------------------------
1 | declare module '*.css';
2 | declare module '*.less';
3 |
--------------------------------------------------------------------------------
/.fatherrc.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | esm: 'rollup',
3 | cjs: 'rollup',
4 | };
5 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | **/*.svg
2 | **/*.ejs
3 | **/*.html
4 | package.json
5 | .umi
6 | .umi-production
7 | .umi-test
8 |
--------------------------------------------------------------------------------
/src/Flow/context/OperatorContext.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | const Context = React.createContext(null)
4 | export default Context;
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | export { default as Flow } from './Flow';
2 | export { default as UserList } from './UserList';
3 | export { default as ConditionList } from './ConditionList';
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "trailingComma": "all",
4 | "printWidth": 80,
5 | "overrides": [
6 | {
7 | "files": ".prettierrc",
8 | "options": { "parser": "json" }
9 | }
10 | ]
11 | }
12 |
--------------------------------------------------------------------------------
/src/UserList/index.md:
--------------------------------------------------------------------------------
1 | Demo:
2 |
3 | ```tsx
4 | import React from 'react';
5 | import { UserList } from 'raycloud-apaas-flow';
6 |
7 | export default () => ;
8 | ```
9 |
10 | More skills for writing demo: https://d.umijs.org/guide/basic#write-component-demo
11 |
--------------------------------------------------------------------------------
/src/Flow/components/End.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | function EndNode(){
4 | return (
)
8 | }
9 |
10 | export default EndNode
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # http://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | charset = utf-8
9 | trim_trailing_whitespace = true
10 | insert_final_newline = true
11 |
12 | [*.md]
13 | trim_trailing_whitespace = false
14 |
15 | [Makefile]
16 | indent_style = tab
17 |
--------------------------------------------------------------------------------
/src/UserList/index.jsx:
--------------------------------------------------------------------------------
1 | import React, { forwardRef, useImperativeHandle, useState } from 'react';
2 |
3 | const UserList = forwardRef((props, ref) => {
4 | useImperativeHandle(ref, () => ({
5 |
6 | }));
7 | return (
8 |
11 | )
12 | })
13 |
14 | export default UserList
--------------------------------------------------------------------------------
/src/Flow/components/TitleElement.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { CloseCircleOutlined } from '@ant-design/icons';
3 | function TitleElement(props) {
4 | return (
5 | {props.nodeName}
6 |
7 |
)
8 | }
9 | export default TitleElement
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # raycloud-apaas-flow
2 |
3 | ## Getting Started
4 |
5 | Install dependencies,
6 |
7 | ```bash
8 | $ npm i
9 | ```
10 |
11 | Start the dev server,
12 |
13 | ```bash
14 | $ npm start
15 | ```
16 |
17 | Build documentation,
18 |
19 | ```bash
20 | $ npm run docs:build
21 | ```
22 |
23 | Build library via `father-build`,
24 |
25 | ```bash
26 | $ npm run build
27 | ```
28 |
--------------------------------------------------------------------------------
/src/Flow/components/Render.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import MatchNode from './Node'
3 |
4 | function Render({ config, pRef }) {
5 | return (
6 |
7 |
8 | {config.childNode && }
9 |
10 | )
11 | }
12 |
13 | export default Render
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /npm-debug.log*
6 | /yarn-error.log
7 | /yarn.lock
8 | /package-lock.json
9 |
10 | # production
11 | /dist
12 | /docs-dist
13 |
14 | # misc
15 | .DS_Store
16 |
17 | # umi
18 | .umi
19 | .umi-production
20 | .umi-test
21 | .env.local
22 |
23 | # ide
24 | /.vscode
25 | /.idea
26 |
--------------------------------------------------------------------------------
/.umirc.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'dumi';
2 |
3 | export default defineConfig({
4 | title: 'raycloud-apaas-flow',
5 | favicon: 'https://user-images.githubusercontent.com/9554297/83762004-a0761b00-a6a9-11ea-83b4-9c8ff721d4b8.png',
6 | logo: 'https://user-images.githubusercontent.com/9554297/83762004-a0761b00-a6a9-11ea-83b4-9c8ff721d4b8.png',
7 | outputPath: 'docs-dist',
8 | // more config: https://d.umijs.org/config
9 | });
10 |
--------------------------------------------------------------------------------
/src/Flow/components/Node.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | import StartNode from './Start'
4 | import ApproverNode from './Approver'
5 | import NotifierNode from './Notifier'
6 | import ConditionNode from './Condition'
7 |
8 | const NodeMaps = {
9 | 0: StartNode,
10 | 1: ApproverNode,
11 | 2: NotifierNode,
12 | 4: ConditionNode
13 | }
14 |
15 | function MatchNode({config, pRef}) {
16 | const Node = NodeMaps[config.type] || null
17 | return Node &&
18 | }
19 |
20 | export default MatchNode
--------------------------------------------------------------------------------
/src/Flow/index.md:
--------------------------------------------------------------------------------
1 | Demo:
2 |
3 | ```tsx
4 | import React from 'react';
5 | import { Flow } from 'raycloud-apaas-flow';
6 |
7 | const config = {}; // 流程配置
8 | const formItems = [{
9 | label: 'String',
10 | value: 'input_123456',
11 | type: 'string'
12 | }, {
13 | label: 'Array',
14 | value: 'checkbox_123456',
15 | type: 'array'
16 | }, {
17 | label: 'Object',
18 | value: 'checkbox2_123456',
19 | type: 'object'
20 | }, {
21 | label: 'Boolean',
22 | value: 'boolean_123456',
23 | type: 'boolean'
24 | }]; // 工单列表字段
25 |
26 | export default () => ;
27 | ```
28 |
--------------------------------------------------------------------------------
/src/Flow/components/Start.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import NodeWrap from './Wrap';
3 |
4 | const getOwner = (userList = []) => {
5 | return userList.map(user => user.name).join('、')
6 | }
7 | function StartNode(props) {
8 | return (
9 | {props.nodeName}}
13 | >
14 | 0 && getOwner(props.nodeUserList)}>{props.nodeUserList?.length > 0 && getOwner(props.nodeUserList) }
15 | {/* */}
16 |
17 | );
18 | }
19 | export default StartNode;
20 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "esnext",
4 | "module": "esnext",
5 | "moduleResolution": "node",
6 | "importHelpers": true,
7 | "jsx": "react",
8 | "esModuleInterop": true,
9 | "sourceMap": true,
10 | "baseUrl": "./",
11 | "strict": true,
12 | "paths": {
13 | "@/*": ["src/*"],
14 | "@@/*": ["src/.umi/*"]
15 | },
16 | "allowSyntheticDefaultImports": true
17 | },
18 | "exclude": [
19 | "node_modules",
20 | "lib",
21 | "es",
22 | "dist",
23 | "typings",
24 | "**/__test__",
25 | "test",
26 | "docs",
27 | "tests"
28 | ]
29 | }
30 |
--------------------------------------------------------------------------------
/src/ConditionList/index.md:
--------------------------------------------------------------------------------
1 | Demo:
2 |
3 | ```tsx
4 | import React from 'react';
5 | import { ConditionList } from 'raycloud-apaas-flow';
6 |
7 | const formItems = [{
8 | label: 'String',
9 | value: 'input_123456',
10 | type: 'string'
11 | }, {
12 | label: 'Array',
13 | value: 'checkbox_123456',
14 | type: 'array'
15 | }, {
16 | label: 'Object',
17 | value: 'checkbox2_123456',
18 | type: 'object'
19 | }, {
20 | label: 'Boolean',
21 | value: 'boolean_123456',
22 | type: 'boolean'
23 | }];
24 | export default () => ;
25 | ```
26 |
27 | More skills for writing demo: https://d.umijs.org/guide/basic#write-component-demo
28 |
--------------------------------------------------------------------------------
/src/Flow/components/MyDrawer.js:
--------------------------------------------------------------------------------
1 | import React, { useState, forwardRef, useImperativeHandle } from 'react';
2 | import { Drawer } from 'antd';
3 |
4 | const ApproverDrawer = forwardRef(({ children, title, ...other }, ref) => {
5 | const [visible, setVisible] = useState(false);
6 | const onClose = () => {
7 | setVisible(false);
8 | };
9 | useImperativeHandle(ref, () => ({
10 | openModal: () => setVisible(true),
11 | closeModal: onClose,
12 | }));
13 | return (
14 |
21 | {children}
22 |
23 | )
24 | })
25 |
26 | export default ApproverDrawer;
27 |
--------------------------------------------------------------------------------
/src/Flow/components/Wrap.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {NodeTypes} from './Constants'
3 | import AddNode from './Add'
4 | function NodeWrap(props) {
5 | return (
6 |
7 |
8 |
9 |
10 | {props.title}
11 |
12 |
13 | {props.children}
14 |
15 |
16 |
17 |
18 |
19 |
20 | )
21 | }
22 | export default NodeWrap
--------------------------------------------------------------------------------
/src/Flow/components/Add.js:
--------------------------------------------------------------------------------
1 | import React, { useContext } from 'react';
2 | import { PlusCircleFilled } from '@ant-design/icons';
3 | import { Popover } from 'antd';
4 | import AddNodeList from './AddOptionList';
5 | import WFC from '../context/OperatorContext';
6 | import 'antd/dist/antd.css';
7 |
8 | function AddNode(props) {
9 | const { onAddNode } = useContext(WFC);
10 | function onOptionClick(type) {
11 | onAddNode(type, props.pRef, props.objRef);
12 | }
13 | return (
14 |
15 |
16 |
} trigger="hover">
17 |
18 |
19 |
20 |
21 | );
22 | }
23 |
24 | export default AddNode;
25 |
--------------------------------------------------------------------------------
/src/Flow/components/Approver.js:
--------------------------------------------------------------------------------
1 | import React, { useContext } from 'react';
2 | import { RightOutlined } from '@ant-design/icons';
3 | import NodeWrap from './Wrap'
4 | import TitleElement from './TitleElement'
5 | import WFC from '../context/OperatorContext'
6 | function ApproverNode(props) {
7 | const { onDeleteNode, onSelectNode, handleOpenApproverDrawer } = useContext(WFC)
8 | const delNode = (e) => {
9 | e.stopPropagation();
10 | onDeleteNode(props.pRef, props.objRef)
11 | }
12 |
13 | function onContentClick() {
14 | onSelectNode(props.pRef, props.objRef)
15 | handleOpenApproverDrawer();
16 | }
17 | // TODO: 这里读取props数据
18 | let TitleEl =
19 | return (
20 |
21 | {props.owner ? props.owner :'请选择审核人'}
22 |
23 |
24 | )
25 | }
26 | export default ApproverNode
--------------------------------------------------------------------------------
/src/Flow/components/Notifier.js:
--------------------------------------------------------------------------------
1 | import React, { useContext } from 'react'
2 | import { RightOutlined } from '@ant-design/icons';
3 | import NodeWrap from './Wrap'
4 | import TitleElement from './TitleElement'
5 | import WFC from '../context/OperatorContext';
6 |
7 | function NotifierNode(props) {
8 | const {onDeleteNode, onSelectNode} = useContext(WFC)
9 | function delNode() {
10 | onDeleteNode(props.pRef, props.objRef)
11 | }
12 | function onChange(val) {
13 | props.pRef.childNode.nodeName = val
14 | }
15 |
16 | function onContentClick() {
17 | onSelectNode(props.pRef, props.objRef)
18 | props.onContentClick && props.onContentClick()
19 | }
20 |
21 | let TitleEl =
22 | return (
23 |
24 | {props.owner ? props.owner : '请选择抄送人'}
25 |
26 |
27 | {/* */}
28 | )
29 | }
30 | export default NotifierNode
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "name": "raycloud-apaas-flow",
4 | "version": "1.0.0",
5 | "scripts": {
6 | "start": "dumi dev",
7 | "docs:build": "dumi build",
8 | "docs:deploy": "gh-pages -d docs-dist",
9 | "build": "father-build",
10 | "deploy": "npm run docs:build && npm run docs:deploy",
11 | "release": "npm run build && npm publish",
12 | "prettier": "prettier --write \"**/*.{js,jsx,tsx,ts,less,md,json}\"",
13 | "test": "umi-test",
14 | "test:coverage": "umi-test --coverage"
15 | },
16 | "main": "dist/index.js",
17 | "module": "dist/index.esm.js",
18 | "typings": "dist/index.d.ts",
19 | "gitHooks": {
20 | "pre-commit": "lint-staged"
21 | },
22 | "lint-staged": {
23 | "*.{js,jsx,less,md,json}": [
24 | "prettier --write"
25 | ],
26 | "*.ts?(x)": [
27 | "prettier --parser=typescript --write"
28 | ]
29 | },
30 | "dependencies": {
31 | "@ant-design/icons": "^4.6.4",
32 | "antd": "^4.16.13",
33 | "lodash": "^4.17.21",
34 | "react": "^16.12.0"
35 | },
36 | "devDependencies": {
37 | "@umijs/test": "^3.0.5",
38 | "dumi": "^1.0.16",
39 | "father-build": "^1.17.2",
40 | "gh-pages": "^3.0.0",
41 | "lint-staged": "^10.0.7",
42 | "prettier": "^2.2.1",
43 | "yorkie": "^2.0.0"
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/Flow/components/SetApprover.js:
--------------------------------------------------------------------------------
1 | import React, { useContext } from 'react';
2 | import { Form, Input, Select, Button, Modal } from 'antd';
3 | import WFC from '../context/OperatorContext';
4 |
5 | const SetApprover = () => {
6 | const { currentNode, updateNode } = useContext(WFC);
7 | const handleChange = ({ key, value }) => {
8 | currentNode[key] = value;
9 | updateNode();
10 | }
11 | return (
12 | <>
13 |
14 | handleChange({ key: 'nodeName', value: e.target.value })}
18 | />
19 |
20 |
21 |
22 |
23 |
24 |
40 | >
41 | );
42 | };
43 |
44 | export default SetApprover;
45 |
--------------------------------------------------------------------------------
/src/ConditionList/util.js:
--------------------------------------------------------------------------------
1 | import { toLower } from 'lodash';
2 |
3 | const EQUAL = {
4 | label: '等于',
5 | value: 'equal'
6 | }
7 |
8 | const NOT_EQUAL = {
9 | label: '不等于',
10 | value: 'not_equal'
11 | }
12 |
13 | const ANY = {
14 | label: '等于任意一个',
15 | value: 'any'
16 | }
17 |
18 | const NOT_ANY = {
19 | label: '不等于任意一个',
20 | value: 'not_any'
21 | }
22 |
23 | const INCLUDES = {
24 | label: '包含',
25 | value: 'includes'
26 | }
27 |
28 | const NOT_INCLUDES = {
29 | label: '不包含',
30 | value: 'not_includes'
31 | }
32 |
33 | const LESS = {
34 | label: '小于',
35 | value: 'less'
36 | }
37 |
38 | const LESS_EQUAL = {
39 | label: '小于等于',
40 | value: 'less_equal'
41 | }
42 |
43 | const GREATER = {
44 | label: '大于',
45 | value: 'greater'
46 | }
47 | const GREATER_EQUAL = {
48 | label: '大于等于',
49 | value: 'greater_equal'
50 | }
51 |
52 | export const findOperatorByType = (type) => {
53 | switch (toLower(type)) {
54 | case 'boolean':
55 | return [EQUAL, NOT_EQUAL];
56 | break;
57 | case 'string':
58 | return [EQUAL, NOT_EQUAL, ANY, NOT_ANY, INCLUDES, NOT_INCLUDES, LESS, LESS_EQUAL,GREATER, GREATER_EQUAL];
59 | break;
60 | case 'object':
61 | case 'array':
62 | return [EQUAL, NOT_EQUAL, ANY, NOT_ANY, INCLUDES, NOT_INCLUDES];
63 | break;
64 | default:
65 | return [];
66 | break;
67 | }
68 | }
--------------------------------------------------------------------------------
/src/Flow/components/ZoomLayout.js:
--------------------------------------------------------------------------------
1 | import React, {useState} from 'react';
2 |
3 | const ZOOM = {
4 | DOWN: 1,
5 | UP: 2,
6 | MIN: 50,
7 | MAX: 300
8 | }
9 |
10 | function ZoomLayout(props){
11 | // 放大比例, 按百分制给 100 为 100%
12 | let [scale, setScale] = useState(100)
13 | function zoomSize(type) {
14 | if(type === ZOOM.DOWN) {
15 | if(scale === ZOOM.MIN) {
16 | return
17 | }
18 | scale -= 10;
19 | setScale(scale)
20 | }
21 | if (type === ZOOM.UP){
22 | if(scale === ZOOM.MAX) {
23 | return
24 | }
25 | scale += 10;
26 | setScale(scale)
27 | }
28 | }
29 | return (
30 |
31 |
zoomSize(ZOOM.DOWN)}>
32 |
{scale}%
33 |
zoomSize(ZOOM.UP)}>
34 |
35 |
36 | {props.children}
37 |
38 |
39 | )
40 | }
41 |
42 | export default ZoomLayout
--------------------------------------------------------------------------------
/src/Flow/components/Constants.js:
--------------------------------------------------------------------------------
1 | // 添加节点类型
2 | export const OptionTypes = {
3 | APPROVER: 1,
4 | NOTIFIER: 2,
5 | BRANCH: 3,
6 | CONDITION: 4
7 | }
8 | export const NodeTypes = {...OptionTypes,START: 0}
9 | // 节点类型默认标题名
10 | export const OptionNames = {
11 | [OptionTypes.APPROVER]: '审批人',
12 | [OptionTypes.NOTIFIER]: '抄送人',
13 | [OptionTypes.CONDITION]:'条件分支'
14 | }
15 | // 节点模板
16 | export const NodeTemplates = {
17 | [OptionTypes.APPROVER]: {
18 | "nodeName": "审核人",
19 | "error": true,
20 | "type": OptionTypes.APPROVER,
21 | "settype": 1,
22 | "selectMode": 0,
23 | "selectRange": 0,
24 | "directorLevel": 1,
25 | "replaceByUp": 0,
26 | "examineMode": 1,
27 | "noHanderAction": 1,
28 | "examineEndDirectorLevel": 0,
29 | "nodeUserList": []
30 | },
31 | [OptionTypes.NOTIFIER]: {
32 | "nodeName": "抄送人",
33 | "type": OptionTypes.NOTIFIER,
34 | "ccSelfSelectFlag": 1,
35 | "nodeUserList": []
36 | },
37 | [OptionTypes.CONDITION]: {
38 | "nodeName": "路由",
39 | "type": OptionTypes.CONDITION,
40 | "childNode": null,
41 | "conditionNodes": [
42 | ]
43 | },
44 | [OptionTypes.BRANCH]:{
45 | "nodeName": "条件1",
46 | "type": OptionTypes.BRANCH,
47 | "priorityLevel": 2,
48 | "conditionList": {},
49 | "nodeUserList": [],
50 | "childNode": null
51 | }
52 | }
53 |
54 |
--------------------------------------------------------------------------------
/src/Flow/components/AddOptionList.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {
3 | AuditOutlined,
4 | DingtalkOutlined,
5 | ApartmentOutlined,
6 | } from '@ant-design/icons';
7 | import { OptionNames, OptionTypes } from './Constants';
8 |
9 | function AddNodeList(props) {
10 | return (
11 |
12 |
13 |
14 |
props.onOptionClick(OptionTypes.APPROVER)}
17 | />
18 |
19 |
{OptionNames[OptionTypes.APPROVER]}
20 |
21 |
22 |
23 |
24 | props.onOptionClick(OptionTypes.NOTIFIER)}
27 | />
28 |
29 |
{OptionNames[OptionTypes.NOTIFIER]}
30 |
31 |
32 |
33 |
props.onOptionClick(OptionTypes.CONDITION)}
36 | />
37 |
38 |
{OptionNames[OptionTypes.CONDITION]}
39 |
40 |
41 | );
42 | }
43 |
44 | export default AddNodeList;
45 |
--------------------------------------------------------------------------------
/src/Flow/init.json:
--------------------------------------------------------------------------------
1 | {
2 | "nodeName": "发起人",
3 | "type": 0,
4 | "conditionList": {},
5 | "nodeUserList": [{
6 | "id": "00001",
7 | "name": "王正贵"
8 | }],
9 | "childNode": {
10 | "nodeName": "审核人",
11 | "error": false,
12 | "type": 1,
13 | "childNode": {
14 | "nodeName": "路由",
15 | "type": 4,
16 | "conditionList": {},
17 | "nodeUserList": [],
18 | "childNode": {
19 | "nodeName": "抄送人",
20 | "type": 2,
21 | "ccSelfSelectFlag": 1,
22 | "childNode": null,
23 | "nodeUserList": [],
24 | "error": false
25 | },
26 | "conditionNodes": [{
27 | "nodeName": "条件1",
28 | "type": 3,
29 | "conditionList": {},
30 | "nodeUserList": [{
31 | "id": 85,
32 | "type": 1,
33 | "name": "天旭"
34 | }],
35 | "childNode": {
36 | "nodeName": "审核人",
37 | "type": 1,
38 | "conditionList": {},
39 | "nodeUserList": [{
40 | "id": 2515744,
41 | "name": "哈哈哈哈"
42 | }],
43 | "childNode": null,
44 | "conditionNodes": [],
45 | "error": false
46 | },
47 | "conditionNodes": [],
48 | "error": false
49 | }, {
50 | "nodeName": "条件2",
51 | "type": 3,
52 | "conditionList": {},
53 | "nodeUserList": [],
54 | "childNode": null,
55 | "conditionNodes": [],
56 | "error": false
57 | }]
58 | },
59 | "rule": "1",
60 | "nodeUserList": [],
61 | "conditionList": {}
62 | },
63 | "conditionNodes": []
64 | }
--------------------------------------------------------------------------------
/src/Flow/components/SetCondition.js:
--------------------------------------------------------------------------------
1 | import React, { useContext, useState, useRef } from 'react';
2 | import { Form, Input, Select, Button, Modal } from 'antd';
3 | import { set, get } from 'lodash';
4 | import WFC from '../context/OperatorContext';
5 | import ConditionList from '../../ConditionList';
6 |
7 | const SetCondition = ({ formItems }) => {
8 | const { currentNode, updateNode } = useContext(WFC);
9 | const [visible, setVisible] = useState(false);
10 | const conditionRef = useRef(null);
11 | const handleOpen = () => {
12 | setVisible(true);
13 | setTimeout(() => {
14 | conditionRef.current.setFormValue(get(currentNode, 'conditionList.conditions', []))
15 | }, 0);
16 | }
17 | const handleClose = () => {
18 | setVisible(false);
19 | conditionRef.current.resetFormValue();
20 | }
21 | const handleOk = () => {
22 | console.log('conditionRef', conditionRef)
23 | const conditions = conditionRef.current.getFormValue();
24 | set(currentNode, 'conditionList.conditions', conditions)
25 | handleClose();
26 | }
27 | const handleChange = ({ key, value }) => {
28 | set(currentNode, key, value)
29 | updateNode();
30 | }
31 | return (
32 | <>
33 |
34 | handleChange({ key: 'nodeName', value: e.target.value })}
38 | />
39 |
40 |
41 |
57 | {
58 | currentNode?.conditionList?.type === '1' && (
59 |
60 |
61 |
62 | )
63 | }
64 |
65 |
66 |
67 | >
68 | );
69 | };
70 |
71 | export default SetCondition;
72 |
--------------------------------------------------------------------------------
/src/Flow/components/Condition.js:
--------------------------------------------------------------------------------
1 | import React, { useContext } from 'react'
2 | import { CloseCircleOutlined, RightOutlined } from '@ant-design/icons';
3 | import AddNode from './Add'
4 | import Render from './Render'
5 | import { NodeTypes} from './Constants'
6 | import WFC from '../context/OperatorContext'
7 |
8 | function CoverLine({first = false, last = false}) {
9 | return (
10 | {first && }
11 | {first && }
12 | {last && }
13 | {last && }
14 | )
15 | }
16 |
17 | function BranchNode(props) {
18 | const {first = false, last = false} = props
19 | return (
20 |
21 |
22 |
props.onBranchClick(props.objRef)}>
23 |
24 | {props.nodeName}
25 | { e.stopPropagation(); props.delBranch()}} />
26 |
27 |
28 |
29 | {props.owner ? props.owner : 请设置条件}
30 |
31 |
32 | {/*
*/}
33 |
34 |
35 |
36 |
37 |
38 | )
39 | }
40 |
41 |
42 | function ConditionNode({conditionNodes:branches = [], ...restProps}) {
43 | const {onAddNode, onDeleteNode, onSelectNode, handleOpenConditionDrawer } = useContext(WFC)
44 | function addBranch() {
45 | onAddNode(NodeTypes.BRANCH,restProps.pRef, restProps.objRef)
46 | }
47 | function delBranch(i){
48 | if(branches.length === 2){
49 | onDeleteNode(restProps.pRef, restProps.objRef)
50 | return
51 | }
52 | console.log('delBranch(i)',(i))
53 | onDeleteNode(restProps.pRef, restProps.objRef, NodeTypes.BRANCH, i)
54 | }
55 | function onBranchClick(objRef) {
56 | onSelectNode(restProps.objRef, objRef)
57 | handleOpenConditionDrawer();
58 | }
59 |
60 | return (
61 | branches && branches.length > 0 &&
62 |
63 |
64 |
65 | {branches.map((item, index) => {
66 | return (
67 | delBranch(index)} last={index === branches.length-1} objRef={item} />
68 | {item.childNode && }
69 |
70 |
)
71 | })}
72 |
73 |
74 |
75 |
76 | )
77 | }
78 |
79 | export default ConditionNode
--------------------------------------------------------------------------------
/src/ConditionList/index.jsx:
--------------------------------------------------------------------------------
1 | import { useImperativeHandle, forwardRef } from 'react';
2 | import { Form, Input, Button, Space, Select } from 'antd';
3 | import { get, find, set, cloneDeep } from 'lodash'
4 | import { PlusOutlined } from '@ant-design/icons';
5 | import { findOperatorByType } from './util';
6 |
7 |
8 | const findOptions = (formItems) => (value, index) => {
9 | const optionByFields = find(formItems, item => item.value === get(value, `${index}.field`));
10 | return findOperatorByType(optionByFields?.type);
11 | }
12 |
13 | const ConditionList = forwardRef(({ formItems = [] }, ref) => {
14 | const [form] = Form.useForm();
15 | const getOptions = findOptions(formItems);
16 | useImperativeHandle(ref, () => ({
17 | getFormValue: () => {
18 | return form.getFieldsValue()
19 | },
20 | setFormValue: (values) => form.setFieldsValue(values),
21 | resetFormValue: () => form.resetFields()
22 | }))
23 |
24 | return (
25 |
27 | {(fields, { add, remove }) => (
28 | <>
29 |
30 |
33 |
34 | {fields.map(field => (
35 |
36 |
41 |
42 |
43 |
48 |
49 |
50 | {
53 | if (get(prevValues, `conditions.${field.fieldKey}.field`) !== get(curValues, `conditions.${field.fieldKey}.field`)) {
54 | const source = cloneDeep(form.getFieldValue('conditions'));
55 | set(source, `${field.fieldKey}.operator`, '');
56 | form.setFieldsValue({
57 | conditions: source
58 | });
59 | return true;
60 | }
61 | return false;
62 | }
63 | }
64 | >
65 | {() => (
66 |
71 |
72 |
73 | )}
74 |
75 |
76 |
81 |
82 |
83 |
84 | {/* */}
85 |
86 | ))}
87 | >
88 | )}
89 |
90 |
91 |
92 |
93 |
94 | );
95 | });
96 |
97 | export default ConditionList;
--------------------------------------------------------------------------------
/src/Flow/index.jsx:
--------------------------------------------------------------------------------
1 | import React, {
2 | forwardRef,
3 | useImperativeHandle,
4 | useState,
5 | useRef,
6 | } from 'react';
7 | import { isEmpty } from 'lodash';
8 | import initConfig from './init.json';
9 | import OpContext from './context/OperatorContext';
10 | import ZoomLayout from './components/ZoomLayout';
11 | import Render from './components/Render';
12 | import EndNode from './components/End';
13 | import MyDrawer from './components/MyDrawer';
14 | import SetApprover from './components/SetApprover';
15 | import SetCondition from './components/SetCondition';
16 | import { OptionTypes, NodeTemplates, NodeTypes } from './components/Constants';
17 | import './index.less';
18 |
19 | const Flow = forwardRef((props, ref) => {
20 | const [config, setConfig] = useState(
21 | isEmpty(props.config) ? initConfig : props.config,
22 | );
23 | const [currentNode, setCurrentNode] = useState({});
24 | const approverRef = useRef(null);
25 | const conditionRef = useRef(null);
26 | useImperativeHandle(ref, () => ({}));
27 | const updateNode = () => {
28 | setConfig({ ...config });
29 | };
30 |
31 | const onAddNode = (type, pRef, objRef) => {
32 | const o = objRef.childNode;
33 | if (type === OptionTypes.APPROVER) {
34 | objRef.childNode = {
35 | ...NodeTemplates[OptionTypes.APPROVER],
36 | childNode: o,
37 | };
38 | }
39 | if (type === OptionTypes.NOTIFIER) {
40 | objRef.childNode = {
41 | ...NodeTemplates[OptionTypes.NOTIFIER],
42 | childNode: o,
43 | };
44 | }
45 | if (type === OptionTypes.CONDITION) {
46 | objRef.childNode = {
47 | ...NodeTemplates[OptionTypes.CONDITION],
48 | conditionNodes: [
49 | {
50 | ...NodeTemplates[OptionTypes.BRANCH],
51 | nodeName: '条件1',
52 | childNode: o,
53 | },
54 | { ...NodeTemplates[OptionTypes.BRANCH], nodeName: '条件2' },
55 | ],
56 | };
57 | }
58 | if (type === OptionTypes.BRANCH) {
59 | objRef.conditionNodes.push({ ...NodeTemplates[NodeTypes.BRANCH] });
60 | }
61 | updateNode();
62 | };
63 | const onDeleteNode = (pRef, objRef, type, index) => {
64 | if (window.confirm('是否删除节点?')) {
65 | if (type === NodeTypes.BRANCH) {
66 | console.log([...objRef.conditionNodes], index);
67 | objRef.conditionNodes.splice(index, 1);
68 | console.log(objRef.conditionNodes);
69 | } else {
70 | const newObj = objRef.childNode;
71 | pRef.childNode = newObj;
72 | }
73 | updateNode();
74 | }
75 | };
76 |
77 | // 获取节点
78 | const onSelectNode = (pRef, objRef) => {
79 | setCurrentNode(objRef)
80 | };
81 |
82 | // 打开审批人Drawer
83 | const handleOpenApproverDrawer = () => approverRef.current.openModal();
84 | const handleCloseApproverDrawer = () => approverRef.current.closeModal();
85 | const handleOpenConditionDrawer = () => conditionRef.current.openModal();
86 | const handleCloseConditionDrawer = () => conditionRef.current.closeModal();
87 |
88 | return (
89 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
115 |
116 |
117 |
123 |
124 |
125 |
126 | );
127 | });
128 |
129 | export default Flow;
130 |
--------------------------------------------------------------------------------
/src/Flow/index.less:
--------------------------------------------------------------------------------
1 | .node-wrap-box {
2 | display: -webkit-inline-box;
3 | display: -ms-inline-flexbox;
4 | display: inline-flex;
5 | -webkit-box-orient: vertical;
6 | -webkit-box-direction: normal;
7 | -ms-flex-direction: column;
8 | flex-direction: column;
9 | position: relative;
10 | width: 220px;
11 | min-height: 72px;
12 | -ms-flex-negative: 0;
13 | flex-shrink: 0;
14 | background: #fff;
15 | border-radius: 4px;
16 | cursor: pointer
17 | }
18 |
19 | .node-wrap-box:after {
20 | pointer-events: none;
21 | content: "";
22 | position: absolute;
23 | top: 0;
24 | bottom: 0;
25 | left: 0;
26 | right: 0;
27 | z-index: 2;
28 | border-radius: 4px;
29 | border: 1px solid transparent;
30 | transition: all .1s cubic-bezier(.645, .045, .355, 1);
31 | box-shadow: 0 2px 5px 0 rgba(0, 0, 0, .1)
32 | }
33 |
34 | .node-wrap-box.active:after,
35 | .node-wrap-box:active:after,
36 | .node-wrap-box:hover:after {
37 | border: 1px solid #3296fa;
38 | box-shadow: 0 0 6px 0 rgba(50, 150, 250, .3)
39 | }
40 |
41 | .node-wrap-box.active .close,
42 | .node-wrap-box:active .close,
43 | .node-wrap-box:hover .close {
44 | display: block
45 | }
46 |
47 | .node-wrap-box.error:after {
48 | border: 1px solid #f25643;
49 | box-shadow: 0 2px 5px 0 rgba(0, 0, 0, .1)
50 | }
51 |
52 | .node-wrap-box .title {
53 | position: relative;
54 | display: flex;
55 | align-items: center;
56 | padding-left: 16px;
57 | padding-right: 8px;
58 | // width: 100%;
59 | height: 24px;
60 | line-height: 24px;
61 | font-size: 12px;
62 | color: #fff;
63 | text-align: left;
64 | background: #576a95;
65 | border-radius: 4px 4px 0 0;
66 | .title-element {
67 | width: 100%;
68 | display: flex;
69 | flex-direction: row;
70 | align-items: center;
71 | justify-content: space-between;
72 | }
73 | }
74 |
75 | .node-wrap-box .title .iconfont {
76 | font-size: 12px;
77 | margin-right: 5px
78 | }
79 |
80 | .node-wrap-box .placeholder {
81 | color: #bfbfbf
82 | }
83 |
84 | .node-wrap-box .close {
85 | display: none;
86 | position: absolute;
87 | right: 10px;
88 | top: 50%;
89 | transform: translateY(-50%);
90 | width: 20px;
91 | height: 20px;
92 | font-size: 14px;
93 | color: #fff;
94 | border-radius: 50%;
95 | text-align: center;
96 | line-height: 20px
97 | }
98 |
99 | .node-wrap-box .content {
100 | position: relative;
101 | font-size: 14px;
102 | padding: 16px;
103 | padding-right: 12px;
104 | display: flex;
105 | flex-direction: row;
106 | justify-content: space-between;
107 | align-items: center;
108 | }
109 |
110 | .node-wrap-box .content .text {
111 | overflow: hidden;
112 | text-overflow: ellipsis;
113 | display: -webkit-box;
114 | -webkit-line-clamp: 3;
115 | -webkit-box-orient: vertical
116 | }
117 |
118 | .node-wrap-box .content .arrow {
119 | position: absolute;
120 | right: 10px;
121 | top: 50%;
122 | transform: translateY(-50%);
123 | width: 20px;
124 | height: 14px;
125 | font-size: 14px;
126 | color: #979797
127 | }
128 |
129 | .start-node.node-wrap-box .content .text {
130 | display: block;
131 | white-space: nowrap
132 | }
133 |
134 | .node-wrapper-box-new {
135 | padding: 12px 10px
136 | }
137 |
138 | .node-wrapper-box-new .actions {
139 | margin-top: 11px;
140 | text-align: right
141 | }
142 |
143 | .node-wrapper-box-new .ant-btn {
144 | margin-left: 8px
145 | }
146 |
147 | .node-wrap-box:before {
148 | content: "";
149 | position: absolute;
150 | top: -12px;
151 | left: 50%;
152 | -webkit-transform: translateX(-50%);
153 | transform: translateX(-50%);
154 | width: 0;
155 | height: 4px;
156 | border-style: solid;
157 | border-width: 8px 6px 4px;
158 | border-color: #cacaca transparent transparent;
159 | background: #f5f5f7
160 | }
161 |
162 | .node-wrap-box.start-node:before {
163 | content: none
164 | }
165 |
166 | .add-node-popover {
167 | min-height: 160px
168 | }
169 |
170 | .add-node-popover-header {
171 | position: relative;
172 | margin-bottom: 15px
173 | }
174 |
175 | .add-node-popover-close {
176 | cursor: pointer;
177 | position: absolute;
178 | top: 5px;
179 | right: 5px;
180 | color: rgba(0, 0, 0, .25)
181 | }
182 |
183 | .add-node-popover-body {
184 | display: flex;
185 | .wrap-container {
186 | display: flex;
187 | flex-direction: column;
188 | .wrap {
189 | width: 64px;
190 | height: 64px;
191 | border-radius: 32px;
192 | border: 1px solid #e2e2e2;
193 | display: flex;
194 | align-items: center;
195 | justify-content: center;
196 | margin-left: 8px;
197 | }
198 | .text {
199 | padding-top: 8px;
200 | text-align: center;
201 | }
202 | }
203 | }
204 |
205 | .add-node-popover-item {
206 | margin-right: 10px;
207 | cursor: pointer;
208 | text-align: center;
209 | flex: 1;
210 | color: #191f25!important
211 | }
212 |
213 | .add-node-popover-item .item-wrapper {
214 | user-select: none;
215 | display: inline-block;
216 | width: 80px;
217 | height: 80px;
218 | margin-bottom: 5px;
219 | background: #fff;
220 | border: 1px solid #e2e2e2;
221 | border-radius: 50%;
222 | transition: all .3s cubic-bezier(.645, .045, .355, 1)
223 | }
224 |
225 | .add-node-popover-item .iconfont {
226 | font-size: 35px;
227 | line-height: 80px
228 | }
229 |
230 | .add-node-popover-item.approver .item-wrapper {
231 | color: #ff943e
232 | }
233 |
234 | .add-node-popover-item.notifier .item-wrapper {
235 | color: #3296fa
236 | }
237 |
238 | .add-node-popover-item.condition .item-wrapper {
239 | color: #15bc83
240 | }
241 |
242 | .add-node-popover-item.auto .item-wrapper {
243 | color: #1059fb
244 | }
245 |
246 | .add-node-popover-item:hover .item-wrapper {
247 | background: #3296fa;
248 | box-shadow: 0 10px 20px 0 rgba(50, 150, 250, .4)
249 | }
250 |
251 | .add-node-popover-item:hover .iconfont {
252 | color: #fff
253 | }
254 |
255 | .add-node-popover-item:active .item-wrapper {
256 | box-shadow: none;
257 | background: #eaeaea
258 | }
259 |
260 | .add-node-popover-item:active .iconfont {
261 | color: inherit
262 | }
263 |
264 |
265 | .top-left-cover-line {
266 | left: -1px
267 | }
268 |
269 | .top-left-cover-line,
270 | .top-right-cover-line {
271 | position: absolute;
272 | height: 3px;
273 | width: 50%;
274 | background-color: #f5f5f7;
275 | top: -2px
276 | }
277 |
278 | .top-right-cover-line {
279 | right: -1px
280 | }
281 |
282 | .bottom-left-cover-line {
283 | left: -1px
284 | }
285 |
286 | .bottom-left-cover-line,
287 | .bottom-right-cover-line {
288 | position: absolute;
289 | height: 3px;
290 | width: 50%;
291 | background-color: #f5f5f7;
292 | bottom: -2px
293 | }
294 |
295 | .bottom-right-cover-line {
296 | right: -1px
297 | }
298 |
299 | .panel-row {
300 | position: relative;
301 | margin-bottom: 10px
302 | }
303 |
304 | .dingflow-design {
305 | width: 100%;
306 | background-color: #f5f5f7;
307 | overflow: auto;
308 | position: absolute;
309 | bottom: 0;
310 | left: 0;
311 | right: 0;
312 | top: 0;
313 | z-index: 1;
314 | }
315 |
316 | .dingflow-design .box-scale {
317 | transform: scale(1);
318 | display: inline-block;
319 | position: relative;
320 | width: 100%;
321 | padding: 54.5px 0;
322 | -webkit-box-align: start;
323 | -ms-flex-align: start;
324 | align-items: flex-start;
325 | -webkit-box-pack: center;
326 | -ms-flex-pack: center;
327 | justify-content: center;
328 | -ms-flex-wrap: wrap;
329 | flex-wrap: wrap;
330 | min-width: -webkit-min-content;
331 | min-width: -moz-min-content;
332 | min-width: min-content;
333 | background-color: #f5f5f7;
334 | -webkit-transform-origin: 0 0 0;
335 | transform-origin: 0 0 0
336 | }
337 |
338 | .dingflow-design .ie-polyfill-container {
339 | display: -ms-grid;
340 | -ms-grid-columns: min-content
341 | }
342 |
343 | .dingflow-design .add-node-btn-box {
344 | width: 240px;
345 | display: -webkit-inline-box;
346 | display: -ms-inline-flexbox;
347 | display: inline-flex;
348 | -ms-flex-negative: 0;
349 | flex-shrink: 0;
350 | -webkit-box-flex: 1;
351 | -ms-flex-positive: 1;
352 | position: relative
353 | }
354 |
355 | .dingflow-design .add-node-btn-box:before {
356 | content: "";
357 | position: absolute;
358 | top: 0;
359 | left: 0;
360 | right: 0;
361 | bottom: 0;
362 | z-index: -1;
363 | margin: auto;
364 | width: 2px;
365 | height: 100%;
366 | background-color: #cacaca
367 | }
368 |
369 | .dingflow-design .node-wrap {
370 | flex-direction: column;
371 | -webkit-box-pack: start;
372 | -ms-flex-pack: start;
373 | justify-content: flex-start;
374 | -webkit-box-align: center;
375 | -ms-flex-align: center;
376 | align-items: center;
377 | -ms-flex-wrap: wrap;
378 | flex-wrap: wrap;
379 | -webkit-box-flex: 1;
380 | -ms-flex-positive: 1;
381 | // padding: 0 50px;
382 | position: relative
383 | }
384 |
385 | .dingflow-design .branch-wrap,
386 | .dingflow-design .node-wrap {
387 | display: inline-flex;
388 | width: 100%
389 | }
390 |
391 | .dingflow-design .branch-box-wrap {
392 | display: flex;
393 | -webkit-box-orient: vertical;
394 | -webkit-box-direction: normal;
395 | -ms-flex-direction: column;
396 | flex-direction: column;
397 | -ms-flex-wrap: wrap;
398 | flex-wrap: wrap;
399 | -webkit-box-align: center;
400 | -ms-flex-align: center;
401 | align-items: center;
402 | min-height: 270px;
403 | width: 100%;
404 | -ms-flex-negative: 0;
405 | flex-shrink: 0
406 | }
407 |
408 | .dingflow-design .branch-box {
409 | display: flex;
410 | overflow: visible;
411 | min-height: 180px;
412 | height: auto;
413 | border-bottom: 2px solid #ccc;
414 | border-top: 2px solid #ccc;
415 | position: relative;
416 | margin-top: 15px
417 | }
418 |
419 | .dingflow-design .branch-box .col-box {
420 | background: #f5f5f7
421 | }
422 |
423 | .dingflow-design .branch-box .col-box:before {
424 | content: "";
425 | position: absolute;
426 | top: 0;
427 | left: 0;
428 | right: 0;
429 | bottom: 0;
430 | z-index: 0;
431 | margin: auto;
432 | width: 2px;
433 | height: 100%;
434 | background-color: #cacaca
435 | }
436 |
437 | .dingflow-design .add-branch {
438 | border: none;
439 | outline: none;
440 | user-select: none;
441 | justify-content: center;
442 | font-size: 12px;
443 | padding: 0 10px;
444 | height: 30px;
445 | line-height: 30px;
446 | border-radius: 15px;
447 | color: #3296fa;
448 | background: #fff;
449 | box-shadow: 0 2px 4px 0 rgba(0, 0, 0, .1);
450 | position: absolute;
451 | top: -16px;
452 | left: 50%;
453 | transform: translateX(-50%);
454 | transform-origin: center center;
455 | cursor: pointer;
456 | z-index: 1;
457 | display: inline-flex;
458 | align-items: center;
459 | -webkit-transition: all .3s cubic-bezier(.645, .045, .355, 1);
460 | transition: all .3s cubic-bezier(.645, .045, .355, 1)
461 | }
462 |
463 | .dingflow-design .add-branch:hover {
464 | transform: translateX(-50%) scale(1.1);
465 | box-shadow: 0 8px 16px 0 rgba(0, 0, 0, .1)
466 | }
467 |
468 | .dingflow-design .add-branch:active {
469 | transform: translateX(-50%);
470 | box-shadow: none
471 | }
472 |
473 | .dingflow-design .col-box {
474 | display: inline-flex;
475 | -webkit-box-orient: vertical;
476 | -webkit-box-direction: normal;
477 | flex-direction: column;
478 | -webkit-box-align: center;
479 | align-items: center;
480 | position: relative
481 | }
482 |
483 | .dingflow-design .condition-node {
484 | min-height: 220px
485 | }
486 |
487 | .dingflow-design .condition-node,
488 | .dingflow-design .condition-node-box {
489 | display: inline-flex;
490 | -webkit-box-orient: vertical;
491 | -webkit-box-direction: normal;
492 | flex-direction: column;
493 | -webkit-box-flex: 1
494 | }
495 |
496 | .dingflow-design .condition-node-box {
497 | padding-top: 30px;
498 | padding-right: 50px;
499 | padding-left: 50px;
500 | -webkit-box-pack: center;
501 | justify-content: center;
502 | -webkit-box-align: center;
503 | align-items: center;
504 | flex-grow: 1;
505 | position: relative
506 | }
507 |
508 | .dingflow-design .condition-node-box:before {
509 | content: "";
510 | position: absolute;
511 | top: 0;
512 | left: 0;
513 | right: 0;
514 | bottom: 0;
515 | margin: auto;
516 | width: 2px;
517 | height: 100%;
518 | background-color: #cacaca
519 | }
520 |
521 | .dingflow-design .auto-judge {
522 | position: relative;
523 | width: 220px;
524 | min-height: 72px;
525 | background: #fff;
526 | border-radius: 4px;
527 | padding: 12px 8px 0 16px;
528 | cursor: pointer
529 | }
530 |
531 | .dingflow-design .auto-judge:after {
532 | pointer-events: none;
533 | content: "";
534 | position: absolute;
535 | top: 0;
536 | bottom: 0;
537 | left: 0;
538 | right: 0;
539 | z-index: 2;
540 | border-radius: 4px;
541 | border: 1px solid transparent;
542 | transition: all .1s cubic-bezier(.645, .045, .355, 1);
543 | box-shadow: 0 2px 5px 0 rgba(0, 0, 0, .1)
544 | }
545 |
546 | .dingflow-design .auto-judge.active:after,
547 | .dingflow-design .auto-judge:active:after,
548 | .dingflow-design .auto-judge:hover:after {
549 | border: 1px solid #3296fa;
550 | box-shadow: 0 0 6px 0 rgba(50, 150, 250, .3)
551 | }
552 |
553 | .dingflow-design .auto-judge.active .close,
554 | .dingflow-design .auto-judge:active .close,
555 | .dingflow-design .auto-judge:hover .close {
556 | display: block
557 | }
558 |
559 | .dingflow-design .auto-judge.error:after {
560 | border: 1px solid #f25643;
561 | box-shadow: 0 2px 5px 0 rgba(0, 0, 0, .1)
562 | }
563 |
564 | .dingflow-design .auto-judge .title-wrapper {
565 | position: relative;
566 | font-size: 12px;
567 | color: #15bc83;
568 | text-align: left;
569 | line-height: 16px;
570 | display: flex;
571 | flex-direction: row;
572 | justify-content: space-between;
573 | align-items: center;
574 | }
575 |
576 | .dingflow-design .auto-judge .title-wrapper .editable-title {
577 | display: inline-block;
578 | max-width: 120px;
579 | overflow: hidden;
580 | white-space: nowrap;
581 | text-overflow: ellipsis
582 | }
583 |
584 | .dingflow-design .auto-judge .title-wrapper .priority-title {
585 | display: inline-block;
586 | float: right;
587 | margin-right: 10px;
588 | color: rgba(25, 31, 37, .56)
589 | }
590 |
591 | .dingflow-design .auto-judge .title-wrapper .priority-button {
592 | display: inline-block;
593 | height: 28px;
594 | float: right;
595 | margin-right: 10px;
596 | border: 1px solid rgba(0, 0, 0, .15);
597 | border-radius: 4px;
598 | color: rgba(0, 0, 0, .65)
599 | }
600 |
601 | .dingflow-design .auto-judge .title-wrapper .priority-button div {
602 | display: inline-block
603 | }
604 |
605 | .dingflow-design .auto-judge .title-wrapper .priority-button .priority-content {
606 | padding: 0 8px;
607 | font-size: 12px;
608 | line-height: 28px;
609 | border-left: 1px solid rgba(0, 0, 0, .15);
610 | border-right: 1px solid rgba(0, 0, 0, .15)
611 | }
612 |
613 | .dingflow-design .auto-judge .placeholder {
614 | color: #bfbfbf
615 | }
616 |
617 | .dingflow-design .auto-judge .close {
618 | display: none;
619 | position: absolute;
620 | right: -10px;
621 | top: -10px;
622 | width: 20px;
623 | height: 20px;
624 | font-size: 14px;
625 | color: rgba(0, 0, 0, .25);
626 | border-radius: 50%;
627 | text-align: center;
628 | line-height: 20px;
629 | z-index: 2
630 | }
631 |
632 | .dingflow-design .auto-judge .content {
633 | font-size: 14px;
634 | color: #191f25;
635 | text-align: left;
636 | margin-top: 6px;
637 | overflow: hidden;
638 | text-overflow: ellipsis;
639 | display: -webkit-box;
640 | -webkit-line-clamp: 3;
641 | -webkit-box-orient: vertical;
642 | padding-right: 12px;
643 | display: flex;
644 | flex-direction: row;
645 | justify-content: space-between;
646 | align-items: center;
647 | }
648 |
649 | .dingflow-design .auto-judge .sort-left,
650 | .dingflow-design .auto-judge .sort-right {
651 | position: absolute;
652 | top: 0;
653 | bottom: 0;
654 | display: none;
655 | z-index: 1
656 | }
657 |
658 | .dingflow-design .auto-judge .sort-left {
659 | left: 0;
660 | border-right: 1px solid #f6f6f6
661 | }
662 |
663 | .dingflow-design .auto-judge .sort-right {
664 | right: 0;
665 | border-left: 1px solid #f6f6f6
666 | }
667 |
668 | .dingflow-design .auto-judge:hover .sort-left,
669 | .dingflow-design .auto-judge:hover .sort-right {
670 | display: flex;
671 | align-items: center
672 | }
673 |
674 | .dingflow-design .auto-judge .sort-left:hover,
675 | .dingflow-design .auto-judge .sort-right:hover {
676 | background: #efefef
677 | }
678 |
679 | .dingflow-design .add-node-btn {
680 | user-select: none;
681 | width: 240px;
682 | padding: 20px 0 32px;
683 | display: flex;
684 | -webkit-box-pack: center;
685 | justify-content: center;
686 | flex-shrink: 0;
687 | -webkit-box-flex: 1;
688 | flex-grow: 1
689 | }
690 |
691 | .dingflow-design .add-node-btn .btn {
692 | outline: none;
693 | box-shadow: 0 2px 4px 0 rgba(0, 0, 0, .1);
694 | width: 30px;
695 | height: 30px;
696 | background: #3296fa;
697 | border-radius: 50%;
698 | position: relative;
699 | border: none;
700 | line-height: 30px;
701 | -webkit-transition: all .3s cubic-bezier(.645, .045, .355, 1);
702 | transition: all .3s cubic-bezier(.645, .045, .355, 1)
703 | }
704 |
705 | .dingflow-design .add-node-btn .btn .iconfont {
706 | color: #fff;
707 | font-size: 16px
708 | }
709 |
710 | .dingflow-design .add-node-btn .btn:hover {
711 | transform: scale(1.3);
712 | box-shadow: 0 13px 27px 0 rgba(0, 0, 0, .1)
713 | }
714 |
715 | .dingflow-design .add-node-btn .btn:active {
716 | transform: none;
717 | background: #1e83e9;
718 | box-shadow: 0 2px 4px 0 rgba(0, 0, 0, .1)
719 | }
720 |
721 | .dingflow-design .end-node {
722 | border-radius: 50%;
723 | font-size: 14px;
724 | color: rgba(25, 31, 37, .4);
725 | text-align: left
726 | }
727 |
728 | .dingflow-design .end-node .end-node-circle {
729 | width: 10px;
730 | height: 10px;
731 | margin: auto;
732 | border-radius: 50%;
733 | background: #dbdcdc
734 | }
735 |
736 | .dingflow-design .end-node .end-node-text {
737 | margin-top: 5px;
738 | text-align: center
739 | }
740 |
741 |
742 | .zoom {
743 | display: flex;
744 | position: fixed;
745 | -webkit-box-align: center;
746 | -ms-flex-align: center;
747 | align-items: center;
748 | -webkit-box-pack: justify;
749 | -ms-flex-pack: justify;
750 | justify-content: space-between;
751 | height: 40px;
752 | width: 125px;
753 | right: 40px;
754 | margin-top: 30px;
755 | z-index: 10
756 | }
757 |
758 | .zoom .zoom-in,
759 | .zoom .zoom-out {
760 | width: 30px;
761 | height: 30px;
762 | background: #fff;
763 | color: #c1c1cd;
764 | cursor: pointer;
765 | background-size: 100%;
766 | background-repeat: no-repeat
767 | }
768 |
769 | .zoom .zoom-out {
770 | background-image: url(https://gw.alicdn.com/tfs/TB1s0qhBHGYBuNjy0FoXXciBFXa-90-90.png)
771 | }
772 |
773 | .zoom .zoom-out.disabled {
774 | opacity: .5
775 | }
776 |
777 | .zoom .zoom-in {
778 | background-image: url(https://gw.alicdn.com/tfs/TB1UIgJBTtYBeNjy1XdXXXXyVXa-90-90.png)
779 | }
780 |
781 | .zoom .zoom-in.disabled {
782 | opacity: .5
783 | }
784 |
785 | .add-icon {
786 | transition: all .3s cubic-bezier(.645, .045, .355, 1)
787 | }
788 | .add-icon:hover {
789 | transform: scale(1.2);
790 | }
791 |
--------------------------------------------------------------------------------