Browse Source

css

pull/10914/head
期贤 3 years ago
parent
commit
440197a7bf
  1. 28
      src/pages/User/register-result/style.style.ts
  2. 28
      src/pages/User/register/style.style.ts
  3. 70
      src/pages/account/center/Center.style.ts
  4. 58
      src/pages/account/center/components/Applications/index.style.ts
  5. 47
      src/pages/account/center/components/Applications/index.tsx
  6. 14
      src/pages/account/center/components/ArticleListContent/index.style.ts
  7. 10
      src/pages/account/center/components/ArticleListContent/index.tsx
  8. 8
      src/pages/account/center/components/Articles/index.style.ts
  9. 22
      src/pages/account/center/components/Articles/index.tsx
  10. 32
      src/pages/account/center/components/AvatarList/index.style.ts
  11. 43
      src/pages/account/center/components/AvatarList/index.tsx
  12. 48
      src/pages/account/center/components/Projects/index.style.ts
  13. 29
      src/pages/account/center/components/Projects/index.tsx
  14. 70
      src/pages/account/center/index.tsx
  15. 42
      src/pages/account/settings/components/BaseView.style.ts
  16. 10
      src/pages/account/settings/components/PhoneView.tsx
  17. 56
      src/pages/account/settings/index.tsx
  18. 72
      src/pages/account/settings/style.style.ts
  19. 31
      src/pages/dashboard/analysis/components/Charts/Bar/index.tsx
  20. 82
      src/pages/dashboard/analysis/components/Charts/ChartCard/index.style.ts
  21. 14
      src/pages/dashboard/analysis/components/Charts/Field/index.style.ts
  22. 4
      src/pages/dashboard/analysis/components/Charts/Field/index.tsx
  23. 22
      src/pages/dashboard/analysis/components/Charts/MiniArea/index.tsx
  24. 31
      src/pages/dashboard/analysis/components/Charts/MiniBar/index.tsx
  25. 8
      src/pages/dashboard/analysis/components/Charts/MiniProgress/index.tsx
  26. 90
      src/pages/dashboard/analysis/components/Charts/Pie/index.tsx
  27. 47
      src/pages/dashboard/analysis/components/Charts/TagCloud/index.tsx
  28. 58
      src/pages/dashboard/analysis/components/Charts/TimelineChart/index.tsx
  29. 34
      src/pages/dashboard/analysis/components/Charts/WaterWave/index.tsx
  30. 26
      src/pages/dashboard/analysis/components/Charts/index.style.ts
  31. 55
      src/pages/dashboard/analysis/components/IntroduceRow.tsx
  32. 42
      src/pages/dashboard/analysis/components/NumberInfo/index.style.ts
  33. 23
      src/pages/dashboard/analysis/components/NumberInfo/index.tsx
  34. 25
      src/pages/dashboard/analysis/components/OfflineData.tsx
  35. 30
      src/pages/dashboard/analysis/components/ProportionSales.tsx
  36. 70
      src/pages/dashboard/analysis/components/SalesCard.tsx
  37. 18
      src/pages/dashboard/analysis/components/Trend/index.style.ts
  38. 20
      src/pages/dashboard/analysis/components/Trend/index.tsx
  39. 72
      src/pages/dashboard/analysis/index.tsx
  40. 136
      src/pages/dashboard/analysis/style.style.ts
  41. 2
      src/pages/dashboard/analysis/utils/utils.style.ts
  42. 67
      src/pages/dashboard/monitor/components/ActiveChart/index.style.ts
  43. 22
      src/pages/dashboard/monitor/components/Charts/MiniArea/index.tsx
  44. 91
      src/pages/dashboard/monitor/components/Charts/Pie/index.tsx
  45. 47
      src/pages/dashboard/monitor/components/Charts/TagCloud/index.tsx
  46. 34
      src/pages/dashboard/monitor/components/Charts/WaterWave/index.tsx
  47. 71
      src/pages/dashboard/monitor/index.tsx
  48. 10
      src/pages/dashboard/monitor/style.style.ts
  49. 16
      src/pages/dashboard/workplace/components/EditableLinkGroup/index.style.ts
  50. 14
      src/pages/dashboard/workplace/components/EditableLinkGroup/index.tsx
  51. 322
      src/pages/dashboard/workplace/components/Radar/index.tsx
  52. 79
      src/pages/dashboard/workplace/index.tsx
  53. 158
      src/pages/dashboard/workplace/style.style.ts
  54. 85
      src/pages/form/advanced-form/components/TableForm.tsx
  55. 196
      src/pages/form/advanced-form/index.tsx
  56. 52
      src/pages/form/advanced-form/style.style.ts
  57. 63
      src/pages/form/basic-form/index.tsx
  58. 4
      src/pages/form/basic-form/style.style.ts
  59. 62
      src/pages/form/step-form/index.tsx
  60. 10
      src/pages/form/step-form/style.style.ts
  61. 32
      src/pages/list/basic-list/components/OperationModal.tsx
  62. 74
      src/pages/list/basic-list/index.tsx
  63. 94
      src/pages/list/basic-list/style.style.ts
  64. 2
      src/pages/list/basic-list/utils/utils.style.ts
  65. 45
      src/pages/list/card-list/index.tsx
  66. 56
      src/pages/list/card-list/style.style.ts
  67. 2
      src/pages/list/card-list/utils/utils.style.ts
  68. 52
      src/pages/list/search/applications/components/StandardFormRow/index.style.ts
  69. 6
      src/pages/list/search/applications/components/StandardFormRow/index.tsx
  70. 38
      src/pages/list/search/applications/components/TagSelect/index.style.ts
  71. 47
      src/pages/list/search/applications/components/TagSelect/index.tsx
  72. 70
      src/pages/list/search/applications/index.tsx
  73. 56
      src/pages/list/search/applications/style.style.ts
  74. 2
      src/pages/list/search/applications/utils/utils.style.ts
  75. 14
      src/pages/list/search/articles/components/ArticleListContent/index.style.ts
  76. 10
      src/pages/list/search/articles/components/ArticleListContent/index.tsx
  77. 54
      src/pages/list/search/articles/components/StandardFormRow/index.style.ts
  78. 6
      src/pages/list/search/articles/components/StandardFormRow/index.tsx
  79. 38
      src/pages/list/search/articles/components/TagSelect/index.style.ts
  80. 47
      src/pages/list/search/articles/components/TagSelect/index.tsx
  81. 71
      src/pages/list/search/articles/index.tsx
  82. 12
      src/pages/list/search/articles/style.style.ts
  83. 32
      src/pages/list/search/projects/components/AvatarList/index.style.ts
  84. 43
      src/pages/list/search/projects/components/AvatarList/index.tsx
  85. 54
      src/pages/list/search/projects/components/StandardFormRow/index.style.ts
  86. 6
      src/pages/list/search/projects/components/StandardFormRow/index.tsx
  87. 38
      src/pages/list/search/projects/components/TagSelect/index.style.ts
  88. 47
      src/pages/list/search/projects/components/TagSelect/index.tsx
  89. 34
      src/pages/list/search/projects/index.tsx
  90. 48
      src/pages/list/search/projects/style.style.ts
  91. 2
      src/pages/list/search/projects/utils/utils.style.ts
  92. 34
      src/pages/profile/advanced/style.style.ts
  93. 100
      src/pages/profile/basic/index.tsx
  94. 8
      src/pages/profile/basic/style.style.ts
  95. 8
      src/pages/result/fail/index.style.ts
  96. 16
      src/pages/result/success/index.style.ts
  97. 10
      src/pages/user/register-result/index.tsx
  98. 100
      src/pages/user/register/index.tsx

28
src/pages/User/register-result/style.style.ts

@ -1,27 +1,27 @@
import { createStyles } from "antd-style";
import { createStyles } from 'antd-style';
const useStyles = createStyles(() => {
return {
registerResult: {
width: "800px",
minHeight: "400px",
margin: "auto",
padding: "80px",
background: "none",
width: '800px',
minHeight: '400px',
margin: 'auto',
padding: '80px',
background: 'none',
},
".anticon": {
fontSize: "64px",
'.anticon': {
fontSize: '64px',
},
title: {
marginTop: "32px",
fontSize: "20px",
lineHeight: "28px",
marginTop: '32px',
fontSize: '20px',
lineHeight: '28px',
},
actions: {
marginTop: "40px",
marginTop: '40px',
},
"a + a": {
marginLeft: "8px",
'a + a': {
marginLeft: '8px',
},
};
});

28
src/pages/User/register/style.style.ts

@ -1,30 +1,30 @@
import { createStyles } from "antd-style";
import { createStyles } from 'antd-style';
const useStyles = createStyles(({ token }) => {
return {
main: {
width: "368px",
margin: "0 auto",
width: '368px',
margin: '0 auto',
},
h3: {
marginBottom: "20px",
fontSize: "16px",
marginBottom: '20px',
fontSize: '16px',
},
password: {
marginBottom: "24px",
marginBottom: '24px',
},
".ant-form-item-explain": {
display: "none",
'.ant-form-item-explain': {
display: 'none',
},
getCaptcha: {
display: "block",
width: "100%",
display: 'block',
width: '100%',
},
submit: {
width: "50%",
width: '50%',
},
login: {
float: "right",
float: 'right',
lineHeight: token.controlHeight,
},
success: {
@ -36,8 +36,8 @@ const useStyles = createStyles(({ token }) => {
error: {
color: token.colorError,
},
".progress-pass > .progress": {},
".ant-progress-bg": {
'.progress-pass > .progress': {},
'.ant-progress-bg': {
backgroundColor: token.colorWarning,
},
};

70
src/pages/account/center/Center.style.ts

@ -1,65 +1,65 @@
import { createStyles } from "antd-style";
import { createStyles } from 'antd-style';
const useStyles = createStyles(({ token }) => {
return {
avatarHolder: {
marginBottom: "24px",
textAlign: "center",
"& > img": { width: "104px", height: "104px", marginBottom: "20px" },
marginBottom: '24px',
textAlign: 'center',
'& > img': { width: '104px', height: '104px', marginBottom: '20px' },
},
name: {
marginBottom: "4px",
marginBottom: '4px',
color: token.colorTextHeading,
fontWeight: "500",
fontSize: "20px",
lineHeight: "28px",
fontWeight: '500',
fontSize: '20px',
lineHeight: '28px',
},
detail: {},
p: {
position: "relative",
marginBottom: "8px",
paddingLeft: "26px",
"&:last-child": { marginBottom: "0" },
position: 'relative',
marginBottom: '8px',
paddingLeft: '26px',
'&:last-child': { marginBottom: '0' },
},
i: {
position: "absolute",
top: "4px",
left: "0",
width: "14px",
height: "14px",
position: 'absolute',
top: '4px',
left: '0',
width: '14px',
height: '14px',
},
tagsTitle: {
marginBottom: "12px",
marginBottom: '12px',
color: token.colorTextHeading,
fontWeight: "500",
fontWeight: '500',
},
teamTitle: {
marginBottom: "12px",
marginBottom: '12px',
color: token.colorTextHeading,
fontWeight: "500",
fontWeight: '500',
},
tags: {},
".ant-tag": {
marginBottom: "8px",
'.ant-tag': {
marginBottom: '8px',
},
team: {},
".ant-avatar": {
marginRight: "12px",
'.ant-avatar': {
marginRight: '12px',
},
a: {
display: "block",
marginBottom: "24px",
overflow: "hidden",
display: 'block',
marginBottom: '24px',
overflow: 'hidden',
color: token.colorText,
whiteSpace: "nowrap",
textOverflow: "ellipsis",
wordBreak: "break-all",
transition: "color 0.3s",
"&:hover": { color: token.colorPrimary },
whiteSpace: 'nowrap',
textOverflow: 'ellipsis',
wordBreak: 'break-all',
transition: 'color 0.3s',
'&:hover': { color: token.colorPrimary },
},
tabsCard: {},
".ant-card-head": {
padding: "0 16px",
'.ant-card-head': {
padding: '0 16px',
},
};
});

58
src/pages/account/center/components/Applications/index.style.ts

@ -1,47 +1,47 @@
import { createStyles } from "antd-style";
import { createStyles } from 'antd-style';
const useStyles = createStyles(({ token }) => {
return {
filterCardList: {
marginBottom: "-24px",
marginBottom: '-24px',
},
".ant-card-meta-content": {
marginTop: "0",
'.ant-card-meta-content': {
marginTop: '0',
},
"// disabled white space .ant-card-meta-avatar": {
fontSize: "0",
'// disabled white space .ant-card-meta-avatar': {
fontSize: '0',
},
".ant-list .ant-list-item-content-single": {
maxWidth: "100%",
'.ant-list .ant-list-item-content-single': {
maxWidth: '100%',
},
cardInfo: {
marginTop: "16px",
marginLeft: "40px",
zoom: "1",
"&::before, &::after": { display: "table", content: "' '" },
"&::after": {
clear: "both",
height: "0",
fontSize: "0",
visibility: "hidden",
marginTop: '16px',
marginLeft: '40px',
zoom: '1',
'&::before, &::after': { display: 'table', content: "' '" },
'&::after': {
clear: 'both',
height: '0',
fontSize: '0',
visibility: 'hidden',
},
"& > div": {
position: "relative",
float: "left",
width: "50%",
textAlign: "left",
'& > div': {
position: 'relative',
float: 'left',
width: '50%',
textAlign: 'left',
},
},
p: {
margin: "0",
fontSize: "24px",
lineHeight: "32px",
margin: '0',
fontSize: '24px',
lineHeight: '32px',
},
"p:first-child": {
marginBottom: "4px",
'p:first-child': {
marginBottom: '4px',
color: token.colorTextSecondary,
fontSize: "12px",
lineHeight: "20px",
fontSize: '12px',
lineHeight: '20px',
},
};
});

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

@ -3,17 +3,17 @@ import {
EditOutlined,
EllipsisOutlined,
ShareAltOutlined,
} from "@ant-design/icons";
import { useRequest } from "@umijs/max";
import { Avatar, Card, Dropdown, List, Menu, Tooltip } from "antd";
import React from "react";
import numeral from "numeral";
import type { ListItemDataType } from "../../data.d";
import { queryFakeList } from "../../service";
import useStyles from "./index.style";
} from '@ant-design/icons';
import { useRequest } from '@umijs/max';
import { Avatar, Card, Dropdown, List, Menu, Tooltip } from 'antd';
import React from 'react';
import numeral from 'numeral';
import type { ListItemDataType } from '../../data.d';
import { queryFakeList } from '../../service';
import useStyles from './index.style';
export function formatWan(val: number) {
const v = val * 1;
if (!v || Number.isNaN(v)) return "";
if (!v || Number.isNaN(v)) return '';
let result: React.ReactNode = val;
if (val > 10000) {
result = (
@ -21,10 +21,10 @@ export function formatWan(val: number) {
{Math.floor(val / 10000)}
<span
style={{
position: "relative",
position: 'relative',
top: -2,
fontSize: 14,
fontStyle: "normal",
fontStyle: 'normal',
marginLeft: 2,
}}
>
@ -46,29 +46,17 @@ const Applications: React.FC = () => {
const itemMenu = (
<Menu>
<Menu.Item>
<a
target="_blank"
rel="noopener noreferrer"
href="https://www.alipay.com/"
>
<a target="_blank" rel="noopener noreferrer" href="https://www.alipay.com/">
1st menu item
</a>
</Menu.Item>
<Menu.Item>
<a
target="_blank"
rel="noopener noreferrer"
href="https://www.taobao.com/"
>
<a target="_blank" rel="noopener noreferrer" href="https://www.taobao.com/">
2nd menu item
</a>
</Menu.Item>
<Menu.Item>
<a
target="_blank"
rel="noopener noreferrer"
href="https://www.tmall.com/"
>
<a target="_blank" rel="noopener noreferrer" href="https://www.tmall.com/">
3d menu item
</a>
</Menu.Item>
@ -125,14 +113,11 @@ const Applications: React.FC = () => {
</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 className={stylesApplications.cardItemContent}>
<CardInfo
activeUser={formatWan(item.activeUser)}
newUser={numeral(item.newUser).format("0,0")}
newUser={numeral(item.newUser).format('0,0')}
/>
</div>
</Card>

14
src/pages/account/center/components/ArticleListContent/index.style.ts

@ -1,4 +1,4 @@
import { createStyles } from "antd-style";
import { createStyles } from 'antd-style';
const useStyles = createStyles(({ token }) => {
return {
@ -6,15 +6,15 @@ const useStyles = createStyles(({ token }) => {
[`@media screen and (max-width: ${token.screenXS}px)`]: {},
},
description: {
maxWidth: "720px",
lineHeight: "22px",
maxWidth: '720px',
lineHeight: '22px',
},
extra: {
[`@media screen and (max-width: ${token.screenXS}px)`]: {
"& > em": {
display: "block",
marginTop: "8px",
marginLeft: "0",
'& > em': {
display: 'block',
marginTop: '8px',
marginLeft: '0',
},
},
},

10
src/pages/account/center/components/ArticleListContent/index.tsx

@ -1,7 +1,7 @@
import { Avatar } from "antd";
import React from "react";
import dayjs from "dayjs";
import useStyles from "./index.style";
import { Avatar } from 'antd';
import React from 'react';
import dayjs from 'dayjs';
import useStyles from './index.style';
export type ApplicationsProps = {
data: {
content?: string;
@ -21,7 +21,7 @@ const ArticleListContent: React.FC<ApplicationsProps> = ({
<div className={styles.extra}>
<Avatar src={avatar} size="small" />
<a href={href}>{owner}</a> <a href={href}>{href}</a>
<em>{dayjs(updatedAt).format("YYYY-MM-DD HH:mm")}</em>
<em>{dayjs(updatedAt).format('YYYY-MM-DD HH:mm')}</em>
</div>
</div>
);

8
src/pages/account/center/components/Articles/index.style.ts

@ -1,12 +1,12 @@
import { createStyles } from "antd-style";
import { createStyles } from 'antd-style';
const useStyles = createStyles(({ token }) => {
return {
articleList: {},
".ant-list-item:first-child": {
paddingTop: "0",
'.ant-list-item:first-child': {
paddingTop: '0',
},
"a.listItemMetaTitle": {
'a.listItemMetaTitle': {
color: token.colorTextHeading,
},
};

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

@ -1,11 +1,11 @@
import React from "react";
import { StarTwoTone, LikeOutlined, MessageFilled } from "@ant-design/icons";
import { useRequest } from "@umijs/max";
import { List, Tag } from "antd";
import ArticleListContent from "../ArticleListContent";
import type { ListItemDataType } from "../../data.d";
import { queryFakeList } from "../../service";
import useStyles from "./index.style";
import React from 'react';
import { StarTwoTone, LikeOutlined, MessageFilled } from '@ant-design/icons';
import { useRequest } from '@umijs/max';
import { List, Tag } from 'antd';
import ArticleListContent from '../ArticleListContent';
import type { ListItemDataType } from '../../data.d';
import { queryFakeList } from '../../service';
import useStyles from './index.style';
const Articles: React.FC = () => {
const { styles } = useStyles();
const IconText: React.FC<{
@ -36,11 +36,7 @@ const Articles: React.FC = () => {
actions={[
<IconText key="star" icon={<StarTwoTone />} text={item.star} />,
<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

32
src/pages/account/center/components/AvatarList/index.style.ts

@ -1,26 +1,26 @@
import { createStyles } from "antd-style";
import { createStyles } from 'antd-style';
const useStyles = createStyles(({ token }) => {
return {
avatarList: {
display: "inline-block",
display: 'inline-block',
},
ul: {
display: "inline-block",
marginLeft: "8px",
fontSize: "0",
display: 'inline-block',
marginLeft: '8px',
fontSize: '0',
},
avatarItem: {
display: "inline-block",
display: 'inline-block',
width: token.controlHeight,
height: token.controlHeight,
marginLeft: "-8px",
marginLeft: '-8px',
fontSize: token.fontSize,
},
".ant-avatar": {
width: "20px",
height: "20px",
lineHeight: "20px",
'.ant-avatar': {
width: '20px',
height: '20px',
lineHeight: '20px',
},
avatarItemLarge: {
width: token.controlHeightLG,
@ -31,12 +31,12 @@ const useStyles = createStyles(({ token }) => {
height: token.controlHeightSM,
},
avatarItemMini: {
width: "20px",
height: "20px",
width: '20px',
height: '20px',
},
".ant-avatar-string": {
fontSize: "12px",
lineHeight: "18px",
'.ant-avatar-string': {
fontSize: '12px',
lineHeight: '18px',
},
};
});

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

@ -1,8 +1,8 @@
import { Avatar, Tooltip } from "antd";
import React from "react";
import classNames from "classnames";
import useStyles from "./index.style";
export declare type SizeType = number | "small" | "default" | "large";
import { Avatar, Tooltip } from 'antd';
import React from 'react';
import classNames from 'classnames';
import useStyles from './index.style';
export declare type SizeType = number | 'small' | 'default' | 'large';
export type AvatarItemProps = {
tips: React.ReactNode;
src: string;
@ -16,22 +16,15 @@ export type AvatarListProps = {
maxLength?: number;
excessItemsStyle?: React.CSSProperties;
style?: React.CSSProperties;
children:
| React.ReactElement<AvatarItemProps>
| React.ReactElement<AvatarItemProps>[];
children: React.ReactElement<AvatarItemProps> | React.ReactElement<AvatarItemProps>[];
};
const avatarSizeToClassName = (size?: SizeType | "mini") =>
const avatarSizeToClassName = (size?: SizeType | 'mini') =>
classNames(styles.avatarItem, {
[styles.avatarItemLarge]: size === "large",
[styles.avatarItemSmall]: size === "small",
[styles.avatarItemMini]: size === "mini",
[styles.avatarItemLarge]: size === 'large',
[styles.avatarItemSmall]: size === 'small',
[styles.avatarItemMini]: size === 'mini',
});
const Item: React.FC<AvatarItemProps> = ({
src,
size,
tips,
onClick = () => {},
}) => {
const Item: React.FC<AvatarItemProps> = ({ src, size, tips, onClick = () => {} }) => {
const cls = avatarSizeToClassName(size);
return (
<li className={cls} onClick={onClick}>
@ -41,7 +34,7 @@ const Item: React.FC<AvatarItemProps> = ({
src={src}
size={size}
style={{
cursor: "pointer",
cursor: 'pointer',
}}
/>
</Tooltip>
@ -57,22 +50,18 @@ const AvatarList: React.FC<AvatarListProps> & {
const { styles } = useStyles();
const numOfChildren = React.Children.count(children);
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) =>
React.cloneElement(child, {
size,
})
}),
);
if (numToShow < numOfChildren) {
const cls = avatarSizeToClassName(size);
childrenWithProps.push(
<li key="exceed" className={cls}>
<Avatar size={size} style={excessItemsStyle}>{`+${
numOfChildren - maxLength
}`}</Avatar>
</li>
<Avatar size={size} style={excessItemsStyle}>{`+${numOfChildren - maxLength}`}</Avatar>
</li>,
);
}
return (

48
src/pages/account/center/components/Projects/index.style.ts

@ -1,47 +1,47 @@
import { createStyles } from "antd-style";
import { createStyles } from 'antd-style';
const useStyles = createStyles(({ token }) => {
return {
coverCardList: {},
card: {
"&:hover": {},
'&:hover': {},
},
".ant-card-meta-title": {
marginBottom: "4px",
"& > a": {
display: "inline-block",
maxWidth: "100%",
'.ant-card-meta-title': {
marginBottom: '4px',
'& > a': {
display: 'inline-block',
maxWidth: '100%',
color: token.colorTextHeading,
},
},
".ant-card-meta-description": {
height: "44px",
overflow: "hidden",
lineHeight: "22px",
'.ant-card-meta-description': {
height: '44px',
overflow: 'hidden',
lineHeight: '22px',
},
".ant-card-meta-title > a": {
'.ant-card-meta-title > a': {
color: token.colorPrimary,
},
cardItemContent: {
display: "flex",
height: "20px",
marginTop: "16px",
marginBottom: "-4px",
lineHeight: "20px",
"& > span": {
flex: "1",
display: 'flex',
height: '20px',
marginTop: '16px',
marginBottom: '-4px',
lineHeight: '20px',
'& > span': {
flex: '1',
color: token.colorTextSecondary,
fontSize: "12px",
fontSize: '12px',
},
},
avatarList: {
flex: "0 1 auto",
flex: '0 1 auto',
},
cardList: {
marginTop: "24px",
marginTop: '24px',
},
".ant-list .ant-list-item-content-single": {
maxWidth: "100%",
'.ant-list .ant-list-item-content-single': {
maxWidth: '100%',
},
};
});

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

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

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

@ -1,25 +1,20 @@
import {
PlusOutlined,
HomeOutlined,
ContactsOutlined,
ClusterOutlined,
} from "@ant-design/icons";
import { Avatar, Card, Col, Divider, Input, InputRef, Row, Tag } from "antd";
import React, { useState, useRef } from "react";
import { GridContent } from "@ant-design/pro-components";
import { Link, useRequest } from "@umijs/max";
import Projects from "./components/Projects";
import Articles from "./components/Articles";
import Applications from "./components/Applications";
import type { CurrentUser, TagType, tabKeyType } from "./data.d";
import { queryCurrent } from "./service";
import useStyles from "./Center.style";
import { PlusOutlined, HomeOutlined, ContactsOutlined, ClusterOutlined } from '@ant-design/icons';
import { Avatar, Card, Col, Divider, Input, InputRef, Row, Tag } from 'antd';
import React, { useState, useRef } from 'react';
import { GridContent } from '@ant-design/pro-components';
import { Link, useRequest } from '@umijs/max';
import Projects from './components/Projects';
import Articles from './components/Articles';
import Applications from './components/Applications';
import type { CurrentUser, TagType, tabKeyType } from './data.d';
import { queryCurrent } from './service';
import useStyles from './Center.style';
const operationTabList = [
{
key: "articles",
key: 'articles',
tab: (
<span>
{" "}
{' '}
<span
style={{
fontSize: 14,
@ -31,10 +26,10 @@ const operationTabList = [
),
},
{
key: "applications",
key: 'applications',
tab: (
<span>
{" "}
{' '}
<span
style={{
fontSize: 14,
@ -46,10 +41,10 @@ const operationTabList = [
),
},
{
key: "projects",
key: 'projects',
tab: (
<span>
{" "}
{' '}
<span
style={{
fontSize: 14,
@ -62,13 +57,13 @@ const operationTabList = [
},
];
const TagList: React.FC<{
tags: CurrentUser["tags"];
tags: CurrentUser['tags'];
}> = ({ tags }) => {
const { styles } = useStyles();
const ref = useRef<InputRef | null>(null);
const [newTags, setNewTags] = useState<TagType[]>([]);
const [inputVisible, setInputVisible] = useState<boolean>(false);
const [inputValue, setInputValue] = useState<string>("");
const [inputValue, setInputValue] = useState<string>('');
const showInput = () => {
setInputVisible(true);
if (ref.current) {
@ -81,10 +76,7 @@ const TagList: React.FC<{
};
const handleInputConfirm = () => {
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,
{
@ -95,7 +87,7 @@ const TagList: React.FC<{
}
setNewTags(tempsTags);
setInputVisible(false);
setInputValue("");
setInputValue('');
};
return (
<div className={styles.tags}>
@ -121,7 +113,7 @@ const TagList: React.FC<{
<Tag
onClick={showInput}
style={{
borderStyle: "dashed",
borderStyle: 'dashed',
}}
>
<PlusOutlined />
@ -132,7 +124,7 @@ const TagList: React.FC<{
};
const Center: React.FC = () => {
const { styles } = useStyles();
const [tabKey, setTabKey] = useState<tabKeyType>("articles");
const [tabKey, setTabKey] = useState<tabKeyType>('articles');
// 获取用户信息
const { data: currentUser, loading } = useRequest(() => {
@ -140,11 +132,7 @@ const Center: React.FC = () => {
});
// 渲染用户信息
const renderUserInfo = ({
title,
group,
geographic,
}: Partial<CurrentUser>) => {
const renderUserInfo = ({ title, group, geographic }: Partial<CurrentUser>) => {
return (
<div className={styles.detail}>
<p>
@ -173,7 +161,7 @@ const Center: React.FC = () => {
(
geographic || {
province: {
label: "",
label: '',
},
}
).province.label
@ -182,7 +170,7 @@ const Center: React.FC = () => {
(
geographic || {
city: {
label: "",
label: '',
},
}
).city.label
@ -194,13 +182,13 @@ const Center: React.FC = () => {
// 渲染tab切换
const renderChildrenByTabKey = (tabValue: tabKeyType) => {
if (tabValue === "projects") {
if (tabValue === 'projects') {
return <Projects />;
}
if (tabValue === "applications") {
if (tabValue === 'applications') {
return <Applications />;
}
if (tabValue === "articles") {
if (tabValue === 'articles') {
return <Articles />;
}
return null;

42
src/pages/account/settings/components/BaseView.style.ts

@ -1,51 +1,51 @@
import { createStyles } from "antd-style";
import { createStyles } from 'antd-style';
const useStyles = createStyles(({ token }) => {
return {
baseView: {
[`@media screen and (max-width: ${token.screenXL}px)`]: {
flexDirection: "column-reverse",
flexDirection: 'column-reverse',
},
},
".ant-legacy-form-item .ant-legacy-form-item-control-wrapper": {
width: "100%",
'.ant-legacy-form-item .ant-legacy-form-item-control-wrapper': {
width: '100%',
},
left: {
minWidth: "224px",
maxWidth: "448px",
minWidth: '224px',
maxWidth: '448px',
},
right: {
[`@media screen and (max-width: ${token.screenXL}px)`]: {
display: "flex",
flexDirection: "column",
alignItems: "center",
maxWidth: "448px",
padding: "20px",
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
maxWidth: '448px',
padding: '20px',
},
},
avatar_title: {
[`@media screen and (max-width: ${token.screenXL}px)`]: {
display: "none",
display: 'none',
},
},
avatar: {
width: "144px",
height: "144px",
marginBottom: "12px",
overflow: "hidden",
width: '144px',
height: '144px',
marginBottom: '12px',
overflow: 'hidden',
},
img: {
width: "100%",
width: '100%',
},
button_view: {
width: "144px",
textAlign: "center",
width: '144px',
textAlign: 'center',
},
area_code: {
width: "72px",
width: '72px',
},
phone_number: {
width: "214px",
width: '214px',
},
};
});

10
src/pages/account/settings/components/PhoneView.tsx

@ -1,6 +1,6 @@
import React from "react";
import { Input } from "antd";
import useStyles from "./PhoneView.style";
import React from 'react';
import { Input } from 'antd';
import useStyles from './PhoneView.style';
type PhoneViewProps = {
value?: string;
onChange?: (value: string) => void;
@ -8,9 +8,9 @@ type PhoneViewProps = {
const PhoneView: React.FC<PhoneViewProps> = (props) => {
const { styles } = useStyles();
const { value, onChange } = props;
let values = ["", ""];
let values = ['', ''];
if (value) {
values = value.split("-");
values = value.split('-');
}
return (
<>

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

@ -1,28 +1,28 @@
import React, { useState, useRef, useLayoutEffect } from "react";
import { GridContent } from "@ant-design/pro-components";
import { Menu } from "antd";
import BaseView from "./components/base";
import BindingView from "./components/binding";
import NotificationView from "./components/notification";
import SecurityView from "./components/security";
import useStyles from "./style.style";
import React, { useState, useRef, useLayoutEffect } from 'react';
import { GridContent } from '@ant-design/pro-components';
import { Menu } from 'antd';
import BaseView from './components/base';
import BindingView from './components/binding';
import NotificationView from './components/notification';
import SecurityView from './components/security';
import useStyles from './style.style';
const { Item } = Menu;
type SettingsStateKeys = "base" | "security" | "binding" | "notification";
type SettingsStateKeys = 'base' | 'security' | 'binding' | 'notification';
type SettingsState = {
mode: "inline" | "horizontal";
mode: 'inline' | 'horizontal';
selectKey: SettingsStateKeys;
};
const Settings: React.FC = () => {
const { styles } = useStyles();
const menuMap: Record<string, React.ReactNode> = {
base: "基本设置",
security: "安全设置",
binding: "账号绑定",
notification: "新消息通知",
base: '基本设置',
security: '安全设置',
binding: '账号绑定',
notification: '新消息通知',
};
const [initConfig, setInitConfig] = useState<SettingsState>({
mode: "inline",
selectKey: "base",
mode: 'inline',
selectKey: 'base',
});
const dom = useRef<HTMLDivElement>();
const resize = () => {
@ -30,44 +30,42 @@ const Settings: React.FC = () => {
if (!dom.current) {
return;
}
let mode: "inline" | "horizontal" = "inline";
let mode: 'inline' | 'horizontal' = 'inline';
const { offsetWidth } = dom.current;
if (dom.current.offsetWidth < 641 && offsetWidth > 400) {
mode = "horizontal";
mode = 'horizontal';
}
if (window.innerWidth < 768 && offsetWidth > 400) {
mode = "horizontal";
mode = 'horizontal';
}
setInitConfig({
...initConfig,
mode: mode as SettingsState["mode"],
mode: mode as SettingsState['mode'],
});
});
};
useLayoutEffect(() => {
if (dom.current) {
window.addEventListener("resize", resize);
window.addEventListener('resize', resize);
resize();
}
return () => {
window.removeEventListener("resize", resize);
window.removeEventListener('resize', resize);
};
}, [dom.current]);
const getMenu = () => {
return Object.keys(menuMap).map((item) => (
<Item key={item}>{menuMap[item]}</Item>
));
return Object.keys(menuMap).map((item) => <Item key={item}>{menuMap[item]}</Item>);
};
const renderChildren = () => {
const { selectKey } = initConfig;
switch (selectKey) {
case "base":
case 'base':
return <BaseView />;
case "security":
case 'security':
return <SecurityView />;
case "binding":
case 'binding':
return <BindingView />;
case "notification":
case 'notification':
return <NotificationView />;
default:
return null;

72
src/pages/account/settings/style.style.ts

@ -1,73 +1,73 @@
import { createStyles } from "antd-style";
import { createStyles } from 'antd-style';
const useStyles = createStyles(({ token }) => {
return {
main: {
[`@media screen and (max-width: ${token.screenMD}px)`]: {
flexDirection: "column",
flexDirection: 'column',
},
},
leftMenu: {
[`@media screen and (max-width: ${token.screenMD}px)`]: {
width: "100%",
border: "none",
width: '100%',
border: 'none',
},
},
".ant-menu-inline": {
border: "none",
'.ant-menu-inline': {
border: 'none',
},
".ant-menu-horizontal": {
fontWeight: "bold",
'.ant-menu-horizontal': {
fontWeight: 'bold',
},
right: {
[`@media screen and (max-width: ${token.screenMD}px)`]: {
padding: "40px",
padding: '40px',
},
},
title: {
marginBottom: "12px",
marginBottom: '12px',
color: token.colorTextHeading,
fontWeight: "500",
fontSize: "20px",
lineHeight: "28px",
fontWeight: '500',
fontSize: '20px',
lineHeight: '28px',
},
".ant-list-split .ant-list-item:last-child": {
borderBottom: "1px solid @border-color-split",
'.ant-list-split .ant-list-item:last-child': {
borderBottom: '1px solid @border-color-split',
},
".ant-list-item": {
paddingTop: "14px",
paddingBottom: "14px",
'.ant-list-item': {
paddingTop: '14px',
paddingBottom: '14px',
},
".ant-list-item-meta": {},
"// 账号绑定图标 .taobao": {
display: "block",
color: "#ff4000",
fontSize: "48px",
lineHeight: "48px",
'.ant-list-item-meta': {},
'// 账号绑定图标 .taobao': {
display: 'block',
color: '#ff4000',
fontSize: '48px',
lineHeight: '48px',
borderRadius: token.borderRadius,
},
dingding: {
margin: "2px",
padding: "6px",
color: "#fff",
fontSize: "32px",
lineHeight: "32px",
backgroundColor: "#2eabff",
margin: '2px',
padding: '6px',
color: '#fff',
fontSize: '32px',
lineHeight: '32px',
backgroundColor: '#2eabff',
borderRadius: token.borderRadius,
},
alipay: {
color: "#2eabff",
fontSize: "48px",
lineHeight: "48px",
color: '#2eabff',
fontSize: '48px',
lineHeight: '48px',
borderRadius: token.borderRadius,
},
"// 密码强度 font.strong": {
'// 密码强度 font.strong': {
color: token.colorSuccess,
},
"font.medium": {
'font.medium': {
color: token.colorWarning,
},
"font.weak": {
'font.weak': {
color: token.colorError,
},
};

31
src/pages/dashboard/analysis/components/Charts/Bar/index.tsx

@ -1,8 +1,8 @@
import { Axis, Chart, Geom, Tooltip } from "bizcharts";
import React, { Component } from "react";
import Debounce from "lodash.debounce";
import autoHeight from "../autoHeight";
import useStyles from "../index.style";
import { Axis, Chart, Geom, Tooltip } from 'bizcharts';
import React, { Component } from 'react';
import Debounce from 'lodash.debounce';
import autoHeight from '../autoHeight';
import useStyles from '../index.style';
export type BarProps = {
title: React.ReactNode;
color?: string;
@ -51,12 +51,12 @@ class Bar extends Component<
}
}, 500);
componentDidMount() {
window.addEventListener("resize", this.resize, {
window.addEventListener('resize', this.resize, {
passive: true,
});
}
componentWillUnmount() {
window.removeEventListener("resize", this.resize);
window.removeEventListener('resize', this.resize);
}
handleRoot = (n: HTMLDivElement) => {
this.root = n;
@ -70,13 +70,13 @@ class Bar extends Component<
title,
forceFit = true,
data,
color = "rgba(24, 144, 255, 0.85)",
color = 'rgba(24, 144, 255, 0.85)',
padding,
} = this.props;
const { autoHideXLabels } = this.state;
const scale = {
x: {
type: "cat",
type: 'cat',
},
y: {
min: 0,
@ -87,9 +87,9 @@ class Bar extends Component<
(...args: any[]) => {
name?: string;
value: string;
}
},
] = [
"x*y",
'x*y',
(x: string, y: string) => ({
name: x,
value: y,
@ -118,7 +118,7 @@ class Bar extends Component<
height={title ? height - 41 : height}
forceFit={forceFit}
data={data}
padding={padding || "auto"}
padding={padding || 'auto'}
>
<Axis
name="x"
@ -128,12 +128,7 @@ class Bar extends Component<
/>
<Axis name="y" min={0} />
<Tooltip showTitle={false} crosshairs={false} />
<Geom
type="interval"
position="x*y"
color={color}
tooltip={tooltip}
/>
<Geom type="interval" position="x*y" color={color} tooltip={tooltip} />
</Chart>
</div>
</div>

82
src/pages/dashboard/analysis/components/Charts/ChartCard/index.style.ts

@ -1,77 +1,77 @@
import { createStyles } from "antd-style";
import { createStyles } from 'antd-style';
const useStyles = createStyles(({ token }) => {
return {
chartCard: {
position: "relative",
position: 'relative',
},
chartTop: {
position: "relative",
width: "100%",
overflow: "hidden",
position: 'relative',
width: '100%',
overflow: 'hidden',
},
chartTopMargin: {
marginBottom: "12px",
marginBottom: '12px',
},
chartTopHasMargin: {
marginBottom: "20px",
marginBottom: '20px',
},
metaWrap: {
float: "left",
float: 'left',
},
avatar: {
position: "relative",
top: "4px",
float: "left",
marginRight: "20px",
position: 'relative',
top: '4px',
float: 'left',
marginRight: '20px',
},
img: {
borderRadius: "100%",
borderRadius: '100%',
},
meta: {
height: "22px",
height: '22px',
color: token.colorTextSecondary,
fontSize: token.fontSize,
lineHeight: "22px",
lineHeight: '22px',
},
action: {
position: "absolute",
top: "4px",
right: "0",
lineHeight: "1",
cursor: "pointer",
position: 'absolute',
top: '4px',
right: '0',
lineHeight: '1',
cursor: 'pointer',
},
total: {
height: "38px",
marginTop: "4px",
marginBottom: "0",
overflow: "hidden",
height: '38px',
marginTop: '4px',
marginBottom: '0',
overflow: 'hidden',
color: token.colorTextHeading,
fontSize: "30px",
lineHeight: "38px",
whiteSpace: "nowrap",
textOverflow: "ellipsis",
wordBreak: "break-all",
fontSize: '30px',
lineHeight: '38px',
whiteSpace: 'nowrap',
textOverflow: 'ellipsis',
wordBreak: 'break-all',
},
content: {
position: "relative",
width: "100%",
marginBottom: "12px",
position: 'relative',
width: '100%',
marginBottom: '12px',
},
contentFixed: {
position: "absolute",
bottom: "0",
left: "0",
width: "100%",
position: 'absolute',
bottom: '0',
left: '0',
width: '100%',
},
footer: {
marginTop: "8px",
paddingTop: "9px",
borderTop: "1px solid @border-color-split",
"& > *": { position: "relative" },
marginTop: '8px',
paddingTop: '9px',
borderTop: '1px solid @border-color-split',
'& > *': { position: 'relative' },
},
footerMargin: {
marginTop: "20px",
marginTop: '20px',
},
};
});

14
src/pages/dashboard/analysis/components/Charts/Field/index.style.ts

@ -1,19 +1,19 @@
import { createStyles } from "antd-style";
import { createStyles } from 'antd-style';
const useStyles = createStyles(({ token }) => {
return {
field: {
margin: "0",
overflow: "hidden",
whiteSpace: "nowrap",
textOverflow: "ellipsis",
margin: '0',
overflow: 'hidden',
whiteSpace: 'nowrap',
textOverflow: 'ellipsis',
},
label: {
fontSize: token.fontSize,
lineHeight: "22px",
lineHeight: '22px',
},
number: {
marginLeft: "8px",
marginLeft: '8px',
color: token.colorTextHeading,
},
};

4
src/pages/dashboard/analysis/components/Charts/Field/index.tsx

@ -1,5 +1,5 @@
import React from "react";
import useStyles from "./index.style";
import React from 'react';
import useStyles from './index.style';
export type FieldProps = {
label: React.ReactNode;
value: React.ReactNode;

22
src/pages/dashboard/analysis/components/Charts/MiniArea/index.tsx

@ -1,8 +1,8 @@
import type { AxisProps } from "bizcharts";
import { Axis, Chart, Geom, Tooltip } from "bizcharts";
import React from "react";
import autoHeight from "../autoHeight";
import useStyles from "../index.style";
import type { AxisProps } from 'bizcharts';
import { Axis, Chart, Geom, Tooltip } from 'bizcharts';
import React from 'react';
import autoHeight from '../autoHeight';
import useStyles from '../index.style';
export type MiniAreaProps = {
color?: string;
height?: number;
@ -32,8 +32,8 @@ const MiniArea: React.FC<MiniAreaProps> = (props) => {
height = 1,
data = [],
forceFit = true,
color = "rgba(24, 144, 255, 0.2)",
borderColor = "#1089ff",
color = 'rgba(24, 144, 255, 0.2)',
borderColor = '#1089ff',
scale = {
x: {},
y: {},
@ -47,7 +47,7 @@ const MiniArea: React.FC<MiniAreaProps> = (props) => {
const padding: [number, number, number, number] = [36, 5, 30, 5];
const scaleProps = {
x: {
type: "cat",
type: 'cat',
range: [0, 1],
...scale.x,
},
@ -61,9 +61,9 @@ const MiniArea: React.FC<MiniAreaProps> = (props) => {
(...args: any[]) => {
name?: string;
value: string;
}
},
] = [
"x*y",
'x*y',
(x: string, y: string) => ({
name: x,
value: y,
@ -128,7 +128,7 @@ const MiniArea: React.FC<MiniAreaProps> = (props) => {
) : (
<span
style={{
display: "none",
display: 'none',
}}
/>
)}

31
src/pages/dashboard/analysis/components/Charts/MiniBar/index.tsx

@ -1,7 +1,7 @@
import { Chart, Geom, Tooltip } from "bizcharts";
import React from "react";
import autoHeight from "../autoHeight";
import useStyles from "../index.style";
import { Chart, Geom, Tooltip } from 'bizcharts';
import React from 'react';
import autoHeight from '../autoHeight';
import useStyles from '../index.style';
export type MiniBarProps = {
color?: string;
height?: number;
@ -14,10 +14,10 @@ export type MiniBarProps = {
};
const MiniBar: React.FC<MiniBarProps> = (props) => {
const { styles } = useStyles();
const { height = 0, forceFit = true, color = "#1890FF", data = [] } = props;
const { height = 0, forceFit = true, color = '#1890FF', data = [] } = props;
const scale = {
x: {
type: "cat",
type: 'cat',
},
y: {
min: 0,
@ -29,9 +29,9 @@ const MiniBar: React.FC<MiniBarProps> = (props) => {
(...args: any[]) => {
name?: string;
value: string;
}
},
] = [
"x*y",
'x*y',
(x: string, y: string) => ({
name: x,
value: y,
@ -48,20 +48,9 @@ const MiniBar: React.FC<MiniBarProps> = (props) => {
}}
>
<div className={styles.chartContent}>
<Chart
scale={scale}
height={chartHeight}
forceFit={forceFit}
data={data}
padding={padding}
>
<Chart scale={scale} height={chartHeight} forceFit={forceFit} data={data} padding={padding}>
<Tooltip showTitle={false} crosshairs={false} />
<Geom
type="interval"
position="x*y"
color={color}
tooltip={tooltip}
/>
<Geom type="interval" position="x*y" color={color} tooltip={tooltip} />
</Chart>
</div>
</div>

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

@ -1,6 +1,6 @@
import React from "react";
import { Tooltip } from "antd";
import useStyles from "./index.style";
import React from 'react';
import { Tooltip } from 'antd';
import useStyles from './index.style';
export type MiniProgressProps = {
target: number;
targetLabel?: string;
@ -12,7 +12,7 @@ export type MiniProgressProps = {
const MiniProgress: React.FC<MiniProgressProps> = ({
targetLabel,
target,
color = "rgb(19, 194, 194)",
color = 'rgb(19, 194, 194)',
strokeWidth,
percent,
}) => {

90
src/pages/dashboard/analysis/components/Charts/Pie/index.tsx

@ -1,12 +1,13 @@
import { Chart, Coord, Geom, Tooltip } from "bizcharts";
import React, { Component } from "react";
import { DataView } from "@antv/data-set";
import Debounce from "lodash.debounce";
import { Divider } from "antd";
import ReactFitText from "react-fittext";
import classNames from "classnames";
import autoHeight from "../autoHeight";
import useStyles from "./index.style";
import { Chart, Coord, Geom, Tooltip } from 'bizcharts';
import React, { Component } from 'react';
import { DataView } from '@antv/data-set';
import Debounce from 'lodash.debounce';
import { Divider } from 'antd';
import ReactFitText from 'react-fittext';
import classNames from 'classnames';
import autoHeight from '../autoHeight';
import useStyles from './index.style';
export type PieProps = {
animate?: boolean;
color?: string;
@ -56,7 +57,7 @@ class Pie extends Component<PieProps, PieState> {
const { hasLegend } = this.props;
const { legendBlock } = this.state;
if (!hasLegend || !this.root) {
window.removeEventListener("resize", this.resize);
window.removeEventListener('resize', this.resize);
return;
}
if (
@ -77,13 +78,13 @@ class Pie extends Component<PieProps, PieState> {
}, 400);
componentDidMount() {
window.addEventListener(
"resize",
'resize',
() => {
this.requestRef = requestAnimationFrame(() => this.resize());
},
{
passive: true,
}
},
);
}
componentDidUpdate(preProps: PieProps) {
@ -98,7 +99,7 @@ class Pie extends Component<PieProps, PieState> {
if (this.requestRef) {
window.cancelAnimationFrame(this.requestRef);
}
window.removeEventListener("resize", this.resize);
window.removeEventListener('resize', this.resize);
if (this.resize) {
(this.resize as any).cancel();
}
@ -116,21 +117,21 @@ class Pie extends Component<PieProps, PieState> {
if (!this.chart) return;
const geom = this.chart.getAllGeoms()[0]; // 获取所有的图形
if (!geom) return;
const items = (geom as any).get("dataArray") || []; // 获取图形对应的
const items = (geom as any).get('dataArray') || []; // 获取图形对应的
const legendData = items.map(
(
item: {
color: any;
_origin: any;
}[]
}[],
) => {
/* eslint no-underscore-dangle:0 */
const origin = item[0]._origin;
origin.color = item[0].color;
origin.checked = true;
return origin;
}
},
);
this.setState({
legendData,
@ -145,14 +146,9 @@ class Pie extends Component<PieProps, PieState> {
const { legendData } = this.state;
const key = i as unknown as number;
legendData[key] = newItem;
const filteredLegendData = legendData
.filter((l) => l.checked)
.map((l) => l.x);
const filteredLegendData = legendData.filter((l) => l.checked).map((l) => l.x);
if (this.chart) {
this.chart.filter(
"x",
(val) => filteredLegendData.indexOf(`${val}`) > -1
);
this.chart.filter('x', (val) => filteredLegendData.indexOf(`${val}`) > -1);
}
this.setState({
legendData,
@ -195,7 +191,7 @@ class Pie extends Component<PieProps, PieState> {
let formatColor;
const scale = {
x: {
type: "cat",
type: 'cat',
range: [0, 1],
},
y: {
@ -206,18 +202,18 @@ class Pie extends Component<PieProps, PieState> {
selected = false;
tooltip = false;
formatColor = (value: string) => {
if (value === "占比") {
return color || "rgba(24, 144, 255, 0.85)";
if (value === '占比') {
return color || 'rgba(24, 144, 255, 0.85)';
}
return "#F0F2F5";
return '#F0F2F5';
};
data = [
{
x: "占比",
x: '占比',
y: parseFloat(`${percent}`),
},
{
x: "反比",
x: '反比',
y: 100 - parseFloat(`${percent}`),
},
];
@ -227,9 +223,9 @@ class Pie extends Component<PieProps, PieState> {
(...args: any[]) => {
name?: string;
value: string;
}
},
] = [
"x*percent",
'x*percent',
(x: string, p: number) => ({
name: x,
value: `${(p * 100).toFixed(2)}%`,
@ -238,10 +234,10 @@ class Pie extends Component<PieProps, PieState> {
const padding = [12, 0, 12, 0] as [number, number, number, number];
const dv = new DataView();
dv.source(data).transform({
type: "percent",
field: "y",
dimension: "x",
as: "percent",
type: 'percent',
field: 'y',
dimension: 'x',
as: 'percent',
});
return (
<div ref={this.handleRoot} className={pieClassName} style={style}>
@ -261,17 +257,12 @@ class Pie extends Component<PieProps, PieState> {
<Geom
style={{
lineWidth,
stroke: "#fff",
stroke: '#fff',
}}
tooltip={tooltip ? tooltipFormat : undefined}
type="intervalStack"
position="percent"
color={
[
"x",
percent || percent === 0 ? formatColor : defaultColors,
] as any
}
color={['x', percent || percent === 0 ? formatColor : defaultColors] as any}
selected={selected}
/>
</Chart>
@ -281,9 +272,7 @@ class Pie extends Component<PieProps, PieState> {
{subTitle && <h4 className="pie-sub-title">{subTitle}</h4>}
{/* eslint-disable-next-line */}
{total && (
<div className="pie-stat">
{typeof total === "function" ? total() : total}
</div>
<div className="pie-stat">{typeof total === 'function' ? total() : total}</div>
)}
</div>
)}
@ -297,20 +286,15 @@ class Pie extends Component<PieProps, PieState> {
<span
className={styles.dot}
style={{
backgroundColor: !item.checked ? "#aaa" : item.color,
backgroundColor: !item.checked ? '#aaa' : item.color,
}}
/>
<span className={styles.legendTitle}>{item.x}</span>
<Divider type="vertical" />
<span className={styles.percent}>
{`${(Number.isNaN(item.percent)
? 0
: item.percent * 100
).toFixed(2)}%`}
</span>
<span className={styles.value}>
{valueFormat ? valueFormat(item.y) : item.y}
{`${(Number.isNaN(item.percent) ? 0 : item.percent * 100).toFixed(2)}%`}
</span>
<span className={styles.value}>{valueFormat ? valueFormat(item.y) : item.y}</span>
</li>
))}
</ul>

47
src/pages/dashboard/analysis/components/Charts/TagCloud/index.tsx

@ -1,16 +1,15 @@
import { Chart, Coord, Geom, Shape, Tooltip } from "bizcharts";
import React, { Component } from "react";
import DataSet from "@antv/data-set";
import Debounce from "lodash.debounce";
import classNames from "classnames";
import autoHeight from "../autoHeight";
import useStyles from "./index.style";
import { Chart, Coord, Geom, Shape, Tooltip } from 'bizcharts';
import React, { Component } from 'react';
import DataSet from '@antv/data-set';
import Debounce from 'lodash.debounce';
import classNames from 'classnames';
import autoHeight from '../autoHeight';
import useStyles from './index.style';
/* eslint no-underscore-dangle: 0 */
/* eslint no-param-reassign: 0 */
const imgUrl =
"https://gw.alipayobjects.com/zos/rmsportal/gWyeGLCdFFRavBGIDzWk.png";
const imgUrl = 'https://gw.alipayobjects.com/zos/rmsportal/gWyeGLCdFFRavBGIDzWk.png';
export type TagCloudProps = {
data: {
name: string;
@ -40,7 +39,7 @@ class TagCloud extends Component<TagCloudProps, TagCloudState> {
this.initTagCloud();
this.renderChart(this.props);
});
window.addEventListener("resize", this.resize, {
window.addEventListener('resize', this.resize, {
passive: true,
});
}
@ -53,7 +52,7 @@ class TagCloud extends Component<TagCloudProps, TagCloudState> {
componentWillUnmount() {
this.isUnmount = true;
window.cancelAnimationFrame(this.requestRef);
window.removeEventListener("resize", this.resize);
window.removeEventListener('resize', this.resize);
}
resize = () => {
this.requestRef = requestAnimationFrame(() => {
@ -78,13 +77,13 @@ class TagCloud extends Component<TagCloudProps, TagCloudState> {
fontSize: cfg.origin._origin.size,
rotate: cfg.origin._origin.rotate,
text: cfg.origin._origin.text,
textAlign: "center",
textAlign: 'center',
fontFamily: cfg.origin._origin.font,
fill: cfg.color,
textBaseline: "Alphabetic",
textBaseline: 'Alphabetic',
};
}
(Shape as any).registerShape("point", "cloud", {
(Shape as any).registerShape('point', 'cloud', {
drawShape(
cfg: {
x: any;
@ -95,12 +94,12 @@ class TagCloud extends Component<TagCloudProps, TagCloudState> {
arg0: string,
arg1: {
attrs: any;
}
},
) => void;
}
},
) {
const attrs = getTextAttrs(cfg);
return container.addShape("text", {
return container.addShape('text', {
attrs: {
...attrs,
x: cfg.x,
@ -120,13 +119,13 @@ class TagCloud extends Component<TagCloudProps, TagCloudState> {
const w = this.root.offsetWidth;
const onload = () => {
const dv = new DataSet.View().source(data);
const range = dv.range("value");
const range = dv.range('value');
const [min, max] = range;
dv.transform({
type: "tag-cloud",
fields: ["name", "value"],
type: 'tag-cloud',
fields: ['name', 'value'],
imageMask: this.imageMask,
font: "Verdana",
font: 'Verdana',
size: [w, h],
// 宽高设置最好根据 imageMask 做调整
padding: 0,
@ -151,7 +150,7 @@ class TagCloud extends Component<TagCloudProps, TagCloudState> {
};
if (!this.imageMask) {
this.imageMask = new Image();
this.imageMask.crossOrigin = "";
this.imageMask.crossOrigin = '';
this.imageMask.src = imgUrl;
this.imageMask.onload = onload;
} else {
@ -165,7 +164,7 @@ class TagCloud extends Component<TagCloudProps, TagCloudState> {
<div
className={classNames(styles.tagCloud, className)}
style={{
width: "100%",
width: '100%',
height,
}}
ref={this.saveRootRef}
@ -193,7 +192,7 @@ class TagCloud extends Component<TagCloudProps, TagCloudState> {
color="text"
shape="cloud"
tooltip={[
"text*value",
'text*value',
function trans(text, value) {
return {
name: text,

58
src/pages/dashboard/analysis/components/Charts/TimelineChart/index.tsx

@ -1,9 +1,9 @@
import { Axis, Chart, Geom, Legend, Tooltip } from "bizcharts";
import DataSet from "@antv/data-set";
import React from "react";
import Slider from "bizcharts-plugin-slider";
import autoHeight from "../autoHeight";
import useStyles from "./index.style";
import { Axis, Chart, Geom, Legend, Tooltip } from 'bizcharts';
import DataSet from '@antv/data-set';
import React from 'react';
import Slider from 'bizcharts-plugin-slider';
import autoHeight from '../autoHeight';
import useStyles from './index.style';
export type TimelineChartProps = {
data: {
x: number;
@ -27,8 +27,8 @@ const TimelineChart: React.FC<TimelineChartProps> = (props) => {
height = 400,
padding = [60, 20, 40, 40] as [number, number, number, number],
titleMap = {
y1: "y1",
y2: "y2",
y1: 'y1',
y2: 'y2',
},
borderWidth = 2,
data: sourceData,
@ -47,7 +47,7 @@ const TimelineChart: React.FC<TimelineChartProps> = (props) => {
if (data[0] && data[0].y1 && data[0].y2) {
max = Math.max(
[...data].sort((a, b) => b.y1 - a.y1)[0].y1,
[...data].sort((a, b) => b.y2 - a.y2)[0].y2
[...data].sort((a, b) => b.y2 - a.y2)[0].y2,
);
}
const ds = new DataSet({
@ -59,36 +59,36 @@ const TimelineChart: React.FC<TimelineChartProps> = (props) => {
const dv = ds.createView();
dv.source(data)
.transform({
type: "filter",
type: 'filter',
callback: (obj: { x: string }) => {
const date = obj.x;
return date <= ds.state.end && date >= ds.state.start;
},
})
.transform({
type: "map",
type: 'map',
callback(row: { y1: string; y2: string }) {
const newRow = {
...row,
};
newRow[titleMap.y1 as "y1"] = row.y1;
newRow[titleMap.y2 as "y2"] = row.y2;
newRow[titleMap.y1 as 'y1'] = row.y1;
newRow[titleMap.y2 as 'y2'] = row.y2;
return newRow;
},
})
.transform({
type: "fold",
type: 'fold',
fields: [titleMap.y1, titleMap.y2],
// 展开字段集
key: "key",
key: 'key',
// key字段
value: "value", // value字段
value: 'value', // value字段
});
const timeScale = {
type: "time",
type: 'time',
tickInterval: 60 * 60 * 1000,
mask: "HH:mm",
mask: 'HH:mm',
range: [0, 1],
};
const cols = {
@ -112,17 +112,11 @@ const TimelineChart: React.FC<TimelineChartProps> = (props) => {
start={ds.state.start}
end={ds.state.end}
backgroundChart={{
type: "line",
type: 'line',
}}
onChange={({
startValue,
endValue,
}: {
startValue: string;
endValue: string;
}) => {
ds.setState("start", startValue);
ds.setState("end", endValue);
onChange={({ startValue, endValue }: { startValue: string; endValue: string }) => {
ds.setState('start', startValue);
ds.setState('end', endValue);
}}
/>
);
@ -135,13 +129,7 @@ const TimelineChart: React.FC<TimelineChartProps> = (props) => {
>
<div>
{title && <h4>{title}</h4>}
<Chart
height={height}
padding={padding}
data={dv}
scale={cols}
forceFit
>
<Chart height={height} padding={padding} data={dv} scale={cols} forceFit>
<Axis name="x" />
<Tooltip />
<Legend name="key" position="top" />

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

@ -1,6 +1,6 @@
import React, { Component } from "react";
import autoHeight from "../autoHeight";
import useStyles from "./index.style";
import React, { Component } from 'react';
import autoHeight from '../autoHeight';
import useStyles from './index.style';
/* eslint no-return-assign: 0 */
/* eslint no-mixed-operators: 0 */
@ -24,28 +24,28 @@ class WaterWave extends Component<WaterWaveProps> {
this.renderChart();
this.resize();
window.addEventListener(
"resize",
'resize',
() => {
requestAnimationFrame(() => this.resize());
},
{
passive: true,
}
},
);
}
componentDidUpdate(props: WaterWaveProps) {
const { percent } = this.props;
if (props.percent !== percent) {
// 不加这个会造成绘制缓慢
this.renderChart("update");
this.renderChart('update');
}
}
componentWillUnmount() {
cancelAnimationFrame(this.timer);
if (this.node) {
this.node.innerHTML = "";
this.node.innerHTML = '';
}
window.removeEventListener("resize", this.resize);
window.removeEventListener('resize', this.resize);
}
resize = () => {
if (this.root) {
@ -57,14 +57,14 @@ class WaterWave extends Component<WaterWaveProps> {
}
};
renderChart(type?: string) {
const { percent, color = "#1890FF" } = this.props;
const { percent, color = '#1890FF' } = this.props;
const data = percent / 100;
cancelAnimationFrame(this.timer);
if (!this.node || (data !== 0 && !data)) {
return;
}
const canvas = this.node;
const ctx = canvas.getContext("2d");
const ctx = canvas.getContext('2d');
if (!ctx) {
return;
}
@ -88,11 +88,7 @@ class WaterWave extends Component<WaterWaveProps> {
const bR = radius - lineWidth;
const circleOffset = -(Math.PI / 2);
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)]);
}
const cStartPoint = arcStack.shift() as number[];
@ -118,7 +114,7 @@ class WaterWave extends Component<WaterWaveProps> {
ctx.lineTo(xOffset, canvasHeight);
ctx.lineTo(startPoint[0], startPoint[1]);
const gradient = ctx.createLinearGradient(0, 0, 0, canvasHeight);
gradient.addColorStop(0, "#ffffff");
gradient.addColorStop(0, '#ffffff');
gradient.addColorStop(1, color);
ctx.fillStyle = gradient;
ctx.fill();
@ -129,7 +125,7 @@ class WaterWave extends Component<WaterWaveProps> {
return;
}
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
if (circleLock && type !== "update") {
if (circleLock && type !== 'update') {
if (arcStack.length) {
const temp = arcStack.shift() as number[];
ctx.lineTo(temp[0], temp[1]);
@ -139,7 +135,7 @@ class WaterWave extends Component<WaterWaveProps> {
ctx.lineTo(cStartPoint[0], cStartPoint[1]);
ctx.stroke();
arcStack = [];
ctx.globalCompositeOperation = "destination-over";
ctx.globalCompositeOperation = 'destination-over';
ctx.beginPath();
ctx.lineWidth = lineWidth;
ctx.arc(radius, radius, bR, 0, 2 * Math.PI, true);
@ -199,7 +195,7 @@ class WaterWave extends Component<WaterWaveProps> {
style={{
width: height,
height,
overflow: "hidden",
overflow: 'hidden',
}}
>
<canvas

26
src/pages/dashboard/analysis/components/Charts/index.style.ts

@ -1,25 +1,25 @@
import { createStyles } from "antd-style";
import { createStyles } from 'antd-style';
const useStyles = createStyles(() => {
return {
miniChart: {
position: "relative",
width: "100%",
position: 'relative',
width: '100%',
},
chartContent: {
position: "absolute",
bottom: "-28px",
width: "100%",
position: 'absolute',
bottom: '-28px',
width: '100%',
},
"> div": {
margin: "0 -5px",
overflow: "hidden",
'> div': {
margin: '0 -5px',
overflow: 'hidden',
},
chartLoading: {
position: "absolute",
top: "16px",
left: "50%",
marginLeft: "-7px",
position: 'absolute',
top: '16px',
left: '50%',
marginLeft: '-7px',
},
};
});

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

@ -1,12 +1,12 @@
import { InfoCircleOutlined } from "@ant-design/icons";
import { TinyArea, TinyColumn, Progress } from "@ant-design/charts";
import { Col, Row, Tooltip } from "antd";
import numeral from "numeral";
import { ChartCard, Field } from "./Charts";
import type { DataItem } from "../data.d";
import Trend from "./Trend";
import Yuan from "../utils/Yuan";
import useStyles from "../style.style";
import { InfoCircleOutlined } from '@ant-design/icons';
import { TinyArea, TinyColumn, Progress } from '@ant-design/charts';
import { Col, Row, Tooltip } from 'antd';
import numeral from 'numeral';
import { ChartCard, Field } from './Charts';
import type { DataItem } from '../data.d';
import Trend from './Trend';
import Yuan from '../utils/Yuan';
import useStyles from '../style.style';
const topColResponsiveProps = {
xs: 24,
sm: 12,
@ -17,13 +17,7 @@ const topColResponsiveProps = {
marginBottom: 24,
},
};
const IntroduceRow = ({
loading,
visitData,
}: {
loading: boolean;
visitData: DataItem[];
}) => {
const IntroduceRow = ({ loading, visitData }: { loading: boolean; visitData: DataItem[] }) => {
const { styles } = useStyles();
return (
<Row gutter={24}>
@ -38,12 +32,7 @@ const IntroduceRow = ({
}
loading={loading}
total={() => <Yuan>126560</Yuan>}
footer={
<Field
label="日销售额"
value={`${numeral(12423).format("0,0")}`}
/>
}
footer={<Field label="日销售额" value={`${numeral(12423).format('0,0')}`} />}
contentHeight={46}
>
<Trend
@ -72,10 +61,8 @@ const IntroduceRow = ({
<InfoCircleOutlined />
</Tooltip>
}
total={numeral(8846).format("0,0")}
footer={
<Field label="日访问量" value={numeral(1234).format("0,0")} />
}
total={numeral(8846).format('0,0')}
footer={<Field label="日访问量" value={numeral(1234).format('0,0')} />}
contentHeight={46}
>
<TinyArea
@ -99,17 +86,11 @@ const IntroduceRow = ({
<InfoCircleOutlined />
</Tooltip>
}
total={numeral(6560).format("0,0")}
total={numeral(6560).format('0,0')}
footer={<Field label="转化率" value="60%" />}
contentHeight={46}
>
<TinyColumn
xField="x"
height={46}
forceFit
yField="y"
data={visitData}
/>
<TinyColumn xField="x" height={46} forceFit yField="y" data={visitData} />
</ChartCard>
</Col>
<Col {...topColResponsiveProps}>
@ -126,8 +107,8 @@ const IntroduceRow = ({
footer={
<div
style={{
whiteSpace: "nowrap",
overflow: "hidden",
whiteSpace: 'nowrap',
overflow: 'hidden',
}}
>
<Trend
@ -157,7 +138,7 @@ const IntroduceRow = ({
{
value: 0.8,
style: {
stroke: "#13C2C2",
stroke: '#13C2C2',
},
},
]}

42
src/pages/dashboard/analysis/components/NumberInfo/index.style.ts

@ -1,48 +1,48 @@
import { createStyles } from "antd-style";
import { createStyles } from 'antd-style';
const useStyles = createStyles(({ token }) => {
return {
numberInfo: {},
suffix: {
marginLeft: "4px",
marginLeft: '4px',
color: token.colorText,
fontSize: "16px",
fontStyle: "normal",
fontSize: '16px',
fontStyle: 'normal',
},
numberInfoTitle: {
marginBottom: "16px",
marginBottom: '16px',
color: token.colorText,
fontSize: token.fontSizeLg,
transition: "all 0.3s",
transition: 'all 0.3s',
},
numberInfoSubTitle: {
height: "22px",
overflow: "hidden",
height: '22px',
overflow: 'hidden',
color: token.colorTextSecondary,
fontSize: token.fontSize,
lineHeight: "22px",
whiteSpace: "nowrap",
textOverflow: "ellipsis",
wordBreak: "break-all",
lineHeight: '22px',
whiteSpace: 'nowrap',
textOverflow: 'ellipsis',
wordBreak: 'break-all',
},
numberInfoValue: {
"& > span": { color: token.colorText },
'& > span': { color: token.colorText },
},
subTotal: {
marginRight: "0",
marginRight: '0',
color: token.colorTextSecondary,
fontSize: token.fontSizeLg,
verticalAlign: "top",
verticalAlign: 'top',
},
".anticon": {
marginLeft: "4px",
fontSize: "12px",
transform: "scale(0.82)",
'.anticon': {
marginLeft: '4px',
fontSize: '12px',
transform: 'scale(0.82)',
},
".anticon-caret-up": {
'.anticon-caret-up': {
color: token.red6,
},
".anticon-caret-down": {
'.anticon-caret-down': {
color: token.green6,
},
numberInfolight: {},

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

@ -1,12 +1,12 @@
import { CaretUpOutlined, CaretDownOutlined } from "@ant-design/icons";
import React from "react";
import classNames from "classnames";
import useStyles from "./index.style";
import { CaretUpOutlined, CaretDownOutlined } from '@ant-design/icons';
import React from 'react';
import classNames from 'classnames';
import useStyles from './index.style';
export type NumberInfoProps = {
title?: React.ReactNode | string;
subTitle?: React.ReactNode | string;
total?: React.ReactNode | string;
status?: "up" | "down";
status?: 'up' | 'down';
theme?: string;
gap?: number;
subTotal?: number;
@ -33,17 +33,14 @@ const NumberInfo: React.FC<NumberInfoProps> = ({
{...rest}
>
{title && (
<div
className={styles.numberInfoTitle}
title={typeof title === "string" ? title : ""}
>
<div className={styles.numberInfoTitle} title={typeof title === 'string' ? title : ''}>
{title}
</div>
)}
{subTitle && (
<div
className={styles.numberInfoSubTitle}
title={typeof subTitle === "string" ? subTitle : ""}
title={typeof subTitle === 'string' ? subTitle : ''}
>
{subTitle}
</div>
@ -65,11 +62,7 @@ const NumberInfo: React.FC<NumberInfoProps> = ({
{(status || subTotal) && (
<span className={styles.subTotal}>
{subTotal}
{status && status === "up" ? (
<CaretUpOutlined />
) : (
<CaretDownOutlined />
)}
{status && status === 'up' ? <CaretUpOutlined /> : <CaretDownOutlined />}
</span>
)}
</div>

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

@ -1,8 +1,8 @@
import { Card, Col, Row, Tabs } from "antd";
import { RingProgress, Line } from "@ant-design/charts";
import type { OfflineDataType, DataItem } from "../data.d";
import NumberInfo from "./NumberInfo";
import useStyles from "../style.style";
import { Card, Col, Row, Tabs } from 'antd';
import { RingProgress, Line } from '@ant-design/charts';
import type { OfflineDataType, DataItem } from '../data.d';
import NumberInfo from './NumberInfo';
import useStyles from '../style.style';
const CustomTab = ({
data,
currentTabKey: currentKey,
@ -14,7 +14,7 @@ const CustomTab = ({
gutter={8}
style={{
width: 138,
margin: "8px 0",
margin: '8px 0',
}}
>
<Col span={12}>
@ -23,7 +23,7 @@ const CustomTab = ({
subTitle="转化率"
gap={2}
total={`${data.cvr * 100}%`}
theme={currentKey !== data.name ? "light" : undefined}
theme={currentKey !== data.name ? 'light' : undefined}
/>
</Col>
<Col
@ -62,13 +62,10 @@ const OfflineData = ({
>
<Tabs activeKey={activeKey} onChange={handleTabChange}>
{offlineData.map((shop) => (
<TabPane
tab={<CustomTab data={shop} currentTabKey={activeKey} />}
key={shop.name}
>
<TabPane tab={<CustomTab data={shop} currentTabKey={activeKey} />} key={shop.name}>
<div
style={{
padding: "0 24px",
padding: '0 24px',
}}
>
<Line
@ -81,12 +78,12 @@ const OfflineData = ({
seriesField="type"
interactions={[
{
type: "slider",
type: 'slider',
cfg: {},
},
]}
legend={{
position: "top-center",
position: 'top-center',
}}
/>
</div>

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

@ -1,11 +1,11 @@
import { Card, Radio, Typography } from "antd";
import numeral from "numeral";
import type { RadioChangeEvent } from "antd/es/radio";
import { Donut } from "@ant-design/charts";
import type { DonutConfig } from "@ant-design/charts/es/donut";
import React from "react";
import type { DataItem } from "../data.d";
import useStyles from "../style.style";
import { Card, Radio, Typography } from 'antd';
import numeral from 'numeral';
import type { RadioChangeEvent } from 'antd/es/radio';
import { Donut } from '@ant-design/charts';
import type { DonutConfig } from '@ant-design/charts/es/donut';
import React from 'react';
import type { DataItem } from '../data.d';
import useStyles from '../style.style';
const { Text } = Typography;
const ProportionSales = ({
dropdownGroup,
@ -16,7 +16,7 @@ const ProportionSales = ({
}: {
loading: boolean;
dropdownGroup: React.ReactNode;
salesType: "all" | "online" | "stores";
salesType: 'all' | 'online' | 'stores';
salesPieData: DataItem[];
handleChangeSalesType?: (e: RadioChangeEvent) => void;
}) => {
@ -28,7 +28,7 @@ const ProportionSales = ({
bordered={false}
title="销售额类别占比"
style={{
height: "100%",
height: '100%',
}}
extra={
<div className={styles.salesCardExtra}>
@ -57,18 +57,16 @@ const ProportionSales = ({
}}
label={{
visible: true,
type: "spider",
type: 'spider',
formatter: (text, item) => {
// eslint-disable-next-line no-underscore-dangle
return `${item._origin.x}: ${numeral(item._origin.y).format(
"0,0"
)}`;
return `${item._origin.x}: ${numeral(item._origin.y).format('0,0')}`;
},
}}
statistic={
{
totalLabel: "销售额",
} as DonutConfig["statistic"]
totalLabel: '销售额',
} as DonutConfig['statistic']
}
/>
</div>

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

@ -1,11 +1,11 @@
import { Card, Col, DatePicker, Row, Tabs } from "antd";
import type { RangePickerProps } from "antd/es/date-picker/generatePicker";
import type dayjs from "dayjs";
import { Column } from "@ant-design/charts";
import numeral from "numeral";
import type { DataItem } from "../data.d";
import useStyles from "../style.style";
export type TimeType = "today" | "week" | "month" | "year";
import { Card, Col, DatePicker, Row, Tabs } from 'antd';
import type { RangePickerProps } from 'antd/es/date-picker/generatePicker';
import type dayjs from 'dayjs';
import { Column } from '@ant-design/charts';
import numeral from 'numeral';
import type { DataItem } from '../data.d';
import useStyles from '../style.style';
export type TimeType = 'today' | 'week' | 'month' | 'year';
const { RangePicker } = DatePicker;
const { TabPane } = Tabs;
const rankingListData: {
@ -26,11 +26,11 @@ const SalesCard = ({
loading,
selectDate,
}: {
rangePickerValue: RangePickerProps<dayjs.Dayjs>["value"];
rangePickerValue: RangePickerProps<dayjs.Dayjs>['value'];
isActive: (key: TimeType) => string;
salesData: DataItem[];
loading: boolean;
handleRangePickerChange: RangePickerProps<dayjs.Dayjs>["onChange"];
handleRangePickerChange: RangePickerProps<dayjs.Dayjs>['onChange'];
selectDate: (key: TimeType) => void;
}) => {
const { styles } = useStyles();
@ -47,28 +47,16 @@ const SalesCard = ({
tabBarExtraContent={
<div className={styles.salesExtraWrap}>
<div className={styles.salesExtra}>
<a
className={isActive("today")}
onClick={() => selectDate("today")}
>
<a className={isActive('today')} onClick={() => selectDate('today')}>
</a>
<a
className={isActive("week")}
onClick={() => selectDate("week")}
>
<a className={isActive('week')} onClick={() => selectDate('week')}>
</a>
<a
className={isActive("month")}
onClick={() => selectDate("month")}
>
<a className={isActive('month')} onClick={() => selectDate('month')}>
</a>
<a
className={isActive("year")}
onClick={() => selectDate("year")}
>
<a className={isActive('year')} onClick={() => selectDate('year')}>
</a>
</div>
@ -110,14 +98,14 @@ const SalesCard = ({
}}
title={{
visible: true,
text: "销售趋势",
text: '销售趋势',
style: {
fontSize: 14,
},
}}
meta={{
y: {
alias: "销售量",
alias: '销售量',
},
}}
/>
@ -130,20 +118,15 @@ const SalesCard = ({
{rankingListData.map((item, i) => (
<li key={item.title}>
<span
className={`${styles.rankingItemNumber} ${
i < 3 ? styles.active : ""
}`}
className={`${styles.rankingItemNumber} ${i < 3 ? styles.active : ''}`}
>
{i + 1}
</span>
<span
className={styles.rankingItemTitle}
title={item.title}
>
<span className={styles.rankingItemTitle} title={item.title}>
{item.title}
</span>
<span className={styles.rankingItemValue}>
{numeral(item.total).format("0,0")}
{numeral(item.total).format('0,0')}
</span>
</li>
))}
@ -176,14 +159,14 @@ const SalesCard = ({
}}
title={{
visible: true,
text: "访问量趋势",
text: '访问量趋势',
style: {
fontSize: 14,
},
}}
meta={{
y: {
alias: "访问量",
alias: '访问量',
},
}}
/>
@ -196,19 +179,14 @@ const SalesCard = ({
{rankingListData.map((item, i) => (
<li key={item.title}>
<span
className={`${styles.rankingItemNumber} ${
i < 3 ? styles.active : ""
}`}
className={`${styles.rankingItemNumber} ${i < 3 ? styles.active : ''}`}
>
{i + 1}
</span>
<span
className={styles.rankingItemTitle}
title={item.title}
>
<span className={styles.rankingItemTitle} title={item.title}>
{item.title}
</span>
<span>{numeral(item.total).format("0,0")}</span>
<span>{numeral(item.total).format('0,0')}</span>
</li>
))}
</ul>

18
src/pages/dashboard/analysis/components/Trend/index.style.ts

@ -1,30 +1,30 @@
import { createStyles } from "antd-style";
import { createStyles } from 'antd-style';
const useStyles = createStyles(({ token }) => {
return {
trendItem: {
display: "inline-block",
display: 'inline-block',
fontSize: token.fontSize,
lineHeight: "22px",
lineHeight: '22px',
},
up: {
color: token.red6,
},
down: {
top: "-1px",
top: '-1px',
color: token.green6,
},
span: {
fontSize: "12px",
transform: "scale(0.83)",
fontSize: '12px',
transform: 'scale(0.83)',
},
"trendItemGrey .up, trendItemGrey .down": {
'trendItemGrey .up, trendItemGrey .down': {
color: token.colorText,
},
"reverseColor .up": {
'reverseColor .up': {
color: token.green6,
},
"reverseColor .down": {
'reverseColor .down': {
color: token.red6,
},
};

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

@ -1,10 +1,10 @@
import { CaretUpOutlined, CaretDownOutlined } from "@ant-design/icons";
import React from "react";
import classNames from "classnames";
import useStyles from "./index.style";
import { CaretUpOutlined, CaretDownOutlined } from '@ant-design/icons';
import React from 'react';
import classNames from 'classnames';
import useStyles from './index.style';
export type TrendProps = {
colorful?: boolean;
flag: "up" | "down";
flag: 'up' | 'down';
style?: React.CSSProperties;
reverseColor?: boolean;
className?: string;
@ -25,18 +25,14 @@ const Trend: React.FC<TrendProps> = ({
[styles.trendItemGrey]: !colorful,
[styles.reverseColor]: reverseColor && colorful,
},
className
className,
);
return (
<div
{...rest}
className={classString}
title={typeof children === "string" ? children : ""}
>
<div {...rest} className={classString} title={typeof children === 'string' ? children : ''}>
<span>{children}</span>
{flag && (
<span className={styles[flag]}>
{flag === "up" ? <CaretUpOutlined /> : <CaretDownOutlined />}
{flag === 'up' ? <CaretUpOutlined /> : <CaretDownOutlined />}
</span>
)}
</div>

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

@ -1,35 +1,35 @@
import type { FC } from "react";
import { Suspense, useState } from "react";
import { EllipsisOutlined } from "@ant-design/icons";
import { Col, Dropdown, Menu, Row } from "antd";
import { GridContent } from "@ant-design/pro-components";
import type { RadioChangeEvent } from "antd/es/radio";
import type { RangePickerProps } from "antd/es/date-picker/generatePicker";
import type dayjs from "dayjs";
import IntroduceRow from "./components/IntroduceRow";
import SalesCard from "./components/SalesCard";
import TopSearch from "./components/TopSearch";
import ProportionSales from "./components/ProportionSales";
import OfflineData from "./components/OfflineData";
import { useRequest } from "@umijs/max";
import { fakeChartData } from "./service";
import PageLoading from "./components/PageLoading";
import type { TimeType } from "./components/SalesCard";
import { getTimeDistance } from "./utils/utils";
import type { AnalysisData } from "./data.d";
import useStyles from "./style.style";
type RangePickerValue = RangePickerProps<dayjs.Dayjs>["value"];
import type { FC } from 'react';
import { Suspense, useState } from 'react';
import { EllipsisOutlined } from '@ant-design/icons';
import { Col, Dropdown, Menu, Row } from 'antd';
import { GridContent } from '@ant-design/pro-components';
import type { RadioChangeEvent } from 'antd/es/radio';
import type { RangePickerProps } from 'antd/es/date-picker/generatePicker';
import type dayjs from 'dayjs';
import IntroduceRow from './components/IntroduceRow';
import SalesCard from './components/SalesCard';
import TopSearch from './components/TopSearch';
import ProportionSales from './components/ProportionSales';
import OfflineData from './components/OfflineData';
import { useRequest } from '@umijs/max';
import { fakeChartData } from './service';
import PageLoading from './components/PageLoading';
import type { TimeType } from './components/SalesCard';
import { getTimeDistance } from './utils/utils';
import type { AnalysisData } from './data.d';
import useStyles from './style.style';
type RangePickerValue = RangePickerProps<dayjs.Dayjs>['value'];
type AnalysisProps = {
dashboardAndanalysis: AnalysisData;
loading: boolean;
};
type SalesType = "all" | "online" | "stores";
type SalesType = 'all' | 'online' | 'stores';
const Analysis: FC<AnalysisProps> = () => {
const { styles } = useStyles();
const [salesType, setSalesType] = useState<SalesType>("all");
const [currentTabKey, setCurrentTabKey] = useState<string>("");
const [salesType, setSalesType] = useState<SalesType>('all');
const [currentTabKey, setCurrentTabKey] = useState<string>('');
const [rangePickerValue, setRangePickerValue] = useState<RangePickerValue>(
getTimeDistance("year")
getTimeDistance('year'),
);
const { loading, data } = useRequest(fakeChartData);
const selectDate = (type: TimeType) => {
@ -40,31 +40,28 @@ const Analysis: FC<AnalysisProps> = () => {
};
const isActive = (type: TimeType) => {
if (!rangePickerValue) {
return "";
return '';
}
const value = getTimeDistance(type);
if (!value) {
return "";
return '';
}
if (!rangePickerValue[0] || !rangePickerValue[1]) {
return "";
return '';
}
if (
rangePickerValue[0].isSame(value[0] as dayjs.Dayjs, "day") &&
rangePickerValue[1].isSame(value[1] as dayjs.Dayjs, "day")
rangePickerValue[0].isSame(value[0] as dayjs.Dayjs, 'day') &&
rangePickerValue[1].isSame(value[1] as dayjs.Dayjs, 'day')
) {
return styles.currentDate;
}
return "";
return '';
};
let salesPieData;
if (salesType === "all") {
if (salesType === 'all') {
salesPieData = data?.salesTypeData;
} else {
salesPieData =
salesType === "online"
? data?.salesTypeDataOnline
: data?.salesTypeDataOffline;
salesPieData = salesType === 'online' ? data?.salesTypeDataOnline : data?.salesTypeDataOffline;
}
const menu = (
<Menu>
@ -85,8 +82,7 @@ const Analysis: FC<AnalysisProps> = () => {
const handleTabChange = (key: string) => {
setCurrentTabKey(key);
};
const activeKey =
currentTabKey || (data?.offlineData[0] && data?.offlineData[0].name) || "";
const activeKey = currentTabKey || (data?.offlineData[0] && data?.offlineData[0].name) || '';
return (
<GridContent>
<>

136
src/pages/dashboard/analysis/style.style.ts

@ -1,14 +1,14 @@
import { createStyles } from "antd-style";
import { createStyles } from 'antd-style';
const useStyles = createStyles(({ token }) => {
return {
iconGroup: {},
"span.anticon": {
marginLeft: "16px",
'span.anticon': {
marginLeft: '16px',
color: token.colorTextSecondary,
cursor: "pointer",
transition: "color 0.32s",
"&:hover": { color: token.colorText },
cursor: 'pointer',
transition: 'color 0.32s',
'&:hover': { color: token.colorText },
},
rankingList: {
[`@media screen and (max-width: ${token.screenLG}px)`]: {},
@ -18,42 +18,42 @@ const useStyles = createStyles(({ token }) => {
},
span: {
color: token.colorText,
fontSize: "14px",
lineHeight: "22px",
fontSize: '14px',
lineHeight: '22px',
},
rankingItemNumber: {
display: "inline-block",
width: "20px",
height: "20px",
marginTop: "1.5px",
marginRight: "16px",
fontWeight: "600",
fontSize: "12px",
lineHeight: "20px",
textAlign: "center",
display: 'inline-block',
width: '20px',
height: '20px',
marginTop: '1.5px',
marginRight: '16px',
fontWeight: '600',
fontSize: '12px',
lineHeight: '20px',
textAlign: 'center',
backgroundColor: token.tagDefaultBg,
borderRadius: "20px",
borderRadius: '20px',
},
active: {
color: "#fff",
backgroundColor: "#314659",
color: '#fff',
backgroundColor: '#314659',
},
rankingItemTitle: {
flex: "1",
marginRight: "8px",
overflow: "hidden",
whiteSpace: "nowrap",
textOverflow: "ellipsis",
flex: '1',
marginRight: '8px',
overflow: 'hidden',
whiteSpace: 'nowrap',
textOverflow: 'ellipsis',
},
salesExtra: {
[`@media screen and (max-width: ${token.screenLG}px)`]: {
display: "none",
display: 'none',
},
},
a: {
marginLeft: "24px",
marginLeft: '24px',
color: token.colorText,
"&:hover": { color: token.colorPrimary },
'&:hover': { color: token.colorPrimary },
},
currentDate: {
color: token.colorPrimary,
@ -63,82 +63,82 @@ const useStyles = createStyles(({ token }) => {
},
salesBar: {
[`@media screen and (max-width: ${token.screenMD}px)`]: {
padding: "16px",
padding: '16px',
},
},
salesRank: {
padding: "0 32px 32px 72px",
padding: '0 32px 32px 72px',
},
".ant-tabs-bar, .ant-tabs-nav-wrap": {
paddingLeft: "16px",
'.ant-tabs-bar, .ant-tabs-nav-wrap': {
paddingLeft: '16px',
},
".ant-tabs-nav .ant-tabs-tab": {
paddingTop: "16px",
paddingBottom: "14px",
lineHeight: "24px",
'.ant-tabs-nav .ant-tabs-tab': {
paddingTop: '16px',
paddingBottom: '14px',
lineHeight: '24px',
},
".ant-tabs-extra-content": {
paddingRight: "24px",
lineHeight: "55px",
'.ant-tabs-extra-content': {
paddingRight: '24px',
lineHeight: '55px',
},
".ant-card-head": {
position: "relative",
'.ant-card-head': {
position: 'relative',
},
".ant-card-head-title": {
alignItems: "normal",
'.ant-card-head-title': {
alignItems: 'normal',
},
salesCardExtra: {
height: "inherit",
height: 'inherit',
},
salesTypeRadio: {
position: "absolute",
right: "54px",
bottom: "12px",
position: 'absolute',
right: '54px',
bottom: '12px',
},
offlineCard: {},
".ant-tabs-ink-bar": {
bottom: "auto",
'.ant-tabs-ink-bar': {
bottom: 'auto',
},
".ant-tabs-bar": {
borderBottom: "none",
'.ant-tabs-bar': {
borderBottom: 'none',
},
".ant-tabs-nav-container-scrolling": {
paddingRight: "40px",
paddingLeft: "40px",
'.ant-tabs-nav-container-scrolling': {
paddingRight: '40px',
paddingLeft: '40px',
},
".ant-tabs-tab-prev-icon::before": {
position: "relative",
left: "6px",
'.ant-tabs-tab-prev-icon::before': {
position: 'relative',
left: '6px',
},
".ant-tabs-tab-next-icon::before": {
position: "relative",
right: "6px",
'.ant-tabs-tab-next-icon::before': {
position: 'relative',
right: '6px',
},
".ant-tabs-tab-active h4": {
'.ant-tabs-tab-active h4': {
color: token.colorPrimary,
},
trendText: {
marginLeft: "8px",
marginLeft: '8px',
color: token.colorTextHeading,
},
"span:first-child": {
'span:first-child': {
[`@media screen and (max-width: ${token.screenLG}px)`]: {
marginRight: "8px",
marginRight: '8px',
},
},
rankingTitle: {
[`@media screen and (max-width: ${token.screenMD}px)`]: {
marginTop: "16px",
marginTop: '16px',
},
},
salesExtraWrap: {
[`@media screen and (max-width: ${token.screenSM}px)`]: {
display: "none",
display: 'none',
},
},
".ant-tabs-content": {
'.ant-tabs-content': {
[`@media screen and (max-width: ${token.screenSM}px)`]: {
paddingTop: "30px",
paddingTop: '30px',
},
},
};

2
src/pages/dashboard/analysis/utils/utils.style.ts

@ -1,4 +1,4 @@
import { createStyles } from "antd-style";
import { createStyles } from 'antd-style';
const useStyles = createStyles(() => {
return {};

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

@ -1,55 +1,54 @@
import { createStyles } from "antd-style";
import { createStyles } from 'antd-style';
const useStyles = createStyles(() => {
return {
activeChart: {
position: "relative",
position: 'relative',
},
activeChartGrid: {},
p: {
position: "absolute",
top: "80px",
position: 'absolute',
top: '80px',
},
"p:last-child": {
top: "115px",
'p:last-child': {
top: '115px',
},
activeChartLegend: {
position: "relative",
height: "20px",
marginTop: "8px",
fontSize: "0",
lineHeight: "20px",
position: 'relative',
height: '20px',
marginTop: '8px',
fontSize: '0',
lineHeight: '20px',
},
span: {
display: "inline-block",
width: "33.33%",
fontSize: "12px",
textAlign: "center",
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',
},
dashedLine: {
position: "relative",
top: "-70px",
left: "-3px",
height: "1px",
position: 'relative',
top: '-70px',
left: '-3px',
height: '1px',
},
line: {
position: "absolute",
top: "0",
left: "0",
width: "100%",
height: "100%",
backgroundImage:
"linear-gradient(to right, transparent 50%, #e9e9e9 50%)",
backgroundSize: "6px",
},
"dashedLine:last-child": {
top: "-36px",
position: 'absolute',
top: '0',
left: '0',
width: '100%',
height: '100%',
backgroundImage: 'linear-gradient(to right, transparent 50%, #e9e9e9 50%)',
backgroundSize: '6px',
},
'dashedLine:last-child': {
top: '-36px',
},
};
});

22
src/pages/dashboard/monitor/components/Charts/MiniArea/index.tsx

@ -1,8 +1,8 @@
import type { AxisProps } from "bizcharts";
import { Axis, Chart, Geom, Tooltip } from "bizcharts";
import React from "react";
import autoHeight from "../autoHeight";
import useStyles from "../index.style";
import type { AxisProps } from 'bizcharts';
import { Axis, Chart, Geom, Tooltip } from 'bizcharts';
import React from 'react';
import autoHeight from '../autoHeight';
import useStyles from '../index.style';
export type MiniAreaProps = {
color?: string;
height?: number;
@ -32,8 +32,8 @@ const MiniArea: React.FC<MiniAreaProps> = (props) => {
height = 1,
data = [],
forceFit = true,
color = "rgba(24, 144, 255, 0.2)",
borderColor = "#1089ff",
color = 'rgba(24, 144, 255, 0.2)',
borderColor = '#1089ff',
scale = {
x: {},
y: {},
@ -47,7 +47,7 @@ const MiniArea: React.FC<MiniAreaProps> = (props) => {
const padding: [number, number, number, number] = [36, 5, 30, 5];
const scaleProps = {
x: {
type: "cat",
type: 'cat',
range: [0, 1],
...scale.x,
},
@ -61,9 +61,9 @@ const MiniArea: React.FC<MiniAreaProps> = (props) => {
(...args: any[]) => {
name?: string;
value: string;
}
},
] = [
"x*y",
'x*y',
(x: string, y: string) => ({
name: x,
value: y,
@ -128,7 +128,7 @@ const MiniArea: React.FC<MiniAreaProps> = (props) => {
) : (
<span
style={{
display: "none",
display: 'none',
}}
/>
)}

91
src/pages/dashboard/monitor/components/Charts/Pie/index.tsx

@ -1,12 +1,12 @@
import { Chart, Coord, Geom, Tooltip } from "bizcharts";
import React, { Component } from "react";
import { DataView } from "@antv/data-set";
import Debounce from "lodash.debounce";
import { Divider } from "antd";
import ReactFitText from "react-fittext";
import classNames from "classnames";
import autoHeight from "../autoHeight";
import useStyles from "./index.style";
import { Chart, Coord, Geom, Tooltip } from 'bizcharts';
import React, { Component } from 'react';
import { DataView } from '@antv/data-set';
import Debounce from 'lodash.debounce';
import { Divider } from 'antd';
import ReactFitText from 'react-fittext';
import classNames from 'classnames';
import autoHeight from '../autoHeight';
import useStyles from './index.style';
export type PieProps = {
animate?: boolean;
color?: string;
@ -56,7 +56,7 @@ class Pie extends Component<PieProps, PieState> {
const { hasLegend } = this.props;
const { legendBlock } = this.state;
if (!hasLegend || !this.root) {
window.removeEventListener("resize", this.resize);
window.removeEventListener('resize', this.resize);
return;
}
if (
@ -77,13 +77,13 @@ class Pie extends Component<PieProps, PieState> {
}, 300);
componentDidMount() {
window.addEventListener(
"resize",
'resize',
() => {
this.requestRef = requestAnimationFrame(() => this.resize());
},
{
passive: true,
}
},
);
}
componentDidUpdate(preProps: PieProps) {
@ -98,7 +98,7 @@ class Pie extends Component<PieProps, PieState> {
if (this.requestRef) {
window.cancelAnimationFrame(this.requestRef);
}
window.removeEventListener("resize", this.resize);
window.removeEventListener('resize', this.resize);
if (this.resize) {
(this.resize as any).cancel();
}
@ -117,21 +117,21 @@ class Pie extends Component<PieProps, PieState> {
const geom = this.chart.getAllGeoms()[0]; // 获取所有的图形
if (!geom) return;
// g2 的类型有问题
const items = (geom as any).get("dataArray") || []; // 获取图形对应的
const items = (geom as any).get('dataArray') || []; // 获取图形对应的
const legendData = items.map(
(
item: {
color: any;
_origin: any;
}[]
}[],
) => {
/* eslint no-underscore-dangle:0 */
const origin = item[0]._origin;
origin.color = item[0].color;
origin.checked = true;
return origin;
}
},
);
this.setState({
legendData,
@ -144,7 +144,7 @@ class Pie extends Component<PieProps, PieState> {
item: {
checked: boolean;
},
i: string | number
i: string | number,
) => {
const newItem = {
...item,
@ -152,14 +152,9 @@ class Pie extends Component<PieProps, PieState> {
newItem.checked = !newItem.checked;
const { legendData } = this.state;
legendData[i as unknown as number] = newItem as any;
const filteredLegendData = legendData
.filter((l) => l.checked)
.map((l) => l.x);
const filteredLegendData = legendData.filter((l) => l.checked).map((l) => l.x);
if (this.chart) {
this.chart.filter(
"x",
(val) => filteredLegendData.indexOf(`${val}`) > -1
);
this.chart.filter('x', (val) => filteredLegendData.indexOf(`${val}`) > -1);
}
this.setState({
legendData,
@ -202,7 +197,7 @@ class Pie extends Component<PieProps, PieState> {
let formatColor;
const scale = {
x: {
type: "cat",
type: 'cat',
range: [0, 1],
},
y: {
@ -213,18 +208,18 @@ class Pie extends Component<PieProps, PieState> {
selected = false;
tooltip = false;
formatColor = (value: string) => {
if (value === "占比") {
return color || "rgba(24, 144, 255, 0.85)";
if (value === '占比') {
return color || 'rgba(24, 144, 255, 0.85)';
}
return "#F0F2F5";
return '#F0F2F5';
};
data = [
{
x: "占比",
x: '占比',
y: parseFloat(`${percent}`),
},
{
x: "反比",
x: '反比',
y: 100 - parseFloat(`${percent}`),
},
];
@ -234,9 +229,9 @@ class Pie extends Component<PieProps, PieState> {
(...args: any[]) => {
name?: string;
value: string;
}
},
] = [
"x*percent",
'x*percent',
(x: string, p: number) => ({
name: x,
value: `${(p * 100).toFixed(2)}%`,
@ -245,10 +240,10 @@ class Pie extends Component<PieProps, PieState> {
const padding = [12, 0, 12, 0] as [number, number, number, number];
const dv = new DataView();
dv.source(data).transform({
type: "percent",
field: "y",
dimension: "x",
as: "percent",
type: 'percent',
field: 'y',
dimension: 'x',
as: 'percent',
});
return (
<div ref={this.handleRoot} className={pieClassName} style={style}>
@ -268,17 +263,12 @@ class Pie extends Component<PieProps, PieState> {
<Geom
style={{
lineWidth,
stroke: "#fff",
stroke: '#fff',
}}
tooltip={tooltip ? tooltipFormat : undefined}
type="intervalStack"
position="percent"
color={
[
"x",
percent || percent === 0 ? formatColor : defaultColors,
] as any
}
color={['x', percent || percent === 0 ? formatColor : defaultColors] as any}
selected={selected}
/>
</Chart>
@ -288,9 +278,7 @@ class Pie extends Component<PieProps, PieState> {
{subTitle && <h4 className="pie-sub-title">{subTitle}</h4>}
{/* eslint-disable-next-line */}
{total && (
<div className="pie-stat">
{typeof total === "function" ? total() : total}
</div>
<div className="pie-stat">{typeof total === 'function' ? total() : total}</div>
)}
</div>
)}
@ -304,20 +292,15 @@ class Pie extends Component<PieProps, PieState> {
<span
className={styles.dot}
style={{
backgroundColor: !item.checked ? "#aaa" : item.color,
backgroundColor: !item.checked ? '#aaa' : item.color,
}}
/>
<span className={styles.legendTitle}>{item.x}</span>
<Divider type="vertical" />
<span className={styles.percent}>
{`${(Number.isNaN(item.percent)
? 0
: item.percent * 100
).toFixed(2)}%`}
</span>
<span className={styles.value}>
{valueFormat ? valueFormat(item.y) : item.y}
{`${(Number.isNaN(item.percent) ? 0 : item.percent * 100).toFixed(2)}%`}
</span>
<span className={styles.value}>{valueFormat ? valueFormat(item.y) : item.y}</span>
</li>
))}
</ul>

47
src/pages/dashboard/monitor/components/Charts/TagCloud/index.tsx

@ -1,16 +1,15 @@
import { Chart, Coord, Geom, Shape, Tooltip } from "bizcharts";
import React, { Component } from "react";
import DataSet from "@antv/data-set";
import Debounce from "lodash.debounce";
import classNames from "classnames";
import autoHeight from "../autoHeight";
import useStyles from "./index.style";
import { Chart, Coord, Geom, Shape, Tooltip } from 'bizcharts';
import React, { Component } from 'react';
import DataSet from '@antv/data-set';
import Debounce from 'lodash.debounce';
import classNames from 'classnames';
import autoHeight from '../autoHeight';
import useStyles from './index.style';
/* eslint no-underscore-dangle: 0 */
/* eslint no-param-reassign: 0 */
const imgUrl =
"https://gw.alipayobjects.com/zos/rmsportal/gWyeGLCdFFRavBGIDzWk.png";
const imgUrl = 'https://gw.alipayobjects.com/zos/rmsportal/gWyeGLCdFFRavBGIDzWk.png';
export type TagCloudProps = {
data: {
name: string;
@ -40,7 +39,7 @@ class TagCloud extends Component<TagCloudProps, TagCloudState> {
this.initTagCloud();
this.renderChart(this.props);
});
window.addEventListener("resize", this.resize, {
window.addEventListener('resize', this.resize, {
passive: true,
});
}
@ -53,7 +52,7 @@ class TagCloud extends Component<TagCloudProps, TagCloudState> {
componentWillUnmount() {
this.isUnmount = true;
window.cancelAnimationFrame(this.requestRef);
window.removeEventListener("resize", this.resize);
window.removeEventListener('resize', this.resize);
}
resize = () => {
this.requestRef = requestAnimationFrame(() => {
@ -78,13 +77,13 @@ class TagCloud extends Component<TagCloudProps, TagCloudState> {
fontSize: cfg.origin._origin.size,
rotate: cfg.origin._origin.rotate,
text: cfg.origin._origin.text,
textAlign: "center",
textAlign: 'center',
fontFamily: cfg.origin._origin.font,
fill: cfg.color,
textBaseline: "Alphabetic",
textBaseline: 'Alphabetic',
};
}
(Shape as any).registerShape("point", "cloud", {
(Shape as any).registerShape('point', 'cloud', {
drawShape(
cfg: {
x: any;
@ -95,12 +94,12 @@ class TagCloud extends Component<TagCloudProps, TagCloudState> {
arg0: string,
arg1: {
attrs: any;
}
},
) => void;
}
},
) {
const attrs = getTextAttrs(cfg);
return container.addShape("text", {
return container.addShape('text', {
attrs: {
...attrs,
x: cfg.x,
@ -120,13 +119,13 @@ class TagCloud extends Component<TagCloudProps, TagCloudState> {
const w = this.root.offsetWidth;
const onload = () => {
const dv = new DataSet.View().source(data);
const range = dv.range("value");
const range = dv.range('value');
const [min, max] = range;
dv.transform({
type: "tag-cloud",
fields: ["name", "value"],
type: 'tag-cloud',
fields: ['name', 'value'],
imageMask: this.imageMask,
font: "Verdana",
font: 'Verdana',
size: [w, h],
// 宽高设置最好根据 imageMask 做调整
padding: 0,
@ -151,7 +150,7 @@ class TagCloud extends Component<TagCloudProps, TagCloudState> {
};
if (!this.imageMask) {
this.imageMask = new Image();
this.imageMask.crossOrigin = "";
this.imageMask.crossOrigin = '';
this.imageMask.src = imgUrl;
this.imageMask.onload = onload;
} else {
@ -165,7 +164,7 @@ class TagCloud extends Component<TagCloudProps, TagCloudState> {
<div
className={classNames(styles.tagCloud, className)}
style={{
width: "100%",
width: '100%',
height,
}}
ref={this.saveRootRef}
@ -193,7 +192,7 @@ class TagCloud extends Component<TagCloudProps, TagCloudState> {
color="text"
shape="cloud"
tooltip={[
"text*value",
'text*value',
function trans(text, value) {
return {
name: text,

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

@ -1,6 +1,6 @@
import React, { Component } from "react";
import autoHeight from "../autoHeight";
import useStyles from "./index.style";
import React, { Component } from 'react';
import autoHeight from '../autoHeight';
import useStyles from './index.style';
/* eslint no-return-assign: 0 */
/* eslint no-mixed-operators: 0 */
@ -24,28 +24,28 @@ class WaterWave extends Component<WaterWaveProps> {
this.renderChart();
this.resize();
window.addEventListener(
"resize",
'resize',
() => {
requestAnimationFrame(() => this.resize());
},
{
passive: true,
}
},
);
}
componentDidUpdate(props: WaterWaveProps) {
const { percent } = this.props;
if (props.percent !== percent) {
// 不加这个会造成绘制缓慢
this.renderChart("update");
this.renderChart('update');
}
}
componentWillUnmount() {
cancelAnimationFrame(this.timer);
if (this.node) {
this.node.innerHTML = "";
this.node.innerHTML = '';
}
window.removeEventListener("resize", this.resize);
window.removeEventListener('resize', this.resize);
}
resize = () => {
if (this.root) {
@ -57,14 +57,14 @@ class WaterWave extends Component<WaterWaveProps> {
}
};
renderChart(type?: string) {
const { percent, color = "#1890FF" } = this.props;
const { percent, color = '#1890FF' } = this.props;
const data = percent / 100;
cancelAnimationFrame(this.timer);
if (!this.node || (data !== 0 && !data)) {
return;
}
const canvas = this.node;
const ctx = canvas.getContext("2d");
const ctx = canvas.getContext('2d');
if (!ctx) {
return;
}
@ -88,11 +88,7 @@ class WaterWave extends Component<WaterWaveProps> {
const bR = radius - lineWidth;
const circleOffset = -(Math.PI / 2);
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)]);
}
const cStartPoint = arcStack.shift() as number[];
@ -118,7 +114,7 @@ class WaterWave extends Component<WaterWaveProps> {
ctx.lineTo(xOffset, canvasHeight);
ctx.lineTo(startPoint[0], startPoint[1]);
const gradient = ctx.createLinearGradient(0, 0, 0, canvasHeight);
gradient.addColorStop(0, "#ffffff");
gradient.addColorStop(0, '#ffffff');
gradient.addColorStop(1, color);
ctx.fillStyle = gradient;
ctx.fill();
@ -129,7 +125,7 @@ class WaterWave extends Component<WaterWaveProps> {
return;
}
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
if (circleLock && type !== "update") {
if (circleLock && type !== 'update') {
if (arcStack.length) {
const temp = arcStack.shift() as number[];
ctx.lineTo(temp[0], temp[1]);
@ -139,7 +135,7 @@ class WaterWave extends Component<WaterWaveProps> {
ctx.lineTo(cStartPoint[0], cStartPoint[1]);
ctx.stroke();
arcStack = [];
ctx.globalCompositeOperation = "destination-over";
ctx.globalCompositeOperation = 'destination-over';
ctx.beginPath();
ctx.lineWidth = lineWidth;
ctx.arc(radius, radius, bR, 0, 2 * Math.PI, true);
@ -199,7 +195,7 @@ class WaterWave extends Component<WaterWaveProps> {
style={{
width: height,
height,
overflow: "hidden",
overflow: 'hidden',
}}
>
<canvas

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

@ -1,14 +1,14 @@
import { Card, Col, Row, Statistic } from "antd";
import { useRequest } from "@umijs/max";
import type { FC } from "react";
import { Gauge, WordCloud, Liquid, RingProgress } from "@ant-design/charts";
import type { WordCloudData } from "@antv/g2plot/esm/plots/word-cloud/layer";
import { GridContent } from "@ant-design/pro-components";
import numeral from "numeral";
import Map from "./components/Map";
import ActiveChart from "./components/ActiveChart";
import { queryTags } from "./service";
import useStyles from "./style.style";
import { Card, Col, Row, Statistic } from 'antd';
import { useRequest } from '@umijs/max';
import type { FC } from 'react';
import { Gauge, WordCloud, Liquid, RingProgress } from '@ant-design/charts';
import type { WordCloudData } from '@antv/g2plot/esm/plots/word-cloud/layer';
import { GridContent } from '@ant-design/pro-components';
import numeral from 'numeral';
import Map from './components/Map';
import ActiveChart from './components/ActiveChart';
import { queryTags } from './service';
import useStyles from './style.style';
const { Countdown } = Statistic;
const deadline = Date.now() + 1000 * 60 * 60 * 24 * 2 + 1000 * 30; // Moment is also OK
@ -42,25 +42,17 @@ const Monitor: FC = () => {
<Statistic
title="今日交易总额"
suffix="元"
value={numeral(124543233).format("0,0")}
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"
/>
<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")}
/>
<Statistic title="每秒交易总额" suffix="元" value={numeral(234).format('0,0')} />
</Col>
</Row>
<div className={styles.mapChart}>
@ -84,7 +76,7 @@ const Monitor: FC = () => {
marginBottom: 24,
}}
bodyStyle={{
textAlign: "center",
textAlign: 'center',
}}
bordered={false}
>
@ -97,8 +89,8 @@ const Monitor: FC = () => {
range={[0, 25, 50, 75, 100]}
statistic={{
visible: true,
text: "优",
color: "#30bf78",
text: '优',
color: '#30bf78',
}}
/>
</Card>
@ -114,14 +106,10 @@ const Monitor: FC = () => {
marginBottom: 24,
}}
>
<Card
title="各品类占比"
bordered={false}
className={styles.pieCard}
>
<Card title="各品类占比" bordered={false} className={styles.pieCard}>
<Row
style={{
padding: "16px 0",
padding: '16px 0',
}}
>
<Col span={8}>
@ -136,20 +124,10 @@ const Monitor: FC = () => {
/> */}
</Col>
<Col span={8}>
<RingProgress
color="#5DDECF"
forceFit
height={128}
percent={0.22}
/>
<RingProgress color="#5DDECF" forceFit height={128} percent={0.22} />
</Col>
<Col span={8}>
<RingProgress
color="#2FC25B"
forceFit
height={128}
percent={0.32}
/>
<RingProgress color="#2FC25B" forceFit height={128} percent={0.32} />
</Col>
</Row>
</Card>
@ -168,7 +146,7 @@ const Monitor: FC = () => {
loading={loading}
bordered={false}
bodyStyle={{
overflow: "hidden",
overflow: 'hidden',
}}
>
<WordCloud
@ -195,7 +173,7 @@ const Monitor: FC = () => {
<Card
title="资源剩余"
bodyStyle={{
textAlign: "center",
textAlign: 'center',
fontSize: 0,
}}
bordered={false}
@ -208,8 +186,7 @@ const Monitor: FC = () => {
forceFit
padding={[0, 0, 0, 0]}
statistic={{
formatter: (value) =>
`${((100 * value) / 10000).toFixed(1)}%`,
formatter: (value) => `${((100 * value) / 10000).toFixed(1)}%`,
}}
/>
</Card>

10
src/pages/dashboard/monitor/style.style.ts

@ -1,16 +1,16 @@
import { createStyles } from "antd-style";
import { createStyles } from 'antd-style';
const useStyles = createStyles(({ token }) => {
return {
mapChart: {
[`@media screen and (max-width: ${token.screenLG}px)`]: {
height: "auto",
height: 'auto',
},
},
img: {
display: "inline-block",
maxWidth: "100%",
maxHeight: "437px",
display: 'inline-block',
maxWidth: '100%',
maxHeight: '437px',
},
};
});

16
src/pages/dashboard/workplace/components/EditableLinkGroup/index.style.ts

@ -1,17 +1,17 @@
import { createStyles } from "antd-style";
import { createStyles } from 'antd-style';
const useStyles = createStyles(({ token }) => {
return {
linkGroup: {
padding: "20px 0 8px 24px",
fontSize: "0",
"& > a": {
display: "inline-block",
width: "25%",
marginBottom: "13px",
padding: '20px 0 8px 24px',
fontSize: '0',
'& > a': {
display: 'inline-block',
width: '25%',
marginBottom: '13px',
color: token.colorText,
fontSize: token.fontSize,
"&:hover": {
'&:hover': {
color: token.colorPrimary,
},
},

14
src/pages/dashboard/workplace/components/EditableLinkGroup/index.tsx

@ -1,7 +1,7 @@
import React, { createElement } from "react";
import { PlusOutlined } from "@ant-design/icons";
import { Button } from "antd";
import useStyles from "./index.style";
import React, { createElement } from 'react';
import { PlusOutlined } from '@ant-design/icons';
import { Button } from 'antd';
import useStyles from './index.style';
export type EditableLink = {
title: string;
href: string;
@ -25,8 +25,8 @@ const EditableLinkGroup: React.FC<EditableLinkGroupProps> = (props) => {
to: link.href,
href: link.href,
},
link.title
)
link.title,
),
)}
<Button size="small" type="primary" ghost onClick={onAdd}>
<PlusOutlined />
@ -37,6 +37,6 @@ const EditableLinkGroup: React.FC<EditableLinkGroupProps> = (props) => {
EditableLinkGroup.defaultProps = {
links: [],
onAdd: () => {},
linkElement: "a",
linkElement: 'a',
};
export default EditableLinkGroup;

322
src/pages/dashboard/workplace/components/Radar/index.tsx

@ -1,8 +1,8 @@
import { Axis, Chart, Coord, Geom, Tooltip } from "bizcharts";
import { Col, Row } from "antd";
import React, { Component } from "react";
import autoHeight from "./autoHeight";
import useStyles from "./index.style";
import { Axis, Chart, Coord, Geom, Tooltip } from 'bizcharts';
import { Col, Row } from 'antd';
import React, { useEffect, useRef, useState } from 'react';
import autoHeight from './autoHeight';
export type RadarProps = {
title?: React.ReactNode;
height?: number;
@ -28,192 +28,148 @@ type RadarState = {
value: string;
}[];
};
/* eslint react/no-danger:0 */
class Radar extends Component<RadarProps, RadarState> {
state: RadarState = {
legendData: [],
};
chart: G2.Chart | undefined = undefined;
node: HTMLDivElement | undefined = undefined;
componentDidMount() {
this.getLegendData();
}
componentDidUpdate(preProps: RadarProps) {
const { data } = this.props;
if (data !== preProps.data) {
this.getLegendData();
}
}
getG2Instance = (chart: G2.Chart) => {
this.chart = chart;
};
// for custom lengend view
getLegendData = () => {
if (!this.chart) return;
const geom = this.chart.getAllGeoms()[0]; // 获取所有的图形
const defaultColors = [
'#1890FF',
'#FACC14',
'#2FC25B',
'#8543E0',
'#F04864',
'#13C2C2',
'#fa8c16',
'#a0d911',
];
const Radar: React.FC<RadarProps> = (props) => {
const {
data = [],
height = 0,
title,
hasLegend = false,
forceFit = true,
tickCount = 5,
padding = [35, 30, 16, 30] as [number, number, number, number],
animate = true,
colors = defaultColors,
} = props;
const chartRef = useRef<G2.Chart>();
const [legendData, setLegendData] = useState<RadarState['legendData']>([]);
const getLegendData = () => {
if (!chartRef.current) return;
const geom = chartRef.current.getAllGeoms()[0];
if (!geom) return;
const items = (geom as any).get("dataArray") || []; // 获取图形对应的
const items = (geom as any).get('dataArray') || [];
const legendData = items.map(
(
item: {
color: any;
_origin: any;
}[]
) => {
// eslint-disable-next-line no-underscore-dangle
const origins = item.map((t) => t._origin);
const result = {
name: origins[0].name,
color: item[0].color,
checked: true,
value: origins.reduce((p, n) => p + n.value, 0),
};
return result;
}
);
this.setState({
legendData,
const legendData = items.map((item: any[]) => {
const origins = item.map((t) => t._origin);
const result = {
name: origins[0].name,
color: item[0].color,
checked: true,
value: origins.reduce((p, n) => p + n.value, 0),
};
return result;
});
setLegendData(legendData);
};
handleRef = (n: HTMLDivElement) => {
this.node = n;
useEffect(() => {
getLegendData();
}, [data]);
const handleLegendClick = (item: any, i: string | number) => {
const newItem = { ...item, checked: !item.checked };
const newLegendData = [...legendData];
newLegendData[i as number] = newItem;
const filteredLegendData = newLegendData.filter((l) => l.checked).map((l) => l.name);
if (chartRef.current) {
chartRef.current.filter('name', (val) => filteredLegendData.indexOf(`${val}`) > -1);
chartRef.current.repaint();
}
setLegendData(newLegendData);
};
handleLegendClick = (
item: {
checked: boolean;
name: string;
const scale = {
value: {
min: 0,
tickCount,
},
i: string | number
) => {
const newItem = item;
newItem.checked = !newItem.checked;
const { legendData } = this.state;
legendData[i as number] = newItem as any;
const filteredLegendData = legendData
.filter((l) => l.checked)
.map((l) => l.name);
if (this.chart) {
this.chart.filter(
"name",
(val) => filteredLegendData.indexOf(`${val}`) > -1
);
this.chart.repaint();
}
this.setState({
legendData,
});
};
render() {
const defaultColors = [
"#1890FF",
"#FACC14",
"#2FC25B",
"#8543E0",
"#F04864",
"#13C2C2",
"#fa8c16",
"#a0d911",
];
const {
data = [],
height = 0,
title,
hasLegend = false,
forceFit = true,
tickCount = 5,
padding = [35, 30, 16, 30] as [number, number, number, number],
animate = true,
colors = defaultColors,
} = this.props;
const { legendData } = this.state;
const scale = {
value: {
min: 0,
tickCount,
},
};
const chartHeight = height - (hasLegend ? 80 : 22);
return (
<div
className={styles.radar}
style={{
height,
const chartHeight = height - (hasLegend ? 80 : 22);
return (
<div style={{ height }}>
{title && <h4>{title}</h4>}
<Chart
scale={scale}
height={chartHeight}
forceFit={forceFit}
data={data}
padding={padding}
animate={animate}
onGetG2Instance={(chart: G2.Chart) => {
chartRef.current = chart;
}}
>
{title && <h4>{title}</h4>}
<Chart
scale={scale}
height={chartHeight}
forceFit={forceFit}
data={data}
padding={padding}
animate={animate}
onGetG2Instance={this.getG2Instance}
>
<Tooltip />
<Coord type="polar" />
<Axis
name="label"
line={undefined}
tickLine={undefined}
grid={{
lineStyle: {
lineDash: undefined,
},
hideFirstLine: false,
}}
/>
<Axis
name="value"
grid={{
type: "polygon",
lineStyle: {
lineDash: undefined,
},
}}
/>
<Geom
type="line"
position="label*value"
color={["name", colors]}
size={1}
/>
<Geom
type="point"
position="label*value"
color={["name", colors]}
shape="circle"
size={3}
/>
</Chart>
{hasLegend && (
<Row className={styles.legend}>
{legendData.map((item, i) => (
<Col
span={24 / legendData.length}
key={item.name}
onClick={() => this.handleLegendClick(item, i)}
>
<div className={styles.legendItem}>
<p>
<span
className={styles.dot}
style={{
backgroundColor: !item.checked ? "#aaa" : item.color,
}}
/>
<span>{item.name}</span>
</p>
<h6>{item.value}</h6>
</div>
</Col>
))}
</Row>
)}
</div>
);
}
}
<Tooltip />
<Coord type="polar" />
<Axis
name="label"
line={undefined}
tickLine={undefined}
grid={{
lineStyle: {
lineDash: undefined,
},
hideFirstLine: false,
}}
/>
<Axis
name="value"
grid={{
type: 'polygon',
lineStyle: {
lineDash: undefined,
},
}}
/>
<Geom type="line" position="label*value" color={['name', colors]} size={1} />
<Geom
type="point"
position="label*value"
color={['name', colors]}
shape="circle"
size={3}
/>
</Chart>
{hasLegend && (
<Row>
{legendData.map((item, i) => (
<Col
span={24 / legendData.length}
key={item.name}
onClick={() => handleLegendClick(item, i)}
>
<div>
<p>
<span
style={{
backgroundColor: !item.checked ? '#aaa' : item.color,
}}
/>
<span>{item.name}</span>
</p>
<h6>{item.value}</h6>
</div>
</Col>
))}
</Row>
)}
</div>
);
};
export default autoHeight()(Radar);

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

@ -1,39 +1,39 @@
import type { FC } from "react";
import { Avatar, Card, Col, List, Skeleton, Row, Statistic } from "antd";
import { Radar } from "@ant-design/charts";
import { Link, useRequest } from "@umijs/max";
import { PageContainer } from "@ant-design/pro-components";
import dayjs from "dayjs";
import EditableLinkGroup from "./components/EditableLinkGroup";
import useStyles from "./style.style";
import type { ActivitiesType, CurrentUser } from "./data.d";
import { queryProjectNotice, queryActivities, fakeChartData } from "./service";
import relativeTime from "dayjs/plugin/relativeTime";
import type { FC } from 'react';
import { Avatar, Card, Col, List, Skeleton, Row, Statistic } from 'antd';
import { Radar } from '@ant-design/charts';
import { Link, useRequest } from '@umijs/max';
import { PageContainer } from '@ant-design/pro-components';
import dayjs from 'dayjs';
import EditableLinkGroup from './components/EditableLinkGroup';
import useStyles from './style.style';
import type { ActivitiesType, CurrentUser } from './data.d';
import { queryProjectNotice, queryActivities, fakeChartData } from './service';
import relativeTime from 'dayjs/plugin/relativeTime';
dayjs.extend(relativeTime);
const links = [
{
title: "操作一",
href: "",
title: '操作一',
href: '',
},
{
title: "操作二",
href: "",
title: '操作二',
href: '',
},
{
title: "操作三",
href: "",
title: '操作三',
href: '',
},
{
title: "操作四",
href: "",
title: '操作四',
href: '',
},
{
title: "操作五",
href: "",
title: '操作五',
href: '',
},
{
title: "操作六",
href: "",
title: '操作六',
href: '',
},
];
const PageHeaderContent: FC<{
@ -88,15 +88,13 @@ const ExtraContent: FC<Record<string, any>> = () => {
};
const Workplace: FC = () => {
const { styles } = useStyles();
const { loading: projectLoading, data: projectNotice = [] } =
useRequest(queryProjectNotice);
const { loading: activitiesLoading, data: activities = [] } =
useRequest(queryActivities);
const { loading: projectLoading, data: projectNotice = [] } = useRequest(queryProjectNotice);
const { loading: activitiesLoading, data: activities = [] } = useRequest(queryActivities);
const { data } = useRequest(fakeChartData);
const renderActivities = (item: ActivitiesType) => {
const events = item.template.split(/@\{([^{}]*)\}/gi).map((key) => {
if (item[key as keyof ActivitiesType]) {
const value = item[key as "user"];
const value = item[key as 'user'];
return (
<a href={value?.link} key={value?.name}>
{value.name}
@ -130,14 +128,13 @@ const Workplace: FC = () => {
content={
<PageHeaderContent
currentUser={{
avatar:
"https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png",
name: "吴彦祖",
userid: "00000001",
email: "antdesign@alipay.com",
signature: "海纳百川,有容乃大",
title: "交互专家",
group: "蚂蚁金服-某某某事业群-某某平台部-某某技术部-UED",
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png',
name: '吴彦祖',
userid: '00000001',
email: 'antdesign@alipay.com',
signature: '海纳百川,有容乃大',
title: '交互专家',
group: '蚂蚁金服-某某某事业群-某某平台部-某某技术部-UED',
}}
/>
}
@ -176,7 +173,7 @@ const Workplace: FC = () => {
description={item.description}
/>
<div className={styles.projectItemContent}>
<Link to={item.memberLink}>{item.member || ""}</Link>
<Link to={item.memberLink}>{item.member || ''}</Link>
{item.updatedAt && (
<span className={styles.datetime} title={item.updatedAt}>
{dayjs(item.updatedAt).fromNow()}
@ -216,11 +213,7 @@ const Workplace: FC = () => {
padding: 0,
}}
>
<EditableLinkGroup
onAdd={() => {}}
links={links}
linkElement={Link}
/>
<EditableLinkGroup onAdd={() => {}} links={links} linkElement={Link} />
</Card>
<Card
style={{
@ -244,7 +237,7 @@ const Workplace: FC = () => {
visible: true,
}}
legend={{
position: "bottom-center",
position: 'bottom-center',
}}
/>
</div>

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

@ -1,147 +1,147 @@
import { createStyles } from "antd-style";
import { createStyles } from 'antd-style';
const useStyles = createStyles(({ token }) => {
return {
activitiesList: {
padding: "0 24px 8px 24px",
padding: '0 24px 8px 24px',
},
username: {
color: token.colorText,
},
event: {
fontWeight: "normal",
fontWeight: 'normal',
},
pageHeaderContent: {
[`@media screen and (max-width: ${token.screenSM}px)`]: {
display: "block",
display: 'block',
},
},
avatar: {
flex: "0 1 72px",
"& > span": {
display: "block",
width: "72px",
height: "72px",
borderRadius: "72px",
flex: '0 1 72px',
'& > span': {
display: 'block',
width: '72px',
height: '72px',
borderRadius: '72px',
},
},
content: {
[`@media screen and (max-width: ${token.screenSM}px)`]: {
marginLeft: "0",
marginLeft: '0',
},
},
contentTitle: {
marginBottom: "12px",
marginBottom: '12px',
color: token.colorTextHeading,
fontWeight: "500",
fontSize: "20px",
lineHeight: "28px",
fontWeight: '500',
fontSize: '20px',
lineHeight: '28px',
},
extraContent: {
[`@media screen and (max-width: ${token.screenSM}px)`]: {},
},
statItem: {
[`@media screen and (max-width: ${token.screenSM}px)`]: { float: "none" },
[`@media screen and (max-width: ${token.screenSM}px)`]: { float: 'none' },
},
"> p:first-child": {
marginBottom: "4px",
'> p:first-child': {
marginBottom: '4px',
color: token.colorTextSecondary,
fontSize: token.fontSize,
lineHeight: "22px",
lineHeight: '22px',
},
"> p": {
margin: "0",
'> p': {
margin: '0',
color: token.colorTextHeading,
fontSize: "30px",
lineHeight: "38px",
fontSize: '30px',
lineHeight: '38px',
},
"> span": {
'> span': {
color: token.colorTextSecondary,
fontSize: "20px",
fontSize: '20px',
},
members: {
[`@media screen and (max-width: ${token.screenLG}px)`]: {
marginBottom: "0",
marginBottom: '0',
},
},
a: {
display: "inline-block",
flex: "1 1 0",
display: 'inline-block',
flex: '1 1 0',
color: token.colorTextSecondary,
position: "relative",
position: 'relative',
maxHeight: token.line * 1.5,
marginRight: "-1em",
paddingRight: "1em",
overflow: "hidden",
lineHeight: "1.5em",
textAlign: "justify",
"&::before": {
position: "absolute",
right: "14px",
bottom: "0",
padding: "0 1px",
marginRight: '-1em',
paddingRight: '1em',
overflow: 'hidden',
lineHeight: '1.5em',
textAlign: 'justify',
'&::before': {
position: 'absolute',
right: '14px',
bottom: '0',
padding: '0 1px',
background: token.bg,
content: "'...'",
},
"&::after": {
position: "absolute",
right: "14px",
width: "1em",
height: "1em",
marginTop: "0.2em",
background: "white",
'&::after': {
position: 'absolute',
right: '14px',
width: '1em',
height: '1em',
marginTop: '0.2em',
background: 'white',
content: "''",
},
"&:hover": { color: token.colorPrimary },
'&:hover': { color: token.colorPrimary },
},
member: {
marginLeft: "12px",
marginLeft: '12px',
fontSize: token.fontSize,
lineHeight: "24px",
verticalAlign: "top",
lineHeight: '24px',
verticalAlign: 'top',
},
projectList: {
[`@media screen and (max-width: ${token.screenXS}px)`]: {},
},
".ant-card-meta-description": {
height: "44px",
overflow: "hidden",
'.ant-card-meta-description': {
height: '44px',
overflow: 'hidden',
color: token.colorTextSecondary,
lineHeight: "22px",
lineHeight: '22px',
},
cardTitle: {
fontSize: "0",
fontSize: '0',
},
projectGrid: {
[`@media screen and (max-width: ${token.screenXS}px)`]: { width: "100%" },
[`@media screen and (max-width: ${token.screenXS}px)`]: { width: '100%' },
},
projectItemContent: {
display: "flex",
height: "20px",
marginTop: "8px",
overflow: "hidden",
fontSize: "12px",
lineHeight: "1.5em",
position: "relative",
display: 'flex',
height: '20px',
marginTop: '8px',
overflow: 'hidden',
fontSize: '12px',
lineHeight: '1.5em',
position: 'relative',
maxHeight: token.line * 1.5,
marginRight: "-1em",
paddingRight: "1em",
textAlign: "justify",
"&::before": {
position: "absolute",
right: "14px",
bottom: "0",
padding: "0 1px",
marginRight: '-1em',
paddingRight: '1em',
textAlign: 'justify',
'&::before': {
position: 'absolute',
right: '14px',
bottom: '0',
padding: '0 1px',
background: token.bg,
content: "'...'",
},
"&::after": {
position: "absolute",
right: "14px",
width: "1em",
height: "1em",
marginTop: "0.2em",
background: "white",
'&::after': {
position: 'absolute',
right: '14px',
width: '1em',
height: '1em',
marginTop: '0.2em',
background: 'white',
content: "''",
},
},
@ -150,7 +150,7 @@ const useStyles = createStyles(({ token }) => {
},
activeCard: {
[`@media screen and (max-width: ${token.screenLG}px)`]: {
marginBottom: "24px",
marginBottom: '24px',
},
},
};

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

@ -1,8 +1,8 @@
import { PlusOutlined } from "@ant-design/icons";
import { Button, Divider, Input, Popconfirm, Table, message } from "antd";
import type { FC } from "react";
import React, { useState } from "react";
import useStyles from "../style.style";
import { PlusOutlined } from '@ant-design/icons';
import { Button, Divider, Input, Popconfirm, Table, message } from 'antd';
import type { FC } from 'react';
import React, { useState } from 'react';
import useStyles from '../style.style';
type TableFormDateType = {
key: string;
workId?: string;
@ -20,16 +20,11 @@ const TableForm: FC<TableFormProps> = ({ value, onChange }) => {
const [clickedCancel, setClickedCancel] = useState(false);
const [loading, setLoading] = useState(false);
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 getRowByKey = (key: string, newData?: TableFormDateType[]) =>
(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();
const newData = data?.map((item) => ({
...item,
@ -54,9 +49,9 @@ const TableForm: FC<TableFormProps> = ({ value, onChange }) => {
})) || [];
newData.push({
key: `NEW_TEMP_ID_${index}`,
workId: "",
name: "",
department: "",
workId: '',
name: '',
department: '',
editable: true,
isNew: true,
});
@ -64,9 +59,7 @@ const TableForm: FC<TableFormProps> = ({ value, onChange }) => {
setData(newData);
};
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);
if (onChange) {
onChange(newData);
@ -75,12 +68,12 @@ const TableForm: FC<TableFormProps> = ({ value, onChange }) => {
const handleFieldChange = (
e: React.ChangeEvent<HTMLInputElement>,
fieldName: keyof TableFormDateType,
key: string
key: string,
) => {
const newData = [...(data as TableFormDateType[])];
const target = getRowByKey(key, newData);
if (target && target[fieldName]) {
target[fieldName as "key"] = e.target.value;
target[fieldName as 'key'] = e.target.value;
setData(newData);
}
};
@ -94,7 +87,7 @@ const TableForm: FC<TableFormProps> = ({ value, onChange }) => {
}
const target = getRowByKey(key) || ({} as any);
if (!target.workId || !target.name || !target.department) {
message.error("请填写完整成员信息。");
message.error('请填写完整成员信息。');
(e.target as HTMLInputElement).focus();
setLoading(false);
return;
@ -108,7 +101,7 @@ const TableForm: FC<TableFormProps> = ({ value, onChange }) => {
}, 500);
};
const handleKeyPress = (e: React.KeyboardEvent, key: string) => {
if (e.key === "Enter") {
if (e.key === 'Enter') {
saveRow(e, key);
}
};
@ -138,17 +131,17 @@ const TableForm: FC<TableFormProps> = ({ value, onChange }) => {
};
const columns = [
{
title: "成员姓名",
dataIndex: "name",
key: "name",
width: "20%",
title: '成员姓名',
dataIndex: 'name',
key: 'name',
width: '20%',
render: (text: string, record: TableFormDateType) => {
if (record.editable) {
return (
<Input
value={text}
autoFocus
onChange={(e) => handleFieldChange(e, "name", record.key)}
onChange={(e) => handleFieldChange(e, 'name', record.key)}
onKeyPress={(e) => handleKeyPress(e, record.key)}
placeholder="成员姓名"
/>
@ -158,16 +151,16 @@ const TableForm: FC<TableFormProps> = ({ value, onChange }) => {
},
},
{
title: "工号",
dataIndex: "workId",
key: "workId",
width: "20%",
title: '工号',
dataIndex: 'workId',
key: 'workId',
width: '20%',
render: (text: string, record: TableFormDateType) => {
if (record.editable) {
return (
<Input
value={text}
onChange={(e) => handleFieldChange(e, "workId", record.key)}
onChange={(e) => handleFieldChange(e, 'workId', record.key)}
onKeyPress={(e) => handleKeyPress(e, record.key)}
placeholder="工号"
/>
@ -177,16 +170,16 @@ const TableForm: FC<TableFormProps> = ({ value, onChange }) => {
},
},
{
title: "所属部门",
dataIndex: "department",
key: "department",
width: "40%",
title: '所属部门',
dataIndex: 'department',
key: 'department',
width: '40%',
render: (text: string, record: TableFormDateType) => {
if (record.editable) {
return (
<Input
value={text}
onChange={(e) => handleFieldChange(e, "department", record.key)}
onChange={(e) => handleFieldChange(e, 'department', record.key)}
onKeyPress={(e) => handleKeyPress(e, record.key)}
placeholder="所属部门"
/>
@ -196,8 +189,8 @@ const TableForm: FC<TableFormProps> = ({ value, onChange }) => {
},
},
{
title: "操作",
key: "action",
title: '操作',
key: 'action',
render: (text: string, record: TableFormDateType) => {
if (!!record.editable && loading) {
return null;
@ -208,10 +201,7 @@ const TableForm: FC<TableFormProps> = ({ value, onChange }) => {
<span>
<a onClick={(e) => saveRow(e, record.key)}></a>
<Divider type="vertical" />
<Popconfirm
title="是否要删除此行?"
onConfirm={() => remove(record.key)}
>
<Popconfirm title="是否要删除此行?" onConfirm={() => remove(record.key)}>
<a></a>
</Popconfirm>
</span>
@ -229,10 +219,7 @@ const TableForm: FC<TableFormProps> = ({ value, onChange }) => {
<span>
<a onClick={(e) => toggleEditable(e, record.key)}></a>
<Divider type="vertical" />
<Popconfirm
title="是否要删除此行?"
onConfirm={() => remove(record.key)}
>
<Popconfirm title="是否要删除此行?" onConfirm={() => remove(record.key)}>
<a></a>
</Popconfirm>
</span>
@ -247,11 +234,11 @@ const TableForm: FC<TableFormProps> = ({ value, onChange }) => {
columns={columns}
dataSource={data}
pagination={false}
rowClassName={(record) => (record.editable ? styles.editable : "")}
rowClassName={(record) => (record.editable ? styles.editable : '')}
/>
<Button
style={{
width: "100%",
width: '100%',
marginTop: 16,
marginBottom: 8,
}}

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

@ -1,19 +1,19 @@
import { CloseCircleOutlined } from "@ant-design/icons";
import { Card, Col, Popover, Row, message } from "antd";
import type { FC } from "react";
import { useState } from "react";
import { CloseCircleOutlined } from '@ant-design/icons';
import { Card, Col, Popover, Row, message } from 'antd';
import type { FC } from 'react';
import { useState } from 'react';
import {
ProForm,
ProFormDateRangePicker,
ProFormSelect,
ProFormText,
ProFormTimePicker,
} from "@ant-design/pro-components";
import type { ProColumnType } from "@ant-design/pro-components";
import { EditableProTable } from "@ant-design/pro-components";
import { PageContainer, FooterToolbar } from "@ant-design/pro-components";
import { fakeSubmitForm } from "./service";
import useStyles from "./style.style";
} from '@ant-design/pro-components';
import type { ProColumnType } from '@ant-design/pro-components';
import { EditableProTable } from '@ant-design/pro-components';
import { PageContainer, FooterToolbar } from '@ant-design/pro-components';
import { fakeSubmitForm } from './service';
import useStyles from './style.style';
interface TableFormDateType {
key: string;
workId?: string;
@ -24,37 +24,37 @@ interface TableFormDateType {
}
type InternalNamePath = (string | number)[];
const fieldLabels = {
name: "仓库名",
url: "仓库域名",
owner: "仓库管理员",
approver: "审批人",
dateRange: "生效日期",
type: "仓库类型",
name2: "任务名",
url2: "任务描述",
owner2: "执行人",
approver2: "责任人",
dateRange2: "生效日期",
type2: "任务类型",
name: '仓库名',
url: '仓库域名',
owner: '仓库管理员',
approver: '审批人',
dateRange: '生效日期',
type: '仓库类型',
name2: '任务名',
url2: '任务描述',
owner2: '执行人',
approver2: '责任人',
dateRange2: '生效日期',
type2: '任务类型',
};
const tableData = [
{
key: "1",
workId: "00001",
name: "John Brown",
department: "New York No. 1 Lake Park",
key: '1',
workId: '00001',
name: 'John Brown',
department: 'New York No. 1 Lake Park',
},
{
key: "2",
workId: "00002",
name: "Jim Green",
department: "London No. 1 Lake Park",
key: '2',
workId: '00002',
name: 'Jim Green',
department: 'London No. 1 Lake Park',
},
{
key: "3",
workId: "00003",
name: "Joe Black",
department: "Sidney No. 1 Lake Park",
key: '3',
workId: '00003',
name: 'Joe Black',
department: 'Sidney No. 1 Lake Park',
},
];
interface ErrorField {
@ -79,19 +79,9 @@ const AdvancedForm: FC<Record<string, any>> = () => {
if (!err || err.errors.length === 0) {
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 (
<li
key={key}
className={styles.errorListItem}
onClick={() => scrollToField(key)}
>
<li key={key} className={styles.errorListItem} onClick={() => scrollToField(key)}>
<CloseCircleOutlined className={styles.errorIcon} />
<div className={styles.errorMessage}>{err.errors[0]}</div>
<div className={styles.errorField}>{fieldLabels[key]}</div>
@ -122,7 +112,7 @@ const AdvancedForm: FC<Record<string, any>> = () => {
setError([]);
try {
await fakeSubmitForm(values);
message.success("提交成功");
message.success('提交成功');
} catch {
// console.log
}
@ -132,27 +122,27 @@ const AdvancedForm: FC<Record<string, any>> = () => {
};
const columns: ProColumnType<TableFormDateType>[] = [
{
title: "成员姓名",
dataIndex: "name",
key: "name",
width: "20%",
title: '成员姓名',
dataIndex: 'name',
key: 'name',
width: '20%',
},
{
title: "工号",
dataIndex: "workId",
key: "workId",
width: "20%",
title: '工号',
dataIndex: 'workId',
key: 'workId',
width: '20%',
},
{
title: "所属部门",
dataIndex: "department",
key: "department",
width: "40%",
title: '所属部门',
dataIndex: 'department',
key: 'department',
width: '40%',
},
{
title: "操作",
key: "action",
valueType: "option",
title: '操作',
key: 'action',
valueType: 'option',
render: (_, record: TableFormDateType, index, action) => {
return [
<a
@ -197,7 +187,7 @@ const AdvancedForm: FC<Record<string, any>> = () => {
rules={[
{
required: true,
message: "请输入仓库名称",
message: '请输入仓库名称',
},
]}
placeholder="请输入仓库名称"
@ -222,15 +212,15 @@ const AdvancedForm: FC<Record<string, any>> = () => {
rules={[
{
required: true,
message: "请选择",
message: '请选择',
},
]}
fieldProps={{
style: {
width: "100%",
width: '100%',
},
addonBefore: "http://",
addonAfter: ".com",
addonBefore: 'http://',
addonAfter: '.com',
}}
placeholder="请输入"
/>
@ -254,17 +244,17 @@ const AdvancedForm: FC<Record<string, any>> = () => {
rules={[
{
required: true,
message: "请选择管理员",
message: '请选择管理员',
},
]}
options={[
{
label: "付晓晓",
value: "xiao",
label: '付晓晓',
value: 'xiao',
},
{
label: "周毛毛",
value: "mao",
label: '周毛毛',
value: 'mao',
},
]}
placeholder="请选择管理员"
@ -279,17 +269,17 @@ const AdvancedForm: FC<Record<string, any>> = () => {
rules={[
{
required: true,
message: "请选择审批员",
message: '请选择审批员',
},
]}
options={[
{
label: "付晓晓",
value: "xiao",
label: '付晓晓',
value: 'xiao',
},
{
label: "周毛毛",
value: "mao",
label: '周毛毛',
value: 'mao',
},
]}
placeholder="请选择审批员"
@ -313,13 +303,13 @@ const AdvancedForm: FC<Record<string, any>> = () => {
name="dateRange"
fieldProps={{
style: {
width: "100%",
width: '100%',
},
}}
rules={[
{
required: true,
message: "请选择生效日期",
message: '请选择生效日期',
},
]}
/>
@ -343,17 +333,17 @@ const AdvancedForm: FC<Record<string, any>> = () => {
rules={[
{
required: true,
message: "请选择仓库类型",
message: '请选择仓库类型',
},
]}
options={[
{
label: "私密",
value: "private",
label: '私密',
value: 'private',
},
{
label: "公开",
value: "public",
label: '公开',
value: 'public',
},
]}
placeholder="请选择仓库类型"
@ -370,7 +360,7 @@ const AdvancedForm: FC<Record<string, any>> = () => {
rules={[
{
required: true,
message: "请输入",
message: '请输入',
},
]}
/>
@ -394,7 +384,7 @@ const AdvancedForm: FC<Record<string, any>> = () => {
rules={[
{
required: true,
message: "请选择",
message: '请选择',
},
]}
/>
@ -418,17 +408,17 @@ const AdvancedForm: FC<Record<string, any>> = () => {
rules={[
{
required: true,
message: "请选择管理员",
message: '请选择管理员',
},
]}
options={[
{
label: "付晓晓",
value: "xiao",
label: '付晓晓',
value: 'xiao',
},
{
label: "周毛毛",
value: "mao",
label: '周毛毛',
value: 'mao',
},
]}
/>
@ -442,17 +432,17 @@ const AdvancedForm: FC<Record<string, any>> = () => {
rules={[
{
required: true,
message: "请选择审批员",
message: '请选择审批员',
},
]}
options={[
{
label: "付晓晓",
value: "xiao",
label: '付晓晓',
value: 'xiao',
},
{
label: "周毛毛",
value: "mao",
label: '周毛毛',
value: 'mao',
},
]}
placeholder="请选择审批员"
@ -477,13 +467,13 @@ const AdvancedForm: FC<Record<string, any>> = () => {
rules={[
{
required: true,
message: "请输入",
message: '请输入',
},
]}
placeholder="提醒时间"
fieldProps={{
style: {
width: "100%",
width: '100%',
},
}}
/>
@ -507,17 +497,17 @@ const AdvancedForm: FC<Record<string, any>> = () => {
rules={[
{
required: true,
message: "请选择仓库类型",
message: '请选择仓库类型',
},
]}
options={[
{
label: "私密",
value: "private",
label: '私密',
value: 'private',
},
{
label: "公开",
value: "public",
label: '公开',
value: 'public',
},
]}
placeholder="请选择仓库类型"

52
src/pages/form/advanced-form/style.style.ts

@ -1,48 +1,48 @@
import { createStyles } from "antd-style";
import { createStyles } from 'antd-style';
const useStyles = createStyles(({ token }) => {
return {
card: {
marginBottom: "24px",
marginBottom: '24px',
},
".ant-legacy-form-item .ant-legacy-form-item-control-wrapper": {
width: "100%",
'.ant-legacy-form-item .ant-legacy-form-item-control-wrapper': {
width: '100%',
},
errorIcon: {
float: "left",
marginTop: "4px",
marginRight: "12px",
paddingBottom: "22px",
float: 'left',
marginTop: '4px',
marginRight: '12px',
paddingBottom: '22px',
color: token.colorError,
},
"span.anticon": {
marginRight: "4px",
'span.anticon': {
marginRight: '4px',
},
errorPopover: {},
".ant-popover-inner-content": {
minWidth: "256px",
maxHeight: "290px",
padding: "0",
overflow: "auto",
'.ant-popover-inner-content': {
minWidth: '256px',
maxHeight: '290px',
padding: '0',
overflow: 'auto',
},
errorListItem: {
padding: "8px 16px",
listStyle: "none",
borderBottom: "1px solid @border-color-split",
cursor: "pointer",
transition: "all 0.3s",
"&:hover": { background: token.colorBgTextActive },
"&:last-child": { border: "0" },
padding: '8px 16px',
listStyle: 'none',
borderBottom: '1px solid @border-color-split',
cursor: 'pointer',
transition: 'all 0.3s',
'&:hover': { background: token.colorBgTextActive },
'&:last-child': { border: '0' },
},
errorField: {
marginTop: "2px",
marginTop: '2px',
color: token.colorTextSecondary,
fontSize: "12px",
fontSize: '12px',
},
editable: {},
td: {
paddingTop: "13px",
paddingBottom: "12.5px",
paddingTop: '13px',
paddingBottom: '12.5px',
},
};
});

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

@ -1,4 +1,4 @@
import { Card, message } from "antd";
import { Card, message } from 'antd';
import {
ProForm,
ProFormDateRangePicker,
@ -8,18 +8,18 @@ import {
ProFormSelect,
ProFormText,
ProFormTextArea,
} from "@ant-design/pro-components";
import { useRequest } from "@umijs/max";
import type { FC } from "react";
import { PageContainer } from "@ant-design/pro-components";
import { fakeSubmitForm } from "./service";
import useStyles from "./style.style";
} from '@ant-design/pro-components';
import { useRequest } from '@umijs/max';
import type { FC } from 'react';
import { PageContainer } from '@ant-design/pro-components';
import { fakeSubmitForm } from './service';
import useStyles from './style.style';
const BasicForm: FC<Record<string, any>> = () => {
const { styles } = useStyles();
const { run } = useRequest(fakeSubmitForm, {
manual: true,
onSuccess: () => {
message.success("提交成功");
message.success('提交成功');
},
});
const onFinish = async (values: Record<string, any>) => {
@ -31,14 +31,14 @@ const BasicForm: FC<Record<string, any>> = () => {
<ProForm
hideRequiredMark
style={{
margin: "auto",
margin: 'auto',
marginTop: 8,
maxWidth: 600,
}}
name="basic"
layout="vertical"
initialValues={{
public: "1",
public: '1',
}}
onFinish={onFinish}
>
@ -49,7 +49,7 @@ const BasicForm: FC<Record<string, any>> = () => {
rules={[
{
required: true,
message: "请输入标题",
message: '请输入标题',
},
]}
placeholder="给目标起个名字"
@ -61,10 +61,10 @@ const BasicForm: FC<Record<string, any>> = () => {
rules={[
{
required: true,
message: "请选择起止日期",
message: '请选择起止日期',
},
]}
placeholder={["开始日期", "结束日期"]}
placeholder={['开始日期', '结束日期']}
/>
<ProFormTextArea
label="目标描述"
@ -73,7 +73,7 @@ const BasicForm: FC<Record<string, any>> = () => {
rules={[
{
required: true,
message: "请输入目标描述",
message: '请输入目标描述',
},
]}
placeholder="请输入你的阶段性工作目标"
@ -86,7 +86,7 @@ const BasicForm: FC<Record<string, any>> = () => {
rules={[
{
required: true,
message: "请输入衡量标准",
message: '请输入衡量标准',
},
]}
placeholder="请输入衡量标准"
@ -131,30 +131,30 @@ const BasicForm: FC<Record<string, any>> = () => {
width="xs"
fieldProps={{
formatter: (value) => `${value || 0}%`,
parser: (value) => Number(value ? value.replace("%", "") : "0"),
parser: (value) => Number(value ? value.replace('%', '') : '0'),
}}
/>
<ProFormRadio.Group
options={[
{
value: "1",
label: "公开",
value: '1',
label: '公开',
},
{
value: "2",
label: "部分公开",
value: '2',
label: '部分公开',
},
{
value: "3",
label: "不公开",
value: '3',
label: '不公开',
},
]}
label="目标公开"
help="客户、邀评人默认被分享"
name="publicType"
/>
<ProFormDependency name={["publicType"]}>
<ProFormDependency name={['publicType']}>
{({ publicType }) => {
return (
<ProFormSelect
@ -162,23 +162,22 @@ const BasicForm: FC<Record<string, any>> = () => {
name="publicUsers"
fieldProps={{
style: {
margin: "8px 0",
display:
publicType && publicType === "2" ? "block" : "none",
margin: '8px 0',
display: publicType && publicType === '2' ? 'block' : 'none',
},
}}
options={[
{
value: "1",
label: "同事甲",
value: '1',
label: '同事甲',
},
{
value: "2",
label: "同事乙",
value: '2',
label: '同事乙',
},
{
value: "3",
label: "同事丙",
value: '3',
label: '同事丙',
},
]}
/>

4
src/pages/form/basic-form/style.style.ts

@ -1,10 +1,10 @@
import { createStyles } from "antd-style";
import { createStyles } from 'antd-style';
const useStyles = createStyles(({ token }) => {
return {
optional: {
color: token.colorTextSecondary,
fontStyle: "normal",
fontStyle: 'normal',
},
};
});

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

@ -1,24 +1,16 @@
import React, { useRef, useState } from "react";
import type { FormInstance } from "antd";
import {
Card,
Result,
Button,
Descriptions,
Divider,
Alert,
Statistic,
} from "antd";
import { PageContainer } from "@ant-design/pro-components";
import React, { useRef, useState } from 'react';
import type { FormInstance } from 'antd';
import { Card, Result, Button, Descriptions, Divider, Alert, Statistic } from 'antd';
import { PageContainer } from '@ant-design/pro-components';
import {
ProForm,
ProFormDigit,
ProFormSelect,
ProFormText,
StepsForm,
} from "@ant-design/pro-components";
import type { StepDataType } from "./data.d";
import useStyles from "./style.style";
} from '@ant-design/pro-components';
import type { StepDataType } from './data.d';
import useStyles from './style.style';
const StepDescriptions: React.FC<{
stepData: StepDataType;
bordered?: boolean;
@ -74,11 +66,11 @@ const StepResult: React.FC<{
const StepForm: React.FC<Record<string, any>> = () => {
const { styles } = useStyles();
const [stepData, setStepData] = useState<StepDataType>({
payAccount: "ant-design@alipay.com",
receiverAccount: "test@example.com",
receiverName: "Alex",
amount: "500",
receiverMode: "alipay",
payAccount: 'ant-design@alipay.com',
receiverAccount: 'test@example.com',
receiverName: 'Alex',
amount: '500',
receiverMode: 'alipay',
});
const [current, setCurrent] = useState(0);
const formRef = useRef<FormInstance>();
@ -113,11 +105,11 @@ const StepForm: React.FC<Record<string, any>> = () => {
rules={[
{
required: true,
message: "请选择付款账户",
message: '请选择付款账户',
},
]}
valueEnum={{
"ant-design@alipay.com": "ant-design@alipay.com",
'ant-design@alipay.com': 'ant-design@alipay.com',
}}
/>
@ -127,12 +119,12 @@ const StepForm: React.FC<Record<string, any>> = () => {
rules={[
{
required: true,
message: "请选择付款账户",
message: '请选择付款账户',
},
]}
valueEnum={{
alipay: "支付宝",
bank: "银行账户",
alipay: '支付宝',
bank: '银行账户',
}}
/>
<ProFormText
@ -140,11 +132,11 @@ const StepForm: React.FC<Record<string, any>> = () => {
rules={[
{
required: true,
message: "请输入收款人账户",
message: '请输入收款人账户',
},
{
type: "email",
message: "账户名应为邮箱格式",
type: 'email',
message: '账户名应为邮箱格式',
},
]}
placeholder="test@example.com"
@ -157,7 +149,7 @@ const StepForm: React.FC<Record<string, any>> = () => {
rules={[
{
required: true,
message: "请输入收款人姓名",
message: '请输入收款人姓名',
},
]}
placeholder="请输入收款人姓名"
@ -169,16 +161,16 @@ const StepForm: React.FC<Record<string, any>> = () => {
rules={[
{
required: true,
message: "请输入转账金额",
message: '请输入转账金额',
},
{
pattern: /^(\d+)((?:\.\d+)?)$/,
message: "请输入合法金额数字",
message: '请输入合法金额数字',
},
]}
placeholder="请输入金额"
fieldProps={{
prefix: "¥",
prefix: '¥',
}}
/>
</StepsForm.StepForm>
@ -196,7 +188,7 @@ const StepForm: React.FC<Record<string, any>> = () => {
<StepDescriptions stepData={stepData} bordered />
<Divider
style={{
margin: "24px 0",
margin: '24px 0',
}}
/>
<ProFormText.Password
@ -207,7 +199,7 @@ const StepForm: React.FC<Record<string, any>> = () => {
rules={[
{
required: true,
message: "需要支付密码才能进行支付",
message: '需要支付密码才能进行支付',
},
]}
/>
@ -226,7 +218,7 @@ const StepForm: React.FC<Record<string, any>> = () => {
</StepsForm>
<Divider
style={{
margin: "40px 0 24px",
margin: '40px 0 24px',
}}
/>
<div className={styles.desc}>

10
src/pages/form/step-form/style.style.ts

@ -1,14 +1,14 @@
import { createStyles } from "antd-style";
import { createStyles } from 'antd-style';
const useStyles = createStyles(() => {
return {
card: {
marginBottom: "24px",
marginBottom: '24px',
},
result: {
maxWidth: "560px",
margin: "0 auto",
padding: "24px 0 8px",
maxWidth: '560px',
margin: '0 auto',
padding: '24px 0 8px',
},
};
});

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

@ -1,14 +1,14 @@
import type { FC } from "react";
import type { FC } from 'react';
import {
ModalForm,
ProFormSelect,
ProFormDateTimePicker,
ProFormText,
ProFormTextArea,
} from "@ant-design/pro-components";
import type { BasicListItemDataType } from "../data.d";
import useStyles from "../style.style";
import { Button, Result } from "antd";
} from '@ant-design/pro-components';
import type { BasicListItemDataType } from '../data.d';
import useStyles from '../style.style';
import { Button, Result } from 'antd';
type OperationModalProps = {
done: boolean;
visible: boolean;
@ -26,7 +26,7 @@ const OperationModal: FC<OperationModalProps> = (props) => {
return (
<ModalForm<BasicListItemDataType>
visible={visible}
title={done ? null : `任务${current ? "编辑" : "添加"}`}
title={done ? null : `任务${current ? '编辑' : '添加'}`}
className={styles.standardListForm}
width={640}
onFinish={async (values) => {
@ -42,7 +42,7 @@ const OperationModal: FC<OperationModalProps> = (props) => {
destroyOnClose: true,
bodyStyle: done
? {
padding: "72px 0",
padding: '72px 0',
}
: {},
}}
@ -55,7 +55,7 @@ const OperationModal: FC<OperationModalProps> = (props) => {
rules={[
{
required: true,
message: "请输入任务名称",
message: '请输入任务名称',
},
]}
placeholder="请输入"
@ -66,12 +66,12 @@ const OperationModal: FC<OperationModalProps> = (props) => {
rules={[
{
required: true,
message: "请选择开始时间",
message: '请选择开始时间',
},
]}
fieldProps={{
style: {
width: "100%",
width: '100%',
},
}}
placeholder="请选择"
@ -82,17 +82,17 @@ const OperationModal: FC<OperationModalProps> = (props) => {
rules={[
{
required: true,
message: "请选择任务负责人",
message: '请选择任务负责人',
},
]}
options={[
{
label: "付晓晓",
value: "xiao",
label: '付晓晓',
value: 'xiao',
},
{
label: "周毛毛",
value: "mao",
label: '周毛毛',
value: 'mao',
},
]}
placeholder="请选择管理员"
@ -102,7 +102,7 @@ const OperationModal: FC<OperationModalProps> = (props) => {
label="产品描述"
rules={[
{
message: "请输入至少五个字符的产品描述!",
message: '请输入至少五个字符的产品描述!',
min: 5,
},
]}

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

@ -1,6 +1,6 @@
import type { FC } from "react";
import React, { useState } from "react";
import { DownOutlined, PlusOutlined } from "@ant-design/icons";
import type { FC } from 'react';
import React, { useState } from 'react';
import { DownOutlined, PlusOutlined } from '@ant-design/icons';
import {
Avatar,
Button,
@ -14,19 +14,14 @@ import {
Progress,
Radio,
Row,
} from "antd";
import { PageContainer } from "@ant-design/pro-components";
import { useRequest } from "@umijs/max";
import dayjs from "dayjs";
import OperationModal from "./components/OperationModal";
import {
addFakeList,
queryFakeList,
removeFakeList,
updateFakeList,
} from "./service";
import type { BasicListItemDataType } from "./data.d";
import useStyles from "./style.style";
} from 'antd';
import { PageContainer } from '@ant-design/pro-components';
import { useRequest } from '@umijs/max';
import dayjs from 'dayjs';
import OperationModal from './components/OperationModal';
import { addFakeList, queryFakeList, removeFakeList, updateFakeList } from './service';
import type { BasicListItemDataType } from './data.d';
import useStyles from './style.style';
const RadioButton = Radio.Button;
const RadioGroup = Radio.Group;
const { Search } = Input;
@ -58,7 +53,7 @@ const ListContent = ({
</div>
<div className={styles.listContentItem}>
<span></span>
<p>{dayjs(createdAt).format("YYYY-MM-DD HH:mm")}</p>
<p>{dayjs(createdAt).format('YYYY-MM-DD HH:mm')}</p>
</div>
<div className={styles.listContentItem}>
<Progress
@ -77,9 +72,7 @@ export const BasicList: FC = () => {
const { styles } = useStyles();
const [done, setDone] = useState<boolean>(false);
const [visible, setVisible] = useState<boolean>(false);
const [current, setCurrent] = useState<
Partial<BasicListItemDataType> | undefined
>(undefined);
const [current, setCurrent] = useState<Partial<BasicListItemDataType> | undefined>(undefined);
const {
data: listData,
loading,
@ -91,10 +84,10 @@ export const BasicList: FC = () => {
});
const { run: postRun } = useRequest(
(method, params) => {
if (method === "remove") {
if (method === 'remove') {
return removeFakeList(params);
}
if (method === "update") {
if (method === 'update') {
return updateFakeList(params);
}
return addFakeList(params);
@ -104,7 +97,7 @@ export const BasicList: FC = () => {
onSuccess: (result) => {
mutate(result);
},
}
},
);
const list = listData?.list || [];
const paginationProps = {
@ -118,21 +111,18 @@ export const BasicList: FC = () => {
setCurrent(item);
};
const deleteItem = (id: string) => {
postRun("remove", {
postRun('remove', {
id,
});
};
const editAndDelete = (
key: string | number,
currentItem: BasicListItemDataType
) => {
if (key === "edit") showEditModal(currentItem);
else if (key === "delete") {
const editAndDelete = (key: string | number, currentItem: BasicListItemDataType) => {
if (key === 'edit') showEditModal(currentItem);
else if (key === 'delete') {
Modal.confirm({
title: "删除任务",
content: "确定删除该任务吗?",
okText: "确认",
cancelText: "取消",
title: '删除任务',
content: '确定删除该任务吗?',
okText: '确认',
cancelText: '取消',
onOk: () => deleteItem(currentItem.id),
});
}
@ -144,11 +134,7 @@ export const BasicList: FC = () => {
<RadioButton value="progress"></RadioButton>
<RadioButton value="waiting"></RadioButton>
</RadioGroup>
<Search
className={styles.extraContentSearch}
placeholder="请输入"
onSearch={() => ({})}
/>
<Search className={styles.extraContentSearch} placeholder="请输入" onSearch={() => ({})} />
</div>
);
const MoreBtn: React.FC<{
@ -174,7 +160,7 @@ export const BasicList: FC = () => {
};
const handleSubmit = (values: BasicListItemDataType) => {
setDone(true);
const method = values?.id ? "update" : "add";
const method = values?.id ? 'update' : 'add';
postRun(method, values);
};
return (
@ -203,7 +189,7 @@ export const BasicList: FC = () => {
marginTop: 24,
}}
bodyStyle={{
padding: "0 32px 40px 32px",
padding: '0 32px 40px 32px',
}}
extra={extraContent}
>
@ -229,9 +215,7 @@ export const BasicList: FC = () => {
]}
>
<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>}
description={item.subDescription}
/>
@ -248,7 +232,7 @@ export const BasicList: FC = () => {
setVisible(true);
}}
style={{
width: "100%",
width: '100%',
marginBottom: 8,
}}
>

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

@ -1,98 +1,98 @@
import { createStyles } from "antd-style";
import { createStyles } from 'antd-style';
const useStyles = createStyles(({ token }) => {
return {
standardList: {
"@media screen and (max-width: 1400px)": {},
'@media screen and (max-width: 1400px)': {},
},
".ant-card-head": {
borderBottom: "none",
'.ant-card-head': {
borderBottom: 'none',
},
".ant-card-head-title": {
'.ant-card-head-title': {
[`@media screen and (max-width: ${token.screenXS}px)`]: {
overflow: "visible",
overflow: 'visible',
},
},
".ant-card-extra": {
padding: "24px 0",
'.ant-card-extra': {
padding: '24px 0',
},
".ant-list-pagination": {
marginTop: "24px",
textAlign: "right",
'.ant-list-pagination': {
marginTop: '24px',
textAlign: 'right',
},
".ant-avatar-lg": {
width: "48px",
height: "48px",
lineHeight: "48px",
'.ant-avatar-lg': {
width: '48px',
height: '48px',
lineHeight: '48px',
},
headerInfo: {
[`@media screen and (max-width: ${token.screenSM}px)`]: {
marginBottom: "16px",
"& > em": {
display: "none",
marginBottom: '16px',
'& > em': {
display: 'none',
},
},
},
listContent: {
"@media screen and (max-width: 1400px)": {
textAlign: "right",
"& > div:last-child": {
top: "0",
'@media screen and (max-width: 1400px)': {
textAlign: 'right',
'& > div:last-child': {
top: '0',
},
},
},
listContentItem: {
display: "inline-block",
marginLeft: "40px",
display: 'inline-block',
marginLeft: '40px',
color: token.colorTextSecondary,
fontSize: token.fontSize,
verticalAlign: "middle",
verticalAlign: 'middle',
},
"> span": {
lineHeight: "20px",
'> span': {
lineHeight: '20px',
},
"> p": {
marginTop: "4px",
marginBottom: "0",
lineHeight: "22px",
'> p': {
marginTop: '4px',
marginBottom: '0',
lineHeight: '22px',
},
extraContentSearch: {
[`@media screen and (max-width: ${token.screenSM}px)`]: {
width: "100%",
marginLeft: "0",
width: '100%',
marginLeft: '0',
},
},
".ant-list-item-content": {
'.ant-list-item-content': {
[`@media screen and (max-width: ${token.screenXS}px)`]: {
display: "block",
flex: "none",
width: "100%",
display: 'block',
flex: 'none',
width: '100%',
},
},
".ant-list-item-action": {
'.ant-list-item-action': {
[`@media screen and (max-width: ${token.screenXS}px)`]: {
marginLeft: "0",
marginLeft: '0',
},
},
listCard: {
[`@media screen and (max-width: ${token.screenMD}px)`]: {},
},
".ant-radio-group": {
'.ant-radio-group': {
[`@media screen and (max-width: ${token.screenMD}px)`]: {
display: "block",
marginBottom: "8px",
display: 'block',
marginBottom: '8px',
},
},
standardListForm: {},
".ant-form-item": {
marginBottom: "12px",
"&:last-child": { marginBottom: "32px", paddingTop: "4px" },
'.ant-form-item': {
marginBottom: '12px',
'&:last-child': { marginBottom: '32px', paddingTop: '4px' },
},
formResult: {
width: "100%",
width: '100%',
},
"[class^='title']": {
marginBottom: "8px",
marginBottom: '8px',
},
};
});

2
src/pages/list/basic-list/utils/utils.style.ts

@ -1,4 +1,4 @@
import { createStyles } from "antd-style";
import { createStyles } from 'antd-style';
const useStyles = createStyles(() => {
return {};

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

@ -1,10 +1,10 @@
import { PlusOutlined } from "@ant-design/icons";
import { Button, Card, List, Typography } from "antd";
import { PageContainer } from "@ant-design/pro-components";
import { useRequest } from "@umijs/max";
import { queryFakeList } from "./service";
import type { CardListItemDataType } from "./data.d";
import useStyles from "./style.style";
import { PlusOutlined } from '@ant-design/icons';
import { Button, Card, List, Typography } from 'antd';
import { PageContainer } from '@ant-design/pro-components';
import { useRequest } from '@umijs/max';
import { queryFakeList } from './service';
import type { CardListItemDataType } from './data.d';
import useStyles from './style.style';
const { Paragraph } = Typography;
const CardList = () => {
const { styles } = useStyles();
@ -17,30 +17,20 @@ const CardList = () => {
const content = (
<div className={styles.pageHeaderContent}>
<p>
ant.design
ant.design
</p>
<div className={styles.contentLink}>
<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>
<img
alt=""
src="https://gw.alipayobjects.com/zos/rmsportal/NbuDUAuBlIApFuDvWiND.svg"
/>{" "}
<img alt="" src="https://gw.alipayobjects.com/zos/rmsportal/NbuDUAuBlIApFuDvWiND.svg" />{' '}
</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>
</div>
@ -78,19 +68,10 @@ const CardList = () => {
<Card
hoverable
className={styles.card}
actions={[
<a key="option1"></a>,
<a key="option2"></a>,
]}
actions={[<a key="option1"></a>, <a key="option2"></a>]}
>
<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>}
description={
<Paragraph

56
src/pages/list/card-list/style.style.ts

@ -1,71 +1,71 @@
import { createStyles } from "antd-style";
import { createStyles } from 'antd-style';
const useStyles = createStyles(({ token }) => {
return {
cardList: {},
card: {},
".ant-card-meta-title": {
marginBottom: "12px",
"& > a": {
display: "inline-block",
maxWidth: "100%",
'.ant-card-meta-title': {
marginBottom: '12px',
'& > a': {
display: 'inline-block',
maxWidth: '100%',
color: token.colorTextHeading,
},
},
".ant-card-body:hover": {},
".ant-card-meta-title > a": {
'.ant-card-body:hover': {},
'.ant-card-meta-title > a': {
color: token.colorPrimary,
},
item: {
height: "64px",
height: '64px',
},
".ant-list .ant-list-item-content-single": {
maxWidth: "100%",
'.ant-list .ant-list-item-content-single': {
maxWidth: '100%',
},
extraImg: {
[`@media screen and (max-width: ${token.screenMD}px)`]: {
display: "none",
display: 'none',
},
},
img: {
[`@media screen and (max-width: ${token.screenSM}px)`]: {
marginRight: "4px",
marginRight: '4px',
},
},
newButton: {
width: "100%",
height: "201px",
width: '100%',
height: '201px',
color: token.colorTextSecondary,
backgroundColor: token.colorBgContainer,
borderColor: token.colorBorder,
},
cardAvatar: {
width: "48px",
height: "48px",
borderRadius: "48px",
width: '48px',
height: '48px',
borderRadius: '48px',
},
cardDescription: {
overflow: "hidden",
whiteSpace: "nowrap",
textOverflow: "ellipsis",
wordBreak: "break-all",
overflow: 'hidden',
whiteSpace: 'nowrap',
textOverflow: 'ellipsis',
wordBreak: 'break-all',
},
pageHeaderContent: {
[`@media screen and (max-width: ${token.screenSM}px)`]: {
paddingBottom: "30px",
paddingBottom: '30px',
},
},
contentLink: {
[`@media screen and (max-width: ${token.screenSM}px)`]: {
position: "absolute",
bottom: "-4px",
left: "0",
width: "1000px",
position: 'absolute',
bottom: '-4px',
left: '0',
width: '1000px',
},
},
a: {
[`@media screen and (max-width: ${token.screenSM}px)`]: {
marginRight: "16px",
marginRight: '16px',
},
},
};

2
src/pages/list/card-list/utils/utils.style.ts

@ -1,4 +1,4 @@
import { createStyles } from "antd-style";
import { createStyles } from 'antd-style';
const useStyles = createStyles(() => {
return {};

52
src/pages/list/search/applications/components/StandardFormRow/index.style.ts

@ -1,51 +1,51 @@
import { createStyles } from "antd-style";
import { createStyles } from 'antd-style';
const useStyles = createStyles(({ token }) => {
return {
standardFormRow: {
display: "flex",
marginBottom: "16px",
paddingBottom: "16px",
borderBottom: "1px dashed @border-color-split",
display: 'flex',
marginBottom: '16px',
paddingBottom: '16px',
borderBottom: '1px dashed @border-color-split',
},
".ant-form-item, .ant-legacy-form-item": {
"&:last-child": { marginRight: "0" },
'.ant-form-item, .ant-legacy-form-item': {
'&:last-child': { marginRight: '0' },
},
".ant-form-item-label, .ant-legacy-form-item-label": {
float: "left",
'.ant-form-item-label, .ant-legacy-form-item-label': {
float: 'left',
},
label: {
flex: "0 0 auto",
marginRight: "24px",
flex: '0 0 auto',
marginRight: '24px',
color: token.colorTextHeading,
fontSize: token.fontSize,
textAlign: "right",
"& > span": {
display: "inline-block",
height: "32px",
lineHeight: "32px",
"&::after": {
textAlign: 'right',
'& > span': {
display: 'inline-block',
height: '32px',
lineHeight: '32px',
'&::after': {
content: "':'",
},
},
},
".ant-form-item-label, .ant-legacy-form-item-label, .ant-form-item-control, .ant-legacy-form-item-control":
'.ant-form-item-label, .ant-legacy-form-item-label, .ant-form-item-control, .ant-legacy-form-item-control':
{
padding: "0",
lineHeight: "32px",
padding: '0',
lineHeight: '32px',
},
content: {
flex: "1 1 0",
flex: '1 1 0',
},
standardFormRowLast: {
marginBottom: "0",
paddingBottom: "0",
border: "none",
marginBottom: '0',
paddingBottom: '0',
border: 'none',
},
standardFormRowBlock: {},
".ant-form-item, .ant-legacy-form-item, div.ant-form-item-control-wrapper, div.ant-legacy-form-item-control-wrapper":
'.ant-form-item, .ant-legacy-form-item, div.ant-form-item-control-wrapper, div.ant-legacy-form-item-control-wrapper':
{
display: "block",
display: 'block',
},
standardFormRowGrid: {},
};

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

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

38
src/pages/list/search/applications/components/TagSelect/index.style.ts

@ -1,35 +1,35 @@
import { createStyles } from "antd-style";
import { createStyles } from 'antd-style';
const useStyles = createStyles(({ token }) => {
return {
tagSelect: {
position: "relative",
maxHeight: "32px",
marginLeft: "-8px",
overflow: "hidden",
lineHeight: "32px",
transition: "all 0.3s",
userSelect: "none",
position: 'relative',
maxHeight: '32px',
marginLeft: '-8px',
overflow: 'hidden',
lineHeight: '32px',
transition: 'all 0.3s',
userSelect: 'none',
},
".ant-tag": {
marginRight: "24px",
padding: "0 8px",
'.ant-tag': {
marginRight: '24px',
padding: '0 8px',
fontSize: token.fontSize,
},
expanded: {
maxHeight: "200px",
transition: "all 0.3s",
maxHeight: '200px',
transition: 'all 0.3s',
},
trigger: {
position: "absolute",
top: "0",
right: "0",
position: 'absolute',
top: '0',
right: '0',
},
"span.anticon": {
fontSize: "12px",
'span.anticon': {
fontSize: '12px',
},
hasExpandTag: {
paddingRight: "50px",
paddingRight: '50px',
},
};
});

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

@ -1,10 +1,10 @@
import { DownOutlined, UpOutlined } from "@ant-design/icons";
import { useBoolean, useControllableValue } from "ahooks";
import { Tag } from "antd";
import classNames from "classnames";
import type { FC } from "react";
import React from "react";
import useStyles from "./index.style";
import { DownOutlined, UpOutlined } from '@ant-design/icons';
import { useBoolean, useControllableValue } from 'ahooks';
import { Tag } from 'antd';
import classNames from 'classnames';
import type { FC } from 'react';
import React from 'react';
import useStyles from './index.style';
const { CheckableTag } = Tag;
export interface TagSelectOptionProps {
value: string | number;
@ -25,10 +25,7 @@ const TagSelectOption: React.FC<TagSelectOptionProps> & {
</CheckableTag>
);
TagSelectOption.isTagSelectOption = true;
type TagSelectOptionElement = React.ReactElement<
TagSelectOptionProps,
typeof TagSelectOption
>;
type TagSelectOptionElement = React.ReactElement<TagSelectOptionProps, typeof TagSelectOption>;
export interface TagSelectProps {
onChange?: (value: (string | number)[]) => void;
expandable?: boolean;
@ -49,25 +46,15 @@ const TagSelect: FC<TagSelectProps> & {
Option: typeof TagSelectOption;
} = (props) => {
const { styles } = useStyles();
const {
children,
hideCheckAll = false,
className,
style,
expandable,
actionsText = {},
} = props;
const { children, hideCheckAll = false, className, style, expandable, actionsText = {} } = props;
const [expand, { toggle }] = useBoolean();
const [value, setValue] = useControllableValue<(string | number)[]>(props);
const isTagSelectOption = (node: TagSelectOptionElement) =>
node &&
node.type &&
(node.type.isTagSelectOption ||
node.type.displayName === "TagSelectOption");
(node.type.isTagSelectOption || node.type.displayName === 'TagSelectOption');
const getAllTags = () => {
const childrenArray = React.Children.toArray(
children
) as TagSelectOptionElement[];
const childrenArray = React.Children.toArray(children) as TagSelectOptionElement[];
const checkedTags = childrenArray
.filter((child) => isTagSelectOption(child))
.map((child) => child.props.value);
@ -91,11 +78,7 @@ const TagSelect: FC<TagSelectProps> & {
setValue(checkedTags);
};
const checkedAll = getAllTags().length === value?.length;
const {
expandText = "展开",
collapseText = "收起",
selectAllText = "全部",
} = actionsText;
const { expandText = '展开', collapseText = '收起', selectAllText = '全部' } = actionsText;
const cls = classNames(styles.tagSelect, className, {
[styles.hasExpandTag]: expandable,
[styles.expanded]: expand,
@ -103,11 +86,7 @@ const TagSelect: FC<TagSelectProps> & {
return (
<div className={cls} style={style}>
{hideCheckAll ? null : (
<CheckableTag
checked={checkedAll}
key="tag-select-__all__"
onChange={onSelectAll}
>
<CheckableTag checked={checkedAll} key="tag-select-__all__" onChange={onSelectAll}>
{selectAllText}
</CheckableTag>
)}

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

@ -3,32 +3,21 @@ import {
EditOutlined,
EllipsisOutlined,
ShareAltOutlined,
} from "@ant-design/icons";
import {
Avatar,
Card,
Col,
Dropdown,
Form,
List,
Menu,
Row,
Select,
Tooltip,
} from "antd";
import numeral from "numeral";
import type { FC } from "react";
import React from "react";
import { useRequest } from "@umijs/max";
import StandardFormRow from "./components/StandardFormRow";
import TagSelect from "./components/TagSelect";
import type { ListItemDataType } from "./data.d";
import { queryFakeList } from "./service";
import useStyles from "./style.style";
} from '@ant-design/icons';
import { Avatar, Card, Col, Dropdown, Form, List, Menu, Row, Select, Tooltip } from 'antd';
import numeral from 'numeral';
import type { FC } from 'react';
import React from 'react';
import { useRequest } from '@umijs/max';
import StandardFormRow from './components/StandardFormRow';
import TagSelect from './components/TagSelect';
import type { ListItemDataType } from './data.d';
import { queryFakeList } from './service';
import useStyles from './style.style';
const { Option } = Select;
export function formatWan(val: number) {
const v = val * 1;
if (!v || Number.isNaN(v)) return "";
if (!v || Number.isNaN(v)) return '';
let result: React.ReactNode = val;
if (val > 10000) {
result = (
@ -36,10 +25,10 @@ export function formatWan(val: number) {
{Math.floor(val / 10000)}
<span
style={{
position: "relative",
position: 'relative',
top: -2,
fontSize: 14,
fontStyle: "normal",
fontStyle: 'normal',
marginLeft: 2,
}}
>
@ -81,7 +70,7 @@ const CardInfo: React.FC<{
export const Applications: FC<Record<string, any>> = () => {
const { styles } = useStyles();
const { data, loading, run } = useRequest((values: any) => {
console.log("form data", values);
console.log('form data', values);
return queryFakeList({
count: 8,
});
@ -90,29 +79,17 @@ export const Applications: FC<Record<string, any>> = () => {
const itemMenu = (
<Menu>
<Menu.Item>
<a
target="_blank"
rel="noopener noreferrer"
href="https://www.alipay.com/"
>
<a target="_blank" rel="noopener noreferrer" href="https://www.alipay.com/">
1st menu item
</a>
</Menu.Item>
<Menu.Item>
<a
target="_blank"
rel="noopener noreferrer"
href="https://www.taobao.com/"
>
<a target="_blank" rel="noopener noreferrer" href="https://www.taobao.com/">
2nd menu item
</a>
</Menu.Item>
<Menu.Item>
<a
target="_blank"
rel="noopener noreferrer"
href="https://www.tmall.com/"
>
<a target="_blank" rel="noopener noreferrer" href="https://www.tmall.com/">
3d menu item
</a>
</Menu.Item>
@ -158,7 +135,7 @@ export const Applications: FC<Record<string, any>> = () => {
placeholder="不限"
style={{
maxWidth: 200,
width: "100%",
width: '100%',
}}
>
<Option value="lisa"></Option>
@ -171,7 +148,7 @@ export const Applications: FC<Record<string, any>> = () => {
placeholder="不限"
style={{
maxWidth: 200,
width: "100%",
width: '100%',
}}
>
<Option value="good"></Option>
@ -219,14 +196,11 @@ export const Applications: FC<Record<string, any>> = () => {
</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 className={styles.cardItemContent}>
<CardInfo
activeUser={formatWan(item.activeUser)}
newUser={numeral(item.newUser).format("0,0")}
newUser={numeral(item.newUser).format('0,0')}
/>
</div>
</Card>

56
src/pages/list/search/applications/style.style.ts

@ -1,45 +1,45 @@
import { createStyles } from "antd-style";
import { createStyles } from 'antd-style';
const useStyles = createStyles(({ token }) => {
return {
filterCardList: {},
".ant-card-meta-content": {
marginTop: "0",
'.ant-card-meta-content': {
marginTop: '0',
},
"// disabled white space .ant-card-meta-avatar": {
fontSize: "0",
'// disabled white space .ant-card-meta-avatar': {
fontSize: '0',
},
".ant-list .ant-list-item-content-single": {
maxWidth: "100%",
'.ant-list .ant-list-item-content-single': {
maxWidth: '100%',
},
cardInfo: {
marginTop: "16px",
marginLeft: "40px",
zoom: "1",
"&::before, &::after": { display: "table", content: "' '" },
"&::after": {
clear: "both",
height: "0",
fontSize: "0",
visibility: "hidden",
marginTop: '16px',
marginLeft: '40px',
zoom: '1',
'&::before, &::after': { display: 'table', content: "' '" },
'&::after': {
clear: 'both',
height: '0',
fontSize: '0',
visibility: 'hidden',
},
"& > div": {
position: "relative",
float: "left",
width: "50%",
textAlign: "left",
'& > div': {
position: 'relative',
float: 'left',
width: '50%',
textAlign: 'left',
},
},
p: {
margin: "0",
fontSize: "24px",
lineHeight: "32px",
margin: '0',
fontSize: '24px',
lineHeight: '32px',
},
"p:first-child": {
marginBottom: "4px",
'p:first-child': {
marginBottom: '4px',
color: token.colorTextSecondary,
fontSize: "12px",
lineHeight: "20px",
fontSize: '12px',
lineHeight: '20px',
},
};
});

2
src/pages/list/search/applications/utils/utils.style.ts

@ -1,4 +1,4 @@
import { createStyles } from "antd-style";
import { createStyles } from 'antd-style';
const useStyles = createStyles(() => {
return {};

14
src/pages/list/search/articles/components/ArticleListContent/index.style.ts

@ -1,4 +1,4 @@
import { createStyles } from "antd-style";
import { createStyles } from 'antd-style';
const useStyles = createStyles(({ token }) => {
return {
@ -6,15 +6,15 @@ const useStyles = createStyles(({ token }) => {
[`@media screen and (max-width: ${token.screenXS}px)`]: {},
},
description: {
maxWidth: "720px",
lineHeight: "22px",
maxWidth: '720px',
lineHeight: '22px',
},
extra: {
[`@media screen and (max-width: ${token.screenXS}px)`]: {
"& > em": {
display: "block",
marginTop: "8px",
marginLeft: "0",
'& > em': {
display: 'block',
marginTop: '8px',
marginLeft: '0',
},
},
},

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

@ -1,7 +1,7 @@
import { Avatar } from "antd";
import React from "react";
import dayjs from "dayjs";
import useStyles from "./index.style";
import { Avatar } from 'antd';
import React from 'react';
import dayjs from 'dayjs';
import useStyles from './index.style';
type ArticleListContentProps = {
data: {
content: React.ReactNode;
@ -21,7 +21,7 @@ const ArticleListContent: React.FC<ArticleListContentProps> = ({
<div className={styles.extra}>
<Avatar src={avatar} size="small" />
<a href={href}>{owner}</a> <a href={href}>{href}</a>
<em>{dayjs(updatedAt).format("YYYY-MM-DD HH:mm")}</em>
<em>{dayjs(updatedAt).format('YYYY-MM-DD HH:mm')}</em>
</div>
</div>
);

54
src/pages/list/search/articles/components/StandardFormRow/index.style.ts

@ -1,52 +1,52 @@
import { createStyles } from "antd-style";
import { createStyles } from 'antd-style';
const useStyles = createStyles(({ token }) => {
return {
standardFormRow: {
display: "flex",
width: "100%",
marginBottom: "16px",
paddingBottom: "16px",
borderBottom: "1px dashed @border-color-split",
display: 'flex',
width: '100%',
marginBottom: '16px',
paddingBottom: '16px',
borderBottom: '1px dashed @border-color-split',
},
".ant-form-item, .ant-legacy-form-item": {
"&:last-child": { display: "block", marginRight: "0" },
'.ant-form-item, .ant-legacy-form-item': {
'&:last-child': { display: 'block', marginRight: '0' },
},
".ant-form-item-label, .ant-legacy-form-item-label": {
float: "left",
'.ant-form-item-label, .ant-legacy-form-item-label': {
float: 'left',
},
label: {
flex: "0 0 auto",
marginRight: "24px",
flex: '0 0 auto',
marginRight: '24px',
color: token.colorTextHeading,
fontSize: token.fontSize,
textAlign: "right",
"& > span": {
display: "inline-block",
height: "32px",
lineHeight: "32px",
"&::after": {
textAlign: 'right',
'& > span': {
display: 'inline-block',
height: '32px',
lineHeight: '32px',
'&::after': {
content: "':'",
},
},
},
".ant-form-item-label, .ant-legacy-form-item-label, .ant-form-item-control, .ant-legacy-form-item-control":
'.ant-form-item-label, .ant-legacy-form-item-label, .ant-form-item-control, .ant-legacy-form-item-control':
{
padding: "0",
lineHeight: "32px",
padding: '0',
lineHeight: '32px',
},
content: {
flex: "1 1 0",
flex: '1 1 0',
},
standardFormRowLast: {
marginBottom: "0",
paddingBottom: "0",
border: "none",
marginBottom: '0',
paddingBottom: '0',
border: 'none',
},
standardFormRowBlock: {},
".ant-form-item, .ant-legacy-form-item, div.ant-form-item-control-wrapper, div.ant-legacy-form-item-control-wrapper":
'.ant-form-item, .ant-legacy-form-item, div.ant-form-item-control-wrapper, div.ant-legacy-form-item-control-wrapper':
{
display: "block",
display: 'block',
},
standardFormRowGrid: {},
};

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

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

38
src/pages/list/search/articles/components/TagSelect/index.style.ts

@ -1,35 +1,35 @@
import { createStyles } from "antd-style";
import { createStyles } from 'antd-style';
const useStyles = createStyles(({ token }) => {
return {
tagSelect: {
position: "relative",
maxHeight: "32px",
marginLeft: "-8px",
overflow: "hidden",
lineHeight: "32px",
transition: "all 0.3s",
userSelect: "none",
position: 'relative',
maxHeight: '32px',
marginLeft: '-8px',
overflow: 'hidden',
lineHeight: '32px',
transition: 'all 0.3s',
userSelect: 'none',
},
".ant-tag": {
marginRight: "24px",
padding: "0 8px",
'.ant-tag': {
marginRight: '24px',
padding: '0 8px',
fontSize: token.fontSize,
},
expanded: {
maxHeight: "200px",
transition: "all 0.3s",
maxHeight: '200px',
transition: 'all 0.3s',
},
trigger: {
position: "absolute",
top: "0",
right: "0",
position: 'absolute',
top: '0',
right: '0',
},
"span.anticon": {
fontSize: "12px",
'span.anticon': {
fontSize: '12px',
},
hasExpandTag: {
paddingRight: "50px",
paddingRight: '50px',
},
};
});

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

@ -1,10 +1,10 @@
import { DownOutlined, UpOutlined } from "@ant-design/icons";
import { useBoolean, useControllableValue } from "ahooks";
import { Tag } from "antd";
import classNames from "classnames";
import type { FC } from "react";
import React from "react";
import useStyles from "./index.style";
import { DownOutlined, UpOutlined } from '@ant-design/icons';
import { useBoolean, useControllableValue } from 'ahooks';
import { Tag } from 'antd';
import classNames from 'classnames';
import type { FC } from 'react';
import React from 'react';
import useStyles from './index.style';
const { CheckableTag } = Tag;
export interface TagSelectOptionProps {
value: string | number;
@ -25,10 +25,7 @@ const TagSelectOption: React.FC<TagSelectOptionProps> & {
</CheckableTag>
);
TagSelectOption.isTagSelectOption = true;
type TagSelectOptionElement = React.ReactElement<
TagSelectOptionProps,
typeof TagSelectOption
>;
type TagSelectOptionElement = React.ReactElement<TagSelectOptionProps, typeof TagSelectOption>;
export interface TagSelectProps {
onChange?: (value: (string | number)[]) => void;
expandable?: boolean;
@ -49,25 +46,15 @@ const TagSelect: FC<TagSelectProps> & {
Option: typeof TagSelectOption;
} = (props) => {
const { styles } = useStyles();
const {
children,
hideCheckAll = false,
className,
style,
expandable,
actionsText = {},
} = props;
const { children, hideCheckAll = false, className, style, expandable, actionsText = {} } = props;
const [expand, { toggle }] = useBoolean();
const [value, setValue] = useControllableValue<(string | number)[]>(props);
const isTagSelectOption = (node: TagSelectOptionElement) =>
node &&
node.type &&
(node.type.isTagSelectOption ||
node.type.displayName === "TagSelectOption");
(node.type.isTagSelectOption || node.type.displayName === 'TagSelectOption');
const getAllTags = () => {
const childrenArray = React.Children.toArray(
children
) as TagSelectOptionElement[];
const childrenArray = React.Children.toArray(children) as TagSelectOptionElement[];
const checkedTags = childrenArray
.filter((child) => isTagSelectOption(child))
.map((child) => child.props.value);
@ -91,11 +78,7 @@ const TagSelect: FC<TagSelectProps> & {
setValue(checkedTags);
};
const checkedAll = getAllTags().length === value?.length;
const {
expandText = "展开",
collapseText = "收起",
selectAllText = "全部",
} = actionsText;
const { expandText = '展开', collapseText = '收起', selectAllText = '全部' } = actionsText;
const cls = classNames(styles.tagSelect, className, {
[styles.hasExpandTag]: expandable,
[styles.expanded]: expand,
@ -103,11 +86,7 @@ const TagSelect: FC<TagSelectProps> & {
return (
<div className={cls} style={style}>
{hideCheckAll ? null : (
<CheckableTag
checked={checkedAll}
key="tag-select-__all__"
onChange={onSelectAll}
>
<CheckableTag checked={checkedAll} key="tag-select-__all__" onChange={onSelectAll}>
{selectAllText}
</CheckableTag>
)}

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

@ -1,19 +1,14 @@
import {
LikeOutlined,
LoadingOutlined,
MessageOutlined,
StarOutlined,
} from "@ant-design/icons";
import { Button, Card, Col, Form, List, Row, Select, Tag } from "antd";
import type { FC } from "react";
import React from "react";
import { useRequest } from "@umijs/max";
import ArticleListContent from "./components/ArticleListContent";
import StandardFormRow from "./components/StandardFormRow";
import TagSelect from "./components/TagSelect";
import type { ListItemDataType } from "./data.d";
import { queryFakeList } from "./service";
import useStyles from "./style.style";
import { LikeOutlined, LoadingOutlined, MessageOutlined, StarOutlined } from '@ant-design/icons';
import { Button, Card, Col, Form, List, Row, Select, Tag } from 'antd';
import type { FC } from 'react';
import React from 'react';
import { useRequest } from '@umijs/max';
import ArticleListContent from './components/ArticleListContent';
import StandardFormRow from './components/StandardFormRow';
import TagSelect from './components/TagSelect';
import type { ListItemDataType } from './data.d';
import { queryFakeList } from './service';
import useStyles from './style.style';
const { Option } = Select;
const FormItem = Form.Item;
const pageSize = 5;
@ -28,34 +23,34 @@ const Articles: FC = () => {
},
{
loadMore: true,
}
},
);
const list = data?.list || [];
const setOwner = () => {
form.setFieldsValue({
owner: ["wzj"],
owner: ['wzj'],
});
};
const owners = [
{
id: "wzj",
name: "我自己",
id: 'wzj',
name: '我自己',
},
{
id: "wjh",
name: "吴家豪",
id: 'wjh',
name: '吴家豪',
},
{
id: "zxx",
name: "周星星",
id: 'zxx',
name: '周星星',
},
{
id: "zly",
name: "赵丽颖",
id: 'zly',
name: '赵丽颖',
},
{
id: "ym",
name: "姚明",
id: 'ym',
name: '姚明',
},
];
const IconText: React.FC<{
@ -63,7 +58,7 @@ const Articles: FC = () => {
text: React.ReactNode;
}> = ({ type, text }) => {
switch (type) {
case "star-o":
case 'star-o':
return (
<span>
<StarOutlined
@ -74,7 +69,7 @@ const Articles: FC = () => {
{text}
</span>
);
case "like-o":
case 'like-o':
return (
<span>
<LikeOutlined
@ -85,7 +80,7 @@ const Articles: FC = () => {
{text}
</span>
);
case "message":
case 'message':
return (
<span>
<MessageOutlined
@ -116,7 +111,7 @@ const Articles: FC = () => {
const loadMoreDom = list.length > 0 && (
<div
style={{
textAlign: "center",
textAlign: 'center',
marginTop: 16,
}}
>
@ -132,7 +127,7 @@ const Articles: FC = () => {
<LoadingOutlined /> ...
</span>
) : (
"加载更多"
'加载更多'
)}
</Button>
</div>
@ -144,7 +139,7 @@ const Articles: FC = () => {
layout="inline"
form={form}
initialValues={{
owner: ["wjh", "zxx"],
owner: ['wjh', 'zxx'],
}}
onValuesChange={reload}
>
@ -178,7 +173,7 @@ const Articles: FC = () => {
mode="multiple"
placeholder="选择 owner"
style={{
minWidth: "6rem",
minWidth: '6rem',
}}
>
{owners.map((owner) => (
@ -200,7 +195,7 @@ const Articles: FC = () => {
placeholder="不限"
style={{
maxWidth: 200,
width: "100%",
width: '100%',
}}
>
<Option value="lisa"></Option>
@ -213,7 +208,7 @@ const Articles: FC = () => {
placeholder="不限"
style={{
maxWidth: 200,
width: "100%",
width: '100%',
}}
>
<Option value="good"></Option>
@ -230,7 +225,7 @@ const Articles: FC = () => {
}}
bordered={false}
bodyStyle={{
padding: "8px 32px 32px 32px",
padding: '8px 32px 32px 32px',
}}
>
<List<ListItemDataType>

12
src/pages/list/search/articles/style.style.ts

@ -1,20 +1,20 @@
import { createStyles } from "antd-style";
import { createStyles } from 'antd-style';
const useStyles = createStyles(({ token }) => {
return {
"a.listItemMetaTitle": {
'a.listItemMetaTitle': {
color: token.colorTextHeading,
},
listItemExtra: {
[`@media screen and (max-width: ${token.screenLG}px)`]: {
width: "0",
height: "1px",
width: '0',
height: '1px',
},
},
selfTrigger: {
[`@media screen and (max-width: ${token.screenMD}px)`]: {
display: "block",
marginLeft: "0",
display: 'block',
marginLeft: '0',
},
},
};

32
src/pages/list/search/projects/components/AvatarList/index.style.ts

@ -1,26 +1,26 @@
import { createStyles } from "antd-style";
import { createStyles } from 'antd-style';
const useStyles = createStyles(({ token }) => {
return {
avatarList: {
display: "inline-block",
display: 'inline-block',
},
ul: {
display: "inline-block",
marginLeft: "8px",
fontSize: "0",
display: 'inline-block',
marginLeft: '8px',
fontSize: '0',
},
avatarItem: {
display: "inline-block",
display: 'inline-block',
width: token.controlHeight,
height: token.controlHeight,
marginLeft: "-8px",
marginLeft: '-8px',
fontSize: token.fontSize,
},
".ant-avatar": {
width: "20px",
height: "20px",
lineHeight: "20px",
'.ant-avatar': {
width: '20px',
height: '20px',
lineHeight: '20px',
},
avatarItemLarge: {
width: token.controlHeightLG,
@ -31,12 +31,12 @@ const useStyles = createStyles(({ token }) => {
height: token.controlHeightSM,
},
avatarItemMini: {
width: "20px",
height: "20px",
width: '20px',
height: '20px',
},
".ant-avatar-string": {
fontSize: "12px",
lineHeight: "18px",
'.ant-avatar-string': {
fontSize: '12px',
lineHeight: '18px',
},
};
});

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

@ -1,8 +1,8 @@
import { Avatar, Tooltip } from "antd";
import React from "react";
import classNames from "classnames";
import useStyles from "./index.style";
export declare type SizeType = number | "small" | "default" | "large";
import { Avatar, Tooltip } from 'antd';
import React from 'react';
import classNames from 'classnames';
import useStyles from './index.style';
export declare type SizeType = number | 'small' | 'default' | 'large';
export type AvatarItemProps = {
tips: React.ReactNode;
src: string;
@ -16,22 +16,15 @@ export type AvatarListProps = {
maxLength?: number;
excessItemsStyle?: React.CSSProperties;
style?: React.CSSProperties;
children:
| React.ReactElement<AvatarItemProps>
| React.ReactElement<AvatarItemProps>[];
children: React.ReactElement<AvatarItemProps> | React.ReactElement<AvatarItemProps>[];
};
const avatarSizeToClassName = (size?: SizeType | "mini") =>
const avatarSizeToClassName = (size?: SizeType | 'mini') =>
classNames(styles.avatarItem, {
[styles.avatarItemLarge]: size === "large",
[styles.avatarItemSmall]: size === "small",
[styles.avatarItemMini]: size === "mini",
[styles.avatarItemLarge]: size === 'large',
[styles.avatarItemSmall]: size === 'small',
[styles.avatarItemMini]: size === 'mini',
});
const Item: React.FC<AvatarItemProps> = ({
src,
size,
tips,
onClick = () => {},
}) => {
const Item: React.FC<AvatarItemProps> = ({ src, size, tips, onClick = () => {} }) => {
const cls = avatarSizeToClassName(size);
return (
<li className={cls} onClick={onClick}>
@ -41,7 +34,7 @@ const Item: React.FC<AvatarItemProps> = ({
src={src}
size={size}
style={{
cursor: "pointer",
cursor: 'pointer',
}}
/>
</Tooltip>
@ -57,22 +50,18 @@ const AvatarList: React.FC<AvatarListProps> & {
const { styles } = useStyles();
const numOfChildren = React.Children.count(children);
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) =>
React.cloneElement(child, {
size,
})
}),
);
if (numToShow < numOfChildren) {
const cls = avatarSizeToClassName(size);
childrenWithProps.push(
<li key="exceed" className={cls}>
<Avatar size={size} style={excessItemsStyle}>{`+${
numOfChildren - maxLength
}`}</Avatar>
</li>
<Avatar size={size} style={excessItemsStyle}>{`+${numOfChildren - maxLength}`}</Avatar>
</li>,
);
}
return (

54
src/pages/list/search/projects/components/StandardFormRow/index.style.ts

@ -1,52 +1,52 @@
import { createStyles } from "antd-style";
import { createStyles } from 'antd-style';
const useStyles = createStyles(({ token }) => {
return {
standardFormRow: {
display: "flex",
width: "100%",
marginBottom: "16px",
paddingBottom: "16px",
borderBottom: "1px dashed @border-color-split",
display: 'flex',
width: '100%',
marginBottom: '16px',
paddingBottom: '16px',
borderBottom: '1px dashed @border-color-split',
},
".ant-form-item, .ant-legacy-form-item": {
"&:last-child": { display: "block", marginRight: "0" },
'.ant-form-item, .ant-legacy-form-item': {
'&:last-child': { display: 'block', marginRight: '0' },
},
".ant-form-item-label, .ant-legacy-form-item-label": {
float: "left",
'.ant-form-item-label, .ant-legacy-form-item-label': {
float: 'left',
},
label: {
flex: "0 0 auto",
marginRight: "24px",
flex: '0 0 auto',
marginRight: '24px',
color: token.colorTextHeading,
fontSize: token.fontSize,
textAlign: "right",
"& > span": {
display: "inline-block",
height: "32px",
lineHeight: "32px",
"&::after": {
textAlign: 'right',
'& > span': {
display: 'inline-block',
height: '32px',
lineHeight: '32px',
'&::after': {
content: "':'",
},
},
},
".ant-form-item-label, .ant-legacy-form-item-label, .ant-form-item-control, .ant-legacy-form-item-control":
'.ant-form-item-label, .ant-legacy-form-item-label, .ant-form-item-control, .ant-legacy-form-item-control':
{
padding: "0",
lineHeight: "32px",
padding: '0',
lineHeight: '32px',
},
content: {
flex: "1 1 0",
flex: '1 1 0',
},
standardFormRowLast: {
marginBottom: "0",
paddingBottom: "0",
border: "none",
marginBottom: '0',
paddingBottom: '0',
border: 'none',
},
standardFormRowBlock: {},
".ant-form-item, .ant-legacy-form-item, div.ant-form-item-control-wrapper, div.ant-legacy-form-item-control-wrapper":
'.ant-form-item, .ant-legacy-form-item, div.ant-form-item-control-wrapper, div.ant-legacy-form-item-control-wrapper':
{
display: "block",
display: 'block',
},
standardFormRowGrid: {},
};

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

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

38
src/pages/list/search/projects/components/TagSelect/index.style.ts

@ -1,35 +1,35 @@
import { createStyles } from "antd-style";
import { createStyles } from 'antd-style';
const useStyles = createStyles(({ token }) => {
return {
tagSelect: {
position: "relative",
maxHeight: "32px",
marginLeft: "-8px",
overflow: "hidden",
lineHeight: "32px",
transition: "all 0.3s",
userSelect: "none",
position: 'relative',
maxHeight: '32px',
marginLeft: '-8px',
overflow: 'hidden',
lineHeight: '32px',
transition: 'all 0.3s',
userSelect: 'none',
},
".ant-tag": {
marginRight: "24px",
padding: "0 8px",
'.ant-tag': {
marginRight: '24px',
padding: '0 8px',
fontSize: token.fontSize,
},
expanded: {
maxHeight: "200px",
transition: "all 0.3s",
maxHeight: '200px',
transition: 'all 0.3s',
},
trigger: {
position: "absolute",
top: "0",
right: "0",
position: 'absolute',
top: '0',
right: '0',
},
"span.anticon": {
fontSize: "12px",
'span.anticon': {
fontSize: '12px',
},
hasExpandTag: {
paddingRight: "50px",
paddingRight: '50px',
},
};
});

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

@ -1,10 +1,10 @@
import { DownOutlined, UpOutlined } from "@ant-design/icons";
import { useBoolean, useControllableValue } from "ahooks";
import { Tag } from "antd";
import classNames from "classnames";
import type { FC } from "react";
import React from "react";
import useStyles from "./index.style";
import { DownOutlined, UpOutlined } from '@ant-design/icons';
import { useBoolean, useControllableValue } from 'ahooks';
import { Tag } from 'antd';
import classNames from 'classnames';
import type { FC } from 'react';
import React from 'react';
import useStyles from './index.style';
const { CheckableTag } = Tag;
export interface TagSelectOptionProps {
value: string | number;
@ -25,10 +25,7 @@ const TagSelectOption: React.FC<TagSelectOptionProps> & {
</CheckableTag>
);
TagSelectOption.isTagSelectOption = true;
type TagSelectOptionElement = React.ReactElement<
TagSelectOptionProps,
typeof TagSelectOption
>;
type TagSelectOptionElement = React.ReactElement<TagSelectOptionProps, typeof TagSelectOption>;
export interface TagSelectProps {
onChange?: (value: (string | number)[]) => void;
expandable?: boolean;
@ -49,25 +46,15 @@ const TagSelect: FC<TagSelectProps> & {
Option: typeof TagSelectOption;
} = (props) => {
const { styles } = useStyles();
const {
children,
hideCheckAll = false,
className,
style,
expandable,
actionsText = {},
} = props;
const { children, hideCheckAll = false, className, style, expandable, actionsText = {} } = props;
const [expand, { toggle }] = useBoolean();
const [value, setValue] = useControllableValue<(string | number)[]>(props);
const isTagSelectOption = (node: TagSelectOptionElement) =>
node &&
node.type &&
(node.type.isTagSelectOption ||
node.type.displayName === "TagSelectOption");
(node.type.isTagSelectOption || node.type.displayName === 'TagSelectOption');
const getAllTags = () => {
const childrenArray = React.Children.toArray(
children
) as TagSelectOptionElement[];
const childrenArray = React.Children.toArray(children) as TagSelectOptionElement[];
const checkedTags = childrenArray
.filter((child) => isTagSelectOption(child))
.map((child) => child.props.value);
@ -91,11 +78,7 @@ const TagSelect: FC<TagSelectProps> & {
setValue(checkedTags);
};
const checkedAll = getAllTags().length === value?.length;
const {
expandText = "展开",
collapseText = "收起",
selectAllText = "全部",
} = actionsText;
const { expandText = '展开', collapseText = '收起', selectAllText = '全部' } = actionsText;
const cls = classNames(styles.tagSelect, className, {
[styles.hasExpandTag]: expandable,
[styles.expanded]: expand,
@ -103,11 +86,7 @@ const TagSelect: FC<TagSelectProps> & {
return (
<div className={cls} style={style}>
{hideCheckAll ? null : (
<CheckableTag
checked={checkedAll}
key="tag-select-__all__"
onChange={onSelectAll}
>
<CheckableTag checked={checkedAll} key="tag-select-__all__" onChange={onSelectAll}>
{selectAllText}
</CheckableTag>
)}

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

@ -1,14 +1,14 @@
import { Card, Col, Form, List, Row, Select, Typography } from "antd";
import type { FC } from "react";
import { useRequest } from "@umijs/max";
import AvatarList from "./components/AvatarList";
import StandardFormRow from "./components/StandardFormRow";
import TagSelect from "./components/TagSelect";
import type { ListItemDataType } from "./data.d";
import { queryFakeList } from "./service";
import useStyles from "./style.style";
import dayjs from "dayjs";
import relativeTime from "dayjs/plugin/relativeTime";
import { Card, Col, Form, List, Row, Select, Typography } from 'antd';
import type { FC } from 'react';
import { useRequest } from '@umijs/max';
import AvatarList from './components/AvatarList';
import StandardFormRow from './components/StandardFormRow';
import TagSelect from './components/TagSelect';
import type { ListItemDataType } from './data.d';
import { queryFakeList } from './service';
import useStyles from './style.style';
import dayjs from 'dayjs';
import relativeTime from 'dayjs/plugin/relativeTime';
dayjs.extend(relativeTime);
const { Option } = Select;
const FormItem = Form.Item;
@ -17,7 +17,7 @@ const getKey = (id: string, index: number) => `${id}-${index}`;
const Projects: FC = () => {
const { styles } = useStyles();
const { data, loading, run } = useRequest((values: any) => {
console.log("form data", values);
console.log('form data', values);
return queryFakeList({
count: 8,
});
@ -39,11 +39,7 @@ const Projects: FC = () => {
dataSource={list}
renderItem={(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
title={<a>{item.title}</a>}
description={
@ -129,7 +125,7 @@ const Projects: FC = () => {
placeholder="不限"
style={{
maxWidth: 200,
width: "100%",
width: '100%',
}}
>
<Option value="lisa"></Option>
@ -142,7 +138,7 @@ const Projects: FC = () => {
placeholder="不限"
style={{
maxWidth: 200,
width: "100%",
width: '100%',
}}
>
<Option value="good"></Option>

48
src/pages/list/search/projects/style.style.ts

@ -1,47 +1,47 @@
import { createStyles } from "antd-style";
import { createStyles } from 'antd-style';
const useStyles = createStyles(({ token }) => {
return {
coverCardList: {},
card: {
"&:hover": {},
'&:hover': {},
},
".ant-card-meta-title": {
marginBottom: "4px",
"& > a": {
display: "inline-block",
maxWidth: "100%",
'.ant-card-meta-title': {
marginBottom: '4px',
'& > a': {
display: 'inline-block',
maxWidth: '100%',
color: token.colorTextHeading,
},
},
".ant-card-meta-description": {
height: "44px",
overflow: "hidden",
lineHeight: "22px",
'.ant-card-meta-description': {
height: '44px',
overflow: 'hidden',
lineHeight: '22px',
},
".ant-card-meta-title > a": {
'.ant-card-meta-title > a': {
color: token.colorPrimary,
},
cardItemContent: {
display: "flex",
height: "20px",
marginTop: "16px",
marginBottom: "-4px",
lineHeight: "20px",
"& > span": {
flex: "1",
display: 'flex',
height: '20px',
marginTop: '16px',
marginBottom: '-4px',
lineHeight: '20px',
'& > span': {
flex: '1',
color: token.colorTextSecondary,
fontSize: "12px",
fontSize: '12px',
},
},
avatarList: {
flex: "0 1 auto",
flex: '0 1 auto',
},
cardList: {
marginTop: "24px",
marginTop: '24px',
},
".ant-list .ant-list-item-content-single": {
maxWidth: "100%",
'.ant-list .ant-list-item-content-single': {
maxWidth: '100%',
},
};
});

2
src/pages/list/search/projects/utils/utils.style.ts

@ -1,4 +1,4 @@
import { createStyles } from "antd-style";
import { createStyles } from 'antd-style';
const useStyles = createStyles(() => {
return {};

34
src/pages/profile/advanced/style.style.ts

@ -1,38 +1,38 @@
import { createStyles } from "antd-style";
import { createStyles } from 'antd-style';
const useStyles = createStyles(({ token }) => {
return {
main: {},
".ant-descriptions-row > td": {
paddingBottom: "8px",
'.ant-descriptions-row > td': {
paddingBottom: '8px',
},
".ant-page-header-heading-extra": {
flexDirection: "column",
'.ant-page-header-heading-extra': {
flexDirection: 'column',
},
headerList: {
marginBottom: "4px",
marginBottom: '4px',
},
stepDescription: {
[`@media screen and (max-width: ${token.screenSM}px)`]: { left: "8px" },
[`@media screen and (max-width: ${token.screenSM}px)`]: { left: '8px' },
},
"> div": {
marginTop: "8px",
marginBottom: "4px",
'> div': {
marginTop: '8px',
marginBottom: '4px',
},
pageHeader: {
[`@media screen and (max-width: ${token.screenSM}px)`]: {},
},
".ant-page-header-heading-extra > * + *": {
marginLeft: "8px",
'.ant-page-header-heading-extra > * + *': {
marginLeft: '8px',
},
moreInfo: {
display: "flex",
justifyContent: "space-between",
width: "200px",
display: 'flex',
justifyContent: 'space-between',
width: '200px',
},
".ant-pro-page-header-wrap-row": {
'.ant-pro-page-header-wrap-row': {
[`@media screen and (max-width: ${token.screenSM}px)`]: {
flexDirection: "column",
flexDirection: 'column',
},
},
};

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

@ -1,44 +1,44 @@
import { PageContainer } from "@ant-design/pro-components";
import type { ProColumns } from "@ant-design/pro-components";
import { ProTable } from "@ant-design/pro-components";
import { Badge, Card, Descriptions, Divider } from "antd";
import type { FC } from "react";
import React from "react";
import { useRequest } from "@umijs/max";
import type { BasicGood, BasicProgress } from "./data.d";
import { queryBasicProfile } from "./service";
import useStyles from "./style.style";
import { PageContainer } from '@ant-design/pro-components';
import type { ProColumns } from '@ant-design/pro-components';
import { ProTable } from '@ant-design/pro-components';
import { Badge, Card, Descriptions, Divider } from 'antd';
import type { FC } from 'react';
import React from 'react';
import { useRequest } from '@umijs/max';
import type { BasicGood, BasicProgress } from './data.d';
import { queryBasicProfile } from './service';
import useStyles from './style.style';
const progressColumns: ProColumns<BasicProgress>[] = [
{
title: "时间",
dataIndex: "time",
key: "time",
title: '时间',
dataIndex: 'time',
key: 'time',
},
{
title: "当前进度",
dataIndex: "rate",
key: "rate",
title: '当前进度',
dataIndex: 'rate',
key: 'rate',
},
{
title: "状态",
dataIndex: "status",
key: "status",
title: '状态',
dataIndex: 'status',
key: 'status',
render: (text: React.ReactNode) => {
if (text === "success") {
if (text === 'success') {
return <Badge status="success" text="成功" />;
}
return <Badge status="processing" text="进行中" />;
},
},
{
title: "操作员ID",
dataIndex: "operator",
key: "operator",
title: '操作员ID',
dataIndex: 'operator',
key: 'operator',
},
{
title: "耗时",
dataIndex: "cost",
key: "cost",
title: '耗时',
dataIndex: 'cost',
key: 'cost',
},
];
const Basic: FC = () => {
@ -59,7 +59,7 @@ const Basic: FC = () => {
amount += Number(item.amount);
});
goodsData = basicGoods.concat({
id: "总计",
id: '总计',
num,
amount,
});
@ -81,9 +81,9 @@ const Basic: FC = () => {
};
const goodsColumns: ProColumns<BasicGood>[] = [
{
title: "商品编号",
dataIndex: "id",
key: "id",
title: '商品编号',
dataIndex: 'id',
key: 'id',
render: (text: React.ReactNode, _: any, index: number) => {
if (index < basicGoods.length) {
return <span>{text}</span>;
@ -105,29 +105,29 @@ const Basic: FC = () => {
},
},
{
title: "商品名称",
dataIndex: "name",
key: "name",
title: '商品名称',
dataIndex: 'name',
key: 'name',
render: renderContent,
},
{
title: "商品条码",
dataIndex: "barcode",
key: "barcode",
title: '商品条码',
dataIndex: 'barcode',
key: 'barcode',
render: renderContent,
},
{
title: "单价",
dataIndex: "price",
key: "price",
align: "right" as "left" | "right" | "center",
title: '单价',
dataIndex: 'price',
key: 'price',
align: 'right' as 'left' | 'right' | 'center',
render: renderContent,
},
{
title: "数量(件)",
dataIndex: "num",
key: "num",
align: "right" as "left" | "right" | "center",
title: '数量(件)',
dataIndex: 'num',
key: 'num',
align: 'right' as 'left' | 'right' | 'center',
render: (text: React.ReactNode, _: any, index: number) => {
if (index < basicGoods.length) {
return text;
@ -144,10 +144,10 @@ const Basic: FC = () => {
},
},
{
title: "金额",
dataIndex: "amount",
key: "amount",
align: "right" as "left" | "right" | "center",
title: '金额',
dataIndex: 'amount',
key: 'amount',
align: 'right' as 'left' | 'right' | 'center',
render: (text: React.ReactNode, _: any, index: number) => {
if (index < basicGoods.length) {
return text;
@ -192,9 +192,7 @@ const Basic: FC = () => {
<Descriptions.Item label="用户姓名"></Descriptions.Item>
<Descriptions.Item label="联系电话">18100000000</Descriptions.Item>
<Descriptions.Item label="常用快递"></Descriptions.Item>
<Descriptions.Item label="取货地址">
西18
</Descriptions.Item>
<Descriptions.Item label="取货地址">西18</Descriptions.Item>
<Descriptions.Item label="备注"></Descriptions.Item>
</Descriptions>
<Divider

8
src/pages/profile/basic/style.style.ts

@ -1,12 +1,12 @@
import { createStyles } from "antd-style";
import { createStyles } from 'antd-style';
const useStyles = createStyles(({ token }) => {
return {
title: {
marginBottom: "16px",
marginBottom: '16px',
color: token.colorTextHeading,
fontWeight: "500",
fontSize: "16px",
fontWeight: '500',
fontSize: '16px',
},
};
});

8
src/pages/result/fail/index.style.ts

@ -1,4 +1,4 @@
import { createStyles } from "antd-style";
import { createStyles } from 'antd-style';
const useStyles = createStyles(({ token }) => {
return {
@ -6,10 +6,10 @@ const useStyles = createStyles(({ token }) => {
color: token.colorBgTextActive,
},
title: {
marginBottom: "16px",
marginBottom: '16px',
color: token.colorTextHeading,
fontWeight: "500",
fontSize: "16px",
fontWeight: '500',
fontSize: '16px',
},
};
});

16
src/pages/result/success/index.style.ts

@ -1,18 +1,18 @@
import { createStyles } from "antd-style";
import { createStyles } from 'antd-style';
const useStyles = createStyles(({ token }) => {
return {
title: {
position: "relative",
position: 'relative',
color: token.colorText,
fontSize: "12px",
textAlign: "center",
fontSize: '12px',
textAlign: 'center',
},
"head-title": {
marginBottom: "20px",
'head-title': {
marginBottom: '20px',
color: token.colorTextHeading,
fontWeight: "500px",
fontSize: "16px",
fontWeight: '500px',
fontSize: '16px',
},
};
});

10
src/pages/user/register-result/index.tsx

@ -1,7 +1,7 @@
import { Button, Result } from "antd";
import { Link, useSearchParams } from "@umijs/max";
import React from "react";
import useStyles from "./style.style";
import { Button, Result } from 'antd';
import { Link, useSearchParams } from '@umijs/max';
import React from 'react';
import useStyles from './style.style';
const actions = (
<div className={styles.actions}>
<a href="">
@ -17,7 +17,7 @@ const actions = (
const RegisterResult: React.FC<Record<string, unknown>> = () => {
const { styles } = useStyles();
const [params] = useSearchParams();
const email = params?.get("account") || "AntDesign@example.com";
const email = params?.get('account') || 'AntDesign@example.com';
return (
<Result
className={styles.registerResult}

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

@ -1,21 +1,11 @@
import type { FC } from "react";
import { useState, useEffect } from "react";
import {
Form,
Button,
Col,
Input,
Popover,
Progress,
Row,
Select,
message,
} from "antd";
import type { Store } from "antd/es/form/interface";
import { Link, useRequest, history } from "@umijs/max";
import type { StateType } from "./service";
import { fakeRegister } from "./service";
import useStyles from "./style.style";
import type { FC } from 'react';
import { useState, useEffect } from 'react';
import { Form, Button, Col, Input, Popover, Progress, Row, Select, message } from 'antd';
import type { Store } from 'antd/es/form/interface';
import { Link, useRequest, history } from '@umijs/max';
import type { StateType } from './service';
import { fakeRegister } from './service';
import useStyles from './style.style';
const FormItem = Form.Item;
const { Option } = Select;
const InputGroup = Input.Group;
@ -37,19 +27,19 @@ const passwordStatusMap = {
),
};
const passwordProgressMap: {
ok: "success";
pass: "normal";
poor: "exception";
ok: 'success';
pass: 'normal';
poor: 'exception';
} = {
ok: "success",
pass: "normal",
poor: "exception",
ok: 'success',
pass: 'normal',
poor: 'exception',
};
const Register: FC = () => {
const { styles } = useStyles();
const [count, setCount]: [number, any] = useState(0);
const [visible, setVisible]: [boolean, any] = useState(false);
const [prefix, setPrefix]: [string, any] = useState("86");
const [prefix, setPrefix]: [string, any] = useState('86');
const [popover, setPopover]: [boolean, any] = useState(false);
const confirmDirty = false;
let interval: number | undefined;
@ -58,7 +48,7 @@ const Register: FC = () => {
() => () => {
clearInterval(interval);
},
[interval]
[interval],
);
const onGetCaptcha = () => {
let counts = 59;
@ -72,24 +62,24 @@ const Register: FC = () => {
}, 1000);
};
const getPasswordStatus = () => {
const value = form.getFieldValue("password");
const value = form.getFieldValue('password');
if (value && value.length > 9) {
return "ok";
return 'ok';
}
if (value && value.length > 5) {
return "pass";
return 'pass';
}
return "poor";
return 'poor';
};
const { loading: submitting, run: register } = useRequest<{
data: StateType;
}>(fakeRegister, {
manual: true,
onSuccess: (data, params) => {
if (data.status === "ok") {
message.success("注册成功!");
if (data.status === 'ok') {
message.success('注册成功!');
history.push({
pathname: "/user/register-result?account=" + params.email,
pathname: '/user/register-result?account=' + params.email,
});
}
},
@ -99,8 +89,8 @@ const Register: FC = () => {
};
const checkConfirm = (_: any, value: string) => {
const promise = Promise;
if (value && value !== form.getFieldValue("password")) {
return promise.reject("两次输入的密码不匹配!");
if (value && value !== form.getFieldValue('password')) {
return promise.reject('两次输入的密码不匹配!');
}
return promise.resolve();
};
@ -109,7 +99,7 @@ const Register: FC = () => {
// 没有值的情况
if (!value) {
setVisible(!!value);
return promise.reject("请输入密码!");
return promise.reject('请输入密码!');
}
// 有值的情况
if (!visible) {
@ -117,10 +107,10 @@ const Register: FC = () => {
}
setPopover(!popover);
if (value.length < 6) {
return promise.reject("");
return promise.reject('');
}
if (value && confirmDirty) {
form.validateFields(["confirm"]);
form.validateFields(['confirm']);
}
return promise.resolve();
};
@ -128,7 +118,7 @@ const Register: FC = () => {
setPrefix(value);
};
const renderPasswordProgress = () => {
const value = form.getFieldValue("password");
const value = form.getFieldValue('password');
const passwordStatus = getPasswordStatus();
return value && value.length ? (
<div className={styles[`progress-${passwordStatus}`]}>
@ -151,11 +141,11 @@ const Register: FC = () => {
rules={[
{
required: true,
message: "请输入邮箱地址!",
message: '请输入邮箱地址!',
},
{
type: "email",
message: "邮箱地址格式错误!",
type: 'email',
message: '邮箱地址格式错误!',
},
]}
>
@ -172,7 +162,7 @@ const Register: FC = () => {
visible && (
<div
style={{
padding: "4px 0",
padding: '4px 0',
}}
>
{passwordStatusMap[getPasswordStatus()]}
@ -196,8 +186,8 @@ const Register: FC = () => {
<FormItem
name="password"
className={
form.getFieldValue("password") &&
form.getFieldValue("password").length > 0 &&
form.getFieldValue('password') &&
form.getFieldValue('password').length > 0 &&
styles.password
}
rules={[
@ -206,11 +196,7 @@ const Register: FC = () => {
},
]}
>
<Input
size="large"
type="password"
placeholder="至少6位密码,区分大小写"
/>
<Input size="large" type="password" placeholder="至少6位密码,区分大小写" />
</FormItem>
</Popover>
<FormItem
@ -218,7 +204,7 @@ const Register: FC = () => {
rules={[
{
required: true,
message: "确认密码",
message: '确认密码',
},
{
validator: checkConfirm,
@ -233,7 +219,7 @@ const Register: FC = () => {
value={prefix}
onChange={changePrefix}
style={{
width: "20%",
width: '20%',
}}
>
<Option value="86">+86</Option>
@ -241,17 +227,17 @@ const Register: FC = () => {
</Select>
<FormItem
style={{
width: "80%",
width: '80%',
}}
name="mobile"
rules={[
{
required: true,
message: "请输入手机号!",
message: '请输入手机号!',
},
{
pattern: /^\d{11}$/,
message: "手机号格式错误!",
message: '手机号格式错误!',
},
]}
>
@ -265,7 +251,7 @@ const Register: FC = () => {
rules={[
{
required: true,
message: "请输入验证码!",
message: '请输入验证码!',
},
]}
>
@ -279,7 +265,7 @@ const Register: FC = () => {
className={styles.getCaptcha}
onClick={onGetCaptcha}
>
{count ? `${count} s` : "获取验证码"}
{count ? `${count} s` : '获取验证码'}
</Button>
</Col>
</Row>

Loading…
Cancel
Save