Browse Source

chore: fix biome lint errors

pull/11501/head
afc163 9 months ago
parent
commit
eb51b87590
  1. 3
      biome.json
  2. 2
      package.json
  3. 6
      src/app.tsx
  4. 2
      src/components/HeaderDropdown/index.tsx
  5. 21
      src/pages/account/center/_mock.ts
  6. 5
      src/pages/account/center/components/Applications/index.tsx
  7. 7
      src/pages/account/center/components/Articles/index.tsx
  8. 20
      src/pages/account/center/components/AvatarList/index.tsx
  9. 12
      src/pages/account/center/components/Projects/index.tsx
  10. 46
      src/pages/account/center/index.tsx
  11. 3
      src/pages/account/settings/_mock.ts
  12. 27
      src/pages/account/settings/components/base.tsx
  13. 6
      src/pages/account/settings/components/binding.tsx
  14. 4
      src/pages/account/settings/components/notification.tsx
  15. 16
      src/pages/account/settings/components/security.tsx
  16. 10
      src/pages/account/settings/index.tsx
  17. 4
      src/pages/account/settings/service.ts
  18. 2
      src/pages/dashboard/analysis/_mock.ts
  19. 21
      src/pages/dashboard/analysis/components/Charts/ChartCard/index.tsx
  20. 6
      src/pages/dashboard/analysis/components/Charts/WaterWave/index.tsx
  21. 26
      src/pages/dashboard/analysis/components/IntroduceRow.tsx
  22. 11
      src/pages/dashboard/analysis/components/NumberInfo/index.tsx
  23. 15
      src/pages/dashboard/analysis/components/OfflineData.tsx
  24. 1
      src/pages/dashboard/analysis/components/ProportionSales.tsx
  25. 34
      src/pages/dashboard/analysis/components/SalesCard.tsx
  26. 10
      src/pages/dashboard/analysis/components/TopSearch.tsx
  27. 6
      src/pages/dashboard/analysis/components/Trend/index.tsx
  28. 113
      src/pages/dashboard/analysis/index.tsx
  29. 9
      src/pages/dashboard/analysis/utils/utils.ts
  30. 10
      src/pages/dashboard/monitor/components/ActiveChart/index.style.ts
  31. 13
      src/pages/dashboard/monitor/components/ActiveChart/index.tsx
  32. 6
      src/pages/dashboard/monitor/components/Charts/WaterWave/index.tsx
  33. 4
      src/pages/dashboard/monitor/components/Charts/autoHeight.tsx
  34. 10
      src/pages/dashboard/monitor/components/Map/index.tsx
  35. 295
      src/pages/dashboard/monitor/index.tsx
  36. 2
      src/pages/dashboard/workplace/_mock.ts
  37. 20
      src/pages/dashboard/workplace/index.tsx
  38. 28
      src/pages/dashboard/workplace/style.style.ts
  39. 24
      src/pages/form/advanced-form/components/TableForm.tsx
  40. 15
      src/pages/form/advanced-form/index.tsx
  41. 4
      src/pages/form/basic-form/index.tsx
  42. 11
      src/pages/form/step-form/index.tsx
  43. 18
      src/pages/list/basic-list/_mock.ts
  44. 1
      src/pages/list/basic-list/components/OperationModal.tsx
  45. 27
      src/pages/list/basic-list/index.tsx
  46. 17
      src/pages/list/basic-list/style.style.ts
  47. 18
      src/pages/list/card-list/_mock.ts
  48. 32
      src/pages/list/card-list/index.tsx
  49. 18
      src/pages/list/search/applications/_mock.ts
  50. 1
      src/pages/list/search/applications/components/StandardFormRow/index.tsx
  51. 47
      src/pages/list/search/applications/components/TagSelect/index.tsx
  52. 28
      src/pages/list/search/applications/index.tsx
  53. 18
      src/pages/list/search/articles/_mock.ts
  54. 1
      src/pages/list/search/articles/components/ArticleListContent/index.tsx
  55. 1
      src/pages/list/search/articles/components/StandardFormRow/index.tsx
  56. 47
      src/pages/list/search/articles/components/TagSelect/index.tsx
  57. 20
      src/pages/list/search/articles/index.tsx
  58. 8
      src/pages/list/search/index.tsx
  59. 18
      src/pages/list/search/projects/_mock.ts
  60. 20
      src/pages/list/search/projects/components/AvatarList/index.tsx
  61. 1
      src/pages/list/search/projects/components/StandardFormRow/index.tsx
  62. 47
      src/pages/list/search/projects/components/TagSelect/index.tsx
  63. 17
      src/pages/list/search/projects/index.tsx
  64. 22
      src/pages/list/table-list/_mock.ts
  65. 22
      src/pages/list/table-list/index.tsx
  66. 15
      src/pages/list/table-list/service.ts
  67. 60
      src/pages/profile/advanced/index.tsx
  68. 5
      src/pages/profile/basic/index.tsx
  69. 4
      src/pages/result/success/index.tsx
  70. 9
      src/pages/table-list/components/CreateForm.tsx
  71. 4
      src/pages/table-list/components/UpdateForm.tsx
  72. 17
      src/pages/table-list/index.tsx
  73. 19
      src/pages/user/register/index.tsx

3
biome.json

@ -28,6 +28,9 @@
"suspicious": { "suspicious": {
"noExplicitAny": "off" "noExplicitAny": "off"
}, },
"correctness": {
"useExhaustiveDependencies": "off"
},
"a11y": { "a11y": {
"noStaticElementInteractions": "off", "noStaticElementInteractions": "off",
"useValidAnchor": "off", "useValidAnchor": "off",

2
package.json

@ -108,4 +108,4 @@
"create-umi" "create-umi"
] ]
} }
} }

6
src/app.tsx

@ -41,7 +41,11 @@ export async function getInitialState(): Promise<{
}; };
// 如果不是登录页面,执行 // 如果不是登录页面,执行
const { location } = history; const { location } = history;
if (![loginPath, '/user/register', '/user/register-result'].includes(location.pathname)) { if (
![loginPath, '/user/register', '/user/register-result'].includes(
location.pathname,
)
) {
const currentUser = await fetchUserInfo(); const currentUser = await fetchUserInfo();
return { return {
fetchUserInfo, fetchUserInfo,

2
src/components/HeaderDropdown/index.tsx

@ -1,6 +1,6 @@
import { Dropdown } from 'antd'; import { Dropdown } from 'antd';
import { createStyles } from 'antd-style';
import type { DropDownProps } from 'antd/es/dropdown'; import type { DropDownProps } from 'antd/es/dropdown';
import { createStyles } from 'antd-style';
import classNames from 'classnames'; import classNames from 'classnames';
import React from 'react'; import React from 'react';

21
src/pages/account/center/_mock.ts

@ -52,7 +52,8 @@ const user = [
// 当前用户信息 // 当前用户信息
const currentUseDetail = { const currentUseDetail = {
name: 'Serati Ma', name: 'Serati Ma',
avatar: 'https://gw.alipayobjects.com/zos/antfincdn/XAosXuNZyF/BiazfanxmamNRoxxVxka.png', avatar:
'https://gw.alipayobjects.com/zos/antfincdn/XAosXuNZyF/BiazfanxmamNRoxxVxka.png',
userid: '00000001', userid: '00000001',
email: 'antdesign@alipay.com', email: 'antdesign@alipay.com',
signature: '海纳百川,有容乃大', signature: '海纳百川,有容乃大',
@ -171,7 +172,10 @@ function fakeList(count: number): ListItemDataType[] {
owner: user[i % 10], owner: user[i % 10],
title: titles[i % 8], title: titles[i % 8],
avatar: avatars[i % 8], avatar: avatars[i % 8],
cover: parseInt(`${i / 4}`, 10) % 2 === 0 ? covers[i % 4] : covers[3 - (i % 4)], cover:
parseInt(`${i / 4}`, 10) % 2 === 0
? covers[i % 4]
: covers[3 - (i % 4)],
status: ['active', 'exception', 'normal'][i % 3] as status: ['active', 'exception', 'normal'][i % 3] as
| 'normal' | 'normal'
| 'exception' | 'exception'
@ -180,8 +184,8 @@ function fakeList(count: number): ListItemDataType[] {
percent: Math.ceil(Math.random() * 50) + 50, percent: Math.ceil(Math.random() * 50) + 50,
logo: avatars[i % 8], logo: avatars[i % 8],
href: 'https://ant.design', href: 'https://ant.design',
updatedAt: new Date(Date.now()- 1000 * 60 * 60 * 2 * i).getTime(), updatedAt: new Date(Date.now() - 1000 * 60 * 60 * 2 * i).getTime(),
createdAt: new Date(Date.now()- 1000 * 60 * 60 * 2 * i).getTime(), createdAt: new Date(Date.now() - 1000 * 60 * 60 * 2 * i).getTime(),
subDescription: desc[i % 5], subDescription: desc[i % 5],
description: description:
'在中台产品的研发过程中,会出现不同的设计规范和实现方式,但其中往往存在很多类似的页面和组件,这些类似的组件会被抽离成一套标准规范。', '在中台产品的研发过程中,会出现不同的设计规范和实现方式,但其中往往存在很多类似的页面和组件,这些类似的组件会被抽离成一套标准规范。',
@ -194,17 +198,20 @@ function fakeList(count: number): ListItemDataType[] {
'段落示意:蚂蚁金服设计平台 ant.design,用最小的工作量,无缝接入蚂蚁金服生态,提供跨越设计与开发的体验解决方案。蚂蚁金服设计平台 ant.design,用最小的工作量,无缝接入蚂蚁金服生态,提供跨越设计与开发的体验解决方案。', '段落示意:蚂蚁金服设计平台 ant.design,用最小的工作量,无缝接入蚂蚁金服生态,提供跨越设计与开发的体验解决方案。蚂蚁金服设计平台 ant.design,用最小的工作量,无缝接入蚂蚁金服生态,提供跨越设计与开发的体验解决方案。',
members: [ members: [
{ {
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/ZiESqWwCXBRQoaPONSJe.png', avatar:
'https://gw.alipayobjects.com/zos/rmsportal/ZiESqWwCXBRQoaPONSJe.png',
name: '曲丽丽', name: '曲丽丽',
id: 'member1', id: 'member1',
}, },
{ {
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/tBOxZPlITHqwlGjsJWaF.png', avatar:
'https://gw.alipayobjects.com/zos/rmsportal/tBOxZPlITHqwlGjsJWaF.png',
name: '王昭君', name: '王昭君',
id: 'member2', id: 'member2',
}, },
{ {
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/sBxjgqiuHMGRkIjqlQCd.png', avatar:
'https://gw.alipayobjects.com/zos/rmsportal/sBxjgqiuHMGRkIjqlQCd.png',
name: '董娜娜', name: '董娜娜',
id: 'member3', id: 'member3',
}, },

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

@ -107,7 +107,10 @@ const Applications: React.FC = () => {
</Dropdown>, </Dropdown>,
]} ]}
> >
<Card.Meta avatar={<Avatar size="small" src={item.avatar} />} title={item.title} /> <Card.Meta
avatar={<Avatar size="small" src={item.avatar} />}
title={item.title}
/>
<div> <div>
<CardInfo <CardInfo
activeUser={formatWan(item.activeUser)} activeUser={formatWan(item.activeUser)}

7
src/pages/account/center/components/Articles/index.tsx

@ -6,6 +6,7 @@ import type { ListItemDataType } from '../../data.d';
import { queryFakeList } from '../../service'; import { queryFakeList } from '../../service';
import ArticleListContent from '../ArticleListContent'; import ArticleListContent from '../ArticleListContent';
import useStyles from './index.style'; import useStyles from './index.style';
const Articles: React.FC = () => { const Articles: React.FC = () => {
const { styles } = useStyles(); const { styles } = useStyles();
const IconText: React.FC<{ const IconText: React.FC<{
@ -36,7 +37,11 @@ const Articles: React.FC = () => {
actions={[ actions={[
<IconText key="star" icon={<StarTwoTone />} text={item.star} />, <IconText key="star" icon={<StarTwoTone />} text={item.star} />,
<IconText key="like" icon={<LikeOutlined />} text={item.like} />, <IconText key="like" icon={<LikeOutlined />} text={item.like} />,
<IconText key="message" icon={<MessageFilled />} text={item.message} />, <IconText
key="message"
icon={<MessageFilled />}
text={item.message}
/>,
]} ]}
> >
<List.Item.Meta <List.Item.Meta

20
src/pages/account/center/components/AvatarList/index.tsx

@ -16,9 +16,16 @@ export type AvatarListProps = {
maxLength?: number; maxLength?: number;
excessItemsStyle?: React.CSSProperties; excessItemsStyle?: React.CSSProperties;
style?: React.CSSProperties; style?: React.CSSProperties;
children: React.ReactElement<AvatarItemProps> | React.ReactElement<AvatarItemProps>[]; children:
| React.ReactElement<AvatarItemProps>
| React.ReactElement<AvatarItemProps>[];
}; };
const Item: React.FC<AvatarItemProps> = ({ src, size, tips, onClick = () => {} }) => { const Item: React.FC<AvatarItemProps> = ({
src,
size,
tips,
onClick = () => {},
}) => {
const { styles } = useStyles(); const { styles } = useStyles();
const avatarSizeToClassName = (size?: SizeType | 'mini') => const avatarSizeToClassName = (size?: SizeType | 'mini') =>
classNames(styles.avatarItem, { classNames(styles.avatarItem, {
@ -51,7 +58,9 @@ const AvatarList: React.FC<AvatarListProps> & {
const { styles } = useStyles(); const { styles } = useStyles();
const numOfChildren = React.Children.count(children); const numOfChildren = React.Children.count(children);
const numToShow = maxLength >= numOfChildren ? numOfChildren : maxLength; const numToShow = maxLength >= numOfChildren ? numOfChildren : maxLength;
const childrenArray = React.Children.toArray(children) as React.ReactElement<AvatarItemProps>[]; const childrenArray = React.Children.toArray(
children,
) as React.ReactElement<AvatarItemProps>[];
const childrenWithProps = childrenArray.slice(0, numToShow).map((child) => const childrenWithProps = childrenArray.slice(0, numToShow).map((child) =>
React.cloneElement(child, { React.cloneElement(child, {
size, size,
@ -61,7 +70,10 @@ const AvatarList: React.FC<AvatarListProps> & {
const cls = avatarSizeToClassName(size); const cls = avatarSizeToClassName(size);
childrenWithProps.push( childrenWithProps.push(
<li key="exceed" className={cls}> <li key="exceed" className={cls}>
<Avatar size={size} style={excessItemsStyle}>{`+${numOfChildren - maxLength}`}</Avatar> <Avatar
size={size}
style={excessItemsStyle}
>{`+${numOfChildren - maxLength}`}</Avatar>
</li>, </li>,
); );
} }

12
src/pages/account/center/components/Projects/index.tsx

@ -7,6 +7,7 @@ import type { ListItemDataType } from '../../data.d';
import { queryFakeList } from '../../service'; import { queryFakeList } from '../../service';
import AvatarList from '../AvatarList'; import AvatarList from '../AvatarList';
import useStyles from './index.style'; import useStyles from './index.style';
dayjs.extend(relativeTime); dayjs.extend(relativeTime);
const Projects: React.FC = () => { const Projects: React.FC = () => {
const { styles } = useStyles(); const { styles } = useStyles();
@ -32,8 +33,15 @@ const Projects: React.FC = () => {
dataSource={listData?.list || []} dataSource={listData?.list || []}
renderItem={(item) => ( renderItem={(item) => (
<List.Item> <List.Item>
<Card className={styles.card} hoverable cover={<img alt={item.title} src={item.cover} />}> <Card
<Card.Meta title={<a>{item.title}</a>} description={item.subDescription} /> className={styles.card}
hoverable
cover={<img alt={item.title} src={item.cover} />}
>
<Card.Meta
title={<a>{item.title}</a>}
description={item.subDescription}
/>
<div className={styles.cardItemContent}> <div className={styles.cardItemContent}>
<span>{dayjs(item.updatedAt).fromNow()}</span> <span>{dayjs(item.updatedAt).fromNow()}</span>
<div className={styles.avatarList}> <div className={styles.avatarList}>

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

@ -1,14 +1,29 @@
import { ClusterOutlined, ContactsOutlined, HomeOutlined, PlusOutlined } from '@ant-design/icons'; import {
ClusterOutlined,
ContactsOutlined,
HomeOutlined,
PlusOutlined,
} from '@ant-design/icons';
import { GridContent } from '@ant-design/pro-components'; import { GridContent } from '@ant-design/pro-components';
import { useRequest } from '@umijs/max'; import { useRequest } from '@umijs/max';
import { Avatar, Card, Col, Divider, Input, type InputRef, Row, Tag } from 'antd'; import {
Avatar,
Card,
Col,
Divider,
Input,
type InputRef,
Row,
Tag,
} from 'antd';
import React, { useRef, useState } from 'react'; import React, { useRef, useState } from 'react';
import useStyles from './Center.style'; import useStyles from './Center.style';
import Applications from './components/Applications'; import Applications from './components/Applications';
import Articles from './components/Articles'; import Articles from './components/Articles';
import Projects from './components/Projects'; import Projects from './components/Projects';
import type { CurrentUser, tabKeyType, TagType } from './data.d'; import type { CurrentUser, TagType, tabKeyType } from './data.d';
import { queryCurrent } from './service'; import { queryCurrent } from './service';
const operationTabList = [ const operationTabList = [
{ {
key: 'articles', key: 'articles',
@ -76,7 +91,10 @@ const TagList: React.FC<{
}; };
const handleInputConfirm = () => { const handleInputConfirm = () => {
let tempsTags = [...newTags]; let tempsTags = [...newTags];
if (inputValue && tempsTags.filter((tag) => tag.label === inputValue).length === 0) { if (
inputValue &&
tempsTags.filter((tag) => tag.label === inputValue).length === 0
) {
tempsTags = [ tempsTags = [
...tempsTags, ...tempsTags,
{ {
@ -132,7 +150,11 @@ const Center: React.FC = () => {
}); });
// 渲染用户信息 // 渲染用户信息
const renderUserInfo = ({ title, group, geographic }: Partial<CurrentUser>) => { const renderUserInfo = ({
title,
group,
geographic,
}: Partial<CurrentUser>) => {
return ( return (
<div className={styles.detail}> <div className={styles.detail}>
<p> <p>
@ -224,13 +246,13 @@ const Center: React.FC = () => {
<div className={styles.teamTitle}></div> <div className={styles.teamTitle}></div>
<Row gutter={36}> <Row gutter={36}>
{currentUser.notice?.map((item) => ( {currentUser.notice?.map((item) => (
<Col key={item.id} lg={24} xl={12}> <Col key={item.id} lg={24} xl={12}>
<a href={item.href}> <a href={item.href}>
<Avatar size="small" src={item.logo} /> <Avatar size="small" src={item.logo} />
{item.member} {item.member}
</a> </a>
</Col> </Col>
))} ))}
</Row> </Row>
</div> </div>
</div> </div>

3
src/pages/account/settings/_mock.ts

@ -19,7 +19,8 @@ function getCurrentUse(_req: Request, res: Response) {
return res.json({ return res.json({
data: { data: {
name: 'Serati Ma', name: 'Serati Ma',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png', avatar:
'https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png',
userid: '00000001', userid: '00000001',
email: 'antdesign@alipay.com', email: 'antdesign@alipay.com',
signature: '海纳百川,有容乃大', signature: '海纳百川,有容乃大',

27
src/pages/account/settings/components/base.tsx

@ -13,7 +13,11 @@ import React from 'react';
import { queryCity, queryCurrent, queryProvince } from '../service'; import { queryCity, queryCurrent, queryProvince } from '../service';
import useStyles from './index.style'; import useStyles from './index.style';
const validatorPhone = (_rule: any, value: string[], callback: (message?: string) => void) => { const validatorPhone = (
_rule: any,
value: string[],
callback: (message?: string) => void,
) => {
if (!value[0]) { if (!value[0]) {
callback('Please input your area code!'); callback('Please input your area code!');
} }
@ -50,7 +54,8 @@ const BaseView: React.FC = () => {
if (currentUser.avatar) { if (currentUser.avatar) {
return currentUser.avatar; return currentUser.avatar;
} }
const url = 'https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png'; const url =
'https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png';
return url; return url;
} }
return ''; return '';
@ -175,14 +180,16 @@ const BaseView: React.FC = () => {
if (!province?.key) { if (!province?.key) {
return []; return [];
} }
return queryCity(province.key || '').then(({ data }) => { return queryCity(province.key || '').then(
return data.map((item) => { ({ data }) => {
return { return data.map((item) => {
label: item.name, return {
value: item.id, label: item.name,
}; value: item.id,
}); };
}); });
},
);
}} }}
/> />
); );

6
src/pages/account/settings/components/binding.tsx

@ -1,4 +1,8 @@
import { AlipayOutlined, DingdingOutlined, TaobaoOutlined } from '@ant-design/icons'; import {
AlipayOutlined,
DingdingOutlined,
TaobaoOutlined,
} from '@ant-design/icons';
import { List } from 'antd'; import { List } from 'antd';
import React, { Fragment } from 'react'; import React, { Fragment } from 'react';

4
src/pages/account/settings/components/notification.tsx

@ -5,7 +5,9 @@ type Unpacked<T> = T extends (infer U)[] ? U : T;
const NotificationView: React.FC = () => { const NotificationView: React.FC = () => {
const getData = () => { const getData = () => {
const Action = <Switch checkedChildren="开" unCheckedChildren="关" defaultChecked />; const Action = (
<Switch checkedChildren="开" unCheckedChildren="关" defaultChecked />
);
return [ return [
{ {
title: '账户密码', title: '账户密码',

16
src/pages/account/settings/components/security.tsx

@ -46,14 +46,14 @@ const SecurityView: React.FC = () => {
const data = getData(); const data = getData();
return ( return (
<List<Unpacked<typeof data>> <List<Unpacked<typeof data>>
itemLayout="horizontal" itemLayout="horizontal"
dataSource={data} dataSource={data}
renderItem={(item) => ( renderItem={(item) => (
<List.Item actions={item.actions}> <List.Item actions={item.actions}>
<List.Item.Meta title={item.title} description={item.description} /> <List.Item.Meta title={item.title} description={item.description} />
</List.Item> </List.Item>
)} )}
/> />
); );
}; };

10
src/pages/account/settings/index.tsx

@ -6,6 +6,7 @@ import BindingView from './components/binding';
import NotificationView from './components/notification'; import NotificationView from './components/notification';
import SecurityView from './components/security'; import SecurityView from './components/security';
import useStyles from './style.style'; import useStyles from './style.style';
type SettingsStateKeys = 'base' | 'security' | 'binding' | 'notification'; type SettingsStateKeys = 'base' | 'security' | 'binding' | 'notification';
type SettingsState = { type SettingsState = {
mode: 'inline' | 'horizontal'; mode: 'inline' | 'horizontal';
@ -23,7 +24,7 @@ const Settings: React.FC = () => {
mode: 'inline', mode: 'inline',
selectKey: 'base', selectKey: 'base',
}); });
const dom = useRef<HTMLDivElement>(); const dom = useRef<HTMLDivElement>(null);
const resize = () => { const resize = () => {
requestAnimationFrame(() => { requestAnimationFrame(() => {
if (!dom.current) { if (!dom.current) {
@ -51,9 +52,12 @@ const Settings: React.FC = () => {
return () => { return () => {
window.removeEventListener('resize', resize); window.removeEventListener('resize', resize);
}; };
}, [resize]); }, []);
const getMenu = () => { const getMenu = () => {
return Object.keys(menuMap).map((item) => ({ key: item, label: menuMap[item] })); return Object.keys(menuMap).map((item) => ({
key: item,
label: menuMap[item],
}));
}; };
const renderChildren = () => { const renderChildren = () => {
const { selectKey } = initConfig; const { selectKey } = initConfig;

4
src/pages/account/settings/service.ts

@ -9,7 +9,9 @@ export async function queryProvince(): Promise<{ data: GeographicItemType[] }> {
return request('/api/geographic/province'); return request('/api/geographic/province');
} }
export async function queryCity(province: string): Promise<{ data: GeographicItemType[] }> { export async function queryCity(
province: string,
): Promise<{ data: GeographicItemType[] }> {
return request(`/api/geographic/city/${province}`); return request(`/api/geographic/city/${province}`);
} }

2
src/pages/dashboard/analysis/_mock.ts

@ -126,7 +126,7 @@ for (let i = 0; i < 10; i += 1) {
} }
const offlineChartData = []; const offlineChartData = [];
for (let i = 0; i < 20; i += 1) { for (let i = 0; i < 20; i += 1) {
const date = dayjs(Date.now()+ 1000 * 60 * 30 * i).format('HH:mm'); const date = dayjs(Date.now() + 1000 * 60 * 30 * i).format('HH:mm');
offlineChartData.push({ offlineChartData.push({
date, date,
type: '客流量', type: '客流量',

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

@ -4,6 +4,7 @@ import type { CardProps } from 'antd/es/card';
import classNames from 'classnames'; import classNames from 'classnames';
import React from 'react'; import React from 'react';
import useStyles from './index.style'; import useStyles from './index.style';
type totalType = () => React.ReactNode; type totalType = () => React.ReactNode;
export type ChartCardProps = { export type ChartCardProps = {
@ -36,7 +37,16 @@ const ChartCard: React.FC<ChartCardProps> = (props) => {
return totalDom; return totalDom;
}; };
const renderContent = () => { const renderContent = () => {
const { contentHeight, title, avatar, action, total, footer, children, loading } = props; const {
contentHeight,
title,
avatar,
action,
total,
footer,
children,
loading,
} = props;
if (loading) { if (loading) {
return false; return false;
} }
@ -63,7 +73,9 @@ const ChartCard: React.FC<ChartCardProps> = (props) => {
height: contentHeight || 'auto', height: contentHeight || 'auto',
}} }}
> >
<div className={contentHeight ? styles.contentFixed : undefined}>{children}</div> <div className={contentHeight ? styles.contentFixed : undefined}>
{children}
</div>
</div> </div>
)} )}
{footer && ( {footer && (
@ -79,10 +91,7 @@ const ChartCard: React.FC<ChartCardProps> = (props) => {
); );
}; };
const { const { loading = false, ...rest } = props;
loading = false,
...rest
} = props;
return ( return (
<Card <Card
loading={loading} loading={loading}

6
src/pages/dashboard/analysis/components/Charts/WaterWave/index.tsx

@ -87,7 +87,11 @@ class WaterWave extends Component<WaterWaveProps> {
const bR = radius - lineWidth; const bR = radius - lineWidth;
const circleOffset = -(Math.PI / 2); const circleOffset = -(Math.PI / 2);
let circleLock = true; let circleLock = true;
for (let i = circleOffset; i < circleOffset + 2 * Math.PI; i += 1 / (8 * Math.PI)) { for (
let i = circleOffset;
i < circleOffset + 2 * Math.PI;
i += 1 / (8 * Math.PI)
) {
arcStack.push([radius + bR * Math.cos(i), radius + bR * Math.sin(i)]); arcStack.push([radius + bR * Math.cos(i), radius + bR * Math.sin(i)]);
} }
const cStartPoint = arcStack.shift() as number[]; const cStartPoint = arcStack.shift() as number[];

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

@ -7,6 +7,7 @@ import useStyles from '../style.style';
import Yuan from '../utils/Yuan'; import Yuan from '../utils/Yuan';
import { ChartCard, Field } from './Charts'; import { ChartCard, Field } from './Charts';
import Trend from './Trend'; import Trend from './Trend';
const topColResponsiveProps = { const topColResponsiveProps = {
xs: 24, xs: 24,
sm: 12, sm: 12,
@ -17,7 +18,13 @@ const topColResponsiveProps = {
marginBottom: 24, marginBottom: 24,
}, },
}; };
const IntroduceRow = ({ loading, visitData }: { loading: boolean; visitData: DataItem[] }) => { const IntroduceRow = ({
loading,
visitData,
}: {
loading: boolean;
visitData: DataItem[];
}) => {
const { styles } = useStyles(); const { styles } = useStyles();
return ( return (
<Row gutter={24}> <Row gutter={24}>
@ -32,7 +39,12 @@ const IntroduceRow = ({ loading, visitData }: { loading: boolean; visitData: Dat
} }
loading={loading} loading={loading}
total={() => <Yuan>126560</Yuan>} total={() => <Yuan>126560</Yuan>}
footer={<Field label="日销售额" value={`${numeral(12423).format('0,0')}`} />} footer={
<Field
label="日销售额"
value={`${numeral(12423).format('0,0')}`}
/>
}
contentHeight={46} contentHeight={46}
> >
<Trend <Trend
@ -62,7 +74,9 @@ const IntroduceRow = ({ loading, visitData }: { loading: boolean; visitData: Dat
</Tooltip> </Tooltip>
} }
total={numeral(8846).format('0,0')} total={numeral(8846).format('0,0')}
footer={<Field label="日访问量" value={numeral(1234).format('0,0')} />} footer={
<Field label="日访问量" value={numeral(1234).format('0,0')} />
}
contentHeight={46} contentHeight={46}
> >
<Area <Area
@ -141,7 +155,11 @@ const IntroduceRow = ({ loading, visitData }: { loading: boolean; visitData: Dat
} }
contentHeight={46} contentHeight={46}
> >
<Progress percent={78} strokeColor={{ from: '#108ee9', to: '#87d068' }} status="active" /> <Progress
percent={78}
strokeColor={{ from: '#108ee9', to: '#87d068' }}
status="active"
/>
</ChartCard> </ChartCard>
</Col> </Col>
</Row> </Row>

11
src/pages/dashboard/analysis/components/NumberInfo/index.tsx

@ -33,7 +33,10 @@ const NumberInfo: React.FC<NumberInfoProps> = ({
{...rest} {...rest}
> >
{title && ( {title && (
<div className={styles.numberInfoTitle} title={typeof title === 'string' ? title : ''}> <div
className={styles.numberInfoTitle}
title={typeof title === 'string' ? title : ''}
>
{title} {title}
</div> </div>
)} )}
@ -62,7 +65,11 @@ const NumberInfo: React.FC<NumberInfoProps> = ({
{(status || subTotal) && ( {(status || subTotal) && (
<span className={styles.subTotal}> <span className={styles.subTotal}>
{subTotal} {subTotal}
{status && status === 'up' ? <CaretUpOutlined /> : <CaretDownOutlined />} {status && status === 'up' ? (
<CaretUpOutlined />
) : (
<CaretDownOutlined />
)}
</span> </span>
)} )}
</div> </div>

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

@ -3,6 +3,7 @@ import { Card, Col, Row, Tabs } from 'antd';
import type { DataItem, OfflineDataType } from '../data.d'; import type { DataItem, OfflineDataType } from '../data.d';
import useStyles from '../style.style'; import useStyles from '../style.style';
import NumberInfo from './NumberInfo'; import NumberInfo from './NumberInfo';
const CustomTab = ({ const CustomTab = ({
data, data,
currentTabKey: currentKey, currentTabKey: currentKey,
@ -32,7 +33,12 @@ const CustomTab = ({
paddingTop: 36, paddingTop: 36,
}} }}
> >
<Tiny.Ring height={60} width={60} percent={data.cvr} color={['#E8EEF4', '#5FABF4']} /> <Tiny.Ring
height={60}
width={60}
percent={data.cvr}
color={['#E8EEF4', '#5FABF4']}
/>
</Col> </Col>
</Row> </Row>
); );
@ -81,7 +87,12 @@ const OfflineData = ({
slider={{ x: true }} slider={{ x: true }}
axis={{ axis={{
x: { title: false }, x: { title: false },
y: { title: false, gridLineDash: null, gridStroke: '#ccc', gridStrokeOpacity: 1 }, y: {
title: false,
gridLineDash: null,
gridStroke: '#ccc',
gridStrokeOpacity: 1,
},
}} }}
legend={{ legend={{
color: { color: {

1
src/pages/dashboard/analysis/components/ProportionSales.tsx

@ -5,6 +5,7 @@ import numeral from 'numeral';
import React from 'react'; import React from 'react';
import type { DataItem } from '../data.d'; import type { DataItem } from '../data.d';
import useStyles from '../style.style'; import useStyles from '../style.style';
const { Text } = Typography; const { Text } = Typography;
const ProportionSales = ({ const ProportionSales = ({
dropdownGroup, dropdownGroup,

34
src/pages/dashboard/analysis/components/SalesCard.tsx

@ -50,16 +50,28 @@ const SalesCard = ({
tabBarExtraContent={ tabBarExtraContent={
<div className={styles.salesExtraWrap}> <div className={styles.salesExtraWrap}>
<div className={styles.salesExtra}> <div className={styles.salesExtra}>
<a className={isActive('today')} onClick={() => selectDate('today')}> <a
className={isActive('today')}
onClick={() => selectDate('today')}
>
</a> </a>
<a className={isActive('week')} onClick={() => selectDate('week')}> <a
className={isActive('week')}
onClick={() => selectDate('week')}
>
</a> </a>
<a className={isActive('month')} onClick={() => selectDate('month')}> <a
className={isActive('month')}
onClick={() => selectDate('month')}
>
</a> </a>
<a className={isActive('year')} onClick={() => selectDate('year')}> <a
className={isActive('year')}
onClick={() => selectDate('year')}
>
</a> </a>
</div> </div>
@ -123,7 +135,10 @@ const SalesCard = ({
> >
{i + 1} {i + 1}
</span> </span>
<span className={styles.rankingItemTitle} title={item.title}> <span
className={styles.rankingItemTitle}
title={item.title}
>
{item.title} {item.title}
</span> </span>
<span>{numeral(item.total).format('0,0')}</span> <span>{numeral(item.total).format('0,0')}</span>
@ -174,12 +189,17 @@ const SalesCard = ({
<li key={item.title}> <li key={item.title}>
<span <span
className={`${ className={`${
i < 3 ? styles.rankingItemNumberActive : styles.rankingItemNumber i < 3
? styles.rankingItemNumberActive
: styles.rankingItemNumber
}`} }`}
> >
{i + 1} {i + 1}
</span> </span>
<span className={styles.rankingItemTitle} title={item.title}> <span
className={styles.rankingItemTitle}
title={item.title}
>
{item.title} {item.title}
</span> </span>
<span>{numeral(item.total).format('0,0')}</span> <span>{numeral(item.total).format('0,0')}</span>

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

@ -116,7 +116,10 @@ const TopSearch = ({
height={45} height={45}
axis={false} axis={false}
padding={-12} padding={-12}
style={{ fill: 'linear-gradient(-90deg, white 0%, #6294FA 100%)', fillOpacity: 0.4 }} style={{
fill: 'linear-gradient(-90deg, white 0%, #6294FA 100%)',
fillOpacity: 0.4,
}}
data={visitData2} data={visitData2}
/> />
</Col> </Col>
@ -151,7 +154,10 @@ const TopSearch = ({
shapeField="smooth" shapeField="smooth"
height={45} height={45}
padding={-12} padding={-12}
style={{ fill: 'linear-gradient(-90deg, white 0%, #6294FA 100%)', fillOpacity: 0.4 }} style={{
fill: 'linear-gradient(-90deg, white 0%, #6294FA 100%)',
fillOpacity: 0.4,
}}
data={visitData2} data={visitData2}
axis={false} axis={false}
/> />

6
src/pages/dashboard/analysis/components/Trend/index.tsx

@ -30,7 +30,11 @@ const Trend: React.FC<TrendProps> = ({
className, className,
); );
return ( return (
<div {...rest} className={classString} title={typeof children === 'string' ? children : ''}> <div
{...rest}
className={classString}
title={typeof children === 'string' ? children : ''}
>
<span>{children}</span> <span>{children}</span>
{flag && ( {flag && (
<span className={styles[flag]}> <span className={styles[flag]}>

113
src/pages/dashboard/analysis/index.tsx

@ -18,8 +18,8 @@ import type { AnalysisData } from './data.d';
import { fakeChartData } from './service'; import { fakeChartData } from './service';
import useStyles from './style.style'; import useStyles from './style.style';
import { getTimeDistance } from './utils/utils'; import { getTimeDistance } from './utils/utils';
type RangePickerValue = RangePickerProps<dayjs.Dayjs>[
'value']; type RangePickerValue = RangePickerProps<dayjs.Dayjs>['value'];
type AnalysisProps = { type AnalysisProps = {
dashboardAndanalysis: AnalysisData; dashboardAndanalysis: AnalysisData;
loading: boolean; loading: boolean;
@ -63,7 +63,10 @@ const Analysis: FC<AnalysisProps> = () => {
if (salesType === 'all') { if (salesType === 'all') {
salesPieData = data?.salesTypeData; salesPieData = data?.salesTypeData;
} else { } else {
salesPieData = salesType === 'online' ? data?.salesTypeDataOnline : data?.salesTypeDataOffline; salesPieData =
salesType === 'online'
? data?.salesTypeDataOnline
: data?.salesTypeDataOffline;
} }
const dropdownGroup = ( const dropdownGroup = (
@ -93,64 +96,62 @@ const Analysis: FC<AnalysisProps> = () => {
const handleTabChange = (key: string) => { const handleTabChange = (key: string) => {
setCurrentTabKey(key); setCurrentTabKey(key);
}; };
const activeKey = currentTabKey || (data?.offlineData[0]?.name) || ''; const activeKey = currentTabKey || data?.offlineData[0]?.name || '';
return ( return (
<GridContent> <GridContent>
<Suspense fallback={<PageLoading />}>
<IntroduceRow loading={loading} visitData={data?.visitData || []} />
</Suspense>
<Suspense fallback={<PageLoading />}> <Suspense fallback={null}>
<IntroduceRow loading={loading} visitData={data?.visitData || []} /> <SalesCard
</Suspense> rangePickerValue={rangePickerValue}
salesData={data?.salesData || []}
<Suspense fallback={null}> isActive={isActive}
<SalesCard handleRangePickerChange={handleRangePickerChange}
rangePickerValue={rangePickerValue} loading={loading}
salesData={data?.salesData || []} selectDate={selectDate}
isActive={isActive} />
handleRangePickerChange={handleRangePickerChange} </Suspense>
loading={loading}
selectDate={selectDate}
/>
</Suspense>
<Row
gutter={24}
style={{
marginTop: 24,
}}
>
<Col xl={12} lg={24} md={24} sm={24} xs={24}>
<Suspense fallback={null}>
<TopSearch
loading={loading}
visitData2={data?.visitData2 || []}
searchData={data?.searchData || []}
dropdownGroup={dropdownGroup}
/>
</Suspense>
</Col>
<Col xl={12} lg={24} md={24} sm={24} xs={24}>
<Suspense fallback={null}>
<ProportionSales
dropdownGroup={dropdownGroup}
salesType={salesType}
loading={loading}
salesPieData={salesPieData || []}
handleChangeSalesType={handleChangeSalesType}
/>
</Suspense>
</Col>
</Row>
<Suspense fallback={null}> <Row
<OfflineData gutter={24}
activeKey={activeKey} style={{
loading={loading} marginTop: 24,
offlineData={data?.offlineData || []} }}
offlineChartData={data?.offlineChartData || []} >
handleTabChange={handleTabChange} <Col xl={12} lg={24} md={24} sm={24} xs={24}>
/> <Suspense fallback={null}>
</Suspense> <TopSearch
loading={loading}
visitData2={data?.visitData2 || []}
searchData={data?.searchData || []}
dropdownGroup={dropdownGroup}
/>
</Suspense>
</Col>
<Col xl={12} lg={24} md={24} sm={24} xs={24}>
<Suspense fallback={null}>
<ProportionSales
dropdownGroup={dropdownGroup}
salesType={salesType}
loading={loading}
salesPieData={salesPieData || []}
handleChangeSalesType={handleChangeSalesType}
/>
</Suspense>
</Col>
</Row>
<Suspense fallback={null}>
<OfflineData
activeKey={activeKey}
loading={loading}
offlineData={data?.offlineData || []}
offlineChartData={data?.offlineChartData || []}
handleTabChange={handleTabChange}
/>
</Suspense>
</GridContent> </GridContent>
); );
}; };

9
src/pages/dashboard/analysis/utils/utils.ts

@ -7,7 +7,9 @@ export function fixedZero(val: number) {
return val * 1 < 10 ? `0${val}` : val; return val * 1 < 10 ? `0${val}` : val;
} }
export function getTimeDistance(type: 'today' | 'week' | 'month' | 'year'): RangePickerValue { export function getTimeDistance(
type: 'today' | 'week' | 'month' | 'year',
): RangePickerValue {
const now = new Date(); const now = new Date();
const oneDay = 1000 * 60 * 60 * 24; const oneDay = 1000 * 60 * 60 * 24;
@ -44,7 +46,10 @@ export function getTimeDistance(type: 'today' | 'week' | 'month' | 'year'): Rang
return [ return [
dayjs(`${year}-${fixedZero(month + 1)}-01 00:00:00`), dayjs(`${year}-${fixedZero(month + 1)}-01 00:00:00`),
dayjs(dayjs(`${nextYear}-${fixedZero(nextMonth + 1)}-01 00:00:00`).valueOf() - 1000), dayjs(
dayjs(`${nextYear}-${fixedZero(nextMonth + 1)}-01 00:00:00`).valueOf() -
1000,
),
]; ];
} }

10
src/pages/dashboard/monitor/components/ActiveChart/index.style.ts

@ -15,7 +15,12 @@ const useStyles = createStyles(() => {
marginTop: '8px', marginTop: '8px',
fontSize: '0', fontSize: '0',
lineHeight: '20px', lineHeight: '20px',
span: { display: 'inline-block', width: '33.33%', fontSize: '12px', textAlign: 'center' }, span: {
display: 'inline-block',
width: '33.33%',
fontSize: '12px',
textAlign: 'center',
},
'span:first-child': { textAlign: 'left' }, 'span:first-child': { textAlign: 'left' },
'span:last-child': { textAlign: 'right' }, 'span:last-child': { textAlign: 'right' },
}, },
@ -31,7 +36,8 @@ const useStyles = createStyles(() => {
left: '0', left: '0',
width: '100%', width: '100%',
height: '100%', height: '100%',
backgroundImage: 'linear-gradient(to right, transparent 50%, #e9e9e9 50%)', backgroundImage:
'linear-gradient(to right, transparent 50%, #e9e9e9 50%)',
backgroundSize: '6px', backgroundSize: '6px',
}, },
'dashedLine:last-child': { 'dashedLine:last-child': {

13
src/pages/dashboard/monitor/components/ActiveChart/index.tsx

@ -1,7 +1,8 @@
import { Area } from '@ant-design/plots'; import { Area } from '@ant-design/plots';
import { Statistic } from 'antd'; import { Statistic } from 'antd';
import { useEffect, useRef, useState, useCallback } from 'react'; import { useCallback, useEffect, useRef, useState } from 'react';
import useStyles from './index.style'; import useStyles from './index.style';
function fixedZero(val: number) { function fixedZero(val: number) {
return val * 1 < 10 ? `0${val}` : val; return val * 1 < 10 ? `0${val}` : val;
} }
@ -54,7 +55,10 @@ const ActiveChart = () => {
axis={false} axis={false}
yField="y" yField="y"
height={84} height={84}
style={{ fill: 'linear-gradient(-90deg, white 0%, #6294FA 100%)', fillOpacity: 0.6 }} style={{
fill: 'linear-gradient(-90deg, white 0%, #6294FA 100%)',
fillOpacity: 0.6,
}}
data={activeData} data={activeData}
/> />
</div> </div>
@ -62,7 +66,10 @@ const ActiveChart = () => {
<div> <div>
<div className={styles.activeChartGrid}> <div className={styles.activeChartGrid}>
<p>{[...activeData].sort()[activeData.length - 1]?.y + 200} 亿</p> <p>{[...activeData].sort()[activeData.length - 1]?.y + 200} 亿</p>
<p>{[...activeData].sort()[Math.floor(activeData.length / 2)]?.y} 亿</p> <p>
{[...activeData].sort()[Math.floor(activeData.length / 2)]?.y}{' '}
亿
</p>
</div> </div>
<div className={styles.dashedLine}> <div className={styles.dashedLine}>
<div className={styles.line} /> <div className={styles.line} />

6
src/pages/dashboard/monitor/components/Charts/WaterWave/index.tsx

@ -87,7 +87,11 @@ class WaterWave extends Component<WaterWaveProps> {
const bR = radius - lineWidth; const bR = radius - lineWidth;
const circleOffset = -(Math.PI / 2); const circleOffset = -(Math.PI / 2);
let circleLock = true; let circleLock = true;
for (let i = circleOffset; i < circleOffset + 2 * Math.PI; i += 1 / (8 * Math.PI)) { for (
let i = circleOffset;
i < circleOffset + 2 * Math.PI;
i += 1 / (8 * Math.PI)
) {
arcStack.push([radius + bR * Math.cos(i), radius + bR * Math.sin(i)]); arcStack.push([radius + bR * Math.cos(i), radius + bR * Math.sin(i)]);
} }
const cStartPoint = arcStack.shift() as number[]; const cStartPoint = arcStack.shift() as number[];

4
src/pages/dashboard/monitor/components/Charts/autoHeight.tsx

@ -1,6 +1,8 @@
import React from 'react'; import React from 'react';
export type IReactComponent<P = any> = React.ComponentClass<P> | React.ClassicComponentClass<P>; export type IReactComponent<P = any> =
| React.ComponentClass<P>
| React.ClassicComponentClass<P>;
function computeHeight(node: HTMLDivElement) { function computeHeight(node: HTMLDivElement) {
const { style } = node; const { style } = node;

10
src/pages/dashboard/monitor/components/Map/index.tsx

@ -2,7 +2,15 @@ import { PageLoading } from '@ant-design/pro-components';
import { HeatmapLayer, MapboxScene, PointLayer } from '@antv/l7-react'; import { HeatmapLayer, MapboxScene, PointLayer } from '@antv/l7-react';
import * as React from 'react'; import * as React from 'react';
const colors = ['#eff3ff', '#c6dbef', '#9ecae1', '#6baed6', '#4292c6', '#2171b5', '#084594']; const colors = [
'#eff3ff',
'#c6dbef',
'#9ecae1',
'#6baed6',
'#4292c6',
'#2171b5',
'#084594',
];
export default class MonitorMap extends React.Component { export default class MonitorMap extends React.Component {
state = { state = {
data: null, data: null,

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

@ -24,160 +24,173 @@ const Monitor: FC = () => {
}); });
return ( return (
<GridContent> <GridContent>
<Row gutter={24}> <Row gutter={24}>
<Col <Col
xl={18} xl={18}
lg={24} lg={24}
md={24} md={24}
sm={24} sm={24}
xs={24} xs={24}
style={{
marginBottom: 24,
}}
>
<Card title="活动实时交易情况" bordered={false}>
<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}>
<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={{ style={{
marginBottom: 24, marginBottom: 24,
}} }}
bordered={false}
> >
<Card title="活动实时交易情况" bordered={false}> <ActiveChart />
<Row> </Card>
<Col md={6} sm={12} xs={24}> <Card
<Statistic title="券核效率"
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}>
<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,
}}
bordered={false}
>
<ActiveChart />
</Card>
<Card
title="券核效率"
style={{
marginBottom: 24,
}}
bodyStyle={{
textAlign: 'center',
}}
bordered={false}
>
<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={{ style={{
marginBottom: 24, marginBottom: 24,
}} }}
> bodyStyle={{
<Card title="各品类占比" bordered={false}> textAlign: 'center',
<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,
}} }}
bordered={false}
> >
<Card <Gauge
title="热门搜索" height={180}
loading={loading} data={
bordered={false} {
bodyStyle={{ target: 80,
overflow: 'hidden', 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="各品类占比" bordered={false}>
<Row
style={{
padding: '16px 0',
}} }}
> >
<WordCloud <Col span={8}>
data={wordCloudData} <Progress type="dashboard" percent={75} />
height={162} </Col>
textField="word" <Col span={8}>
colorField="word" <Progress type="dashboard" percent={48} />
layout={{ spiral: 'rectangular', fontSize: [10, 20] }} </Col>
/> <Col span={8}>
</Card> <Progress type="dashboard" percent={33} />
</Col> </Col>
<Col </Row>
xl={6} </Card>
lg={12} </Col>
sm={24} <Col
xs={24} xl={6}
style={{ lg={12}
marginBottom: 24, sm={24}
xs={24}
style={{
marginBottom: 24,
}}
>
<Card
title="热门搜索"
loading={loading}
bordered={false}
bodyStyle={{
overflow: 'hidden',
}} }}
> >
<Card <WordCloud
title="资源剩余" data={wordCloudData}
bodyStyle={{ height={162}
textAlign: 'center', textField="word"
fontSize: 0, colorField="word"
}} layout={{ spiral: 'rectangular', fontSize: [10, 20] }}
bordered={false} />
> </Card>
<Liquid height={160} percent={0.35} /> </Col>
</Card> <Col
</Col> xl={6}
</Row> lg={12}
sm={24}
xs={24}
style={{
marginBottom: 24,
}}
>
<Card
title="资源剩余"
bodyStyle={{
textAlign: 'center',
fontSize: 0,
}}
bordered={false}
>
<Liquid height={160} percent={0.35} />
</Card>
</Col>
</Row>
</GridContent> </GridContent>
); );
}; };

2
src/pages/dashboard/workplace/_mock.ts

@ -127,7 +127,7 @@ for (let i = 0; i < 10; i += 1) {
const offlineChartData: DataItem[] = []; const offlineChartData: DataItem[] = [];
for (let i = 0; i < 20; i += 1) { for (let i = 0; i < 20; i += 1) {
offlineChartData.push({ offlineChartData.push({
x: Date.now()+ 1000 * 60 * 30 * i, x: Date.now() + 1000 * 60 * 30 * i,
y1: Math.floor(Math.random() * 100) + 10, y1: Math.floor(Math.random() * 100) + 10,
y2: Math.floor(Math.random() * 100) + 10, y2: Math.floor(Math.random() * 100) + 10,
}); });

20
src/pages/dashboard/workplace/index.tsx

@ -9,6 +9,7 @@ import EditableLinkGroup from './components/EditableLinkGroup';
import type { ActivitiesType, CurrentUser } from './data.d'; import type { ActivitiesType, CurrentUser } from './data.d';
import { fakeChartData, queryActivities, queryProjectNotice } from './service'; import { fakeChartData, queryActivities, queryProjectNotice } from './service';
import useStyles from './style.style'; import useStyles from './style.style';
dayjs.extend(relativeTime); dayjs.extend(relativeTime);
const links = [ const links = [
@ -89,8 +90,10 @@ const ExtraContent: FC<Record<string, any>> = () => {
}; };
const Workplace: FC = () => { const Workplace: FC = () => {
const { styles } = useStyles(); const { styles } = useStyles();
const { loading: projectLoading, data: projectNotice = [] } = useRequest(queryProjectNotice); const { loading: projectLoading, data: projectNotice = [] } =
const { loading: activitiesLoading, data: activities = [] } = useRequest(queryActivities); useRequest(queryProjectNotice);
const { loading: activitiesLoading, data: activities = [] } =
useRequest(queryActivities);
const { data } = useRequest(fakeChartData); const { data } = useRequest(fakeChartData);
const renderActivities = (item: ActivitiesType) => { const renderActivities = (item: ActivitiesType) => {
const events = item.template.split(/@\{([^{}]*)\}/gi).map((key) => { const events = item.template.split(/@\{([^{}]*)\}/gi).map((key) => {
@ -130,7 +133,8 @@ const Workplace: FC = () => {
content={ content={
<PageHeaderContent <PageHeaderContent
currentUser={{ currentUser={{
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png', avatar:
'https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png',
name: '吴彦祖', name: '吴彦祖',
userid: '00000001', userid: '00000001',
email: 'antdesign@alipay.com', email: 'antdesign@alipay.com',
@ -218,7 +222,11 @@ const Workplace: FC = () => {
padding: 0, padding: 0,
}} }}
> >
<EditableLinkGroup onAdd={() => {}} links={links} linkElement={Link} /> <EditableLinkGroup
onAdd={() => {}}
links={links}
linkElement={Link}
/>
</Card> </Card>
<Card <Card
style={{ style={{
@ -271,7 +279,9 @@ const Workplace: FC = () => {
<Col span={12} key={`members-item-${item.id}`}> <Col span={12} key={`members-item-${item.id}`}>
<a> <a>
<Avatar src={item.logo} size="small" /> <Avatar src={item.logo} size="small" />
<span className={styles.member}>{item.member.substring(0, 3)}</span> <span className={styles.member}>
{item.member.substring(0, 3)}
</span>
</a> </a>
</Col> </Col>
); );

28
src/pages/dashboard/workplace/style.style.ts

@ -55,9 +55,10 @@ const useStyles = createStyles(({ token }) => {
}, },
float: 'right', float: 'right',
whiteSpace: 'nowrap', whiteSpace: 'nowrap',
[`@media screen and (max-width: ${token.screenXL}px) and (min-width: @screen-lg)`]: { [`@media screen and (max-width: ${token.screenXL}px) and (min-width: @screen-lg)`]:
marginLeft: '-44px', {
}, marginLeft: '-44px',
},
[`@media screen and (max-width: ${token.screenLG}px)`]: { [`@media screen and (max-width: ${token.screenLG}px)`]: {
float: 'none', float: 'none',
marginRight: '0', marginRight: '0',
@ -101,9 +102,10 @@ const useStyles = createStyles(({ token }) => {
display: 'none', display: 'none',
}, },
}, },
[`@media screen and (max-width: ${token.screenXL}px) and (min-width: @screen-lg)`]: { [`@media screen and (max-width: ${token.screenXL}px) and (min-width: @screen-lg)`]:
padding: '0 16px', {
}, padding: '0 16px',
},
[`@media screen and (max-width: ${token.screenLG}px)`]: { [`@media screen and (max-width: ${token.screenLG}px)`]: {
padding: '0 16px', padding: '0 16px',
textAlign: 'left', textAlign: 'left',
@ -128,9 +130,10 @@ const useStyles = createStyles(({ token }) => {
color: token.colorPrimary, color: token.colorPrimary,
}, },
}, },
[`@media screen and (max-width: ${token.screenXL}px) and (min-width: @screen-lg)`]: { [`@media screen and (max-width: ${token.screenXL}px) and (min-width: @screen-lg)`]:
marginBottom: '0', {
}, marginBottom: '0',
},
[`@media screen and (max-width: ${token.screenLG}px)`]: { [`@media screen and (max-width: ${token.screenLG}px)`]: {
marginBottom: '0', marginBottom: '0',
}, },
@ -199,9 +202,10 @@ const useStyles = createStyles(({ token }) => {
color: token.colorTextDisabled, color: token.colorTextDisabled,
}, },
activeCard: { activeCard: {
[`@media screen and (max-width: ${token.screenXL}px) and (min-width: @screen-lg)`]: { [`@media screen and (max-width: ${token.screenXL}px) and (min-width: @screen-lg)`]:
marginBottom: '24px', {
}, marginBottom: '24px',
},
[`@media screen and (max-width: ${token.screenLG}px)`]: { [`@media screen and (max-width: ${token.screenLG}px)`]: {
marginBottom: '24px', marginBottom: '24px',
}, },

24
src/pages/form/advanced-form/components/TableForm.tsx

@ -3,6 +3,7 @@ import { Button, Divider, Input, message, Popconfirm, Table } from 'antd';
import type { FC } from 'react'; import type { FC } from 'react';
import React, { useState } from 'react'; import React, { useState } from 'react';
import useStyles from '../style.style'; import useStyles from '../style.style';
type TableFormDateType = { type TableFormDateType = {
key: string; key: string;
workId?: string; workId?: string;
@ -20,11 +21,16 @@ const TableForm: FC<TableFormProps> = ({ value, onChange }) => {
const [clickedCancel, setClickedCancel] = useState(false); const [clickedCancel, setClickedCancel] = useState(false);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [index, setIndex] = useState(0); const [index, setIndex] = useState(0);
const [cacheOriginData, setCacheOriginData] = useState<Record<string, any>>({}); const [cacheOriginData, setCacheOriginData] = useState<Record<string, any>>(
{},
);
const [data, setData] = useState(value); const [data, setData] = useState(value);
const getRowByKey = (key: string, newData?: TableFormDateType[]) => const getRowByKey = (key: string, newData?: TableFormDateType[]) =>
(newData || data)?.filter((item) => item.key === key)[0]; (newData || data)?.filter((item) => item.key === key)[0];
const toggleEditable = (e: React.MouseEvent | React.KeyboardEvent, key: string) => { const toggleEditable = (
e: React.MouseEvent | React.KeyboardEvent,
key: string,
) => {
e.preventDefault(); e.preventDefault();
const newData = data?.map((item) => ({ const newData = data?.map((item) => ({
...item, ...item,
@ -59,7 +65,9 @@ const TableForm: FC<TableFormProps> = ({ value, onChange }) => {
setData(newData); setData(newData);
}; };
const remove = (key: string) => { const remove = (key: string) => {
const newData = data?.filter((item) => item.key !== key) as TableFormDateType[]; const newData = data?.filter(
(item) => item.key !== key,
) as TableFormDateType[];
setData(newData); setData(newData);
if (onChange) { if (onChange) {
onChange(newData); onChange(newData);
@ -201,7 +209,10 @@ const TableForm: FC<TableFormProps> = ({ value, onChange }) => {
<span> <span>
<a onClick={(e) => saveRow(e, record.key)}></a> <a onClick={(e) => saveRow(e, record.key)}></a>
<Divider type="vertical" /> <Divider type="vertical" />
<Popconfirm title="是否要删除此行?" onConfirm={() => remove(record.key)}> <Popconfirm
title="是否要删除此行?"
onConfirm={() => remove(record.key)}
>
<a></a> <a></a>
</Popconfirm> </Popconfirm>
</span> </span>
@ -219,7 +230,10 @@ const TableForm: FC<TableFormProps> = ({ value, onChange }) => {
<span> <span>
<a onClick={(e) => toggleEditable(e, record.key)}></a> <a onClick={(e) => toggleEditable(e, record.key)}></a>
<Divider type="vertical" /> <Divider type="vertical" />
<Popconfirm title="是否要删除此行?" onConfirm={() => remove(record.key)}> <Popconfirm
title="是否要删除此行?"
onConfirm={() => remove(record.key)}
>
<a></a> <a></a>
</Popconfirm> </Popconfirm>
</span> </span>

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

@ -15,6 +15,7 @@ import type { FC } from 'react';
import { useState } from 'react'; import { useState } from 'react';
import { fakeSubmitForm } from './service'; import { fakeSubmitForm } from './service';
import useStyles from './style.style'; import useStyles from './style.style';
interface TableFormDateType { interface TableFormDateType {
key: string; key: string;
workId?: string; workId?: string;
@ -80,9 +81,19 @@ const AdvancedForm: FC<Record<string, any>> = () => {
if (!err || err.errors.length === 0) { if (!err || err.errors.length === 0) {
return null; return null;
} }
const key = err.name[0] as 'name' | 'url' | 'owner' | 'approver' | 'dateRange' | 'type'; const key = err.name[0] as
| 'name'
| 'url'
| 'owner'
| 'approver'
| 'dateRange'
| 'type';
return ( return (
<li key={key} className={styles.errorListItem} onClick={() => scrollToField(key)}> <li
key={key}
className={styles.errorListItem}
onClick={() => scrollToField(key)}
>
<CloseCircleOutlined className={styles.errorIcon} /> <CloseCircleOutlined className={styles.errorIcon} />
<div className={styles.errorMessage}>{err.errors[0]}</div> <div className={styles.errorMessage}>{err.errors[0]}</div>
<div className={styles.errorField}>{fieldLabels[key]}</div> <div className={styles.errorField}>{fieldLabels[key]}</div>

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

@ -14,6 +14,7 @@ import { Card, message } from 'antd';
import type { FC } from 'react'; import type { FC } from 'react';
import { fakeSubmitForm } from './service'; import { fakeSubmitForm } from './service';
import useStyles from './style.style'; import useStyles from './style.style';
const BasicForm: FC<Record<string, any>> = () => { const BasicForm: FC<Record<string, any>> = () => {
const { styles } = useStyles(); const { styles } = useStyles();
const { run } = useRequest(fakeSubmitForm, { const { run } = useRequest(fakeSubmitForm, {
@ -163,7 +164,8 @@ const BasicForm: FC<Record<string, any>> = () => {
fieldProps={{ fieldProps={{
style: { style: {
margin: '8px 0', margin: '8px 0',
display: publicType && publicType === '2' ? 'block' : 'none', display:
publicType && publicType === '2' ? 'block' : 'none',
}, },
}} }}
options={[ options={[

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

@ -7,10 +7,19 @@ import {
StepsForm, StepsForm,
} from '@ant-design/pro-components'; } from '@ant-design/pro-components';
import type { FormInstance } from 'antd'; import type { FormInstance } from 'antd';
import { Alert, Button, Card, Descriptions, Divider, Result, Statistic } from 'antd'; import {
Alert,
Button,
Card,
Descriptions,
Divider,
Result,
Statistic,
} from 'antd';
import React, { useRef, useState } from 'react'; import React, { useRef, useState } from 'react';
import type { StepDataType } from './data.d'; import type { StepDataType } from './data.d';
import useStyles from './style.style'; import useStyles from './style.style';
const StepDescriptions: React.FC<{ const StepDescriptions: React.FC<{
stepData: StepDataType; stepData: StepDataType;
bordered?: boolean; bordered?: boolean;

18
src/pages/list/basic-list/_mock.ts

@ -57,7 +57,10 @@ function fakeList(count: number): BasicListItemDataType[] {
owner: user[i % 10], owner: user[i % 10],
title: titles[i % 8], title: titles[i % 8],
avatar: avatars[i % 8], avatar: avatars[i % 8],
cover: parseInt(`${i / 4}`, 10) % 2 === 0 ? covers[i % 4] : covers[3 - (i % 4)], cover:
parseInt(`${i / 4}`, 10) % 2 === 0
? covers[i % 4]
: covers[3 - (i % 4)],
status: ['active', 'exception', 'normal'][i % 3] as status: ['active', 'exception', 'normal'][i % 3] as
| 'normal' | 'normal'
| 'exception' | 'exception'
@ -66,8 +69,8 @@ function fakeList(count: number): BasicListItemDataType[] {
percent: Math.ceil(Math.random() * 50) + 50, percent: Math.ceil(Math.random() * 50) + 50,
logo: avatars[i % 8], logo: avatars[i % 8],
href: 'https://ant.design', href: 'https://ant.design',
updatedAt: new Date(Date.now()- 1000 * 60 * 60 * 2 * i).getTime(), updatedAt: new Date(Date.now() - 1000 * 60 * 60 * 2 * i).getTime(),
createdAt: new Date(Date.now()- 1000 * 60 * 60 * 2 * i).getTime(), createdAt: new Date(Date.now() - 1000 * 60 * 60 * 2 * i).getTime(),
subDescription: desc[i % 5], subDescription: desc[i % 5],
description: description:
'在中台产品的研发过程中,会出现不同的设计规范和实现方式,但其中往往存在很多类似的页面和组件,这些类似的组件会被抽离成一套标准规范。', '在中台产品的研发过程中,会出现不同的设计规范和实现方式,但其中往往存在很多类似的页面和组件,这些类似的组件会被抽离成一套标准规范。',
@ -80,17 +83,20 @@ function fakeList(count: number): BasicListItemDataType[] {
'段落示意:蚂蚁金服设计平台 ant.design,用最小的工作量,无缝接入蚂蚁金服生态,提供跨越设计与开发的体验解决方案。蚂蚁金服设计平台 ant.design,用最小的工作量,无缝接入蚂蚁金服生态,提供跨越设计与开发的体验解决方案。', '段落示意:蚂蚁金服设计平台 ant.design,用最小的工作量,无缝接入蚂蚁金服生态,提供跨越设计与开发的体验解决方案。蚂蚁金服设计平台 ant.design,用最小的工作量,无缝接入蚂蚁金服生态,提供跨越设计与开发的体验解决方案。',
members: [ members: [
{ {
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/ZiESqWwCXBRQoaPONSJe.png', avatar:
'https://gw.alipayobjects.com/zos/rmsportal/ZiESqWwCXBRQoaPONSJe.png',
name: '曲丽丽', name: '曲丽丽',
id: 'member1', id: 'member1',
}, },
{ {
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/tBOxZPlITHqwlGjsJWaF.png', avatar:
'https://gw.alipayobjects.com/zos/rmsportal/tBOxZPlITHqwlGjsJWaF.png',
name: '王昭君', name: '王昭君',
id: 'member2', id: 'member2',
}, },
{ {
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/sBxjgqiuHMGRkIjqlQCd.png', avatar:
'https://gw.alipayobjects.com/zos/rmsportal/sBxjgqiuHMGRkIjqlQCd.png',
name: '董娜娜', name: '董娜娜',
id: 'member3', id: 'member3',
}, },

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

@ -9,6 +9,7 @@ import { Button, Result } from 'antd';
import type { FC } from 'react'; import type { FC } from 'react';
import type { BasicListItemDataType } from '../data.d'; import type { BasicListItemDataType } from '../data.d';
import useStyles from '../style.style'; import useStyles from '../style.style';
type OperationModalProps = { type OperationModalProps = {
done: boolean; done: boolean;
open: boolean; open: boolean;

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

@ -19,8 +19,14 @@ import type { FC } from 'react';
import React, { useState } from 'react'; import React, { useState } from 'react';
import OperationModal from './components/OperationModal'; import OperationModal from './components/OperationModal';
import type { BasicListItemDataType } from './data.d'; import type { BasicListItemDataType } from './data.d';
import { addFakeList, queryFakeList, removeFakeList, updateFakeList } from './service'; import {
addFakeList,
queryFakeList,
removeFakeList,
updateFakeList,
} from './service';
import useStyles from './style.style'; import useStyles from './style.style';
const RadioButton = Radio.Button; const RadioButton = Radio.Button;
const RadioGroup = Radio.Group; const RadioGroup = Radio.Group;
const { Search } = Input; const { Search } = Input;
@ -71,7 +77,9 @@ export const BasicList: FC = () => {
const { styles } = useStyles(); const { styles } = useStyles();
const [done, setDone] = useState<boolean>(false); const [done, setDone] = useState<boolean>(false);
const [open, setVisible] = useState<boolean>(false); const [open, setVisible] = useState<boolean>(false);
const [current, setCurrent] = useState<Partial<BasicListItemDataType> | undefined>(undefined); const [current, setCurrent] = useState<
Partial<BasicListItemDataType> | undefined
>(undefined);
const { const {
data: listData, data: listData,
loading, loading,
@ -114,7 +122,10 @@ export const BasicList: FC = () => {
id, id,
}); });
}; };
const editAndDelete = (key: string | number, currentItem: BasicListItemDataType) => { const editAndDelete = (
key: string | number,
currentItem: BasicListItemDataType,
) => {
if (key === 'edit') showEditModal(currentItem); if (key === 'edit') showEditModal(currentItem);
else if (key === 'delete') { else if (key === 'delete') {
Modal.confirm({ Modal.confirm({
@ -133,7 +144,11 @@ export const BasicList: FC = () => {
<RadioButton value="progress"></RadioButton> <RadioButton value="progress"></RadioButton>
<RadioButton value="waiting"></RadioButton> <RadioButton value="waiting"></RadioButton>
</RadioGroup> </RadioGroup>
<Search className={styles.extraContentSearch} placeholder="请输入" onSearch={() => ({})} /> <Search
className={styles.extraContentSearch}
placeholder="请输入"
onSearch={() => ({})}
/>
</div> </div>
); );
const MoreBtn: React.FC<{ const MoreBtn: React.FC<{
@ -221,7 +236,9 @@ export const BasicList: FC = () => {
]} ]}
> >
<List.Item.Meta <List.Item.Meta
avatar={<Avatar src={item.logo} shape="square" size="large" />} avatar={
<Avatar src={item.logo} shape="square" size="large" />
}
title={<a href={item.href}>{item.title}</a>} title={<a href={item.href}>{item.title}</a>}
description={item.subDescription} description={item.subDescription}
/> />

17
src/pages/list/basic-list/style.style.ts

@ -67,15 +67,16 @@ const useStyles = createStyles(({ token }) => {
width: '100%', width: '100%',
}, },
}, },
[`@media screen and (max-width: ${token.screenLG}px) and (min-width: @screen-md)`]: { [`@media screen and (max-width: ${token.screenLG}px) and (min-width: @screen-md)`]:
'& > div': { {
display: 'block', '& > div': {
display: 'block',
},
'& > div:last-child': {
top: '0',
width: '100%',
},
}, },
'& > div:last-child': {
top: '0',
width: '100%',
},
},
[`@media screen and (max-width: ${token.screenXL}px)`]: { [`@media screen and (max-width: ${token.screenXL}px)`]: {
'& > div': { '& > div': {
marginLeft: '24px', marginLeft: '24px',

18
src/pages/list/card-list/_mock.ts

@ -57,7 +57,10 @@ function fakeList(count: number): CardListItemDataType[] {
owner: user[i % 10], owner: user[i % 10],
title: titles[i % 8], title: titles[i % 8],
avatar: avatars[i % 8], avatar: avatars[i % 8],
cover: parseInt(`${i / 4}`, 10) % 2 === 0 ? covers[i % 4] : covers[3 - (i % 4)], cover:
parseInt(`${i / 4}`, 10) % 2 === 0
? covers[i % 4]
: covers[3 - (i % 4)],
status: ['active', 'exception', 'normal'][i % 3] as status: ['active', 'exception', 'normal'][i % 3] as
| 'normal' | 'normal'
| 'exception' | 'exception'
@ -66,8 +69,8 @@ function fakeList(count: number): CardListItemDataType[] {
percent: Math.ceil(Math.random() * 50) + 50, percent: Math.ceil(Math.random() * 50) + 50,
logo: avatars[i % 8], logo: avatars[i % 8],
href: 'https://ant.design', href: 'https://ant.design',
updatedAt: new Date(Date.now()- 1000 * 60 * 60 * 2 * i).getTime(), updatedAt: new Date(Date.now() - 1000 * 60 * 60 * 2 * i).getTime(),
createdAt: new Date(Date.now()- 1000 * 60 * 60 * 2 * i).getTime(), createdAt: new Date(Date.now() - 1000 * 60 * 60 * 2 * i).getTime(),
subDescription: desc[i % 5], subDescription: desc[i % 5],
description: description:
'在中台产品的研发过程中,会出现不同的设计规范和实现方式,但其中往往存在很多类似的页面和组件,这些类似的组件会被抽离成一套标准规范。', '在中台产品的研发过程中,会出现不同的设计规范和实现方式,但其中往往存在很多类似的页面和组件,这些类似的组件会被抽离成一套标准规范。',
@ -80,17 +83,20 @@ function fakeList(count: number): CardListItemDataType[] {
'段落示意:蚂蚁金服设计平台 ant.design,用最小的工作量,无缝接入蚂蚁金服生态,提供跨越设计与开发的体验解决方案。蚂蚁金服设计平台 ant.design,用最小的工作量,无缝接入蚂蚁金服生态,提供跨越设计与开发的体验解决方案。', '段落示意:蚂蚁金服设计平台 ant.design,用最小的工作量,无缝接入蚂蚁金服生态,提供跨越设计与开发的体验解决方案。蚂蚁金服设计平台 ant.design,用最小的工作量,无缝接入蚂蚁金服生态,提供跨越设计与开发的体验解决方案。',
members: [ members: [
{ {
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/ZiESqWwCXBRQoaPONSJe.png', avatar:
'https://gw.alipayobjects.com/zos/rmsportal/ZiESqWwCXBRQoaPONSJe.png',
name: '曲丽丽', name: '曲丽丽',
id: 'member1', id: 'member1',
}, },
{ {
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/tBOxZPlITHqwlGjsJWaF.png', avatar:
'https://gw.alipayobjects.com/zos/rmsportal/tBOxZPlITHqwlGjsJWaF.png',
name: '王昭君', name: '王昭君',
id: 'member2', id: 'member2',
}, },
{ {
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/sBxjgqiuHMGRkIjqlQCd.png', avatar:
'https://gw.alipayobjects.com/zos/rmsportal/sBxjgqiuHMGRkIjqlQCd.png',
name: '董娜娜', name: '董娜娜',
id: 'member3', id: 'member3',
}, },

32
src/pages/list/card-list/index.tsx

@ -5,6 +5,7 @@ import { Button, Card, List, Typography } from 'antd';
import type { CardListItemDataType } from './data.d'; import type { CardListItemDataType } from './data.d';
import { queryFakeList } from './service'; import { queryFakeList } from './service';
import useStyles from './style.style'; import useStyles from './style.style';
const { Paragraph } = Typography; const { Paragraph } = Typography;
const CardList = () => { const CardList = () => {
const { styles } = useStyles(); const { styles } = useStyles();
@ -17,20 +18,30 @@ const CardList = () => {
const content = ( const content = (
<div className={styles.pageHeaderContent}> <div className={styles.pageHeaderContent}>
<p> <p>
ant.design
ant.design
</p> </p>
<div className={styles.contentLink}> <div className={styles.contentLink}>
<a> <a>
<img alt="" src="https://gw.alipayobjects.com/zos/rmsportal/MjEImQtenlyueSmVEfUD.svg" />{' '} <img
alt=""
src="https://gw.alipayobjects.com/zos/rmsportal/MjEImQtenlyueSmVEfUD.svg"
/>{' '}
</a> </a>
<a> <a>
<img alt="" src="https://gw.alipayobjects.com/zos/rmsportal/NbuDUAuBlIApFuDvWiND.svg" />{' '} <img
alt=""
src="https://gw.alipayobjects.com/zos/rmsportal/NbuDUAuBlIApFuDvWiND.svg"
/>{' '}
</a> </a>
<a> <a>
<img alt="" src="https://gw.alipayobjects.com/zos/rmsportal/ohOEPSYdDTNnyMbGuyLb.svg" />{' '} <img
alt=""
src="https://gw.alipayobjects.com/zos/rmsportal/ohOEPSYdDTNnyMbGuyLb.svg"
/>{' '}
</a> </a>
</div> </div>
@ -68,10 +79,19 @@ const CardList = () => {
<Card <Card
hoverable hoverable
className={styles.card} className={styles.card}
actions={[<a key="option1"></a>, <a key="option2"></a>]} actions={[
<a key="option1"></a>,
<a key="option2"></a>,
]}
> >
<Card.Meta <Card.Meta
avatar={<img alt="" className={styles.cardAvatar} src={item.avatar} />} avatar={
<img
alt=""
className={styles.cardAvatar}
src={item.avatar}
/>
}
title={<a>{item.title}</a>} title={<a>{item.title}</a>}
description={ description={
<Paragraph <Paragraph

18
src/pages/list/search/applications/_mock.ts

@ -56,7 +56,10 @@ function fakeList(count: number): ListItemDataType[] {
owner: user[i % 10], owner: user[i % 10],
title: titles[i % 8], title: titles[i % 8],
avatar: avatars[i % 8], avatar: avatars[i % 8],
cover: parseInt(`${i / 4}`, 10) % 2 === 0 ? covers[i % 4] : covers[3 - (i % 4)], cover:
parseInt(`${i / 4}`, 10) % 2 === 0
? covers[i % 4]
: covers[3 - (i % 4)],
status: ['active', 'exception', 'normal'][i % 3] as status: ['active', 'exception', 'normal'][i % 3] as
| 'normal' | 'normal'
| 'exception' | 'exception'
@ -65,8 +68,8 @@ function fakeList(count: number): ListItemDataType[] {
percent: Math.ceil(Math.random() * 50) + 50, percent: Math.ceil(Math.random() * 50) + 50,
logo: avatars[i % 8], logo: avatars[i % 8],
href: 'https://ant.design', href: 'https://ant.design',
updatedAt: new Date(Date.now()- 1000 * 60 * 60 * 2 * i).getTime(), updatedAt: new Date(Date.now() - 1000 * 60 * 60 * 2 * i).getTime(),
createdAt: new Date(Date.now()- 1000 * 60 * 60 * 2 * i).getTime(), createdAt: new Date(Date.now() - 1000 * 60 * 60 * 2 * i).getTime(),
subDescription: desc[i % 5], subDescription: desc[i % 5],
description: description:
'在中台产品的研发过程中,会出现不同的设计规范和实现方式,但其中往往存在很多类似的页面和组件,这些类似的组件会被抽离成一套标准规范。', '在中台产品的研发过程中,会出现不同的设计规范和实现方式,但其中往往存在很多类似的页面和组件,这些类似的组件会被抽离成一套标准规范。',
@ -79,17 +82,20 @@ function fakeList(count: number): ListItemDataType[] {
'段落示意:蚂蚁金服设计平台 ant.design,用最小的工作量,无缝接入蚂蚁金服生态,提供跨越设计与开发的体验解决方案。蚂蚁金服设计平台 ant.design,用最小的工作量,无缝接入蚂蚁金服生态,提供跨越设计与开发的体验解决方案。', '段落示意:蚂蚁金服设计平台 ant.design,用最小的工作量,无缝接入蚂蚁金服生态,提供跨越设计与开发的体验解决方案。蚂蚁金服设计平台 ant.design,用最小的工作量,无缝接入蚂蚁金服生态,提供跨越设计与开发的体验解决方案。',
members: [ members: [
{ {
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/ZiESqWwCXBRQoaPONSJe.png', avatar:
'https://gw.alipayobjects.com/zos/rmsportal/ZiESqWwCXBRQoaPONSJe.png',
name: '曲丽丽', name: '曲丽丽',
id: 'member1', id: 'member1',
}, },
{ {
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/tBOxZPlITHqwlGjsJWaF.png', avatar:
'https://gw.alipayobjects.com/zos/rmsportal/tBOxZPlITHqwlGjsJWaF.png',
name: '王昭君', name: '王昭君',
id: 'member2', id: 'member2',
}, },
{ {
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/sBxjgqiuHMGRkIjqlQCd.png', avatar:
'https://gw.alipayobjects.com/zos/rmsportal/sBxjgqiuHMGRkIjqlQCd.png',
name: '董娜娜', name: '董娜娜',
id: 'member3', id: 'member3',
}, },

1
src/pages/list/search/applications/components/StandardFormRow/index.tsx

@ -1,6 +1,7 @@
import classNames from 'classnames'; import classNames from 'classnames';
import React from 'react'; import React from 'react';
import useStyles from './index.style'; import useStyles from './index.style';
type StandardFormRowProps = { type StandardFormRowProps = {
title?: string; title?: string;
last?: boolean; last?: boolean;

47
src/pages/list/search/applications/components/TagSelect/index.tsx

@ -4,6 +4,7 @@ import classNames from 'classnames';
import { useMergedState } from 'rc-util'; import { useMergedState } from 'rc-util';
import React, { type FC, useState } from 'react'; import React, { type FC, useState } from 'react';
import useStyles from './index.style'; import useStyles from './index.style';
const { CheckableTag } = Tag; const { CheckableTag } = Tag;
export interface TagSelectOptionProps { export interface TagSelectOptionProps {
value: string | number; value: string | number;
@ -26,7 +27,10 @@ const TagSelectOption: React.FC<TagSelectOptionProps> & {
TagSelectOption.isTagSelectOption = true; TagSelectOption.isTagSelectOption = true;
type TagSelectOptionElement = React.ReactElement<TagSelectOptionProps, typeof TagSelectOption>; type TagSelectOptionElement = React.ReactElement<
TagSelectOptionProps,
typeof TagSelectOption
>;
export interface TagSelectProps { export interface TagSelectProps {
onChange?: (value: (string | number)[]) => void; onChange?: (value: (string | number)[]) => void;
@ -48,20 +52,33 @@ const TagSelect: FC<TagSelectProps> & {
Option: typeof TagSelectOption; Option: typeof TagSelectOption;
} = (props) => { } = (props) => {
const { styles } = useStyles(); const { styles } = useStyles();
const { children, hideCheckAll = false, className, style, expandable, actionsText = {} } = props; const {
children,
hideCheckAll = false,
className,
style,
expandable,
actionsText = {},
} = props;
const [expand, setExpand] = useState<boolean>(false); const [expand, setExpand] = useState<boolean>(false);
const [value, setValue] = useMergedState<(string | number)[]>(props.defaultValue || [], { const [value, setValue] = useMergedState<(string | number)[]>(
value: props.value, props.defaultValue || [],
defaultValue: props.defaultValue, {
onChange: props.onChange, value: props.value,
}); defaultValue: props.defaultValue,
onChange: props.onChange,
},
);
const isTagSelectOption = (node: TagSelectOptionElement) => const isTagSelectOption = (node: TagSelectOptionElement) =>
node?.type && node?.type &&
(node.type.isTagSelectOption || node.type.displayName === 'TagSelectOption'); (node.type.isTagSelectOption ||
node.type.displayName === 'TagSelectOption');
const getAllTags = () => { const getAllTags = () => {
const childrenArray = React.Children.toArray(children) as TagSelectOptionElement[]; const childrenArray = React.Children.toArray(
children,
) as TagSelectOptionElement[];
const checkedTags = childrenArray const checkedTags = childrenArray
.filter((child) => isTagSelectOption(child)) .filter((child) => isTagSelectOption(child))
.map((child) => child.props.value); .map((child) => child.props.value);
@ -85,7 +102,11 @@ const TagSelect: FC<TagSelectProps> & {
setValue(checkedTags); setValue(checkedTags);
}; };
const checkedAll = getAllTags().length === value?.length; const checkedAll = getAllTags().length === value?.length;
const { expandText = '展开', collapseText = '收起', selectAllText = '全部' } = actionsText; const {
expandText = '展开',
collapseText = '收起',
selectAllText = '全部',
} = actionsText;
const cls = classNames(styles.tagSelect, className, { const cls = classNames(styles.tagSelect, className, {
[styles.hasExpandTag]: expandable, [styles.hasExpandTag]: expandable,
[styles.expanded]: expand, [styles.expanded]: expand,
@ -93,7 +114,11 @@ const TagSelect: FC<TagSelectProps> & {
return ( return (
<div className={cls} style={style}> <div className={cls} style={style}>
{hideCheckAll ? null : ( {hideCheckAll ? null : (
<CheckableTag checked={checkedAll} key="tag-select-__all__" onChange={onSelectAll}> <CheckableTag
checked={checkedAll}
key="tag-select-__all__"
onChange={onSelectAll}
>
{selectAllText} {selectAllText}
</CheckableTag> </CheckableTag>
)} )}

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

@ -5,7 +5,17 @@ import {
ShareAltOutlined, ShareAltOutlined,
} from '@ant-design/icons'; } from '@ant-design/icons';
import { useRequest } from '@umijs/max'; import { useRequest } from '@umijs/max';
import { Avatar, Card, Col, Dropdown, Form, List, Row, Select, Tooltip } from 'antd'; import {
Avatar,
Card,
Col,
Dropdown,
Form,
List,
Row,
Select,
Tooltip,
} from 'antd';
import numeral from 'numeral'; import numeral from 'numeral';
import type { FC } from 'react'; import type { FC } from 'react';
import React from 'react'; import React from 'react';
@ -97,11 +107,16 @@ export const Applications: FC<Record<string, any>> = () => {
<TagSelect expandable> <TagSelect expandable>
{categoryOptions {categoryOptions
.filter( .filter(
(category): category is { value: string | number; label: string } => (
category.value !== undefined && category.value !== null category,
): category is { value: string | number; label: string } =>
category.value !== undefined && category.value !== null,
) )
.map((category) => ( .map((category) => (
<TagSelect.Option value={category.value} key={category.value}> <TagSelect.Option
value={category.value}
key={category.value}
>
{category.label} {category.label}
</TagSelect.Option> </TagSelect.Option>
))} ))}
@ -202,7 +217,10 @@ export const Applications: FC<Record<string, any>> = () => {
</Dropdown>, </Dropdown>,
]} ]}
> >
<Card.Meta avatar={<Avatar size="small" src={item.avatar} />} title={item.title} /> <Card.Meta
avatar={<Avatar size="small" src={item.avatar} />}
title={item.title}
/>
<div> <div>
<CardInfo <CardInfo
activeUser={formatWan(item.activeUser)} activeUser={formatWan(item.activeUser)}

18
src/pages/list/search/articles/_mock.ts

@ -56,7 +56,10 @@ function fakeList(count: number): ListItemDataType[] {
owner: user[i % 10], owner: user[i % 10],
title: titles[i % 8], title: titles[i % 8],
avatar: avatars[i % 8], avatar: avatars[i % 8],
cover: parseInt(`${i / 4}`, 10) % 2 === 0 ? covers[i % 4] : covers[3 - (i % 4)], cover:
parseInt(`${i / 4}`, 10) % 2 === 0
? covers[i % 4]
: covers[3 - (i % 4)],
status: ['active', 'exception', 'normal'][i % 3] as status: ['active', 'exception', 'normal'][i % 3] as
| 'normal' | 'normal'
| 'exception' | 'exception'
@ -65,8 +68,8 @@ function fakeList(count: number): ListItemDataType[] {
percent: Math.ceil(Math.random() * 50) + 50, percent: Math.ceil(Math.random() * 50) + 50,
logo: avatars[i % 8], logo: avatars[i % 8],
href: 'https://ant.design', href: 'https://ant.design',
updatedAt: new Date(Date.now()- 1000 * 60 * 60 * 2 * i).getTime(), updatedAt: new Date(Date.now() - 1000 * 60 * 60 * 2 * i).getTime(),
createdAt: new Date(Date.now()- 1000 * 60 * 60 * 2 * i).getTime(), createdAt: new Date(Date.now() - 1000 * 60 * 60 * 2 * i).getTime(),
subDescription: desc[i % 5], subDescription: desc[i % 5],
description: description:
'在中台产品的研发过程中,会出现不同的设计规范和实现方式,但其中往往存在很多类似的页面和组件,这些类似的组件会被抽离成一套标准规范。', '在中台产品的研发过程中,会出现不同的设计规范和实现方式,但其中往往存在很多类似的页面和组件,这些类似的组件会被抽离成一套标准规范。',
@ -79,17 +82,20 @@ function fakeList(count: number): ListItemDataType[] {
'段落示意:蚂蚁金服设计平台 ant.design,用最小的工作量,无缝接入蚂蚁金服生态,提供跨越设计与开发的体验解决方案。蚂蚁金服设计平台 ant.design,用最小的工作量,无缝接入蚂蚁金服生态,提供跨越设计与开发的体验解决方案。', '段落示意:蚂蚁金服设计平台 ant.design,用最小的工作量,无缝接入蚂蚁金服生态,提供跨越设计与开发的体验解决方案。蚂蚁金服设计平台 ant.design,用最小的工作量,无缝接入蚂蚁金服生态,提供跨越设计与开发的体验解决方案。',
members: [ members: [
{ {
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/ZiESqWwCXBRQoaPONSJe.png', avatar:
'https://gw.alipayobjects.com/zos/rmsportal/ZiESqWwCXBRQoaPONSJe.png',
name: '曲丽丽', name: '曲丽丽',
id: 'member1', id: 'member1',
}, },
{ {
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/tBOxZPlITHqwlGjsJWaF.png', avatar:
'https://gw.alipayobjects.com/zos/rmsportal/tBOxZPlITHqwlGjsJWaF.png',
name: '王昭君', name: '王昭君',
id: 'member2', id: 'member2',
}, },
{ {
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/sBxjgqiuHMGRkIjqlQCd.png', avatar:
'https://gw.alipayobjects.com/zos/rmsportal/sBxjgqiuHMGRkIjqlQCd.png',
name: '董娜娜', name: '董娜娜',
id: 'member3', id: 'member3',
}, },

1
src/pages/list/search/articles/components/ArticleListContent/index.tsx

@ -2,6 +2,7 @@ import { Avatar } from 'antd';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import React from 'react'; import React from 'react';
import useStyles from './index.style'; import useStyles from './index.style';
type ArticleListContentProps = { type ArticleListContentProps = {
data: { data: {
content: React.ReactNode; content: React.ReactNode;

1
src/pages/list/search/articles/components/StandardFormRow/index.tsx

@ -1,6 +1,7 @@
import classNames from 'classnames'; import classNames from 'classnames';
import React from 'react'; import React from 'react';
import useStyles from './index.style'; import useStyles from './index.style';
type StandardFormRowProps = { type StandardFormRowProps = {
title?: string; title?: string;
last?: boolean; last?: boolean;

47
src/pages/list/search/articles/components/TagSelect/index.tsx

@ -4,6 +4,7 @@ import classNames from 'classnames';
import { useMergedState } from 'rc-util'; import { useMergedState } from 'rc-util';
import React, { type FC, useState } from 'react'; import React, { type FC, useState } from 'react';
import useStyles from './index.style'; import useStyles from './index.style';
const { CheckableTag } = Tag; const { CheckableTag } = Tag;
export interface TagSelectOptionProps { export interface TagSelectOptionProps {
value: string | number; value: string | number;
@ -26,7 +27,10 @@ const TagSelectOption: React.FC<TagSelectOptionProps> & {
TagSelectOption.isTagSelectOption = true; TagSelectOption.isTagSelectOption = true;
type TagSelectOptionElement = React.ReactElement<TagSelectOptionProps, typeof TagSelectOption>; type TagSelectOptionElement = React.ReactElement<
TagSelectOptionProps,
typeof TagSelectOption
>;
export interface TagSelectProps { export interface TagSelectProps {
onChange?: (value: (string | number)[]) => void; onChange?: (value: (string | number)[]) => void;
@ -48,20 +52,33 @@ const TagSelect: FC<TagSelectProps> & {
Option: typeof TagSelectOption; Option: typeof TagSelectOption;
} = (props) => { } = (props) => {
const { styles } = useStyles(); const { styles } = useStyles();
const { children, hideCheckAll = false, className, style, expandable, actionsText = {} } = props; const {
children,
hideCheckAll = false,
className,
style,
expandable,
actionsText = {},
} = props;
const [expand, setExpand] = useState<boolean>(false); const [expand, setExpand] = useState<boolean>(false);
const [value, setValue] = useMergedState<(string | number)[]>(props.defaultValue || [], { const [value, setValue] = useMergedState<(string | number)[]>(
value: props.value, props.defaultValue || [],
defaultValue: props.defaultValue, {
onChange: props.onChange, value: props.value,
}); defaultValue: props.defaultValue,
onChange: props.onChange,
},
);
const isTagSelectOption = (node: TagSelectOptionElement) => const isTagSelectOption = (node: TagSelectOptionElement) =>
node?.type && node?.type &&
(node.type.isTagSelectOption || node.type.displayName === 'TagSelectOption'); (node.type.isTagSelectOption ||
node.type.displayName === 'TagSelectOption');
const getAllTags = () => { const getAllTags = () => {
const childrenArray = React.Children.toArray(children) as TagSelectOptionElement[]; const childrenArray = React.Children.toArray(
children,
) as TagSelectOptionElement[];
const checkedTags = childrenArray const checkedTags = childrenArray
.filter((child) => isTagSelectOption(child)) .filter((child) => isTagSelectOption(child))
.map((child) => child.props.value); .map((child) => child.props.value);
@ -85,7 +102,11 @@ const TagSelect: FC<TagSelectProps> & {
setValue(checkedTags); setValue(checkedTags);
}; };
const checkedAll = getAllTags().length === value?.length; const checkedAll = getAllTags().length === value?.length;
const { expandText = '展开', collapseText = '收起', selectAllText = '全部' } = actionsText; const {
expandText = '展开',
collapseText = '收起',
selectAllText = '全部',
} = actionsText;
const cls = classNames(styles.tagSelect, className, { const cls = classNames(styles.tagSelect, className, {
[styles.hasExpandTag]: expandable, [styles.hasExpandTag]: expandable,
[styles.expanded]: expand, [styles.expanded]: expand,
@ -93,7 +114,11 @@ const TagSelect: FC<TagSelectProps> & {
return ( return (
<div className={cls} style={style}> <div className={cls} style={style}>
{hideCheckAll ? null : ( {hideCheckAll ? null : (
<CheckableTag checked={checkedAll} key="tag-select-__all__" onChange={onSelectAll}> <CheckableTag
checked={checkedAll}
key="tag-select-__all__"
onChange={onSelectAll}
>
{selectAllText} {selectAllText}
</CheckableTag> </CheckableTag>
)} )}

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

@ -1,4 +1,9 @@
import { LikeOutlined, LoadingOutlined, MessageOutlined, StarOutlined } from '@ant-design/icons'; import {
LikeOutlined,
LoadingOutlined,
MessageOutlined,
StarOutlined,
} from '@ant-design/icons';
import { useRequest } from '@umijs/max'; import { useRequest } from '@umijs/max';
import { Button, Card, Col, Form, List, Row, Select, Tag } from 'antd'; import { Button, Card, Col, Form, List, Row, Select, Tag } from 'antd';
import type { DefaultOptionType } from 'antd/es/select'; import type { DefaultOptionType } from 'antd/es/select';
@ -139,13 +144,18 @@ const Articles: FC = () => {
<StandardFormRow title="所属类目" block style={{ paddingBottom: 11 }}> <StandardFormRow title="所属类目" block style={{ paddingBottom: 11 }}>
<FormItem name="category"> <FormItem name="category">
<TagSelect expandable> <TagSelect expandable>
{categoryOptions {categoryOptions
.filter( .filter(
(category): category is { value: string | number; label: string } => (
category.value !== undefined && category.value !== null category,
): category is { value: string | number; label: string } =>
category.value !== undefined && category.value !== null,
) )
.map((category) => ( .map((category) => (
<TagSelect.Option value={category.value} key={category.value}> <TagSelect.Option
value={category.value}
key={category.value}
>
{category.label} {category.label}
</TagSelect.Option> </TagSelect.Option>
))} ))}

8
src/pages/list/search/index.tsx

@ -27,7 +27,9 @@ const Search: FC<SearchProps> = () => {
const match = useMatch(location.pathname); const match = useMatch(location.pathname);
const handleTabChange = (key: string) => { const handleTabChange = (key: string) => {
const url = const url =
match?.pathname === '/' ? '' : match?.pathname.substring(0, match.pathname.lastIndexOf('/')); match?.pathname === '/'
? ''
: match?.pathname.substring(0, match.pathname.lastIndexOf('/'));
switch (key) { switch (key) {
case 'articles': case 'articles':
history.push(`${url}/articles`); history.push(`${url}/articles`);
@ -49,7 +51,9 @@ const Search: FC<SearchProps> = () => {
}; };
const getTabKey = () => { const getTabKey = () => {
const tabKey = location.pathname.substring(location.pathname.lastIndexOf('/') + 1); const tabKey = location.pathname.substring(
location.pathname.lastIndexOf('/') + 1,
);
if (tabKey && tabKey !== '/') { if (tabKey && tabKey !== '/') {
return tabKey; return tabKey;
} }

18
src/pages/list/search/projects/_mock.ts

@ -56,7 +56,10 @@ function fakeList(count: number): ListItemDataType[] {
owner: user[i % 10], owner: user[i % 10],
title: titles[i % 8], title: titles[i % 8],
avatar: avatars[i % 8], avatar: avatars[i % 8],
cover: parseInt(`${i / 4}`, 10) % 2 === 0 ? covers[i % 4] : covers[3 - (i % 4)], cover:
parseInt(`${i / 4}`, 10) % 2 === 0
? covers[i % 4]
: covers[3 - (i % 4)],
status: ['active', 'exception', 'normal'][i % 3] as status: ['active', 'exception', 'normal'][i % 3] as
| 'normal' | 'normal'
| 'exception' | 'exception'
@ -65,8 +68,8 @@ function fakeList(count: number): ListItemDataType[] {
percent: Math.ceil(Math.random() * 50) + 50, percent: Math.ceil(Math.random() * 50) + 50,
logo: avatars[i % 8], logo: avatars[i % 8],
href: 'https://ant.design', href: 'https://ant.design',
updatedAt: new Date(Date.now()- 1000 * 60 * 60 * 2 * i).getTime(), updatedAt: new Date(Date.now() - 1000 * 60 * 60 * 2 * i).getTime(),
createdAt: new Date(Date.now()- 1000 * 60 * 60 * 2 * i).getTime(), createdAt: new Date(Date.now() - 1000 * 60 * 60 * 2 * i).getTime(),
subDescription: desc[i % 5], subDescription: desc[i % 5],
description: description:
'在中台产品的研发过程中,会出现不同的设计规范和实现方式,但其中往往存在很多类似的页面和组件,这些类似的组件会被抽离成一套标准规范。', '在中台产品的研发过程中,会出现不同的设计规范和实现方式,但其中往往存在很多类似的页面和组件,这些类似的组件会被抽离成一套标准规范。',
@ -79,17 +82,20 @@ function fakeList(count: number): ListItemDataType[] {
'段落示意:蚂蚁金服设计平台 ant.design,用最小的工作量,无缝接入蚂蚁金服生态,提供跨越设计与开发的体验解决方案。蚂蚁金服设计平台 ant.design,用最小的工作量,无缝接入蚂蚁金服生态,提供跨越设计与开发的体验解决方案。', '段落示意:蚂蚁金服设计平台 ant.design,用最小的工作量,无缝接入蚂蚁金服生态,提供跨越设计与开发的体验解决方案。蚂蚁金服设计平台 ant.design,用最小的工作量,无缝接入蚂蚁金服生态,提供跨越设计与开发的体验解决方案。',
members: [ members: [
{ {
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/ZiESqWwCXBRQoaPONSJe.png', avatar:
'https://gw.alipayobjects.com/zos/rmsportal/ZiESqWwCXBRQoaPONSJe.png',
name: '曲丽丽', name: '曲丽丽',
id: 'member1', id: 'member1',
}, },
{ {
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/tBOxZPlITHqwlGjsJWaF.png', avatar:
'https://gw.alipayobjects.com/zos/rmsportal/tBOxZPlITHqwlGjsJWaF.png',
name: '王昭君', name: '王昭君',
id: 'member2', id: 'member2',
}, },
{ {
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/sBxjgqiuHMGRkIjqlQCd.png', avatar:
'https://gw.alipayobjects.com/zos/rmsportal/sBxjgqiuHMGRkIjqlQCd.png',
name: '董娜娜', name: '董娜娜',
id: 'member3', id: 'member3',
}, },

20
src/pages/list/search/projects/components/AvatarList/index.tsx

@ -16,7 +16,9 @@ export type AvatarListProps = {
maxLength?: number; maxLength?: number;
excessItemsStyle?: React.CSSProperties; excessItemsStyle?: React.CSSProperties;
style?: React.CSSProperties; style?: React.CSSProperties;
children: React.ReactElement<AvatarItemProps> | React.ReactElement<AvatarItemProps>[]; children:
| React.ReactElement<AvatarItemProps>
| React.ReactElement<AvatarItemProps>[];
}; };
const avatarSizeToClassName = (size: SizeType | 'mini', styles: any) => const avatarSizeToClassName = (size: SizeType | 'mini', styles: any) =>
classNames(styles.avatarItem, { classNames(styles.avatarItem, {
@ -25,7 +27,12 @@ const avatarSizeToClassName = (size: SizeType | 'mini', styles: any) =>
[styles.avatarItemMini]: size === 'mini', [styles.avatarItemMini]: size === 'mini',
}); });
const Item: React.FC<AvatarItemProps> = ({ src, size, tips, onClick = () => {} }) => { const Item: React.FC<AvatarItemProps> = ({
src,
size,
tips,
onClick = () => {},
}) => {
const { styles } = useStyles(); const { styles } = useStyles();
const cls = avatarSizeToClassName(size || 'default', styles); const cls = avatarSizeToClassName(size || 'default', styles);
@ -54,7 +61,9 @@ const AvatarList: React.FC<AvatarListProps> & {
const { styles } = useStyles(); const { styles } = useStyles();
const numOfChildren = React.Children.count(children); const numOfChildren = React.Children.count(children);
const numToShow = maxLength >= numOfChildren ? numOfChildren : maxLength; const numToShow = maxLength >= numOfChildren ? numOfChildren : maxLength;
const childrenArray = React.Children.toArray(children) as React.ReactElement<AvatarItemProps>[]; const childrenArray = React.Children.toArray(
children,
) as React.ReactElement<AvatarItemProps>[];
const childrenWithProps = childrenArray.slice(0, numToShow).map((child) => const childrenWithProps = childrenArray.slice(0, numToShow).map((child) =>
React.cloneElement(child, { React.cloneElement(child, {
@ -65,7 +74,10 @@ const AvatarList: React.FC<AvatarListProps> & {
const cls = avatarSizeToClassName(size || 'default', styles); const cls = avatarSizeToClassName(size || 'default', styles);
childrenWithProps.push( childrenWithProps.push(
<li key="exceed" className={cls}> <li key="exceed" className={cls}>
<Avatar size={size} style={excessItemsStyle}>{`+${numOfChildren - maxLength}`}</Avatar> <Avatar
size={size}
style={excessItemsStyle}
>{`+${numOfChildren - maxLength}`}</Avatar>
</li>, </li>,
); );
} }

1
src/pages/list/search/projects/components/StandardFormRow/index.tsx

@ -1,6 +1,7 @@
import classNames from 'classnames'; import classNames from 'classnames';
import React from 'react'; import React from 'react';
import useStyles from './index.style'; import useStyles from './index.style';
type StandardFormRowProps = { type StandardFormRowProps = {
title?: string; title?: string;
last?: boolean; last?: boolean;

47
src/pages/list/search/projects/components/TagSelect/index.tsx

@ -4,6 +4,7 @@ import classNames from 'classnames';
import { useMergedState } from 'rc-util'; import { useMergedState } from 'rc-util';
import React, { type FC, useState } from 'react'; import React, { type FC, useState } from 'react';
import useStyles from './index.style'; import useStyles from './index.style';
const { CheckableTag } = Tag; const { CheckableTag } = Tag;
export interface TagSelectOptionProps { export interface TagSelectOptionProps {
value: string | number; value: string | number;
@ -26,7 +27,10 @@ const TagSelectOption: React.FC<TagSelectOptionProps> & {
TagSelectOption.isTagSelectOption = true; TagSelectOption.isTagSelectOption = true;
type TagSelectOptionElement = React.ReactElement<TagSelectOptionProps, typeof TagSelectOption>; type TagSelectOptionElement = React.ReactElement<
TagSelectOptionProps,
typeof TagSelectOption
>;
export interface TagSelectProps { export interface TagSelectProps {
onChange?: (value: (string | number)[]) => void; onChange?: (value: (string | number)[]) => void;
@ -48,20 +52,33 @@ const TagSelect: FC<TagSelectProps> & {
Option: typeof TagSelectOption; Option: typeof TagSelectOption;
} = (props) => { } = (props) => {
const { styles } = useStyles(); const { styles } = useStyles();
const { children, hideCheckAll = false, className, style, expandable, actionsText = {} } = props; const {
children,
hideCheckAll = false,
className,
style,
expandable,
actionsText = {},
} = props;
const [expand, setExpand] = useState<boolean>(false); const [expand, setExpand] = useState<boolean>(false);
const [value, setValue] = useMergedState<(string | number)[]>(props.defaultValue || [], { const [value, setValue] = useMergedState<(string | number)[]>(
value: props.value, props.defaultValue || [],
defaultValue: props.defaultValue, {
onChange: props.onChange, value: props.value,
}); defaultValue: props.defaultValue,
onChange: props.onChange,
},
);
const isTagSelectOption = (node: TagSelectOptionElement) => const isTagSelectOption = (node: TagSelectOptionElement) =>
node?.type && node?.type &&
(node.type.isTagSelectOption || node.type.displayName === 'TagSelectOption'); (node.type.isTagSelectOption ||
node.type.displayName === 'TagSelectOption');
const getAllTags = () => { const getAllTags = () => {
const childrenArray = React.Children.toArray(children) as TagSelectOptionElement[]; const childrenArray = React.Children.toArray(
children,
) as TagSelectOptionElement[];
const checkedTags = childrenArray const checkedTags = childrenArray
.filter((child) => isTagSelectOption(child)) .filter((child) => isTagSelectOption(child))
.map((child) => child.props.value); .map((child) => child.props.value);
@ -85,7 +102,11 @@ const TagSelect: FC<TagSelectProps> & {
setValue(checkedTags); setValue(checkedTags);
}; };
const checkedAll = getAllTags().length === value?.length; const checkedAll = getAllTags().length === value?.length;
const { expandText = '展开', collapseText = '收起', selectAllText = '全部' } = actionsText; const {
expandText = '展开',
collapseText = '收起',
selectAllText = '全部',
} = actionsText;
const cls = classNames(styles.tagSelect, className, { const cls = classNames(styles.tagSelect, className, {
[styles.hasExpandTag]: expandable, [styles.hasExpandTag]: expandable,
[styles.expanded]: expand, [styles.expanded]: expand,
@ -93,7 +114,11 @@ const TagSelect: FC<TagSelectProps> & {
return ( return (
<div className={cls} style={style}> <div className={cls} style={style}>
{hideCheckAll ? null : ( {hideCheckAll ? null : (
<CheckableTag checked={checkedAll} key="tag-select-__all__" onChange={onSelectAll}> <CheckableTag
checked={checkedAll}
key="tag-select-__all__"
onChange={onSelectAll}
>
{selectAllText} {selectAllText}
</CheckableTag> </CheckableTag>
)} )}

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

@ -41,7 +41,11 @@ const Projects: FC = () => {
dataSource={list} dataSource={list}
renderItem={(item) => ( renderItem={(item) => (
<List.Item> <List.Item>
<Card className={styles.card} hoverable cover={<img alt={item.title} src={item.cover} />}> <Card
className={styles.card}
hoverable
cover={<img alt={item.title} src={item.cover} />}
>
<Card.Meta <Card.Meta
title={<a>{item.title}</a>} title={<a>{item.title}</a>}
description={ description={
@ -105,11 +109,16 @@ const Projects: FC = () => {
<TagSelect expandable> <TagSelect expandable>
{categoryOptions {categoryOptions
.filter( .filter(
(category): category is { value: string | number; label: string } => (
category.value !== undefined && category.value !== null category,
): category is { value: string | number; label: string } =>
category.value !== undefined && category.value !== null,
) )
.map((category) => ( .map((category) => (
<TagSelect.Option value={category.value} key={category.value}> <TagSelect.Option
value={category.value}
key={category.value}
>
{category.label} {category.label}
</TagSelect.Option> </TagSelect.Option>
))} ))}

22
src/pages/list/table-list/_mock.ts

@ -1,5 +1,5 @@
import type { Request, Response } from 'express';
import { parse } from 'node:url'; import { parse } from 'node:url';
import type { Request, Response } from 'express';
import type { TableListItem, TableListParams } from './data.d'; import type { TableListItem, TableListParams } from './data.d';
// mock tableListDataSource // mock tableListDataSource
@ -34,7 +34,10 @@ let tableListDataSource = genList(1, 100);
function getRule(req: Request, res: Response, u: string) { function getRule(req: Request, res: Response, u: string) {
let realUrl = u; let realUrl = u;
if (!realUrl || Object.prototype.toString.call(realUrl) !== '[object String]') { if (
!realUrl ||
Object.prototype.toString.call(realUrl) !== '[object String]'
) {
realUrl = req.url; realUrl = req.url;
} }
const { current = 1, pageSize = 10 } = req.query; const { current = 1, pageSize = 10 } = req.query;
@ -84,7 +87,9 @@ function getRule(req: Request, res: Response, u: string) {
} }
if (params.name) { if (params.name) {
dataSource = dataSource.filter((data) => data.name.includes(params.name || '')); dataSource = dataSource.filter((data) =>
data.name.includes(params.name || ''),
);
} }
let finalPageSize = 10; let finalPageSize = 10;
@ -105,17 +110,22 @@ function getRule(req: Request, res: Response, u: string) {
function postRule(req: Request, res: Response, u: string, b: Request) { function postRule(req: Request, res: Response, u: string, b: Request) {
let realUrl = u; let realUrl = u;
if (!realUrl || Object.prototype.toString.call(realUrl) !== '[object String]') { if (
!realUrl ||
Object.prototype.toString.call(realUrl) !== '[object String]'
) {
realUrl = req.url; realUrl = req.url;
} }
const body = (b?.body) || req.body; const body = b?.body || req.body;
const { name, desc, key } = body; const { name, desc, key } = body;
switch (req.method) { switch (req.method) {
/* eslint no-case-declarations:0 */ /* eslint no-case-declarations:0 */
case 'DELETE': case 'DELETE':
tableListDataSource = tableListDataSource.filter((item) => key.indexOf(item.key) === -1); tableListDataSource = tableListDataSource.filter(
(item) => key.indexOf(item.key) === -1,
);
break; break;
case 'POST': case 'POST':
(() => { (() => {

22
src/pages/list/table-list/index.tsx

@ -1,5 +1,9 @@
import { PlusOutlined } from '@ant-design/icons'; import { PlusOutlined } from '@ant-design/icons';
import type { ActionType, ProColumns, ProDescriptionsItemProps } from '@ant-design/pro-components'; import type {
ActionType,
ProColumns,
ProDescriptionsItemProps,
} from '@ant-design/pro-components';
import { import {
FooterToolbar, FooterToolbar,
ModalForm, ModalForm,
@ -15,6 +19,7 @@ import type { FormValueType } from './components/UpdateForm';
import UpdateForm from './components/UpdateForm'; import UpdateForm from './components/UpdateForm';
import type { TableListItem, TableListPagination } from './data'; import type { TableListItem, TableListPagination } from './data';
import { addRule, removeRule, rule, updateRule } from './service'; import { addRule, removeRule, rule, updateRule } from './service';
/** /**
* *
* *
@ -41,7 +46,10 @@ const handleAdd = async (fields: TableListItem) => {
* @param fields * @param fields
*/ */
const handleUpdate = async (fields: FormValueType, currentRow?: TableListItem) => { const handleUpdate = async (
fields: FormValueType,
currentRow?: TableListItem,
) => {
const hide = message.loading('正在配置'); const hide = message.loading('正在配置');
try { try {
@ -87,7 +95,8 @@ const TableList: React.FC = () => {
const [createModalVisible, handleModalVisible] = useState<boolean>(false); const [createModalVisible, handleModalVisible] = useState<boolean>(false);
/** 分布更新窗口的弹窗 */ /** 分布更新窗口的弹窗 */
const [updateModalVisible, handleUpdateModalVisible] = useState<boolean>(false); const [updateModalVisible, handleUpdateModalVisible] =
useState<boolean>(false);
const [showDetail, setShowDetail] = useState<boolean>(false); const [showDetail, setShowDetail] = useState<boolean>(false);
const actionRef = useRef<ActionType>(); const actionRef = useRef<ActionType>();
const [currentRow, setCurrentRow] = useState<TableListItem>(); const [currentRow, setCurrentRow] = useState<TableListItem>();
@ -229,7 +238,12 @@ const TableList: React.FC = () => {
</a>{' '} </a>{' '}
&nbsp;&nbsp; &nbsp;&nbsp;
<span> <span>
{selectedRowsState.reduce((pre, item) => pre + (item.callNo ?? 0), 0)} {' '}
{selectedRowsState.reduce(
(pre, item) => pre + (item.callNo ?? 0),
0,
)}{' '}
</span> </span>
</div> </div>
} }

15
src/pages/list/table-list/service.ts

@ -29,7 +29,10 @@ export async function rule(
} }
/** 新建规则 PUT /api/rule */ /** 新建规则 PUT /api/rule */
export async function updateRule(data: { [key: string]: any }, options?: { [key: string]: any }) { export async function updateRule(
data: { [key: string]: any },
options?: { [key: string]: any },
) {
return request<TableListItem>('/api/rule', { return request<TableListItem>('/api/rule', {
data, data,
method: 'PUT', method: 'PUT',
@ -38,7 +41,10 @@ export async function updateRule(data: { [key: string]: any }, options?: { [key:
} }
/** 新建规则 POST /api/rule */ /** 新建规则 POST /api/rule */
export async function addRule(data: { [key: string]: any }, options?: { [key: string]: any }) { export async function addRule(
data: { [key: string]: any },
options?: { [key: string]: any },
) {
return request<TableListItem>('/api/rule', { return request<TableListItem>('/api/rule', {
data, data,
method: 'POST', method: 'POST',
@ -47,7 +53,10 @@ export async function addRule(data: { [key: string]: any }, options?: { [key: st
} }
/** 删除规则 DELETE /api/rule */ /** 删除规则 DELETE /api/rule */
export async function removeRule(data: { key: number[] }, options?: { [key: string]: any }) { export async function removeRule(
data: { key: number[] },
options?: { [key: string]: any },
) {
return request<Record<string, any>>('/api/rule', { return request<Record<string, any>>('/api/rule', {
data, data,
method: 'DELETE', method: 'DELETE',

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

@ -4,7 +4,11 @@ import {
EllipsisOutlined, EllipsisOutlined,
InfoCircleOutlined, InfoCircleOutlined,
} from '@ant-design/icons'; } from '@ant-design/icons';
import { GridContent, PageContainer, RouteContext } from '@ant-design/pro-components'; import {
GridContent,
PageContainer,
RouteContext,
} from '@ant-design/pro-components';
import { useRequest } from '@umijs/max'; import { useRequest } from '@umijs/max';
import { import {
Badge, Badge,
@ -160,15 +164,23 @@ const Advanced: FC = () => {
const description = ( const description = (
<RouteContext.Consumer> <RouteContext.Consumer>
{({ isMobile }) => ( {({ isMobile }) => (
<Descriptions className={styles.headerList} size="small" column={isMobile ? 1 : 2}> <Descriptions
className={styles.headerList}
size="small"
column={isMobile ? 1 : 2}
>
<Descriptions.Item label="创建人"></Descriptions.Item> <Descriptions.Item label="创建人"></Descriptions.Item>
<Descriptions.Item label="订购产品">XX </Descriptions.Item> <Descriptions.Item label="订购产品">XX </Descriptions.Item>
<Descriptions.Item label="创建时间">2017-07-07</Descriptions.Item> <Descriptions.Item label="创建时间">2017-07-07</Descriptions.Item>
<Descriptions.Item label="关联单据"> <Descriptions.Item label="关联单据">
<a href="">12421</a> <a href="">12421</a>
</Descriptions.Item> </Descriptions.Item>
<Descriptions.Item label="生效日期">2017-07-07 ~ 2017-08-08</Descriptions.Item> <Descriptions.Item label="生效日期">
<Descriptions.Item label="备注"></Descriptions.Item> 2017-07-07 ~ 2017-08-08
</Descriptions.Item>
<Descriptions.Item label="备注">
</Descriptions.Item>
</Descriptions> </Descriptions>
)} )}
</RouteContext.Consumer> </RouteContext.Consumer>
@ -252,7 +264,11 @@ const Advanced: FC = () => {
); );
if (status === 'process') { if (status === 'process') {
return ( return (
<Popover placement="topLeft" arrowPointAtCenter content={popoverContent}> <Popover
placement="topLeft"
arrowPointAtCenter
content={popoverContent}
>
<span>{dot}</span> <span>{dot}</span>
</Popover> </Popover>
); );
@ -358,9 +374,15 @@ const Advanced: FC = () => {
}} }}
> >
<Descriptions.Item label="用户姓名"></Descriptions.Item> <Descriptions.Item label="用户姓名"></Descriptions.Item>
<Descriptions.Item label="会员卡号">32943898021309809423</Descriptions.Item> <Descriptions.Item label="会员卡号">
<Descriptions.Item label="身份证">3321944288191034921</Descriptions.Item> 32943898021309809423
<Descriptions.Item label="联系方式">18112345678</Descriptions.Item> </Descriptions.Item>
<Descriptions.Item label="身份证">
3321944288191034921
</Descriptions.Item>
<Descriptions.Item label="联系方式">
18112345678
</Descriptions.Item>
<Descriptions.Item label="联系地址"> <Descriptions.Item label="联系地址">
18100000000 西 18100000000 西
</Descriptions.Item> </Descriptions.Item>
@ -372,7 +394,9 @@ const Advanced: FC = () => {
title="信息组" title="信息组"
> >
<Descriptions.Item label="某某数据">725</Descriptions.Item> <Descriptions.Item label="某某数据">725</Descriptions.Item>
<Descriptions.Item label="该数据更新时间">2017-08-08</Descriptions.Item> <Descriptions.Item label="该数据更新时间">
2017-08-08
</Descriptions.Item>
<Descriptions.Item <Descriptions.Item
label={ label={
<span> <span>
@ -390,7 +414,9 @@ const Advanced: FC = () => {
> >
725 725
</Descriptions.Item> </Descriptions.Item>
<Descriptions.Item label="该数据更新时间">2017-08-08</Descriptions.Item> <Descriptions.Item label="该数据更新时间">
2017-08-08
</Descriptions.Item>
</Descriptions> </Descriptions>
<h4 <h4
style={{ style={{
@ -408,8 +434,12 @@ const Advanced: FC = () => {
> >
<Descriptions.Item label="负责人"></Descriptions.Item> <Descriptions.Item label="负责人"></Descriptions.Item>
<Descriptions.Item label="角色码">1234567</Descriptions.Item> <Descriptions.Item label="角色码">1234567</Descriptions.Item>
<Descriptions.Item label="所属部门">XX公司 - YY部</Descriptions.Item> <Descriptions.Item label="所属部门">
<Descriptions.Item label="过期时间">2017-08-08</Descriptions.Item> XX公司 - YY部
</Descriptions.Item>
<Descriptions.Item label="过期时间">
2017-08-08
</Descriptions.Item>
<Descriptions.Item label="描述"> <Descriptions.Item label="描述">
... ...
</Descriptions.Item> </Descriptions.Item>
@ -451,7 +481,11 @@ const Advanced: FC = () => {
> >
<Empty /> <Empty />
</Card> </Card>
<Card bordered={false} tabList={operationTabList} onTabChange={onOperationTabChange}> <Card
bordered={false}
tabList={operationTabList}
onTabChange={onOperationTabChange}
>
{contentList[tabStatus.operationKey] as React.ReactNode} {contentList[tabStatus.operationKey] as React.ReactNode}
</Card> </Card>
</GridContent> </GridContent>

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

@ -7,6 +7,7 @@ import React from 'react';
import type { BasicGood, BasicProgress } from './data.d'; import type { BasicGood, BasicProgress } from './data.d';
import { queryBasicProfile } from './service'; import { queryBasicProfile } from './service';
import useStyles from './style.style'; import useStyles from './style.style';
const progressColumns: ProColumns<BasicProgress>[] = [ const progressColumns: ProColumns<BasicProgress>[] = [
{ {
title: '时间', title: '时间',
@ -191,7 +192,9 @@ const Basic: FC = () => {
<Descriptions.Item label="用户姓名"></Descriptions.Item> <Descriptions.Item label="用户姓名"></Descriptions.Item>
<Descriptions.Item label="联系电话">18100000000</Descriptions.Item> <Descriptions.Item label="联系电话">18100000000</Descriptions.Item>
<Descriptions.Item label="常用快递"></Descriptions.Item> <Descriptions.Item label="常用快递"></Descriptions.Item>
<Descriptions.Item label="取货地址">西18</Descriptions.Item> <Descriptions.Item label="取货地址">
西18
</Descriptions.Item>
<Descriptions.Item label="备注"></Descriptions.Item> <Descriptions.Item label="备注"></Descriptions.Item>
</Descriptions> </Descriptions>
<Divider <Divider

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

@ -56,7 +56,9 @@ export default () => {
<Descriptions title="项目名称"> <Descriptions title="项目名称">
<Descriptions.Item label="项目 ID">23421</Descriptions.Item> <Descriptions.Item label="项目 ID">23421</Descriptions.Item>
<Descriptions.Item label="负责人"></Descriptions.Item> <Descriptions.Item label="负责人"></Descriptions.Item>
<Descriptions.Item label="生效时间">2016-12-12 ~ 2017-12-12</Descriptions.Item> <Descriptions.Item label="生效时间">
2016-12-12 ~ 2017-12-12
</Descriptions.Item>
</Descriptions> </Descriptions>
<br /> <br />
<Steps progressDot current={1}> <Steps progressDot current={1}>

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

@ -1,9 +1,14 @@
import { addRule } from '@/services/ant-design-pro/api';
import { PlusOutlined } from '@ant-design/icons'; import { PlusOutlined } from '@ant-design/icons';
import { type ActionType, ModalForm, ProFormText, ProFormTextArea } from '@ant-design/pro-components'; import {
type ActionType,
ModalForm,
ProFormText,
ProFormTextArea,
} from '@ant-design/pro-components';
import { FormattedMessage, useIntl, useRequest } from '@umijs/max'; import { FormattedMessage, useIntl, useRequest } from '@umijs/max';
import { Button, message } from 'antd'; import { Button, message } from 'antd';
import type { FC } from 'react'; import type { FC } from 'react';
import { addRule } from '@/services/ant-design-pro/api';
interface CreateFormProps { interface CreateFormProps {
reload?: ActionType['reload']; reload?: ActionType['reload'];

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

@ -1,4 +1,3 @@
import { updateRule } from '@/services/ant-design-pro/api';
import { import {
ProFormDateTimePicker, ProFormDateTimePicker,
ProFormRadio, ProFormRadio,
@ -8,8 +7,9 @@ import {
StepsForm, StepsForm,
} from '@ant-design/pro-components'; } from '@ant-design/pro-components';
import { FormattedMessage, useIntl, useRequest } from '@umijs/max'; import { FormattedMessage, useIntl, useRequest } from '@umijs/max';
import { message, Modal } from 'antd'; import { Modal, message } from 'antd';
import React, { cloneElement, useCallback, useState } from 'react'; import React, { cloneElement, useCallback, useState } from 'react';
import { updateRule } from '@/services/ant-design-pro/api';
export type FormValueType = { export type FormValueType = {
target?: string; target?: string;

17
src/pages/table-list/index.tsx

@ -1,5 +1,8 @@
import { removeRule, rule } from '@/services/ant-design-pro/api'; import type {
import type { ActionType, ProColumns, ProDescriptionsItemProps } from '@ant-design/pro-components'; ActionType,
ProColumns,
ProDescriptionsItemProps,
} from '@ant-design/pro-components';
import { import {
FooterToolbar, FooterToolbar,
PageContainer, PageContainer,
@ -9,6 +12,7 @@ import {
import { FormattedMessage, useIntl, useRequest } from '@umijs/max'; import { FormattedMessage, useIntl, useRequest } from '@umijs/max';
import { Button, Drawer, Input, message } from 'antd'; import { Button, Drawer, Input, message } from 'antd';
import React, { useCallback, useRef, useState } from 'react'; import React, { useCallback, useRef, useState } from 'react';
import { removeRule, rule } from '@/services/ant-design-pro/api';
import CreateForm from './components/CreateForm'; import CreateForm from './components/CreateForm';
import UpdateForm from './components/UpdateForm'; import UpdateForm from './components/UpdateForm';
@ -178,7 +182,10 @@ const TableList: React.FC = () => {
<UpdateForm <UpdateForm
trigger={ trigger={
<a> <a>
<FormattedMessage id="pages.searchTable.config" defaultMessage="Configuration" /> <FormattedMessage
id="pages.searchTable.config"
defaultMessage="Configuration"
/>
</a> </a>
} }
key="config" key="config"
@ -231,7 +238,9 @@ const TableList: React.FC = () => {
search={{ search={{
labelWidth: 120, labelWidth: 120,
}} }}
toolBarRender={() => [<CreateForm key="create" reload={actionRef.current?.reload} />]} toolBarRender={() => [
<CreateForm key="create" reload={actionRef.current?.reload} />,
]}
request={rule} request={rule}
columns={columns} columns={columns}
rowSelection={{ rowSelection={{

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

@ -1,5 +1,16 @@
import { history, Link, useRequest } from '@umijs/max'; import { history, Link, useRequest } from '@umijs/max';
import { Button, Col, Form, Input, message, Popover, Progress, Row, Select, Space } from 'antd'; import {
Button,
Col,
Form,
Input,
message,
Popover,
Progress,
Row,
Select,
Space,
} from 'antd';
import type { Store } from 'antd/es/form/interface'; import type { Store } from 'antd/es/form/interface';
import type { FC } from 'react'; import type { FC } from 'react';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
@ -198,7 +209,11 @@ const Register: FC = () => {
}, },
]} ]}
> >
<Input size="large" type="password" placeholder="至少6位密码,区分大小写" /> <Input
size="large"
type="password"
placeholder="至少6位密码,区分大小写"
/>
</FormItem> </FormItem>
</Popover> </Popover>
<FormItem <FormItem

Loading…
Cancel
Save