Merge branch 'temp221' into dev/1.0
This commit is contained in:
@@ -257,7 +257,11 @@ const localDevConfig = ({
|
||||
// })['2811']; // 本地
|
||||
// })['5g-317']; // 电磁兼容
|
||||
// })['5g-351']; //
|
||||
<<<<<<< HEAD
|
||||
})['5g-97']; // 本地
|
||||
=======
|
||||
})['2881']; // 本地
|
||||
>>>>>>> temp221
|
||||
// })['local-2']; // 本地
|
||||
// })['local-11']; // 本地
|
||||
// })['1-test']; // test
|
||||
|
||||
@@ -234,10 +234,10 @@
|
||||
<!-- #ifdef MP-WEIXIN -->
|
||||
<!-- PR-CHAT-SELECTABLE (2026-09-23): rich-text 不支持文本选中, 改用 mp-html + selectable
|
||||
开启原生长按选中(剪切/复制/粘贴/全选); force 同时兼容微信 iOS -->
|
||||
<mp-html class="ai-message-rich" :content="getAIDisplayContent(message.content)" selectable="force" />
|
||||
<mp-html class="ai-message-rich" :content="getAIDisplayContent(message.content, message.isWelcome)" selectable="force" />
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef H5 -->
|
||||
<view class="ai-message-text selectable-md" v-html="getAIDisplayContent(message.content)"></view>
|
||||
<view class="ai-message-text selectable-md" v-html="getAIDisplayContent(message.content, message.isWelcome)"></view>
|
||||
<!-- #endif -->
|
||||
</view>
|
||||
|
||||
@@ -250,10 +250,10 @@
|
||||
<view class="markdown-body">
|
||||
<!-- #ifdef MP-WEIXIN -->
|
||||
<!-- PR-CHAT-SELECTABLE (2026-09-23): 同上, mp-html + selectable 支持长按选中复制 -->
|
||||
<mp-html class="ai-message-rich" :content="getAIDisplayContent(message.content)" selectable="force" />
|
||||
<mp-html class="ai-message-rich" :content="getAIDisplayContent(message.content, message.isWelcome)" selectable="force" />
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef H5 -->
|
||||
<view class="selectable-md" v-html="getAIDisplayContent(message.content)"></view>
|
||||
<view class="selectable-md" v-html="getAIDisplayContent(message.content, message.isWelcome)"></view>
|
||||
<!-- #endif -->
|
||||
</view>
|
||||
</view>
|
||||
@@ -529,17 +529,30 @@
|
||||
① 默认(未输入/未聚焦): 单行胶囊 —— 语音图标 + 输入框 + 加号
|
||||
② 语音模式(点语音图标进入): 「按住说话」按钮 + 底部工具栏(表情/模型/加号)
|
||||
③ 文字输入(聚焦或有文字): 输入框独占一行 + 底部工具栏(语音/模型/加号/发送) -->
|
||||
<!-- 语音模式: 按住说话 (PR-FRONTEND-VOICE-INPUT 2026-09-24) -->
|
||||
<!-- 语音模式 (PR-VOICE-MODE-ONE-ROW-V2): 整行即白色胶囊(flex),
|
||||
键盘图标在左、+ 在右、按住说话占中间 —— 不依赖绝对定位, 结构上保证单行 -->
|
||||
<view
|
||||
v-if="voiceMode"
|
||||
class="voice-hold-btn"
|
||||
:class="{ 'is-holding': voiceHolding, 'is-cancelling': voiceHoldCancelling }"
|
||||
@touchstart.stop.prevent="onVoiceHoldStart"
|
||||
@touchmove.stop.prevent="onVoiceHoldMove"
|
||||
@touchend.stop.prevent="onVoiceHoldEnd"
|
||||
@touchcancel.stop.prevent="onVoiceHoldCancel"
|
||||
@click.stop="onVoiceHoldEnd">
|
||||
<text class="voice-hold-text">{{ voiceHoldText }}</text>
|
||||
class="voice-mode-row"
|
||||
:class="{ 'is-holding': voiceHolding, 'is-cancelling': voiceHoldCancelling }">
|
||||
<!-- 左侧: 键盘图标 (点击回到文字输入) -->
|
||||
<view class="voice-side-btn voice-side-left" @click="exitVoiceMode">
|
||||
<view class="emoji-icon-bg"></view>
|
||||
</view>
|
||||
<!-- 中间: 按住说话 (按住录音, 松开发送) -->
|
||||
<view
|
||||
class="voice-hold-btn"
|
||||
@touchstart.stop.prevent="onVoiceHoldStart"
|
||||
@touchmove.stop.prevent="onVoiceHoldMove"
|
||||
@touchend.stop.prevent="onVoiceHoldEnd"
|
||||
@touchcancel.stop.prevent="onVoiceHoldCancel"
|
||||
@click.stop="onVoiceHoldEnd">
|
||||
<text class="voice-hold-text">{{ voiceHoldText }}</text>
|
||||
</view>
|
||||
<!-- 右侧: 加号 -->
|
||||
<button class="top-plus-btn voice-side-right" @click="showMoreTools">
|
||||
<text class="plus-icon">+</text>
|
||||
</button>
|
||||
</view>
|
||||
<!-- 按住时的「上滑取消」提示 (H5/MP 共用) -->
|
||||
<view v-if="voiceHolding" class="voice-cancel-hint">{{ voiceHoldCancelling ? $lang('ai-chat.index.slideUpToCancelHint') : $lang('ai-chat.index.slideUpToCancel') }}</view>
|
||||
@@ -587,14 +600,10 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部工具栏行: 语音模式 / 文字输入时显示 -->
|
||||
<view v-if="voiceMode || showTextMode" class="input-toolbar-row">
|
||||
<!-- 语音模式: 键盘图标 (点击回到文字输入) -->
|
||||
<view v-if="voiceMode" class="toolbar-round-btn" @click="exitVoiceMode">
|
||||
<view class="emoji-icon-bg"></view>
|
||||
</view>
|
||||
<!-- 底部工具栏行: 仅文字输入时显示 (语音模式的键盘/加号已并入按住说话同一行) -->
|
||||
<view v-if="showTextMode" class="input-toolbar-row">
|
||||
<!-- 文字输入: 语音图标 (切到按住说话) -->
|
||||
<view v-else class="toolbar-round-btn" @click="enterVoiceMode">
|
||||
<view class="toolbar-round-btn" @click="enterVoiceMode">
|
||||
<view class="voice-icon-bg"></view>
|
||||
</view>
|
||||
|
||||
@@ -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(/(<img[^>]*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 插入的 <img>, 不带 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;
|
||||
|
||||
Reference in New Issue
Block a user