Skip to content

Commit 16ee3ae

Browse files
committed
add action icon
1 parent 69d366e commit 16ee3ae

6 files changed

Lines changed: 634 additions & 28 deletions

File tree

frontend/packages/flow-pc/flow-pc-approval/src/components/flow-approval/components/action-button.tsx

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,14 @@
11
import {Button} from "antd";
22
import React from "react";
33
import {DisplayStyle, FlowActionDisplay} from "@flow-engine/flow-types";
4-
4+
import {Icon} from "@flow-engine/flow-pc-ui";
55

66
interface ActionButtonProps {
77
onClick: () => void;
88
title: string;
99
display: FlowActionDisplay;
1010
}
1111

12-
/**
13-
* 展示样式
14-
*/
15-
export interface DisplayStyle {
16-
// 边框颜色
17-
borderColor?: string;
18-
// 背景颜色
19-
backgroundColor?: string;
20-
// 边框大小
21-
borderSize?: string;
22-
// 边框圆角
23-
borderRadius?: string;
24-
}
25-
2612
export const ActionButton: React.FC<ActionButtonProps> = (props) => {
2713

2814
const display = props.display;
@@ -56,6 +42,7 @@ export const ActionButton: React.FC<ActionButtonProps> = (props) => {
5642
<Button
5743
onClick={props.onClick}
5844
style={style}
45+
icon={<Icon type={display.icon} />}
5946
>
6047
{title}
6148
</Button>
Lines changed: 100 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,105 @@
11
import React from "react";
2-
import {Input} from "antd";
2+
import {Button, Col, Popover, Row} from "antd";
3+
import {Icon} from "@flow-engine/flow-pc-ui";
4+
import {icons} from "@flow-engine/flow-types";
35

4-
5-
interface ActionIconProps{
6-
value?:string;
7-
onChange?:(value:string) => void;
6+
interface ActionIconProps {
7+
value?: string;
8+
onChange?: (value: string) => void;
89
}
910

10-
export const ActionIcon:React.FC<ActionIconProps> = (props)=>{
11+
12+
export const ActionIcon: React.FC<ActionIconProps> = (props) => {
13+
const { value, onChange } = props;
14+
15+
const options = React.useMemo(() => {
16+
return icons.groups;
17+
}, []);
18+
19+
const handleSelectIcon = (iconType: string) => {
20+
onChange?.(iconType);
21+
};
22+
23+
const content = () => {
24+
return (
25+
<div
26+
style={{
27+
maxHeight: 400,
28+
width: 500,
29+
overflowY: 'auto', // 添加滚动
30+
padding: '4px'
31+
}}
32+
>
33+
<Row gutter={[12, 12]}>
34+
{options.map((group) => (
35+
<React.Fragment key={group.label}>
36+
<Col span={24}>
37+
<div style={{
38+
fontWeight: 500,
39+
marginBottom: 8,
40+
color: '#666',
41+
fontSize: 13
42+
}}>
43+
{group.label}
44+
</div>
45+
</Col>
46+
47+
{group.icons.map((iconType) => (
48+
<Col span={4} key={iconType}>
49+
<div
50+
onClick={() => handleSelectIcon(iconType)}
51+
style={{
52+
padding: '12px 8px',
53+
borderRadius: 6,
54+
cursor: 'pointer',
55+
display: 'flex',
56+
justifyContent: 'center',
57+
alignItems: 'center',
58+
backgroundColor: value === iconType ? '#e6f7ff' : 'transparent',
59+
border: value === iconType ? '1px solid #1890ff' : '1px solid transparent',
60+
transition: 'all 0.3s'
61+
}}
62+
onMouseEnter={(e) => {
63+
if (value !== iconType) {
64+
e.currentTarget.style.backgroundColor = '#f5f5f5';
65+
e.currentTarget.style.borderColor = '#d9d9d9';
66+
}
67+
}}
68+
onMouseLeave={(e) => {
69+
if (value !== iconType) {
70+
e.currentTarget.style.backgroundColor = 'transparent';
71+
e.currentTarget.style.borderColor = 'transparent';
72+
}
73+
}}
74+
>
75+
<Icon type={iconType} style={{ fontSize: 24 }} />
76+
</div>
77+
</Col>
78+
))}
79+
</React.Fragment>
80+
))}
81+
</Row>
82+
</div>
83+
);
84+
};
85+
1186
return (
12-
<>
13-
<Input placeholder={"请输入按钮图标"}/>
14-
</>
15-
)
16-
}
87+
<Popover
88+
content={content}
89+
title="选择图标"
90+
trigger="click"
91+
placement="bottomLeft"
92+
>
93+
<Button>
94+
{value ? (
95+
<>
96+
<Icon type={value} style={{ marginRight: 8 }} />
97+
更换图标
98+
</>
99+
) : (
100+
'选择图标'
101+
)}
102+
</Button>
103+
</Popover>
104+
);
105+
};
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import React, {CSSProperties, lazy} from "react";
2+
3+
interface IconProps {
4+
type: string;
5+
style?: CSSProperties;
6+
}
7+
8+
// 动态导入图标的函数
9+
const loadIcon = (type: string) => {
10+
return lazy(() =>
11+
import("@ant-design/icons")
12+
.then(module => {
13+
//@ts-ignore
14+
const IconComponent = module[type];
15+
if (!IconComponent) {
16+
throw new Error(`Icon ${type} not found`);
17+
}
18+
return { default: IconComponent };
19+
})
20+
);
21+
};
22+
23+
export const Icon: React.FC<IconProps> = ({ type, style }) => {
24+
const [IconComponent, setIconComponent] = React.useState<React.ComponentType<any> | null>(null);
25+
const [error, setError] = React.useState(false);
26+
27+
React.useEffect(() => {
28+
let mounted = true;
29+
setError(false);
30+
31+
// 动态导入图标
32+
import("@ant-design/icons")
33+
.then(module => {
34+
//@ts-ignore
35+
if (mounted && module[type]) {
36+
//@ts-ignore
37+
setIconComponent(() => module[type]);
38+
} else if (mounted) {
39+
setError(true);
40+
}
41+
})
42+
.catch(() => {
43+
if (mounted) setError(true);
44+
});
45+
46+
return () => {
47+
mounted = false;
48+
};
49+
}, [type]);
50+
51+
if (error) {
52+
console.warn(`Icon ${type} not found`);
53+
return null;
54+
}
55+
56+
if (!IconComponent) {
57+
return <div style={style}>Loading...</div>;
58+
}
59+
60+
return <IconComponent style={style} />;
61+
};

frontend/packages/flow-pc/flow-pc-ui/src/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@ export * from '@/components/drawer';
22
export * from '@/components/panel';
33
export * from '@/components/table';
44
export * from '@/components/card-from';
5-
export * from '@/components/text';
5+
export * from '@/components/text';
6+
export * from '@/components/icon';

0 commit comments

Comments
 (0)