feat: login
This commit is contained in:
@@ -1,80 +1,80 @@
|
||||
import { PlusOutlined } from '@ant-design/icons';
|
||||
import {
|
||||
type ActionType,
|
||||
ModalForm,
|
||||
ProFormText,
|
||||
ProFormTextArea,
|
||||
} from '@ant-design/pro-components';
|
||||
import { FormattedMessage, useIntl, useRequest } from '@umijs/max';
|
||||
import { Button, message } from 'antd';
|
||||
import type { FC } from 'react';
|
||||
import { addRule } from '@/services/ant-design-pro/api';
|
||||
// import { PlusOutlined } from '@ant-design/icons';
|
||||
// import {
|
||||
// type ActionType,
|
||||
// ModalForm,
|
||||
// ProFormText,
|
||||
// ProFormTextArea,
|
||||
// } from '@ant-design/pro-components';
|
||||
// import { FormattedMessage, useIntl, useRequest } from '@umijs/max';
|
||||
// import { Button, message } from 'antd';
|
||||
// import type { FC } from 'react';
|
||||
// import { addRule } from '@/services/ant-design-pro/api';
|
||||
|
||||
interface CreateFormProps {
|
||||
reload?: ActionType['reload'];
|
||||
}
|
||||
// interface CreateFormProps {
|
||||
// reload?: ActionType['reload'];
|
||||
// }
|
||||
|
||||
const CreateForm: FC<CreateFormProps> = (props) => {
|
||||
const { reload } = props;
|
||||
// const CreateForm: FC<CreateFormProps> = (props) => {
|
||||
// const { reload } = props;
|
||||
|
||||
const [messageApi, contextHolder] = message.useMessage();
|
||||
/**
|
||||
* @en-US International configuration
|
||||
* @zh-CN 国际化配置
|
||||
* */
|
||||
const intl = useIntl();
|
||||
// const [messageApi, contextHolder] = message.useMessage();
|
||||
// /**
|
||||
// * @en-US International configuration
|
||||
// * @zh-CN 国际化配置
|
||||
// * */
|
||||
// const intl = useIntl();
|
||||
|
||||
const { run, loading } = useRequest(addRule, {
|
||||
manual: true,
|
||||
onSuccess: () => {
|
||||
messageApi.success('Added successfully');
|
||||
reload?.();
|
||||
},
|
||||
onError: () => {
|
||||
messageApi.error('Adding failed, please try again!');
|
||||
},
|
||||
});
|
||||
// const { run, loading } = useRequest(addRule, {
|
||||
// manual: true,
|
||||
// onSuccess: () => {
|
||||
// messageApi.success('Added successfully');
|
||||
// reload?.();
|
||||
// },
|
||||
// onError: () => {
|
||||
// messageApi.error('Adding failed, please try again!');
|
||||
// },
|
||||
// });
|
||||
|
||||
return (
|
||||
<>
|
||||
{contextHolder}
|
||||
<ModalForm
|
||||
title={intl.formatMessage({
|
||||
id: 'pages.searchTable.createForm.newRule',
|
||||
defaultMessage: 'New rule',
|
||||
})}
|
||||
trigger={
|
||||
<Button type="primary" icon={<PlusOutlined />}>
|
||||
<FormattedMessage id="pages.searchTable.new" defaultMessage="New" />
|
||||
</Button>
|
||||
}
|
||||
width="400px"
|
||||
modalProps={{ okButtonProps: { loading } }}
|
||||
onFinish={async (value) => {
|
||||
await run({ data: value as API.RuleListItem });
|
||||
// return (
|
||||
// <>
|
||||
// {contextHolder}
|
||||
// <ModalForm
|
||||
// title={intl.formatMessage({
|
||||
// id: 'pages.searchTable.createForm.newRule',
|
||||
// defaultMessage: 'New rule',
|
||||
// })}
|
||||
// trigger={
|
||||
// <Button type="primary" icon={<PlusOutlined />}>
|
||||
// <FormattedMessage id="pages.searchTable.new" defaultMessage="New" />
|
||||
// </Button>
|
||||
// }
|
||||
// width="400px"
|
||||
// modalProps={{ okButtonProps: { loading } }}
|
||||
// onFinish={async (value) => {
|
||||
// await run({ data: value as API.RuleListItem });
|
||||
|
||||
return true;
|
||||
}}
|
||||
>
|
||||
<ProFormText
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: (
|
||||
<FormattedMessage
|
||||
id="pages.searchTable.ruleName"
|
||||
defaultMessage="Rule name is required"
|
||||
/>
|
||||
),
|
||||
},
|
||||
]}
|
||||
width="md"
|
||||
name="name"
|
||||
/>
|
||||
<ProFormTextArea width="md" name="desc" />
|
||||
</ModalForm>
|
||||
</>
|
||||
);
|
||||
};
|
||||
// return true;
|
||||
// }}
|
||||
// >
|
||||
// <ProFormText
|
||||
// rules={[
|
||||
// {
|
||||
// required: true,
|
||||
// message: (
|
||||
// <FormattedMessage
|
||||
// id="pages.searchTable.ruleName"
|
||||
// defaultMessage="Rule name is required"
|
||||
// />
|
||||
// ),
|
||||
// },
|
||||
// ]}
|
||||
// width="md"
|
||||
// name="name"
|
||||
// />
|
||||
// <ProFormTextArea width="md" name="desc" />
|
||||
// </ModalForm>
|
||||
// </>
|
||||
// );
|
||||
// };
|
||||
|
||||
export default CreateForm;
|
||||
// export default CreateForm;
|
||||
|
||||
@@ -1,251 +1,251 @@
|
||||
import {
|
||||
ProFormDateTimePicker,
|
||||
ProFormRadio,
|
||||
ProFormSelect,
|
||||
ProFormText,
|
||||
ProFormTextArea,
|
||||
StepsForm,
|
||||
} from '@ant-design/pro-components';
|
||||
import { FormattedMessage, useIntl, useRequest } from '@umijs/max';
|
||||
import { Modal, message } from 'antd';
|
||||
import React, { cloneElement, useCallback, useState } from 'react';
|
||||
import { updateRule } from '@/services/ant-design-pro/api';
|
||||
// import {
|
||||
// ProFormDateTimePicker,
|
||||
// ProFormRadio,
|
||||
// ProFormSelect,
|
||||
// ProFormText,
|
||||
// ProFormTextArea,
|
||||
// StepsForm,
|
||||
// } from '@ant-design/pro-components';
|
||||
// import { FormattedMessage, useIntl, useRequest } from '@umijs/max';
|
||||
// import { Modal, message } from 'antd';
|
||||
// import React, { cloneElement, useCallback, useState } from 'react';
|
||||
// import { updateRule } from '@/services/ant-design-pro/api';
|
||||
|
||||
export type FormValueType = {
|
||||
target?: string;
|
||||
template?: string;
|
||||
type?: string;
|
||||
time?: string;
|
||||
frequency?: string;
|
||||
} & Partial<API.RuleListItem>;
|
||||
// export type FormValueType = {
|
||||
// target?: string;
|
||||
// template?: string;
|
||||
// type?: string;
|
||||
// time?: string;
|
||||
// frequency?: string;
|
||||
// } & Partial<API.RuleListItem>;
|
||||
|
||||
export type UpdateFormProps = {
|
||||
trigger?: React.ReactElement<any>;
|
||||
onOk?: () => void;
|
||||
values: Partial<API.RuleListItem>;
|
||||
};
|
||||
// export type UpdateFormProps = {
|
||||
// trigger?: React.ReactElement<any>;
|
||||
// onOk?: () => void;
|
||||
// values: Partial<API.RuleListItem>;
|
||||
// };
|
||||
|
||||
const UpdateForm: React.FC<UpdateFormProps> = (props) => {
|
||||
const { onOk, values, trigger } = props;
|
||||
// const UpdateForm: React.FC<UpdateFormProps> = (props) => {
|
||||
// const { onOk, values, trigger } = props;
|
||||
|
||||
const intl = useIntl();
|
||||
// const intl = useIntl();
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
// const [open, setOpen] = useState(false);
|
||||
|
||||
const [messageApi, contextHolder] = message.useMessage();
|
||||
// const [messageApi, contextHolder] = message.useMessage();
|
||||
|
||||
const { run } = useRequest(updateRule, {
|
||||
manual: true,
|
||||
onSuccess: () => {
|
||||
messageApi.success('Configuration is successful');
|
||||
onOk?.();
|
||||
},
|
||||
onError: () => {
|
||||
messageApi.error('Configuration failed, please try again!');
|
||||
},
|
||||
});
|
||||
// const { run } = useRequest(updateRule, {
|
||||
// manual: true,
|
||||
// onSuccess: () => {
|
||||
// messageApi.success('Configuration is successful');
|
||||
// onOk?.();
|
||||
// },
|
||||
// onError: () => {
|
||||
// messageApi.error('Configuration failed, please try again!');
|
||||
// },
|
||||
// });
|
||||
|
||||
const onCancel = useCallback(() => {
|
||||
setOpen(false);
|
||||
}, []);
|
||||
// const onCancel = useCallback(() => {
|
||||
// setOpen(false);
|
||||
// }, []);
|
||||
|
||||
const onOpen = useCallback(() => {
|
||||
setOpen(true);
|
||||
}, []);
|
||||
// const onOpen = useCallback(() => {
|
||||
// setOpen(true);
|
||||
// }, []);
|
||||
|
||||
const onFinish = useCallback(
|
||||
async (values?: any) => {
|
||||
await run({ data: values });
|
||||
// const onFinish = useCallback(
|
||||
// async (values?: any) => {
|
||||
// await run({ data: values });
|
||||
|
||||
onCancel();
|
||||
},
|
||||
[onCancel, run],
|
||||
);
|
||||
// onCancel();
|
||||
// },
|
||||
// [onCancel, run],
|
||||
// );
|
||||
|
||||
return (
|
||||
<>
|
||||
{contextHolder}
|
||||
{trigger
|
||||
? cloneElement(trigger, {
|
||||
onClick: onOpen,
|
||||
})
|
||||
: null}
|
||||
<StepsForm
|
||||
stepsProps={{
|
||||
size: 'small',
|
||||
}}
|
||||
stepsFormRender={(dom, submitter) => {
|
||||
return (
|
||||
<Modal
|
||||
width={640}
|
||||
styles={{
|
||||
body: {
|
||||
padding: '32px 40px 48px',
|
||||
},
|
||||
}}
|
||||
destroyOnHidden
|
||||
title={intl.formatMessage({
|
||||
id: 'pages.searchTable.updateForm.ruleConfig',
|
||||
defaultMessage: '规则配置',
|
||||
})}
|
||||
open={open}
|
||||
footer={submitter}
|
||||
onCancel={onCancel}
|
||||
>
|
||||
{dom}
|
||||
</Modal>
|
||||
);
|
||||
}}
|
||||
onFinish={onFinish}
|
||||
>
|
||||
<StepsForm.StepForm
|
||||
initialValues={values}
|
||||
title={intl.formatMessage({
|
||||
id: 'pages.searchTable.updateForm.basicConfig',
|
||||
defaultMessage: '基本信息',
|
||||
})}
|
||||
>
|
||||
<ProFormText
|
||||
name="name"
|
||||
label={intl.formatMessage({
|
||||
id: 'pages.searchTable.updateForm.ruleName.nameLabel',
|
||||
defaultMessage: '规则名称',
|
||||
})}
|
||||
width="md"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: (
|
||||
<FormattedMessage
|
||||
id="pages.searchTable.updateForm.ruleName.nameRules"
|
||||
defaultMessage="请输入规则名称!"
|
||||
/>
|
||||
),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<ProFormTextArea
|
||||
name="desc"
|
||||
width="md"
|
||||
label={intl.formatMessage({
|
||||
id: 'pages.searchTable.updateForm.ruleDesc.descLabel',
|
||||
defaultMessage: '规则描述',
|
||||
})}
|
||||
placeholder={intl.formatMessage({
|
||||
id: 'pages.searchTable.updateForm.ruleDesc.descPlaceholder',
|
||||
defaultMessage: '请输入至少五个字符',
|
||||
})}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: (
|
||||
<FormattedMessage
|
||||
id="pages.searchTable.updateForm.ruleDesc.descRules"
|
||||
defaultMessage="请输入至少五个字符的规则描述!"
|
||||
/>
|
||||
),
|
||||
min: 5,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</StepsForm.StepForm>
|
||||
<StepsForm.StepForm
|
||||
initialValues={{
|
||||
target: '0',
|
||||
template: '0',
|
||||
}}
|
||||
title={intl.formatMessage({
|
||||
id: 'pages.searchTable.updateForm.ruleProps.title',
|
||||
defaultMessage: '配置规则属性',
|
||||
})}
|
||||
>
|
||||
<ProFormSelect
|
||||
name="target"
|
||||
width="md"
|
||||
label={intl.formatMessage({
|
||||
id: 'pages.searchTable.updateForm.object',
|
||||
defaultMessage: '监控对象',
|
||||
})}
|
||||
valueEnum={{
|
||||
0: '表一',
|
||||
1: '表二',
|
||||
}}
|
||||
/>
|
||||
<ProFormSelect
|
||||
name="template"
|
||||
width="md"
|
||||
label={intl.formatMessage({
|
||||
id: 'pages.searchTable.updateForm.ruleProps.templateLabel',
|
||||
defaultMessage: '规则模板',
|
||||
})}
|
||||
valueEnum={{
|
||||
0: '规则模板一',
|
||||
1: '规则模板二',
|
||||
}}
|
||||
/>
|
||||
<ProFormRadio.Group
|
||||
name="type"
|
||||
label={intl.formatMessage({
|
||||
id: 'pages.searchTable.updateForm.ruleProps.typeLabel',
|
||||
defaultMessage: '规则类型',
|
||||
})}
|
||||
options={[
|
||||
{
|
||||
value: '0',
|
||||
label: '强',
|
||||
},
|
||||
{
|
||||
value: '1',
|
||||
label: '弱',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</StepsForm.StepForm>
|
||||
<StepsForm.StepForm
|
||||
initialValues={{
|
||||
type: '1',
|
||||
frequency: 'month',
|
||||
}}
|
||||
title={intl.formatMessage({
|
||||
id: 'pages.searchTable.updateForm.schedulingPeriod.title',
|
||||
defaultMessage: '设定调度周期',
|
||||
})}
|
||||
>
|
||||
<ProFormDateTimePicker
|
||||
name="time"
|
||||
width="md"
|
||||
label={intl.formatMessage({
|
||||
id: 'pages.searchTable.updateForm.schedulingPeriod.timeLabel',
|
||||
defaultMessage: '开始时间',
|
||||
})}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: (
|
||||
<FormattedMessage
|
||||
id="pages.searchTable.updateForm.schedulingPeriod.timeRules"
|
||||
defaultMessage="请选择开始时间!"
|
||||
/>
|
||||
),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<ProFormSelect
|
||||
name="frequency"
|
||||
label={intl.formatMessage({
|
||||
id: 'pages.searchTable.updateForm.object',
|
||||
defaultMessage: '监控对象',
|
||||
})}
|
||||
width="md"
|
||||
valueEnum={{
|
||||
month: '月',
|
||||
week: '周',
|
||||
}}
|
||||
/>
|
||||
</StepsForm.StepForm>
|
||||
</StepsForm>
|
||||
</>
|
||||
);
|
||||
};
|
||||
// return (
|
||||
// <>
|
||||
// {contextHolder}
|
||||
// {trigger
|
||||
// ? cloneElement(trigger, {
|
||||
// onClick: onOpen,
|
||||
// })
|
||||
// : null}
|
||||
// <StepsForm
|
||||
// stepsProps={{
|
||||
// size: 'small',
|
||||
// }}
|
||||
// stepsFormRender={(dom, submitter) => {
|
||||
// return (
|
||||
// <Modal
|
||||
// width={640}
|
||||
// styles={{
|
||||
// body: {
|
||||
// padding: '32px 40px 48px',
|
||||
// },
|
||||
// }}
|
||||
// destroyOnHidden
|
||||
// title={intl.formatMessage({
|
||||
// id: 'pages.searchTable.updateForm.ruleConfig',
|
||||
// defaultMessage: '规则配置',
|
||||
// })}
|
||||
// open={open}
|
||||
// footer={submitter}
|
||||
// onCancel={onCancel}
|
||||
// >
|
||||
// {dom}
|
||||
// </Modal>
|
||||
// );
|
||||
// }}
|
||||
// onFinish={onFinish}
|
||||
// >
|
||||
// <StepsForm.StepForm
|
||||
// initialValues={values}
|
||||
// title={intl.formatMessage({
|
||||
// id: 'pages.searchTable.updateForm.basicConfig',
|
||||
// defaultMessage: '基本信息',
|
||||
// })}
|
||||
// >
|
||||
// <ProFormText
|
||||
// name="name"
|
||||
// label={intl.formatMessage({
|
||||
// id: 'pages.searchTable.updateForm.ruleName.nameLabel',
|
||||
// defaultMessage: '规则名称',
|
||||
// })}
|
||||
// width="md"
|
||||
// rules={[
|
||||
// {
|
||||
// required: true,
|
||||
// message: (
|
||||
// <FormattedMessage
|
||||
// id="pages.searchTable.updateForm.ruleName.nameRules"
|
||||
// defaultMessage="请输入规则名称!"
|
||||
// />
|
||||
// ),
|
||||
// },
|
||||
// ]}
|
||||
// />
|
||||
// <ProFormTextArea
|
||||
// name="desc"
|
||||
// width="md"
|
||||
// label={intl.formatMessage({
|
||||
// id: 'pages.searchTable.updateForm.ruleDesc.descLabel',
|
||||
// defaultMessage: '规则描述',
|
||||
// })}
|
||||
// placeholder={intl.formatMessage({
|
||||
// id: 'pages.searchTable.updateForm.ruleDesc.descPlaceholder',
|
||||
// defaultMessage: '请输入至少五个字符',
|
||||
// })}
|
||||
// rules={[
|
||||
// {
|
||||
// required: true,
|
||||
// message: (
|
||||
// <FormattedMessage
|
||||
// id="pages.searchTable.updateForm.ruleDesc.descRules"
|
||||
// defaultMessage="请输入至少五个字符的规则描述!"
|
||||
// />
|
||||
// ),
|
||||
// min: 5,
|
||||
// },
|
||||
// ]}
|
||||
// />
|
||||
// </StepsForm.StepForm>
|
||||
// <StepsForm.StepForm
|
||||
// initialValues={{
|
||||
// target: '0',
|
||||
// template: '0',
|
||||
// }}
|
||||
// title={intl.formatMessage({
|
||||
// id: 'pages.searchTable.updateForm.ruleProps.title',
|
||||
// defaultMessage: '配置规则属性',
|
||||
// })}
|
||||
// >
|
||||
// <ProFormSelect
|
||||
// name="target"
|
||||
// width="md"
|
||||
// label={intl.formatMessage({
|
||||
// id: 'pages.searchTable.updateForm.object',
|
||||
// defaultMessage: '监控对象',
|
||||
// })}
|
||||
// valueEnum={{
|
||||
// 0: '表一',
|
||||
// 1: '表二',
|
||||
// }}
|
||||
// />
|
||||
// <ProFormSelect
|
||||
// name="template"
|
||||
// width="md"
|
||||
// label={intl.formatMessage({
|
||||
// id: 'pages.searchTable.updateForm.ruleProps.templateLabel',
|
||||
// defaultMessage: '规则模板',
|
||||
// })}
|
||||
// valueEnum={{
|
||||
// 0: '规则模板一',
|
||||
// 1: '规则模板二',
|
||||
// }}
|
||||
// />
|
||||
// <ProFormRadio.Group
|
||||
// name="type"
|
||||
// label={intl.formatMessage({
|
||||
// id: 'pages.searchTable.updateForm.ruleProps.typeLabel',
|
||||
// defaultMessage: '规则类型',
|
||||
// })}
|
||||
// options={[
|
||||
// {
|
||||
// value: '0',
|
||||
// label: '强',
|
||||
// },
|
||||
// {
|
||||
// value: '1',
|
||||
// label: '弱',
|
||||
// },
|
||||
// ]}
|
||||
// />
|
||||
// </StepsForm.StepForm>
|
||||
// <StepsForm.StepForm
|
||||
// initialValues={{
|
||||
// type: '1',
|
||||
// frequency: 'month',
|
||||
// }}
|
||||
// title={intl.formatMessage({
|
||||
// id: 'pages.searchTable.updateForm.schedulingPeriod.title',
|
||||
// defaultMessage: '设定调度周期',
|
||||
// })}
|
||||
// >
|
||||
// <ProFormDateTimePicker
|
||||
// name="time"
|
||||
// width="md"
|
||||
// label={intl.formatMessage({
|
||||
// id: 'pages.searchTable.updateForm.schedulingPeriod.timeLabel',
|
||||
// defaultMessage: '开始时间',
|
||||
// })}
|
||||
// rules={[
|
||||
// {
|
||||
// required: true,
|
||||
// message: (
|
||||
// <FormattedMessage
|
||||
// id="pages.searchTable.updateForm.schedulingPeriod.timeRules"
|
||||
// defaultMessage="请选择开始时间!"
|
||||
// />
|
||||
// ),
|
||||
// },
|
||||
// ]}
|
||||
// />
|
||||
// <ProFormSelect
|
||||
// name="frequency"
|
||||
// label={intl.formatMessage({
|
||||
// id: 'pages.searchTable.updateForm.object',
|
||||
// defaultMessage: '监控对象',
|
||||
// })}
|
||||
// width="md"
|
||||
// valueEnum={{
|
||||
// month: '月',
|
||||
// week: '周',
|
||||
// }}
|
||||
// />
|
||||
// </StepsForm.StepForm>
|
||||
// </StepsForm>
|
||||
// </>
|
||||
// );
|
||||
// };
|
||||
|
||||
export default UpdateForm;
|
||||
// export default UpdateForm;
|
||||
|
||||
@@ -1,330 +1,330 @@
|
||||
import type {
|
||||
ActionType,
|
||||
ProColumns,
|
||||
ProDescriptionsItemProps,
|
||||
} from '@ant-design/pro-components';
|
||||
import {
|
||||
FooterToolbar,
|
||||
PageContainer,
|
||||
ProDescriptions,
|
||||
ProTable,
|
||||
} from '@ant-design/pro-components';
|
||||
import { FormattedMessage, useIntl, useRequest } from '@umijs/max';
|
||||
import { Button, Drawer, Input, message } from 'antd';
|
||||
import React, { useCallback, useRef, useState } from 'react';
|
||||
import { removeRule, rule } from '@/services/ant-design-pro/api';
|
||||
import CreateForm from './components/CreateForm';
|
||||
import UpdateForm from './components/UpdateForm';
|
||||
// import type {
|
||||
// ActionType,
|
||||
// ProColumns,
|
||||
// ProDescriptionsItemProps,
|
||||
// } from '@ant-design/pro-components';
|
||||
// import {
|
||||
// FooterToolbar,
|
||||
// PageContainer,
|
||||
// ProDescriptions,
|
||||
// ProTable,
|
||||
// } from '@ant-design/pro-components';
|
||||
// import { FormattedMessage, useIntl, useRequest } from '@umijs/max';
|
||||
// import { Button, Drawer, Input, message } from 'antd';
|
||||
// import React, { useCallback, useRef, useState } from 'react';
|
||||
// import { removeRule, rule } from '@/services/ant-design-pro/api';
|
||||
// import CreateForm from './components/CreateForm';
|
||||
// import UpdateForm from './components/UpdateForm';
|
||||
|
||||
const TableList: React.FC = () => {
|
||||
const actionRef = useRef<ActionType | null>(null);
|
||||
// const TableList: React.FC = () => {
|
||||
// const actionRef = useRef<ActionType | null>(null);
|
||||
|
||||
const [showDetail, setShowDetail] = useState<boolean>(false);
|
||||
const [currentRow, setCurrentRow] = useState<API.RuleListItem>();
|
||||
const [selectedRowsState, setSelectedRows] = useState<API.RuleListItem[]>([]);
|
||||
// const [showDetail, setShowDetail] = useState<boolean>(false);
|
||||
// const [currentRow, setCurrentRow] = useState<API.RuleListItem>();
|
||||
// const [selectedRowsState, setSelectedRows] = useState<API.RuleListItem[]>([]);
|
||||
|
||||
/**
|
||||
* @en-US International configuration
|
||||
* @zh-CN 国际化配置
|
||||
* */
|
||||
const intl = useIntl();
|
||||
// /**
|
||||
// * @en-US International configuration
|
||||
// * @zh-CN 国际化配置
|
||||
// * */
|
||||
// const intl = useIntl();
|
||||
|
||||
const [messageApi, contextHolder] = message.useMessage();
|
||||
// const [messageApi, contextHolder] = message.useMessage();
|
||||
|
||||
const { run: delRun, loading } = useRequest(removeRule, {
|
||||
manual: true,
|
||||
onSuccess: () => {
|
||||
setSelectedRows([]);
|
||||
actionRef.current?.reloadAndRest?.();
|
||||
// const { run: delRun, loading } = useRequest(removeRule, {
|
||||
// manual: true,
|
||||
// onSuccess: () => {
|
||||
// setSelectedRows([]);
|
||||
// actionRef.current?.reloadAndRest?.();
|
||||
|
||||
messageApi.success('Deleted successfully and will refresh soon');
|
||||
},
|
||||
onError: () => {
|
||||
messageApi.error('Delete failed, please try again');
|
||||
},
|
||||
});
|
||||
// messageApi.success('Deleted successfully and will refresh soon');
|
||||
// },
|
||||
// onError: () => {
|
||||
// messageApi.error('Delete failed, please try again');
|
||||
// },
|
||||
// });
|
||||
|
||||
const columns: ProColumns<API.RuleListItem>[] = [
|
||||
{
|
||||
title: (
|
||||
<FormattedMessage
|
||||
id="pages.searchTable.updateForm.ruleName.nameLabel"
|
||||
defaultMessage="Rule name"
|
||||
/>
|
||||
),
|
||||
dataIndex: 'name',
|
||||
render: (dom, entity) => {
|
||||
return (
|
||||
<a
|
||||
onClick={() => {
|
||||
setCurrentRow(entity);
|
||||
setShowDetail(true);
|
||||
}}
|
||||
>
|
||||
{dom}
|
||||
</a>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: (
|
||||
<FormattedMessage
|
||||
id="pages.searchTable.titleDesc"
|
||||
defaultMessage="Description"
|
||||
/>
|
||||
),
|
||||
dataIndex: 'desc',
|
||||
valueType: 'textarea',
|
||||
},
|
||||
{
|
||||
title: (
|
||||
<FormattedMessage
|
||||
id="pages.searchTable.titleCallNo"
|
||||
defaultMessage="Number of service calls"
|
||||
/>
|
||||
),
|
||||
dataIndex: 'callNo',
|
||||
sorter: true,
|
||||
hideInForm: true,
|
||||
renderText: (val: string) =>
|
||||
`${val}${intl.formatMessage({
|
||||
id: 'pages.searchTable.tenThousand',
|
||||
defaultMessage: ' 万 ',
|
||||
})}`,
|
||||
},
|
||||
{
|
||||
title: (
|
||||
<FormattedMessage
|
||||
id="pages.searchTable.titleStatus"
|
||||
defaultMessage="Status"
|
||||
/>
|
||||
),
|
||||
dataIndex: 'status',
|
||||
hideInForm: true,
|
||||
valueEnum: {
|
||||
0: {
|
||||
text: (
|
||||
<FormattedMessage
|
||||
id="pages.searchTable.nameStatus.default"
|
||||
defaultMessage="Shut down"
|
||||
/>
|
||||
),
|
||||
status: 'Default',
|
||||
},
|
||||
1: {
|
||||
text: (
|
||||
<FormattedMessage
|
||||
id="pages.searchTable.nameStatus.running"
|
||||
defaultMessage="Running"
|
||||
/>
|
||||
),
|
||||
status: 'Processing',
|
||||
},
|
||||
2: {
|
||||
text: (
|
||||
<FormattedMessage
|
||||
id="pages.searchTable.nameStatus.online"
|
||||
defaultMessage="Online"
|
||||
/>
|
||||
),
|
||||
status: 'Success',
|
||||
},
|
||||
3: {
|
||||
text: (
|
||||
<FormattedMessage
|
||||
id="pages.searchTable.nameStatus.abnormal"
|
||||
defaultMessage="Abnormal"
|
||||
/>
|
||||
),
|
||||
status: 'Error',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
title: (
|
||||
<FormattedMessage
|
||||
id="pages.searchTable.titleUpdatedAt"
|
||||
defaultMessage="Last scheduled time"
|
||||
/>
|
||||
),
|
||||
sorter: true,
|
||||
dataIndex: 'updatedAt',
|
||||
valueType: 'dateTime',
|
||||
renderFormItem: (item, { defaultRender, ...rest }, form) => {
|
||||
const status = form.getFieldValue('status');
|
||||
if (`${status}` === '0') {
|
||||
return false;
|
||||
}
|
||||
if (`${status}` === '3') {
|
||||
return (
|
||||
<Input
|
||||
{...rest}
|
||||
placeholder={intl.formatMessage({
|
||||
id: 'pages.searchTable.exception',
|
||||
defaultMessage: 'Please enter the reason for the exception!',
|
||||
})}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return defaultRender(item);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: (
|
||||
<FormattedMessage
|
||||
id="pages.searchTable.titleOption"
|
||||
defaultMessage="Operating"
|
||||
/>
|
||||
),
|
||||
dataIndex: 'option',
|
||||
valueType: 'option',
|
||||
render: (_, record) => [
|
||||
<UpdateForm
|
||||
trigger={
|
||||
<a>
|
||||
<FormattedMessage
|
||||
id="pages.searchTable.config"
|
||||
defaultMessage="Configuration"
|
||||
/>
|
||||
</a>
|
||||
}
|
||||
key="config"
|
||||
onOk={actionRef.current?.reload}
|
||||
values={record}
|
||||
/>,
|
||||
<a key="subscribeAlert" href="https://procomponents.ant.design/">
|
||||
<FormattedMessage
|
||||
id="pages.searchTable.subscribeAlert"
|
||||
defaultMessage="Subscribe to alerts"
|
||||
/>
|
||||
</a>,
|
||||
],
|
||||
},
|
||||
];
|
||||
// const columns: ProColumns<API.RuleListItem>[] = [
|
||||
// {
|
||||
// title: (
|
||||
// <FormattedMessage
|
||||
// id="pages.searchTable.updateForm.ruleName.nameLabel"
|
||||
// defaultMessage="Rule name"
|
||||
// />
|
||||
// ),
|
||||
// dataIndex: 'name',
|
||||
// render: (dom, entity) => {
|
||||
// return (
|
||||
// <a
|
||||
// onClick={() => {
|
||||
// setCurrentRow(entity);
|
||||
// setShowDetail(true);
|
||||
// }}
|
||||
// >
|
||||
// {dom}
|
||||
// </a>
|
||||
// );
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// title: (
|
||||
// <FormattedMessage
|
||||
// id="pages.searchTable.titleDesc"
|
||||
// defaultMessage="Description"
|
||||
// />
|
||||
// ),
|
||||
// dataIndex: 'desc',
|
||||
// valueType: 'textarea',
|
||||
// },
|
||||
// {
|
||||
// title: (
|
||||
// <FormattedMessage
|
||||
// id="pages.searchTable.titleCallNo"
|
||||
// defaultMessage="Number of service calls"
|
||||
// />
|
||||
// ),
|
||||
// dataIndex: 'callNo',
|
||||
// sorter: true,
|
||||
// hideInForm: true,
|
||||
// renderText: (val: string) =>
|
||||
// `${val}${intl.formatMessage({
|
||||
// id: 'pages.searchTable.tenThousand',
|
||||
// defaultMessage: ' 万 ',
|
||||
// })}`,
|
||||
// },
|
||||
// {
|
||||
// title: (
|
||||
// <FormattedMessage
|
||||
// id="pages.searchTable.titleStatus"
|
||||
// defaultMessage="Status"
|
||||
// />
|
||||
// ),
|
||||
// dataIndex: 'status',
|
||||
// hideInForm: true,
|
||||
// valueEnum: {
|
||||
// 0: {
|
||||
// text: (
|
||||
// <FormattedMessage
|
||||
// id="pages.searchTable.nameStatus.default"
|
||||
// defaultMessage="Shut down"
|
||||
// />
|
||||
// ),
|
||||
// status: 'Default',
|
||||
// },
|
||||
// 1: {
|
||||
// text: (
|
||||
// <FormattedMessage
|
||||
// id="pages.searchTable.nameStatus.running"
|
||||
// defaultMessage="Running"
|
||||
// />
|
||||
// ),
|
||||
// status: 'Processing',
|
||||
// },
|
||||
// 2: {
|
||||
// text: (
|
||||
// <FormattedMessage
|
||||
// id="pages.searchTable.nameStatus.online"
|
||||
// defaultMessage="Online"
|
||||
// />
|
||||
// ),
|
||||
// status: 'Success',
|
||||
// },
|
||||
// 3: {
|
||||
// text: (
|
||||
// <FormattedMessage
|
||||
// id="pages.searchTable.nameStatus.abnormal"
|
||||
// defaultMessage="Abnormal"
|
||||
// />
|
||||
// ),
|
||||
// status: 'Error',
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// title: (
|
||||
// <FormattedMessage
|
||||
// id="pages.searchTable.titleUpdatedAt"
|
||||
// defaultMessage="Last scheduled time"
|
||||
// />
|
||||
// ),
|
||||
// sorter: true,
|
||||
// dataIndex: 'updatedAt',
|
||||
// valueType: 'dateTime',
|
||||
// renderFormItem: (item, { defaultRender, ...rest }, form) => {
|
||||
// const status = form.getFieldValue('status');
|
||||
// if (`${status}` === '0') {
|
||||
// return false;
|
||||
// }
|
||||
// if (`${status}` === '3') {
|
||||
// return (
|
||||
// <Input
|
||||
// {...rest}
|
||||
// placeholder={intl.formatMessage({
|
||||
// id: 'pages.searchTable.exception',
|
||||
// defaultMessage: 'Please enter the reason for the exception!',
|
||||
// })}
|
||||
// />
|
||||
// );
|
||||
// }
|
||||
// return defaultRender(item);
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// title: (
|
||||
// <FormattedMessage
|
||||
// id="pages.searchTable.titleOption"
|
||||
// defaultMessage="Operating"
|
||||
// />
|
||||
// ),
|
||||
// dataIndex: 'option',
|
||||
// valueType: 'option',
|
||||
// render: (_, record) => [
|
||||
// <UpdateForm
|
||||
// trigger={
|
||||
// <a>
|
||||
// <FormattedMessage
|
||||
// id="pages.searchTable.config"
|
||||
// defaultMessage="Configuration"
|
||||
// />
|
||||
// </a>
|
||||
// }
|
||||
// key="config"
|
||||
// onOk={actionRef.current?.reload}
|
||||
// values={record}
|
||||
// />,
|
||||
// <a key="subscribeAlert" href="https://procomponents.ant.design/">
|
||||
// <FormattedMessage
|
||||
// id="pages.searchTable.subscribeAlert"
|
||||
// defaultMessage="Subscribe to alerts"
|
||||
// />
|
||||
// </a>,
|
||||
// ],
|
||||
// },
|
||||
// ];
|
||||
|
||||
/**
|
||||
* Delete node
|
||||
* @zh-CN 删除节点
|
||||
*
|
||||
* @param selectedRows
|
||||
*/
|
||||
const handleRemove = useCallback(
|
||||
async (selectedRows: API.RuleListItem[]) => {
|
||||
if (!selectedRows?.length) {
|
||||
messageApi.warning('请选择删除项');
|
||||
// /**
|
||||
// * Delete node
|
||||
// * @zh-CN 删除节点
|
||||
// *
|
||||
// * @param selectedRows
|
||||
// */
|
||||
// const handleRemove = useCallback(
|
||||
// async (selectedRows: API.RuleListItem[]) => {
|
||||
// if (!selectedRows?.length) {
|
||||
// messageApi.warning('请选择删除项');
|
||||
|
||||
return;
|
||||
}
|
||||
// return;
|
||||
// }
|
||||
|
||||
await delRun({
|
||||
data: {
|
||||
key: selectedRows.map((row) => row.key),
|
||||
},
|
||||
});
|
||||
},
|
||||
[delRun, messageApi.warning],
|
||||
);
|
||||
// await delRun({
|
||||
// data: {
|
||||
// key: selectedRows.map((row) => row.key),
|
||||
// },
|
||||
// });
|
||||
// },
|
||||
// [delRun, messageApi.warning],
|
||||
// );
|
||||
|
||||
return (
|
||||
<PageContainer>
|
||||
{contextHolder}
|
||||
<ProTable<API.RuleListItem, API.PageParams>
|
||||
headerTitle={intl.formatMessage({
|
||||
id: 'pages.searchTable.title',
|
||||
defaultMessage: 'Enquiry form',
|
||||
})}
|
||||
actionRef={actionRef}
|
||||
rowKey="key"
|
||||
search={{
|
||||
labelWidth: 120,
|
||||
}}
|
||||
toolBarRender={() => [
|
||||
<CreateForm key="create" reload={actionRef.current?.reload} />,
|
||||
]}
|
||||
request={rule}
|
||||
columns={columns}
|
||||
rowSelection={{
|
||||
onChange: (_, selectedRows) => {
|
||||
setSelectedRows(selectedRows);
|
||||
},
|
||||
}}
|
||||
/>
|
||||
{selectedRowsState?.length > 0 && (
|
||||
<FooterToolbar
|
||||
extra={
|
||||
<div>
|
||||
<FormattedMessage
|
||||
id="pages.searchTable.chosen"
|
||||
defaultMessage="Chosen"
|
||||
/>{' '}
|
||||
<a style={{ fontWeight: 600 }}>{selectedRowsState.length}</a>{' '}
|
||||
<FormattedMessage
|
||||
id="pages.searchTable.item"
|
||||
defaultMessage="项"
|
||||
/>
|
||||
|
||||
<span>
|
||||
<FormattedMessage
|
||||
id="pages.searchTable.totalServiceCalls"
|
||||
defaultMessage="Total number of service calls"
|
||||
/>{' '}
|
||||
{selectedRowsState.reduce(
|
||||
(pre, item) => pre + (item.callNo ?? 0),
|
||||
0,
|
||||
)}{' '}
|
||||
<FormattedMessage
|
||||
id="pages.searchTable.tenThousand"
|
||||
defaultMessage="万"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<Button
|
||||
loading={loading}
|
||||
onClick={() => {
|
||||
handleRemove(selectedRowsState);
|
||||
}}
|
||||
>
|
||||
<FormattedMessage
|
||||
id="pages.searchTable.batchDeletion"
|
||||
defaultMessage="Batch deletion"
|
||||
/>
|
||||
</Button>
|
||||
<Button type="primary">
|
||||
<FormattedMessage
|
||||
id="pages.searchTable.batchApproval"
|
||||
defaultMessage="Batch approval"
|
||||
/>
|
||||
</Button>
|
||||
</FooterToolbar>
|
||||
)}
|
||||
// return (
|
||||
// <PageContainer>
|
||||
// {contextHolder}
|
||||
// <ProTable<API.RuleListItem, API.PageParams>
|
||||
// headerTitle={intl.formatMessage({
|
||||
// id: 'pages.searchTable.title',
|
||||
// defaultMessage: 'Enquiry form',
|
||||
// })}
|
||||
// actionRef={actionRef}
|
||||
// rowKey="key"
|
||||
// search={{
|
||||
// labelWidth: 120,
|
||||
// }}
|
||||
// toolBarRender={() => [
|
||||
// <CreateForm key="create" reload={actionRef.current?.reload} />,
|
||||
// ]}
|
||||
// request={rule}
|
||||
// columns={columns}
|
||||
// rowSelection={{
|
||||
// onChange: (_, selectedRows) => {
|
||||
// setSelectedRows(selectedRows);
|
||||
// },
|
||||
// }}
|
||||
// />
|
||||
// {selectedRowsState?.length > 0 && (
|
||||
// <FooterToolbar
|
||||
// extra={
|
||||
// <div>
|
||||
// <FormattedMessage
|
||||
// id="pages.searchTable.chosen"
|
||||
// defaultMessage="Chosen"
|
||||
// />{' '}
|
||||
// <a style={{ fontWeight: 600 }}>{selectedRowsState.length}</a>{' '}
|
||||
// <FormattedMessage
|
||||
// id="pages.searchTable.item"
|
||||
// defaultMessage="项"
|
||||
// />
|
||||
//
|
||||
// <span>
|
||||
// <FormattedMessage
|
||||
// id="pages.searchTable.totalServiceCalls"
|
||||
// defaultMessage="Total number of service calls"
|
||||
// />{' '}
|
||||
// {selectedRowsState.reduce(
|
||||
// (pre, item) => pre + (item.callNo ?? 0),
|
||||
// 0,
|
||||
// )}{' '}
|
||||
// <FormattedMessage
|
||||
// id="pages.searchTable.tenThousand"
|
||||
// defaultMessage="万"
|
||||
// />
|
||||
// </span>
|
||||
// </div>
|
||||
// }
|
||||
// >
|
||||
// <Button
|
||||
// loading={loading}
|
||||
// onClick={() => {
|
||||
// handleRemove(selectedRowsState);
|
||||
// }}
|
||||
// >
|
||||
// <FormattedMessage
|
||||
// id="pages.searchTable.batchDeletion"
|
||||
// defaultMessage="Batch deletion"
|
||||
// />
|
||||
// </Button>
|
||||
// <Button type="primary">
|
||||
// <FormattedMessage
|
||||
// id="pages.searchTable.batchApproval"
|
||||
// defaultMessage="Batch approval"
|
||||
// />
|
||||
// </Button>
|
||||
// </FooterToolbar>
|
||||
// )}
|
||||
|
||||
<Drawer
|
||||
width={600}
|
||||
open={showDetail}
|
||||
onClose={() => {
|
||||
setCurrentRow(undefined);
|
||||
setShowDetail(false);
|
||||
}}
|
||||
closable={false}
|
||||
>
|
||||
{currentRow?.name && (
|
||||
<ProDescriptions<API.RuleListItem>
|
||||
column={2}
|
||||
title={currentRow?.name}
|
||||
request={async () => ({
|
||||
data: currentRow || {},
|
||||
})}
|
||||
params={{
|
||||
id: currentRow?.name,
|
||||
}}
|
||||
columns={columns as ProDescriptionsItemProps<API.RuleListItem>[]}
|
||||
/>
|
||||
)}
|
||||
</Drawer>
|
||||
</PageContainer>
|
||||
);
|
||||
};
|
||||
// <Drawer
|
||||
// width={600}
|
||||
// open={showDetail}
|
||||
// onClose={() => {
|
||||
// setCurrentRow(undefined);
|
||||
// setShowDetail(false);
|
||||
// }}
|
||||
// closable={false}
|
||||
// >
|
||||
// {currentRow?.name && (
|
||||
// <ProDescriptions<API.RuleListItem>
|
||||
// column={2}
|
||||
// title={currentRow?.name}
|
||||
// request={async () => ({
|
||||
// data: currentRow || {},
|
||||
// })}
|
||||
// params={{
|
||||
// id: currentRow?.name,
|
||||
// }}
|
||||
// columns={columns as ProDescriptionsItemProps<API.RuleListItem>[]}
|
||||
// />
|
||||
// )}
|
||||
// </Drawer>
|
||||
// </PageContainer>
|
||||
// );
|
||||
// };
|
||||
|
||||
export default TableList;
|
||||
// export default TableList;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,397 +1,283 @@
|
||||
import {
|
||||
AlipayCircleOutlined,
|
||||
AlipayOutlined,
|
||||
LockOutlined,
|
||||
MobileOutlined,
|
||||
TaobaoCircleOutlined,
|
||||
TaobaoOutlined,
|
||||
UserOutlined,
|
||||
WeiboCircleOutlined,
|
||||
} from '@ant-design/icons';
|
||||
WeiboOutlined,
|
||||
} from "@ant-design/icons";
|
||||
import {
|
||||
LoginForm,
|
||||
LoginFormPage,
|
||||
ProConfigProvider,
|
||||
ProFormCaptcha,
|
||||
ProFormCheckbox,
|
||||
ProFormText,
|
||||
} from '@ant-design/pro-components';
|
||||
import {
|
||||
FormattedMessage,
|
||||
Helmet,
|
||||
SelectLang,
|
||||
useIntl,
|
||||
useModel,
|
||||
} from '@umijs/max';
|
||||
import { Alert, App, Tabs } from 'antd';
|
||||
import { createStyles } from 'antd-style';
|
||||
import React, { useState } from 'react';
|
||||
import { flushSync } from 'react-dom';
|
||||
import { Footer } from '@/components';
|
||||
import { login } from '@/services/ant-design-pro/api';
|
||||
import { getFakeCaptcha } from '@/services/ant-design-pro/login';
|
||||
import Settings from '../../../../config/defaultSettings';
|
||||
} from "@ant-design/pro-components";
|
||||
import { Button, Divider, Space, Tabs, message, theme } from "antd";
|
||||
import type { CSSProperties } from "react";
|
||||
import { useState } from "react";
|
||||
|
||||
const useStyles = createStyles(({ token }) => {
|
||||
return {
|
||||
action: {
|
||||
marginLeft: '8px',
|
||||
color: 'rgba(0, 0, 0, 0.2)',
|
||||
fontSize: '24px',
|
||||
verticalAlign: 'middle',
|
||||
cursor: 'pointer',
|
||||
transition: 'color 0.3s',
|
||||
'&:hover': {
|
||||
color: token.colorPrimaryActive,
|
||||
},
|
||||
},
|
||||
lang: {
|
||||
width: 42,
|
||||
height: 42,
|
||||
lineHeight: '42px',
|
||||
position: 'fixed',
|
||||
right: 16,
|
||||
borderRadius: token.borderRadius,
|
||||
':hover': {
|
||||
backgroundColor: token.colorBgTextHover,
|
||||
},
|
||||
},
|
||||
container: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
height: '100vh',
|
||||
overflow: 'auto',
|
||||
backgroundImage:
|
||||
"url('https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/V-_oS6r-i7wAAAAAAAAAAAAAFl94AQBr')",
|
||||
backgroundSize: '100% 100%',
|
||||
},
|
||||
};
|
||||
});
|
||||
type LoginType = "phone" | "account";
|
||||
|
||||
const ActionIcons = () => {
|
||||
const { styles } = useStyles();
|
||||
|
||||
return (
|
||||
<>
|
||||
<AlipayCircleOutlined
|
||||
key="AlipayCircleOutlined"
|
||||
className={styles.action}
|
||||
/>
|
||||
<TaobaoCircleOutlined
|
||||
key="TaobaoCircleOutlined"
|
||||
className={styles.action}
|
||||
/>
|
||||
<WeiboCircleOutlined
|
||||
key="WeiboCircleOutlined"
|
||||
className={styles.action}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
const iconStyles: CSSProperties = {
|
||||
color: "rgba(0, 0, 0, 0.2)",
|
||||
fontSize: "18px",
|
||||
verticalAlign: "middle",
|
||||
cursor: "pointer",
|
||||
};
|
||||
|
||||
const Lang = () => {
|
||||
const { styles } = useStyles();
|
||||
|
||||
const Page = () => {
|
||||
const [loginType, setLoginType] = useState<LoginType>("phone");
|
||||
const { token } = theme.useToken();
|
||||
return (
|
||||
<div className={styles.lang} data-lang>
|
||||
{SelectLang && <SelectLang />}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const LoginMessage: React.FC<{
|
||||
content: string;
|
||||
}> = ({ content }) => {
|
||||
return (
|
||||
<Alert
|
||||
<div
|
||||
style={{
|
||||
marginBottom: 24,
|
||||
backgroundColor: "white",
|
||||
height: "100vh",
|
||||
}}
|
||||
message={content}
|
||||
type="error"
|
||||
showIcon
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const Login: React.FC = () => {
|
||||
const [userLoginState, setUserLoginState] = useState<API.LoginResult>({});
|
||||
const [type, setType] = useState<string>('account');
|
||||
const { initialState, setInitialState } = useModel('@@initialState');
|
||||
const { styles } = useStyles();
|
||||
const { message } = App.useApp();
|
||||
const intl = useIntl();
|
||||
|
||||
const fetchUserInfo = async () => {
|
||||
const userInfo = await initialState?.fetchUserInfo?.();
|
||||
if (userInfo) {
|
||||
flushSync(() => {
|
||||
setInitialState((s) => ({
|
||||
...s,
|
||||
currentUser: userInfo,
|
||||
}));
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const handleSubmit = async (values: API.LoginParams) => {
|
||||
try {
|
||||
// 登录
|
||||
const msg = await login({ ...values, type });
|
||||
if (msg.status === 'ok') {
|
||||
const defaultLoginSuccessMessage = intl.formatMessage({
|
||||
id: 'pages.login.success',
|
||||
defaultMessage: '登录成功!',
|
||||
});
|
||||
message.success(defaultLoginSuccessMessage);
|
||||
await fetchUserInfo();
|
||||
const urlParams = new URL(window.location.href).searchParams;
|
||||
window.location.href = urlParams.get('redirect') || '/';
|
||||
return;
|
||||
}
|
||||
console.log(msg);
|
||||
// 如果失败去设置用户错误信息
|
||||
setUserLoginState(msg);
|
||||
} catch (error) {
|
||||
const defaultLoginFailureMessage = intl.formatMessage({
|
||||
id: 'pages.login.failure',
|
||||
defaultMessage: '登录失败,请重试!',
|
||||
});
|
||||
console.log(error);
|
||||
message.error(defaultLoginFailureMessage);
|
||||
}
|
||||
};
|
||||
const { status, type: loginType } = userLoginState;
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<Helmet>
|
||||
<title>
|
||||
{intl.formatMessage({
|
||||
id: 'menu.login',
|
||||
defaultMessage: '登录页',
|
||||
})}
|
||||
{Settings.title && ` - ${Settings.title}`}
|
||||
</title>
|
||||
</Helmet>
|
||||
<Lang />
|
||||
<div
|
||||
style={{
|
||||
flex: '1',
|
||||
padding: '32px 0',
|
||||
>
|
||||
<LoginFormPage
|
||||
backgroundImageUrl="https://mdn.alipayobjects.com/huamei_gcee1x/afts/img/A*y0ZTS6WLwvgAAAAAAAAAAAAADml6AQ/fmt.webp"
|
||||
logo="https://github.githubassets.com/favicons/favicon.png"
|
||||
backgroundVideoUrl="https://gw.alipayobjects.com/v/huamei_gcee1x/afts/video/jXRBRK_VAwoAAAAAAAAAAAAAK4eUAQBr"
|
||||
title="Github"
|
||||
containerStyle={{
|
||||
backgroundColor: "rgba(0, 0, 0,0.65)",
|
||||
backdropFilter: "blur(4px)",
|
||||
}}
|
||||
>
|
||||
<LoginForm
|
||||
contentStyle={{
|
||||
minWidth: 280,
|
||||
maxWidth: '75vw',
|
||||
}}
|
||||
logo={<img alt="logo" src="/logo.svg" />}
|
||||
title="Ant Design"
|
||||
subTitle={intl.formatMessage({
|
||||
id: 'pages.layouts.userLayout.title',
|
||||
})}
|
||||
initialValues={{
|
||||
autoLogin: true,
|
||||
}}
|
||||
actions={[
|
||||
<FormattedMessage
|
||||
key="loginWith"
|
||||
id="pages.login.loginWith"
|
||||
defaultMessage="其他登录方式"
|
||||
/>,
|
||||
<ActionIcons key="icons" />,
|
||||
]}
|
||||
onFinish={async (values) => {
|
||||
await handleSubmit(values as API.LoginParams);
|
||||
}}
|
||||
>
|
||||
<Tabs
|
||||
activeKey={type}
|
||||
onChange={setType}
|
||||
centered
|
||||
items={[
|
||||
{
|
||||
key: 'account',
|
||||
label: intl.formatMessage({
|
||||
id: 'pages.login.accountLogin.tab',
|
||||
defaultMessage: '账户密码登录',
|
||||
}),
|
||||
},
|
||||
{
|
||||
key: 'mobile',
|
||||
label: intl.formatMessage({
|
||||
id: 'pages.login.phoneLogin.tab',
|
||||
defaultMessage: '手机号登录',
|
||||
}),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
{status === 'error' && loginType === 'account' && (
|
||||
<LoginMessage
|
||||
content={intl.formatMessage({
|
||||
id: 'pages.login.accountLogin.errorMessage',
|
||||
defaultMessage: '账户或密码错误(admin/ant.design)',
|
||||
})}
|
||||
/>
|
||||
)}
|
||||
{type === 'account' && (
|
||||
<>
|
||||
<ProFormText
|
||||
name="username"
|
||||
fieldProps={{
|
||||
size: 'large',
|
||||
prefix: <UserOutlined />,
|
||||
}}
|
||||
placeholder={intl.formatMessage({
|
||||
id: 'pages.login.username.placeholder',
|
||||
defaultMessage: '用户名: admin or user',
|
||||
})}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: (
|
||||
<FormattedMessage
|
||||
id="pages.login.username.required"
|
||||
defaultMessage="请输入用户名!"
|
||||
/>
|
||||
),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<ProFormText.Password
|
||||
name="password"
|
||||
fieldProps={{
|
||||
size: 'large',
|
||||
prefix: <LockOutlined />,
|
||||
}}
|
||||
placeholder={intl.formatMessage({
|
||||
id: 'pages.login.password.placeholder',
|
||||
defaultMessage: '密码: ant.design',
|
||||
})}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: (
|
||||
<FormattedMessage
|
||||
id="pages.login.password.required"
|
||||
defaultMessage="请输入密码!"
|
||||
/>
|
||||
),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
{status === 'error' && loginType === 'mobile' && (
|
||||
<LoginMessage content="验证码错误" />
|
||||
)}
|
||||
{type === 'mobile' && (
|
||||
<>
|
||||
<ProFormText
|
||||
fieldProps={{
|
||||
size: 'large',
|
||||
prefix: <MobileOutlined />,
|
||||
}}
|
||||
name="mobile"
|
||||
placeholder={intl.formatMessage({
|
||||
id: 'pages.login.phoneNumber.placeholder',
|
||||
defaultMessage: '手机号',
|
||||
})}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: (
|
||||
<FormattedMessage
|
||||
id="pages.login.phoneNumber.required"
|
||||
defaultMessage="请输入手机号!"
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
pattern: /^1\d{10}$/,
|
||||
message: (
|
||||
<FormattedMessage
|
||||
id="pages.login.phoneNumber.invalid"
|
||||
defaultMessage="手机号格式错误!"
|
||||
/>
|
||||
),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<ProFormCaptcha
|
||||
fieldProps={{
|
||||
size: 'large',
|
||||
prefix: <LockOutlined />,
|
||||
}}
|
||||
captchaProps={{
|
||||
size: 'large',
|
||||
}}
|
||||
placeholder={intl.formatMessage({
|
||||
id: 'pages.login.captcha.placeholder',
|
||||
defaultMessage: '请输入验证码',
|
||||
})}
|
||||
captchaTextRender={(timing, count) => {
|
||||
if (timing) {
|
||||
return `${count} ${intl.formatMessage({
|
||||
id: 'pages.getCaptchaSecondText',
|
||||
defaultMessage: '获取验证码',
|
||||
})}`;
|
||||
}
|
||||
return intl.formatMessage({
|
||||
id: 'pages.login.phoneLogin.getVerificationCode',
|
||||
defaultMessage: '获取验证码',
|
||||
});
|
||||
}}
|
||||
name="captcha"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: (
|
||||
<FormattedMessage
|
||||
id="pages.login.captcha.required"
|
||||
defaultMessage="请输入验证码!"
|
||||
/>
|
||||
),
|
||||
},
|
||||
]}
|
||||
onGetCaptcha={async (phone) => {
|
||||
const result = await getFakeCaptcha({
|
||||
phone,
|
||||
});
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
message.success('获取验证码成功!验证码为:1234');
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<div
|
||||
style={{
|
||||
marginBottom: 24,
|
||||
}}
|
||||
>
|
||||
<ProFormCheckbox noStyle name="autoLogin">
|
||||
<FormattedMessage
|
||||
id="pages.login.rememberMe"
|
||||
defaultMessage="自动登录"
|
||||
/>
|
||||
</ProFormCheckbox>
|
||||
<a
|
||||
subTitle="全球最大的代码托管平台"
|
||||
activityConfig={{
|
||||
style: {
|
||||
boxShadow: "0px 0px 8px rgba(0, 0, 0, 0.2)",
|
||||
color: token.colorTextHeading,
|
||||
borderRadius: 8,
|
||||
backgroundColor: "rgba(255,255,255,0.25)",
|
||||
backdropFilter: "blur(4px)",
|
||||
},
|
||||
title: "活动标题,可配置图片",
|
||||
subTitle: "活动介绍说明文字",
|
||||
action: (
|
||||
<Button
|
||||
size="large"
|
||||
style={{
|
||||
float: 'right',
|
||||
borderRadius: 20,
|
||||
background: token.colorBgElevated,
|
||||
color: token.colorPrimary,
|
||||
width: 120,
|
||||
}}
|
||||
>
|
||||
<FormattedMessage
|
||||
id="pages.login.forgotPassword"
|
||||
defaultMessage="忘记密码"
|
||||
/>
|
||||
</a>
|
||||
去看看
|
||||
</Button>
|
||||
),
|
||||
}}
|
||||
actions={
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
flexDirection: "column",
|
||||
}}
|
||||
>
|
||||
<Divider plain>
|
||||
<span
|
||||
style={{
|
||||
color: token.colorTextPlaceholder,
|
||||
fontWeight: "normal",
|
||||
fontSize: 14,
|
||||
}}
|
||||
>
|
||||
其他登录方式
|
||||
</span>
|
||||
</Divider>
|
||||
<Space align="center" size={24}>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
flexDirection: "column",
|
||||
height: 40,
|
||||
width: 40,
|
||||
border: "1px solid " + token.colorPrimaryBorder,
|
||||
borderRadius: "50%",
|
||||
}}
|
||||
>
|
||||
<AlipayOutlined style={{ ...iconStyles, color: "#1677FF" }} />
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
flexDirection: "column",
|
||||
height: 40,
|
||||
width: 40,
|
||||
border: "1px solid " + token.colorPrimaryBorder,
|
||||
borderRadius: "50%",
|
||||
}}
|
||||
>
|
||||
<TaobaoOutlined style={{ ...iconStyles, color: "#FF6A10" }} />
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
flexDirection: "column",
|
||||
height: 40,
|
||||
width: 40,
|
||||
border: "1px solid " + token.colorPrimaryBorder,
|
||||
borderRadius: "50%",
|
||||
}}
|
||||
>
|
||||
<WeiboOutlined style={{ ...iconStyles, color: "#1890ff" }} />
|
||||
</div>
|
||||
</Space>
|
||||
</div>
|
||||
</LoginForm>
|
||||
</div>
|
||||
<Footer />
|
||||
}
|
||||
>
|
||||
<Tabs
|
||||
centered
|
||||
activeKey={loginType}
|
||||
onChange={(activeKey) => setLoginType(activeKey as LoginType)}
|
||||
>
|
||||
<Tabs.TabPane key={"account"} tab={"账号密码登录"} />
|
||||
<Tabs.TabPane key={"phone"} tab={"手机号登录"} />
|
||||
</Tabs>
|
||||
{loginType === "account" && (
|
||||
<>
|
||||
<ProFormText
|
||||
name="username"
|
||||
fieldProps={{
|
||||
size: "large",
|
||||
prefix: (
|
||||
<UserOutlined
|
||||
style={{
|
||||
color: token.colorText,
|
||||
}}
|
||||
className={"prefixIcon"}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
placeholder={"用户名: admin or user"}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: "请输入用户名!",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<ProFormText.Password
|
||||
name="password"
|
||||
fieldProps={{
|
||||
size: "large",
|
||||
prefix: (
|
||||
<LockOutlined
|
||||
style={{
|
||||
color: token.colorText,
|
||||
}}
|
||||
className={"prefixIcon"}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
placeholder={"密码: ant.design"}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: "请输入密码!",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{loginType === "phone" && (
|
||||
<>
|
||||
<ProFormText
|
||||
fieldProps={{
|
||||
size: "large",
|
||||
prefix: (
|
||||
<MobileOutlined
|
||||
style={{
|
||||
color: token.colorText,
|
||||
}}
|
||||
className={"prefixIcon"}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
name="mobile"
|
||||
placeholder={"手机号"}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: "请输入手机号!",
|
||||
},
|
||||
{
|
||||
pattern: /^1\d{10}$/,
|
||||
message: "手机号格式错误!",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<ProFormCaptcha
|
||||
fieldProps={{
|
||||
size: "large",
|
||||
prefix: (
|
||||
<LockOutlined
|
||||
style={{
|
||||
color: token.colorText,
|
||||
}}
|
||||
className={"prefixIcon"}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
captchaProps={{
|
||||
size: "large",
|
||||
}}
|
||||
placeholder={"请输入验证码"}
|
||||
captchaTextRender={(timing, count) => {
|
||||
if (timing) {
|
||||
return `${count} ${"获取验证码"}`;
|
||||
}
|
||||
return "获取验证码";
|
||||
}}
|
||||
name="captcha"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: "请输入验证码!",
|
||||
},
|
||||
]}
|
||||
onGetCaptcha={async () => {
|
||||
message.success("获取验证码成功!验证码为:1234");
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<div
|
||||
style={{
|
||||
marginBlockEnd: 24,
|
||||
}}
|
||||
>
|
||||
<ProFormCheckbox noStyle name="autoLogin">
|
||||
自动登录
|
||||
</ProFormCheckbox>
|
||||
<a
|
||||
style={{
|
||||
float: "right",
|
||||
}}
|
||||
>
|
||||
忘记密码
|
||||
</a>
|
||||
</div>
|
||||
</LoginFormPage>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Login;
|
||||
export default () => {
|
||||
return (
|
||||
<ProConfigProvider dark>
|
||||
<Page />
|
||||
</ProConfigProvider>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
// @ts-ignore
|
||||
import { startMock } from '@@/requestRecordMock';
|
||||
import { TestBrowser } from '@@/testBrowser';
|
||||
import { fireEvent, render } from '@testing-library/react';
|
||||
import React, { act } from 'react';
|
||||
|
||||
const waitTime = (time: number = 100) => {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve(true);
|
||||
}, time);
|
||||
});
|
||||
};
|
||||
|
||||
let server: {
|
||||
close: () => void;
|
||||
};
|
||||
|
||||
describe('Login Page', () => {
|
||||
beforeAll(async () => {
|
||||
server = await startMock({
|
||||
port: 8000,
|
||||
scene: 'login',
|
||||
});
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
server?.close();
|
||||
});
|
||||
|
||||
it('should show login form', async () => {
|
||||
const historyRef = React.createRef<any>();
|
||||
const rootContainer = render(
|
||||
<TestBrowser
|
||||
historyRef={historyRef}
|
||||
location={{
|
||||
pathname: '/user/login',
|
||||
}}
|
||||
/>,
|
||||
);
|
||||
|
||||
await rootContainer.findAllByText('Ant Design');
|
||||
|
||||
act(() => {
|
||||
historyRef.current?.push('/user/login');
|
||||
});
|
||||
|
||||
expect(
|
||||
rootContainer.baseElement?.querySelector('.ant-pro-form-login-desc')
|
||||
?.textContent,
|
||||
).toBe(
|
||||
'Ant Design is the most influential web design specification in Xihu district',
|
||||
);
|
||||
|
||||
expect(rootContainer.asFragment()).toMatchSnapshot();
|
||||
|
||||
rootContainer.unmount();
|
||||
});
|
||||
|
||||
it('should login success', async () => {
|
||||
const historyRef = React.createRef<any>();
|
||||
const rootContainer = render(
|
||||
<TestBrowser
|
||||
historyRef={historyRef}
|
||||
location={{
|
||||
pathname: '/user/login',
|
||||
}}
|
||||
/>,
|
||||
);
|
||||
|
||||
await rootContainer.findAllByText('Ant Design');
|
||||
|
||||
const userNameInput = await rootContainer.findByPlaceholderText(
|
||||
'Username: admin or user',
|
||||
);
|
||||
|
||||
act(() => {
|
||||
fireEvent.change(userNameInput, { target: { value: 'admin' } });
|
||||
});
|
||||
|
||||
const passwordInput = await rootContainer.findByPlaceholderText(
|
||||
'Password: ant.design',
|
||||
);
|
||||
|
||||
act(() => {
|
||||
fireEvent.change(passwordInput, { target: { value: 'ant.design' } });
|
||||
});
|
||||
|
||||
await (await rootContainer.findByText('Login')).click();
|
||||
|
||||
// 等待接口返回结果
|
||||
await waitTime(5000);
|
||||
|
||||
await rootContainer.findAllByText('Ant Design Pro');
|
||||
|
||||
expect(rootContainer.asFragment()).toMatchSnapshot();
|
||||
|
||||
await waitTime(2000);
|
||||
|
||||
rootContainer.unmount();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user