Files
MuMuAINovel/frontend/src/components/CharacterCard.tsx
T

173 lines
6.2 KiB
TypeScript
Raw Normal View History

2025-10-30 11:14:43 +08:00
import { Card, Space, Tag, Typography, Popconfirm } from 'antd';
import { EditOutlined, DeleteOutlined, UserOutlined, BankOutlined } from '@ant-design/icons';
import { cardStyles } from './CardStyles';
import type { Character } from '../types';
const { Text, Paragraph } = Typography;
interface CharacterCardProps {
character: Character;
onEdit?: (character: Character) => void;
onDelete: (id: string) => void;
}
export const CharacterCard: React.FC<CharacterCardProps> = ({ character, onEdit, onDelete }) => {
const getRoleTypeColor = (roleType?: string) => {
const roleColors: Record<string, string> = {
'protagonist': 'blue',
'supporting': 'green',
'antagonist': 'red',
};
return roleColors[roleType || ''] || 'default';
};
const getRoleTypeLabel = (roleType?: string) => {
const roleLabels: Record<string, string> = {
'protagonist': '主角',
'supporting': '配角',
'antagonist': '反派',
};
return roleLabels[roleType || ''] || '其他';
};
const isOrganization = character.is_organization;
return (
<Card
hoverable
style={isOrganization ? cardStyles.organization : cardStyles.character}
styles={{
body: {
flex: 1,
overflow: 'auto',
display: 'flex',
flexDirection: 'column'
},
actions: {
borderRadius: '0 0 12px 12px'
}
}}
actions={[
...(onEdit ? [<EditOutlined key="edit" onClick={() => onEdit(character)} />] : []),
<Popconfirm
key="delete"
title={`确定删除这个${isOrganization ? '组织' : '角色'}吗?`}
onConfirm={() => onDelete(character.id)}
okText="确定"
cancelText="取消"
>
<DeleteOutlined />
</Popconfirm>,
]}
>
<Card.Meta
avatar={
isOrganization ? (
<BankOutlined style={{ fontSize: 32, color: '#52c41a' }} />
) : (
<UserOutlined style={{ fontSize: 32, color: '#1890ff' }} />
)
}
title={
<Space>
<span style={cardStyles.ellipsis}>{character.name}</span>
{isOrganization ? (
<Tag color="green"></Tag>
) : (
character.role_type && (
<Tag color={getRoleTypeColor(character.role_type)}>
{getRoleTypeLabel(character.role_type)}
</Tag>
)
)}
</Space>
}
description={
<div style={cardStyles.description}>
{/* 角色特有字段 */}
{!isOrganization && (
<>
{character.age && (
<div style={{ marginBottom: 8, display: 'flex', alignItems: 'flex-start' }}>
<Text type="secondary" style={{ flexShrink: 0 }}></Text>
<Text style={{ flex: 1 }}>{character.age}</Text>
</div>
)}
{character.gender && (
<div style={{ marginBottom: 8, display: 'flex', alignItems: 'flex-start' }}>
<Text type="secondary" style={{ flexShrink: 0 }}></Text>
<Text style={{ flex: 1 }}>{character.gender}</Text>
</div>
)}
{character.personality && (
<div style={{ marginBottom: 8, display: 'flex', alignItems: 'flex-start' }}>
<Text type="secondary" style={{ flexShrink: 0 }}></Text>
<Text
style={{ flex: 1, minWidth: 0 }}
ellipsis={{ tooltip: character.personality }}
>
{character.personality}
</Text>
</div>
)}
</>
)}
{/* 组织特有字段 */}
{isOrganization && (
<>
{character.organization_type && (
<div style={{ marginBottom: 8, display: 'flex', alignItems: 'center' }}>
<Text type="secondary" style={{ flexShrink: 0 }}></Text>
<Tag color="cyan">{character.organization_type}</Tag>
</div>
)}
{character.organization_purpose && (
<div style={{ marginBottom: 8, display: 'flex', alignItems: 'flex-start' }}>
<Text type="secondary" style={{ flexShrink: 0 }}></Text>
<Text
style={{ flex: 1, minWidth: 0 }}
ellipsis={{ tooltip: character.organization_purpose }}
>
{character.organization_purpose}
</Text>
</div>
)}
{character.organization_members && (
<div style={{ marginBottom: 8, display: 'flex', alignItems: 'flex-start' }}>
<Text type="secondary" style={{ flexShrink: 0 }}></Text>
<Text
style={{ flex: 1, minWidth: 0 }}
ellipsis={{
tooltip: typeof character.organization_members === 'string'
? character.organization_members
: JSON.stringify(character.organization_members)
}}
>
{typeof character.organization_members === 'string'
? character.organization_members
: JSON.stringify(character.organization_members)}
</Text>
</div>
)}
</>
)}
{/* 通用字段 - 背景信息截断显示 */}
{character.background && (
<div style={{ marginTop: 12 }}>
<Paragraph
type="secondary"
style={{ fontSize: 12, marginBottom: 0 }}
ellipsis={{ tooltip: character.background, rows: 3 }}
>
{character.background}
</Paragraph>
</div>
)}
</div>
}
/>
</Card>
);
};