• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

SkylerHu / antd-restful / #3

10 Jul 2025 02:38PM UTC coverage: 77.983%. First build
#3

push

web-flow
feat: 扩展组件支持远程获取数据 (#1)

扩展组件支持远程获取数据

1016 of 1392 branches covered (72.99%)

Branch coverage included in aggregate %.

1352 of 1644 new or added lines in 28 files covered. (82.24%)

1389 of 1692 relevant lines covered (82.09%)

26.95 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

87.23
/src/components/formitems/TableSelect.jsx
1
import React, { useCallback, useEffect, useMemo, useState } from "react";
2
import PropTypes from "prop-types";
3
import { version as antdVersion, Button, Collapse, Space } from "antd";
4
import { CloseOutlined } from "@ant-design/icons";
5
import { dequal as deepEqual } from "dequal";
6
import { isArray, isDict, isFunction } from "src/common/typeTools";
7
import RestTable from "src/components/RestTable";
8

9
const TableSelect = ({
2✔
10
  value,
11
  onChange,
12
  disabled = false,
24✔
13
  readOnly = false,
24✔
14
  expandSelected = true,
26✔
15
  rowKey = "id",
×
16
  columns = [],
×
17
  antdTableProps,
18
  antdCollapseProps,
19
  antdSpaceProps,
20
  ...restProps
21
}) => {
22
  const [selectedKeys, setSelectedKeys] = useState([]);
28✔
23
  const [selectedRows, setSelectedRows] = useState([]);
28✔
24

25
  useEffect(() => {
28✔
26
    setSelectedKeys((oldv) => {
14✔
27
      let newV = [];
14✔
28
      if (isArray(value)) {
14✔
29
        newV = value.map((v) => v[rowKey]);
13✔
30
      }
31
      if (deepEqual(oldv, newV)) {
14✔
32
        return oldv;
5✔
33
      }
34
      return newV;
9✔
35
    });
36
    setSelectedRows((oldV) => {
14✔
37
      const newV = value || [];
14✔
38
      if (deepEqual(oldV, newV)) {
14✔
39
        return oldV;
5✔
40
      }
41
      return newV;
9✔
42
    });
43
  }, [value, rowKey]);
44

45
  const updateSelectedRows = useCallback(
28✔
46
    (keys, rows) => {
47
      setSelectedKeys(keys);
3✔
48
      // 保留已选中的行
49
      let newRows = selectedRows.filter((item) => isDict(item) && keys.includes(item[rowKey]));
3✔
50
      if (isArray(rows)) {
3✔
51
        const partKeys = newRows.map((item) => item[rowKey]);
2✔
52
        // 添加新选中的行
53
        const partRows = rows.filter(
2✔
54
          (item) => isDict(item) && !partKeys.includes(item[rowKey]) && keys.includes(item[rowKey])
5✔
55
        );
56
        newRows = [...newRows, ...partRows];
2✔
57
      }
58
      if (deepEqual(newRows, selectedRows)) {
3!
NEW
59
        return;
×
60
      }
61
      setSelectedRows(newRows);
3✔
62
      if (isFunction(onChange)) {
3!
63
        onChange(newRows);
3✔
64
      }
65
    },
66
    [rowKey, onChange, selectedRows]
67
  );
68

69
  // 添加取消选择按钮
70
  const columensWithActions = useMemo(() => {
28✔
71
    let _columns = [...columns];
25✔
72
    if (!disabled && !readOnly) {
25✔
73
      _columns.push({
17✔
74
        title: "取消",
75
        key: "actions",
76
        width: 80,
77
        render: (text, record) => {
78
          return (
13✔
79
            <Button
80
              icon={<CloseOutlined style={{ color: "red" }} />}
81
              type="text"
82
              onClick={() => updateSelectedRows(selectedKeys.filter((k) => k !== record[rowKey]))}
1✔
83
            />
84
          );
85
        },
86
      });
87
    }
88
    return _columns;
25✔
89
  }, [rowKey, selectedKeys, columns, updateSelectedRows, disabled, readOnly]);
90

91
  const readOnlyView = useMemo(() => {
28✔
92
    return (
28✔
93
      <RestTable
94
        tools={false}
95
        {...restProps}
96
        baseParams={{}}
97
        forceParams={{}}
98
        restful={null}
99
        dataSource={selectedRows}
100
        rowKey={rowKey}
101
        columns={columensWithActions}
102
      />
103
    );
104
  }, [selectedRows, rowKey, columensWithActions, restProps]);
105

106
  if (disabled || readOnly) {
28✔
107
    return readOnlyView;
8✔
108
  }
109
  return (
20✔
110
    <Space.Compact block direction="vertical" gap={0} {...antdSpaceProps}>
111
      {antdVersion && antdVersion >= "5" ? (
60!
112
        <Collapse
113
          defaultActiveKey={expandSelected ? "title" : undefined}
20!
114
          {...antdCollapseProps}
115
          items={[
116
            {
117
              key: "title",
118
              label: `选中 ${selectedRows?.length || 0} 条数据`,
30✔
119
              children: readOnlyView,
120
            },
121
          ]}
122
        />
123
      ) : (
124
        <Collapse defaultActiveKey={expandSelected ? "title" : undefined} {...antdCollapseProps}>
×
125
          <Collapse.Panel key="title" header={`选中 ${selectedRows?.length || 0} 条数据`}>
×
126
            {readOnlyView}
127
          </Collapse.Panel>
128
        </Collapse>
129
      )}
130
      <RestTable
131
        tools={false}
132
        {...restProps}
133
        rowKey={rowKey}
134
        columns={columns}
135
        antdTableProps={{
136
          ...antdTableProps,
137
          rowSelection: disabled ? undefined : {
20!
138
            ...antdTableProps?.rowSelection,
139
            hideSelectAll: disabled || antdTableProps?.rowSelection?.hideSelectAll,
40✔
140
            preserveSelectedRowKeys: true, // 当数据被删除时仍然保留选项的 key
141
            selectedRowKeys: selectedKeys,
142
            onChange: (_selectedRowKeys, _selectedRows) => {
143
              updateSelectedRows(_selectedRowKeys, _selectedRows);
2✔
144
            },
145
            getCheckboxProps: (record) => ({
39✔
146
              disabled: disabled || record.disabled,
78✔
147
            }),
148
          },
149
        }}
150
      />
151
    </Space.Compact>
152
  );
153
};
154

155
TableSelect.propTypes = {
2✔
156
  // 值仅支持 [{}] 格式
157
  value: PropTypes.arrayOf(PropTypes.object),
158
  onChange: PropTypes.func,
159

160
  // 禁用后只读
161
  disabled: PropTypes.bool,
162
  readOnly: PropTypes.bool,
163
  // 是否默认展开显示选中数据
164
  expandSelected: PropTypes.bool,
165

166
  rowKey: PropTypes.string,
167
  columns: PropTypes.array,
168
  antdTableProps: PropTypes.object,
169
  antdCollapseProps: PropTypes.object,
170
  antdSpaceProps: PropTypes.object,
171
};
172

173
export default TableSelect;
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc