@hzab/list-render 1.9.2 → 1.9.3-beta1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ # @hzab/list-render@1.9.3
2
+
3
+ feat: 列表请求取消上一次列表请求,解决数据返回先后顺序导致展示异常问题
4
+
1
5
  # @hzab/list-render@1.9.2
2
6
 
3
7
  fix: Drawer 模式 首次编辑 scenario 状态不正确问题修复
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hzab/list-render",
3
- "version": "1.9.2",
3
+ "version": "1.9.3-beta1",
4
4
  "description": "",
5
5
  "main": "src",
6
6
  "scripts": {
@@ -20,7 +20,7 @@
20
20
  "license": "ISC",
21
21
  "devDependencies": {
22
22
  "@ant-design/icons": "^4.8.1",
23
- "@hzab/data-model": "^1.6.0",
23
+ "@hzab/data-model": "^1.7.4",
24
24
  "@hzab/form-render": "^1.1.5",
25
25
  "@hzab/schema-descriptions": "^1.0.0",
26
26
  "@hzab/webpack-config": "^0.7.2",
@@ -40,7 +40,7 @@
40
40
  "@formily/core": "2.3.1",
41
41
  "@formily/react": "2.3.1",
42
42
  "@formily/reactive-react": "2.3.1",
43
- "@hzab/data-model": ">=1.5.0",
43
+ "@hzab/data-model": ">=1.7.4",
44
44
  "@hzab/form-render": ">=1.0.0",
45
45
  "@hzab/schema-descriptions": ">=1.0.0",
46
46
  "antd": "4.x",
@@ -1,4 +1,4 @@
1
- import ListRender from "./list-render.jsx";
1
+ import ListRender from "./list-render";
2
2
 
3
3
  export * from "@hzab/data-model";
4
4
 
@@ -5,6 +5,8 @@ model 不要定义在组件外部,避免出现 query 异常的情况。
5
5
  import { forwardRef, useEffect, useImperativeHandle, useRef, useState } from "react";
6
6
  import { Button, message } from "antd";
7
7
  import _ from "lodash";
8
+ import axios, { getCancelTokenSource } from "@hzab/data-model/src/axios";
9
+ import { CancelTokenSource } from "axios";
8
10
 
9
11
  import QueryRender from "./query-render";
10
12
  import Pagination from "./pagination-render";
@@ -14,9 +16,11 @@ import DetailModal from "./DetailModal";
14
16
 
15
17
  import { objToFormData } from "./common/utils";
16
18
 
19
+ import { IListRenderProps, IFormModal, IDetailModal, IQuery } from "./type";
20
+
17
21
  import "./index.less";
18
22
 
19
- const ListRender = forwardRef(function (props, parentRef) {
23
+ const ListRender = forwardRef(function (props: IListRenderProps, parentRef) {
20
24
  const {
21
25
  idKey = "id",
22
26
  i18n,
@@ -34,20 +38,26 @@ const ListRender = forwardRef(function (props, parentRef) {
34
38
  * 表单提交是否使用 FormData 格式
35
39
  */
36
40
  useFormData: _useFormData,
41
+ /**
42
+ * 是否有分页
43
+ */
44
+ hasPagination = true,
37
45
  } = props;
46
+
38
47
  const { createText = props.createText } = i18n || {};
39
48
  const [total, setTotal] = useState(0);
40
49
  const [list, setList] = useState([]);
41
50
  const [formState, setFormState] = useState("");
42
51
  const [rowId, setRowId] = useState(0);
43
52
  const [listLoading, setListLoading] = useState(false);
44
- const formModalRef = useRef();
45
- const detailModalRef = useRef();
46
- const queryRef = useRef();
47
- const modelQueryRef = useRef({});
48
- const formQueryRef = useRef({});
49
- const paginationQueryRef = useRef({ pageNum: 1, pageSize: 10 });
53
+ const formModalRef = useRef<IFormModal>();
54
+ const detailModalRef = useRef<IDetailModal>();
55
+ const queryRef = useRef<IQuery>();
56
+ const formQueryRef = useRef<IQuery>({});
57
+ const modelQueryRef = useRef<IQuery>({});
58
+ const paginationQueryRef = useRef<IQuery>(hasPagination ? { pageNum: 1, pageSize: 10 } : {});
50
59
  const useFormData = _useFormData ?? dialogConf.useFormData ?? modalConf?.useFormData;
60
+ const getListSourceRef = useRef<CancelTokenSource>();
51
61
 
52
62
  useImperativeHandle(parentRef, () => ({
53
63
  getList,
@@ -61,7 +71,7 @@ const ListRender = forwardRef(function (props, parentRef) {
61
71
  onDel,
62
72
  }));
63
73
 
64
- const { schema = {}, config = {}, model = {}, msgConf = {} } = props;
74
+ const { schema, config = {}, model, msgConf = {} }: IListRenderProps = props;
65
75
 
66
76
  useEffect(() => {
67
77
  if (model) {
@@ -70,7 +80,9 @@ const ListRender = forwardRef(function (props, parentRef) {
70
80
  } else {
71
81
  modelQueryRef.current = model?.query;
72
82
  }
73
- model.query.pageNum = 1;
83
+ if (hasPagination) {
84
+ model.query.pageNum = 1;
85
+ }
74
86
  }
75
87
  !props.closeAutoRequest && getList();
76
88
  }, []);
@@ -98,7 +110,7 @@ const ListRender = forwardRef(function (props, parentRef) {
98
110
  if (!model?.getList && Array.isArray(props.list)) {
99
111
  setListLoading(true);
100
112
  const { list } = props;
101
- const { pageNum = 1, pageSize = 10 } = modelQueryRef.current || {};
113
+ const { pageNum = 1, pageSize = hasPagination ? 10 : Infinity } = modelQueryRef.current || {};
102
114
  setList(list.slice(pageSize * (pageNum - 1), pageNum * pageSize));
103
115
  setTotal(list.length);
104
116
  props.onGetListEnd && props.onGetListEnd({ list, pagination: { pageNum, pageSize } });
@@ -129,18 +141,37 @@ const ListRender = forwardRef(function (props, parentRef) {
129
141
 
130
142
  model.query = mergedQueries;
131
143
 
144
+ // 取消上一次请求
145
+ getListSourceRef.current?.cancel(
146
+ JSON.stringify({ code: 601, message: "取消上一次请求", getListApi: model.getListApi, query: model.query }),
147
+ );
148
+
149
+ // 重新获取 source
150
+ getListSourceRef.current = getCancelTokenSource();
151
+
132
152
  model
133
- ?.getList(mergedQueries)
153
+ ?.getList(
154
+ mergedQueries,
155
+ {},
156
+ {
157
+ cancelToken: getListSourceRef.current?.token,
158
+ },
159
+ )
134
160
  .then((res) => {
161
+ getListSourceRef.current = null;
135
162
  setList(res.list);
136
163
  setTotal(res.pagination?.total);
137
164
  props.onGetListEnd && props.onGetListEnd(res);
138
165
  setListLoading(false);
139
166
  })
140
167
  .catch((err) => {
141
- console.error(err);
142
- handleMessage(err._message);
168
+ if (axios.isCancel(err)) {
169
+ console.info(`请求已取消:`, "", err.message);
170
+ return Promise.reject(err);
171
+ }
172
+ handleMessage(err?._message);
143
173
  setListLoading(false);
174
+ return Promise.reject(err);
144
175
  });
145
176
  }
146
177
 
@@ -166,7 +197,9 @@ const ListRender = forwardRef(function (props, parentRef) {
166
197
  model.query.pageSize = 10;
167
198
  }
168
199
  formQueryRef.current = query;
169
- model.query = Object.assign(model.query, query);
200
+ if (model.query) {
201
+ model.query = Object.assign(model.query, query);
202
+ }
170
203
  getList(query);
171
204
  }
172
205
 
@@ -200,7 +233,7 @@ const ListRender = forwardRef(function (props, parentRef) {
200
233
 
201
234
  function onDetail(row, idx) {
202
235
  if (props.fetchOnEdit !== false) {
203
- const getQuery = {};
236
+ const getQuery = { id: undefined };
204
237
  if (props.fetchById !== false) {
205
238
  getQuery.id = row[idKey];
206
239
  } else {
@@ -214,6 +247,7 @@ const ListRender = forwardRef(function (props, parentRef) {
214
247
  .catch((err) => {
215
248
  console.error("err", err);
216
249
  handleMessage(err._message);
250
+ return Promise.reject(err);
217
251
  });
218
252
  } else {
219
253
  handleDetail(row, row[idKey]);
@@ -227,7 +261,9 @@ const ListRender = forwardRef(function (props, parentRef) {
227
261
 
228
262
  function onEdit(row, idx) {
229
263
  if (props.fetchOnEdit !== false) {
230
- const getQuery = {};
264
+ const getQuery = {
265
+ id: undefined,
266
+ };
231
267
  if (props.fetchById !== false) {
232
268
  getQuery.id = row[idKey];
233
269
  } else {
@@ -241,6 +277,7 @@ const ListRender = forwardRef(function (props, parentRef) {
241
277
  .catch((err) => {
242
278
  console.error("err", err);
243
279
  handleMessage(err._message);
280
+ return Promise.reject(err);
244
281
  });
245
282
  } else {
246
283
  handleEdit(row, row[idKey]);
@@ -256,7 +293,7 @@ const ListRender = forwardRef(function (props, parentRef) {
256
293
  async function onEditSubmit(data) {
257
294
  let _data = data;
258
295
  if (isPatchUpdate) {
259
- if (model?.patchMap === "function") {
296
+ if (typeof model?.patchMap === "function") {
260
297
  _data = model.patchMap(data);
261
298
  }
262
299
  } else if (typeof model?.updateMap === "function") {
@@ -291,6 +328,7 @@ const ListRender = forwardRef(function (props, parentRef) {
291
328
  })
292
329
  .catch((err) => {
293
330
  handleMessage(err._message);
331
+ return Promise.reject(err);
294
332
  });
295
333
  }
296
334
 
@@ -408,10 +446,4 @@ const ListRender = forwardRef(function (props, parentRef) {
408
446
  );
409
447
  });
410
448
 
411
- ListRender.defaultProps = {
412
- model: {
413
- query: {},
414
- },
415
- };
416
-
417
449
  export default ListRender;
package/src/type.ts ADDED
@@ -0,0 +1,335 @@
1
+ import { Schema } from "@formily/react";
2
+
3
+ /**
4
+ * 文案
5
+ */
6
+ export interface II18n {
7
+ /**
8
+ * 新增按钮文案 默认 新增
9
+ */
10
+ createText?: string;
11
+ }
12
+
13
+ /**
14
+ * 弹窗配置
15
+ */
16
+ export interface IModalConf {
17
+ /**
18
+ * 使用 FormData 格式传输数据
19
+ */
20
+ useFormData?: boolean;
21
+ }
22
+
23
+ /**
24
+ * query 参数
25
+ */
26
+ export interface IQuery {
27
+ /**
28
+ * 分页当前页码
29
+ */
30
+ pageNum?: number;
31
+ /**
32
+ * 分页条数
33
+ */
34
+ pageSize?: number;
35
+ }
36
+
37
+ /**
38
+ * 表单弹窗
39
+ */
40
+ export interface IFormModal {
41
+ show: Function;
42
+ }
43
+
44
+ /**
45
+ * 详情弹窗
46
+ */
47
+ export interface IDetailModal {
48
+ show: Function;
49
+ }
50
+
51
+ /**
52
+ * data model
53
+ */
54
+ export interface IDataModel {
55
+ /**
56
+ * 列表请求 api
57
+ */
58
+ getListApi: string;
59
+ /**
60
+ * 列表请求函数
61
+ */
62
+ getList: Function;
63
+ /**
64
+ * 详情请求函数
65
+ */
66
+ get: Function;
67
+ /**
68
+ * 新增请求函数
69
+ */
70
+ create: Function;
71
+ /**
72
+ * put 编辑请求函数
73
+ */
74
+ update: Function;
75
+ /**
76
+ * patch 编辑请求函数
77
+ */
78
+ patch: Function;
79
+ /**
80
+ * 删除请求函数
81
+ */
82
+ delete: Function;
83
+ /**
84
+ * get 请求入参
85
+ */
86
+ query?: {
87
+ /**
88
+ * 分页当前页码
89
+ */
90
+ pageNum?: number;
91
+ /**
92
+ * 分页条数
93
+ */
94
+ pageSize?: number;
95
+ };
96
+ /**
97
+ * 新增入参数据处理
98
+ * @param d
99
+ * @returns
100
+ */
101
+ createMap?: (d) => typeof d;
102
+ /**
103
+ * 编辑数据处理
104
+ * @param d
105
+ * @returns
106
+ */
107
+ updateMap?: (d) => typeof d;
108
+ /**
109
+ * patch 编辑数据处理
110
+ * @param d
111
+ * @returns
112
+ */
113
+ patchMap?: (d) => typeof d;
114
+ }
115
+
116
+ export interface ISlots {
117
+ /**
118
+ * header 操作按钮前插槽
119
+ */
120
+ headerActionPrefix?: Function;
121
+ /**
122
+ * header 操作按钮后插槽
123
+ */
124
+ headerActionSuffix?: Function;
125
+ /**
126
+ * header 外面的插槽
127
+ */
128
+ HeaderOthersSuffix?: Function;
129
+ }
130
+
131
+ /**
132
+ * list render props
133
+ */
134
+ export interface IListRenderProps {
135
+ /**
136
+ * 容器类名
137
+ */
138
+ className?: string;
139
+ /**
140
+ * 列表 schema 配置
141
+ */
142
+ schema: { schema: Schema };
143
+ /**
144
+ * data-model 实例
145
+ */
146
+ model?: IDataModel;
147
+ /**
148
+ * 列表数据,用于直接渲染而不进行请求或处理。需要本地增删改查使用 data-mode/src/array-data-model.js
149
+ */
150
+ list?: [Object];
151
+ /**
152
+ * 列表配置
153
+ */
154
+ config?: Object;
155
+ /**
156
+ * message 消息配置
157
+ */
158
+ msgConf?: Object;
159
+ /**
160
+ * 新增按钮文案 默认 新增
161
+ */
162
+ createText?: string;
163
+ /**
164
+ * 列表唯一值 默认 id
165
+ */
166
+ idKey: string;
167
+ /**
168
+ * i18n 文案
169
+ */
170
+ i18n?: II18n;
171
+ /**
172
+ * query 是否继承 model query, 默认 false
173
+ */
174
+ queryFormIsExtendModelQuery?: boolean;
175
+ /**
176
+ * dialog 弹窗配置
177
+ */
178
+ dialogConf: IModalConf;
179
+ /**
180
+ * dialog drawer 弹窗配置
181
+ */
182
+ modalConf: IModalConf;
183
+ /**
184
+ * 编辑接口使用 patch 发起请求 默认 false
185
+ */
186
+ isPatchUpdate: boolean;
187
+ /**
188
+ * 表单、详情 展示模式: dialog drawer
189
+ */
190
+ modalMode?: "dialog" | "drawer";
191
+ /**
192
+ * 表单提交是否使用 FormData 格式
193
+ */
194
+ useFormData?: boolean;
195
+ /**
196
+ * 是否关闭初始自动请求
197
+ */
198
+ closeAutoRequest?: boolean;
199
+ /**
200
+ * 获取列表完成回调
201
+ */
202
+ onGetListEnd?: ({ list, pagination: { pageNum, pageSize } }) => void;
203
+ /**
204
+ * 新增完成回调
205
+ */
206
+ onCreateSuc?: (res) => void;
207
+ /**
208
+ * 编辑完成回调
209
+ */
210
+ onEditSuc?: (res) => void;
211
+ /**
212
+ * 删除完成回调
213
+ */
214
+ onDelSuc?: (res) => void;
215
+ /**
216
+ * 请求获取详情数据,而非直接使用列表数据 默认 true
217
+ */
218
+ fetchOnEdit?: boolean;
219
+ /**
220
+ * 通过 id 请求获取详情数据
221
+ */
222
+ fetchById?: boolean;
223
+ /**
224
+ * 列表插槽
225
+ */
226
+ Slots?: ISlots;
227
+ /**
228
+ * 【废弃】弹窗表单 props
229
+ */
230
+ dialogFormProps?: Object;
231
+ /**
232
+ * 弹窗表单 props
233
+ */
234
+ modalFormProps?: Object;
235
+ /**
236
+ * 【废弃】表单弹窗关闭回调
237
+ */
238
+ onFormDialogClose?: Function;
239
+ /**
240
+ * 表单弹窗关闭回调
241
+ */
242
+ onFormModalClose?: Function;
243
+ /**
244
+ * 【废弃】表单弹窗 props
245
+ */
246
+ dialogProps?: Object;
247
+ /**
248
+ * 表单弹窗 props
249
+ */
250
+ modalProps?: Object;
251
+ /**
252
+ * 【废弃】弹窗表单 渲染完毕回调
253
+ */
254
+ dialogFormMount?: Function;
255
+ /**
256
+ * 弹窗表单 渲染完毕回调
257
+ */
258
+ modalFormMount?: Function;
259
+ /**
260
+ * 【废弃】弹窗详情组件 props
261
+ */
262
+ dialogDetailProps?: Function;
263
+ /**
264
+ * 弹窗详情组件 props
265
+ */
266
+ modalDetailProps?: Function;
267
+ /**
268
+ * header 布局
269
+ */
270
+ verticalHeader?: boolean;
271
+ /**
272
+ * 是否有过滤项
273
+ */
274
+ hasQuery?: boolean;
275
+ /**
276
+ * 搜索过滤项文案,入参字段为 search
277
+ */
278
+ search?: string;
279
+ /**
280
+ * 过滤项字段数组
281
+ */
282
+ filters?: [string];
283
+ /**
284
+ * query 配置
285
+ */
286
+ queryConf?: Object;
287
+ /**
288
+ * query 表单默认值
289
+ */
290
+ queryFormInitialValues?: Object;
291
+ /**
292
+ * formily scope 自定义参数
293
+ */
294
+ schemaScope?: Object;
295
+ /**
296
+ * formily components 自定义组件
297
+ */
298
+ components?: Object;
299
+ /**
300
+ * 是否有新增按钮
301
+ */
302
+ hasCreate?: boolean;
303
+ /**
304
+ * 是否有操作列
305
+ */
306
+ hasAction?: boolean;
307
+ /**
308
+ * 是否有 分页
309
+ */
310
+ hasPagination?: boolean;
311
+ /**
312
+ * table 配置
313
+ */
314
+ tableConf?: Object;
315
+ /**
316
+ * table props 参数
317
+ */
318
+ tableProps?: Object;
319
+ /**
320
+ * getFieldList opt 获取 field list 的配置
321
+ */
322
+ getFieldListOpt?: Object;
323
+ /**
324
+ * 分页器配置 props
325
+ */
326
+ paginationConf?: Object;
327
+ /**
328
+ * 新增、编辑、详情表单初始值
329
+ */
330
+ formInitialValues?: Object;
331
+ /**
332
+ * 详情自定义组件
333
+ */
334
+ detailComponents?: Object;
335
+ }
File without changes