@jiangood/open-admin 3.0.15 → 3.1.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 +15 -2
- package/src/framework/biz/OrgTree.tsx +10 -6
- package/src/framework/biz/PermActions.tsx +5 -3
- package/src/framework/biz/RoleTree.tsx +10 -6
- package/src/framework/biz/index.tsx +1 -0
- package/src/framework/components/ContextMenu/index.tsx +17 -1
- package/src/framework/components/DownloadModal/index.tsx +40 -33
- package/src/framework/components/DrawerForm/index.tsx +108 -0
- package/src/framework/components/FormModal/index.tsx +16 -9
- package/src/framework/components/NamedIcon/index.tsx +2 -2
- package/src/framework/components/OrgSwitcher/index.tsx +6 -7
- package/src/framework/components/PageLoading/index.tsx +3 -3
- package/src/framework/components/ProTable/index.tsx +28 -25
- package/src/framework/components/ValueType/index.tsx +1 -1
- package/src/framework/components/index.ts +1 -0
- package/src/framework/config/themeConfig.ts +5 -5
- package/src/framework/fields/BaseRemoteSelect/index.tsx +23 -21
- package/src/framework/fields/FieldBoolean/index.tsx +6 -6
- package/src/framework/fields/FieldDate/index.tsx +10 -10
- package/src/framework/fields/FieldDateRange/index.tsx +20 -20
- package/src/framework/fields/FieldDictSelect/index.tsx +2 -2
- package/src/framework/fields/FieldEditor/index.tsx +1 -1
- package/src/framework/fields/FieldNumberRange/index.tsx +16 -17
- package/src/framework/fields/FieldPercent/index.tsx +2 -2
- package/src/framework/fields/FieldRemoteSelect/index.tsx +4 -4
- package/src/framework/fields/FieldRemoteTree/index.tsx +1 -1
- package/src/framework/fields/FieldRemoteTreeCascader/index.tsx +1 -1
- package/src/framework/fields/FieldRemoteTreeSelect/index.tsx +1 -1
- package/src/framework/fields/FieldSysOrgTree/index.tsx +1 -1
- package/src/framework/fields/FieldSysOrgTreeSelect/index.tsx +1 -1
- package/src/framework/fields/FieldTable/index.tsx +15 -13
- package/src/framework/fields/FieldTableSelect/index.tsx +5 -5
- package/src/framework/fields/FieldUploadFile/index.tsx +3 -3
- package/src/framework/fields/FieldUploadImage/index.tsx +31 -29
- package/src/framework/fields/types.ts +0 -2
- package/src/framework/router/PageFrame.tsx +1 -1
- package/src/framework/router/matcher.ts +2 -2
- package/src/framework/utils/ArrayUtils.ts +2 -2
- package/src/framework/utils/DateUtils.ts +1 -1
- package/src/framework/utils/{system/DictUtils.ts → DictUtils.ts} +1 -1
- package/src/framework/utils/EventBus.ts +7 -7
- package/src/framework/utils/HttpClient.ts +283 -0
- package/src/framework/utils/{system/PageUtils.ts → PageUtils.ts} +4 -4
- package/src/framework/utils/{system/PermUtils.ts → PermUtils.ts} +3 -3
- package/src/framework/utils/StringUtils.ts +10 -8
- package/src/framework/utils/TreeUtils.ts +3 -3
- package/src/framework/utils/UrlUtils.ts +2 -2
- package/src/framework/utils/index.ts +4 -1
- package/src/framework/views/ViewApproveStatus/index.tsx +1 -2
- package/src/framework/views/ViewBoolean/index.tsx +4 -1
- package/src/framework/views/ViewFile/index.tsx +4 -4
- package/src/framework/views/ViewImage/index.tsx +2 -2
- package/src/framework/views/ViewPassword/index.tsx +3 -2
- package/src/framework/views/ViewText/index.tsx +12 -3
- package/src/framework/views/types.ts +2 -4
- package/src/layouts/admin/AdminTabs.jsx +9 -0
- package/src/layouts/admin/AdminTabs.less +2 -2
- package/src/layouts/admin/HeaderRight.jsx +8 -7
- package/src/layouts/admin/TabLayout.jsx +2 -2
- package/src/layouts/admin/index.jsx +15 -11
- package/src/layouts/admin/index.less +16 -1
- package/src/layouts/index.tsx +24 -18
- package/src/pages/404.jsx +1 -1
- package/src/pages/article/$code.jsx +4 -4
- package/src/pages/index.jsx +1 -1
- package/src/pages/public/login.jsx +34 -27
- package/src/pages/public/test.jsx +1 -1
- package/src/pages/standalone/forceUpdatePwd.jsx +9 -7
- package/src/pages/system/article/index.jsx +9 -8
- package/src/pages/system/dict/index.jsx +19 -16
- package/src/pages/system/file/index.jsx +9 -9
- package/src/pages/system/job/index.jsx +17 -17
- package/src/pages/system/log/index.jsx +5 -7
- package/src/pages/system/org/index.jsx +31 -18
- package/src/pages/system/role/index.jsx +13 -12
- package/src/pages/system/role/rolePerm.jsx +25 -21
- package/src/pages/system/user/index.jsx +35 -33
- package/src/pages/system/user/userPerm.jsx +12 -12
- package/src/pages/userCenter/index.jsx +11 -9
- package/src/pages/userCenter/permView.jsx +7 -7
- package/src/framework/utils/system/HttpUtils.ts +0 -97
- package/src/framework/utils/system/index.ts +0 -4
|
@@ -2,7 +2,7 @@ import React from 'react';
|
|
|
2
2
|
import {Layout, Menu, Skeleton, Watermark} from 'antd';
|
|
3
3
|
|
|
4
4
|
import "./index.less"
|
|
5
|
-
import {
|
|
5
|
+
import {HttpClient, NamedIcon, PageUtils, GlobalData, TreeUtils, history, Link, ARTICLE_HEADER_LEFT, OrgSwitcher} from "../../framework";
|
|
6
6
|
|
|
7
7
|
import { HeaderRight } from "./HeaderRight";
|
|
8
8
|
import { TabLayout } from "./TabLayout";
|
|
@@ -10,7 +10,7 @@ const {Header, Sider, Content} = Layout;
|
|
|
10
10
|
/**
|
|
11
11
|
* 带菜单的布局,主要处理布局宇框架结构
|
|
12
12
|
*/
|
|
13
|
-
export default class extends React.Component {
|
|
13
|
+
export default class AdminLayout extends React.Component {
|
|
14
14
|
|
|
15
15
|
state = {
|
|
16
16
|
loginInfo: {},
|
|
@@ -50,8 +50,8 @@ export default class extends React.Component {
|
|
|
50
50
|
|
|
51
51
|
initMenu = () => {
|
|
52
52
|
this.setState({menuLoading: true})
|
|
53
|
-
|
|
54
|
-
const {menuTree, pathMenuMap, menuMap} = info
|
|
53
|
+
HttpClient.get('/admin/menu-info', null, {toastError: false}).then(info => {
|
|
54
|
+
const {menuTree, pathMenuMap, menuMap} = info.data
|
|
55
55
|
this.setState({menuMap})
|
|
56
56
|
|
|
57
57
|
const pathname = PageUtils.currentPathname();
|
|
@@ -86,15 +86,15 @@ export default class extends React.Component {
|
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
this.setState({menuTree, pathMenuMap, topMenus, sideMenus, activeTopMenuKey, currentMenuKey})
|
|
89
|
+
this.setState({menuLoading: false})
|
|
89
90
|
|
|
90
91
|
}).catch(err => {
|
|
91
92
|
console.error('加载菜单失败:', err)
|
|
92
93
|
this.setState({menuTree: [], topMenus: [], sideMenus: []})
|
|
93
|
-
}).finally(()=>{
|
|
94
94
|
this.setState({menuLoading: false})
|
|
95
95
|
})
|
|
96
96
|
}
|
|
97
|
-
actionRef = React.createRef()
|
|
97
|
+
actionRef = React.createRef() // NOSONAR: React ref 由父组件通过 ref 访问
|
|
98
98
|
|
|
99
99
|
classifyMenus = (menuTree) => {
|
|
100
100
|
const topMenus = [];
|
|
@@ -166,13 +166,14 @@ export default class extends React.Component {
|
|
|
166
166
|
return (
|
|
167
167
|
<nav className="top-nav">
|
|
168
168
|
{topMenus.map(item => (
|
|
169
|
-
<
|
|
169
|
+
<button
|
|
170
170
|
key={item.key}
|
|
171
|
+
type="button"
|
|
171
172
|
className={'top-nav-item' + (item.key === activeTopMenuKey ? ' active' : '')}
|
|
172
173
|
onClick={() => this.onTopMenuClick({key: item.key})}
|
|
173
174
|
>
|
|
174
175
|
{item.label}
|
|
175
|
-
</
|
|
176
|
+
</button>
|
|
176
177
|
))}
|
|
177
178
|
</nav>
|
|
178
179
|
);
|
|
@@ -188,7 +189,10 @@ return <Layout className='main-layout'>
|
|
|
188
189
|
breakpoint={'md'}
|
|
189
190
|
>
|
|
190
191
|
<div className='sider-header'>
|
|
191
|
-
<
|
|
192
|
+
<button type="button" className='logo-img'
|
|
193
|
+
onClick={() => history.push('/')}>
|
|
194
|
+
<img src="./logo.png" alt='logo'/>
|
|
195
|
+
</button>
|
|
192
196
|
<h3 className='hide-on-mobile'>
|
|
193
197
|
<Link to="/" style={{color: 'rgba(255,255,255,0.85)'}}>{siteInfo.title}</Link>
|
|
194
198
|
</h3>
|
|
@@ -201,8 +205,8 @@ return <Layout className='main-layout'>
|
|
|
201
205
|
<Header className='header'>
|
|
202
206
|
{this.renderTopMenu()}
|
|
203
207
|
{this.state.headerLeftArticles.map(a => (
|
|
204
|
-
<
|
|
205
|
-
|
|
208
|
+
<button key={a.code} type="button" className='item'
|
|
209
|
+
onClick={() => PageUtils.open('/article/' + a.code, a.title)}>{a.title}</button>
|
|
206
210
|
))}
|
|
207
211
|
{this.props.showOrgSwitcher?.({
|
|
208
212
|
activeTopMenu: this.getActiveTopMenu(),
|
|
@@ -27,6 +27,9 @@
|
|
|
27
27
|
color: rgba(0, 0, 0, 0.65);
|
|
28
28
|
transition: color 0.2s;
|
|
29
29
|
white-space: nowrap;
|
|
30
|
+
background: none;
|
|
31
|
+
border: none;
|
|
32
|
+
font: inherit;
|
|
30
33
|
|
|
31
34
|
&:hover {
|
|
32
35
|
color: var(--primary-color, var(--primary-color, #1961AC));
|
|
@@ -50,10 +53,13 @@
|
|
|
50
53
|
align-items: center;
|
|
51
54
|
padding: 0 0.5rem;
|
|
52
55
|
cursor: pointer;
|
|
56
|
+
background: none;
|
|
57
|
+
border: none;
|
|
58
|
+
font: inherit;
|
|
53
59
|
|
|
54
60
|
&:hover {
|
|
55
61
|
background: var(--primary-color-hover, #4990CD);
|
|
56
|
-
color: white;
|
|
62
|
+
color: white; /* NOSONAR: 主题色悬停态,对比度由主题色决定 */
|
|
57
63
|
}
|
|
58
64
|
}
|
|
59
65
|
}
|
|
@@ -74,6 +80,15 @@
|
|
|
74
80
|
.logo-img {
|
|
75
81
|
height: 36px;
|
|
76
82
|
cursor: pointer;
|
|
83
|
+
background: none;
|
|
84
|
+
border: none;
|
|
85
|
+
padding: 0;
|
|
86
|
+
display: inline-flex;
|
|
87
|
+
align-items: center;
|
|
88
|
+
|
|
89
|
+
img {
|
|
90
|
+
height: 36px;
|
|
91
|
+
}
|
|
77
92
|
}
|
|
78
93
|
|
|
79
94
|
h3 {
|
package/src/layouts/index.tsx
CHANGED
|
@@ -3,12 +3,10 @@ import {ConfigProvider, Modal} from "antd";
|
|
|
3
3
|
import zhCN from 'antd/locale/zh_CN';
|
|
4
4
|
import dayjs from 'dayjs';
|
|
5
5
|
import 'dayjs/locale/zh-cn';
|
|
6
|
-
import {history,
|
|
6
|
+
import {ErrorBoundary, GlobalData, HttpClient, PageFrame, PageLoading, PageUtils, history, getThemeConfig, setThemeColors, EventBus} from "../framework";
|
|
7
|
+
import type {ThemeColors} from "../framework";
|
|
7
8
|
|
|
8
9
|
import AdminLayout from "./admin"
|
|
9
|
-
import {HttpUtils, PageLoading, PageUtils, GlobalData, getThemeConfig, setThemeColors, EventBus} from "../framework";
|
|
10
|
-
import {ErrorBoundary} from "../framework";
|
|
11
|
-
import type {ThemeColors} from "../framework";
|
|
12
10
|
|
|
13
11
|
import '../style/global.less'
|
|
14
12
|
import './index.less'
|
|
@@ -76,8 +74,8 @@ export class Layouts extends React.Component<LayoutsProps> {
|
|
|
76
74
|
}
|
|
77
75
|
|
|
78
76
|
loadSiteInfo() {
|
|
79
|
-
|
|
80
|
-
GlobalData.setSiteInfo(data);
|
|
77
|
+
HttpClient.get("/admin/public/site-info", null, {toastError: false}).then(data => {
|
|
78
|
+
GlobalData.setSiteInfo(data.data);
|
|
81
79
|
this.setState({siteInfoLoaded: true});
|
|
82
80
|
}).catch(() => {
|
|
83
81
|
console.error('[Layout] 加载站点信息失败');
|
|
@@ -85,12 +83,12 @@ export class Layouts extends React.Component<LayoutsProps> {
|
|
|
85
83
|
}
|
|
86
84
|
|
|
87
85
|
loadLoginInfo() {
|
|
88
|
-
|
|
89
|
-
GlobalData.setDictInfo(data.dictInfo);
|
|
90
|
-
GlobalData.setLoginInfo(data.loginInfo);
|
|
91
|
-
GlobalData.setSiteArticles(data.siteArticles);
|
|
86
|
+
HttpClient.get('/admin/public/login-info', null, {toastError: false}).then(data => {
|
|
87
|
+
GlobalData.setDictInfo(data.data.dictInfo);
|
|
88
|
+
GlobalData.setLoginInfo(data.data.loginInfo);
|
|
89
|
+
GlobalData.setSiteArticles(data.data.siteArticles);
|
|
92
90
|
|
|
93
|
-
if (data.needUpdatePwd) {
|
|
91
|
+
if (data.data.needUpdatePwd) {
|
|
94
92
|
this.setState({loginChecked: true});
|
|
95
93
|
history.push('/standalone/forceUpdatePwd');
|
|
96
94
|
return;
|
|
@@ -116,7 +114,7 @@ export class Layouts extends React.Component<LayoutsProps> {
|
|
|
116
114
|
this.loadData();
|
|
117
115
|
}
|
|
118
116
|
|
|
119
|
-
componentDidUpdate(prevProps:
|
|
117
|
+
componentDidUpdate(prevProps: LayoutsProps, prevState: typeof this.state) {
|
|
120
118
|
if (this.state.location !== prevState.location) {
|
|
121
119
|
this.loadData();
|
|
122
120
|
}
|
|
@@ -144,18 +142,26 @@ export class Layouts extends React.Component<LayoutsProps> {
|
|
|
144
142
|
return (
|
|
145
143
|
<ErrorBoundary minimal>
|
|
146
144
|
<ConfigProvider {...baseConfigProps} theme={getThemeConfig()}>
|
|
147
|
-
{showPageFrame
|
|
148
|
-
<PageLoading messages={[
|
|
149
|
-
!siteInfoLoaded && '加载站点信息...',
|
|
150
|
-
!loginChecked && '检查登录中...',
|
|
151
|
-
].filter(Boolean)}/>
|
|
152
|
-
)}
|
|
145
|
+
{this.renderContent(showPageFrame, ready, pathname, search)}
|
|
153
146
|
{this.renderLoginExpiredModal()}
|
|
154
147
|
</ConfigProvider>
|
|
155
148
|
</ErrorBoundary>
|
|
156
149
|
);
|
|
157
150
|
}
|
|
158
151
|
|
|
152
|
+
renderContent(showPageFrame: boolean, ready: boolean, pathname: string, search: string) {
|
|
153
|
+
if (showPageFrame) {
|
|
154
|
+
return <PageFrame url={pathname + search}/>;
|
|
155
|
+
}
|
|
156
|
+
if (ready) {
|
|
157
|
+
return <AdminLayout headerExtra={this.props.headerExtra} showOrgSwitcher={this.props.showOrgSwitcher} loginInfo={GlobalData.getLoginInfo()}/>;
|
|
158
|
+
}
|
|
159
|
+
return <PageLoading messages={[
|
|
160
|
+
!this.state.siteInfoLoaded && '加载站点信息...',
|
|
161
|
+
!this.state.loginChecked && '检查登录中...',
|
|
162
|
+
].filter(Boolean)}/>;
|
|
163
|
+
}
|
|
164
|
+
|
|
159
165
|
renderLoginExpiredModal() {
|
|
160
166
|
return (
|
|
161
167
|
<Modal open={this.state.loginExpiredVisible} title="确认操作" okText="确定"
|
package/src/pages/404.jsx
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import {
|
|
2
|
+
import {HttpClient, Page, UrlUtils} from "../../framework";
|
|
3
3
|
import "./article.less";
|
|
4
4
|
|
|
5
|
-
export default class extends React.Component {
|
|
5
|
+
export default class ArticlePage extends React.Component {
|
|
6
6
|
|
|
7
7
|
state = {
|
|
8
8
|
article: null,
|
|
@@ -12,8 +12,8 @@ export default class extends React.Component {
|
|
|
12
12
|
componentDidMount() {
|
|
13
13
|
const code = this.props.params?.code
|
|
14
14
|
if (code) {
|
|
15
|
-
|
|
16
|
-
this.setState({article: rs, loading: false})
|
|
15
|
+
HttpClient.get('admin/article/getByCode', {code}, {toastError: false}).then(rs => {
|
|
16
|
+
this.setState({article: rs.data, loading: false})
|
|
17
17
|
}).catch(() => {
|
|
18
18
|
this.setState({loading: false})
|
|
19
19
|
})
|
package/src/pages/index.jsx
CHANGED
|
@@ -2,7 +2,7 @@ import React from "react";
|
|
|
2
2
|
import {Card} from "antd";
|
|
3
3
|
import {Page} from "../framework";
|
|
4
4
|
|
|
5
|
-
export default class extends React.Component {
|
|
5
|
+
export default class HomePage extends React.Component {
|
|
6
6
|
render() {
|
|
7
7
|
return <Page title="首页" description="欢迎使用本系统">
|
|
8
8
|
<Card>欢迎使用本系统</Card>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import {Button, Form, Input, message} from 'antd';
|
|
3
3
|
import {LockOutlined, UserOutlined, WarningOutlined} from '@ant-design/icons';
|
|
4
|
-
import {EventBus,
|
|
4
|
+
import {EventBus, HttpClient, GlobalData, history} from "../../framework";
|
|
5
5
|
|
|
6
6
|
import "./login.less"
|
|
7
7
|
|
|
@@ -13,54 +13,61 @@ function getRedirect(query) {
|
|
|
13
13
|
return redirect;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
function postLogin(values, query) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
})
|
|
16
|
+
function postLogin(values, query, success, error) {
|
|
17
|
+
HttpClient.post('/admin/auth/login', values, null, {toastError: false}).then(rs => {
|
|
18
|
+
EventBus.emit('loginSuccess')
|
|
19
|
+
history.push(getRedirect(query))
|
|
20
|
+
success?.(rs)
|
|
21
|
+
}).catch(e => {
|
|
22
|
+
console.error('[Login] 登录失败:', e);
|
|
23
|
+
message.error(HttpClient.errToMsg(e))
|
|
24
|
+
error?.(e)
|
|
26
25
|
})
|
|
27
26
|
}
|
|
28
27
|
|
|
29
28
|
function encodePassword(pwd) {
|
|
30
29
|
const chars = [];
|
|
31
30
|
for (let i = 0; i < pwd.length; i++)
|
|
32
|
-
chars.push(pwd.
|
|
33
|
-
return btoa(String.
|
|
31
|
+
chars.push(pwd.codePointAt(i) + i + 2);
|
|
32
|
+
return btoa(String.fromCodePoint(...chars));
|
|
34
33
|
}
|
|
35
34
|
|
|
36
|
-
export default class extends React.Component {
|
|
35
|
+
export default class LoginPage extends React.Component {
|
|
37
36
|
|
|
38
37
|
state = {
|
|
39
38
|
logging: false,
|
|
40
39
|
siteInfo: {}
|
|
41
40
|
}
|
|
42
41
|
|
|
43
|
-
|
|
42
|
+
componentDidMount() {
|
|
44
43
|
const siteInfo = GlobalData.getSiteInfo()
|
|
45
|
-
if (siteInfo
|
|
44
|
+
if (siteInfo?.title) {
|
|
46
45
|
this.setState({siteInfo})
|
|
47
46
|
return
|
|
48
47
|
}
|
|
49
48
|
// localStorage 中无站点信息,从服务端重新加载
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
console.error('[Login] 加载站点信息失败:', e);
|
|
49
|
+
HttpClient.get('/admin/public/site-info', null, {toastError: false}).then(rs => {
|
|
50
|
+
GlobalData.setSiteInfo(rs.data)
|
|
51
|
+
this.setState({siteInfo: rs.data})
|
|
52
|
+
}).catch(() => {
|
|
53
|
+
console.error('[Login] 加载站点信息失败');
|
|
56
54
|
message.error('加载站点信息失败,请刷新页面重试')
|
|
57
|
-
}
|
|
55
|
+
})
|
|
58
56
|
}
|
|
59
57
|
|
|
60
58
|
submit = values => {
|
|
61
59
|
this.setState({logging: true})
|
|
62
|
-
|
|
63
|
-
|
|
60
|
+
try {
|
|
61
|
+
values.password = encodePassword(values.password)
|
|
62
|
+
} catch (e) {
|
|
63
|
+
console.error('[Login] 密码编码失败:', e);
|
|
64
|
+
this.setState({logging: false})
|
|
65
|
+
message.error('密码含不支持字符,请联系管理员重置')
|
|
66
|
+
return
|
|
67
|
+
}
|
|
68
|
+
postLogin(values, this.props.location?.query, () => {
|
|
69
|
+
this.setState({logging: false})
|
|
70
|
+
}, () => {
|
|
64
71
|
this.setState({logging: false})
|
|
65
72
|
})
|
|
66
73
|
}
|
|
@@ -76,14 +83,14 @@ export default class extends React.Component {
|
|
|
76
83
|
<section className='login-page' style={pageStyle}>
|
|
77
84
|
<div className="login-content">
|
|
78
85
|
<h1>{siteInfo.title}</h1>
|
|
79
|
-
{this.getForm(
|
|
86
|
+
{this.getForm()}
|
|
80
87
|
{this.renderFormBottom()}
|
|
81
88
|
</div>
|
|
82
89
|
</section>
|
|
83
90
|
);
|
|
84
91
|
}
|
|
85
92
|
|
|
86
|
-
getForm =
|
|
93
|
+
getForm = () => {
|
|
87
94
|
const form = (
|
|
88
95
|
<Form
|
|
89
96
|
name="normal_login"
|
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import {Button, Form, Input, message} from "antd";
|
|
3
|
-
import {
|
|
3
|
+
import {HttpClient, history} from "../../framework";
|
|
4
4
|
|
|
5
|
-
export default class extends React.Component {
|
|
5
|
+
export default class ForceUpdatePwdPage extends React.Component {
|
|
6
6
|
|
|
7
7
|
onFinish = (values) => {
|
|
8
|
-
|
|
8
|
+
HttpClient.post('admin/userCenter/update-pwd', values, null).then(() => {
|
|
9
9
|
message.success('修改密码成功,请重新登录');
|
|
10
10
|
history.push('/public/login');
|
|
11
11
|
})
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
validator = (rule, value) => {
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
validator = (rule, value) => HttpClient.get("admin/sysUser/pwd-strength", {password: value}, {toastError: false})
|
|
15
|
+
.catch(e => {
|
|
16
|
+
throw new Error(e.message)
|
|
17
|
+
})
|
|
17
18
|
|
|
18
19
|
render() {
|
|
19
20
|
return (
|
|
@@ -42,10 +43,11 @@ export default class extends React.Component {
|
|
|
42
43
|
extra={'请输入字母、数字、特殊字符'}
|
|
43
44
|
rules={[
|
|
44
45
|
{required: true, message: '请输入新密码'},
|
|
46
|
+
{pattern: /^[\x20-\x7E]{1,64}$/, message: '密码仅支持英文、数字与常见符号,长度不超过64位'},
|
|
45
47
|
{validator: this.validator}
|
|
46
48
|
]}
|
|
47
49
|
>
|
|
48
|
-
<Input.Password/>
|
|
50
|
+
<Input.Password maxLength={64}/>
|
|
49
51
|
</Form.Item>
|
|
50
52
|
<Form.Item style={{marginTop: 40}}>
|
|
51
53
|
<Button type="primary" htmlType="submit" block size='large'>
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
FieldEditor,
|
|
9
9
|
FieldUploadImage,
|
|
10
10
|
FormModal,
|
|
11
|
-
|
|
11
|
+
HttpClient,
|
|
12
12
|
Page,
|
|
13
13
|
PageUtils,
|
|
14
14
|
PermActions,
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
ViewImage
|
|
17
17
|
} from "../../../framework";
|
|
18
18
|
|
|
19
|
-
export default class extends React.Component {
|
|
19
|
+
export default class ArticleListPage extends React.Component {
|
|
20
20
|
|
|
21
21
|
state = {
|
|
22
22
|
editing: false,
|
|
@@ -42,12 +42,12 @@ export default class extends React.Component {
|
|
|
42
42
|
onFinish = async values => {
|
|
43
43
|
const isNew = !values.id;
|
|
44
44
|
const url = isNew ? 'admin/article/create' : 'admin/article/update';
|
|
45
|
-
await
|
|
45
|
+
await HttpClient.post(url, values)
|
|
46
46
|
this.tableRef.current.reload()
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
handleDelete = record => {
|
|
50
|
-
|
|
50
|
+
HttpClient.post('admin/article/delete', {id: record.id}, null).then(() => {
|
|
51
51
|
this.tableRef.current.reload()
|
|
52
52
|
})
|
|
53
53
|
}
|
|
@@ -84,7 +84,8 @@ export default class extends React.Component {
|
|
|
84
84
|
title: '启用',
|
|
85
85
|
dataIndex: 'enabled',
|
|
86
86
|
render(v) {
|
|
87
|
-
|
|
87
|
+
if (v == null) return null;
|
|
88
|
+
return v ? '是' : '否';
|
|
88
89
|
},
|
|
89
90
|
},
|
|
90
91
|
{
|
|
@@ -111,14 +112,14 @@ export default class extends React.Component {
|
|
|
111
112
|
>
|
|
112
113
|
<ProTable
|
|
113
114
|
actionRef={this.tableRef}
|
|
114
|
-
toolBarRender={() => (
|
|
115
|
+
toolBarRender={() => ( // NOSONAR: AntD 渲染函数惯例
|
|
115
116
|
<PermActions>
|
|
116
117
|
<Button perm='article:create' type='primary' icon={<PlusOutlined/>} onClick={this.handleAdd}>新增</Button>
|
|
117
118
|
</PermActions>
|
|
118
119
|
)}
|
|
119
|
-
request={(params) =>
|
|
120
|
+
request={(params) => HttpClient.get('admin/article/page', params)}
|
|
120
121
|
columns={this.columns}
|
|
121
|
-
searchFormRender={() => (
|
|
122
|
+
searchFormRender={() => ( // NOSONAR: AntD 渲染函数惯例
|
|
122
123
|
<>
|
|
123
124
|
<Form.Item label='编码' name='code'>
|
|
124
125
|
<Input/>
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
PermActions,
|
|
6
6
|
FieldBoolean,
|
|
7
7
|
FormModal,
|
|
8
|
-
|
|
8
|
+
HttpClient,
|
|
9
9
|
Page,
|
|
10
10
|
ProTable,
|
|
11
11
|
ViewSwitch,
|
|
@@ -23,7 +23,7 @@ const COLOR_OPTIONS = [
|
|
|
23
23
|
{value: 'GRAY', label: '灰色'},
|
|
24
24
|
]
|
|
25
25
|
|
|
26
|
-
export default class extends React.Component {
|
|
26
|
+
export default class DictPage extends React.Component {
|
|
27
27
|
|
|
28
28
|
state = {
|
|
29
29
|
typeTree: [],
|
|
@@ -42,9 +42,10 @@ export default class extends React.Component {
|
|
|
42
42
|
|
|
43
43
|
loadTree = () => {
|
|
44
44
|
this.setState({treeLoading: true})
|
|
45
|
-
|
|
46
|
-
this.setState({typeTree: rs})
|
|
47
|
-
|
|
45
|
+
HttpClient.get('admin/dict/type-tree', null, {toastError: false}).then(rs => {
|
|
46
|
+
this.setState({typeTree: rs.data})
|
|
47
|
+
this.setState({treeLoading: false})
|
|
48
|
+
}).catch(() => {
|
|
48
49
|
this.setState({treeLoading: false})
|
|
49
50
|
})
|
|
50
51
|
}
|
|
@@ -62,7 +63,7 @@ export default class extends React.Component {
|
|
|
62
63
|
handleTypeDelete = () => {
|
|
63
64
|
const {selectedType} = this.state
|
|
64
65
|
if (!selectedType) return
|
|
65
|
-
|
|
66
|
+
HttpClient.post('admin/dict/type-delete', {id: selectedType.id}, null).then(() => {
|
|
66
67
|
this.setState({selectedType: null, selectedTypeCode: null})
|
|
67
68
|
this.loadTree()
|
|
68
69
|
})
|
|
@@ -71,7 +72,7 @@ export default class extends React.Component {
|
|
|
71
72
|
handleTypeFormFinish = async values => {
|
|
72
73
|
const isNew = !values.id
|
|
73
74
|
const url = isNew ? 'admin/dict/type-create' : 'admin/dict/type-update'
|
|
74
|
-
await
|
|
75
|
+
await HttpClient.post(url, values)
|
|
75
76
|
this.loadTree()
|
|
76
77
|
}
|
|
77
78
|
|
|
@@ -98,11 +99,13 @@ export default class extends React.Component {
|
|
|
98
99
|
this.setState({selectedType: null, selectedTypeCode: null})
|
|
99
100
|
return
|
|
100
101
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
102
|
+
this.setState((prevState) => {
|
|
103
|
+
const node = this.findNode(prevState.typeTree, selectedKeys[0])
|
|
104
|
+
return {
|
|
105
|
+
selectedType: node,
|
|
106
|
+
selectedTypeCode: node?.typeCode || null
|
|
107
|
+
}
|
|
108
|
+
}, () => this.tableRef.current.reload())
|
|
106
109
|
}
|
|
107
110
|
|
|
108
111
|
handleItemAdd = () => {
|
|
@@ -114,7 +117,7 @@ export default class extends React.Component {
|
|
|
114
117
|
}
|
|
115
118
|
|
|
116
119
|
handleItemDelete = row => {
|
|
117
|
-
|
|
120
|
+
HttpClient.post('admin/dict/delete', row, null).then(() => {
|
|
118
121
|
this.tableRef.current.reload()
|
|
119
122
|
})
|
|
120
123
|
}
|
|
@@ -122,7 +125,7 @@ export default class extends React.Component {
|
|
|
122
125
|
onItemFormFinish = async values => {
|
|
123
126
|
const isNew = !values.id
|
|
124
127
|
const url = isNew ? 'admin/dict/create' : 'admin/dict/update'
|
|
125
|
-
await
|
|
128
|
+
await HttpClient.post(url, values)
|
|
126
129
|
this.tableRef.current.reload()
|
|
127
130
|
}
|
|
128
131
|
|
|
@@ -220,7 +223,7 @@ export default class extends React.Component {
|
|
|
220
223
|
actionRef={this.tableRef}
|
|
221
224
|
request={(params) => {
|
|
222
225
|
params.typeCode = selectedTypeCode
|
|
223
|
-
return
|
|
226
|
+
return HttpClient.get('admin/dict/page', params)
|
|
224
227
|
}}
|
|
225
228
|
columns={this.columns}
|
|
226
229
|
/>
|
|
@@ -266,7 +269,7 @@ export default class extends React.Component {
|
|
|
266
269
|
allowClear
|
|
267
270
|
maxLength={20}
|
|
268
271
|
options={COLOR_OPTIONS}
|
|
269
|
-
filterOption={(input, option) =>
|
|
272
|
+
filterOption={(input, option) => // NOSONAR: AntD AutoComplete 过滤回调惯例
|
|
270
273
|
(option.value + option.label).toLowerCase().includes(input.toLowerCase())
|
|
271
274
|
}
|
|
272
275
|
placeholder='如 SUCCESS、#ff0000'
|
|
@@ -2,9 +2,9 @@ import React from 'react'
|
|
|
2
2
|
import {Button, Form, Input, Modal, Space} from 'antd'
|
|
3
3
|
import {CloudUploadOutlined} from "@ant-design/icons";
|
|
4
4
|
|
|
5
|
-
import {PermActions, DictUtils, FieldDateRange, FieldDictSelect, FieldUploadFile,
|
|
5
|
+
import {PermActions, DictUtils, FieldDateRange, FieldDictSelect, FieldUploadFile, HttpClient, Page, ProTable, UrlUtils, ViewImage} from "../../../framework";
|
|
6
6
|
|
|
7
|
-
export default class extends React.Component {
|
|
7
|
+
export default class FilePage extends React.Component {
|
|
8
8
|
|
|
9
9
|
state = {
|
|
10
10
|
formOpen: false,
|
|
@@ -15,13 +15,13 @@ export default class extends React.Component {
|
|
|
15
15
|
formRef = React.createRef()
|
|
16
16
|
|
|
17
17
|
handleDelete = row => {
|
|
18
|
-
|
|
18
|
+
HttpClient.post('admin/sysFile/delete', {value: row.objectName}, null).then(() => {
|
|
19
19
|
this.tableRef.current.reload()
|
|
20
20
|
})
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
handleBatchDelete = ids => {
|
|
24
|
-
|
|
24
|
+
HttpClient.post('admin/sysFile/deleteBatch', ids, null).then(() => {
|
|
25
25
|
this.tableRef.current.reload()
|
|
26
26
|
this.tableRef.current.clearSelection()
|
|
27
27
|
})
|
|
@@ -32,7 +32,7 @@ export default class extends React.Component {
|
|
|
32
32
|
title: '缩略图',
|
|
33
33
|
dataIndex: 'objectName',
|
|
34
34
|
width: 80,
|
|
35
|
-
render: (objectName, record) => {
|
|
35
|
+
render: (objectName, record) => { // NOSONAR: 返回元素或占位文本,类型不同属预期
|
|
36
36
|
if (record.type !== 'image') {
|
|
37
37
|
return '-'
|
|
38
38
|
}
|
|
@@ -151,12 +151,12 @@ export default class extends React.Component {
|
|
|
151
151
|
<ProTable
|
|
152
152
|
actionRef={this.tableRef}
|
|
153
153
|
rowSelection={{}}
|
|
154
|
-
toolBarRender={(params, selection) => (
|
|
154
|
+
toolBarRender={(params, selection) => ( // NOSONAR: AntD 渲染函数惯例
|
|
155
155
|
<Space>
|
|
156
156
|
<Button type='primary' icon={<CloudUploadOutlined/>} onClick={() => this.setState({formOpen: true})}>上传文件</Button>
|
|
157
157
|
<PermActions
|
|
158
158
|
actions={[{
|
|
159
|
-
label:
|
|
159
|
+
label: '批量删除' + (selection.selectedRowKeys.length ? `(${selection.selectedRowKeys.length})` : ''),
|
|
160
160
|
perm: 'sys-file:delete',
|
|
161
161
|
danger: true,
|
|
162
162
|
disabled: !selection.selectedRowKeys.length,
|
|
@@ -167,11 +167,11 @@ export default class extends React.Component {
|
|
|
167
167
|
</Space>
|
|
168
168
|
)}
|
|
169
169
|
request={(params) => {
|
|
170
|
-
return
|
|
170
|
+
return HttpClient.get('admin/sysFile/page', params);
|
|
171
171
|
}}
|
|
172
172
|
|
|
173
173
|
columns={this.columns}
|
|
174
|
-
searchFormRender={() => (
|
|
174
|
+
searchFormRender={() => ( // NOSONAR: AntD 渲染函数惯例
|
|
175
175
|
<>
|
|
176
176
|
<Form.Item label='文件名' name='originName'>
|
|
177
177
|
<Input/>
|