480fe21d by charles

feat: 更新

1 parent 9b990809
Showing 55 changed files with 30 additions and 6979 deletions
......@@ -21,7 +21,7 @@ const getRoutes = (routes, maps = {}) => {
};
};
const { routes, maps } = getRoutes([user, app]);
const { routes, maps } = getRoutes([user]);
export const routeMaps = maps;
......
export default {
path: '/user',
path: '/',
component: '../layouts/UserLayout',
routes: [
{ path: '/user', name: 'login', redirect: '/user/login' },
{ path: '/user/login', name: 'login', component: './User/Login' },
{ path: '/user/risk', name: 'login', component: './User/Risk' },
{ path: '/', name: 'Risk', component: './Risk' },
{ path: '/:id', component: './Risk' },
],
};
......
import { connect } from 'umi';
import React from 'react';
import styles from './UserLayout.less';
const UserLayout = props => {
const { children } = props;
return (
<>
<div className={styles.container}>
<div className={styles.bgTop}>
<div>一网打“净”数智在线</div>
</div>
<div className={styles.content}>
<div className={styles.login}>{children}</div>
</div>
</div>
</>
);
return <div className={styles.container}>{children}</div>;
};
export default connect(({ settings, user }) => ({
...settings,
currentUser: user.currentUser,
}))(UserLayout);
export default UserLayout;
......
......@@ -7,32 +7,6 @@
height: 100vh;
overflow: auto;
position: relative;
background-color: #F5F5F5;
.bgTop {
background-color: @primary-color;
height: 400px;
div {
color: #fff;
text-align: center;
font-size: 22px;
position: absolute;
top: 170px;
left: 50%;
letter-spacing: 2px;
transform: translateX(-50%);
}
}
.content {
position: absolute;
background-color: #fff;
border-radius: 2px;
top: 220px;
left: 50%;
z-index: 2;
transform: translateX(-50%);
.login {
width: 400px;
box-shadow: 0 4px 50px 0 rgba(121,173,201,.17);
}
}
padding: 20px;
}
......
import { queryNotices } from '@/services/user';
const GlobalModel = {
namespace: 'global',
state: {
collapsed: false,
loading: false,
urlFileExport: '',
dataModal: {
modalType: '',
modalShow: false,
modalData: {},
},
preImgDataModal: {
modalType: '',
modalShow: false,
modalData: {},
},
},
effects: {},
reducers: {
changeLayoutCollapsed(
state = {
notices: [],
collapsed: true,
},
{ payload },
) {
return { ...state, collapsed: payload };
},
},
subscriptions: {
setup({ history, dispatch }) {
// Subscribe history(url) change, trigger `load` action if pathname is `/`
history.listen(({ pathname, search }) => {
// 路由发生变化的时候切换菜单
const whiteList = ['/user/login'];
if (!whiteList.includes(pathname)) {
// 获取用户信息
dispatch({ type: 'user/fetchCurrent' });
}
});
},
},
};
export default GlobalModel;
import { queryLogin, loginOut } from '@/services/login';
import { getUserInfo, getBosUserList } from '@/services/user';
import { message } from 'antd';
import { history } from 'umi';
import md5 from 'blueimp-md5';
import defaultSettings from '../../config/defaultSettings';
import { getDataMenus } from '@/utils/menu';
const { tokenKey, md5Key } = defaultSettings;
const Model = {
namespace: 'login',
state: {
status: undefined,
},
effects: {
//退出登录
*logout({ payload }, { call, put, select }) {
try {
const res = yield call(loginOut);
if (res.code === 0 && res.data) {
if (!payload) {
message.success('退出成功');
}
localStorage.removeItem(tokenKey);
setTimeout(() => {
window.location.href = '/user/login';
}, 500);
}
} catch (err) {
console.error(err);
}
},
//登录
*login({ payload }, { call, put }) {
try {
const res = yield call(queryLogin, payload);
if (res.code === 0) {
localStorage.setItem(tokenKey, res.data);
// const userinfo = yield call(getUserInfo);
// const { permissionVos = [] } = userinfo.data;
// const dataMenus = getDataMenus(permissionVos);
// console.log(dataMenus);
// if (dataMenus.length) {
// history.replace(dataMenus[0].path);
// } else {
// history.replace('/');
// }
history.replace('/');
message.success('登录成功');
}
} catch (err) {
console.error(err);
}
},
},
reducers: {
changeLoginStatus(state, { payload }) {
return { ...state, status: payload.status, type: payload.type };
},
},
};
export default Model;
import defaultSettings from '../../config/defaultSettings';
const updateColorWeak = colorWeak => {
const root = document.getElementById('root');
if (root) {
root.className = colorWeak ? 'colorWeak' : '';
}
};
const SettingModel = {
namespace: 'settings',
state: defaultSettings,
reducers: {
changeSetting(state = defaultSettings, { payload }) {
const { colorWeak, contentWidth } = payload;
if (state.contentWidth !== contentWidth && window.dispatchEvent) {
window.dispatchEvent(new Event('resize'));
}
updateColorWeak(!!colorWeak);
return { ...state, ...payload };
},
},
};
export default SettingModel;
import { getUserInfo, updatePassword } from '@/services/user';
import { getDataMenus } from '@/utils/menu';
import { message } from 'antd';
const UserModel = {
namespace: 'user',
state: {
currentUser: {
admin: {},
dataMenus: [],
username: '',
},
userAuths: [], // 权限
dataModal: {
modalType: '',
modalShow: false,
modalData: {},
},
},
effects: {
*fetchCurrent(_, { call, put, select }) {
const {
currentUser,
currentUser: { username },
} = yield select(state => state.user);
if (!currentUser || !username) {
try {
const res = yield call(getUserInfo);
// data.dataMenus = getDataMenus(data.permissionVos);
if (res.code === 0) {
res.data.menus = [
{
children: [],
id: 999999,
parentId: 0,
resourceCode: 'Home',
resourceNodeType: '1',
title: '数智大屏',
},
...(res.data.menus || []),
{
resourceCode: '404',
},
];
yield put({ type: 'saveCurrentUser', payload: res.data });
}
} catch (err) {
console.error(err, 'err');
}
}
},
/* 修改密码 */
*updatePassword({ payload }, { call, put, select }) {
try {
const res = yield call(updatePassword, payload);
if (res.code === 0) {
message.success('修改成功');
yield put({ type: 'cancelModal' });
yield put({ type: 'login/logout', payload: { message: 1 } });
}
} catch (err) {
console.error(err);
}
},
},
reducers: {
changeState(state, { payload }) {
return {
...state,
...payload,
};
},
cancelModal(state, { payload }) {
return {
...state,
dataModal: {
modalType: '',
modalShow: false,
modalData: {},
},
};
},
saveCurrentUser(state, { payload }) {
return {
...state,
currentUser: payload || {},
// userAuths: payload.authorities.map(_ => _.code),
};
},
},
};
export default UserModel;
/**
* Author: llw
* Date: 2020.7.20
* Description: [应用详情]
*/
import React, { useEffect } from 'react';
import { connect, Link } from 'umi';
import { Modal, Card, Breadcrumb, Form, Input, Button, Tree, message, Spin } from 'antd';
import { IconFontConfig } from '@/common';
import { EditOutlined, DeleteOutlined, ExclamationCircleOutlined } from '@ant-design/icons';
import ModalSetAuth from './ModalSetAuth';
import { getAuthData, getAllMenuParams, getPermissionList, getDelAuthData, getDragData } from '@/utils/utils';
const { TreeNode } = Tree;
const layout = {labelCol: { span: 3 }, wrapperCol: { span: 12 }};
const ApplicationInfo = props => {
const [form] = Form.useForm();
let {
loading,
isRepeat,
dispatch,
dataModal,
oldInfo = {},
dataAuth = [],
dataMenuList = [],
dataExpandedKeys = [],
location: { query: { id } },
} = props;
/* 获取应用详情 */
useEffect(() => {
if (id) {
dispatch({type: 'Application/getApplicationInfo', payload: {id}}).then(res => {
const { name, url, code, apiDomain } = res.data || {};
form.setFieldsValue({
name, url, code, apiDomain
});
});
}
return (() => {
dispatch({type: 'Application/changeState', payload: {
dataMenuList: [],
dataAuth: [],
dataExpandedKeys: [],
dataApplicationInfo: {}
}})
})
}, []);
/* 添加权限 */
const handleAddTemp = () => {
dispatch({type: 'Application/changeState', payload: {
dataModal: {
modalType: 'AUTH_SET_MODAL',
modalShow: true,
modalData: {isEdit: false}
}
}})
};
/* 关闭弹框 */
const handleCancelModal = () => {
dispatch({type: 'Application/changeState', payload: {oldInfo: {}}});
dispatch({type: 'Application/cancelModal'});
};
/* 保存权限配置 */
const handleAuthSetOk = (values) => {
const { isEdit } = values;
const { allCode = [], allMenuName = [] } = getAllMenuParams(dataAuth);
if (oldInfo.name !== values.name && allMenuName.includes(values.name)) {
message.warning("菜单名称不能重复~")
return false;
}
if (oldInfo.code !== values.code && allCode.includes(values.code)) {
message.warning("code不能重复~")
return false;
}
/* 上述条件不成立时才会走下面生成tree */
let params = {
subPermissionList: [],
...values,
isEdit: undefined,
key: values.code,
oldCode: (oldInfo.parentCode && oldInfo.parentCode !== values.parentCode) ? oldInfo.parentCode : undefined
};
let dataSetAuth =
!isEdit
?
getAuthData(dataAuth, params)
:
getDelAuthData(dataAuth, params, 'EDIT');
const { data, dataMenu, dataExpandedKeys } = dataSetAuth;
handleCancelModal();
dispatch({type: 'Application/changeState', payload: {
dataAuth: JSON.parse(JSON.stringify(data)),
dataMenuList: JSON.parse(JSON.stringify(dataMenu)),
dataExpandedKeys: JSON.parse(JSON.stringify(dataExpandedKeys))
}});
};
// TreeNode的DOM
const renderTreeNode = (data) => {
return data.map((item) => {
if (item.subPermissionList && item.subPermissionList.length) {
return (
<TreeNode
title={
<>
{item.name}
<EditOutlined title="编辑" className="ml-10" onClick={() => handleTreeNode(item, "INFO")} />
<DeleteOutlined title="删除" className="ml-10" onClick={() => handleTreeNode(item, "DEL")} />
</>
}
key={item.code}
icon={<IconFontConfig type={(item.type === 3 || item.type === "BTN") ? "icon-btn" : "icon-menu"} style={{fontSize: '14px'}} />}
>
{renderTreeNode(item.subPermissionList)}
</TreeNode>
)
}
return (
<TreeNode
title={
<>
{item.name}
<EditOutlined title="编辑" className="ml-10" onClick={() => handleTreeNode(item, "INFO")} />
<DeleteOutlined title="删除" className="ml-10" onClick={() => handleTreeNode(item, "DEL")} />
</>
}
key={item.code}
icon={<IconFontConfig type={(item.type === 3 || item.type === "BTN") ? "icon-btn" : "icon-menu"} style={{fontSize: '14px'}} />}
/>
)
})
};
// 点击TreeNode
const handleTreeNode = (item, type) => {
if (type === "INFO") {
dispatch({type: 'Application/changeState', payload: {
oldInfo: {...item},
dataModal: {
modalType: 'AUTH_SET_MODAL',
modalShow: true,
modalData: {...item, isEdit: true}
}
}})
} else if (type === "DEL") {
const { data, dataMenu, dataExpandedKeys } = getDelAuthData(dataAuth, item, 'DEL');
Modal.confirm({
title: '确定删除吗?',
icon: <ExclamationCircleOutlined />,
okText: '确定',
cancelText: '取消',
onOk() {
dispatch({type: 'Application/changeState', payload: {
dataAuth: JSON.parse(JSON.stringify(data)),
dataMenuList: JSON.parse(JSON.stringify(dataMenu)),
dataExpandedKeys: JSON.parse(JSON.stringify(dataExpandedKeys))
}});
}
});
}
};
// 点击Tree
const handleOnExpand = (expandedKeys) => {
dispatch({type: 'Application/changeState', payload: {
dataExpandedKeys: expandedKeys
}});
};
// 保存应用
const handleSaveApplication = () => {
let permissionList = getPermissionList(dataAuth);
form.validateFields().then(values => {
dispatch({type: 'Application/updateApplication', payload: {
...values,
id,
permissionList
}})
})
};
/* 拖拽排序 */
const onDrop = info => {
const dropKey = info.node.props.eventKey;
const dragKey = info.dragNode.props.eventKey;
const dropPos = info.node.props.pos.split('-');
const dropPosition = info.dropPosition - Number(dropPos[dropPos.length - 1]);
const loop = (data, key, callback) => {
for (let i = 0; i < data.length; i++) {
if (data[i].key === key) {
return callback(data[i], i, data);
}
if (data[i].subPermissionList) {
loop(data[i].subPermissionList, key, callback);
}
}
};
let dataStateAuth = JSON.parse(JSON.stringify(dataAuth));
const data = [...dataStateAuth];
// Find dragObject
let dragObj;
loop(data, dragKey, (item, index, arr) => {
arr.splice(index, 1);
dragObj = item;
});
if (!info.dropToGap) {
// Drop on the content
loop(data, dropKey, item => {
item.subPermissionList = item.subPermissionList || [];
// where to insert 示例添加到尾部,可以是随意位置
item.subPermissionList.push(dragObj);
});
} else if (
(info.node.props.subPermissionList || []).length > 0 &&
info.node.props.expanded &&
dropPosition === 1
) {
loop(data, dropKey, item => {
item.subPermissionList = item.subPermissionList || [];
// where to insert 示例添加到头部,可以是随意位置
item.subPermissionList.unshift(dragObj);
});
} else {
let ar;
let i;
loop(data, dropKey, (item, index, arr) => {
ar = arr;
i = index;
});
if (dropPosition === -1) {
ar.splice(i, 0, dragObj);
} else {
ar.splice(i + 1, 0, dragObj);
}
}
let { dataDragAuth, dataMenu, dataExpandedKeys } = getDragData(data);
dispatch({type: 'Application/changeState', payload: {
dataAuth: JSON.parse(JSON.stringify(dataDragAuth.length > 0 ? dataDragAuth : dataAuth)),
dataMenuList: JSON.parse(JSON.stringify(dataMenu)),
dataExpandedKeys: JSON.parse(JSON.stringify(dataExpandedKeys))
}});
};
/* 清空所有权限 */
const handleRemoveAuth = () => {
Modal.confirm({
title: '确定清空该应用权限的相关数据吗?',
icon: <ExclamationCircleOutlined />,
okText: '确定',
cancelText: '取消',
onOk() {
dispatch({type: 'Application/changeState', payload: {
dataAuth: [],
dataMenuList: [],
dataExpandedKeys: []
}});
}
});
};
return (
<div className="box-info">
<Breadcrumb>
<Breadcrumb.Item><Link to="/appliction">应用列表</Link></Breadcrumb.Item>
<Breadcrumb.Item>{!id ? '新建应用' : '编辑应用'}</Breadcrumb.Item>
</Breadcrumb>
<Spin spinning={id ? loading : false}>
<Card bordered={false} className="mt-15">
<Form
{...layout}
form={form}
name="applicationInfo"
>
<Form.Item
label="应用名称"
name="name"
rules={[{ required: true, message: '请输入应用名称' }]}
>
<Input placeholder="请输入应用名称" />
</Form.Item>
<Form.Item
label="应用标识码"
name="code"
>
<Input placeholder="请输入应用标识码" />
</Form.Item>
<Form.Item
label="应用Api域名地址"
name="apiDomain"
>
<Input placeholder="请输入应用api域名地址" />
</Form.Item>
<Form.Item
label="应用链接地址"
name="url"
>
<Input placeholder="请输入应用链接地址" />
</Form.Item>
<Form.Item label="权限服务模板">
<Button onClick={handleAddTemp}>添加</Button>
</Form.Item>
<Form.Item label="权限预览" className="view-tree-auth">
{
dataAuth.length > 0 ?
(
<Tree
showLine
showIcon
draggable
selectedKeys={[]}
className="info-tree"
onExpand={handleOnExpand}
expandedKeys={dataExpandedKeys}
onDrop={onDrop}
>
{renderTreeNode(dataAuth)}
</Tree>
)
:
<span>暂无数据</span>
}
</Form.Item>
<Form.Item className="footer-btn" wrapperCol={{span: 24}}>
<Button disabled={!dataAuth.length} onClick={handleRemoveAuth} className="mr-10">清空权限</Button>
<Button loading={isRepeat} onClick={handleSaveApplication} type="primary" className="ml-10">保存应用</Button>
</Form.Item>
</Form>
</Card>
{/* 设置权限抽屉 */}
<ModalSetAuth
dataModal={dataModal}
dataMenuList={dataMenuList}
handleAuthSetOk={handleAuthSetOk}
handleCancelModal={handleCancelModal}
/>
</Spin>
</div>
)
};
export default connect(({ Application, loading }) => ({
...Application,
isRepeat: loading.effects["Application/updateApplication"],
loading: loading.effects["Application/getApplicationInfo"]
}))(ApplicationInfo);
\ No newline at end of file
/**
* Author: llw
* Date: 2020.7.20
* Description: [设置权限弹框]
*/
import React, { useEffect, useState } from 'react';
import { Drawer, Radio, Form, Select, Input, Button } from 'antd';
const { Option } = Select;
const formItemLayout = {labelCol: { span: 4 }, wrapperCol: { span: 20 }};
const ModalSetAuth = props => {
const [menuType, setType] = useState(1);
const [form] = Form.useForm();
let {
handleCancelModal,
handleAuthSetOk,
dataMenuList = [],
dataModal: {
modalType,
modalShow,
modalData,
modalData: { name, code, type, url, icon, parentCode, isEdit }
}
} = props;
dataMenuList = code ? dataMenuList.filter(item => code !== item.code) : dataMenuList;
/* 重置type */
useEffect(() => {
if (modalType === "AUTH_SET_MODAL" && modalShow) {
setType(type || 1);
setTimeout(() => {
form.resetFields();
form.setFieldsValue({
name,
code,
url,
icon,
parentCode,
type: type || 1,
});
}, 100)
}
}, [modalType, modalShow])
/* 点击保存 */
const handleSave = () => {
form.validateFields().then(values => {
handleAuthSetOk({
...modalData,
...values,
isEdit
});
})
};
/* 选择菜单类型 */
const handleChangeRadio = (value) => {
form.resetFields();
setType(value);
form.setFieldsValue({type: value});
};
return (
<Drawer
title="权限设置"
placement="right"
width={600}
maskClosable={false}
onClose={handleCancelModal}
visible={modalType === 'AUTH_SET_MODAL' && modalShow}
footer={
<div
style={{
textAlign: 'right',
}}
>
<Button onClick={handleCancelModal} className="mr-10">取消</Button>
<Button onClick={handleSave} type="primary">保存</Button>
</div>
}
>
<Form
form={form}
{...formItemLayout}
name="auth_set_modal"
initialValues={{ type: 1 }}
>
<Form.Item
name="type"
label="菜单类型"
>
<Radio.Group buttonStyle="solid" onChange={(e) => handleChangeRadio(e.target.value)}>
<Radio.Button disabled={(isEdit && type !== 1) ? true : false} value={1}>一级菜单</Radio.Button>
<Radio.Button disabled={(isEdit && type !== 2) ? true : false} value={2}>子菜单</Radio.Button>
<Radio.Button disabled={(isEdit && type !== 3) ? true : false} value={3}>按钮</Radio.Button>
</Radio.Group>
</Form.Item>
{
menuType !== 1 && <Form.Item
name="parentCode"
label={menuType === 2 ? "上级菜单" : "包含菜单"}
rules={
[{required: true, message: menuType === 2 ? "请选择上级菜单" : "请选择包含该按钮的菜单"}]
}
>
<Select
showSearch
placeholder={menuType === 2 ? '请选择上级菜单' : '请选择包含该按钮的菜单'}
optionFilterProp="children"
filterOption={(input, option) =>
option.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
}
>
{
dataMenuList.map(item => {
return (
<Option key={item.code} value={item.code}>{item.name}</Option>
)
})
}
</Select>
</Form.Item>
}
<Form.Item
name="name"
label={menuType === 3 ? "按钮名称" : "菜单名称"}
rules={
[
{required: true, message: menuType === 3 ? '请输入按钮名称' : '请输入菜单名称'},
{min: 2, max: 15, message: '名称长度2~15个字符'}
]
}
>
<Input maxLength={15} placeholder={menuType === 3 ? "请输入按钮名称" : "请输入菜单名称"} />
</Form.Item>
<Form.Item
name="code"
label={menuType === 3 ? "按钮code" : "菜单code"}
rules={
[{required: true, message: menuType === 3 ? '请输入按钮code' : '请输入菜单code'}]
}
>
<Input maxLength={20} placeholder={menuType === 3 ? "请输入按钮code" : "请输入菜单code"} />
</Form.Item>
{
menuType !== 3 && <>
<Form.Item
name="url"
label="菜单URL"
rules={
[{required: true, message: '请输入菜单URL'}]
}
>
<Input placeholder="请输入菜单URL" />
</Form.Item>
<Form.Item
name="icon"
label="菜单Icon"
>
<Input placeholder="请输入菜单Icon" />
</Form.Item>
</>
}
</Form>
</Drawer>
)
};
export default ModalSetAuth;
\ No newline at end of file
/**
* Author: llw
* Date: 2020.7.16
* Description: [应用列表]
*/
import React, { useEffect } from 'react';
import { connect, Link } from 'umi';
import { Card, Form, DatePicker, Input, Button, Table, Divider, Modal } from 'antd';
import { ExclamationCircleOutlined } from '@ant-design/icons';
import { paginations } from '@/constants';
import moment from 'moment';
const { RangePicker } = DatePicker;
const FormItem = Form.Item;
/* SearchForm */
const SearchForm = props => {
const [form] = Form.useForm();
const {
dataSearch,
handleReset,
handleFinish,
dataSearch: { createTimeBegin, createTimeEnd }
} = props;
useEffect(() => {
form.setFieldsValue({
...dataSearch,
createTime: [createTimeBegin ? moment(createTimeBegin) : undefined, createTimeEnd ? moment(createTimeEnd) : undefined]
});
}, [dataSearch]);
/* 点击搜索 */
const onFinish = (values) => {
handleFinish(values);
};
/* 点击重置 */
const onReset = () => {
handleReset();
};
return (
<Form
name="Form_Application"
layout="inline"
form={form}
onFinish={onFinish}
>
<FormItem label="应用名称" name="name">
<Input placeholder="请输入应用名称" style={{width: "220px"}} />
</FormItem>
<FormItem label="创建时间" name="createTime">
<RangePicker allowClear={false} />
</FormItem>
<FormItem>
<Button type="primary" htmlType="submit" className="mr-15">搜索</Button>
<Button className="mr-15" htmlType="button" onClick={onReset}>重置</Button>
<Link to="/appliction/info"><Button>创建应用</Button></Link>
</FormItem>
</Form>
)
};
/* DataTable */
const DataTable = props => {
const {
loading,
handleDel,
handleGetList,
dataApplication: { data = [], page, size, totalItem }
} = props;
/* 点击分页 */
const handlePageChange = (page, size) => {
handleGetList(page, size);
};
const columns = [
{
title: '应用名称',
dataIndex: 'name',
align: 'center'
},
{
title: '应用标识码',
dataIndex: 'code',
align: 'center',
render(t, r) {
return t || '--'
}
},
{
title: '应用链接地址',
dataIndex: 'url',
align: 'center',
render(t, r) {
return t || '--'
}
},
{
title: '创建时间',
dataIndex: 'createTime',
align: 'center',
render(t, r) {
return t ? moment(t).format("YYYY-MM-DD HH:mm:ss") : '--'
}
},
{
title: '操作',
align: 'center',
render(t, r) {
return (
<>
<Link to={`/appliction/info?id=${r.id}`}>编辑</Link>
<Divider type="vertical" />
<a onClick={() => handleDel(r)}>删除</a>
</>
)
}
}
];
const pagination = {
...paginations,
total: totalItem,
pageSize: size,
current: page,
showSizeChanger: totalItem > 20,
onChange: (page, pageSize) => {
handlePageChange(page, pageSize);
},
onShowSizeChange: (page, pageSize) => {
handlePageChange(1, pageSize);
},
showTotal(total) {
return `总共 ${total} 条数据`;
},
};
return (
<Table
rowKey="id"
loading={loading}
dataSource={data}
columns={columns}
pagination={pagination}
/>
)
};
/* Main */
const Application = props => {
const { dispatch, loading, dataSearch, dataApplication, dataApplication: { size } } = props;
useEffect(() => {
handleGetList(1, 10);
}, [])
/* 应用列表 */
const handleGetList = (page, size) => {
dispatch({type: 'Application/getApplicationList', payload: {
page: page || 1,
size: size || 10
}});
};
/* 点击搜索 */
const handleFinish = (values) => {
const { createTime, name } = values;
dispatch({type: 'Application/changeState', payload: {
dataSearch: {
name,
createTimeBegin: createTime[0] ? createTime[0].startOf('day').valueOf() : undefined,
createTimeEnd: createTime[1] ? createTime[1].endOf('day').valueOf() : undefined,
}
}});
handleGetList(0, size);
};
/* 点击重置 */
const handleReset = () => {
dispatch({type: 'Application/resetSearch'});
handleGetList(0, 10);
};
/* 点击删除 */
const handleDel = ({ id }) => {
Modal.confirm({
title: '确定删除该应用吗?',
icon: <ExclamationCircleOutlined />,
okText: '确定',
cancelText: '取消',
onOk() {
dispatch({type: 'Application/delApplication', payload: {id}});
},
});
};
return (
<Card bordered={false}>
<SearchForm
dataSearch={dataSearch}
handleReset={handleReset}
handleFinish={handleFinish}
/>
<div className="mt-24">
<DataTable
loading={loading}
handleDel={handleDel}
handleGetList={handleGetList}
dataApplication={dataApplication}
/>
</div>
</Card>
)
};
export default connect(({ Application, loading }) => ({
...Application,
loading: loading.effects["Application/getApplicationList"]
}))(Application)
\ No newline at end of file
import { routerRedux } from 'dva';
import { message } from 'antd';
import { getPermissionList } from '@/utils/utils';
import * as services from '@/services/application';
/* SerachParams */
const staticSearch = {
name: undefined,
createTimeBegin: undefined,
createTimeEnd: undefined
};
export default {
namespace: 'Application',
state: {
dataSearch: {
...staticSearch
},
dataApplication: {
data: [],
page: 1,
size: 10,
totalItem: 0,
totalPage: 0,
},
dataModal: {
modalType: '',
modalShow: false,
modalData: {}
},
dataMenuList: [], // 获取所有的菜单
dataAuth: [], // 权限模块提交给后端的数据
dataExpandedKeys: [], // tree展开的数据
dataApplicationInfo: {}, // 应用相关信息
oldInfo: {}, // 上一次权限信息
},
effects: {
/* 获取应用列表 */
*getApplicationList({ payload }, { call, put, select }) {
const { dataSearch } = yield select(state => state.Application);
try {
const res = yield call(services.getApplicationList, {
page: 1,
size: 10,
...dataSearch,
...payload
});
if (res.status === 1) {
res.data.data = res.data.data || [];
yield put({type: 'changeState', payload: {
dataApplication: res.data
}})
}
} catch (err) {
console.error(err)
}
},
/* 删除应用 */
*delApplication({ payload }, { call, put, select }) {
const { dataApplication: { data = [], page, size } } = yield select(state => state.Application);
try {
const res = yield call(services.delApplication, payload);
if (res.status === 1) {
message.success("删除成功~");
yield put({type: 'getApplicationList', payload: {
size,
page: (data.length === 1 ? (page === 1 ? 1 : page - 1) : page)
}})
}
} catch (err) {
console.error(err)
}
},
/* 新增、修改应用 */
*updateApplication({ payload }, { call, put, select }) {
const { id } = payload;
try {
const res = yield call(services[!id ? "addApplication" : "updateApplication"], payload);
if (res.status === 1) {
message.success(!id ? "新增成功~" : "修改成功~");
yield put(routerRedux.push('/appliction'));
}
} catch (err) {
console.error(err)
}
},
/* 获取应用详情 */
*getApplicationInfo({ payload }, { call, put, select }) {
try {
const res = yield call(services.getApplicationInfo, payload);
if (res.status === 1) {
const { data, dataMenu, dataExpandedKeys } = getPermissionList(res.data.permissionList, true);
yield put({type: 'changeState', payload: {
dataApplicationInfo: res.data || {},
dataAuth: data,
dataMenuList: dataMenu,
dataExpandedKeys
}})
};
return res;
} catch (err) {
console.error(err)
}
}
},
reducers: {
changeState(state, { payload }) {
return {
...state,
...payload
}
},
cancelModal(state, { payload }) {
return {
...state,
dataModal: {
modalType: '',
modalShow: false,
modalData: {}
}
}
},
resetSearch(state, { payload }) {
return {
...state,
dataSearch: {
...staticSearch
}
}
}
}
};
/**
* Author: llw
* Date: 2022.9.14
* Description: [行政执法案件详情]
*/
import React, { useEffect } from 'react';
import { connect } from 'umi';
import { Drawer } from 'antd';
import { StyledText } from '@/components/style';
import { mapCause } from '@/constants';
const ModalEnforceMent = props => {
let {
dispatch,
dataModal: {
modalType,
modalShow,
modalData: { id },
},
enforcementInfo,
} = props;
useEffect(() => {
if (modalType === 'Enforce_Ment_Modal' && modalShow) {
dispatch({ type: 'Enforcement/getEventIllegalDetail', payload: { id } });
}
}, [modalType, modalShow]);
return (
<Drawer
title="详情"
placement="right"
width={900}
maskClosable={false}
onClose={() => {
dispatch({ type: 'Enforcement/cancelModal' });
}}
visible={modalType === 'Enforce_Ment_Modal' && modalShow}
footer={null}
>
<StyledText>
<div className="item-text">
<div className="title">立案单位</div>
<div className="desc">{enforcementInfo.company || '-'}</div>
</div>
<div className="item-text">
<div className="title">类型</div>
<div className="desc">
{(mapCause[enforcementInfo.type] && mapCause[enforcementInfo.type].label) || '-'}
</div>
</div>
<div className="item-text">
<div className="title">案件编号</div>
<div className="desc">{enforcementInfo.num || '-'}</div>
</div>
<div className="item-text">
<div className="title">呈批时间</div>
<div className="desc">{enforcementInfo.submitDate || '-'}</div>
</div>
<div className="item-text">
<div className="title">法定代表人及负责人</div>
<div className="desc">{enforcementInfo.placeUserName || '-'}</div>
</div>
<div className="item-text">
<div className="title">电话</div>
<div className="desc">{enforcementInfo.placeUserTel || '-'}</div>
</div>
<div className="item-text">
<div className="title">案件来源</div>
<div className="desc">{enforcementInfo.source || '-'}</div>
</div>
<div className="item-text">
<div className="title">执法人员及执法编号</div>
<div className="desc">{enforcementInfo.nameCode || '-'}</div>
</div>
<div className="item-text">
<div className="title">案由</div>
<div className="desc">{enforcementInfo.cause || '-'}</div>
</div>
<div className="item-text">
<div className="title">案发区域</div>
<div className="desc">{enforcementInfo.area || '-'}</div>
</div>
<div className="item-text" style={{ width: '100%' }}>
<div className="title">违法依据</div>
<div className="desc">{enforcementInfo.illegalBasis || '-'}</div>
</div>
<div className="item-text" style={{ width: '100%' }}>
<div className="title">处罚依据</div>
<div className="desc">{enforcementInfo.punishBasis || '-'}</div>
</div>
<div className="item-text" style={{ width: '100%' }}>
<div className="title">地址</div>
<div className="desc">{enforcementInfo.placeName || '-'}</div>
</div>
<div className="item-text" style={{ width: '100%' }}>
<div className="title">处罚内容</div>
<div className="desc">{enforcementInfo.contents || '-'}</div>
</div>
<div className="item-text" style={{ width: '100%' }}>
<div className="title">案卷相关文书</div>
<div className="desc">{enforcementInfo.instruments || '-'}</div>
</div>
</StyledText>
</Drawer>
);
};
export default connect(({ Enforcement }) => ({
...Enforcement,
}))(ModalEnforceMent);
/**
* Author: llw
* Date: 2022.9.14
* Description: [基层网络详情]
*/
import React, { useEffect } from 'react';
import { connect } from 'umi';
import { Drawer } from 'antd';
import { StyledText } from '@/components/style';
const ModalNetworkEvent = props => {
let {
dispatch,
dataModal: {
modalType,
modalShow,
modalData: { id },
},
baseGridInfo,
} = props;
useEffect(() => {
if (modalType === 'Network_Event_Modal' && modalShow) {
dispatch({ type: 'NetworkEvent/getBaseGridDetail', payload: { id } });
}
}, [modalType, modalShow]);
return (
<Drawer
title="详情"
placement="right"
width={600}
maskClosable={false}
onClose={() => {
dispatch({ type: 'NetworkEvent/cancelModal' });
}}
visible={modalType === 'Network_Event_Modal' && modalShow}
footer={null}
>
<StyledText>
<div className="item-text">
<div className="title">事件编号</div>
<div className="desc">{baseGridInfo.eventCode || '-'}</div>
</div>
<div className="item-text">
<div className="title">事件来源</div>
<div className="desc">{baseGridInfo.eventSource || '-'}</div>
</div>
<div className="item-text">
<div className="title">发起人</div>
<div className="desc">{baseGridInfo.sponsor || '-'}</div>
</div>
<div className="item-text">
<div className="title">发起组织</div>
<div className="desc">{baseGridInfo.sponsorOrg || '-'}</div>
</div>
<div className="item-text">
<div className="title">联系方式</div>
<div className="desc">{baseGridInfo.sponsorTel || '-'}</div>
</div>
<div className="item-text">
<div className="title">发起时间</div>
<div className="desc">{baseGridInfo.origTime || '-'}</div>
</div>
<div className="item-text">
<div className="title">处理时间</div>
<div className="desc">{baseGridInfo.processingTime || '-'}</div>
</div>
<div className="item-text">
<div className="title">截止时间</div>
<div className="desc">{baseGridInfo.deadTime || '-'}</div>
</div>
<div className="item-text">
<div className="title">事发时间</div>
<div className="desc">{baseGridInfo.incidentTime || '-'}</div>
</div>
<div className="item-text">
<div className="title">事发地址</div>
<div className="desc">{baseGridInfo.incidentAddress || '-'}</div>
</div>
<div className="item-text">
<div className="title">事发经度</div>
<div className="desc">{baseGridInfo.longitude || '-'}</div>
</div>
<div className="item-text">
<div className="title">事发维度</div>
<div className="desc">{baseGridInfo.latitude || '-'}</div>
</div>
<div className="item-text">
<div className="title">统一地址</div>
<div className="desc">{baseGridInfo.address || '-'}</div>
</div>
<div className="item-text">
<div className="title">事发区县</div>
<div className="desc">{baseGridInfo.county || '-'}</div>
</div>
<div className="item-text">
<div className="title">事发镇街</div>
<div className="desc">{baseGridInfo.town || '-'}</div>
</div>
<div className="item-text">
<div className="title">事发村社</div>
<div className="desc">{baseGridInfo.village || '-'}</div>
</div>
<div className="item-text">
<div className="title">事发网格</div>
<div className="desc">{baseGridInfo.grid || '-'}</div>
</div>
<div className="item-text">
<div className="title">事发小区</div>
<div className="desc">{baseGridInfo.quarters || '-'}</div>
</div>
<div className="item-text">
<div className="title">事项大类</div>
<div className="desc">{baseGridInfo.matterBig || '-'}</div>
</div>
<div className="item-text">
<div className="title">事项小类</div>
<div className="desc">{baseGridInfo.matterSmall || '-'}</div>
</div>
<div className="item-text">
<div className="title">事项细类</div>
<div className="desc">{baseGridInfo.matterFine || '-'}</div>
</div>
<div className="item-text">
<div className="title">事项编码</div>
<div className="desc">{baseGridInfo.matterCode || '-'}</div>
</div>
<div className="item-text">
<div className="title">事件级别</div>
<div className="desc">{baseGridInfo.matterLevel || '-'}</div>
</div>
<div className="item-text">
<div className="title">事项性质</div>
<div className="desc">{baseGridInfo.matterNature || '-'}</div>
</div>
<div className="item-text" style={{ width: '100%' }}>
<div className="title">事件状态</div>
<div className="desc">{baseGridInfo.stateName || '-'}</div>
</div>
<div className="item-text" style={{ width: '100%' }}>
<div className="title">事件详情</div>
<div className="desc">{baseGridInfo.matterDetailed || '-'}</div>
</div>
<div className="item-text" style={{ width: '100%' }}>
<div className="title">事件描述</div>
<div className="desc">{baseGridInfo.matterDescribe || '-'}</div>
</div>
</StyledText>
</Drawer>
);
};
export default connect(({ NetworkEvent }) => ({
...NetworkEvent,
}))(ModalNetworkEvent);
/**
* Author: Charles
* Date: 2022.9.13
* Description: [投诉举报列表]
*/
import React, { useEffect } from 'react';
import { connect } from 'umi';
import { Card, Form, Input, Button, Table, Tooltip, DatePicker } from 'antd';
import { paginations } from '@/constants';
import { StyledPageContainer, StyledPageContent, StyledEllipsisWrap } from '@/components/style';
import { ZoomInOutlined } from '@ant-design/icons';
import moment from 'moment';
const FormItem = Form.Item;
const { RangePicker } = DatePicker;
/* SearchForm */
const SearchForm = props => {
const [form] = Form.useForm();
const {
dataSearch,
dataSearch: { startDate, endDate },
handleReset,
handleFinish,
} = props;
useEffect(() => {
form.setFieldsValue({
...dataSearch,
createTime: [
startDate ? moment(startDate) : undefined,
endDate ? moment(endDate) : undefined,
],
});
}, [dataSearch]);
/* 点击搜索 */
const onFinish = values => {
handleFinish(values);
};
/* 点击重置 */
const onReset = () => {
handleReset();
};
return (
<Form name="Form_Complaint" layout="inline" form={form} onFinish={onFinish}>
<FormItem label="公司名称" name="keyWord">
<Input placeholder="请输入公司名称" style={{ width: '250px' }} />
</FormItem>
<FormItem label="投诉举报时间" name="createTime">
<RangePicker allowClear={false} style={{ width: '300px' }} />
</FormItem>
<FormItem>
<Button type="primary" htmlType="submit" className="mr-15">
搜索
</Button>
<Button className="mr-15" htmlType="button" onClick={onReset}>
重置
</Button>
</FormItem>
</Form>
);
};
/* DataTable */
const DataTable = props => {
const {
loading,
handleGetList,
dataComplaint: { records = [], current, size, total },
} = props;
/* 点击分页 */
const handlePageChange = (current, size) => {
handleGetList(current, size);
};
const columns = [
{
title: '序号',
dataIndex: 'id',
align: 'center',
fixed: 'left',
width: 80,
render(t, r, idx) {
return (current - 1) * size + idx + 1;
},
},
{
title: '公司名称',
dataIndex: 'name',
align: 'center',
width: 200,
render: (t, r) => {
return t ? (
<Tooltip placement="top" title={t}>
<StyledEllipsisWrap maxLine={1}>{t}</StyledEllipsisWrap>
</Tooltip>
) : (
'-'
);
},
},
{
title: '公司地址',
dataIndex: 'address',
align: 'center',
width: 220,
render: (t, r) => {
return t ? (
<Tooltip placement="top" title={t}>
<StyledEllipsisWrap maxLine={2}>{t}</StyledEllipsisWrap>
</Tooltip>
) : (
'-'
);
},
},
{
title: '通讯地址',
dataIndex: 'postalAddress',
align: 'center',
width: 220,
render: (t, r) => {
return t ? (
<Tooltip placement="top" title={t}>
<StyledEllipsisWrap maxLine={2}>{t}</StyledEllipsisWrap>
</Tooltip>
) : (
'-'
);
},
},
{
title: '所属地区',
dataIndex: 'region',
align: 'center',
width: 160,
render: (t, r) => {
return t ? (
<Tooltip placement="top" title={t}>
<StyledEllipsisWrap maxLine={2}>{t}</StyledEllipsisWrap>
</Tooltip>
) : (
'-'
);
},
},
{
title: '负责人',
dataIndex: 'person',
align: 'center',
width: 150,
},
{
title: '身份证号码',
dataIndex: 'personCode',
align: 'center',
width: 220,
},
{
title: '负责人电话',
dataIndex: 'personTel',
align: 'center',
width: 150,
},
{
title: '联系人',
dataIndex: 'contacts',
align: 'center',
width: 150,
},
{
title: '联系人电话',
dataIndex: 'contactsTel',
align: 'center',
width: 180,
},
{
title: '主营范围',
dataIndex: 'mainScope',
align: 'center',
width: 180,
render: (t, r) => {
return t ? (
<Tooltip placement="top" title={t}>
<StyledEllipsisWrap maxLine={2}>{t}</StyledEllipsisWrap>
</Tooltip>
) : (
'-'
);
},
},
{
title: '备注',
dataIndex: 'remarks',
align: 'center',
width: 200,
render: (t, r) => {
return t ? (
<Tooltip placement="top" title={t}>
<StyledEllipsisWrap maxLine={2}>{t}</StyledEllipsisWrap>
</Tooltip>
) : (
'-'
);
},
},
// {
// title: '操作',
// align: 'center',
// fixed: 'right',
// width: 80,
// render(t, r) {
// return (
// <Tooltip placement="top" title="查看详情">
// <ZoomInOutlined style={{ cursor: 'pointer', fontSize: 18 }} onClick={() => {}} />
// </Tooltip>
// );
// },
// },
];
const pagination = {
...paginations,
total: total,
pageSize: size,
current,
showSizeChanger: total > 10,
onChange: (current, pageSize) => {
handlePageChange(current, pageSize);
},
onShowSizeChange: (current, pageSize) => {
handlePageChange(1, pageSize);
},
showTotal(total) {
return `总共 ${total} 条数据`;
},
};
return (
<Table
rowKey="id"
loading={loading}
dataSource={records}
columns={columns}
pagination={pagination}
scroll={{ x: 2000, y: `calc(100vh - 350px)` }}
/>
);
};
/* Main */
const Complaint = props => {
const {
dispatch,
loading,
dataSearch,
dataComplaint,
dataComplaint: { size },
} = props;
useEffect(() => {
handleGetList(1, 10);
}, []);
/* 列表 */
const handleGetList = (current, size) => {
dispatch({
type: 'Complaint/getComplaintList',
payload: {
current: current || 1,
size: size || 10,
},
});
};
/* 点击搜索 */
const handleFinish = values => {
const { keyWord, createTime } = values;
dispatch({
type: 'Complaint/changeState',
payload: {
dataSearch: {
keyWord,
startDate: createTime[0]
? moment(createTime[0].startOf('day').valueOf()).format('YYYY-MM-DD HH:mm:ss')
: undefined,
endDate: createTime[1]
? moment(createTime[1].endOf('day').valueOf()).format('YYYY-MM-DD HH:mm:ss')
: undefined,
},
},
});
handleGetList(0, size);
};
/* 点击重置 */
const handleReset = () => {
dispatch({ type: 'Complaint/resetSearch' });
handleGetList(0, 10);
};
return (
<StyledPageContainer>
<StyledPageContent>
<Card bordered={false}>
<SearchForm
dataSearch={dataSearch}
handleReset={handleReset}
handleFinish={handleFinish}
/>
<div className="mt-16">
<DataTable
loading={loading}
handleGetList={handleGetList}
dataComplaint={dataComplaint}
/>
</div>
</Card>
</StyledPageContent>
</StyledPageContainer>
);
};
export default connect(({ Complaint, loading }) => ({
...Complaint,
loading: loading.effects['Complaint/getComplaintList'],
}))(Complaint);
/**
* Author: Charles
* Date: 2022.9.13
* Description: [行政执法列表]
*/
import React, { useEffect } from 'react';
import { connect } from 'umi';
import { Card, Form, Input, Button, Table, Tooltip, Upload, message, Select } from 'antd';
import { paginations } from '@/constants';
import {
StyledPageContainer,
StyledPageContent,
StyledEllipsisWrap,
StyledPageHeader,
} from '@/components/style';
import { ZoomInOutlined, UploadOutlined } from '@ant-design/icons';
import * as services from '@/services/data';
import { ExportFile } from '@/utils/utils';
import { mapCause, enumYear } from '@/constants';
import ModalEnforcement from './Modal/ModalEnforcement';
const FormItem = Form.Item;
const Option = Select.Option;
/* SearchForm */
const SearchForm = props => {
const [form] = Form.useForm();
const { dataSearch, handleReset, handleFinish } = props;
useEffect(() => {
form.setFieldsValue({
...dataSearch,
});
}, [dataSearch]);
/* 点击搜索 */
const onFinish = values => {
handleFinish(values);
};
/* 点击重置 */
const onReset = () => {
handleReset();
};
return (
<Form name="Form_Enforcement" layout="inline" form={form} onFinish={onFinish}>
<FormItem label="当事人或法人姓名" name="placeName">
<Input placeholder="请输入当事人或法人姓名" style={{ width: '220px' }} />
</FormItem>
<FormItem label="办案单位" name="company">
<Input placeholder="请输入办案单位" style={{ width: '220px' }} />
</FormItem>
<FormItem label="案件类型" name="type">
<Select placeholder="请选择案件类型" style={{ width: '150px' }}>
<Option value="ALL">全部</Option>
{Object.values(mapCause).map(item => {
return (
<Option key={item.value} value={item.value}>
{item.label}
</Option>
);
})}
</Select>
</FormItem>
<FormItem label="处罚年份" name="yearDate">
<Select placeholder="请选择处罚年份" style={{ width: '150px' }} showSearch>
<Option value="ALL">全部</Option>
{enumYear().map(item => {
return (
<Option key={item.value} value={item.value}>
{item.label}
</Option>
);
})}
</Select>
</FormItem>
<FormItem>
<Button type="primary" htmlType="submit" className="mr-15">
搜索
</Button>
<Button className="mr-15" htmlType="button" onClick={onReset}>
重置
</Button>
</FormItem>
</Form>
);
};
/* DataTable */
const DataTable = props => {
const {
dispatch,
loading,
handleGetList,
dataEnforcement: { records = [], current, size, total },
} = props;
/* 点击分页 */
const handlePageChange = (current, size) => {
handleGetList(current, size);
};
const columns = [
{
title: '序号',
dataIndex: 'id',
align: 'center',
fixed: 'left',
width: 80,
render(t, r, idx) {
return (current - 1) * size + idx + 1;
},
},
{
title: '统一编号',
dataIndex: 'num',
align: 'center',
width: 200,
},
{
title: '案件类型',
dataIndex: 'type',
align: 'center',
width: 120,
render: (t, r) => {
return (mapCause[t] && mapCause[t].label) || '-';
},
},
{
title: '当事人',
dataIndex: 'placeUserName',
align: 'center',
width: 160,
render: (t, r) => {
return t ? (
<Tooltip placement="top" title={t}>
<StyledEllipsisWrap maxLine={1}>{t}</StyledEllipsisWrap>
</Tooltip>
) : (
'-'
);
},
},
{
title: '案由',
dataIndex: 'cause',
align: 'center',
width: 220,
render: (t, r) => {
return t ? (
<Tooltip placement="top" title={t}>
<StyledEllipsisWrap maxLine={2}>{t}</StyledEllipsisWrap>
</Tooltip>
) : (
'-'
);
},
},
{
title: '办案单位',
dataIndex: 'company',
align: 'center',
width: 160,
render: (t, r) => {
return t ? (
<Tooltip placement="top" title={t}>
<StyledEllipsisWrap maxLine={1}>{t}</StyledEllipsisWrap>
</Tooltip>
) : (
'-'
);
},
},
{
title: '立案时间',
dataIndex: 'filingDate',
align: 'center',
width: 160,
render: (t, r) => {
return t || '-';
},
},
{
title: '处罚时间',
dataIndex: 'punishDate',
align: 'center',
width: 160,
render: (t, r) => {
return t || '-';
},
},
{
title: '结案时间',
dataIndex: 'closeDate',
align: 'center',
width: 160,
render: (t, r) => {
return t || '-';
},
},
{
title: '操作',
align: 'center',
fixed: 'right',
width: 80,
render(t, r) {
return (
<Tooltip placement="top" title="查看详情">
<ZoomInOutlined
style={{ cursor: 'pointer', fontSize: 18 }}
onClick={() => {
dispatch({
type: 'Enforcement/changeState',
payload: {
dataModal: {
modalType: 'Enforce_Ment_Modal',
modalShow: true,
modalData: r,
},
},
});
}}
/>
</Tooltip>
);
},
},
];
const pagination = {
...paginations,
total: total,
pageSize: size,
current,
showSizeChanger: total > 10,
onChange: (current, pageSize) => {
handlePageChange(current, pageSize);
},
onShowSizeChange: (current, pageSize) => {
handlePageChange(1, pageSize);
},
showTotal(total) {
return `总共 ${total} 条数据`;
},
};
return (
<Table
rowKey="id"
loading={loading}
dataSource={records}
columns={columns}
pagination={pagination}
scroll={{ x: 2000, y: `calc(100vh - 448px)` }}
/>
);
};
/* Main */
const Enforcement = props => {
const {
dispatch,
loading,
loadingUpload,
dataSearch,
dataEnforcement,
dataEnforcement: { size },
} = props;
useEffect(() => {
handleGetList(1, 10);
}, []);
/* 列表 */
const handleGetList = (current, size) => {
dispatch({
type: 'Enforcement/getEnforcementList',
payload: {
current: current || 1,
size: size || 10,
},
});
};
/* 点击搜索 */
const handleFinish = values => {
dispatch({
type: 'Enforcement/changeState',
payload: {
dataSearch: {
...values,
},
},
});
handleGetList(0, size);
};
/* 点击重置 */
const handleReset = () => {
dispatch({ type: 'Enforcement/resetSearch' });
handleGetList(0, 10);
};
/* 上传组件配置 */
const uploadProps = {
customRequest: file => {
const formData = new FormData();
formData.append('file', file.file);
dispatch({ type: 'Enforcement/importEventIllegal', payload: formData });
},
beforeUpload: file => {
const isLt50M = file.size / 1024 / 1024 < 50;
if (!isLt50M) {
message.error('文件大小需小于50M');
return false;
}
return isLt50M;
},
};
return (
<StyledPageContainer>
<StyledPageHeader border={true}>
<Upload {...uploadProps}>
<Button loading={loadingUpload} type="primary" icon={<UploadOutlined />}>
数据导入
</Button>
</Upload>
<Button
type="primary"
onClick={() => {
ExportFile('行政执法案件模版', services.exportEventIllegalTemplate, {});
}}
>
模版下载
</Button>
</StyledPageHeader>
<StyledPageContent>
<Card bordered={false}>
<SearchForm
dataSearch={dataSearch}
handleReset={handleReset}
handleFinish={handleFinish}
/>
<div className="mt-16">
<DataTable
loading={loading}
dispatch={dispatch}
handleGetList={handleGetList}
dataEnforcement={dataEnforcement}
/>
</div>
</Card>
</StyledPageContent>
<ModalEnforcement />
</StyledPageContainer>
);
};
export default connect(({ Enforcement, loading }) => ({
...Enforcement,
loading: loading.effects['Enforcement/getEnforcementList'],
loadingUpload: loading.effects['Enforcement/importEventIllegal'],
}))(Enforcement);
import { Tabs } from 'antd';
import React, { useState } from 'react';
import Place from './place';
import Complaint from './complaint';
import Enforcement from './enforcement';
import NetworkEvent from './networkEvent';
import { StyledWapperTab } from '@/components/style';
const Data = () => {
const [activeKey, setActiveKey] = useState('1');
const [dataTab, setDataTab] = useState(() => {
return [
{ label: '行政执法案件', value: '1' },
{ label: '基层网络事件', value: '2' },
{ label: '场所/网站备案信息', value: '3' },
{ label: '投诉举报事件', value: '4' },
];
});
return (
<StyledWapperTab>
<Tabs
defaultActiveKey={activeKey}
onChange={key => {
setActiveKey(key);
}}
>
{dataTab.map(item => {
return <Tabs.TabPane tab={item.label} key={item.value}></Tabs.TabPane>;
})}
</Tabs>
{activeKey === '1' ? <Enforcement /> : null}
{activeKey === '2' ? <NetworkEvent /> : null}
{activeKey === '3' ? <Place /> : null}
{activeKey === '4' ? <Complaint /> : null}
</StyledWapperTab>
);
};
export default Data;
import * as services from '@/services/data';
import moment from 'moment';
/* SerachParams */
const staticSearch = {
current: 1,
size: 10,
keyWord: undefined,
startDate: moment(new Date())
.add(-7, 'days')
.startOf('day'),
endDate: moment(new Date())
.add(0, 'days')
.endOf('day'),
};
export default {
namespace: 'Complaint',
state: {
dataSearch: {
...staticSearch,
},
dataComplaint: {
records: [],
current: 1,
size: 10,
total: 0,
totalPage: 0,
},
},
effects: {
/* 获取投诉举报列表 */
*getComplaintList({ payload }, { call, put, select }) {
const {
dataSearch,
dataSearch: { startDate, endDate },
} = yield select(state => state.Complaint);
try {
const res = yield call(services.getComplaintList, {
current: 1,
size: 10,
...dataSearch,
...payload,
startDate: moment(startDate).format('YYYY-MM-DD HH:mm:ss'),
endDate: moment(endDate).format('YYYY-MM-DD HH:mm:ss'),
});
if (res.code === 0) {
res.data.records =
res.data.records.map(item => {
return {
...(item.placeVo || {}),
...item,
};
}) || [];
yield put({
type: 'changeState',
payload: {
dataComplaint: res.data,
},
});
}
} catch (err) {
console.error(err);
}
},
},
reducers: {
changeState(state, { payload }) {
return {
...state,
...payload,
};
},
resetSearch(state, { payload }) {
return {
...state,
dataSearch: {
...staticSearch,
},
};
},
},
};
import * as services from '@/services/data';
import { message } from 'antd';
import moment from 'moment';
/* SerachParams */
const staticSearch = {
current: 1,
size: 10,
placeName: undefined,
company: undefined,
type: 'ALL',
yearDate: 'ALL',
};
export default {
namespace: 'Enforcement',
state: {
dataSearch: {
...staticSearch,
},
dataEnforcement: {
records: [],
current: 1,
size: 10,
total: 0,
totalPage: 0,
},
dataModal: {
modalType: '',
modalShow: false,
modalData: {},
},
enforcementInfo: {},
},
effects: {
/* 获取行政执法列表 */
*getEnforcementList({ payload }, { call, put, select }) {
const {
dataSearch,
dataSearch: { type, yearDate },
} = yield select(state => state.Enforcement);
try {
const res = yield call(services.getEventIllegalList, {
current: 1,
size: 10,
...dataSearch,
...payload,
type: type === 'ALL' ? '' : type,
yearDate: yearDate === 'ALL' ? '' : yearDate,
});
if (res.code === 0) {
res.data.records =
res.data.records.map(item => {
return {
...(item.placeVo || {}),
...item,
};
}) || [];
yield put({
type: 'changeState',
payload: {
dataEnforcement: res.data,
},
});
}
} catch (err) {
console.error(err);
}
},
/* 行政执法案件导入 */
*importEventIllegal({ payload }, { call, put, select }) {
try {
const res = yield call(services.importEventIllegal, payload);
if (res.code === 0) {
message.success('导入成功');
yield put({ type: 'getEnforcementList' });
}
} catch (err) {
console.error(err);
}
},
/* 获取详情 */
*getEventIllegalDetail({ payload }, { call, put, select }) {
try {
const res = yield call(services.getEventIllegalDetail, payload);
if (res.code === 0) {
yield put({ type: 'changeState', payload: { enforcementInfo: res.data } });
}
} catch (err) {
console.error(err);
}
},
},
reducers: {
changeState(state, { payload }) {
return {
...state,
...payload,
};
},
cancelModal(state, { payload }) {
return {
...state,
dataModal: {
modalType: '',
modalShow: false,
modalData: {},
},
};
},
resetSearch(state, { payload }) {
return {
...state,
dataSearch: {
...staticSearch,
},
};
},
},
};
import * as services from '@/services/data';
import moment from 'moment';
/* SerachParams */
const staticSearch = {
current: 1,
size: 10,
eventCode: undefined,
keyWord: undefined,
region: 'ALL',
sponsor: 'ALL',
handledBy: 'ALL',
sponsorOrg: 'ALL',
matterBig: 'ALL',
eventSource: 'ALL',
state: 'ALL',
startDate: moment(new Date())
.add(-7, 'days')
.startOf('day'),
endDate: moment(new Date())
.add(0, 'days')
.endOf('day'),
};
export default {
namespace: 'NetworkEvent',
state: {
dataSearch: {
...staticSearch,
},
dataNetworkEvent: {
records: [],
current: 1,
size: 10,
total: 0,
totalPage: 0,
},
dataModal: {
modalType: '',
modalShow: false,
modalData: {},
},
baseGridInfo: {}, // 基层网格详情
eventSourceList: [], // 事件源
matterBigList: [], // 事件类型
handledByList: [], // 处理人
sponsorList: [], // 发起人
sponsorOrgList: [], // 发起组织
},
effects: {
/* 获取基层网络列表 */
*getNetworkEventList({ payload }, { call, put, select }) {
const {
dataSearch,
dataSearch: {
region,
sponsor,
handledBy,
sponsorOrg,
matterBig,
eventSource,
state,
startDate,
endDate,
},
} = yield select(state => state.NetworkEvent);
try {
const res = yield call(services.getNetworkEventList, {
current: 1,
size: 10,
...dataSearch,
...payload,
startDate: moment(startDate).format('YYYY-MM-DD HH:mm:ss'),
endDate: moment(endDate).format('YYYY-MM-DD HH:mm:ss'),
region: region === 'ALL' ? '' : region,
sponsor: sponsor === 'ALL' ? '' : sponsor,
handledBy: handledBy === 'ALL' ? '' : handledBy,
sponsorOrg: sponsorOrg === 'ALL' ? '' : sponsorOrg,
matterBig: matterBig === 'ALL' ? '' : matterBig,
eventSource: eventSource === 'ALL' ? '' : eventSource,
state: state === 'ALL' ? '' : state,
});
if (res.code === 0) {
res.data.records =
res.data.records.map(item => {
return {
...(item.placeVo || {}),
...item,
};
}) || [];
yield put({
type: 'changeState',
payload: {
dataNetworkEvent: res.data,
},
});
}
} catch (err) {
console.error(err);
}
},
/* 获取搜索条件 */
*getBaseGridSponsor({ payload }, { call, put, select }) {
try {
const res = yield call(services.getBaseGridSponsor);
if (res.code === 0) {
res.data = res.data || {};
yield put({
type: 'changeState',
payload: {
eventSourceList: res.data.eventSourceList || [],
handledByList: res.data.handledByList || [],
sponsorList: res.data.sponsorList || [],
sponsorOrgList: res.data.sponsorOrgList || [],
matterBigList: res.data.matterBigList || [],
},
});
}
} catch (err) {
console.error(err);
}
},
/* 获取详情 */
*getBaseGridDetail({ payload }, { call, put, select }) {
try {
const res = yield call(services.getBaseGridDetail, payload);
if (res.code === 0) {
yield put({
type: 'changeState',
payload: { baseGridInfo: res.data || {} },
});
}
} catch (err) {
console.error(err);
}
},
},
reducers: {
changeState(state, { payload }) {
return {
...state,
...payload,
};
},
cancelModal(state, { payload }) {
return {
...state,
dataModal: {
modalType: '',
modalShow: false,
modalData: {},
},
};
},
resetSearch(state, { payload }) {
return {
...state,
dataSearch: {
...staticSearch,
},
};
},
},
};
import * as services from '@/services/data';
import { message } from 'antd';
/* SerachParams */
const staticSearch = {
current: 1,
size: 10,
name: undefined,
};
export default {
namespace: 'Place',
state: {
dataSearch: {
...staticSearch,
},
dataPlace: {
records: [],
current: 1,
size: 10,
total: 0,
totalPage: 0,
},
},
effects: {
/* 获取场所列表 */
*getPlaceList({ payload }, { call, put, select }) {
const { dataSearch } = yield select(state => state.Place);
try {
const res = yield call(services.getPlaceList, {
current: 1,
size: 10,
...dataSearch,
...payload,
});
if (res.code === 0) {
res.data.records = res.data.records || [];
yield put({
type: 'changeState',
payload: {
dataPlace: res.data,
},
});
}
} catch (err) {
console.error(err);
}
},
/* 场所导入 */
*importPlace({ payload }, { call, put, select }) {
try {
const res = yield call(services.importPlace, payload);
if (res.code === 0) {
message.success('导入成功');
yield put({ type: 'getPlaceList' });
}
} catch (err) {
console.error(err);
}
},
},
reducers: {
changeState(state, { payload }) {
return {
...state,
...payload,
};
},
resetSearch(state, { payload }) {
return {
...state,
dataSearch: {
...staticSearch,
},
};
},
},
};
/**
* Author: Charles
* Date: 2022.9.13
* Description: [基础网络事件列表]
*/
import React, { useEffect } from 'react';
import { connect } from 'umi';
import { Card, Form, Input, Button, Table, Tooltip, Select, DatePicker } from 'antd';
import { paginations, mapEventStatus, enumArea } from '@/constants';
import { StyledPageContainer, StyledPageContent, StyledEllipsisWrap } from '@/components/style';
import { ZoomInOutlined } from '@ant-design/icons';
import moment from 'moment';
import ModalNetworkEvent from './Modal/ModalNetworkEvent';
const { RangePicker } = DatePicker;
const FormItem = Form.Item;
const Option = Select.Option;
/* SearchForm */
const SearchForm = props => {
const [form] = Form.useForm();
const {
dataSearch,
dataSearch: { startDate, endDate },
handleReset,
handleFinish,
eventSourceList,
matterBigList,
handledByList,
sponsorList,
sponsorOrgList,
} = props;
useEffect(() => {
form.setFieldsValue({
...dataSearch,
createTime: [
startDate ? moment(startDate) : undefined,
endDate ? moment(endDate) : undefined,
],
});
}, [dataSearch]);
/* 点击搜索 */
const onFinish = values => {
handleFinish(values);
};
/* 点击重置 */
const onReset = () => {
handleReset();
};
return (
<Form name="Form_NetworkEvent" layout="inline" form={form} onFinish={onFinish}>
<FormItem label="事件编号" name="eventCode">
<Input placeholder="请输入事件编号" style={{ width: '200px' }} />
</FormItem>
<FormItem label="事件关键字" name="keyWord">
<Input placeholder="请输入事件关键字" style={{ width: '200px' }} />
</FormItem>
<FormItem label="区域" name="region">
<Select placeholder="请选择区域" style={{ width: '150px' }}>
<Option value="ALL">全部</Option>
{enumArea.map(item => {
return (
<Option key={item} value={item}>
{item}
</Option>
);
})}
</Select>
</FormItem>
<FormItem label="发起人" name="sponsor">
<Select placeholder="请选择发起人" style={{ width: '150px' }}>
<Option value="ALL">全部</Option>
{sponsorList.map(item => {
return (
<Option key={item} value={item}>
{item}
</Option>
);
})}
</Select>
</FormItem>
<FormItem label="处理人" name="handledBy">
<Select placeholder="请选择处理人" style={{ width: '150px' }}>
<Option value="ALL">全部</Option>
{handledByList.map(item => {
return (
<Option key={item} value={item}>
{item}
</Option>
);
})}
</Select>
</FormItem>
<FormItem label="发起组织" name="sponsorOrg">
<Select placeholder="请选择发起组织" style={{ width: '150px' }}>
<Option value="ALL">全部</Option>
{sponsorOrgList.map(item => {
return (
<Option key={item} value={item}>
{item}
</Option>
);
})}
</Select>
</FormItem>
<FormItem label="事件类型" name="matterBig">
<Select placeholder="请选择事件类型" style={{ width: '150px' }}>
<Option value="ALL">全部</Option>
{matterBigList.map(item => {
return (
<Option key={item} value={item}>
{item}
</Option>
);
})}
</Select>
</FormItem>
<FormItem label="事件来源" name="eventSource">
<Select placeholder="请选择事件来源" style={{ width: '150px' }}>
<Option value="ALL">全部</Option>
{eventSourceList.map(item => {
return (
<Option key={item} value={item}>
{item}
</Option>
);
})}
</Select>
</FormItem>
<FormItem label="事件状态" name="state">
<Select placeholder="请选择事件状态" style={{ width: '150px' }}>
<Option value="ALL">全部</Option>
{Object.values(mapEventStatus).map(item => {
const { label, value } = item;
return (
<Option key={value} value={value}>
{label}
</Option>
);
})}
</Select>
</FormItem>
<FormItem label="发起时间" name="createTime">
<RangePicker allowClear={false} style={{ width: '320px' }} />
</FormItem>
<FormItem>
<Button type="primary" htmlType="submit" className="mr-15">
搜索
</Button>
<Button className="mr-15" htmlType="button" onClick={onReset}>
重置
</Button>
</FormItem>
</Form>
);
};
/* DataTable */
const DataTable = props => {
const {
dispatch,
loading,
handleGetList,
dataNetworkEvent: { records = [], current, size, total },
} = props;
/* 点击分页 */
const handlePageChange = (current, size) => {
handleGetList(current, size);
};
const columns = [
{
title: '序号',
dataIndex: 'id',
align: 'center',
fixed: 'left',
width: 80,
render(t, r, idx) {
return (current - 1) * size + idx + 1;
},
},
{
title: '事件编号',
dataIndex: 'eventCode',
align: 'center',
width: 180,
render: (t, r) => {
return t || '-';
},
},
{
title: '镇街',
dataIndex: 'town',
align: 'center',
width: 180,
render: (t, r) => {
return t || '-';
},
},
{
title: '村庄',
dataIndex: 'village',
align: 'center',
width: 180,
render: (t, r) => {
return t || '-';
},
},
{
title: '网络',
dataIndex: 'grid',
align: 'center',
width: 160,
render: (t, r) => {
return t || '-';
},
},
{
title: '发起人',
dataIndex: 'sponsor',
align: 'center',
width: 140,
},
{
title: '事件来源',
dataIndex: 'eventSource',
align: 'center',
width: 140,
},
{
title: '事件级别',
dataIndex: 'matterLevel',
align: 'center',
width: 140,
},
{
title: '事件大类',
dataIndex: 'matterBig',
align: 'center',
width: 140,
},
{
title: '事件小类',
dataIndex: 'matterSmall',
align: 'center',
width: 140,
},
{
title: '事件描述',
dataIndex: 'matterDescribe',
align: 'center',
width: 220,
render: (t, r) => {
return t ? (
<Tooltip placement="top" title={t}>
<StyledEllipsisWrap maxLine={2}>{t}</StyledEllipsisWrap>
</Tooltip>
) : (
'-'
);
},
},
{
title: '发起事件时间',
dataIndex: 'origTime',
align: 'center',
width: 200,
},
{
title: '事件状态',
dataIndex: 'stateName',
align: 'center',
width: 160,
},
{
title: '操作',
align: 'center',
fixed: 'right',
width: 80,
render(t, r) {
return (
<Tooltip placement="top" title="查看详情">
<ZoomInOutlined
style={{ cursor: 'pointer', fontSize: 18 }}
onClick={() => {
dispatch({
type: 'NetworkEvent/changeState',
payload: {
dataModal: {
modalType: 'Network_Event_Modal',
modalShow: true,
modalData: r,
},
},
});
}}
/>
</Tooltip>
);
},
},
];
const pagination = {
...paginations,
total: total,
pageSize: size,
current,
showSizeChanger: total > 10,
onChange: (current, pageSize) => {
handlePageChange(current, pageSize);
},
onShowSizeChange: (current, pageSize) => {
handlePageChange(1, pageSize);
},
showTotal(total) {
return `总共 ${total} 条数据`;
},
};
return (
<Table
rowKey="id"
loading={loading}
dataSource={records}
columns={columns}
pagination={pagination}
scroll={{ x: 2000, y: `calc(100vh - 446px)` }}
/>
);
};
/* Main */
const NetworkEvent = props => {
const {
dispatch,
loading,
dataNetworkEvent,
dataNetworkEvent: { size },
} = props;
useEffect(() => {
handleGetList(1, 10);
dispatch({ type: 'NetworkEvent/getBaseGridSponsor' });
}, []);
/* 列表 */
const handleGetList = (current, size) => {
dispatch({
type: 'NetworkEvent/getNetworkEventList',
payload: {
current: current || 1,
size: size || 10,
},
});
};
/* 点击搜索 */
const handleFinish = values => {
const { createTime } = values;
dispatch({
type: 'NetworkEvent/changeState',
payload: {
dataSearch: {
...values,
startDate: createTime[0]
? moment(createTime[0].startOf('day').valueOf()).format('YYYY-MM-DD HH:mm:ss')
: undefined,
endDate: createTime[1]
? moment(createTime[1].endOf('day').valueOf()).format('YYYY-MM-DD HH:mm:ss')
: undefined,
createTime: undefined,
},
},
});
handleGetList(0, size);
};
/* 点击重置 */
const handleReset = () => {
dispatch({ type: 'NetworkEvent/resetSearch' });
handleGetList(0, 10);
};
return (
<StyledPageContainer>
<StyledPageContent>
<Card bordered={false}>
<SearchForm handleReset={handleReset} handleFinish={handleFinish} {...props} />
<div className="mt-16">
<DataTable
dispatch={dispatch}
loading={loading}
handleGetList={handleGetList}
dataNetworkEvent={dataNetworkEvent}
/>
</div>
</Card>
</StyledPageContent>
<ModalNetworkEvent />
</StyledPageContainer>
);
};
export default connect(({ NetworkEvent, loading }) => ({
...NetworkEvent,
loading: loading.effects['NetworkEvent/getNetworkEventList'],
}))(NetworkEvent);
/**
* Author: Charles
* Date: 2022.9.13
* Description: [场所列表]
*/
import React, { useEffect } from 'react';
import { connect } from 'umi';
import { Card, Form, Input, Button, Table, Tooltip, Upload, message } from 'antd';
import { paginations } from '@/constants';
import {
StyledPageContainer,
StyledPageContent,
StyledEllipsisWrap,
StyledPageHeader,
} from '@/components/style';
import { ZoomInOutlined, UploadOutlined } from '@ant-design/icons';
import * as services from '@/services/data';
import { ExportFile } from '@/utils/utils';
const FormItem = Form.Item;
/* SearchForm */
const SearchForm = props => {
const [form] = Form.useForm();
const { dataSearch, handleReset, handleFinish } = props;
useEffect(() => {
form.setFieldsValue({
...dataSearch,
});
}, [dataSearch]);
/* 点击搜索 */
const onFinish = values => {
handleFinish(values);
};
/* 点击重置 */
const onReset = () => {
handleReset();
};
return (
<Form name="Form_Place" layout="inline" form={form} onFinish={onFinish}>
<FormItem label="公司名称" name="name">
<Input placeholder="请输入公司名称" style={{ width: '250px' }} />
</FormItem>
<FormItem>
<Button type="primary" htmlType="submit" className="mr-15">
搜索
</Button>
<Button className="mr-15" htmlType="button" onClick={onReset}>
重置
</Button>
</FormItem>
</Form>
);
};
/* DataTable */
const DataTable = props => {
const {
loading,
handleGetList,
dataPlace: { records = [], current, size, total },
} = props;
/* 点击分页 */
const handlePageChange = (current, size) => {
handleGetList(current, size);
};
const columns = [
{
title: '序号',
dataIndex: 'id',
align: 'center',
fixed: 'left',
width: 80,
render(t, r, idx) {
return (current - 1) * size + idx + 1;
},
},
{
title: '公司名称',
dataIndex: 'name',
align: 'center',
width: 200,
render: (t, r) => {
return t ? (
<Tooltip placement="top" title={t}>
<StyledEllipsisWrap maxLine={1}>{t}</StyledEllipsisWrap>
</Tooltip>
) : (
'-'
);
},
},
{
title: '公司地址',
dataIndex: 'address',
align: 'center',
width: 220,
render: (t, r) => {
return t ? (
<Tooltip placement="top" title={t}>
<StyledEllipsisWrap maxLine={2}>{t}</StyledEllipsisWrap>
</Tooltip>
) : (
'-'
);
},
},
{
title: '通讯地址',
dataIndex: 'postalAddress',
align: 'center',
width: 220,
render: (t, r) => {
return t ? (
<Tooltip placement="top" title={t}>
<StyledEllipsisWrap maxLine={2}>{t}</StyledEllipsisWrap>
</Tooltip>
) : (
'-'
);
},
},
{
title: '所属地区',
dataIndex: 'region',
align: 'center',
width: 160,
render: (t, r) => {
return t ? (
<Tooltip placement="top" title={t}>
<StyledEllipsisWrap maxLine={2}>{t}</StyledEllipsisWrap>
</Tooltip>
) : (
'-'
);
},
},
{
title: '负责人',
dataIndex: 'person',
align: 'center',
width: 150,
},
{
title: '身份证号码',
dataIndex: 'personCode',
align: 'center',
width: 220,
},
{
title: '负责人电话',
dataIndex: 'personTel',
align: 'center',
width: 150,
},
{
title: '联系人',
dataIndex: 'contacts',
align: 'center',
width: 150,
},
{
title: '联系人电话',
dataIndex: 'contactsTel',
align: 'center',
width: 180,
},
{
title: '主营范围',
dataIndex: 'mainScope',
align: 'center',
width: 180,
render: (t, r) => {
return t ? (
<Tooltip placement="top" title={t}>
<StyledEllipsisWrap maxLine={2}>{t}</StyledEllipsisWrap>
</Tooltip>
) : (
'-'
);
},
},
{
title: '备注',
dataIndex: 'remarks',
align: 'center',
width: 200,
render: (t, r) => {
return t ? (
<Tooltip placement="top" title={t}>
<StyledEllipsisWrap maxLine={2}>{t}</StyledEllipsisWrap>
</Tooltip>
) : (
'-'
);
},
},
// {
// title: '操作',
// align: 'center',
// fixed: 'right',
// width: 80,
// render(t, r) {
// return (
// <Tooltip placement="top" title="查看详情">
// <ZoomInOutlined style={{ cursor: 'pointer', fontSize: 18 }} onClick={() => {}} />
// </Tooltip>
// );
// },
// },
];
const pagination = {
...paginations,
total: total,
pageSize: size,
current,
showSizeChanger: total > 10,
onChange: (current, pageSize) => {
handlePageChange(current, pageSize);
},
onShowSizeChange: (current, pageSize) => {
handlePageChange(1, pageSize);
},
showTotal(total) {
return `总共 ${total} 条数据`;
},
};
return (
<Table
rowKey="id"
loading={loading}
dataSource={records}
columns={columns}
pagination={pagination}
scroll={{ x: 2000, y: `calc(100vh - 400px)` }}
/>
);
};
/* Main */
const Place = props => {
const {
dispatch,
loading,
loadingUpload,
dataSearch,
dataPlace,
dataPlace: { size },
} = props;
useEffect(() => {
handleGetList(1, 10);
}, []);
/* 列表 */
const handleGetList = (current, size) => {
dispatch({
type: 'Place/getPlaceList',
payload: {
current: current || 1,
size: size || 10,
},
});
};
/* 点击搜索 */
const handleFinish = values => {
const { name } = values;
dispatch({
type: 'Place/changeState',
payload: {
dataSearch: { name },
},
});
handleGetList(0, size);
};
/* 点击重置 */
const handleReset = () => {
dispatch({ type: 'Place/resetSearch' });
handleGetList(0, 10);
};
/* 上传组件配置 */
const uploadProps = {
customRequest: file => {
const formData = new FormData();
formData.append('file', file.file);
dispatch({ type: 'Place/importPlace', payload: formData });
},
beforeUpload: file => {
const isLt50M = file.size / 1024 / 1024 < 50;
if (!isLt50M) {
message.error('文件大小需小于50M');
return false;
}
return isLt50M;
},
};
return (
<StyledPageContainer>
<StyledPageHeader border={true}>
<Upload {...uploadProps}>
<Button loading={loadingUpload} type="primary" icon={<UploadOutlined />}>
数据导入
</Button>
</Upload>
<Button
type="primary"
onClick={() => {
ExportFile('场所/网站备案信息模版', services.exportPlaceTemplate, {});
}}
>
模版下载
</Button>
</StyledPageHeader>
<StyledPageContent>
<Card bordered={false}>
<SearchForm
dataSearch={dataSearch}
handleReset={handleReset}
handleFinish={handleFinish}
/>
<div className="mt-16">
<DataTable loading={loading} handleGetList={handleGetList} dataPlace={dataPlace} />
</div>
</Card>
</StyledPageContent>
</StyledPageContainer>
);
};
export default connect(({ Place, loading }) => ({
...Place,
loading: loading.effects['Place/getPlaceList'],
loadingUpload: loading.effects['Place/importPlace'],
}))(Place);
/**
* Author: Charles
* Date: 2022.9.13
* Description: [事件风险详情]
*/
import React, { useEffect } from 'react';
import { connect } from 'umi';
import { Modal, Tooltip, Table } from 'antd';
import { paginations, mapStatus, mapRiskType, mapRiskSourceType } from '@/constants';
import { StyledEllipsisWrap } from '@/components/style';
const ModalEventInfo = props => {
const {
dispatch,
loading,
dataModal: {
modalType,
modalShow,
modalData: { id },
},
dataEventRiskList,
} = props;
useEffect(() => {
if (modalType === 'EVENT_INFO_MODAL' && modalShow) {
dispatch({ type: 'Event/getEventRiskList', payload: { eventId: id } });
}
}, [modalType, modalShow]);
const columns = [
{
title: '序号',
dataIndex: 'id',
align: 'center',
fixed: 'left',
width: 80,
render(t, r, idx) {
return idx + 1;
},
},
{
title: '风险源名称',
dataIndex: 'riskName',
align: 'center',
width: 160,
render: (t, r) => {
return (
<Tooltip placement="top" title={t}>
<StyledEllipsisWrap maxLine={1}>{t}</StyledEllipsisWrap>
</Tooltip>
);
},
},
{
title: '风险源地址',
dataIndex: 'riskUrl',
align: 'center',
width: 160,
render: (t, r) => {
return (
<Tooltip placement="top" title={t}>
<StyledEllipsisWrap maxLine={2}>{t}</StyledEllipsisWrap>
</Tooltip>
);
},
},
{
title: '风险站点',
dataIndex: 'riskHost',
align: 'center',
width: 160,
render: (t, r) => {
return (
<Tooltip placement="top" title={t}>
<StyledEllipsisWrap maxLine={2}>{t}</StyledEllipsisWrap>
</Tooltip>
);
},
},
{
title: '风险类型',
dataIndex: 'riskType',
align: 'center',
width: 160,
render: (t, r) => {
return mapRiskType[t] ? mapRiskType[t].label : '-';
},
},
{
title: '风险源类型',
dataIndex: 'fileFormat',
align: 'center',
width: 160,
render: (t, r) => {
return mapRiskSourceType[t] ? mapRiskSourceType[t].label : '-';
},
},
{
title: '检测时间',
dataIndex: 'checkTime',
align: 'center',
width: 160,
render: (t, r) => {
return t || '-';
},
},
{
title: '处理状态',
dataIndex: 'status',
align: 'center',
fixed: 'right',
width: 100,
render: (t, r) => {
return mapStatus[t] ? mapStatus[t].label : '-';
},
},
];
const pagination = {
...paginations,
total: dataEventRiskList.length,
pageSize: 500,
current: 1,
showSizeChanger: dataEventRiskList.length > 500,
showTotal(total) {
return `总共 ${total} 条数据`;
},
};
return (
<Modal
title="事件风险详情"
placement="right"
width={1000}
maskClosable={false}
onCancel={() => {
dispatch({ type: 'Event/cancelModal' });
}}
visible={modalType === 'EVENT_INFO_MODAL' && modalShow}
footer={null}
>
<Table
rowKey="id"
loading={loading}
dataSource={dataEventRiskList}
columns={columns}
pagination={pagination}
scroll={{ x: 1500, y: 600 }}
/>
</Modal>
);
};
export default connect(({ Event, loading }) => ({
...Event,
loading: loading.effects['Event/getEventRiskList'],
}))(ModalEventInfo);
/**
* Author: Charles
* Date: 2022.9.13
* Description: [事件日志]
*/
import React, { useEffect } from 'react';
import { connect } from 'umi';
import { Modal, Tooltip, Table } from 'antd';
import { paginations, mapStatus, mapRiskType, mapRiskSourceType } from '@/constants';
import { StyledEllipsisWrap } from '@/components/style';
const ModalEventLog = props => {
const {
dispatch,
loading,
dataModal: {
modalType,
modalShow,
modalData: { id },
},
dataEventLogList: { records = [], current, size, total },
} = props;
useEffect(() => {
if (modalType === 'View_Event_Log' && modalShow) {
dispatch({ type: 'Event/getEventRiskLog', payload: { eventId: id } });
}
}, [modalType, modalShow]);
/* 点击分页 */
const handlePageChange = (current, size) => {
dispatch({ type: 'Event/getEventRiskLog', payload: { eventId: id, current, size } });
};
const columns = [
{
title: '序号',
dataIndex: 'id',
align: 'center',
fixed: 'left',
width: 60,
render(t, r, idx) {
return idx + 1;
},
},
{
title: '发送内容',
dataIndex: 'content',
align: 'center',
width: 160,
render: (t, r) => {
return (
<Tooltip placement="top" title={t}>
<StyledEllipsisWrap maxLine={1}>{t || '-'}</StyledEllipsisWrap>
</Tooltip>
);
},
},
{
title: '接收者信息',
dataIndex: 'recipient',
align: 'center',
width: 160,
render: (t, r) => {
return r.type == 2
? `${r.recipientName || '-'}${r.recipient || '-'})`
: `${r.recipientName || '-'}`;
},
},
{
title: '状态',
dataIndex: 'status',
align: 'center',
width: 120,
},
{
title: '失败原因',
dataIndex: 'statusMessage:',
align: 'center',
width: 160,
render: (t, r) => {
return (
<Tooltip placement="top" title={t}>
<StyledEllipsisWrap maxLine={1}>{t || '-'}</StyledEllipsisWrap>
</Tooltip>
);
},
},
];
const pagination = {
...paginations,
total: total,
pageSize: size,
current,
showSizeChanger: total > 10,
onChange: (current, pageSize) => {
handlePageChange(current, pageSize);
},
onShowSizeChange: (current, pageSize) => {
handlePageChange(1, pageSize);
},
showTotal(total) {
return `总共 ${total} 条数据`;
},
};
return (
<Modal
title="事件日志"
placement="right"
width={1000}
maskClosable={false}
onCancel={() => {
dispatch({ type: 'Event/cancelModal' });
}}
visible={modalType === 'View_Event_Log' && modalShow}
footer={null}
>
<Table
rowKey="id"
loading={loading}
dataSource={records}
columns={columns}
pagination={pagination}
scroll={{ x: 1500, y: 600 }}
/>
</Modal>
);
};
export default connect(({ Event, loading }) => ({
...Event,
loading: loading.effects['Event/getEventRiskLog'],
}))(ModalEventLog);
/**
* Author: Charles
* Date: 2022.9.13
* Description: [事件列表]
*/
import React, { useEffect } from 'react';
import { connect } from 'umi';
import { Card, Form, Input, Button, Table, Select, DatePicker, Tooltip, Divider } from 'antd';
import { paginations, mapStatus, mapEventLevel, mapEventType, enumRiskLabel } from '@/constants';
import { ZoomInOutlined, SearchOutlined } from '@ant-design/icons';
import { StyledPageContainer, StyledPageContent, StyledEllipsisWrap } from '@/components/style';
import ModalEventInfo from './ModalEventInfo';
import ModalEventLog from './ModalEventLog';
import moment from 'moment';
const { RangePicker } = DatePicker;
const FormItem = Form.Item;
const { Option } = Select;
/* SearchForm */
const SearchForm = props => {
const [form] = Form.useForm();
const {
dataSearch,
dataSearch: { startTime, endTime },
handleReset,
handleFinish,
} = props;
useEffect(() => {
form.setFieldsValue({
...dataSearch,
createTime: [
startTime ? moment(startTime) : undefined,
endTime ? moment(endTime) : undefined,
],
});
}, [dataSearch]);
/* 点击搜索 */
const onFinish = values => {
handleFinish(values);
};
/* 点击重置 */
const onReset = () => {
handleReset();
};
return (
<Form name="Form_Event" layout="inline" form={form} onFinish={onFinish}>
<FormItem label="公司名称" name="companyName">
<Input placeholder="请输入公司名称" style={{ width: '250px' }} />
</FormItem>
<FormItem label="事件类型" name="eventType">
<Select placeholder="请选择事件类型" style={{ width: '150px' }}>
<Option value="ALL">全部</Option>
{Object.values(mapEventType).map(item => {
const { label, value } = item;
return (
<Option key={value} value={value}>
{label}
</Option>
);
})}
</Select>
</FormItem>
<FormItem label="事件等级" name="eventLevel">
<Select placeholder="请选择事件等级" style={{ width: '150px' }}>
<Option value="ALL">全部</Option>
{Object.values(mapEventLevel).map(item => {
const { label, value } = item;
return (
<Option key={value} value={value}>
{label}
</Option>
);
})}
</Select>
</FormItem>
<FormItem label="处理状态" name="status">
<Select placeholder="请选择处理状态" style={{ width: '150px' }}>
<Option value="ALL">全部</Option>
{Object.values(mapStatus).map(item => {
const { label, value } = item;
return (
<Option key={value} value={value}>
{label}
</Option>
);
})}
</Select>
</FormItem>
<FormItem label="创建时间" name="createTime">
<RangePicker allowClear={false} />
</FormItem>
<FormItem>
<Button type="primary" htmlType="submit" className="mr-15">
搜索
</Button>
<Button className="mr-15" htmlType="button" onClick={onReset}>
重置
</Button>
</FormItem>
</Form>
);
};
/* DataTable */
const DataTable = props => {
const {
dispatch,
loading,
handleGetList,
dataEvent: { records = [], current, size, total },
} = props;
/* 点击分页 */
const handlePageChange = (current, size) => {
handleGetList(current, size);
};
const columns = [
{
title: '序号',
dataIndex: 'id',
align: 'center',
fixed: 'left',
width: 80,
render(t, r, idx) {
return (current - 1) * size + idx + 1;
},
},
{
title: '事件编号',
dataIndex: 'serialNumber',
align: 'center',
width: 220,
},
{
title: '事件类型',
dataIndex: 'eventType',
align: 'center',
width: 160,
render: (t, r) => {
return mapEventType[t] ? mapEventType[t].label : '-';
},
},
{
title: '事件等级',
dataIndex: 'eventLevel',
align: 'center',
width: 160,
render: (t, r) => {
return mapEventLevel[t] ? mapEventLevel[t].label : '-';
},
},
{
title: '公司名称',
dataIndex: 'companyName',
align: 'center',
width: 160,
render: (t, r) => {
return t ? (
<Tooltip placement="top" title={t}>
<StyledEllipsisWrap maxLine={1}>{t}</StyledEllipsisWrap>
</Tooltip>
) : (
'-'
);
},
},
{
title: '公司地址',
dataIndex: 'companyAddress',
align: 'center',
width: 260,
render: (t, r) => {
return t ? (
<Tooltip placement="top" title={t}>
<StyledEllipsisWrap maxLine={2}>{t}</StyledEllipsisWrap>
</Tooltip>
) : (
'-'
);
},
},
{
title: '风险站点',
dataIndex: 'riskHost',
align: 'center',
width: 160,
render: (t, r) => {
return t ? (
<Tooltip placement="top" title={t}>
<StyledEllipsisWrap maxLine={2}>{t}</StyledEllipsisWrap>
</Tooltip>
) : (
'-'
);
},
},
{
title: '风险数量',
dataIndex: 'riskNumber',
align: 'center',
width: 120,
},
{
title: '风险标签',
dataIndex: 'riskLabel',
align: 'center',
width: 120,
render: (t, r) => {
let riskLabel = [];
if (t) {
for (let i = 0; i < enumRiskLabel.length; i++) {
for (let j = 0; j < t.split(',').length; j++) {
if (enumRiskLabel[i].value === t.split(',')[j]) {
riskLabel.push(enumRiskLabel[i].label);
}
}
}
}
return t ? riskLabel.join(',') : '-';
},
},
{
title: '限期整改',
dataIndex: 'deadlineDesc',
align: 'center',
width: 120,
},
{
title: '创建时间',
dataIndex: 'createTime',
align: 'center',
width: 160,
},
{
title: '处理状态',
dataIndex: 'status',
align: 'center',
width: 100,
render: (t, r) => {
return mapStatus[t] ? mapStatus[t].label : '-';
},
},
{
title: '操作',
align: 'center',
fixed: 'right',
width: 120,
render(t, r) {
return (
<>
<Tooltip placement="top" title="查看详情">
<ZoomInOutlined
style={{ cursor: 'pointer', fontSize: 18 }}
onClick={() => {
dispatch({
type: 'Event/getEventRiskLog',
payload: { eventId: r.id },
});
dispatch({
type: 'Event/changeState',
payload: {
dataModal: {
modalType: 'EVENT_INFO_MODAL',
modalShow: true,
modalData: r,
},
},
});
}}
/>
</Tooltip>
<Divider type="vertical" style={{ margin: '0 16px' }} />
<Tooltip
placement="top"
title="查看日志"
onClick={() => {
dispatch({
type: 'Event/changeState',
payload: {
dataModal: {
modalType: 'View_Event_Log',
modalShow: true,
modalData: r,
},
},
});
}}
>
<SearchOutlined style={{ cursor: 'pointer', fontSize: 20 }} />
</Tooltip>
</>
);
},
},
];
const pagination = {
...paginations,
total: total,
pageSize: size,
current,
showSizeChanger: total > 10,
onChange: (current, pageSize) => {
handlePageChange(current, pageSize);
},
onShowSizeChange: (current, pageSize) => {
handlePageChange(1, pageSize);
},
showTotal(total) {
return `总共 ${total} 条数据`;
},
};
return (
<Table
rowKey="id"
loading={loading}
dataSource={records}
columns={columns}
pagination={pagination}
scroll={{ x: 1500, y: `calc(100vh - 340px)` }}
/>
);
};
/* Main */
const Event = props => {
const {
dispatch,
loading,
dataSearch,
dataEvent,
dataEvent: { size },
} = props;
useEffect(() => {
handleGetList(1, 10);
}, []);
/* 账号列表 */
const handleGetList = (current, size) => {
dispatch({
type: 'Event/getEventList',
payload: {
current: current || 1,
size: size || 10,
},
});
};
/* 点击搜索 */
const handleFinish = values => {
const { status, eventType, eventLevel, companyName, createTime } = values;
dispatch({
type: 'Event/changeState',
payload: {
dataSearch: {
status,
eventType,
eventLevel,
companyName,
startTime: createTime[0]
? moment(createTime[0].startOf('day').valueOf()).format('YYYY-MM-DD HH:mm:ss')
: undefined,
endTime: createTime[1]
? moment(createTime[1].endOf('day').valueOf()).format('YYYY-MM-DD HH:mm:ss')
: undefined,
},
},
});
handleGetList(0, size);
};
/* 点击重置 */
const handleReset = () => {
dispatch({ type: 'Event/resetSearch' });
handleGetList(0, 10);
};
return (
<StyledPageContainer>
<StyledPageContent>
<Card bordered={false}>
<SearchForm
dataSearch={dataSearch}
handleReset={handleReset}
handleFinish={handleFinish}
/>
<div className="mt-16">
<DataTable
dispatch={dispatch}
loading={loading}
handleGetList={handleGetList}
dataEvent={dataEvent}
/>
</div>
</Card>
</StyledPageContent>
{/* 事件详情 */}
<ModalEventInfo />
{/* 事件日志 */}
<ModalEventLog />
</StyledPageContainer>
);
};
export default connect(({ Event, loading }) => ({
...Event,
loading: loading.effects['Event/getEventList'],
}))(Event);
import * as services from '@/services/incident';
import moment from 'moment';
/* SerachParams */
const staticSearch = {
current: 1,
size: 10,
status: 'ALL',
eventType: 'ALL',
eventLevel: 'ALL',
companyName: undefined,
startTime: moment(new Date())
.add(-7, 'days')
.startOf('day'),
endTime: moment(new Date())
.add(0, 'days')
.endOf('day'),
};
export default {
namespace: 'Event',
state: {
dataSearch: {
...staticSearch,
},
dataEvent: {
records: [],
current: 1,
size: 10,
total: 0,
totalPage: 0,
},
dataEventRiskList: [],
dataModal: {
modalType: '',
modalShow: false,
modalData: {},
},
dataEventLogList: {
records: [],
current: 1,
size: 10,
total: 0,
totalPage: 0,
},
},
effects: {
/* 获取事件列表 */
*getEventList({ payload }, { call, put, select }) {
const {
dataSearch,
dataSearch: { status, eventType, eventLevel, startTime, endTime },
} = yield select(state => state.Event);
try {
const res = yield call(services.getEventList, {
current: 1,
size: 10,
...dataSearch,
...payload,
startTime: moment(startTime).format('YYYY-MM-DD HH:mm:ss'),
endTime: moment(endTime).format('YYYY-MM-DD HH:mm:ss'),
status: status === 'ALL' ? '' : status,
eventType: eventType === 'ALL' ? '' : eventType,
eventLevel: eventLevel === 'ALL' ? '' : eventLevel,
});
if (res.code === 0) {
res.data.records = res.data.records || [];
yield put({
type: 'changeState',
payload: {
dataEvent: res.data,
},
});
}
} catch (err) {
console.error(err);
}
},
/* 事件详情 */
*getEventRiskList({ payload }, { call, put, select }) {
try {
const res = yield call(services.getEventRiskList, {
current: 1,
size: 10,
...payload,
});
if (res.code === 0) {
res.data.records = res.data.records || [];
yield put({
type: 'changeState',
payload: {
dataEventRiskList: res.data,
},
});
}
} catch (err) {
console.error(err);
}
},
/* 事件日志 */
*getEventRiskLog({ payload }, { call, put, select }) {
try {
const res = yield call(services.getEventRiskLog, {
current: 1,
size: 10,
...payload,
});
if (res.code === 0) {
res.data.records = res.data.records || [];
yield put({
type: 'changeState',
payload: {
dataEventLogList: res.data,
},
});
}
} catch (err) {
console.error(err);
}
},
},
reducers: {
changeState(state, { payload }) {
return {
...state,
...payload,
};
},
cancelModal(state, { payload }) {
return {
...state,
dataModal: {
modalType: '',
modalShow: false,
modalData: {},
},
};
},
resetSearch(state, { payload }) {
return {
...state,
dataSearch: {
...staticSearch,
},
};
},
},
};
/**
* Author: wjw
* Date: 2019.05.13
* Description: '图片预览'
*/
import React, { useState, useEffect } from 'react';
import { connect } from 'umi';
import { Modal } from 'antd';
const ModalPreImg = props => {
const {
preImgDataModal: {
modalType,
modalShow,
modalData: { imgUrl, title, type = 'imgurl' },
},
width,
dispatch,
} = props;
const params = {
width,
};
// const QRCode = require('qrcode.react');
const handleCancel = () => {
const payload = {
preImgDataModal: {
modalType: '',
modalShow: false,
modalData: {},
},
};
dispatch({ type: 'global/changeState', payload });
};
return (
<Modal
zIndex={10001}
{...params}
visible={modalType === 'PREVIEWIMG' && modalShow}
footer={null}
getContainer={()=> document.body}
onCancel={() => {
handleCancel();
}}
>
<div style={{ textAlign: 'center' }}>
<p>{title}</p>
{type === 'imgurl' && imgUrl && (
<img alt="example" style={{ width: '100%' }} src={imgUrl} />
)}
{/* {type === 'qrcode' && (
<div style={{ textAlign: 'center' }}>
{imgUrl ? <QRCode value={imgUrl} style={{ width: '250px', height: '250px' }} /> : ''}
</div>
)} */}
</div>
</Modal>
);
};
const mapStateToProps = ({ global }) => {
return {
preImgDataModal: global.preImgDataModal,
};
};
export default connect(mapStateToProps)(ModalPreImg);
......@@ -5,136 +5,14 @@
*/
import React, { useEffect } from 'react';
import { connect } from 'umi';
import {
Card,
Form,
Input,
Button,
Table,
Select,
DatePicker,
Tooltip,
Upload,
message,
} from 'antd';
import { Table, Tooltip } from 'antd';
import { paginations, mapStatus, mapRiskType, mapRiskSourceType } from '@/constants';
import {
StyledPageContainer,
StyledPageContent,
StyledEllipsisWrap,
StyledPageHeader,
} from '@/components/style';
import { UploadOutlined } from '@ant-design/icons';
import { StyledEllipsisWrap } from '@/components/style';
import moment from 'moment';
import * as services from '@/services/risk';
import { ExportFile } from '@/utils/utils';
const { RangePicker } = DatePicker;
const FormItem = Form.Item;
const { Option } = Select;
/* SearchForm */
const SearchForm = props => {
const [form] = Form.useForm();
const {
dataSearch,
dataSearch: { startTime, endTime },
handleReset,
handleFinish,
} = props;
useEffect(() => {
form.setFieldsValue({
...dataSearch,
createTime: [
startTime ? moment(startTime) : undefined,
endTime ? moment(endTime) : undefined,
],
});
}, [dataSearch]);
/* 点击搜索 */
const onFinish = values => {
handleFinish(values);
};
/* 点击重置 */
const onReset = () => {
handleReset();
};
return (
<Form name="Form_Risk" layout="inline" form={form} onFinish={onFinish}>
<FormItem label="网站地址" name="riskHost">
<Input placeholder="请输入网站地址" style={{ width: '250px' }} />
</FormItem>
<FormItem label="风险类型" name="riskType">
<Select placeholder="请选择风险类型" style={{ width: '150px' }}>
<Option value="ALL">全部</Option>
{Object.values(mapRiskType).map(item => {
const { label, value } = item;
return (
<Option key={value} value={value}>
{label}
</Option>
);
})}
</Select>
</FormItem>
<FormItem label="风险源类型" name="fileFormat">
<Select placeholder="请选择风险源类型" style={{ width: '150px' }}>
<Option value="ALL">全部</Option>
{Object.values(mapRiskSourceType).map(item => {
const { label, value } = item;
return (
<Option key={value} value={value}>
{label}
</Option>
);
})}
</Select>
</FormItem>
<FormItem label="处理状态" name="status">
<Select placeholder="请选择处理状态" style={{ width: '150px' }}>
<Option value="ALL">全部</Option>
{Object.values(mapStatus).map(item => {
const { label, value } = item;
return (
<Option key={value} value={value}>
{label}
</Option>
);
})}
</Select>
</FormItem>
<FormItem label="检测时间" name="createTime">
<RangePicker allowClear={false} />
</FormItem>
<FormItem>
<Button type="primary" htmlType="submit" className="mr-15">
搜索
</Button>
<Button className="mr-15" htmlType="button" onClick={onReset}>
重置
</Button>
</FormItem>
</Form>
);
};
/* DataTable */
const DataTable = props => {
const {
loading,
handleGetList,
dataRisk: { records = [], current, size, total },
} = props;
/* 点击分页 */
const handlePageChange = (current, size) => {
handleGetList(current, size);
};
const { loading, dataRisk } = props;
const columns = [
{
......@@ -144,7 +22,7 @@ const DataTable = props => {
fixed: 'left',
width: 80,
render(t, r, idx) {
return (current - 1) * size + idx + 1;
return idx + 1;
},
},
{
......@@ -239,16 +117,10 @@ const DataTable = props => {
];
const pagination = {
...paginations,
total: total,
pageSize: size,
current,
showSizeChanger: total > 10,
onChange: (current, pageSize) => {
handlePageChange(current, pageSize);
},
onShowSizeChange: (current, pageSize) => {
handlePageChange(1, pageSize);
},
total: dataRisk.length,
pageSize: 500,
current: 1,
showSizeChanger: dataRisk.length > 500,
showTotal(total) {
return `总共 ${total} 条数据`;
},
......@@ -257,7 +129,7 @@ const DataTable = props => {
<Table
rowKey="id"
loading={loading}
dataSource={records}
dataSource={dataRisk}
columns={columns}
pagination={pagination}
scroll={{ x: 1500, y: `calc(100vh - 400px)` }}
......@@ -266,15 +138,8 @@ const DataTable = props => {
};
/* Main */
const Risk = props => {
const {
dispatch,
loading,
loadingUpload,
dataSearch,
dataRisk,
dataRisk: { size },
} = props;
const RiskBlock = props => {
const { dispatch, loading, dataRisk } = props;
useEffect(() => {
handleGetList(1, 10);
......@@ -283,7 +148,7 @@ const Risk = props => {
/* 账号列表 */
const handleGetList = (current, size) => {
dispatch({
type: 'Risk/getRiskList',
type: 'RiskBlock/getEventRiskList',
payload: {
current: current || 1,
size: size || 10,
......@@ -291,87 +156,14 @@ const Risk = props => {
});
};
/* 点击搜索 */
const handleFinish = values => {
const { status, riskType, fileFormat, riskHost, createTime } = values;
dispatch({
type: 'Risk/changeState',
payload: {
dataSearch: {
status,
riskType,
fileFormat,
riskHost,
startTime: createTime[0]
? moment(createTime[0].startOf('day').valueOf()).format('YYYY-MM-DD HH:mm:ss')
: undefined,
endTime: createTime[1]
? moment(createTime[1].endOf('day').valueOf()).format('YYYY-MM-DD HH:mm:ss')
: undefined,
},
},
});
handleGetList(0, size);
};
/* 点击重置 */
const handleReset = () => {
dispatch({ type: 'Risk/resetSearch' });
handleGetList(0, 10);
};
/* 上传组件配置 */
const uploadProps = {
customRequest: file => {
const formData = new FormData();
formData.append('file', file.file);
dispatch({ type: 'Risk/importRisk', payload: formData });
},
beforeUpload: file => {
const isLt50M = file.size / 1024 / 1024 < 50;
if (!isLt50M) {
message.error('文件大小需小于50M');
return false;
}
return isLt50M;
},
};
return (
<StyledPageContainer>
<StyledPageHeader>
<Upload {...uploadProps}>
<Button loading={loadingUpload} type="primary" icon={<UploadOutlined />}>
数据导入
</Button>
</Upload>
<Button
type="primary"
onClick={() => {
ExportFile('风险模版', services.exportRiskTemplate, {});
}}
>
模版下载
</Button>
</StyledPageHeader>
<StyledPageContent>
<Card bordered={false}>
<SearchForm
dataSearch={dataSearch}
handleReset={handleReset}
handleFinish={handleFinish}
/>
<div className="mt-16">
<DataTable loading={loading} handleGetList={handleGetList} dataRisk={dataRisk} />
<DataTable loading={loading} dataRisk={dataRisk} />
</div>
</Card>
</StyledPageContent>
</StyledPageContainer>
);
};
export default connect(({ Risk, loading }) => ({
...Risk,
loading: loading.effects['Risk/getRiskList'],
loadingUpload: loading.effects['Risk/importRisk'],
}))(Risk);
export default connect(({ RiskBlock, loading }) => ({
...RiskBlock,
loading: loading.effects['RiskBlock/getEventRiskList'],
}))(RiskBlock);
......
import * as services from '@/services/risk';
import { message } from 'antd';
import moment from 'moment';
/* SerachParams */
const staticSearch = {
current: 1,
size: 10,
status: 'ALL',
riskType: 'ALL',
fileFormat: 'ALL',
riskHost: undefined,
startTime: moment(new Date())
.add(-7, 'days')
.startOf('day'),
endTime: moment(new Date())
.add(0, 'days')
.endOf('day'),
};
export default {
namespace: 'Risk',
namespace: 'RiskBlock',
state: {
dataSearch: {
...staticSearch,
},
dataRisk: {
records: [],
current: 1,
size: 10,
total: 0,
totalPage: 0,
},
dataRisk: [],
},
effects: {
/* 获取风险列表 */
*getRiskList({ payload }, { call, put, select }) {
const {
dataSearch,
dataSearch: { status, riskType, fileFormat, startTime, endTime },
} = yield select(state => state.Risk);
*getEventRiskList({ payload }, { call, put, select }) {
try {
const res = yield call(services.getRiskList, {
const res = yield call(services.getEventRiskList, {
current: 1,
size: 10,
...dataSearch,
...payload,
startTime: moment(startTime).format('YYYY-MM-DD HH:mm:ss'),
endTime: moment(endTime).format('YYYY-MM-DD HH:mm:ss'),
status: status === 'ALL' ? '' : status,
riskType: riskType === 'ALL' ? '' : riskType,
fileFormat: fileFormat === 'ALL' ? '' : fileFormat,
});
if (res.code === 0) {
res.data.records = res.data.records || [];
yield put({
type: 'changeState',
payload: {
dataRisk: res.data,
dataRisk: res.data || [],
},
});
}
......@@ -64,18 +26,6 @@ export default {
console.error(err);
}
},
/* 风险导入 */
*importRisk({ payload }, { call, put, select }) {
try {
const res = yield call(services.importRisk, payload);
if (res.code === 0) {
message.success('导入成功');
yield put({ type: 'getRiskList' });
}
} catch (err) {
console.error(err);
}
},
},
reducers: {
changeState(state, { payload }) {
......@@ -84,13 +34,5 @@ export default {
...payload,
};
},
resetSearch(state, { payload }) {
return {
...state,
dataSearch: {
...staticSearch,
},
};
},
},
};
......
import { StyledWapperIframe } from '@/components/style';
const Index = () => {
return (
<StyledWapperIframe>
<iframe
frameBorder="0"
src="https://yh2-screen.jimilicai.com/"
style={{ width: '100%', height: '100%' }}
allowfullscreen="true"
webkitallowfullscreen="true"
mozallowfullscreen="true"
></iframe>
</StyledWapperIframe>
);
};
export default Index;
/**
* Author: Charles
* Date: 2022.9.13
* Description: [重置密码]
*/
import React, { useEffect } from 'react';
import { Modal, Form, Input, Button } from 'antd';
import {aesEncrypt} from '@/utils/encrypt';
const formItemLayout = { labelCol: { span: 4 }, wrapperCol: { span: 20 } };
const ModalResetPassword = props => {
const [form] = Form.useForm();
const {
handleCancelModal,
handleOk,
dataModal: {
modalType,
modalShow,
modalData: { id },
},
} = props;
useEffect(() => {
if (modalType === 'PASSWORD_SET_MODAL' && modalShow) {
form.resetFields();
}
}, [modalType, modalShow]);
/* 点击保存 */
const handleSave = () => {
form.validateFields().then(values => {
const saveData = {
newPassword: aesEncrypt(values.newPassword),
checkPassword: aesEncrypt(values.checkPassword)
}
handleOk({ saveType: 'PASSWORD', id, ...saveData });
});
};
return (
<Modal
title="重置密码"
placement="right"
width={700}
maskClosable={false}
onCancel={handleCancelModal}
visible={modalType === 'PASSWORD_SET_MODAL' && modalShow}
footer={
<div
style={{
textAlign: 'right',
}}
>
<Button onClick={handleCancelModal} className="mr-10">
取消
</Button>
<Button onClick={handleSave} type="primary">
保存
</Button>
</div>
}
>
<Form form={form} {...formItemLayout} name="password_set_modal">
<Form.Item
name="newPassword"
label="密码"
rules={[
{ required: true, message: '请输入密码' },
{
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}$/,
// pattern: /^(?![\d]+$)(?![a-zA-Z]+$)(?![!#$%^&*]+$)[\da-zA-Z!#$%^&@*]{8,16}$/,
message: '密码至少包含大小写字母、数字、特殊符号的三种组合,限制8~16个字符~',
},
]}
>
<Input.Password placeholder="请输入密码" />
</Form.Item>
<Form.Item
name="checkPassword"
label="密码确认"
rules={[
{ required: true, message: '请输入确认密码' },
({ getFieldValue }) => ({
validator(_, value) {
if (!value || getFieldValue('newPassword') === value) {
return Promise.resolve();
}
return Promise.reject(new Error('两次密码不一致,请重新输入'));
},
}),
]}
>
<Input.Password placeholder="请确认密码" />
</Form.Item>
</Form>
</Modal>
);
};
export default ModalResetPassword;
/**
* Author: Charles
* Date: 2022.9.13
* Description: [更新账号]
*/
import React, { useEffect } from 'react';
import { connect } from 'umi';
import { Modal, Form, Select, Input, Button } from 'antd';
import {aesEncrypt} from '@/utils/encrypt';
const { Option } = Select;
const formItemLayout = { labelCol: { span: 4 }, wrapperCol: { span: 20 } };
const ModalSetAccount = props => {
const [form] = Form.useForm();
const {
dispatch,
handleCancelModal,
handleOk,
dataRoleList,
dataModal: {
modalType,
modalShow,
modalData: { id, realName, username, roleId },
},
} = props;
useEffect(() => {
if (modalType === 'ACCOUNT_SET_MODAL' && modalShow) {
dispatch({ type: 'Account/getRoleSelect' });
form.resetFields();
form.setFieldsValue({
realName,
username,
roleId,
});
}
}, [modalType, modalShow]);
/* 点击保存 */
const handleSave = () => {
form.validateFields().then(values => {
const saveData = {...values}
saveData.password = aesEncrypt(values.password),
saveData.checkPassword = aesEncrypt(values.checkPassword),
handleOk({ saveType: 'ACCOUNT', id, ...saveData });
});
};
return (
<Modal
title={id ? '编辑账号' : '新增账号'}
placement="right"
width={700}
maskClosable={false}
onCancel={handleCancelModal}
visible={modalType === 'ACCOUNT_SET_MODAL' && modalShow}
footer={
<div
style={{
textAlign: 'right',
}}
>
<Button onClick={handleCancelModal} className="mr-10">
取消
</Button>
<Button onClick={handleSave} type="primary">
保存
</Button>
</div>
}
>
<Form form={form} {...formItemLayout} name="account_set_modal">
<Form.Item
name="username"
label="账号"
rules={[
{ required: true, message: '请输入账号名称, 由4~10位字母、数字、符号组成不包括空格' },
{
pattern: /^[0-9a-zA-Z]{4,10}$/,
message: '账号名称由4~10位字母、数字、符号组成不包括空格~',
},
]}
>
<Input placeholder="请输入账号" disabled={id ? true : false} />
</Form.Item>
<Form.Item
name="realName"
label="姓名"
rules={[
{ required: true, message: '请输入姓名, 由2~10位非空格字符组成' },
{ pattern: /^[\S]{2,10}$/, message: '昵称由2~10位非空格字符组成' },
]}
>
<Input placeholder="请输入姓名" />
</Form.Item>
{!id && (
<>
<Form.Item
name="password"
label="密码"
rules={[
{ required: true, message: '请输入密码' },
{
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}$/,
// pattern: /^(?![\d]+$)(?![a-zA-Z]+$)(?![!#$%^&*]+$)[\da-zA-Z!#$%^&@*]{6,16}$/,
message: '密码至少包含大小写字母、数字、特殊符号的三种组合,限制8~16个字符~',
},
]}
>
<Input.Password placeholder="请输入密码" />
</Form.Item>
<Form.Item
name="checkPassword"
label="密码确认"
rules={[
{ required: true, message: '请输入确认密码' },
({ getFieldValue }) => ({
validator(_, value) {
if (!value || getFieldValue('password') === value) {
return Promise.resolve();
}
return Promise.reject(new Error('两次密码不一致,请重新输入'));
},
}),
]}
>
<Input.Password placeholder="请输入确认密码" />
</Form.Item>
</>
)}
<Form.Item
name="roleId"
label="角色"
rules={[{ required: true, message: '请选择关联的角色' }]}
>
<Select placeholder="请选择关联的角色">
{dataRoleList.map(item => {
return (
<Option key={item.id} value={item.id}>
{item.name}
</Option>
);
})}
</Select>
</Form.Item>
</Form>
</Modal>
);
};
export default connect(({ Account }) => ({
...Account,
}))(ModalSetAccount);
/**
* Author: Charles
* Date: 2022.9.13
* Description: [账号列表]
*/
import React, { useEffect } from 'react';
import { connect } from 'umi';
import { Card, Form, Input, Button, Table, Divider, Tooltip, Select, Switch } from 'antd';
import { EditOutlined, RedoOutlined } from '@ant-design/icons';
import { paginations } from '@/constants';
import ModalUpdateAccount from './ModalUpdateAccount';
import ModalResetPassword from './ModalResetPassword';
import { StyledPageContainer, StyledPageHeader, StyledPageContent } from '@/components/style';
const FormItem = Form.Item;
const { Option } = Select;
/* SearchForm */
const SearchForm = props => {
const [form] = Form.useForm();
const { dataSearch, handleReset, handleFinish } = props;
useEffect(() => {
form.setFieldsValue({
...dataSearch,
});
}, [dataSearch]);
/* 点击搜索 */
const onFinish = values => {
handleFinish(values);
};
/* 点击重置 */
const onReset = () => {
handleReset();
};
return (
<Form name="Form_Account" layout="inline" form={form} onFinish={onFinish}>
<FormItem label="账号名称" name="keyword">
<Input placeholder="请输入账号名称" style={{ width: '220px' }} />
</FormItem>
<FormItem label="账号状态" name="status">
<Select placeholder="请选择账号状态" style={{ width: '180px' }}>
<Option value="ALL">全部</Option>
<Option value="1">启用</Option>
<Option value="0">禁用</Option>
</Select>
</FormItem>
<FormItem>
<Button type="primary" htmlType="submit" className="mr-15">
搜索
</Button>
<Button className="mr-15" htmlType="button" onClick={onReset}>
重置
</Button>
</FormItem>
</Form>
);
};
/* DataTable */
const DataTable = props => {
const {
dispatch,
loading,
handleGetList,
currentUser: { name },
dataAccount: { records = [], current, size, total },
} = props;
/* 点击分页 */
const handlePageChange = (current, size) => {
handleGetList(current, size);
};
const columns = [
{
title: '序号',
dataIndex: 'id',
align: 'center',
width: 100,
render(t, r, idx) {
return (current - 1) * size + idx + 1;
},
},
{
title: '账号',
dataIndex: 'username',
align: 'center',
width: 140,
},
{
title: '姓名',
dataIndex: 'realName',
align: 'center',
width: 140,
},
{
title: '角色',
dataIndex: 'roleName',
align: 'center',
width: 140,
},
{
title: '账号状态',
dataIndex: 'status',
align: 'center',
width: 160,
render(t, r, idx) {
return (
<Switch
checkedChildren="启用"
unCheckedChildren="已禁用"
checked={t === 1}
disabled={name === r.username}
onChange={checked => {
dispatch({
type: 'Account/changeStatus',
payload: {
id: r.id,
status: checked ? 1 : 0,
},
});
}}
/>
);
},
},
{
title: '创建时间',
dataIndex: 'createTime',
align: 'center',
width: 200,
render(t, r, idx) {
return t || '-';
},
},
{
title: '操作',
align: 'center',
width: 160,
render(t, r) {
return (
<>
<Tooltip placement="top" title="编辑">
<EditOutlined
style={{ cursor: 'pointer', fontSize: 16 }}
onClick={() => {
dispatch({
type: 'Account/changeState',
payload: {
dataModal: {
modalType: 'ACCOUNT_SET_MODAL',
modalShow: true,
modalData: r,
},
},
});
}}
/>
</Tooltip>
<Divider type="vertical" style={{ margin: '0 16px' }} />
<Tooltip
placement="top"
title="重置密码"
onClick={() => {
dispatch({
type: 'Account/changeState',
payload: {
dataModal: {
modalType: 'PASSWORD_SET_MODAL',
modalShow: true,
modalData: r,
},
},
});
}}
>
<RedoOutlined style={{ cursor: 'pointer', fontSize: 16 }} />
</Tooltip>
</>
);
},
},
];
const pagination = {
...paginations,
total: total,
pageSize: size,
current,
showSizeChanger: total > 10,
onChange: (current, pageSize) => {
handlePageChange(current, pageSize);
},
onShowSizeChange: (current, pageSize) => {
handlePageChange(1, pageSize);
},
showTotal(total) {
return `总共 ${total} 条数据`;
},
};
return (
<Table
rowKey="id"
loading={loading}
dataSource={records}
columns={columns}
pagination={pagination}
scroll={{ y: `calc(100vh - 353px)` }}
/>
);
};
/* Main */
const Account = props => {
const {
dispatch,
loading,
dataSearch,
dataModal,
currentUser,
dataAccount,
dataAccount: { size },
} = props;
useEffect(() => {
handleGetList(1, 10);
}, []);
/* 账号列表 */
const handleGetList = (current, size) => {
dispatch({
type: 'Account/getAccountList',
payload: {
current: current || 1,
size: size || 10,
},
});
};
/* 点击搜索 */
const handleFinish = values => {
const { status, keyword } = values;
dispatch({
type: 'Account/changeState',
payload: {
dataSearch: {
keyword,
status,
},
},
});
handleGetList(0, size);
};
/* 点击重置 */
const handleReset = () => {
dispatch({ type: 'Account/resetSearch' });
handleGetList(0, 10);
};
// 关闭弹框
const handleCancelModal = () => {
dispatch({ type: 'Account/cancelModal' });
};
// 点击保存
const handleOk = values => {
const { saveType } = values;
if (saveType === 'ACCOUNT') {
dispatch({ type: 'Account/updateApplication', payload: { ...values, saveType: undefined } });
} else if (saveType === 'PASSWORD') {
dispatch({ type: 'Account/resetPassword', payload: { ...values, saveType: undefined } });
}
};
return (
<StyledPageContainer>
<StyledPageHeader>
<Button
type="primary"
onClick={() => {
dispatch({
type: 'Account/changeState',
payload: {
dataModal: {
modalType: 'ACCOUNT_SET_MODAL',
modalShow: true,
modalData: {},
},
},
});
}}
>
新增用户
</Button>
</StyledPageHeader>
<StyledPageContent>
<Card bordered={false}>
<SearchForm
dataSearch={dataSearch}
handleReset={handleReset}
handleFinish={handleFinish}
/>
<div className="mt-16">
<DataTable
dispatch={dispatch}
loading={loading}
handleGetList={handleGetList}
dataAccount={dataAccount}
currentUser={currentUser}
/>
</div>
</Card>
</StyledPageContent>
<ModalUpdateAccount
dataModal={dataModal}
handleCancelModal={handleCancelModal}
handleOk={handleOk}
/>
<ModalResetPassword
dataModal={dataModal}
handleCancelModal={handleCancelModal}
handleOk={handleOk}
/>
</StyledPageContainer>
);
};
export default connect(({ Account, user, loading }) => ({
...Account,
currentUser: user.currentUser,
loading: loading.effects['Account/getAccountList'],
}))(Account);
import { message } from 'antd';
import * as services from '@/services/account';
/* SerachParams */
const staticSearch = {
keyword: undefined,
current: 1,
size: 10,
status: 'ALL',
};
export default {
namespace: 'Account',
state: {
dataSearch: {
...staticSearch,
},
dataAccount: {
records: [],
current: 1,
size: 10,
total: 0,
totalPage: 0,
},
dataModal: {
modalType: '',
modalShow: false,
modalData: {},
},
dataRoleList: [],
},
effects: {
/* 获取账号列表 */
*getAccountList({ payload }, { call, put, select }) {
const {
dataSearch,
dataSearch: { status },
} = yield select(state => state.Account);
try {
const res = yield call(services.getAccountList, {
current: 1,
size: 10,
...dataSearch,
...payload,
status: status === 'ALL' ? '' : status,
});
if (res.code === 0) {
res.data.records = res.data.records || [];
yield put({
type: 'changeState',
payload: {
dataAccount: res.data,
},
});
}
} catch (err) {
console.error(err);
}
},
/* 新增、修改账号 */
*updateApplication({ payload }, { call, put, select }) {
const { id } = payload;
const {
dataAccount: { current, size },
} = yield select(state => state.Account);
try {
const res = yield call(services[!id ? 'addAccount' : 'updateAccount'], payload);
if (res.code === 0) {
message.success(!id ? '新增成功' : '修改成功');
yield put({
type: 'getAccountList',
payload: { size, current },
});
yield put({ type: 'cancelModal' });
}
} catch (err) {
console.error(err);
}
},
/* 重置密码 */
*resetPassword({ payload }, { call, put, select }) {
try {
const res = yield call(services.resetPassword, payload);
if (res.code === 0) {
message.success('重置成功');
yield put({ type: 'cancelModal' });
}
} catch (err) {
console.error(err);
}
},
/* 状态修改 */
*changeStatus({ payload }, { call, put, select }) {
const { status } = payload;
const {
dataAccount: { current, size },
} = yield select(state => state.Account);
try {
const res = yield call(services.changeStatus, payload);
if (res.code === 0) {
message.success(status == '1' ? '启用成功' : '禁用成功');
yield put({
type: 'getAccountList',
payload: { size, current },
});
}
} catch (err) {
console.error(err);
}
},
/* 获取角色列表 */
*getRoleSelect({ payload }, { call, put, select }) {
try {
const res = yield call(services.getRoleSelect);
if (res.code === 0) {
yield put({
type: 'changeState',
payload: {
dataRoleList: res.data,
},
});
}
} catch (err) {
console.error(err);
}
},
},
reducers: {
changeState(state, { payload }) {
return {
...state,
...payload,
};
},
cancelModal(state, { payload }) {
return {
...state,
dataModal: {
modalType: '',
modalShow: false,
modalData: {},
},
};
},
resetSearch(state, { payload }) {
return {
...state,
dataSearch: {
...staticSearch,
},
};
},
},
};
/**
* Author: llw
* Date: 2022.9.14
* Description: [菜单层级树]
*/
import React from 'react';
import { connect } from 'umi';
import { Tree } from 'antd';
const { TreeNode } = Tree;
const MenuTree = props => {
const { dispatch, dataSystemMenu, dataLevelMenu, dataExpandedKeys } = props;
// TreeNode的DOM
const renderTreeNode = data => {
return data.map(item => {
if (item.children && item.children.length) {
return (
<TreeNode title={item.title} key={item.resourceCode}>
{renderTreeNode(item.children)}
</TreeNode>
);
}
return <TreeNode title={item.title} key={item.resourceCode} />;
});
};
return (
<Tree
showLine
showIcon
className="info-tree"
expandedKeys={dataExpandedKeys}
onSelect={([key], e) => {
const meunInfo = dataLevelMenu.find(item => item.resourceCode === key);
dispatch({
type: 'SystemMenu/changeState',
payload: {
dataMenuInfo: !key || !meunInfo ? [] : [{ ...meunInfo, children: undefined }],
},
});
}}
>
{renderTreeNode(dataSystemMenu)}
</Tree>
);
};
export default connect(({ SystemMenu }) => ({
...SystemMenu,
}))(MenuTree);
/**
* Author: llw
* Date: 2022.9.14
* Description: [设置菜单弹框]
*/
import React, { useEffect, useState } from 'react';
import { connect } from 'umi';
import { Drawer, Radio, Form, Select, Input, Button } from 'antd';
const { Option } = Select;
const formItemLayout = { labelCol: { span: 4 }, wrapperCol: { span: 20 } };
const ModalSetMenu = props => {
const [menuType, setType] = useState(1);
const [form] = Form.useForm();
let {
dispatch,
handleCancelModal,
dataLevelMenu = [],
dataModal: {
modalType,
modalShow,
modalData: { id, title, resourceCode, resourceNodeType, isEdit, parentId },
},
} = props;
/* 重置resourceNodeType */
useEffect(() => {
if (modalType === 'MENU_SET_MODAL' && modalShow) {
setType(resourceNodeType ? +resourceNodeType : 1);
setTimeout(() => {
form.resetFields();
form.setFieldsValue({
parentId,
title,
resourceCode,
resourceNodeType: resourceNodeType ? +resourceNodeType : 1,
});
}, 100);
}
}, [modalType, modalShow]);
/* 点击保存 */
const handleSave = () => {
form.validateFields().then(values => {
dispatch({ type: 'SystemMenu/updateSystemMenu', payload: { ...values, id } });
});
};
/* 选择菜单类型 */
const handleChangeRadio = value => {
form.resetFields();
setType(value);
form.setFieldsValue({ resourceNodeType: value });
};
return (
<Drawer
title="菜单设置"
placement="right"
width={600}
maskClosable={false}
onClose={handleCancelModal}
visible={modalType === 'MENU_SET_MODAL' && modalShow}
footer={
<div
style={{
textAlign: 'right',
}}
>
<Button onClick={handleCancelModal} className="mr-10">
取消
</Button>
<Button onClick={handleSave} type="primary">
保存
</Button>
</div>
}
>
<Form
form={form}
{...formItemLayout}
name="auth_set_modal"
initialValues={{ resourceNodeType: 1 }}
>
<Form.Item name="resourceNodeType" label="菜单类型">
<Radio.Group buttonStyle="solid" onChange={e => handleChangeRadio(e.target.value)}>
<Radio.Button disabled={isEdit && +resourceNodeType !== 1 ? true : false} value={1}>
一级菜单
</Radio.Button>
<Radio.Button disabled={isEdit && +resourceNodeType !== 2 ? true : false} value={2}>
子菜单
</Radio.Button>
{/* <Radio.Button disabled={isEdit && resourceNodeType !== 3 ? true : false} value={3}>
按钮
</Radio.Button> */}
</Radio.Group>
</Form.Item>
{menuType !== 1 && (
<Form.Item
name="parentId"
label={menuType === 2 ? '上级菜单' : '包含菜单'}
rules={[
{
required: true,
message: menuType === 2 ? '请选择上级菜单' : '请选择包含该按钮的菜单',
},
]}
>
<Select
showSearch
placeholder={menuType === 2 ? '请选择上级菜单' : '请选择包含该按钮的菜单'}
optionFilterProp="children"
filterOption={(input, option) =>
option.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
}
>
{dataLevelMenu
.filter(_ =>
isEdit ? _.resourceCode && _.resourceCode !== resourceCode : _.resourceCode,
)
.map(item => {
return (
<Option key={item.id} value={item.id}>
{item.title}
</Option>
);
})}
</Select>
</Form.Item>
)}
<Form.Item
name="title"
label={menuType === 3 ? '按钮名称' : '菜单名称'}
rules={[
{ required: true, message: menuType === 3 ? '请输入按钮名称' : '请输入菜单名称' },
{ min: 2, max: 15, message: '名称长度2~15个字符' },
]}
>
<Input
maxLength={15}
placeholder={menuType === 3 ? '请输入按钮名称' : '请输入菜单名称'}
/>
</Form.Item>
<Form.Item
name="resourceCode"
label={menuType === 3 ? '按钮code' : '菜单code'}
rules={[
{ required: true, message: menuType === 3 ? '请输入按钮code' : '请输入菜单code' },
]}
>
<Input
maxLength={20}
placeholder={menuType === 3 ? '请输入按钮code' : '请输入菜单code'}
/>
</Form.Item>
</Form>
</Drawer>
);
};
export default connect(({ SystemMenu }) => ({
...SystemMenu,
}))(ModalSetMenu);
/**
* Author: Charles
* Date: 2022.9.13
* Description: [菜单设置]
*/
import React, { useEffect } from 'react';
import { connect } from 'umi';
import { Card, Button, Table, Tooltip, Divider, Modal } from 'antd';
import ModalSetMenu from './ModalSetMenu';
import MenuTree from './MenuTree';
import { EditOutlined, DeleteOutlined, ExclamationCircleOutlined } from '@ant-design/icons';
import {
StyledPageContainer,
StyledPageHeader,
StyledPageContent,
StyledPageFlex,
StyledPageLeft,
StyledPageRight,
} from '@/components/style';
/* DataTable */
const DataTable = props => {
const { dispatch, dataMenuInfo } = props;
const columns = [
{
title: '菜单ID',
dataIndex: 'id',
align: 'center',
width: 120,
},
{
title: '菜单名称',
dataIndex: 'title',
align: 'center',
width: 160,
},
{
title: '菜单code',
dataIndex: 'resourceCode',
align: 'center',
width: 160,
},
{
title: '操作',
align: 'center',
width: 120,
render(t, r) {
return (
<>
<Tooltip placement="top" title="编辑">
<EditOutlined
style={{ cursor: 'pointer', fontSize: 16 }}
onClick={() => {
dispatch({
type: 'SystemMenu/changeState',
payload: {
dataModal: {
modalType: 'MENU_SET_MODAL',
modalShow: true,
modalData: { ...r, isEdit: true },
},
},
});
}}
/>
</Tooltip>
<Divider type="vertical" style={{ margin: '0 16px' }} />
<Tooltip
placement="top"
title="删除"
onClick={() => {
Modal.confirm({
title: '删除',
icon: <ExclamationCircleOutlined />,
content: '确定删除该菜单吗?',
centered: true,
onOk() {
dispatch({
type: 'SystemMenu/delSystemMenu',
payload: { id: r.id },
});
},
onCancel() {},
});
}}
>
<DeleteOutlined style={{ cursor: 'pointer', fontSize: 16 }} />
</Tooltip>
</>
);
},
},
];
return <Table rowKey="id" dataSource={dataMenuInfo} columns={columns} pagination={false} />;
};
/* Main */
const SystemMenu = props => {
const { dispatch, dataModal, dataMenuInfo } = props;
useEffect(() => {
dispatch({ type: 'SystemMenu/getAllSystemMenu' });
}, []);
// 关闭弹框
const handleCancelModal = () => {
dispatch({ type: 'SystemMenu/cancelModal' });
};
// 点击保存
const handleOk = values => {};
return (
<StyledPageContainer>
<StyledPageHeader>
<Button
type="primary"
onClick={() => {
dispatch({
type: 'SystemMenu/changeState',
payload: {
dataModal: {
modalType: 'MENU_SET_MODAL',
modalShow: true,
modalData: {},
},
},
});
}}
>
新增菜单
</Button>
</StyledPageHeader>
<StyledPageContent>
<StyledPageFlex>
<StyledPageLeft>
<MenuTree />
</StyledPageLeft>
<StyledPageRight>
<Card bordered={false}>
<div className="mt-16">
<DataTable dispatch={dispatch} dataMenuInfo={dataMenuInfo} />
</div>
</Card>
</StyledPageRight>
</StyledPageFlex>
</StyledPageContent>
<ModalSetMenu
dataModal={dataModal}
handleCancelModal={handleCancelModal}
handleOk={handleOk}
/>
</StyledPageContainer>
);
};
export default connect(({ SystemMenu }) => ({
...SystemMenu,
}))(SystemMenu);
import * as services from '@/services/menu';
import { message } from 'antd';
import { getPermissionList } from '@/utils/menu';
export default {
namespace: 'SystemMenu',
state: {
dataSystemMenu: [], // 层级菜单
dataLevelMenu: [], // 铺平菜单
dataMenuInfo: [], // 菜单详情
dataExpandedKeys: [], // 菜单code
dataModal: {
modalType: '',
modalShow: false,
modalData: {},
},
},
effects: {
/* 获取菜单层级 */
*getAllSystemMenu({ payload }, { call, put, select }) {
const { dataMenuInfo } = yield select(state => state.SystemMenu);
try {
const res = yield call(services.getAllMenu);
if (res.code === 0) {
const { dataMenu, dataExpandedKeys } = getPermissionList(res.data || []);
yield put({
type: 'changeState',
payload: {
dataSystemMenu: res.data || [],
dataLevelMenu: dataMenu,
dataExpandedKeys,
},
});
// 处理菜单选中进行编辑、删除的情况
if (payload && payload.isEdit && dataMenuInfo.length) {
const selectMenuInfo = dataMenu.find(
item => item.resourceCode === dataMenuInfo[0].resourceCode,
);
yield put({
type: 'changeState',
payload: {
dataMenuInfo: [{ ...selectMenuInfo, children: undefined }],
},
});
} else if (payload && payload.isDel && dataMenuInfo.length) {
const selectMenuInfo = dataMenu.find(
item => item.resourceCode === dataMenuInfo[0].resourceCode,
);
yield put({
type: 'changeState',
payload: {
dataMenuInfo: selectMenuInfo ? [{ ...selectMenuInfo, children: undefined }] : [],
},
});
}
}
} catch (err) {
console.error(err);
}
},
/* 新增、编辑菜单 */
*updateSystemMenu({ payload }, { call, put, select }) {
try {
const res = yield call(services[!payload.id ? 'addMenu' : 'updateMenu'], payload);
if (res.code === 0) {
message.success(!payload.id ? '新增成功' : '编辑成功');
yield put({ type: 'cancelModal' });
yield put({ type: 'getAllSystemMenu', payload: { isEdit: payload.id ? true : false } });
}
} catch (err) {
console.error(err);
}
},
/* 删除菜单 */
*delSystemMenu({ payload }, { call, put, select }) {
try {
const res = yield call(services.delMenu, payload);
if (res.code === 0) {
message.success('删除成功');
yield put({ type: 'getAllSystemMenu', payload: { isDel: true } });
}
} catch (err) {
console.error(err);
}
},
},
reducers: {
changeState(state, { payload }) {
return {
...state,
...payload,
};
},
cancelModal(state, { payload }) {
return {
...state,
dataModal: {
modalType: '',
modalShow: false,
modalData: {},
},
};
},
},
};
/**
* Author: Charles
* Date: 2022.9.13
* Description: [更新角色]
*/
import React, { useEffect, useState } from 'react';
import { connect } from 'umi';
import { Modal, Form, Input, Button, TreeSelect } from 'antd';
const formItemLayout = { labelCol: { span: 4 }, wrapperCol: { span: 20 } };
const ModalSetRole = props => {
const [form] = Form.useForm();
const {
dispatch,
dataUserMenu,
handleCancelModal,
handleOk,
dataRoleMenuId,
dataModal: {
modalType,
modalShow,
modalData: { id, name, description },
},
} = props;
useEffect(() => {
if (modalType === 'ROLE_SET_MODAL' && modalShow) {
dispatch({ type: 'Role/getUserMenu' });
if (id) {
dispatch({ type: 'Role/getRoleMenuId', payload: { id } });
}
form.resetFields();
form.setFieldsValue({
name,
description,
});
}
}, [modalType, modalShow]);
const [value, setValue] = useState([]);
useEffect(() => {
form.setFieldsValue({
menuIds: dataRoleMenuId,
});
}, [dataRoleMenuId]);
// treeSelect配置
const tProps = {
treeData: dataUserMenu,
value: dataRoleMenuId || [],
onChange: () => {},
treeCheckable: true,
showCheckedStrategy: TreeSelect.SHOW_ALL,
placeholder: '请选择菜单权限',
style: {
width: '100%',
},
fieldNames: {
label: 'title',
value: 'id',
},
};
/* 点击保存 */
const handleSave = () => {
form.validateFields().then(values => {
console.log(values, 'values');
handleOk({ id, ...values });
});
};
return (
<Modal
title={id ? '编辑角色' : '新增角色'}
placement="right"
width={700}
maskClosable={false}
onCancel={handleCancelModal}
visible={modalType === 'ROLE_SET_MODAL' && modalShow}
footer={
<div
style={{
textAlign: 'right',
}}
>
<Button onClick={handleCancelModal} className="mr-10">
取消
</Button>
<Button onClick={handleSave} type="primary">
保存
</Button>
</div>
}
>
<Form form={form} {...formItemLayout} name="role_set_modal">
<Form.Item
name="name"
label="角色名称"
rules={[
{ required: true, message: '请输入角色名称,由2~10位非空格的字符组成' },
{ pattern: /^[\S]{2,10}$/, message: '角色名称由2~10位非空格的字符组成' },
]}
>
<Input placeholder="请输入角色名称" />
</Form.Item>
<Form.Item
name="description"
label="角色描述"
rules={[
{ required: false, message: '请输入角色描述' },
{ max: 30, message: '角色描述字符长度不能超过30' },
]}
>
<Input.TextArea autoSize={{ minRows: 4, maxRows: 4 }} placeholder="请输入角色描述" />
</Form.Item>
<Form.Item
name="menuIds"
label="菜单权限"
rules={[{ required: true, message: '请选择菜单权限' }]}
>
<TreeSelect {...tProps} />
</Form.Item>
</Form>
</Modal>
);
};
export default connect(({ Role }) => ({
...Role,
}))(ModalSetRole);
/**
* Author: Charles
* Date: 2022.9.13
* Description: [角色列表]
*/
import React, { useEffect } from 'react';
import { connect } from 'umi';
import { Card, Form, Input, Button, Table, Divider, Tooltip, Modal } from 'antd';
import { EditOutlined, DeleteOutlined, ExclamationCircleOutlined } from '@ant-design/icons';
import { paginations } from '@/constants';
import ModalUpdateRole from './ModalUpdateRole';
import { StyledPageContainer, StyledPageHeader, StyledPageContent } from '@/components/style';
const FormItem = Form.Item;
/* SearchForm */
const SearchForm = props => {
const [form] = Form.useForm();
const { dataSearch, handleReset, handleFinish } = props;
useEffect(() => {
form.setFieldsValue({
...dataSearch,
});
}, [dataSearch]);
/* 点击搜索 */
const onFinish = values => {
handleFinish(values);
};
/* 点击重置 */
const onReset = () => {
handleReset();
};
return (
<Form name="Form_Role" layout="inline" form={form} onFinish={onFinish}>
<FormItem label="角色名称" name="search">
<Input placeholder="请输入角色名称" style={{ width: '220px' }} />
</FormItem>
<FormItem>
<Button type="primary" htmlType="submit" className="mr-15">
搜索
</Button>
<Button className="mr-15" htmlType="button" onClick={onReset}>
重置
</Button>
</FormItem>
</Form>
);
};
/* DataTable */
const DataTable = props => {
const {
dispatch,
loading,
handleGetList,
dataRole: { records = [], current, size, total },
} = props;
/* 点击分页 */
const handlePageChange = (current, size) => {
handleGetList(current, size);
};
const columns = [
{
title: '序号',
dataIndex: 'id',
align: 'center',
width: 120,
render(t, r, idx) {
return (current - 1) * size + idx + 1;
},
},
{
title: '角色名称',
dataIndex: 'name',
align: 'center',
width: 160,
},
{
title: '角色描述',
dataIndex: 'description',
align: 'center',
width: 200,
render: (t, r) => {
return t || '-';
},
},
{
title: '创建时间',
dataIndex: 'createTime',
align: 'center',
width: 200,
render(t, r, idx) {
return t || '-';
},
},
{
title: '操作',
align: 'center',
width: 150,
render(t, r) {
return (
<>
<Tooltip placement="top" title="编辑">
<EditOutlined
style={{ cursor: 'pointer', fontSize: 16 }}
onClick={() => {
dispatch({
type: 'Role/changeState',
payload: {
dataModal: {
modalType: 'ROLE_SET_MODAL',
modalShow: true,
modalData: r,
},
},
});
}}
/>
</Tooltip>
<Divider type="vertical" style={{ margin: '0 16px' }} />
<Tooltip
placement="top"
title="删除"
onClick={() => {
Modal.confirm({
title: '删除',
icon: <ExclamationCircleOutlined />,
content: '确定删除该角色吗?',
centered: true,
onOk() {
dispatch({
type: 'Role/delRole',
payload: { id: r.id },
});
},
onCancel() {},
});
}}
>
<DeleteOutlined style={{ cursor: 'pointer', fontSize: 16 }} />
</Tooltip>
</>
);
},
},
];
const pagination = {
...paginations,
total: total,
pageSize: size,
current,
showSizeChanger: total > 10,
onChange: (current, pageSize) => {
handlePageChange(current, pageSize);
},
onShowSizeChange: (current, pageSize) => {
handlePageChange(1, pageSize);
},
showTotal(total) {
return `总共 ${total} 条数据`;
},
};
return (
<Table
rowKey="id"
loading={loading}
dataSource={records}
columns={columns}
pagination={pagination}
scroll={{ y: `calc(100vh - 353px)` }}
/>
);
};
/* Main */
const Role = props => {
const {
dispatch,
loading,
dataSearch,
dataModal,
currentUser,
dataRole,
dataRole: { size },
} = props;
useEffect(() => {
handleGetList(1, 10);
}, []);
/* 账号列表 */
const handleGetList = (current, size) => {
dispatch({
type: 'Role/getRoleList',
payload: {
current: current || 1,
size: size || 10,
},
});
};
/* 点击搜索 */
const handleFinish = values => {
const { status, search } = values;
dispatch({
type: 'Role/changeState',
payload: {
dataSearch: {
search,
status,
},
},
});
handleGetList(0, size);
};
/* 点击重置 */
const handleReset = () => {
dispatch({ type: 'Role/resetSearch' });
handleGetList(0, 10);
};
// 关闭弹框
const handleCancelModal = () => {
dispatch({ type: 'Role/cancelModal' });
};
// 点击保存
const handleOk = values => {
dispatch({ type: 'Role/updateRole', payload: { ...values } });
};
return (
<StyledPageContainer>
<StyledPageHeader>
<Button
type="primary"
onClick={() => {
dispatch({
type: 'Role/changeState',
payload: {
dataModal: {
modalType: 'ROLE_SET_MODAL',
modalShow: true,
modalData: {},
},
},
});
}}
>
新增角色
</Button>
</StyledPageHeader>
<StyledPageContent>
<Card bordered={false}>
<SearchForm
dataSearch={dataSearch}
handleReset={handleReset}
handleFinish={handleFinish}
/>
<div className="mt-16">
<DataTable
dispatch={dispatch}
loading={loading}
handleGetList={handleGetList}
dataRole={dataRole}
currentUser={currentUser}
/>
</div>
</Card>
</StyledPageContent>
<ModalUpdateRole
dataModal={dataModal}
handleCancelModal={handleCancelModal}
handleOk={handleOk}
/>
</StyledPageContainer>
);
};
export default connect(({ Role, user, loading }) => ({
...Role,
loading: loading.effects['Role/getRoleList'],
}))(Role);
import { message } from 'antd';
import * as services from '@/services/role';
/* SerachParams */
const staticSearch = {
search: undefined,
current: 1,
size: 10,
};
export default {
namespace: 'Role',
state: {
dataSearch: {
...staticSearch,
},
dataRole: {
records: [],
current: 1,
size: 10,
total: 0,
totalPage: 0,
},
dataModal: {
modalType: '',
modalShow: false,
modalData: {},
},
dataUserMenu: [],
dataRoleMenuId: [],
},
effects: {
/* 获取角色列表 */
*getRoleList({ payload }, { call, put, select }) {
const { dataSearch } = yield select(state => state.Role);
try {
const res = yield call(services.getRoleList, {
current: 1,
size: 10,
...dataSearch,
...payload,
});
if (res.code === 0) {
res.data.records = res.data.records || [];
yield put({
type: 'changeState',
payload: {
dataRole: res.data,
},
});
}
} catch (err) {
console.error(err);
}
},
/* 新增、修改角色 */
*updateRole({ payload }, { call, put, select }) {
const { id } = payload;
const {
dataRole: { current, size },
} = yield select(state => state.Role);
const {
currentUser: { roleId },
} = yield select(state => state.user);
try {
const res = yield call(services[!id ? 'addRole' : 'updateRole'], payload);
if (res.code === 0) {
message.success(!id ? '新增成功' : '修改成功');
yield put({
type: 'getRoleList',
payload: { size, current },
});
yield put({ type: 'cancelModal' });
if (roleId === id) {
setTimeout(() => {
window.location.href = '/user/login';
}, 500);
}
}
} catch (err) {
console.error(err);
}
},
/* 删除角色 */
*delRole({ payload }, { call, put, select }) {
const {
dataRole: { records = [], current, size },
} = yield select(state => state.Role);
try {
const res = yield call(services.delRole, payload);
if (res.code === 0) {
message.success('删除成功');
yield put({
type: 'getRoleList',
payload: {
size,
current: records.length === 1 ? (current === 1 ? 1 : current - 1) : current,
},
});
}
} catch (err) {
console.error(err);
}
},
/* 获取用户菜单 */
*getUserMenu({ payload }, { call, put, select }) {
try {
const res = yield call(services.getUserMenu);
if (res.code === 0) {
yield put({
type: 'changeState',
payload: {
dataUserMenu: res.data || [],
},
});
}
} catch (err) {
console.error(err);
}
},
/* 获取角色菜单id集合 */
*getRoleMenuId({ payload }, { call, put, select }) {
try {
const res = yield call(services.getRoleMenuId, payload);
if (res.code === 0) {
yield put({
type: 'changeState',
payload: {
dataRoleMenuId: res.data.menuId || [],
},
});
}
} catch (err) {
console.error(err);
}
},
},
reducers: {
changeState(state, { payload }) {
return {
...state,
...payload,
};
},
cancelModal(state, { payload }) {
return {
...state,
dataModal: {
modalType: '',
modalShow: false,
modalData: {},
},
};
},
resetSearch(state, { payload }) {
return {
...state,
dataSearch: {
...staticSearch,
},
};
},
},
};
/**
* Author: llw
* Date: 2020-7-16
* Description: [登录页面]
*/
import React, { useEffect } from 'react';
import { connect } from 'umi';
import { IconFontConfig } from '@/common';
import { Form, Button, Input } from 'antd';
import loginless from './index.less';
import {aesEncrypt} from '@/utils/encrypt';
const Loginform = props => {
const { loading, dispatch } = props;
const handleSubmit = values => {
const loginData = {
username: values.username,
password: aesEncrypt(values.password)
};
dispatch({
type: 'login/login',
payload: loginData,
});
};
return (
<div className={loginless.main}>
<Form onFinish={handleSubmit}>
<Form.Item
name="username"
rules={[{ required: true, message: '请输入您的用户名' }]}
>
<Input
size="large"
placeholder="请输入您的用户名"
prefix={<IconFontConfig type="icon-user" />}
/>
</Form.Item>
<Form.Item
name="password"
rules={[{ required: true, message: '请输入您的密码' }]}
>
<Input.Password
size="large"
visibilityToggle={false}
placeholder="请输入您的密码"
prefix={<IconFontConfig type="icon-password" />}
/>
</Form.Item>
<Button
block
size="large"
type="primary"
htmlType="submit"
loading={loading}
className={loginless.loginbtn}
>
登录
</Button>
</Form>
</div>
);
};
export default connect(({ login, loading }) => ({
login,
loading: loading.effects['login/login'],
}))(Loginform);
.title {
font-size: 15px;
font-weight: 500;
color: rgba(51, 51, 51, 1);
margin-bottom: 25px;
}
.main {
width: 100%;
padding: 40px 25px;
.ipticon {
width: auto;
height: 18px;
margin-right: 11px;
}
:global(.ant-form-item) {
height: 62px;
margin-bottom: 0;
input {
font-size: 14px;
padding-left: 3px;
}
input:-webkit-autofill,
textarea:-webkit-autofill,
select:-webkit-autofill {
background-color: #fff !important;
background-image: none;
}
input:-webkit-autofill:hover {
background-color: #fff !important;
-webkit-box-shadow: 0 0 0px 1000px white inset;
}
input:-webkit-autofill {
background-color: #fff !important;
-webkit-box-shadow: 0 0 0px 1000px white inset;
}
input:-webkit-autofill:focus {
background-color: #fff !important;
/* style code */
-webkit-box-shadow: 0 0 0px 1000px white inset;
}
}
}
.loginbtn {
letter-spacing: -1px;
font-size: 15px;
margin-top: 10px;
height: 44px;
}
/**
* Author: Charles
* Date: 2022.9.13
* Description: [风险列表]
*/
import React, { useEffect } from 'react';
import { connect } from 'umi';
import { Table, Tooltip } from 'antd';
import { paginations, mapStatus, mapRiskType, mapRiskSourceType } from '@/constants';
import { StyledEllipsisWrap } from '@/components/style';
import moment from 'moment';
/* DataTable */
const DataTable = props => {
const {
loading,
handleGetList,
dataRisk: { records = [], current, size, total },
} = props;
/* 点击分页 */
const handlePageChange = (current, size) => {
handleGetList(current, size);
};
const columns = [
{
title: '序号',
dataIndex: 'id',
align: 'center',
fixed: 'left',
width: 80,
render(t, r, idx) {
return (current - 1) * size + idx + 1;
},
},
{
title: '风险源名称',
dataIndex: 'riskName',
align: 'center',
width: 160,
render: (t, r) => {
return (
<Tooltip placement="top" title={t}>
<StyledEllipsisWrap maxLine={1}>{t}</StyledEllipsisWrap>
</Tooltip>
);
},
},
{
title: '风险源地址',
dataIndex: 'riskUrl',
align: 'center',
width: 160,
render: (t, r) => {
return (
<Tooltip placement="top" title={t}>
<StyledEllipsisWrap maxLine={2}>{t}</StyledEllipsisWrap>
</Tooltip>
);
},
},
{
title: '风险站点',
dataIndex: 'riskHost',
align: 'center',
width: 160,
render: (t, r) => {
return (
<Tooltip placement="top" title={t}>
<StyledEllipsisWrap maxLine={2}>{t}</StyledEllipsisWrap>
</Tooltip>
);
},
},
{
title: '关键词',
dataIndex: 'riskKeyword',
align: 'center',
width: 260,
render: (t, r) => {
return (
<Tooltip placement="top" title={t}>
<StyledEllipsisWrap maxLine={2}>{t}</StyledEllipsisWrap>
</Tooltip>
);
},
},
{
title: '风险类型',
dataIndex: 'riskType',
align: 'center',
width: 160,
render: (t, r) => {
return mapRiskType[t] ? mapRiskType[t].label : '-';
},
},
{
title: '风险源类型',
dataIndex: 'fileFormat',
align: 'center',
width: 160,
render: (t, r) => {
return mapRiskSourceType[t] ? mapRiskSourceType[t].label : '-';
},
},
{
title: '检测时间',
dataIndex: 'checkTime',
align: 'center',
width: 160,
render: (t, r) => {
return t ? moment(t).format('YYYY-MM-DD HH:mm:ss') : '-';
},
},
{
title: '处理状态',
dataIndex: 'status',
align: 'center',
fixed: 'right',
width: 100,
render: (t, r) => {
return mapStatus[t] ? mapStatus[t].label : '-';
},
},
];
const pagination = {
...paginations,
total: total,
pageSize: size,
current,
showSizeChanger: total > 10,
onChange: (current, pageSize) => {
handlePageChange(current, pageSize);
},
onShowSizeChange: (current, pageSize) => {
handlePageChange(1, pageSize);
},
showTotal(total) {
return `总共 ${total} 条数据`;
},
};
return (
<Table
rowKey="id"
loading={loading}
dataSource={records}
columns={columns}
pagination={pagination}
scroll={{ x: 1500, y: `calc(100vh - 400px)` }}
/>
);
};
/* Main */
const RiskBlock = props => {
const {
dispatch,
loading,
loadingUpload,
dataSearch,
dataRisk,
dataRisk: { size },
} = props;
useEffect(() => {
handleGetList(1, 10);
}, []);
/* 账号列表 */
const handleGetList = (current, size) => {
dispatch({
type: 'RiskBlock/getEventRiskList',
payload: {
current: current || 1,
size: size || 10,
},
});
};
return (
<div className="mt-16">
<DataTable loading={loading} handleGetList={handleGetList} dataRisk={dataRisk} />
</div>
);
};
export default connect(({ RiskBlock, loading }) => ({
...RiskBlock,
loading: loading.effects['RiskBlock/getEventRiskList'],
}))(RiskBlock);
import * as services from '@/services/risk';
export default {
namespace: 'RiskBlock',
state: {
dataRisk: {
records: [],
current: 1,
size: 10,
total: 0,
totalPage: 0,
},
},
effects: {
/* 获取风险列表 */
*getEventRiskList({ payload }, { call, put, select }) {
try {
const res = yield call(services.getEventRiskList, {
current: 1,
size: 10,
...payload,
});
if (res.code === 0) {
res.data.records = res.data.records || [];
yield put({
type: 'changeState',
payload: {
dataRisk: res.data,
},
});
}
} catch (err) {
console.error(err);
}
},
},
reducers: {
changeState(state, { payload }) {
return {
...state,
...payload,
};
},
},
};
import request from '@/utils/request';
// 账号列表
export async function getAccountList(params) {
return request('/v1/user/page', { params, methods: 'GET' });
}
// 新增账号
export async function addAccount(data) {
return request('/v1/user', { data });
}
// 修改账号
export async function updateAccount(data) {
const { id } = data;
return request(`/v1/user/${id}`, { data: { ...data, id: undefined } });
}
// 重置密码
export async function resetPassword(data) {
const { id } = data;
return request(`/v1/user/${id}/password/reset`, { data: { ...data, id: undefined } });
}
// 角色下拉
export async function getRoleSelect(params) {
return request('/role/all', { params, methods: 'GET' });
}
// 状态修改
export async function changeStatus(data) {
const { id } = data;
return request(`/v1/user/${id}/status`, { data });
}
import request from '@/utils/request';
// 应用列表
export async function getApplicationList(data) {
return request('/web/tenant/list', { data });
}
// 删除应用
export async function delApplication(data) {
return request('web/tenant/delete', { data });
}
// 新增应用
export async function addApplication(data) {
return request('web/tenant/add', { data });
}
// 修改应用
export async function updateApplication(data) {
return request('web/tenant/update', { data });
}
// 应用详情
export async function getApplicationInfo(data) {
return request(`web/tenant/get?id=${data.id}`, { methods: 'get' });
}
import request from '@/utils/request';
// 场所网站备案信息
export async function getPlaceList(params) {
return request('/place/list', { params, methods: 'GET' });
}
// 行政执法案件
export async function getEventIllegalList(params) {
return request('/eventIllegal/list', { params, methods: 'GET' });
}
// 投诉举报事件
export async function getComplaintList(params) {
return request('/complaints/list', { params, methods: 'GET' });
}
// 基层网络事件
export async function getNetworkEventList(params) {
return request('/baseGrid/list', { params, methods: 'GET' });
}
// 场所导入
export async function importPlace(data) {
return request('/place/import', { data, requestType: 'form' });
}
// 场所导出模版
export async function exportPlaceTemplate(params) {
return request('/place/template', { params, methods: 'GET', responseType: 'blob' });
}
// 行政执法案件导入
export async function importEventIllegal(data) {
return request('/eventIllegal/import', { data, requestType: 'form' });
}
// 行政执法案件导出模版
export async function exportEventIllegalTemplate(params) {
return request('/eventIllegal/template', { params, methods: 'GET', responseType: 'blob' });
}
// 基层网格搜索下拉框
export async function getBaseGridSponsor(params) {
return request('/baseGrid/getSponsor', { params, methods: 'GET' });
}
// 投诉举报事件详情
export async function getComplaintsDetail(params) {
return request('/complaints/selectById', { params, methods: 'GET' });
}
// 基层网络详情
export async function getBaseGridDetail(params) {
return request('/baseGrid/getById', { params, methods: 'GET' });
}
// 行政执法案件详情
export async function getEventIllegalDetail(params) {
return request('/eventIllegal/selectById', { params, methods: 'GET' });
}
import request from '@/utils/request';
// 事件列表
export async function getEventList(params) {
return request('/event/list', { params, methods: 'GET' });
}
// 事件详情
export async function getEventDetail(params) {
return request('/event/detail', { params, methods: 'GET' });
}
// 事件风险列表
export async function getEventRiskList(params) {
return request('/risk/getEventRiskList', { params, methods: 'GET' });
}
// 事件日志
export async function getEventRiskLog(params) {
return request(`/event/${params?.eventId}/log/list`, { params, methods: 'GET' });
}
import request from '@/utils/request';
// 登录
export async function queryLogin(data) {
return request('/v1/user/auth/login', {
data,
headers: { 'Content-Type': 'application/json' },
});
}
// 退出登录
export async function loginOut(data) {
return request('/v1/user/auth/logout', { data });
}
import request from '@/utils/request';
// 新增菜单
export async function addMenu(data) {
return request('/menu', { data });
}
// 更新菜单
export async function updateMenu(data) {
const { id } = data;
return request(`/menu/${id}`, { data });
}
// 删除菜单
export async function delMenu(data) {
const { id } = data;
return request(`/menu/${id}/delete`);
}
// 获取所有的菜单
export async function getAllMenu(params) {
return request('/menu/tree', { params, methods: 'GET' });
}
import request from '@/utils/request';
// 角色列表
export async function getRoleList(params) {
return request('/role', { params, methods: 'GET' });
}
// 新增角色
export async function addRole(data) {
return request('/role', { data });
}
// 修改角色
export async function updateRole(data) {
const { id } = data;
return request(`/role/${id}`, { data });
}
// 删除角色
export async function delRole(data) {
const { id } = data;
return request(`/role/${id}/delete`);
}
// 获取用户权限
export async function getUserMenu(params) {
return request('/menu/tree', { params, methods: 'GET' });
}
// 获取用户的meunId
export async function getRoleMenuId(params) {
const { id } = params;
return request(`/role/${id}`, { methods: 'GET' });
}
import request from '@/utils/request';
// 用户信息
export async function getUserInfo(params) {
return request('/v1/user/auth/me', { params, methods: 'GET' });
}
// 修改密码
export async function updatePassword(data) {
return request('/v1/user/password/reset', { data, methods: 'POST' });
}
......@@ -68,22 +68,12 @@ request.interceptors.request.use((url, options) => {
});
//响应拦截
request.interceptors.response.use(async response => {
if (
response.url.indexOf('/risk/template') > -1 ||
response.url.indexOf('/place/template') > -1 ||
response.url.indexOf('/eventIllegal/template') > -1
) {
return response;
} else {
const data = await response?.clone()?.json();
if ([4001, 40002].includes(data.code)) {
window.location.href = '/user/login';
} else if (data.code === 0) {
if (data.code === 0) {
return response;
} else {
message.error(`${data.message}`);
}
return response;
}
});
export default request;
......
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!