chore:添加欢迎语配套快捷问题功能,支持用户快速发送常见问题;优化数据格式处理与样式

This commit is contained in:
2026-09-20 15:07:43 +08:00
parent 2b1f8a4fe2
commit 8fd68033ed

View File

@@ -288,7 +288,22 @@
</text>
</view>
</view>
<!-- PR-WELCOME-QUICK-CHIPS (2026-09-19): 欢迎语配套快捷问题
欢迎语气泡下方显示快捷问题 chips, 点击直接作为用户消息发送
一次性,点了之后从 message 上摘除 (避免重复点) -->
<view v-if="message.quickQuestions && message.quickQuestions.length > 0" class="quick-questions-row">
<view
v-for="(q, qi) in message.quickQuestions"
:key="qi"
class="quick-question-chip"
hover-class="quick-question-chip--hover"
@click="onQuickQuestionClick(message, q)">
<text class="quick-question-icon">💬</text>
<text class="quick-question-text">{{ getQuickQuestionText(q) }}</text>
</view>
</view>
<!-- 操作按钮 -->
<view class="message-actions" v-if="message.actions && message.actions.length > 0">
<button
@@ -1011,13 +1026,16 @@ export default {
let welcomeText = ''
let isMarkdown = false
let welcomeLoaded = false
// PR-FIX (2026-09-20): welcomeInfo 原为 if 块内 const,第 3 步拼 quickQuestions
// 时在块外引用 → ReferenceError, 提升到函数作用域
let welcomeInfo = null
// 1. 尝试从 API 获取远程欢迎语
try {
const config = await aiService.getServiceConfig()
console.log('[AI Chat] API getServiceConfig 返回:', JSON.stringify(config))
if (config) {
const welcomeInfo = config.welcome_info
welcomeInfo = config.welcome_info
console.log('[AI Chat] welcomeInfo:', JSON.stringify(welcomeInfo))
const remoteText = welcomeInfo?.welcome || ''
const isEnabled = welcomeInfo?.is_enabled
@@ -1053,7 +1071,11 @@ export default {
type: isMarkdown ? 'markdown' : 'text',
content: welcomeText,
timestamp: Date.now(),
actions: []
actions: [],
// PR-WELCOME-QUICK-CHIPS (2026-09-19): 欢迎语配套快捷问题 (chips)
// 后端可存 string[] 或 {id,text}[] ,前端统一归一化为 string[]
// message.quickQuestions 数组非空 → 模板渲染 chips;点击调 onQuickQuestionClick
quickQuestions: this.normalizeQuickQuestions(welcomeInfo && welcomeInfo.quick_questions)
}
this.messages.push(welcomeMsg)
this.$nextTick(() => this.scrollToBottom())
@@ -1061,6 +1083,46 @@ export default {
}
},
// PR-WELCOME-QUICK-CHIPS (2026-09-19): 归一化 quick_questions 数据格式
// 后端可能存 string[] ("如何下单?" / "退换货流程")
// 也可能存 {id, text}[] ({id:'q1',text:'如何下单?'})
// 前端统一抽出 text,空值过滤
normalizeQuickQuestions(raw) {
if (!Array.isArray(raw)) return []
return raw
.map(function (q) {
if (q && typeof q === 'object') return q.text || q.label || ''
return String(q || '')
})
.filter(function (s) { return s && s.trim() !== '' })
},
// PR-WELCOME-QUICK-CHIPS (2026-09-19): 渲染文本提取
getQuickQuestionText(q) {
if (q && typeof q === 'object') return q.text || q.label || ''
return String(q || '')
},
// PR-WELCOME-QUICK-CHIPS (2026-09-19): 点击 chip
// 1. 把文本塞进 inputText,模拟"用户已输入"
// 2. 清空 welcome bubble 的 chips (一次性)
// 3. 调 sendMessage() 走正常 chat 流 (建 user bubble + AI 回复)
async onQuickQuestionClick(message, q) {
const text = this.getQuickQuestionText(q)
if (!text || !text.trim()) return
try {
// 一次性:点了就摘掉 chips,避免重复点
message.quickQuestions = []
// 走现有 sendMessage 流程 (inputText → 校验 → sendStream/Normal)
this.inputText = text
// 让 DOM 先更新再发,避免用户视觉上"消息凭空出现"
await this.$nextTick()
await this.sendMessage()
} catch (e) {
console.warn('[AI Chat] onQuickQuestionClick failed:', e && e.message)
}
},
// 生成消息的唯一 key(兼容非 H5 平台)
getMessageKey(message, index) {
const rawId = message.id || message.timestamp || index;
@@ -3827,6 +3889,50 @@ _handleStreamError(msg) {
}
}
// PR-WELCOME-QUICK-CHIPS (2026-09-19): 欢迎语配套快捷问题 chip 样式
.quick-questions-row {
margin-top: 16rpx;
display: flex;
flex-wrap: wrap;
gap: 16rpx;
justify-content: flex-start;
max-width: 100%;
.quick-question-chip {
display: inline-flex;
align-items: center;
gap: 8rpx;
padding: 12rpx 24rpx;
background: #ffffff;
border: 1rpx solid #1E9FFF;
border-radius: 32rpx;
font-size: 26rpx;
color: #1E9FFF;
cursor: pointer;
transition: all 0.2s ease;
max-width: 100%;
line-height: 1.4;
.quick-question-icon {
font-size: 24rpx;
flex-shrink: 0;
}
.quick-question-text {
flex: 1;
word-break: break-word;
white-space: pre-wrap;
}
}
.quick-question-chip--hover {
background: #1E9FFF;
color: #ffffff;
transform: translateY(-1rpx);
box-shadow: 0 4rpx 12rpx rgba(30, 159, 255, 0.2);
}
}
.message-actions {
margin-top: 24rpx;
display: flex;
@@ -3834,7 +3940,7 @@ _handleStreamError(msg) {
justify-content: flex-start;
flex-wrap: nowrap;
width: 100%;
.action-btn {
border-radius: $radius-lg;
font-size: 22rpx;