@jiangood/open-admin 2.5.9 → 3.0.1
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 +27 -13
- package/src/layouts/admin/TabLayout.jsx +124 -0
- package/src/layouts/admin/index.jsx +5 -6
- package/src/layouts/admin/index.less +1 -82
- 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 +2 -2
- 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 -24
- package/src/pages/system/article/index.jsx +51 -56
- 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 -2257
- 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 -47
- 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 -10
- package/src/framework/GlobalData.js +0 -42
- 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 -120
- package/src/loading.jsx +0 -19
- package/src/pages/about.jsx +0 -16
- /package/src/pages/{login.less → public/login.less} +0 -0
package/package.json
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"devDependencies": {
|
|
3
|
+
"@playwright/test": "^1.62.0",
|
|
3
4
|
"@types/qs": "^6.15.1",
|
|
4
5
|
"@types/react": "^19.2.2",
|
|
5
6
|
"@types/react-dom": "^19.0.0",
|
|
7
|
+
"@vitejs/plugin-react": "^6.0.0",
|
|
6
8
|
"babel-plugin-react-compiler": "^1.0.0",
|
|
7
|
-
"
|
|
9
|
+
"less": "^4.2.0",
|
|
10
|
+
"typescript": "^7.0.0",
|
|
11
|
+
"vite": "^8.0.0"
|
|
8
12
|
},
|
|
9
13
|
"peerDependencies": {
|
|
10
14
|
"@ant-design/icons": "^6.0.0",
|
|
@@ -16,8 +20,7 @@
|
|
|
16
20
|
"lodash": "^4.17.23",
|
|
17
21
|
"qs": "^6.14.0",
|
|
18
22
|
"react": "^19.0.0",
|
|
19
|
-
"react-dom": "^19.0.0"
|
|
20
|
-
"umi": "^4.0.0"
|
|
23
|
+
"react-dom": "^19.0.0"
|
|
21
24
|
},
|
|
22
25
|
"name": "@jiangood/open-admin",
|
|
23
26
|
"repository": {
|
|
@@ -25,16 +28,25 @@
|
|
|
25
28
|
"url": "https://github.com/jiangood/open-admin"
|
|
26
29
|
},
|
|
27
30
|
"description": "open-admin",
|
|
31
|
+
"type": "module",
|
|
28
32
|
"files": [
|
|
29
33
|
"src/*",
|
|
30
|
-
"
|
|
31
|
-
"!src/.umi",
|
|
34
|
+
"vite-plugin/*",
|
|
32
35
|
"!src/pages/test/*"
|
|
33
36
|
],
|
|
34
37
|
"main": "src/index.ts",
|
|
38
|
+
"exports": {
|
|
39
|
+
".": "./src/index.ts",
|
|
40
|
+
"./vite-plugin": "./vite-plugin/index.js",
|
|
41
|
+
"./src/*": "./src/*",
|
|
42
|
+
"./package.json": "./package.json"
|
|
43
|
+
},
|
|
35
44
|
"scripts": {
|
|
36
|
-
"dev": "
|
|
37
|
-
"build": "
|
|
45
|
+
"dev": "vite",
|
|
46
|
+
"build": "vite build",
|
|
47
|
+
"preview": "vite preview",
|
|
48
|
+
"test:e2e": "playwright test",
|
|
49
|
+
"test:e2e:ui": "playwright test --ui"
|
|
38
50
|
},
|
|
39
|
-
"version": "
|
|
51
|
+
"version": "3.0.1"
|
|
40
52
|
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import {StorageUtils} from './utils/StorageUtils';
|
|
2
|
+
|
|
3
|
+
const SITE_INFO_KEY = "siteInfo";
|
|
4
|
+
const LOGIN_INFO_KEY = "loginInfo";
|
|
5
|
+
const DICT_INFO_KEY = "dictInfo";
|
|
6
|
+
const SITE_ARTICLES_KEY = "siteArticles";
|
|
7
|
+
|
|
8
|
+
export interface SiteInfo {
|
|
9
|
+
title?: string;
|
|
10
|
+
waterMark?: boolean;
|
|
11
|
+
[key: string]: unknown;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface LoginInfo {
|
|
15
|
+
name?: string;
|
|
16
|
+
account?: string;
|
|
17
|
+
phone?: string;
|
|
18
|
+
email?: string;
|
|
19
|
+
unit?: string;
|
|
20
|
+
dept?: string;
|
|
21
|
+
roles?: string;
|
|
22
|
+
createTime?: string;
|
|
23
|
+
permissions?: string[];
|
|
24
|
+
[key: string]: unknown;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface DictItem {
|
|
28
|
+
code: string | number;
|
|
29
|
+
label: string;
|
|
30
|
+
color?: string;
|
|
31
|
+
typeCode?: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface ArticleItem {
|
|
35
|
+
code: string;
|
|
36
|
+
title: string;
|
|
37
|
+
[key: string]: unknown;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface SiteArticles {
|
|
41
|
+
HEADER_AVATAR_DROPDOWN?: ArticleItem[];
|
|
42
|
+
HEADER_RIGHT?: ArticleItem[];
|
|
43
|
+
HEADER_LEFT?: ArticleItem[];
|
|
44
|
+
[key: string]: unknown;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export class GlobalData {
|
|
48
|
+
static setSiteInfo(data: SiteInfo): void {
|
|
49
|
+
StorageUtils.set(SITE_INFO_KEY, data);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
static getSiteInfo(): SiteInfo {
|
|
53
|
+
return StorageUtils.get<SiteInfo>(SITE_INFO_KEY) || {};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
static setLoginInfo(data: LoginInfo): void {
|
|
57
|
+
StorageUtils.set(LOGIN_INFO_KEY, data);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
static getLoginInfo(): LoginInfo {
|
|
61
|
+
return StorageUtils.get<LoginInfo>(LOGIN_INFO_KEY) || {};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
static setDictInfo(data: DictItem[] | null): void {
|
|
65
|
+
StorageUtils.set(DICT_INFO_KEY, data);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
static getDictInfo(): DictItem[] | null {
|
|
69
|
+
return StorageUtils.get<DictItem[]>(DICT_INFO_KEY);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
static setSiteArticles(data: SiteArticles): void {
|
|
73
|
+
StorageUtils.set(SITE_ARTICLES_KEY, data);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
static getSiteArticles(): SiteArticles {
|
|
77
|
+
return StorageUtils.get<SiteArticles>(SITE_ARTICLES_KEY) || {};
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export const ARTICLE_HEADER_LEFT = 'HEADER_LEFT';
|
|
82
|
+
export const ARTICLE_HEADER_RIGHT = 'HEADER_RIGHT';
|
|
83
|
+
export const ARTICLE_HEADER_AVATAR_DROPDOWN = 'HEADER_AVATAR_DROPDOWN';
|
|
84
|
+
|
|
85
|
+
export { SITE_INFO_KEY, LOGIN_INFO_KEY, DICT_INFO_KEY, SITE_ARTICLES_KEY };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {Alert, Skeleton, Tree} from 'antd';
|
|
2
2
|
import React from 'react';
|
|
3
|
-
import * as Icons from '@ant-design/icons';
|
|
4
3
|
import {HttpUtils} from "../utils";
|
|
4
|
+
import {NamedIcon} from "../components/NamedIcon";
|
|
5
5
|
|
|
6
6
|
interface OrgTreeProps {
|
|
7
7
|
onChange?: (orgId: string | null) => void;
|
|
@@ -48,12 +48,7 @@ export class OrgTree extends React.Component<OrgTreeProps, OrgTreeState> {
|
|
|
48
48
|
onSelect={this.onSelectOrg}
|
|
49
49
|
showIcon
|
|
50
50
|
blockNode
|
|
51
|
-
icon={item => {
|
|
52
|
-
const icon = Icons[item.iconName]
|
|
53
|
-
if (icon) {
|
|
54
|
-
return React.createElement(icon)
|
|
55
|
-
}
|
|
56
|
-
}}
|
|
51
|
+
icon={item => item.iconName ? <NamedIcon name={item.iconName}/> : null}
|
|
57
52
|
/>
|
|
58
53
|
}
|
|
59
54
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React, {ReactNode} from "react";
|
|
2
|
+
import {PermUtils} from "../utils";
|
|
3
|
+
|
|
4
|
+
export class Perm extends React.Component<{ code: string, children: ReactNode }> {
|
|
5
|
+
render() {
|
|
6
|
+
if (PermUtils.hasPermission(this.props.code)) {
|
|
7
|
+
return this.props.children;
|
|
8
|
+
}
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -2,22 +2,25 @@ import React from 'react';
|
|
|
2
2
|
import { Space } from 'antd';
|
|
3
3
|
import { PermUtils } from '../utils';
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
5
|
+
interface PermActionsProps {
|
|
6
|
+
gap?: boolean;
|
|
7
|
+
children?: React.ReactNode;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export class PermActions extends React.Component<PermActionsProps> {
|
|
11
|
+
render() {
|
|
12
|
+
const { children, gap = true } = this.props;
|
|
11
13
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
const checkPerm = (element) => {
|
|
15
|
+
const _props = element?.props;
|
|
16
|
+
return !_props?.perm || PermUtils.hasPermission(_props.perm);
|
|
17
|
+
};
|
|
16
18
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
const nodes = React.Children.toArray(children).filter(
|
|
20
|
+
(child) => child != null && checkPerm(child)
|
|
21
|
+
);
|
|
20
22
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
+
if (!gap) return <>{nodes}</>;
|
|
24
|
+
return <Space>{nodes}</Space>;
|
|
25
|
+
}
|
|
23
26
|
}
|
|
@@ -1,31 +1,46 @@
|
|
|
1
|
-
import {FieldRemoteSelect,
|
|
2
|
-
import React from "react";
|
|
1
|
+
import {FieldRemoteSelect, FieldRemoteTreeSelect} from "../fields";
|
|
2
|
+
import React, {type ComponentProps} from "react";
|
|
3
3
|
|
|
4
4
|
export * from './PermActions'
|
|
5
|
-
export * from './
|
|
5
|
+
export * from './Perm'
|
|
6
6
|
export * from './OrgTree'
|
|
7
7
|
export * from './RoleTree'
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
class InnerFieldUserSelect extends React.Component<ComponentProps<typeof FieldRemoteSelect>> {
|
|
10
|
+
render() {
|
|
11
|
+
return <FieldRemoteSelect url="admin/sysUser/options" {...this.props} />;
|
|
12
|
+
}
|
|
11
13
|
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
+
class InnerFieldUserSelectMultiple extends React.Component<ComponentProps<typeof FieldRemoteSelect>> {
|
|
15
|
+
render() {
|
|
16
|
+
return <FieldRemoteSelect url="admin/sysUser/options" multiple {...this.props} />;
|
|
17
|
+
}
|
|
14
18
|
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
19
|
+
class InnerFieldUnitTreeSelect extends React.Component<ComponentProps<typeof FieldRemoteTreeSelect>> {
|
|
20
|
+
render() {
|
|
21
|
+
return <FieldRemoteTreeSelect url="admin/sysOrg/unit-tree" {...this.props} />;
|
|
22
|
+
}
|
|
18
23
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
24
|
+
class InnerFieldDeptTreeSelect extends React.Component<ComponentProps<typeof FieldRemoteTreeSelect>> {
|
|
25
|
+
render() {
|
|
26
|
+
return <FieldRemoteTreeSelect url="admin/sysOrg/dept-tree" {...this.props} />;
|
|
27
|
+
}
|
|
22
28
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
29
|
+
class InnerFieldOrgTreeSelect extends React.Component<ComponentProps<typeof FieldRemoteTreeSelect>> {
|
|
30
|
+
render() {
|
|
31
|
+
return <FieldRemoteTreeSelect url="admin/sysOrg/dept-tree" {...this.props} />;
|
|
32
|
+
}
|
|
26
33
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
34
|
+
class InnerFieldOrgTreeMultipleSelect extends React.Component<ComponentProps<typeof FieldRemoteTreeSelect>> {
|
|
35
|
+
render() {
|
|
36
|
+
return <FieldRemoteTreeSelect url="admin/sysOrg/dept-tree" multiple {...this.props} />;
|
|
37
|
+
}
|
|
30
38
|
}
|
|
31
39
|
|
|
40
|
+
export const FieldUserSelect = InnerFieldUserSelect;
|
|
41
|
+
export const FieldUserSelectMultiple = InnerFieldUserSelectMultiple;
|
|
42
|
+
export const FieldUnitTreeSelect = InnerFieldUnitTreeSelect;
|
|
43
|
+
export const FieldDeptTreeSelect = InnerFieldDeptTreeSelect;
|
|
44
|
+
export const FieldOrgTreeSelect = InnerFieldOrgTreeSelect;
|
|
45
|
+
export const FieldOrgTreeMultipleSelect = InnerFieldOrgTreeMultipleSelect;
|
|
46
|
+
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React
|
|
1
|
+
import React from 'react';
|
|
2
2
|
|
|
3
3
|
interface ContextMenuItem {
|
|
4
4
|
key: string;
|
|
@@ -17,83 +17,110 @@ interface ContextMenuProps {
|
|
|
17
17
|
onClose: () => void;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
export
|
|
21
|
-
|
|
20
|
+
export class ContextMenu extends React.Component<ContextMenuProps> {
|
|
21
|
+
menuRef = React.createRef<HTMLDivElement>();
|
|
22
|
+
timer: ReturnType<typeof setTimeout> | null = null;
|
|
22
23
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
24
|
+
handleMouseDown = (e: MouseEvent) => {
|
|
25
|
+
if (this.menuRef.current && !this.menuRef.current.contains(e.target as Node)) {
|
|
26
|
+
this.props.onClose();
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
handleScroll = () => {
|
|
31
|
+
this.props.onClose();
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
handleKeyDown = (e: KeyboardEvent) => {
|
|
35
|
+
if (e.key === 'Escape') this.props.onClose();
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
componentDidMount() {
|
|
39
|
+
this.timer = setTimeout(() => {
|
|
40
|
+
document.addEventListener('mousedown', this.handleMouseDown);
|
|
41
|
+
document.addEventListener('scroll', this.handleScroll, true);
|
|
42
|
+
document.addEventListener('keydown', this.handleKeyDown);
|
|
37
43
|
}, 0);
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
componentDidUpdate(prevProps: ContextMenuProps) {
|
|
47
|
+
if (prevProps.onClose !== this.props.onClose) {
|
|
48
|
+
if (this.timer !== null) clearTimeout(this.timer);
|
|
49
|
+
document.removeEventListener('mousedown', this.handleMouseDown);
|
|
50
|
+
document.removeEventListener('scroll', this.handleScroll, true);
|
|
51
|
+
document.removeEventListener('keydown', this.handleKeyDown);
|
|
52
|
+
this.timer = setTimeout(() => {
|
|
53
|
+
document.addEventListener('mousedown', this.handleMouseDown);
|
|
54
|
+
document.addEventListener('scroll', this.handleScroll, true);
|
|
55
|
+
document.addEventListener('keydown', this.handleKeyDown);
|
|
56
|
+
}, 0);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
45
59
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
}
|
|
60
|
+
componentWillUnmount() {
|
|
61
|
+
if (this.timer !== null) {
|
|
62
|
+
clearTimeout(this.timer);
|
|
63
|
+
}
|
|
64
|
+
document.removeEventListener('mousedown', this.handleMouseDown);
|
|
65
|
+
document.removeEventListener('scroll', this.handleScroll, true);
|
|
66
|
+
document.removeEventListener('keydown', this.handleKeyDown);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
render() {
|
|
70
|
+
const { x, y, items, onClick, onClose } = this.props;
|
|
71
|
+
|
|
72
|
+
return (
|
|
73
|
+
<div
|
|
74
|
+
ref={this.menuRef}
|
|
75
|
+
style={{
|
|
76
|
+
position: 'fixed',
|
|
77
|
+
left: x,
|
|
78
|
+
top: y,
|
|
79
|
+
zIndex: 1050,
|
|
80
|
+
background: '#fff',
|
|
81
|
+
borderRadius: 4,
|
|
82
|
+
padding: '4px 0',
|
|
83
|
+
minWidth: 120,
|
|
84
|
+
boxShadow: '0 6px 16px 0 rgba(0,0,0,0.08), 0 3px 6px -4px rgba(0,0,0,0.12), 0 9px 28px 8px rgba(0,0,0,0.05)',
|
|
85
|
+
}}
|
|
86
|
+
>
|
|
87
|
+
{items.map(item => (
|
|
88
|
+
item.divider ? (
|
|
89
|
+
<div key={item.key} style={{ height: 1, background: '#f0f0f0', margin: '4px 0' }} />
|
|
90
|
+
) : (
|
|
91
|
+
<div
|
|
92
|
+
key={item.key}
|
|
93
|
+
onClick={() => {
|
|
94
|
+
if (!item.disabled) {
|
|
95
|
+
onClick({ key: item.key });
|
|
96
|
+
onClose();
|
|
97
|
+
}
|
|
98
|
+
}}
|
|
99
|
+
style={{
|
|
100
|
+
padding: '5px 12px',
|
|
101
|
+
fontSize: 13,
|
|
102
|
+
cursor: item.disabled ? 'not-allowed' : 'pointer',
|
|
103
|
+
color: item.danger ? '#ff4d4f' : item.disabled ? 'rgba(0,0,0,0.25)' : '#333',
|
|
104
|
+
display: 'flex',
|
|
105
|
+
alignItems: 'center',
|
|
106
|
+
gap: 8,
|
|
107
|
+
background: 'transparent',
|
|
108
|
+
transition: 'background 0.15s',
|
|
109
|
+
userSelect: 'none',
|
|
110
|
+
}}
|
|
111
|
+
onMouseEnter={(e) => {
|
|
112
|
+
if (!item.disabled) e.currentTarget.style.background = '#f5f5f5';
|
|
113
|
+
}}
|
|
114
|
+
onMouseLeave={(e) => {
|
|
115
|
+
e.currentTarget.style.background = 'transparent';
|
|
116
|
+
}}
|
|
117
|
+
>
|
|
118
|
+
{item.icon && <span style={{ fontSize: 14, lineHeight: 1 }}>{item.icon}</span>}
|
|
119
|
+
<span>{item.label}</span>
|
|
120
|
+
</div>
|
|
121
|
+
)
|
|
122
|
+
))}
|
|
123
|
+
</div>
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
@@ -9,7 +9,7 @@ import axios from "axios";
|
|
|
9
9
|
import qs from 'qs';
|
|
10
10
|
|
|
11
11
|
const axiosInstance = axios.create({
|
|
12
|
-
baseURL:
|
|
12
|
+
baseURL: import.meta.env.VITE_SERVER_SERVLET_CONTEXT_PATH,
|
|
13
13
|
withCredentials: true,
|
|
14
14
|
headers: {'Content-Type': 'application/json'},
|
|
15
15
|
paramsSerializer: (params) => qs.stringify(params, {indices: false})
|
|
@@ -34,15 +34,19 @@ interface ModalState {
|
|
|
34
34
|
errorMessage: string;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
export
|
|
38
|
-
|
|
37
|
+
export interface DownloadModalProps {
|
|
38
|
+
title?: string;
|
|
39
|
+
onFinish?: () => void;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export class DownloadModal extends React.Component<DownloadModalProps, ModalState> {
|
|
39
43
|
private abortController: AbortController | null = null;
|
|
40
44
|
private lastOptions: DownloadOptions | null = null;
|
|
41
45
|
private lastTime: number = 0;
|
|
42
46
|
private lastLoaded: number = 0;
|
|
43
47
|
private speedTimer: ReturnType<typeof setInterval> | null = null;
|
|
44
48
|
|
|
45
|
-
constructor(props:
|
|
49
|
+
constructor(props: DownloadModalProps) {
|
|
46
50
|
super(props);
|
|
47
51
|
this.state = {
|
|
48
52
|
open: false,
|
|
@@ -54,21 +58,14 @@ export class DownloadModal extends React.Component<{}, ModalState> {
|
|
|
54
58
|
speed: '',
|
|
55
59
|
errorMessage: '',
|
|
56
60
|
};
|
|
57
|
-
DownloadModal.instance = this;
|
|
58
61
|
}
|
|
59
62
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
instance.startDownload(options);
|
|
64
|
-
} else {
|
|
65
|
-
console.warn('[DownloadModal] 组件未挂载,download() 调用被忽略');
|
|
66
|
-
}
|
|
67
|
-
}
|
|
63
|
+
download = (options: DownloadOptions) => {
|
|
64
|
+
this.startDownload(options);
|
|
65
|
+
};
|
|
68
66
|
|
|
69
67
|
componentWillUnmount() {
|
|
70
68
|
this.clearSpeedTimer();
|
|
71
|
-
DownloadModal.instance = null;
|
|
72
69
|
}
|
|
73
70
|
|
|
74
71
|
private clearSpeedTimer() {
|
|
@@ -236,6 +233,7 @@ export class DownloadModal extends React.Component<{}, ModalState> {
|
|
|
236
233
|
speed: '',
|
|
237
234
|
loaded: total || this.state.loaded,
|
|
238
235
|
});
|
|
236
|
+
this.props.onFinish?.();
|
|
239
237
|
}).catch((error: any) => {
|
|
240
238
|
this.clearSpeedTimer();
|
|
241
239
|
if (axios.isCancel(error)) {
|
|
@@ -260,9 +258,9 @@ export class DownloadModal extends React.Component<{}, ModalState> {
|
|
|
260
258
|
|
|
261
259
|
return (
|
|
262
260
|
<Modal
|
|
263
|
-
title={<span><DownloadOutlined style={{marginRight: 8}}
|
|
261
|
+
title={<span><DownloadOutlined style={{marginRight: 8}}/>{this.props.title || '文件下载'}</span>}
|
|
264
262
|
open={open}
|
|
265
|
-
|
|
263
|
+
mask={{closable: false}}
|
|
266
264
|
closable={status !== 'downloading'}
|
|
267
265
|
onCancel={this.handleClose}
|
|
268
266
|
footer={
|
|
@@ -275,7 +273,7 @@ export class DownloadModal extends React.Component<{}, ModalState> {
|
|
|
275
273
|
</>
|
|
276
274
|
) : null
|
|
277
275
|
}
|
|
278
|
-
|
|
276
|
+
destroyOnHidden
|
|
279
277
|
>
|
|
280
278
|
<div style={{padding: '20px 0'}}>
|
|
281
279
|
{/* 文件名 */}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import {Button, Collapse, Result} from 'antd';
|
|
3
|
-
import {
|
|
3
|
+
import {getToken} from '../../config';
|
|
4
4
|
|
|
5
5
|
interface Props {
|
|
6
6
|
children: React.ReactNode;
|
|
@@ -69,7 +69,7 @@ export default class ErrorBoundary extends React.Component<Props, State> {
|
|
|
69
69
|
fontSize: 12, fontFamily: 'monospace',
|
|
70
70
|
whiteSpace: 'pre-wrap', wordBreak: 'break-all',
|
|
71
71
|
background: '#f5f5f5', padding: 12, borderRadius: 4,
|
|
72
|
-
color:
|
|
72
|
+
color: getToken().colorError,
|
|
73
73
|
};
|
|
74
74
|
|
|
75
75
|
return (
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import {Form, FormInstance, Modal} from 'antd'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
|
|
4
|
+
export interface FormModalProps {
|
|
5
|
+
title: string
|
|
6
|
+
onFinish?: (values: Record<string, any>) => Promise<void> | void
|
|
7
|
+
onValuesChange?: (changedValues: any, allValues: any) => void
|
|
8
|
+
width?: number
|
|
9
|
+
labelCol?: Record<string, any>
|
|
10
|
+
children?: React.ReactNode
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export default class FormModal extends React.Component<FormModalProps> {
|
|
14
|
+
|
|
15
|
+
state = {
|
|
16
|
+
visible: false,
|
|
17
|
+
confirmLoading: false,
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
private pendingValues: Record<string, any> | null = null
|
|
21
|
+
private formRef = React.createRef<FormInstance>()
|
|
22
|
+
|
|
23
|
+
get formInstance() {
|
|
24
|
+
return this.formRef.current
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
open = (values?: Record<string, any>) => {
|
|
28
|
+
this.pendingValues = values || {}
|
|
29
|
+
this.setState({visible: true})
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
componentDidUpdate(_: Readonly<FormModalProps>, prevState: Readonly<{ visible: boolean; confirmLoading: boolean }>) {
|
|
33
|
+
if (this.state.visible && !prevState.visible) {
|
|
34
|
+
setTimeout(() => {
|
|
35
|
+
if (this.pendingValues && Object.keys(this.pendingValues).length > 0) {
|
|
36
|
+
this.formRef.current?.setFieldsValue(this.pendingValues)
|
|
37
|
+
} else {
|
|
38
|
+
this.formRef.current?.resetFields()
|
|
39
|
+
}
|
|
40
|
+
this.pendingValues = null
|
|
41
|
+
})
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
private handleOk = async () => {
|
|
46
|
+
this.setState({confirmLoading: true})
|
|
47
|
+
try {
|
|
48
|
+
const values = await this.formRef.current?.validateFields()
|
|
49
|
+
if (values == null) return
|
|
50
|
+
await this.props.onFinish?.(values)
|
|
51
|
+
this.setState({visible: false})
|
|
52
|
+
} finally {
|
|
53
|
+
this.setState({confirmLoading: false})
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
render() {
|
|
58
|
+
return (
|
|
59
|
+
<Modal
|
|
60
|
+
title={this.props.title}
|
|
61
|
+
open={this.state.visible}
|
|
62
|
+
confirmLoading={this.state.confirmLoading}
|
|
63
|
+
onOk={this.handleOk}
|
|
64
|
+
onCancel={() => this.setState({visible: false})}
|
|
65
|
+
destroyOnHidden
|
|
66
|
+
width={this.props.width ?? 600}
|
|
67
|
+
>
|
|
68
|
+
<Form ref={this.formRef} labelCol={this.props.labelCol ?? {flex: '100px'}}
|
|
69
|
+
onValuesChange={this.props.onValuesChange}>
|
|
70
|
+
<Form.Item name='id' noStyle/>
|
|
71
|
+
{this.props.children}
|
|
72
|
+
</Form>
|
|
73
|
+
</Modal>
|
|
74
|
+
)
|
|
75
|
+
}
|
|
76
|
+
}
|