feat:init

This commit is contained in:
2025-09-09 11:22:17 +08:00
commit d6457f59f7
155 changed files with 36102 additions and 0 deletions

View File

@@ -0,0 +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';
interface CreateFormProps {
reload?: ActionType['reload'];
}
const CreateForm: FC<CreateFormProps> = (props) => {
const { reload } = props;
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!');
},
});
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>
</>
);
};
export default CreateForm;

View File

@@ -0,0 +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';
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>;
};
const UpdateForm: React.FC<UpdateFormProps> = (props) => {
const { onOk, values, trigger } = props;
const intl = useIntl();
const [open, setOpen] = useState(false);
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 onCancel = useCallback(() => {
setOpen(false);
}, []);
const onOpen = useCallback(() => {
setOpen(true);
}, []);
const onFinish = useCallback(
async (values?: any) => {
await run({ data: values });
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>
</>
);
};
export default UpdateForm;

View File

@@ -0,0 +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';
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[]>([]);
/**
* @en-US International configuration
* @zh-CN 国际化配置
* */
const intl = useIntl();
const [messageApi, contextHolder] = message.useMessage();
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');
},
});
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('请选择删除项');
return;
}
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="项"
/>
&nbsp;&nbsp;
<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>
);
};
export default TableList;