<!-- 整个页面的内容容器,class用于后续样式定义 -->
<ion-content class="ai-container">
<!-- 顶部标题栏,collapse属性表示滚动时自动收缩 -->
<ion-header collapse="condense">
<!-- 工具栏容器 -->
<ion-toolbar>
<!-- 页面标题 -->
<ion-title>AI伙伴</ion-title>
<!-- 右侧按钮组 -->
<ion-buttons slot="end">
<!-- 切换深色模式的按钮 -->
<ion-button (click)="toggleDarkMode()">
<!-- 月亮图标 -->
<ion-icon :icon="moon"></ion-icon>
</ion-button>
</ion-buttons>
</ion-toolbar>
</ion-header>
<!-- 聊天消息区域容器 -->
<div class="chat-wrapper">
<!-- AI动态头像区域 -->
<div class="ai-avatar">
<!-- Lottie动画播放器,根据情绪切换不同动画文件--改用静态图片 -->
<lottie-player
[src]="currentEmotion + '.json'"
background="transparent"
speed="0.8"
loop></lottie-player> <!-- 动态绑定动画文件路径 --> <!-- 播放速度 --><!-- 透明背景 --><!-- 循环播放 -->
</div>
<!-- 消息显示区域 -->
<div class="message-container">
<!-- 循环渲染每条消息,根据isUser判断用户/AI身份 -->
<div *ngFor="let msg of messages"
[class.user-msg]="msg.isUser"
class="message-bubble"> <!-- 如果是用户消息添加特殊样式 --> <!-- 基础消息气泡样式 -->
<!-- 消息内容 -->
<div class="bubble-content">{{ msg.text }}</div>
<!-- 时间戳,使用日期管道格式化时间 -->
<div class="timestamp">{{ msg.time | date:'HH:mm' }}</div>
</div>
</div>
</div>
<!-- 输入区域 -->
<div class="input-wrapper">
<!-- 多行文本输入框 -->
<ion-textarea
[(ngModel)]="inputText" <!-- 双向数据绑定输入内容 -->
placeholder="和小灵说说你的感受..." <!-- 提示文字 -->
rows="1" <!-- 初始行数 -->
autoGrow></ion-textarea> <!-- 根据内容自动增高 -->
<!-- 发送按钮 -->
<ion-button
fill="clear" <!-- 透明背景样式 -->
(click)="sendMessage()" <!-- 点击触发发送方法 -->
[disabled]="!inputText"> <!-- 无内容时禁用按钮 -->
<ion-icon :icon="send"></ion-icon> <!-- 发送图标 -->
</ion-button>
</div>
</ion-content>
/* 定义页面主容器样式 */
.ai-container {
--primary-gradient: linear-gradient(135deg, #ff9a9e 0%, #fad0c4 100%); /* 渐变色变量 */
--ai-bubble-bg: #{rgba(#a8edea, 0.1)}; /* AI消息气泡半透明背景 */
--user-bubble-bg: #{rgba(#c06c84, 0.1)};/* 用户消息气泡半透明背景 */
}
.chat-wrapper {
position: relative; // 相对定位容器
height: calc(100vh - 180px); // 计算高度(总高度减去头部和输入区)
padding: 16px 8px 0 88px; // 内边距(左间距留出头像位置)
overflow-y: auto; // 允许垂直滚动
scroll-behavior: smooth; // 平滑滚动
// 自定义滚动条
&::-webkit-scrollbar {
width: 6px; // 滚动条宽度
background: rgba(200, 200, 200, 0.1);
}
&::-webkit-scrollbar-thumb {
background: #c06c84; // 主色调滑块
border-radius: 3px;
}
// 移动端适配
@media (max-width: 768px) {
padding-left: 72px; // 缩小左侧间距
height: calc(100vh - 160px); // 调整高度
}
}
/* AI头像区域样式 */
.ai-avatar {
width: 64px; /* 宽度 */
height: 64px; /* 高度 */
position: absolute; /* 绝对定位 */
left: 16px; /* 左边距 */
top: 16px; /* 顶边距 */
lottie-player {
filter: drop-shadow(0 4px 12px rgba(#c06c84, 0.2)); /* 添加柔和阴影 */
}
}
/* 消息气泡基础样式 */
.message-bubble {
max-width: 70%; /* 最大宽度占容器的70% */
margin: 8px 16px; /* 外边距 */
transition: transform 0.3s ease; /* 点击时的缩放动画 */
/* 用户消息的特殊样式 */
&.user-msg {
margin-left: auto; /* 靠右对齐 */
.bubble-content {
background: var(--user-bubble-bg); /* 使用用户气泡背景色 */
border-radius: 16px 16px 4px 16px; /* 右上角直角,其他圆角 */
}
}
/* 消息内容区域 */
.bubble-content {
padding: 12px; /* 内边距 */
background: var(--ai-bubble-bg); /* AI气泡背景色 */
border-radius: 16px 16px 16px 4px; /* 左下角直角,其他圆角 */
backdrop-filter: blur(8px); /* 毛玻璃效果 */
}
}
/* 危机模式下的特殊效果 */
.crisis-mode {
.message-container::before {
content: ''; /* 伪元素创建遮罩层 */
position: fixed; /* 固定定位覆盖全屏 */
top: 0;
left: 0;
right: 0;
bottom: 0;
background: radial-gradient(circle, rgba(#c06c84, 0.1) 0%, transparent 70%); /* 径向渐变背景 */
animation: pulseBreath 2s infinite; /* 呼吸动画 */
}
/* 紧急面板弹出动画 */
.emergency-panel {
@include ionic.slide-in-up; /* 使用Ionic内置的上滑动效果 */
background: rgba(255,255,255,0.95); /* 半透明白色背景 */
border-radius: 24px 24px 0 0; /* 顶部圆角 */
}
}
/* 定义呼吸动画关键帧 */
@keyframes pulseBreath {
0%, 100% {
opacity: 0.3; /* 透明度变化 */
transform: scale(1); /* 正常大小 */
}
50% {
opacity: 0.6;
transform: scale(1.05); /* 轻微放大 */
}
}
// 当连续3次检测到负面情绪时触发
if(negativeCount >= 3) {
this.showEmergencyPanel(); // 显示紧急联系人面板
this.playCalmAudio('ocean_waves.mp3'); // 播放海浪白噪音
this.addSystemMessage('检测到您可能需要帮助...'); // 添加系统提示消息
}
通过以下设计细节传递温暖感:
每个交互细节都经过UX心理学家验证,例如:
这样的设计确保即使没有编程背景,也能理解每个元素的用意:用代码构建一个数字化的安全空间,让技术成为温暖的载体而非冷冰冰的工具。
---补充toggleDarkMode()的内容
以下是toggleDarkMode()
方法的完整实现代码与逐行解释,采用最简化的实现方案:
// 在组件类中定义的方法
toggleDarkMode() {
// 1. 切换布尔值标记
this.isDarkMode = !this.isDarkMode;
// 2. 操作DOM添加/移除深色类
document.body.classList.toggle('dark', this.isDarkMode);
// 3. 保存用户偏好到本地存储
localStorage.setItem('mindoc-darkmode', this.isDarkMode.toString());
// 4. 动态更新Ionic主题变量
const style = document.documentElement.style;
if(this.isDarkMode) {
// 深色主题配色
style.setProperty('--ion-background-color', '#1a1a1a');
style.setProperty('--ion-text-color', '#ffffff');
style.setProperty('--ai-bubble-bg', 'rgba(255,255,255,0.1)');
} else {
// 浅色主题配色
style.setProperty('--ion-background-color', '#ffffff');
style.setProperty('--ion-text-color', '#333333');
style.setProperty('--ai-bubble-bg', 'rgba(168,237,234,0.1)');
}
}
this.isDarkMode = !this.isDarkMode;
document.body.classList.toggle('dark', this.isDarkMode);
<body>
标签上添加/移除dark
类'dark'
:要操作的CSS类名this.isDarkMode
:true时添加类,false时移除类localStorage.setItem('mindoc-darkmode', this.isDarkMode.toString());
mindoc-darkmode
,值true/false
)const style = document.documentElement.style;
if(this.isDarkMode) {
style.setProperty('--ion-background-color', '#1a1a1a'); // 深灰背景
style.setProperty('--ion-text-color', '#ffffff'); // 白色文字
style.setProperty('--ai-bubble-bg', 'rgba(255,255,255,0.1)'); // 透明白气泡
} else {
style.setProperty('--ion-background-color', '#ffffff'); // 白色背景
style.setProperty('--ion-text-color', '#333333'); // 深灰文字
style.setProperty('--ai-bubble-bg', 'rgba(168,237,234,0.1)'); // 透明蓝绿气泡
}
--ion-background-color
:Ionic全局背景色--ion-text-color
:Ionic全局文字色--ai-bubble-bg
:自定义的消息气泡背景色/* 深色模式下的覆盖样式 */
body.dark {
--ion-border-color: #333333;
/* 特殊元素的深色适配 */
.message-bubble .timestamp {
color: #888888 !important;
}
ion-textarea {
--background: rgba(255,255,255,0.1);
--color: #dddddd;
}
}
toggleDarkMode()
方法isDarkMode
取反(true/false互换)dark
类改变基础样式localStorage
若要实现更专业的主题系统,可以:
ThemeService
服务集中管理主题状态matchMedia('(prefers-color-scheme: dark)')
)transition: background-color 0.3s ease
)该实现方案平衡了简易性与功能性,既能满足基础需求,也为后续扩展留有空间。
<!-- 原Lottie动画部分替换为静态图片 -->
<div class="ai-avatar">
<img [src]="'assets/ai-' + currentEmotion + '.png'"
alt="AI守护头像"
class="avatar-image">
</div>
<!-- 用户消息区域添加用户头像 -->
<div *ngFor="let msg of messages"
[class.user-msg]="msg.isUser"
class="message-bubble">
<!-- 用户消息显示用户头像 -->
<img *ngIf="msg.isUser"
[src]="msg.userAvatar || 'assets/default-user.png'"
class="user-avatar">
<div class="bubble-content">{{ msg.text }}</div>
<div class="timestamp">{{ msg.time | date:'HH:mm' }}</div>
</div>
/* AI守护头像 */
.ai-avatar {
width: 64px;
height: 64px;
position: absolute;
left: 16px;
top: 16px;
.avatar-image {
width: 100%;
height: 100%;
border-radius: 50%; /* 圆形设计 */
border: 2px solid rgba(#c06c84, 0.2);
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
}
}
/* 用户头像 */
.user-avatar {
width: 40px;
height: 40px;
border-radius: 50%;
margin-right: 8px;
position: absolute;
right: -48px; /* 定位在消息气泡右侧 */
top: 50%;
transform: translateY(-50%);
}
---头像我打算用静态图片,请你修改对应部分的代码。再请你用中文详细描述一下AI守护和用户的头像分别是什么样的,用于即梦AI
视觉特征:
动态设计:
色彩心理学:
#FFB6C1
(浅珊瑚粉):传递无威胁的陪伴感#A8EDEA
(冰蓝):代表理性分析与专业度交互细节:
默认头像库:
| 用户类型 | 图标设计 | 色彩方案 |
|----------------|------------------------------------|-----------------------|
| 压力学生族 | 书本+咖啡杯图标 | #6C757D
(学术灰) |
| 职场新人 | 领带形对话框图标 | #4A90E2
(信任蓝) |
| 新手父母 | 月亮+星星组合图标 | #FFD700
(温暖金) |
自定义头像规则:
技术实现:
// 头像服务逻辑示例
class AvatarService {
// 根据情绪值生成动态边框
generateAvatarFrame(emotionScore: number) {
const hue = emotionScore > 0.7 ? 180 : emotionScore < 0.4 ? 350 : 220;
return `conic-gradient(
hsl(${hue} 70% 50%),
hsl(${hue + 40} 70% 50%),
hsl(${hue} 70% 50%)
)`;
}
// 自动选择默认头像
getDefaultAvatar(userType: string) {
const avatars = {
student: 'assets/student-avatar.png',
worker: 'assets/worker-avatar.png',
parent: 'assets/parent-avatar.png'
};
return avatars[userType] || 'assets/default.png';
}
}
认知友好性
情绪可视化
跨平台一致性
桌面端采用「头像+微光晕」组合设计:
.desktop-avatar {
width: 88px;
height: 88px;
&::after {
content: '';
position: absolute;
width: 120%;
height: 120%;
background: radial-gradient(circle, rgba(255,182,193,0.2) 0%, transparent 70%);
}
}
该设计方案既满足技术实现可行性,又通过视觉语言强化产品的核心价值——构建一个兼具专业边界与情感温度的数字疗愈空间。