From 7e19534ef35b6a3b2a772f9e2b36f01584d2e42a Mon Sep 17 00:00:00 2001 From: 15945162479 <15945162479@qq.com> Date: Sat, 13 Dec 2025 14:46:21 +0800 Subject: [PATCH] Add File --- src/family/pages/FamilyMessages.tsx | 435 ++++++++++++++++++++++++++++ 1 file changed, 435 insertions(+) create mode 100644 src/family/pages/FamilyMessages.tsx diff --git a/src/family/pages/FamilyMessages.tsx b/src/family/pages/FamilyMessages.tsx new file mode 100644 index 0000000..f32f286 --- /dev/null +++ b/src/family/pages/FamilyMessages.tsx @@ -0,0 +1,435 @@ +import React, { useState, useEffect } from 'react'; +import { + Plus, + X, + Send, + Heart, + Trash2, + User, +} from 'lucide-react'; +import * as messageService from '../services/messageService'; + +type MessageType = 'text'; + +interface FamilyMessage { + id: string; + type: MessageType; + content: string; + sender: string; + senderRelation: string; // 留言人称呼(如:儿子、女儿、孙女等) + senderAvatar?: string; + timestamp: string; // 留言创建时间 + scheduledTime?: string; // 预约播报时间(家属指定) + played: boolean; + playedAt?: string; // 实际播报时间(系统记录) + liked: boolean; +} + +/** + * 家属留言页面 + * 家属可以给老人留文字留言 + * 老人端会播放这些留言 + */ +export const FamilyMessages: React.FC = () => { + const [showComposer, setShowComposer] = useState(false); + const [messageContent, setMessageContent] = useState(''); + const [senderName, setSenderName] = useState(''); + const [senderRelation, setSenderRelation] = useState(''); + const [scheduledTime, setScheduledTime] = useState(''); + const [messages, setMessages] = useState([]); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + + const FAMILY_ID = 'family_001'; // 暂时硬编码,后续可从用户登录信息获取 + + // 加载留言列表 + const loadMessages = async () => { + try { + setLoading(true); + setError(null); + const data = await messageService.getFamilyMessages(FAMILY_ID); + + // 转换后端数据格式为前端格式 + const formattedMessages: FamilyMessage[] = data.map((msg) => ({ + id: String(msg.id), + type: 'text' as MessageType, + content: msg.content, + sender: msg.sender_name, + senderRelation: msg.sender_relation, + timestamp: messageService.formatDateTime(msg.created_at), + scheduledTime: messageService.formatDateTime(msg.scheduled_time), + played: msg.played, + playedAt: msg.played_at ? messageService.formatDateTime(msg.played_at) : undefined, + liked: msg.liked, + })); + + setMessages(formattedMessages); + } catch (err) { + console.error('加载留言失败:', err); + setError('加载留言失败,请稍后重试'); + } finally { + setLoading(false); + } + }; + + // 组件挂载时加载留言 + useEffect(() => { + loadMessages(); + }, []); + + const handleSendMessage = async () => { + if (!messageContent.trim()) { + alert('请输入留言内容'); + return; + } + if (!senderName.trim()) { + alert('请输入您的姓名'); + return; + } + if (!senderRelation) { + alert('请选择您与老人的关系'); + return; + } + if (!scheduledTime) { + alert('请选择播报时间'); + return; + } + + try { + setLoading(true); + await messageService.createMessage({ + family_id: FAMILY_ID, + content: messageContent, + sender_name: senderName, + sender_relation: senderRelation, + scheduled_time: scheduledTime, + }); + + // 发送成功,重新加载列表 + await loadMessages(); + + // 清空表单 + setMessageContent(''); + setSenderName(''); + setSenderRelation(''); + setScheduledTime(''); + setShowComposer(false); + } catch (err) { + console.error('发送留言失败:', err); + alert('发送留言失败,请稍后重试'); + } finally { + setLoading(false); + } + }; + + const handleDelete = async (msgId: string) => { + if (!confirm('确定要删除这条留言吗?')) { + return; + } + + try { + setLoading(true); + await messageService.deleteMessage(Number(msgId)); + + // 删除成功,重新加载列表 + await loadMessages(); + + alert('留言删除成功'); + } catch (err) { + console.error('删除留言失败:', err); + alert('删除留言失败,请稍后重试'); + } finally { + setLoading(false); + } + }; + + return ( +
+ {/* 顶部导航 */} +
+
+
+
+

家属留言

+

+ 给老人发送温馨留言 +

+
+ +
+
+
+ + {/* 错误提示 */} + {error && ( +
+ {error} +
+ )} + + {/* 留言列表 */} +
+ {/* 加载状态 */} + {loading && messages.length === 0 && ( +
+

加载中...

+
+ )} + + {/* 统计卡片 */} + {!loading && messages.length > 0 && ( +
+
+
+ {messages.length} +
+
总留言
+
+
+
+ {messages.filter((m) => m.played).length} +
+
已播放
+
+
+
+ {messages.filter((m) => m.liked).length} +
+
老人点赞
+
+
+ )} + + {/* 留言卡片列表 */} + {!loading && messages.length > 0 && ( +
+ {messages.map((msg) => ( +
+ {/* 头部:发件人信息 */} +
+
+
+ +
+
+
+ {msg.sender} + {msg.senderRelation && ( + + ({msg.senderRelation}) + + )} +
+
+ {msg.timestamp} +
+
+
+ + {/* 操作按钮 */} +
+ +
+
+ + {/* 留言内容 */} +
+
+

{msg.content}

+
+
+ + {/* 底部:状态标签和时间信息 */} +
+ {/* 预约播报时间 */} + {msg.scheduledTime && ( +
+ ⏰ 预约播报:{msg.scheduledTime} +
+ )} + + {/* 状态标签 */} +
+ + {msg.played ? '✓ 已播放' : '未播放'} + + {msg.liked && ( + + + 老人喜欢 + + )} +
+ + {/* 实际播报时间 */} + {msg.played && msg.playedAt && ( +
+ 🔊 实际播报:{msg.playedAt} +
+ )} +
+
+ ))} +
+ )} + + {/* 空状态 */} + {!loading && messages.length === 0 && ( +
+

还没有留言

+ +
+ )} +
+ + {/* 留言编辑器弹窗 */} + {showComposer && ( +
+
+ {/* 头部 */} +
+

发送留言

+ +
+ + {/* 内容区 */} +
+ {/* 发送者姓名 */} +
+ + setSenderName(e.target.value)} + placeholder="请输入您的姓名" + className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent" + maxLength={20} + /> +
+ + {/* 称呼选择(卡片式) */} +
+ +
+ {[ + { value: '儿子', icon: '👨' }, + { value: '女儿', icon: '👩' }, + { value: '孙子', icon: '👦' }, + { value: '孙女', icon: '👧' }, + { value: '外孙', icon: '👦' }, + { value: '外孙女', icon: '👧' }, + { value: '女婿', icon: '🤵' }, + { value: '儿媳', icon: '👰' }, + { value: '侄子', icon: '👨‍🦱' }, + { value: '侄女', icon: '👩‍🦱' }, + { value: '其他', icon: '👤' }, + ].map((relation) => ( + + ))} +
+
+ + {/* 播报时间 */} +
+ + setScheduledTime(e.target.value)} + className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent" + /> +

+ ⏰ 留言将在指定时间播报给老人 +

+
+ + {/* 文字输入 */} +
+ +