@jiangood/open-admin 2.5.8 → 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.8"
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.8"
41
+ "version": "2.5.9"
42
42
  },
43
43
  "pkgPath": "/home/runner/work/open-admin/open-admin/web/package.json",
44
44
  "plugins": {
@@ -51,7 +51,7 @@
51
51
  "config": {},
52
52
  "time": {
53
53
  "hooks": {},
54
- "register": 1
54
+ "register": 0
55
55
  },
56
56
  "enableBy": "register"
57
57
  },
@@ -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,10 +142,10 @@
142
142
  "time": {
143
143
  "hooks": {
144
144
  "modifyAppData": [
145
- 72
145
+ 79
146
146
  ]
147
147
  },
148
- "register": 20
148
+ "register": 21
149
149
  },
150
150
  "enableBy": "register"
151
151
  },
@@ -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
  },
@@ -1091,7 +1091,7 @@
1091
1091
  "time": {
1092
1092
  "hooks": {
1093
1093
  "onStart": [
1094
- 1
1094
+ 0
1095
1095
  ]
1096
1096
  },
1097
1097
  "register": 1
@@ -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
  },
@@ -1120,7 +1120,7 @@
1120
1120
  "config": {},
1121
1121
  "time": {
1122
1122
  "hooks": {},
1123
- "register": 103
1123
+ "register": 96
1124
1124
  },
1125
1125
  "enableBy": "register"
1126
1126
  },
@@ -1133,7 +1133,7 @@
1133
1133
  "config": {},
1134
1134
  "time": {
1135
1135
  "hooks": {},
1136
- "register": 30
1136
+ "register": 29
1137
1137
  },
1138
1138
  "enableBy": "config"
1139
1139
  },
@@ -1146,7 +1146,7 @@
1146
1146
  "config": {},
1147
1147
  "time": {
1148
1148
  "hooks": {},
1149
- "register": 10
1149
+ "register": 9
1150
1150
  },
1151
1151
  "enableBy": "config"
1152
1152
  },
@@ -1160,7 +1160,7 @@
1160
1160
  "time": {
1161
1161
  "hooks": {
1162
1162
  "modifyAppData": [
1163
- 0
1163
+ 1
1164
1164
  ]
1165
1165
  },
1166
1166
  "register": 1
@@ -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
  },
@@ -1202,7 +1202,7 @@
1202
1202
  "config": {},
1203
1203
  "time": {
1204
1204
  "hooks": {},
1205
- "register": 39
1205
+ "register": 31
1206
1206
  }
1207
1207
  },
1208
1208
  "./node_modules/@umijs/preset-umi/dist/features/mpa/mpa": {
@@ -1281,7 +1281,7 @@
1281
1281
  "config": {},
1282
1282
  "time": {
1283
1283
  "hooks": {},
1284
- "register": 1
1284
+ "register": 0
1285
1285
  },
1286
1286
  "enableBy": "register"
1287
1287
  },
@@ -1307,7 +1307,7 @@
1307
1307
  "config": {},
1308
1308
  "time": {
1309
1309
  "hooks": {},
1310
- "register": 0
1310
+ "register": 1
1311
1311
  },
1312
1312
  "enableBy": "config"
1313
1313
  },
@@ -1320,7 +1320,7 @@
1320
1320
  "config": {},
1321
1321
  "time": {
1322
1322
  "hooks": {},
1323
- "register": 1
1323
+ "register": 0
1324
1324
  },
1325
1325
  "enableBy": "config"
1326
1326
  },
@@ -1333,7 +1333,7 @@
1333
1333
  "config": {},
1334
1334
  "time": {
1335
1335
  "hooks": {},
1336
- "register": 0
1336
+ "register": 1
1337
1337
  },
1338
1338
  "enableBy": "register"
1339
1339
  },
@@ -1372,7 +1372,7 @@
1372
1372
  "config": {},
1373
1373
  "time": {
1374
1374
  "hooks": {},
1375
- "register": 1
1375
+ "register": 0
1376
1376
  }
1377
1377
  },
1378
1378
  "./node_modules/@umijs/preset-umi/dist/features/ssr/ssr": {
@@ -1384,7 +1384,7 @@
1384
1384
  "config": {},
1385
1385
  "time": {
1386
1386
  "hooks": {},
1387
- "register": 1
1387
+ "register": 2
1388
1388
  },
1389
1389
  "enableBy": "config"
1390
1390
  },
@@ -1397,7 +1397,7 @@
1397
1397
  "config": {},
1398
1398
  "time": {
1399
1399
  "hooks": {},
1400
- "register": 1
1400
+ "register": 2
1401
1401
  },
1402
1402
  "enableBy": "register"
1403
1403
  },
@@ -1410,7 +1410,7 @@
1410
1410
  "config": {},
1411
1411
  "time": {
1412
1412
  "hooks": {},
1413
- "register": 4
1413
+ "register": 3
1414
1414
  },
1415
1415
  "enableBy": "register"
1416
1416
  },
@@ -1423,7 +1423,7 @@
1423
1423
  "config": {},
1424
1424
  "time": {
1425
1425
  "hooks": {},
1426
- "register": 4
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
  },
@@ -1461,7 +1461,7 @@
1461
1461
  "config": {},
1462
1462
  "time": {
1463
1463
  "hooks": {},
1464
- "register": 26
1464
+ "register": 20
1465
1465
  },
1466
1466
  "enableBy": "config"
1467
1467
  },
@@ -1565,7 +1565,7 @@
1565
1565
  "config": {},
1566
1566
  "time": {
1567
1567
  "hooks": {},
1568
- "register": 0
1568
+ "register": 1
1569
1569
  },
1570
1570
  "enableBy": "config"
1571
1571
  },
@@ -1578,7 +1578,7 @@
1578
1578
  "config": {},
1579
1579
  "time": {
1580
1580
  "hooks": {},
1581
- "register": 1
1581
+ "register": 0
1582
1582
  }
1583
1583
  },
1584
1584
  "./node_modules/@umijs/preset-umi/dist/features/hmrGuardian/hmrGuardian": {
@@ -1590,7 +1590,7 @@
1590
1590
  "config": {},
1591
1591
  "time": {
1592
1592
  "hooks": {},
1593
- "register": 2
1593
+ "register": 3
1594
1594
  }
1595
1595
  },
1596
1596
  "./node_modules/@umijs/preset-umi/dist/features/routePreloadOnLoad/routePreloadOnLoad": {
@@ -1602,7 +1602,7 @@
1602
1602
  "config": {},
1603
1603
  "time": {
1604
1604
  "hooks": {},
1605
- "register": 32
1605
+ "register": 28
1606
1606
  }
1607
1607
  },
1608
1608
  "./node_modules/@umijs/preset-umi/dist/features/forget/forget": {
@@ -1627,7 +1627,7 @@
1627
1627
  "config": {},
1628
1628
  "time": {
1629
1629
  "hooks": {},
1630
- "register": 2
1630
+ "register": 1
1631
1631
  },
1632
1632
  "enableBy": "register"
1633
1633
  },
@@ -1666,7 +1666,7 @@
1666
1666
  "config": {},
1667
1667
  "time": {
1668
1668
  "hooks": {},
1669
- "register": 16
1669
+ "register": 17
1670
1670
  }
1671
1671
  },
1672
1672
  "./node_modules/@umijs/preset-umi/dist/commands/help": {
@@ -1808,7 +1808,7 @@
1808
1808
  "config": {},
1809
1809
  "time": {
1810
1810
  "hooks": {},
1811
- "register": 0
1811
+ "register": 1
1812
1812
  },
1813
1813
  "enableBy": "register"
1814
1814
  },
@@ -1912,7 +1912,7 @@
1912
1912
  "config": {},
1913
1913
  "time": {
1914
1914
  "hooks": {},
1915
- "register": 21
1915
+ "register": 22
1916
1916
  },
1917
1917
  "enableBy": "register"
1918
1918
  },
@@ -1925,7 +1925,7 @@
1925
1925
  "config": {},
1926
1926
  "time": {
1927
1927
  "hooks": {},
1928
- "register": 1
1928
+ "register": 0
1929
1929
  },
1930
1930
  "enableBy": "register"
1931
1931
  },
@@ -1938,7 +1938,7 @@
1938
1938
  "config": {},
1939
1939
  "time": {
1940
1940
  "hooks": {},
1941
- "register": 1
1941
+ "register": 2
1942
1942
  },
1943
1943
  "enableBy": "register"
1944
1944
  },
@@ -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
  },
@@ -1968,7 +1968,7 @@
1968
1968
  0
1969
1969
  ]
1970
1970
  },
1971
- "register": 5
1971
+ "register": 6
1972
1972
  },
1973
1973
  "enableBy": "register"
1974
1974
  }
@@ -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
+ }