小程序迁移 静态页面完成!!!
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
import { mockChatMessages } from '../../utils/mock-data'
|
||||
import type { ChatMessage } from '../../utils/mock-data'
|
||||
import { simulateStreamOutput } from '../../utils/chat'
|
||||
import { formatRelativeTime, formatIMTime, shouldShowTimeDivider } from '../../utils/time'
|
||||
|
||||
/** 将 referenceCard.data (Record<string,string>) 转为数组供 WXML wx:for 渲染 */
|
||||
function toDataList(data?: Record<string, string>): Array<{ key: string; value: string }> {
|
||||
@@ -9,10 +10,16 @@ function toDataList(data?: Record<string, string>): Array<{ key: string; value:
|
||||
return Object.keys(data).map((k) => ({ key: k, value: data[k] }))
|
||||
}
|
||||
|
||||
/** 为消息列表中的 referenceCard 补充 dataList 字段 */
|
||||
/** 为消息列表补充展示字段(时间分割线、IM时间、引用卡片)*/
|
||||
function enrichMessages(msgs: ChatMessage[]) {
|
||||
return msgs.map((m) => ({
|
||||
return msgs.map((m, i) => ({
|
||||
...m,
|
||||
timeLabel: formatRelativeTime(m.timestamp),
|
||||
imTimeLabel: formatIMTime(m.timestamp),
|
||||
showTimeDivider: shouldShowTimeDivider(
|
||||
i === 0 ? null : msgs[i - 1].timestamp,
|
||||
m.timestamp,
|
||||
),
|
||||
referenceCard: m.referenceCard
|
||||
? { ...m.referenceCard, dataList: toDataList(m.referenceCard.data) }
|
||||
: undefined,
|
||||
@@ -33,7 +40,12 @@ Page({
|
||||
/** 状态栏高度 */
|
||||
statusBarHeight: 0,
|
||||
/** 消息列表 */
|
||||
messages: [] as Array<ChatMessage & { referenceCard?: ChatMessage['referenceCard'] & { dataList?: Array<{ key: string; value: string }> } }>,
|
||||
messages: [] as Array<ChatMessage & {
|
||||
timeLabel?: string
|
||||
imTimeLabel?: string
|
||||
showTimeDivider?: boolean
|
||||
referenceCard?: ChatMessage['referenceCard'] & { dataList?: Array<{ key: string; value: string }> }
|
||||
}>,
|
||||
/** 输入框内容 */
|
||||
inputText: '',
|
||||
/** AI 正在流式回复 */
|
||||
@@ -46,6 +58,8 @@ Page({
|
||||
referenceCard: null as { title: string; summary: string } | null,
|
||||
/** 客户 ID */
|
||||
customerId: '',
|
||||
/** 输入栏距底部距离(软键盘弹出时动态调整)*/
|
||||
inputBarBottom: 0,
|
||||
},
|
||||
|
||||
/** 消息计数器,用于生成唯一 ID */
|
||||
@@ -84,7 +98,6 @@ Page({
|
||||
referenceCard,
|
||||
})
|
||||
|
||||
// 滚动到底部
|
||||
this.scrollToBottom()
|
||||
}, 500)
|
||||
} catch {
|
||||
@@ -102,6 +115,18 @@ Page({
|
||||
this.loadMessages(this.data.customerId)
|
||||
},
|
||||
|
||||
/** 软键盘弹出:输入栏上移至键盘顶部 */
|
||||
onInputFocus(e: WechatMiniprogram.InputFocus) {
|
||||
const keyboardHeight = e.detail.height || 0
|
||||
this.setData({ inputBarBottom: keyboardHeight })
|
||||
setTimeout(() => this.scrollToBottom(), 120)
|
||||
},
|
||||
|
||||
/** 软键盘收起:输入栏归位 */
|
||||
onInputBlur() {
|
||||
this.setData({ inputBarBottom: 0 })
|
||||
},
|
||||
|
||||
/** 输入框内容变化 */
|
||||
onInputChange(e: WechatMiniprogram.Input) {
|
||||
this.setData({ inputText: e.detail.value })
|
||||
@@ -113,11 +138,17 @@ Page({
|
||||
if (!text || this.data.isStreaming) return
|
||||
|
||||
this._msgCounter++
|
||||
const now = new Date().toISOString()
|
||||
const prevMsgs = this.data.messages
|
||||
const prevTs = prevMsgs.length > 0 ? prevMsgs[prevMsgs.length - 1].timestamp : null
|
||||
const userMsg = {
|
||||
id: `msg-user-${this._msgCounter}`,
|
||||
role: 'user' as const,
|
||||
content: text,
|
||||
timestamp: new Date().toISOString(),
|
||||
timestamp: now,
|
||||
timeLabel: '刚刚',
|
||||
imTimeLabel: formatIMTime(now),
|
||||
showTimeDivider: shouldShowTimeDivider(prevTs, now),
|
||||
}
|
||||
|
||||
const messages = [...this.data.messages, userMsg]
|
||||
@@ -129,7 +160,6 @@ Page({
|
||||
|
||||
this.scrollToBottom()
|
||||
|
||||
// 模拟 AI 回复
|
||||
setTimeout(() => {
|
||||
this.triggerAIReply()
|
||||
}, 300)
|
||||
@@ -141,12 +171,17 @@ Page({
|
||||
const aiMsgId = `msg-ai-${this._msgCounter}`
|
||||
const replyText = mockAIReplies[this._msgCounter % mockAIReplies.length]
|
||||
|
||||
// 先添加空的 AI 消息占位
|
||||
const aiNow = new Date().toISOString()
|
||||
const prevMsgs = this.data.messages
|
||||
const prevTs = prevMsgs.length > 0 ? prevMsgs[prevMsgs.length - 1].timestamp : null
|
||||
const aiMsg = {
|
||||
id: aiMsgId,
|
||||
role: 'assistant' as const,
|
||||
content: '',
|
||||
timestamp: new Date().toISOString(),
|
||||
timestamp: aiNow,
|
||||
timeLabel: '刚刚',
|
||||
imTimeLabel: formatIMTime(aiNow),
|
||||
showTimeDivider: shouldShowTimeDivider(prevTs, aiNow),
|
||||
}
|
||||
|
||||
const messages = [...this.data.messages, aiMsg]
|
||||
@@ -158,7 +193,6 @@ Page({
|
||||
|
||||
this.scrollToBottom()
|
||||
|
||||
// 流式输出
|
||||
const aiIndex = messages.length - 1
|
||||
simulateStreamOutput(replyText, (partial: string) => {
|
||||
const key = `messages[${aiIndex}].content`
|
||||
@@ -177,7 +211,6 @@ Page({
|
||||
|
||||
/** 滚动到底部 */
|
||||
scrollToBottom() {
|
||||
// 使用 nextTick 确保 DOM 更新后再滚动
|
||||
setTimeout(() => {
|
||||
this.setData({ scrollToId: '' })
|
||||
setTimeout(() => {
|
||||
|
||||
Reference in New Issue
Block a user