@jiangood/open-admin 2.5.8 → 3.0.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.
- package/package.json +20 -8
- package/src/framework/GlobalData.ts +85 -0
- package/src/framework/biz/OrgTree.tsx +2 -7
- package/src/framework/biz/Perm.tsx +11 -0
- package/src/framework/biz/PermActions.tsx +18 -15
- package/src/framework/biz/index.tsx +34 -19
- package/src/framework/components/ContextMenu/index.tsx +105 -78
- package/src/framework/components/DownloadModal/index.tsx +15 -17
- package/src/framework/components/ErrorBoundary/index.tsx +2 -2
- package/src/framework/components/FormModal/index.tsx +76 -0
- package/src/framework/components/Gap/index.tsx +1 -1
- package/src/framework/components/NamedIcon/index.tsx +55 -9
- package/src/framework/components/Page/index.less +0 -1
- package/src/framework/components/Page/index.tsx +34 -27
- package/src/framework/components/PageLoading/index.less +15 -0
- package/src/framework/components/PageLoading/index.tsx +32 -16
- package/src/framework/components/ProTable/index.tsx +86 -15
- package/src/framework/components/index.ts +1 -0
- package/src/framework/config/index.ts +1 -0
- package/src/framework/config/themeConfig.ts +39 -0
- package/src/framework/fields/FieldBoolean/index.tsx +11 -2
- package/src/framework/fields/FieldDate/index.tsx +22 -7
- package/src/framework/fields/FieldDateRange/index.tsx +24 -6
- package/src/framework/fields/FieldDictSelect/index.tsx +1 -0
- package/src/framework/fields/FieldEditor/index.tsx +7 -1
- package/src/framework/fields/FieldNumberRange/index.tsx +14 -5
- package/src/framework/fields/FieldPercent/index.tsx +16 -5
- package/src/framework/fields/FieldRemoteSelect/index.tsx +4 -2
- package/src/framework/fields/FieldRemoteTreeSelect/index.tsx +2 -1
- package/src/framework/fields/FieldSysOrgTree/index.tsx +6 -1
- package/src/framework/fields/FieldSysOrgTreeSelect/index.tsx +6 -1
- package/src/framework/fields/FieldTable/index.tsx +35 -6
- package/src/framework/fields/FieldTableSelect/index.tsx +18 -2
- package/src/framework/fields/FieldUploadFile/index.tsx +69 -28
- package/src/framework/fields/index.ts +0 -1
- package/src/framework/index.ts +2 -0
- package/src/framework/router/Link.tsx +26 -0
- package/src/framework/router/PageFrame.tsx +31 -0
- package/src/framework/router/history.ts +50 -0
- package/src/framework/router/index.ts +4 -0
- package/src/framework/router/matcher.ts +58 -0
- package/src/framework/utils/{ArrayUtils.js → ArrayUtils.ts} +5 -5
- package/src/framework/utils/{DateUtils.js → DateUtils.ts} +19 -19
- package/src/framework/utils/{DeviceUtils.js → DeviceUtils.ts} +8 -1
- package/src/framework/utils/{EventBus.js → EventBus.ts} +13 -6
- package/src/framework/utils/MessageApi.ts +5 -0
- package/src/framework/utils/ModalApi.ts +5 -0
- package/src/framework/utils/ObjectUtils.ts +15 -0
- package/src/framework/utils/{StorageUtils.js → StorageUtils.ts} +7 -7
- package/src/framework/utils/{StringUtils.js → StringUtils.ts} +15 -15
- package/src/framework/utils/{TreeUtils.js → TreeUtils.ts} +19 -12
- package/src/framework/utils/{UrlUtils.js → UrlUtils.ts} +10 -10
- package/src/framework/utils/index.ts +2 -1
- package/src/framework/utils/system/{DictUtils.js → DictUtils.ts} +16 -4
- package/src/framework/utils/system/{HttpUtils.js → HttpUtils.ts} +25 -21
- package/src/framework/utils/system/PageUtils.ts +49 -0
- package/src/framework/utils/system/{PermUtils.js → PermUtils.ts} +5 -6
- package/src/framework/utils/system/index.ts +0 -2
- package/src/framework/views/ViewBoolean/index.tsx +6 -3
- package/src/framework/views/ViewFileButton/index.tsx +13 -8
- package/src/framework/views/ViewImage/index.tsx +19 -14
- package/src/framework/views/ViewRange/index.tsx +10 -7
- package/src/framework/views/ViewText/index.tsx +9 -11
- package/src/layouts/admin/AdminTabs.jsx +79 -0
- package/src/layouts/admin/AdminTabs.less +63 -0
- package/src/layouts/admin/HeaderRight.jsx +66 -33
- package/src/layouts/admin/TabLayout.jsx +124 -0
- package/src/layouts/admin/index.jsx +12 -5
- package/src/layouts/admin/index.less +5 -83
- package/src/layouts/index.tsx +148 -0
- package/src/main.jsx +8 -0
- package/src/pages/account/changePassword.jsx +14 -10
- package/src/pages/article/$code.jsx +43 -0
- package/src/pages/index.jsx +6 -4
- package/src/pages/{login.jsx → public/login.jsx} +7 -10
- package/src/pages/public/test.jsx +30 -0
- package/src/pages/{forceUpdatePwd.jsx → standalone/forceUpdatePwd.jsx} +3 -32
- package/src/pages/system/article/index.jsx +147 -0
- package/src/pages/system/dict/index.jsx +60 -91
- package/src/pages/system/file/index.jsx +23 -17
- package/src/pages/system/job/index.jsx +63 -72
- package/src/pages/system/log/index.jsx +11 -8
- package/src/pages/system/org/index.jsx +60 -80
- package/src/pages/system/role/index.jsx +50 -86
- package/src/pages/system/role/rolePerm.jsx +2 -2
- package/src/pages/system/user/index.jsx +120 -73
- package/src/pages/system/user/userPerm.jsx +2 -2
- package/vite-plugin/index.js +107 -0
- package/config/common-plugin.js +0 -145
- package/config/config.js +0 -5
- package/config/utils.js +0 -73
- package/src/.umi-production/appData.json +0 -2237
- package/src/.umi-production/core/EmptyRoute.tsx +0 -9
- package/src/.umi-production/core/defineApp.ts +0 -16
- package/src/.umi-production/core/helmet.ts +0 -10
- package/src/.umi-production/core/helmetContext.ts +0 -4
- package/src/.umi-production/core/history.ts +0 -72
- package/src/.umi-production/core/historyIntelli.ts +0 -132
- package/src/.umi-production/core/plugin.ts +0 -40
- package/src/.umi-production/core/pluginConfig.ts +0 -330
- package/src/.umi-production/core/pluginConfigJoi.d.ts +0 -7
- package/src/.umi-production/core/polyfill.ts +0 -220
- package/src/.umi-production/core/route.tsx +0 -45
- package/src/.umi-production/core/routeProps.js +0 -5
- package/src/.umi-production/core/routeProps.ts +0 -6
- package/src/.umi-production/core/terminal.ts +0 -37
- package/src/.umi-production/exports.ts +0 -17
- package/src/.umi-production/testBrowser.tsx +0 -90
- package/src/.umi-production/tsconfig.json +0 -43
- package/src/.umi-production/typings.d.ts +0 -136
- package/src/.umi-production/umi.ts +0 -83
- package/src/framework/GlobalData.d.ts +0 -8
- package/src/framework/GlobalData.js +0 -33
- package/src/framework/biz/HasPerm.tsx +0 -14
- package/src/framework/fields/FieldRemoteSelectMultiple/index.tsx +0 -29
- package/src/framework/utils/ArrayUtils.d.ts +0 -6
- package/src/framework/utils/DateUtils.d.ts +0 -20
- package/src/framework/utils/DeviceUtils.d.ts +0 -3
- package/src/framework/utils/EventBus.d.ts +0 -6
- package/src/framework/utils/MessageUtils.d.ts +0 -10
- package/src/framework/utils/MessageUtils.js +0 -43
- package/src/framework/utils/ObjectUtils.d.ts +0 -14
- package/src/framework/utils/ObjectUtils.js +0 -12
- package/src/framework/utils/StorageUtils.d.ts +0 -4
- package/src/framework/utils/StringUtils.d.ts +0 -17
- package/src/framework/utils/TreeUtils.d.ts +0 -13
- package/src/framework/utils/UrlUtils.d.ts +0 -6
- package/src/framework/utils/system/DictUtils.d.ts +0 -20
- package/src/framework/utils/system/FormRegistry.d.ts +0 -8
- package/src/framework/utils/system/FormRegistry.js +0 -31
- package/src/framework/utils/system/HttpUtils.d.ts +0 -14
- package/src/framework/utils/system/PageUtils.d.ts +0 -14
- package/src/framework/utils/system/PageUtils.js +0 -59
- package/src/framework/utils/system/PermUtils.d.ts +0 -5
- package/src/framework/utils/system/ThemeUtils.d.ts +0 -6
- package/src/framework/utils/system/ThemeUtils.js +0 -52
- package/src/layouts/PageRender.tsx +0 -29
- package/src/layouts/admin/TabPageRender.jsx +0 -210
- package/src/layouts/index.jsx +0 -119
- package/src/loading.jsx +0 -19
- package/src/pages/about.jsx +0 -11
- /package/src/pages/{login.less → public/login.less} +0 -0
|
@@ -1,6 +1,25 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
|
|
1
|
+
import {WarningOutlined} from '@ant-design/icons';
|
|
2
|
+
import React, {useEffect, useState} from 'react';
|
|
3
|
+
|
|
4
|
+
type IconComponent = React.ComponentType<React.ComponentProps<typeof WarningOutlined>>;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 构建期生成 "图标名 -> 按需加载函数" 的映射。
|
|
8
|
+
* 避免 import * as Icons 全量打包 @ant-design/icons(800+ 图标),
|
|
9
|
+
* 每个图标编译为独立 chunk,仅在菜单/数据引用时按需加载。
|
|
10
|
+
*/
|
|
11
|
+
const iconLoaders: Record<string, () => Promise<{ default: IconComponent }>> = {};
|
|
12
|
+
for (const [path, loader] of Object.entries(
|
|
13
|
+
import.meta.glob('/node_modules/@ant-design/icons/es/icons/*.js')
|
|
14
|
+
)) {
|
|
15
|
+
const name = /([^/]+)\.js$/.exec(path)?.[1];
|
|
16
|
+
if (name) {
|
|
17
|
+
iconLoaders[name] = loader as () => Promise<{ default: IconComponent }>;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** 已加载图标缓存,命中后渲染为同步 */
|
|
22
|
+
const iconCache = new Map<string, IconComponent>();
|
|
4
23
|
|
|
5
24
|
type NamedIconProps = {
|
|
6
25
|
name: string;
|
|
@@ -8,12 +27,39 @@ type NamedIconProps = {
|
|
|
8
27
|
|
|
9
28
|
export function NamedIcon(props: NamedIconProps): React.ReactElement {
|
|
10
29
|
const {name, ...rest} = props;
|
|
11
|
-
const
|
|
30
|
+
const [loaded, setLoaded] = useState<{ name: string; comp: IconComponent } | null>(null);
|
|
12
31
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
if (iconCache.has(name)) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const loader = iconLoaders[name];
|
|
37
|
+
if (!loader) {
|
|
38
|
+
console.warn(`NamedIcon: icon "${name}" not found, using fallback`);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
let cancelled = false;
|
|
42
|
+
loader().then(mod => {
|
|
43
|
+
iconCache.set(name, mod.default);
|
|
44
|
+
if (!cancelled) {
|
|
45
|
+
setLoaded({name, comp: mod.default});
|
|
46
|
+
}
|
|
47
|
+
}).catch(e => {
|
|
48
|
+
console.warn(`NamedIcon: failed to load icon "${name}"`, e);
|
|
49
|
+
});
|
|
50
|
+
return () => {
|
|
51
|
+
cancelled = true;
|
|
52
|
+
};
|
|
53
|
+
}, [name]);
|
|
54
|
+
|
|
55
|
+
const Icon = (loaded && loaded.name === name) ? loaded.comp : iconCache.get(name);
|
|
16
56
|
|
|
17
|
-
|
|
18
|
-
|
|
57
|
+
if (Icon) {
|
|
58
|
+
return <Icon {...rest} />;
|
|
59
|
+
}
|
|
60
|
+
if (!iconLoaders[name]) {
|
|
61
|
+
return <WarningOutlined {...rest} />;
|
|
62
|
+
}
|
|
63
|
+
// 加载中:1em 占位,避免菜单布局抖动
|
|
64
|
+
return <span style={{display: 'inline-block', width: '1em', height: '1em', verticalAlign: '-0.125em'}}/>;
|
|
19
65
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { Typography } from "antd";
|
|
3
3
|
import './index.less'
|
|
4
|
-
import {
|
|
4
|
+
import {getToken} from "../../config";
|
|
5
5
|
import { PermActions } from "../../biz/PermActions";
|
|
6
6
|
|
|
7
7
|
interface PageProps {
|
|
@@ -14,34 +14,41 @@ interface PageProps {
|
|
|
14
14
|
children?: React.ReactNode;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
export
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
export class Page extends React.Component<PageProps> {
|
|
18
|
+
render() {
|
|
19
|
+
const { padding = true, backgroundGray = false, debug = false, title, description, actions, children } = this.props;
|
|
20
|
+
const hasHeader = title != null || description != null || actions != null;
|
|
21
|
+
const style: React.CSSProperties = {};
|
|
20
22
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
23
|
+
if (padding) {
|
|
24
|
+
style.padding = 16;
|
|
25
|
+
}
|
|
26
|
+
const token = getToken();
|
|
27
|
+
if (backgroundGray) {
|
|
28
|
+
style.backgroundColor = token.colorBgLayout;
|
|
29
|
+
}
|
|
30
|
+
if (debug) {
|
|
31
|
+
style.backgroundColor = 'rgba(255, 0, 0, 0.08)';
|
|
32
|
+
}
|
|
33
|
+
if (!style.backgroundColor) {
|
|
34
|
+
style.backgroundColor = token.colorBgLayout;
|
|
35
|
+
}
|
|
30
36
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
return <div className={'oa-page'} style={style}>
|
|
38
|
+
{hasHeader && (
|
|
39
|
+
<div className="oa-page-header">
|
|
40
|
+
<div className="oa-page-header-top">
|
|
41
|
+
<div className="oa-page-header-left">
|
|
42
|
+
<div>
|
|
43
|
+
{title && <Typography.Title level={5} style={{ margin: 0 }}>{title}</Typography.Title>}
|
|
44
|
+
{description && <div><Typography.Text type="secondary">{description}</Typography.Text></div>}
|
|
45
|
+
</div>
|
|
39
46
|
</div>
|
|
47
|
+
{actions && <PermActions>{actions}</PermActions>}
|
|
40
48
|
</div>
|
|
41
|
-
{actions && <PermActions>{actions}</PermActions>}
|
|
42
49
|
</div>
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
50
|
+
)}
|
|
51
|
+
{children}
|
|
52
|
+
</div>;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -1,24 +1,40 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import {Alert, Spin} from "antd";
|
|
3
|
-
import {
|
|
3
|
+
import {LoadingOutlined} from "@ant-design/icons";
|
|
4
|
+
import {getToken} from "../../config";
|
|
5
|
+
import './index.less'
|
|
4
6
|
|
|
5
|
-
export
|
|
7
|
+
export interface PageLoadingProps {
|
|
8
|
+
message?: string;
|
|
9
|
+
messages?: string[];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function PageLoading(props: PageLoadingProps) {
|
|
6
13
|
const titles = props.messages || (props.message ? [props.message] : ['页面加载中...']);
|
|
14
|
+
const primaryColor = getToken().colorPrimary;
|
|
7
15
|
|
|
8
|
-
return
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
return (
|
|
17
|
+
<div className="oa-page-loading">
|
|
18
|
+
<div className="oa-page-loading-content">
|
|
19
|
+
<div>
|
|
20
|
+
<Spin indicator={<LoadingOutlined style={{fontSize: 48, color: primaryColor}} spin/>}/>
|
|
21
|
+
</div>
|
|
22
|
+
<div className="oa-page-loading-messages">
|
|
23
|
+
{titles.map((msg, i) => (
|
|
24
|
+
<Alert
|
|
25
|
+
key={i}
|
|
26
|
+
title={<span style={{color: primaryColor}}>{msg}</span>}
|
|
27
|
+
type="info"
|
|
28
|
+
showIcon
|
|
29
|
+
style={{
|
|
30
|
+
marginBottom: i < titles.length - 1 ? 8 : 0,
|
|
31
|
+
border: `1px solid ${primaryColor}20`,
|
|
32
|
+
background: `${primaryColor}08`,
|
|
33
|
+
}}
|
|
34
|
+
/>
|
|
35
|
+
))}
|
|
36
|
+
</div>
|
|
21
37
|
</div>
|
|
22
38
|
</div>
|
|
23
|
-
|
|
39
|
+
);
|
|
24
40
|
}
|
|
@@ -1,15 +1,81 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import {Button, Form, Table} from 'antd';
|
|
3
|
+
import type {FormInstance, TableProps} from 'antd';
|
|
3
4
|
|
|
4
5
|
import {StringUtils} from "../../utils";
|
|
5
6
|
|
|
6
7
|
import './index.less'
|
|
7
8
|
|
|
9
|
+
/** 通过 actionRef 暴露的表格操作 */
|
|
10
|
+
export interface ProTableActionRef {
|
|
11
|
+
reload: () => void;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** request 返回结构(Spring Data Page 序列化 + 扩展数据) */
|
|
15
|
+
export interface ProTableRequestResult<T = any> {
|
|
16
|
+
content: T[];
|
|
17
|
+
totalElements: number | string;
|
|
18
|
+
size: number;
|
|
19
|
+
extData?: {
|
|
20
|
+
summary?: React.ReactNode;
|
|
21
|
+
[key: string]: any;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface ProTableProps<T = any> {
|
|
26
|
+
/** 数据请求,框架自动注入 page/size/sort 参数 */
|
|
27
|
+
request: (params: Record<string, any>) => Promise<ProTableRequestResult<T>>;
|
|
28
|
+
/** antd Table 列定义 */
|
|
29
|
+
columns: TableProps<T>['columns'];
|
|
30
|
+
/** 获取表格操作句柄(reload) */
|
|
31
|
+
actionRef?: React.MutableRefObject<ProTableActionRef | undefined>;
|
|
32
|
+
/** 获取搜索表单实例 */
|
|
33
|
+
formRef?: React.MutableRefObject<FormInstance | undefined>;
|
|
34
|
+
/** 工具栏渲染,参数为当前搜索值与行选择状态 */
|
|
35
|
+
toolBarRender?: (params: Record<string, any>, selection: {
|
|
36
|
+
selectedRows: T[];
|
|
37
|
+
selectedRowKeys: React.Key[];
|
|
38
|
+
}) => React.ReactNode;
|
|
39
|
+
rowKey?: string;
|
|
40
|
+
/** 行选择:true 为默认 checkbox,对象可覆盖 type/onChange */
|
|
41
|
+
rowSelection?: boolean | {
|
|
42
|
+
type?: 'checkbox' | 'radio';
|
|
43
|
+
onChange?: (selectedRowKeys: React.Key[], selectedRows: T[]) => void;
|
|
44
|
+
};
|
|
45
|
+
defaultPageSize?: number;
|
|
46
|
+
/** 搜索栏每行列数,默认 4 */
|
|
47
|
+
searchFormCols?: number;
|
|
48
|
+
/** 搜索表单渲染函数,返回 Form.Item 列表 */
|
|
49
|
+
searchFormRender?: () => React.ReactNode;
|
|
50
|
+
scrollY?: number | string;
|
|
51
|
+
bordered?: boolean;
|
|
52
|
+
}
|
|
8
53
|
|
|
9
|
-
|
|
54
|
+
interface ProTableState<T = any> {
|
|
55
|
+
selectedRowKeys: React.Key[];
|
|
56
|
+
selectedRows: T[];
|
|
57
|
+
tableSize: 'small' | 'middle' | 'large';
|
|
58
|
+
loading: boolean;
|
|
59
|
+
params: Record<string, any>;
|
|
60
|
+
dataSource: T[];
|
|
61
|
+
total: number;
|
|
62
|
+
current: number;
|
|
63
|
+
pageSize: number;
|
|
64
|
+
sorter: {
|
|
65
|
+
field?: string;
|
|
66
|
+
order?: 'ascend' | 'descend' | null;
|
|
67
|
+
};
|
|
68
|
+
extData: {
|
|
69
|
+
summary?: React.ReactNode;
|
|
70
|
+
[key: string]: any;
|
|
71
|
+
};
|
|
72
|
+
scrollY: number | string | null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export class ProTable<T = any> extends React.Component<ProTableProps<T>, ProTableState<T>> {
|
|
10
76
|
|
|
11
77
|
|
|
12
|
-
state = {
|
|
78
|
+
state: ProTableState<T> = {
|
|
13
79
|
selectedRowKeys: [],
|
|
14
80
|
selectedRows: [],
|
|
15
81
|
|
|
@@ -39,7 +105,10 @@ export class ProTable extends React.Component {
|
|
|
39
105
|
}
|
|
40
106
|
|
|
41
107
|
|
|
42
|
-
|
|
108
|
+
id: string;
|
|
109
|
+
formRef: React.RefObject<FormInstance | null> = React.createRef();
|
|
110
|
+
|
|
111
|
+
constructor(props: ProTableProps<T>) {
|
|
43
112
|
super(props);
|
|
44
113
|
if (props.defaultPageSize) {
|
|
45
114
|
this.state.pageSize = props.defaultPageSize
|
|
@@ -47,8 +116,6 @@ export class ProTable extends React.Component {
|
|
|
47
116
|
this.id = StringUtils.random(32)
|
|
48
117
|
}
|
|
49
118
|
|
|
50
|
-
formRef = React.createRef()
|
|
51
|
-
|
|
52
119
|
componentDidMount() {
|
|
53
120
|
this.loadData()
|
|
54
121
|
if (this.props.actionRef) {
|
|
@@ -72,7 +139,7 @@ export class ProTable extends React.Component {
|
|
|
72
139
|
const {sorter} = this.state
|
|
73
140
|
|
|
74
141
|
const {field, order} = sorter
|
|
75
|
-
if (field) {
|
|
142
|
+
if (field && order) {
|
|
76
143
|
params.sort = field + "," + (order === 'ascend' ? 'asc' : 'desc')
|
|
77
144
|
}
|
|
78
145
|
|
|
@@ -82,7 +149,7 @@ export class ProTable extends React.Component {
|
|
|
82
149
|
const {content, totalElements, size,extData} = rs;
|
|
83
150
|
|
|
84
151
|
|
|
85
|
-
this.setState({dataSource: content, total:
|
|
152
|
+
this.setState({dataSource: content, total: Number(totalElements),pageSize:size})
|
|
86
153
|
if (extData) {
|
|
87
154
|
this.setState({extData})
|
|
88
155
|
}
|
|
@@ -160,19 +227,23 @@ export class ProTable extends React.Component {
|
|
|
160
227
|
|
|
161
228
|
|
|
162
229
|
renderForm = () => {
|
|
163
|
-
if (
|
|
230
|
+
if (this.props.children) {
|
|
231
|
+
throw new Error('[ProTable] children 已废弃,请使用 searchFormRender prop 替代')
|
|
232
|
+
}
|
|
233
|
+
const searchContent = this.props.searchFormRender?.()
|
|
234
|
+
if (!searchContent) return
|
|
164
235
|
|
|
165
236
|
return (
|
|
166
237
|
<Form
|
|
167
238
|
className="filter-bar"
|
|
168
|
-
style={{gridTemplateColumns: `repeat(${this.props.
|
|
239
|
+
style={{gridTemplateColumns: `repeat(${this.props.searchFormCols ?? 4}, 1fr)`}}
|
|
169
240
|
onFinish={(values) => this.onSearch(values)}
|
|
170
241
|
ref={(instance) => {
|
|
171
242
|
this.formRef.current = instance;
|
|
172
243
|
if (this.props.formRef) this.props.formRef.current = instance;
|
|
173
244
|
}}
|
|
174
245
|
>
|
|
175
|
-
{
|
|
246
|
+
{searchContent}
|
|
176
247
|
<div className="filter-actions">
|
|
177
248
|
<Button type='primary' htmlType="submit">查询</Button>
|
|
178
249
|
<Button onClick={() => {
|
|
@@ -184,7 +255,7 @@ export class ProTable extends React.Component {
|
|
|
184
255
|
)
|
|
185
256
|
};
|
|
186
257
|
|
|
187
|
-
getToolBarRenderNode(toolBarRender) {
|
|
258
|
+
getToolBarRenderNode(toolBarRender: NonNullable<ProTableProps<T>['toolBarRender']>) {
|
|
188
259
|
if (!toolBarRender) {
|
|
189
260
|
return
|
|
190
261
|
}
|
|
@@ -195,7 +266,7 @@ export class ProTable extends React.Component {
|
|
|
195
266
|
});
|
|
196
267
|
}
|
|
197
268
|
|
|
198
|
-
getRowSelectionProps = rowSelection => {
|
|
269
|
+
getRowSelectionProps = (rowSelection: ProTableProps<T>['rowSelection']) => {
|
|
199
270
|
if (rowSelection == null || rowSelection === false) {
|
|
200
271
|
return null
|
|
201
272
|
}
|
|
@@ -217,11 +288,11 @@ export class ProTable extends React.Component {
|
|
|
217
288
|
};
|
|
218
289
|
};
|
|
219
290
|
|
|
220
|
-
onSearch = (values) => {
|
|
221
|
-
this.setState({params: values, current: 1}, this.loadData)
|
|
291
|
+
onSearch = (values: Record<string, any>) => {
|
|
292
|
+
this.setState({params: values, current: 1, sorter: {}}, this.loadData)
|
|
222
293
|
}
|
|
223
294
|
|
|
224
|
-
changeFormValues = (values) => {
|
|
295
|
+
changeFormValues = (values: Record<string, any>) => {
|
|
225
296
|
if (this.formRef.current) {
|
|
226
297
|
this.formRef.current.resetFields()
|
|
227
298
|
this.formRef.current.setFieldsValue(values)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { getThemeConfig, getToken } from './themeConfig'
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { theme } from 'antd';
|
|
2
|
+
import type { ThemeConfig } from 'antd';
|
|
3
|
+
|
|
4
|
+
const { getDesignToken } = theme;
|
|
5
|
+
|
|
6
|
+
let cachedConfig: ThemeConfig | null = null;
|
|
7
|
+
let cachedToken: Record<string, any> | null = null;
|
|
8
|
+
|
|
9
|
+
function buildConfig(): ThemeConfig {
|
|
10
|
+
const token: Record<string, any> = { borderRadius: 4 };
|
|
11
|
+
const components: Record<string, any> = {
|
|
12
|
+
Layout: { headerBg: 'white', triggerHeight: 32 },
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
try {
|
|
16
|
+
const env = import.meta.env;
|
|
17
|
+
if (env.VITE_THEME_PRIMARY_COLOR) token.colorPrimary = env.VITE_THEME_PRIMARY_COLOR;
|
|
18
|
+
if (env.VITE_THEME_SUCCESS_COLOR) token.colorSuccess = env.VITE_THEME_SUCCESS_COLOR;
|
|
19
|
+
if (env.VITE_THEME_WARNING_COLOR) token.colorWarning = env.VITE_THEME_WARNING_COLOR;
|
|
20
|
+
if (env.VITE_THEME_ERROR_COLOR) token.colorError = env.VITE_THEME_ERROR_COLOR;
|
|
21
|
+
if (env.VITE_THEME_BACKGROUND_COLOR) token.colorBgLayout = env.VITE_THEME_BACKGROUND_COLOR;
|
|
22
|
+
} catch (e) {}
|
|
23
|
+
|
|
24
|
+
return { token, components };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function getThemeConfig(): ThemeConfig {
|
|
28
|
+
if (!cachedConfig) {
|
|
29
|
+
cachedConfig = buildConfig();
|
|
30
|
+
}
|
|
31
|
+
return cachedConfig;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function getToken(): Record<string, any> {
|
|
35
|
+
if (!cachedToken) {
|
|
36
|
+
cachedToken = getDesignToken(getThemeConfig());
|
|
37
|
+
}
|
|
38
|
+
return cachedToken;
|
|
39
|
+
}
|
|
@@ -11,8 +11,17 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import React from 'react';
|
|
13
13
|
import {Checkbox, Radio, Select, Switch} from 'antd';
|
|
14
|
+
import type {FieldProps} from '../types';
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
/** 布尔值的展示类型 */
|
|
17
|
+
export type FieldBooleanType = 'select' | 'radio' | 'checkbox' | 'switch';
|
|
18
|
+
|
|
19
|
+
export interface FieldBooleanProps extends FieldProps<boolean> {
|
|
20
|
+
/** 展示类型,默认 select */
|
|
21
|
+
type?: FieldBooleanType;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export class FieldBoolean extends React.Component<FieldBooleanProps> {
|
|
16
25
|
|
|
17
26
|
static defaultProps = {
|
|
18
27
|
type: 'select'
|
|
@@ -58,7 +67,7 @@ export class FieldBoolean extends React.Component {
|
|
|
58
67
|
|
|
59
68
|
}
|
|
60
69
|
|
|
61
|
-
parseBoolean(v) {
|
|
70
|
+
parseBoolean(v: any): boolean | undefined {
|
|
62
71
|
if (v === null || v === undefined) {
|
|
63
72
|
return undefined;
|
|
64
73
|
}
|
|
@@ -5,15 +5,29 @@ import React from "react";
|
|
|
5
5
|
import dayjs from "dayjs";
|
|
6
6
|
import {DatePicker, TimePicker} from "antd";
|
|
7
7
|
import {DateUtils} from "../../utils";
|
|
8
|
+
import type {FieldProps} from '../types';
|
|
8
9
|
|
|
9
|
-
export
|
|
10
|
+
export interface FieldDateProps extends FieldProps<string> {
|
|
11
|
+
/** 日期类型,如 YYYY-MM-DD、YYYY-MM、HH:mm:ss 等,默认 YYYY-MM-DD */
|
|
12
|
+
type?: string;
|
|
13
|
+
/** 占位文本(透传给 DatePicker/TimePicker) */
|
|
14
|
+
placeholder?: string;
|
|
15
|
+
/** 是否禁用 */
|
|
16
|
+
disabled?: boolean;
|
|
17
|
+
/** 自定义样式 */
|
|
18
|
+
style?: React.CSSProperties;
|
|
19
|
+
/** 其余属性透传给 DatePicker/TimePicker */
|
|
20
|
+
[key: string]: any;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export class FieldDate extends React.Component<FieldDateProps> {
|
|
10
24
|
static defaultProps = {
|
|
11
25
|
type: 'YYYY-MM-DD'
|
|
12
26
|
};
|
|
13
27
|
|
|
14
28
|
render() {
|
|
15
29
|
const {type, value, onChange, ...rest} = this.props;
|
|
16
|
-
const formattedType = DateUtils.convertTypeToFormat(type);
|
|
30
|
+
const formattedType = DateUtils.convertTypeToFormat(type as string);
|
|
17
31
|
|
|
18
32
|
switch (formattedType) {
|
|
19
33
|
case 'YYYY':
|
|
@@ -77,19 +91,20 @@ export class FieldDate extends React.Component {
|
|
|
77
91
|
|
|
78
92
|
}
|
|
79
93
|
|
|
80
|
-
strToDate(value, fmt) {
|
|
94
|
+
strToDate(value: string | number | dayjs.Dayjs | null | undefined, fmt: string): dayjs.Dayjs | null | undefined {
|
|
81
95
|
if (value != null && value !== '') {
|
|
82
96
|
const type = typeof value;
|
|
83
97
|
if (type === 'string' || type === 'number') {
|
|
84
|
-
return dayjs(value, fmt);
|
|
98
|
+
return dayjs(value as string | number, fmt);
|
|
85
99
|
}
|
|
86
100
|
}
|
|
87
101
|
|
|
88
|
-
return value;
|
|
102
|
+
return value as dayjs.Dayjs | null | undefined;
|
|
89
103
|
}
|
|
90
104
|
|
|
91
|
-
dateToStr(date, fmt) {
|
|
92
|
-
|
|
105
|
+
dateToStr(date: dayjs.Dayjs | null | undefined, fmt: string): string {
|
|
106
|
+
// 清空时 date 为 null,此时按 null 回调给父组件
|
|
107
|
+
return date ? date.format(fmt) : (null as unknown as string);
|
|
93
108
|
}
|
|
94
109
|
|
|
95
110
|
}
|
|
@@ -5,17 +5,34 @@ import React from "react";
|
|
|
5
5
|
import dayjs from "dayjs";
|
|
6
6
|
import {DatePicker, TimePicker} from "antd";
|
|
7
7
|
import {DateUtils, StringUtils} from "../../utils";
|
|
8
|
+
import type {FieldProps} from '../types';
|
|
8
9
|
|
|
9
10
|
const SP = StringUtils.ISO_SPLITTER;
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
/** 日期范围值,形如 "2024-01-01/2024-01-31"(起止以 / 分隔) */
|
|
13
|
+
export type FieldDateRangeValue = string;
|
|
14
|
+
|
|
15
|
+
export interface FieldDateRangeProps extends FieldProps<FieldDateRangeValue> {
|
|
16
|
+
/** 日期类型,如 YYYY-MM-DD、YYYY-MM、HH:mm:ss 等,默认 YYYY-MM-DD */
|
|
17
|
+
type?: string;
|
|
18
|
+
/** 占位文本(透传给 RangePicker) */
|
|
19
|
+
placeholder?: string | [string, string];
|
|
20
|
+
/** 是否禁用 */
|
|
21
|
+
disabled?: boolean | [boolean, boolean];
|
|
22
|
+
/** 自定义样式 */
|
|
23
|
+
style?: React.CSSProperties;
|
|
24
|
+
/** 其余属性透传给 RangePicker */
|
|
25
|
+
[key: string]: any;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export class FieldDateRange extends React.Component<FieldDateRangeProps> {
|
|
12
29
|
static defaultProps = {
|
|
13
30
|
type: 'YYYY-MM-DD'
|
|
14
31
|
};
|
|
15
32
|
|
|
16
33
|
render() {
|
|
17
34
|
const {type, value, onChange, ...rest} = this.props;
|
|
18
|
-
const formattedType = DateUtils.convertTypeToFormat(type);
|
|
35
|
+
const formattedType = DateUtils.convertTypeToFormat(type as string);
|
|
19
36
|
|
|
20
37
|
switch (formattedType) {
|
|
21
38
|
case 'YYYY':
|
|
@@ -79,7 +96,7 @@ export class FieldDateRange extends React.Component {
|
|
|
79
96
|
|
|
80
97
|
}
|
|
81
98
|
|
|
82
|
-
strToDate(v, fmt) {
|
|
99
|
+
strToDate(v: string | null | undefined, fmt: string): [dayjs.Dayjs, dayjs.Dayjs] | null {
|
|
83
100
|
if (!v) {
|
|
84
101
|
return null;
|
|
85
102
|
}
|
|
@@ -90,9 +107,10 @@ export class FieldDateRange extends React.Component {
|
|
|
90
107
|
return [dayjs(s1), dayjs(s2)];
|
|
91
108
|
}
|
|
92
109
|
|
|
93
|
-
dateToStr(dateArr, fmt) {
|
|
94
|
-
const
|
|
95
|
-
const
|
|
110
|
+
dateToStr(dateArr: [dayjs.Dayjs | null, dayjs.Dayjs | null] | null, fmt: string): string {
|
|
111
|
+
const arr = dateArr as [dayjs.Dayjs | null, dayjs.Dayjs | null];
|
|
112
|
+
const d1 = arr[0];
|
|
113
|
+
const d2 = arr[1];
|
|
96
114
|
|
|
97
115
|
const s1 = d1 ? d1.format(fmt) : "";
|
|
98
116
|
const s2 = d2 ? d2.format(fmt) : "";
|
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import {Editor as TinyMceEditor} from '@tinymce/tinymce-react';
|
|
3
3
|
import {UrlUtils} from '../../utils';
|
|
4
|
+
import type {FieldProps} from '../types';
|
|
5
|
+
|
|
6
|
+
export interface FieldEditorProps extends FieldProps<string> {
|
|
7
|
+
/** 编辑器高度,默认 300 */
|
|
8
|
+
height?: number;
|
|
9
|
+
}
|
|
4
10
|
|
|
5
11
|
/**
|
|
6
12
|
* 富文本编辑器
|
|
7
13
|
*
|
|
8
14
|
* 图片上传相关配置 https://www.tiny.cloud/docs/tinymce/7/image/
|
|
9
15
|
*/
|
|
10
|
-
export class FieldEditor extends React.Component {
|
|
16
|
+
export class FieldEditor extends React.Component<FieldEditorProps> {
|
|
11
17
|
render() {
|
|
12
18
|
const uploadUrl = UrlUtils.contextPath('/admin/sysFile/upload');
|
|
13
19
|
const jsUrl = UrlUtils.contextPath('/admin/tinymce/tinymce.min.js');
|