Commit bc62d01c7c7e4246aecc63ac833c9a28a8fa5a4e

Authored by qiang.tian
1 parent 97f7ab95

fix: builder error

... ... @@ -7,14 +7,16 @@ const cwd = process.cwd();
7 7
8 8 module.exports = {
9 9 output: {
10   - filename: 'index.js',
  10 + filename: 'qx-[name]-[contenthash].bundle.js',
11 11 libraryTarget: 'umd',
  12 + clean: true,
12 13 },
13 14 entry: path.resolve(cwd, './src/index.tsx'),
14 15 module: {
15 16 rules: [
16 17 {
17 18 test: /\.(js|jsx)$/,
  19 + exclude: /node_modules/,
18 20 use: {
19 21 loader: 'babel-loader',
20 22 options: {
... ... @@ -29,14 +31,23 @@ module.exports = {
29 31 },
30 32 },
31 33 {
32   - test: /\.(ttf|eot|woff(2)?)(\?[a-z0-9=&.]+)?$/,
  34 + test: /\.(png|jpeg|jpg|ttf|eot|woff(2)?)(\?[a-z0-9=&.]+)?$/,
33 35 use: {
34 36 loader: 'file-loader',
35 37 },
36 38 },
37 39 {
38 40 test: /\.less$/i,
39   - use: ['style-loader', 'css-loader', 'less-loader'],
  41 + use: [
  42 + 'style-loader',
  43 + 'css-loader',
  44 + {
  45 + loader: 'less-loader',
  46 + options: {
  47 + additionalData: `@import '@qx/ui/dist/src/style/variable.less';`,
  48 + },
  49 + },
  50 + ],
40 51 },
41 52 {
42 53 test: /\.svg$/,
... ...
... ... @@ -24,6 +24,7 @@
24 24 "license": "ISC",
25 25 "dependencies": {
26 26 "@ant-design/icons": "^5.2.5",
  27 + "@qx/common": "0.2.31-alpha.5",
27 28 "@qx/flow": "1.0.0-alpha.10",
28 29 "@qx/icon-btn": "^0.0.13",
29 30 "@qx/ui": "0.0.3-beta.1",
... ...
1   -import React, { memo } from 'react';
2   -
3   -const DynamicComponent: React.FC<DynamicComponentProps> = (props) => {
4   - return <div>DynamicComponent</div>;
5   -};
6   -
7   -interface DynamicComponentProps {
8   - loader: (path: string) => any;
9   -}
10   -
11   -export default memo(DynamicComponent);
... ... @@ -26,6 +26,7 @@ const FlowVersion: React.FC<FlowVersionProps> = (props) => {
26 26 return (
27 27 <>
28 28 {versionText ||
  29 + // @ts-ignore
29 30 (statusEnums || FlowStatusEnums)[status || 'UNPUBLISHED'] ? (
30 31 <div
31 32 className={cls(
... ... @@ -51,6 +52,7 @@ const FlowVersion: React.FC<FlowVersionProps> = (props) => {
51 52 >
52 53 {!!versionText ? <span>V&nbsp;{versionText}</span> : null}
53 54 {!!status ? (
  55 + // @ts-ignore
54 56 <span>{(statusEnums || FlowStatusEnums)[status]}</span>
55 57 ) : null}
56 58 </div>
... ...
  1 +import React, { Suspense } from 'react';
  2 +import { Skeleton } from 'antd';
  3 +
  4 +const lazyComponent = (importComp: () => any) => {
  5 + const Comp = React.lazy(importComp);
  6 + return (
  7 + <Suspense fallback={<Skeleton.Input />}>
  8 + <Comp></Comp>
  9 + </Suspense>
  10 + );
  11 +};
  12 +
  13 +export default lazyComponent;
... ...
... ... @@ -62,6 +62,7 @@ const NameDescriptionSetting: React.FC<NameDescriptionSettingProps> = (
62 62 if (_.isEmpty(values)) {
63 63 form.resetFields();
64 64 } else {
  65 + // @ts-ignore
65 66 form.setValues(values);
66 67 }
67 68 }, 100);
... ... @@ -114,6 +115,7 @@ const NameDescriptionSetting: React.FC<NameDescriptionSettingProps> = (
114 115 form={form}
115 116 schema={FORM_SCHEMA}
116 117 onMount={() => {}}
  118 + // @ts-ignore
117 119 onFinish={onFinish}
118 120 watch={{}}
119 121 />
... ...
... ... @@ -2,12 +2,13 @@ import React, { memo, useContext, useEffect, useState } from 'react';
2 2 import { BuilderContext } from '@qx/flow';
3 3 import { Drawer, Spin, Tabs } from 'antd';
4 4 import NodeList, { NodeItemsProps } from './components/node-list';
5   -import { useLocation, useSearchParams } from 'react-router-dom';
  5 +import { useSearchParams } from '@/hooks';
6 6 import { getListGroupNode } from '@/services';
7 7 import { QxIcon } from '@/components';
8 8 import { ReactSortable } from 'react-sortablejs';
9 9 import { cloneDeep } from 'lodash-es';
10 10 import { v4 as uuid } from 'uuid';
  11 +// @ts-ignore
11 12 import type { INodePanelProps } from '@qx/flow';
12 13 import Empty from './img/empty.png';
13 14
... ... @@ -31,10 +32,10 @@ const panelTabs = [
31 32 ];
32 33
33 34 const NodePanel: React.FC<NodePanelProps> = (props) => {
34   - const { visible, onClose } = props;
35 35 // @ts-ignore
36   - const [searchParams] = useSearchParams();
37   - const appId = searchParams.get('appId');
  36 + const { visible, onClose } = props;
  37 + const [query] = useSearchParams<any>();
  38 + const appId = query?.appId;
38 39 const { registerNodes } = useContext(BuilderContext);
39 40 const [loading, setLoading] = useState(false);
40 41 const [activeKey, setActiveKey] = useState('SYSTEM');
... ...
1 1 export * from './useTheme';
  2 +export * from './useSearchParams';
  3 +export * from './useFlowTableScrollY';
... ...
  1 +import React, { useEffect, useMemo, useRef, useState } from 'react';
  2 +
  3 +// 表格 Scroll 高度计算
  4 +export const useFlowTableScrollY = (
  5 + deps: {
  6 + columns: any[];
  7 + size?: 'small' | 'middle' | 'default';
  8 + tableBoxClassName?: string;
  9 + classNames?: string[]; // 表格DOM内嵌元素 列名 添加在此,
  10 + hasPagination?: boolean;
  11 + listProps?: any;
  12 + } = {
  13 + size: 'small',
  14 + tableBoxClassName: '',
  15 + classNames: [],
  16 + hasPagination: false,
  17 + columns: [],
  18 + listProps: {},
  19 + },
  20 +) => {
  21 + const itemHeaderHeight =
  22 + (deps?.size === 'middle' ? 48 : deps?.size === 'default' ? 56 : 40) + 1;
  23 + const TABLE_VIEW_LIST = deps?.tableBoxClassName || 'qx-data-flow-table';
  24 + let tableHeader = itemHeaderHeight;
  25 + const tableViewListDefaultHeight = 400;
  26 + const defaultPagePadding = 0;
  27 +
  28 + const $ = (selectors: string) =>
  29 + document.querySelector<HTMLElement>(selectors);
  30 +
  31 + const defaultScrollY = useMemo(
  32 + () => document.body.clientHeight,
  33 + [tableHeader],
  34 + );
  35 +
  36 + const [scrollY, setScrollY] = useState<number>(defaultScrollY ?? 200);
  37 +
  38 + // @ts-ignore
  39 + const timer = useRef<NodeJS.Timer>();
  40 +
  41 + const getScrollY = () => {
  42 + const tableViewList = $(`.${TABLE_VIEW_LIST}`);
  43 +
  44 + const tableViewListClientHeight =
  45 + tableViewList?.clientHeight || tableViewListDefaultHeight;
  46 + // 分页大小 目前已经固定 所以直接用56px
  47 + const antPaginationHeight = deps?.hasPagination ? 56 : 0;
  48 +
  49 + const _domHeightByClassName = (deps?.classNames || []).map(
  50 + (_v: string) => $(`.${_v}`)?.clientHeight ?? 0,
  51 + );
  52 + let result =
  53 + tableViewListClientHeight -
  54 + tableHeader -
  55 + defaultPagePadding -
  56 + antPaginationHeight;
  57 + if (!!_domHeightByClassName?.length) {
  58 + result = result - eval(_domHeightByClassName.join('+'));
  59 + }
  60 +
  61 + if (tableViewList) {
  62 + tableViewList.style.overflowY = result < 200 ? 'auto' : 'hidden';
  63 + }
  64 +
  65 + setScrollY(result < 100 ? 100 : result);
  66 + };
  67 +
  68 + const observer = () => {
  69 + window.addEventListener('resize', getScrollY);
  70 + };
  71 +
  72 + const removeObserver = () => {
  73 + if (timer.current) window.clearTimeout(timer.current);
  74 + window.removeEventListener('resize', getScrollY);
  75 + };
  76 +
  77 + useEffect(() => {
  78 + observer();
  79 + return () => {
  80 + removeObserver();
  81 + };
  82 + }, [tableHeader]);
  83 +
  84 + useEffect(() => {
  85 + if (deps) {
  86 + timer.current = setTimeout(() => {
  87 + getScrollY();
  88 + }, 100);
  89 + }
  90 + }, [JSON.stringify(deps)]);
  91 +
  92 + return [scrollY, getScrollY];
  93 +};
... ...
  1 +import { useMemo } from 'react';
  2 +import { useSearchParams as useRouterDOMSearchParams } from 'react-router-dom';
  3 +
  4 +export const useSearchParams = <T = Record<string, any>>() => {
  5 + const [searchParams, setQuery] = useRouterDOMSearchParams();
  6 +
  7 + const query = useMemo<T>(() => {
  8 + const params = {} as T;
  9 + searchParams.forEach((value, key) => {
  10 + (params as Record<string, any>)[key] = value;
  11 + });
  12 + return params;
  13 + }, []);
  14 +
  15 + return [query, setQuery];
  16 +};
... ...
... ... @@ -17,7 +17,7 @@ import { Start, End } from './nodes';
17 17 import { NodeTypes, ProcessItemProps, FlowStatusEnums } from '@/interface';
18 18 import { handleWindowOpen } from '@qx/utils';
19 19 // import { history } from '@@/core/history';
20   -import { useLocation, useSearchParams } from 'react-router-dom';
  20 +import { useLocation } from 'react-router-dom';
21 21 import { useTitle } from 'ahooks';
22 22 // 头部相关
23 23 import {
... ... @@ -31,6 +31,7 @@ import cls from 'classnames';
31 31 import styles from '@/components/header/index.module.less';
32 32 import { getIcon } from '@/utils';
33 33 import { QxIcon } from '@/components';
  34 +import { useSearchParams } from '@/hooks';
34 35 import {
35 36 getProcessDetailsById,
36 37 publishProcessById,
... ... @@ -71,8 +72,7 @@ const systemNodes: IRegisterNode[] = [
71 72 export default () => {
72 73 const [nodes, setNodes] = useState<INode[]>([]);
73 74 const [remoteNodes, setRemoteNodes] = useState<IRegisterRemoteNode[]>([]);
74   - // @ts-ignore
75   - const [searchParams] = useSearchParams();
  75 + const [query, setQuery] = useSearchParams<any>();
76 76 const [showEditTitle, setShowEditTitle] = useState(false);
77 77 const {
78 78 appId, // 应用id
... ... @@ -80,13 +80,7 @@ export default () => {
80 80 returnUrl, // 来自页面跳转返回可跳转
81 81 processId, // 流程Id preview
82 82 type, // 流程类型 edit 编辑 preview 预览
83   - } = {
84   - appId: searchParams.get('appId'),
85   - funCode: searchParams.get('funCode'),
86   - returnUrl: searchParams.get('returnUrl'),
87   - processId: searchParams.get('processId'),
88   - type: searchParams.get('type'),
89   - };
  83 + } = query;
90 84
91 85 const [processDetails, setProcessDetails] = useState<ProcessItemProps>({
92 86 id: '',
... ... @@ -116,6 +110,7 @@ export default () => {
116 110 .catch((err: { msg?: string }) => {
117 111 message.warning(err?.msg || '流程详情数据请求失败', 5);
118 112 setProcessDetails(
  113 + // @ts-ignore
119 114 _data || {
120 115 id: _id,
121 116 name: '未命名流程',
... ... @@ -198,7 +193,7 @@ export default () => {
198 193 // 发布流程
199 194 // TODO 要先校验是否保存 才能发布
200 195 publishProcessById(processDetails.id || '')
201   - .then((res) => {
  196 + .then((res: any) => {
202 197 console.log('res ====', res);
203 198 })
204 199 .catch((err: { msg?: string }) => {
... ... @@ -237,11 +232,8 @@ export default () => {
237 232 remark: data.remark,
238 233 });
239 234 if (!processDetails?.id) {
240   - history.replace({
241   - query: {
242   - ...query,
243   - processId: res,
244   - },
  235 + setQuery({
  236 + processId: res,
245 237 });
246 238 }
247 239 }
... ... @@ -389,6 +381,7 @@ export default () => {
389 381 useEffect(() => {
390 382 let _data: ProcessItemProps = {};
391 383 _data.name = '未命名流程';
  384 + // @ts-ignore
392 385 _data.appId = appId;
393 386 if (!!funCode) {
394 387 _data.funCode = funCode;
... ... @@ -416,6 +409,7 @@ export default () => {
416 409 defaultTools: INode[],
417 410 actions: any,
418 411 ) => {
  412 + console.log('nodes', nodes);
419 413 const { copyNodeAndChildren } = actions;
420 414 switch (node.type) {
421 415 case 'condition':
... ... @@ -452,6 +446,7 @@ export default () => {
452 446 registerNodes={systemNodes}
453 447 historyTool
454 448 zoomTool
  449 + // @ts-ignore
455 450 expandAllTool
456 451 DrawerComponent={Drawer}
457 452 PopoverComponent={Popover}
... ... @@ -463,6 +458,7 @@ export default () => {
463 458 registerRemoteNodes={remoteNodes}
464 459 ConfigDrawerContainer={ConfigDrawer}
465 460 NodePanel={NodesPanel}
  461 + // @ts-ignore
466 462 getNodeTool={getNodeTool}
467 463 />
468 464 <NameDescriptionSetting cRef={formModalRef} handleClick={handleClick} />
... ...
1 1 import React, { useContext, memo, useImperativeHandle } from 'react';
2   -import { useForm } from '@qx/form-render';
3   -import QxFormRender from '@/packages/qx-form-generator/src/form-render';
4   -import { conditionSetting } from '../../setting-configs';
  2 +// import { useForm } from '@qx/form-render';
  3 +// import QxFormRender from '@/packages/qx-form-generator/src/form-render';
  4 +// import { conditionSetting } from '../../setting-configs';
5 5 import styles from './index.less';
6 6 import type { IConfigComponent } from '@qx/flow';
7 7
8 8 const StartConfigComponent = React.forwardRef<any, StartConfigComponentProps>(
9 9 (props, ref) => {
10   - const form = useForm();
  10 + // const form = useForm();
11 11
12 12 const handleValuesChange = (values: any) => {
13 13 props?.onChange(values);
14 14 };
15 15
16 16 useImperativeHandle(ref, () => ({
17   - validateFields: form.validateFields,
  17 + // validateFields: form.validateFields,
18 18 }));
19 19
20 20 return (
21 21 <div className={styles['qx-flow-single-records-config']}>
22   - <QxFormRender
  22 + {/* <QxFormRender
23 23 form={form}
24 24 schema={conditionSetting}
25 25 widgets={{}}
26 26 watch={{}}
27 27 onValuesChange={handleValuesChange}
28   - />
  28 + /> */}
29 29 </div>
30 30 );
31 31 },
... ...
1 1 import React, { useContext, memo } from 'react';
2   -import { useForm } from '@qx/form-render';
  2 +// import { useForm } from '@qx/form-render';
3 3 import { useDrawer } from '@qx/flow';
4   -import { ConfigComponentFooter } from '../../components';
5   -import QxFormRender from '@/packages/qx-form-generator/src/form-render';
6   -import { startSetting } from '../../setting-configs';
  4 +// import { ConfigComponentFooter } from '../../components';
  5 +// import QxFormRender from '@/packages/qx-form-generator/src/form-render';
  6 +// import { startSetting } from '../../setting-configs';
7 7 import styles from './index.less';
8 8 import type { IConfigComponent } from '@qx/flow';
9 9
10 10 const EndConfigComponent: React.FC<EndConfigComponentProps> = (props) => {
11   - const form = useForm();
12   - const { closeDrawer: cancel, saveDrawer: save } = useDrawer();
  11 + // const form = useForm();
13 12
14   - const onSave = async () => {
15   - try {
16   - await form.submit();
17   - const values = form.getValues();
18   - console.log('values', values);
19   - save(values);
20   - } catch (error) {
21   - console.log(error);
22   - }
23   - };
24   -
25   - return (
26   - <div className={styles['qx-flow-single-records-config']}>
27   - <QxFormRender form={form} schema={startSetting} widgets={{}} watch={{}} />
28   - <ConfigComponentFooter onSave={onSave} onCancel={cancel} />
29   - </div>
30   - );
  13 + return <div className={styles['qx-flow-single-records-config']}></div>;
31 14 };
32 15
33 16 interface EndConfigComponentProps extends IConfigComponent {}
... ...
1 1 import React, { memo } from 'react';
2   -// import { ReactComponent as Icon } from "../../public/icons/outlined.svg";
  2 +import { Button, Typography } from 'antd';
  3 +import { useAction } from '@qx/flow';
  4 +const { Text } = Typography;
3 5 import type { IDisplayComponent, INode } from '@qx/flow';
4   -import './index.less';
  6 +
  7 +const paramsEnums: Record<string, string> = {
  8 + STRING: '文本',
  9 + NUMBER: '数字',
  10 + TIME: '日期',
  11 + BOOL: '布尔',
  12 + OBJECT: '对象',
  13 + ARRAY: '数组',
  14 + ANNEX: '附件',
  15 + PIC: '图片',
  16 + FORM: '表单',
  17 + USER: '人员',
  18 + ORG: '部门',
  19 +};
5 20
6 21 const DisplayComponent: React.FC<DisplayComponentProps> = (props) => {
7 22 const { node, nodes } = props;
8 23
  24 + const handleChangeName = (newValue: string) => {
  25 + node.name = newValue;
  26 + props.onChange?.([...nodes]);
  27 + };
  28 +
  29 + const { clickNode } = useAction();
  30 +
9 31 return (
10 32 <div className="qx-flow-default-node">
11 33 <div className="qx-flow-default-node__header">
... ... @@ -16,13 +38,38 @@ const DisplayComponent: React.FC<DisplayComponentProps> = (props) => {
16 38 <span className="qx-flow-default-node__title--name">{node.name}</span>
17 39 </span>
18 40 </div>
19   - <div className="qx-flow-default-node__content">
20   - {!node.data ? (
21   - <span className="qx-flow-start-node__button">设置入参</span>
22   - ) : (
23   - <span>节点配置内容</span>
24   - )}
25   - </div>
  41 + {!!node?.data?.params?.length ? (
  42 + <>
  43 + <div className="qx-flow-default-node__content">
  44 + {props?.node?.data?.params.map((_v: any) => {
  45 + return (
  46 + <Text
  47 + style={{
  48 + width: '100%',
  49 + lineHeight: '22px',
  50 + }}
  51 + ellipsis={{
  52 + tooltip: `${paramsEnums?.[_v.type || '']}&nbsp;${
  53 + _v.title || '未命名'
  54 + }`,
  55 + }}
  56 + >
  57 + {paramsEnums?.[_v.type || '']}&nbsp;{_v.title || '未命名'}
  58 + </Text>
  59 + );
  60 + })}
  61 + </div>
  62 + </>
  63 + ) : (
  64 + <Button
  65 + style={{ marginTop: 8 }}
  66 + type="link"
  67 + size="small"
  68 + // onClick={() => clickNode()}
  69 + >
  70 + 设置入参
  71 + </Button>
  72 + )}
26 73 </div>
27 74 );
28 75 };
... ...
1 1 export { default as Start } from './start';
2 2 export { default as End } from './end';
3 3 // export { default as Condition } from './condition';
4   -export { default as Loop } from './loop';
... ...
1   -import React, { useContext, memo } from 'react';
2   -import { useForm } from '@qx/form-render';
3   -import { useDrawer } from '@qx/flow';
4   -import { ConfigComponentFooter } from '../../components';
5   -import QxFormRender from '@/packages/qx-form-generator/src/form-render';
6   -import { loopSetting } from '../../setting-configs';
7   -import styles from './index.less';
8   -import type { IConfigComponent } from '@qx/flow';
9   -
10   -const LoopConfigComponent: React.FC<LoopConfigComponentProps> = (props) => {
11   - const form = useForm();
12   - const { closeDrawer: cancel, saveDrawer: save } = useDrawer();
13   -
14   - const onSave = async () => {
15   - try {
16   - await form.submit();
17   - const values = form.getValues();
18   - console.log('values', values);
19   - save(values);
20   - } catch (error) {
21   - console.log(error);
22   - }
23   - };
24   -
25   - return (
26   - <div className={styles['qx-flow-single-records-config']}>
27   - <QxFormRender form={form} schema={LoopSetting} widgets={{}} watch={{}} />
28   - <ConfigComponentFooter onSave={onSave} onCancel={cancel} />
29   - </div>
30   - );
31   -};
32   -
33   -interface LoopConfigComponentProps extends IConfigComponent {}
34   -
35   -export default memo(LoopConfigComponent);
1   -import React, { memo, useContext } from 'react';
2   -import { useAction } from '@qx/flow';
3   -import type { IDisplayComponent } from '@qx/flow';
4   -
5   -const ConditionDisplayComponent: React.FC<ConditionDisplayComponentProps> = (
6   - props,
7   -) => {
8   - return <>条件节点内容</>;
9   -};
10   -
11   -interface ConditionDisplayComponentProps extends IDisplayComponent {}
12   -
13   -export default memo(ConditionDisplayComponent);
1   -import ConfigComponent from './configComponent';
2   -import DisplayComponent from './displayComponent';
3   -
4   -export default {
5   - // DisplayComponent,
6   - // ConfigComponent,
7   -};
1   -import React, {
2   - useContext,
3   - memo,
4   - useState,
5   - useEffect,
6   - useImperativeHandle,
7   -} from 'react';
8   -import { Checkbox, Form, Input, Radio, Space, Tooltip } from 'antd';
9   -import type { CheckboxChangeEvent, RadioChangeEvent } from 'antd/es/checkbox';
10   -
  1 +import React, { memo, useState, useEffect, useImperativeHandle } from 'react';
  2 +import { Checkbox, Form, Radio, Space, Tooltip } from 'antd';
  3 +import type { RadioChangeEvent } from 'antd';
  4 +import type { CheckboxChangeEvent } from 'antd/es/checkbox';
11 5 import type { IConfigComponent } from '@qx/flow';
12 6 import { QxParameterSetting } from '@qx/common';
13 7 import { QxIcon } from '@/components';
14   -import _ from 'lodash';
  8 +import { isEmpty, isEqual, cloneDeep } from 'lodash-es';
  9 +
  10 +const propagationList: {
  11 + value: string;
  12 + label: string;
  13 + tips: string;
  14 +}[] = [
  15 + {
  16 + value: 'REQUIRED',
  17 + label: '需要事务',
  18 + tips: '如果当前存在事务,则加入该事务;如果不存在事务,则创建一个新的事务',
  19 + },
  20 + {
  21 + value: 'SUPPORTS',
  22 + label: '支持当前事务',
  23 + tips: '如果当前存在事务,则加入该事务;如果不存在事务,则直接执行',
  24 + },
  25 + {
  26 + value: 'REQUIRES_NEW',
  27 + label: '新建事务',
  28 + tips: '不管当前是否存在事务,必定创建一个新事务,如果当前存在事务这个事务会被挂起。新事务在层级上与之前的事务是平级的,两者互不干扰',
  29 + },
  30 +];
  31 +
  32 +const isolationList: {
  33 + value: string;
  34 + label: string;
  35 + tips: string;
  36 +}[] = [
  37 + {
  38 + value: 'READ_UNCOMMITTED',
  39 + label: '读未提交',
  40 + tips: '可以读到其它事务未提交的数据',
  41 + },
  42 + {
  43 + value: 'READ_COMMITTED',
  44 + label: '已提交读取',
  45 + tips: '可以读到其它事务已提交的数据',
  46 + },
  47 + {
  48 + value: 'REPEATABLE_READ',
  49 + label: '可重复读取',
  50 + tips: '不会读到其它事务已提交的数据',
  51 + },
  52 + {
  53 + value: 'SERIALIZABLE',
  54 + label: '可串行化的',
  55 + tips: '串行化读',
  56 + },
  57 +];
15 58
16   -import { isolationList, propagationList } from '../../setting-configs/start';
17 59 interface PropagationSettingProps {
18 60 value: string;
19 61 onChange: (val: string) => void;
... ... @@ -63,29 +105,24 @@ const StartConfigComponent: React.FC<StartConfigComponentProps> =
63 105 }));
64 106
65 107 const [values, setValues] = useState<{
66   - params: any[];
67   - enablePropagation: boolean;
68   - propagation: string;
69   - isolation: string;
70   - }>({
71   - params: [],
72   - enablePropagation: false,
73   - propagation: 'REQUIRED',
74   - isolation: 'REPEATABLE_READ',
75   - });
76   -
  108 + params?: any[];
  109 + enablePropagation?: boolean;
  110 + propagation?: string;
  111 + isolation?: string;
  112 + }>();
77 113 useEffect(() => {
78   - if (_.isEmpty(props?.node?.data)) {
  114 + if (isEmpty(props?.node?.data)) {
79 115 return;
80 116 }
81   - if (_.isEqual(props?.node?.data, values)) {
  117 + if (isEqual(props?.node?.data, values)) {
82 118 return;
83 119 }
84   - setValues(props?.node?.data);
85   - }, [props?.node?.data]);
  120 + setValues({ ...props?.node?.data });
  121 + form.setFieldsValue({ ...props?.node?.data });
  122 + }, [JSON.stringify(props?.node?.data)]);
86 123
87 124 const onCheckedChange = (e: CheckboxChangeEvent) => {
88   - const _cloneVal = _.cloneDeep(values);
  125 + const _cloneVal = !!values ? cloneDeep(values) : {};
89 126 setValues({
90 127 ..._cloneVal,
91 128 enablePropagation: e.target.checked,
... ... @@ -93,11 +130,11 @@ const StartConfigComponent: React.FC<StartConfigComponentProps> =
93 130 };
94 131
95 132 useEffect(() => {
96   - if (_.isEqual(props?.node?.data, values)) {
  133 + if (!values || isEqual(props?.node?.data, values)) {
97 134 return;
98 135 }
99 136 props.onChange(values);
100   - }, [values]);
  137 + }, [JSON.stringify(values)]);
101 138
102 139 return (
103 140 <Form
... ... @@ -109,37 +146,55 @@ const StartConfigComponent: React.FC<StartConfigComponentProps> =
109 146 isolation: 'REPEATABLE_READ',
110 147 }}
111 148 >
112   - <Form.Item name="params">
  149 + <Form.Item
  150 + style={{
  151 + marginBottom: '24px',
  152 + }}
  153 + name="params"
  154 + >
113 155 <h3 className={'qx-flow-form__label-title'}>入参设置</h3>
114 156 <p className={'qx-flow-form__label-tips'}>
115 157 参数可以被后面的所有数据流节点使用
116 158 </p>
117 159 <QxParameterSetting
118   - value={values.params}
  160 + // @ts-ignore
  161 + value={values?.params || []}
119 162 onChange={(_v: any) => {
120   - console.log('参数 === ', _v);
  163 + const _cloneVal = cloneDeep(values);
  164 + setValues({
  165 + ..._cloneVal,
  166 + params: _v,
  167 + });
121 168 }}
122 169 />
123 170 </Form.Item>
124   - <Form.Item name="enablePropagation">
  171 + <Form.Item
  172 + style={{
  173 + marginBottom: '16px',
  174 + }}
  175 + name="enablePropagation"
  176 + >
125 177 <h3 className={'qx-flow-form__label-title'}>事务控制</h3>
126 178 <Checkbox
127   - checked={values.enablePropagation}
  179 + checked={values?.enablePropagation}
128 180 onChange={onCheckedChange}
129 181 >
130 182 设置事务的传播行为和隔离级别
131 183 </Checkbox>
132 184 </Form.Item>
133 185 <Form.Item
134   - hidden={!values.enablePropagation}
  186 + hidden={!values?.enablePropagation}
135 187 label="事务传播行为"
136 188 name="propagation"
  189 + style={{
  190 + marginBottom: '16px',
  191 + }}
137 192 >
138 193 <PropagationSetting
139 194 optionsList={propagationList}
140   - value={'REQUIRED'}
  195 + value={values?.propagation || 'REQUIRED'}
141 196 onChange={(_v: string) => {
142   - const _cloneVal = _.cloneDeep(values);
  197 + const _cloneVal = cloneDeep(values);
143 198 setValues({
144 199 ..._cloneVal,
145 200 propagation: _v,
... ... @@ -148,15 +203,15 @@ const StartConfigComponent: React.FC<StartConfigComponentProps> =
148 203 />
149 204 </Form.Item>
150 205 <Form.Item
151   - hidden={!values.enablePropagation}
  206 + hidden={!values?.enablePropagation}
152 207 label="事务隔离级别"
153 208 name="isolation"
154 209 >
155 210 <PropagationSetting
156 211 optionsList={isolationList}
157   - value={'REPEATABLE_READ'}
  212 + value={values?.isolation || 'REPEATABLE_READ'}
158 213 onChange={(_v: string) => {
159   - const _cloneVal = _.cloneDeep(values);
  214 + const _cloneVal = cloneDeep(values);
160 215 setValues({
161 216 ..._cloneVal,
162 217 isolation: _v,
... ...
1 1 import React, { memo } from 'react';
2   -// import { ReactComponent as Icon } from '../../public/icons/outlined.svg';
  2 +import { Button, Typography } from 'antd';
  3 +import { useAction } from '@qx/flow';
  4 +const { Text } = Typography;
3 5 import type { IDisplayComponent, INode } from '@qx/flow';
4   -// import './index.less';
  6 +
  7 +const paramsEnums: Record<string, string> = {
  8 + STRING: '文本',
  9 + NUMBER: '数字',
  10 + TIME: '日期',
  11 + BOOL: '布尔',
  12 + OBJECT: '对象',
  13 + ARRAY: '数组',
  14 + ANNEX: '附件',
  15 + PIC: '图片',
  16 + FORM: '表单',
  17 + USER: '人员',
  18 + ORG: '部门',
  19 +};
5 20
6 21 const DisplayComponent: React.FC<DisplayComponentProps> = (props) => {
7 22 const { node, nodes } = props;
... ... @@ -11,6 +26,8 @@ const DisplayComponent: React.FC<DisplayComponentProps> = (props) => {
11 26 props.onChange?.([...nodes]);
12 27 };
13 28
  29 + const { clickNode } = useAction();
  30 +
14 31 return (
15 32 <div className="qx-flow-default-node">
16 33 <div className="qx-flow-default-node__header">
... ... @@ -21,13 +38,38 @@ const DisplayComponent: React.FC<DisplayComponentProps> = (props) => {
21 38 <span className="qx-flow-default-node__title--name">{node.name}</span>
22 39 </span>
23 40 </div>
24   - <div className="qx-flow-default-node__content">
25   - {!node.data ? (
26   - <span className="qx-flow-end-node__button">设置入参</span>
27   - ) : (
28   - <span>节点配置内容</span>
29   - )}
30   - </div>
  41 + {!!node?.data?.params?.length ? (
  42 + <>
  43 + <div className="qx-flow-default-node__content">
  44 + {props?.node?.data?.params.map((_v: any) => {
  45 + return (
  46 + <Text
  47 + style={{
  48 + width: '100%',
  49 + lineHeight: '22px',
  50 + }}
  51 + ellipsis={{
  52 + tooltip: `${paramsEnums?.[_v.type || '']}&nbsp;${
  53 + _v.title || '未命名'
  54 + }`,
  55 + }}
  56 + >
  57 + {paramsEnums?.[_v.type || '']}&nbsp;{_v.title || '未命名'}
  58 + </Text>
  59 + );
  60 + })}
  61 + </div>
  62 + </>
  63 + ) : (
  64 + <Button
  65 + style={{ marginTop: 8 }}
  66 + type="link"
  67 + size="small"
  68 + // onClick={() => clickNode()}
  69 + >
  70 + 设置入参
  71 + </Button>
  72 + )}
31 73 </div>
32 74 );
33 75 };
... ...
... ... @@ -9,8 +9,9 @@ import { QxIcon } from '@/components';
9 9 import { isEmpty } from 'lodash-es';
10 10 import { handleWindowOpen } from '@qx/utils';
11 11 // import {} from '@/src/services/data-flow';
12   -import { getIcon, useFlowTableScrollY } from '@/utils';
  12 +import { getIcon } from '@/utils';
13 13 import { useDebounceEffect } from 'ahooks';
  14 +import { useFlowTableScrollY } from '@/hooks';
14 15
15 16 const { Text } = Typography;
16 17
... ...
... ... @@ -16,7 +16,8 @@ import { useDebounceEffect, useDebounceFn } from 'ahooks';
16 16 import { isEmpty, cloneDeep } from 'lodash-es';
17 17
18 18 import { FlowSettingProps } from '@/page/view/constant';
19   -import { getIcon, useFlowTableScrollY } from '@/utils';
  19 +import { getIcon } from '@/utils';
  20 +import { useFlowTableScrollY } from '@/hooks';
20 21 import actions from '@/utils/actions';
21 22
22 23 import { copyProcessById, deleteProcessById, getListProcess } from '@/services';
... ...
1 1 import React from 'react';
2 2 // import { history } from '@@/core/history';
3   -import { useSearchParams } from 'react-router-dom';
  3 +import { useSearchParams } from '@/hooks';
4 4 import { useTitle } from 'ahooks';
5 5 // @ts-ignore;
6 6 import { handleWindowOpen } from '@qx/utils';
... ... @@ -13,16 +13,12 @@ import styles from '@/page/view/index.module.less';
13 13 const prefix = 'qx-data-flow';
14 14
15 15 const DataFlowView: React.FC = ({}) => {
16   - const [searchParams] = useSearchParams();
  16 + const [query] = useSearchParams<any>();
17 17 const {
18 18 appId, // 应用id
19 19 funCode, // 表单id
20 20 returnUrl, // 来自页面跳转返回可跳转
21   - } = {
22   - appId: searchParams.get('appId'),
23   - funCode: searchParams.get('funCode'),
24   - returnUrl: searchParams.get('returnUrl'),
25   - };
  21 + } = query;
26 22
27 23 // 添加标题
28 24 if (!!appId && !funCode) {
... ...
... ... @@ -44,94 +44,3 @@ export const getIcon = (icon: string, type?: string) => {
44 44 );
45 45 }
46 46 };
47   -
48   -// 表格 Scroll 高度计算
49   -export const useFlowTableScrollY = (
50   - deps: {
51   - columns: any[];
52   - size?: 'small' | 'middle' | 'default';
53   - tableBoxClassName?: string;
54   - classNames?: string[]; // 表格DOM内嵌元素 列名 添加在此,
55   - hasPagination?: boolean;
56   - listProps?: any;
57   - } = {
58   - size: 'small',
59   - tableBoxClassName: '',
60   - classNames: [],
61   - hasPagination: false,
62   - columns: [],
63   - listProps: {},
64   - },
65   -) => {
66   - const itemHeaderHeight =
67   - (deps?.size === 'middle' ? 48 : deps?.size === 'default' ? 56 : 40) + 1;
68   - const TABLE_VIEW_LIST = deps?.tableBoxClassName || 'qx-data-flow-table';
69   - let tableHeader = itemHeaderHeight;
70   - const tableViewListDefaultHeight = 400;
71   - const defaultPagePadding = 0;
72   -
73   - const $ = (selectors: string) =>
74   - document.querySelector<HTMLElement>(selectors);
75   -
76   - const defaultScrollY = useMemo(
77   - () => document.body.clientHeight,
78   - [tableHeader],
79   - );
80   -
81   - const [scrollY, setScrollY] = useState<number>(defaultScrollY ?? 200);
82   -
83   - const timer = useRef<NodeJS.Timer>();
84   -
85   - const getScrollY = () => {
86   - const tableViewList = $(`.${TABLE_VIEW_LIST}`);
87   -
88   - const tableViewListClientHeight =
89   - tableViewList?.clientHeight || tableViewListDefaultHeight;
90   - // 分页大小 目前已经固定 所以直接用56px
91   - const antPaginationHeight = deps?.hasPagination ? 56 : 0;
92   -
93   - const _domHeightByClassName = (deps?.classNames || []).map(
94   - (_v: string) => $(`.${_v}`)?.clientHeight ?? 0,
95   - );
96   - let result =
97   - tableViewListClientHeight -
98   - tableHeader -
99   - defaultPagePadding -
100   - antPaginationHeight;
101   - if (!!_domHeightByClassName?.length) {
102   - result = result - eval(_domHeightByClassName.join('+'));
103   - }
104   -
105   - if (tableViewList) {
106   - tableViewList.style.overflowY = result < 200 ? 'auto' : 'hidden';
107   - }
108   -
109   - setScrollY(result < 100 ? 100 : result);
110   - };
111   -
112   - const observer = () => {
113   - window.addEventListener('resize', getScrollY);
114   - };
115   -
116   - const removeObserver = () => {
117   - if (timer.current) window.clearTimeout(timer.current);
118   - window.removeEventListener('resize', getScrollY);
119   - };
120   -
121   - useEffect(() => {
122   - observer();
123   - return () => {
124   - removeObserver();
125   - };
126   - }, [tableHeader]);
127   -
128   - useEffect(() => {
129   - if (deps) {
130   - timer.current = setTimeout(() => {
131   - getScrollY();
132   - }, 100);
133   - }
134   - }, [JSON.stringify(deps)]);
135   -
136   - return [scrollY, getScrollY];
137   -};
... ...
... ... @@ -11,14 +11,13 @@ import {
11 11 Avatar,
12 12 } from 'antd';
13 13
14   -import { SettingOutlined } from '@ant-design/icons/lib';
15   -import { useSearchParams } from 'react-router-dom';
  14 +import { useSearchParams } from '@/hooks';
16 15 import { useTitle } from 'ahooks';
17 16 import { QxIcon } from '@/components';
18 17 import { handleWindowOpen } from '@qx/utils';
19 18 import { FlowHeader, FlowVersion } from '@/components';
20 19
21   -import { useFlowTableScrollY } from '@/utils';
  20 +import { useFlowTableScrollY } from '@/hooks';
22 21 import actions from '@/utils/actions';
23 22
24 23 import { isEmpty, cloneDeep } from 'lodash-es';
... ... @@ -33,17 +32,12 @@ import { FlowVersionStatusEnums } from '@/interface';
33 32 const prefix = 'qx-flow-setting';
34 33
35 34 const DataFlowVersion: React.FC = ({}) => {
36   - // @ts-ignore
37   - const [searchParams] = useSearchParams();
  35 + const [query] = useSearchParams<any>();
38 36 const {
39 37 processId, // 流程ID
40 38 name, // 流程名称
41 39 returnUrl, // 来自页面跳转返回可跳转
42   - } = {
43   - processId: searchParams.get('processId'),
44   - name: searchParams.get('name'),
45   - returnUrl: searchParams.get('returnUrl'),
46   - };
  40 + } = query;
47 41 const [pageData, setPageData] = useState<any[]>([]);
48 42 const [tableLoading, setTableLoading] = useState<boolean>(true); // 表格loading
49 43 // 表格是否添加scroll 属性
... ...
1 1 import { createHashRouter, RouterProvider } from 'react-router-dom';
2 2 import Root from '../page/root';
3   -import About from '../page/about';
4   -import Designer from '../page/designer';
5   -import List from '../page/view/list';
6   -import Version from '../page/view/version';
  3 +import lazyComponent from '@/components/lazy-component';
7 4
8 5 export default () => (
9 6 <RouterProvider
... ... @@ -14,19 +11,27 @@ export default () => (
14 11 children: [
15 12 {
16 13 path: '/about',
17   - element: <About />,
  14 + element: lazyComponent(
  15 + () => import(/*qx-dataflow-about*/ '@/page/about'),
  16 + ),
18 17 },
19 18 {
20 19 path: '/designer',
21   - element: <Designer />,
  20 + element: lazyComponent(
  21 + () => import(/*qx-dataflow-designer*/ '@/page/designer'),
  22 + ),
22 23 },
23 24 {
24 25 path: '/list',
25   - element: <List />,
  26 + element: lazyComponent(
  27 + () => import(/*qx-dataflow-list*/ '@/page/view/list'),
  28 + ),
26 29 },
27 30 {
28 31 path: '/version',
29   - element: <Version />,
  32 + element: lazyComponent(
  33 + () => import(/*qx-dataflow-version*/ '@/page/view/version'),
  34 + ),
30 35 },
31 36 ],
32 37 },
... ...
... ... @@ -4,6 +4,7 @@ import request from '@/request';
4 4 const qxSdk = new QxSdk();
5 5
6 6 qxSdk.registerSdk({
  7 + // @ts-ignore
7 8 getFormFields(appCode: string, funCode: string, viewCode: string) {
8 9 return request.get(
9 10 `/qx-apaas-lowcode/app/${appCode}/form/${funCode}/field/option/${viewCode}?withRel=true`,
... ...
1   -import React, { useEffect, useMemo, useRef, useState } from 'react';
2   -
3   -import { Button, Image, message, Modal, Tooltip, Upload } from 'antd';
  1 +import { Image, Skeleton } from 'antd';
4 2 import { QxIcon } from '@/components';
5 3
6   -import defaultImg from '@/components/default/default_cover.png';
  4 +import defaultImg from '@/public/imgs/default_cover.png';
7 5
8 6 const defaultIcon: Record<string, string> = {
9 7 form: 'icon-app-file-fill',
... ... @@ -44,94 +42,3 @@ export const getIcon = (icon: string, type?: string) => {
44 42 );
45 43 }
46 44 };
47   -
48   -// 表格 Scroll 高度计算
49   -export const useFlowTableScrollY = (
50   - deps: {
51   - columns: any[];
52   - size?: 'small' | 'middle' | 'default';
53   - tableBoxClassName?: string;
54   - classNames?: string[]; // 表格DOM内嵌元素 列名 添加在此,
55   - hasPagination?: boolean;
56   - listProps?: any;
57   - } = {
58   - size: 'small',
59   - tableBoxClassName: '',
60   - classNames: [],
61   - hasPagination: false,
62   - columns: [],
63   - listProps: {},
64   - },
65   -) => {
66   - const itemHeaderHeight =
67   - (deps?.size === 'middle' ? 48 : deps?.size === 'default' ? 56 : 40) + 1;
68   - const TABLE_VIEW_LIST = deps?.tableBoxClassName || 'qx-data-flow-table';
69   - let tableHeader = itemHeaderHeight;
70   - const tableViewListDefaultHeight = 400;
71   - const defaultPagePadding = 0;
72   -
73   - const $ = (selectors: string) =>
74   - document.querySelector<HTMLElement>(selectors);
75   -
76   - const defaultScrollY = useMemo(
77   - () => document.body.clientHeight,
78   - [tableHeader],
79   - );
80   -
81   - const [scrollY, setScrollY] = useState<number>(defaultScrollY ?? 200);
82   -
83   - const timer = useRef<NodeJS.Timer>();
84   -
85   - const getScrollY = () => {
86   - const tableViewList = $(`.${TABLE_VIEW_LIST}`);
87   -
88   - const tableViewListClientHeight =
89   - tableViewList?.clientHeight || tableViewListDefaultHeight;
90   - // 分页大小 目前已经固定 所以直接用56px
91   - const antPaginationHeight = deps?.hasPagination ? 56 : 0;
92   -
93   - const _domHeightByClassName = (deps?.classNames || []).map(
94   - (_v: string) => $(`.${_v}`)?.clientHeight ?? 0,
95   - );
96   - let result =
97   - tableViewListClientHeight -
98   - tableHeader -
99   - defaultPagePadding -
100   - antPaginationHeight;
101   - if (!!_domHeightByClassName?.length) {
102   - result = result - eval(_domHeightByClassName.join('+'));
103   - }
104   -
105   - if (tableViewList) {
106   - tableViewList.style.overflowY = result < 200 ? 'auto' : 'hidden';
107   - }
108   -
109   - setScrollY(result < 100 ? 100 : result);
110   - };
111   -
112   - const observer = () => {
113   - window.addEventListener('resize', getScrollY);
114   - };
115   -
116   - const removeObserver = () => {
117   - if (timer.current) window.clearTimeout(timer.current);
118   - window.removeEventListener('resize', getScrollY);
119   - };
120   -
121   - useEffect(() => {
122   - observer();
123   - return () => {
124   - removeObserver();
125   - };
126   - }, [tableHeader]);
127   -
128   - useEffect(() => {
129   - if (deps) {
130   - timer.current = setTimeout(() => {
131   - getScrollY();
132   - }, 100);
133   - }
134   - }, [JSON.stringify(deps)]);
135   -
136   - return [scrollY, getScrollY];
137   -};
... ...