| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519 |
- const _app = getApp()
- // 办公助手服务配置
- const ServiceConfig = {
- // 样例API地址,请替换为您的真实服务地址
- apiUrl: 'https://kt.colexiu.com/edu-app/open/coze/agent',
- // 请求超时时间(毫秒)
- timeout: 60000,
- // 请求头配置
- headers: {
- 'Content-Type': 'application/json'
- }
- }
- // 用户信息管理
- const UserManager = {
- // 获取用户唯一标识
- getUserIdentifier: function () {
- return new Promise((resolve, _reject) => {
- // 尝试从缓存获取用户ID
- const cachedUserId = tt.getStorageSync('user_id')
- if (cachedUserId) {
- resolve(cachedUserId)
- return
- }
-
- // 调用登录API获取用户标识
- tt.login({
- force: false, // 不强制调起登录框
- success: function (res) {
- console.log('登录成功:', res)
-
- if (res.isLogin && res.code) {
- // 已登录用户,使用code作为临时标识
- // 实际应用中,应该将code发送到服务端换取openid
- const userId = 'user_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9)
-
- // 缓存用户ID
- tt.setStorageSync('user_id', userId)
- resolve(userId)
- } else if (res.anonymousCode) {
- // 匿名用户,使用anonymousCode作为标识
- const anonymousUserId = 'anonymous_' + res.anonymousCode.substr(0, 16)
-
- // 缓存匿名用户ID
- tt.setStorageSync('user_id', anonymousUserId)
- resolve(anonymousUserId)
- } else {
- // 生成默认用户ID
- const defaultUserId = 'default_' + Date.now()
- tt.setStorageSync('user_id', defaultUserId)
- resolve(defaultUserId)
- }
- },
- fail: function (err) {
- console.error('登录失败:', err)
- // 生成默认用户ID作为备选
- const defaultUserId = 'default_' + Date.now()
- tt.setStorageSync('user_id', defaultUserId)
- resolve(defaultUserId)
- }
- })
- })
- },
-
- // 清除用户信息
- clearUserInfo: function () {
- tt.removeStorageSync('user_id')
- }
- }
- Page({
- data: {
- appName: '酷乐秀',
- version: '1.0.0',
- messageContent: '',
- showReply: false,
- replyContent: '',
- isLoading: false,
- apiError: false,
- currentUserId: '',
- chatMessages: [], // 聊天消息列表(按时间顺序)
- scrollTop: 0, // 滚动位置
- scrollIntoView: '' // 滚动锚点
- },
-
- onLoad: function () {
- console.log('办公效率助手小程序已加载')
- this.setData({
- appName: '酷乐秀',
- version: '1.0.0'
- })
- // 初始化用户标识
- this.initUserIdentifier()
- },
-
- // 初始化用户标识
- initUserIdentifier: function () {
- const that = this
- UserManager.getUserIdentifier()
- .then(userId => {
- console.log('获取到用户ID:', userId)
- that.setData({
- currentUserId: userId
- })
- })
- .catch(err => {
- console.error('获取用户ID失败:', err)
- // 生成默认用户ID
- const defaultUserId = 'default_' + Date.now()
- that.setData({
- currentUserId: defaultUserId
- })
- tt.setStorageSync('user_id', defaultUserId)
- })
- },
-
- onShow: function () {
- console.log('办公效率助手小程序页面显示')
- },
-
- // 页面初次渲染完成
- onReady: function () {
- console.log('页面初次渲染完成')
- // 可以在这里添加需要在页面渲染完成后执行的逻辑
- },
-
- // 点击发送消息按钮(兼容两种方法名)
- handleSendMessage: function () {
- this.handleSendPrivateMessage()
- },
-
- // 点击发送消息按钮
- handleSendPrivateMessage: function () {
- const content = this.data.messageContent.trim()
-
- if (!content) {
- tt.showToast({
- title: '请输入消息内容',
- icon: 'none',
- duration: 2000
- })
- return
- }
-
- // 将用户消息添加到聊天记录
- const userMessage = {
- type: 'user',
- content: content,
- time: this.getCurrentTime(),
- timestamp: Date.now()
- }
-
- this.setData({
- chatMessages: [...this.data.chatMessages, userMessage],
- isLoading: true,
- apiError: false,
- messageContent: ''
- }, () => {
- // 滚动到底部
- this.scrollToBottom()
- })
-
- // 调用助手服务
- this.callReplyService(content)
- },
-
- // 调用助手服务
- callReplyService: function (userMessage) {
- const that = this
-
- // 获取用户ID并调用服务
- UserManager.getUserIdentifier()
- .then(userId => {
- console.log('调用助手服务,用户ID:', userId)
-
- // 更新当前用户ID
- that.setData({
- currentUserId: userId
- })
-
- // 发起服务请求
- tt.request({
- url: ServiceConfig.apiUrl,
- method: 'POST',
- data: {
- message: userMessage,
- userId: userId, // 添加用户ID参数
- appId: 'yyszkt_help',
- timestamp: Date.now(),
- // 可以根据需要添加更多参数
- context: 'music_assistant', // 保持接口参数不变
- language: 'zh-CN',
- userType: userId.startsWith('anonymous_') ? 'anonymous' : 'registered'
- },
- header: ServiceConfig.headers,
- timeout: ServiceConfig.timeout,
- success: function (res) {
- console.log('服务调用成功:', res)
-
- // 处理助手回复
- let assistantReply = ''
-
- if (res.statusCode === 200 && res.data) {
- // 根据API响应格式处理回复
- if (typeof res.data === 'string') {
- assistantReply = res.data
- } else if (res.data.reply) {
- assistantReply = res.data.reply
- } else if (res.data.choices && res.data.choices[0] && res.data.choices[0].message) {
- assistantReply = res.data.choices[0].message.content
- } else {
- assistantReply = '已收到您的消息,我这边正在为您整理建议。'
- }
- } else {
- // API调用失败,使用备用回复
- assistantReply = that.generateFallbackResponse(userMessage)
- }
-
- // 将助手回复添加到聊天记录
- const assistantReplyMessage = {
- type: 'assistant',
- content: assistantReply,
- time: that.getCurrentTime(),
- timestamp: Date.now()
- }
-
- that.setData({
- chatMessages: [...that.data.chatMessages, assistantReplyMessage],
- replyContent: assistantReply,
- showReply: true,
- isLoading: false
- }, () => {
- // 滚动到底部
- that.scrollToBottom()
- })
-
- // 清空输入框
- that.setData({
- messageContent: ''
- })
- },
- fail: function (err) {
- console.error('服务调用失败:', err)
-
- // 显示错误提示
- tt.showToast({
- title: '网络异常,使用本地建议',
- icon: 'none',
- duration: 2000
- })
-
- // 使用本地备用建议
- const fallbackReply = that.generateFallbackResponse(userMessage)
-
- that.setData({
- replyContent: fallbackReply,
- showReply: true,
- isLoading: false,
- apiError: true
- })
-
- // 清空输入框
- that.setData({
- messageContent: ''
- })
- },
- complete: function () {
- console.log('服务调用完成')
- }
- })
- })
- .catch(err => {
- console.error('获取用户ID失败:', err)
-
- // 使用默认用户ID继续调用
- const defaultUserId = 'default_' + Date.now()
- that.callReplyServiceWithUserId(userMessage, defaultUserId)
- })
- },
-
- // 使用指定用户ID调用服务
- callReplyServiceWithUserId: function (userMessage, userId) {
- const that = this
-
- tt.request({
- url: ServiceConfig.apiUrl,
- method: 'POST',
- data: {
- message: userMessage,
- userId: userId,
- appId: 'yyszkt_help',
- timestamp: Date.now(),
- context: 'music_assistant',
- language: 'zh-CN',
- userType: userId.startsWith('anonymous_') ? 'anonymous' : 'registered'
- },
- header: ServiceConfig.headers,
- timeout: ServiceConfig.timeout,
- success: function (res) {
- // 成功处理逻辑...
- let assistantReply = ''
-
- if (res.statusCode === 200 && res.data) {
- if (typeof res.data === 'string') {
- assistantReply = res.data
- } else if (res.data.reply) {
- assistantReply = res.data.reply
- } else if (res.data.choices && res.data.choices[0] && res.data.choices[0].message) {
- assistantReply = res.data.choices[0].message.content
- } else {
- assistantReply = '已收到您的消息,我这边正在为您整理建议。'
- }
- } else {
- assistantReply = that.generateFallbackResponse(userMessage)
- }
-
- // 将助手回复添加到聊天记录
- const assistantReplyMessage = {
- type: 'assistant',
- content: assistantReply,
- time: that.getCurrentTime(),
- timestamp: Date.now()
- }
-
- that.setData({
- chatMessages: [...that.data.chatMessages, assistantReplyMessage],
- replyContent: assistantReply,
- showReply: true,
- isLoading: false
- }, () => {
- // 滚动到底部
- that.scrollToBottom()
- })
-
- that.setData({
- messageContent: ''
- })
- },
- fail: function (err) {
- console.error('服务调用失败:', err)
-
- tt.showToast({
- title: '网络异常,使用本地建议',
- icon: 'none',
- duration: 2000
- })
-
- const fallbackReply = that.generateFallbackResponse(userMessage)
-
- // 将助手回复添加到聊天记录
- const assistantReplyMessage = {
- type: 'assistant',
- content: fallbackReply,
- time: that.getCurrentTime(),
- timestamp: Date.now()
- }
-
- that.setData({
- chatMessages: [...that.data.chatMessages, assistantReplyMessage],
- replyContent: fallbackReply,
- showReply: true,
- isLoading: false,
- apiError: true
- }, () => {
- // 滚动到底部
- that.scrollToBottom()
- })
-
- that.setData({
- messageContent: ''
- })
- },
- complete: function () {
- }
- })
- },
-
- // 生成备用回复(当API调用失败时使用)
- generateFallbackResponse: function (userMessage) {
- return this.generateReplyResponse(userMessage)
- },
-
- // 生成助手回复内容(本地备用)
- generateReplyResponse: function (userMessage) {
-
- return '当前客服不在线,暂无法回复消息,请稍等。'
- },
-
- // 关闭助手回复区域
- handleCloseReply: function () {
- this.setData({
- showReply: false,
- replyContent: '',
- apiError: false
- })
- },
-
- // 重新获取用户ID(用于调试或重置)
- refreshUserIdentifier: function () {
- const that = this
- UserManager.clearUserInfo()
-
- tt.showLoading({
- title: '重新获取用户信息...',
- mask: true
- })
-
- UserManager.getUserIdentifier()
- .then(userId => {
- tt.hideLoading()
- that.setData({
- currentUserId: userId
- })
- tt.showToast({
- title: '用户信息更新成功',
- icon: 'success',
- duration: 2000
- })
- })
- .catch(_err => {
- tt.hideLoading()
- tt.showToast({
- title: '用户信息更新失败',
- icon: 'none',
- duration: 2000
- })
- })
- },
-
- // 输入框内容变化
- handleInputChange: function (e) {
- this.setData({
- messageContent: e.detail.value
- })
- },
- // 跳转产品介绍
- handleGoProduct: function () {
- tt.redirectTo({
- url: '/pages/product/index'
- })
- },
- // 跳转申请试用
- handleGoTrial: function () {
- tt.redirectTo({
- url: '/pages/trial/index'
- })
- },
-
- // 获取当前时间
- getCurrentTime: function () {
- const now = new Date()
- const hours = now.getHours().toString().padStart(2, '0')
- const minutes = now.getMinutes().toString().padStart(2, '0')
- return `${hours}:${minutes}`
- },
-
- // 滚动到底部 - 完全重写的专业级实现
- scrollToBottom: function () {
- this.setData({
- scrollIntoView: ''
- })
- setTimeout(() => {
- this.setData({
- scrollIntoView: 'bottom-anchor'
- })
- }, 20)
- setTimeout(() => {
- this.setData({
- scrollTop: this.data.scrollTop + 9999
- })
- }, 120)
- setTimeout(() => {
- this.ensureLastMessageInView(0)
- }, 180)
- },
- // 确保最后一条消息完整显示在消息区可视范围内
- ensureLastMessageInView: function (retryCount) {
- const MAX_RETRY = 5
- if (retryCount >= MAX_RETRY) {
- return
- }
- const query = tt.createSelectorQuery()
- query.selectAll('.message-item').boundingClientRect()
- query.select('.chat-container').boundingClientRect()
- query.exec((res) => {
- const messageRects = res[0]
- const chatRect = res[1]
- if (!messageRects || !messageRects.length || !chatRect) {
- return
- }
- const lastMessageRect = messageRects[messageRects.length - 1]
- const safeBottom = chatRect.bottom - 16
- const overlapHeight = lastMessageRect.bottom - safeBottom
- if (overlapHeight > 0) {
- this.setData({
- scrollIntoView: '',
- scrollTop: this.data.scrollTop + overlapHeight + 24
- })
- setTimeout(() => {
- this.ensureLastMessageInView(retryCount + 1)
- }, 60)
- }
- })
- },
- })
|