480fe21d by charles

feat: 更新

1 parent 9b990809
Showing 55 changed files with 29 additions and 4751 deletions
...@@ -21,7 +21,7 @@ const getRoutes = (routes, maps = {}) => { ...@@ -21,7 +21,7 @@ const getRoutes = (routes, maps = {}) => {
21 }; 21 };
22 }; 22 };
23 23
24 const { routes, maps } = getRoutes([user, app]); 24 const { routes, maps } = getRoutes([user]);
25 25
26 export const routeMaps = maps; 26 export const routeMaps = maps;
27 27
......
1 export default { 1 export default {
2 path: '/user', 2 path: '/',
3 component: '../layouts/UserLayout', 3 component: '../layouts/UserLayout',
4 routes: [ 4 routes: [
5 { path: '/user', name: 'login', redirect: '/user/login' }, 5 { path: '/', name: 'Risk', component: './Risk' },
6 { path: '/user/login', name: 'login', component: './User/Login' }, 6 { path: '/:id', component: './Risk' },
7 { path: '/user/risk', name: 'login', component: './User/Risk' },
8 ], 7 ],
9 }; 8 };
......
1 import { connect } from 'umi';
2 import React from 'react'; 1 import React from 'react';
3 import styles from './UserLayout.less'; 2 import styles from './UserLayout.less';
4 3
5 const UserLayout = props => { 4 const UserLayout = props => {
6 const { children } = props; 5 const { children } = props;
7 return ( 6 return <div className={styles.container}>{children}</div>;
8 <>
9 <div className={styles.container}>
10 <div className={styles.bgTop}>
11 <div>一网打“净”数智在线</div>
12 </div>
13 <div className={styles.content}>
14 <div className={styles.login}>{children}</div>
15 </div>
16 </div>
17 </>
18 );
19 }; 7 };
20 8
21 export default connect(({ settings, user }) => ({ 9 export default UserLayout;
22 ...settings,
23 currentUser: user.currentUser,
24 }))(UserLayout);
......
...@@ -7,32 +7,6 @@ ...@@ -7,32 +7,6 @@
7 height: 100vh; 7 height: 100vh;
8 overflow: auto; 8 overflow: auto;
9 position: relative; 9 position: relative;
10 background-color: #F5F5F5;
11 .bgTop {
12 background-color: @primary-color;
13 height: 400px;
14 div {
15 color: #fff;
16 text-align: center;
17 font-size: 22px;
18 position: absolute;
19 top: 170px;
20 left: 50%;
21 letter-spacing: 2px;
22 transform: translateX(-50%);
23 }
24 }
25 .content {
26 position: absolute;
27 background-color: #fff; 10 background-color: #fff;
28 border-radius: 2px; 11 padding: 20px;
29 top: 220px;
30 left: 50%;
31 z-index: 2;
32 transform: translateX(-50%);
33 .login {
34 width: 400px;
35 box-shadow: 0 4px 50px 0 rgba(121,173,201,.17);
36 }
37 }
38 } 12 }
......
1 import { queryNotices } from '@/services/user';
2 const GlobalModel = {
3 namespace: 'global',
4 state: {
5 collapsed: false,
6 loading: false,
7 urlFileExport: '',
8 dataModal: {
9 modalType: '',
10 modalShow: false,
11 modalData: {},
12 },
13 preImgDataModal: {
14 modalType: '',
15 modalShow: false,
16 modalData: {},
17 },
18 },
19 effects: {},
20 reducers: {
21 changeLayoutCollapsed(
22 state = {
23 notices: [],
24 collapsed: true,
25 },
26 { payload },
27 ) {
28 return { ...state, collapsed: payload };
29 },
30 },
31 subscriptions: {
32 setup({ history, dispatch }) {
33 // Subscribe history(url) change, trigger `load` action if pathname is `/`
34 history.listen(({ pathname, search }) => {
35 // 路由发生变化的时候切换菜单
36 const whiteList = ['/user/login'];
37
38 if (!whiteList.includes(pathname)) {
39 // 获取用户信息
40 dispatch({ type: 'user/fetchCurrent' });
41 }
42 });
43 },
44 },
45 };
46 export default GlobalModel;
1 import { queryLogin, loginOut } from '@/services/login';
2 import { getUserInfo, getBosUserList } from '@/services/user';
3 import { message } from 'antd';
4 import { history } from 'umi';
5 import md5 from 'blueimp-md5';
6 import defaultSettings from '../../config/defaultSettings';
7 import { getDataMenus } from '@/utils/menu';
8 const { tokenKey, md5Key } = defaultSettings;
9 const Model = {
10 namespace: 'login',
11 state: {
12 status: undefined,
13 },
14 effects: {
15 //退出登录
16 *logout({ payload }, { call, put, select }) {
17 try {
18 const res = yield call(loginOut);
19 if (res.code === 0 && res.data) {
20 if (!payload) {
21 message.success('退出成功');
22 }
23 localStorage.removeItem(tokenKey);
24 setTimeout(() => {
25 window.location.href = '/user/login';
26 }, 500);
27 }
28 } catch (err) {
29 console.error(err);
30 }
31 },
32 //登录
33 *login({ payload }, { call, put }) {
34 try {
35 const res = yield call(queryLogin, payload);
36 if (res.code === 0) {
37 localStorage.setItem(tokenKey, res.data);
38 // const userinfo = yield call(getUserInfo);
39 // const { permissionVos = [] } = userinfo.data;
40 // const dataMenus = getDataMenus(permissionVos);
41 // console.log(dataMenus);
42 // if (dataMenus.length) {
43 // history.replace(dataMenus[0].path);
44 // } else {
45 // history.replace('/');
46 // }
47 history.replace('/');
48 message.success('登录成功');
49 }
50 } catch (err) {
51 console.error(err);
52 }
53 },
54 },
55 reducers: {
56 changeLoginStatus(state, { payload }) {
57 return { ...state, status: payload.status, type: payload.type };
58 },
59 },
60 };
61 export default Model;
1 import defaultSettings from '../../config/defaultSettings';
2
3 const updateColorWeak = colorWeak => {
4 const root = document.getElementById('root');
5
6 if (root) {
7 root.className = colorWeak ? 'colorWeak' : '';
8 }
9 };
10
11 const SettingModel = {
12 namespace: 'settings',
13 state: defaultSettings,
14 reducers: {
15 changeSetting(state = defaultSettings, { payload }) {
16 const { colorWeak, contentWidth } = payload;
17
18 if (state.contentWidth !== contentWidth && window.dispatchEvent) {
19 window.dispatchEvent(new Event('resize'));
20 }
21
22 updateColorWeak(!!colorWeak);
23 return { ...state, ...payload };
24 },
25 },
26 };
27 export default SettingModel;
1 import { getUserInfo, updatePassword } from '@/services/user';
2 import { getDataMenus } from '@/utils/menu';
3 import { message } from 'antd';
4 const UserModel = {
5 namespace: 'user',
6 state: {
7 currentUser: {
8 admin: {},
9 dataMenus: [],
10 username: '',
11 },
12 userAuths: [], // 权限
13 dataModal: {
14 modalType: '',
15 modalShow: false,
16 modalData: {},
17 },
18 },
19 effects: {
20 *fetchCurrent(_, { call, put, select }) {
21 const {
22 currentUser,
23 currentUser: { username },
24 } = yield select(state => state.user);
25 if (!currentUser || !username) {
26 try {
27 const res = yield call(getUserInfo);
28 // data.dataMenus = getDataMenus(data.permissionVos);
29 if (res.code === 0) {
30 res.data.menus = [
31 {
32 children: [],
33 id: 999999,
34 parentId: 0,
35 resourceCode: 'Home',
36 resourceNodeType: '1',
37 title: '数智大屏',
38 },
39 ...(res.data.menus || []),
40 {
41 resourceCode: '404',
42 },
43 ];
44 yield put({ type: 'saveCurrentUser', payload: res.data });
45 }
46 } catch (err) {
47 console.error(err, 'err');
48 }
49 }
50 },
51 /* 修改密码 */
52 *updatePassword({ payload }, { call, put, select }) {
53 try {
54 const res = yield call(updatePassword, payload);
55 if (res.code === 0) {
56 message.success('修改成功');
57 yield put({ type: 'cancelModal' });
58 yield put({ type: 'login/logout', payload: { message: 1 } });
59 }
60 } catch (err) {
61 console.error(err);
62 }
63 },
64 },
65 reducers: {
66 changeState(state, { payload }) {
67 return {
68 ...state,
69 ...payload,
70 };
71 },
72 cancelModal(state, { payload }) {
73 return {
74 ...state,
75 dataModal: {
76 modalType: '',
77 modalShow: false,
78 modalData: {},
79 },
80 };
81 },
82 saveCurrentUser(state, { payload }) {
83 return {
84 ...state,
85 currentUser: payload || {},
86 // userAuths: payload.authorities.map(_ => _.code),
87 };
88 },
89 },
90 };
91 export default UserModel;
1 /**
2 * Author: llw
3 * Date: 2020.7.20
4 * Description: [设置权限弹框]
5 */
6 import React, { useEffect, useState } from 'react';
7 import { Drawer, Radio, Form, Select, Input, Button } from 'antd';
8
9 const { Option } = Select;
10 const formItemLayout = {labelCol: { span: 4 }, wrapperCol: { span: 20 }};
11
12 const ModalSetAuth = props => {
13 const [menuType, setType] = useState(1);
14 const [form] = Form.useForm();
15 let {
16 handleCancelModal,
17 handleAuthSetOk,
18 dataMenuList = [],
19 dataModal: {
20 modalType,
21 modalShow,
22 modalData,
23 modalData: { name, code, type, url, icon, parentCode, isEdit }
24 }
25 } = props;
26
27 dataMenuList = code ? dataMenuList.filter(item => code !== item.code) : dataMenuList;
28
29 /* 重置type */
30 useEffect(() => {
31 if (modalType === "AUTH_SET_MODAL" && modalShow) {
32 setType(type || 1);
33 setTimeout(() => {
34 form.resetFields();
35 form.setFieldsValue({
36 name,
37 code,
38 url,
39 icon,
40 parentCode,
41 type: type || 1,
42 });
43 }, 100)
44 }
45 }, [modalType, modalShow])
46
47 /* 点击保存 */
48 const handleSave = () => {
49 form.validateFields().then(values => {
50 handleAuthSetOk({
51 ...modalData,
52 ...values,
53 isEdit
54 });
55 })
56 };
57
58 /* 选择菜单类型 */
59 const handleChangeRadio = (value) => {
60 form.resetFields();
61 setType(value);
62 form.setFieldsValue({type: value});
63 };
64
65 return (
66 <Drawer
67 title="权限设置"
68 placement="right"
69 width={600}
70 maskClosable={false}
71 onClose={handleCancelModal}
72 visible={modalType === 'AUTH_SET_MODAL' && modalShow}
73 footer={
74 <div
75 style={{
76 textAlign: 'right',
77 }}
78 >
79 <Button onClick={handleCancelModal} className="mr-10">取消</Button>
80 <Button onClick={handleSave} type="primary">保存</Button>
81 </div>
82 }
83 >
84 <Form
85 form={form}
86 {...formItemLayout}
87 name="auth_set_modal"
88 initialValues={{ type: 1 }}
89 >
90 <Form.Item
91 name="type"
92 label="菜单类型"
93 >
94 <Radio.Group buttonStyle="solid" onChange={(e) => handleChangeRadio(e.target.value)}>
95 <Radio.Button disabled={(isEdit && type !== 1) ? true : false} value={1}>一级菜单</Radio.Button>
96 <Radio.Button disabled={(isEdit && type !== 2) ? true : false} value={2}>子菜单</Radio.Button>
97 <Radio.Button disabled={(isEdit && type !== 3) ? true : false} value={3}>按钮</Radio.Button>
98 </Radio.Group>
99 </Form.Item>
100 {
101 menuType !== 1 && <Form.Item
102 name="parentCode"
103 label={menuType === 2 ? "上级菜单" : "包含菜单"}
104 rules={
105 [{required: true, message: menuType === 2 ? "请选择上级菜单" : "请选择包含该按钮的菜单"}]
106 }
107 >
108 <Select
109 showSearch
110 placeholder={menuType === 2 ? '请选择上级菜单' : '请选择包含该按钮的菜单'}
111 optionFilterProp="children"
112 filterOption={(input, option) =>
113 option.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
114 }
115 >
116 {
117 dataMenuList.map(item => {
118 return (
119 <Option key={item.code} value={item.code}>{item.name}</Option>
120 )
121 })
122 }
123 </Select>
124 </Form.Item>
125 }
126 <Form.Item
127 name="name"
128 label={menuType === 3 ? "按钮名称" : "菜单名称"}
129 rules={
130 [
131 {required: true, message: menuType === 3 ? '请输入按钮名称' : '请输入菜单名称'},
132 {min: 2, max: 15, message: '名称长度2~15个字符'}
133 ]
134 }
135 >
136 <Input maxLength={15} placeholder={menuType === 3 ? "请输入按钮名称" : "请输入菜单名称"} />
137 </Form.Item>
138 <Form.Item
139 name="code"
140 label={menuType === 3 ? "按钮code" : "菜单code"}
141 rules={
142 [{required: true, message: menuType === 3 ? '请输入按钮code' : '请输入菜单code'}]
143 }
144 >
145 <Input maxLength={20} placeholder={menuType === 3 ? "请输入按钮code" : "请输入菜单code"} />
146 </Form.Item>
147 {
148 menuType !== 3 && <>
149 <Form.Item
150 name="url"
151 label="菜单URL"
152 rules={
153 [{required: true, message: '请输入菜单URL'}]
154 }
155 >
156 <Input placeholder="请输入菜单URL" />
157 </Form.Item>
158 <Form.Item
159 name="icon"
160 label="菜单Icon"
161 >
162 <Input placeholder="请输入菜单Icon" />
163 </Form.Item>
164 </>
165 }
166 </Form>
167 </Drawer>
168 )
169 };
170
171 export default ModalSetAuth;
...\ No newline at end of file ...\ No newline at end of file
1 /**
2 * Author: llw
3 * Date: 2020.7.16
4 * Description: [应用列表]
5 */
6 import React, { useEffect } from 'react';
7 import { connect, Link } from 'umi';
8 import { Card, Form, DatePicker, Input, Button, Table, Divider, Modal } from 'antd';
9 import { ExclamationCircleOutlined } from '@ant-design/icons';
10 import { paginations } from '@/constants';
11 import moment from 'moment';
12
13 const { RangePicker } = DatePicker;
14 const FormItem = Form.Item;
15
16 /* SearchForm */
17 const SearchForm = props => {
18 const [form] = Form.useForm();
19 const {
20 dataSearch,
21 handleReset,
22 handleFinish,
23 dataSearch: { createTimeBegin, createTimeEnd }
24 } = props;
25
26 useEffect(() => {
27 form.setFieldsValue({
28 ...dataSearch,
29 createTime: [createTimeBegin ? moment(createTimeBegin) : undefined, createTimeEnd ? moment(createTimeEnd) : undefined]
30 });
31 }, [dataSearch]);
32
33 /* 点击搜索 */
34 const onFinish = (values) => {
35 handleFinish(values);
36 };
37
38 /* 点击重置 */
39 const onReset = () => {
40 handleReset();
41 };
42
43 return (
44 <Form
45 name="Form_Application"
46 layout="inline"
47 form={form}
48 onFinish={onFinish}
49 >
50 <FormItem label="应用名称" name="name">
51 <Input placeholder="请输入应用名称" style={{width: "220px"}} />
52 </FormItem>
53 <FormItem label="创建时间" name="createTime">
54 <RangePicker allowClear={false} />
55 </FormItem>
56 <FormItem>
57 <Button type="primary" htmlType="submit" className="mr-15">搜索</Button>
58 <Button className="mr-15" htmlType="button" onClick={onReset}>重置</Button>
59 <Link to="/appliction/info"><Button>创建应用</Button></Link>
60 </FormItem>
61 </Form>
62 )
63 };
64
65 /* DataTable */
66 const DataTable = props => {
67 const {
68 loading,
69 handleDel,
70 handleGetList,
71 dataApplication: { data = [], page, size, totalItem }
72 } = props;
73
74 /* 点击分页 */
75 const handlePageChange = (page, size) => {
76 handleGetList(page, size);
77 };
78
79 const columns = [
80 {
81 title: '应用名称',
82 dataIndex: 'name',
83 align: 'center'
84 },
85 {
86 title: '应用标识码',
87 dataIndex: 'code',
88 align: 'center',
89 render(t, r) {
90 return t || '--'
91 }
92 },
93 {
94 title: '应用链接地址',
95 dataIndex: 'url',
96 align: 'center',
97 render(t, r) {
98 return t || '--'
99 }
100 },
101 {
102 title: '创建时间',
103 dataIndex: 'createTime',
104 align: 'center',
105 render(t, r) {
106 return t ? moment(t).format("YYYY-MM-DD HH:mm:ss") : '--'
107 }
108 },
109 {
110 title: '操作',
111 align: 'center',
112 render(t, r) {
113 return (
114 <>
115 <Link to={`/appliction/info?id=${r.id}`}>编辑</Link>
116 <Divider type="vertical" />
117 <a onClick={() => handleDel(r)}>删除</a>
118 </>
119 )
120 }
121 }
122 ];
123 const pagination = {
124 ...paginations,
125 total: totalItem,
126 pageSize: size,
127 current: page,
128 showSizeChanger: totalItem > 20,
129 onChange: (page, pageSize) => {
130 handlePageChange(page, pageSize);
131 },
132 onShowSizeChange: (page, pageSize) => {
133 handlePageChange(1, pageSize);
134 },
135 showTotal(total) {
136 return `总共 ${total} 条数据`;
137 },
138 };
139 return (
140 <Table
141 rowKey="id"
142 loading={loading}
143 dataSource={data}
144 columns={columns}
145 pagination={pagination}
146 />
147 )
148 };
149
150 /* Main */
151 const Application = props => {
152 const { dispatch, loading, dataSearch, dataApplication, dataApplication: { size } } = props;
153
154 useEffect(() => {
155 handleGetList(1, 10);
156 }, [])
157
158 /* 应用列表 */
159 const handleGetList = (page, size) => {
160 dispatch({type: 'Application/getApplicationList', payload: {
161 page: page || 1,
162 size: size || 10
163 }});
164 };
165
166 /* 点击搜索 */
167 const handleFinish = (values) => {
168 const { createTime, name } = values;
169 dispatch({type: 'Application/changeState', payload: {
170 dataSearch: {
171 name,
172 createTimeBegin: createTime[0] ? createTime[0].startOf('day').valueOf() : undefined,
173 createTimeEnd: createTime[1] ? createTime[1].endOf('day').valueOf() : undefined,
174 }
175 }});
176 handleGetList(0, size);
177 };
178
179 /* 点击重置 */
180 const handleReset = () => {
181 dispatch({type: 'Application/resetSearch'});
182 handleGetList(0, 10);
183 };
184
185 /* 点击删除 */
186 const handleDel = ({ id }) => {
187 Modal.confirm({
188 title: '确定删除该应用吗?',
189 icon: <ExclamationCircleOutlined />,
190 okText: '确定',
191 cancelText: '取消',
192 onOk() {
193 dispatch({type: 'Application/delApplication', payload: {id}});
194 },
195 });
196 };
197
198 return (
199 <Card bordered={false}>
200 <SearchForm
201 dataSearch={dataSearch}
202 handleReset={handleReset}
203 handleFinish={handleFinish}
204 />
205 <div className="mt-24">
206 <DataTable
207 loading={loading}
208 handleDel={handleDel}
209 handleGetList={handleGetList}
210 dataApplication={dataApplication}
211 />
212 </div>
213 </Card>
214 )
215 };
216
217 export default connect(({ Application, loading }) => ({
218 ...Application,
219 loading: loading.effects["Application/getApplicationList"]
220 }))(Application)
...\ No newline at end of file ...\ No newline at end of file
1 import { routerRedux } from 'dva';
2 import { message } from 'antd';
3 import { getPermissionList } from '@/utils/utils';
4 import * as services from '@/services/application';
5
6 /* SerachParams */
7 const staticSearch = {
8 name: undefined,
9 createTimeBegin: undefined,
10 createTimeEnd: undefined
11 };
12
13 export default {
14 namespace: 'Application',
15 state: {
16 dataSearch: {
17 ...staticSearch
18 },
19 dataApplication: {
20 data: [],
21 page: 1,
22 size: 10,
23 totalItem: 0,
24 totalPage: 0,
25 },
26 dataModal: {
27 modalType: '',
28 modalShow: false,
29 modalData: {}
30 },
31 dataMenuList: [], // 获取所有的菜单
32 dataAuth: [], // 权限模块提交给后端的数据
33 dataExpandedKeys: [], // tree展开的数据
34 dataApplicationInfo: {}, // 应用相关信息
35 oldInfo: {}, // 上一次权限信息
36 },
37 effects: {
38 /* 获取应用列表 */
39 *getApplicationList({ payload }, { call, put, select }) {
40 const { dataSearch } = yield select(state => state.Application);
41 try {
42 const res = yield call(services.getApplicationList, {
43 page: 1,
44 size: 10,
45 ...dataSearch,
46 ...payload
47 });
48 if (res.status === 1) {
49 res.data.data = res.data.data || [];
50 yield put({type: 'changeState', payload: {
51 dataApplication: res.data
52 }})
53 }
54 } catch (err) {
55 console.error(err)
56 }
57 },
58 /* 删除应用 */
59 *delApplication({ payload }, { call, put, select }) {
60 const { dataApplication: { data = [], page, size } } = yield select(state => state.Application);
61 try {
62 const res = yield call(services.delApplication, payload);
63 if (res.status === 1) {
64 message.success("删除成功~");
65 yield put({type: 'getApplicationList', payload: {
66 size,
67 page: (data.length === 1 ? (page === 1 ? 1 : page - 1) : page)
68 }})
69 }
70 } catch (err) {
71 console.error(err)
72 }
73 },
74 /* 新增、修改应用 */
75 *updateApplication({ payload }, { call, put, select }) {
76 const { id } = payload;
77 try {
78 const res = yield call(services[!id ? "addApplication" : "updateApplication"], payload);
79 if (res.status === 1) {
80 message.success(!id ? "新增成功~" : "修改成功~");
81 yield put(routerRedux.push('/appliction'));
82 }
83 } catch (err) {
84 console.error(err)
85 }
86 },
87 /* 获取应用详情 */
88 *getApplicationInfo({ payload }, { call, put, select }) {
89 try {
90 const res = yield call(services.getApplicationInfo, payload);
91 if (res.status === 1) {
92 const { data, dataMenu, dataExpandedKeys } = getPermissionList(res.data.permissionList, true);
93 yield put({type: 'changeState', payload: {
94 dataApplicationInfo: res.data || {},
95 dataAuth: data,
96 dataMenuList: dataMenu,
97 dataExpandedKeys
98 }})
99 };
100 return res;
101 } catch (err) {
102 console.error(err)
103 }
104 }
105 },
106 reducers: {
107 changeState(state, { payload }) {
108 return {
109 ...state,
110 ...payload
111 }
112 },
113 cancelModal(state, { payload }) {
114 return {
115 ...state,
116 dataModal: {
117 modalType: '',
118 modalShow: false,
119 modalData: {}
120 }
121 }
122 },
123 resetSearch(state, { payload }) {
124 return {
125 ...state,
126 dataSearch: {
127 ...staticSearch
128 }
129 }
130 }
131 }
132 };
1 /**
2 * Author: llw
3 * Date: 2022.9.14
4 * Description: [行政执法案件详情]
5 */
6 import React, { useEffect } from 'react';
7 import { connect } from 'umi';
8 import { Drawer } from 'antd';
9 import { StyledText } from '@/components/style';
10 import { mapCause } from '@/constants';
11
12 const ModalEnforceMent = props => {
13 let {
14 dispatch,
15 dataModal: {
16 modalType,
17 modalShow,
18 modalData: { id },
19 },
20 enforcementInfo,
21 } = props;
22
23 useEffect(() => {
24 if (modalType === 'Enforce_Ment_Modal' && modalShow) {
25 dispatch({ type: 'Enforcement/getEventIllegalDetail', payload: { id } });
26 }
27 }, [modalType, modalShow]);
28
29 return (
30 <Drawer
31 title="详情"
32 placement="right"
33 width={900}
34 maskClosable={false}
35 onClose={() => {
36 dispatch({ type: 'Enforcement/cancelModal' });
37 }}
38 visible={modalType === 'Enforce_Ment_Modal' && modalShow}
39 footer={null}
40 >
41 <StyledText>
42 <div className="item-text">
43 <div className="title">立案单位</div>
44 <div className="desc">{enforcementInfo.company || '-'}</div>
45 </div>
46 <div className="item-text">
47 <div className="title">类型</div>
48 <div className="desc">
49 {(mapCause[enforcementInfo.type] && mapCause[enforcementInfo.type].label) || '-'}
50 </div>
51 </div>
52 <div className="item-text">
53 <div className="title">案件编号</div>
54 <div className="desc">{enforcementInfo.num || '-'}</div>
55 </div>
56 <div className="item-text">
57 <div className="title">呈批时间</div>
58 <div className="desc">{enforcementInfo.submitDate || '-'}</div>
59 </div>
60 <div className="item-text">
61 <div className="title">法定代表人及负责人</div>
62 <div className="desc">{enforcementInfo.placeUserName || '-'}</div>
63 </div>
64 <div className="item-text">
65 <div className="title">电话</div>
66 <div className="desc">{enforcementInfo.placeUserTel || '-'}</div>
67 </div>
68 <div className="item-text">
69 <div className="title">案件来源</div>
70 <div className="desc">{enforcementInfo.source || '-'}</div>
71 </div>
72 <div className="item-text">
73 <div className="title">执法人员及执法编号</div>
74 <div className="desc">{enforcementInfo.nameCode || '-'}</div>
75 </div>
76 <div className="item-text">
77 <div className="title">案由</div>
78 <div className="desc">{enforcementInfo.cause || '-'}</div>
79 </div>
80 <div className="item-text">
81 <div className="title">案发区域</div>
82 <div className="desc">{enforcementInfo.area || '-'}</div>
83 </div>
84 <div className="item-text" style={{ width: '100%' }}>
85 <div className="title">违法依据</div>
86 <div className="desc">{enforcementInfo.illegalBasis || '-'}</div>
87 </div>
88 <div className="item-text" style={{ width: '100%' }}>
89 <div className="title">处罚依据</div>
90 <div className="desc">{enforcementInfo.punishBasis || '-'}</div>
91 </div>
92 <div className="item-text" style={{ width: '100%' }}>
93 <div className="title">地址</div>
94 <div className="desc">{enforcementInfo.placeName || '-'}</div>
95 </div>
96 <div className="item-text" style={{ width: '100%' }}>
97 <div className="title">处罚内容</div>
98 <div className="desc">{enforcementInfo.contents || '-'}</div>
99 </div>
100 <div className="item-text" style={{ width: '100%' }}>
101 <div className="title">案卷相关文书</div>
102 <div className="desc">{enforcementInfo.instruments || '-'}</div>
103 </div>
104 </StyledText>
105 </Drawer>
106 );
107 };
108 export default connect(({ Enforcement }) => ({
109 ...Enforcement,
110 }))(ModalEnforceMent);
1 /**
2 * Author: llw
3 * Date: 2022.9.14
4 * Description: [基层网络详情]
5 */
6 import React, { useEffect } from 'react';
7 import { connect } from 'umi';
8 import { Drawer } from 'antd';
9 import { StyledText } from '@/components/style';
10
11 const ModalNetworkEvent = props => {
12 let {
13 dispatch,
14 dataModal: {
15 modalType,
16 modalShow,
17 modalData: { id },
18 },
19 baseGridInfo,
20 } = props;
21
22 useEffect(() => {
23 if (modalType === 'Network_Event_Modal' && modalShow) {
24 dispatch({ type: 'NetworkEvent/getBaseGridDetail', payload: { id } });
25 }
26 }, [modalType, modalShow]);
27
28 return (
29 <Drawer
30 title="详情"
31 placement="right"
32 width={600}
33 maskClosable={false}
34 onClose={() => {
35 dispatch({ type: 'NetworkEvent/cancelModal' });
36 }}
37 visible={modalType === 'Network_Event_Modal' && modalShow}
38 footer={null}
39 >
40 <StyledText>
41 <div className="item-text">
42 <div className="title">事件编号</div>
43 <div className="desc">{baseGridInfo.eventCode || '-'}</div>
44 </div>
45 <div className="item-text">
46 <div className="title">事件来源</div>
47 <div className="desc">{baseGridInfo.eventSource || '-'}</div>
48 </div>
49 <div className="item-text">
50 <div className="title">发起人</div>
51 <div className="desc">{baseGridInfo.sponsor || '-'}</div>
52 </div>
53 <div className="item-text">
54 <div className="title">发起组织</div>
55 <div className="desc">{baseGridInfo.sponsorOrg || '-'}</div>
56 </div>
57 <div className="item-text">
58 <div className="title">联系方式</div>
59 <div className="desc">{baseGridInfo.sponsorTel || '-'}</div>
60 </div>
61 <div className="item-text">
62 <div className="title">发起时间</div>
63 <div className="desc">{baseGridInfo.origTime || '-'}</div>
64 </div>
65 <div className="item-text">
66 <div className="title">处理时间</div>
67 <div className="desc">{baseGridInfo.processingTime || '-'}</div>
68 </div>
69 <div className="item-text">
70 <div className="title">截止时间</div>
71 <div className="desc">{baseGridInfo.deadTime || '-'}</div>
72 </div>
73 <div className="item-text">
74 <div className="title">事发时间</div>
75 <div className="desc">{baseGridInfo.incidentTime || '-'}</div>
76 </div>
77 <div className="item-text">
78 <div className="title">事发地址</div>
79 <div className="desc">{baseGridInfo.incidentAddress || '-'}</div>
80 </div>
81 <div className="item-text">
82 <div className="title">事发经度</div>
83 <div className="desc">{baseGridInfo.longitude || '-'}</div>
84 </div>
85 <div className="item-text">
86 <div className="title">事发维度</div>
87 <div className="desc">{baseGridInfo.latitude || '-'}</div>
88 </div>
89 <div className="item-text">
90 <div className="title">统一地址</div>
91 <div className="desc">{baseGridInfo.address || '-'}</div>
92 </div>
93 <div className="item-text">
94 <div className="title">事发区县</div>
95 <div className="desc">{baseGridInfo.county || '-'}</div>
96 </div>
97 <div className="item-text">
98 <div className="title">事发镇街</div>
99 <div className="desc">{baseGridInfo.town || '-'}</div>
100 </div>
101 <div className="item-text">
102 <div className="title">事发村社</div>
103 <div className="desc">{baseGridInfo.village || '-'}</div>
104 </div>
105 <div className="item-text">
106 <div className="title">事发网格</div>
107 <div className="desc">{baseGridInfo.grid || '-'}</div>
108 </div>
109 <div className="item-text">
110 <div className="title">事发小区</div>
111 <div className="desc">{baseGridInfo.quarters || '-'}</div>
112 </div>
113 <div className="item-text">
114 <div className="title">事项大类</div>
115 <div className="desc">{baseGridInfo.matterBig || '-'}</div>
116 </div>
117 <div className="item-text">
118 <div className="title">事项小类</div>
119 <div className="desc">{baseGridInfo.matterSmall || '-'}</div>
120 </div>
121 <div className="item-text">
122 <div className="title">事项细类</div>
123 <div className="desc">{baseGridInfo.matterFine || '-'}</div>
124 </div>
125 <div className="item-text">
126 <div className="title">事项编码</div>
127 <div className="desc">{baseGridInfo.matterCode || '-'}</div>
128 </div>
129 <div className="item-text">
130 <div className="title">事件级别</div>
131 <div className="desc">{baseGridInfo.matterLevel || '-'}</div>
132 </div>
133 <div className="item-text">
134 <div className="title">事项性质</div>
135 <div className="desc">{baseGridInfo.matterNature || '-'}</div>
136 </div>
137
138 <div className="item-text" style={{ width: '100%' }}>
139 <div className="title">事件状态</div>
140 <div className="desc">{baseGridInfo.stateName || '-'}</div>
141 </div>
142 <div className="item-text" style={{ width: '100%' }}>
143 <div className="title">事件详情</div>
144 <div className="desc">{baseGridInfo.matterDetailed || '-'}</div>
145 </div>
146 <div className="item-text" style={{ width: '100%' }}>
147 <div className="title">事件描述</div>
148 <div className="desc">{baseGridInfo.matterDescribe || '-'}</div>
149 </div>
150 </StyledText>
151 </Drawer>
152 );
153 };
154 export default connect(({ NetworkEvent }) => ({
155 ...NetworkEvent,
156 }))(ModalNetworkEvent);
1 /**
2 * Author: Charles
3 * Date: 2022.9.13
4 * Description: [投诉举报列表]
5 */
6 import React, { useEffect } from 'react';
7 import { connect } from 'umi';
8 import { Card, Form, Input, Button, Table, Tooltip, DatePicker } from 'antd';
9 import { paginations } from '@/constants';
10 import { StyledPageContainer, StyledPageContent, StyledEllipsisWrap } from '@/components/style';
11 import { ZoomInOutlined } from '@ant-design/icons';
12 import moment from 'moment';
13
14 const FormItem = Form.Item;
15 const { RangePicker } = DatePicker;
16
17 /* SearchForm */
18 const SearchForm = props => {
19 const [form] = Form.useForm();
20 const {
21 dataSearch,
22 dataSearch: { startDate, endDate },
23 handleReset,
24 handleFinish,
25 } = props;
26
27 useEffect(() => {
28 form.setFieldsValue({
29 ...dataSearch,
30 createTime: [
31 startDate ? moment(startDate) : undefined,
32 endDate ? moment(endDate) : undefined,
33 ],
34 });
35 }, [dataSearch]);
36
37 /* 点击搜索 */
38
39 const onFinish = values => {
40 handleFinish(values);
41 };
42
43 /* 点击重置 */
44 const onReset = () => {
45 handleReset();
46 };
47
48 return (
49 <Form name="Form_Complaint" layout="inline" form={form} onFinish={onFinish}>
50 <FormItem label="公司名称" name="keyWord">
51 <Input placeholder="请输入公司名称" style={{ width: '250px' }} />
52 </FormItem>
53 <FormItem label="投诉举报时间" name="createTime">
54 <RangePicker allowClear={false} style={{ width: '300px' }} />
55 </FormItem>
56 <FormItem>
57 <Button type="primary" htmlType="submit" className="mr-15">
58 搜索
59 </Button>
60 <Button className="mr-15" htmlType="button" onClick={onReset}>
61 重置
62 </Button>
63 </FormItem>
64 </Form>
65 );
66 };
67
68 /* DataTable */
69 const DataTable = props => {
70 const {
71 loading,
72 handleGetList,
73 dataComplaint: { records = [], current, size, total },
74 } = props;
75
76 /* 点击分页 */
77 const handlePageChange = (current, size) => {
78 handleGetList(current, size);
79 };
80
81 const columns = [
82 {
83 title: '序号',
84 dataIndex: 'id',
85 align: 'center',
86 fixed: 'left',
87 width: 80,
88 render(t, r, idx) {
89 return (current - 1) * size + idx + 1;
90 },
91 },
92 {
93 title: '公司名称',
94 dataIndex: 'name',
95 align: 'center',
96 width: 200,
97 render: (t, r) => {
98 return t ? (
99 <Tooltip placement="top" title={t}>
100 <StyledEllipsisWrap maxLine={1}>{t}</StyledEllipsisWrap>
101 </Tooltip>
102 ) : (
103 '-'
104 );
105 },
106 },
107 {
108 title: '公司地址',
109 dataIndex: 'address',
110 align: 'center',
111 width: 220,
112 render: (t, r) => {
113 return t ? (
114 <Tooltip placement="top" title={t}>
115 <StyledEllipsisWrap maxLine={2}>{t}</StyledEllipsisWrap>
116 </Tooltip>
117 ) : (
118 '-'
119 );
120 },
121 },
122 {
123 title: '通讯地址',
124 dataIndex: 'postalAddress',
125 align: 'center',
126 width: 220,
127 render: (t, r) => {
128 return t ? (
129 <Tooltip placement="top" title={t}>
130 <StyledEllipsisWrap maxLine={2}>{t}</StyledEllipsisWrap>
131 </Tooltip>
132 ) : (
133 '-'
134 );
135 },
136 },
137 {
138 title: '所属地区',
139 dataIndex: 'region',
140 align: 'center',
141 width: 160,
142 render: (t, r) => {
143 return t ? (
144 <Tooltip placement="top" title={t}>
145 <StyledEllipsisWrap maxLine={2}>{t}</StyledEllipsisWrap>
146 </Tooltip>
147 ) : (
148 '-'
149 );
150 },
151 },
152 {
153 title: '负责人',
154 dataIndex: 'person',
155 align: 'center',
156 width: 150,
157 },
158 {
159 title: '身份证号码',
160 dataIndex: 'personCode',
161 align: 'center',
162 width: 220,
163 },
164 {
165 title: '负责人电话',
166 dataIndex: 'personTel',
167 align: 'center',
168 width: 150,
169 },
170 {
171 title: '联系人',
172 dataIndex: 'contacts',
173 align: 'center',
174 width: 150,
175 },
176 {
177 title: '联系人电话',
178 dataIndex: 'contactsTel',
179 align: 'center',
180 width: 180,
181 },
182 {
183 title: '主营范围',
184 dataIndex: 'mainScope',
185 align: 'center',
186 width: 180,
187 render: (t, r) => {
188 return t ? (
189 <Tooltip placement="top" title={t}>
190 <StyledEllipsisWrap maxLine={2}>{t}</StyledEllipsisWrap>
191 </Tooltip>
192 ) : (
193 '-'
194 );
195 },
196 },
197 {
198 title: '备注',
199 dataIndex: 'remarks',
200 align: 'center',
201 width: 200,
202 render: (t, r) => {
203 return t ? (
204 <Tooltip placement="top" title={t}>
205 <StyledEllipsisWrap maxLine={2}>{t}</StyledEllipsisWrap>
206 </Tooltip>
207 ) : (
208 '-'
209 );
210 },
211 },
212 // {
213 // title: '操作',
214 // align: 'center',
215 // fixed: 'right',
216 // width: 80,
217 // render(t, r) {
218 // return (
219 // <Tooltip placement="top" title="查看详情">
220 // <ZoomInOutlined style={{ cursor: 'pointer', fontSize: 18 }} onClick={() => {}} />
221 // </Tooltip>
222 // );
223 // },
224 // },
225 ];
226 const pagination = {
227 ...paginations,
228 total: total,
229 pageSize: size,
230 current,
231 showSizeChanger: total > 10,
232 onChange: (current, pageSize) => {
233 handlePageChange(current, pageSize);
234 },
235 onShowSizeChange: (current, pageSize) => {
236 handlePageChange(1, pageSize);
237 },
238 showTotal(total) {
239 return `总共 ${total} 条数据`;
240 },
241 };
242 return (
243 <Table
244 rowKey="id"
245 loading={loading}
246 dataSource={records}
247 columns={columns}
248 pagination={pagination}
249 scroll={{ x: 2000, y: `calc(100vh - 350px)` }}
250 />
251 );
252 };
253
254 /* Main */
255 const Complaint = props => {
256 const {
257 dispatch,
258 loading,
259 dataSearch,
260 dataComplaint,
261 dataComplaint: { size },
262 } = props;
263
264 useEffect(() => {
265 handleGetList(1, 10);
266 }, []);
267
268 /* 列表 */
269 const handleGetList = (current, size) => {
270 dispatch({
271 type: 'Complaint/getComplaintList',
272 payload: {
273 current: current || 1,
274 size: size || 10,
275 },
276 });
277 };
278
279 /* 点击搜索 */
280 const handleFinish = values => {
281 const { keyWord, createTime } = values;
282 dispatch({
283 type: 'Complaint/changeState',
284 payload: {
285 dataSearch: {
286 keyWord,
287 startDate: createTime[0]
288 ? moment(createTime[0].startOf('day').valueOf()).format('YYYY-MM-DD HH:mm:ss')
289 : undefined,
290 endDate: createTime[1]
291 ? moment(createTime[1].endOf('day').valueOf()).format('YYYY-MM-DD HH:mm:ss')
292 : undefined,
293 },
294 },
295 });
296 handleGetList(0, size);
297 };
298
299 /* 点击重置 */
300 const handleReset = () => {
301 dispatch({ type: 'Complaint/resetSearch' });
302 handleGetList(0, 10);
303 };
304
305 return (
306 <StyledPageContainer>
307 <StyledPageContent>
308 <Card bordered={false}>
309 <SearchForm
310 dataSearch={dataSearch}
311 handleReset={handleReset}
312 handleFinish={handleFinish}
313 />
314 <div className="mt-16">
315 <DataTable
316 loading={loading}
317 handleGetList={handleGetList}
318 dataComplaint={dataComplaint}
319 />
320 </div>
321 </Card>
322 </StyledPageContent>
323 </StyledPageContainer>
324 );
325 };
326
327 export default connect(({ Complaint, loading }) => ({
328 ...Complaint,
329 loading: loading.effects['Complaint/getComplaintList'],
330 }))(Complaint);
1 /**
2 * Author: Charles
3 * Date: 2022.9.13
4 * Description: [行政执法列表]
5 */
6 import React, { useEffect } from 'react';
7 import { connect } from 'umi';
8 import { Card, Form, Input, Button, Table, Tooltip, Upload, message, Select } from 'antd';
9 import { paginations } from '@/constants';
10 import {
11 StyledPageContainer,
12 StyledPageContent,
13 StyledEllipsisWrap,
14 StyledPageHeader,
15 } from '@/components/style';
16 import { ZoomInOutlined, UploadOutlined } from '@ant-design/icons';
17 import * as services from '@/services/data';
18 import { ExportFile } from '@/utils/utils';
19 import { mapCause, enumYear } from '@/constants';
20 import ModalEnforcement from './Modal/ModalEnforcement';
21
22 const FormItem = Form.Item;
23 const Option = Select.Option;
24
25 /* SearchForm */
26 const SearchForm = props => {
27 const [form] = Form.useForm();
28 const { dataSearch, handleReset, handleFinish } = props;
29
30 useEffect(() => {
31 form.setFieldsValue({
32 ...dataSearch,
33 });
34 }, [dataSearch]);
35
36 /* 点击搜索 */
37
38 const onFinish = values => {
39 handleFinish(values);
40 };
41
42 /* 点击重置 */
43 const onReset = () => {
44 handleReset();
45 };
46
47 return (
48 <Form name="Form_Enforcement" layout="inline" form={form} onFinish={onFinish}>
49 <FormItem label="当事人或法人姓名" name="placeName">
50 <Input placeholder="请输入当事人或法人姓名" style={{ width: '220px' }} />
51 </FormItem>
52 <FormItem label="办案单位" name="company">
53 <Input placeholder="请输入办案单位" style={{ width: '220px' }} />
54 </FormItem>
55 <FormItem label="案件类型" name="type">
56 <Select placeholder="请选择案件类型" style={{ width: '150px' }}>
57 <Option value="ALL">全部</Option>
58 {Object.values(mapCause).map(item => {
59 return (
60 <Option key={item.value} value={item.value}>
61 {item.label}
62 </Option>
63 );
64 })}
65 </Select>
66 </FormItem>
67 <FormItem label="处罚年份" name="yearDate">
68 <Select placeholder="请选择处罚年份" style={{ width: '150px' }} showSearch>
69 <Option value="ALL">全部</Option>
70 {enumYear().map(item => {
71 return (
72 <Option key={item.value} value={item.value}>
73 {item.label}
74 </Option>
75 );
76 })}
77 </Select>
78 </FormItem>
79 <FormItem>
80 <Button type="primary" htmlType="submit" className="mr-15">
81 搜索
82 </Button>
83 <Button className="mr-15" htmlType="button" onClick={onReset}>
84 重置
85 </Button>
86 </FormItem>
87 </Form>
88 );
89 };
90
91 /* DataTable */
92 const DataTable = props => {
93 const {
94 dispatch,
95 loading,
96 handleGetList,
97 dataEnforcement: { records = [], current, size, total },
98 } = props;
99
100 /* 点击分页 */
101 const handlePageChange = (current, size) => {
102 handleGetList(current, size);
103 };
104
105 const columns = [
106 {
107 title: '序号',
108 dataIndex: 'id',
109 align: 'center',
110 fixed: 'left',
111 width: 80,
112 render(t, r, idx) {
113 return (current - 1) * size + idx + 1;
114 },
115 },
116 {
117 title: '统一编号',
118 dataIndex: 'num',
119 align: 'center',
120 width: 200,
121 },
122 {
123 title: '案件类型',
124 dataIndex: 'type',
125 align: 'center',
126 width: 120,
127 render: (t, r) => {
128 return (mapCause[t] && mapCause[t].label) || '-';
129 },
130 },
131 {
132 title: '当事人',
133 dataIndex: 'placeUserName',
134 align: 'center',
135 width: 160,
136 render: (t, r) => {
137 return t ? (
138 <Tooltip placement="top" title={t}>
139 <StyledEllipsisWrap maxLine={1}>{t}</StyledEllipsisWrap>
140 </Tooltip>
141 ) : (
142 '-'
143 );
144 },
145 },
146 {
147 title: '案由',
148 dataIndex: 'cause',
149 align: 'center',
150 width: 220,
151 render: (t, r) => {
152 return t ? (
153 <Tooltip placement="top" title={t}>
154 <StyledEllipsisWrap maxLine={2}>{t}</StyledEllipsisWrap>
155 </Tooltip>
156 ) : (
157 '-'
158 );
159 },
160 },
161 {
162 title: '办案单位',
163 dataIndex: 'company',
164 align: 'center',
165 width: 160,
166 render: (t, r) => {
167 return t ? (
168 <Tooltip placement="top" title={t}>
169 <StyledEllipsisWrap maxLine={1}>{t}</StyledEllipsisWrap>
170 </Tooltip>
171 ) : (
172 '-'
173 );
174 },
175 },
176 {
177 title: '立案时间',
178 dataIndex: 'filingDate',
179 align: 'center',
180 width: 160,
181 render: (t, r) => {
182 return t || '-';
183 },
184 },
185 {
186 title: '处罚时间',
187 dataIndex: 'punishDate',
188 align: 'center',
189 width: 160,
190 render: (t, r) => {
191 return t || '-';
192 },
193 },
194 {
195 title: '结案时间',
196 dataIndex: 'closeDate',
197 align: 'center',
198 width: 160,
199 render: (t, r) => {
200 return t || '-';
201 },
202 },
203 {
204 title: '操作',
205 align: 'center',
206 fixed: 'right',
207 width: 80,
208 render(t, r) {
209 return (
210 <Tooltip placement="top" title="查看详情">
211 <ZoomInOutlined
212 style={{ cursor: 'pointer', fontSize: 18 }}
213 onClick={() => {
214 dispatch({
215 type: 'Enforcement/changeState',
216 payload: {
217 dataModal: {
218 modalType: 'Enforce_Ment_Modal',
219 modalShow: true,
220 modalData: r,
221 },
222 },
223 });
224 }}
225 />
226 </Tooltip>
227 );
228 },
229 },
230 ];
231 const pagination = {
232 ...paginations,
233 total: total,
234 pageSize: size,
235 current,
236 showSizeChanger: total > 10,
237 onChange: (current, pageSize) => {
238 handlePageChange(current, pageSize);
239 },
240 onShowSizeChange: (current, pageSize) => {
241 handlePageChange(1, pageSize);
242 },
243 showTotal(total) {
244 return `总共 ${total} 条数据`;
245 },
246 };
247 return (
248 <Table
249 rowKey="id"
250 loading={loading}
251 dataSource={records}
252 columns={columns}
253 pagination={pagination}
254 scroll={{ x: 2000, y: `calc(100vh - 448px)` }}
255 />
256 );
257 };
258
259 /* Main */
260 const Enforcement = props => {
261 const {
262 dispatch,
263 loading,
264 loadingUpload,
265 dataSearch,
266 dataEnforcement,
267 dataEnforcement: { size },
268 } = props;
269
270 useEffect(() => {
271 handleGetList(1, 10);
272 }, []);
273
274 /* 列表 */
275 const handleGetList = (current, size) => {
276 dispatch({
277 type: 'Enforcement/getEnforcementList',
278 payload: {
279 current: current || 1,
280 size: size || 10,
281 },
282 });
283 };
284
285 /* 点击搜索 */
286 const handleFinish = values => {
287 dispatch({
288 type: 'Enforcement/changeState',
289 payload: {
290 dataSearch: {
291 ...values,
292 },
293 },
294 });
295 handleGetList(0, size);
296 };
297
298 /* 点击重置 */
299 const handleReset = () => {
300 dispatch({ type: 'Enforcement/resetSearch' });
301 handleGetList(0, 10);
302 };
303
304 /* 上传组件配置 */
305 const uploadProps = {
306 customRequest: file => {
307 const formData = new FormData();
308 formData.append('file', file.file);
309 dispatch({ type: 'Enforcement/importEventIllegal', payload: formData });
310 },
311 beforeUpload: file => {
312 const isLt50M = file.size / 1024 / 1024 < 50;
313 if (!isLt50M) {
314 message.error('文件大小需小于50M');
315 return false;
316 }
317 return isLt50M;
318 },
319 };
320
321 return (
322 <StyledPageContainer>
323 <StyledPageHeader border={true}>
324 <Upload {...uploadProps}>
325 <Button loading={loadingUpload} type="primary" icon={<UploadOutlined />}>
326 数据导入
327 </Button>
328 </Upload>
329 <Button
330 type="primary"
331 onClick={() => {
332 ExportFile('行政执法案件模版', services.exportEventIllegalTemplate, {});
333 }}
334 >
335 模版下载
336 </Button>
337 </StyledPageHeader>
338 <StyledPageContent>
339 <Card bordered={false}>
340 <SearchForm
341 dataSearch={dataSearch}
342 handleReset={handleReset}
343 handleFinish={handleFinish}
344 />
345 <div className="mt-16">
346 <DataTable
347 loading={loading}
348 dispatch={dispatch}
349 handleGetList={handleGetList}
350 dataEnforcement={dataEnforcement}
351 />
352 </div>
353 </Card>
354 </StyledPageContent>
355 <ModalEnforcement />
356 </StyledPageContainer>
357 );
358 };
359
360 export default connect(({ Enforcement, loading }) => ({
361 ...Enforcement,
362 loading: loading.effects['Enforcement/getEnforcementList'],
363 loadingUpload: loading.effects['Enforcement/importEventIllegal'],
364 }))(Enforcement);
1 import { Tabs } from 'antd';
2 import React, { useState } from 'react';
3 import Place from './place';
4 import Complaint from './complaint';
5 import Enforcement from './enforcement';
6 import NetworkEvent from './networkEvent';
7 import { StyledWapperTab } from '@/components/style';
8
9 const Data = () => {
10 const [activeKey, setActiveKey] = useState('1');
11 const [dataTab, setDataTab] = useState(() => {
12 return [
13 { label: '行政执法案件', value: '1' },
14 { label: '基层网络事件', value: '2' },
15 { label: '场所/网站备案信息', value: '3' },
16 { label: '投诉举报事件', value: '4' },
17 ];
18 });
19 return (
20 <StyledWapperTab>
21 <Tabs
22 defaultActiveKey={activeKey}
23 onChange={key => {
24 setActiveKey(key);
25 }}
26 >
27 {dataTab.map(item => {
28 return <Tabs.TabPane tab={item.label} key={item.value}></Tabs.TabPane>;
29 })}
30 </Tabs>
31 {activeKey === '1' ? <Enforcement /> : null}
32 {activeKey === '2' ? <NetworkEvent /> : null}
33 {activeKey === '3' ? <Place /> : null}
34 {activeKey === '4' ? <Complaint /> : null}
35 </StyledWapperTab>
36 );
37 };
38
39 export default Data;
1 import * as services from '@/services/data';
2 import moment from 'moment';
3
4 /* SerachParams */
5 const staticSearch = {
6 current: 1,
7 size: 10,
8 keyWord: undefined,
9 startDate: moment(new Date())
10 .add(-7, 'days')
11 .startOf('day'),
12 endDate: moment(new Date())
13 .add(0, 'days')
14 .endOf('day'),
15 };
16
17 export default {
18 namespace: 'Complaint',
19 state: {
20 dataSearch: {
21 ...staticSearch,
22 },
23 dataComplaint: {
24 records: [],
25 current: 1,
26 size: 10,
27 total: 0,
28 totalPage: 0,
29 },
30 },
31 effects: {
32 /* 获取投诉举报列表 */
33 *getComplaintList({ payload }, { call, put, select }) {
34 const {
35 dataSearch,
36 dataSearch: { startDate, endDate },
37 } = yield select(state => state.Complaint);
38 try {
39 const res = yield call(services.getComplaintList, {
40 current: 1,
41 size: 10,
42 ...dataSearch,
43 ...payload,
44 startDate: moment(startDate).format('YYYY-MM-DD HH:mm:ss'),
45 endDate: moment(endDate).format('YYYY-MM-DD HH:mm:ss'),
46 });
47 if (res.code === 0) {
48 res.data.records =
49 res.data.records.map(item => {
50 return {
51 ...(item.placeVo || {}),
52 ...item,
53 };
54 }) || [];
55 yield put({
56 type: 'changeState',
57 payload: {
58 dataComplaint: res.data,
59 },
60 });
61 }
62 } catch (err) {
63 console.error(err);
64 }
65 },
66 },
67 reducers: {
68 changeState(state, { payload }) {
69 return {
70 ...state,
71 ...payload,
72 };
73 },
74 resetSearch(state, { payload }) {
75 return {
76 ...state,
77 dataSearch: {
78 ...staticSearch,
79 },
80 };
81 },
82 },
83 };
1 import * as services from '@/services/data';
2 import { message } from 'antd';
3 import moment from 'moment';
4
5 /* SerachParams */
6 const staticSearch = {
7 current: 1,
8 size: 10,
9 placeName: undefined,
10 company: undefined,
11 type: 'ALL',
12 yearDate: 'ALL',
13 };
14
15 export default {
16 namespace: 'Enforcement',
17 state: {
18 dataSearch: {
19 ...staticSearch,
20 },
21 dataEnforcement: {
22 records: [],
23 current: 1,
24 size: 10,
25 total: 0,
26 totalPage: 0,
27 },
28 dataModal: {
29 modalType: '',
30 modalShow: false,
31 modalData: {},
32 },
33 enforcementInfo: {},
34 },
35 effects: {
36 /* 获取行政执法列表 */
37 *getEnforcementList({ payload }, { call, put, select }) {
38 const {
39 dataSearch,
40 dataSearch: { type, yearDate },
41 } = yield select(state => state.Enforcement);
42 try {
43 const res = yield call(services.getEventIllegalList, {
44 current: 1,
45 size: 10,
46 ...dataSearch,
47 ...payload,
48 type: type === 'ALL' ? '' : type,
49 yearDate: yearDate === 'ALL' ? '' : yearDate,
50 });
51 if (res.code === 0) {
52 res.data.records =
53 res.data.records.map(item => {
54 return {
55 ...(item.placeVo || {}),
56 ...item,
57 };
58 }) || [];
59 yield put({
60 type: 'changeState',
61 payload: {
62 dataEnforcement: res.data,
63 },
64 });
65 }
66 } catch (err) {
67 console.error(err);
68 }
69 },
70 /* 行政执法案件导入 */
71 *importEventIllegal({ payload }, { call, put, select }) {
72 try {
73 const res = yield call(services.importEventIllegal, payload);
74 if (res.code === 0) {
75 message.success('导入成功');
76 yield put({ type: 'getEnforcementList' });
77 }
78 } catch (err) {
79 console.error(err);
80 }
81 },
82 /* 获取详情 */
83 *getEventIllegalDetail({ payload }, { call, put, select }) {
84 try {
85 const res = yield call(services.getEventIllegalDetail, payload);
86 if (res.code === 0) {
87 yield put({ type: 'changeState', payload: { enforcementInfo: res.data } });
88 }
89 } catch (err) {
90 console.error(err);
91 }
92 },
93 },
94 reducers: {
95 changeState(state, { payload }) {
96 return {
97 ...state,
98 ...payload,
99 };
100 },
101 cancelModal(state, { payload }) {
102 return {
103 ...state,
104 dataModal: {
105 modalType: '',
106 modalShow: false,
107 modalData: {},
108 },
109 };
110 },
111 resetSearch(state, { payload }) {
112 return {
113 ...state,
114 dataSearch: {
115 ...staticSearch,
116 },
117 };
118 },
119 },
120 };
1 import * as services from '@/services/data';
2 import moment from 'moment';
3
4 /* SerachParams */
5 const staticSearch = {
6 current: 1,
7 size: 10,
8 eventCode: undefined,
9 keyWord: undefined,
10 region: 'ALL',
11 sponsor: 'ALL',
12 handledBy: 'ALL',
13 sponsorOrg: 'ALL',
14 matterBig: 'ALL',
15 eventSource: 'ALL',
16 state: 'ALL',
17 startDate: moment(new Date())
18 .add(-7, 'days')
19 .startOf('day'),
20 endDate: moment(new Date())
21 .add(0, 'days')
22 .endOf('day'),
23 };
24
25 export default {
26 namespace: 'NetworkEvent',
27 state: {
28 dataSearch: {
29 ...staticSearch,
30 },
31 dataNetworkEvent: {
32 records: [],
33 current: 1,
34 size: 10,
35 total: 0,
36 totalPage: 0,
37 },
38 dataModal: {
39 modalType: '',
40 modalShow: false,
41 modalData: {},
42 },
43 baseGridInfo: {}, // 基层网格详情
44 eventSourceList: [], // 事件源
45 matterBigList: [], // 事件类型
46 handledByList: [], // 处理人
47 sponsorList: [], // 发起人
48 sponsorOrgList: [], // 发起组织
49 },
50 effects: {
51 /* 获取基层网络列表 */
52 *getNetworkEventList({ payload }, { call, put, select }) {
53 const {
54 dataSearch,
55 dataSearch: {
56 region,
57 sponsor,
58 handledBy,
59 sponsorOrg,
60 matterBig,
61 eventSource,
62 state,
63 startDate,
64 endDate,
65 },
66 } = yield select(state => state.NetworkEvent);
67 try {
68 const res = yield call(services.getNetworkEventList, {
69 current: 1,
70 size: 10,
71 ...dataSearch,
72 ...payload,
73 startDate: moment(startDate).format('YYYY-MM-DD HH:mm:ss'),
74 endDate: moment(endDate).format('YYYY-MM-DD HH:mm:ss'),
75 region: region === 'ALL' ? '' : region,
76 sponsor: sponsor === 'ALL' ? '' : sponsor,
77 handledBy: handledBy === 'ALL' ? '' : handledBy,
78 sponsorOrg: sponsorOrg === 'ALL' ? '' : sponsorOrg,
79 matterBig: matterBig === 'ALL' ? '' : matterBig,
80 eventSource: eventSource === 'ALL' ? '' : eventSource,
81 state: state === 'ALL' ? '' : state,
82 });
83 if (res.code === 0) {
84 res.data.records =
85 res.data.records.map(item => {
86 return {
87 ...(item.placeVo || {}),
88 ...item,
89 };
90 }) || [];
91 yield put({
92 type: 'changeState',
93 payload: {
94 dataNetworkEvent: res.data,
95 },
96 });
97 }
98 } catch (err) {
99 console.error(err);
100 }
101 },
102 /* 获取搜索条件 */
103 *getBaseGridSponsor({ payload }, { call, put, select }) {
104 try {
105 const res = yield call(services.getBaseGridSponsor);
106 if (res.code === 0) {
107 res.data = res.data || {};
108 yield put({
109 type: 'changeState',
110 payload: {
111 eventSourceList: res.data.eventSourceList || [],
112 handledByList: res.data.handledByList || [],
113 sponsorList: res.data.sponsorList || [],
114 sponsorOrgList: res.data.sponsorOrgList || [],
115 matterBigList: res.data.matterBigList || [],
116 },
117 });
118 }
119 } catch (err) {
120 console.error(err);
121 }
122 },
123 /* 获取详情 */
124 *getBaseGridDetail({ payload }, { call, put, select }) {
125 try {
126 const res = yield call(services.getBaseGridDetail, payload);
127 if (res.code === 0) {
128 yield put({
129 type: 'changeState',
130 payload: { baseGridInfo: res.data || {} },
131 });
132 }
133 } catch (err) {
134 console.error(err);
135 }
136 },
137 },
138 reducers: {
139 changeState(state, { payload }) {
140 return {
141 ...state,
142 ...payload,
143 };
144 },
145 cancelModal(state, { payload }) {
146 return {
147 ...state,
148 dataModal: {
149 modalType: '',
150 modalShow: false,
151 modalData: {},
152 },
153 };
154 },
155 resetSearch(state, { payload }) {
156 return {
157 ...state,
158 dataSearch: {
159 ...staticSearch,
160 },
161 };
162 },
163 },
164 };
1 import * as services from '@/services/data';
2 import { message } from 'antd';
3
4 /* SerachParams */
5 const staticSearch = {
6 current: 1,
7 size: 10,
8 name: undefined,
9 };
10
11 export default {
12 namespace: 'Place',
13 state: {
14 dataSearch: {
15 ...staticSearch,
16 },
17 dataPlace: {
18 records: [],
19 current: 1,
20 size: 10,
21 total: 0,
22 totalPage: 0,
23 },
24 },
25 effects: {
26 /* 获取场所列表 */
27 *getPlaceList({ payload }, { call, put, select }) {
28 const { dataSearch } = yield select(state => state.Place);
29 try {
30 const res = yield call(services.getPlaceList, {
31 current: 1,
32 size: 10,
33 ...dataSearch,
34 ...payload,
35 });
36 if (res.code === 0) {
37 res.data.records = res.data.records || [];
38 yield put({
39 type: 'changeState',
40 payload: {
41 dataPlace: res.data,
42 },
43 });
44 }
45 } catch (err) {
46 console.error(err);
47 }
48 },
49 /* 场所导入 */
50 *importPlace({ payload }, { call, put, select }) {
51 try {
52 const res = yield call(services.importPlace, payload);
53 if (res.code === 0) {
54 message.success('导入成功');
55 yield put({ type: 'getPlaceList' });
56 }
57 } catch (err) {
58 console.error(err);
59 }
60 },
61 },
62 reducers: {
63 changeState(state, { payload }) {
64 return {
65 ...state,
66 ...payload,
67 };
68 },
69 resetSearch(state, { payload }) {
70 return {
71 ...state,
72 dataSearch: {
73 ...staticSearch,
74 },
75 };
76 },
77 },
78 };
1 /**
2 * Author: Charles
3 * Date: 2022.9.13
4 * Description: [场所列表]
5 */
6 import React, { useEffect } from 'react';
7 import { connect } from 'umi';
8 import { Card, Form, Input, Button, Table, Tooltip, Upload, message } from 'antd';
9 import { paginations } from '@/constants';
10 import {
11 StyledPageContainer,
12 StyledPageContent,
13 StyledEllipsisWrap,
14 StyledPageHeader,
15 } from '@/components/style';
16 import { ZoomInOutlined, UploadOutlined } from '@ant-design/icons';
17 import * as services from '@/services/data';
18 import { ExportFile } from '@/utils/utils';
19
20 const FormItem = Form.Item;
21
22 /* SearchForm */
23 const SearchForm = props => {
24 const [form] = Form.useForm();
25 const { dataSearch, handleReset, handleFinish } = props;
26
27 useEffect(() => {
28 form.setFieldsValue({
29 ...dataSearch,
30 });
31 }, [dataSearch]);
32
33 /* 点击搜索 */
34
35 const onFinish = values => {
36 handleFinish(values);
37 };
38
39 /* 点击重置 */
40 const onReset = () => {
41 handleReset();
42 };
43
44 return (
45 <Form name="Form_Place" layout="inline" form={form} onFinish={onFinish}>
46 <FormItem label="公司名称" name="name">
47 <Input placeholder="请输入公司名称" style={{ width: '250px' }} />
48 </FormItem>
49 <FormItem>
50 <Button type="primary" htmlType="submit" className="mr-15">
51 搜索
52 </Button>
53 <Button className="mr-15" htmlType="button" onClick={onReset}>
54 重置
55 </Button>
56 </FormItem>
57 </Form>
58 );
59 };
60
61 /* DataTable */
62 const DataTable = props => {
63 const {
64 loading,
65 handleGetList,
66 dataPlace: { records = [], current, size, total },
67 } = props;
68
69 /* 点击分页 */
70 const handlePageChange = (current, size) => {
71 handleGetList(current, size);
72 };
73
74 const columns = [
75 {
76 title: '序号',
77 dataIndex: 'id',
78 align: 'center',
79 fixed: 'left',
80 width: 80,
81 render(t, r, idx) {
82 return (current - 1) * size + idx + 1;
83 },
84 },
85 {
86 title: '公司名称',
87 dataIndex: 'name',
88 align: 'center',
89 width: 200,
90 render: (t, r) => {
91 return t ? (
92 <Tooltip placement="top" title={t}>
93 <StyledEllipsisWrap maxLine={1}>{t}</StyledEllipsisWrap>
94 </Tooltip>
95 ) : (
96 '-'
97 );
98 },
99 },
100 {
101 title: '公司地址',
102 dataIndex: 'address',
103 align: 'center',
104 width: 220,
105 render: (t, r) => {
106 return t ? (
107 <Tooltip placement="top" title={t}>
108 <StyledEllipsisWrap maxLine={2}>{t}</StyledEllipsisWrap>
109 </Tooltip>
110 ) : (
111 '-'
112 );
113 },
114 },
115 {
116 title: '通讯地址',
117 dataIndex: 'postalAddress',
118 align: 'center',
119 width: 220,
120 render: (t, r) => {
121 return t ? (
122 <Tooltip placement="top" title={t}>
123 <StyledEllipsisWrap maxLine={2}>{t}</StyledEllipsisWrap>
124 </Tooltip>
125 ) : (
126 '-'
127 );
128 },
129 },
130 {
131 title: '所属地区',
132 dataIndex: 'region',
133 align: 'center',
134 width: 160,
135 render: (t, r) => {
136 return t ? (
137 <Tooltip placement="top" title={t}>
138 <StyledEllipsisWrap maxLine={2}>{t}</StyledEllipsisWrap>
139 </Tooltip>
140 ) : (
141 '-'
142 );
143 },
144 },
145 {
146 title: '负责人',
147 dataIndex: 'person',
148 align: 'center',
149 width: 150,
150 },
151 {
152 title: '身份证号码',
153 dataIndex: 'personCode',
154 align: 'center',
155 width: 220,
156 },
157 {
158 title: '负责人电话',
159 dataIndex: 'personTel',
160 align: 'center',
161 width: 150,
162 },
163 {
164 title: '联系人',
165 dataIndex: 'contacts',
166 align: 'center',
167 width: 150,
168 },
169 {
170 title: '联系人电话',
171 dataIndex: 'contactsTel',
172 align: 'center',
173 width: 180,
174 },
175 {
176 title: '主营范围',
177 dataIndex: 'mainScope',
178 align: 'center',
179 width: 180,
180 render: (t, r) => {
181 return t ? (
182 <Tooltip placement="top" title={t}>
183 <StyledEllipsisWrap maxLine={2}>{t}</StyledEllipsisWrap>
184 </Tooltip>
185 ) : (
186 '-'
187 );
188 },
189 },
190 {
191 title: '备注',
192 dataIndex: 'remarks',
193 align: 'center',
194 width: 200,
195 render: (t, r) => {
196 return t ? (
197 <Tooltip placement="top" title={t}>
198 <StyledEllipsisWrap maxLine={2}>{t}</StyledEllipsisWrap>
199 </Tooltip>
200 ) : (
201 '-'
202 );
203 },
204 },
205 // {
206 // title: '操作',
207 // align: 'center',
208 // fixed: 'right',
209 // width: 80,
210 // render(t, r) {
211 // return (
212 // <Tooltip placement="top" title="查看详情">
213 // <ZoomInOutlined style={{ cursor: 'pointer', fontSize: 18 }} onClick={() => {}} />
214 // </Tooltip>
215 // );
216 // },
217 // },
218 ];
219 const pagination = {
220 ...paginations,
221 total: total,
222 pageSize: size,
223 current,
224 showSizeChanger: total > 10,
225 onChange: (current, pageSize) => {
226 handlePageChange(current, pageSize);
227 },
228 onShowSizeChange: (current, pageSize) => {
229 handlePageChange(1, pageSize);
230 },
231 showTotal(total) {
232 return `总共 ${total} 条数据`;
233 },
234 };
235 return (
236 <Table
237 rowKey="id"
238 loading={loading}
239 dataSource={records}
240 columns={columns}
241 pagination={pagination}
242 scroll={{ x: 2000, y: `calc(100vh - 400px)` }}
243 />
244 );
245 };
246
247 /* Main */
248 const Place = props => {
249 const {
250 dispatch,
251 loading,
252 loadingUpload,
253 dataSearch,
254 dataPlace,
255 dataPlace: { size },
256 } = props;
257
258 useEffect(() => {
259 handleGetList(1, 10);
260 }, []);
261
262 /* 列表 */
263 const handleGetList = (current, size) => {
264 dispatch({
265 type: 'Place/getPlaceList',
266 payload: {
267 current: current || 1,
268 size: size || 10,
269 },
270 });
271 };
272
273 /* 点击搜索 */
274 const handleFinish = values => {
275 const { name } = values;
276 dispatch({
277 type: 'Place/changeState',
278 payload: {
279 dataSearch: { name },
280 },
281 });
282 handleGetList(0, size);
283 };
284
285 /* 点击重置 */
286 const handleReset = () => {
287 dispatch({ type: 'Place/resetSearch' });
288 handleGetList(0, 10);
289 };
290
291 /* 上传组件配置 */
292 const uploadProps = {
293 customRequest: file => {
294 const formData = new FormData();
295 formData.append('file', file.file);
296 dispatch({ type: 'Place/importPlace', payload: formData });
297 },
298 beforeUpload: file => {
299 const isLt50M = file.size / 1024 / 1024 < 50;
300 if (!isLt50M) {
301 message.error('文件大小需小于50M');
302 return false;
303 }
304 return isLt50M;
305 },
306 };
307
308 return (
309 <StyledPageContainer>
310 <StyledPageHeader border={true}>
311 <Upload {...uploadProps}>
312 <Button loading={loadingUpload} type="primary" icon={<UploadOutlined />}>
313 数据导入
314 </Button>
315 </Upload>
316 <Button
317 type="primary"
318 onClick={() => {
319 ExportFile('场所/网站备案信息模版', services.exportPlaceTemplate, {});
320 }}
321 >
322 模版下载
323 </Button>
324 </StyledPageHeader>
325 <StyledPageContent>
326 <Card bordered={false}>
327 <SearchForm
328 dataSearch={dataSearch}
329 handleReset={handleReset}
330 handleFinish={handleFinish}
331 />
332 <div className="mt-16">
333 <DataTable loading={loading} handleGetList={handleGetList} dataPlace={dataPlace} />
334 </div>
335 </Card>
336 </StyledPageContent>
337 </StyledPageContainer>
338 );
339 };
340
341 export default connect(({ Place, loading }) => ({
342 ...Place,
343 loading: loading.effects['Place/getPlaceList'],
344 loadingUpload: loading.effects['Place/importPlace'],
345 }))(Place);
1 /**
2 * Author: Charles
3 * Date: 2022.9.13
4 * Description: [事件风险详情]
5 */
6 import React, { useEffect } from 'react';
7 import { connect } from 'umi';
8 import { Modal, Tooltip, Table } from 'antd';
9 import { paginations, mapStatus, mapRiskType, mapRiskSourceType } from '@/constants';
10 import { StyledEllipsisWrap } from '@/components/style';
11
12 const ModalEventInfo = props => {
13 const {
14 dispatch,
15 loading,
16 dataModal: {
17 modalType,
18 modalShow,
19 modalData: { id },
20 },
21 dataEventRiskList,
22 } = props;
23
24 useEffect(() => {
25 if (modalType === 'EVENT_INFO_MODAL' && modalShow) {
26 dispatch({ type: 'Event/getEventRiskList', payload: { eventId: id } });
27 }
28 }, [modalType, modalShow]);
29
30 const columns = [
31 {
32 title: '序号',
33 dataIndex: 'id',
34 align: 'center',
35 fixed: 'left',
36 width: 80,
37 render(t, r, idx) {
38 return idx + 1;
39 },
40 },
41 {
42 title: '风险源名称',
43 dataIndex: 'riskName',
44 align: 'center',
45 width: 160,
46 render: (t, r) => {
47 return (
48 <Tooltip placement="top" title={t}>
49 <StyledEllipsisWrap maxLine={1}>{t}</StyledEllipsisWrap>
50 </Tooltip>
51 );
52 },
53 },
54 {
55 title: '风险源地址',
56 dataIndex: 'riskUrl',
57 align: 'center',
58 width: 160,
59 render: (t, r) => {
60 return (
61 <Tooltip placement="top" title={t}>
62 <StyledEllipsisWrap maxLine={2}>{t}</StyledEllipsisWrap>
63 </Tooltip>
64 );
65 },
66 },
67 {
68 title: '风险站点',
69 dataIndex: 'riskHost',
70 align: 'center',
71 width: 160,
72 render: (t, r) => {
73 return (
74 <Tooltip placement="top" title={t}>
75 <StyledEllipsisWrap maxLine={2}>{t}</StyledEllipsisWrap>
76 </Tooltip>
77 );
78 },
79 },
80 {
81 title: '风险类型',
82 dataIndex: 'riskType',
83 align: 'center',
84 width: 160,
85 render: (t, r) => {
86 return mapRiskType[t] ? mapRiskType[t].label : '-';
87 },
88 },
89 {
90 title: '风险源类型',
91 dataIndex: 'fileFormat',
92 align: 'center',
93 width: 160,
94 render: (t, r) => {
95 return mapRiskSourceType[t] ? mapRiskSourceType[t].label : '-';
96 },
97 },
98 {
99 title: '检测时间',
100 dataIndex: 'checkTime',
101 align: 'center',
102 width: 160,
103 render: (t, r) => {
104 return t || '-';
105 },
106 },
107 {
108 title: '处理状态',
109 dataIndex: 'status',
110 align: 'center',
111 fixed: 'right',
112 width: 100,
113 render: (t, r) => {
114 return mapStatus[t] ? mapStatus[t].label : '-';
115 },
116 },
117 ];
118
119 const pagination = {
120 ...paginations,
121 total: dataEventRiskList.length,
122 pageSize: 500,
123 current: 1,
124 showSizeChanger: dataEventRiskList.length > 500,
125 showTotal(total) {
126 return `总共 ${total} 条数据`;
127 },
128 };
129
130 return (
131 <Modal
132 title="事件风险详情"
133 placement="right"
134 width={1000}
135 maskClosable={false}
136 onCancel={() => {
137 dispatch({ type: 'Event/cancelModal' });
138 }}
139 visible={modalType === 'EVENT_INFO_MODAL' && modalShow}
140 footer={null}
141 >
142 <Table
143 rowKey="id"
144 loading={loading}
145 dataSource={dataEventRiskList}
146 columns={columns}
147 pagination={pagination}
148 scroll={{ x: 1500, y: 600 }}
149 />
150 </Modal>
151 );
152 };
153
154 export default connect(({ Event, loading }) => ({
155 ...Event,
156 loading: loading.effects['Event/getEventRiskList'],
157 }))(ModalEventInfo);
1 /**
2 * Author: Charles
3 * Date: 2022.9.13
4 * Description: [事件日志]
5 */
6 import React, { useEffect } from 'react';
7 import { connect } from 'umi';
8 import { Modal, Tooltip, Table } from 'antd';
9 import { paginations, mapStatus, mapRiskType, mapRiskSourceType } from '@/constants';
10 import { StyledEllipsisWrap } from '@/components/style';
11
12 const ModalEventLog = props => {
13 const {
14 dispatch,
15 loading,
16 dataModal: {
17 modalType,
18 modalShow,
19 modalData: { id },
20 },
21 dataEventLogList: { records = [], current, size, total },
22 } = props;
23
24 useEffect(() => {
25 if (modalType === 'View_Event_Log' && modalShow) {
26 dispatch({ type: 'Event/getEventRiskLog', payload: { eventId: id } });
27 }
28 }, [modalType, modalShow]);
29
30 /* 点击分页 */
31 const handlePageChange = (current, size) => {
32 dispatch({ type: 'Event/getEventRiskLog', payload: { eventId: id, current, size } });
33 };
34
35 const columns = [
36 {
37 title: '序号',
38 dataIndex: 'id',
39 align: 'center',
40 fixed: 'left',
41 width: 60,
42 render(t, r, idx) {
43 return idx + 1;
44 },
45 },
46 {
47 title: '发送内容',
48 dataIndex: 'content',
49 align: 'center',
50 width: 160,
51 render: (t, r) => {
52 return (
53 <Tooltip placement="top" title={t}>
54 <StyledEllipsisWrap maxLine={1}>{t || '-'}</StyledEllipsisWrap>
55 </Tooltip>
56 );
57 },
58 },
59 {
60 title: '接收者信息',
61 dataIndex: 'recipient',
62 align: 'center',
63 width: 160,
64 render: (t, r) => {
65 return r.type == 2
66 ? `${r.recipientName || '-'}${r.recipient || '-'})`
67 : `${r.recipientName || '-'}`;
68 },
69 },
70 {
71 title: '状态',
72 dataIndex: 'status',
73 align: 'center',
74 width: 120,
75 },
76 {
77 title: '失败原因',
78 dataIndex: 'statusMessage:',
79 align: 'center',
80 width: 160,
81 render: (t, r) => {
82 return (
83 <Tooltip placement="top" title={t}>
84 <StyledEllipsisWrap maxLine={1}>{t || '-'}</StyledEllipsisWrap>
85 </Tooltip>
86 );
87 },
88 },
89 ];
90
91 const pagination = {
92 ...paginations,
93 total: total,
94 pageSize: size,
95 current,
96 showSizeChanger: total > 10,
97 onChange: (current, pageSize) => {
98 handlePageChange(current, pageSize);
99 },
100 onShowSizeChange: (current, pageSize) => {
101 handlePageChange(1, pageSize);
102 },
103 showTotal(total) {
104 return `总共 ${total} 条数据`;
105 },
106 };
107
108 return (
109 <Modal
110 title="事件日志"
111 placement="right"
112 width={1000}
113 maskClosable={false}
114 onCancel={() => {
115 dispatch({ type: 'Event/cancelModal' });
116 }}
117 visible={modalType === 'View_Event_Log' && modalShow}
118 footer={null}
119 >
120 <Table
121 rowKey="id"
122 loading={loading}
123 dataSource={records}
124 columns={columns}
125 pagination={pagination}
126 scroll={{ x: 1500, y: 600 }}
127 />
128 </Modal>
129 );
130 };
131
132 export default connect(({ Event, loading }) => ({
133 ...Event,
134 loading: loading.effects['Event/getEventRiskLog'],
135 }))(ModalEventLog);
1 import * as services from '@/services/incident';
2 import moment from 'moment';
3
4 /* SerachParams */
5 const staticSearch = {
6 current: 1,
7 size: 10,
8 status: 'ALL',
9 eventType: 'ALL',
10 eventLevel: 'ALL',
11 companyName: undefined,
12 startTime: moment(new Date())
13 .add(-7, 'days')
14 .startOf('day'),
15 endTime: moment(new Date())
16 .add(0, 'days')
17 .endOf('day'),
18 };
19
20 export default {
21 namespace: 'Event',
22 state: {
23 dataSearch: {
24 ...staticSearch,
25 },
26 dataEvent: {
27 records: [],
28 current: 1,
29 size: 10,
30 total: 0,
31 totalPage: 0,
32 },
33 dataEventRiskList: [],
34 dataModal: {
35 modalType: '',
36 modalShow: false,
37 modalData: {},
38 },
39 dataEventLogList: {
40 records: [],
41 current: 1,
42 size: 10,
43 total: 0,
44 totalPage: 0,
45 },
46 },
47 effects: {
48 /* 获取事件列表 */
49 *getEventList({ payload }, { call, put, select }) {
50 const {
51 dataSearch,
52 dataSearch: { status, eventType, eventLevel, startTime, endTime },
53 } = yield select(state => state.Event);
54 try {
55 const res = yield call(services.getEventList, {
56 current: 1,
57 size: 10,
58 ...dataSearch,
59 ...payload,
60 startTime: moment(startTime).format('YYYY-MM-DD HH:mm:ss'),
61 endTime: moment(endTime).format('YYYY-MM-DD HH:mm:ss'),
62 status: status === 'ALL' ? '' : status,
63 eventType: eventType === 'ALL' ? '' : eventType,
64 eventLevel: eventLevel === 'ALL' ? '' : eventLevel,
65 });
66 if (res.code === 0) {
67 res.data.records = res.data.records || [];
68 yield put({
69 type: 'changeState',
70 payload: {
71 dataEvent: res.data,
72 },
73 });
74 }
75 } catch (err) {
76 console.error(err);
77 }
78 },
79 /* 事件详情 */
80 *getEventRiskList({ payload }, { call, put, select }) {
81 try {
82 const res = yield call(services.getEventRiskList, {
83 current: 1,
84 size: 10,
85 ...payload,
86 });
87 if (res.code === 0) {
88 res.data.records = res.data.records || [];
89 yield put({
90 type: 'changeState',
91 payload: {
92 dataEventRiskList: res.data,
93 },
94 });
95 }
96 } catch (err) {
97 console.error(err);
98 }
99 },
100 /* 事件日志 */
101 *getEventRiskLog({ payload }, { call, put, select }) {
102 try {
103 const res = yield call(services.getEventRiskLog, {
104 current: 1,
105 size: 10,
106 ...payload,
107 });
108 if (res.code === 0) {
109 res.data.records = res.data.records || [];
110 yield put({
111 type: 'changeState',
112 payload: {
113 dataEventLogList: res.data,
114 },
115 });
116 }
117 } catch (err) {
118 console.error(err);
119 }
120 },
121 },
122 reducers: {
123 changeState(state, { payload }) {
124 return {
125 ...state,
126 ...payload,
127 };
128 },
129 cancelModal(state, { payload }) {
130 return {
131 ...state,
132 dataModal: {
133 modalType: '',
134 modalShow: false,
135 modalData: {},
136 },
137 };
138 },
139 resetSearch(state, { payload }) {
140 return {
141 ...state,
142 dataSearch: {
143 ...staticSearch,
144 },
145 };
146 },
147 },
148 };
1 /**
2 * Author: wjw
3 * Date: 2019.05.13
4 * Description: '图片预览'
5 */
6 import React, { useState, useEffect } from 'react';
7 import { connect } from 'umi';
8 import { Modal } from 'antd';
9 const ModalPreImg = props => {
10 const {
11 preImgDataModal: {
12 modalType,
13 modalShow,
14 modalData: { imgUrl, title, type = 'imgurl' },
15 },
16 width,
17 dispatch,
18 } = props;
19 const params = {
20 width,
21 };
22 // const QRCode = require('qrcode.react');
23 const handleCancel = () => {
24 const payload = {
25 preImgDataModal: {
26 modalType: '',
27 modalShow: false,
28 modalData: {},
29 },
30 };
31 dispatch({ type: 'global/changeState', payload });
32 };
33 return (
34 <Modal
35 zIndex={10001}
36 {...params}
37 visible={modalType === 'PREVIEWIMG' && modalShow}
38 footer={null}
39 getContainer={()=> document.body}
40 onCancel={() => {
41 handleCancel();
42 }}
43 >
44 <div style={{ textAlign: 'center' }}>
45 <p>{title}</p>
46 {type === 'imgurl' && imgUrl && (
47 <img alt="example" style={{ width: '100%' }} src={imgUrl} />
48 )}
49 {/* {type === 'qrcode' && (
50 <div style={{ textAlign: 'center' }}>
51 {imgUrl ? <QRCode value={imgUrl} style={{ width: '250px', height: '250px' }} /> : ''}
52 </div>
53 )} */}
54 </div>
55 </Modal>
56 );
57 };
58 const mapStateToProps = ({ global }) => {
59 return {
60 preImgDataModal: global.preImgDataModal,
61 };
62 };
63 export default connect(mapStateToProps)(ModalPreImg);
...@@ -5,136 +5,14 @@ ...@@ -5,136 +5,14 @@
5 */ 5 */
6 import React, { useEffect } from 'react'; 6 import React, { useEffect } from 'react';
7 import { connect } from 'umi'; 7 import { connect } from 'umi';
8 import { 8 import { Table, Tooltip } from 'antd';
9 Card,
10 Form,
11 Input,
12 Button,
13 Table,
14 Select,
15 DatePicker,
16 Tooltip,
17 Upload,
18 message,
19 } from 'antd';
20 import { paginations, mapStatus, mapRiskType, mapRiskSourceType } from '@/constants'; 9 import { paginations, mapStatus, mapRiskType, mapRiskSourceType } from '@/constants';
21 import { 10 import { StyledEllipsisWrap } from '@/components/style';
22 StyledPageContainer,
23 StyledPageContent,
24 StyledEllipsisWrap,
25 StyledPageHeader,
26 } from '@/components/style';
27 import { UploadOutlined } from '@ant-design/icons';
28 import moment from 'moment'; 11 import moment from 'moment';
29 import * as services from '@/services/risk';
30 import { ExportFile } from '@/utils/utils';
31
32 const { RangePicker } = DatePicker;
33 const FormItem = Form.Item;
34 const { Option } = Select;
35
36 /* SearchForm */
37 const SearchForm = props => {
38 const [form] = Form.useForm();
39 const {
40 dataSearch,
41 dataSearch: { startTime, endTime },
42 handleReset,
43 handleFinish,
44 } = props;
45
46 useEffect(() => {
47 form.setFieldsValue({
48 ...dataSearch,
49 createTime: [
50 startTime ? moment(startTime) : undefined,
51 endTime ? moment(endTime) : undefined,
52 ],
53 });
54 }, [dataSearch]);
55
56 /* 点击搜索 */
57
58 const onFinish = values => {
59 handleFinish(values);
60 };
61
62 /* 点击重置 */
63 const onReset = () => {
64 handleReset();
65 };
66
67 return (
68 <Form name="Form_Risk" layout="inline" form={form} onFinish={onFinish}>
69 <FormItem label="网站地址" name="riskHost">
70 <Input placeholder="请输入网站地址" style={{ width: '250px' }} />
71 </FormItem>
72 <FormItem label="风险类型" name="riskType">
73 <Select placeholder="请选择风险类型" style={{ width: '150px' }}>
74 <Option value="ALL">全部</Option>
75 {Object.values(mapRiskType).map(item => {
76 const { label, value } = item;
77 return (
78 <Option key={value} value={value}>
79 {label}
80 </Option>
81 );
82 })}
83 </Select>
84 </FormItem>
85 <FormItem label="风险源类型" name="fileFormat">
86 <Select placeholder="请选择风险源类型" style={{ width: '150px' }}>
87 <Option value="ALL">全部</Option>
88 {Object.values(mapRiskSourceType).map(item => {
89 const { label, value } = item;
90 return (
91 <Option key={value} value={value}>
92 {label}
93 </Option>
94 );
95 })}
96 </Select>
97 </FormItem>
98 <FormItem label="处理状态" name="status">
99 <Select placeholder="请选择处理状态" style={{ width: '150px' }}>
100 <Option value="ALL">全部</Option>
101 {Object.values(mapStatus).map(item => {
102 const { label, value } = item;
103 return (
104 <Option key={value} value={value}>
105 {label}
106 </Option>
107 );
108 })}
109 </Select>
110 </FormItem>
111 <FormItem label="检测时间" name="createTime">
112 <RangePicker allowClear={false} />
113 </FormItem>
114 <FormItem>
115 <Button type="primary" htmlType="submit" className="mr-15">
116 搜索
117 </Button>
118 <Button className="mr-15" htmlType="button" onClick={onReset}>
119 重置
120 </Button>
121 </FormItem>
122 </Form>
123 );
124 };
125 12
126 /* DataTable */ 13 /* DataTable */
127 const DataTable = props => { 14 const DataTable = props => {
128 const { 15 const { loading, dataRisk } = props;
129 loading,
130 handleGetList,
131 dataRisk: { records = [], current, size, total },
132 } = props;
133
134 /* 点击分页 */
135 const handlePageChange = (current, size) => {
136 handleGetList(current, size);
137 };
138 16
139 const columns = [ 17 const columns = [
140 { 18 {
...@@ -144,7 +22,7 @@ const DataTable = props => { ...@@ -144,7 +22,7 @@ const DataTable = props => {
144 fixed: 'left', 22 fixed: 'left',
145 width: 80, 23 width: 80,
146 render(t, r, idx) { 24 render(t, r, idx) {
147 return (current - 1) * size + idx + 1; 25 return idx + 1;
148 }, 26 },
149 }, 27 },
150 { 28 {
...@@ -239,16 +117,10 @@ const DataTable = props => { ...@@ -239,16 +117,10 @@ const DataTable = props => {
239 ]; 117 ];
240 const pagination = { 118 const pagination = {
241 ...paginations, 119 ...paginations,
242 total: total, 120 total: dataRisk.length,
243 pageSize: size, 121 pageSize: 500,
244 current, 122 current: 1,
245 showSizeChanger: total > 10, 123 showSizeChanger: dataRisk.length > 500,
246 onChange: (current, pageSize) => {
247 handlePageChange(current, pageSize);
248 },
249 onShowSizeChange: (current, pageSize) => {
250 handlePageChange(1, pageSize);
251 },
252 showTotal(total) { 124 showTotal(total) {
253 return `总共 ${total} 条数据`; 125 return `总共 ${total} 条数据`;
254 }, 126 },
...@@ -257,7 +129,7 @@ const DataTable = props => { ...@@ -257,7 +129,7 @@ const DataTable = props => {
257 <Table 129 <Table
258 rowKey="id" 130 rowKey="id"
259 loading={loading} 131 loading={loading}
260 dataSource={records} 132 dataSource={dataRisk}
261 columns={columns} 133 columns={columns}
262 pagination={pagination} 134 pagination={pagination}
263 scroll={{ x: 1500, y: `calc(100vh - 400px)` }} 135 scroll={{ x: 1500, y: `calc(100vh - 400px)` }}
...@@ -266,15 +138,8 @@ const DataTable = props => { ...@@ -266,15 +138,8 @@ const DataTable = props => {
266 }; 138 };
267 139
268 /* Main */ 140 /* Main */
269 const Risk = props => { 141 const RiskBlock = props => {
270 const { 142 const { dispatch, loading, dataRisk } = props;
271 dispatch,
272 loading,
273 loadingUpload,
274 dataSearch,
275 dataRisk,
276 dataRisk: { size },
277 } = props;
278 143
279 useEffect(() => { 144 useEffect(() => {
280 handleGetList(1, 10); 145 handleGetList(1, 10);
...@@ -283,7 +148,7 @@ const Risk = props => { ...@@ -283,7 +148,7 @@ const Risk = props => {
283 /* 账号列表 */ 148 /* 账号列表 */
284 const handleGetList = (current, size) => { 149 const handleGetList = (current, size) => {
285 dispatch({ 150 dispatch({
286 type: 'Risk/getRiskList', 151 type: 'RiskBlock/getEventRiskList',
287 payload: { 152 payload: {
288 current: current || 1, 153 current: current || 1,
289 size: size || 10, 154 size: size || 10,
...@@ -291,87 +156,14 @@ const Risk = props => { ...@@ -291,87 +156,14 @@ const Risk = props => {
291 }); 156 });
292 }; 157 };
293 158
294 /* 点击搜索 */
295 const handleFinish = values => {
296 const { status, riskType, fileFormat, riskHost, createTime } = values;
297 dispatch({
298 type: 'Risk/changeState',
299 payload: {
300 dataSearch: {
301 status,
302 riskType,
303 fileFormat,
304 riskHost,
305 startTime: createTime[0]
306 ? moment(createTime[0].startOf('day').valueOf()).format('YYYY-MM-DD HH:mm:ss')
307 : undefined,
308 endTime: createTime[1]
309 ? moment(createTime[1].endOf('day').valueOf()).format('YYYY-MM-DD HH:mm:ss')
310 : undefined,
311 },
312 },
313 });
314 handleGetList(0, size);
315 };
316
317 /* 点击重置 */
318 const handleReset = () => {
319 dispatch({ type: 'Risk/resetSearch' });
320 handleGetList(0, 10);
321 };
322
323 /* 上传组件配置 */
324 const uploadProps = {
325 customRequest: file => {
326 const formData = new FormData();
327 formData.append('file', file.file);
328 dispatch({ type: 'Risk/importRisk', payload: formData });
329 },
330 beforeUpload: file => {
331 const isLt50M = file.size / 1024 / 1024 < 50;
332 if (!isLt50M) {
333 message.error('文件大小需小于50M');
334 return false;
335 }
336 return isLt50M;
337 },
338 };
339
340 return ( 159 return (
341 <StyledPageContainer>
342 <StyledPageHeader>
343 <Upload {...uploadProps}>
344 <Button loading={loadingUpload} type="primary" icon={<UploadOutlined />}>
345 数据导入
346 </Button>
347 </Upload>
348 <Button
349 type="primary"
350 onClick={() => {
351 ExportFile('风险模版', services.exportRiskTemplate, {});
352 }}
353 >
354 模版下载
355 </Button>
356 </StyledPageHeader>
357 <StyledPageContent>
358 <Card bordered={false}>
359 <SearchForm
360 dataSearch={dataSearch}
361 handleReset={handleReset}
362 handleFinish={handleFinish}
363 />
364 <div className="mt-16"> 160 <div className="mt-16">
365 <DataTable loading={loading} handleGetList={handleGetList} dataRisk={dataRisk} /> 161 <DataTable loading={loading} dataRisk={dataRisk} />
366 </div> 162 </div>
367 </Card>
368 </StyledPageContent>
369 </StyledPageContainer>
370 ); 163 );
371 }; 164 };
372 165
373 export default connect(({ Risk, loading }) => ({ 166 export default connect(({ RiskBlock, loading }) => ({
374 ...Risk, 167 ...RiskBlock,
375 loading: loading.effects['Risk/getRiskList'], 168 loading: loading.effects['RiskBlock/getEventRiskList'],
376 loadingUpload: loading.effects['Risk/importRisk'], 169 }))(RiskBlock);
377 }))(Risk);
......
1 import * as services from '@/services/risk'; 1 import * as services from '@/services/risk';
2 import { message } from 'antd';
3 import moment from 'moment';
4
5 /* SerachParams */
6 const staticSearch = {
7 current: 1,
8 size: 10,
9 status: 'ALL',
10 riskType: 'ALL',
11 fileFormat: 'ALL',
12 riskHost: undefined,
13 startTime: moment(new Date())
14 .add(-7, 'days')
15 .startOf('day'),
16 endTime: moment(new Date())
17 .add(0, 'days')
18 .endOf('day'),
19 };
20 2
21 export default { 3 export default {
22 namespace: 'Risk', 4 namespace: 'RiskBlock',
23 state: { 5 state: {
24 dataSearch: { 6 dataRisk: [],
25 ...staticSearch,
26 },
27 dataRisk: {
28 records: [],
29 current: 1,
30 size: 10,
31 total: 0,
32 totalPage: 0,
33 },
34 }, 7 },
35 effects: { 8 effects: {
36 /* 获取风险列表 */ 9 /* 获取风险列表 */
37 *getRiskList({ payload }, { call, put, select }) { 10 *getEventRiskList({ payload }, { call, put, select }) {
38 const {
39 dataSearch,
40 dataSearch: { status, riskType, fileFormat, startTime, endTime },
41 } = yield select(state => state.Risk);
42 try { 11 try {
43 const res = yield call(services.getRiskList, { 12 const res = yield call(services.getEventRiskList, {
44 current: 1, 13 current: 1,
45 size: 10, 14 size: 10,
46 ...dataSearch,
47 ...payload, 15 ...payload,
48 startTime: moment(startTime).format('YYYY-MM-DD HH:mm:ss'),
49 endTime: moment(endTime).format('YYYY-MM-DD HH:mm:ss'),
50 status: status === 'ALL' ? '' : status,
51 riskType: riskType === 'ALL' ? '' : riskType,
52 fileFormat: fileFormat === 'ALL' ? '' : fileFormat,
53 }); 16 });
54 if (res.code === 0) { 17 if (res.code === 0) {
55 res.data.records = res.data.records || [];
56 yield put({ 18 yield put({
57 type: 'changeState', 19 type: 'changeState',
58 payload: { 20 payload: {
59 dataRisk: res.data, 21 dataRisk: res.data || [],
60 }, 22 },
61 }); 23 });
62 } 24 }
...@@ -64,18 +26,6 @@ export default { ...@@ -64,18 +26,6 @@ export default {
64 console.error(err); 26 console.error(err);
65 } 27 }
66 }, 28 },
67 /* 风险导入 */
68 *importRisk({ payload }, { call, put, select }) {
69 try {
70 const res = yield call(services.importRisk, payload);
71 if (res.code === 0) {
72 message.success('导入成功');
73 yield put({ type: 'getRiskList' });
74 }
75 } catch (err) {
76 console.error(err);
77 }
78 },
79 }, 29 },
80 reducers: { 30 reducers: {
81 changeState(state, { payload }) { 31 changeState(state, { payload }) {
...@@ -84,13 +34,5 @@ export default { ...@@ -84,13 +34,5 @@ export default {
84 ...payload, 34 ...payload,
85 }; 35 };
86 }, 36 },
87 resetSearch(state, { payload }) {
88 return {
89 ...state,
90 dataSearch: {
91 ...staticSearch,
92 },
93 };
94 },
95 }, 37 },
96 }; 38 };
......
1 import { StyledWapperIframe } from '@/components/style';
2
3 const Index = () => {
4 return (
5 <StyledWapperIframe>
6 <iframe
7 frameBorder="0"
8 src="https://yh2-screen.jimilicai.com/"
9 style={{ width: '100%', height: '100%' }}
10 allowfullscreen="true"
11 webkitallowfullscreen="true"
12 mozallowfullscreen="true"
13 ></iframe>
14 </StyledWapperIframe>
15 );
16 };
17
18 export default Index;
1 /**
2 * Author: Charles
3 * Date: 2022.9.13
4 * Description: [重置密码]
5 */
6 import React, { useEffect } from 'react';
7 import { Modal, Form, Input, Button } from 'antd';
8 import {aesEncrypt} from '@/utils/encrypt';
9
10 const formItemLayout = { labelCol: { span: 4 }, wrapperCol: { span: 20 } };
11
12 const ModalResetPassword = props => {
13 const [form] = Form.useForm();
14 const {
15 handleCancelModal,
16 handleOk,
17 dataModal: {
18 modalType,
19 modalShow,
20 modalData: { id },
21 },
22 } = props;
23
24 useEffect(() => {
25 if (modalType === 'PASSWORD_SET_MODAL' && modalShow) {
26 form.resetFields();
27 }
28 }, [modalType, modalShow]);
29
30 /* 点击保存 */
31 const handleSave = () => {
32
33 form.validateFields().then(values => {
34 const saveData = {
35 newPassword: aesEncrypt(values.newPassword),
36 checkPassword: aesEncrypt(values.checkPassword)
37 }
38 handleOk({ saveType: 'PASSWORD', id, ...saveData });
39 });
40 };
41
42 return (
43 <Modal
44 title="重置密码"
45 placement="right"
46 width={700}
47 maskClosable={false}
48 onCancel={handleCancelModal}
49 visible={modalType === 'PASSWORD_SET_MODAL' && modalShow}
50 footer={
51 <div
52 style={{
53 textAlign: 'right',
54 }}
55 >
56 <Button onClick={handleCancelModal} className="mr-10">
57 取消
58 </Button>
59 <Button onClick={handleSave} type="primary">
60 保存
61 </Button>
62 </div>
63 }
64 >
65 <Form form={form} {...formItemLayout} name="password_set_modal">
66 <Form.Item
67 name="newPassword"
68 label="密码"
69 rules={[
70 { required: true, message: '请输入密码' },
71 {
72 pattern: /^(?![a-zA-Z]+$)(?![A-Z0-9]+$)(?![A-Z\W_]+$)(?![a-z0-9]+$)(?![a-z\W_]+$)(?![0-9\W_]+$)[a-zA-Z0-9\W_]{8,16}$/,
73 // pattern: /^(?![\d]+$)(?![a-zA-Z]+$)(?![!#$%^&*]+$)[\da-zA-Z!#$%^&@*]{8,16}$/,
74 message: '密码至少包含大小写字母、数字、特殊符号的三种组合,限制8~16个字符~',
75 },
76 ]}
77 >
78 <Input.Password placeholder="请输入密码" />
79 </Form.Item>
80 <Form.Item
81 name="checkPassword"
82 label="密码确认"
83 rules={[
84 { required: true, message: '请输入确认密码' },
85 ({ getFieldValue }) => ({
86 validator(_, value) {
87 if (!value || getFieldValue('newPassword') === value) {
88 return Promise.resolve();
89 }
90 return Promise.reject(new Error('两次密码不一致,请重新输入'));
91 },
92 }),
93 ]}
94 >
95 <Input.Password placeholder="请确认密码" />
96 </Form.Item>
97 </Form>
98 </Modal>
99 );
100 };
101
102 export default ModalResetPassword;
1 /**
2 * Author: Charles
3 * Date: 2022.9.13
4 * Description: [更新账号]
5 */
6 import React, { useEffect } from 'react';
7 import { connect } from 'umi';
8 import { Modal, Form, Select, Input, Button } from 'antd';
9 import {aesEncrypt} from '@/utils/encrypt';
10
11 const { Option } = Select;
12 const formItemLayout = { labelCol: { span: 4 }, wrapperCol: { span: 20 } };
13
14 const ModalSetAccount = props => {
15 const [form] = Form.useForm();
16 const {
17 dispatch,
18 handleCancelModal,
19 handleOk,
20 dataRoleList,
21 dataModal: {
22 modalType,
23 modalShow,
24 modalData: { id, realName, username, roleId },
25 },
26 } = props;
27
28 useEffect(() => {
29 if (modalType === 'ACCOUNT_SET_MODAL' && modalShow) {
30 dispatch({ type: 'Account/getRoleSelect' });
31 form.resetFields();
32 form.setFieldsValue({
33 realName,
34 username,
35 roleId,
36 });
37 }
38 }, [modalType, modalShow]);
39
40 /* 点击保存 */
41 const handleSave = () => {
42 form.validateFields().then(values => {
43 const saveData = {...values}
44 saveData.password = aesEncrypt(values.password),
45 saveData.checkPassword = aesEncrypt(values.checkPassword),
46 handleOk({ saveType: 'ACCOUNT', id, ...saveData });
47 });
48 };
49
50 return (
51 <Modal
52 title={id ? '编辑账号' : '新增账号'}
53 placement="right"
54 width={700}
55 maskClosable={false}
56 onCancel={handleCancelModal}
57 visible={modalType === 'ACCOUNT_SET_MODAL' && modalShow}
58 footer={
59 <div
60 style={{
61 textAlign: 'right',
62 }}
63 >
64 <Button onClick={handleCancelModal} className="mr-10">
65 取消
66 </Button>
67 <Button onClick={handleSave} type="primary">
68 保存
69 </Button>
70 </div>
71 }
72 >
73 <Form form={form} {...formItemLayout} name="account_set_modal">
74 <Form.Item
75 name="username"
76 label="账号"
77 rules={[
78 { required: true, message: '请输入账号名称, 由4~10位字母、数字、符号组成不包括空格' },
79 {
80 pattern: /^[0-9a-zA-Z]{4,10}$/,
81 message: '账号名称由4~10位字母、数字、符号组成不包括空格~',
82 },
83 ]}
84 >
85 <Input placeholder="请输入账号" disabled={id ? true : false} />
86 </Form.Item>
87 <Form.Item
88 name="realName"
89 label="姓名"
90 rules={[
91 { required: true, message: '请输入姓名, 由2~10位非空格字符组成' },
92 { pattern: /^[\S]{2,10}$/, message: '昵称由2~10位非空格字符组成' },
93 ]}
94 >
95 <Input placeholder="请输入姓名" />
96 </Form.Item>
97 {!id && (
98 <>
99 <Form.Item
100 name="password"
101 label="密码"
102 rules={[
103 { required: true, message: '请输入密码' },
104 {
105 pattern: /^(?![a-zA-Z]+$)(?![A-Z0-9]+$)(?![A-Z\W_]+$)(?![a-z0-9]+$)(?![a-z\W_]+$)(?![0-9\W_]+$)[a-zA-Z0-9\W_]{8,16}$/,
106 // pattern: /^(?![\d]+$)(?![a-zA-Z]+$)(?![!#$%^&*]+$)[\da-zA-Z!#$%^&@*]{6,16}$/,
107 message: '密码至少包含大小写字母、数字、特殊符号的三种组合,限制8~16个字符~',
108 },
109 ]}
110 >
111 <Input.Password placeholder="请输入密码" />
112 </Form.Item>
113 <Form.Item
114 name="checkPassword"
115 label="密码确认"
116 rules={[
117 { required: true, message: '请输入确认密码' },
118 ({ getFieldValue }) => ({
119 validator(_, value) {
120 if (!value || getFieldValue('password') === value) {
121 return Promise.resolve();
122 }
123 return Promise.reject(new Error('两次密码不一致,请重新输入'));
124 },
125 }),
126 ]}
127 >
128 <Input.Password placeholder="请输入确认密码" />
129 </Form.Item>
130 </>
131 )}
132 <Form.Item
133 name="roleId"
134 label="角色"
135 rules={[{ required: true, message: '请选择关联的角色' }]}
136 >
137 <Select placeholder="请选择关联的角色">
138 {dataRoleList.map(item => {
139 return (
140 <Option key={item.id} value={item.id}>
141 {item.name}
142 </Option>
143 );
144 })}
145 </Select>
146 </Form.Item>
147 </Form>
148 </Modal>
149 );
150 };
151
152 export default connect(({ Account }) => ({
153 ...Account,
154 }))(ModalSetAccount);
1 /**
2 * Author: Charles
3 * Date: 2022.9.13
4 * Description: [账号列表]
5 */
6 import React, { useEffect } from 'react';
7 import { connect } from 'umi';
8 import { Card, Form, Input, Button, Table, Divider, Tooltip, Select, Switch } from 'antd';
9 import { EditOutlined, RedoOutlined } from '@ant-design/icons';
10 import { paginations } from '@/constants';
11 import ModalUpdateAccount from './ModalUpdateAccount';
12 import ModalResetPassword from './ModalResetPassword';
13 import { StyledPageContainer, StyledPageHeader, StyledPageContent } from '@/components/style';
14
15 const FormItem = Form.Item;
16 const { Option } = Select;
17
18 /* SearchForm */
19 const SearchForm = props => {
20 const [form] = Form.useForm();
21 const { dataSearch, handleReset, handleFinish } = props;
22
23 useEffect(() => {
24 form.setFieldsValue({
25 ...dataSearch,
26 });
27 }, [dataSearch]);
28
29 /* 点击搜索 */
30
31 const onFinish = values => {
32 handleFinish(values);
33 };
34
35 /* 点击重置 */
36 const onReset = () => {
37 handleReset();
38 };
39
40 return (
41 <Form name="Form_Account" layout="inline" form={form} onFinish={onFinish}>
42 <FormItem label="账号名称" name="keyword">
43 <Input placeholder="请输入账号名称" style={{ width: '220px' }} />
44 </FormItem>
45 <FormItem label="账号状态" name="status">
46 <Select placeholder="请选择账号状态" style={{ width: '180px' }}>
47 <Option value="ALL">全部</Option>
48 <Option value="1">启用</Option>
49 <Option value="0">禁用</Option>
50 </Select>
51 </FormItem>
52 <FormItem>
53 <Button type="primary" htmlType="submit" className="mr-15">
54 搜索
55 </Button>
56 <Button className="mr-15" htmlType="button" onClick={onReset}>
57 重置
58 </Button>
59 </FormItem>
60 </Form>
61 );
62 };
63
64 /* DataTable */
65 const DataTable = props => {
66 const {
67 dispatch,
68 loading,
69 handleGetList,
70 currentUser: { name },
71 dataAccount: { records = [], current, size, total },
72 } = props;
73
74 /* 点击分页 */
75 const handlePageChange = (current, size) => {
76 handleGetList(current, size);
77 };
78
79 const columns = [
80 {
81 title: '序号',
82 dataIndex: 'id',
83 align: 'center',
84 width: 100,
85 render(t, r, idx) {
86 return (current - 1) * size + idx + 1;
87 },
88 },
89 {
90 title: '账号',
91 dataIndex: 'username',
92 align: 'center',
93 width: 140,
94 },
95 {
96 title: '姓名',
97 dataIndex: 'realName',
98 align: 'center',
99 width: 140,
100 },
101 {
102 title: '角色',
103 dataIndex: 'roleName',
104 align: 'center',
105 width: 140,
106 },
107 {
108 title: '账号状态',
109 dataIndex: 'status',
110 align: 'center',
111 width: 160,
112 render(t, r, idx) {
113 return (
114 <Switch
115 checkedChildren="启用"
116 unCheckedChildren="已禁用"
117 checked={t === 1}
118 disabled={name === r.username}
119 onChange={checked => {
120 dispatch({
121 type: 'Account/changeStatus',
122 payload: {
123 id: r.id,
124 status: checked ? 1 : 0,
125 },
126 });
127 }}
128 />
129 );
130 },
131 },
132 {
133 title: '创建时间',
134 dataIndex: 'createTime',
135 align: 'center',
136 width: 200,
137 render(t, r, idx) {
138 return t || '-';
139 },
140 },
141 {
142 title: '操作',
143 align: 'center',
144 width: 160,
145 render(t, r) {
146 return (
147 <>
148 <Tooltip placement="top" title="编辑">
149 <EditOutlined
150 style={{ cursor: 'pointer', fontSize: 16 }}
151 onClick={() => {
152 dispatch({
153 type: 'Account/changeState',
154 payload: {
155 dataModal: {
156 modalType: 'ACCOUNT_SET_MODAL',
157 modalShow: true,
158 modalData: r,
159 },
160 },
161 });
162 }}
163 />
164 </Tooltip>
165 <Divider type="vertical" style={{ margin: '0 16px' }} />
166 <Tooltip
167 placement="top"
168 title="重置密码"
169 onClick={() => {
170 dispatch({
171 type: 'Account/changeState',
172 payload: {
173 dataModal: {
174 modalType: 'PASSWORD_SET_MODAL',
175 modalShow: true,
176 modalData: r,
177 },
178 },
179 });
180 }}
181 >
182 <RedoOutlined style={{ cursor: 'pointer', fontSize: 16 }} />
183 </Tooltip>
184 </>
185 );
186 },
187 },
188 ];
189 const pagination = {
190 ...paginations,
191 total: total,
192 pageSize: size,
193 current,
194 showSizeChanger: total > 10,
195 onChange: (current, pageSize) => {
196 handlePageChange(current, pageSize);
197 },
198 onShowSizeChange: (current, pageSize) => {
199 handlePageChange(1, pageSize);
200 },
201 showTotal(total) {
202 return `总共 ${total} 条数据`;
203 },
204 };
205 return (
206 <Table
207 rowKey="id"
208 loading={loading}
209 dataSource={records}
210 columns={columns}
211 pagination={pagination}
212 scroll={{ y: `calc(100vh - 353px)` }}
213 />
214 );
215 };
216
217 /* Main */
218 const Account = props => {
219 const {
220 dispatch,
221 loading,
222 dataSearch,
223 dataModal,
224 currentUser,
225 dataAccount,
226 dataAccount: { size },
227 } = props;
228
229 useEffect(() => {
230 handleGetList(1, 10);
231 }, []);
232
233 /* 账号列表 */
234 const handleGetList = (current, size) => {
235 dispatch({
236 type: 'Account/getAccountList',
237 payload: {
238 current: current || 1,
239 size: size || 10,
240 },
241 });
242 };
243
244 /* 点击搜索 */
245 const handleFinish = values => {
246 const { status, keyword } = values;
247 dispatch({
248 type: 'Account/changeState',
249 payload: {
250 dataSearch: {
251 keyword,
252 status,
253 },
254 },
255 });
256 handleGetList(0, size);
257 };
258
259 /* 点击重置 */
260 const handleReset = () => {
261 dispatch({ type: 'Account/resetSearch' });
262 handleGetList(0, 10);
263 };
264
265 // 关闭弹框
266 const handleCancelModal = () => {
267 dispatch({ type: 'Account/cancelModal' });
268 };
269
270 // 点击保存
271 const handleOk = values => {
272 const { saveType } = values;
273 if (saveType === 'ACCOUNT') {
274 dispatch({ type: 'Account/updateApplication', payload: { ...values, saveType: undefined } });
275 } else if (saveType === 'PASSWORD') {
276 dispatch({ type: 'Account/resetPassword', payload: { ...values, saveType: undefined } });
277 }
278 };
279
280 return (
281 <StyledPageContainer>
282 <StyledPageHeader>
283 <Button
284 type="primary"
285 onClick={() => {
286 dispatch({
287 type: 'Account/changeState',
288 payload: {
289 dataModal: {
290 modalType: 'ACCOUNT_SET_MODAL',
291 modalShow: true,
292 modalData: {},
293 },
294 },
295 });
296 }}
297 >
298 新增用户
299 </Button>
300 </StyledPageHeader>
301 <StyledPageContent>
302 <Card bordered={false}>
303 <SearchForm
304 dataSearch={dataSearch}
305 handleReset={handleReset}
306 handleFinish={handleFinish}
307 />
308 <div className="mt-16">
309 <DataTable
310 dispatch={dispatch}
311 loading={loading}
312 handleGetList={handleGetList}
313 dataAccount={dataAccount}
314 currentUser={currentUser}
315 />
316 </div>
317 </Card>
318 </StyledPageContent>
319 <ModalUpdateAccount
320 dataModal={dataModal}
321 handleCancelModal={handleCancelModal}
322 handleOk={handleOk}
323 />
324 <ModalResetPassword
325 dataModal={dataModal}
326 handleCancelModal={handleCancelModal}
327 handleOk={handleOk}
328 />
329 </StyledPageContainer>
330 );
331 };
332
333 export default connect(({ Account, user, loading }) => ({
334 ...Account,
335 currentUser: user.currentUser,
336 loading: loading.effects['Account/getAccountList'],
337 }))(Account);
1 import { message } from 'antd';
2 import * as services from '@/services/account';
3
4 /* SerachParams */
5 const staticSearch = {
6 keyword: undefined,
7 current: 1,
8 size: 10,
9 status: 'ALL',
10 };
11
12 export default {
13 namespace: 'Account',
14 state: {
15 dataSearch: {
16 ...staticSearch,
17 },
18 dataAccount: {
19 records: [],
20 current: 1,
21 size: 10,
22 total: 0,
23 totalPage: 0,
24 },
25 dataModal: {
26 modalType: '',
27 modalShow: false,
28 modalData: {},
29 },
30 dataRoleList: [],
31 },
32 effects: {
33 /* 获取账号列表 */
34 *getAccountList({ payload }, { call, put, select }) {
35 const {
36 dataSearch,
37 dataSearch: { status },
38 } = yield select(state => state.Account);
39 try {
40 const res = yield call(services.getAccountList, {
41 current: 1,
42 size: 10,
43 ...dataSearch,
44 ...payload,
45 status: status === 'ALL' ? '' : status,
46 });
47 if (res.code === 0) {
48 res.data.records = res.data.records || [];
49 yield put({
50 type: 'changeState',
51 payload: {
52 dataAccount: res.data,
53 },
54 });
55 }
56 } catch (err) {
57 console.error(err);
58 }
59 },
60 /* 新增、修改账号 */
61 *updateApplication({ payload }, { call, put, select }) {
62 const { id } = payload;
63 const {
64 dataAccount: { current, size },
65 } = yield select(state => state.Account);
66 try {
67 const res = yield call(services[!id ? 'addAccount' : 'updateAccount'], payload);
68 if (res.code === 0) {
69 message.success(!id ? '新增成功' : '修改成功');
70 yield put({
71 type: 'getAccountList',
72 payload: { size, current },
73 });
74 yield put({ type: 'cancelModal' });
75 }
76 } catch (err) {
77 console.error(err);
78 }
79 },
80 /* 重置密码 */
81 *resetPassword({ payload }, { call, put, select }) {
82 try {
83 const res = yield call(services.resetPassword, payload);
84 if (res.code === 0) {
85 message.success('重置成功');
86 yield put({ type: 'cancelModal' });
87 }
88 } catch (err) {
89 console.error(err);
90 }
91 },
92 /* 状态修改 */
93 *changeStatus({ payload }, { call, put, select }) {
94 const { status } = payload;
95 const {
96 dataAccount: { current, size },
97 } = yield select(state => state.Account);
98 try {
99 const res = yield call(services.changeStatus, payload);
100 if (res.code === 0) {
101 message.success(status == '1' ? '启用成功' : '禁用成功');
102 yield put({
103 type: 'getAccountList',
104 payload: { size, current },
105 });
106 }
107 } catch (err) {
108 console.error(err);
109 }
110 },
111 /* 获取角色列表 */
112 *getRoleSelect({ payload }, { call, put, select }) {
113 try {
114 const res = yield call(services.getRoleSelect);
115 if (res.code === 0) {
116 yield put({
117 type: 'changeState',
118 payload: {
119 dataRoleList: res.data,
120 },
121 });
122 }
123 } catch (err) {
124 console.error(err);
125 }
126 },
127 },
128 reducers: {
129 changeState(state, { payload }) {
130 return {
131 ...state,
132 ...payload,
133 };
134 },
135 cancelModal(state, { payload }) {
136 return {
137 ...state,
138 dataModal: {
139 modalType: '',
140 modalShow: false,
141 modalData: {},
142 },
143 };
144 },
145 resetSearch(state, { payload }) {
146 return {
147 ...state,
148 dataSearch: {
149 ...staticSearch,
150 },
151 };
152 },
153 },
154 };
1 /**
2 * Author: llw
3 * Date: 2022.9.14
4 * Description: [菜单层级树]
5 */
6 import React from 'react';
7 import { connect } from 'umi';
8 import { Tree } from 'antd';
9
10 const { TreeNode } = Tree;
11
12 const MenuTree = props => {
13 const { dispatch, dataSystemMenu, dataLevelMenu, dataExpandedKeys } = props;
14 // TreeNode的DOM
15 const renderTreeNode = data => {
16 return data.map(item => {
17 if (item.children && item.children.length) {
18 return (
19 <TreeNode title={item.title} key={item.resourceCode}>
20 {renderTreeNode(item.children)}
21 </TreeNode>
22 );
23 }
24 return <TreeNode title={item.title} key={item.resourceCode} />;
25 });
26 };
27 return (
28 <Tree
29 showLine
30 showIcon
31 className="info-tree"
32 expandedKeys={dataExpandedKeys}
33 onSelect={([key], e) => {
34 const meunInfo = dataLevelMenu.find(item => item.resourceCode === key);
35 dispatch({
36 type: 'SystemMenu/changeState',
37 payload: {
38 dataMenuInfo: !key || !meunInfo ? [] : [{ ...meunInfo, children: undefined }],
39 },
40 });
41 }}
42 >
43 {renderTreeNode(dataSystemMenu)}
44 </Tree>
45 );
46 };
47 export default connect(({ SystemMenu }) => ({
48 ...SystemMenu,
49 }))(MenuTree);
1 /**
2 * Author: llw
3 * Date: 2022.9.14
4 * Description: [设置菜单弹框]
5 */
6 import React, { useEffect, useState } from 'react';
7 import { connect } from 'umi';
8 import { Drawer, Radio, Form, Select, Input, Button } from 'antd';
9
10 const { Option } = Select;
11 const formItemLayout = { labelCol: { span: 4 }, wrapperCol: { span: 20 } };
12
13 const ModalSetMenu = props => {
14 const [menuType, setType] = useState(1);
15 const [form] = Form.useForm();
16 let {
17 dispatch,
18 handleCancelModal,
19 dataLevelMenu = [],
20 dataModal: {
21 modalType,
22 modalShow,
23 modalData: { id, title, resourceCode, resourceNodeType, isEdit, parentId },
24 },
25 } = props;
26
27 /* 重置resourceNodeType */
28 useEffect(() => {
29 if (modalType === 'MENU_SET_MODAL' && modalShow) {
30 setType(resourceNodeType ? +resourceNodeType : 1);
31 setTimeout(() => {
32 form.resetFields();
33 form.setFieldsValue({
34 parentId,
35 title,
36 resourceCode,
37 resourceNodeType: resourceNodeType ? +resourceNodeType : 1,
38 });
39 }, 100);
40 }
41 }, [modalType, modalShow]);
42
43 /* 点击保存 */
44 const handleSave = () => {
45 form.validateFields().then(values => {
46 dispatch({ type: 'SystemMenu/updateSystemMenu', payload: { ...values, id } });
47 });
48 };
49
50 /* 选择菜单类型 */
51 const handleChangeRadio = value => {
52 form.resetFields();
53 setType(value);
54 form.setFieldsValue({ resourceNodeType: value });
55 };
56
57 return (
58 <Drawer
59 title="菜单设置"
60 placement="right"
61 width={600}
62 maskClosable={false}
63 onClose={handleCancelModal}
64 visible={modalType === 'MENU_SET_MODAL' && modalShow}
65 footer={
66 <div
67 style={{
68 textAlign: 'right',
69 }}
70 >
71 <Button onClick={handleCancelModal} className="mr-10">
72 取消
73 </Button>
74 <Button onClick={handleSave} type="primary">
75 保存
76 </Button>
77 </div>
78 }
79 >
80 <Form
81 form={form}
82 {...formItemLayout}
83 name="auth_set_modal"
84 initialValues={{ resourceNodeType: 1 }}
85 >
86 <Form.Item name="resourceNodeType" label="菜单类型">
87 <Radio.Group buttonStyle="solid" onChange={e => handleChangeRadio(e.target.value)}>
88 <Radio.Button disabled={isEdit && +resourceNodeType !== 1 ? true : false} value={1}>
89 一级菜单
90 </Radio.Button>
91 <Radio.Button disabled={isEdit && +resourceNodeType !== 2 ? true : false} value={2}>
92 子菜单
93 </Radio.Button>
94 {/* <Radio.Button disabled={isEdit && resourceNodeType !== 3 ? true : false} value={3}>
95 按钮
96 </Radio.Button> */}
97 </Radio.Group>
98 </Form.Item>
99 {menuType !== 1 && (
100 <Form.Item
101 name="parentId"
102 label={menuType === 2 ? '上级菜单' : '包含菜单'}
103 rules={[
104 {
105 required: true,
106 message: menuType === 2 ? '请选择上级菜单' : '请选择包含该按钮的菜单',
107 },
108 ]}
109 >
110 <Select
111 showSearch
112 placeholder={menuType === 2 ? '请选择上级菜单' : '请选择包含该按钮的菜单'}
113 optionFilterProp="children"
114 filterOption={(input, option) =>
115 option.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
116 }
117 >
118 {dataLevelMenu
119 .filter(_ =>
120 isEdit ? _.resourceCode && _.resourceCode !== resourceCode : _.resourceCode,
121 )
122 .map(item => {
123 return (
124 <Option key={item.id} value={item.id}>
125 {item.title}
126 </Option>
127 );
128 })}
129 </Select>
130 </Form.Item>
131 )}
132 <Form.Item
133 name="title"
134 label={menuType === 3 ? '按钮名称' : '菜单名称'}
135 rules={[
136 { required: true, message: menuType === 3 ? '请输入按钮名称' : '请输入菜单名称' },
137 { min: 2, max: 15, message: '名称长度2~15个字符' },
138 ]}
139 >
140 <Input
141 maxLength={15}
142 placeholder={menuType === 3 ? '请输入按钮名称' : '请输入菜单名称'}
143 />
144 </Form.Item>
145 <Form.Item
146 name="resourceCode"
147 label={menuType === 3 ? '按钮code' : '菜单code'}
148 rules={[
149 { required: true, message: menuType === 3 ? '请输入按钮code' : '请输入菜单code' },
150 ]}
151 >
152 <Input
153 maxLength={20}
154 placeholder={menuType === 3 ? '请输入按钮code' : '请输入菜单code'}
155 />
156 </Form.Item>
157 </Form>
158 </Drawer>
159 );
160 };
161 export default connect(({ SystemMenu }) => ({
162 ...SystemMenu,
163 }))(ModalSetMenu);
1 /**
2 * Author: Charles
3 * Date: 2022.9.13
4 * Description: [菜单设置]
5 */
6 import React, { useEffect } from 'react';
7 import { connect } from 'umi';
8 import { Card, Button, Table, Tooltip, Divider, Modal } from 'antd';
9 import ModalSetMenu from './ModalSetMenu';
10 import MenuTree from './MenuTree';
11 import { EditOutlined, DeleteOutlined, ExclamationCircleOutlined } from '@ant-design/icons';
12 import {
13 StyledPageContainer,
14 StyledPageHeader,
15 StyledPageContent,
16 StyledPageFlex,
17 StyledPageLeft,
18 StyledPageRight,
19 } from '@/components/style';
20
21 /* DataTable */
22 const DataTable = props => {
23 const { dispatch, dataMenuInfo } = props;
24
25 const columns = [
26 {
27 title: '菜单ID',
28 dataIndex: 'id',
29 align: 'center',
30 width: 120,
31 },
32 {
33 title: '菜单名称',
34 dataIndex: 'title',
35 align: 'center',
36 width: 160,
37 },
38 {
39 title: '菜单code',
40 dataIndex: 'resourceCode',
41 align: 'center',
42 width: 160,
43 },
44 {
45 title: '操作',
46 align: 'center',
47 width: 120,
48 render(t, r) {
49 return (
50 <>
51 <Tooltip placement="top" title="编辑">
52 <EditOutlined
53 style={{ cursor: 'pointer', fontSize: 16 }}
54 onClick={() => {
55 dispatch({
56 type: 'SystemMenu/changeState',
57 payload: {
58 dataModal: {
59 modalType: 'MENU_SET_MODAL',
60 modalShow: true,
61 modalData: { ...r, isEdit: true },
62 },
63 },
64 });
65 }}
66 />
67 </Tooltip>
68 <Divider type="vertical" style={{ margin: '0 16px' }} />
69 <Tooltip
70 placement="top"
71 title="删除"
72 onClick={() => {
73 Modal.confirm({
74 title: '删除',
75 icon: <ExclamationCircleOutlined />,
76 content: '确定删除该菜单吗?',
77 centered: true,
78 onOk() {
79 dispatch({
80 type: 'SystemMenu/delSystemMenu',
81 payload: { id: r.id },
82 });
83 },
84 onCancel() {},
85 });
86 }}
87 >
88 <DeleteOutlined style={{ cursor: 'pointer', fontSize: 16 }} />
89 </Tooltip>
90 </>
91 );
92 },
93 },
94 ];
95 return <Table rowKey="id" dataSource={dataMenuInfo} columns={columns} pagination={false} />;
96 };
97
98 /* Main */
99 const SystemMenu = props => {
100 const { dispatch, dataModal, dataMenuInfo } = props;
101
102 useEffect(() => {
103 dispatch({ type: 'SystemMenu/getAllSystemMenu' });
104 }, []);
105
106 // 关闭弹框
107 const handleCancelModal = () => {
108 dispatch({ type: 'SystemMenu/cancelModal' });
109 };
110
111 // 点击保存
112 const handleOk = values => {};
113
114 return (
115 <StyledPageContainer>
116 <StyledPageHeader>
117 <Button
118 type="primary"
119 onClick={() => {
120 dispatch({
121 type: 'SystemMenu/changeState',
122 payload: {
123 dataModal: {
124 modalType: 'MENU_SET_MODAL',
125 modalShow: true,
126 modalData: {},
127 },
128 },
129 });
130 }}
131 >
132 新增菜单
133 </Button>
134 </StyledPageHeader>
135 <StyledPageContent>
136 <StyledPageFlex>
137 <StyledPageLeft>
138 <MenuTree />
139 </StyledPageLeft>
140 <StyledPageRight>
141 <Card bordered={false}>
142 <div className="mt-16">
143 <DataTable dispatch={dispatch} dataMenuInfo={dataMenuInfo} />
144 </div>
145 </Card>
146 </StyledPageRight>
147 </StyledPageFlex>
148 </StyledPageContent>
149 <ModalSetMenu
150 dataModal={dataModal}
151 handleCancelModal={handleCancelModal}
152 handleOk={handleOk}
153 />
154 </StyledPageContainer>
155 );
156 };
157
158 export default connect(({ SystemMenu }) => ({
159 ...SystemMenu,
160 }))(SystemMenu);
1 import * as services from '@/services/menu';
2 import { message } from 'antd';
3 import { getPermissionList } from '@/utils/menu';
4
5 export default {
6 namespace: 'SystemMenu',
7 state: {
8 dataSystemMenu: [], // 层级菜单
9 dataLevelMenu: [], // 铺平菜单
10 dataMenuInfo: [], // 菜单详情
11 dataExpandedKeys: [], // 菜单code
12 dataModal: {
13 modalType: '',
14 modalShow: false,
15 modalData: {},
16 },
17 },
18 effects: {
19 /* 获取菜单层级 */
20 *getAllSystemMenu({ payload }, { call, put, select }) {
21 const { dataMenuInfo } = yield select(state => state.SystemMenu);
22 try {
23 const res = yield call(services.getAllMenu);
24 if (res.code === 0) {
25 const { dataMenu, dataExpandedKeys } = getPermissionList(res.data || []);
26 yield put({
27 type: 'changeState',
28 payload: {
29 dataSystemMenu: res.data || [],
30 dataLevelMenu: dataMenu,
31 dataExpandedKeys,
32 },
33 });
34 // 处理菜单选中进行编辑、删除的情况
35 if (payload && payload.isEdit && dataMenuInfo.length) {
36 const selectMenuInfo = dataMenu.find(
37 item => item.resourceCode === dataMenuInfo[0].resourceCode,
38 );
39 yield put({
40 type: 'changeState',
41 payload: {
42 dataMenuInfo: [{ ...selectMenuInfo, children: undefined }],
43 },
44 });
45 } else if (payload && payload.isDel && dataMenuInfo.length) {
46 const selectMenuInfo = dataMenu.find(
47 item => item.resourceCode === dataMenuInfo[0].resourceCode,
48 );
49 yield put({
50 type: 'changeState',
51 payload: {
52 dataMenuInfo: selectMenuInfo ? [{ ...selectMenuInfo, children: undefined }] : [],
53 },
54 });
55 }
56 }
57 } catch (err) {
58 console.error(err);
59 }
60 },
61 /* 新增、编辑菜单 */
62 *updateSystemMenu({ payload }, { call, put, select }) {
63 try {
64 const res = yield call(services[!payload.id ? 'addMenu' : 'updateMenu'], payload);
65 if (res.code === 0) {
66 message.success(!payload.id ? '新增成功' : '编辑成功');
67 yield put({ type: 'cancelModal' });
68 yield put({ type: 'getAllSystemMenu', payload: { isEdit: payload.id ? true : false } });
69 }
70 } catch (err) {
71 console.error(err);
72 }
73 },
74 /* 删除菜单 */
75 *delSystemMenu({ payload }, { call, put, select }) {
76 try {
77 const res = yield call(services.delMenu, payload);
78 if (res.code === 0) {
79 message.success('删除成功');
80 yield put({ type: 'getAllSystemMenu', payload: { isDel: true } });
81 }
82 } catch (err) {
83 console.error(err);
84 }
85 },
86 },
87 reducers: {
88 changeState(state, { payload }) {
89 return {
90 ...state,
91 ...payload,
92 };
93 },
94 cancelModal(state, { payload }) {
95 return {
96 ...state,
97 dataModal: {
98 modalType: '',
99 modalShow: false,
100 modalData: {},
101 },
102 };
103 },
104 },
105 };
1 /**
2 * Author: Charles
3 * Date: 2022.9.13
4 * Description: [更新角色]
5 */
6 import React, { useEffect, useState } from 'react';
7 import { connect } from 'umi';
8 import { Modal, Form, Input, Button, TreeSelect } from 'antd';
9
10 const formItemLayout = { labelCol: { span: 4 }, wrapperCol: { span: 20 } };
11
12 const ModalSetRole = props => {
13 const [form] = Form.useForm();
14 const {
15 dispatch,
16 dataUserMenu,
17 handleCancelModal,
18 handleOk,
19 dataRoleMenuId,
20 dataModal: {
21 modalType,
22 modalShow,
23 modalData: { id, name, description },
24 },
25 } = props;
26
27 useEffect(() => {
28 if (modalType === 'ROLE_SET_MODAL' && modalShow) {
29 dispatch({ type: 'Role/getUserMenu' });
30 if (id) {
31 dispatch({ type: 'Role/getRoleMenuId', payload: { id } });
32 }
33 form.resetFields();
34 form.setFieldsValue({
35 name,
36 description,
37 });
38 }
39 }, [modalType, modalShow]);
40
41 const [value, setValue] = useState([]);
42
43 useEffect(() => {
44 form.setFieldsValue({
45 menuIds: dataRoleMenuId,
46 });
47 }, [dataRoleMenuId]);
48
49 // treeSelect配置
50 const tProps = {
51 treeData: dataUserMenu,
52 value: dataRoleMenuId || [],
53 onChange: () => {},
54 treeCheckable: true,
55 showCheckedStrategy: TreeSelect.SHOW_ALL,
56 placeholder: '请选择菜单权限',
57 style: {
58 width: '100%',
59 },
60 fieldNames: {
61 label: 'title',
62 value: 'id',
63 },
64 };
65
66 /* 点击保存 */
67 const handleSave = () => {
68 form.validateFields().then(values => {
69 console.log(values, 'values');
70 handleOk({ id, ...values });
71 });
72 };
73
74 return (
75 <Modal
76 title={id ? '编辑角色' : '新增角色'}
77 placement="right"
78 width={700}
79 maskClosable={false}
80 onCancel={handleCancelModal}
81 visible={modalType === 'ROLE_SET_MODAL' && modalShow}
82 footer={
83 <div
84 style={{
85 textAlign: 'right',
86 }}
87 >
88 <Button onClick={handleCancelModal} className="mr-10">
89 取消
90 </Button>
91 <Button onClick={handleSave} type="primary">
92 保存
93 </Button>
94 </div>
95 }
96 >
97 <Form form={form} {...formItemLayout} name="role_set_modal">
98 <Form.Item
99 name="name"
100 label="角色名称"
101 rules={[
102 { required: true, message: '请输入角色名称,由2~10位非空格的字符组成' },
103 { pattern: /^[\S]{2,10}$/, message: '角色名称由2~10位非空格的字符组成' },
104 ]}
105 >
106 <Input placeholder="请输入角色名称" />
107 </Form.Item>
108 <Form.Item
109 name="description"
110 label="角色描述"
111 rules={[
112 { required: false, message: '请输入角色描述' },
113 { max: 30, message: '角色描述字符长度不能超过30' },
114 ]}
115 >
116 <Input.TextArea autoSize={{ minRows: 4, maxRows: 4 }} placeholder="请输入角色描述" />
117 </Form.Item>
118 <Form.Item
119 name="menuIds"
120 label="菜单权限"
121 rules={[{ required: true, message: '请选择菜单权限' }]}
122 >
123 <TreeSelect {...tProps} />
124 </Form.Item>
125 </Form>
126 </Modal>
127 );
128 };
129
130 export default connect(({ Role }) => ({
131 ...Role,
132 }))(ModalSetRole);
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!