Browse Source

refactor: remove unused pages

pull/11531/head
afc163 8 months ago
parent
commit
cb64940608
  1. 130
      src/pages/account/center/components/Applications/index.tsx
  2. 278
      src/pages/account/center/index.tsx
  3. 110
      src/pages/dashboard/analysis/components/Charts/ChartCard/index.tsx
  4. 48
      src/pages/dashboard/analysis/components/Charts/MiniProgress/index.tsx
  5. 168
      src/pages/dashboard/analysis/components/IntroduceRow.tsx
  6. 110
      src/pages/dashboard/analysis/components/OfflineData.tsx
  7. 181
      src/pages/dashboard/analysis/components/TopSearch.tsx
  8. 203
      src/pages/dashboard/monitor/index.tsx
  9. 549
      src/pages/form/advanced-form/index.tsx
  10. 194
      src/pages/form/basic-form/index.tsx
  11. 248
      src/pages/form/step-form/index.tsx
  12. 129
      src/pages/list/basic-list/components/OperationModal.tsx
  13. 280
      src/pages/list/basic-list/index.tsx
  14. 239
      src/pages/list/search/applications/index.tsx
  15. 261
      src/pages/list/search/articles/index.tsx
  16. 176
      src/pages/list/search/projects/index.tsx
  17. 26
      src/pages/list/table-list/components/CreateForm.tsx
  18. 161
      src/pages/list/table-list/components/UpdateForm.tsx
  19. 493
      src/pages/profile/advanced/index.tsx
  20. 236
      src/pages/profile/basic/index.tsx
  21. 75
      src/pages/result/fail/index.tsx
  22. 137
      src/pages/result/success/index.tsx
  23. 309
      src/pages/user/register/index.tsx

130
src/pages/account/center/components/Applications/index.tsx

@ -1,130 +0,0 @@
import {
DownloadOutlined,
EditOutlined,
EllipsisOutlined,
ShareAltOutlined,
} from '@ant-design/icons';
import { useRequest } from '@umijs/max';
import { Avatar, Card, Dropdown, List, Tooltip } from 'antd';
import numeral from 'numeral';
import React from 'react';
import type { ListItemDataType } from '../../data.d';
import { queryFakeList } from '../../service';
import useStyles from './index.style';
export function formatWan(val: number) {
const v = val * 1;
if (!v || Number.isNaN(v)) return '';
let result: React.ReactNode = val;
if (val > 10000) {
result = (
<span>
{Math.floor(val / 10000)}
<span
style={{
position: 'relative',
top: -2,
fontSize: 14,
fontStyle: 'normal',
marginLeft: 2,
}}
>
</span>
</span>
);
}
return result;
}
const Applications: React.FC = () => {
const { styles: stylesApplications } = useStyles();
// 获取tab列表数据
const { data: listData } = useRequest(() => {
return queryFakeList({
count: 30,
});
});
const CardInfo: React.FC<{
activeUser: React.ReactNode;
newUser: React.ReactNode;
}> = ({ activeUser, newUser }) => (
<div className={stylesApplications.cardInfo}>
<div>
<p></p>
<p>{activeUser}</p>
</div>
<div>
<p></p>
<p>{newUser}</p>
</div>
</div>
);
return (
<List<ListItemDataType>
rowKey="id"
className={stylesApplications.filterCardList}
grid={{
gutter: 24,
xxl: 3,
xl: 2,
lg: 2,
md: 2,
sm: 2,
xs: 1,
}}
dataSource={listData?.list || []}
renderItem={(item) => (
<List.Item key={item.id}>
<Card
hoverable
styles={{
body: {
paddingBottom: 20,
},
}}
actions={[
<Tooltip key="download" title="下载">
<DownloadOutlined />
</Tooltip>,
<Tooltip title="编辑" key="edit">
<EditOutlined />
</Tooltip>,
<Tooltip title="分享" key="share">
<ShareAltOutlined />
</Tooltip>,
<Dropdown
menu={{
items: [
{
key: '1',
title: '1st menu item',
},
{
key: '2',
title: '2nd menu item',
},
],
}}
key="ellipsis"
>
<EllipsisOutlined />
</Dropdown>,
]}
>
<Card.Meta
avatar={<Avatar size="small" src={item.avatar} />}
title={item.title}
/>
<div>
<CardInfo
activeUser={formatWan(item.activeUser)}
newUser={numeral(item.newUser).format('0,0')}
/>
</div>
</Card>
</List.Item>
)}
/>
);
};
export default Applications;

278
src/pages/account/center/index.tsx

@ -1,278 +0,0 @@
import {
ClusterOutlined,
ContactsOutlined,
HomeOutlined,
PlusOutlined,
} from '@ant-design/icons';
import { GridContent } from '@ant-design/pro-components';
import { useRequest } from '@umijs/max';
import {
Avatar,
Card,
Col,
Divider,
Input,
type InputRef,
Row,
Tag,
} from 'antd';
import React, { useRef, useState } from 'react';
import useStyles from './Center.style';
import Applications from './components/Applications';
import Articles from './components/Articles';
import Projects from './components/Projects';
import type { CurrentUser, TagType, tabKeyType } from './data.d';
import { queryCurrent } from './service';
const operationTabList = [
{
key: 'articles',
tab: (
<span>
{' '}
<span
style={{
fontSize: 14,
}}
>
(8)
</span>
</span>
),
},
{
key: 'applications',
tab: (
<span>
{' '}
<span
style={{
fontSize: 14,
}}
>
(8)
</span>
</span>
),
},
{
key: 'projects',
tab: (
<span>
{' '}
<span
style={{
fontSize: 14,
}}
>
(8)
</span>
</span>
),
},
];
const TagList: React.FC<{
tags: CurrentUser['tags'];
}> = ({ tags }) => {
const { styles } = useStyles();
const ref = useRef<InputRef | null>(null);
const [newTags, setNewTags] = useState<TagType[]>([]);
const [inputVisible, setInputVisible] = useState<boolean>(false);
const [inputValue, setInputValue] = useState<string>('');
const showInput = () => {
setInputVisible(true);
if (ref.current) {
// eslint-disable-next-line no-unused-expressions
ref.current?.focus();
}
};
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setInputValue(e.target.value);
};
const handleInputConfirm = () => {
let tempsTags = [...newTags];
if (
inputValue &&
tempsTags.filter((tag) => tag.label === inputValue).length === 0
) {
tempsTags = [
...tempsTags,
{
key: `new-${tempsTags.length}`,
label: inputValue,
},
];
}
setNewTags(tempsTags);
setInputVisible(false);
setInputValue('');
};
return (
<div className={styles.tags}>
<div className={styles.tagsTitle}></div>
{(tags || []).concat(newTags).map((item) => (
<Tag key={item.key}>{item.label}</Tag>
))}
{inputVisible && (
<Input
ref={ref}
size="small"
style={{
width: 78,
}}
value={inputValue}
onChange={handleInputChange}
onBlur={handleInputConfirm}
onPressEnter={handleInputConfirm}
/>
)}
{!inputVisible && (
<Tag
onClick={showInput}
style={{
borderStyle: 'dashed',
}}
>
<PlusOutlined />
</Tag>
)}
</div>
);
};
const Center: React.FC = () => {
const { styles } = useStyles();
const [tabKey, setTabKey] = useState<tabKeyType>('articles');
// 获取用户信息
const { data: currentUser, loading } = useRequest(() => {
return queryCurrent();
});
// 渲染用户信息
const renderUserInfo = ({
title,
group,
geographic,
}: Partial<CurrentUser>) => {
return (
<div className={styles.detail}>
<p>
<ContactsOutlined
style={{
marginRight: 8,
}}
/>
{title}
</p>
<p>
<ClusterOutlined
style={{
marginRight: 8,
}}
/>
{group}
</p>
<p>
<HomeOutlined
style={{
marginRight: 8,
}}
/>
{
(
geographic || {
province: {
label: '',
},
}
).province.label
}
{
(
geographic || {
city: {
label: '',
},
}
).city.label
}
</p>
</div>
);
};
// 渲染tab切换
const renderChildrenByTabKey = (tabValue: tabKeyType) => {
if (tabValue === 'projects') {
return <Projects />;
}
if (tabValue === 'applications') {
return <Applications />;
}
if (tabValue === 'articles') {
return <Articles />;
}
return null;
};
return (
<GridContent>
<Row gutter={24}>
<Col lg={7} md={24}>
<Card
variant="borderless"
style={{
marginBottom: 24,
}}
loading={loading}
>
{!loading && currentUser && (
<>
<div className={styles.avatarHolder}>
<img alt="" src={currentUser.avatar} />
<div className={styles.name}>{currentUser.name}</div>
<div>{currentUser?.signature}</div>
</div>
{renderUserInfo(currentUser)}
<Divider dashed />
<TagList tags={currentUser.tags || []} />
<Divider
style={{
marginTop: 16,
}}
dashed
/>
<div className={styles.team}>
<div className={styles.teamTitle}></div>
<Row gutter={36}>
{currentUser.notice?.map((item) => (
<Col key={item.id} lg={24} xl={12}>
<a href={item.href}>
<Avatar size="small" src={item.logo} />
{item.member}
</a>
</Col>
))}
</Row>
</div>
</>
)}
</Card>
</Col>
<Col lg={17} md={24}>
<Card
className={styles.tabsCard}
variant="borderless"
tabList={operationTabList}
activeTabKey={tabKey}
onTabChange={(_tabKey: string) => {
setTabKey(_tabKey as tabKeyType);
}}
>
{renderChildrenByTabKey(tabKey)}
</Card>
</Col>
</Row>
</GridContent>
);
};
export default Center;

110
src/pages/dashboard/analysis/components/Charts/ChartCard/index.tsx

@ -1,110 +0,0 @@
import { Card } from 'antd';
import type { CardProps } from 'antd/es/card';
import classNames from 'classnames';
import omit from 'rc-util/lib/omit';
import React from 'react';
import useStyles from './index.style';
type totalType = () => React.ReactNode;
export type ChartCardProps = {
title: React.ReactNode;
action?: React.ReactNode;
total?: React.ReactNode | number | (() => React.ReactNode | number);
footer?: React.ReactNode;
contentHeight?: number;
avatar?: React.ReactNode;
style?: React.CSSProperties;
} & CardProps;
const ChartCard: React.FC<ChartCardProps> = (props) => {
const { styles } = useStyles();
const renderTotal = (total?: number | totalType | React.ReactNode) => {
if (!total && total !== 0) {
return null;
}
let totalDom: React.ReactNode | null = null;
switch (typeof total) {
case 'undefined':
totalDom = null;
break;
case 'function':
totalDom = <div className={styles.total}>{total()}</div>;
break;
default:
totalDom = <div className={styles.total}>{total}</div>;
}
return totalDom;
};
const renderContent = () => {
const {
contentHeight,
title,
avatar,
action,
total,
footer,
children,
loading,
} = props;
if (loading) {
return false;
}
return (
<div className={styles.chartCard}>
<div
className={classNames(styles.chartTop, {
[styles.chartTopMargin]: !children && !footer,
})}
>
<div className={styles.avatar}>{avatar}</div>
<div className={styles.metaWrap}>
<div className={styles.meta}>
<span>{title}</span>
<span className={styles.action}>{action}</span>
</div>
{renderTotal(total)}
</div>
</div>
{children && (
<div
className={styles.content}
style={{
height: contentHeight || 'auto',
}}
>
<div className={contentHeight ? styles.contentFixed : undefined}>
{children}
</div>
</div>
)}
{footer && (
<div
className={classNames(styles.footer, {
[styles.footerMargin]: !children,
})}
>
{footer}
</div>
)}
</div>
);
};
const { loading = false, ...rest } = props;
const cardProps = omit(rest, ['total', 'contentHeight', 'action']);
return (
<Card
loading={loading}
styles={{
body: {
padding: '20px 24px 8px 24px',
},
}}
{...cardProps}
>
{renderContent()}
</Card>
);
};
export default ChartCard;

48
src/pages/dashboard/analysis/components/Charts/MiniProgress/index.tsx

@ -1,48 +0,0 @@
import { Tooltip } from 'antd';
import React from 'react';
export type MiniProgressProps = {
target: number;
targetLabel?: string;
color?: string;
size?: number;
percent?: number;
style?: React.CSSProperties;
};
const MiniProgress: React.FC<MiniProgressProps> = ({
targetLabel,
target,
color = 'rgb(19, 194, 194)',
size,
percent,
}) => {
return (
<div>
<Tooltip title={targetLabel}>
<div
style={{
left: target ? `${target}%` : undefined,
}}
>
<span
style={{
backgroundColor: color || undefined,
}}
/>
<span
style={{
backgroundColor: color || undefined,
}}
/>
</div>
</Tooltip>
<div
style={{
backgroundColor: color || undefined,
width: percent ? `${percent}%` : undefined,
height: size || undefined,
}}
/>
</div>
);
};
export default MiniProgress;

168
src/pages/dashboard/analysis/components/IntroduceRow.tsx

@ -1,168 +0,0 @@
import { InfoCircleOutlined } from '@ant-design/icons';
import { Area, Column } from '@ant-design/plots';
import { Col, Progress, Row, Tooltip } from 'antd';
import numeral from 'numeral';
import type { DataItem } from '../data.d';
import useStyles from '../style.style';
import Yuan from '../utils/Yuan';
import { ChartCard, Field } from './Charts';
import Trend from './Trend';
const topColResponsiveProps = {
xs: 24,
sm: 12,
md: 12,
lg: 12,
xl: 6,
style: {
marginBottom: 24,
},
};
const IntroduceRow = ({
loading,
visitData,
}: {
loading: boolean;
visitData: DataItem[];
}) => {
const { styles } = useStyles();
return (
<Row gutter={24}>
<Col {...topColResponsiveProps}>
<ChartCard
variant="borderless"
title="总销售额"
action={
<Tooltip title="指标说明">
<InfoCircleOutlined />
</Tooltip>
}
loading={loading}
total={() => <Yuan>126560</Yuan>}
footer={
<Field
label="日销售额"
value={`${numeral(12423).format('0,0')}`}
/>
}
contentHeight={46}
>
<Trend
flag="up"
style={{
marginRight: 16,
}}
>
<span className={styles.trendText}>12%</span>
</Trend>
<Trend flag="down">
<span className={styles.trendText}>11%</span>
</Trend>
</ChartCard>
</Col>
<Col {...topColResponsiveProps}>
<ChartCard
variant="borderless"
loading={loading}
title="访问量"
action={
<Tooltip title="指标说明">
<InfoCircleOutlined />
</Tooltip>
}
total={numeral(8846).format('0,0')}
footer={
<Field label="日访问量" value={numeral(1234).format('0,0')} />
}
contentHeight={46}
>
<Area
xField="x"
yField="y"
shapeField="smooth"
height={46}
axis={false}
style={{
fill: 'linear-gradient(-90deg, white 0%, #975FE4 100%)',
fillOpacity: 0.6,
width: '100%',
}}
padding={-20}
data={visitData}
/>
</ChartCard>
</Col>
<Col {...topColResponsiveProps}>
<ChartCard
variant="borderless"
loading={loading}
title="支付笔数"
action={
<Tooltip title="指标说明">
<InfoCircleOutlined />
</Tooltip>
}
total={numeral(6560).format('0,0')}
footer={<Field label="转化率" value="60%" />}
contentHeight={46}
>
<Column
xField="x"
yField="y"
padding={-20}
axis={false}
height={46}
data={visitData}
scale={{ x: { paddingInner: 0.4 } }}
/>
</ChartCard>
</Col>
<Col {...topColResponsiveProps}>
<ChartCard
loading={loading}
variant="borderless"
title="运营活动效果"
action={
<Tooltip title="指标说明">
<InfoCircleOutlined />
</Tooltip>
}
total="78%"
footer={
<div
style={{
whiteSpace: 'nowrap',
overflow: 'hidden',
}}
>
<Trend
flag="up"
style={{
marginRight: 16,
}}
>
<span className={styles.trendText}>12%</span>
</Trend>
<Trend flag="down">
<span className={styles.trendText}>11%</span>
</Trend>
</div>
}
contentHeight={46}
>
<Progress
percent={78}
strokeColor={{ from: '#108ee9', to: '#87d068' }}
status="active"
/>
</ChartCard>
</Col>
</Row>
);
};
export default IntroduceRow;

110
src/pages/dashboard/analysis/components/OfflineData.tsx

@ -1,110 +0,0 @@
import { Line, Tiny } from '@ant-design/plots';
import { Card, Col, Row, Tabs } from 'antd';
import type { DataItem, OfflineDataType } from '../data.d';
import useStyles from '../style.style';
import NumberInfo from './NumberInfo';
const CustomTab = ({
data,
currentTabKey: currentKey,
}: {
data: OfflineDataType;
currentTabKey: string;
}) => (
<Row
gutter={8}
style={{
width: 138,
margin: '8px 0',
}}
>
<Col span={12}>
<NumberInfo
title={data.name}
subTitle="转化率"
gap={2}
total={`${data.cvr * 100}%`}
theme={currentKey !== data.name ? 'light' : undefined}
/>
</Col>
<Col
span={12}
style={{
paddingTop: 36,
}}
>
<Tiny.Ring
height={60}
width={60}
percent={data.cvr}
color={['#E8EEF4', '#5FABF4']}
/>
</Col>
</Row>
);
const OfflineData = ({
activeKey,
loading,
offlineData,
offlineChartData,
handleTabChange,
}: {
activeKey: string;
loading: boolean;
offlineData: OfflineDataType[];
offlineChartData: DataItem[];
handleTabChange: (activeKey: string) => void;
}) => {
const { styles } = useStyles();
return (
<Card
loading={loading}
className={styles.offlineCard}
variant="borderless"
style={{
marginTop: 32,
}}
>
<Tabs
activeKey={activeKey}
onChange={handleTabChange}
items={offlineData.map((shop) => ({
key: shop.name,
label: <CustomTab data={shop} currentTabKey={activeKey} />,
children: (
<div
style={{
padding: '0 24px',
}}
>
<Line
height={400}
data={offlineChartData}
xField="date"
yField="value"
colorField="type"
slider={{ x: true }}
axis={{
x: { title: false },
y: {
title: false,
gridLineDash: null,
gridStroke: '#ccc',
gridStrokeOpacity: 1,
},
}}
legend={{
color: {
layout: { justifyContent: 'center' },
},
}}
/>
</div>
),
}))}
/>
</Card>
);
};
export default OfflineData;

181
src/pages/dashboard/analysis/components/TopSearch.tsx

@ -1,181 +0,0 @@
import { InfoCircleOutlined } from '@ant-design/icons';
import { Area } from '@ant-design/plots';
import { Card, Col, Row, Table, Tooltip } from 'antd';
import numeral from 'numeral';
import React from 'react';
import type { DataItem } from '../data.d';
import NumberInfo from './NumberInfo';
import Trend from './Trend';
const TopSearch = ({
loading,
visitData2,
searchData,
dropdownGroup,
}: {
loading: boolean;
visitData2: DataItem[];
dropdownGroup: React.ReactNode;
searchData: DataItem[];
}) => {
const columns = [
{
title: '排名',
dataIndex: 'index',
key: 'index',
},
{
title: '搜索关键词',
dataIndex: 'keyword',
key: 'keyword',
render: (text: React.ReactNode) => <a href="/">{text}</a>,
},
{
title: '用户数',
dataIndex: 'count',
key: 'count',
sorter: (
a: {
count: number;
},
b: {
count: number;
},
) => a.count - b.count,
},
{
title: '周涨幅',
dataIndex: 'range',
key: 'range',
sorter: (
a: {
range: number;
},
b: {
range: number;
},
) => a.range - b.range,
render: (
text: React.ReactNode,
record: {
status: number;
},
) => (
<Trend flag={record.status === 1 ? 'down' : 'up'}>
<span
style={{
marginRight: 4,
}}
>
{text}%
</span>
</Trend>
),
},
];
return (
<Card
loading={loading}
variant="borderless"
title="线上热门搜索"
extra={dropdownGroup}
style={{
height: '100%',
}}
>
<Row gutter={68}>
<Col
sm={12}
xs={24}
style={{
marginBottom: 24,
}}
>
<NumberInfo
subTitle={
<span>
<Tooltip title="指标说明">
<InfoCircleOutlined
style={{
marginLeft: 8,
}}
/>
</Tooltip>
</span>
}
gap={8}
total={numeral(12321).format('0,0')}
status="up"
subTotal={17.1}
/>
<Area
xField="x"
yField="y"
shapeField="smooth"
height={45}
axis={false}
padding={-12}
style={{
fill: 'linear-gradient(-90deg, white 0%, #6294FA 100%)',
fillOpacity: 0.4,
}}
data={visitData2}
/>
</Col>
<Col
sm={12}
xs={24}
style={{
marginBottom: 24,
}}
>
<NumberInfo
subTitle={
<span>
<Tooltip title="指标说明">
<InfoCircleOutlined
style={{
marginLeft: 8,
}}
/>
</Tooltip>
</span>
}
total={2.7}
status="down"
subTotal={26.2}
gap={8}
/>
<Area
xField="x"
yField="y"
shapeField="smooth"
height={45}
padding={-12}
style={{
fill: 'linear-gradient(-90deg, white 0%, #6294FA 100%)',
fillOpacity: 0.4,
}}
data={visitData2}
axis={false}
/>
</Col>
</Row>
<Table<any>
rowKey={(record) => record.index}
size="small"
columns={columns}
dataSource={searchData}
pagination={{
style: {
marginBottom: 0,
},
pageSize: 5,
}}
/>
</Card>
);
};
export default TopSearch;

203
src/pages/dashboard/monitor/index.tsx

@ -1,203 +0,0 @@
import { Gauge, Liquid, WordCloud } from '@ant-design/plots';
import { GridContent } from '@ant-design/pro-components';
import { useRequest } from '@umijs/max';
import { Card, Col, Progress, Row, Statistic } from 'antd';
import numeral from 'numeral';
import type { FC } from 'react';
import ActiveChart from './components/ActiveChart';
import MonitorMap from './components/Map';
import { queryTags } from './service';
import useStyles from './style.style';
const deadline = Date.now() + 1000 * 60 * 60 * 24 * 2 + 1000 * 30; // Moment is also OK
const Monitor: FC = () => {
const { styles } = useStyles();
const { loading, data } = useRequest(queryTags);
const wordCloudData = (data?.list || []).map((item) => {
return {
id: +Date.now(),
word: item.name,
weight: item.value,
};
});
return (
<GridContent>
<Row gutter={24}>
<Col
xl={18}
lg={24}
md={24}
sm={24}
xs={24}
style={{
marginBottom: 24,
}}
>
<Card title="活动实时交易情况" variant="borderless">
<Row>
<Col md={6} sm={12} xs={24}>
<Statistic
title="今日交易总额"
suffix="元"
value={numeral(124543233).format('0,0')}
/>
</Col>
<Col md={6} sm={12} xs={24}>
<Statistic title="销售目标完成率" value="92%" />
</Col>
<Col md={6} sm={12} xs={24}>
<Statistic.Timer
type="countdown"
title="活动剩余时间"
value={deadline}
format="HH:mm:ss:SSS"
/>
</Col>
<Col md={6} sm={12} xs={24}>
<Statistic
title="每秒交易总额"
suffix="元"
value={numeral(234).format('0,0')}
/>
</Col>
</Row>
<div className={styles.mapChart}>
<MonitorMap />
</div>
</Card>
</Col>
<Col xl={6} lg={24} md={24} sm={24} xs={24}>
<Card
title="活动情况预测"
style={{
marginBottom: 24,
}}
variant="borderless"
>
<ActiveChart />
</Card>
<Card
title="券核效率"
style={{
marginBottom: 24,
}}
styles={{
body: {
textAlign: 'center',
},
}}
variant="borderless"
>
<Gauge
height={180}
data={
{
target: 80,
total: 100,
name: 'score',
thresholds: [20, 40, 60, 80, 100],
} as any
}
padding={-16}
style={{
textContent: () => '优',
}}
meta={{
color: {
range: [
'#6395FA',
'#62DAAB',
'#657798',
'#F7C128',
'#1F8718',
],
},
}}
/>
</Card>
</Col>
</Row>
<Row gutter={24}>
<Col
xl={12}
lg={24}
sm={24}
xs={24}
style={{
marginBottom: 24,
}}
>
<Card title="各品类占比" variant="borderless">
<Row
style={{
padding: '16px 0',
}}
>
<Col span={8}>
<Progress type="dashboard" percent={75} />
</Col>
<Col span={8}>
<Progress type="dashboard" percent={48} />
</Col>
<Col span={8}>
<Progress type="dashboard" percent={33} />
</Col>
</Row>
</Card>
</Col>
<Col
xl={6}
lg={12}
sm={24}
xs={24}
style={{
marginBottom: 24,
}}
>
<Card
title="热门搜索"
loading={loading}
variant="borderless"
styles={{
body: {
overflow: 'hidden',
},
}}
>
<WordCloud
data={wordCloudData}
height={162}
textField="word"
colorField="word"
layout={{ spiral: 'rectangular', fontSize: [10, 20] }}
/>
</Card>
</Col>
<Col
xl={6}
lg={12}
sm={24}
xs={24}
style={{
marginBottom: 24,
}}
>
<Card
title="资源剩余"
styles={{
body: {
textAlign: 'center',
fontSize: 0,
},
}}
variant="borderless"
>
<Liquid height={160} percent={0.35} />
</Card>
</Col>
</Row>
</GridContent>
);
};
export default Monitor;

549
src/pages/form/advanced-form/index.tsx

@ -1,549 +0,0 @@
import { CloseCircleOutlined } from '@ant-design/icons';
import type { ProColumnType } from '@ant-design/pro-components';
import {
EditableProTable,
FooterToolbar,
PageContainer,
ProForm,
ProFormDateRangePicker,
ProFormSelect,
ProFormText,
ProFormTimePicker,
} from '@ant-design/pro-components';
import { Card, Col, message, Popover, Row } from 'antd';
import type { FC } from 'react';
import { useState } from 'react';
import { fakeSubmitForm } from './service';
import useStyles from './style.style';
interface TableFormDateType {
key: string;
workId?: string;
name?: string;
department?: string;
isNew?: boolean;
editable?: boolean;
}
type InternalNamePath = (string | number)[];
const fieldLabels = {
name: '仓库名',
url: '仓库域名',
owner: '仓库管理员',
approver: '审批人',
dateRange: '生效日期',
type: '仓库类型',
name2: '任务名',
url2: '任务描述',
owner2: '执行人',
approver2: '责任人',
dateRange2: '生效日期',
type2: '任务类型',
};
const tableData = [
{
key: '1',
workId: '00001',
name: 'John Brown',
department: 'New York No. 1 Lake Park',
},
{
key: '2',
workId: '00002',
name: 'Jim Green',
department: 'London No. 1 Lake Park',
},
{
key: '3',
workId: '00003',
name: 'Joe Black',
department: 'Sidney No. 1 Lake Park',
},
];
interface ErrorField {
name: InternalNamePath;
errors: string[];
}
const AdvancedForm: FC<Record<string, any>> = () => {
const { styles } = useStyles();
const [error, setError] = useState<ErrorField[]>([]);
const getErrorInfo = (errors: ErrorField[]) => {
const errorCount = errors.filter((item) => item.errors.length > 0).length;
if (!errors || errorCount === 0) {
return null;
}
const scrollToField = (fieldKey: string) => {
const labelNode = document.querySelector(`label[for="${fieldKey}"]`);
if (labelNode) {
labelNode.scrollIntoView(true);
}
};
const errorList = errors.map((err) => {
if (!err || err.errors.length === 0) {
return null;
}
const key = err.name[0] as
| 'name'
| 'url'
| 'owner'
| 'approver'
| 'dateRange'
| 'type';
return (
<li
key={key}
className={styles.errorListItem}
onClick={() => scrollToField(key)}
>
<CloseCircleOutlined className={styles.errorIcon} />
<div>{err.errors[0]}</div>
<div className={styles.errorField}>{fieldLabels[key]}</div>
</li>
);
});
return (
<span className={styles.errorIcon}>
<Popover
title="表单校验信息"
content={errorList}
overlayClassName={styles.errorPopover}
trigger="click"
getPopupContainer={(trigger: HTMLElement) => {
if (trigger?.parentNode) {
return trigger.parentNode as HTMLElement;
}
return trigger;
}}
>
<CloseCircleOutlined />
</Popover>
{errorCount}
</span>
);
};
const onFinish = async (values: Record<string, any>) => {
setError([]);
try {
await fakeSubmitForm(values);
message.success('提交成功');
} catch {
// console.log
}
};
const onFinishFailed = (errorInfo: any) => {
setError(errorInfo.errorFields);
};
const columns: ProColumnType<TableFormDateType>[] = [
{
title: '成员姓名',
dataIndex: 'name',
key: 'name',
width: '20%',
},
{
title: '工号',
dataIndex: 'workId',
key: 'workId',
width: '20%',
},
{
title: '所属部门',
dataIndex: 'department',
key: 'department',
width: '40%',
},
{
title: '操作',
key: 'action',
valueType: 'option',
render: (_, record: TableFormDateType, _index, action) => {
return [
<a
key="eidit"
onClick={() => {
action?.startEditable(record.key);
}}
>
</a>,
];
},
},
];
return (
<ProForm
layout="vertical"
hideRequiredMark
submitter={{
render: (_props, dom) => {
return (
<FooterToolbar>
{getErrorInfo(error)}
{dom}
</FooterToolbar>
);
},
}}
initialValues={{
members: tableData,
}}
onFinish={onFinish}
onFinishFailed={onFinishFailed}
>
<PageContainer content="高级表单常见于一次性输入和提交大批量数据的场景。">
<Card title="仓库管理" className={styles.card} variant="borderless">
<Row gutter={16}>
<Col lg={6} md={12} sm={24}>
<ProFormText
label={fieldLabels.name}
name="name"
rules={[
{
required: true,
message: '请输入仓库名称',
},
]}
placeholder="请输入仓库名称"
/>
</Col>
<Col
xl={{
span: 6,
offset: 2,
}}
lg={{
span: 8,
}}
md={{
span: 12,
}}
sm={24}
>
<ProFormText
label={fieldLabels.url}
name="url"
rules={[
{
required: true,
message: '请选择',
},
]}
fieldProps={{
style: {
width: '100%',
},
addonBefore: 'http://',
addonAfter: '.com',
}}
placeholder="请输入"
/>
</Col>
<Col
xl={{
span: 8,
offset: 2,
}}
lg={{
span: 10,
}}
md={{
span: 24,
}}
sm={24}
>
<ProFormSelect
label={fieldLabels.owner}
name="owner"
rules={[
{
required: true,
message: '请选择管理员',
},
]}
options={[
{
label: '付晓晓',
value: 'xiao',
},
{
label: '周毛毛',
value: 'mao',
},
]}
placeholder="请选择管理员"
/>
</Col>
</Row>
<Row gutter={16}>
<Col lg={6} md={12} sm={24}>
<ProFormSelect
label={fieldLabels.approver}
name="approver"
rules={[
{
required: true,
message: '请选择审批员',
},
]}
options={[
{
label: '付晓晓',
value: 'xiao',
},
{
label: '周毛毛',
value: 'mao',
},
]}
placeholder="请选择审批员"
/>
</Col>
<Col
xl={{
span: 6,
offset: 2,
}}
lg={{
span: 8,
}}
md={{
span: 12,
}}
sm={24}
>
<ProFormDateRangePicker
label={fieldLabels.dateRange}
name="dateRange"
fieldProps={{
style: {
width: '100%',
},
}}
rules={[
{
required: true,
message: '请选择生效日期',
},
]}
/>
</Col>
<Col
xl={{
span: 8,
offset: 2,
}}
lg={{
span: 10,
}}
md={{
span: 24,
}}
sm={24}
>
<ProFormSelect
label={fieldLabels.type}
name="type"
rules={[
{
required: true,
message: '请选择仓库类型',
},
]}
options={[
{
label: '私密',
value: 'private',
},
{
label: '公开',
value: 'public',
},
]}
placeholder="请选择仓库类型"
/>
</Col>
</Row>
</Card>
<Card title="任务管理" className={styles.card} variant="borderless">
<Row gutter={16}>
<Col lg={6} md={12} sm={24}>
<ProFormText
label={fieldLabels.name2}
name="name2"
rules={[
{
required: true,
message: '请输入',
},
]}
/>
</Col>
<Col
xl={{
span: 6,
offset: 2,
}}
lg={{
span: 8,
}}
md={{
span: 12,
}}
sm={24}
>
<ProFormText
label={fieldLabels.url2}
name="url2"
rules={[
{
required: true,
message: '请选择',
},
]}
/>
</Col>
<Col
xl={{
span: 8,
offset: 2,
}}
lg={{
span: 10,
}}
md={{
span: 24,
}}
sm={24}
>
<ProFormSelect
label={fieldLabels.owner2}
name="owner2"
rules={[
{
required: true,
message: '请选择管理员',
},
]}
options={[
{
label: '付晓晓',
value: 'xiao',
},
{
label: '周毛毛',
value: 'mao',
},
]}
/>
</Col>
</Row>
<Row gutter={16}>
<Col lg={6} md={12} sm={24}>
<ProFormSelect
label={fieldLabels.approver2}
name="approver2"
rules={[
{
required: true,
message: '请选择审批员',
},
]}
options={[
{
label: '付晓晓',
value: 'xiao',
},
{
label: '周毛毛',
value: 'mao',
},
]}
placeholder="请选择审批员"
/>
</Col>
<Col
xl={{
span: 6,
offset: 2,
}}
lg={{
span: 8,
}}
md={{
span: 12,
}}
sm={24}
>
<ProFormTimePicker
label={fieldLabels.dateRange2}
name="dateRange2"
rules={[
{
required: true,
message: '请输入',
},
]}
placeholder="提醒时间"
fieldProps={{
style: {
width: '100%',
},
}}
/>
</Col>
<Col
xl={{
span: 8,
offset: 2,
}}
lg={{
span: 10,
}}
md={{
span: 24,
}}
sm={24}
>
<ProFormSelect
label={fieldLabels.type2}
name="type2"
rules={[
{
required: true,
message: '请选择仓库类型',
},
]}
options={[
{
label: '私密',
value: 'private',
},
{
label: '公开',
value: 'public',
},
]}
placeholder="请选择仓库类型"
/>
</Col>
</Row>
</Card>
<Card title="成员管理" variant="borderless">
<ProForm.Item name="members">
<EditableProTable<TableFormDateType>
recordCreatorProps={{
record: () => {
return {
key: `0${Date.now()}`,
};
},
}}
columns={columns}
rowKey="key"
/>
</ProForm.Item>
</Card>
</PageContainer>
</ProForm>
);
};
export default AdvancedForm;

194
src/pages/form/basic-form/index.tsx

@ -1,194 +0,0 @@
import {
PageContainer,
ProForm,
ProFormDateRangePicker,
ProFormDependency,
ProFormDigit,
ProFormRadio,
ProFormSelect,
ProFormText,
ProFormTextArea,
} from '@ant-design/pro-components';
import { useRequest } from '@umijs/max';
import { Card, message } from 'antd';
import type { FC } from 'react';
import { fakeSubmitForm } from './service';
import useStyles from './style.style';
const BasicForm: FC<Record<string, any>> = () => {
const { styles } = useStyles();
const { run } = useRequest(fakeSubmitForm, {
manual: true,
onSuccess: () => {
message.success('提交成功');
},
});
const onFinish = async (values: Record<string, any>) => {
run(values);
};
return (
<PageContainer content="表单页用于向用户收集或验证信息,基础表单常见于数据项较少的表单场景。">
<Card variant="borderless">
<ProForm
hideRequiredMark
style={{
margin: 'auto',
marginTop: 8,
maxWidth: 600,
}}
name="basic"
layout="vertical"
initialValues={{
public: '1',
}}
onFinish={onFinish}
>
<ProFormText
width="md"
label="标题"
name="title"
rules={[
{
required: true,
message: '请输入标题',
},
]}
placeholder="给目标起个名字"
/>
<ProFormDateRangePicker
label="起止日期"
width="md"
name="date"
rules={[
{
required: true,
message: '请选择起止日期',
},
]}
placeholder={['开始日期', '结束日期']}
/>
<ProFormTextArea
label="目标描述"
width="xl"
name="goal"
rules={[
{
required: true,
message: '请输入目标描述',
},
]}
placeholder="请输入你的阶段性工作目标"
/>
<ProFormTextArea
label="衡量标准"
name="standard"
width="xl"
rules={[
{
required: true,
message: '请输入衡量标准',
},
]}
placeholder="请输入衡量标准"
/>
<ProFormText
width="md"
label={
<span>
<em className={styles.optional}></em>
</span>
}
tooltip="目标的服务对象"
name="client"
placeholder="请描述你服务的客户,内部客户直接 @姓名/工号"
/>
<ProFormText
width="md"
label={
<span>
<em className={styles.optional}></em>
</span>
}
name="invites"
placeholder="请直接 @姓名/工号,最多可邀请 5 人"
/>
<ProFormDigit
label={
<span>
<em className={styles.optional}></em>
</span>
}
name="weight"
placeholder="请输入"
min={0}
max={100}
width="xs"
fieldProps={{
formatter: (value) => `${value || 0}%`,
parser: (value) => Number(value ? value.replace('%', '') : '0'),
}}
/>
<ProFormRadio.Group
options={[
{
value: '1',
label: '公开',
},
{
value: '2',
label: '部分公开',
},
{
value: '3',
label: '不公开',
},
]}
label="目标公开"
help="客户、邀评人默认被分享"
name="publicType"
/>
<ProFormDependency name={['publicType']}>
{({ publicType }) => {
return (
<ProFormSelect
width="md"
name="publicUsers"
fieldProps={{
style: {
margin: '8px 0',
display:
publicType && publicType === '2' ? 'block' : 'none',
},
}}
options={[
{
value: '1',
label: '同事甲',
},
{
value: '2',
label: '同事乙',
},
{
value: '3',
label: '同事丙',
},
]}
/>
);
}}
</ProFormDependency>
</ProForm>
</Card>
</PageContainer>
);
};
export default BasicForm;

248
src/pages/form/step-form/index.tsx

@ -1,248 +0,0 @@
import {
PageContainer,
ProForm,
ProFormDigit,
ProFormSelect,
ProFormText,
StepsForm,
} from '@ant-design/pro-components';
import type { FormInstance } from 'antd';
import {
Alert,
Button,
Card,
Descriptions,
Divider,
Result,
Statistic,
} from 'antd';
import React, { useRef, useState } from 'react';
import type { StepDataType } from './data.d';
import useStyles from './style.style';
const StepDescriptions: React.FC<{
stepData: StepDataType;
bordered?: boolean;
}> = ({ stepData, bordered }) => {
const { payAccount, receiverAccount, receiverName, amount } = stepData;
return (
<Descriptions column={1} bordered={bordered}>
<Descriptions.Item label="付款账户"> {payAccount}</Descriptions.Item>
<Descriptions.Item label="收款账户"> {receiverAccount}</Descriptions.Item>
<Descriptions.Item label="收款人姓名"> {receiverName}</Descriptions.Item>
<Descriptions.Item label="转账金额">
<Statistic
value={amount}
suffix={
<span
style={{
fontSize: 14,
}}
>
</span>
}
precision={2}
/>
</Descriptions.Item>
</Descriptions>
);
};
const StepResult: React.FC<{
onFinish: () => Promise<void>;
children?: React.ReactNode;
}> = (props) => {
const { styles } = useStyles();
return (
<Result
status="success"
title="操作成功"
subTitle="预计两小时内到账"
extra={
<>
<Button type="primary" onClick={props.onFinish}>
</Button>
<Button></Button>
</>
}
className={styles.result}
>
{props.children}
</Result>
);
};
const StepForm: React.FC<Record<string, any>> = () => {
const { styles } = useStyles();
const [stepData, setStepData] = useState<StepDataType>({
payAccount: 'ant-design@alipay.com',
receiverAccount: 'test@example.com',
receiverName: 'Alex',
amount: '500',
receiverMode: 'alipay',
});
const [current, setCurrent] = useState(0);
const formRef = useRef<FormInstance>(null);
return (
<PageContainer content="将一个冗长或用户不熟悉的表单任务分成多个步骤,指导用户完成。">
<Card variant="borderless">
<StepsForm
current={current}
onCurrentChange={setCurrent}
submitter={{
render: (props, dom) => {
if (props.step === 2) {
return null;
}
return dom;
},
}}
>
<StepsForm.StepForm<StepDataType>
formRef={formRef}
title="填写转账信息"
initialValues={stepData}
onFinish={async (values) => {
setStepData(values);
return true;
}}
>
<ProFormSelect
label="付款账户"
width="md"
name="payAccount"
rules={[
{
required: true,
message: '请选择付款账户',
},
]}
valueEnum={{
'ant-design@alipay.com': 'ant-design@alipay.com',
}}
/>
<ProForm.Group title="收款账户" size={8}>
<ProFormSelect
name="receiverMode"
rules={[
{
required: true,
message: '请选择付款账户',
},
]}
valueEnum={{
alipay: '支付宝',
bank: '银行账户',
}}
/>
<ProFormText
name="receiverAccount"
rules={[
{
required: true,
message: '请输入收款人账户',
},
{
type: 'email',
message: '账户名应为邮箱格式',
},
]}
placeholder="test@example.com"
/>
</ProForm.Group>
<ProFormText
label="收款人姓名"
width="md"
name="receiverName"
rules={[
{
required: true,
message: '请输入收款人姓名',
},
]}
placeholder="请输入收款人姓名"
/>
<ProFormDigit
label="转账金额"
name="amount"
width="md"
rules={[
{
required: true,
message: '请输入转账金额',
},
{
pattern: /^(\d+)((?:\.\d+)?)$/,
message: '请输入合法金额数字',
},
]}
placeholder="请输入金额"
fieldProps={{
prefix: '¥',
}}
/>
</StepsForm.StepForm>
<StepsForm.StepForm title="确认转账信息">
<div className={styles.result}>
<Alert
closable
showIcon
message="确认转账后,资金将直接打入对方账户,无法退回。"
style={{
marginBottom: 24,
}}
/>
<StepDescriptions stepData={stepData} bordered />
<Divider
style={{
margin: '24px 0',
}}
/>
<ProFormText.Password
label="支付密码"
width="md"
name="password"
required={false}
rules={[
{
required: true,
message: '需要支付密码才能进行支付',
},
]}
/>
</div>
</StepsForm.StepForm>
<StepsForm.StepForm title="完成">
<StepResult
onFinish={async () => {
setCurrent(0);
formRef.current?.resetFields();
}}
>
<StepDescriptions stepData={stepData} />
</StepResult>
</StepsForm.StepForm>
</StepsForm>
<Divider
style={{
margin: '40px 0 24px',
}}
/>
<div>
<h3></h3>
<h4></h4>
<p>
</p>
<h4></h4>
<p>
</p>
</div>
</Card>
</PageContainer>
);
};
export default StepForm;

129
src/pages/list/basic-list/components/OperationModal.tsx

@ -1,129 +0,0 @@
import {
ModalForm,
ProFormDateTimePicker,
ProFormSelect,
ProFormText,
ProFormTextArea,
} from '@ant-design/pro-components';
import { Button, Result } from 'antd';
import type { FC } from 'react';
import type { BasicListItemDataType } from '../data.d';
import useStyles from '../style.style';
type OperationModalProps = {
done: boolean;
open: boolean;
current: Partial<BasicListItemDataType> | undefined;
onDone: () => void;
onSubmit: (values: BasicListItemDataType) => void;
children?: React.ReactNode;
};
const OperationModal: FC<OperationModalProps> = (props) => {
const { styles } = useStyles();
const { done, open, current, onDone, onSubmit, children } = props;
if (!open) {
return null;
}
return (
<ModalForm<BasicListItemDataType>
open={open}
title={done ? null : `任务${current ? '编辑' : '添加'}`}
className={styles.standardListForm}
width={640}
onFinish={async (values) => {
onSubmit(values);
}}
initialValues={current}
submitter={{
render: (_, dom) => (done ? null : dom),
}}
trigger={children}
modalProps={{
onCancel: () => onDone(),
destroyOnHidden: true,
bodyStyle: done
? {
padding: '72px 0',
}
: {},
}}
>
{!done ? (
<>
<ProFormText
name="title"
label="任务名称"
rules={[
{
required: true,
message: '请输入任务名称',
},
]}
placeholder="请输入"
/>
<ProFormDateTimePicker
name="createdAt"
label="开始时间"
rules={[
{
required: true,
message: '请选择开始时间',
},
]}
fieldProps={{
style: {
width: '100%',
},
}}
placeholder="请选择"
/>
<ProFormSelect
name="owner"
label="任务负责人"
rules={[
{
required: true,
message: '请选择任务负责人',
},
]}
options={[
{
label: '付晓晓',
value: 'xiao',
},
{
label: '周毛毛',
value: 'mao',
},
]}
placeholder="请选择管理员"
/>
<ProFormTextArea
name="subDescription"
label="产品描述"
rules={[
{
message: '请输入至少五个字符的产品描述!',
min: 5,
},
]}
placeholder="请输入至少五个字符"
/>
</>
) : (
<Result
status="success"
title="操作成功"
subTitle="一系列的信息描述,很短同样也可以带标点。"
extra={
<Button type="primary" onClick={onDone}>
</Button>
}
className={styles.formResult}
/>
)}
</ModalForm>
);
};
export default OperationModal;

280
src/pages/list/basic-list/index.tsx

@ -1,280 +0,0 @@
import { DownOutlined, PlusOutlined } from '@ant-design/icons';
import { PageContainer } from '@ant-design/pro-components';
import { useRequest } from '@umijs/max';
import {
Avatar,
Button,
Card,
Col,
Dropdown,
Input,
List,
Modal,
Progress,
Row,
Segmented,
} from 'antd';
import dayjs from 'dayjs';
import type { FC } from 'react';
import React, { useState } from 'react';
import OperationModal from './components/OperationModal';
import type { BasicListItemDataType } from './data.d';
import {
addFakeList,
queryFakeList,
removeFakeList,
updateFakeList,
} from './service';
import useStyles from './style.style';
const { Search } = Input;
const Info: FC<{
title: React.ReactNode;
value: React.ReactNode;
bordered?: boolean;
}> = ({ title, value, bordered }) => {
const { styles } = useStyles();
return (
<div className={styles.headerInfo}>
<span>{title}</span>
<p>{value}</p>
{bordered && <em />}
</div>
);
};
const ListContent = ({
data: { owner, createdAt, percent, status },
}: {
data: BasicListItemDataType;
}) => {
const { styles } = useStyles();
return (
<div>
<div className={styles.listContentItem}>
<span>Owner</span>
<p>{owner}</p>
</div>
<div className={styles.listContentItem}>
<span></span>
<p>{dayjs(createdAt).format('YYYY-MM-DD HH:mm')}</p>
</div>
<div className={styles.listContentItem}>
<Progress
percent={percent}
status={status}
size={6}
style={{
width: 180,
}}
/>
</div>
</div>
);
};
export const BasicList: FC = () => {
const { styles } = useStyles();
const [done, setDone] = useState<boolean>(false);
const [open, setVisible] = useState<boolean>(false);
const [current, setCurrent] = useState<
Partial<BasicListItemDataType> | undefined
>(undefined);
const {
data: listData,
loading,
mutate,
} = useRequest(() => {
return queryFakeList({
count: 50,
});
});
const { run: postRun } = useRequest(
(method, params) => {
if (method === 'remove') {
return removeFakeList(params);
}
if (method === 'update') {
return updateFakeList(params);
}
return addFakeList(params);
},
{
manual: true,
onSuccess: (result) => {
mutate(result);
},
},
);
const list = listData?.list || [];
const paginationProps = {
showSizeChanger: true,
showQuickJumper: true,
pageSize: 5,
total: list.length,
};
const showEditModal = (item: BasicListItemDataType) => {
setVisible(true);
setCurrent(item);
};
const deleteItem = (id: string) => {
postRun('remove', {
id,
});
};
const editAndDelete = (
key: string | number,
currentItem: BasicListItemDataType,
) => {
if (key === 'edit') showEditModal(currentItem);
else if (key === 'delete') {
Modal.confirm({
title: '删除任务',
content: '确定删除该任务吗?',
okText: '确认',
cancelText: '取消',
onOk: () => deleteItem(currentItem.id),
});
}
};
const extraContent = (
<div>
<Segmented
defaultValue="all"
options={[
{ label: '全部', value: 'all' },
{ label: '进行中', value: 'progress' },
{ label: '等待中', value: 'waiting' },
]}
// 如有需要可添加 onChange 事件
/>
<Search
className={styles.extraContentSearch}
placeholder="请输入"
onSearch={() => ({})}
variant="filled"
/>
</div>
);
const MoreBtn: React.FC<{
item: BasicListItemDataType;
}> = ({ item }) => (
<Dropdown
menu={{
onClick: ({ key }) => editAndDelete(key, item),
items: [
{
key: 'edit',
label: '编辑',
},
{
key: 'delete',
label: '删除',
},
],
}}
>
<a>
<DownOutlined />
</a>
</Dropdown>
);
const handleDone = () => {
setDone(false);
setVisible(false);
setCurrent({});
};
const handleSubmit = (values: BasicListItemDataType) => {
setDone(true);
const method = values?.id ? 'update' : 'add';
postRun(method, values);
};
return (
<div>
<PageContainer>
<div className={styles.standardList}>
<Card variant="borderless">
<Row>
<Col sm={8} xs={24}>
<Info title="我的待办" value="8个任务" bordered />
</Col>
<Col sm={8} xs={24}>
<Info title="本周任务平均处理时间" value="32分钟" bordered />
</Col>
<Col sm={8} xs={24}>
<Info title="本周完成任务数" value="24个任务" />
</Col>
</Row>
</Card>
<Card
className={styles.listCard}
variant="borderless"
title="基本列表"
style={{
marginTop: 24,
}}
styles={{
body: {
padding: '0 32px 40px 32px',
},
}}
extra={extraContent}
>
<List
size="large"
rowKey="id"
loading={loading}
pagination={paginationProps}
dataSource={list}
renderItem={(item) => (
<List.Item
actions={[
<a
key="edit"
onClick={(e) => {
e.preventDefault();
showEditModal(item);
}}
>
</a>,
<MoreBtn key="more" item={item} />,
]}
>
<List.Item.Meta
avatar={
<Avatar src={item.logo} shape="square" size="large" />
}
title={<a href={item.href}>{item.title}</a>}
description={item.subDescription}
/>
<ListContent data={item} />
</List.Item>
)}
/>
</Card>
</div>
</PageContainer>
<Button
type="dashed"
onClick={() => {
setVisible(true);
}}
style={{
width: '100%',
marginBottom: 8,
}}
>
<PlusOutlined />
</Button>
<OperationModal
done={done}
open={open}
current={current}
onDone={handleDone}
onSubmit={handleSubmit}
/>
</div>
);
};
export default BasicList;

239
src/pages/list/search/applications/index.tsx

@ -1,239 +0,0 @@
import {
DownloadOutlined,
EditOutlined,
EllipsisOutlined,
ShareAltOutlined,
} from '@ant-design/icons';
import { useRequest } from '@umijs/max';
import {
Avatar,
Card,
Col,
Dropdown,
Form,
List,
Row,
Select,
Tooltip,
} from 'antd';
import numeral from 'numeral';
import type { FC } from 'react';
import React from 'react';
import { categoryOptions } from '../../mock';
import StandardFormRow from './components/StandardFormRow';
import TagSelect from './components/TagSelect';
import type { ListItemDataType } from './data.d';
import { queryFakeList } from './service';
import useStyles from './style.style';
export function formatWan(val: number) {
const v = val * 1;
if (!v || Number.isNaN(v)) return '';
let result: React.ReactNode = val;
if (val > 10000) {
result = (
<span>
{Math.floor(val / 10000)}
<span
style={{
position: 'relative',
top: -2,
fontSize: 14,
fontStyle: 'normal',
marginLeft: 2,
}}
>
</span>
</span>
);
}
return result;
}
const formItemLayout = {
wrapperCol: {
xs: {
span: 24,
},
sm: {
span: 16,
},
},
};
const CardInfo: React.FC<{
activeUser: React.ReactNode;
newUser: React.ReactNode;
}> = ({ activeUser, newUser }) => {
const { styles } = useStyles();
return (
<div className={styles.cardInfo}>
<div>
<p></p>
<p>{activeUser}</p>
</div>
<div>
<p></p>
<p>{newUser}</p>
</div>
</div>
);
};
export const Applications: FC<Record<string, any>> = () => {
const { styles } = useStyles();
const { data, loading, run } = useRequest((values: any) => {
console.log('form data', values);
return queryFakeList({
count: 8,
});
});
const list = data?.list || [];
return (
<div className={styles.filterCardList}>
<Card variant="borderless">
<Form
onValuesChange={(_, values) => {
run(values);
}}
>
<StandardFormRow
title="所属类目"
block
style={{
paddingBottom: 11,
}}
>
<Form.Item name="category">
<TagSelect expandable>
{categoryOptions
.filter(
(
category,
): category is { value: string | number; label: string } =>
category.value !== undefined && category.value !== null,
)
.map((category) => (
<TagSelect.Option
value={category.value}
key={category.value}
>
{category.label}
</TagSelect.Option>
))}
</TagSelect>
</Form.Item>
</StandardFormRow>
<StandardFormRow title="其它选项" grid last>
<Row gutter={16}>
<Col lg={8} md={10} sm={10} xs={24}>
<Form.Item {...formItemLayout} name="author" label="作者">
<Select
placeholder="不限"
style={{
maxWidth: 200,
width: '100%',
}}
options={[
{
label: '王昭君',
value: 'lisa',
},
]}
/>
</Form.Item>
</Col>
<Col lg={8} md={10} sm={10} xs={24}>
<Form.Item {...formItemLayout} name="rate" label="好评度">
<Select
placeholder="不限"
style={{
maxWidth: 200,
width: '100%',
}}
options={[
{
label: '优秀',
value: 'good',
},
{
label: '普通',
value: 'normal',
},
]}
/>
</Form.Item>
</Col>
</Row>
</StandardFormRow>
</Form>
</Card>
<br />
<List<ListItemDataType>
rowKey="id"
grid={{
gutter: 16,
xs: 1,
sm: 2,
md: 3,
lg: 3,
xl: 4,
xxl: 4,
}}
loading={loading}
dataSource={list}
renderItem={(item) => (
<List.Item key={item.id}>
<Card
hoverable
styles={{
body: {
paddingBottom: 20,
},
}}
actions={[
<Tooltip key="download" title="下载">
<DownloadOutlined />
</Tooltip>,
<Tooltip key="edit" title="编辑">
<EditOutlined />
</Tooltip>,
<Tooltip title="分享" key="share">
<ShareAltOutlined />
</Tooltip>,
<Dropdown
key="ellipsis"
menu={{
items: [
{
key: '1',
title: '1st menu item',
},
{
key: '2',
title: '2st menu item',
},
],
}}
>
<EllipsisOutlined />
</Dropdown>,
]}
>
<Card.Meta
avatar={<Avatar size="small" src={item.avatar} />}
title={item.title}
/>
<div>
<CardInfo
activeUser={formatWan(item.activeUser)}
newUser={numeral(item.newUser).format('0,0')}
/>
</div>
</Card>
</List.Item>
)}
/>
</div>
);
};
export default Applications;

261
src/pages/list/search/articles/index.tsx

@ -1,261 +0,0 @@
import {
LikeOutlined,
LoadingOutlined,
MessageOutlined,
StarOutlined,
} from '@ant-design/icons';
import { useRequest } from '@umijs/max';
import { Button, Card, Col, Form, List, Row, Select, Tag } from 'antd';
import type { DefaultOptionType } from 'antd/es/select';
import type { FC } from 'react';
import React, { useMemo } from 'react';
import { categoryOptions } from '../../mock';
import ArticleListContent from './components/ArticleListContent';
import StandardFormRow from './components/StandardFormRow';
import TagSelect from './components/TagSelect';
import type { ListItemDataType } from './data.d';
import { queryFakeList } from './service';
import useStyles from './style.style';
const FormItem = Form.Item;
const pageSize = 5;
const Articles: FC = () => {
const [form] = Form.useForm();
const { styles } = useStyles();
const { data, reload, loading, loadMore, loadingMore } = useRequest(
() => {
return queryFakeList({
count: pageSize,
});
},
{
loadMore: true,
},
);
const list = data?.list || [];
const setOwner = () => {
form.setFieldsValue({
owner: ['wzj'],
});
};
const owners = [
{
id: 'wzj',
name: '我自己',
},
{
id: 'wjh',
name: '吴家豪',
},
{
id: 'zxx',
name: '周星星',
},
{
id: 'zly',
name: '赵丽颖',
},
{
id: 'ym',
name: '姚明',
},
];
const IconText: React.FC<{
type: string;
text: React.ReactNode;
}> = ({ type, text }) => {
switch (type) {
case 'star-o':
return (
<span>
<StarOutlined style={{ marginRight: 8 }} />
{text}
</span>
);
case 'like-o':
return (
<span>
<LikeOutlined style={{ marginRight: 8 }} />
{text}
</span>
);
case 'message':
return (
<span>
<MessageOutlined style={{ marginRight: 8 }} />
{text}
</span>
);
default:
return null;
}
};
const formItemLayout = {
wrapperCol: {
xs: { span: 24 },
sm: { span: 24 },
md: { span: 12 },
},
};
const loadMoreDom = list.length > 0 && (
<div style={{ textAlign: 'center', marginTop: 16 }}>
<Button onClick={loadMore} style={{ paddingLeft: 48, paddingRight: 48 }}>
{loadingMore ? (
<span>
<LoadingOutlined /> ...
</span>
) : (
'加载更多'
)}
</Button>
</div>
);
const ownerOptions = useMemo<DefaultOptionType[]>(
() =>
owners.map((item) => ({
label: item.name,
value: item.id,
})),
[],
);
return (
<>
<Card variant="borderless">
<Form
layout="inline"
form={form}
initialValues={{
owner: ['wjh', 'zxx'],
}}
onValuesChange={reload}
>
<StandardFormRow title="所属类目" block style={{ paddingBottom: 11 }}>
<FormItem name="category">
<TagSelect expandable>
{categoryOptions
.filter(
(
category,
): category is { value: string | number; label: string } =>
category.value !== undefined && category.value !== null,
)
.map((category) => (
<TagSelect.Option
value={category.value}
key={category.value}
>
{category.label}
</TagSelect.Option>
))}
</TagSelect>
</FormItem>
</StandardFormRow>
<StandardFormRow title="owner" grid>
<FormItem name="owner" noStyle>
<Select
mode="multiple"
placeholder="选择 owner"
style={{ minWidth: '6rem' }}
options={ownerOptions}
/>
</FormItem>
<a className={styles.selfTrigger} onClick={setOwner}>
</a>
</StandardFormRow>
<StandardFormRow title="其它选项" grid last>
<Row gutter={16}>
<Col xl={8} lg={10} md={12} sm={24} xs={24}>
<FormItem {...formItemLayout} label="活跃用户" name="user">
<Select
placeholder="不限"
style={{ maxWidth: 200, width: '100%' }}
options={[
{
label: '李三',
value: 'lisa',
},
]}
/>
</FormItem>
</Col>
<Col xl={8} lg={10} md={12} sm={24} xs={24}>
<FormItem {...formItemLayout} label="好评度" name="rate">
<Select
placeholder="不限"
style={{ maxWidth: 200, width: '100%' }}
options={[
{
label: '优秀',
value: 'good',
},
]}
/>
</FormItem>
</Col>
</Row>
</StandardFormRow>
</Form>
</Card>
<Card
style={{ marginTop: 24 }}
variant="borderless"
styles={{
body: {
padding: '8px 32px 32px 32px',
},
}}
>
<List<ListItemDataType>
size="large"
loading={loading}
rowKey="id"
itemLayout="vertical"
loadMore={loadMoreDom}
dataSource={list}
renderItem={(item) => (
<List.Item
key={item.id}
actions={[
<IconText key="star" type="star-o" text={item.star} />,
<IconText key="like" type="like-o" text={item.like} />,
<IconText key="message" type="message" text={item.message} />,
]}
extra={<div className={styles.listItemExtra} />}
>
<List.Item.Meta
title={
<a className={styles.listItemMetaTitle} href={item.href}>
{item.title}
</a>
}
description={
<span>
<Tag>Ant Design</Tag>
<Tag></Tag>
<Tag></Tag>
</span>
}
/>
<ArticleListContent data={item} />
</List.Item>
)}
/>
</Card>
</>
);
};
export default Articles;

176
src/pages/list/search/projects/index.tsx

@ -1,176 +0,0 @@
import { useRequest } from '@umijs/max';
import { Card, Col, Form, List, Row, Select, Typography } from 'antd';
import dayjs from 'dayjs';
import relativeTime from 'dayjs/plugin/relativeTime';
import type { FC } from 'react';
import { categoryOptions } from '../../mock';
import AvatarList from './components/AvatarList';
import StandardFormRow from './components/StandardFormRow';
import TagSelect from './components/TagSelect';
import type { ListItemDataType } from './data.d';
import { queryFakeList } from './service';
import useStyles from './style.style';
dayjs.extend(relativeTime);
const FormItem = Form.Item;
const { Paragraph } = Typography;
const getKey = (id: string, index: number) => `${id}-${index}`;
const Projects: FC = () => {
const { styles } = useStyles();
const { data, loading, run } = useRequest((values: any) => {
console.log('form data', values);
return queryFakeList({
count: 8,
});
});
const list = data?.list || [];
const cardList = list && (
<List<ListItemDataType>
rowKey="id"
loading={loading}
grid={{
gutter: 16,
xs: 1,
sm: 2,
md: 3,
lg: 3,
xl: 4,
xxl: 4,
}}
dataSource={list}
renderItem={(item) => (
<List.Item>
<Card
className={styles.card}
hoverable
cover={<img alt={item.title} src={item.cover} />}
>
<Card.Meta
title={<a>{item.title}</a>}
description={
<Paragraph
ellipsis={{
rows: 2,
}}
>
{item.subDescription}
</Paragraph>
}
/>
<div className={styles.cardItemContent}>
<span>{dayjs(item.updatedAt).fromNow()}</span>
<div className={styles.avatarList}>
<AvatarList size="small">
{item.members.map((member, i) => (
<AvatarList.Item
key={getKey(item.id, i)}
src={member.avatar}
tips={member.name}
/>
))}
</AvatarList>
</div>
</div>
</Card>
</List.Item>
)}
/>
);
const formItemLayout = {
wrapperCol: {
xs: {
span: 24,
},
sm: {
span: 16,
},
},
};
return (
<div className={styles.coverCardList}>
<Card variant="borderless">
<Form
layout="inline"
onValuesChange={(_, values) => {
// 表单项变化时请求数据
// 模拟查询表单生效
run(values);
}}
>
<StandardFormRow
title="所属类目"
block
style={{
paddingBottom: 11,
}}
>
<FormItem name="category">
<TagSelect expandable>
{categoryOptions
.filter(
(
category,
): category is { value: string | number; label: string } =>
category.value !== undefined && category.value !== null,
)
.map((category) => (
<TagSelect.Option
value={category.value}
key={category.value}
>
{category.label}
</TagSelect.Option>
))}
</TagSelect>
</FormItem>
</StandardFormRow>
<StandardFormRow title="其它选项" grid last>
<Row gutter={16}>
<Col lg={8} md={10} sm={10} xs={24}>
<FormItem {...formItemLayout} label="作者" name="author">
<Select
placeholder="不限"
style={{
maxWidth: 200,
width: '100%',
}}
options={[
{
label: '王昭君',
value: 'lisa',
},
]}
/>
</FormItem>
</Col>
<Col lg={8} md={10} sm={10} xs={24}>
<FormItem {...formItemLayout} label="好评度" name="rate">
<Select
placeholder="不限"
style={{
maxWidth: 200,
width: '100%',
}}
options={[
{
label: '优秀',
value: 'good',
},
{
label: '普通',
value: 'normal',
},
]}
/>
</FormItem>
</Col>
</Row>
</StandardFormRow>
</Form>
</Card>
<div className={styles.cardList}>{cardList}</div>
</div>
);
};
export default Projects;

26
src/pages/list/table-list/components/CreateForm.tsx

@ -1,26 +0,0 @@
import { Modal } from 'antd';
import React from 'react';
type CreateFormProps = {
modalVisible: boolean;
children?: React.ReactNode;
onCancel: () => void;
};
const CreateForm: React.FC<CreateFormProps> = (props) => {
const { modalVisible, onCancel } = props;
return (
<Modal
destroyOnHidden
title="新建规则"
open={modalVisible}
onCancel={() => onCancel()}
footer={null}
>
{props.children}
</Modal>
);
};
export default CreateForm;

161
src/pages/list/table-list/components/UpdateForm.tsx

@ -1,161 +0,0 @@
import {
ProFormDateTimePicker,
ProFormRadio,
ProFormSelect,
ProFormText,
ProFormTextArea,
StepsForm,
} from '@ant-design/pro-components';
import { Modal } from 'antd';
import React from 'react';
import type { TableListItem } from '../data';
export type FormValueType = {
target?: string;
template?: string;
type?: string;
time?: string;
frequency?: string;
} & Partial<TableListItem>;
export type UpdateFormProps = {
onCancel: (flag?: boolean, formVals?: FormValueType) => void;
onSubmit: (values: FormValueType) => Promise<void>;
updateModalVisible: boolean;
values: Partial<TableListItem>;
};
const UpdateForm: React.FC<UpdateFormProps> = (props) => {
return (
<StepsForm
stepsProps={{
size: 'small',
}}
stepsFormRender={(dom, submitter) => {
return (
<Modal
width={640}
styles={{
body: {
padding: '32px 40px 48px',
},
}}
destroyOnHidden
title="规则配置"
open={props.updateModalVisible}
footer={submitter}
onCancel={() => {
props.onCancel();
}}
>
{dom}
</Modal>
);
}}
onFinish={props.onSubmit}
>
<StepsForm.StepForm
initialValues={{
name: props.values.name,
desc: props.values.desc,
}}
title="基本信息"
>
<ProFormText
name="name"
label="规则名称"
width="md"
rules={[
{
required: true,
message: '请输入规则名称!',
},
]}
/>
<ProFormTextArea
name="desc"
width="md"
label="规则描述"
placeholder="请输入至少五个字符"
rules={[
{
required: true,
message: '请输入至少五个字符的规则描述!',
min: 5,
},
]}
/>
</StepsForm.StepForm>
<StepsForm.StepForm
initialValues={{
target: '0',
template: '0',
}}
title="配置规则属性"
>
<ProFormSelect
name="target"
width="md"
label="监控对象"
valueEnum={{
0: '表一',
1: '表二',
}}
/>
<ProFormSelect
name="template"
width="md"
label="规则模板"
valueEnum={{
0: '规则模板一',
1: '规则模板二',
}}
/>
<ProFormRadio.Group
name="type"
label="规则类型"
options={[
{
value: '0',
label: '强',
},
{
value: '1',
label: '弱',
},
]}
/>
</StepsForm.StepForm>
<StepsForm.StepForm
initialValues={{
type: '1',
frequency: 'month',
}}
title="设定调度周期"
>
<ProFormDateTimePicker
name="time"
width="md"
label="开始时间"
rules={[
{
required: true,
message: '请选择开始时间!',
},
]}
/>
<ProFormSelect
name="frequency"
label="监控对象"
width="md"
valueEnum={{
month: '月',
week: '周',
}}
/>
</StepsForm.StepForm>
</StepsForm>
);
};
export default UpdateForm;

493
src/pages/profile/advanced/index.tsx

@ -1,493 +0,0 @@
import {
DingdingOutlined,
DownOutlined,
EllipsisOutlined,
InfoCircleOutlined,
} from '@ant-design/icons';
import {
GridContent,
PageContainer,
RouteContext,
} from '@ant-design/pro-components';
import { useRequest } from '@umijs/max';
import {
Badge,
Button,
Card,
Descriptions,
Divider,
Dropdown,
Empty,
Popover,
Space,
Statistic,
Steps,
Table,
Tooltip,
} from 'antd';
import classNames from 'classnames';
import type { FC } from 'react';
import React, { useState } from 'react';
import type { AdvancedProfileData } from './data.d';
import { queryAdvancedProfile } from './service';
import useStyles from './style.style';
const { Step } = Steps;
const action = (
<RouteContext.Consumer>
{({ isMobile }) => {
if (isMobile) {
return (
<Dropdown.Button
type="primary"
icon={<DownOutlined />}
menu={{
items: [
{
key: '1',
label: '操作一',
},
{
key: '2',
label: '操作二',
},
{
key: '3',
label: '操作三',
},
],
}}
placement="bottomRight"
>
</Dropdown.Button>
);
}
return (
<Space>
<Space.Compact>
<Button></Button>
<Button></Button>
<Dropdown
menu={{
items: [
{
key: '1',
label: '选项一',
},
{
key: '2',
label: '选项二',
},
{
key: '3',
label: '选项三',
},
],
}}
placement="bottomRight"
>
<Button>
<EllipsisOutlined />
</Button>
</Dropdown>
</Space.Compact>
<Button type="primary"></Button>
</Space>
);
}}
</RouteContext.Consumer>
);
const operationTabList = [
{
key: 'tab1',
tab: '操作日志一',
},
{
key: 'tab2',
tab: '操作日志二',
},
{
key: 'tab3',
tab: '操作日志三',
},
];
const columns = [
{
title: '操作类型',
dataIndex: 'type',
key: 'type',
},
{
title: '操作人',
dataIndex: 'name',
key: 'name',
},
{
title: '执行结果',
dataIndex: 'status',
key: 'status',
render: (text: string) => {
if (text === 'agree') {
return <Badge status="success" text="成功" />;
}
return <Badge status="error" text="驳回" />;
},
},
{
title: '操作时间',
dataIndex: 'updatedAt',
key: 'updatedAt',
},
{
title: '备注',
dataIndex: 'memo',
key: 'memo',
},
];
type AdvancedState = {
operationKey: 'tab1' | 'tab2' | 'tab3';
tabActiveKey: string;
};
const Advanced: FC = () => {
const { styles } = useStyles();
const extra = (
<div className={styles.moreInfo}>
<Statistic title="状态" value="待审批" />
<Statistic title="订单金额" value={568.08} prefix="¥" />
</div>
);
const description = (
<RouteContext.Consumer>
{({ isMobile }) => (
<Descriptions
className={styles.headerList}
size="small"
column={isMobile ? 1 : 2}
>
<Descriptions.Item label="创建人"></Descriptions.Item>
<Descriptions.Item label="订购产品">XX </Descriptions.Item>
<Descriptions.Item label="创建时间">2017-07-07</Descriptions.Item>
<Descriptions.Item label="关联单据">
<a href="">12421</a>
</Descriptions.Item>
<Descriptions.Item label="生效日期">
2017-07-07 ~ 2017-08-08
</Descriptions.Item>
<Descriptions.Item label="备注">
</Descriptions.Item>
</Descriptions>
)}
</RouteContext.Consumer>
);
const desc1 = (
<div className={classNames(styles.stepDescription)}>
<DingdingOutlined
style={{
marginLeft: 8,
}}
/>
<div>2016-12-12 12:32</div>
</div>
);
const desc2 = (
<div className={styles.stepDescription}>
<DingdingOutlined
style={{
color: '#00A0E9',
marginLeft: 8,
}}
/>
<div>
<a href=""></a>
</div>
</div>
);
const [tabStatus, seTabStatus] = useState<AdvancedState>({
operationKey: 'tab1',
tabActiveKey: 'detail',
});
const customDot = (
dot: React.ReactNode,
{
status,
}: {
status: string;
},
) => {
const popoverContent = (
<div
style={{
width: 160,
}}
>
<span
style={{
float: 'right',
}}
>
<Badge
status="default"
text={
<span
style={{
color: 'rgba(0, 0, 0, 0.45)',
}}
>
</span>
}
/>
</span>
<div
style={{
marginTop: 4,
}}
>
225
</div>
</div>
);
if (status === 'process') {
return (
<Popover
placement="topLeft"
arrow={{
pointAtCenter: true,
}}
content={popoverContent}
>
<span>{dot}</span>
</Popover>
);
}
return dot;
};
const { data = {}, loading } = useRequest<{
data: AdvancedProfileData;
}>(queryAdvancedProfile);
const { advancedOperation1, advancedOperation2, advancedOperation3 } = data;
const contentList = {
tab1: (
<Table
pagination={false}
loading={loading}
dataSource={advancedOperation1}
columns={columns}
/>
),
tab2: (
<Table
pagination={false}
loading={loading}
dataSource={advancedOperation2}
columns={columns}
/>
),
tab3: (
<Table
pagination={false}
loading={loading}
dataSource={advancedOperation3}
columns={columns}
/>
),
};
const onTabChange = (tabActiveKey: string) => {
seTabStatus({
...tabStatus,
tabActiveKey,
});
};
const onOperationTabChange = (key: string) => {
seTabStatus({
...tabStatus,
operationKey: key as 'tab1',
});
};
return (
<PageContainer
title="单号:234231029431"
extra={action}
className={styles.pageHeader}
content={description}
extraContent={extra}
tabActiveKey={tabStatus.tabActiveKey}
onTabChange={onTabChange}
tabList={[
{
key: 'detail',
tab: '详情',
},
{
key: 'rule',
tab: '规则',
},
]}
>
<div className={styles.main}>
<GridContent>
<Card
title="流程进度"
style={{
marginBottom: 24,
}}
>
<RouteContext.Consumer>
{({ isMobile }) => (
<Steps
direction={isMobile ? 'vertical' : 'horizontal'}
progressDot={customDot}
current={1}
>
<Step title="创建项目" description={desc1} />
<Step title="部门初审" description={desc2} />
<Step title="财务复核" />
<Step title="完成" />
</Steps>
)}
</RouteContext.Consumer>
</Card>
<Card
title="用户信息"
style={{
marginBottom: 24,
}}
variant="borderless"
>
<Descriptions
style={{
marginBottom: 24,
}}
>
<Descriptions.Item label="用户姓名"></Descriptions.Item>
<Descriptions.Item label="会员卡号">
32943898021309809423
</Descriptions.Item>
<Descriptions.Item label="身份证">
3321944288191034921
</Descriptions.Item>
<Descriptions.Item label="联系方式">
18112345678
</Descriptions.Item>
<Descriptions.Item label="联系地址">
18100000000 西
</Descriptions.Item>
</Descriptions>
<Descriptions
style={{
marginBottom: 24,
}}
title="信息组"
>
<Descriptions.Item label="某某数据">725</Descriptions.Item>
<Descriptions.Item label="该数据更新时间">
2017-08-08
</Descriptions.Item>
<Descriptions.Item
label={
<span>
<Tooltip title="数据说明">
<InfoCircleOutlined
style={{
color: 'rgba(0, 0, 0, 0.43)',
marginLeft: 4,
}}
/>
</Tooltip>
</span>
}
>
725
</Descriptions.Item>
<Descriptions.Item label="该数据更新时间">
2017-08-08
</Descriptions.Item>
</Descriptions>
<h4
style={{
marginBottom: 16,
}}
>
</h4>
<Card type="inner" title="多层级信息组">
<Descriptions
style={{
marginBottom: 16,
}}
title="组名称"
>
<Descriptions.Item label="负责人"></Descriptions.Item>
<Descriptions.Item label="角色码">1234567</Descriptions.Item>
<Descriptions.Item label="所属部门">
XX公司 - YY部
</Descriptions.Item>
<Descriptions.Item label="过期时间">
2017-08-08
</Descriptions.Item>
<Descriptions.Item label="描述">
...
</Descriptions.Item>
</Descriptions>
<Divider
style={{
margin: '16px 0',
}}
/>
<Descriptions
style={{
marginBottom: 16,
}}
title="组名称"
column={1}
>
<Descriptions.Item label="学名">
Citrullus lanatus (Thunb.) Matsum. et
Nakai一年生蔓生藤本..
</Descriptions.Item>
</Descriptions>
<Divider
style={{
margin: '16px 0',
}}
/>
<Descriptions title="组名称">
<Descriptions.Item label="负责人"></Descriptions.Item>
<Descriptions.Item label="角色码">1234568</Descriptions.Item>
</Descriptions>
</Card>
</Card>
<Card
title="用户近半年来电记录"
style={{
marginBottom: 24,
}}
variant="borderless"
>
<Empty />
</Card>
<Card
variant="borderless"
tabList={operationTabList}
onTabChange={onOperationTabChange}
>
{contentList[tabStatus.operationKey] as React.ReactNode}
</Card>
</GridContent>
</div>
</PageContainer>
);
};
export default Advanced;

236
src/pages/profile/basic/index.tsx

@ -1,236 +0,0 @@
import type { ProColumns } from '@ant-design/pro-components';
import { PageContainer, ProTable } from '@ant-design/pro-components';
import { useRequest } from '@umijs/max';
import { Badge, Card, Descriptions, Divider } from 'antd';
import type { FC } from 'react';
import React from 'react';
import type { BasicGood, BasicProgress } from './data.d';
import { queryBasicProfile } from './service';
import useStyles from './style.style';
const progressColumns: ProColumns<BasicProgress>[] = [
{
title: '时间',
dataIndex: 'time',
key: 'time',
},
{
title: '当前进度',
dataIndex: 'rate',
key: 'rate',
},
{
title: '状态',
dataIndex: 'status',
key: 'status',
render: (text: React.ReactNode) => {
if (text === 'success') {
return <Badge status="success" text="成功" />;
}
return <Badge status="processing" text="进行中" />;
},
},
{
title: '操作员ID',
dataIndex: 'operator',
key: 'operator',
},
{
title: '耗时',
dataIndex: 'cost',
key: 'cost',
},
];
const Basic: FC = () => {
const { styles } = useStyles();
const { data, loading } = useRequest(() => {
return queryBasicProfile();
});
const { basicGoods, basicProgress } = data || {
basicGoods: [],
basicProgress: [],
};
let goodsData: typeof basicGoods = [];
if (basicGoods.length) {
let num = 0;
let amount = 0;
basicGoods.forEach((item) => {
num += Number(item.num);
amount += Number(item.amount);
});
goodsData = basicGoods.concat({
id: '总计',
num,
amount,
});
}
const renderContent = (value: any, _: any, index: any) => {
const obj: {
children: any;
props: {
colSpan?: number;
};
} = {
children: value,
props: {},
};
if (index === basicGoods.length) {
obj.props.colSpan = 0;
}
return obj;
};
const goodsColumns: ProColumns<BasicGood>[] = [
{
title: '商品编号',
dataIndex: 'id',
key: 'id',
render: (text: React.ReactNode, _: any, index: number) => {
if (index < basicGoods.length) {
return <span>{text}</span>;
}
return {
children: (
<span
style={{
fontWeight: 600,
}}
>
</span>
),
props: {
colSpan: 4,
},
};
},
},
{
title: '商品名称',
dataIndex: 'name',
key: 'name',
render: renderContent,
},
{
title: '商品条码',
dataIndex: 'barcode',
key: 'barcode',
render: renderContent,
},
{
title: '单价',
dataIndex: 'price',
key: 'price',
align: 'right' as 'left' | 'right' | 'center',
render: renderContent,
},
{
title: '数量(件)',
dataIndex: 'num',
key: 'num',
align: 'right' as 'left' | 'right' | 'center',
render: (text: React.ReactNode, _: any, index: number) => {
if (index < basicGoods.length) {
return text;
}
return (
<span
style={{
fontWeight: 600,
}}
>
{text}
</span>
);
},
},
{
title: '金额',
dataIndex: 'amount',
key: 'amount',
align: 'right' as 'left' | 'right' | 'center',
render: (text: React.ReactNode, _: any, index: number) => {
if (index < basicGoods.length) {
return text;
}
return (
<span
style={{
fontWeight: 600,
}}
>
{text}
</span>
);
},
},
];
return (
<PageContainer>
<Card variant="borderless">
<Descriptions
title="退款申请"
style={{
marginBottom: 32,
}}
>
<Descriptions.Item label="取货单号">1000000000</Descriptions.Item>
<Descriptions.Item label="状态"></Descriptions.Item>
<Descriptions.Item label="销售单号">1234123421</Descriptions.Item>
<Descriptions.Item label="子订单">3214321432</Descriptions.Item>
</Descriptions>
<Divider
style={{
marginBottom: 32,
}}
/>
<Descriptions
title="用户信息"
style={{
marginBottom: 32,
}}
>
<Descriptions.Item label="用户姓名"></Descriptions.Item>
<Descriptions.Item label="联系电话">18100000000</Descriptions.Item>
<Descriptions.Item label="常用快递"></Descriptions.Item>
<Descriptions.Item label="取货地址">
西18
</Descriptions.Item>
<Descriptions.Item label="备注"></Descriptions.Item>
</Descriptions>
<Divider
style={{
marginBottom: 32,
}}
/>
<div className={styles.title}>退</div>
<ProTable
style={{
marginBottom: 24,
}}
pagination={false}
search={false}
loading={loading}
options={false}
toolBarRender={false}
dataSource={goodsData}
columns={goodsColumns}
rowKey="id"
/>
<div className={styles.title}>退</div>
<ProTable
style={{
marginBottom: 16,
}}
pagination={false}
loading={loading}
search={false}
options={false}
toolBarRender={false}
dataSource={basicProgress}
columns={progressColumns}
/>
</Card>
</PageContainer>
);
};
export default Basic;

75
src/pages/result/fail/index.tsx

@ -1,75 +0,0 @@
import { CloseCircleOutlined, RightOutlined } from '@ant-design/icons';
import { GridContent } from '@ant-design/pro-components';
import { Button, Card, Result } from 'antd';
import useStyles from './index.style';
export default () => {
const { styles } = useStyles();
const Content = (
<>
<div className={styles.title}>
<span></span>
</div>
<div
style={{
marginBottom: 16,
}}
>
<CloseCircleOutlined
style={{
marginRight: 8,
}}
className={styles.error_icon}
/>
<span></span>
<a
style={{
marginLeft: 16,
}}
>
<span></span>
<RightOutlined />
</a>
</div>
<div>
<CloseCircleOutlined
style={{
marginRight: 8,
}}
className={styles.error_icon}
/>
<span></span>
<a
style={{
marginLeft: 16,
}}
>
<span></span>
<RightOutlined />
</a>
</div>
</>
);
return (
<GridContent>
<Card variant="borderless">
<Result
status="error"
title="提交失败"
subTitle="请核对并修改以下信息后,再重新提交。"
extra={
<Button type="primary">
<span></span>
</Button>
}
style={{
marginTop: 48,
marginBottom: 16,
}}
>
{Content}
</Result>
</Card>
</GridContent>
);
};

137
src/pages/result/success/index.tsx

@ -1,137 +0,0 @@
import { DingdingOutlined } from '@ant-design/icons';
import { GridContent } from '@ant-design/pro-components';
import { Button, Card, Descriptions, Result, Steps } from 'antd';
import useStyles from './index.style';
const { Step } = Steps;
export default () => {
const { styles } = useStyles();
const desc1 = (
<div className={styles.title}>
<div
style={{
margin: '8px 0 4px',
}}
>
<span></span>
<DingdingOutlined
style={{
marginLeft: 8,
color: '#00A0E9',
}}
/>
</div>
<div>2016-12-12 12:32</div>
</div>
);
const desc2 = (
<div
style={{
fontSize: 12,
}}
className={styles.title}
>
<div
style={{
margin: '8px 0 4px',
}}
>
<span></span>
<a href="">
<DingdingOutlined
style={{
color: '#00A0E9',
marginLeft: 8,
}}
/>
<span></span>
</a>
</div>
</div>
);
const content = (
<>
<Descriptions title="项目名称">
<Descriptions.Item label="项目 ID">23421</Descriptions.Item>
<Descriptions.Item label="负责人"></Descriptions.Item>
<Descriptions.Item label="生效时间">
2016-12-12 ~ 2017-12-12
</Descriptions.Item>
</Descriptions>
<br />
<Steps progressDot current={1}>
<Step
title={
<span
style={{
fontSize: 14,
}}
>
</span>
}
description={desc1}
/>
<Step
title={
<span
style={{
fontSize: 14,
}}
>
</span>
}
description={desc2}
/>
<Step
title={
<span
style={{
fontSize: 14,
}}
>
</span>
}
/>
<Step
title={
<span
style={{
fontSize: 14,
}}
>
</span>
}
/>
</Steps>
</>
);
const extra = (
<>
<Button type="primary"></Button>
<Button></Button>
<Button></Button>
</>
);
return (
<GridContent>
<Card variant="borderless">
<Result
status="success"
title="提交成功"
subTitle="提交结果页用于反馈一系列操作任务的处理结果, 如果仅是简单操作,使用 Message 全局提示反馈即可。 本文字区域可以展示简单的补充说明,如果有类似展示 “单据”的需求,下面这个灰色区域可以呈现比较复杂的内容。"
extra={extra}
style={{
marginBottom: 16,
}}
>
{content}
</Result>
</Card>
</GridContent>
);
};

309
src/pages/user/register/index.tsx

@ -1,309 +0,0 @@
import { history, Link, useRequest } from '@umijs/max';
import {
Button,
Col,
Form,
Input,
message,
Popover,
Progress,
Row,
Select,
Space,
} from 'antd';
import type { Store } from 'antd/es/form/interface';
import type { FC } from 'react';
import { useEffect, useState } from 'react';
import type { StateType } from './service';
import { fakeRegister } from './service';
import useStyles from './styles';
const FormItem = Form.Item;
const { Option } = Select;
const passwordProgressMap: {
ok: 'success';
pass: 'normal';
poor: 'exception';
} = {
ok: 'success',
pass: 'normal',
poor: 'exception',
};
const Register: FC = () => {
const { styles } = useStyles();
const [count, setCount]: [number, any] = useState(0);
const [open, setVisible]: [boolean, any] = useState(false);
const [prefix, setPrefix]: [string, any] = useState('86');
const [popover, setPopover]: [boolean, any] = useState(false);
const confirmDirty = false;
let interval: number | undefined;
const passwordStatusMap = {
ok: (
<div className={styles.success}>
<span></span>
</div>
),
pass: (
<div className={styles.warning}>
<span></span>
</div>
),
poor: (
<div className={styles.error}>
<span></span>
</div>
),
};
const [form] = Form.useForm();
useEffect(
() => () => {
clearInterval(interval);
},
[interval],
);
const onGetCaptcha = () => {
let counts = 59;
setCount(counts);
interval = window.setInterval(() => {
counts -= 1;
setCount(counts);
if (counts === 0) {
clearInterval(interval);
}
}, 1000);
};
const getPasswordStatus = () => {
const value = form.getFieldValue('password');
if (value && value.length > 9) {
return 'ok';
}
if (value && value.length > 5) {
return 'pass';
}
return 'poor';
};
const { loading: submitting, run: register } = useRequest<{
data: StateType;
}>(fakeRegister, {
manual: true,
onSuccess: (data, params) => {
if (data.status === 'ok') {
message.success('注册成功!');
history.push({
pathname: `/user/register-result?account=${params[0].email}`,
});
}
},
});
const onFinish = (values: Store) => {
register(values);
};
const checkConfirm = (_: any, value: string) => {
const promise = Promise;
if (value && value !== form.getFieldValue('password')) {
return promise.reject('两次输入的密码不匹配!');
}
return promise.resolve();
};
const checkPassword = (_: any, value: string) => {
const promise = Promise;
// 没有值的情况
if (!value) {
setVisible(!!value);
return promise.reject('请输入密码!');
}
// 有值的情况
if (!open) {
setVisible(!!value);
}
setPopover(!popover);
if (value.length < 6) {
return promise.reject('');
}
if (value && confirmDirty) {
form.validateFields(['confirm']);
}
return promise.resolve();
};
const changePrefix = (value: string) => {
setPrefix(value);
};
const renderPasswordProgress = () => {
const value = form.getFieldValue('password');
const passwordStatus = getPasswordStatus();
return value?.length ? (
<div
className={styles[`progress-${passwordStatus}` as keyof typeof styles]}
>
<Progress
status={passwordProgressMap[passwordStatus]}
size={6}
percent={value.length * 10 > 100 ? 100 : value.length * 10}
showInfo={false}
/>
</div>
) : null;
};
return (
<div className={styles.main}>
<h3></h3>
<Form form={form} name="UserRegister" onFinish={onFinish}>
<FormItem
name="email"
rules={[
{
required: true,
message: '请输入邮箱地址!',
},
{
type: 'email',
message: '邮箱地址格式错误!',
},
]}
>
<Input size="large" placeholder="邮箱" />
</FormItem>
<Popover
getPopupContainer={(node) => {
if (node?.parentNode) {
return node.parentNode as HTMLElement;
}
return node;
}}
content={
open && (
<div
style={{
padding: '4px 0',
}}
>
{passwordStatusMap[getPasswordStatus()]}
{renderPasswordProgress()}
<div
style={{
marginTop: 10,
}}
>
<span> 6 使</span>
</div>
</div>
)
}
overlayStyle={{
width: 240,
}}
placement="right"
open={open}
>
<FormItem
name="password"
className={
form.getFieldValue('password') &&
form.getFieldValue('password').length > 0 &&
styles.password
}
rules={[
{
validator: checkPassword,
},
]}
>
<Input
size="large"
type="password"
placeholder="至少6位密码,区分大小写"
/>
</FormItem>
</Popover>
<FormItem
name="confirm"
rules={[
{
required: true,
message: '确认密码',
},
{
validator: checkConfirm,
},
]}
>
<Input size="large" type="password" placeholder="确认密码" />
</FormItem>
<FormItem
name="mobile"
rules={[
{
required: true,
message: '请输入手机号!',
},
{
pattern: /^\d{11}$/,
message: '手机号格式错误!',
},
]}
>
<Space.Compact style={{ width: '100%' }}>
<Select
size="large"
value={prefix}
onChange={changePrefix}
style={{
width: '30%',
}}
>
<Option value="86">+86</Option>
<Option value="87">+87</Option>
</Select>
<Input size="large" placeholder="手机号" />
</Space.Compact>
</FormItem>
<Row gutter={8}>
<Col span={16}>
<FormItem
name="captcha"
rules={[
{
required: true,
message: '请输入验证码!',
},
]}
>
<Input size="large" placeholder="验证码" />
</FormItem>
</Col>
<Col span={8}>
<Button
size="large"
disabled={!!count}
className={styles.getCaptcha}
onClick={onGetCaptcha}
>
{count ? `${count} s` : '获取验证码'}
</Button>
</Col>
</Row>
<FormItem>
<div className={styles.footer}>
<Button
size="large"
loading={submitting}
className={styles.submit}
type="primary"
htmlType="submit"
>
<span></span>
</Button>
<Link to="/user/login">
<span>使</span>
</Link>
</div>
</FormItem>
</Form>
</div>
);
};
export default Register;
Loading…
Cancel
Save