2025-10-18 14:31:34 +08:00

353 lines
9.3 KiB
TypeScript

import React, { useState } from 'react';
import Box from '@mui/material/Box';
import TextField from '@mui/material/TextField';
import { IconButton, SxProps } from '@mui/material';
import AddIcon from '@mui/icons-material/Add';
import Divider from '@mui/material/Divider';
import RemoveIcon from '@mui/icons-material/Remove';
import AdjustIcon from '@mui/icons-material/Adjust';
import { ObjectProps, ProcessProps } from './interface';
import AgentIcon from '@/components/AgentIcon';
import DescriptionCard from '@/components/ProcessDiscription/DescriptionCard';
import { globalStorage } from '@/storage';
export interface IEditObjectProps {
finishEdit: (objectName: string) => void;
}
export const EditObjectCard: React.FC<IEditObjectProps> = React.memo(
({ finishEdit }) => {
const handleKeyPress = (event: any) => {
if (event.key === 'Enter') {
finishEdit(event.target.value);
}
};
return (
<TextField
onKeyPress={handleKeyPress}
sx={{
backgroundColor: '#D9D9D9',
borderRadius: '6px',
padding: '8px',
userSelect: 'none',
margin: '6px 0px',
}}
/>
);
},
);
interface IHoverIconButtonProps {
onAddClick: () => void;
isActive: boolean;
style: SxProps;
responseToHover?: boolean;
addOrRemove: boolean | undefined; // true for add, false for remove,undefined for adjust
}
const HoverIconButton: React.FC<IHoverIconButtonProps> = ({
onAddClick,
isActive,
style,
addOrRemove,
responseToHover = true,
}) => {
const [addIconHover, setAddIconHover] = useState(false);
return (
<Box
onMouseOver={() => {
setAddIconHover(true);
}}
onMouseOut={() => {
setAddIconHover(false);
}}
onClick={() => {
onAddClick();
}}
sx={{ ...style, justifySelf: 'start' }}
>
<IconButton
sx={{
color: 'primary',
'&:hover': {
color: 'primary.dark',
},
padding: '0px',
borderRadius: 10,
border: '1px dotted #333',
visibility:
(responseToHover && addIconHover) || isActive
? 'visible'
: 'hidden',
'& .MuiSvgIcon-root': {
fontSize: '1.25rem',
},
}}
>
{addOrRemove === undefined ? <AdjustIcon /> : <></>}
{addOrRemove === true ? <AddIcon /> : <></>}
{addOrRemove === false ? <RemoveIcon /> : <></>}
</IconButton>
</Box>
);
};
interface IEditableBoxProps {
text: string;
inputCallback: (text: string) => void;
}
const EditableBox: React.FC<IEditableBoxProps> = ({ text, inputCallback }) => {
const [isEditable, setIsEditable] = useState(false);
const handleDoubleClick = () => {
setIsEditable(true);
};
const handleKeyPress = (event: any) => {
if (event.key === 'Enter') {
inputCallback(event.target.value);
setIsEditable(false);
}
};
return (
<Box>
{isEditable ? (
<TextField
defaultValue={text}
multiline
onKeyPress={handleKeyPress}
onBlur={() => setIsEditable(false)} // 失去焦点时也关闭编辑状态
autoFocus
sx={{
'& .MuiInputBase-root': {
// 目标 MUI 的输入基础根元素
padding: '0px 0px', // 你可以设置为你希望的内边距值
},
width: '100%',
}}
/>
) : (
<span
onDoubleClick={handleDoubleClick}
style={{
color: '#707070',
// textDecoration: 'underline',
// textDecorationColor: '#C1C1C1',
borderBottom: '1.5px solid #C1C1C1',
fontSize: '15px',
}}
>
{text}
</span>
)}
</Box>
);
};
export interface IObjectCardProps {
object: ObjectProps;
isAddActive?: boolean;
handleAddActive?: (objectName: string) => void;
addOrRemove?: boolean;
}
export const ObjectCard = React.memo<IObjectCardProps>(
({
object,
isAddActive = false,
handleAddActive = (objectName: string) => {
console.log(objectName);
},
addOrRemove = true,
}) => {
const onAddClick = () => {
handleAddActive(object.name);
};
return (
<Box
sx={{
position: 'relative',
// maxWidth: '100%',
}}
>
<HoverIconButton
style={{
position: 'absolute',
left: '100%',
top: '50%',
transform: 'translateY(-50%)translateX(-50%)',
}}
onAddClick={onAddClick}
isActive={isAddActive}
responseToHover={false}
addOrRemove={addOrRemove}
/>
<Box
ref={object.cardRef}
sx={{
backgroundColor: '#F6F6F6',
borderRadius: '15px',
border: '2px solid #E5E5E5',
padding: '10px 4px',
userSelect: 'none',
margin: '12px 0px',
maxWidth: '100%',
wordWrap: 'break-word',
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
fontSize: '16px',
fontWeight: 800,
textAlign: 'center',
color: '#222',
}}
>
{object.name}
</Box>
</Box>
);
},
);
export interface IProcessCardProps {
process: ProcessProps;
handleProcessClick: (stepId: string) => void;
isFocusing: boolean;
isAddActive?: boolean;
handleAddActive?: (objectName: string) => void;
handleEditContent: (stepTaskId: string, newContent: string) => void;
// handleSizeChange: () => void;
}
export const ProcessCard: React.FC<IProcessCardProps> = React.memo(
({
process,
handleProcessClick,
isFocusing,
isAddActive = false,
handleAddActive = (objectName: string) => {
console.log(objectName);
},
// handleSizeChange,
handleEditContent,
}) => {
const onAddClick = () => {
handleAddActive(process.id);
};
return (
<Box
sx={{
position: 'relative',
// width: '100%',
}}
>
<HoverIconButton
style={{
position: 'absolute',
left: '0',
top: '50%',
transform: 'translateY(-50%)translateX(-50%)',
}}
onAddClick={onAddClick}
isActive={isAddActive}
addOrRemove={undefined}
/>
<Box
ref={process.cardRef}
sx={{
backgroundColor: '#F6F6F6',
borderRadius: '15px',
padding: '8px',
margin: '18px 0px',
userSelect: 'none',
cursor: 'pointer',
border: isFocusing ? '2px solid #43b2aa' : '2px solid #E5E5E5',
transition: 'all 80ms ease-in-out',
'&:hover': {
border: isFocusing ? '2px solid #03a89d' : '2px solid #b3b3b3',
backgroundImage: 'linear-gradient(0, #0001, #0001)',
},
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
}}
onClick={() => handleProcessClick(process.id)}
>
<Box
sx={{
fontSize: '16px',
fontWeight: 800,
textAlign: 'center',
color: '#222',
marginTop: '4px',
marginBottom: '4px',
}}
>
{process.name}
</Box>
{/* Assuming AgentIcon is another component */}
<Box
sx={{
display: 'flex',
alignItems: 'center',
width: '100%',
justifyContent: 'center',
flexWrap: 'wrap',
margin: '8px 0',
}}
>
{process.agents.map(agentName => (
<AgentIcon
key={`outline.${process.name}.${agentName}`}
name={globalStorage.agentMap.get(agentName)?.icon ?? 'unknown'}
style={{
width: '40px',
height: 'auto',
marginRight: '3px',
userSelect: 'none',
}}
tooltipInfo={globalStorage.agentMap.get(agentName)}
/>
))}
</Box>
{isFocusing && (
<Box onClick={e => e.stopPropagation()}>
<Divider
sx={{
margin: '5px 0px',
borderBottom: '2px dashed', // 设置为虚线
borderColor: '#d4d4d4',
}}
/>
<EditableBox
text={process.content}
inputCallback={(text: string) => {
handleEditContent(process.id, text);
// handleEditStep(step.name, { ...step, task: text });
}}
/>
{/* 这里直接渲染对应的 DescriptionCard */}
{/* {(() => {
const step = globalStorage.planManager.currentPlan.find(
s => s.id === process.id
);
return step ? <DescriptionCard step={step} /> : null;
})()} */}
</Box>
)}
</Box>
</Box>
);
},
);
const Card: React.FC = React.memo(() => {
return <></>; // Replace with your component JSX
});
export default Card;