Merge branch 'develop' of https://github.com/opengoofy/hippo4j into develop
After Width: | Height: | Size: 6.5 KiB |
After Width: | Height: | Size: 8.9 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 70 KiB |
After Width: | Height: | Size: 8.9 KiB |
Before Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 7.2 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 9.7 KiB |
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 56 KiB |
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 7.5 KiB |
After Width: | Height: | Size: 7.1 KiB |
Before Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 5.0 KiB |
Before Width: | Height: | Size: 9.7 KiB After Width: | Height: | Size: 8.9 KiB |
After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 8.9 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 52 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 52 KiB |
@ -0,0 +1,3 @@
|
||||
// .custom-icon {
|
||||
// color: red !important;
|
||||
// }
|
@ -1,15 +1,15 @@
|
||||
import { createFromIconfontCN } from '@ant-design/icons';
|
||||
|
||||
interface Props {
|
||||
type: string;
|
||||
}
|
||||
import React from 'react';
|
||||
import style from './index.module.less';
|
||||
|
||||
const MyIcon = createFromIconfontCN({
|
||||
scriptUrl: '//at.alicdn.com/t/c/font_4254722_3l4m6by7h34.js', // 在 iconfont.cn 上生成
|
||||
scriptUrl: '//at.alicdn.com/t/c/font_4254722_vw34zn7su2.js', // 在 iconfont.cn 上生成
|
||||
});
|
||||
|
||||
const IconFont = (props: Props) => {
|
||||
return <MyIcon {...props}></MyIcon>;
|
||||
type MyComponentProps = React.HTMLProps<HTMLDivElement> & { type: string };
|
||||
|
||||
const IconFont: React.FC<MyComponentProps> = props => {
|
||||
return <MyIcon className={style['custom-icon']} {...props}></MyIcon>;
|
||||
};
|
||||
|
||||
export default IconFont;
|
||||
|
@ -0,0 +1,27 @@
|
||||
import { Button, ButtonProps } from 'antd';
|
||||
import React from 'react';
|
||||
import { SearchOutlined, PlusOutlined, RedoOutlined } from '@ant-design/icons';
|
||||
|
||||
function withSearchIconButton<P extends ButtonProps>(WrappedComponent: React.ComponentType<P>) {
|
||||
return function EnhancedComponent(props: P) {
|
||||
return <WrappedComponent icon={<SearchOutlined></SearchOutlined>} {...props} />;
|
||||
};
|
||||
}
|
||||
|
||||
function withAddIconButton<P extends ButtonProps>(WrappedComponent: React.ComponentType<P>) {
|
||||
return function EnhancedComponent(props: P) {
|
||||
return <WrappedComponent icon={<PlusOutlined />} {...props}></WrappedComponent>;
|
||||
};
|
||||
}
|
||||
|
||||
function withResetIconButton<P extends ButtonProps>(WrappedComponent: React.ComponentType<P>) {
|
||||
return function EnhancedComponent(props: P) {
|
||||
return <WrappedComponent {...props} icon={<RedoOutlined />}></WrappedComponent>;
|
||||
};
|
||||
}
|
||||
|
||||
export const SearchButton = withSearchIconButton(Button);
|
||||
|
||||
export const AddButton = withAddIconButton(Button);
|
||||
|
||||
export const ResetButton = withResetIconButton(Button);
|
@ -0,0 +1,108 @@
|
||||
import { useRequest } from 'ahooks';
|
||||
import { Form, Modal, Input, Select, notification } from 'antd';
|
||||
import React, { useEffect } from 'react';
|
||||
import { fetchTenantOptions } from '../tenant/service';
|
||||
import { fetchAddItem, fetchUpdateItem } from './service';
|
||||
|
||||
interface IProps {
|
||||
type: string;
|
||||
data: any;
|
||||
visible: boolean;
|
||||
onClose: () => void;
|
||||
reset: () => void;
|
||||
}
|
||||
|
||||
const ItemCreate: React.FC<IProps> = props => {
|
||||
const { visible, onClose, data, type, reset } = props;
|
||||
const [form] = Form.useForm();
|
||||
const tenantRequest = useRequest(fetchTenantOptions, {
|
||||
ready: !!type,
|
||||
});
|
||||
const updateRequest = useRequest(fetchUpdateItem, {
|
||||
manual: true,
|
||||
onSuccess: () => {
|
||||
notification.success({ message: '更新成功' });
|
||||
form.resetFields();
|
||||
onClose();
|
||||
reset();
|
||||
},
|
||||
onError: err => {
|
||||
notification.error({ message: err.message });
|
||||
},
|
||||
});
|
||||
const addRequest = useRequest(fetchAddItem, {
|
||||
manual: true,
|
||||
onSuccess: () => {
|
||||
notification.success({ message: '创建成功' });
|
||||
form.resetFields();
|
||||
onClose();
|
||||
reset();
|
||||
},
|
||||
onError: err => {
|
||||
notification.error({ message: err.message });
|
||||
},
|
||||
});
|
||||
const onSave = () => {
|
||||
form
|
||||
.validateFields()
|
||||
.then(values => {
|
||||
addRequest.run({ ...values });
|
||||
})
|
||||
.catch(info => {
|
||||
console.log('Validate Failed:', info);
|
||||
});
|
||||
};
|
||||
const onUpdate = () => {
|
||||
form
|
||||
.validateFields()
|
||||
.then(values => {
|
||||
updateRequest.run({ id: data.id, ...values });
|
||||
})
|
||||
.catch(info => {
|
||||
console.log('Validate Failed:', info);
|
||||
});
|
||||
};
|
||||
useEffect(() => {
|
||||
if (type === 'edit') {
|
||||
form.setFieldsValue({
|
||||
...data,
|
||||
});
|
||||
}
|
||||
}, [type, data, form]);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
open={visible}
|
||||
onCancel={onClose}
|
||||
width={600}
|
||||
title={type === 'edit' ? '编辑' : '创建'}
|
||||
onOk={type === 'edit' ? onUpdate : onSave}
|
||||
confirmLoading={addRequest.loading || updateRequest.loading}
|
||||
>
|
||||
<Form labelAlign="right" labelCol={{ span: 6 }} wrapperCol={{ span: 15 }} form={form}>
|
||||
<Form.Item label="租户" name="tenantId" rules={[{ required: true }]}>
|
||||
<Select
|
||||
options={tenantRequest.data}
|
||||
placeholder="请选择"
|
||||
loading={tenantRequest.loading}
|
||||
disabled={type === 'edit'}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item label="项目" name="itemId" rules={[{ required: true }]}>
|
||||
<Input placeholder="请输入" disabled={type === 'edit'} />
|
||||
</Form.Item>
|
||||
<Form.Item label="项目名称" name="itemName" rules={[{ required: true }]}>
|
||||
<Input placeholder="请输入" />
|
||||
</Form.Item>
|
||||
<Form.Item label="负责人" name="owner" rules={[{ required: true }]}>
|
||||
<Input placeholder="请输入" />
|
||||
</Form.Item>
|
||||
<Form.Item label="项目简介" name="itemDesc" rules={[{ required: true }]}>
|
||||
<Input.TextArea placeholder="请输入" />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default ItemCreate;
|
@ -0,0 +1,33 @@
|
||||
import { Descriptions, Modal } from 'antd';
|
||||
import React from 'react';
|
||||
|
||||
const LogDetail: React.FC<{
|
||||
data: any;
|
||||
visible: boolean;
|
||||
onClose: () => void;
|
||||
}> = props => {
|
||||
const { visible, onClose, data } = props;
|
||||
return (
|
||||
<Modal open={visible} onCancel={onClose} footer={null} width={600}>
|
||||
<Descriptions title={'详情'} column={1}>
|
||||
<Descriptions.Item span={1} label="业务类型">
|
||||
{data.category}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item span={1} label="业务标识">
|
||||
{data.bizNo}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item span={1} label="操作人">
|
||||
{data.operator}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item span={1} label="创建时间">
|
||||
{data.createTime}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item span={1} label="日志内容">
|
||||
{data.action}
|
||||
</Descriptions.Item>
|
||||
</Descriptions>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default LogDetail;
|
@ -1,79 +1,24 @@
|
||||
import request from '@/utils';
|
||||
|
||||
const fetchTenantList = async (
|
||||
const fetchLogList = async (
|
||||
pageProps: { current: number; pageSize: number },
|
||||
formData: { tencent: string | number }
|
||||
formData: { category: string | number; bizNo: string; operator: string }
|
||||
): Promise<{ total: number; list: Array<any> }> => {
|
||||
const res: any = await request('/hippo4j/v1/cs/tenant/query/page', {
|
||||
const res: any = await request('/hippo4j/v1/cs/log/query/page', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization:
|
||||
'Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiI3LGJhb3hpbnlpX2FkbWluIiwiaXNzIjoiYWRtaW4iLCJleHAiOjE2OTUzOTg4NDksImlhdCI6MTY5NDc5NDA0OSwicm9sIjoiUk9MRV9BRE1JTiJ9.syRDshKpd-xETsSdeMPRtk956f4BJkPt4utVsUl4smgH71Woj8SUq4w2RX1YtGTC4aTZRJYdKOfkTqwK0g_dHQ',
|
||||
cookie:
|
||||
'Admin-Token=Bearer%20eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiI3LGJhb3hpbnlpX2FkbWluIiwiaXNzIjoiYWRtaW4iLCJleHAiOjE2OTUzOTg4NDksImlhdCI6MTY5NDc5NDA0OSwicm9sIjoiUk9MRV9BRE1JTiJ9.syRDshKpd-xETsSdeMPRtk956f4BJkPt4utVsUl4smgH71Woj8SUq4w2RX1YtGTC4aTZRJYdKOfkTqwK0g_dHQ; userName=baoxinyi_admin',
|
||||
},
|
||||
body: {
|
||||
...formData,
|
||||
current: pageProps.current,
|
||||
size: pageProps.pageSize,
|
||||
desc: true,
|
||||
},
|
||||
});
|
||||
if (res && res.success) {
|
||||
return {
|
||||
total: res.data.total,
|
||||
list: res.data.records,
|
||||
list: res.data.records.map((item: any, index: number) => ({ id: index + 1, ...item })),
|
||||
};
|
||||
}
|
||||
throw new Error(res.msg || '服务器开小差啦~');
|
||||
};
|
||||
|
||||
const fetchAddTenant = async (id: string) => {
|
||||
const res = await request('/hippo4j/v1/cs/tenant/save', {
|
||||
method: 'POST',
|
||||
params: { id },
|
||||
});
|
||||
|
||||
if (res && res.success) {
|
||||
return res;
|
||||
}
|
||||
throw new Error(res.msg || '服务器开小差啦~');
|
||||
};
|
||||
|
||||
const fetchDeleteTenant = async (id: string) => {
|
||||
const res = await request('/tenants', {
|
||||
method: 'POST',
|
||||
params: { id },
|
||||
});
|
||||
|
||||
if (res && res.success) {
|
||||
return res;
|
||||
}
|
||||
throw new Error(res.msg || '服务器开小差啦~');
|
||||
};
|
||||
|
||||
const fetchUpdateTenant = async (id: string) => {
|
||||
const res = await request('hippo4j/v1/cs/tenant/update', {
|
||||
method: 'POST',
|
||||
params: { id },
|
||||
});
|
||||
|
||||
if (res && res.success) {
|
||||
return res;
|
||||
}
|
||||
throw new Error(res.msg || '服务器开小差啦~');
|
||||
};
|
||||
|
||||
const fetchTenantDetail = async (id: string) => {
|
||||
const res = await request('/tenants', {
|
||||
method: 'POST',
|
||||
params: { id },
|
||||
});
|
||||
|
||||
if (res && res.success) {
|
||||
return res;
|
||||
}
|
||||
throw new Error(res.msg || '服务器开小差啦~');
|
||||
};
|
||||
|
||||
export { fetchTenantList, fetchAddTenant, fetchDeleteTenant, fetchUpdateTenant, fetchTenantDetail };
|
||||
export { fetchLogList };
|
||||
|
@ -0,0 +1,96 @@
|
||||
import { useRequest } from 'ahooks';
|
||||
import { Form, Modal, Input, notification } from 'antd';
|
||||
import React, { useEffect } from 'react';
|
||||
import { fetchAddTenant, fetchUpdateTenant } from './service';
|
||||
|
||||
interface IProps {
|
||||
type: string;
|
||||
data: any;
|
||||
visible: boolean;
|
||||
onClose: () => void;
|
||||
reset: () => void;
|
||||
}
|
||||
|
||||
const TenantCreate: React.FC<IProps> = props => {
|
||||
const { visible, onClose, data, type, reset } = props;
|
||||
const [form] = Form.useForm();
|
||||
const updateRequest = useRequest(fetchUpdateTenant, {
|
||||
manual: true,
|
||||
onSuccess: () => {
|
||||
notification.success({ message: '更新成功' });
|
||||
form.resetFields();
|
||||
onClose();
|
||||
reset();
|
||||
},
|
||||
onError: err => {
|
||||
notification.error({ message: err.message });
|
||||
},
|
||||
});
|
||||
const addRequest = useRequest(fetchAddTenant, {
|
||||
manual: true,
|
||||
onSuccess: () => {
|
||||
notification.success({ message: '创建成功' });
|
||||
form.resetFields();
|
||||
onClose();
|
||||
reset();
|
||||
},
|
||||
onError: err => {
|
||||
notification.error({ message: err.message });
|
||||
},
|
||||
});
|
||||
const onSave = () => {
|
||||
form
|
||||
.validateFields()
|
||||
.then(values => {
|
||||
addRequest.run({ ...values });
|
||||
})
|
||||
.catch(info => {
|
||||
console.log('Validate Failed:', info);
|
||||
});
|
||||
};
|
||||
const onUpdate = () => {
|
||||
form
|
||||
.validateFields()
|
||||
.then(values => {
|
||||
updateRequest.run({ id: data.id, ...values });
|
||||
})
|
||||
.catch(info => {
|
||||
console.log('Validate Failed:', info);
|
||||
});
|
||||
};
|
||||
useEffect(() => {
|
||||
if (type === 'edit') {
|
||||
form.setFieldsValue({
|
||||
...data,
|
||||
});
|
||||
}
|
||||
}, [type, data, form]);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
open={visible}
|
||||
onCancel={onClose}
|
||||
width={600}
|
||||
title={type === 'edit' ? '编辑' : '创建'}
|
||||
onOk={type === 'edit' ? onUpdate : onSave}
|
||||
confirmLoading={addRequest.loading || updateRequest.loading}
|
||||
>
|
||||
<Form labelAlign="right" labelCol={{ span: 6 }} wrapperCol={{ span: 15 }} form={form}>
|
||||
<Form.Item label="租户" name="tenantId" rules={[{ required: true }]}>
|
||||
<Input placeholder="请输入" disabled={type === 'edit'} />
|
||||
</Form.Item>
|
||||
<Form.Item label="租户名称" name="tenantName" rules={[{ required: true }]}>
|
||||
<Input placeholder="请输入" />
|
||||
</Form.Item>
|
||||
<Form.Item label="负责人" name="owner" rules={[{ required: true }]}>
|
||||
<Input placeholder="请输入" />
|
||||
</Form.Item>
|
||||
<Form.Item label="租户简介" name="tenantDesc" rules={[{ required: true }]}>
|
||||
<Input.TextArea placeholder="请输入" />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default TenantCreate;
|
@ -0,0 +1,34 @@
|
||||
import * as echarts from 'echarts/core';
|
||||
import { GridComponent } from 'echarts/components';
|
||||
import { LineChart } from 'echarts/charts';
|
||||
import { UniversalTransition } from 'echarts/features';
|
||||
import { CanvasRenderer } from 'echarts/renderers';
|
||||
import { useEffect } from 'react';
|
||||
echarts.use([GridComponent, LineChart, CanvasRenderer, UniversalTransition]);
|
||||
|
||||
const ThreadPoolMonitor = () => {
|
||||
useEffect(() => {
|
||||
let chartDom = document.getElementById('main');
|
||||
let myChart = echarts.init(chartDom);
|
||||
let option;
|
||||
option = {
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
},
|
||||
series: [
|
||||
{
|
||||
data: [150, 230, 224, 218, 135, 147, 260],
|
||||
type: 'line',
|
||||
},
|
||||
],
|
||||
};
|
||||
option && myChart.setOption(option);
|
||||
});
|
||||
return <div id="main" style={{ width: '400px', height: '400px' }}></div>;
|
||||
};
|
||||
|
||||
export default ThreadPoolMonitor;
|
@ -0,0 +1,11 @@
|
||||
import { IRouterList } from '@/typings';
|
||||
import ThreadPoolMonitor from '.';
|
||||
|
||||
const routerList: IRouterList[] = [
|
||||
{
|
||||
path: '/echarts',
|
||||
component: ThreadPoolMonitor,
|
||||
},
|
||||
];
|
||||
|
||||
export default routerList;
|
@ -0,0 +1,23 @@
|
||||
export const QUEUE_TYPE_MAP: { [key: string]: string } = {
|
||||
'1': 'ArrayBlockingQueue',
|
||||
'2': 'LinkedBlockingQueue',
|
||||
'3': 'LinkedBlockingDeque',
|
||||
'4': 'SynchronousQueue',
|
||||
'5': 'LinkedTransferQueue',
|
||||
'6': 'PriorityBlockingQueue',
|
||||
'9': 'ResizableLinkedBlockingQueue',
|
||||
};
|
||||
|
||||
export const REJECT_TYPE_MAP: { [key: string]: string } = {
|
||||
'1': 'CallerRunsPolicy',
|
||||
'2': 'AbortPolicy',
|
||||
'3': 'DiscardPolicy',
|
||||
'4': 'DiscardOldestPolicy',
|
||||
'5': 'RunsOldestTaskPolicy',
|
||||
'6': 'SyncPutQueuePolicy',
|
||||
};
|
||||
|
||||
export const paramsType = { project: 0, thpool: 0 };
|
||||
export const eBtnStyle = {
|
||||
padding: '0 6px',
|
||||
};
|
@ -0,0 +1,17 @@
|
||||
import request from '@/utils';
|
||||
import { Result, ThreadPoolTableBody, ThreadPoolTableRes } from './type';
|
||||
|
||||
const fetchThreadPoolTable = async (body: ThreadPoolTableBody): Promise<Result> => {
|
||||
const { data } = await request<ThreadPoolTableRes>('/hippo4j/v1/cs/thread/pool/query/page', {
|
||||
method: 'POST',
|
||||
body,
|
||||
});
|
||||
return {
|
||||
total: data?.total,
|
||||
list: data?.records,
|
||||
};
|
||||
};
|
||||
|
||||
export default {
|
||||
fetchThreadPoolTable,
|
||||
};
|
@ -0,0 +1,123 @@
|
||||
import { Params } from 'ahooks/lib/useAntdTable/types';
|
||||
|
||||
// body
|
||||
export interface ThreadPoolTableBody {
|
||||
/**
|
||||
* current page
|
||||
*/
|
||||
current: number;
|
||||
/**
|
||||
* project id
|
||||
*/
|
||||
itemId?: string;
|
||||
/**
|
||||
* page size
|
||||
*/
|
||||
size: number;
|
||||
/**
|
||||
*tenant Id
|
||||
*/
|
||||
tenantId?: string;
|
||||
/**
|
||||
* thread pool ID
|
||||
*/
|
||||
tpId?: string;
|
||||
}
|
||||
|
||||
export interface Record {
|
||||
/**
|
||||
* 是否超时
|
||||
*/
|
||||
allowCoreThreadTimeOut?: number;
|
||||
/**
|
||||
* 队列容量
|
||||
*/
|
||||
capacity?: number;
|
||||
/**
|
||||
* 容量报警
|
||||
*/
|
||||
capacityAlarm?: number;
|
||||
/**
|
||||
* 核心线程数
|
||||
*/
|
||||
coreSize?: number;
|
||||
/**
|
||||
* 执行超市
|
||||
*/
|
||||
executeTimeOut?: number;
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
gmtCreate?: string;
|
||||
/**
|
||||
* 修改时间
|
||||
*/
|
||||
gmtModified?: string;
|
||||
/**
|
||||
* ID
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* 是否报警
|
||||
*/
|
||||
isAlarm?: number;
|
||||
/**
|
||||
* 项目ID
|
||||
*/
|
||||
itemId?: string;
|
||||
/**
|
||||
* 空闲回收
|
||||
*/
|
||||
keepAliveTime?: number;
|
||||
/**
|
||||
* 活跃度报警
|
||||
*/
|
||||
livenessAlarm?: number;
|
||||
/**
|
||||
* 最大线程数
|
||||
*/
|
||||
maxSize?: number;
|
||||
/**
|
||||
* 队列名称
|
||||
*/
|
||||
queueName?: null;
|
||||
/**
|
||||
* 队列类型
|
||||
*/
|
||||
queueType?: number;
|
||||
/**
|
||||
* 拒绝策略类型
|
||||
*/
|
||||
rejectedType?: number;
|
||||
/**
|
||||
* 租户ID
|
||||
*/
|
||||
tenantId?: string;
|
||||
/**
|
||||
* 线程池ID
|
||||
*/
|
||||
tpId?: string;
|
||||
}
|
||||
|
||||
export interface ThreadPoolTableRes {
|
||||
countId: null;
|
||||
current: number;
|
||||
desc: boolean;
|
||||
hitCount: boolean;
|
||||
itemId: string;
|
||||
maxLimit: null;
|
||||
optimizeCountSql: boolean;
|
||||
orders: string[];
|
||||
pages: number;
|
||||
records: Record[];
|
||||
searchCount: boolean;
|
||||
size: number;
|
||||
tenantId: string;
|
||||
total: number;
|
||||
tpId: string;
|
||||
}
|
||||
|
||||
export interface Result {
|
||||
total: number;
|
||||
list: Record[];
|
||||
}
|
@ -0,0 +1,115 @@
|
||||
import { useRequest } from 'ahooks';
|
||||
import { Form, Modal, Input, notification, Select, Checkbox, message } from 'antd';
|
||||
import React, { useEffect } from 'react';
|
||||
import { fetchAddUser, fetchUpdateUser } from './service';
|
||||
import { fetchTenantOptions } from '../tenant/service';
|
||||
|
||||
interface IProps {
|
||||
type: string;
|
||||
data: any;
|
||||
visible: boolean;
|
||||
onClose: () => void;
|
||||
reset: () => void;
|
||||
}
|
||||
|
||||
const ROLE_OPTIONS = [
|
||||
{
|
||||
label: 'ROLE_USER',
|
||||
value: 'ROLE_USER',
|
||||
},
|
||||
{
|
||||
label: 'ROLE_ADMIN',
|
||||
value: 'ROLE_ADMIN',
|
||||
},
|
||||
{
|
||||
label: 'ROLE_MANAGE',
|
||||
value: 'ROLE_MANAGE',
|
||||
},
|
||||
];
|
||||
|
||||
const UserCreate: React.FC<IProps> = props => {
|
||||
const { visible, onClose, data, type, reset } = props;
|
||||
const [form] = Form.useForm();
|
||||
const tenantRequest = useRequest(fetchTenantOptions, {
|
||||
ready: !!type,
|
||||
});
|
||||
const updateRequest = useRequest(fetchUpdateUser, {
|
||||
manual: true,
|
||||
onSuccess: () => {
|
||||
notification.success({ message: '更新成功' });
|
||||
form.resetFields();
|
||||
onClose();
|
||||
reset();
|
||||
},
|
||||
onError: err => {
|
||||
message.error(err.message);
|
||||
},
|
||||
});
|
||||
const addRequest = useRequest(fetchAddUser, {
|
||||
manual: true,
|
||||
onSuccess: () => {
|
||||
notification.success({ message: '创建成功' });
|
||||
form.resetFields();
|
||||
onClose();
|
||||
reset();
|
||||
},
|
||||
onError: err => {
|
||||
message.error(err.message);
|
||||
},
|
||||
});
|
||||
const onSave = () => {
|
||||
form
|
||||
.validateFields()
|
||||
.then(values => {
|
||||
addRequest.run({ ...values });
|
||||
})
|
||||
.catch(info => {
|
||||
console.log('Validate Failed:', info);
|
||||
});
|
||||
};
|
||||
const onUpdate = () => {
|
||||
form
|
||||
.validateFields()
|
||||
.then(values => {
|
||||
updateRequest.run({ id: data.id, ...values });
|
||||
})
|
||||
.catch(info => {
|
||||
console.log('Validate Failed:', info);
|
||||
});
|
||||
};
|
||||
useEffect(() => {
|
||||
if (type === 'edit') {
|
||||
form.setFieldsValue({
|
||||
...data,
|
||||
});
|
||||
}
|
||||
}, [type, data, form]);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
open={visible}
|
||||
onCancel={onClose}
|
||||
width={600}
|
||||
title={type === 'edit' ? '编辑' : '创建'}
|
||||
onOk={type === 'edit' ? onUpdate : onSave}
|
||||
confirmLoading={addRequest.loading || updateRequest.loading}
|
||||
>
|
||||
<Form labelAlign="right" labelCol={{ span: 6 }} wrapperCol={{ span: 15 }} form={form}>
|
||||
<Form.Item label="用户名" name="userName" rules={[{ required: true }]}>
|
||||
<Input placeholder="请输入" disabled={type === 'edit'} />
|
||||
</Form.Item>
|
||||
<Form.Item label="密码" name="password" rules={[{ required: true }]}>
|
||||
<Input placeholder="请输入" />
|
||||
</Form.Item>
|
||||
<Form.Item label="角色" name="role" rules={[{ required: true }]}>
|
||||
<Select options={ROLE_OPTIONS} placeholder="请选择" disabled={type === 'edit'} />
|
||||
</Form.Item>
|
||||
<Form.Item label="租户" name="tempResources">
|
||||
<Checkbox.Group options={tenantRequest.data} />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default UserCreate;
|