我们是
袋鼠云数栈 UED 团队
,致力于打造优秀的一站式数据中台产品。我们始终保持工匠精神,探索前端道路,为社区积累并传播经验价值。

本文作者:
霜序
本文首发于:
https://juejin.cn/post/7299384698882539574

在大数据业务中,时常会出现且或关系逻辑的拼接,有需要做成可视化配置,如下图

file

目前该组件已经开源到了我们组件库
dt-react-component

详细查看

前期分析

需要确定好数据结构

因为是嵌套结构,可以通过 ➕➖ 来增加层级或者数据,因此采用树形结构来存储数据。

export interface IFilterValue<T> {
  key: string;
  level?: number; // 当前节点的层级,用于判断一些按钮的展示
  type?: number; // 当前节点的条件关系,1 | 2
  rowValues?: T; // Form 节点的相关的信息(子节点无条件节点时才有)
  children?: IFilterValue<T>[]; // 子节点的信息(子节点存在条件节点时才有)
}

上述的图片的数据为:

 {
    "key": "qTipLrlUt",
    "level": 1,
    "children": [
        {
            "key": "B6Jrbqcfof",
            "type": 2,
            "level": 2,
            "children": [
                {
                    "rowValues": {
                        "condition": 1,
                        "rowPermission": ""
                    },
                    "key": "deg8x8UgZ",
                    "level": 2
                },
                {
                    "key": "_sczw_1h8H",
                    "type": 1,
                    "level": 3,
                    "children": [
                        {
                            "key": "Z5UkUPJoA",
                            "rowValues": {
                                "condition": 1,
                                "rowPermission": ""
                            },
                            "level": 3
                        },
                        {
                            "key": "MbpJILqHGx",
                            "rowValues": {
                                "condition": 1,
                                "rowPermission": ""
                            },
                            "level": 3
                        }
                    ]
                }
            ]
        },
        {
            "rowValues": {
                "condition": 1,
                "rowPermission": ""
            },
            "key": "qx6bG0o5H",
            "level": 1
        }
    ],
    "type": 1
}

明确每个操作按钮的实现

明确组件的封装

  • 组件只希望实现条件节点/线条/操作按钮的展示,因此后面的组件需要作为参数 component 传入
  • 组件对层级有一个控制,支持 maxLevel 来控制
  • 每一次新增数据的时候,默认值需要传入
    initValues
  • 支持两种模式 编辑状态 和 查看状态
  • 支持受控和非受控两种模式

组件封装

FilterRules

提供给用户使用的组件,实现数据的增删改查操作。可以采用受控和非受控两种模式。
它接受的参数如下:

interface IProps<T> {
  value?: IFilterValue<T>;
  disabled?: boolean;
  maxLevel?: number;
  initValues: T;
  notEmpty?: { data: boolean; message?: string };
  component: (props: IComponentProps<T>) => React.ReactNode;
  onChange?: (value: IFilterValue<T> | undefined) => void;
}
export const FilterRules = <T>(props: IProps<T>) => {
  const {
    component,
    maxLevel = 5,
    disabled = false,
    notEmpty = { data: true, message: '必须有一条数据' },
    value,
    initValues,
    onChange,
  } = props;
  // 查找当前操作的节点
  const finRelationNode = (
    parentData: IFilterValue<T>,
    targetKey: string,
    needCurrent?: boolean,
  ): IFilterValue<T> | null | undefined => {};
  const handleAddCondition = (keyObj: { key: string; isOut?: boolean }) => {};
  // 增加新的数据,判断是在当前节点下新增或者新生成一个条件节点
  const addCondition = (
    treeNode: any,
    keyObj: { key: string; isOut?: boolean },
    initRowValue: T,
  ) => {};
  const handleDeleteCondition = (key: string) => {};
  // 删除节点,删除当前节点下的一条数据或者是删除一个条件节点
  const deleteCondition = (parentData: IFilterValue<T>, key: string) => {};
  // 删除一个条件节点时,更新当前数据的层级
  const updateLevel = (node: IFilterValue<T>) => {};
  // 更改条件节点的条件
  const handleChangeCondition = (
    key: string,
    type: ROW_PERMISSION_RELATION,
  ) => {};
  // 改变节点的的数据
  const handleChangeRowValues = (key: string, values: T) => {};
  return (
    <RulesController<T>
      maxLevel={maxLevel}
      disabled={disabled}
      value={value}
      component={component}
      onAddCondition={handleAddCondition}
      onDeleteCondition={handleDeleteCondition}
      onChangeCondition={handleChangeCondition}
      onChangeRowValues={handleChangeRowValues}
    />
  );
};

编辑情况

非受控组件使用
<Form form={form}>
  <Form.Item name={'condition'}>
    <FilterRules<IRowValue>
      component={(props) => (
        <RowColumnConfig columns={record?.columns ?? []} {...props} />
      )}
      maxLevel={MAX_LEVEL}
      initValues={INIT_ROW_VALUES}
    />
  </Form.Item>
</Form>;

// RowColumnConfig 实现,name 可能是 children[0].formValues
<Form.Item
  name={['condition', ...name, 'column']}
  rules={[{ message: '请选择字段', required: true }]}
  initialValue={column}
>
  <Select placeholder="请选择字段">
    {columns.map((item) => (
      <Option key={item} value={item}>
        {item}
      </Option>
    ))}
  </Select>
</Form.Item>;

// 最后通过 form.validateFields() 拿到的和上述的数据结构一致
受控组件使用
const [ruleData, setRuleData] = useState({
  key: shortid(),
  level: 0,
  rowValues: {
    column: first.column,
    condition: first.condition,
    rowPermission: first?.value,
  },
});

<FilterRules<IRowValue>
  value={ruleData}
  component={(props) => (
    <RowColumnConfig columns={record?.columns ?? []} {...props} />
  )}
  maxLevel={MAX_LEVEL}
  initValues={INIT_ROW_VALUES}
  onChange={setRuleData}
/>;
// 通过 ruleData 就能够拿到最后的结果

查看使用

<FilterRules
  component={(props) => <RowColumnConfig columns={[]} {...props} />}
  disabled
  value={value}
/>

编辑查看使用(后续新增)

file

上图为最后实现的效果,适用于部分数据禁用且可以编辑其他数据。常见业务情景:上一次保存的数据不可修改,但需要在当前基础上继续新增数据。
在这种使用模式下,FilterRules 组件上的 props 依旧为 false,通过设置 value 中每一个节点的 disabled 属性来实现上述功能

// 修改 IFilterValue 的类型
//

标签: none

添加新评论