From d32801cb5b97709234a4a3982860bee382405f53 Mon Sep 17 00:00:00 2001 From: zhiyun Date: Thu, 5 Feb 2026 01:07:28 +0800 Subject: [PATCH] Apply stashed changes and resolve conflicts --- pages/chat-detail/chat-detail.js | 364 ++++++++++++++++--- pages/city-activities/city-activities.wxml | 6 +- pages/entertainment/entertainment.js | 62 ++-- pages/interest-partner/interest-partner.js | 36 +- pages/interest-partner/interest-partner.wxml | 9 - pages/interest-partner/interest-partner.wxss | 2 +- pages/performance/performance.js | 20 +- pages/performance/performance.wxml | 5 +- pages/performance/performance.wxss | 37 ++ pages/profile/profile.js | 2 +- pages/team/team.js | 10 + pages/team/team.wxml | 2 +- pages/team/team.wxss | 29 +- utils/api.js | 11 + 14 files changed, 473 insertions(+), 122 deletions(-) diff --git a/pages/chat-detail/chat-detail.js b/pages/chat-detail/chat-detail.js index 1488798..6f8cb25 100644 --- a/pages/chat-detail/chat-detail.js +++ b/pages/chat-detail/chat-detail.js @@ -127,7 +127,10 @@ Page({ // 免费畅聊相关 freeTime: null, - countdownText: '' + countdownText: '', + + // 聊天模式 (ai | human) + chatMode: 'ai' }, onLoad(options) { @@ -140,6 +143,10 @@ Page({ this.messageTimer = null this.isProcessing = false + // 获取当前用户ID + const userId = app.globalData.userId || wx.getStorageSync(config.STORAGE_KEYS.USER_ID) + this.setData({ userId }) + // 获取参数 const characterId = options.id || '' const conversationId = options.conversationId || '' @@ -177,10 +184,20 @@ Page({ if (!this.data.loading) { this.loadQuotaStatus() } + + // 开启消息轮询 + this.startPolling() + }, + + onHide() { + // 页面隐藏时停止轮询 + this.stopPolling() }, onUnload() { // 页面卸载时清理 + this.stopPolling() + // 清除消息处理定时器 if (this.messageTimer) { clearTimeout(this.messageTimer) @@ -201,6 +218,156 @@ Page({ } }, + /** + * 开启消息轮询 (智能自适应模式) + * 策略: + * 1. 默认状态:低频轮询 (每4秒),降低性能损耗 + * 2. 交互状态:当用户发送消息后,进入"高速模式" (每1.5秒),持续60秒,确保及时收到回复 + */ + startPolling() { + this.stopPolling() + + // 如果处于高速模式,使用短间隔 + const interval = this.isFastPolling ? 1500 : 4000 + + console.log(`[chat-detail] 开启消息轮询 (模式: ${this.isFastPolling ? '高速' : '省流'}, 间隔: ${interval}ms)`) + + this.pollingTimer = setTimeout(() => { + this.checkNewMessages().finally(() => { + // 递归调用,确保上一次请求结束后才开始下一次计时 + // 页面未卸载且未停止轮询时继续 + if (this.data.conversationId) { + this.startPolling() + } + }) + }, interval) + }, + + /** + * 触发高速轮询模式 + * 在用户发送消息后调用 + */ + triggerFastPolling() { + console.log('[chat-detail] 激活高速轮询模式') + this.isFastPolling = true + this.startPolling() // 立即重启轮询以应用新间隔 + + // 清除旧的定时器 + if (this.fastPollingTimeout) clearTimeout(this.fastPollingTimeout) + + // 60秒后自动恢复普通模式 + this.fastPollingTimeout = setTimeout(() => { + console.log('[chat-detail] 高速模式结束,恢复省流模式') + this.isFastPolling = false + // 不需要立即重启,下次轮询会自动使用新间隔 + }, 60000) + }, + + /** + * 停止消息轮询 + */ + stopPolling() { + if (this.pollingTimer) { + clearTimeout(this.pollingTimer) + this.pollingTimer = null + } + }, + + /** + * 检查新消息 + */ + async checkNewMessages() { + // 如果正在加载中、正在发送消息或页面不可见,跳过 + if (this.data.loading || this.data.loadingMore || this.data.isSending) return + + const { characterId, messages, conversationId } = this.data + if (!characterId) return + + try { + // 1. 获取最新的一页消息 + // 添加时间戳防止缓存 + const res = await api.chat.getChatHistoryByCharacter(characterId, { + limit: 20, + page: 1, + _t: Date.now() + }) + + if (res.success && res.data && res.data.length > 0) { + // 转换消息格式 + const latestMessages = res.data.map(msg => this.transformMessage(msg)) + + // 筛选出本地不存在的新消息 + // 重点:只筛选对方发来的消息(isMe: false),避免本地已存在的用户消息重复显示 + // 用户自己的消息(isMe: true)由本地乐观更新处理,轮询时不重复添加 + const newMessages = latestMessages.filter(msg => { + // 2. 本地必须不存在该ID + const exists = messages.some(m => m.id === msg.id) + return !exists + }) + + if (newMessages.length > 0) { + console.log('[chat-detail] 轮询发现新消息:', newMessages.length, '条') + + // 将新消息追加到列表末尾 + // 按时间排序确保顺序正确 + newMessages.sort((a, b) => new Date(a.time) - new Date(b.time)) + + const updatedMessages = [...messages, ...newMessages] + + this.setData({ + messages: updatedMessages + }, () => { + this.scrollToBottom() + + // 如果有新消息,标记会话已读 + if (this.data.conversationId) { + this.markConversationAsRead(this.data.conversationId) + } + + // 收到新消息时,如果是对方发的,也可以触发一下高速模式,以便快速接收连续回复 + this.triggerFastPolling() + + // 更新本地缓存 + this.saveMessagesToCache(updatedMessages) + }) + } + } + + // 2. 检查会话模式状态 + if (conversationId) { + // 降低频率:只有在高速模式或者每5次轮询检查一次会话状态 + // 简单起见,这里每次轮询都检查(因为是 silent 请求,且频率不高) + this.checkConversationStatus(conversationId) + } + + } catch (err) { + // 静默失败,不打印过多日志 + } + }, + + /** + * 检查会话状态 (AI/Human 模式) + */ + async checkConversationStatus(conversationId) { + try { + const res = await api.chat.getConversationDetail(conversationId) + if (res && res.success && res.data) { + const mode = res.data.currentMode || res.data.mode || 'ai' + + // 如果模式发生变化,或者首次获取 + if (mode !== this.data.chatMode) { + console.log('[chat-detail] 会话模式变更为:', mode) + this.setData({ chatMode: mode }) + + // 移除人工模式的显式提示,保持沉浸感 + // 让用户感觉不到是真人在接管 + } + } + } catch (err) { + // 静默失败 + } + }, + /** * 标记会话已读 * 进入聊天详情页时调用,清除未读数 @@ -450,68 +617,101 @@ Page({ /** * 加载聊天历史(首次加载最近20条) + * 优化策略:优先从本地缓存加载,实现"无感"体验,防止后端切换模式导致消息丢失 */ async loadChatHistory() { const { characterId, pageSize } = this.data if (!characterId) { - const welcomeMsg = { - id: 'welcome', - text: `你好!我是${this.data.character.name},很高兴认识你~`, - isMe: false, - time: util.formatTime(new Date(), 'HH:mm'), - type: 'text' - } - this.setData({ - messages: [welcomeMsg], - isFirstLoad: false, - hasMore: false - }) + this.showWelcomeMessage() return } + // 1. 先尝试从本地缓存加载,确保秒开且不丢失历史 + const cachedMessages = wx.getStorageSync(`chat_history_${characterId}`) || [] + if (cachedMessages.length > 0) { + console.log(`[chat-detail] 从本地缓存加载了 ${cachedMessages.length} 条消息`) + this.setData({ + messages: cachedMessages, + isFirstLoad: false, + hasMore: true // 假设还有更多,允许下拉 + }, () => { + this.scrollToBottom() + }) + } + try { - console.log('[chat-detail] 开始加载聊天历史, characterId:', characterId) + console.log('[chat-detail] 开始从API同步聊天历史, characterId:', characterId) // 首次只加载最近20条消息 const res = await api.chat.getChatHistoryByCharacter(characterId, { limit: pageSize, - page: 1 + page: 1, + _t: Date.now() // 防缓存 }) - console.log('[chat-detail] API响应:', JSON.stringify(res).substring(0, 200)) - if (res.success && res.data && res.data.length > 0) { - console.log('[chat-detail] 收到历史消息数量:', res.data.length) + console.log('[chat-detail] API返回消息数量:', res.data.length) - const messages = res.data.map(msg => this.transformMessage(msg)) + const apiMessages = res.data.map(msg => this.transformMessage(msg)) - this.setData({ - messages, - hasMore: res.data.length >= pageSize, - page: 1, - isFirstLoad: false - }) + // 合并策略:以API数据为准更新,但保留API未返回的本地旧数据(如果有) + // 简单起见,如果本地为空,直接用API;如果本地有值,做去重合并 - console.log('[chat-detail] 消息已设置, 当前数量:', this.data.messages.length) - console.log('[chat-detail] 首次加载完成,不自动滚动到底部') - } else { - console.log('[chat-detail] 没有历史记录,显示欢迎消息') - const welcomeMsg = { - id: 'welcome', - text: `你好!我是${this.data.character.name},很高兴认识你~`, - isMe: false, - time: util.formatTime(new Date(), 'HH:mm'), - type: 'text' + let finalMessages = [] + if (this.data.messages.length === 0) { + finalMessages = apiMessages + } else { + // 合并逻辑:将API返回的新消息合并到现有列表中 + // 1. 创建现有消息的ID映射 + const existingIds = new Set(this.data.messages.map(m => m.id)) + + // 2. 找出API返回中本地没有的消息 + const newApiMessages = apiMessages.filter(m => !existingIds.has(m.id)) + + // 3. 将新消息追加进来 (注意顺序) + // API通常返回按时间排序好的,或者我们需要重排 + finalMessages = [...this.data.messages, ...newApiMessages] + + // 4. 按时间重新排序确保正确 + finalMessages.sort((a, b) => new Date(a.time) - new Date(b.time)) + } + + // 只有当消息列表真的发生变化时才更新,避免闪烁 + if (finalMessages.length !== this.data.messages.length) { + this.setData({ + messages: finalMessages, + hasMore: res.data.length >= pageSize, + page: 1, + isFirstLoad: false + }, () => { + this.scrollToBottom() + // 更新缓存 + this.saveMessagesToCache(finalMessages) + }) + } else { + console.log('[chat-detail] 消息列表无变化,跳过更新') + this.setData({ isFirstLoad: false }) + } + + } else { + console.log('[chat-detail] API未返回历史记录') + if (this.data.messages.length === 0) { + this.showWelcomeMessage() } - this.setData({ - messages: [welcomeMsg], - isFirstLoad: false, - hasMore: false - }) } } catch (err) { console.log('加载聊天历史失败:', err) + if (this.data.messages.length === 0) { + this.showWelcomeMessage() + } + } + }, + + /** + * 显示欢迎消息 + */ + showWelcomeMessage() { const welcomeMsg = { id: 'welcome', text: `你好!我是${this.data.character.name},很高兴认识你~`, @@ -524,7 +724,16 @@ Page({ isFirstLoad: false, hasMore: false }) - } + }, + + /** + * 将消息保存到本地缓存 + */ + saveMessagesToCache(messages) { + if (!this.data.characterId || !messages || messages.length === 0) return + // 只缓存最近100条,避免Storage爆满 + const messagesToSave = messages.slice(-100) + wx.setStorageSync(`chat_history_${this.data.characterId}`, messagesToSave) }, /** @@ -591,10 +800,35 @@ Page({ * 转换消息格式 */ transformMessage(msg) { + // 调试日志:打印原始消息结构,帮助排查 role/sender_id 问题 + console.log('[chat-detail] transformMessage raw:', msg) + + let isMe = false + const currentUserId = this.data.userId || app.globalData.userId || wx.getStorageSync(config.STORAGE_KEYS.USER_ID) + + // 1. 优先使用 sender_id 判断 (最准确) + if (msg.sender_id && currentUserId) { + isMe = String(msg.sender_id) === String(currentUserId) + } + // 2. 其次使用 role 判断 + else if (msg.role) { + // 只有明确是 user 且不是 assistant/system 时才认为是自己 + isMe = msg.role === 'user' + } + // 3. 最后尝试 sender_type + else if (msg.sender_type) { + isMe = msg.sender_type === 'user' + } + + // 4. 强制修正:如果 role 是 assistant 或 system,绝对不是我 + if (msg.role === 'assistant' || msg.role === 'system') { + isMe = false + } + const baseMessage = { id: msg.id, text: msg.content, - isMe: msg.role === 'user', + isMe: isMe, time: util.formatTime(msg.created_at || msg.timestamp, 'HH:mm'), type: msg.message_type || 'text' } @@ -743,6 +977,9 @@ Page({ // 只检查输入是否为空 if (!inputText.trim()) return + + // 触发高速轮询模式,确保及时收到回复 + this.triggerFastPolling() // 检查登录 if (app.checkNeedLogin()) return @@ -842,8 +1079,10 @@ Page({ console.log('[chat-detail] 合并处理消息:', messagesToProcess.length, '条') console.log('[chat-detail] 合并后内容:', combinedMessage) - // 显示AI正在输入 - this.setData({ isTyping: true }) + // 显示AI正在输入(仅在AI模式下) + if (this.data.chatMode === 'ai') { + this.setData({ isTyping: true }) + } try { // 构建对话历史(最近10条消息,只包含文字消息) @@ -918,22 +1157,29 @@ Page({ }) } - // 添加AI回复 - const aiMessage = { - id: res.data.id || util.generateId(), - text: res.data.content || res.data.message, - isMe: false, - time: util.formatTime(new Date(), 'HH:mm'), - audioUrl: res.data.audio_url, - type: 'text' // 标记为文字消息 + // 只有当有回复内容时才添加AI消息 + // 如果是人工模式(human),后端可能只返回成功但不返回content,或者content为空 + const content = res.data.content || res.data.message + if (content) { + // 添加AI回复 + const aiMessage = { + id: res.data.id || util.generateId(), + text: content, + isMe: false, + time: util.formatTime(new Date(), 'HH:mm'), + audioUrl: res.data.audio_url, + type: 'text' // 标记为文字消息 + } + + this.setData({ + messages: [...this.data.messages, aiMessage] + }, () => { + // AI回复后滚动到底部 + this.scrollToBottom() + }) + } else { + console.log('[chat-detail] 收到空回复,不添加消息气泡 (可能是Human模式)') } - - this.setData({ - messages: [...this.data.messages, aiMessage] - }, () => { - // AI回复后滚动到底部 - this.scrollToBottom() - }) } else { throw new Error(res.error || res.message || '发送失败') } diff --git a/pages/city-activities/city-activities.wxml b/pages/city-activities/city-activities.wxml index e1ee6e9..a888e06 100644 --- a/pages/city-activities/city-activities.wxml +++ b/pages/city-activities/city-activities.wxml @@ -49,9 +49,9 @@ - - {{item.venue}} - + + {{item.venue}} + diff --git a/pages/entertainment/entertainment.js b/pages/entertainment/entertainment.js index d0aa799..69296a4 100644 --- a/pages/entertainment/entertainment.js +++ b/pages/entertainment/entertainment.js @@ -121,50 +121,32 @@ Page({ /** * 加载功能入口图标 - * 从后台素材管理API加载 (group=entries) + * 从后台素材管理API加载 */ async loadEntries() { - // 暂时禁用API加载,使用本地配置的图标 - console.log('使用本地配置的功能入口图标') - return; - /* try { - const res = await api.pageAssets.getAssets('entries') - console.log('功能入口 API响应:', res) + const res = await api.pageAssets.getEntertainmentCategories() + console.log('娱乐页分类图标 API响应:', res) - if (res.success && res.data) { - const icons = res.data - const { categoryList } = this.data + if (res.success && res.data && res.data.length > 0) { + // 映射API数据到前端格式 + const categoryList = res.data.map(item => ({ + id: item.id, + name: item.name, + icon: this.processImageUrl(item.iconUrl || item.icon), + url: item.pagePath || item.url || '', + sort: item.sort || 0 + })).sort((a, b) => a.sort - b.sort) // 按sort字段排序 - // 映射图标:搭子(id=1), 同城(id=2), 户外(id=3), 定制(id=4), 学堂(id=5), 传递(id=6) - const idMap = { - 1: 'entry_1', // 兴趣搭子 - 2: 'entry_2', // 同城活动 - 3: 'entry_3', // 户外郊游 - 4: 'entry_4', // 定制主题 - 5: 'entry_5', // 快乐学堂 - 6: 'entry_6' // 爱心传递 - } - - const updatedCategoryList = categoryList.map(item => { - const assetKey = idMap[item.id] - const iconUrl = icons[assetKey] - if (iconUrl) { - return { - ...item, - icon: this.processImageUrl(iconUrl) - } - } - return item - }) - - this.setData({ categoryList: updatedCategoryList }) - console.log('已更新娱乐页功能入口图标') + this.setData({ categoryList }) + console.log(`加载了 ${categoryList.length} 个娱乐页分类图标`) + } else { + console.log('娱乐页分类图标API返回为空,使用本地默认配置') } } catch (err) { - console.error('加载功能入口失败', err) + console.error('加载功能入口图标失败', err) + // 失败时保持使用 data 初始化时的本地配置,无需额外操作 } - */ }, /** @@ -523,7 +505,13 @@ Page({ onCategoryTap(e) { const { id, name, url } = e.currentTarget.dataset - // 从版本配置中获取分类信息 + // 优先跳转配置的 URL + if (url) { + wx.navigateTo({ url: url }) + return + } + + // 从版本配置中获取分类信息(作为兜底) const categoryList = versionConfig.getCategoryList() const category = categoryList.find(item => item.id === id) diff --git a/pages/interest-partner/interest-partner.js b/pages/interest-partner/interest-partner.js index 7309346..bbc0c93 100644 --- a/pages/interest-partner/interest-partner.js +++ b/pages/interest-partner/interest-partner.js @@ -57,6 +57,7 @@ Page({ async loadBanner() { try { // 尝试获取 interest_partner 分组的素材 + // 后端已修复:请求 group=interest_partner 时,会自动返回 interest_partner_banners 的数据,并封装成 { banners: [] } 格式 const res = await api.pageAssets.getAssets('interest_partner') console.log('[兴趣搭子] Banner API响应:', res) @@ -66,12 +67,14 @@ Page({ // 如果 banners 为空,尝试读取单图字段 if (!banners || banners.length === 0) { - const singleBanner = res.data.banner || res.data.interest_banner || res.data.top_banner + const singleBanner = res.data.banner || res.data.interest_banner || res.data.top_banner || (Array.isArray(res.data) ? res.data : []) if (singleBanner) { // 支持逗号分隔的多图字符串 if (typeof singleBanner === 'string' && singleBanner.includes(',')) { banners = singleBanner.split(',').map(s => s.trim()).filter(s => s) - } else { + } else if (Array.isArray(singleBanner)) { + banners = singleBanner + } else if (typeof singleBanner === 'string') { banners = [singleBanner] } } @@ -79,8 +82,16 @@ Page({ if (banners && banners.length > 0) { // 处理图片URL - const bannerList = banners.map(url => { - if (typeof url !== 'string') return '' + const bannerList = banners.map(item => { + let url = '' + if (typeof item === 'string') { + url = item + } else if (item && typeof item === 'object') { + url = item.asset_url || item.url || item.imageUrl || '' + } + + if (!url) return '' + let fullUrl = url if (fullUrl.startsWith('/')) { fullUrl = config.API_BASE_URL.replace('/api', '') + fullUrl @@ -138,10 +149,21 @@ Page({ console.log('[兴趣搭子] API原始响应:', JSON.stringify(res).substring(0, 500)) - // 线上API返回格式:{ success: true, data: [...] } 或 { success: true, data: { list: [...] } } + // 线上API返回格式:{ success: true, data: [...] } 或 { success: true, data: { list: [...] } } 或 { success: true, data: { data: [...] } } if (res.success && res.data) { - // 兼容两种返回格式 - let partnerList = Array.isArray(res.data) ? res.data : (res.data.list || []) + // 兼容多种返回格式 + // 1. res.data 是数组 + // 2. res.data.data 是数组 (Laravel分页或标准包装) + // 3. res.data.list 是数组 (自定义列表包装) + let partnerList = [] + + if (Array.isArray(res.data)) { + partnerList = res.data + } else if (res.data.data && Array.isArray(res.data.data)) { + partnerList = res.data.data + } else if (res.data.list && Array.isArray(res.data.list)) { + partnerList = res.data.list + } console.log('[兴趣搭子] 解析后的列表数量:', partnerList.length) if (partnerList.length > 0) { diff --git a/pages/interest-partner/interest-partner.wxml b/pages/interest-partner/interest-partner.wxml index 7110fc0..e4a5b53 100644 --- a/pages/interest-partner/interest-partner.wxml +++ b/pages/interest-partner/interest-partner.wxml @@ -28,15 +28,6 @@ - - - - - - - 寻找志同道合的伙伴 - 加入感兴趣的社群,开启精彩退休生活 - diff --git a/pages/interest-partner/interest-partner.wxss b/pages/interest-partner/interest-partner.wxss index 0413b0c..461eaf5 100644 --- a/pages/interest-partner/interest-partner.wxss +++ b/pages/interest-partner/interest-partner.wxss @@ -19,7 +19,7 @@ page { /* 顶部Banner */ .hero-banner { margin: 32rpx 32rpx 48rpx; - height: 240rpx; + height: 400rpx; border-radius: 32rpx; position: relative; overflow: hidden; diff --git a/pages/performance/performance.js b/pages/performance/performance.js index 0c6ebed..2fafce9 100644 --- a/pages/performance/performance.js +++ b/pages/performance/performance.js @@ -164,13 +164,31 @@ Page({ // 优先使用API返回的中文等级名称 const userLevel = record.fromUserRoleName || record.userRoleName || roleMap[record.fromUserRole] || roleMap[record.userRole] || record.levelText || '普通用户'; + const type = record.orderType || record.type; + let productName = this.getOrderTypeText(type); + + // 后端已把年卡会员改成分销商等级,不显示 VIP会员 + if (type === 'vip') { + productName = ''; + } + + // Determine level class + const rawRole = record.fromUserRole || record.userRole || record.distributorRole || ''; + let levelClass = ''; + if (rawRole.includes('soulmate')) levelClass = 'tag-soulmate'; + else if (rawRole.includes('guardian')) levelClass = 'tag-guardian'; + else if (rawRole.includes('companion')) levelClass = 'tag-companion'; + else if (rawRole.includes('listener')) levelClass = 'tag-listener'; + else if (rawRole.includes('partner')) levelClass = 'tag-partner'; + return { id: record.id, orderNo: record.orderNo || record.order_no || record.id || '---', userName: record.fromUserName || record.userName || '匿名用户', userAvatar: avatar || this.data.defaultAvatar, - productName: this.getOrderTypeText(record.orderType || record.type), + productName: productName, userLevel: userLevel, + levelClass: levelClass, orderAmount: record.orderAmount ? Number(record.orderAmount).toFixed(2) : (record.amount ? Number(record.amount).toFixed(2) : '0.00'), time: fmtTime } diff --git a/pages/performance/performance.wxml b/pages/performance/performance.wxml index 3b9e80b..d4e7be8 100644 --- a/pages/performance/performance.wxml +++ b/pages/performance/performance.wxml @@ -53,7 +53,10 @@ {{item.userName}} - {{item.productName}} · {{item.userLevel}} + + {{item.productName ? item.productName + ' · ' : ''}} + {{item.userLevel}} + 时间: {{item.time}} 单号: {{item.orderNo}} diff --git a/pages/performance/performance.wxss b/pages/performance/performance.wxss index ba03a8c..b221069 100644 --- a/pages/performance/performance.wxss +++ b/pages/performance/performance.wxss @@ -191,6 +191,43 @@ color: #B06AB3; } +/* Tag Styles */ +.tag-badge { + display: inline-block; + font-size: 20rpx; + font-weight: 700; + padding: 2rpx 10rpx; + border-radius: 999rpx; + margin-left: 8rpx; + background: #E5E7EB; + color: #374151; +} + +.tag-soulmate { + background: #7C3AED; + color: #ffffff; +} + +.tag-guardian { + background: #3B82F6; + color: #ffffff; +} + +.tag-companion { + background: #10B981; + color: #ffffff; +} + +.tag-listener { + background: #F59E0B; + color: #ffffff; +} + +.tag-partner { + background: #EF4444; + color: #ffffff; +} + /* 底部提示 */ .bottom-tip { text-align: center; diff --git a/pages/profile/profile.js b/pages/profile/profile.js index bf870ce..9c5cb94 100644 --- a/pages/profile/profile.js +++ b/pages/profile/profile.js @@ -161,7 +161,7 @@ Page({ const roleMap = { 'soulmate': { text: '心伴会员', class: 'vip-soulmate' }, 'guardian': { text: '守护会员', class: 'vip-guardian' }, - 'companion': { text: '心伴会员', class: 'vip-companion' }, + 'companion': { text: '陪伴会员', class: 'vip-companion' }, 'listener': { text: '倾听会员', class: 'vip-listener' }, 'partner': { text: '城市合伙人', class: 'vip-partner' } }; diff --git a/pages/team/team.js b/pages/team/team.js index 3e5492e..6fcf8cf 100644 --- a/pages/team/team.js +++ b/pages/team/team.js @@ -137,6 +137,15 @@ Page({ roleMap[x.distributorRole] || roleMap[user.distributorRole] || roleMap[x.role] || roleMap[user.role] || '普通用户'; + + // Determine level class + const rawRole = x.userRole || user.userRole || x.distributorRole || user.distributorRole || x.role || user.role || ''; + let levelClass = ''; + if (rawRole.includes('soulmate')) levelClass = 'tag-soulmate'; + else if (rawRole.includes('guardian')) levelClass = 'tag-guardian'; + else if (rawRole.includes('companion')) levelClass = 'tag-companion'; + else if (rawRole.includes('listener')) levelClass = 'tag-listener'; + else if (rawRole.includes('partner')) levelClass = 'tag-partner'; return { ...x, @@ -144,6 +153,7 @@ Page({ userAvatar: avatar || this.data.defaultAvatar, userName: name, levelText: levelText, + levelClass: levelClass, totalContribution: contribution, boundAtText: this.formatDate(new Date(dateStr)) }; diff --git a/pages/team/team.wxml b/pages/team/team.wxml index 436436e..0e83595 100644 --- a/pages/team/team.wxml +++ b/pages/team/team.wxml @@ -49,7 +49,7 @@ {{item.userName}} - {{item.levelText}} + {{item.levelText}} {{item.boundAtText}} diff --git a/pages/team/team.wxss b/pages/team/team.wxss index e755b47..890a4bf 100644 --- a/pages/team/team.wxss +++ b/pages/team/team.wxss @@ -150,14 +150,39 @@ } .tag-badge { - background: #B06AB3; - color: #ffffff; + background: #E5E7EB; + color: #374151; font-size: 20rpx; font-weight: 700; padding: 4rpx 12rpx; border-radius: 999rpx; } +.tag-soulmate { + background: #7C3AED; + color: #ffffff; +} + +.tag-guardian { + background: #3B82F6; + color: #ffffff; +} + +.tag-companion { + background: #10B981; + color: #ffffff; +} + +.tag-listener { + background: #F59E0B; + color: #ffffff; +} + +.tag-partner { + background: #EF4444; + color: #ffffff; +} + .member-meta { font-size: 24rpx; color: #6B7280; diff --git a/utils/api.js b/utils/api.js index a6700f3..bf75c22 100644 --- a/utils/api.js +++ b/utils/api.js @@ -402,6 +402,12 @@ const chat = { */ getConversations: () => request('/conversations', { silent: true }), + /** + * 获取会话详情 + * @param {string} id - 会话ID + */ + getConversationDetail: (id) => request(`/conversations/${id}`, { silent: true }), + /** * 删除会话 * @param {string} conversationId - 会话ID @@ -910,6 +916,11 @@ const pageAssets = { */ getEntertainmentBanners: () => request('/page-assets/entertainment-banners'), + /** + * 获取娱乐页分类图标列表 + */ + getEntertainmentCategories: () => request('/page-assets/entertainment-categories'), + /** * 获取合作入驻页在线Banner列表 */