feat: 更新 CoachScreen 和欢迎消息生成逻辑
- 在 CoachScreen 中优化欢迎消息的生成,整合用户配置文件数据,支持选择选项和表情 - 更新欢迎消息生成函数,返回包含内容、选择和交互类型的结构 - 在多个组件中调整样式,提升用户体验和界面一致性 - 在 Statistics 组件中添加记录更新时间,确保数据展示的准确性 - 在 FitnessRingsCard 中修正卡路里和运动时间的显示,确保数值四舍五入
This commit is contained in:
@@ -65,6 +65,7 @@ type AiChoiceOption = {
|
||||
label: string;
|
||||
value: any;
|
||||
recommended?: boolean;
|
||||
emoji?: string;
|
||||
};
|
||||
|
||||
// 餐次类型
|
||||
@@ -256,13 +257,17 @@ export default function CoachScreen() {
|
||||
// 初始化欢迎消息
|
||||
const initializeWelcomeMessage = useCallback(() => {
|
||||
const { transformedUserProfile, paramsName, hasRecordedMoodTodayValue } = latestValuesRef.current;
|
||||
const welcomeData = generateWelcomeMessage({
|
||||
userProfile: transformedUserProfile,
|
||||
hasRecordedMoodToday: hasRecordedMoodTodayValue
|
||||
});
|
||||
|
||||
const welcomeMessage: ChatMessage = {
|
||||
id: 'm_welcome',
|
||||
role: 'assistant',
|
||||
content: generateWelcomeMessage({
|
||||
userProfile: transformedUserProfile,
|
||||
hasRecordedMoodToday: hasRecordedMoodTodayValue
|
||||
}),
|
||||
content: welcomeData.content,
|
||||
choices: welcomeData.choices,
|
||||
interactionType: welcomeData.interactionType,
|
||||
};
|
||||
setMessages([welcomeMessage]);
|
||||
}, []); // 空依赖项,通过 ref 获取最新值
|
||||
@@ -402,7 +407,7 @@ export default function CoachScreen() {
|
||||
useEffect(() => {
|
||||
// 确保用户已登录且消息已加载
|
||||
if (!isLoggedIn || messages.length === 0) return;
|
||||
|
||||
|
||||
// 检查是否有动作参数
|
||||
if (params.action) {
|
||||
const executeAction = async () => {
|
||||
@@ -419,7 +424,7 @@ export default function CoachScreen() {
|
||||
await sendStream(message);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 'weight':
|
||||
if (params.subAction === 'card') {
|
||||
// 插入体重记录卡片
|
||||
@@ -430,12 +435,12 @@ export default function CoachScreen() {
|
||||
await sendStream(message);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 'mood':
|
||||
// 跳转到心情记录页面
|
||||
pushIfAuthedElseLogin('/mood/calendar');
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
console.warn('未知的动作类型:', params.action);
|
||||
}
|
||||
@@ -573,14 +578,21 @@ export default function CoachScreen() {
|
||||
attachments: undefined,
|
||||
}));
|
||||
setConversationId(detail.conversationId);
|
||||
setMessages(mapped.length ? mapped : [{
|
||||
id: 'm_welcome',
|
||||
role: 'assistant',
|
||||
content: generateWelcomeMessage({
|
||||
if (mapped.length) {
|
||||
setMessages(mapped);
|
||||
} else {
|
||||
const welcomeData = generateWelcomeMessage({
|
||||
userProfile: transformedUserProfile,
|
||||
hasRecordedMoodToday: hasRecordedMoodTodayValue
|
||||
})
|
||||
}]);
|
||||
});
|
||||
setMessages([{
|
||||
id: 'm_welcome',
|
||||
role: 'assistant',
|
||||
content: welcomeData.content,
|
||||
choices: welcomeData.choices,
|
||||
interactionType: welcomeData.interactionType,
|
||||
}]);
|
||||
}
|
||||
setHistoryVisible(false);
|
||||
setTimeout(scrollToEnd, 0);
|
||||
} catch (e) {
|
||||
@@ -597,13 +609,16 @@ export default function CoachScreen() {
|
||||
await deleteConversation(id);
|
||||
if (conversationId === id) {
|
||||
setConversationId(undefined);
|
||||
const welcomeData = generateWelcomeMessage({
|
||||
userProfile: transformedUserProfile,
|
||||
hasRecordedMoodToday: hasRecordedMoodTodayValue
|
||||
});
|
||||
setMessages([{
|
||||
id: 'm_welcome',
|
||||
role: 'assistant',
|
||||
content: generateWelcomeMessage({
|
||||
userProfile: transformedUserProfile,
|
||||
hasRecordedMoodToday: hasRecordedMoodTodayValue
|
||||
})
|
||||
content: welcomeData.content,
|
||||
choices: welcomeData.choices,
|
||||
interactionType: welcomeData.interactionType,
|
||||
}]);
|
||||
}
|
||||
await refreshHistory(historyPage);
|
||||
@@ -1501,9 +1516,9 @@ export default function CoachScreen() {
|
||||
}
|
||||
|
||||
// 检查是否有选择选项需要显示
|
||||
if (item.choices && item.choices.length > 0 && item.interactionType === 'food_confirmation') {
|
||||
if (item.choices && item.choices.length > 0 && (item.interactionType === 'food_confirmation' || item.interactionType === 'selection')) {
|
||||
return (
|
||||
<View style={{ gap: 12 }}>
|
||||
<View style={{ gap: 12, width: '100%' }}>
|
||||
<Markdown style={markdownStyles} mergeStyle>
|
||||
{item.content || ''}
|
||||
</Markdown>
|
||||
@@ -1533,14 +1548,19 @@ export default function CoachScreen() {
|
||||
}}
|
||||
>
|
||||
<View style={styles.choiceContent}>
|
||||
<Text style={[
|
||||
styles.choiceLabel,
|
||||
choice.recommended && styles.choiceLabelRecommended,
|
||||
isSelected && styles.choiceLabelSelected,
|
||||
isDisabled && styles.choiceLabelDisabled,
|
||||
]}>
|
||||
{choice.label}
|
||||
</Text>
|
||||
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 8, flex: 1 }}>
|
||||
{choice.emoji && (
|
||||
<Text style={{ fontSize: 16 }}>{choice.emoji}</Text>
|
||||
)}
|
||||
<Text style={[
|
||||
styles.choiceLabel,
|
||||
choice.recommended && styles.choiceLabelRecommended,
|
||||
isSelected && styles.choiceLabelSelected,
|
||||
isDisabled && styles.choiceLabelDisabled,
|
||||
]}>
|
||||
{choice.label}
|
||||
</Text>
|
||||
</View>
|
||||
<View style={styles.choiceStatusContainer}>
|
||||
{choice.recommended && !isSelected && (
|
||||
<View style={styles.recommendedBadge}>
|
||||
@@ -1811,7 +1831,7 @@ export default function CoachScreen() {
|
||||
setPendingChoiceConfirmation(prev => ({ ...prev, [message.id]: true }));
|
||||
|
||||
// 构建确认请求
|
||||
const confirmationText = `我选择记录${choice.label}`;
|
||||
const confirmationText = `${choice.label}`;
|
||||
|
||||
try {
|
||||
// 发送确认消息,包含选择的数据
|
||||
@@ -2644,6 +2664,7 @@ const styles = StyleSheet.create({
|
||||
// 选择选项相关样式
|
||||
choicesContainer: {
|
||||
gap: 8,
|
||||
width: '100%',
|
||||
},
|
||||
choiceButton: {
|
||||
backgroundColor: 'rgba(255,255,255,0.9)',
|
||||
@@ -2651,6 +2672,8 @@ const styles = StyleSheet.create({
|
||||
borderColor: '#7a5af84d', // 紫色主题 30% opacity
|
||||
borderRadius: 12,
|
||||
padding: 12,
|
||||
width: '100%',
|
||||
minWidth: 0,
|
||||
},
|
||||
choiceButtonRecommended: {
|
||||
borderColor: '#7a5af899', // 紫色主题 60% opacity
|
||||
@@ -2670,12 +2693,14 @@ const styles = StyleSheet.create({
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
width: '100%',
|
||||
},
|
||||
choiceLabel: {
|
||||
fontSize: 15,
|
||||
fontWeight: '600',
|
||||
color: '#192126',
|
||||
flex: 1,
|
||||
flexWrap: 'wrap',
|
||||
},
|
||||
choiceLabelRecommended: {
|
||||
color: '#19b36e', // success[500]
|
||||
|
||||
@@ -256,6 +256,7 @@ export default function ExploreScreen() {
|
||||
|
||||
if (data.records.length > 0) {
|
||||
const summary = calculateNutritionSummary(data.records);
|
||||
summary.updatedAt = data.records[0].updatedAt;
|
||||
setNutritionSummary(summary);
|
||||
} else {
|
||||
setNutritionSummary(null);
|
||||
|
||||
Reference in New Issue
Block a user