Task 12 - 患者管理: - PatientList: 搜索+状态筛选+CRUD+行点击跳转详情 - PatientTagManage: 患者标签管理+批量打标 - PatientDetail: 3Tab详情页(基本信息/健康数据/随访记录)+编辑 Task 13 - 医护预约: - DoctorList: 科室筛选+CRUD+在线状态Badge - AppointmentList: 状态筛选+日期筛选+创建预约+状态流转 - DoctorSchedule: 医生选择+列表/日历视图+排班CRUD Task 14 - 随访咨询: - FollowUpTaskList: 任务CRUD+填写记录+分配医护 - FollowUpRecordList: 只读台账+日期范围筛选+导出 - ConsultationList: 会话列表+创建+关闭+行点击跳转 - ConsultationDetail: 聊天界面+消息分页+发送+图片预览 修正: consultations.ts Session类型补充 updated_at/version
75 lines
2.0 KiB
TypeScript
75 lines
2.0 KiB
TypeScript
import { Avatar, Typography } from 'antd';
|
|
import { UserOutlined } from '@ant-design/icons';
|
|
|
|
interface Props {
|
|
senderRole: 'patient' | 'doctor' | 'system';
|
|
senderName?: string;
|
|
content: string;
|
|
contentType?: string;
|
|
createdAt: string;
|
|
}
|
|
|
|
const ROLE_CONFIG = {
|
|
patient: { align: 'flex-start' as const, bg: '#f0f0f0', color: '#000' },
|
|
doctor: { align: 'flex-end' as const, bg: '#1890ff', color: '#fff' },
|
|
system: { align: 'center' as const, bg: '#fafafa', color: '#999' },
|
|
};
|
|
|
|
export function ChatBubble({
|
|
senderRole,
|
|
senderName,
|
|
content,
|
|
createdAt,
|
|
}: Props) {
|
|
const cfg = ROLE_CONFIG[senderRole] ?? ROLE_CONFIG.system;
|
|
|
|
if (senderRole === 'system') {
|
|
return (
|
|
<div style={{ textAlign: 'center', padding: '8px 0' }}>
|
|
<Typography.Text type="secondary" style={{ fontSize: 12 }}>
|
|
{content}
|
|
</Typography.Text>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div style={{ display: 'flex', justifyContent: cfg.align, marginBottom: 12 }}>
|
|
{senderRole === 'patient' && (
|
|
<Avatar icon={<UserOutlined />} style={{ marginRight: 8, flexShrink: 0 }} />
|
|
)}
|
|
<div style={{ maxWidth: '70%' }}>
|
|
{senderName && (
|
|
<Typography.Text
|
|
type="secondary"
|
|
style={{ fontSize: 12, display: 'block', marginBottom: 2 }}
|
|
>
|
|
{senderName}
|
|
</Typography.Text>
|
|
)}
|
|
<div
|
|
style={{
|
|
background: cfg.bg,
|
|
color: cfg.color,
|
|
padding: '8px 12px',
|
|
borderRadius: 8,
|
|
wordBreak: 'break-word',
|
|
}}
|
|
>
|
|
<Typography.Paragraph
|
|
style={{ margin: 0, color: 'inherit' }}
|
|
>
|
|
{content}
|
|
</Typography.Paragraph>
|
|
</div>
|
|
<Typography.Text type="secondary" style={{ fontSize: 11 }}>
|
|
{createdAt}
|
|
</Typography.Text>
|
|
</div>
|
|
{senderRole === 'doctor' && (
|
|
<Avatar icon={<UserOutlined />} style={{ marginLeft: 8, flexShrink: 0 }} />
|
|
)}
|
|
</div>
|
|
);
|
|
}
|