diff --git a/.local.config.js b/.local.config.js index 973319c..f81a81b 100644 --- a/.local.config.js +++ b/.local.config.js @@ -257,7 +257,11 @@ const localDevConfig = ({ // })['2811']; // 本地 // })['5g-317']; // 电磁兼容 // })['5g-351']; // +<<<<<<< HEAD })['5g-97']; // 本地 +======= + })['2881']; // 本地 +>>>>>>> temp221 // })['local-2']; // 本地 // })['local-11']; // 本地 // })['1-test']; // test diff --git a/pages_tool/ai-chat/ai-chat-message.vue b/pages_tool/ai-chat/ai-chat-message.vue index 38e75f3..fe0ee3b 100644 --- a/pages_tool/ai-chat/ai-chat-message.vue +++ b/pages_tool/ai-chat/ai-chat-message.vue @@ -234,10 +234,10 @@ - + - + @@ -250,10 +250,10 @@ - + - + @@ -529,17 +529,30 @@ ① 默认(未输入/未聚焦): 单行胶囊 —— 语音图标 + 输入框 + 加号 ② 语音模式(点语音图标进入): 「按住说话」按钮 + 底部工具栏(表情/模型/加号) ③ 文字输入(聚焦或有文字): 输入框独占一行 + 底部工具栏(语音/模型/加号/发送) --> - + - {{ voiceHoldText }} + class="voice-mode-row" + :class="{ 'is-holding': voiceHolding, 'is-cancelling': voiceHoldCancelling }"> + + + + + + + {{ voiceHoldText }} + + + {{ voiceHoldCancelling ? $lang('ai-chat.index.slideUpToCancelHint') : $lang('ai-chat.index.slideUpToCancel') }} @@ -587,14 +600,10 @@ - - - - - - + + - + @@ -3928,17 +3937,24 @@ _handleStreamError(msg) { }, // AI 消息渲染(含关键词高亮) - getAIDisplayContent(content) { + // isWelcome: 欢迎语消息 — 小程序端 mp-html 组件有样式隔离, 页面样式(::v-deep)进不去, + // 图片间距只能在内容层面改内联样式(机器人图片与下方标题的间距, 对齐 WorkBuddy 参考稿) + getAIDisplayContent(content, isWelcome) { + let html if (!this.searchKeyword || !content) { - return this.parseMarkdown(content) + html = this.parseMarkdown(content) + } else if (content.toLowerCase().indexOf(this.searchKeyword.toLowerCase()) === -1) { + html = this.parseMarkdown(content) + } else { + // 先做 markdown 渲染,再做关键词高亮 + const mdHtml = this.parseMarkdown(content) + html = this._wrapHighlightInHtml(mdHtml, this.searchKeyword) } - // 仅当内容包含关键词时才执行高亮,避免非匹配消息的额外处理 - if (content.toLowerCase().indexOf(this.searchKeyword.toLowerCase()) === -1) { - return this.parseMarkdown(content) + if (isWelcome && html) { + // 仅替换 img 的 margin(机器人图片), 不影响列表等其他元素的 margin:8rpx 0 + html = html.replace(/(]*style="[^"]*?)margin:\s*8rpx 0;/, '$1margin:0 0 48rpx 0;') } - // 先做 markdown 渲染,再做关键词高亮 - const mdHtml = this.parseMarkdown(content) - return this._wrapHighlightInHtml(mdHtml, this.searchKeyword) + return html }, // 在纯文本中高亮关键词(用于用户消息) @@ -4780,11 +4796,24 @@ _handleStreamError(msg) { background: #ffffff !important; } + // 欢迎语消息: 图片(机器人)与下方标题的间距加大, 对齐 WorkBuddy 参考稿 + // 图片是 v-html 插入的 , 不带 scoped 的 data-v 属性, + // 普通 img 选择器编译后会匹配不到, 必须用 ::v-deep 穿透 + &.is-welcome .ai-message .message-bubble ::v-deep img { + margin-bottom: 48rpx !important; + } + // 欢迎语消息: 隐藏上方时间戳 &.is-welcome .ai-message .message-nickname.ai-nickname { display: none; } + // 欢迎语消息: 标题与快捷问题的间距, 与"图片→标题"保持一致 (48rpx) + // 下方 5326 行的 .quick-questions-row 嵌套链更长、特异性更高, 必须 !important 覆盖 + &.is-welcome .quick-questions-row { + margin-top: 48rpx !important; + } + // 搜索定位 - 当前结果: 用柔和的浅绿底色提示 (WorkBuddy 风格, 无气泡 box-shadow) &.search-current { position: relative; @@ -5323,7 +5352,7 @@ _handleStreamError(msg) { margin-bottom: 16rpx; padding: 12rpx 28rpx; background: #ffffff; - border: 1rpx solid #e4e6eb; + border: 1rpx solid #eef0f3; border-radius: 999rpx; font-size: 26rpx; color: #1a1a1a; @@ -5331,7 +5360,7 @@ _handleStreamError(msg) { transition: all 0.2s ease; max-width: 100%; line-height: 1.4; - box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08); + box-shadow: 0 6rpx 20rpx rgba(0, 0, 0, 0.14); &:last-child { margin-bottom: 0; @@ -5753,6 +5782,7 @@ _handleStreamError(msg) { height: 56rpx; padding: 0 20rpx; gap: 8rpx; + margin-top: 20rpx; .refresh-icon { width: 28rpx; @@ -5810,9 +5840,12 @@ _handleStreamError(msg) { justify-content: space-between; background: #ffffff; border-radius: 999rpx; - padding: 18rpx 14rpx 18rpx 32rpx; - min-height: 108rpx; - box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.06); + /* 高度与语音模式胶囊(.voice-mode-row: height 96rpx)保持一致: + 内部图标容器 76rpx + 上下 padding 10rpx*2 = 96rpx */ + padding: 10rpx 14rpx 10rpx 32rpx; + min-height: 96rpx; + /* 与快捷问题按钮(.quick-question-chip)同款阴影, 白底更突出 */ + box-shadow: 0 6rpx 20rpx rgba(0, 0, 0, 0.14); /* 无文字时左侧语音图标,点击打开语音面板 PR-INPUT-LAYOUT-SYMMETRY (2026-09-28): 容器从 52rpx 扩大到 76rpx, @@ -5944,17 +5977,24 @@ _handleStreamError(msg) { background-size: contain; } - /* 展开态: 卡片变白底圆角容器, 内部输入行不再单独成胶囊 */ + /* 展开态: 文字输入时卡片变白底圆角容器; + 语音模式卡片保持透明, 白色胶囊由 .voice-mode-row 自身呈现 (避免双层白底) */ .input-card { - &.is-voice-mode, &.is-text-mode { background: #ffffff; border-radius: 28rpx; padding: 14rpx 16rpx 6rpx; - box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.06); + /* 与快捷问题按钮(.quick-question-chip)同款阴影 */ + box-shadow: 0 6rpx 20rpx rgba(0, 0, 0, 0.14); + } + + &.is-voice-mode { + background: transparent; + border-radius: 0; + padding: 0; + box-shadow: none; } - &.is-voice-mode .input-row-top, &.is-text-mode .input-row-top { background: transparent; border-radius: 0; @@ -5964,30 +6004,54 @@ _handleStreamError(msg) { } } - /* 语音模式: 按住说话 */ - .voice-hold-btn { + /* 语音模式单行 (PR-VOICE-MODE-ONE-ROW-V2): 整行即白色胶囊(flex布局,不依赖绝对定位) + 键盘图标在左 / 按住说话占中间 / + 在右, 与参考稿一致 */ + .voice-mode-row { + position: relative; /* 「上滑取消」提示 .voice-cancel-hint 锚定到这里 */ display: flex; align-items: center; - justify-content: center; height: 96rpx; margin: 4rpx 0 8rpx; - border-radius: 16rpx; - background: #f2f2f3; - position: relative; // PR-FRONTEND-VOICE-INPUT: 让 .voice-cancel-hint 锚定到这里 + padding: 0 10rpx 0 24rpx; + border-radius: 999rpx; + background: #ffffff; + box-shadow: 0 6rpx 20rpx rgba(0, 0, 0, 0.14); transition: background-color 0.15s ease-out; &.is-holding { - background: #e2e2e4; + background: #f2f2f3; } // PR-FRONTEND-VOICE-INPUT (2026-09-24): 上滑到 80px+ 视为取消手势 &.is-cancelling { background: #fdecec; + .voice-hold-text { color: #d23f3f; } } + .voice-side-btn { + flex-shrink: 0; + display: flex; + align-items: center; + justify-content: center; + } + + .voice-side-right { + margin-left: 8rpx; + } + + /* 按住说话区域: 透明, 占据中间剩余全部空间 */ + .voice-hold-btn { + flex: 1; + height: 100%; + min-width: 0; + display: flex; + align-items: center; + justify-content: center; + } + .voice-hold-text { font-size: 30rpx; color: #1f1f1f;