diff --git a/components/ai-chat-message/ai-chat-message.vue b/components/ai-chat-message/ai-chat-message.vue index 0790fae..13a8bab 100644 --- a/components/ai-chat-message/ai-chat-message.vue +++ b/components/ai-chat-message/ai-chat-message.vue @@ -27,6 +27,8 @@ + + {{ localUserNickname }} {{ message.content }} @@ -41,6 +43,8 @@ + + 智能助手 @@ -189,6 +193,10 @@ + + @@ -311,6 +319,42 @@ + + + + + + + 修改昵称 + + + + + + + 昵称长度限制1-12个字符,仅自己可见 + + + + + + + @@ -334,6 +378,11 @@ export default { type: String, default: '' }, + // 初始用户昵称(外部传入,可选) + initUserNickname: { + type: String, + default: '' + }, // 是否显示加载更多 showLoadMore: { type: Boolean, @@ -380,6 +429,11 @@ export default { defaultAvatar: '/static/images/default-avatar.png', // 头像选择弹窗控制 showAvatarSelector: false, + // 新增:用户昵称相关 + localUserNickname: '', // 当前用户昵称 + defaultNickname: '我', // 默认昵称 + showNicknameEditor: false, // 昵称编辑弹窗控制 + tempNickname: '', // 昵称编辑临时值 // Dify API相关 currentConversationId: null, isAIServiceAvailable: true, @@ -392,6 +446,8 @@ export default { this.initAudioContext() // 初始化用户头像(缓存优先) this.initUserAvatarData() + // 初始化用户昵称(缓存优先) + this.initUserNicknameData() }, mounted() { this.scrollToBottom() @@ -436,6 +492,26 @@ export default { } }, + // 新增:初始化用户昵称(支持缓存持久化) + initUserNicknameData() { + // 1. 优先读取本地缓存的昵称 + const cachedNickname = uni.getStorageSync('user_nickname') + + if (cachedNickname) { + this.localUserNickname = cachedNickname + } + // 2. 无缓存时,使用外部传入的初始昵称 + else if (this.initUserNickname) { + this.localUserNickname = this.initUserNickname + // 缓存初始昵称 + uni.setStorageSync('user_nickname', this.initUserNickname) + } + // 3. 最后使用默认昵称 + else { + this.localUserNickname = this.defaultNickname + } + }, + // 打开头像选择弹窗 openAvatarSelector() { this.showAvatarSelector = true @@ -504,6 +580,44 @@ export default { }) }, + // 新增:打开昵称编辑弹窗 + openNicknameEditor() { + // 初始化临时昵称值为当前昵称 + this.tempNickname = this.localUserNickname + this.showNicknameEditor = true + }, + + // 新增:关闭昵称编辑弹窗 + closeNicknameEditor() { + this.showNicknameEditor = false + // 清空临时值 + this.tempNickname = '' + }, + + // 新增:保存用户昵称 + saveNickname() { + if (!this.tempNickname.trim()) return + + // 1. 更新本地昵称 + this.localUserNickname = this.tempNickname.trim() + + // 2. 持久化缓存(支持页面刷新后保留) + uni.setStorageSync('user_nickname', this.localUserNickname) + + // 3. 通知父组件(可选,用于同步到服务器等场景) + this.$emit('nickname-changed', this.localUserNickname) + + // 4. 关闭弹窗 + this.closeNicknameEditor() + + // 5. 提示成功 + uni.showToast({ + title: '昵称修改成功', + icon: 'success', + duration: 1500 + }) + }, + // 发送消息 async sendMessage() { if (!this.inputText.trim()) return @@ -1194,8 +1308,11 @@ $radius-lg: 36rpx; font-size: 24rpx; color: $color-text-light; margin-bottom: 8rpx; - text-align: right; // 与用户消息右对齐 letter-spacing: 0.5rpx; + // 用户昵称右对齐,AI昵称左对齐 + &:not(.ai-message .message-nickname) { + text-align: right; + } } .message-bubble { @@ -1835,737 +1952,767 @@ $radius-lg: 36rpx; z-index: 1001; } } + + + + + +// 昵称编辑弹窗样式(修复右侧溢出问题) +.nickname-editor-popup { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: 1001; +} - // 昵称编辑弹窗样式 - .nickname-editor-popup { - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - z-index: 1001; - } +.nickname-editor-mask { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0, 0, 0, 0.4); + backdrop-filter: blur(6rpx); +} - .nickname-editor-mask { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - background-color: rgba(0, 0, 0, 0.4); - backdrop-filter: blur(6rpx); - } +.nickname-editor-panel { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + background-color: $bg-card; + border-radius: $radius-lg; + padding: 24rpx 32rpx; // 统一内边距 + width: calc(100% - 80rpx); // 限制弹窗宽度(避免超出屏幕) + max-width: 520rpx; // 最大宽度(适配不同设备) + box-shadow: 0 8rpx 36rpx rgba(0, 0, 0, 0.15); + box-sizing: border-box; // 确保内边距不影响宽度 - .nickname-editor-panel { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - background-color: $bg-card; - border-radius: $radius-lg; - padding: 32rpx; - width: 580rpx; - box-shadow: 0 8rpx 36rpx rgba(0, 0, 0, 0.15); + .nickname-editor-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 24rpx; + border-bottom: 2rpx solid #f0f4f8; + padding-bottom: 16rpx; - .nickname-editor-header { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 32rpx; - border-bottom: 2rpx solid #f0f4f8; - padding-bottom: 24rpx; - - text { - font-size: 34rpx; - font-weight: 600; - color: $color-text; - } - - .close-btn { - width: 64rpx; - height: 64rpx; - border-radius: 50%; - background-color: $bg-main; - display: flex; - align-items: center; - justify-content: center; - transition: all 0.2s ease; - border: none; - - &:hover { - background-color: #e8edf3; - } - - .iconfont { - font-size: 34rpx; - color: $color-text-light; - } - } + text { + font-size: 34rpx; + font-weight: 600; + color: $color-text; } - .nickname-editor-content { - .nickname-input-container { - margin-bottom: 24rpx; + .close-btn { + width: 56rpx; + height: 56rpx; + border-radius: 50%; + background-color: $bg-main; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.2s ease; + border: none; - .nickname-input { - width: 100%; - height: 96rpx; - padding: 0 24rpx; - border-radius: $radius-lg; - border: 2rpx solid #f0f4f8; - font-size: 28rpx; - color: $color-text; - background-color: $bg-main; - transition: all 0.2s ease; - - &:focus { - border-color: $color-primary; - box-shadow: 0 0 0 4rpx rgba(108, 142, 191, 0.1); - } - - &::placeholder { - color: $color-text-light; - opacity: 0.8; - } - } + &:hover { + background-color: #e8edf3; } - .nickname-tip { - font-size: 24rpx; + .iconfont { + font-size: 28rpx; color: $color-text-light; - margin-bottom: 32rpx; - text-align: center; - } - - .nickname-editor-actions { - display: flex; - gap: 24rpx; - - .nickname-action-btn { - flex: 1; - height: 96rpx; - border-radius: $radius-lg; - font-size: 28rpx; - font-weight: 500; - transition: all 0.2s ease; - - &.cancel { - background-color: $bg-card; - border: 2rpx solid #f0f4f8; - color: $color-text-light; - - &:hover { - background-color: #f8fafc; - } - } - - &.confirm { - background-color: $color-primary; - color: white; - box-shadow: 0 4rpx 12rpx rgba(108, 142, 191, 0.2); - - &:hover { - background-color: #5a7cb0; - transform: translateY(-2rpx); - } - - &.disabled { - background-color: $color-primary-light; - box-shadow: none; - opacity: 0.7; - transform: none; - } - } - } } } } - /* 弹窗样式基础 */ - .tools-popup, .voice-popup, .avatar-selector-popup { - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - z-index: 999; - } + .nickname-editor-content { + .nickname-input-container { + margin-bottom: 24rpx; + width: 100%; // 输入框容器占满弹窗宽度 + box-sizing: border-box; - .tools-mask, .voice-mask, .avatar-selector-mask { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - background-color: rgba(0, 0, 0, 0.4); - backdrop-filter: blur(6rpx); - } - - /* 工具面板样式 */ - .tools-panel { - position: absolute; - bottom: 0; - left: 0; - right: 0; - background-color: $bg-card; - border-radius: $radius-lg $radius-lg 0 0; - box-shadow: 0 -4rpx 24rpx rgba(0, 0, 0, 0.1); - - .tools-header { - display: flex; - justify-content: space-between; - align-items: center; - padding: 32rpx; - border-bottom: 2rpx solid #f0f4f8; - - text { - font-size: 34rpx; - font-weight: 600; + .nickname-input { + width: 100%; + height: 96rpx; + padding: 0 24rpx; + border-radius: $radius-lg; + border: 2rpx solid #f0f4f8; + font-size: 28rpx; color: $color-text; - } - - .close-btn { - width: 64rpx; - height: 64rpx; - border-radius: 50%; - background-color: $bg-main; - display: flex; - align-items: center; - justify-content: center; - transition: all 0.2s ease; - border: none; - - &:hover { - background-color: #e8edf3; - } - - .iconfont { - font-size: 34rpx; - color: $color-text-light; - } - } - } - - .tools-grid { - display: grid; - grid-template-columns: repeat(4, 1fr); - padding: 32rpx; - gap: 32rpx; - - .tool-item { - display: flex; - flex-direction: column; - align-items: center; - transition: all 0.3s ease; - - &:hover { - transform: translateY(-4rpx); - } - - .tool-icon { - width: 96rpx; - height: 96rpx; - border-radius: 50%; - background-color: $bg-main; - display: flex; - align-items: center; - justify-content: center; - margin-bottom: 16rpx; - box-shadow: $shadow-sm; - - .iconfont { - font-size: 48rpx; - color: $color-primary; - } - } - - .tool-text { - font-size: 26rpx; - color: $color-text; - } - } - } - } - - /* 语音输入面板样式 */ - .voice-input-panel { - position: absolute; - bottom: 0; - left: 0; - right: 0; - background-color: $bg-card; - border-radius: $radius-lg $radius-lg 0 0; - box-shadow: 0 -4rpx 24rpx rgba(0, 0, 0, 0.1); - - .voice-header { - display: flex; - justify-content: space-between; - align-items: center; - padding: 32rpx; - border-bottom: 2rpx solid #f0f4f8; - - text { - font-size: 34rpx; - font-weight: 600; - color: $color-text; - } - - .close-btn { - width: 64rpx; - height: 64rpx; - border-radius: 50%; - background-color: $bg-main; - display: flex; - align-items: center; - justify-content: center; - transition: all 0.2s ease; - border: none; - - &:hover { - background-color: #e8edf3; - } - - .iconfont { - font-size: 34rpx; - color: $color-text-light; - } - } - } - - .voice-content { - padding: 64rpx 32rpx; - display: flex; - flex-direction: column; - align-items: center; - - .voice-wave { - width: 240rpx; - height: 240rpx; - border-radius: 50%; - background-color: $bg-main; - display: flex; - align-items: center; - justify-content: center; - margin-bottom: 48rpx; - box-shadow: $shadow-md; - - .wave-bar { - width: 12rpx; - height: 40rpx; - background-color: $color-primary-light; - border-radius: 6rpx; - margin: 0 8rpx; - transition: height 0.3s ease; - } - - &.recording { - .wave-bar { - animation: waveAnimation 1.2s infinite ease-in-out; - } - } - } - - .voice-tip { - font-size: 28rpx; - color: $color-text; - } - } - - .voice-actions { - padding: 32rpx; - display: flex; - justify-content: center; - - .voice-btn { - width: 120rpx; - height: 120rpx; - border-radius: 50%; - background-color: $color-user; - display: flex; - align-items: center; - justify-content: center; - box-shadow: 0 8rpx 24rpx rgba(134, 117, 169, 0.3); - transition: all 0.3s ease; - - &:hover { - transform: scale(1.05); - background-color: #756298; - } - - .iconfont { - font-size: 56rpx; - color: white; - } - } - } - } - - /* 头像选择弹窗样式 */ - .avatar-selector-panel { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - background-color: $bg-card; - border-radius: $radius-lg; - padding: 32rpx; - width: 580rpx; - box-shadow: 0 8rpx 36rpx rgba(0, 0, 0, 0.15); - - .avatar-selector-header { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 32rpx; - border-bottom: 2rpx solid #f0f4f8; - padding-bottom: 24rpx; - - text { - font-size: 34rpx; - font-weight: 600; - color: $color-text; - } - - .close-btn { - width: 64rpx; - height: 64rpx; - border-radius: 50%; - background-color: $bg-main; - display: flex; - align-items: center; - justify-content: center; - transition: all 0.2s ease; - border: none; - - &:hover { - background-color: #e8edf3; - } - - .iconfont { - font-size: 34rpx; - color: $color-text-light; - } - } - } - - .avatar-selector-content { - .current-avatar-preview { - width: 200rpx; - height: 200rpx; - border-radius: 50%; - overflow: hidden; - margin: 0 auto 48rpx; - box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.1); - border: 8rpx solid $bg-main; - - image { - width: 100%; - height: 100%; - object-fit: cover; - } - } - - .avatar-selector-actions { - display: flex; - flex-direction: column; - gap: 24rpx; - - .avatar-select-action { - height: 96rpx; - border-radius: $radius-lg; - background-color: $bg-main; - font-size: 28rpx; - color: $color-text; - display: flex; - align-items: center; - justify-content: center; - gap: 16rpx; - transition: all 0.2s ease; - border: 2rpx solid #f0f4f8; - - &:hover { - background-color: #e8edf3; - } - - &.cancel { - background-color: $bg-card; - color: $color-text-light; - - &:hover { - background-color: #f8fafc; - } - } - - .iconfont { - font-size: 36rpx; - color: $color-primary; - } - } - } - } - } - - /* 动画定义 */ - @keyframes dotPulse { - 0%, 100% { - transform: scale(1); - opacity: 0.7; - } - 50% { - transform: scale(1.3); - opacity: 1; - } - } - - @keyframes shine { - 0% { - left: -100%; - } - 100% { - left: 200%; - } - } - - @keyframes waveAnimation { - 0%, 100% { - height: 40rpx; - background-color: $color-primary-light; - } - 50% { - height: 120rpx; - background-color: $color-primary; - } + background-color: $bg-main; + transition: all 0.2s ease; + box-shadow: none; + box-sizing: border-box; // 确保输入框不超出容器 + + &:focus { + border-color: $color-primary; + box-shadow: 0 0 0 4rpx rgba(108, 142, 191, 0.1); } - /* 新增:渐变流动动画(仅为背景增加动效,不影响其他样式) */ - @keyframes gradient-flow { - 0% { - background-position: 0% 50%; - } - 50% { - background-position: 100% 50%; - } - 100% { - background-position: 0% 50%; - } - } - - /* 富文本样式补充 */ - rich-text { - line-height: 1.8; - font-size: 26rpx; - color: $color-text; - display: block; - - strong { - font-weight: 600; - color: $color-text; - } - - em { - font-style: italic; - color: $color-text-light; - } - - code { - background-color: #f0f4f8; - padding: 4rpx 8rpx; - border-radius: $radius-sm; - font-family: monospace; - font-size: 24rpx; - color: $color-primary; - } - - a { - color: $color-primary; - text-decoration: underline; - text-underline-offset: 4rpx; - } - - br { - display: block; - height: 24rpx; - } - } - - /* 适配小程序和H5的按钮默认样式重置 */ - button { - padding: 0; - margin: 0; - border: none; - background: none; - line-height: normal; - font-weight: normal; - outline: none; - - &::after { - border: none; - } - } - - /* 滑块样式优化 */ - slider { - height: 12rpx; - - &::before { - height: 12rpx; - border-radius: 6rpx; - } - - &::after { - width: 24rpx; - height: 24rpx; - border-radius: 50%; - background-color: $color-primary; - border: none; - box-shadow: 0 2rpx 8rpx rgba(108, 142, 191, 0.3); - } - } - - /* 输入框聚焦样式优化 */ - input:focus, textarea:focus { - outline: none; - } - - /* 响应式适配:小屏幕设备 */ - @media (max-width: 375px) { - .ai-chat-container { - padding-bottom: calc(env(safe-area-inset-bottom) + 16rpx); - } - - .chat-messages { - padding: 16rpx 24rpx; - } - - .message-item { - margin-bottom: 24rpx; - } - - .user-message, .ai-message { - .avatar { - width: 72rpx; - height: 72rpx; - } - - .message-content { - margin-left: 16rpx; - max-width: calc(100% - 88rpx); - } - - .user-message .message-content { - margin-right: 16rpx; - } - } - - .message-bubble { - padding: 20rpx 24rpx !important; - } - - .message-text { - font-size: 26rpx !important; - } - - .input-area { - padding: 16rpx 24rpx; - padding-bottom: calc(16rpx + env(safe-area-inset-bottom)); - } - - .input-tools .tool-btn { - width: 56rpx; - height: 56rpx; - margin-right: 12rpx; - } - - .input-container .message-input { - min-height: 76rpx; - padding: 20rpx 24rpx; - font-size: 26rpx; - } - - .send-btn { - width: 96rpx; - height: 68rpx; - font-size: 26rpx; - } - - .avatar-selector-panel, .nickname-editor-panel { - width: 90vw; - padding: 24rpx; - } - - .avatar-selector-content .current-avatar-preview { - width: 160rpx; - height: 160rpx; - margin-bottom: 32rpx; - } - - .voice-input-panel .voice-content .voice-wave { - width: 200rpx; - height: 200rpx; - } - } - - /* 深色模式适配(可选) */ - @media (prefers-color-scheme: dark) { - $bg-main: #1e2128; - $bg-card: #2d3139; - $color-text: #e5e7eb; - $color-text-light: #9ca3af; - $color-primary: #8197c3; - $color-primary-light: #9aa7c0; - $color-user: #a594cc; - - .ai-chat-container { - background-color: $bg-main; - } - - .message-bubble { - border-color: #3d4149; - } - - .ai-message .message-bubble::before { - background: $bg-card; - border-color: #3d4149; - } - - .input-area { - background-color: $bg-card; - border-top-color: #3d4149; - } - - .input-tools .tool-btn, - .tools-header .close-btn, - .voice-header .close-btn, - .avatar-selector-header .close-btn, - .nickname-editor-header .close-btn { - background-color: $bg-main; - } - - .message-input, - .nickname-input { - background-color: $bg-main; - border-color: #3d4149; - color: $color-text; - } - - .tools-panel, .voice-input-panel, .avatar-selector-panel, .nickname-editor-panel { - background-color: $bg-card; - } - - .tools-header, .voice-header, .avatar-selector-header, .nickname-editor-header { - border-bottom-color: #3d4149; - } - - .tool-item .tool-icon, - .voice-wave { - background-color: $bg-main; - } - - .avatar-select-action, - .nickname-action-btn.cancel { - background-color: $bg-main; - border-color: #3d4149; - } + &::placeholder { + color: $color-text-light; + opacity: 0.8; } } - \ No newline at end of file + } + + .nickname-tip { + font-size: 24rpx; + color: $color-text-light; + margin-bottom: 32rpx; + text-align: center; + width: 100%; + box-sizing: border-box; + } + + .nickname-editor-actions { + display: flex; + gap: 24rpx; + width: 100%; + box-sizing: border-box; + justify-content: center; + padding: 0 20rpx; + + .nickname-action-btn { + flex: none; + width: 160rpx; + height: 96rpx; + border-radius: $radius-lg; + font-size: 28rpx; + font-weight: 500; + transition: all 0.2s ease; + box-sizing: border-box; + // 核心:文字下移 + 垂直居中 + padding-top: 12rpx; // 顶部内边距增加,文字下移 + padding-bottom: 0; + line-height: 1; + display: flex; + align-items: center; + justify-content: center; + + // hover动效:文字轻微上移 + &:hover { + padding-top: 8rpx; + } + + &.cancel { + background-color: $bg-card; + border: 2rpx solid #f0f4f8; + color: $color-text-light; + + // 修复:替换未定义的 $f8fafc 为已定义的 $bg-main + &:hover { + background-color: $bg-main; + } + } + + &.confirm { + background-color: $color-primary; + color: white; + box-shadow: 0 4rpx 12rpx rgba(108, 142, 191, 0.2); + + &:hover { + background-color: #5a7cb0; + transform: translateY(-2rpx); + } + + &.disabled { + background-color: $color-primary-light; + box-shadow: none; + opacity: 0.7; + transform: none; + } + } + } + } + } + } + /* 弹窗样式基础 */ + .tools-popup, .voice-popup, .avatar-selector-popup { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: 999; + } + + .tools-mask, .voice-mask, .avatar-selector-mask { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0, 0, 0, 0.4); + backdrop-filter: blur(6rpx); + } + + /* 工具面板样式 */ + .tools-panel { + position: absolute; + bottom: 0; + left: 0; + right: 0; + background-color: $bg-card; + border-radius: $radius-lg $radius-lg 0 0; + box-shadow: 0 -4rpx 24rpx rgba(0, 0, 0, 0.1); + + .tools-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 32rpx; + border-bottom: 2rpx solid #f0f4f8; + + text { + font-size: 34rpx; + font-weight: 600; + color: $color-text; + } + + .close-btn { + width: 64rpx; + height: 64rpx; + border-radius: 50%; + background-color: $bg-main; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.2s ease; + border: none; + + &:hover { + background-color: #e8edf3; + } + + .iconfont { + font-size: 34rpx; + color: $color-text-light; + } + } + } + + .tools-grid { + display: grid; + grid-template-columns: repeat(4, 1fr); + padding: 32rpx; + gap: 32rpx; + + .tool-item { + display: flex; + flex-direction: column; + align-items: center; + transition: all 0.3s ease; + + &:hover { + transform: translateY(-4rpx); + } + + .tool-icon { + width: 96rpx; + height: 96rpx; + border-radius: 50%; + background-color: $bg-main; + display: flex; + align-items: center; + justify-content: center; + margin-bottom: 16rpx; + box-shadow: $shadow-sm; + + .iconfont { + font-size: 48rpx; + color: $color-primary; + } + } + + .tool-text { + font-size: 26rpx; + color: $color-text; + } + } + } + } + + /* 语音输入面板样式 */ + .voice-input-panel { + position: absolute; + bottom: 0; + left: 0; + right: 0; + background-color: $bg-card; + border-radius: $radius-lg $radius-lg 0 0; + box-shadow: 0 -4rpx 24rpx rgba(0, 0, 0, 0.1); + + .voice-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 32rpx; + border-bottom: 2rpx solid #f0f4f8; + + text { + font-size: 34rpx; + font-weight: 600; + color: $color-text; + } + + .close-btn { + width: 64rpx; + height: 64rpx; + border-radius: 50%; + background-color: $bg-main; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.2s ease; + border: none; + + &:hover { + background-color: #e8edf3; + } + + .iconfont { + font-size: 34rpx; + color: $color-text-light; + } + } + } + + .voice-content { + padding: 64rpx 32rpx; + display: flex; + flex-direction: column; + align-items: center; + + .voice-wave { + width: 240rpx; + height: 240rpx; + border-radius: 50%; + background-color: $bg-main; + display: flex; + align-items: center; + justify-content: center; + margin-bottom: 48rpx; + box-shadow: $shadow-md; + + .wave-bar { + width: 12rpx; + height: 40rpx; + background-color: $color-primary-light; + border-radius: 6rpx; + margin: 0 8rpx; + transition: height 0.3s ease; + } + + &.recording { + .wave-bar { + animation: waveAnimation 1.2s infinite ease-in-out; + } + } + } + + .voice-tip { + font-size: 28rpx; + color: $color-text; + } + } + + .voice-actions { + padding: 32rpx; + display: flex; + justify-content: center; + + .voice-btn { + width: 120rpx; + height: 120rpx; + border-radius: 50%; + background-color: $color-user; + display: flex; + align-items: center; + justify-content: center; + box-shadow: 0 8rpx 24rpx rgba(134, 117, 169, 0.3); + transition: all 0.3s ease; + + &:hover { + transform: scale(1.05); + background-color: #756298; + } + + .iconfont { + font-size: 56rpx; + color: white; + } + } + } + } + + /* 头像选择弹窗样式 */ + .avatar-selector-panel { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + background-color: $bg-card; + border-radius: $radius-lg; + padding: 32rpx; + width: 580rpx; + box-shadow: 0 8rpx 36rpx rgba(0, 0, 0, 0.15); + + .avatar-selector-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 32rpx; + border-bottom: 2rpx solid #f0f4f8; + padding-bottom: 24rpx; + + text { + font-size: 34rpx; + font-weight: 600; + color: $color-text; + } + + .close-btn { + width: 64rpx; + height: 64rpx; + border-radius: 50%; + background-color: $bg-main; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.2s ease; + border: none; + + &:hover { + background-color: #e8edf3; + } + + .iconfont { + font-size: 34rpx; + color: $color-text-light; + } + } + } + + .avatar-selector-content { + .current-avatar-preview { + width: 200rpx; + height: 200rpx; + border-radius: 50%; + overflow: hidden; + margin: 0 auto 48rpx; + box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.1); + border: 8rpx solid $bg-main; + + image { + width: 100%; + height: 100%; + object-fit: cover; + } + } + + .avatar-selector-actions { + display: flex; + flex-direction: column; + gap: 24rpx; + + .avatar-select-action { + height: 96rpx; + border-radius: $radius-lg; + background-color: $bg-main; + font-size: 28rpx; + color: $color-text; + display: flex; + align-items: center; + justify-content: center; + gap: 16rpx; + transition: all 0.2s ease; + border: 2rpx solid #f0f4f8; + + &:hover { + background-color: #e8edf3; + } + + &.cancel { + background-color: $bg-card; + color: $color-text-light; + + &:hover { + background-color: #f8fafc; + } + } + + .iconfont { + font-size: 36rpx; + color: $color-primary; + } + } + } + } + } + + /* 动画定义 */ + @keyframes dotPulse { + 0%, 100% { + transform: scale(1); + opacity: 0.7; + } + 50% { + transform: scale(1.3); + opacity: 1; + } + } + + @keyframes shine { + 0% { + left: -100%; + } + 100% { + left: 200%; + } + } + + @keyframes waveAnimation { + 0%, 100% { + height: 40rpx; + background-color: $color-primary-light; + } + 50% { + height: 120rpx; + background-color: $color-primary; + } + } + + /* 新增:渐变流动动画(仅为背景增加动效,不影响其他样式) */ + @keyframes gradient-flow { + 0% { + background-position: 0% 50%; + } + 50% { + background-position: 100% 50%; + } + 100% { + background-position: 0% 50%; + } + } + + /* 富文本样式补充 */ + rich-text { + line-height: 1.8; + font-size: 26rpx; + color: $color-text; + display: block; + + strong { + font-weight: 600; + color: $color-text; + } + + em { + font-style: italic; + color: $color-text-light; + } + + code { + background-color: #f0f4f8; + padding: 4rpx 8rpx; + border-radius: $radius-sm; + font-family: monospace; + font-size: 24rpx; + color: $color-primary; + } + + a { + color: $color-primary; + text-decoration: underline; + text-underline-offset: 4rpx; + } + + br { + display: block; + height: 24rpx; + } + } + + /* 适配小程序和H5的按钮默认样式重置 */ + button { + padding: 0; + margin: 0; + border: none; + background: none; + line-height: normal; + font-weight: normal; + outline: none; + + &::after { + border: none; + } + } + + /* 滑块样式优化 */ + slider { + height: 12rpx; + + &::before { + height: 12rpx; + border-radius: 6rpx; + } + + &::after { + width: 24rpx; + height: 24rpx; + border-radius: 50%; + background-color: $color-primary; + border: none; + box-shadow: 0 2rpx 8rpx rgba(108, 142, 191, 0.3); + } + } + + /* 输入框聚焦样式优化 */ + input:focus, textarea:focus { + outline: none; + } + + /* 响应式适配:小屏幕设备 */ + @media (max-width: 375px) { + .ai-chat-container { + padding-bottom: calc(env(safe-area-inset-bottom) + 16rpx); + } + + .chat-messages { + padding: 16rpx 24rpx; + } + + .message-item { + margin-bottom: 24rpx; + } + + .user-message, .ai-message { + .avatar { + width: 72rpx; + height: 72rpx; + } + + .message-content { + margin-left: 16rpx; + max-width: calc(100% - 88rpx); + } + + .user-message .message-content { + margin-right: 16rpx; + } + } + + .message-bubble { + padding: 20rpx 24rpx !important; + } + + .message-text { + font-size: 26rpx !important; + } + + .input-area { + padding: 16rpx 24rpx; + padding-bottom: calc(16rpx + env(safe-area-inset-bottom)); + } + + .input-tools .tool-btn { + width: 56rpx; + height: 56rpx; + margin-right: 12rpx; + } + + .input-container .message-input { + min-height: 76rpx; + padding: 20rpx 24rpx; + font-size: 26rpx; + } + + .send-btn { + width: 96rpx; + height: 68rpx; + font-size: 26rpx; + } + + .avatar-selector-panel, .nickname-editor-panel { + width: 90vw; + padding: 24rpx; + } + + .avatar-selector-content .current-avatar-preview { + width: 160rpx; + height: 160rpx; + margin-bottom: 32rpx; + } + + .voice-input-panel .voice-content .voice-wave { + width: 200rpx; + height: 200rpx; + } + } + + /* 深色模式适配(可选) */ + @media (prefers-color-scheme: dark) { + $bg-main: #1e2128; + $bg-card: #2d3139; + $color-text: #e5e7eb; + $color-text-light: #9ca3af; + $color-primary: #8197c3; + $color-primary-light: #9aa7c0; + $color-user: #a594cc; + + .ai-chat-container { + background-color: $bg-main; + } + + .message-bubble { + border-color: #3d4149; + } + + .ai-message .message-bubble::before { + background: $bg-card; + border-color: #3d4149; + } + + .input-area { + background-color: $bg-card; + border-top-color: #3d4149; + } + + .input-tools .tool-btn, + .tools-header .close-btn, + .voice-header .close-btn, + .avatar-selector-header .close-btn, + .nickname-editor-header .close-btn { + background-color: $bg-main; + } + + .message-input, + .nickname-input { + background-color: $bg-main; + border-color: #3d4149; + color: $color-text; + } + + .tools-panel, .voice-input-panel, .avatar-selector-panel, .nickname-editor-panel { + background-color: $bg-card; + } + + .tools-header, .voice-header, .avatar-selector-header, .nickname-editor-header { + border-bottom-color: #3d4149; + } + + .tool-item .tool-icon, + .voice-wave { + background-color: $bg-main; + } + + .avatar-select-action, + .nickname-action-btn.cancel { + background-color: $bg-main; + border-color: #3d4149; + } + } + } + \ No newline at end of file