Commit 9b76daed9b63167790bc919bdcbe10372ee4bda0

Authored by 邱嘉伟
1 parent 94859ef5

feat: 增加参数设计器 高级(不含默认值组件 待迁)

... ... @@ -17,7 +17,6 @@
17 17 "lint": "npm run lint:es && npm run lint:css",
18 18 "lint:css": "stylelint \"{src,test}/**/*.{css,less}\"",
19 19 "lint:es": "eslint \"{src,test}/**/*.{js,jsx,ts,tsx}\"",
20   - "prepare": "husky install && dumi setup",
21 20 "prepublishOnly": "father doctor && npm run build",
22 21 "start": "npm run dev"
23 22 },
... ... @@ -46,7 +45,12 @@
46 45 "dependencies": {
47 46 "@ant-design/icons": "^5.2.5",
48 47 "@qx/ui": "0.0.3-beta.1",
49   - "lodash-es": "^4.17.21"
  48 + "ahooks": "^3.7.8",
  49 + "codemirror": "^5.65.15",
  50 + "lodash-es": "^4.17.21",
  51 + "moment": "^2.29.4",
  52 + "react-codemirror2": "^7.2.1",
  53 + "umi-request": "^1.4.0"
50 54 },
51 55 "devDependencies": {
52 56 "@commitlint/cli": "^17.1.2",
... ...
  1 +export * from './qx-parameter-setting';
1 2 export * from './qx-sort-condition';
  3 +// export * from './qx-filter-condition';
  4 +// export * from './qx-btn';
  5 +// export { default as FieldSetter } from './qx-field-setter';
... ...
  1 +/* eslint-disable array-callback-return */
  2 +/* eslint-disable eqeqeq */
  3 +import {
  4 + DeleteOutlined,
  5 + PlusOutlined,
  6 + SearchOutlined,
  7 + SisternodeOutlined,
  8 + SnippetsOutlined,
  9 +} from '@ant-design/icons';
  10 +import {
  11 + Button,
  12 + Col,
  13 + DatePicker,
  14 + Form,
  15 + Input,
  16 + InputNumber,
  17 + Modal,
  18 + Row,
  19 + Select,
  20 + Space,
  21 + Table,
  22 + message,
  23 +} from 'antd';
  24 +import type { FormInstance } from 'antd/es/form';
  25 +import React, {
  26 + useCallback,
  27 + useContext,
  28 + useEffect,
  29 + useRef,
  30 + useState,
  31 +} from 'react';
  32 +import JSONEditor from './codeMirror';
  33 +import './style.less';
  34 +// import { FieldSetter } from '@qx/common';
  35 +import { formatEnum } from './constant';
  36 +// import {
  37 +// typeTranslateFieIdtype,
  38 +// typeTranslateWidget,
  39 +// typeTranslateGrouptype,
  40 +// typeTranslateItemtype,
  41 +// } from './constant';
  42 +// import { Controlled as CodeMirror } from 'react-codemirror2'
  43 +import _ from 'lodash';
  44 +import moment from 'moment';
  45 +const valueOptions = [
  46 + { key: 'STRING', title: '文本' },
  47 + { key: 'NUMBER', title: '数字' },
  48 + { key: 'TIME', title: '日期' },
  49 + { key: 'BOOL', title: '布尔' },
  50 + { key: 'OBJECT', title: '对象' },
  51 + { key: 'ARRAY', title: '数组' },
  52 + { key: 'ANNEX', title: '附件' },
  53 + { key: 'PIC', title: '图片' },
  54 + { key: 'FORM', title: '表单' },
  55 + { key: 'USER', title: '人员' },
  56 + { key: 'ORG', title: '部门' },
  57 +];
  58 +
  59 +const timeFormat = [
  60 + { lable: '年', value: 'YEAR' },
  61 + { lable: '年-月', value: 'YEAR_MONTH' },
  62 + { lable: '年-月-日', value: 'YEAR_DATE' },
  63 + { lable: '年-月-日 时', value: 'YEAR_HOUR' },
  64 + { lable: '年-月-日 时:分', value: 'YEAR_MIN' },
  65 + { lable: '年-月-日 时:分:秒', value: 'YEAR_SEC' },
  66 +];
  67 +
  68 +interface ParameterSettingProps {
  69 + nodeItem?: any;
  70 + inputKey: any;
  71 + data: any;
  72 + treeData: any;
  73 + visible: boolean;
  74 + handleCancel: (val: any) => void;
  75 + handleChangeField: (val?: any, data?: any) => void;
  76 + handleChange: (e?: any, data?: any, code?: string) => void;
  77 + handleDrop: (val: any) => void;
  78 + handleAddtree: (val: any) => void;
  79 + handleAdd: (val: any) => void;
  80 + handleDelete: (val: any) => void;
  81 +}
  82 +const EditableContext = React.createContext<FormInstance<any> | null>(null);
  83 +
  84 +const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
  85 + console.log('onChange', e);
  86 + e.persist();
  87 + const { value } = e.target;
  88 + console.log('onChange value', value);
  89 +
  90 + // if (!value) {
  91 + // setExpandedKeys(undefined);
  92 + // setAutoExpandParent(false);
  93 + // setSearchValue(value);
  94 + // return;
  95 + // }
  96 + // const newExpandedKeys = (list || [])
  97 + // .map((item) => {
  98 + // if (item.title.indexOf(value) > -1 || item.code.indexOf(value) > -1) {
  99 + // return getParentKey(item.id, treeData);
  100 + // }
  101 + // return null;
  102 + // })
  103 + // .filter((item, i, self) => item && self.indexOf(item) === i);
  104 + // setExpandedKeys(newExpandedKeys as React.Key[]);
  105 + // setSearchValue(value);
  106 + // setAutoExpandParent(true);
  107 +};
  108 +
  109 +const ParameterModal: React.FC<ParameterSettingProps> = (props) => {
  110 + const {
  111 + visible,
  112 + data,
  113 + treeData,
  114 + handleCancel,
  115 + handleDrop,
  116 + handleAdd,
  117 + handleAddtree,
  118 + handleDelete,
  119 + handleChange,
  120 + // handleChangeField,
  121 + inputKey,
  122 + } = props;
  123 + console.log('data', data);
  124 + // const [form] = Form.useForm()
  125 +
  126 + //判断数组是否只有一个子节点
  127 + const checkShowAdd = (_data: any) => {
  128 + const _newTreeData = _.cloneDeep(treeData);
  129 + if (!!_data.pid) {
  130 + const pidIndex = _newTreeData.findIndex(
  131 + (item: any) => item.id === _data.pid,
  132 + );
  133 + if (_newTreeData[pidIndex].type == 'ARRAY') {
  134 + return false;
  135 + }
  136 + }
  137 + return true;
  138 + };
  139 +
  140 + const checkShowTree = (_data: any) => {
  141 + if (_data.type == 'ARRAY') {
  142 + if (_data.child && _data.child.length > 0) {
  143 + return false;
  144 + }
  145 + }
  146 + return true;
  147 + };
  148 +
  149 + const columns = [
  150 + {
  151 + title: (
  152 + <div style={{ display: 'flex', flexDirection: 'row' }}>
  153 + <span style={{ color: 'red' }}>*</span>
  154 + <span>参数编码</span>
  155 + </div>
  156 + ),
  157 + dataIndex: 'code',
  158 + width: '15%',
  159 + editable: true,
  160 + key: 'code',
  161 + // render: (text, record) => (
  162 + // < Form.Item
  163 + // name={'code' + record.id}
  164 + // rules={
  165 + // [{
  166 + // required: true,
  167 + // message: '不能为空!',
  168 + // },
  169 + // ]}
  170 + // // initialValue={record.code}
  171 + // >
  172 + // <Input
  173 + // defaultValue={record.code}
  174 + // disabled={record.disabled} onBlur={(e) => props.handleChange(e, record, 'code')} />
  175 + // </Form.Item >
  176 + // ),
  177 + },
  178 + {
  179 + title: (
  180 + <div style={{ display: 'flex', flexDirection: 'row' }}>
  181 + <span style={{ color: 'red' }}>*</span>
  182 + <span>参数名</span>
  183 + </div>
  184 + ),
  185 + dataIndex: 'title',
  186 + width: '15%',
  187 + editable: true,
  188 + key: 'title',
  189 + // render: (text, record) => (
  190 + // <Form.Item
  191 + // name={'title' + record.id}
  192 + // rules={[
  193 + // {
  194 + // required: true,
  195 + // message: '不能为空!',
  196 + // },
  197 + // ]}
  198 + // // initialValue={record.title}
  199 + // >
  200 + // <Input
  201 + // defaultValue={record.title}
  202 + // disabled={record.disabled} onBlur={(e) => props.handleChange(e, record, 'title')} />
  203 + // </Form.Item>
  204 + // ),
  205 + },
  206 + {
  207 + title: (
  208 + <div style={{ display: 'flex', flexDirection: 'row' }}>
  209 + <span style={{ color: 'red' }}>*</span>
  210 + <span>参数类型</span>
  211 + </div>
  212 + ),
  213 + dataIndex: 'type',
  214 + editable: true,
  215 + width: '8%',
  216 + key: 'type',
  217 + render: (text) =>
  218 + // <Form.Item
  219 + // name={'type' + record.id}
  220 + // rules={[
  221 + // {
  222 + // required: true,
  223 + // message: '不能为空!',
  224 + // },
  225 + // ]}
  226 + // initialValue={record.type}
  227 + // >
  228 + // <Select
  229 + // disabled={record.disabled}
  230 + // onSelect={(e) => handleChange(e, record, 'type')} >
  231 + valueOptions.map((item) => {
  232 + if (text == item.key) {
  233 + return <span key={item.key}>{item.title}</span>;
  234 + }
  235 + }),
  236 + // </Select>
  237 + // </Form.Item>
  238 + },
  239 + {
  240 + title: '取值范围',
  241 + dataIndex: 'qxProps',
  242 + editable: true,
  243 + key: 'qxProps',
  244 + render: (text, record) => (
  245 + <div key={record.id}>
  246 + <span>
  247 + {record.type == 'TIME'
  248 + ? moment(text?.min).format(
  249 + formatEnum[text?.format] || 'YYYY-MM-DD',
  250 + )
  251 + : text?.min}
  252 + </span>
  253 + {text?.min && (
  254 + <Space style={{ marginLeft: 5, marginRight: 5 }}>-</Space>
  255 + )}
  256 + <span>
  257 + {record.type == 'TIME'
  258 + ? moment(text?.max).format(
  259 + formatEnum[text?.format] || 'YYYY-MM-DD',
  260 + )
  261 + : text?.max}
  262 + </span>
  263 + </div>
  264 + // <Form.Item
  265 + // name={'qxProps' + record.id}
  266 + // >
  267 + // <>
  268 + // <Input disabled={record.disabled} defaultValue={text?.min} onBlur={(e) => props.handleChange(e, record, 'qxProps-min')} style={{ width: '45%' }} />
  269 + // &nbsp; - &nbsp;
  270 + // <Input disabled={record.disabled} defaultValue={text?.max} onBlur={(e) => props.handleChange(e, record, 'qxProps-max')} style={{ width: '45%' }} />
  271 + // </>
  272 + // </Form.Item>
  273 + ),
  274 + },
  275 + {
  276 + title: '必填',
  277 + dataIndex: 'required',
  278 + editable: true,
  279 + key: 'required',
  280 + width: '5%',
  281 + render: (text, record) => (
  282 + <span key={record.id}>{text ? '是' : '否'}</span>
  283 + // <Form.Item
  284 + // name={'required' + record.id}
  285 + // initialValue={record.required}
  286 + // >
  287 + // <Select
  288 + // disabled={record.disabled}
  289 + // onSelect={(e) => props.handleChange(e, record, 'required')}
  290 + // >
  291 + // <Select.Option value={true}>是</Select.Option>
  292 + // <Select.Option value={false}>否</Select.Option>
  293 + // </Select>
  294 + // </Form.Item>
  295 + ),
  296 + },
  297 + {
  298 + title: '默认值',
  299 + dataIndex: 'qxProps',
  300 + width: '10%',
  301 + editable: true,
  302 + key: 'qxProps',
  303 + render: (text, record) => (
  304 + // console.log('text', text)
  305 + <span key={record.id}>{text?.default}</span>
  306 +
  307 + // <Form.Item
  308 + // name={'default' + record.id}
  309 + // initialValue={text?.default}
  310 + // >
  311 + // <Input disabled={record.disabled} onBlur={(e) => props.handleChange(e, record, 'qxProps-default')} />
  312 + // </Form.Item>
  313 + ),
  314 + },
  315 + {
  316 + title: '参数说明',
  317 + dataIndex: 'description',
  318 + editable: true,
  319 + width: '10%',
  320 + key: 'description',
  321 + render: (text, record) => (
  322 + <span key={record.id}>{text}</span>
  323 + // <span key={record.id}>{text?.remark}</span>
  324 +
  325 + // // <Form.Item
  326 + // // name={'remark' + record.id}
  327 + // // initialValue={text?.remark}
  328 + // // >
  329 + // // <Input disabled={record.disabled} onBlur={(e) => props.handleChange(e, record, 'qxProps-remark')} />
  330 + // // </Form.Item>
  331 + ),
  332 + },
  333 + {
  334 + title: '操作',
  335 + key: 'action',
  336 + width: '10%',
  337 + render: (text, record) => {
  338 + const isShowAdd = (record && checkShowAdd(record)) || true;
  339 + const isShowTree = (record && checkShowTree(record)) || true;
  340 + return (
  341 + <Space size="small">
  342 + {isShowAdd && (
  343 + <Button
  344 + type="link"
  345 + disabled={record.disabled}
  346 + icon={<PlusOutlined />}
  347 + onClick={() => handleAdd(record.pid)}
  348 + />
  349 + )}
  350 + {(record.type === 'OBJECT' || record.type === 'ARRAY') &&
  351 + isShowTree && (
  352 + <Button
  353 + type="link"
  354 + disabled={record.disabled}
  355 + icon={<SisternodeOutlined />}
  356 + onClick={() => handleAddtree(record.id)}
  357 + />
  358 + )}
  359 + <Button
  360 + type="link"
  361 + className="btn-high-del"
  362 + disabled={record.disabled}
  363 + icon={<DeleteOutlined />}
  364 + onClick={() => handleDelete(record)}
  365 + />
  366 + </Space>
  367 + );
  368 + },
  369 + },
  370 + ];
  371 +
  372 + interface EditableRowProps {
  373 + index: number;
  374 + }
  375 +
  376 + const EditableRow: React.FC<EditableRowProps> = ({ ..._props }) => {
  377 + const [form] = Form.useForm();
  378 + return (
  379 + <Form form={form} component={false}>
  380 + <EditableContext.Provider value={form}>
  381 + <tr {..._props} />
  382 + </EditableContext.Provider>
  383 + </Form>
  384 + );
  385 + };
  386 +
  387 + interface EditableCellProps {
  388 + title: React.ReactNode;
  389 + editable: boolean;
  390 + children: React.ReactNode;
  391 + dataIndex: keyof any;
  392 + record: any;
  393 + // handleSave: (record: Item) => void;
  394 + }
  395 +
  396 + const EditableCell: React.FC<EditableCellProps> = ({
  397 + title,
  398 + editable,
  399 + children,
  400 + dataIndex,
  401 + record,
  402 + index,
  403 + ...restProps
  404 + }) => {
  405 + const [editing, setEditing] = useState(false);
  406 + const inputRef = useRef<any>(null);
  407 + const form = useContext(EditableContext)!;
  408 + const qxProps = record?.qxProps || {};
  409 + // const [currentNode, setCurrentNode] = useState<any>('');
  410 + // console.log('qxProps', qxProps)
  411 + // console.log('dataIndex', dataIndex)
  412 +
  413 + useEffect(() => {
  414 + if (editing) {
  415 + if (inputRef.current) {
  416 + // console.log('setEditing', inputRef)
  417 + inputRef.current!.focus();
  418 + }
  419 + }
  420 + }, [editing]);
  421 +
  422 + const toggleEdit = () => {
  423 + // if (_index != currentNode) {
  424 + // setEditing(!editing);
  425 + // }
  426 + // setCurrentNode(_index)
  427 + setEditing(!editing);
  428 + // if (dataIndex !== 'qxProps') {
  429 + form.setFieldsValue({ [dataIndex]: record[dataIndex] });
  430 + // }
  431 + };
  432 +
  433 + // const toggleEdit1 = (e) => {
  434 + // e.persist();
  435 + // // setCurrentNode(e.currentTarget)
  436 + // // console.log('e-onburl', e.currentTarget.key)
  437 + // //
  438 + // // if (e.currentTarget == e.target) {
  439 + // // // setEditing(!editing);
  440 + // // }
  441 + // // form.setFieldsValue({ [dataIndex]: record[dataIndex] });
  442 + // };
  443 +
  444 + // const toggleEdit2 = (e) => {
  445 + // e.persist();
  446 + // // console.log('e-onforce', e.currentTarget)
  447 +
  448 + // // e.dataTransfer.setData('text', e.target.getAttribute('data-row-key'));
  449 + // // console.log('currentTarget-fource', currentNode)
  450 + // // form.setFieldsValue({ [dataIndex]: record[dataIndex] });
  451 + // };
  452 +
  453 + const save = async (code: string) => {
  454 + const isProps = code.indexOf('qxProps');
  455 + const _newCode = isProps > -1 ? code.slice(8) : '';
  456 + // e.persist()
  457 + try {
  458 + const values = await form.validateFields();
  459 + const newValue = _newCode
  460 + ? values[dataIndex][_newCode]
  461 + : values[dataIndex];
  462 + props.handleChange(newValue, record, code);
  463 + // toggleEdit();
  464 + } catch (errInfo) {
  465 + console.log('Save failed:', errInfo);
  466 + }
  467 + };
  468 +
  469 + let childNode = children;
  470 +
  471 + // const rules = dataIndex == 'id' || 'title' || 'code' ?
  472 + // [{
  473 + // required: true,
  474 + // message: `不能为空!`,
  475 + // },] : []
  476 +
  477 + const qxPropsRange = () => {
  478 + switch (record.type) {
  479 + case 'STRING':
  480 + return (
  481 + <div
  482 + key={record.id}
  483 + ref={inputRef}
  484 + className="editable-center-cell"
  485 + /* onBlur={(e) => toggleEdit1(e)} onFocus={(e) => toggleEdit2(e)} */ tabIndex={
  486 + 0
  487 + }
  488 + >
  489 + <InputNumber
  490 + defaultValue={qxProps.min}
  491 + onBlur={() => save('qxProps-min')}
  492 + placeholder="最小长度"
  493 + />
  494 + &nbsp; - &nbsp;
  495 + <InputNumber
  496 + defaultValue={qxProps.max}
  497 + onBlur={() => save('qxProps-max')}
  498 + placeholder="最大长度"
  499 + />
  500 + </div>
  501 + );
  502 + case 'NUMBER':
  503 + return (
  504 + <div
  505 + key={record.id}
  506 + ref={inputRef}
  507 + className="editable-around-cell"
  508 + /* onBlur={(e) => toggleEdit1(e)} onFocus={(e) => toggleEdit2(e)} */ tabIndex={
  509 + 0
  510 + }
  511 + >
  512 + <div>
  513 + <InputNumber
  514 + defaultValue={qxProps.min}
  515 + onBlur={() => save('qxProps-min')}
  516 + style={{ width: '110px' }}
  517 + placeholder="最小值"
  518 + />
  519 + &nbsp; - &nbsp;
  520 + <InputNumber
  521 + defaultValue={qxProps.max}
  522 + onBlur={() => save('qxProps-max')}
  523 + style={{ width: '110px' }}
  524 + placeholder="最大值"
  525 + />
  526 + </div>
  527 + <InputNumber
  528 + defaultValue={qxProps.precision}
  529 + onBlur={() => save('qxProps-precision')}
  530 + placeholder="小数位数"
  531 + />
  532 + </div>
  533 + );
  534 + case 'TIME':
  535 + return (
  536 + <div
  537 + key={record.id}
  538 + ref={inputRef}
  539 + className="editable-around-cell"
  540 + /* onBlur={(e) => toggleEdit1(e)} onFocus={(e) => toggleEdit2(e)} */ tabIndex={
  541 + 0
  542 + }
  543 + >
  544 + <div>
  545 + <DatePicker
  546 + defaultValue={
  547 + qxProps?.min
  548 + ? moment(qxProps.min, formatEnum[qxProps?.format])
  549 + : undefined
  550 + }
  551 + format={formatEnum[qxProps?.format]}
  552 + // onChange={dateChange}
  553 + style={{ width: '130px' }}
  554 + onBlur={() => save('qxProps-min')}
  555 + showTime
  556 + placeholder="开始日期"
  557 + />
  558 + {/* <DatePicker defaultValue={moment(qxProps.min)} onBlur={() => save('qxProps-min')} placeholder='开始日期' /> */}
  559 + &nbsp; ~ &nbsp;
  560 + <DatePicker
  561 + defaultValue={
  562 + qxProps?.max
  563 + ? moment(qxProps.max, formatEnum[qxProps?.format])
  564 + : undefined
  565 + }
  566 + format={formatEnum[qxProps?.format]}
  567 + style={{ width: '130px' }}
  568 + // onChange={dateChange}
  569 + showTime
  570 + // onBlur={toggleEdit}
  571 + onSelect={(e) => props.handleChange(e, record, 'qxProps-max')}
  572 + placeholder="结束日期"
  573 + />
  574 + {/* <DatePicker defaultValue={moment(qxProps.max)} onBlur={() => save('qxProps-max')} placeholder='结束日期' /> */}
  575 + </div>
  576 + <Select
  577 + style={{ width: '90px' }}
  578 + placeholder="格式"
  579 + dropdownMatchSelectWidth={false}
  580 + defaultValue={qxProps.format}
  581 + onSelect={(e) =>
  582 + props.handleChange(e, record, 'qxProps-format')
  583 + }
  584 + >
  585 + {timeFormat.map((item) => {
  586 + return (
  587 + <Select.Option
  588 + style={{ width: '200px' }}
  589 + key={item.value}
  590 + value={item.value}
  591 + >
  592 + {item.lable}
  593 + </Select.Option>
  594 + );
  595 + })}
  596 + </Select>
  597 + </div>
  598 + );
  599 + default:
  600 + return (
  601 + <div
  602 + ref={inputRef}
  603 + /* onBlur={(e) => toggleEdit1(e)} */ tabIndex={0}
  604 + >
  605 + <Input placeholder="无" disabled />
  606 + </div>
  607 + );
  608 + }
  609 + };
  610 +
  611 + // const getValueOptions = (item: any): ValueOptionProps[] | undefined => {
  612 + // const widget = typeTranslateWidget(item.type);
  613 + // if (widget === 'userSelector') {
  614 + // return [];
  615 + // // return [{key: 'MYSELF', value: "当前用户"}]
  616 + // }
  617 + // if (widget === 'orgSelector') {
  618 + // // return [{key: 'MY_ORG', value: "当前人所在部门"}]
  619 + // return [];
  620 + // }
  621 + // if (widget === 'qxDatetime') {
  622 + // return [{ key: 'NOW', value: '当前时间' }];
  623 + // }
  624 + // return undefined;
  625 + // };
  626 +
  627 + const qxPropsDefault = () => {
  628 + return (
  629 + <div>
  630 + <Input
  631 + defaultValue={record?.qxProps?.default}
  632 + ref={inputRef}
  633 + onBlur={() => save('qxProps-default')}
  634 + />
  635 + {/* <FieldSetter
  636 + value={[{
  637 + type: typeTranslateItemtype(record.type),
  638 + value: record?.qxProps?.default
  639 + }]}
  640 + params={{ appCode: 'appCode', useId: true }}
  641 + valueOptions={getValueOptions(record)}
  642 + field={record.type}
  643 + widget={typeTranslateWidget(record.type)}
  644 + fieldType={typeTranslateFieIdtype(record.type)}
  645 + fieldGroupType={typeTranslateGrouptype(record.type)}
  646 + isMixValue={typeTranslateFieIdtype(record.type) == 'STRING' ? true : false}
  647 + isMultiple={false}
  648 + // onChange={(val) => handleChangeField(val, record)} //需要onblur
  649 + /> */}
  650 + </div>
  651 + );
  652 + };
  653 +
  654 + const qxPropsRemark = () => {
  655 + return (
  656 + <Input
  657 + defaultValue={record?.description}
  658 + ref={inputRef}
  659 + onBlur={() => save('description')}
  660 + />
  661 + );
  662 + };
  663 +
  664 + if (editable) {
  665 + childNode = editing ? (
  666 + <Form.Item
  667 + style={{ margin: 0 }}
  668 + // @ts-ignore
  669 + name={dataIndex}
  670 + // rules={rules}
  671 + >
  672 + {dataIndex == 'type' ? (
  673 + <Select
  674 + ref={inputRef}
  675 + onBlur={() => toggleEdit(index)}
  676 + onSelect={(e) => handleChange(e, record, dataIndex)}
  677 + >
  678 + {valueOptions.map((item) => {
  679 + return (
  680 + <Select.Option key={item.key} value={item.key}>
  681 + {item.title}
  682 + </Select.Option>
  683 + );
  684 + })}
  685 + </Select>
  686 + ) : dataIndex == 'required' ? (
  687 + <Select
  688 + ref={inputRef}
  689 + onBlur={() => toggleEdit(index)}
  690 + onSelect={(e) => props.handleChange(e, record, dataIndex)}
  691 + >
  692 + <Select.Option value={true}>是</Select.Option>
  693 + <Select.Option value={false}>否</Select.Option>
  694 + </Select>
  695 + ) : dataIndex == 'qxProps' ? (
  696 + title == '取值范围' ? (
  697 + qxPropsRange()
  698 + ) : title == '默认值' ? (
  699 + qxPropsDefault()
  700 + ) : (
  701 + qxPropsRemark()
  702 + )
  703 + ) : (
  704 + // @ts-ignore
  705 + <Input
  706 + ref={inputRef}
  707 + onPressEnter={save}
  708 + onBlur={() => save(dataIndex)}
  709 + />
  710 + )}
  711 + </Form.Item>
  712 + ) : (
  713 + <div
  714 + className="editable-cell-value-wrap"
  715 + onClick={() => toggleEdit(index)}
  716 + >
  717 + {children}
  718 + </div>
  719 + );
  720 + } else {
  721 + childNode = (
  722 + <div className="editable-cell-value-wrap-none">{children}</div>
  723 + );
  724 + }
  725 + return <td {...restProps}>{childNode}</td>;
  726 + };
  727 +
  728 + // type EditableTableProps = Parameters<typeof Table>[0];
  729 +
  730 + // interface DataType {
  731 + // key: React.Key;
  732 + // name: string;
  733 + // age: string;
  734 + // address: string;
  735 + // }
  736 +
  737 + // type ColumnTypes = Exclude<EditableTableProps['columns'], undefined>;
  738 +
  739 + // const handleSave = (row: DataType) => {
  740 + // const newData = [...dataSource];
  741 + // const index = newData.findIndex(item => row.key === item.key);
  742 + // const item = newData[index];
  743 + // newData.splice(index, 1, {
  744 + // ...item,
  745 + // ...row,
  746 + // });
  747 + // setDataSource(newData);
  748 + // };
  749 +
  750 + const components = {
  751 + body: {
  752 + row: EditableRow,
  753 + cell: EditableCell,
  754 + },
  755 + };
  756 +
  757 + const columns1 = columns.map((col) => {
  758 + if (!col.editable) {
  759 + return col;
  760 + }
  761 + return {
  762 + ...col,
  763 + onCell: (record: any, index: any) => ({
  764 + index,
  765 + record,
  766 + editable: record.disabled ? false : true,
  767 + dataIndex: col.dataIndex,
  768 + title: col.title,
  769 + // handleSave,
  770 + }),
  771 + };
  772 + });
  773 + // const isDeveloper = window.sessionStorage.getItem('DEVELOPER_MODE') === '1';
  774 + const [isShowJson, setIsShowJson] = useState<any>(false);
  775 + const [midData, setMidData] = useState<any>([]);
  776 + useEffect(() => {
  777 + if (visible) {
  778 + if (data.length == 0) {
  779 + handleAdd('');
  780 + }
  781 + }
  782 + // easyTableRef.current.refresh()
  783 + // setTimeout(() => {
  784 + // setNewData(data)
  785 + // }, 0)
  786 + // form.setFieldsValue(data)
  787 + }, [visible]);
  788 +
  789 + // useEffect(() => {
  790 + // }, []);
  791 + //展开 所有子节点
  792 + const generateTreeData = useCallback(
  793 + (_data: any[], _keywords?: string): any[] => {
  794 + const _treeNode: any[] = [];
  795 + (_data || []).map((item) => {
  796 + if (item.pid == _keywords) {
  797 + const child = generateTreeData(_data, item.id);
  798 + if (
  799 + child?.length &&
  800 + (item?.type == 'OBJECT' || item?.type == 'ARRAY')
  801 + ) {
  802 + item.child = child;
  803 + }
  804 + _treeNode.push(item);
  805 + }
  806 + });
  807 + return _treeNode;
  808 + },
  809 + [],
  810 + );
  811 +
  812 + //每行拖拽渲染
  813 + const onRow = () => ({
  814 + draggable: true,
  815 + style: { cursor: 'move' },
  816 + onDragStart: (ev: any) => {
  817 + ev.persist();
  818 + ev.dataTransfer.effectAllowed = 'move';
  819 + ev.dataTransfer.setData('text', ev.target.getAttribute('data-row-key'));
  820 + },
  821 + onDragEnter: (ev: any) => {
  822 + ev.persist();
  823 + let nodes;
  824 + switch (ev.target.tagName) {
  825 + case 'TD':
  826 + nodes = ev.target.parentNode.childNodes;
  827 + break;
  828 + case 'DIV':
  829 + nodes = ev.target.parentNode.parentNode.childNodes;
  830 + break;
  831 + default:
  832 + nodes = [];
  833 + }
  834 + nodes?.forEach(
  835 + (item: any) => (item.style.borderTop = '2px dashed #1890ff'),
  836 + );
  837 + },
  838 + onDragLeave: (ev: any) => {
  839 + ev.persist();
  840 + let nodes;
  841 + switch (ev.target.tagName) {
  842 + case 'TD':
  843 + nodes = ev.target.parentNode.childNodes;
  844 + break;
  845 + case 'DIV':
  846 + nodes = ev.target.parentNode.parentNode.childNodes;
  847 + break;
  848 + default:
  849 + nodes = [];
  850 + }
  851 + nodes?.forEach((item: any) => (item.style.borderTop = ''));
  852 + },
  853 +
  854 + onDrop: (ev: any) => {
  855 + ev.preventDefault();
  856 + ev.stopPropagation();
  857 + const dragId = ev.dataTransfer.getData('text');
  858 + let dropCol;
  859 + switch (ev.target.tagName) {
  860 + case 'TD':
  861 + dropCol = ev.target.parentNode;
  862 + break;
  863 + case 'DIV':
  864 + dropCol = ev.target.parentNode.parentNode;
  865 + break;
  866 + default:
  867 + dropCol = ev.target;
  868 + }
  869 + // dropCol.parentNode.insertBefore(dragCol, dropCol); // DOM操作
  870 + const dropId =
  871 + dropCol.getAttribute('data-row-key') ||
  872 + dropCol.getAttribute('id')?.slice(4);
  873 + const _newTreeData = _.cloneDeep(treeData);
  874 + const dragIndex = _newTreeData.findIndex(
  875 + (item: any) => item.id === dragId,
  876 + ); //要drop的index
  877 + const dropIndex = _newTreeData.findIndex(
  878 + (item: any) => item.id === dropId,
  879 + ); // 要drop到目标的index
  880 + if (dragIndex == dropIndex || !dragId || !dropId) {
  881 + dropCol.childNodes.forEach((item: any) => (item.style.borderTop = ''));
  882 + dropCol.parentNode.childNodes.forEach(
  883 + (item: any) => (item.style.borderTop = ''),
  884 + );
  885 + return;
  886 + } else {
  887 + if (!!_newTreeData[dropIndex].pid) {
  888 + const pidIndex = _newTreeData.findIndex(
  889 + (item: any) => item.id === _newTreeData[dropIndex].pid,
  890 + );
  891 + if (_newTreeData[pidIndex].type == 'ARRAY') {
  892 + message.warning('数组有且只有一个子节点,请重试!');
  893 + dropCol.childNodes.forEach(
  894 + (item: any) => (item.style.borderTop = ''),
  895 + );
  896 + dropCol.parentNode.childNodes.forEach(
  897 + (item: any) => (item.style.borderTop = ''),
  898 + );
  899 + return;
  900 + }
  901 + _newTreeData[dragIndex].pid = _newTreeData[dropIndex].pid;
  902 + } else {
  903 + _newTreeData[dragIndex].pid = '';
  904 + }
  905 + const todoData = _newTreeData.splice(dragIndex, 1); //获取要drop的item
  906 + _newTreeData.splice(dropIndex, 0, todoData[0]); // 插入
  907 + }
  908 + const _newData = generateTreeData(_newTreeData, '');
  909 + handleDrop(_newData);
  910 + dropCol.childNodes.forEach((item: any) => (item.style.borderTop = ''));
  911 + dropCol.parentNode.childNodes.forEach(
  912 + (item: any) => (item.style.borderTop = ''),
  913 + );
  914 + },
  915 + onDragOver: (ev: any) => ev.preventDefault(),
  916 + });
  917 +
  918 + const onCancel = () => {
  919 + setIsShowJson(false);
  920 + handleCancel(inputKey + 1);
  921 + };
  922 +
  923 + const submit = () => {
  924 + try {
  925 + JSON.parse(midData);
  926 + handleDrop(JSON.parse(midData));
  927 + message.success('保存成功');
  928 + setTimeout(() => {
  929 + onCancel();
  930 + }, 0);
  931 + } catch (error) {
  932 + message.error('JSON转成数据有错误请重试!');
  933 + return;
  934 + }
  935 + };
  936 +
  937 + const onOpen = () => {
  938 + setMidData(JSON.stringify(data, null, 4));
  939 + setIsShowJson(true);
  940 + };
  941 +
  942 + const onJsonChange = (_data: any) => {
  943 + setMidData(_data);
  944 + };
  945 +
  946 + return (
  947 + <>
  948 + <Modal
  949 + title="高级参数设计器"
  950 + visible={visible}
  951 + destroyOnClose
  952 + footer={null}
  953 + // onOk={handleCancel}
  954 + onCancel={onCancel}
  955 + width={'100%'}
  956 + >
  957 + {isShowJson ? (
  958 + <Row>
  959 + <Col span={12}>
  960 + <Button
  961 + type="link"
  962 + icon={<SnippetsOutlined />}
  963 + onClick={() => setIsShowJson(false)}
  964 + >
  965 + {'表单参数设置'}
  966 + </Button>
  967 + </Col>
  968 + </Row>
  969 + ) : (
  970 + <Row>
  971 + <Col span={12}>
  972 + <Button type="link" onClick={() => onOpen()}>
  973 + {'</>JSON参数设置'}
  974 + </Button>
  975 + </Col>
  976 + <Col
  977 + className="border-none"
  978 + span={12}
  979 + style={{
  980 + display: 'flex',
  981 + flexDirection: 'row-reverse',
  982 + marginBottom: '10px',
  983 + textAlign: 'center',
  984 + }}
  985 + >
  986 + <Input
  987 + className={'qx-parameter-setting--search'}
  988 + placeholder="按名称搜索"
  989 + prefix={<SearchOutlined />}
  990 + onChange={onChange}
  991 + style={{ width: 219 }}
  992 + />
  993 + </Col>
  994 + </Row>
  995 + )}
  996 + {
  997 + isShowJson ? (
  998 + <>
  999 + <JSONEditor value={midData} onChange={onJsonChange} />
  1000 + <Col
  1001 + className="border-none"
  1002 + span={24}
  1003 + style={{
  1004 + display: 'flex',
  1005 + flexDirection: 'row-reverse',
  1006 + marginBottom: '10px',
  1007 + textAlign: 'center',
  1008 + }}
  1009 + >
  1010 + <Space>
  1011 + <Button onClick={() => onCancel()}>{'取消'}</Button>
  1012 + <Button type="primary" onClick={() => submit()}>
  1013 + {'确定'}
  1014 + </Button>
  1015 + </Space>
  1016 + </Col>
  1017 + </>
  1018 + ) : (
  1019 + // <Form form={form}>
  1020 + <Table
  1021 + components={components}
  1022 + defaultExpandAllRows
  1023 + onRow={() => onRow()}
  1024 + scroll={{ x: 1600 }}
  1025 + childrenColumnName={'child'}
  1026 + // className={'param-setting-table'}
  1027 + rowClassName={() => 'editable-row'}
  1028 + bordered
  1029 + pagination={false}
  1030 + size={'small'}
  1031 + // @ts-ignore
  1032 + columns={columns1}
  1033 + dataSource={data}
  1034 + rowKey={'id'}
  1035 + />
  1036 + )
  1037 + // </Form >
  1038 + }
  1039 + </Modal>
  1040 + </>
  1041 + );
  1042 +};
  1043 +
  1044 +export default ParameterModal;
... ...
  1 +import 'codemirror/lib/codemirror.css';
  2 +import 'codemirror/lib/codemirror.js';
  3 +import 'codemirror/theme/xq-light.css';
  4 +import React from 'react';
  5 +import { Controlled as CodeMirror } from 'react-codemirror2';
  6 +// import 'codemirror/mode/css/css';
  7 +import 'codemirror/addon/fold/brace-fold.js';
  8 +import 'codemirror/addon/fold/comment-fold.js';
  9 +import 'codemirror/addon/fold/foldcode.js';
  10 +import 'codemirror/addon/fold/foldgutter.css';
  11 +import 'codemirror/addon/fold/foldgutter.js';
  12 +import 'codemirror/addon/scroll/simplescrollbars.css';
  13 +import 'codemirror/addon/scroll/simplescrollbars.js';
  14 +import 'codemirror/addon/selection/active-line';
  15 +import 'codemirror/mode/javascript/javascript';
  16 +
  17 +type CodeMirrorProps = {
  18 + value: any;
  19 + onChange: (val: any) => void;
  20 +};
  21 +
  22 +/**
  23 + * 代码块
  24 + *
  25 + * @param value
  26 + * @param onChange
  27 + * @constructor
  28 + */
  29 +const CodeMirrorSetting: React.FC<CodeMirrorProps> = ({ value, onChange }) => {
  30 + return (
  31 + <CodeMirror
  32 + value={value}
  33 + onBeforeChange={(editor, data, val) => {
  34 + onChange(val);
  35 + }}
  36 + options={{
  37 + // lineNumbers: true, //显示行号
  38 + // mode: 'javascript', //语言
  39 + mode: 'application/json',
  40 + autofocus: false, //自动获取焦点
  41 + styleActiveLine: true, //光标代码高亮
  42 + theme: 'xq-light', //主题
  43 + // scrollbarStyle: 'overlay',
  44 + smartIndent: true,
  45 + lineWrapping: false, //代码自动换行
  46 + foldGutter: true,
  47 + autoCloseBrackets: true,
  48 + gutters: ['CodeMirror-linenumbers', 'CodeMirrorfoldgutter'], //end
  49 + lint: true,
  50 + indentWithTabs: true,
  51 + }}
  52 + />
  53 + );
  54 +};
  55 +
  56 +export default CodeMirrorSetting;
... ...
  1 +import type { DataNode } from 'antd/lib/tree';
  2 +
  3 +export const formatEnum = {
  4 + YEAR: 'YYYY',
  5 + YEAR_MONTH: 'YYYY-MM',
  6 + YEAR_DATE: 'YYYY-MM-DD',
  7 + YEAR_HOUR: 'YYYY-MM-DD HH:00',
  8 + YEAR_MIN: 'YYYY-MM-DD HH:mm',
  9 + YEAR_SEC: 'YYYY-MM-DD HH:mm:ss',
  10 + // "HOUR_MIN": "HH:mm",
  11 + // "HOUR_SEC": "HH:mm:ss"
  12 +};
  13 +
  14 +export const typeText = (type: string) => {
  15 + switch (type) {
  16 + case 'STRING':
  17 + return '文本';
  18 + case 'TEXT':
  19 + return '文本';
  20 + case 'NUMBER':
  21 + return '数字';
  22 + case 'NUM':
  23 + return '数字';
  24 + case 'TIME':
  25 + return '日期';
  26 + case 'BOOL':
  27 + return '布尔';
  28 + case 'OBJECT':
  29 + return '对象';
  30 + case 'ARRAY':
  31 + return '数组';
  32 + case 'FORM':
  33 + return '表单';
  34 + case 'REL':
  35 + return '表单';
  36 + case 'USER':
  37 + return '人员';
  38 + case 'ORG':
  39 + return '部门';
  40 + default:
  41 + return;
  42 + }
  43 +};
  44 +
  45 +export const typeTranslateGrouptype = (type: string) => {
  46 + switch (type) {
  47 + case 'STRING':
  48 + return 'TEXT';
  49 + case 'TEXT':
  50 + return 'TEXT';
  51 + case 'NUMBER':
  52 + return 'NUM';
  53 + case 'NUM':
  54 + return 'NUM';
  55 + case 'TIME':
  56 + return 'DATE';
  57 + case 'DATE':
  58 + return 'DATE';
  59 + case 'BOOL':
  60 + return 'BOOL';
  61 + case 'OBJECT':
  62 + return 'OBJECT';
  63 + case 'ARRAY':
  64 + return 'ARRAY';
  65 + case 'FORM':
  66 + return 'REL';
  67 + case 'REL':
  68 + return 'REL';
  69 + case 'USER':
  70 + return 'USER';
  71 + case 'ORG':
  72 + return 'ORG';
  73 + default:
  74 + return undefined;
  75 + }
  76 +};
  77 +
  78 +export enum ParamValueType {
  79 + // 手动填写
  80 + MANUAL = 'MANUAL',
  81 + // 数据类型选项值
  82 + OPERATOR = 'OPERATOR',
  83 + // 字段
  84 + FIELD = 'FIELD',
  85 +}
  86 +
  87 +export const typeTranslateItemtype = (type: string | undefined) => {
  88 + switch (type) {
  89 + case 'STRING':
  90 + return 'MANUAL';
  91 + case 'TEXT':
  92 + return 'MANUAL';
  93 + case 'NUMBER':
  94 + return 'MANUAL';
  95 + case 'NUM':
  96 + return 'MANUAL';
  97 + case 'DATE':
  98 + return 'OPERATOR';
  99 + case 'TIME':
  100 + return 'OPERATOR';
  101 + case 'BOOL':
  102 + return 'OPERATOR';
  103 + case 'OBJECT':
  104 + return 'FIELD';
  105 + case 'ARRAY':
  106 + return 'FIELD';
  107 + case 'FORM':
  108 + return 'FIELD';
  109 + case 'REL':
  110 + return 'FIELD';
  111 + case 'USER':
  112 + return 'FIELD';
  113 + case 'ORG':
  114 + return 'FIELD';
  115 + default:
  116 + return;
  117 + }
  118 +};
  119 +
  120 +export const typeTranslateFieIdtype = (type: string | undefined) => {
  121 + switch (type) {
  122 + case 'STRING':
  123 + return 'STRING';
  124 + case 'TEXT':
  125 + return 'STRING';
  126 + case 'NUMBER':
  127 + return 'DOUBLE';
  128 + case 'NUM':
  129 + return 'DOUBLE';
  130 + case 'DATE':
  131 + return 'YEAR_SEC';
  132 + case 'TIME':
  133 + return 'YEAR_SEC';
  134 + case 'BOOL':
  135 + return 'BOOL';
  136 + case 'OBJECT':
  137 + return 'OBJECT';
  138 + case 'ARRAY':
  139 + return 'ARRAY';
  140 + case 'FORM':
  141 + return 'REL';
  142 + case 'REL':
  143 + return 'REL';
  144 + case 'USER':
  145 + return 'USER';
  146 + case 'ORG':
  147 + return 'ORG';
  148 + default:
  149 + return;
  150 + }
  151 +};
  152 +
  153 +export const typeTranslateWidget = (type: string | undefined) => {
  154 + switch (type) {
  155 + case 'STRING':
  156 + return 'qxInput';
  157 + case 'TEXT':
  158 + return 'qxInput';
  159 + case 'NUMBER':
  160 + return 'qxNumber';
  161 + case 'NUM':
  162 + return 'qxNumber';
  163 + case 'DATE':
  164 + return 'qxDatetime';
  165 + case 'TIME':
  166 + return 'qxDatetime';
  167 + case 'BOOL':
  168 + return 'qxSwitch';
  169 + case 'OBJECT':
  170 + return 'qxInput';
  171 + case 'ARRAY':
  172 + return 'qxInput';
  173 + case 'FORM' || 'REL':
  174 + return 'relSelector';
  175 + case 'USER':
  176 + return 'userSelector';
  177 + case 'ORG':
  178 + return 'orgSelector';
  179 + case 'YEAR_SEC':
  180 + return 'qxDatetime';
  181 + default:
  182 + return;
  183 + }
  184 +};
  185 +
  186 +// 基础
  187 +export const BASE_MODAL_SCHEMA: any = {
  188 + type: 'object',
  189 + properties: {
  190 + type: {
  191 + type: 'string',
  192 + hidden: true,
  193 + },
  194 + id: {
  195 + type: 'string',
  196 + hidden: true,
  197 + },
  198 + pid: {
  199 + title: '上级对象',
  200 + type: 'string',
  201 + default: '',
  202 + widget: 'parentIdSetting',
  203 + displayType: 'row',
  204 + labelWidth: 100,
  205 + },
  206 + code: {
  207 + title: '变量名',
  208 + type: 'string',
  209 + widget: 'input',
  210 + displayType: 'row',
  211 + labelWidth: 100,
  212 + required: true,
  213 + max: 32,
  214 + // rules: [
  215 + // {
  216 + // "pattern": "^([a-zA-Z|_])([a-zA-Z0-9_]{0,32}$)",
  217 + // "message": "以字母,下划线,数字组合,开头不能是数字"
  218 + // }
  219 + // ],
  220 + },
  221 + title: {
  222 + title: '标题',
  223 + type: 'string',
  224 + widget: 'input',
  225 + displayType: 'row',
  226 + labelWidth: 100,
  227 + required: true,
  228 + },
  229 + required: {
  230 + title: '必填',
  231 + type: 'boolean',
  232 + widget: 'switchSetting',
  233 + displayType: 'row',
  234 + default: false,
  235 + labelWidth: 100,
  236 + },
  237 + qxProps: {
  238 + type: 'object',
  239 + hidden: true,
  240 + },
  241 + disabled: {
  242 + type: 'boolean',
  243 + hidden: true,
  244 + default: false,
  245 + },
  246 + },
  247 +};
  248 +
  249 +// 文本
  250 +export const TEXT_MODAL_SCHEMA: any = {
  251 + min: {
  252 + title: '字符长度',
  253 + type: 'number',
  254 + placeholder: '最小值',
  255 + displayType: 'row',
  256 + width: '48%',
  257 + min: 0,
  258 + max: 32,
  259 + labelWidth: 100,
  260 + bind: 'qxProps.min',
  261 + },
  262 + 'range-split': {
  263 + type: 'html',
  264 + width: '5%',
  265 + default: '~',
  266 + bind: false,
  267 + },
  268 + max: {
  269 + labelWidth: 1,
  270 + displayType: 'row',
  271 + title: '',
  272 + type: 'number',
  273 + placeholder: '最大值',
  274 + width: '26%',
  275 + min: 0,
  276 + max: 32,
  277 + // rules: [{ validator: (rule, value) => value === 'muji' }],
  278 + // rules: [{ len: 8, message: '长度不能超过8' }],
  279 + bind: 'qxProps.max',
  280 + },
  281 + options: {
  282 + title: '可选值',
  283 + type: 'array',
  284 + placeholder: '多个可选值用逗号隔开',
  285 + displayType: 'row',
  286 + labelWidth: 100,
  287 + Width: 200,
  288 + widget: 'optionsSetting',
  289 + bind: 'qxProps.options',
  290 + },
  291 + default: {
  292 + title: '默认值',
  293 + type: 'string',
  294 + widget: 'input',
  295 + displayType: 'row',
  296 + labelWidth: 100,
  297 + className: 'end',
  298 + Width: 200,
  299 + bind: 'qxProps.default',
  300 + },
  301 + // format: {
  302 + // title: '格式限制',
  303 + // type: 'string',
  304 + // enum: ['NO_LIMIT', 'TELEPHONE', 'MOBILE', 'MAIL', 'UPPERCASE', 'LOWERCASE', ' LETTER_NUMBER', 'LETTER', 'ID_CARD', 'URL', 'REGEX'],
  305 + // enumNames: ['不限制', '固定电话', '手机', '邮箱', '大写字母', '小写字母', '字母数字', '字母', '身份证', '地址', '正则表达式'],
  306 + // default: 'NO_LIMIT',
  307 + // widget: 'select',
  308 + // displayType: 'row',
  309 + // labelWidth: 100,
  310 + // Width: 200,
  311 + // bind: 'qxProps.format',
  312 + // },
  313 +};
  314 +
  315 +// 数字
  316 +export const NUMBER_MODAL_SCHEMA: any = {
  317 + min: {
  318 + title: '数字范围',
  319 + type: 'number',
  320 + placeholder: '最小值',
  321 + displayType: 'row',
  322 + width: '48%',
  323 + min: -999999999999999,
  324 + max: 999999999999999,
  325 + labelWidth: 100,
  326 + bind: 'qxProps.min',
  327 + },
  328 + 'range-split': {
  329 + type: 'html',
  330 + width: '5%',
  331 + default: '~',
  332 + bind: false,
  333 + },
  334 + max: {
  335 + labelWidth: 1,
  336 + displayType: 'row',
  337 + title: '',
  338 + type: 'number',
  339 + placeholder: '最大值',
  340 + width: '26%',
  341 + min: -999999999999999,
  342 + max: 999999999999999,
  343 + bind: 'qxProps.max',
  344 + },
  345 + options: {
  346 + title: '可选值',
  347 + type: 'array',
  348 + placeholder: '多个可选值用逗号隔开',
  349 + displayType: 'row',
  350 + labelWidth: 100,
  351 + Width: 200,
  352 + widget: 'optionsSetting',
  353 + bind: 'qxProps.options',
  354 + },
  355 + default: {
  356 + title: '默认值',
  357 + type: 'number',
  358 + displayType: 'row',
  359 + labelWidth: 100,
  360 + className: 'end',
  361 + Width: 200,
  362 + bind: 'qxProps.default',
  363 + },
  364 + precision: {
  365 + title: '小数位数',
  366 + displayType: 'row',
  367 + labelWidth: 100,
  368 + type: 'number',
  369 + placeholder: '0',
  370 + default: 0,
  371 + width: 200,
  372 + min: 0,
  373 + max: 9,
  374 + bind: 'qxProps.precision',
  375 + },
  376 +};
  377 +
  378 +// 日期
  379 +export const DATE_MODAL_SCHEMA: any = {
  380 + min: {
  381 + title: '可选范围',
  382 + type: 'date',
  383 + placeholder: '最小值',
  384 + displayType: 'row',
  385 + widget: 'dateSetting',
  386 + width: '48%',
  387 + labelWidth: 100,
  388 + props: {
  389 + format: '{{formData.format}}',
  390 + },
  391 + bind: 'qxProps.min',
  392 + },
  393 + 'range-split': {
  394 + type: 'html',
  395 + width: '5%',
  396 + default: '~',
  397 + bind: false,
  398 + },
  399 + max: {
  400 + labelWidth: 1,
  401 + displayType: 'row',
  402 + title: '',
  403 + type: 'date',
  404 + widget: 'dateSetting',
  405 + placeholder: '最大值',
  406 + width: '26%',
  407 + props: {
  408 + format: '{{formData.format}}',
  409 + },
  410 + bind: 'qxProps.max',
  411 + },
  412 + options: {
  413 + title: '可选值',
  414 + type: 'array',
  415 + placeholder: '多个可选值用逗号隔开',
  416 + displayType: 'row',
  417 + labelWidth: 100,
  418 + Width: 200,
  419 + widget: 'optionsSetting',
  420 + bind: 'qxProps.options',
  421 + },
  422 + default: {
  423 + title: '默认值',
  424 + type: 'date',
  425 + widget: 'dateSetting',
  426 + displayType: 'row',
  427 + labelWidth: 100,
  428 + className: 'end',
  429 + Width: 200,
  430 + props: {
  431 + format: '{{formData.format}}',
  432 + },
  433 + bind: 'qxProps.default',
  434 + },
  435 + format: {
  436 + title: '格式限制',
  437 + type: 'string',
  438 + displayType: 'row',
  439 + labelWidth: 100,
  440 + enum: Object.keys(formatEnum),
  441 + enumNames: [
  442 + '年',
  443 + '年-月',
  444 + '年-月-日',
  445 + '年-月-日 时',
  446 + '年-月-日 时:分',
  447 + '年-月-日 时:分:秒',
  448 + '时:分',
  449 + '时:分:秒',
  450 + ],
  451 + default: 'YEAR_DATE',
  452 + bind: 'qxProps.format',
  453 + },
  454 +};
  455 +
  456 +// 布尔
  457 +export const BOOLEAN_MODAL_SCHEMA: any = {
  458 + default: {
  459 + title: '默认值',
  460 + type: 'string',
  461 + enum: ['无', 'TRUE', 'FALSE'],
  462 + enumNames: ['无', 'TRUE', 'FALSE'],
  463 + default: '无',
  464 + widget: 'select',
  465 + displayType: 'row',
  466 + labelWidth: 100,
  467 + Width: 200,
  468 + bind: 'qxProps.default',
  469 + },
  470 +};
  471 +
  472 +// 表单
  473 +export const FORM_MODAL_SCHEMA: any = {
  474 + formId: {
  475 + title: '关联表单',
  476 + labelWidth: 100,
  477 + type: 'string',
  478 + displayType: 'row',
  479 + widget: 'relSetting',
  480 + props: {
  481 + hiddenTitle: true,
  482 + haveChildren: true,
  483 + },
  484 + required: true,
  485 + placeholder: '请选择工作表',
  486 + bind: 'qxProps.formId',
  487 + },
  488 + appId: {
  489 + type: 'string',
  490 + hidden: true,
  491 + bind: 'qxProps.appId',
  492 + },
  493 + formName: {
  494 + type: 'string',
  495 + hidden: true,
  496 + bind: 'qxProps.formName',
  497 + },
  498 +};
  499 +
  500 +// 人员
  501 +export const USER_MODAL_SCHEMA: any = {
  502 + formId: {
  503 + title: '关联表单',
  504 + labelWidth: 100,
  505 + type: 'string',
  506 + displayType: 'row',
  507 + widget: 'relSetting',
  508 + props: {
  509 + hiddenTitle: true,
  510 + disabledSelect: true,
  511 + },
  512 + required: true,
  513 + placeholder: '请选择工作表',
  514 + bind: 'qxProps.formId',
  515 + default: 'PbOC6xBYOvZ1IB2mwUc',
  516 + },
  517 + appId: {
  518 + type: 'string',
  519 + hidden: true,
  520 + bind: 'qxProps.appId',
  521 + default: 'eSnLZ42R2TA5Z18dNsJ',
  522 + },
  523 + formName: {
  524 + type: 'string',
  525 + hidden: true,
  526 + bind: 'qxProps.formName',
  527 + default: '人员',
  528 + },
  529 +};
  530 +
  531 +// 部门
  532 +export const ORG_MODAL_SCHEMA: any = {
  533 + formId: {
  534 + title: '关联表单',
  535 + labelWidth: 100,
  536 + type: 'string',
  537 + displayType: 'row',
  538 + widget: 'relSetting',
  539 + props: {
  540 + hiddenTitle: true,
  541 + disabledSelect: true,
  542 + },
  543 + required: true,
  544 + placeholder: '请选择工作表',
  545 + bind: 'qxProps.formId',
  546 + default: 'UsoOGnrJLPziSQwGDwj',
  547 + },
  548 + appId: {
  549 + type: 'string',
  550 + hidden: true,
  551 + bind: 'qxProps.appId',
  552 + default: 'eSnLZ42R2TA5Z18dNsJ',
  553 + },
  554 + formName: {
  555 + type: 'string',
  556 + hidden: true,
  557 + bind: 'qxProps.formName',
  558 + default: '部门',
  559 + },
  560 +};
  561 +
  562 +export const ItemTypes = 'DraggableBodyRow';
  563 +
  564 +// 操作类型
  565 +export const optionsTyps = {
  566 + didDrop: 'didDrop', // 拖拽出区域
  567 + hover: 'hover',
  568 + drop: 'drop', // 放置
  569 +};
  570 +
  571 +// 数据类型
  572 +export const dataType = {
  573 + group: 'group',
  574 + child: 'child',
  575 +};
  576 +
  577 +//参数配置
  578 +export interface ParamDesignModel extends DataNode {
  579 + code: string;
  580 + format?: string;
  581 + type: string;
  582 + id: string;
  583 + pid?: string;
  584 + required?: boolean;
  585 + title?: string;
  586 + qxProps?: any;
  587 + child?: ParamDesignModel[];
  588 +}
... ...
  1 +---
  2 +# nav:
  3 +# path: /component
  4 +# title: 组件
  5 +# order: 1
  6 +# group:
  7 +# path: /common
  8 +# title: 公共组件方法
  9 +# order: 0
  10 +---
  11 +
  12 +## parameterSetting 参数设计器
  13 +
  14 +Demo:
  15 +
  16 +```tsx
  17 +import { QxParameterSetting } from '@qx/common';
  18 +import { Input } from 'antd';
  19 +import React, { useState } from 'react';
  20 +
  21 +export default () => {
  22 + const [value, setValue] = useState([
  23 + {
  24 + code: '29gnd',
  25 + id: 'f7724ff3557041588fcdcf69d31bec1d',
  26 + pid: '',
  27 + showCode: true,
  28 + qxProps: {
  29 + appId: 'HBZy3te6d9SxSMO3lLr',
  30 + formId: 'j9s5sUXvLiT2a1PJOsh',
  31 + formName: '合同管理',
  32 + },
  33 + required: false,
  34 + title: '流程类萨',
  35 + type: 'OBJECT',
  36 + disabled: true,
  37 + child: [
  38 + {
  39 + id: '519338cceed64b08aeadcc7f5b4c9d94',
  40 + pid: 'f7724ff3557041588fcdcf69d31bec1d',
  41 + code: '60edb3',
  42 + showCode: true,
  43 + title: '问问',
  44 + required: true,
  45 + qxProps: {
  46 + min: '2023-08-18',
  47 + max: '2023-08-08',
  48 + options: ['1231231231321'],
  49 + default: '2023-08-02',
  50 + format: 'YEAR_DATE',
  51 + },
  52 + disabled: false,
  53 + type: 'TIME',
  54 + },
  55 + ],
  56 + },
  57 + {
  58 + id: '6370b8fd52484b83abd702379870b05f',
  59 + pid: '',
  60 + code: 'ufsqtk',
  61 + showCode: true,
  62 + title: '爱的人翁热',
  63 + required: true,
  64 + qxProps: {
  65 + min: 1,
  66 + max: 10,
  67 + options: ['232312312323423'],
  68 + default: 112,
  69 + precision: 2,
  70 + },
  71 + disabled: false,
  72 + type: 'NUMBER',
  73 + },
  74 + {
  75 + id: '2df392beea224ad5af58ac96dad04e7b',
  76 + pid: '',
  77 + code: 'ci4ihw',
  78 + showCode: true,
  79 + title: '来来来',
  80 + required: false,
  81 + child: [
  82 + {
  83 + id: 'db1cd3c513534a82ae85f63e82cf0951',
  84 + pid: '2df392beea224ad5af58ac96dad04e7b',
  85 + code: 'b3cbef',
  86 + title: '啊实打实',
  87 + required: false,
  88 + qxProps: {
  89 + min: '2023-08-16',
  90 + max: '2023-08-01',
  91 + options: ["asdaa'd "],
  92 + default: '2023-08-03',
  93 + format: 'YEAR_DATE',
  94 + },
  95 + disabled: false,
  96 + type: 'TIME',
  97 + },
  98 + ],
  99 + disabled: false,
  100 + type: 'ARRAY',
  101 + },
  102 + ]);
  103 + const handleChange = (newValue) => {
  104 + setValue(newValue);
  105 + };
  106 +
  107 + const DefaultComponent: React.FC = () => {
  108 + return <Input style={{ width: '100%' }}></Input>;
  109 + };
  110 +
  111 + const [comValue, setComValue] = useState([
  112 + 'jsadlfjlf',
  113 + 'djslfjaljdlsf123',
  114 + 'jsadlfjlfjalsf123',
  115 + '3dsfjlsjflsdsjf24',
  116 + 'vdsnflsjfsjfskljfvvv',
  117 + ]);
  118 +
  119 + const [nodeItem, setNodeItem] = useState([
  120 + {
  121 + iconName: 'icon-flow-start',
  122 + key: '5dec2f28-8dd1-48be-a14d-e7c4e3cdb89d',
  123 + nodeType: 'WF_START',
  124 + selectable: false,
  125 + title: '开始',
  126 + titleStr: '开始',
  127 + },
  128 + {
  129 + iconName: 'icon-flow-end',
  130 + key: '5dec2f28-8888-48be-a14d-e7c4e3cdb89d',
  131 + nodeType: 'WF_END',
  132 + selectable: true,
  133 + title: 'jieshu',
  134 + titleStr: '结束',
  135 + },
  136 + ]);
  137 +
  138 + const comHandleChange = (newValue) => {
  139 + setComValue(newValue);
  140 + };
  141 +
  142 + const isHide = true;
  143 + const isShow = true;
  144 +
  145 + const componentItem = {
  146 + value: comValue,
  147 + onChange: comHandleChange,
  148 + };
  149 + return (
  150 + <QxParameterSetting
  151 + value={value}
  152 + nodeItem={nodeItem}
  153 + // componentItem={componentItem}
  154 + onChange={handleChange}
  155 + isHideSearch={isHide}
  156 + isShowTitle={isShow}
  157 + isShowField={true}
  158 + title={'sadaasdasdasdwwwwwwwasdasdasdsdsd'}
  159 + // component={QxTagsInput}
  160 + />
  161 + );
  162 +};
  163 +```
  164 +
  165 +## 入参数据格式
  166 +
  167 +| 参数 | 说明 | 类型 | 默认值 |
  168 +| ------------ | -------------------------------- | ------ | ------ |
  169 +| isHideSearch | 是否隐藏搜索框 | bool | - |
  170 +| nodeItem | 节点信息,默认值右侧选择节点使用 | [] | - |
  171 +| value | | [] | - |
  172 +| isShowTitle | 是否显示左侧标题 | bool | - |
  173 +| title | 左侧标题 | string | - |
  174 +| isShowField | 是否显示下部默认值 item | bool | - |
  175 +| onChange | | | - |
  176 +
  177 +## 出参数据格式
  178 +
  179 +| 参数 | 说明 | 类型 | 默认值 |
  180 +| --------------- | -------------- | ------------------ | ------ |
  181 +| code | 参数编码 | string | - |
  182 +| id | id | string | - |
  183 +| pid | 上级 id | string | - |
  184 +| title | 参数名 | string | - |
  185 +| required | 是否必填 | bool | - |
  186 +| disabled | 是否禁用 | bool | - |
  187 +| type | 类型 | string[] | |
  188 +| child | 子节点 | string[] | |
  189 +| qxProps | 高级参数器数据 | object{} | |
  190 +| qxProps-min | 取值范围最小 | string[] \| string | |
  191 +| qxProps-max | 取值范围最大 | string[] \| string | |
  192 +| qxProps-options | 可选值 | string[] \| string | |
  193 +| qxProps-default | 默认值 | string[] \| string | |
  194 +
  195 +More skills for writing demo: https://d.umijs.org/guide/basic#write-component-demo
... ...
  1 +/* eslint-disable eqeqeq */
  2 +/* eslint-disable array-callback-return */
  3 +import React, { useCallback, useEffect, useState } from 'react';
  4 +// import type { FRWidgetProps } from '@/packages/qx-form-generator/src';
  5 +import {
  6 + DeleteOutlined,
  7 + PlusOutlined,
  8 + SearchOutlined,
  9 + SettingOutlined,
  10 +} from '@ant-design/icons';
  11 +import {
  12 + Button,
  13 + Dropdown,
  14 + Input,
  15 + Menu,
  16 + Modal,
  17 + Select,
  18 + Tree,
  19 + message,
  20 +} from 'antd';
  21 +import type { TreeProps } from 'antd/lib/tree';
  22 +import ParameterModal from './ParameterModal';
  23 +// import { FieldSetter } from '@qx/common';
  24 +import { formatEnum } from './constant';
  25 +// import type { InputRef } from 'antd';
  26 +// import {
  27 +// typeTranslateFieIdtype,
  28 +// typeTranslateWidget,
  29 +// typeTranslateGrouptype,
  30 +// typeTranslateItemtype,
  31 +// } from './constant';
  32 +
  33 +import _ from 'lodash';
  34 +import moment from 'moment';
  35 +import type { ParamDesignModel } from './constant';
  36 +import { uidGen } from './stringUtil';
  37 +import './style.less';
  38 +
  39 +const valueOptions = [
  40 + { key: 'STRING', label: '文本' },
  41 + { key: 'NUMBER', label: '数字' },
  42 + { key: 'TIME', label: '日期' },
  43 + { key: 'BOOL', label: '布尔' },
  44 + { key: 'OBJECT', label: '对象' },
  45 + { key: 'ARRAY', label: '数组' },
  46 + { key: 'ANNEX', label: '附件' },
  47 + { key: 'PIC', label: '图片' },
  48 + { key: 'FORM', label: '表单' },
  49 + { key: 'USER', label: '人员' },
  50 + { key: 'ORG', label: '部门' },
  51 +];
  52 +
  53 +const getParentKey = (key: React.Key, tree: ParamDesignModel[]): React.Key => {
  54 + let parentKey: React.Key;
  55 + for (let i = 0; i < tree.length; i++) {
  56 + const node = tree[i];
  57 + if (node.child) {
  58 + if (node.child.some((item) => item.id === key)) {
  59 + parentKey = node?.id;
  60 + } else if (getParentKey(key, node.child)) {
  61 + parentKey = getParentKey(key, node.child);
  62 + }
  63 + }
  64 + }
  65 + return parentKey!;
  66 +};
  67 +
  68 +interface ParameterSettingProps {
  69 + nodeItem: any; //默认值右侧选择节点数据
  70 + onChange: (val: any) => void;
  71 + value: any;
  72 + isHideSearch?: boolean; //是否隐藏搜索框
  73 + isShowTitle?: boolean; //是否显示左侧标题
  74 + isShowField?: boolean; //是否显示下部默认值组件
  75 + title?: string;
  76 + // component?: any;
  77 + // componentItem?: any;
  78 + // comHandleChange?: (val: any) => void;
  79 +}
  80 +
  81 +export const QxParameterSetting: React.FC<ParameterSettingProps> = (props) => {
  82 + const [treeData, setTreeData] = useState<ParamDesignModel[]>([]); //展示树列表数据
  83 + const [list, setList] = useState<ParamDesignModel[]>([]); //所有节点数据
  84 + const [visible, setVisible] = useState<any>(false);
  85 + const [inputKey, setInputKey] = useState<any>(0);
  86 + const [expandedKeys, setExpandedKeys] = useState<React.Key[] | undefined>();
  87 + const [defaultExpandedKeys, setDefaultExpandedKeys] = useState<React.Key[]>(); //树节点的id 有了则展开
  88 + const [autoExpandParent, setAutoExpandParent] = useState(true);
  89 + const [searchValue, setSearchValue] = useState('');
  90 + // const isDeveloper = window.sessionStorage.getItem('DEVELOPER_MODE') === '1';
  91 + // const inputRef = useRef<InputRef>(null);
  92 + //把所有子节点都展开拿出来
  93 + const generateList = useCallback((_data: any[]): any[] => {
  94 + const _listNode: any[] = [];
  95 + (_data || []).map((item) => {
  96 + if (item?.child) {
  97 + const data = generateList(item?.child);
  98 + data.map((value) => {
  99 + _listNode.push(value);
  100 + });
  101 + }
  102 + _listNode.push(item);
  103 + });
  104 + return _listNode;
  105 + }, []);
  106 +
  107 + useEffect(() => {
  108 + if (props?.value?.length > 0) {
  109 + const value = _.cloneDeep(props?.value);
  110 + const expandedArray: any = [];
  111 + (value || []).map((_item: ParamDesignModel) => {
  112 + expandedArray.push(_item.id);
  113 + });
  114 + setDefaultExpandedKeys(expandedArray);
  115 + setTreeData(value);
  116 + // const newData = generateTreeData(value, '')
  117 + const Treelist = generateList(value);
  118 + const newList = _.cloneDeep(Treelist);
  119 + newList.map((_item) => {
  120 + delete _item.child;
  121 + });
  122 + setList(newList);
  123 + } else {
  124 + setList([]);
  125 + setTreeData([]);
  126 + }
  127 + }, [props?.value, generateList, visible]);
  128 +
  129 + //展开 所有子节点
  130 + const generateTreeData = useCallback(
  131 + (_data: any[], _keywords?: string): any[] => {
  132 + const _treeNode: any[] = [];
  133 + (_data || []).map((item) => {
  134 + if (item.pid == _keywords) {
  135 + const child = generateTreeData(_data, item.id);
  136 + if (
  137 + child?.length &&
  138 + (item?.type == 'OBJECT' || item?.type == 'ARRAY')
  139 + ) {
  140 + item.child = child;
  141 + }
  142 + _treeNode.push(item);
  143 + }
  144 + });
  145 + return _treeNode;
  146 + },
  147 + [],
  148 + );
  149 +
  150 + //同名校验
  151 + const validateCode: any = (
  152 + // newList: ParamDesignModel[],
  153 + data: ParamDesignModel,
  154 + // newType: string,
  155 + ) => {
  156 + let treeList = _.cloneDeep(list);
  157 + // todo 编辑重名bug 貌似有点问题 待修改
  158 + treeList = (treeList || []).filter((item) => item.id != data.id);
  159 + if (!treeList || treeList.length == 0) {
  160 + return true;
  161 + }
  162 + for (let i = 0; i < treeList.length; i++) {
  163 + // if (!data.pid) {
  164 + const codeList = (treeList || []).map((_item: { code: string }) => {
  165 + return _item.code;
  166 + });
  167 + if (codeList.indexOf(data.code) == -1) {
  168 + return true;
  169 + } else {
  170 + return false;
  171 + }
  172 + // }
  173 + // if (treeList[i].id == data.pid && treeList[i].type == 'OBJECT') {
  174 + // if (treeList[i]?.child?.length > 0) {
  175 + // }
  176 + // return true;
  177 + // } else if (treeList[i].id == data.pid && treeList[i].type == 'ARRAY') {
  178 + // if (treeList[i]?.child?.length > 0) {
  179 + // return false;
  180 + // }
  181 + // return true;
  182 + // } else {
  183 + // if (typeof validateCode(treeList[i].child, data) === 'boolean') {
  184 + // return validateCode(treeList[i].child, data);
  185 + // }
  186 + // }
  187 + }
  188 + };
  189 +
  190 + //根据code更新tree里对应的key的值
  191 +
  192 + // @ts-ignore
  193 + const handleChange = (e?: any, data?: any, code?: string) => {
  194 + let value,
  195 + oldValue,
  196 + _qxProps = {};
  197 + if (!!e?.target) {
  198 + e.persist();
  199 + value = e.target.value;
  200 + } else {
  201 + value = e;
  202 + }
  203 + if (
  204 + data.type == 'TIME' &&
  205 + (code == 'qxProps-min' || code == 'qxProps-max')
  206 + ) {
  207 + const { qxProps } = data;
  208 + value = moment(value).format(formatEnum[qxProps?.format] || 'YYYY-MM-DD');
  209 + }
  210 +
  211 + if (code == 'type') {
  212 + if (data.child && data.child.length > 0) {
  213 + message.error('该节点含有子节点,无法更改类型,请重试!');
  214 + return;
  215 + }
  216 + }
  217 +
  218 + const isProps = code.indexOf('qxProps');
  219 + const _newCode = isProps > -1 ? code.slice(8) : '';
  220 + const _newData = _.cloneDeep(treeData);
  221 + if (code == 'code') {
  222 + data.code = value;
  223 + const codeValid = validateCode(data);
  224 + if (!codeValid) {
  225 + message.error('变量名不可重复');
  226 + return;
  227 + }
  228 + }
  229 +
  230 + if (isProps == -1) {
  231 + if (!value) {
  232 + value = data[code];
  233 + oldValue = 1;
  234 + }
  235 + }
  236 +
  237 + const loopChangeTree = (treeList: ParamDesignModel[]) => {
  238 + for (let i = 0; i < treeList.length; i++) {
  239 + if (treeList[i].id == data.id) {
  240 + if (isProps > -1) {
  241 + _qxProps = { ...data.qxProps };
  242 + _qxProps[_newCode] = value;
  243 + treeList[i].qxProps = _qxProps;
  244 + } else {
  245 + if (code == 'type') {
  246 + treeList[i].qxProps = {};
  247 + }
  248 + treeList[i][code] = value;
  249 + }
  250 + return;
  251 + } else if (treeList[i].child) {
  252 + loopChangeTree(treeList[i].child);
  253 + }
  254 + }
  255 + };
  256 + loopChangeTree(_newData);
  257 + setTreeData(_newData);
  258 + if (oldValue) {
  259 + setInputKey(inputKey + 1);
  260 + }
  261 + props?.onChange(_newData);
  262 + };
  263 +
  264 + //高级拖拽后
  265 + const handleDrop = (data: any) => {
  266 + const newTreelist = generateList([...data]);
  267 + setTreeData([...data]);
  268 + setList(newTreelist);
  269 + props?.onChange(data);
  270 + };
  271 +
  272 + const handleCancel = (num: number) => {
  273 + setInputKey(num);
  274 + console.log('_cancel', num);
  275 + console.log('inputkey', inputKey);
  276 + setVisible(false);
  277 + };
  278 +
  279 + //打开高级
  280 + const openModal = () => {
  281 + setVisible(true);
  282 + };
  283 +
  284 + // 删除树
  285 + const deleteParameter = (data: ParamDesignModel) => {
  286 + Modal.confirm({
  287 + title: '删除',
  288 + content: `确定要删除此参数吗?`,
  289 + cancelText: '取消',
  290 + okText: '确认',
  291 + okType: 'danger',
  292 + onOk: () => {
  293 + const listData = _.cloneDeep(treeData);
  294 + // const newData = generateTreeData(listData, '');
  295 + const loopDeleteTree = (treeList: ParamDesignModel[]) => {
  296 + for (let i = 0; i < treeList.length; i++) {
  297 + if (treeList[i].id == data.id) {
  298 + treeList.splice(i, 1);
  299 + return;
  300 + } else if (treeList[i].child) {
  301 + loopDeleteTree(treeList[i].child);
  302 + }
  303 + }
  304 + };
  305 + loopDeleteTree(listData);
  306 + props?.onChange(listData);
  307 + message.success('删除成功');
  308 + },
  309 + });
  310 + };
  311 +
  312 + const onDrop: TreeProps['onDrop'] = (info) => {
  313 + const dropKey = info.node.key;
  314 + const dragKey = info.dragNode.key;
  315 + const dropPos = info.node.pos.split('-');
  316 + const dropPosition =
  317 + info.dropPosition - Number(dropPos[dropPos.length - 1]);
  318 + const loop = (
  319 + data: ParamDesignModel[],
  320 + key: React.Key,
  321 + callback: (
  322 + node: ParamDesignModel,
  323 + i: number,
  324 + data: ParamDesignModel[],
  325 + ) => void,
  326 + ) => {
  327 + for (let i = 0; i < data.length; i++) {
  328 + if (data[i]?.id === key) {
  329 + return callback(data[i], i, data);
  330 + }
  331 + if (data[i].child) {
  332 + loop(data[i].child!, key, callback);
  333 + }
  334 + }
  335 + };
  336 +
  337 + let data = _.cloneDeep(treeData);
  338 + // Find dragObject
  339 + let dragObj: ParamDesignModel;
  340 + loop(data, dragKey, (item, index, arr) => {
  341 + arr.splice(index, 1);
  342 + dragObj = item;
  343 + });
  344 + if (!info.dropToGap) {
  345 + // Drop on the content
  346 + loop(data, dropKey, (item) => {
  347 + item.child = item.child || [];
  348 + if (
  349 + item.type == 'OBJECT' ||
  350 + (item.type == 'ARRAY' && item?.child?.length == 0)
  351 + ) {
  352 + dragObj.pid = item?.id;
  353 + item.child.unshift(dragObj);
  354 + } else {
  355 + message.warning('无法拖拽至该节点,请重试!');
  356 + data = treeData;
  357 + }
  358 + // where to insert 示例添加到头部,可以是随意位置
  359 + });
  360 + } else if (
  361 + ((info.node as any).props.child || []).length > 0 && // Has child
  362 + (info.node as any).props.expanded && // Is expanded
  363 + dropPosition === 1 // On the bottom gap
  364 + ) {
  365 + loop(data, dropKey, (item) => {
  366 + item.child = item.child || [];
  367 + // where to insert 示例添加到头部,可以是随意位置
  368 + item.child.unshift(dragObj);
  369 + // in previous version, we use item.child.push(dragObj) to insert the
  370 + // item to the tail of the child
  371 + });
  372 + } else {
  373 + let ar: ParamDesignModel[] = [];
  374 + let i: number;
  375 + loop(data, dropKey, (_item, index, arr) => {
  376 + ar = arr;
  377 + i = index;
  378 + dragObj.pid = '';
  379 + });
  380 + if (dropPosition === -1) {
  381 + ar.splice(i!, 0, dragObj!);
  382 + } else {
  383 + ar.splice(i! + 1, 0, dragObj!);
  384 + }
  385 + }
  386 + // @ts-ignore
  387 + const codeValid = validateCode(dragObj);
  388 + if (codeValid) {
  389 + props.onChange(data);
  390 + } else {
  391 + message.warning('变量名不可重复');
  392 + }
  393 + };
  394 +
  395 + //搜索时
  396 + const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
  397 + e.persist();
  398 + const { value } = e.target;
  399 +
  400 + if (!value) {
  401 + setExpandedKeys(undefined);
  402 + setAutoExpandParent(false);
  403 + setSearchValue(value);
  404 + return;
  405 + }
  406 + const newExpandedKeys = (list || [])
  407 + .map((item) => {
  408 + if (item.title.indexOf(value) > -1 || item.code.indexOf(value) > -1) {
  409 + return getParentKey(item.id, treeData);
  410 + }
  411 + return null;
  412 + })
  413 + .filter((item, i, self) => item && self.indexOf(item) === i);
  414 + setExpandedKeys(newExpandedKeys as React.Key[]);
  415 + setSearchValue(value);
  416 + setAutoExpandParent(true);
  417 + };
  418 +
  419 + //普通增加节点,高级增加当前层级节点
  420 + const handleAdd = (_pid?: string, _type: string = 'STRING') => {
  421 + const _treeData = [...treeData];
  422 + const id = uidGen();
  423 + const code = uidGen(undefined, 6);
  424 + // @ts-ignore
  425 + const loopAddTree = (treeList: any[]) => {
  426 + for (let i = 0; i < treeList.length; i++) {
  427 + if (treeList[i].id == _pid) {
  428 + treeList[i].child.push({
  429 + id,
  430 + code,
  431 + type: _type,
  432 + pid: _pid,
  433 + title: code,
  434 + });
  435 + return;
  436 + } else if (treeList[i].child) {
  437 + loopAddTree(treeList[i].child);
  438 + }
  439 + }
  440 + };
  441 +
  442 + if (!_pid) {
  443 + _treeData.push({ id, code, type: _type, title: code });
  444 + } else {
  445 + loopAddTree(_treeData);
  446 + }
  447 + setTreeData(_treeData);
  448 + props?.onChange(_treeData);
  449 + };
  450 +
  451 + //增加子节点
  452 + const onAddtree = (key: string) => {
  453 + function addNode(pid: string, data: any) {
  454 + data.forEach((item) => {
  455 + const id = uidGen();
  456 + const code = uidGen(undefined, 6);
  457 + if (item.id === pid) {
  458 + if (item.child && item.child.length > 0) {
  459 + item.child.push({ id, type: 'STRING', pid, code, title: code });
  460 + } else {
  461 + item.child = [{ id, type: 'STRING', pid, code, title: code }];
  462 + }
  463 + } else {
  464 + if (item.child) {
  465 + addNode(pid, item.child);
  466 + }
  467 + }
  468 + });
  469 + return data;
  470 + }
  471 + const _treeData = JSON.parse(JSON.stringify(treeData));
  472 + const _treeDataNew = addNode(key, _treeData);
  473 + setTreeData(_treeDataNew);
  474 + props?.onChange(_treeDataNew);
  475 + };
  476 +
  477 + const onExpand = (newExpandedKeys: any) => {
  478 + setExpandedKeys(newExpandedKeys);
  479 + setAutoExpandParent(false);
  480 + };
  481 +
  482 + const checkShowTree = (_data: any) => {
  483 + if (_data.type == 'ARRAY') {
  484 + if (_data.child && _data.child.length > 0) {
  485 + return false;
  486 + }
  487 + }
  488 + return true;
  489 + };
  490 +
  491 + const onFocus = (e) => {
  492 + e.persist();
  493 + const parentNode = e.currentTarget.parentNode.parentNode.parentNode;
  494 + if (!!parentNode) {
  495 + parentNode.style.backgroundColor = '#bae7ff';
  496 + }
  497 + };
  498 +
  499 + const onBlur = (e) => {
  500 + e.persist();
  501 + const parentNode = e.currentTarget.parentNode.parentNode.parentNode;
  502 + const currentNode = e.target.parentNode;
  503 + console.log('currentNode', currentNode);
  504 + if (!!parentNode) {
  505 + parentNode.style.backgroundColor = '';
  506 + }
  507 + if (!!currentNode) {
  508 + currentNode.style.width = '';
  509 + }
  510 + };
  511 +
  512 + // const getValueOptions = (item: any): ValueOptionProps[] | undefined => {
  513 + // const widget = typeTranslateWidget(item.type);
  514 + // if (widget === 'userSelector') {
  515 + // return [];
  516 + // // return [{key: 'MYSELF', value: "当前用户"}]
  517 + // }
  518 + // if (widget === 'orgSelector') {
  519 + // // return [{key: 'MY_ORG', value: "当前人所在部门"}]
  520 + // return [];
  521 + // }
  522 + // if (widget === 'qxDatetime') {
  523 + // return [{ key: 'NOW', value: '当前时间' }];
  524 + // }
  525 + // return undefined;
  526 + // };
  527 +
  528 + const changeField = (val: string, data: amy) => {
  529 + const _newData = _.cloneDeep(treeData);
  530 + const _qxProps = {};
  531 +
  532 + const loopChangeTree = (treeList: ParamDesignModel[]) => {
  533 + for (let i = 0; i < treeList.length; i++) {
  534 + if (treeList[i].id == data.id) {
  535 + if (!treeList[i].qxProps) {
  536 + treeList[i].qxProps = _qxProps;
  537 + }
  538 + if (data.type == 'TIME') {
  539 + treeList[i].qxProps.default = val[0]?.extVal || '';
  540 + treeList[i].mappingValues = [val[0]?.extVal] || [];
  541 + } else {
  542 + treeList[i].qxProps.default = val[0].value;
  543 + treeList[i].mappingValues = [val[0].value];
  544 + }
  545 + return;
  546 + } else if (treeList[i].child) {
  547 + loopChangeTree(treeList[i].child);
  548 + }
  549 + }
  550 + };
  551 +
  552 + loopChangeTree(_newData);
  553 + setTreeData(_newData);
  554 + props?.onChange(_newData);
  555 + };
  556 +
  557 + // 渲染节点
  558 + const renderTitle = (nodeData: any) => {
  559 + const strTitle = (nodeData.title as string) || '';
  560 + // const strCode = nodeData.code as string;
  561 + const index = strTitle.indexOf(searchValue);
  562 + const isShowTree = checkShowTree(nodeData);
  563 + const disabled = nodeData.disabled;
  564 + console.log(index);
  565 + return (
  566 + <div onBlur={(e) => onBlur(e)} tabIndex={0} onFocus={(e) => onFocus(e)}>
  567 + <div
  568 + style={{
  569 + padding: '2px',
  570 + justifyContent: 'flex-end',
  571 + display: 'flex',
  572 + width: '100%',
  573 + flexDirection: 'row-reverse',
  574 + }}
  575 + >
  576 + <div className={'opt-btn'}>
  577 + <Select
  578 + value={nodeData.type}
  579 + disabled={disabled}
  580 + className={'select-tree'}
  581 + bordered={false}
  582 + getPopupContainer={(triggerNode) => triggerNode}
  583 + onChange={(e: any) => {
  584 + handleChange(e, nodeData, 'type');
  585 + }}
  586 + >
  587 + {valueOptions.map((item) => {
  588 + return (
  589 + <Select.Option key={item.key} value={item.key}>
  590 + {item.label}
  591 + </Select.Option>
  592 + );
  593 + })}
  594 + </Select>
  595 + {(nodeData.type === 'OBJECT' || nodeData.type === 'ARRAY') &&
  596 + isShowTree && (
  597 + <Button
  598 + icon={<PlusOutlined />}
  599 + disabled={disabled}
  600 + type="text"
  601 + className="title-btn"
  602 + onClick={() => onAddtree(nodeData.id)}
  603 + />
  604 + )}
  605 + <Button
  606 + className="title-btn-del"
  607 + icon={<DeleteOutlined />}
  608 + disabled={disabled}
  609 + type="text"
  610 + onClick={() => deleteParameter(nodeData)}
  611 + />
  612 + </div>
  613 + <div className="opt-left">
  614 + <Input
  615 + // ref={inputRef}
  616 + key={inputKey}
  617 + style={{ width: '100%' }}
  618 + maxLength={50}
  619 + disabled={disabled}
  620 + bordered={true}
  621 + defaultValue={nodeData.title}
  622 + onBlur={(e) => {
  623 + handleChange(e, nodeData, 'title');
  624 + }}
  625 + />
  626 + </div>
  627 + </div>
  628 + {props?.isShowField && (
  629 + <div className="opt-left-down">
  630 + {/* <FieldSetter
  631 + disabled={disabled}
  632 + value={[
  633 + {
  634 + type: typeTranslateItemtype(nodeData.type),
  635 + value: nodeData?.qxProps?.default || '',
  636 + },
  637 + ]}
  638 + params={{ appCode: 'appCode', useId: true }}
  639 + valueOptions={getValueOptions(nodeData)}
  640 + field={nodeData.code}
  641 + widget={typeTranslateWidget(nodeData.type)}
  642 + fieldType={typeTranslateFieIdtype(nodeData.type)}
  643 + fieldGroupType={typeTranslateGrouptype(nodeData.type)}
  644 + isMixValue={typeTranslateFieIdtype(nodeData.type) == 'STRING' ? true : false}
  645 + colsTree={props.nodeItem}
  646 + isMultiple={false}
  647 + onChange={(val) => changeField(val, nodeData)}
  648 + /> */}
  649 + </div>
  650 + )}
  651 + </div>
  652 + );
  653 + };
  654 +
  655 + const onSelect = (e: any) => {
  656 + handleAdd('', e.key);
  657 + };
  658 +
  659 + return (
  660 + <div>
  661 + <div className={'qx-parameter-setting-content'}>
  662 + <div style={{ display: 'flex', flexDirection: 'row' }}>
  663 + <Dropdown
  664 + trigger={['click']}
  665 + className={'hidden-select'}
  666 + overlay={
  667 + <Menu
  668 + items={valueOptions}
  669 + className={'dropdown'}
  670 + onClick={onSelect}
  671 + />
  672 + }
  673 + >
  674 + <Button type={'link'}>
  675 + <PlusOutlined />
  676 + 添加参数
  677 + </Button>
  678 + </Dropdown>
  679 + <Button
  680 + type={'link'}
  681 + onClick={() => {
  682 + openModal();
  683 + }}
  684 + >
  685 + <SettingOutlined />
  686 + 高级设置
  687 + </Button>
  688 + </div>
  689 + {!props.isHideSearch && (
  690 + <Input
  691 + className={'qx-parameter-setting--search'}
  692 + placeholder="按名称搜索"
  693 + prefix={<SearchOutlined />}
  694 + onChange={onChange}
  695 + />
  696 + )}
  697 + {props.isShowTitle && (
  698 + <div style={{ overflow: 'hidden', textOverflow: 'ellipsis' }}>
  699 + <span style={{ fontSize: '18px' }}>{props.title}</span>
  700 + </div>
  701 + )}
  702 + </div>
  703 + <div className="tree-wrapper">
  704 + {props?.value?.length > 0
  705 + ? treeData?.length > 0 &&
  706 + defaultExpandedKeys && (
  707 + <Tree
  708 + // className={'tree-list'}
  709 + // rootClassName={'tree-list'}
  710 + treeData={treeData || []}
  711 + fieldNames={{
  712 + title: 'label',
  713 + key: 'id',
  714 + children: 'child',
  715 + }}
  716 + titleRender={(nodeData) => renderTitle(nodeData)}
  717 + style={{ height: '100%' }}
  718 + onDrop={onDrop}
  719 + draggable
  720 + blockNode
  721 + selectable
  722 + checkStrictly={true} //??这是啥意思
  723 + expandedKeys={expandedKeys ? expandedKeys : defaultExpandedKeys}
  724 + autoExpandParent={autoExpandParent}
  725 + onExpand={onExpand}
  726 + />
  727 + )
  728 + : null}
  729 + </div>
  730 + <ParameterModal
  731 + nodeItem={props.nodeItem}
  732 + inputKey={inputKey}
  733 + treeData={list}
  734 + data={treeData}
  735 + handleChangeField={changeField}
  736 + handleCancel={handleCancel}
  737 + handleAdd={handleAdd}
  738 + handleDelete={deleteParameter}
  739 + handleChange={handleChange}
  740 + handleDrop={handleDrop}
  741 + handleAddtree={onAddtree}
  742 + visible={visible}
  743 + />
  744 + </div>
  745 + );
  746 +};
  747 +
  748 +// export default QxParameterSetting;
... ...
  1 +/**
  2 + * UUID生成
  3 + *
  4 + * @param len 长度数值
  5 + * @param radix 基数,如:2/10/16
  6 + */
  7 +export const uuidGen = (len?: number, radix?: number) => {
  8 + const chars: string[] =
  9 + '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
  10 + const uuid: string[] = [];
  11 + let i: number;
  12 + const radixNew = radix || chars.length;
  13 +
  14 + if (len) {
  15 + // Compact form
  16 + for (i = 0; i < len; i++) uuid[i] = chars[0 | (Math.random() * radixNew)];
  17 + } else {
  18 + // rfc4122, version 4 form
  19 + let r;
  20 +
  21 + // rfc4122 requires these characters
  22 + uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
  23 + uuid[14] = '4';
  24 +
  25 + // Fill in random data. At i==19 set the high bits of clock sequence as
  26 + // per rfc4122, sec. 4.1.5
  27 + for (i = 0; i < 36; i++) {
  28 + if (!uuid[i]) {
  29 + r = 0 | (Math.random() * 16);
  30 + uuid[i] = chars[i === 19 ? (r & 0x3) | 0x8 : r];
  31 + }
  32 + }
  33 + }
  34 + return uuid.join('');
  35 +};
  36 +
  37 +/**
  38 + * 唯一ID生成(小写,无'-'字符)
  39 + *
  40 + * @param prefix
  41 + * @param len
  42 + * @param radix
  43 + */
  44 +export const uidGen = (prefix?: string, len?: number, radix?: number) => {
  45 + return (prefix || '') + uuidGen(len, radix).replaceAll('-', '').toLowerCase();
  46 +};
... ...
  1 +/* stylelint-disable declaration-block-no-redundant-longhand-properties */
  2 +.border-none .ant-select:not(.ant-select-customize-input) .ant-select-selector {
  3 + border: none;
  4 + box-shadow: none;
  5 +}
  6 +
  7 +.qx-parameter-setting-content {
  8 + position: relative;
  9 + display: flex;
  10 + flex-direction: row-reverse;
  11 + flex-wrap: nowrap;
  12 + justify-content: space-between;
  13 + // flex-shrink:0;
  14 + // min-height: 32px;
  15 + // padding: 1px;
  16 + // position: 'relative', display: 'flex', flexWrap: 'wrap'
  17 +
  18 + // > .ant-tag {
  19 + // margin: 3px;
  20 +
  21 + // &:first-child {
  22 + // margin-left: 10px;
  23 + // }
  24 +
  25 + // ~ .qx-tags-input__box {
  26 + // padding-left: 5px;
  27 + // }
  28 + // }
  29 +}
  30 +
  31 +.tree-wrapper {
  32 + margin-top: 20px;
  33 +
  34 + .ant-tree-treenode {
  35 + padding-top: 4px !important;
  36 + border-radius: 4px;
  37 +
  38 + &:hover {
  39 + background-color: #f4f4f5;
  40 + }
  41 + }
  42 +
  43 + .ant-tree .ant-tree-node-content-wrapper.ant-tree-node-selected {
  44 + background-color: transparent;
  45 + }
  46 +
  47 + .ant-tree .ant-tree-node-content-wrapper:hover {
  48 + background-color: transparent;
  49 + }
  50 +}
  51 +
  52 +// .ant-tree-node-selected:hover ~ .ant-tree-treenode:hover{
  53 +// background-color: #bae7ff !important;
  54 +// }
  55 +
  56 +// .ant-tree-node-content-wrapper :hover ~ .ant-tree-treenode{
  57 +// // background-color: #F4F4F5;
  58 +// // padding-top: 4px;
  59 +// }
  60 +
  61 +// .tree-list :hover{
  62 +// background-color: #ff72;
  63 +// }
  64 +
  65 +// .ant-tree .ant-tree-treenode :hover{
  66 +// background-color: #00f;
  67 +// border-radius:4px;
  68 +// }
  69 +
  70 +.border-none
  71 + .ant-select-focused:not(.ant-select-disabled).ant-select:not(
  72 + .ant-select-customize-input
  73 + )
  74 + .ant-select-selector {
  75 + border: none;
  76 + box-shadow: none;
  77 +}
  78 +
  79 +.hidden-tree {
  80 + .ant-select-tree-switcher-noop {
  81 + display: none;
  82 + }
  83 +
  84 + .ant-select-tree-treenode {
  85 + text-align: center;
  86 + }
  87 +}
  88 +
  89 +.opt-btn {
  90 + display: flex;
  91 + // width: 180px;
  92 + flex-direction: row;
  93 + align-items: center;
  94 + margin-left: 10px;
  95 +
  96 + .title-btn-del {
  97 + display: none;
  98 + color: #666;
  99 +
  100 + &:hover {
  101 + color: red;
  102 + opacity: 1;
  103 + }
  104 + }
  105 +
  106 + .title-btn {
  107 + display: none;
  108 + color: #666;
  109 +
  110 + &:hover {
  111 + color: #91d5ff;
  112 + opacity: 1;
  113 + }
  114 + }
  115 +
  116 + .select-tree {
  117 + height: 90%;
  118 + background-color: #fff;
  119 + border-radius: 3px;
  120 + }
  121 +}
  122 +
  123 +.opt-left {
  124 + display: flex;
  125 + // transition: all 0.5s ease-in-out;
  126 + align-items: center;
  127 + // -webkit-transition: width .4s;
  128 + // transition: width .4s;
  129 + width: 100%;
  130 + margin-top: 2px;
  131 + // min-width: 100px;
  132 + margin-bottom: 2px;
  133 + overflow: hidden;
  134 + text-overflow: ellipsi;
  135 +}
  136 +
  137 +.opt-left-down {
  138 + display: flex;
  139 + // transition: all 0.5s ease-in-out;
  140 + // -webkit-transition: width .4s;
  141 + // transition: width .4s;
  142 + align-items: center;
  143 + width: 100%;
  144 + // min-width: 100px;
  145 + margin-top: 2px;
  146 + margin-bottom: 2px;
  147 + overflow: hidden;
  148 + text-overflow: ellipsi;
  149 +}
  150 +
  151 +// .ant-tree-node-content-wrapper :hover .select-tree {
  152 +// // display: none;
  153 +// // padding: 2px;
  154 +// // fle
  155 +// height: 90%;
  156 +// border-radius: 3px;
  157 +// background-color: #fff;
  158 +// }
  159 +
  160 +.ant-tree-node-content-wrapper :hover .opt-left {
  161 + width: 65%;
  162 + // height: 100%;
  163 + // transform: scale(0.5) translate(-25%, -25%)
  164 +}
  165 +
  166 +// .ant-tree .ant-tree-node-content-wrapper.ant-tree-node-selected .opt-left {
  167 +// // height: 100%;
  168 +// width: 65%;
  169 +// // transform: scale(0.5) translate(-25%, -25%)
  170 +// }
  171 +
  172 +.ant-tree-node-content-wrapper :hover .opt-left-down {
  173 + width: 85%;
  174 +}
  175 +
  176 +// .ant-tree .ant-tree-node-content-wrapper.ant-tree-node-selected .opt-left-down {
  177 +// width: 85%;
  178 +// }
  179 +
  180 +@keyframes title-btn-del {
  181 + 0% {
  182 + opacity: 0;
  183 + }
  184 +
  185 + 20% {
  186 + opacity: 0.3;
  187 + }
  188 +
  189 + 50% {
  190 + opacity: 0.4;
  191 + }
  192 +
  193 + 70% {
  194 + opacity: 0.6;
  195 + }
  196 +
  197 + 100% {
  198 + opacity: 0.8;
  199 + }
  200 +}
  201 +
  202 +@keyframes title-btn {
  203 + 0% {
  204 + opacity: 0;
  205 + }
  206 +
  207 + 20% {
  208 + opacity: 0.3;
  209 + }
  210 +
  211 + 50% {
  212 + opacity: 0.4;
  213 + }
  214 +
  215 + 70% {
  216 + opacity: 0.6;
  217 + }
  218 +
  219 + 100% {
  220 + opacity: 0.8;
  221 + }
  222 +}
  223 +
  224 +.ant-tree-node-content-wrapper :hover .title-btn-del {
  225 + display: block;
  226 + animation-name: title-btn-del;
  227 + animation-duration: 2s;
  228 + animation-iteration-count: 1;
  229 +}
  230 +
  231 +.ant-tree-node-content-wrapper :hover .title-btn {
  232 + display: block;
  233 + animation-name: title-btn-del;
  234 + animation-duration: 2s;
  235 + animation-iteration-count: 1;
  236 +}
  237 +
  238 +.btn-high-del {
  239 + &:hover {
  240 + color: red !important;
  241 + }
  242 +}
  243 +
  244 +.editable-row:hover .editable-cell-value-wrap {
  245 + padding: 4px 11px;
  246 + border: 1px solid #d9d9d9;
  247 + border-radius: 2px;
  248 +}
  249 +
  250 +.editable-cell {
  251 + position: relative;
  252 +}
  253 +
  254 +.editable-center-cell {
  255 + display: flex;
  256 + flex-direction: row;
  257 + align-items: center;
  258 + justify-content: center;
  259 +}
  260 +
  261 +.editable-around-cell {
  262 + display: flex;
  263 + flex-direction: row;
  264 + justify-content: space-around;
  265 +}
  266 +
  267 +.editable-cell-value-wrap {
  268 + min-height: 30px;
  269 + padding: 5px 12px;
  270 + border-radius: 2px;
  271 + cursor: pointer;
  272 + display: flex;
  273 + flex-direction: row;
  274 + align-items: center;
  275 +}
  276 +
  277 +.editable-cell-value-wrap-none {
  278 + min-height: 30px;
  279 + padding: 5px 12px;
  280 + display: flex;
  281 + flex-direction: row;
  282 + align-items: center;
  283 +}
  284 +
  285 +.hidden-select {
  286 + .ant-select-selector {
  287 + visibility: hidden;
  288 + }
  289 +
  290 + .ant-select-arrow {
  291 + visibility: hidden;
  292 + }
  293 +
  294 + .ant-select-tree-switcher-noop {
  295 + display: none;
  296 + }
  297 +
  298 + .ant-select-tree-treenode {
  299 + text-align: center;
  300 + }
  301 +}
  302 +
  303 +.dropdown {
  304 + min-width: 80px;
  305 + overflow: auto;
  306 + text-align: center !important;
  307 +}
  308 +
  309 +//TODO 写法不行
  310 +// #root .hidden-select {
  311 +// .ant-select-tree
  312 +// .ant-select-tree-node-content-wrapper.ant-select-tree-node-selected {
  313 +// // background-color: #bae7ff;
  314 +// background-color: @primary-2;
  315 +// }
  316 +// }
  317 +// .ant-form-item
  318 +// .qx-parameter-setting__tree-list {
  319 +// .ant-tree-draggable-icon {
  320 +// line-height: 32px;
  321 +// }
  322 +
  323 +// &.ant-tree
  324 +// .ant-tree-treenode:not(.ant-tree-treenode-disabled)
  325 +// .ant-tree-node-content-wrapper {
  326 +// border-radius: 4px;
  327 +
  328 +// &.ant-tree-node-selected {
  329 +// background-color: transparent;
  330 +// }
  331 +
  332 +// &:hover,
  333 +// &.ant-tree-node-selected:hover {
  334 +// background-color: @N3;
  335 +// // opacity: 1 !important;
  336 +// // background-color: #91d5ff;
  337 +// }
  338 +// }
  339 +// }
  340 +
  341 +// .ant-form-item{
  342 +// margin-bottom: 0;
  343 +// }
  344 +
  345 +.json-editor {
  346 + width: 90%;
  347 + margin-bottom: 20px;
  348 + padding: 0;
  349 + // 这句是必要的,是要解决一个样式的Bug
  350 + :global(.ace-jsoneditor) {
  351 + min-height: 350px;
  352 + font-size: 12px !important;
  353 + }
  354 +
  355 + :global(.jsoneditor-menu) {
  356 + display: none;
  357 + }
  358 +
  359 + :global(.jsoneditor-navigation-bar) {
  360 + display: none;
  361 + }
  362 +
  363 + :global(.jsoneditor-outer.has-main-menu-bar) {
  364 + margin-top: 0 !important;
  365 + padding-top: 0 !important;
  366 + }
  367 +}
... ...
... ... @@ -9,7 +9,8 @@
9 9 "paths": {
10 10 "@@/*": [".dumi/tmp/*"],
11 11 "@qx/common ": ["src"],
12   - "@qx/common /*": ["src/*", "*"]
  12 + "@qx/common /*": ["src/*", "*"],
  13 + "@qx/*": ["./*/"]
13 14 }
14 15 },
15 16 "include": [".dumi/**/*", ".dumirc.ts", "src/**/*", "typings.d.ts"]
... ...