@jiangood/open-admin 2.5.7 → 2.5.9

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 CHANGED
@@ -36,5 +36,5 @@
36
36
  "dev": "umi dev",
37
37
  "build": "umi build"
38
38
  },
39
- "version": "2.5.7"
39
+ "version": "2.5.9"
40
40
  }
@@ -38,7 +38,7 @@
38
38
  "dev": "umi dev",
39
39
  "build": "umi build"
40
40
  },
41
- "version": "2.5.7"
41
+ "version": "2.5.9"
42
42
  },
43
43
  "pkgPath": "/home/runner/work/open-admin/open-admin/web/package.json",
44
44
  "plugins": {
@@ -98,7 +98,7 @@
98
98
  1
99
99
  ]
100
100
  },
101
- "register": 1
101
+ "register": 2
102
102
  },
103
103
  "enableBy": "register"
104
104
  },
@@ -115,7 +115,7 @@
115
115
  0
116
116
  ]
117
117
  },
118
- "register": 1
118
+ "register": 0
119
119
  },
120
120
  "enableBy": "register"
121
121
  },
@@ -142,7 +142,7 @@
142
142
  "time": {
143
143
  "hooks": {
144
144
  "modifyAppData": [
145
- 69
145
+ 79
146
146
  ]
147
147
  },
148
148
  "register": 21
@@ -158,7 +158,7 @@
158
158
  "config": {},
159
159
  "time": {
160
160
  "hooks": {},
161
- "register": 1
161
+ "register": 0
162
162
  },
163
163
  "enableBy": "register"
164
164
  },
@@ -195,7 +195,7 @@
195
195
  0
196
196
  ]
197
197
  },
198
- "register": 0
198
+ "register": 1
199
199
  },
200
200
  "enableBy": "register"
201
201
  },
@@ -208,7 +208,7 @@
208
208
  "config": {},
209
209
  "time": {
210
210
  "hooks": {},
211
- "register": 1
211
+ "register": 0
212
212
  },
213
213
  "enableBy": "config"
214
214
  },
@@ -225,7 +225,7 @@
225
225
  0
226
226
  ]
227
227
  },
228
- "register": 6
228
+ "register": 5
229
229
  },
230
230
  "enableBy": "register"
231
231
  },
@@ -1077,7 +1077,7 @@
1077
1077
  "config": {},
1078
1078
  "time": {
1079
1079
  "hooks": {},
1080
- "register": 1
1080
+ "register": 0
1081
1081
  },
1082
1082
  "enableBy": "config"
1083
1083
  },
@@ -1107,7 +1107,7 @@
1107
1107
  "config": {},
1108
1108
  "time": {
1109
1109
  "hooks": {},
1110
- "register": 0
1110
+ "register": 1
1111
1111
  },
1112
1112
  "enableBy": "register"
1113
1113
  },
@@ -1163,7 +1163,7 @@
1163
1163
  1
1164
1164
  ]
1165
1165
  },
1166
- "register": 0
1166
+ "register": 1
1167
1167
  },
1168
1168
  "enableBy": "register"
1169
1169
  },
@@ -1176,7 +1176,7 @@
1176
1176
  "config": {},
1177
1177
  "time": {
1178
1178
  "hooks": {},
1179
- "register": 1
1179
+ "register": 0
1180
1180
  },
1181
1181
  "enableBy": "register"
1182
1182
  },
@@ -1189,7 +1189,7 @@
1189
1189
  "config": {},
1190
1190
  "time": {
1191
1191
  "hooks": {},
1192
- "register": 1
1192
+ "register": 2
1193
1193
  },
1194
1194
  "enableBy": "config"
1195
1195
  },
@@ -1214,7 +1214,7 @@
1214
1214
  "config": {},
1215
1215
  "time": {
1216
1216
  "hooks": {},
1217
- "register": 0
1217
+ "register": 1
1218
1218
  },
1219
1219
  "enableBy": "config"
1220
1220
  },
@@ -1227,7 +1227,7 @@
1227
1227
  "config": {},
1228
1228
  "time": {
1229
1229
  "hooks": {},
1230
- "register": 1
1230
+ "register": 0
1231
1231
  }
1232
1232
  },
1233
1233
  "./node_modules/@umijs/preset-umi/dist/features/overrides/overrides": {
@@ -1266,7 +1266,7 @@
1266
1266
  "time": {
1267
1267
  "hooks": {
1268
1268
  "modifyConfig": [
1269
- 1
1269
+ 0
1270
1270
  ]
1271
1271
  },
1272
1272
  "register": 1
@@ -1423,7 +1423,7 @@
1423
1423
  "config": {},
1424
1424
  "time": {
1425
1425
  "hooks": {},
1426
- "register": 2
1426
+ "register": 3
1427
1427
  },
1428
1428
  "enableBy": "config"
1429
1429
  },
@@ -1436,7 +1436,7 @@
1436
1436
  "config": {},
1437
1437
  "time": {
1438
1438
  "hooks": {},
1439
- "register": 1
1439
+ "register": 0
1440
1440
  },
1441
1441
  "enableBy": "config"
1442
1442
  },
@@ -1449,7 +1449,7 @@
1449
1449
  "config": {},
1450
1450
  "time": {
1451
1451
  "hooks": {},
1452
- "register": 3
1452
+ "register": 4
1453
1453
  }
1454
1454
  },
1455
1455
  "./node_modules/@umijs/preset-umi/dist/features/monorepo/redirect": {
@@ -1461,7 +1461,7 @@
1461
1461
  "config": {},
1462
1462
  "time": {
1463
1463
  "hooks": {},
1464
- "register": 22
1464
+ "register": 20
1465
1465
  },
1466
1466
  "enableBy": "config"
1467
1467
  },
@@ -1653,7 +1653,7 @@
1653
1653
  "config": {},
1654
1654
  "time": {
1655
1655
  "hooks": {},
1656
- "register": 43
1656
+ "register": 46
1657
1657
  },
1658
1658
  "enableBy": "register"
1659
1659
  },
@@ -1666,7 +1666,7 @@
1666
1666
  "config": {},
1667
1667
  "time": {
1668
1668
  "hooks": {},
1669
- "register": 18
1669
+ "register": 17
1670
1670
  }
1671
1671
  },
1672
1672
  "./node_modules/@umijs/preset-umi/dist/commands/help": {
@@ -1678,7 +1678,7 @@
1678
1678
  "config": {},
1679
1679
  "time": {
1680
1680
  "hooks": {},
1681
- "register": 0
1681
+ "register": 1
1682
1682
  },
1683
1683
  "enableBy": "register"
1684
1684
  },
@@ -1691,7 +1691,7 @@
1691
1691
  "config": {},
1692
1692
  "time": {
1693
1693
  "hooks": {},
1694
- "register": 1
1694
+ "register": 0
1695
1695
  },
1696
1696
  "enableBy": "register"
1697
1697
  },
@@ -1769,7 +1769,7 @@
1769
1769
  "config": {},
1770
1770
  "time": {
1771
1771
  "hooks": {},
1772
- "register": 0
1772
+ "register": 1
1773
1773
  },
1774
1774
  "enableBy": "register"
1775
1775
  },
@@ -1782,7 +1782,7 @@
1782
1782
  "config": {},
1783
1783
  "time": {
1784
1784
  "hooks": {},
1785
- "register": 1
1785
+ "register": 0
1786
1786
  },
1787
1787
  "enableBy": "register"
1788
1788
  },
@@ -1912,7 +1912,7 @@
1912
1912
  "config": {},
1913
1913
  "time": {
1914
1914
  "hooks": {},
1915
- "register": 23
1915
+ "register": 22
1916
1916
  },
1917
1917
  "enableBy": "register"
1918
1918
  },
@@ -1951,7 +1951,7 @@
1951
1951
  "config": {},
1952
1952
  "time": {
1953
1953
  "hooks": {},
1954
- "register": 1
1954
+ "register": 0
1955
1955
  },
1956
1956
  "enableBy": "register"
1957
1957
  },
@@ -2049,6 +2049,16 @@
2049
2049
  "__isJSFile": true,
2050
2050
  "__absFile": "/home/runner/work/open-admin/open-admin/web/src/pages/account/changePassword.jsx"
2051
2051
  },
2052
+ "system/article/index": {
2053
+ "path": "system/article",
2054
+ "id": "system/article/index",
2055
+ "parentId": "@@/global-layout",
2056
+ "file": "system/article/index.jsx",
2057
+ "absPath": "/system/article",
2058
+ "__content": "import {PlusOutlined} from '@ant-design/icons'\nimport {Button, Form, Input, InputNumber, Modal, Popconfirm} from 'antd'\nimport React from 'react'\nimport {\n DictUtils,\n FieldBoolean,\n FieldDictSelect,\n FieldEditor,\n HttpUtils,\n Page,\n PermActions,\n ProTable\n} from \"../../../framework\";\n\nconst {TextArea} = Input;\n\nexport default class extends React.Component {\n\n state = {\n formValues: {},\n formOpen: false,\n }\n\n formRef = React.createRef()\n tableRef = React.createRef()\n\n handleAdd = () => {\n this.setState({formOpen: true, formValues: {}})\n }\n\n handleEdit = record => {\n this.setState({formOpen: true, formValues: record})\n }\n\n onFinish = values => {\n const isNew = !values.id;\n const url = isNew ? 'admin/article/create' : 'admin/article/update';\n HttpUtils.post(url, values).then(rs => {\n this.setState({formOpen: false})\n this.tableRef.current.reload()\n })\n }\n\n handleDelete = record => {\n HttpUtils.post('admin/article/delete', {id: record.id}).then(rs => {\n this.tableRef.current.reload()\n })\n }\n\n columns = [\n {\n title: '编码',\n dataIndex: 'code',\n },\n {\n title: '标题',\n dataIndex: 'title',\n },\n {\n title: '显示位置',\n dataIndex: 'position',\n render(v) {\n return DictUtils.dictLabel('articlePosition', v) || v\n },\n },\n {\n title: '排序',\n dataIndex: 'seq',\n },\n {\n title: '启用',\n dataIndex: 'enabled',\n render(v) {\n return v == null ? null : (v ? '是' : '否')\n },\n },\n {\n title: '操作',\n dataIndex: 'option',\n render: (_, record) => {\n return (\n <PermActions>\n <Button size='small' perm='article:update' onClick={() => this.handleEdit(record)}>编辑</Button>\n <Popconfirm perm='article:delete' title='确定删除?' onConfirm={() => this.handleDelete(record)}>\n <Button size='small'>删除</Button>\n </Popconfirm>\n </PermActions>\n );\n },\n },\n ]\n\n render() {\n return <Page\n title=\"文章管理\"\n description=\"管理系统文章,如关于、帮助等页面\"\n actions={<Button perm='article:create' type='primary' icon={<PlusOutlined/>} onClick={this.handleAdd}>新增</Button>}\n >\n <ProTable\n actionRef={this.tableRef}\n request={(params) => HttpUtils.get('admin/article/page', params)}\n columns={this.columns}\n >\n <Form.Item label='编码' name='code'>\n <Input/>\n </Form.Item>\n <Form.Item label='标题' name='title'>\n <Input/>\n </Form.Item>\n </ProTable>\n\n <Modal title='文章'\n open={this.state.formOpen}\n onOk={() => this.formRef.current.submit()}\n onCancel={() => this.setState({formOpen: false})}\n destroyOnHidden\n width={800}\n >\n <Form ref={this.formRef} labelCol={{flex: '100px'}}\n initialValues={this.state.formValues}\n onFinish={this.onFinish}\n >\n <Form.Item name='id' noStyle></Form.Item>\n\n <Form.Item label='编码' name='code' rules={[{required: true}]}>\n <Input disabled={!!this.state.formValues.id}/>\n </Form.Item>\n\n <Form.Item label='标题' name='title' rules={[{required: true}]}>\n <Input/>\n </Form.Item>\n\n <Form.Item label='内容' name='content'>\n <FieldEditor />\n </Form.Item>\n\n <Form.Item label='显示位置' name='position' rules={[{required: true}]}>\n <FieldDictSelect typeCode='articlePosition'/>\n </Form.Item>\n\n <Form.Item label='排序' name='seq'>\n <InputNumber/>\n </Form.Item>\n\n <Form.Item label='启用' name='enabled'>\n <FieldBoolean/>\n </Form.Item>\n </Form>\n </Modal>\n </Page>\n }\n}\n",
2059
+ "__isJSFile": true,
2060
+ "__absFile": "/home/runner/work/open-admin/open-admin/web/src/pages/system/article/index.jsx"
2061
+ },
2052
2062
  "system/role/rolePerm": {
2053
2063
  "path": "system/role/rolePerm",
2054
2064
  "id": "system/role/rolePerm",
@@ -2145,7 +2155,7 @@
2145
2155
  "parentId": "@@/global-layout",
2146
2156
  "file": "forceUpdatePwd.jsx",
2147
2157
  "absPath": "/forceUpdatePwd",
2148
- "__content": "import React from \"react\";\nimport {Button, Form, Input, message} from \"antd\";\nimport {history} from 'umi'\nimport {HttpUtils, PageUtils, GlobalData} from \"../framework\";\n\nexport default class extends React.Component {\n\n state = {\n checking: true\n }\n\n async componentDidMount() {\n try {\n const rs = await HttpUtils.get('/admin/public/user-info', null, {showError: false});\n if (!rs.login) {\n PageUtils.redirectToLogin();\n return;\n }\n GlobalData.setLoginInfo(rs.loginInfo);\n this.setState({checking: false});\n } catch (e) {\n PageUtils.redirectToLogin();\n }\n }\n\n onFinish = (values) => {\n HttpUtils.post('admin/userCenter/update-pwd', values).then(() => {\n message.success('修改密码成功,请重新登录');\n history.push('/login');\n })\n }\n\n validator = (rule, value) => {\n return new Promise((resolve, reject) => {\n HttpUtils.get(\"admin/sysUser/pwd-strength\", {password: value}).then(response => {\n const rs = response.data\n if (!rs.success) {\n reject(rs.message)\n }\n resolve()\n })\n })\n }\n\n render() {\n if (this.state.checking) return null;\n\n return (\n <div style={{\n display: 'flex',\n justifyContent: 'center',\n alignItems: 'center',\n minHeight: '100vh',\n background: '#f0f2f5'\n }}>\n <div style={{\n background: '#fff',\n padding: '40px',\n borderRadius: '8px',\n boxShadow: '0 2px 8px rgba(0,0,0,0.1)',\n maxWidth: 400,\n width: '100%'\n }}>\n <h2 style={{textAlign: 'center', marginBottom: 24}}>修改密码</h2>\n <p style={{textAlign: 'center', color: '#999', marginBottom: 24}}>\n 首次登录或密码已被重置,请修改密码后重新登录\n </p>\n <Form onFinish={this.onFinish}>\n <Form.Item name='newPassword'\n label='新密码'\n extra={'请输入字母、数字、特殊字符'}\n rules={[\n {required: true, message: '请输入新密码'},\n {validator: this.validator}\n ]}\n >\n <Input.Password/>\n </Form.Item>\n <Form.Item style={{marginTop: 40}}>\n <Button type=\"primary\" htmlType=\"submit\" block size='large'>\n 确定\n </Button>\n </Form.Item>\n </Form>\n </div>\n </div>\n )\n }\n}\n",
2158
+ "__content": "import React from \"react\";\nimport {Button, Form, Input, message} from \"antd\";\nimport {history} from 'umi'\nimport {HttpUtils, PageUtils, GlobalData} from \"../framework\";\n\nexport default class extends React.Component {\n\n state = {\n checking: true\n }\n\n async componentDidMount() {\n try {\n const rs = await HttpUtils.get('/admin/public/user-info', null, {showError: false});\n if (!rs.login) {\n PageUtils.redirectToLogin();\n return;\n }\n GlobalData.setLoginInfo(rs.loginInfo);\n this.setState({checking: false});\n } catch (e) {\n PageUtils.redirectToLogin();\n }\n }\n\n onFinish = (values) => {\n HttpUtils.post('admin/userCenter/update-pwd', values).then(() => {\n message.success('修改密码成功,请重新登录');\n history.push('/login');\n })\n }\n\n validator = (rule, value) => {\n return HttpUtils.get(\"admin/sysUser/pwd-strength\", {password: value})\n }\n\n render() {\n if (this.state.checking) return null;\n\n return (\n <div style={{\n display: 'flex',\n justifyContent: 'center',\n alignItems: 'center',\n minHeight: '100vh',\n background: '#f0f2f5'\n }}>\n <div style={{\n background: '#fff',\n padding: '40px',\n borderRadius: '8px',\n boxShadow: '0 2px 8px rgba(0,0,0,0.1)',\n maxWidth: 400,\n width: '100%'\n }}>\n <h2 style={{textAlign: 'center', marginBottom: 24}}>修改密码</h2>\n <p style={{textAlign: 'center', color: '#999', marginBottom: 24}}>\n 首次登录或密码已被重置,请修改密码后重新登录\n </p>\n <Form onFinish={this.onFinish}>\n <Form.Item name='newPassword'\n label='新密码'\n extra={'请输入字母、数字、特殊字符'}\n rules={[\n {required: true, message: '请输入新密码'},\n {validator: this.validator}\n ]}\n >\n <Input.Password/>\n </Form.Item>\n <Form.Item style={{marginTop: 40}}>\n <Button type=\"primary\" htmlType=\"submit\" block size='large'>\n 确定\n </Button>\n </Form.Item>\n </Form>\n </div>\n </div>\n )\n }\n}\n",
2149
2159
  "__isJSFile": true,
2150
2160
  "__absFile": "/home/runner/work/open-admin/open-admin/web/src/pages/forceUpdatePwd.jsx"
2151
2161
  },
@@ -2159,13 +2169,23 @@
2159
2169
  "__isJSFile": true,
2160
2170
  "__absFile": "/home/runner/work/open-admin/open-admin/web/src/pages/account/index.jsx"
2161
2171
  },
2172
+ "article/$code": {
2173
+ "path": "article/:code",
2174
+ "id": "article/$code",
2175
+ "parentId": "@@/global-layout",
2176
+ "file": "article/$code.jsx",
2177
+ "absPath": "/article/:code",
2178
+ "__content": "import React from \"react\";\nimport {HttpUtils, Page, PageUtils} from \"../../framework\";\n\nexport default class extends React.Component {\n\n state = {\n article: null,\n loading: true,\n }\n\n componentDidMount() {\n const code = PageUtils.currentPathnameLastPart()\n if (code) {\n HttpUtils.get('admin/article/getByCode', {code}).then(rs => {\n this.setState({article: rs, loading: false})\n }).catch(() => {\n this.setState({loading: false})\n })\n } else {\n this.setState({loading: false})\n }\n }\n\n render() {\n const {article, loading} = this.state\n\n if (loading) {\n return <Page title=\"加载中...\">\n <div>加载中...</div>\n </Page>\n }\n\n if (!article) {\n return <Page title=\"文章不存在\">\n <div>文章不存在或已禁用</div>\n </Page>\n }\n\n return <Page title={article.title}>\n <div dangerouslySetInnerHTML={{__html: article.content}}/>\n </Page>\n }\n}\n",
2179
+ "__isJSFile": true,
2180
+ "__absFile": "/home/runner/work/open-admin/open-admin/web/src/pages/article/$code.jsx"
2181
+ },
2162
2182
  "about": {
2163
2183
  "path": "about",
2164
2184
  "id": "about",
2165
2185
  "parentId": "@@/global-layout",
2166
2186
  "file": "about.jsx",
2167
2187
  "absPath": "/about",
2168
- "__content": "import React from \"react\";\nimport {Page} from \"../framework\";\n\nexport default class extends React.Component {\n\n render() {\n return <Page title=\"关于\" description=\"了解系统版本与相关信息\">\n <h1>关于</h1>\n </Page>\n }\n}\n",
2188
+ "__content": "import React from \"react\";\nimport {history} from \"umi\";\nimport {Page} from \"../framework\";\n\nexport default class extends React.Component {\n\n componentDidMount() {\n history.push('/article/about')\n }\n\n render() {\n return <Page title=\"关于系统\">\n <div>跳转中...</div>\n </Page>\n }\n}\n",
2169
2189
  "__isJSFile": true,
2170
2190
  "__absFile": "/home/runner/work/open-admin/open-admin/web/src/pages/about.jsx"
2171
2191
  },
@@ -19,12 +19,13 @@ if (process.env.NODE_ENV === 'development') {
19
19
  import React from 'react';
20
20
 
21
21
  export async function getRoutes() {
22
- const routes = {"404":{"path":"*","id":"404","parentId":"@@/global-layout"},"account/changePassword":{"path":"account/changePassword","id":"account/changePassword","parentId":"@@/global-layout"},"system/role/rolePerm":{"path":"system/role/rolePerm","id":"system/role/rolePerm","parentId":"@@/global-layout"},"system/user/userPerm":{"path":"system/user/userPerm","id":"system/user/userPerm","parentId":"@@/global-layout"},"system/dict/index":{"path":"system/dict","id":"system/dict/index","parentId":"@@/global-layout"},"system/file/index":{"path":"system/file","id":"system/file/index","parentId":"@@/global-layout"},"system/role/index":{"path":"system/role","id":"system/role/index","parentId":"@@/global-layout"},"system/user/index":{"path":"system/user","id":"system/user/index","parentId":"@@/global-layout"},"system/job/index":{"path":"system/job","id":"system/job/index","parentId":"@@/global-layout"},"system/log/index":{"path":"system/log","id":"system/log/index","parentId":"@@/global-layout"},"system/org/index":{"path":"system/org","id":"system/org/index","parentId":"@@/global-layout"},"forceUpdatePwd":{"path":"forceUpdatePwd","id":"forceUpdatePwd","parentId":"@@/global-layout"},"account/index":{"path":"account","id":"account/index","parentId":"@@/global-layout"},"about":{"path":"about","id":"about","parentId":"@@/global-layout"},"index":{"path":"/","id":"index","parentId":"@@/global-layout"},"login":{"path":"login","id":"login","parentId":"@@/global-layout"},"@@/global-layout":{"id":"@@/global-layout","path":"/","isLayout":true}} as const;
22
+ const routes = {"404":{"path":"*","id":"404","parentId":"@@/global-layout"},"account/changePassword":{"path":"account/changePassword","id":"account/changePassword","parentId":"@@/global-layout"},"system/article/index":{"path":"system/article","id":"system/article/index","parentId":"@@/global-layout"},"system/role/rolePerm":{"path":"system/role/rolePerm","id":"system/role/rolePerm","parentId":"@@/global-layout"},"system/user/userPerm":{"path":"system/user/userPerm","id":"system/user/userPerm","parentId":"@@/global-layout"},"system/dict/index":{"path":"system/dict","id":"system/dict/index","parentId":"@@/global-layout"},"system/file/index":{"path":"system/file","id":"system/file/index","parentId":"@@/global-layout"},"system/role/index":{"path":"system/role","id":"system/role/index","parentId":"@@/global-layout"},"system/user/index":{"path":"system/user","id":"system/user/index","parentId":"@@/global-layout"},"system/job/index":{"path":"system/job","id":"system/job/index","parentId":"@@/global-layout"},"system/log/index":{"path":"system/log","id":"system/log/index","parentId":"@@/global-layout"},"system/org/index":{"path":"system/org","id":"system/org/index","parentId":"@@/global-layout"},"forceUpdatePwd":{"path":"forceUpdatePwd","id":"forceUpdatePwd","parentId":"@@/global-layout"},"account/index":{"path":"account","id":"account/index","parentId":"@@/global-layout"},"article/$code":{"path":"article/:code","id":"article/$code","parentId":"@@/global-layout"},"about":{"path":"about","id":"about","parentId":"@@/global-layout"},"index":{"path":"/","id":"index","parentId":"@@/global-layout"},"login":{"path":"login","id":"login","parentId":"@@/global-layout"},"@@/global-layout":{"id":"@@/global-layout","path":"/","isLayout":true}} as const;
23
23
  return {
24
24
  routes,
25
25
  routeComponents: {
26
26
  '404': React.lazy(() => import(/* webpackChunkName: "src__pages__404" */'../../../src/pages/404.jsx')),
27
27
  'account/changePassword': React.lazy(() => import(/* webpackChunkName: "src__pages__account__changePassword" */'../../../src/pages/account/changePassword.jsx')),
28
+ 'system/article/index': React.lazy(() => import(/* webpackChunkName: "src__pages__system__article__index" */'../../../src/pages/system/article/index.jsx')),
28
29
  'system/role/rolePerm': React.lazy(() => import(/* webpackChunkName: "src__pages__system__role__rolePerm" */'../../../src/pages/system/role/rolePerm.jsx')),
29
30
  'system/user/userPerm': React.lazy(() => import(/* webpackChunkName: "src__pages__system__user__userPerm" */'../../../src/pages/system/user/userPerm.jsx')),
30
31
  'system/dict/index': React.lazy(() => import(/* webpackChunkName: "src__pages__system__dict__index" */'../../../src/pages/system/dict/index.jsx')),
@@ -36,6 +37,7 @@ export async function getRoutes() {
36
37
  'system/org/index': React.lazy(() => import(/* webpackChunkName: "src__pages__system__org__index" */'../../../src/pages/system/org/index.jsx')),
37
38
  'forceUpdatePwd': React.lazy(() => import(/* webpackChunkName: "src__pages__forceUpdatePwd" */'../../../src/pages/forceUpdatePwd.jsx')),
38
39
  'account/index': React.lazy(() => import(/* webpackChunkName: "src__pages__account__index" */'../../../src/pages/account/index.jsx')),
40
+ 'article/$code': React.lazy(() => import(/* webpackChunkName: "src__pages__article__$code" */'../../../src/pages/article/$code.jsx')),
39
41
  'about': React.lazy(() => import(/* webpackChunkName: "src__pages__about" */'../../../src/pages/about.jsx')),
40
42
  'index': React.lazy(() => import(/* webpackChunkName: "src__pages__index" */'../../../src/pages/index.jsx')),
41
43
  'login': React.lazy(() => import(/* webpackChunkName: "src__pages__login" */'../../../src/pages/login.jsx')),
@@ -5,4 +5,6 @@ export class GlobalData {
5
5
  static getLoginInfo(): object;
6
6
  static setDictInfo(data: object | null): void;
7
7
  static getDictInfo(): object | null;
8
+ static setSiteArticles(data: object): void;
9
+ static getSiteArticles(): object;
8
10
  }
@@ -3,6 +3,7 @@ import {StorageUtils} from './utils/StorageUtils';
3
3
  const SITE_INFO_KEY = "siteInfo";
4
4
  const LOGIN_INFO_KEY = "loginInfo";
5
5
  const DICT_INFO_KEY = "dictInfo";
6
+ const SITE_ARTICLES_KEY = "siteArticles";
6
7
 
7
8
  export class GlobalData {
8
9
  static setSiteInfo(data) {
@@ -28,6 +29,14 @@ export class GlobalData {
28
29
  static getDictInfo() {
29
30
  return StorageUtils.get(DICT_INFO_KEY);
30
31
  }
32
+
33
+ static setSiteArticles(data) {
34
+ StorageUtils.set(SITE_ARTICLES_KEY, data);
35
+ }
36
+
37
+ static getSiteArticles() {
38
+ return StorageUtils.get(SITE_ARTICLES_KEY) || {};
39
+ }
31
40
  }
32
41
 
33
- export { SITE_INFO_KEY, LOGIN_INFO_KEY, DICT_INFO_KEY };
42
+ export { SITE_INFO_KEY, LOGIN_INFO_KEY, DICT_INFO_KEY, SITE_ARTICLES_KEY };
@@ -1,21 +1,30 @@
1
1
  import {Avatar, Dropdown} from "antd";
2
2
  import React from "react";
3
3
  import {history} from "umi";
4
- import {DeviceUtils, HttpUtils, MessageUtils, PageUtils, GlobalData} from "../../framework";
4
+ import {DeviceUtils, HttpUtils, MessageUtils, PageUtils, GlobalData, ThemeUtils} from "../../framework";
5
5
 
6
6
  export class HeaderRight extends React.Component {
7
7
 
8
8
  state = {
9
- isMobileDevice: false
9
+ isMobileDevice: false,
10
+ dropdownArticles: [],
11
+ headerArticles: [],
10
12
  };
11
13
 
12
14
  componentDidMount() {
13
15
  if (DeviceUtils.isMobileDevice()) {
14
16
  this.setState({isMobileDevice: true})
15
17
  }
18
+ this.loadArticles()
16
19
  }
17
20
 
18
-
21
+ loadArticles = () => {
22
+ const siteArticles = GlobalData.getSiteArticles();
23
+ this.setState({
24
+ dropdownArticles: siteArticles['HEADER_AVATAR_DROPDOWN'] || [],
25
+ headerArticles: siteArticles['HEADER_RIGHT'] || [],
26
+ })
27
+ }
19
28
 
20
29
  logout = () => {
21
30
  HttpUtils.post('admin/auth/logout').then(async () => {
@@ -36,8 +45,13 @@ export class HeaderRight extends React.Component {
36
45
  PageUtils.open('/account', '个人中心')
37
46
  }
38
47
 
48
+ openArticle = (code, title) => {
49
+ PageUtils.open('/article/' + code, title)
50
+ }
51
+
39
52
  render() {
40
53
  const info = GlobalData.getLoginInfo()
54
+ const {dropdownArticles, headerArticles} = this.state
41
55
 
42
56
  if (this.state.isMobileDevice) {
43
57
  return <div className='header-right'>
@@ -45,41 +59,46 @@ export class HeaderRight extends React.Component {
45
59
  </div>
46
60
  }
47
61
 
62
+ const articleItems = dropdownArticles.map(a => ({
63
+ key: 'article:' + a.code,
64
+ label: a.title,
65
+ }))
66
+
67
+ const menuItems = [
68
+ {key: 'account', label: '个人中心'},
69
+ ...articleItems,
70
+ {key: 'logout', label: '退出登录'},
71
+ ]
72
+
48
73
  return <div className='header-right'>
74
+ {headerArticles.map(a => (
75
+ <div key={a.code} className='item' style={{cursor: 'pointer'}}
76
+ onClick={() => this.openArticle(a.code, a.title)}>
77
+ {a.title}
78
+ </div>
79
+ ))}
49
80
 
50
81
  <Dropdown menu={{
51
82
  onClick: ({key}) => {
52
- switch (key) {
53
- case 'account':
54
- this.account()
55
- break;
56
- case 'logout':
57
- this.logout();
58
- break;
59
- case 'about':
60
- this.about()
61
- break
83
+ if (key === 'account') {
84
+ this.account()
85
+ } else if (key === 'logout') {
86
+ this.logout();
87
+ } else if (key.startsWith('article:')) {
88
+ const code = key.substring(8)
89
+ const article = dropdownArticles.find(a => a.code === code)
90
+ this.openArticle(code, article ? article.title : code)
62
91
  }
63
92
  },
64
- items: [
65
- {key: 'account', label: '个人中心'},
66
- {key: 'about', label: '关于系统'},
67
- {key: 'logout', label: '退出登录'},
68
- ]
93
+ items: menuItems,
69
94
  }}>
70
95
  <div className='item' style={{cursor: 'pointer'}}>
71
- <Avatar size="small" style={{backgroundColor: '#1677ff', verticalAlign: 'middle'}}>
96
+ <Avatar size="default" style={{backgroundColor: ThemeUtils.getColor('primary-color')}}>
72
97
  {info.name?.charAt(0)}
73
98
  </Avatar>
74
99
  <span style={{marginLeft: 8}}>{info.name}</span>
75
100
  </div>
76
101
  </Dropdown>
77
-
78
102
  </div>
79
103
  }
80
-
81
-
82
- about = () => {
83
- history.push("/about")
84
- }
85
104
  }
@@ -30,6 +30,7 @@ export default class extends React.Component {
30
30
 
31
31
  siteInfo: {},
32
32
 
33
+ headerLeftArticles: [],
33
34
  }
34
35
 
35
36
 
@@ -42,6 +43,9 @@ export default class extends React.Component {
42
43
  this.setState({siteInfo, loginInfo})
43
44
 
44
45
  this.initMenu()
46
+
47
+ const siteArticles = GlobalData.getSiteArticles();
48
+ this.setState({headerLeftArticles: siteArticles['HEADER_LEFT'] || []})
45
49
  }
46
50
 
47
51
 
@@ -172,7 +176,7 @@ export default class extends React.Component {
172
176
  render() {
173
177
  const {siteInfo, loginInfo} = this.state
174
178
 
175
- return <Layout className='main-layout' style={{'--primary-color': ThemeUtils.getColor("primary-color"), '--primary-color-click': ThemeUtils.getColor("primary-color-click")}}>
179
+ return <Layout className='main-layout' style={{'--primary-color': ThemeUtils.getColor("primary-color"), '--primary-color-click': ThemeUtils.getColor("primary-color-click"), '--primary-color-hover': ThemeUtils.getColor("primary-color-hover")}}>
176
180
  <Sider id='left-sider'
177
181
  width={180}
178
182
  collapsible
@@ -191,6 +195,10 @@ export default class extends React.Component {
191
195
  <Layout style={{flex: 1, overflow: 'hidden'}}>
192
196
  <Header className='header'>
193
197
  {this.renderTopMenu()}
198
+ {this.state.headerLeftArticles.map(a => (
199
+ <div key={a.code} className='item' style={{cursor: 'pointer', padding: '0 12px', whiteSpace: 'nowrap'}}
200
+ onClick={() => PageUtils.open('/article/' + a.code, a.title)}>{a.title}</div>
201
+ ))}
194
202
  <HeaderRight/>
195
203
  </Header>
196
204
 
@@ -7,6 +7,7 @@
7
7
  display: flex;
8
8
  align-items: center;
9
9
  background-color: #fff;
10
+ border-bottom: 1px solid #e8e8e8;
10
11
 
11
12
  .top-nav {
12
13
  flex: 1;
@@ -45,11 +46,13 @@
45
46
  flex-shrink: 0;
46
47
 
47
48
  .item {
49
+ display: inline-flex;
50
+ align-items: center;
48
51
  padding: 0 0.5rem;
49
52
  cursor: pointer;
50
53
 
51
54
  &:hover {
52
- background: var(--primary-color-click, #124B93);
55
+ background: var(--primary-color-hover, #4990CD);
53
56
  color: white;
54
57
  }
55
58
  }
@@ -85,6 +85,7 @@ export function Layouts() {
85
85
  HttpUtils.get('/admin/public/user-info').then(data => {
86
86
  GlobalData.setDictInfo(data.dictInfo);
87
87
  GlobalData.setLoginInfo(data.loginInfo);
88
+ GlobalData.setSiteArticles(data.siteArticles);
88
89
 
89
90
  if (data.needUpdatePwd && pathname !== '/forceUpdatePwd') {
90
91
  history.push('/forceUpdatePwd');
@@ -1,11 +1,16 @@
1
1
  import React from "react";
2
+ import {history} from "umi";
2
3
  import {Page} from "../framework";
3
4
 
4
5
  export default class extends React.Component {
5
6
 
7
+ componentDidMount() {
8
+ history.push('/article/about')
9
+ }
10
+
6
11
  render() {
7
- return <Page title="关于" description="了解系统版本与相关信息">
8
- <h1>关于</h1>
12
+ return <Page title="关于系统">
13
+ <div>跳转中...</div>
9
14
  </Page>
10
15
  }
11
16
  }
@@ -0,0 +1,43 @@
1
+ import React from "react";
2
+ import {HttpUtils, Page, PageUtils} from "../../framework";
3
+
4
+ export default class extends React.Component {
5
+
6
+ state = {
7
+ article: null,
8
+ loading: true,
9
+ }
10
+
11
+ componentDidMount() {
12
+ const code = PageUtils.currentPathnameLastPart()
13
+ if (code) {
14
+ HttpUtils.get('admin/article/getByCode', {code}).then(rs => {
15
+ this.setState({article: rs, loading: false})
16
+ }).catch(() => {
17
+ this.setState({loading: false})
18
+ })
19
+ } else {
20
+ this.setState({loading: false})
21
+ }
22
+ }
23
+
24
+ render() {
25
+ const {article, loading} = this.state
26
+
27
+ if (loading) {
28
+ return <Page title="加载中...">
29
+ <div>加载中...</div>
30
+ </Page>
31
+ }
32
+
33
+ if (!article) {
34
+ return <Page title="文章不存在">
35
+ <div>文章不存在或已禁用</div>
36
+ </Page>
37
+ }
38
+
39
+ return <Page title={article.title}>
40
+ <div dangerouslySetInnerHTML={{__html: article.content}}/>
41
+ </Page>
42
+ }
43
+ }
@@ -31,15 +31,7 @@ export default class extends React.Component {
31
31
  }
32
32
 
33
33
  validator = (rule, value) => {
34
- return new Promise((resolve, reject) => {
35
- HttpUtils.get("admin/sysUser/pwd-strength", {password: value}).then(response => {
36
- const rs = response.data
37
- if (!rs.success) {
38
- reject(rs.message)
39
- }
40
- resolve()
41
- })
42
- })
34
+ return HttpUtils.get("admin/sysUser/pwd-strength", {password: value})
43
35
  }
44
36
 
45
37
  render() {
@@ -0,0 +1,152 @@
1
+ import {PlusOutlined} from '@ant-design/icons'
2
+ import {Button, Form, Input, InputNumber, Modal, Popconfirm} from 'antd'
3
+ import React from 'react'
4
+ import {
5
+ DictUtils,
6
+ FieldBoolean,
7
+ FieldDictSelect,
8
+ FieldEditor,
9
+ HttpUtils,
10
+ Page,
11
+ PermActions,
12
+ ProTable
13
+ } from "../../../framework";
14
+
15
+ const {TextArea} = Input;
16
+
17
+ export default class extends React.Component {
18
+
19
+ state = {
20
+ formValues: {},
21
+ formOpen: false,
22
+ }
23
+
24
+ formRef = React.createRef()
25
+ tableRef = React.createRef()
26
+
27
+ handleAdd = () => {
28
+ this.setState({formOpen: true, formValues: {}})
29
+ }
30
+
31
+ handleEdit = record => {
32
+ this.setState({formOpen: true, formValues: record})
33
+ }
34
+
35
+ onFinish = values => {
36
+ const isNew = !values.id;
37
+ const url = isNew ? 'admin/article/create' : 'admin/article/update';
38
+ HttpUtils.post(url, values).then(rs => {
39
+ this.setState({formOpen: false})
40
+ this.tableRef.current.reload()
41
+ })
42
+ }
43
+
44
+ handleDelete = record => {
45
+ HttpUtils.post('admin/article/delete', {id: record.id}).then(rs => {
46
+ this.tableRef.current.reload()
47
+ })
48
+ }
49
+
50
+ columns = [
51
+ {
52
+ title: '编码',
53
+ dataIndex: 'code',
54
+ },
55
+ {
56
+ title: '标题',
57
+ dataIndex: 'title',
58
+ },
59
+ {
60
+ title: '显示位置',
61
+ dataIndex: 'position',
62
+ render(v) {
63
+ return DictUtils.dictLabel('articlePosition', v) || v
64
+ },
65
+ },
66
+ {
67
+ title: '排序',
68
+ dataIndex: 'seq',
69
+ },
70
+ {
71
+ title: '启用',
72
+ dataIndex: 'enabled',
73
+ render(v) {
74
+ return v == null ? null : (v ? '是' : '否')
75
+ },
76
+ },
77
+ {
78
+ title: '操作',
79
+ dataIndex: 'option',
80
+ render: (_, record) => {
81
+ return (
82
+ <PermActions>
83
+ <Button size='small' perm='article:update' onClick={() => this.handleEdit(record)}>编辑</Button>
84
+ <Popconfirm perm='article:delete' title='确定删除?' onConfirm={() => this.handleDelete(record)}>
85
+ <Button size='small'>删除</Button>
86
+ </Popconfirm>
87
+ </PermActions>
88
+ );
89
+ },
90
+ },
91
+ ]
92
+
93
+ render() {
94
+ return <Page
95
+ title="文章管理"
96
+ description="管理系统文章,如关于、帮助等页面"
97
+ actions={<Button perm='article:create' type='primary' icon={<PlusOutlined/>} onClick={this.handleAdd}>新增</Button>}
98
+ >
99
+ <ProTable
100
+ actionRef={this.tableRef}
101
+ request={(params) => HttpUtils.get('admin/article/page', params)}
102
+ columns={this.columns}
103
+ >
104
+ <Form.Item label='编码' name='code'>
105
+ <Input/>
106
+ </Form.Item>
107
+ <Form.Item label='标题' name='title'>
108
+ <Input/>
109
+ </Form.Item>
110
+ </ProTable>
111
+
112
+ <Modal title='文章'
113
+ open={this.state.formOpen}
114
+ onOk={() => this.formRef.current.submit()}
115
+ onCancel={() => this.setState({formOpen: false})}
116
+ destroyOnHidden
117
+ width={800}
118
+ >
119
+ <Form ref={this.formRef} labelCol={{flex: '100px'}}
120
+ initialValues={this.state.formValues}
121
+ onFinish={this.onFinish}
122
+ >
123
+ <Form.Item name='id' noStyle></Form.Item>
124
+
125
+ <Form.Item label='编码' name='code' rules={[{required: true}]}>
126
+ <Input disabled={!!this.state.formValues.id}/>
127
+ </Form.Item>
128
+
129
+ <Form.Item label='标题' name='title' rules={[{required: true}]}>
130
+ <Input/>
131
+ </Form.Item>
132
+
133
+ <Form.Item label='内容' name='content'>
134
+ <FieldEditor />
135
+ </Form.Item>
136
+
137
+ <Form.Item label='显示位置' name='position' rules={[{required: true}]}>
138
+ <FieldDictSelect typeCode='articlePosition'/>
139
+ </Form.Item>
140
+
141
+ <Form.Item label='排序' name='seq'>
142
+ <InputNumber/>
143
+ </Form.Item>
144
+
145
+ <Form.Item label='启用' name='enabled'>
146
+ <FieldBoolean/>
147
+ </Form.Item>
148
+ </Form>
149
+ </Modal>
150
+ </Page>
151
+ }
152
+ }