开发: 删除不用的文件
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
import Footer from '@/components/Footer';
|
import Footer from '@/components/Footer';
|
||||||
import { LinkOutlined } from '@ant-design/icons';
|
import { LinkOutlined } from '@ant-design/icons';
|
||||||
import type { Settings as LayoutSettings } from '@ant-design/pro-components';
|
import { Settings as LayoutSettings } from '@ant-design/pro-components';
|
||||||
import type { RequestConfig, RunTimeLayoutConfig } from '@umijs/max';
|
import type { RequestConfig, RunTimeLayoutConfig } from '@umijs/max';
|
||||||
import { history, Link } from '@umijs/max';
|
import { history, Link } from '@umijs/max';
|
||||||
import { App } from 'antd';
|
import { App } from 'antd';
|
||||||
@@ -114,7 +114,7 @@ export const layout: RunTimeLayoutConfig = ({ initialState, setInitialState }) =
|
|||||||
childrenRender: (children) => {
|
childrenRender: (children) => {
|
||||||
// if (initialState?.loading) return <PageLoading />;
|
// if (initialState?.loading) return <PageLoading />;
|
||||||
return (
|
return (
|
||||||
<>
|
<div style={{ minHeight: 'calc(100vh - 55px - 60px)' }}>
|
||||||
{children}
|
{children}
|
||||||
{/* <FloatButton
|
{/* <FloatButton
|
||||||
icon={<VerticalAlignTopOutlined />}
|
icon={<VerticalAlignTopOutlined />}
|
||||||
@@ -134,7 +134,7 @@ export const layout: RunTimeLayoutConfig = ({ initialState, setInitialState }) =
|
|||||||
}));
|
}));
|
||||||
}}
|
}}
|
||||||
/> */}
|
/> */}
|
||||||
</>
|
</div>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
...initialState?.settings,
|
...initialState?.settings,
|
||||||
|
@@ -1,20 +1,13 @@
|
|||||||
import { DefaultFooter } from '@ant-design/pro-components';
|
import { DefaultFooter } from '@ant-design/pro-components';
|
||||||
import { useIntl } from '@umijs/max';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
const Footer: React.FC = () => {
|
const Footer: React.FC = () => {
|
||||||
const intl = useIntl();
|
|
||||||
const defaultMessage = intl.formatMessage({
|
|
||||||
id: 'app.copyright.produced',
|
|
||||||
defaultMessage: '2021 - 2028 福州晨丰科技有限公司',
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DefaultFooter
|
<DefaultFooter
|
||||||
style={{
|
style={{
|
||||||
background: 'none',
|
background: 'none',
|
||||||
}}
|
}}
|
||||||
copyright={`${defaultMessage}`}
|
copyright={`2021 - 2028 福州晨丰科技有限公司`}
|
||||||
links={[
|
links={[
|
||||||
{
|
{
|
||||||
key: 'scrm.antd',
|
key: 'scrm.antd',
|
||||||
|
@@ -18,10 +18,6 @@ body,
|
|||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ant-pro-page-container {
|
|
||||||
min-height: calc(100vh - 55px - 60px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.ant-pro-global-footer {
|
.ant-pro-global-footer {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
import { useIntl } from '@umijs/max';
|
|
||||||
import { Button, message, notification } from 'antd';
|
import { Button, message, notification } from 'antd';
|
||||||
import defaultSettings from '../config/defaultSettings';
|
import defaultSettings from '../config/defaultSettings';
|
||||||
|
|
||||||
@@ -23,7 +22,7 @@ const clearCache = () => {
|
|||||||
if (pwa) {
|
if (pwa) {
|
||||||
// Notify user if offline now
|
// Notify user if offline now
|
||||||
window.addEventListener('sw.offline', () => {
|
window.addEventListener('sw.offline', () => {
|
||||||
message.warning(useIntl().formatMessage({ id: 'app.pwa.offline' }));
|
message.warning('当前处于离线状态');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Pop up a prompt on the page asking the user if they want to use the latest version
|
// Pop up a prompt on the page asking the user if they want to use the latest version
|
||||||
@@ -62,12 +61,12 @@ if (pwa) {
|
|||||||
reloadSW();
|
reloadSW();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{useIntl().formatMessage({ id: 'app.pwa.serviceworker.updated.ok' })}
|
刷新
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
notification.open({
|
notification.open({
|
||||||
message: useIntl().formatMessage({ id: 'app.pwa.serviceworker.updated' }),
|
message: '有新内容',
|
||||||
description: useIntl().formatMessage({ id: 'app.pwa.serviceworker.updated.hint' }),
|
description: '请点击“刷新”按钮或者手动刷新页面',
|
||||||
btn,
|
btn,
|
||||||
key,
|
key,
|
||||||
onClose: async () => null,
|
onClose: async () => null,
|
||||||
|
@@ -1,45 +0,0 @@
|
|||||||
import { HeartTwoTone, SmileTwoTone } from '@ant-design/icons';
|
|
||||||
import { PageContainer } from '@ant-design/pro-components';
|
|
||||||
import { useIntl } from '@umijs/max';
|
|
||||||
import { Alert, Card, Typography } from 'antd';
|
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
const Admin: React.FC = () => {
|
|
||||||
const intl = useIntl();
|
|
||||||
return (
|
|
||||||
<PageContainer
|
|
||||||
content={intl.formatMessage({
|
|
||||||
id: 'pages.admin.subPage.title',
|
|
||||||
defaultMessage: 'This page can only be viewed by admin',
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
<Card>
|
|
||||||
<Alert
|
|
||||||
message={intl.formatMessage({
|
|
||||||
id: 'pages.welcome.alertMessage',
|
|
||||||
defaultMessage: 'Faster and stronger heavy-duty components have been released.',
|
|
||||||
})}
|
|
||||||
type="success"
|
|
||||||
showIcon
|
|
||||||
banner
|
|
||||||
style={{
|
|
||||||
margin: -12,
|
|
||||||
marginBottom: 48,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Typography.Title level={2} style={{ textAlign: 'center' }}>
|
|
||||||
<SmileTwoTone /> Ant Design Pro <HeartTwoTone twoToneColor="#eb2f96" /> You
|
|
||||||
</Typography.Title>
|
|
||||||
</Card>
|
|
||||||
<p style={{ textAlign: 'center', marginTop: 24 }}>
|
|
||||||
Want to add more pages? Please refer to{' '}
|
|
||||||
<a href="https://pro.ant.design/docs/block-cn" target="_blank" rel="noopener noreferrer">
|
|
||||||
use block
|
|
||||||
</a>
|
|
||||||
。
|
|
||||||
</p>
|
|
||||||
</PageContainer>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Admin;
|
|
@@ -70,6 +70,7 @@ export interface IGroup {
|
|||||||
|
|
||||||
export interface IGroupMembers {
|
export interface IGroupMembers {
|
||||||
avatar: string;
|
avatar: string;
|
||||||
|
staff_avatar?: string;
|
||||||
|
|
||||||
cust_id: string;
|
cust_id: string;
|
||||||
gender: number;
|
gender: number;
|
||||||
|
@@ -186,11 +186,12 @@ const ChatLogs: React.FC = () => {
|
|||||||
}).then((res) => {
|
}).then((res) => {
|
||||||
if (res.err_code == 0) {
|
if (res.err_code == 0) {
|
||||||
if (Array.isArray(res.data)) {
|
if (Array.isArray(res.data)) {
|
||||||
setGroupMembersList(res.data);
|
|
||||||
groupMembersObjRef.current = {};
|
groupMembersObjRef.current = {};
|
||||||
res.data.forEach((item: IGroupMembers) => {
|
res.data.forEach((item: IGroupMembers) => {
|
||||||
|
item.avatar = item.staff_avatar || item.avatar;
|
||||||
groupMembersObjRef.current[item.user_id] = item;
|
groupMembersObjRef.current[item.user_id] = item;
|
||||||
});
|
});
|
||||||
|
setGroupMembersList(res.data);
|
||||||
page(1);
|
page(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,209 +0,0 @@
|
|||||||
import {
|
|
||||||
ProFormDateTimePicker,
|
|
||||||
ProFormRadio,
|
|
||||||
ProFormSelect,
|
|
||||||
ProFormText,
|
|
||||||
ProFormTextArea,
|
|
||||||
StepsForm,
|
|
||||||
} from '@ant-design/pro-components';
|
|
||||||
import { FormattedMessage, useIntl } from '@umijs/max';
|
|
||||||
import { Modal } from 'antd';
|
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
export type FormValueType = {
|
|
||||||
target?: string;
|
|
||||||
template?: string;
|
|
||||||
type?: string;
|
|
||||||
time?: string;
|
|
||||||
frequency?: string;
|
|
||||||
} & Partial<API.RuleListItem>;
|
|
||||||
|
|
||||||
export type UpdateFormProps = {
|
|
||||||
onCancel: (flag?: boolean, formVals?: FormValueType) => void;
|
|
||||||
onSubmit: (values: FormValueType) => Promise<void>;
|
|
||||||
updateModalOpen: boolean;
|
|
||||||
values: Partial<API.RuleListItem>;
|
|
||||||
};
|
|
||||||
|
|
||||||
const UpdateForm: React.FC<UpdateFormProps> = (props) => {
|
|
||||||
const intl = useIntl();
|
|
||||||
return (
|
|
||||||
<StepsForm
|
|
||||||
stepsProps={{
|
|
||||||
size: 'small',
|
|
||||||
}}
|
|
||||||
stepsFormRender={(dom, submitter) => {
|
|
||||||
return (
|
|
||||||
<Modal
|
|
||||||
width={640}
|
|
||||||
bodyStyle={{ padding: '32px 40px 48px' }}
|
|
||||||
destroyOnClose
|
|
||||||
title={intl.formatMessage({
|
|
||||||
id: 'pages.searchTable.updateForm.ruleConfig',
|
|
||||||
defaultMessage: '规则配置',
|
|
||||||
})}
|
|
||||||
open={props.updateModalOpen}
|
|
||||||
footer={submitter}
|
|
||||||
onCancel={() => {
|
|
||||||
props.onCancel();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{dom}
|
|
||||||
</Modal>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
onFinish={props.onSubmit}
|
|
||||||
>
|
|
||||||
<StepsForm.StepForm
|
|
||||||
initialValues={{
|
|
||||||
name: props.values.name,
|
|
||||||
desc: props.values.desc,
|
|
||||||
}}
|
|
||||||
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;
|
|
@@ -1,422 +0,0 @@
|
|||||||
import { addRule, removeRule, rule, updateRule } from '@/services/ant-design-pro/api';
|
|
||||||
import { PlusOutlined } from '@ant-design/icons';
|
|
||||||
import type { ActionType, ProColumns, ProDescriptionsItemProps } from '@ant-design/pro-components';
|
|
||||||
import {
|
|
||||||
FooterToolbar,
|
|
||||||
ModalForm,
|
|
||||||
PageContainer,
|
|
||||||
ProDescriptions,
|
|
||||||
ProFormText,
|
|
||||||
ProFormTextArea,
|
|
||||||
ProTable,
|
|
||||||
} from '@ant-design/pro-components';
|
|
||||||
import { FormattedMessage, useIntl, useModel } from '@umijs/max';
|
|
||||||
import { Button, Drawer, Input, message } from 'antd';
|
|
||||||
import React, { useRef, useState } from 'react';
|
|
||||||
import type { FormValueType } from './components/UpdateForm';
|
|
||||||
import UpdateForm from './components/UpdateForm';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @en-US Add node
|
|
||||||
* @zh-CN 添加节点
|
|
||||||
* @param fields
|
|
||||||
*/
|
|
||||||
const handleAdd = async (fields: API.RuleListItem) => {
|
|
||||||
const hide = message.loading('正在添加');
|
|
||||||
try {
|
|
||||||
await addRule({ ...fields });
|
|
||||||
hide();
|
|
||||||
message.success('Added successfully');
|
|
||||||
return true;
|
|
||||||
} catch (error) {
|
|
||||||
hide();
|
|
||||||
message.error('Adding failed, please try again!');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @en-US Update node
|
|
||||||
* @zh-CN 更新节点
|
|
||||||
*
|
|
||||||
* @param fields
|
|
||||||
*/
|
|
||||||
const handleUpdate = async (fields: FormValueType) => {
|
|
||||||
const hide = message.loading('Configuring');
|
|
||||||
try {
|
|
||||||
await updateRule({
|
|
||||||
name: fields.name,
|
|
||||||
desc: fields.desc,
|
|
||||||
key: fields.key,
|
|
||||||
});
|
|
||||||
hide();
|
|
||||||
|
|
||||||
message.success('Configuration is successful');
|
|
||||||
return true;
|
|
||||||
} catch (error) {
|
|
||||||
hide();
|
|
||||||
message.error('Configuration failed, please try again!');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete node
|
|
||||||
* @zh-CN 删除节点
|
|
||||||
*
|
|
||||||
* @param selectedRows
|
|
||||||
*/
|
|
||||||
const handleRemove = async (selectedRows: API.RuleListItem[]) => {
|
|
||||||
const hide = message.loading('正在删除');
|
|
||||||
if (!selectedRows) return true;
|
|
||||||
try {
|
|
||||||
await removeRule({
|
|
||||||
key: selectedRows.map((row) => row.key),
|
|
||||||
});
|
|
||||||
hide();
|
|
||||||
message.success('Deleted successfully and will refresh soon');
|
|
||||||
return true;
|
|
||||||
} catch (error) {
|
|
||||||
hide();
|
|
||||||
message.error('Delete failed, please try again');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const TableList: React.FC = () => {
|
|
||||||
/**
|
|
||||||
* @en-US Pop-up window of new window
|
|
||||||
* @zh-CN 新建窗口的弹窗
|
|
||||||
* */
|
|
||||||
const [createModalOpen, handleModalOpen] = useState<boolean>(false);
|
|
||||||
/**
|
|
||||||
* @en-US The pop-up window of the distribution update window
|
|
||||||
* @zh-CN 分布更新窗口的弹窗
|
|
||||||
* */
|
|
||||||
const [updateModalOpen, handleUpdateModalOpen] = useState<boolean>(false);
|
|
||||||
|
|
||||||
const [showDetail, setShowDetail] = useState<boolean>(false);
|
|
||||||
|
|
||||||
const actionRef = useRef<ActionType>();
|
|
||||||
const [currentRow, setCurrentRow] = useState<API.RuleListItem>();
|
|
||||||
const [selectedRowsState, setSelectedRows] = useState<API.RuleListItem[]>([]);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @en-US International configuration
|
|
||||||
* @zh-CN 国际化配置
|
|
||||||
* */
|
|
||||||
const intl = useIntl();
|
|
||||||
|
|
||||||
const columns: ProColumns<API.RuleListItem>[] = [
|
|
||||||
{
|
|
||||||
title: (
|
|
||||||
<FormattedMessage
|
|
||||||
id="pages.searchTable.updateForm.ruleName.nameLabel"
|
|
||||||
defaultMessage="Rule name"
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
dataIndex: 'name',
|
|
||||||
tip: 'The rule name is the unique key',
|
|
||||||
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) => [
|
|
||||||
<a
|
|
||||||
key="config"
|
|
||||||
onClick={() => {
|
|
||||||
handleUpdateModalOpen(true);
|
|
||||||
setCurrentRow(record);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<FormattedMessage id="pages.searchTable.config" defaultMessage="Configuration" />
|
|
||||||
</a>,
|
|
||||||
<a key="subscribeAlert" href="https://procomponents.ant.design/">
|
|
||||||
<FormattedMessage
|
|
||||||
id="pages.searchTable.subscribeAlert"
|
|
||||||
defaultMessage="Subscribe to alerts"
|
|
||||||
/>
|
|
||||||
</a>,
|
|
||||||
],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const { add, minus, counter } = useModel('demo', (ret) => ({
|
|
||||||
add: ret.increment,
|
|
||||||
minus: ret.decrement,
|
|
||||||
counter: ret.counter,
|
|
||||||
}));
|
|
||||||
|
|
||||||
return (
|
|
||||||
<PageContainer>
|
|
||||||
<div style={{ marginBottom: 12 }}>
|
|
||||||
<Button
|
|
||||||
onClick={() => {
|
|
||||||
add();
|
|
||||||
}}
|
|
||||||
style={{ marginRight: 12 }}
|
|
||||||
>
|
|
||||||
加+1
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
onClick={() => {
|
|
||||||
minus();
|
|
||||||
}}
|
|
||||||
style={{ marginRight: 12 }}
|
|
||||||
>
|
|
||||||
减-1
|
|
||||||
</Button>
|
|
||||||
<span>{counter}</span>
|
|
||||||
</div>
|
|
||||||
<ProTable<API.RuleListItem, API.PageParams>
|
|
||||||
headerTitle={intl.formatMessage({
|
|
||||||
id: 'pages.searchTable.title',
|
|
||||||
defaultMessage: 'Enquiry form',
|
|
||||||
})}
|
|
||||||
actionRef={actionRef}
|
|
||||||
rowKey="key"
|
|
||||||
search={{
|
|
||||||
labelWidth: 120,
|
|
||||||
}}
|
|
||||||
toolBarRender={() => [
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
key="primary"
|
|
||||||
onClick={() => {
|
|
||||||
handleModalOpen(true);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<PlusOutlined /> <FormattedMessage id="pages.searchTable.new" defaultMessage="New" />
|
|
||||||
</Button>,
|
|
||||||
]}
|
|
||||||
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)}{' '}
|
|
||||||
<FormattedMessage id="pages.searchTable.tenThousand" defaultMessage="万" />
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Button
|
|
||||||
onClick={async () => {
|
|
||||||
await handleRemove(selectedRowsState);
|
|
||||||
setSelectedRows([]);
|
|
||||||
actionRef.current?.reloadAndRest?.();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<FormattedMessage
|
|
||||||
id="pages.searchTable.batchDeletion"
|
|
||||||
defaultMessage="Batch deletion"
|
|
||||||
/>
|
|
||||||
</Button>
|
|
||||||
<Button type="primary">
|
|
||||||
<FormattedMessage
|
|
||||||
id="pages.searchTable.batchApproval"
|
|
||||||
defaultMessage="Batch approval"
|
|
||||||
/>
|
|
||||||
</Button>
|
|
||||||
</FooterToolbar>
|
|
||||||
)}
|
|
||||||
<ModalForm
|
|
||||||
title={intl.formatMessage({
|
|
||||||
id: 'pages.searchTable.createForm.newRule',
|
|
||||||
defaultMessage: 'New rule',
|
|
||||||
})}
|
|
||||||
width="400px"
|
|
||||||
open={createModalOpen}
|
|
||||||
onOpenChange={handleModalOpen}
|
|
||||||
onFinish={async (value) => {
|
|
||||||
const success = await handleAdd(value as API.RuleListItem);
|
|
||||||
if (success) {
|
|
||||||
handleModalOpen(false);
|
|
||||||
if (actionRef.current) {
|
|
||||||
actionRef.current.reload();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<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>
|
|
||||||
<UpdateForm
|
|
||||||
onSubmit={async (value) => {
|
|
||||||
const success = await handleUpdate(value);
|
|
||||||
if (success) {
|
|
||||||
handleUpdateModalOpen(false);
|
|
||||||
setCurrentRow(undefined);
|
|
||||||
if (actionRef.current) {
|
|
||||||
actionRef.current.reload();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
onCancel={() => {
|
|
||||||
handleUpdateModalOpen(false);
|
|
||||||
if (!showDetail) {
|
|
||||||
setCurrentRow(undefined);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
updateModalOpen={updateModalOpen}
|
|
||||||
values={currentRow || {}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<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;
|
|
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,5 @@
|
|||||||
import Footer from '@/components/Footer';
|
import Footer from '@/components/Footer';
|
||||||
import { IAjaxReturn, post } from '@/services/ajax';
|
import { IAjaxReturn, post } from '@/services/ajax';
|
||||||
import { getFakeCaptcha } from '@/services/ant-design-pro/login';
|
|
||||||
import {
|
import {
|
||||||
AlipayCircleOutlined,
|
AlipayCircleOutlined,
|
||||||
LockOutlined,
|
LockOutlined,
|
||||||
@@ -16,8 +15,8 @@ import {
|
|||||||
ProFormText,
|
ProFormText,
|
||||||
} from '@ant-design/pro-components';
|
} from '@ant-design/pro-components';
|
||||||
import { useEmotionCss } from '@ant-design/use-emotion-css';
|
import { useEmotionCss } from '@ant-design/use-emotion-css';
|
||||||
import { FormattedMessage, Helmet, history, SelectLang, useIntl, useModel } from '@umijs/max';
|
import { FormattedMessage, Helmet, history, SelectLang, useModel } from '@umijs/max';
|
||||||
import { Alert, App, message, Tabs } from 'antd';
|
import { Alert, App, Tabs } from 'antd';
|
||||||
import { stringify as qsStringify } from 'qs';
|
import { stringify as qsStringify } from 'qs';
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { flushSync } from 'react-dom';
|
import { flushSync } from 'react-dom';
|
||||||
@@ -101,8 +100,6 @@ const Login: React.FC = () => {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
const intl = useIntl();
|
|
||||||
|
|
||||||
const fetchUserInfo = async () => {
|
const fetchUserInfo = async () => {
|
||||||
const userInfo = await initialState?.fetchUserInfo?.();
|
const userInfo = await initialState?.fetchUserInfo?.();
|
||||||
if (userInfo) {
|
if (userInfo) {
|
||||||
@@ -148,13 +145,7 @@ const Login: React.FC = () => {
|
|||||||
return (
|
return (
|
||||||
<div className={containerClassName}>
|
<div className={containerClassName}>
|
||||||
<Helmet>
|
<Helmet>
|
||||||
<title>
|
<title>登录页 - {Settings.title}</title>
|
||||||
{intl.formatMessage({
|
|
||||||
id: 'menu.login',
|
|
||||||
defaultMessage: '登录页',
|
|
||||||
})}
|
|
||||||
- {Settings.title}
|
|
||||||
</title>
|
|
||||||
</Helmet>
|
</Helmet>
|
||||||
{/* <Lang /> */}
|
{/* <Lang /> */}
|
||||||
<div
|
<div
|
||||||
@@ -211,28 +202,17 @@ const Login: React.FC = () => {
|
|||||||
items={[
|
items={[
|
||||||
{
|
{
|
||||||
key: 'account',
|
key: 'account',
|
||||||
label: intl.formatMessage({
|
label: '账户密码登录',
|
||||||
id: 'pages.login.accountLogin.tab',
|
|
||||||
defaultMessage: '账户密码登录',
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
// {
|
// {
|
||||||
// key: 'mobile',
|
// key: 'mobile',
|
||||||
// label: intl.formatMessage({
|
// label: '手机号登录',
|
||||||
// id: 'pages.login.phoneLogin.tab',
|
|
||||||
// defaultMessage: '手机号登录',
|
|
||||||
// }),
|
|
||||||
// },
|
// },
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{status === 'error' && loginType === 'account' && (
|
{status === 'error' && loginType === 'account' && (
|
||||||
<LoginMessage
|
<LoginMessage content={'账户或密码错误(admin/ant.design)'} />
|
||||||
content={intl.formatMessage({
|
|
||||||
id: 'pages.login.accountLogin.errorMessage',
|
|
||||||
defaultMessage: '账户或密码错误(admin/ant.design)',
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
{type === 'account' && (
|
{type === 'account' && (
|
||||||
<>
|
<>
|
||||||
@@ -242,10 +222,7 @@ const Login: React.FC = () => {
|
|||||||
size: 'large',
|
size: 'large',
|
||||||
prefix: <UserOutlined />,
|
prefix: <UserOutlined />,
|
||||||
}}
|
}}
|
||||||
placeholder={intl.formatMessage({
|
placeholder={'用户名'}
|
||||||
id: 'pages.login.username.placeholder',
|
|
||||||
defaultMessage: '用户名: admin or user',
|
|
||||||
})}
|
|
||||||
rules={[
|
rules={[
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
@@ -264,10 +241,7 @@ const Login: React.FC = () => {
|
|||||||
size: 'large',
|
size: 'large',
|
||||||
prefix: <LockOutlined />,
|
prefix: <LockOutlined />,
|
||||||
}}
|
}}
|
||||||
placeholder={intl.formatMessage({
|
placeholder={'请输入密码'}
|
||||||
id: 'pages.login.password.placeholder',
|
|
||||||
defaultMessage: '请输入密码',
|
|
||||||
})}
|
|
||||||
rules={[
|
rules={[
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
@@ -292,10 +266,7 @@ const Login: React.FC = () => {
|
|||||||
prefix: <MobileOutlined />,
|
prefix: <MobileOutlined />,
|
||||||
}}
|
}}
|
||||||
name="mobile"
|
name="mobile"
|
||||||
placeholder={intl.formatMessage({
|
placeholder={'手机号'}
|
||||||
id: 'pages.login.phoneNumber.placeholder',
|
|
||||||
defaultMessage: '手机号',
|
|
||||||
})}
|
|
||||||
rules={[
|
rules={[
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
@@ -325,21 +296,12 @@ const Login: React.FC = () => {
|
|||||||
captchaProps={{
|
captchaProps={{
|
||||||
size: 'large',
|
size: 'large',
|
||||||
}}
|
}}
|
||||||
placeholder={intl.formatMessage({
|
placeholder={'请输入验证码'}
|
||||||
id: 'pages.login.captcha.placeholder',
|
|
||||||
defaultMessage: '请输入验证码',
|
|
||||||
})}
|
|
||||||
captchaTextRender={(timing, count) => {
|
captchaTextRender={(timing, count) => {
|
||||||
if (timing) {
|
if (timing) {
|
||||||
return `${count} ${intl.formatMessage({
|
return `${count} 获取验证码`;
|
||||||
id: 'pages.getCaptchaSecondText',
|
|
||||||
defaultMessage: '获取验证码',
|
|
||||||
})}`;
|
|
||||||
}
|
}
|
||||||
return intl.formatMessage({
|
return '获取验证码';
|
||||||
id: 'pages.login.phoneLogin.getVerificationCode',
|
|
||||||
defaultMessage: '获取验证码',
|
|
||||||
});
|
|
||||||
}}
|
}}
|
||||||
name="captcha"
|
name="captcha"
|
||||||
rules={[
|
rules={[
|
||||||
@@ -354,13 +316,13 @@ const Login: React.FC = () => {
|
|||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
onGetCaptcha={async (phone) => {
|
onGetCaptcha={async (phone) => {
|
||||||
const result = await getFakeCaptcha({
|
// const result = await getFakeCaptcha({
|
||||||
phone,
|
// phone,
|
||||||
});
|
// });
|
||||||
if (!result) {
|
// if (!result) {
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
message.success('获取验证码成功!验证码为:1234');
|
// message.success('获取验证码成功!验证码为:1234');
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
|
@@ -1,96 +0,0 @@
|
|||||||
import { render, fireEvent, act } from '@testing-library/react';
|
|
||||||
import React from 'react';
|
|
||||||
import { TestBrowser } from '@@/testBrowser';
|
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
import { startMock } from '@@/requestRecordMock';
|
|
||||||
|
|
||||||
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();
|
|
||||||
});
|
|
||||||
});
|
|
@@ -1,168 +0,0 @@
|
|||||||
import { PageContainer } from '@ant-design/pro-components';
|
|
||||||
import { useModel } from '@umijs/max';
|
|
||||||
import { Card, theme } from 'antd';
|
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 每个单独的卡片,为了复用样式抽成了组件
|
|
||||||
* @param param0
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
const InfoCard: React.FC<{
|
|
||||||
title: string;
|
|
||||||
index: number;
|
|
||||||
desc: string;
|
|
||||||
href: string;
|
|
||||||
}> = ({ title, href, index, desc }) => {
|
|
||||||
const { useToken } = theme;
|
|
||||||
|
|
||||||
const { token } = useToken();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
backgroundColor: token.colorBgContainer,
|
|
||||||
boxShadow: token.boxShadow,
|
|
||||||
borderRadius: '8px',
|
|
||||||
fontSize: '14px',
|
|
||||||
color: token.colorTextSecondary,
|
|
||||||
lineHeight: '22px',
|
|
||||||
padding: '16px 19px',
|
|
||||||
minWidth: '220px',
|
|
||||||
flex: 1,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: 'flex',
|
|
||||||
gap: '4px',
|
|
||||||
alignItems: 'center',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
width: 48,
|
|
||||||
height: 48,
|
|
||||||
lineHeight: '22px',
|
|
||||||
backgroundSize: '100%',
|
|
||||||
textAlign: 'center',
|
|
||||||
padding: '8px 16px 16px 12px',
|
|
||||||
color: '#FFF',
|
|
||||||
fontWeight: 'bold',
|
|
||||||
backgroundImage:
|
|
||||||
"url('https://gw.alipayobjects.com/zos/bmw-prod/daaf8d50-8e6d-4251-905d-676a24ddfa12.svg')",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{index}
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
fontSize: '16px',
|
|
||||||
color: token.colorText,
|
|
||||||
paddingBottom: 8,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{title}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
fontSize: '14px',
|
|
||||||
color: token.colorTextSecondary,
|
|
||||||
textAlign: 'justify',
|
|
||||||
lineHeight: '22px',
|
|
||||||
marginBottom: 8,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{desc}
|
|
||||||
</div>
|
|
||||||
<a href={href} target="_blank" rel="noreferrer">
|
|
||||||
了解更多 {'>'}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const Welcome: React.FC = () => {
|
|
||||||
const { token } = theme.useToken();
|
|
||||||
const { initialState } = useModel('@@initialState');
|
|
||||||
|
|
||||||
const count = useModel('demo');
|
|
||||||
|
|
||||||
return (
|
|
||||||
<PageContainer>
|
|
||||||
<span>{count.counter}</span>
|
|
||||||
<Card
|
|
||||||
style={{
|
|
||||||
borderRadius: 8,
|
|
||||||
}}
|
|
||||||
bodyStyle={{
|
|
||||||
backgroundImage:
|
|
||||||
initialState?.settings?.navTheme === 'realDark'
|
|
||||||
? 'background-image: linear-gradient(75deg, #1A1B1F 0%, #191C1F 100%)'
|
|
||||||
: 'background-image: linear-gradient(75deg, #FBFDFF 0%, #F5F7FF 100%)',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
backgroundPosition: '100% -30%',
|
|
||||||
backgroundRepeat: 'no-repeat',
|
|
||||||
backgroundSize: '274px auto',
|
|
||||||
backgroundImage:
|
|
||||||
"url('https://gw.alipayobjects.com/mdn/rms_a9745b/afts/img/A*BuFmQqsB2iAAAAAAAAAAAAAAARQnAQ')",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
fontSize: '20px',
|
|
||||||
color: token.colorTextHeading,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
欢迎使用 Ant Design Pro
|
|
||||||
</div>
|
|
||||||
<p
|
|
||||||
style={{
|
|
||||||
fontSize: '14px',
|
|
||||||
color: token.colorTextSecondary,
|
|
||||||
lineHeight: '22px',
|
|
||||||
marginTop: 16,
|
|
||||||
marginBottom: 32,
|
|
||||||
width: '65%',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Ant Design Pro 是一个整合了 umi,Ant Design 和 ProComponents
|
|
||||||
的脚手架方案。致力于在设计规范和基础组件的基础上,继续向上构建,提炼出典型模板/业务组件/配套设计资源,进一步提升企业级中后台产品设计研发过程中的『用户』和『设计者』的体验。
|
|
||||||
</p>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: 'flex',
|
|
||||||
flexWrap: 'wrap',
|
|
||||||
gap: 16,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<InfoCard
|
|
||||||
index={1}
|
|
||||||
href="https://umijs.org/docs/introduce/introduce"
|
|
||||||
title="了解 umi"
|
|
||||||
desc="umi 是一个可扩展的企业级前端应用框架,umi 以路由为基础的,同时支持配置式路由和约定式路由,保证路由的功能完备,并以此进行功能扩展。"
|
|
||||||
/>
|
|
||||||
<InfoCard
|
|
||||||
index={2}
|
|
||||||
title="了解 ant design"
|
|
||||||
href="https://ant.design"
|
|
||||||
desc="antd 是基于 Ant Design 设计体系的 React UI 组件库,主要用于研发企业级中后台产品。"
|
|
||||||
/>
|
|
||||||
<InfoCard
|
|
||||||
index={3}
|
|
||||||
title="了解 Pro Components"
|
|
||||||
href="https://procomponents.ant.design"
|
|
||||||
desc="ProComponents 是一个基于 Ant Design 做了更高抽象的模板组件,以 一个组件就是一个页面为开发理念,为中后台开发带来更好的体验。"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Card>
|
|
||||||
</PageContainer>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Welcome;
|
|
@@ -10,8 +10,12 @@
|
|||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
border-right: 1px solid #ddd;
|
|
||||||
padding-left: 24px;
|
padding-left: 24px;
|
||||||
|
border-right: 1px solid #ddd;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.dataIconBox {
|
.dataIconBox {
|
||||||
@@ -41,8 +45,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.dataCard {
|
.dataCard {
|
||||||
|
flex: 1;
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
border: 1px solid #ddd;
|
border: 1px solid #ddd;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
flex: 1;
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user