@jiangood/open-admin 3.0.15 → 3.1.0

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.
Files changed (80) hide show
  1. package/package.json +15 -2
  2. package/src/framework/biz/OrgTree.tsx +10 -6
  3. package/src/framework/biz/PermActions.tsx +5 -3
  4. package/src/framework/biz/RoleTree.tsx +10 -6
  5. package/src/framework/biz/index.tsx +1 -0
  6. package/src/framework/components/ContextMenu/index.tsx +17 -1
  7. package/src/framework/components/DownloadModal/index.tsx +40 -33
  8. package/src/framework/components/FormModal/index.tsx +10 -8
  9. package/src/framework/components/NamedIcon/index.tsx +2 -2
  10. package/src/framework/components/OrgSwitcher/index.tsx +6 -7
  11. package/src/framework/components/PageLoading/index.tsx +3 -3
  12. package/src/framework/components/ProTable/index.tsx +28 -25
  13. package/src/framework/components/ValueType/index.tsx +1 -1
  14. package/src/framework/config/themeConfig.ts +5 -5
  15. package/src/framework/fields/BaseRemoteSelect/index.tsx +23 -21
  16. package/src/framework/fields/FieldBoolean/index.tsx +6 -6
  17. package/src/framework/fields/FieldDate/index.tsx +10 -10
  18. package/src/framework/fields/FieldDateRange/index.tsx +20 -20
  19. package/src/framework/fields/FieldDictSelect/index.tsx +2 -2
  20. package/src/framework/fields/FieldEditor/index.tsx +1 -1
  21. package/src/framework/fields/FieldNumberRange/index.tsx +16 -17
  22. package/src/framework/fields/FieldPercent/index.tsx +2 -2
  23. package/src/framework/fields/FieldRemoteSelect/index.tsx +4 -4
  24. package/src/framework/fields/FieldRemoteTree/index.tsx +1 -1
  25. package/src/framework/fields/FieldRemoteTreeCascader/index.tsx +1 -1
  26. package/src/framework/fields/FieldRemoteTreeSelect/index.tsx +1 -1
  27. package/src/framework/fields/FieldSysOrgTree/index.tsx +1 -1
  28. package/src/framework/fields/FieldSysOrgTreeSelect/index.tsx +1 -1
  29. package/src/framework/fields/FieldTable/index.tsx +15 -13
  30. package/src/framework/fields/FieldTableSelect/index.tsx +5 -5
  31. package/src/framework/fields/FieldUploadFile/index.tsx +3 -3
  32. package/src/framework/fields/FieldUploadImage/index.tsx +31 -29
  33. package/src/framework/fields/types.ts +0 -2
  34. package/src/framework/router/PageFrame.tsx +1 -1
  35. package/src/framework/router/matcher.ts +2 -2
  36. package/src/framework/utils/ArrayUtils.ts +2 -2
  37. package/src/framework/utils/DateUtils.ts +1 -1
  38. package/src/framework/utils/{system/DictUtils.ts → DictUtils.ts} +1 -1
  39. package/src/framework/utils/EventBus.ts +7 -7
  40. package/src/framework/utils/HttpClient.ts +283 -0
  41. package/src/framework/utils/{system/PageUtils.ts → PageUtils.ts} +4 -4
  42. package/src/framework/utils/{system/PermUtils.ts → PermUtils.ts} +3 -3
  43. package/src/framework/utils/StringUtils.ts +10 -8
  44. package/src/framework/utils/TreeUtils.ts +3 -3
  45. package/src/framework/utils/UrlUtils.ts +2 -2
  46. package/src/framework/utils/index.ts +4 -1
  47. package/src/framework/views/ViewApproveStatus/index.tsx +1 -2
  48. package/src/framework/views/ViewBoolean/index.tsx +4 -1
  49. package/src/framework/views/ViewFile/index.tsx +4 -4
  50. package/src/framework/views/ViewImage/index.tsx +2 -2
  51. package/src/framework/views/ViewPassword/index.tsx +3 -2
  52. package/src/framework/views/ViewText/index.tsx +12 -3
  53. package/src/framework/views/types.ts +2 -4
  54. package/src/layouts/admin/AdminTabs.jsx +9 -0
  55. package/src/layouts/admin/AdminTabs.less +2 -2
  56. package/src/layouts/admin/HeaderRight.jsx +8 -7
  57. package/src/layouts/admin/TabLayout.jsx +2 -2
  58. package/src/layouts/admin/index.jsx +15 -11
  59. package/src/layouts/admin/index.less +16 -1
  60. package/src/layouts/index.tsx +24 -18
  61. package/src/pages/404.jsx +1 -1
  62. package/src/pages/article/$code.jsx +4 -4
  63. package/src/pages/index.jsx +1 -1
  64. package/src/pages/public/login.jsx +34 -27
  65. package/src/pages/public/test.jsx +1 -1
  66. package/src/pages/standalone/forceUpdatePwd.jsx +9 -7
  67. package/src/pages/system/article/index.jsx +9 -8
  68. package/src/pages/system/dict/index.jsx +19 -16
  69. package/src/pages/system/file/index.jsx +9 -9
  70. package/src/pages/system/job/index.jsx +17 -17
  71. package/src/pages/system/log/index.jsx +5 -7
  72. package/src/pages/system/org/index.jsx +31 -18
  73. package/src/pages/system/role/index.jsx +13 -12
  74. package/src/pages/system/role/rolePerm.jsx +25 -21
  75. package/src/pages/system/user/index.jsx +35 -33
  76. package/src/pages/system/user/userPerm.jsx +12 -12
  77. package/src/pages/userCenter/index.jsx +11 -9
  78. package/src/pages/userCenter/permView.jsx +7 -7
  79. package/src/framework/utils/system/HttpUtils.ts +0 -97
  80. package/src/framework/utils/system/index.ts +0 -4
@@ -21,18 +21,18 @@ export const DEFAULT_COLORS: Required<ThemeColors> = {
21
21
 
22
22
  let overrideColors: Partial<ThemeColors> | null = null;
23
23
  let cachedConfig: ThemeConfig | null = null;
24
- let cachedToken: Record<string, any> | null = null;
24
+ let cachedToken: Record<string, unknown> | null = null;
25
25
 
26
26
  function buildConfig(): ThemeConfig {
27
- const token: Record<string, any> = { borderRadius: 4, ...DEFAULT_COLORS, ...overrideColors };
28
- const components: Record<string, any> = {
27
+ const token: Record<string, unknown> = { borderRadius: 4, ...DEFAULT_COLORS, ...overrideColors };
28
+ const components: Record<string, unknown> = {
29
29
  Layout: { headerBg: 'white', triggerHeight: 32 },
30
30
  };
31
31
 
32
32
  return { token, components };
33
33
  }
34
34
 
35
- function syncCssVars(token: Record<string, any>) {
35
+ function syncCssVars(token: Record<string, unknown>) {
36
36
  if (typeof document === 'undefined') return;
37
37
  const el = document.documentElement;
38
38
  el.style.setProperty('--primary-color', token.colorPrimary);
@@ -54,7 +54,7 @@ export function getThemeConfig(): ThemeConfig {
54
54
  return cachedConfig;
55
55
  }
56
56
 
57
- export function getToken(): Record<string, any> {
57
+ export function getToken(): ThemeColors & Record<string, unknown> {
58
58
  if (!cachedToken) {
59
59
  cachedToken = getDesignToken(getThemeConfig());
60
60
  }
@@ -1,18 +1,18 @@
1
1
  import React from 'react';
2
2
  import { Spin } from 'antd';
3
3
  import { debounce } from 'lodash';
4
- import { HttpUtils } from '../../utils';
4
+ import { HttpClient } from '../../utils';
5
5
 
6
6
  interface BaseRemoteSelectState {
7
- data: any[];
7
+ data: Record<string, unknown>[];
8
8
  loading: boolean;
9
9
  }
10
10
 
11
11
  export interface BaseRemoteSelectProps {
12
12
  url?: string;
13
- value?: any;
13
+ value?: unknown;
14
14
  debounceTime?: number;
15
- [key: string]: any;
15
+ [key: string]: unknown;
16
16
  }
17
17
 
18
18
  /**
@@ -21,11 +21,11 @@ export interface BaseRemoteSelectProps {
21
21
  * 处理通用的数据加载、防抖搜索、竞态处理、错误提示逻辑。
22
22
  * 子类只需覆写 getLoadParams() 和 render()。
23
23
  */
24
- export class BaseRemoteSelect<P extends BaseRemoteSelectProps = BaseRemoteSelectProps> extends React.Component<P, BaseRemoteSelectState> {
25
- private fetchIdRef: number = 0;
24
+ export class BaseRemoteSelect<P extends BaseRemoteSelectProps = BaseRemoteSelectProps> extends React.Component<P, BaseRemoteSelectState> { // NOSONAR: state/防抖字段构造器赋值
25
+ private fetchIdRef: number = 0; // NOSONAR: 构造器中赋值
26
26
  private loadDataDebounce: ReturnType<typeof debounce>;
27
27
 
28
- static defaultProps = {
28
+ static readonly defaultProps = {
29
29
  debounceTime: 300,
30
30
  };
31
31
 
@@ -35,7 +35,7 @@ export class BaseRemoteSelect<P extends BaseRemoteSelectProps = BaseRemoteSelect
35
35
  data: [],
36
36
  loading: false,
37
37
  };
38
- this.loadDataDebounce = debounce(this._loadData, (props as any).debounceTime || 300);
38
+ this.loadDataDebounce = debounce(this._loadData, props.debounceTime || 300);
39
39
  }
40
40
 
41
41
  componentDidMount() {
@@ -56,7 +56,7 @@ export class BaseRemoteSelect<P extends BaseRemoteSelectProps = BaseRemoteSelect
56
56
  }
57
57
 
58
58
  /** 返回请求参数。searchText=undefined 表示初始加载 */
59
- getLoadParams(searchText?: string): Record<string, any> {
59
+ getLoadParams(searchText?: string): Record<string, unknown> {
60
60
  return { searchText, selected: this.props.value };
61
61
  }
62
62
 
@@ -67,28 +67,30 @@ export class BaseRemoteSelect<P extends BaseRemoteSelectProps = BaseRemoteSelect
67
67
 
68
68
  // ========== 数据加载 ==========
69
69
 
70
- private _loadData = async (searchText?: string) => {
70
+ private _loadData = (searchText?: string) => {
71
71
  const url = this.getUrl();
72
72
  const fetchId = ++this.fetchIdRef;
73
73
 
74
74
  this.setState({ loading: true });
75
75
 
76
- try {
77
- const data = await HttpUtils.get(url, this.getLoadParams(searchText));
76
+ const done = () => {
77
+ if (fetchId === this.fetchIdRef) {
78
+ this.setState({ loading: false });
79
+ }
80
+ };
78
81
 
82
+ HttpClient.get(url, this.getLoadParams(searchText), {toastError: false}).then((data) => {
79
83
  if (fetchId === this.fetchIdRef) {
80
- this.setState({ data: data || [] });
84
+ this.setState({ data: data.data || [] });
81
85
  }
82
- } catch (error) {
86
+ done();
87
+ }).catch((error) => {
83
88
  console.warn('[BaseRemoteSelect] 加载失败:', error);
84
89
  if (fetchId === this.fetchIdRef) {
85
90
  this.setState({ data: [] });
86
91
  }
87
- } finally {
88
- if (fetchId === this.fetchIdRef) {
89
- this.setState({ loading: false });
90
- }
91
- }
92
+ done();
93
+ });
92
94
  };
93
95
 
94
96
  /**
@@ -115,14 +117,14 @@ export class BaseRemoteSelect<P extends BaseRemoteSelectProps = BaseRemoteSelect
115
117
 
116
118
  // ========== Helper 方法 ==========
117
119
 
118
- getShowSearch(): { filterOption: false; onSearch: (value: string) => void } {
120
+ getShowSearch(): { filterOption: false; onSearch: (value: string) => void } { // NOSONAR: 由子类通过 this.getShowSearch() 调用
119
121
  return {
120
122
  filterOption: false,
121
123
  onSearch: this.handleSearch,
122
124
  };
123
125
  }
124
126
 
125
- getNotFoundContent(): React.ReactNode {
127
+ getNotFoundContent(): React.ReactNode { // NOSONAR: 由子类通过 this.getNotFoundContent() 调用
126
128
  return this.state.loading ? <Spin size="small" /> : '数据为空';
127
129
  }
128
130
  }
@@ -23,7 +23,7 @@ export interface FieldBooleanProps extends FieldProps<boolean> {
23
23
 
24
24
  export class FieldBoolean extends React.Component<FieldBooleanProps> {
25
25
 
26
- static defaultProps = {
26
+ static readonly defaultProps = {
27
27
  type: 'select'
28
28
  };
29
29
 
@@ -34,7 +34,7 @@ export class FieldBoolean extends React.Component<FieldBooleanProps> {
34
34
 
35
35
  switch (type) {
36
36
  case 'radio':
37
- return <Radio.Group value={v} onChange={e => onChange && onChange(e.target.value)}>
37
+ return <Radio.Group value={v} onChange={e => onChange?.(e.target.value)}>
38
38
  <Radio value={true}>是</Radio>
39
39
  <Radio value={false}>否</Radio>
40
40
  </Radio.Group>;
@@ -42,7 +42,7 @@ export class FieldBoolean extends React.Component<FieldBooleanProps> {
42
42
  return <Checkbox
43
43
  checked={v}
44
44
  onChange={(e) => {
45
- onChange && onChange(e.target.checked);
45
+ onChange?.(e.target.checked);
46
46
  }}
47
47
  />;
48
48
  case 'select':
@@ -51,7 +51,7 @@ export class FieldBoolean extends React.Component<FieldBooleanProps> {
51
51
  {value: false, label: '否'},
52
52
  ]}
53
53
  value={v}
54
- onChange={value => onChange && onChange(value)}
54
+ onChange={value => onChange?.(value)}
55
55
  style={{width: '100%'}}
56
56
  allowClear={true}
57
57
  placeholder={'请选择'}
@@ -59,7 +59,7 @@ export class FieldBoolean extends React.Component<FieldBooleanProps> {
59
59
  case 'switch':
60
60
  return <Switch
61
61
  checked={v}
62
- onChange={checked => onChange && onChange(checked)}
62
+ onChange={checked => onChange?.(checked)}
63
63
  />;
64
64
  default:
65
65
  return null;
@@ -67,7 +67,7 @@ export class FieldBoolean extends React.Component<FieldBooleanProps> {
67
67
 
68
68
  }
69
69
 
70
- parseBoolean(v: any): boolean | undefined {
70
+ parseBoolean(v: unknown): boolean | undefined {
71
71
  if (v === null || v === undefined) {
72
72
  return undefined;
73
73
  }
@@ -17,11 +17,11 @@ export interface FieldDateProps extends FieldProps<string> {
17
17
  /** 自定义样式 */
18
18
  style?: React.CSSProperties;
19
19
  /** 其余属性透传给 DatePicker/TimePicker */
20
- [key: string]: any;
20
+ [key: string]: unknown;
21
21
  }
22
22
 
23
23
  export class FieldDate extends React.Component<FieldDateProps> {
24
- static defaultProps = {
24
+ static readonly defaultProps = {
25
25
  type: 'YYYY-MM-DD'
26
26
  };
27
27
 
@@ -33,34 +33,34 @@ export class FieldDate extends React.Component<FieldDateProps> {
33
33
  case 'YYYY':
34
34
  return <DatePicker
35
35
  value={this.strToDate(value, formattedType)}
36
- onChange={v => onChange && onChange(this.dateToStr(v, 'YYYY'))}
36
+ onChange={v => onChange?.(this.dateToStr(v, 'YYYY'))}
37
37
  picker="year"
38
38
  {...rest}
39
39
  />;
40
40
  case 'YYYY-MM':
41
41
  return <DatePicker
42
42
  value={this.strToDate(value, 'YYYY-MM')}
43
- onChange={v => onChange && onChange(this.dateToStr(v, 'YYYY-MM'))}
43
+ onChange={v => onChange?.(this.dateToStr(v, 'YYYY-MM'))}
44
44
  picker="month"
45
45
  {...rest}
46
46
  />;
47
47
  case 'YYYY-QQ':
48
48
  return <DatePicker
49
49
  value={this.strToDate(value, 'YYYY-QQ')}
50
- onChange={v => onChange && onChange(this.dateToStr(v, 'YYYY-QQ'))}
50
+ onChange={v => onChange?.(this.dateToStr(v, 'YYYY-QQ'))}
51
51
  picker="quarter"
52
52
  {...rest}
53
53
  />;
54
54
  case 'YYYY-MM-DD':
55
55
  return <DatePicker
56
56
  value={this.strToDate(value, 'YYYY-MM-DD')}
57
- onChange={v => onChange && onChange(this.dateToStr(v, 'YYYY-MM-DD'))}
57
+ onChange={v => onChange?.(this.dateToStr(v, 'YYYY-MM-DD'))}
58
58
  {...rest}
59
59
  ></DatePicker>;
60
60
  case 'YYYY-MM-DD HH:mm':
61
61
  return <DatePicker
62
62
  value={this.strToDate(value, 'YYYY-MM-DD HH:mm')}
63
- onChange={v => onChange && onChange(this.dateToStr(v, 'YYYY-MM-DD HH:mm'))}
63
+ onChange={v => onChange?.(this.dateToStr(v, 'YYYY-MM-DD HH:mm'))}
64
64
  format='YYYY-MM-DD HH:mm'
65
65
  showTime
66
66
  {...rest}
@@ -68,7 +68,7 @@ export class FieldDate extends React.Component<FieldDateProps> {
68
68
  case 'YYYY-MM-DD HH:mm:ss':
69
69
  return <DatePicker
70
70
  value={this.strToDate(value, 'YYYY-MM-DD HH:mm:ss')}
71
- onChange={v => onChange && onChange(this.dateToStr(v, 'YYYY-MM-DD HH:mm:ss'))}
71
+ onChange={v => onChange?.(this.dateToStr(v, 'YYYY-MM-DD HH:mm:ss'))}
72
72
  showTime
73
73
  {...rest}
74
74
  ></DatePicker>;
@@ -76,13 +76,13 @@ export class FieldDate extends React.Component<FieldDateProps> {
76
76
  return <TimePicker
77
77
  format='HH:mm'
78
78
  value={this.strToDate(value, 'HH:mm')}
79
- onChange={v => onChange && onChange(this.dateToStr(v, 'HH:mm'))}
79
+ onChange={v => onChange?.(this.dateToStr(v, 'HH:mm'))}
80
80
  {...rest}
81
81
  ></TimePicker>;
82
82
  case 'HH:mm:ss':
83
83
  return <TimePicker
84
84
  value={this.strToDate(value, 'HH:mm:ss')}
85
- onChange={v => onChange && onChange(this.dateToStr(v, 'HH:mm:ss'))}
85
+ onChange={v => onChange?.(this.dateToStr(v, 'HH:mm:ss'))}
86
86
  {...rest}
87
87
  ></TimePicker>;
88
88
  default:
@@ -10,7 +10,7 @@ import type {FieldProps} from '../types';
10
10
  const SP = StringUtils.ISO_SPLITTER;
11
11
 
12
12
  /** 日期范围值,形如 "2024-01-01/2024-01-31"(起止以 / 分隔) */
13
- export type FieldDateRangeValue = string;
13
+ export type FieldDateRangeValue = string; // NOSONAR: npm 包导出类型,业务项目引用
14
14
 
15
15
  export interface FieldDateRangeProps extends FieldProps<FieldDateRangeValue> {
16
16
  /** 日期类型,如 YYYY-MM-DD、YYYY-MM、HH:mm:ss 等,默认 YYYY-MM-DD */
@@ -22,11 +22,11 @@ export interface FieldDateRangeProps extends FieldProps<FieldDateRangeValue> {
22
22
  /** 自定义样式 */
23
23
  style?: React.CSSProperties;
24
24
  /** 其余属性透传给 RangePicker */
25
- [key: string]: any;
25
+ [key: string]: unknown;
26
26
  }
27
27
 
28
28
  export class FieldDateRange extends React.Component<FieldDateRangeProps> {
29
- static defaultProps = {
29
+ static readonly defaultProps = {
30
30
  type: 'YYYY-MM-DD'
31
31
  };
32
32
 
@@ -37,57 +37,57 @@ export class FieldDateRange extends React.Component<FieldDateRangeProps> {
37
37
  switch (formattedType) {
38
38
  case 'YYYY':
39
39
  return <DatePicker.RangePicker
40
- value={this.strToDate(value, 'YYYY')}
41
- onChange={v => onChange && onChange(this.dateToStr(v, 'YYYY'))}
40
+ value={this.strToDate(value)}
41
+ onChange={v => onChange?.(this.dateToStr(v, 'YYYY'))}
42
42
  picker="year"
43
43
  {...rest}
44
44
  />;
45
45
  case 'YYYY-MM':
46
46
  return <DatePicker.RangePicker
47
- value={this.strToDate(value, 'YYYY-MM')}
48
- onChange={v => onChange && onChange(this.dateToStr(v, 'YYYY-MM'))}
47
+ value={this.strToDate(value)}
48
+ onChange={v => onChange?.(this.dateToStr(v, 'YYYY-MM'))}
49
49
  picker="month"
50
50
  {...rest}
51
51
  />;
52
52
  case 'YYYY-QQ':
53
53
  return <DatePicker.RangePicker
54
- value={this.strToDate(value, 'YYYY-QQ')}
55
- onChange={v => onChange && onChange(this.dateToStr(v, 'YYYY-QQ'))}
54
+ value={this.strToDate(value)}
55
+ onChange={v => onChange?.(this.dateToStr(v, 'YYYY-QQ'))}
56
56
  picker="quarter"
57
57
  {...rest}
58
58
  />;
59
59
  case 'YYYY-MM-DD':
60
60
  return <DatePicker.RangePicker
61
- value={this.strToDate(value, 'YYYY-MM-DD')}
62
- onChange={v => onChange && onChange(this.dateToStr(v, 'YYYY-MM-DD'))}
61
+ value={this.strToDate(value)}
62
+ onChange={v => onChange?.(this.dateToStr(v, 'YYYY-MM-DD'))}
63
63
  {...rest}
64
64
  />;
65
65
  case 'YYYY-MM-DD HH:mm':
66
66
  return <DatePicker.RangePicker
67
- value={this.strToDate(value, 'YYYY-MM-DD HH:mm')}
68
- onChange={v => onChange && onChange(this.dateToStr(v, 'YYYY-MM-DD HH:mm'))}
67
+ value={this.strToDate(value)}
68
+ onChange={v => onChange?.(this.dateToStr(v, 'YYYY-MM-DD HH:mm'))}
69
69
  format='YYYY-MM-DD HH:mm'
70
70
  showTime
71
71
  {...rest}
72
72
  />;
73
73
  case 'YYYY-MM-DD HH:mm:ss':
74
74
  return <DatePicker.RangePicker
75
- value={this.strToDate(value, 'YYYY-MM-DD HH:mm:ss')}
76
- onChange={v => onChange && onChange(this.dateToStr(v, 'YYYY-MM-DD HH:mm:ss'))}
75
+ value={this.strToDate(value)}
76
+ onChange={v => onChange?.(this.dateToStr(v, 'YYYY-MM-DD HH:mm:ss'))}
77
77
  showTime
78
78
  {...rest}
79
79
  />;
80
80
  case 'HH:mm':
81
81
  return <TimePicker.RangePicker
82
82
  format='HH:mm'
83
- value={this.strToDate(value, 'HH:mm')}
84
- onChange={v => onChange && onChange(this.dateToStr(v, 'HH:mm'))}
83
+ value={this.strToDate(value)}
84
+ onChange={v => onChange?.(this.dateToStr(v, 'HH:mm'))}
85
85
  {...rest}
86
86
  />;
87
87
  case 'HH:mm:ss':
88
88
  return <TimePicker.RangePicker
89
- value={this.strToDate(value, 'HH:mm:ss')}
90
- onChange={v => onChange && onChange(this.dateToStr(v, 'HH:mm:ss'))}
89
+ value={this.strToDate(value)}
90
+ onChange={v => onChange?.(this.dateToStr(v, 'HH:mm:ss'))}
91
91
  {...rest}
92
92
  />;
93
93
  default:
@@ -96,7 +96,7 @@ export class FieldDateRange extends React.Component<FieldDateRangeProps> {
96
96
 
97
97
  }
98
98
 
99
- strToDate(v: string | null | undefined, fmt: string): [dayjs.Dayjs, dayjs.Dayjs] | null {
99
+ strToDate(v: string | null | undefined): [dayjs.Dayjs, dayjs.Dayjs] | null {
100
100
  if (!v) {
101
101
  return null;
102
102
  }
@@ -4,7 +4,7 @@ import {DictUtils} from "../../utils";
4
4
  import type {SelectProps} from "antd/es/select";
5
5
  import type {FieldProps} from '../types';
6
6
 
7
- interface FieldDictSelectProps extends Omit<SelectProps, 'options' | 'children' | 'mode' | 'value' | 'onChange'>, FieldProps<any> {
7
+ interface FieldDictSelectProps extends Omit<SelectProps, 'options' | 'children' | 'mode' | 'value' | 'onChange'>, FieldProps<unknown> {
8
8
  typeCode: string;
9
9
  }
10
10
 
@@ -12,7 +12,7 @@ export class FieldDictSelect extends React.Component<FieldDictSelectProps> {
12
12
  render() {
13
13
  const {value, typeCode} = this.props;
14
14
  const options = DictUtils.dictOptions(typeCode);
15
- const strValue = value == null ? null : String(value);
15
+ const strValue = value == null ? null : String(value); // NOSONAR: value 经 String() 显式转换,无隐式字符串化
16
16
 
17
17
  return <Select value={strValue}
18
18
  onChange={this.props.onChange}
@@ -69,7 +69,7 @@ export class FieldEditor extends React.Component<FieldEditorProps, {loading: boo
69
69
  setup: function (editor) {
70
70
  editor.on('OpenWindow', function(e) {
71
71
  const dialog = e.dialog;
72
- if (dialog && dialog.getData().dimensions) {
72
+ if (dialog?.getData().dimensions) {
73
73
  dialog.showTab("upload");
74
74
  }
75
75
  });
@@ -6,7 +6,9 @@ import type {FieldProps} from '../types';
6
6
  const SP = StringUtils.ISO_SPLITTER;
7
7
 
8
8
  /** 数字范围值,形如 "1/100"(起止以 / 分隔) */
9
- export type FieldNumberRangeValue = string;
9
+ export type FieldNumberRangeValue = string; // NOSONAR: npm 包导出类型,业务项目引用
10
+
11
+ export type RangePartValue = number | string | null;
10
12
 
11
13
  export interface FieldNumberRangeProps extends FieldProps<FieldNumberRangeValue> {
12
14
  /** 默认值(形如 "1/100"),value 为空时挂载后回填 */
@@ -14,23 +16,21 @@ export interface FieldNumberRangeProps extends FieldProps<FieldNumberRangeValue>
14
16
  }
15
17
 
16
18
  export class FieldNumberRange extends React.Component<FieldNumberRangeProps> {
17
- onChangeA = (a: number | string | null) => {
19
+ onChangeA = (a: RangePartValue) => {
18
20
  const {b} = this.parse(this.props.value);
19
- this.props.onChange && this.props.onChange(this.merge(a, b));
21
+ this.props.onChange?.(this.merge(this.toPart(a), this.toPart(b)));
20
22
  };
21
23
 
22
- onChangeB = (b: number | string | null) => {
24
+ onChangeB = (b: RangePartValue) => {
23
25
  const {a} = this.parse(this.props.value);
24
- this.props.onChange && this.props.onChange(this.merge(a, b));
26
+ this.props.onChange?.(this.merge(this.toPart(a), this.toPart(b)));
25
27
  };
26
28
 
27
- merge(a: number | string | null, b: number | string | null): string {
28
- if (a == null) {
29
- a = '';
30
- }
31
- if (b == null) {
32
- b = '';
33
- }
29
+ private toPart(v: RangePartValue): number | string {
30
+ return v ?? '';
31
+ }
32
+
33
+ merge(a: number | string, b: number | string): string {
34
34
  return a + SP + b;
35
35
  }
36
36
 
@@ -45,15 +45,14 @@ export class FieldNumberRange extends React.Component<FieldNumberRangeProps> {
45
45
  componentDidMount() {
46
46
  const {value, defaultValue, onChange} = this.props;
47
47
  if (value == null && defaultValue) {
48
- onChange && onChange(defaultValue);
48
+ onChange?.(defaultValue);
49
49
  }
50
50
  }
51
51
 
52
52
  render() {
53
- let {value, defaultValue} = this.props;
54
- if (value == null) {
55
- value = defaultValue;
56
- }
53
+ const {defaultValue} = this.props;
54
+ let {value} = this.props;
55
+ value = value ?? defaultValue;
57
56
  const {a, b} = this.parse(value);
58
57
 
59
58
  return <div style={{display: 'flex', alignItems: 'center'}}>
@@ -12,7 +12,7 @@ export interface FieldPercentProps extends Omit<InputNumberProps, 'value' | 'onC
12
12
  * 数字的百分数输入框
13
13
  */
14
14
  export class FieldPercent extends React.Component<FieldPercentProps> {
15
- static defaultProps = {
15
+ static readonly defaultProps = {
16
16
  precision: 2,
17
17
  };
18
18
 
@@ -28,7 +28,7 @@ export class FieldPercent extends React.Component<FieldPercentProps> {
28
28
  onChange={v => {
29
29
  if (v != null) {
30
30
  const percentValue = Number((v / 100).toFixed(precision));
31
- onChange && onChange(percentValue);
31
+ onChange?.(percentValue);
32
32
  }
33
33
  }}
34
34
  {...rest}
@@ -4,16 +4,16 @@ import {BaseRemoteSelect} from '../BaseRemoteSelect';
4
4
  import type {SelectProps} from "antd/es/select";
5
5
  import type {FieldProps} from '../types';
6
6
 
7
- interface FieldRemoteSelectProps extends Omit<SelectProps, 'value' | 'onChange' | 'mode'>, FieldProps<any> {
7
+ interface FieldRemoteSelectProps extends Omit<SelectProps, 'value' | 'onChange' | 'mode'>, FieldProps<unknown> {
8
8
  url: string;
9
9
  debounceTime?: number;
10
10
  multiple?: boolean;
11
- paramsProcessor?: (params: any) => any;
12
- responseProcessor?: (response: any) => any;
11
+ paramsProcessor?: (params: Record<string, unknown>) => Record<string, unknown>;
12
+ responseProcessor?: (response: unknown) => unknown;
13
13
  }
14
14
 
15
15
  export class FieldRemoteSelect extends BaseRemoteSelect<FieldRemoteSelectProps> {
16
- static defaultProps = {
16
+ static readonly defaultProps = {
17
17
  placeholder: '请搜索选择',
18
18
  };
19
19
 
@@ -20,7 +20,7 @@ export class FieldRemoteTree extends BaseRemoteSelect {
20
20
  <Tree
21
21
  multiple
22
22
  checkable
23
- onCheck={(checkedInfo) => this.props.onChange && this.props.onChange(checkedInfo.checked)}
23
+ onCheck={(checkedInfo) => this.props.onChange?.(checkedInfo.checked)}
24
24
  checkedKeys={this.props.value}
25
25
  treeData={this.state.data}
26
26
  defaultExpandAll
@@ -28,7 +28,7 @@ export class FieldRemoteTreeCascader extends BaseRemoteSelect {
28
28
  <Cascader
29
29
  options={data}
30
30
  onChange={(arr) => {
31
- onChange && onChange(arr[arr.length - 1]);
31
+ onChange?.(arr[arr.length - 1]);
32
32
  }}
33
33
  value={arr}
34
34
  fieldNames={{ label: 'title', value: 'key' }}
@@ -4,7 +4,7 @@ import { StringUtils } from '../../utils';
4
4
  import { BaseRemoteSelect } from '../BaseRemoteSelect';
5
5
 
6
6
  export class FieldRemoteTreeSelect extends BaseRemoteSelect {
7
- static defaultProps = {
7
+ static readonly defaultProps = {
8
8
  treeDefaultExpandAll: true,
9
9
  };
10
10
 
@@ -10,7 +10,7 @@ interface FieldSysOrgTreeProps extends FieldProps<string[]> {
10
10
  }
11
11
 
12
12
  export class FieldSysOrgTree extends React.Component<FieldSysOrgTreeProps> {
13
- static defaultProps = {
13
+ static readonly defaultProps = {
14
14
  type: 'dept',
15
15
  };
16
16
 
@@ -8,7 +8,7 @@ interface FieldSysOrgTreeSelectProps extends FieldProps<string | string[]> {
8
8
 
9
9
  export class FieldSysOrgTreeSelect extends React.Component<FieldSysOrgTreeSelectProps> {
10
10
 
11
- static defaultProps = {
11
+ static readonly defaultProps = {
12
12
  type: 'dept',
13
13
  };
14
14
 
@@ -16,12 +16,12 @@ export interface FieldTableColumn {
16
16
  /** 列宽 */
17
17
  width?: number | string;
18
18
  /** 自定义渲染(返回的组件会被注入 value/onChange) */
19
- render?: (value: any, record: Record<string, any>, index: number) => React.ReactElement;
19
+ render?: (value: unknown, record: Record<string, unknown>, index: number) => React.ReactElement;
20
20
  /** 其余 antd Table 列属性 */
21
- [key: string]: any;
21
+ [key: string]: unknown;
22
22
  }
23
23
 
24
- export interface FieldTableProps extends FieldProps<Record<string, any>[]> {
24
+ export interface FieldTableProps extends FieldProps<Record<string, unknown>[]> {
25
25
  /** 列配置(操作列由组件自动追加) */
26
26
  columns: FieldTableColumn[];
27
27
  /** 容器样式 */
@@ -29,7 +29,7 @@ export interface FieldTableProps extends FieldProps<Record<string, any>[]> {
29
29
  }
30
30
 
31
31
  interface FieldTableState {
32
- dataSource: Record<string, any>[];
32
+ dataSource: Record<string, unknown>[];
33
33
  }
34
34
 
35
35
  /**
@@ -84,13 +84,13 @@ export class FieldTable extends React.Component<FieldTableProps, FieldTableState
84
84
  dataSource: []
85
85
  };
86
86
 
87
- onCellChange = (index: number, dataIndex: string | undefined, e: any) => {
87
+ onCellChange = (index: number, dataIndex: string | undefined, e: unknown) => {
88
88
  const {dataSource} = this.state;
89
89
  const row = dataSource[index];
90
90
 
91
- let v = e;
91
+ let v: unknown = e;
92
92
  if (e != null && typeof e === 'object' && 'target' in e) {
93
- v = e.target.value;
93
+ v = (e as {target: {value: unknown}}).target.value;
94
94
  }
95
95
 
96
96
  const next = [...dataSource];
@@ -104,25 +104,27 @@ export class FieldTable extends React.Component<FieldTableProps, FieldTableState
104
104
  this.setState({dataSource}, this.notifyParent);
105
105
  };
106
106
 
107
- remove = (record: Record<string, any>) => {
107
+ remove = (record: Record<string, unknown>) => {
108
108
  const {dataSource} = this.state;
109
109
  this.setState({dataSource: dataSource.filter(item => item !== record)}, this.notifyParent);
110
110
  };
111
111
 
112
112
  notifyParent = () => {
113
113
  const {dataSource} = this.state;
114
- this.props.onChange && this.props.onChange(dataSource);
114
+ this.props.onChange?.(dataSource);
115
115
  };
116
116
 
117
+ renderFooter = () => <Button type='dashed'
118
+ icon={<PlusOutlined/>}
119
+ onClick={this.add}>增加一行
120
+ </Button>;
121
+
117
122
  render() {
118
123
  return <div className='edit-table' style={this.props.style}>
119
124
  <Table columns={this.columns}
120
125
  dataSource={this.state.dataSource}
121
126
  size='small'
122
- footer={() => <Button type='dashed'
123
- icon={<PlusOutlined/>}
124
- onClick={this.add}>增加一行
125
- </Button>}
127
+ footer={this.renderFooter}
126
128
  pagination={false}
127
129
  >
128
130