feat: 更新 CoachScreen 和欢迎消息生成逻辑
- 在 CoachScreen 中优化欢迎消息的生成,整合用户配置文件数据,支持选择选项和表情 - 更新欢迎消息生成函数,返回包含内容、选择和交互类型的结构 - 在多个组件中调整样式,提升用户体验和界面一致性 - 在 Statistics 组件中添加记录更新时间,确保数据展示的准确性 - 在 FitnessRingsCard 中修正卡路里和运动时间的显示,确保数值四舍五入
This commit is contained in:
@@ -65,6 +65,7 @@ type AiChoiceOption = {
|
|||||||
label: string;
|
label: string;
|
||||||
value: any;
|
value: any;
|
||||||
recommended?: boolean;
|
recommended?: boolean;
|
||||||
|
emoji?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 餐次类型
|
// 餐次类型
|
||||||
@@ -256,13 +257,17 @@ export default function CoachScreen() {
|
|||||||
// 初始化欢迎消息
|
// 初始化欢迎消息
|
||||||
const initializeWelcomeMessage = useCallback(() => {
|
const initializeWelcomeMessage = useCallback(() => {
|
||||||
const { transformedUserProfile, paramsName, hasRecordedMoodTodayValue } = latestValuesRef.current;
|
const { transformedUserProfile, paramsName, hasRecordedMoodTodayValue } = latestValuesRef.current;
|
||||||
|
const welcomeData = generateWelcomeMessage({
|
||||||
|
userProfile: transformedUserProfile,
|
||||||
|
hasRecordedMoodToday: hasRecordedMoodTodayValue
|
||||||
|
});
|
||||||
|
|
||||||
const welcomeMessage: ChatMessage = {
|
const welcomeMessage: ChatMessage = {
|
||||||
id: 'm_welcome',
|
id: 'm_welcome',
|
||||||
role: 'assistant',
|
role: 'assistant',
|
||||||
content: generateWelcomeMessage({
|
content: welcomeData.content,
|
||||||
userProfile: transformedUserProfile,
|
choices: welcomeData.choices,
|
||||||
hasRecordedMoodToday: hasRecordedMoodTodayValue
|
interactionType: welcomeData.interactionType,
|
||||||
}),
|
|
||||||
};
|
};
|
||||||
setMessages([welcomeMessage]);
|
setMessages([welcomeMessage]);
|
||||||
}, []); // 空依赖项,通过 ref 获取最新值
|
}, []); // 空依赖项,通过 ref 获取最新值
|
||||||
@@ -402,7 +407,7 @@ export default function CoachScreen() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// 确保用户已登录且消息已加载
|
// 确保用户已登录且消息已加载
|
||||||
if (!isLoggedIn || messages.length === 0) return;
|
if (!isLoggedIn || messages.length === 0) return;
|
||||||
|
|
||||||
// 检查是否有动作参数
|
// 检查是否有动作参数
|
||||||
if (params.action) {
|
if (params.action) {
|
||||||
const executeAction = async () => {
|
const executeAction = async () => {
|
||||||
@@ -419,7 +424,7 @@ export default function CoachScreen() {
|
|||||||
await sendStream(message);
|
await sendStream(message);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'weight':
|
case 'weight':
|
||||||
if (params.subAction === 'card') {
|
if (params.subAction === 'card') {
|
||||||
// 插入体重记录卡片
|
// 插入体重记录卡片
|
||||||
@@ -430,12 +435,12 @@ export default function CoachScreen() {
|
|||||||
await sendStream(message);
|
await sendStream(message);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'mood':
|
case 'mood':
|
||||||
// 跳转到心情记录页面
|
// 跳转到心情记录页面
|
||||||
pushIfAuthedElseLogin('/mood/calendar');
|
pushIfAuthedElseLogin('/mood/calendar');
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
console.warn('未知的动作类型:', params.action);
|
console.warn('未知的动作类型:', params.action);
|
||||||
}
|
}
|
||||||
@@ -573,14 +578,21 @@ export default function CoachScreen() {
|
|||||||
attachments: undefined,
|
attachments: undefined,
|
||||||
}));
|
}));
|
||||||
setConversationId(detail.conversationId);
|
setConversationId(detail.conversationId);
|
||||||
setMessages(mapped.length ? mapped : [{
|
if (mapped.length) {
|
||||||
id: 'm_welcome',
|
setMessages(mapped);
|
||||||
role: 'assistant',
|
} else {
|
||||||
content: generateWelcomeMessage({
|
const welcomeData = generateWelcomeMessage({
|
||||||
userProfile: transformedUserProfile,
|
userProfile: transformedUserProfile,
|
||||||
hasRecordedMoodToday: hasRecordedMoodTodayValue
|
hasRecordedMoodToday: hasRecordedMoodTodayValue
|
||||||
})
|
});
|
||||||
}]);
|
setMessages([{
|
||||||
|
id: 'm_welcome',
|
||||||
|
role: 'assistant',
|
||||||
|
content: welcomeData.content,
|
||||||
|
choices: welcomeData.choices,
|
||||||
|
interactionType: welcomeData.interactionType,
|
||||||
|
}]);
|
||||||
|
}
|
||||||
setHistoryVisible(false);
|
setHistoryVisible(false);
|
||||||
setTimeout(scrollToEnd, 0);
|
setTimeout(scrollToEnd, 0);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -597,13 +609,16 @@ export default function CoachScreen() {
|
|||||||
await deleteConversation(id);
|
await deleteConversation(id);
|
||||||
if (conversationId === id) {
|
if (conversationId === id) {
|
||||||
setConversationId(undefined);
|
setConversationId(undefined);
|
||||||
|
const welcomeData = generateWelcomeMessage({
|
||||||
|
userProfile: transformedUserProfile,
|
||||||
|
hasRecordedMoodToday: hasRecordedMoodTodayValue
|
||||||
|
});
|
||||||
setMessages([{
|
setMessages([{
|
||||||
id: 'm_welcome',
|
id: 'm_welcome',
|
||||||
role: 'assistant',
|
role: 'assistant',
|
||||||
content: generateWelcomeMessage({
|
content: welcomeData.content,
|
||||||
userProfile: transformedUserProfile,
|
choices: welcomeData.choices,
|
||||||
hasRecordedMoodToday: hasRecordedMoodTodayValue
|
interactionType: welcomeData.interactionType,
|
||||||
})
|
|
||||||
}]);
|
}]);
|
||||||
}
|
}
|
||||||
await refreshHistory(historyPage);
|
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 (
|
return (
|
||||||
<View style={{ gap: 12 }}>
|
<View style={{ gap: 12, width: '100%' }}>
|
||||||
<Markdown style={markdownStyles} mergeStyle>
|
<Markdown style={markdownStyles} mergeStyle>
|
||||||
{item.content || ''}
|
{item.content || ''}
|
||||||
</Markdown>
|
</Markdown>
|
||||||
@@ -1533,14 +1548,19 @@ export default function CoachScreen() {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<View style={styles.choiceContent}>
|
<View style={styles.choiceContent}>
|
||||||
<Text style={[
|
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 8, flex: 1 }}>
|
||||||
styles.choiceLabel,
|
{choice.emoji && (
|
||||||
choice.recommended && styles.choiceLabelRecommended,
|
<Text style={{ fontSize: 16 }}>{choice.emoji}</Text>
|
||||||
isSelected && styles.choiceLabelSelected,
|
)}
|
||||||
isDisabled && styles.choiceLabelDisabled,
|
<Text style={[
|
||||||
]}>
|
styles.choiceLabel,
|
||||||
{choice.label}
|
choice.recommended && styles.choiceLabelRecommended,
|
||||||
</Text>
|
isSelected && styles.choiceLabelSelected,
|
||||||
|
isDisabled && styles.choiceLabelDisabled,
|
||||||
|
]}>
|
||||||
|
{choice.label}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
<View style={styles.choiceStatusContainer}>
|
<View style={styles.choiceStatusContainer}>
|
||||||
{choice.recommended && !isSelected && (
|
{choice.recommended && !isSelected && (
|
||||||
<View style={styles.recommendedBadge}>
|
<View style={styles.recommendedBadge}>
|
||||||
@@ -1811,7 +1831,7 @@ export default function CoachScreen() {
|
|||||||
setPendingChoiceConfirmation(prev => ({ ...prev, [message.id]: true }));
|
setPendingChoiceConfirmation(prev => ({ ...prev, [message.id]: true }));
|
||||||
|
|
||||||
// 构建确认请求
|
// 构建确认请求
|
||||||
const confirmationText = `我选择记录${choice.label}`;
|
const confirmationText = `${choice.label}`;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 发送确认消息,包含选择的数据
|
// 发送确认消息,包含选择的数据
|
||||||
@@ -2644,6 +2664,7 @@ const styles = StyleSheet.create({
|
|||||||
// 选择选项相关样式
|
// 选择选项相关样式
|
||||||
choicesContainer: {
|
choicesContainer: {
|
||||||
gap: 8,
|
gap: 8,
|
||||||
|
width: '100%',
|
||||||
},
|
},
|
||||||
choiceButton: {
|
choiceButton: {
|
||||||
backgroundColor: 'rgba(255,255,255,0.9)',
|
backgroundColor: 'rgba(255,255,255,0.9)',
|
||||||
@@ -2651,6 +2672,8 @@ const styles = StyleSheet.create({
|
|||||||
borderColor: '#7a5af84d', // 紫色主题 30% opacity
|
borderColor: '#7a5af84d', // 紫色主题 30% opacity
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
padding: 12,
|
padding: 12,
|
||||||
|
width: '100%',
|
||||||
|
minWidth: 0,
|
||||||
},
|
},
|
||||||
choiceButtonRecommended: {
|
choiceButtonRecommended: {
|
||||||
borderColor: '#7a5af899', // 紫色主题 60% opacity
|
borderColor: '#7a5af899', // 紫色主题 60% opacity
|
||||||
@@ -2670,12 +2693,14 @@ const styles = StyleSheet.create({
|
|||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
|
width: '100%',
|
||||||
},
|
},
|
||||||
choiceLabel: {
|
choiceLabel: {
|
||||||
fontSize: 15,
|
fontSize: 15,
|
||||||
fontWeight: '600',
|
fontWeight: '600',
|
||||||
color: '#192126',
|
color: '#192126',
|
||||||
flex: 1,
|
flex: 1,
|
||||||
|
flexWrap: 'wrap',
|
||||||
},
|
},
|
||||||
choiceLabelRecommended: {
|
choiceLabelRecommended: {
|
||||||
color: '#19b36e', // success[500]
|
color: '#19b36e', // success[500]
|
||||||
|
|||||||
@@ -256,6 +256,7 @@ export default function ExploreScreen() {
|
|||||||
|
|
||||||
if (data.records.length > 0) {
|
if (data.records.length > 0) {
|
||||||
const summary = calculateNutritionSummary(data.records);
|
const summary = calculateNutritionSummary(data.records);
|
||||||
|
summary.updatedAt = data.records[0].updatedAt;
|
||||||
setNutritionSummary(summary);
|
setNutritionSummary(summary);
|
||||||
} else {
|
} else {
|
||||||
setNutritionSummary(null);
|
setNutritionSummary(null);
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ export function FitnessRingsCard({
|
|||||||
<View style={styles.dataContainer}>
|
<View style={styles.dataContainer}>
|
||||||
<View style={styles.dataRow}>
|
<View style={styles.dataRow}>
|
||||||
<Text style={styles.dataText}>
|
<Text style={styles.dataText}>
|
||||||
<Text style={styles.dataValue}>{activeCalories}</Text>
|
<Text style={styles.dataValue}>{Math.round(activeCalories)}</Text>
|
||||||
<Text style={styles.dataGoal}>/{activeCaloriesGoal}</Text>
|
<Text style={styles.dataGoal}>/{activeCaloriesGoal}</Text>
|
||||||
</Text>
|
</Text>
|
||||||
<Text style={styles.dataUnit}>千卡</Text>
|
<Text style={styles.dataUnit}>千卡</Text>
|
||||||
@@ -97,7 +97,7 @@ export function FitnessRingsCard({
|
|||||||
|
|
||||||
<View style={styles.dataRow}>
|
<View style={styles.dataRow}>
|
||||||
<Text style={styles.dataText}>
|
<Text style={styles.dataText}>
|
||||||
<Text style={styles.dataValue}>{exerciseMinutes}</Text>
|
<Text style={styles.dataValue}>{Math.round(exerciseMinutes)}</Text>
|
||||||
<Text style={styles.dataGoal}>/{exerciseMinutesGoal}</Text>
|
<Text style={styles.dataGoal}>/{exerciseMinutesGoal}</Text>
|
||||||
</Text>
|
</Text>
|
||||||
<Text style={styles.dataUnit}>分钟</Text>
|
<Text style={styles.dataUnit}>分钟</Text>
|
||||||
@@ -105,7 +105,7 @@ export function FitnessRingsCard({
|
|||||||
|
|
||||||
<View style={styles.dataRow}>
|
<View style={styles.dataRow}>
|
||||||
<Text style={styles.dataText}>
|
<Text style={styles.dataText}>
|
||||||
<Text style={styles.dataValue}>{standHours}</Text>
|
<Text style={styles.dataValue}>{Math.round(standHours)}</Text>
|
||||||
<Text style={styles.dataGoal}>/{standHoursGoal}</Text>
|
<Text style={styles.dataGoal}>/{standHoursGoal}</Text>
|
||||||
</Text>
|
</Text>
|
||||||
<Text style={styles.dataUnit}>小时</Text>
|
<Text style={styles.dataUnit}>小时</Text>
|
||||||
|
|||||||
@@ -693,7 +693,7 @@ export const CreateGoalModal: React.FC<CreateGoalModalProps> = ({
|
|||||||
<DateTimePicker
|
<DateTimePicker
|
||||||
value={tempSelectedDate || getCurrentEndDate()}
|
value={tempSelectedDate || getCurrentEndDate()}
|
||||||
mode="date"
|
mode="date"
|
||||||
display={Platform.OS === 'ios' ? 'calendar' : 'default'}
|
display={Platform.OS === 'ios' ? 'spinner' : 'default'}
|
||||||
onChange={handleDateChange}
|
onChange={handleDateChange}
|
||||||
minimumDate={new Date()}
|
minimumDate={new Date()}
|
||||||
locale="zh-CN"
|
locale="zh-CN"
|
||||||
@@ -788,7 +788,7 @@ const styles = StyleSheet.create({
|
|||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
paddingHorizontal: 20,
|
paddingHorizontal: 20,
|
||||||
paddingTop: 60,
|
paddingTop: 20,
|
||||||
paddingBottom: 20,
|
paddingBottom: 20,
|
||||||
},
|
},
|
||||||
cancelButton: {
|
cancelButton: {
|
||||||
|
|||||||
@@ -8,6 +8,22 @@ type UserProfile = {
|
|||||||
pilatesPurposes?: string[];
|
pilatesPurposes?: string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 选择选项类型
|
||||||
|
export type WelcomeChoice = {
|
||||||
|
id: string;
|
||||||
|
label: string;
|
||||||
|
value: string;
|
||||||
|
emoji: string;
|
||||||
|
recommended?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 欢迎消息数据结构
|
||||||
|
export type WelcomeMessageData = {
|
||||||
|
content: string;
|
||||||
|
choices: WelcomeChoice[];
|
||||||
|
interactionType: 'selection';
|
||||||
|
};
|
||||||
|
|
||||||
// 参数类型
|
// 参数类型
|
||||||
type GenerateWelcomeMessageParams = {
|
type GenerateWelcomeMessageParams = {
|
||||||
userProfile?: UserProfile;
|
userProfile?: UserProfile;
|
||||||
@@ -17,114 +33,174 @@ type GenerateWelcomeMessageParams = {
|
|||||||
/**
|
/**
|
||||||
* 生成个性化欢迎消息
|
* 生成个性化欢迎消息
|
||||||
* @param params 参数对象,包含用户配置和今日是否已记录心情
|
* @param params 参数对象,包含用户配置和今日是否已记录心情
|
||||||
* @returns 个性化欢迎消息字符串
|
* @returns 个性化欢迎消息数据,包含内容和选择选项
|
||||||
*/
|
*/
|
||||||
export function generateWelcomeMessage(params: GenerateWelcomeMessageParams): string {
|
export function generateWelcomeMessage(params: GenerateWelcomeMessageParams): WelcomeMessageData {
|
||||||
const { userProfile, hasRecordedMoodToday = false } = params;
|
const { userProfile, hasRecordedMoodToday = false } = params;
|
||||||
const hour = new Date().getHours();
|
const hour = new Date().getHours();
|
||||||
const name = userProfile?.name || '朋友';
|
const name = userProfile?.name || '朋友';
|
||||||
|
|
||||||
// 时段问候
|
// 特殊情况的欢迎消息(优先级最高)
|
||||||
let timeGreeting = '';
|
if (!userProfile?.weight && !userProfile?.height) {
|
||||||
|
return {
|
||||||
|
content: `你好,${name}!🐳\n\n我是你的小海豹Seal!发现你还没有完善健康档案呢~让我帮你开启个性化的健康管理之旅吧!\n\n完善档案后,我就能为你量身定制专属的营养方案、运动计划和生活建议啦!`,
|
||||||
|
choices: [
|
||||||
|
{ id: 'profile_setup', label: '完善我的健康档案', value: '我想要完善健康档案,建立个人健康数据', emoji: '📋', recommended: true },
|
||||||
|
{ id: 'health_goals', label: '了解健康目标设定', value: '我想了解如何设定合理的健康目标', emoji: '🎯' },
|
||||||
|
{ id: 'nutrition_basics', label: '营养基础知识科普', value: '我想了解一些基础的营养知识', emoji: '🥗' },
|
||||||
|
{ id: 'quick_start', label: '快速开始体验', value: '我想直接体验一下你的功能', emoji: '🚀' }
|
||||||
|
],
|
||||||
|
interactionType: 'selection'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userProfile && (!userProfile.pilatesPurposes || userProfile.pilatesPurposes.length === 0)) {
|
||||||
|
return {
|
||||||
|
content: `${getTimeGreeting(hour)},${name}!🐋\n\n作为你的小海豹,我想更了解你的健康需求~这样才能为你制定最适合的个性化方案!\n\n告诉我你最想在哪个方面实现突破吧!`,
|
||||||
|
choices: [
|
||||||
|
{ id: 'weight_management', label: '体重管理和塑形', value: '我想要管理体重,塑造更好的身材', emoji: '⚖️', recommended: true },
|
||||||
|
{ id: 'nutrition_balance', label: '营养均衡摄入', value: '我希望学会营养均衡的饮食搭配', emoji: '🥑' },
|
||||||
|
{ id: 'fitness_routine', label: '规律运动健身', value: '我想建立规律的运动健身习惯', emoji: '💪' },
|
||||||
|
{ id: 'lifestyle_improvement', label: '生活方式优化', value: '我希望全面优化健康的生活方式', emoji: '🌟' }
|
||||||
|
],
|
||||||
|
interactionType: 'selection'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hour >= 20 && !hasRecordedMoodToday) {
|
||||||
|
return {
|
||||||
|
content: `${getTimeGreeting(hour)},${name}!🌙\n\n夜深了,小海豹注意到你今天还没有记录心情呢~\n\n情绪健康同样重要!记录心情能帮你更好地了解自己,也有助于制定更贴心的健康方案哦!`,
|
||||||
|
choices: [
|
||||||
|
{ id: 'record_mood', label: '现在记录今天的心情', value: '我想记录一下今天的心情状态', emoji: '😊', recommended: true },
|
||||||
|
{ id: 'mood_tips', label: '了解情绪管理技巧', value: '我想学习一些情绪管理的方法', emoji: '🧘' },
|
||||||
|
{ id: 'sleep_advice', label: '获取睡眠建议', value: '我想了解如何改善睡眠质量', emoji: '🛌' },
|
||||||
|
{ id: 'tomorrow_plan', label: '规划明天的健康计划', value: '我想为明天制定一个健康计划', emoji: '📅' }
|
||||||
|
],
|
||||||
|
interactionType: 'selection'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据时间段生成不同的欢迎消息
|
||||||
|
return generateTimeBasedWelcome(hour, name, userProfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取时间问候语
|
||||||
|
function getTimeGreeting(hour: number): string {
|
||||||
|
if (hour >= 5 && hour < 9) return '早上好';
|
||||||
|
if (hour >= 9 && hour < 12) return '上午好';
|
||||||
|
if (hour >= 12 && hour < 14) return '中午好';
|
||||||
|
if (hour >= 14 && hour < 18) return '下午好';
|
||||||
|
if (hour >= 18 && hour < 22) return '晚上好';
|
||||||
|
return '夜深了';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据时间段生成个性化欢迎消息
|
||||||
|
function generateTimeBasedWelcome(hour: number, name: string, userProfile?: UserProfile): WelcomeMessageData {
|
||||||
|
const timeGreeting = getTimeGreeting(hour);
|
||||||
|
|
||||||
if (hour >= 5 && hour < 9) {
|
if (hour >= 5 && hour < 9) {
|
||||||
timeGreeting = '早上好';
|
// 早晨时段 (5-9点)
|
||||||
} else if (hour >= 9 && hour < 12) {
|
const morningMessages = [
|
||||||
timeGreeting = '上午好';
|
`${timeGreeting},${name}!🌅\n\n新的一天开始啦!小海豹已经准备好陪你开启元气满满的健康旅程了~\n\n今天想从哪个方面开始呢?让我们一起制定一个完美的开始!`,
|
||||||
} else if (hour >= 12 && hour < 14) {
|
`${timeGreeting},${name}!🐳\n\n早晨的阳光真好呢~小海豹发现,早上是养成健康习惯的黄金时间!\n\n要不要先从一个简单但有效的健康行动开始今天?`,
|
||||||
timeGreeting = '中午好';
|
`${timeGreeting},${name}!☀️\n\n小海豹在这里等你啦!新的一天意味着新的机会~\n\n让我帮你规划今天的健康目标,让身心都充满活力!`
|
||||||
} else if (hour >= 14 && hour < 18) {
|
];
|
||||||
timeGreeting = '下午好';
|
|
||||||
} else if (hour >= 18 && hour < 22) {
|
const content = morningMessages[Math.floor(Math.random() * morningMessages.length)];
|
||||||
timeGreeting = '晚上好';
|
|
||||||
} else {
|
return {
|
||||||
timeGreeting = '夜深了';
|
content,
|
||||||
|
choices: [
|
||||||
|
{ id: 'morning_routine', label: '制定晨间健康计划', value: '我想制定一个晨间健康常规计划', emoji: '🌅', recommended: true },
|
||||||
|
{ id: 'breakfast_plan', label: '营养早餐搭配建议', value: '我想了解营养丰富的早餐搭配', emoji: '🥞' },
|
||||||
|
{ id: 'morning_exercise', label: '晨间运动指导', value: '我想要一些适合晨间的运动建议', emoji: '🏃♀️' },
|
||||||
|
{ id: 'energy_boost', label: '提升一天活力的秘诀', value: '我想知道如何让一天都保持活力', emoji: '⚡' }
|
||||||
|
],
|
||||||
|
interactionType: 'selection'
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// 欢迎消息模板
|
if (hour >= 9 && hour < 12) {
|
||||||
const welcomeMessages = [
|
// 上午时段 (9-12点)
|
||||||
{
|
const morningMessages = [
|
||||||
condition: () => hour >= 5 && hour < 9,
|
`${timeGreeting},${name}!💼\n\n上午工作时光,别忘了关爱自己哦~小海豹发现很多人在忙碌中忽略了健康!\n\n让我帮你在工作间隙也能保持最佳状态!`,
|
||||||
messages: [
|
`${timeGreeting},${name}!🐳\n\n上午是大脑最活跃的时候呢!小海豹想提醒你,身体和心理的平衡很重要~\n\n要不要了解一些工作日的健康小贴士?`
|
||||||
`${timeGreeting},${name}!🐳 我是你的小海豹,新的一天开始啦!让我们一起游向健康的目标吧~`,
|
];
|
||||||
`${timeGreeting}!🌅 早晨的阳光真好呢,我是你的专属小海豹健康伙伴!要不要先制定今天的健康计划呢?`,
|
|
||||||
`${timeGreeting},${name}!🐋 小海豹来报到啦!今天想从哪个方面开始我们的健康之旅呢?营养、运动还是生活管理,我都可以帮你哦~`
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
condition: () => hour >= 9 && hour < 12,
|
|
||||||
messages: [
|
|
||||||
`${timeGreeting},${name}!🐳 上午是身体最活跃的时候呢,小海豹在这里为你加油!有什么健康目标需要我帮你规划吗?`,
|
|
||||||
`${timeGreeting}!☀️ 工作忙碌的上午,别忘了给身体一些关爱哦~我是你的小海豹,随时准备为你提供营养建议和运动指导!`,
|
|
||||||
`${timeGreeting},${name}!🐋 作为你的小海豹伙伴,我想说:每一个健康的选择都在让我们的身体更棒呢!今天想从哪个方面开始呢?`
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
condition: () => hour >= 12 && hour < 14,
|
|
||||||
messages: [
|
|
||||||
`${timeGreeting},${name}!🍽️ 午餐时间到啦!小海豹提醒你,合理的营养搭配能让下午充满能量哦~`,
|
|
||||||
`${timeGreeting}!🌊 忙碌的上午结束了,该给身体补充能量啦!我是你的小海豹,无论是饮食调整还是运动安排,都可以找我商量哦~`,
|
|
||||||
`${timeGreeting},${name}!🐳 午间时光,小海豹建议你关注饮食均衡,也要适度放松一下呢~`
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
condition: () => hour >= 14 && hour < 18,
|
|
||||||
messages: [
|
|
||||||
`${timeGreeting},${name}!🌊 下午是运动的黄金时段呢!小海豹可以为你制定个性化的健身计划,让我们一起游向更好的身材吧~`,
|
|
||||||
`${timeGreeting}!🐋 午后时光,正是关注健康的好时机!我是你的小海豹,从营养到运动,我都能为你提供贴心指导哦~`,
|
|
||||||
`${timeGreeting},${name}!🐳 下午时光,身心健康同样重要呢!作为你的小海豹,我在这里支持你的每一个健康目标~`
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
condition: () => hour >= 18 && hour < 22,
|
|
||||||
messages: [
|
|
||||||
`${timeGreeting},${name}!🌙 忙碌了一天,现在是放松身心的好时候呢!小海豹可以为你提供放松建议和恢复方案哦~`,
|
|
||||||
`${timeGreeting}!🌊 夜幕降临,这是一天中最适合总结的时刻!我是你的小海豹,让我们一起回顾今天的健康表现,规划明天的目标吧~`,
|
|
||||||
`${timeGreeting},${name}!🐳 晚间时光属于你自己,也是关爱身体的珍贵时间!作为你的小海豹,我想陪你聊聊如何更好地管理健康生活呢~`
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
condition: () => hour >= 22 || hour < 5,
|
|
||||||
messages: [
|
|
||||||
`${timeGreeting},${name}!🌙 优质睡眠是健康的基石呢!小海豹提醒你,如果需要睡眠优化建议,随时可以问我哦~`,
|
|
||||||
`夜深了,${name}。🌊 充足的睡眠对身体恢复很重要呢!我是你的小海豹,有什么关于睡眠健康的问题都可以咨询我~`,
|
|
||||||
`夜深了,愿你能拥有甜甜的睡眠。🐳 我是你的小海豹,明天我们继续在健康管理的海洋里同行。晚安,${name}!`
|
|
||||||
]
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
// 特殊情况的消息
|
const content = morningMessages[Math.floor(Math.random() * morningMessages.length)];
|
||||||
const specialMessages = [
|
|
||||||
{
|
|
||||||
condition: () => !userProfile?.weight && !userProfile?.height,
|
|
||||||
message: `你好,${name}!🐳 我是你的小海豹!我注意到你还没有完善健康档案呢,不如先聊聊你的健康目标和身体状况,这样小海豹就能为你制定更贴心的健康方案啦~`
|
|
||||||
},
|
|
||||||
{
|
|
||||||
condition: () => userProfile && (!userProfile.pilatesPurposes || userProfile.pilatesPurposes.length === 0),
|
|
||||||
message: `${timeGreeting},${name}!🐋 作为你的小海豹,我想更好地了解你的健康需求呢!告诉我你希望在营养摄入、身材管理、健身锻炼或生活管理方面实现什么目标吧~`
|
|
||||||
},
|
|
||||||
// 新增:晚上20点后且未记录心情的特殊提示
|
|
||||||
{
|
|
||||||
condition: () => hour >= 20 && !hasRecordedMoodToday,
|
|
||||||
message: `${timeGreeting},${name}!🌙 夜深了,小海豹注意到你今天还没有记录心情呢。记录心情有助于更好地了解自己的情绪变化,对健康管理很有帮助哦~要不要现在记录一下今天的心情?`
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
// 检查特殊情况
|
return {
|
||||||
for (const special of specialMessages) {
|
content,
|
||||||
if (special.condition()) {
|
choices: [
|
||||||
return special.message;
|
{ id: 'work_wellness', label: '工作日健康管理', value: '我想了解如何在工作中保持健康', emoji: '💻', recommended: true },
|
||||||
}
|
{ id: 'hydration_reminder', label: '科学补水指导', value: '我想了解正确的补水方法和时机', emoji: '💧' },
|
||||||
|
{ id: 'stress_management', label: '上午压力缓解', value: '我想学习一些缓解工作压力的方法', emoji: '🧘♀️' },
|
||||||
|
{ id: 'snack_healthy', label: '健康零食推荐', value: '我想知道有哪些健康的上午零食', emoji: '🍎' }
|
||||||
|
],
|
||||||
|
interactionType: 'selection'
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// 根据时间选择合适的消息组
|
if (hour >= 12 && hour < 14) {
|
||||||
const timeGroup = welcomeMessages.find(group => group.condition());
|
// 午餐时段 (12-14点)
|
||||||
if (timeGroup) {
|
return {
|
||||||
const messages = timeGroup.messages;
|
content: `${timeGreeting},${name}!🍽️\n\n午餐时间到啦!小海豹要提醒你,午餐可是一天中最重要的能量补充时刻~\n\n合理的午餐搭配能让你下午精神饱满,让我帮你优化午餐营养吧!`,
|
||||||
return messages[Math.floor(Math.random() * messages.length)];
|
choices: [
|
||||||
|
{ id: 'lunch_nutrition', label: '午餐营养搭配指导', value: '我想了解营养均衡的午餐搭配方案', emoji: '🥗', recommended: true },
|
||||||
|
{ id: 'portion_control', label: '食物份量控制技巧', value: '我想学习合理控制食物份量的方法', emoji: '⚖️' },
|
||||||
|
{ id: 'meal_prep', label: '健康餐食准备建议', value: '我想了解如何准备健康的工作日午餐', emoji: '🥘' },
|
||||||
|
{ id: 'digestive_health', label: '促进消化的小贴士', value: '我想了解一些促进消化的健康建议', emoji: '🌿' }
|
||||||
|
],
|
||||||
|
interactionType: 'selection'
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// 默认消息
|
if (hour >= 14 && hour < 18) {
|
||||||
return `你好,我是你的小海豹!🐳 可以向我咨询营养摄入、身材管理、健身锻炼、生活管理等各方面的健康问题哦~`;
|
// 下午时段 (14-18点)
|
||||||
|
const afternoonMessages = [
|
||||||
|
`${timeGreeting},${name}!🌊\n\n下午是运动的黄金时段呢!小海豹发现这个时间身体机能最活跃~\n\n要不要趁着这个时机为身体注入一些活力?`,
|
||||||
|
`${timeGreeting},${name}!💪\n\n下午时光,正是让身体动起来的好时机!小海豹已经为你准备了各种健身方案~\n\n让我帮你找到最适合的运动方式!`
|
||||||
|
];
|
||||||
|
|
||||||
|
const content = afternoonMessages[Math.floor(Math.random() * afternoonMessages.length)];
|
||||||
|
|
||||||
|
return {
|
||||||
|
content,
|
||||||
|
choices: [
|
||||||
|
{ id: 'afternoon_workout', label: '下午运动计划制定', value: '我想制定一个下午运动锻炼计划', emoji: '🏋️♀️', recommended: true },
|
||||||
|
{ id: 'office_exercise', label: '办公室运动指导', value: '我想了解一些办公室里能做的运动', emoji: '🪑' },
|
||||||
|
{ id: 'energy_snack', label: '下午健康能量补充', value: '我想了解下午适合的健康能量补充', emoji: '🥜' },
|
||||||
|
{ id: 'posture_correction', label: '体态矫正建议', value: '我想了解如何改善日常体态问题', emoji: '🧍♀️' }
|
||||||
|
],
|
||||||
|
interactionType: 'selection'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hour >= 18 && hour < 22) {
|
||||||
|
// 晚上时段 (18-22点)
|
||||||
|
return {
|
||||||
|
content: `${timeGreeting},${name}!🌆\n\n忙碌的一天即将结束,这是最适合放松身心的美好时光~\n\n小海豹想陪你一起回顾今天,同时为身心健康做一些温和的调理!`,
|
||||||
|
choices: [
|
||||||
|
{ id: 'evening_routine', label: '晚间健康常规建立', value: '我想建立一个健康的晚间常规', emoji: '🌙', recommended: true },
|
||||||
|
{ id: 'dinner_light', label: '晚餐轻食建议', value: '我想了解适合晚餐的轻食搭配', emoji: '🥙' },
|
||||||
|
{ id: 'relaxation_tips', label: '放松减压指导', value: '我想学习一些晚间放松减压的方法', emoji: '🕯️' },
|
||||||
|
{ id: 'daily_summary', label: '今日健康总结', value: '我想回顾和总结今天的健康表现', emoji: '📝' }
|
||||||
|
],
|
||||||
|
interactionType: 'selection'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 深夜时段 (22点-5点)
|
||||||
|
return {
|
||||||
|
content: `${timeGreeting},${name}!🌙\n\n夜深了,小海豹关心你的睡眠质量~优质的睡眠是健康的基石呢!\n\n让我帮你为今晚的好眠做一些准备,或者聊聊明天的健康规划吧!`,
|
||||||
|
choices: [
|
||||||
|
{ id: 'sleep_optimization', label: '睡眠质量优化建议', value: '我想了解如何提高睡眠质量', emoji: '😴', recommended: true },
|
||||||
|
{ id: 'bedtime_routine', label: '睡前放松仪式', value: '我想建立一个有助睡眠的睡前仪式', emoji: '🛌' },
|
||||||
|
{ id: 'tomorrow_prep', label: '明日健康规划', value: '我想为明天制定健康计划', emoji: '📅' },
|
||||||
|
{ id: 'night_wellness', label: '夜间健康小贴士', value: '我想了解一些夜间的健康注意事项', emoji: '🌜' }
|
||||||
|
],
|
||||||
|
interactionType: 'selection'
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -134,9 +210,9 @@ export function generateWelcomeMessage(params: GenerateWelcomeMessageParams): st
|
|||||||
*/
|
*/
|
||||||
export function hasRecordedMoodToday(lastMoodDate?: string | Date): boolean {
|
export function hasRecordedMoodToday(lastMoodDate?: string | Date): boolean {
|
||||||
if (!lastMoodDate) return false;
|
if (!lastMoodDate) return false;
|
||||||
|
|
||||||
const today = dayjs().format('YYYY-MM-DD');
|
const today = dayjs().format('YYYY-MM-DD');
|
||||||
const lastMoodDay = dayjs(lastMoodDate).format('YYYY-MM-DD');
|
const lastMoodDay = dayjs(lastMoodDate).format('YYYY-MM-DD');
|
||||||
|
|
||||||
return today === lastMoodDay;
|
return today === lastMoodDay;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user