fix: resolve conflicts after pull
This commit is contained in:
commit
f6b25747bc
23
.gitattributes
vendored
Normal file
23
.gitattributes
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
* text=auto
|
||||
|
||||
*.js text eol=lf
|
||||
*.json text eol=lf
|
||||
*.wxml text eol=lf
|
||||
*.wxss text eol=lf
|
||||
*.wxs text eol=lf
|
||||
*.md text eol=lf
|
||||
*.sh text eol=lf
|
||||
*.yml text eol=lf
|
||||
*.yaml text eol=lf
|
||||
*.xml text eol=lf
|
||||
*.svg text eol=lf
|
||||
|
||||
*.bat text eol=crlf
|
||||
*.cmd text eol=crlf
|
||||
|
||||
*.png binary
|
||||
*.jpg binary
|
||||
*.jpeg binary
|
||||
*.gif binary
|
||||
*.webp binary
|
||||
*.ico binary
|
||||
29
app.js
29
app.js
|
|
@ -437,20 +437,37 @@ App({
|
|||
return this.globalData.isLoggedIn
|
||||
},
|
||||
|
||||
/**
|
||||
* 加载审核状态
|
||||
*/
|
||||
async loadAuditStatus() {
|
||||
const localAppVersion = config.APP_VERSION || ''
|
||||
|
||||
try {
|
||||
const res = await api.common.getAuditStatus()
|
||||
if (res.code === 0 && res.data) {
|
||||
this.globalData.auditStatus = Number(res.data.auditStatus || 0)
|
||||
console.log('获取审核状态成功:', this.globalData.auditStatus)
|
||||
const serverAppVersion = res.data.app_version || res.data.appVersion || ''
|
||||
|
||||
if (localAppVersion !== serverAppVersion) {
|
||||
this.globalData.auditStatus = 0
|
||||
wx.setStorageSync('auditStatus', 0)
|
||||
return
|
||||
}
|
||||
|
||||
const auditStatus = Number(res.data.auditStatus || 0)
|
||||
this.globalData.auditStatus = auditStatus
|
||||
wx.setStorageSync('auditStatus', auditStatus)
|
||||
return
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('获取审核状态失败', err)
|
||||
// 失败时默认为 0(正式环境),或根据需要设为 1(保守方案)
|
||||
}
|
||||
|
||||
const cachedStatus = wx.getStorageSync('auditStatus')
|
||||
if (cachedStatus !== undefined) {
|
||||
this.globalData.auditStatus = cachedStatus
|
||||
return
|
||||
}
|
||||
|
||||
this.globalData.auditStatus = 0
|
||||
wx.setStorageSync('auditStatus', 0)
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -32,10 +32,14 @@ const ENV = {
|
|||
// development: 本地开发 staging: 测试环境 production: 正式环境
|
||||
const CURRENT_ENV = 'production'
|
||||
|
||||
// 硬编码版本号 - 用于审核开关对比
|
||||
const APP_VERSION = '1.0'
|
||||
|
||||
// 导出配置
|
||||
const config = {
|
||||
...ENV[CURRENT_ENV],
|
||||
ENV: CURRENT_ENV,
|
||||
APP_VERSION: APP_VERSION,
|
||||
|
||||
// 存储键名
|
||||
STORAGE_KEYS: {
|
||||
|
|
|
|||
174
config/version.js
Normal file
174
config/version.js
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
/**
|
||||
* 小程序版本配置文件
|
||||
* 用于控制不同版本显示不同内容
|
||||
*
|
||||
* 版本号格式:主版本.次版本.修订版本
|
||||
* 示例:'1.0.0', '2.0.0'
|
||||
*
|
||||
* 使用方式:
|
||||
* - 修改 CURRENT_VERSION 来切换当前开发版本
|
||||
* - 在 pages 中使用 getVersion() 获取当前版本
|
||||
* - 使用 getContent(version) 获取对应版本的内容配置
|
||||
*/
|
||||
|
||||
const CURRENT_VERSION = '1.0.0'
|
||||
|
||||
const VERSION_CONFIG = {
|
||||
'1.0.0': {
|
||||
name: 'V1基础版',
|
||||
description: '初始版本',
|
||||
categoryList: [
|
||||
{
|
||||
id: 1,
|
||||
name: '兴趣搭子',
|
||||
icon: 'https://ai-c.maimanji.com/images/icon-interest.png',
|
||||
url: '/pages/interest-partner/interest-partner'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: '同城活动',
|
||||
icon: 'https://ai-c.maimanji.com/images/icon-city.png',
|
||||
url: '/pages/city-activities/city-activities'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: '户外郊游',
|
||||
icon: 'https://ai-c.maimanji.com/images/icon-outdoor.png',
|
||||
url: '/pages/outdoor-activities/outdoor-activities'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: '高端定制',
|
||||
icon: 'https://ai-c.maimanji.com/images/icon-travel.png',
|
||||
url: '/pages/theme-travel/theme-travel'
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: '快乐学堂',
|
||||
icon: 'https://ai-c.maimanji.com/images/icon-checkin.png',
|
||||
url: '/pages/happy-school/happy-school'
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: '单身聚会',
|
||||
icon: 'https://ai-c.maimanji.com/images/icon-love.png',
|
||||
url: '/pages/singles-party/singles-party'
|
||||
}
|
||||
],
|
||||
features: {
|
||||
showNewFeature: false,
|
||||
showBetaFeature: false,
|
||||
useNewUI: false,
|
||||
useOldUI: true
|
||||
}
|
||||
},
|
||||
|
||||
'2.0.0': {
|
||||
name: 'V2升级版',
|
||||
description: '全新UI设计,新增功能入口',
|
||||
categoryList: [
|
||||
{
|
||||
id: 1,
|
||||
name: '兴趣搭子',
|
||||
icon: 'https://ai-c.maimanji.com/images/v2/icon-interest.png',
|
||||
url: '/pages/interest-partner/interest-partner'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: '同城活动',
|
||||
icon: 'https://ai-c.maimanji.com/images/v2/icon-city.png',
|
||||
url: '/pages/city-activities/city-activities'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: '户外郊游',
|
||||
icon: 'https://ai-c.maimanji.com/images/v2/icon-outdoor.png',
|
||||
url: '/pages/outdoor-activities/outdoor-activities'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: '主题旅行',
|
||||
icon: 'https://ai-c.maimanji.com/images/v2/icon-travel.png',
|
||||
url: '/pages/theme-travel/theme-travel'
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: '快乐学堂',
|
||||
icon: 'https://ai-c.maimanji.com/images/v2/icon-checkin.png',
|
||||
url: '/pages/happy-school/happy-school'
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: '爱心传递',
|
||||
icon: 'https://ai-c.maimanji.com/images/v2/icon-love.png',
|
||||
url: '/pages/love-transmission/love-transmission'
|
||||
}
|
||||
],
|
||||
features: {
|
||||
showNewFeature: true,
|
||||
showBetaFeature: true,
|
||||
useNewUI: true,
|
||||
useOldUI: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getVersion() {
|
||||
const debugVersion = wx.getStorageSync('debugVersion')
|
||||
if (debugVersion && VERSION_CONFIG[debugVersion]) {
|
||||
return debugVersion
|
||||
}
|
||||
return CURRENT_VERSION
|
||||
}
|
||||
|
||||
function getVersionInfo(version = CURRENT_VERSION) {
|
||||
return VERSION_CONFIG[version] || VERSION_CONFIG['1.0.0']
|
||||
}
|
||||
|
||||
function getCategoryList(version = CURRENT_VERSION) {
|
||||
const config = getVersionInfo(version)
|
||||
return config ? config.categoryList : []
|
||||
}
|
||||
|
||||
function getFeatureFlag(featureName, version = CURRENT_VERSION) {
|
||||
const config = getVersionInfo(version)
|
||||
return config ? config.features[featureName] : false
|
||||
}
|
||||
|
||||
function compareVersion(v1, v2) {
|
||||
const v1s = v1.split('.')
|
||||
const v2s = v2.split('.')
|
||||
const len = Math.max(v1s.length, v2s.length)
|
||||
for (let i = 0; i < len; i++) {
|
||||
const n1 = parseInt(v1s[i]) || 0
|
||||
const n2 = parseInt(v2s[i]) || 0
|
||||
if (n1 > n2) return 1
|
||||
if (n1 < n2) return -1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
function isVersionOrAbove(targetVersion, currentVersion = CURRENT_VERSION) {
|
||||
return compareVersion(currentVersion, targetVersion) >= 0
|
||||
}
|
||||
|
||||
function isVersionBelow(targetVersion, currentVersion = CURRENT_VERSION) {
|
||||
return compareVersion(currentVersion, targetVersion) < 0
|
||||
}
|
||||
|
||||
function getAllVersions() {
|
||||
return Object.keys(VERSION_CONFIG)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
CURRENT_VERSION,
|
||||
VERSION_CONFIG,
|
||||
getVersion,
|
||||
getVersionInfo,
|
||||
getCategoryList,
|
||||
getFeatureFlag,
|
||||
compareVersion,
|
||||
isVersionOrAbove,
|
||||
isVersionBelow,
|
||||
getAllVersions
|
||||
}
|
||||
|
|
@ -2,6 +2,8 @@
|
|||
* 协议页面
|
||||
* 显示用户服务协议或隐私协议
|
||||
*/
|
||||
const config = require('../../config/index')
|
||||
|
||||
Page({
|
||||
data: {
|
||||
statusBarHeight: 20,
|
||||
|
|
@ -25,7 +27,8 @@ Page({
|
|||
wx.showLoading({ title: '加载中...' });
|
||||
|
||||
// 优先读取本地缓存
|
||||
const cached = wx.getStorageSync(`agreement_${code}`);
|
||||
const cacheKey = code === 'privacy_policy' ? 'privacy_policy' : `agreement_${code}`;
|
||||
const cached = wx.getStorageSync(cacheKey);
|
||||
const CACHE_DURATION = 60 * 60 * 1000; // 1小时
|
||||
const now = Date.now();
|
||||
|
||||
|
|
@ -38,9 +41,12 @@ Page({
|
|||
return;
|
||||
}
|
||||
|
||||
// 从配置文件获取API域名
|
||||
const baseUrl = String(config.API_BASE_URL || '').replace(/\/api$/, '')
|
||||
|
||||
// 网络请求
|
||||
wx.request({
|
||||
url: `https://ai-c.maimanji.com/api/agreements?code=${code}`,
|
||||
url: `${baseUrl}/api/agreements?code=${code}`,
|
||||
method: 'GET',
|
||||
success: (res) => {
|
||||
wx.hideLoading();
|
||||
|
|
@ -52,7 +58,7 @@ Page({
|
|||
});
|
||||
|
||||
// 写入缓存
|
||||
wx.setStorageSync(`agreement_${code}`, {
|
||||
wx.setStorageSync(cacheKey, {
|
||||
data: data,
|
||||
timestamp: now
|
||||
});
|
||||
|
|
|
|||
|
|
@ -22,7 +22,10 @@ Page({
|
|||
data: {
|
||||
statusBarHeight: 44,
|
||||
navHeight: 96,
|
||||
|
||||
|
||||
// 审核状态
|
||||
auditStatus: 0,
|
||||
|
||||
// 角色信息
|
||||
characterId: '',
|
||||
conversationId: '',
|
||||
|
|
@ -128,25 +131,28 @@ Page({
|
|||
},
|
||||
|
||||
onLoad(options) {
|
||||
// 从本地存储读取审核状态
|
||||
const auditStatus = wx.getStorageSync('auditStatus') || 0
|
||||
const { statusBarHeight, navHeight } = app.globalData
|
||||
|
||||
|
||||
// 初始化消息处理相关变量
|
||||
this.pendingMessages = []
|
||||
this.messageTimer = null
|
||||
this.isProcessing = false
|
||||
|
||||
|
||||
// 获取参数
|
||||
const characterId = options.id || ''
|
||||
const conversationId = options.conversationId || ''
|
||||
const characterName = decodeURIComponent(options.name || '')
|
||||
|
||||
|
||||
// 设置用户头像
|
||||
const userInfo = app.globalData.userInfo
|
||||
const myAvatar = imageUrl.getAvatarUrl(userInfo?.avatar)
|
||||
|
||||
|
||||
this.setData({
|
||||
statusBarHeight,
|
||||
navHeight,
|
||||
auditStatus,
|
||||
characterId,
|
||||
conversationId,
|
||||
myAvatar,
|
||||
|
|
@ -163,6 +169,10 @@ Page({
|
|||
},
|
||||
|
||||
onShow() {
|
||||
// 从本地存储读取审核状态
|
||||
const auditStatus = wx.getStorageSync('auditStatus') || 0
|
||||
this.setData({ auditStatus })
|
||||
|
||||
// 每次显示页面时,刷新一次配额状态,确保免费畅聊时间等状态是最新的
|
||||
if (!this.data.loading) {
|
||||
this.loadQuotaStatus()
|
||||
|
|
@ -1927,127 +1937,123 @@ Page({
|
|||
|
||||
onVoiceTouchEnd() {
|
||||
clearInterval(this.recordingTimer)
|
||||
|
||||
|
||||
const { voiceCancelHint, recordingDuration, characterId, character, isUnlocked, remainingCount } = this.data
|
||||
|
||||
|
||||
this.setData({ isRecording: false })
|
||||
|
||||
|
||||
if (this.recorderManager) {
|
||||
this.recorderManager.stop()
|
||||
|
||||
if (voiceCancelHint) {
|
||||
// 取消发送
|
||||
util.showToast('已取消')
|
||||
return
|
||||
}
|
||||
|
||||
if (recordingDuration < 1) {
|
||||
util.showError('录音时间太短')
|
||||
return
|
||||
}
|
||||
|
||||
this.recorderManager.onStop(async (res) => {
|
||||
console.log('[chat-detail] 录音完成:', res.tempFilePath, '时长:', recordingDuration)
|
||||
|
||||
// 先显示语音消息(带识别中状态)
|
||||
const newId = util.generateId()
|
||||
const voiceMessage = {
|
||||
id: newId,
|
||||
type: 'voice',
|
||||
audioUrl: res.tempFilePath,
|
||||
duration: recordingDuration,
|
||||
isMe: true,
|
||||
time: util.formatTime(new Date(), 'HH:mm'),
|
||||
recognizing: true, // 识别中状态
|
||||
recognizedText: '' // 识别出的文字
|
||||
}
|
||||
|
||||
this.setData({
|
||||
messages: [...this.data.messages, voiceMessage]
|
||||
}, () => {
|
||||
this.scrollToBottom()
|
||||
})
|
||||
|
||||
// 进行语音识别
|
||||
try {
|
||||
wx.showLoading({ title: '语音识别中...' })
|
||||
|
||||
// 读取音频文件并转换为base64
|
||||
const fs = wx.getFileSystemManager()
|
||||
const audioData = fs.readFileSync(res.tempFilePath)
|
||||
const audioBase64 = wx.arrayBufferToBase64(audioData)
|
||||
|
||||
// 调用语音识别API
|
||||
const recognizeRes = await api.speech.recognize({
|
||||
audio: audioBase64,
|
||||
format: 'mp3'
|
||||
})
|
||||
|
||||
wx.hideLoading()
|
||||
|
||||
let recognizedText = ''
|
||||
if (recognizeRes.success && recognizeRes.data && recognizeRes.data.text) {
|
||||
recognizedText = recognizeRes.data.text
|
||||
console.log('[chat-detail] 语音识别结果:', recognizedText)
|
||||
} else {
|
||||
// 识别失败,使用默认文字
|
||||
recognizedText = '[语音消息]'
|
||||
console.log('[chat-detail] 语音识别失败,使用默认文字')
|
||||
}
|
||||
|
||||
// 更新语音消息的识别状态
|
||||
const messages = this.data.messages.map(msg => {
|
||||
if (msg.id === newId) {
|
||||
return { ...msg, recognizing: false, recognizedText }
|
||||
}
|
||||
return msg
|
||||
})
|
||||
this.setData({ messages })
|
||||
|
||||
// 如果识别出了有效文字,发送给AI
|
||||
if (recognizedText && recognizedText !== '[语音消息]') {
|
||||
// 检查聊天权限
|
||||
const canChatByFreeTime = !!(this.data.freeTime && this.data.freeTime.isActive)
|
||||
const canChatByVip = !!this.data.isVip
|
||||
|
||||
if (!isUnlocked && !canChatByVip && !canChatByFreeTime) {
|
||||
console.log('[chat-detail] 语音消息无聊天权限', { isUnlocked, isVip, canChatByFreeTime })
|
||||
this.setData({ showUnlockPopup: true })
|
||||
return
|
||||
}
|
||||
|
||||
// 将识别出的文字加入待处理队列
|
||||
this.pendingMessages.push(recognizedText)
|
||||
|
||||
// 如果没有正在等待的定时器,启动延迟处理
|
||||
if (!this.messageTimer) {
|
||||
this.startMessageTimer(characterId, this.data.conversationId, character, isUnlocked, remainingCount)
|
||||
}
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
wx.hideLoading()
|
||||
console.error('[chat-detail] 语音识别失败:', err)
|
||||
|
||||
// 更新消息状态
|
||||
const messages = this.data.messages.map(msg => {
|
||||
if (msg.id === newId) {
|
||||
return { ...msg, recognizing: false, recognizedText: '[语音消息]' }
|
||||
}
|
||||
return msg
|
||||
})
|
||||
this.setData({ messages })
|
||||
|
||||
util.showError('语音识别失败')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 取消发送
|
||||
if (voiceCancelHint) {
|
||||
util.showToast('已取消')
|
||||
return
|
||||
}
|
||||
|
||||
// 录音时间太短
|
||||
if (recordingDuration < 1) {
|
||||
util.showError('录音时间太短')
|
||||
return
|
||||
}
|
||||
|
||||
// 等待录音停止后再处理
|
||||
this.recorderManager.onStop(async (res) => {
|
||||
console.log('[chat-detail] 录音完成:', res.tempFilePath, '时长:', recordingDuration)
|
||||
|
||||
// 先显示语音消息(带识别中状态)
|
||||
const newId = util.generateId()
|
||||
const voiceMessage = {
|
||||
id: newId,
|
||||
type: 'voice',
|
||||
audioUrl: res.tempFilePath,
|
||||
duration: recordingDuration,
|
||||
isMe: true,
|
||||
time: util.formatTime(newId, 'HH:mm'),
|
||||
recognizing: true,
|
||||
recognizedText: ''
|
||||
}
|
||||
|
||||
this.setData({
|
||||
messages: [...this.data.messages, voiceMessage]
|
||||
}, () => {
|
||||
this.scrollToBottom()
|
||||
})
|
||||
|
||||
// 进行语音识别
|
||||
try {
|
||||
wx.showLoading({ title: '语音识别中...' })
|
||||
|
||||
const fs = wx.getFileSystemManager()
|
||||
const audioData = fs.readFileSync(res.tempFilePath)
|
||||
const audioBase64 = wx.arrayBufferToBase64(audioData)
|
||||
console.log('[chat-detail] 音频文件大小:', audioData.byteLength, 'bytes')
|
||||
console.log('[chat-detail] Base64长度:', audioBase64.length, 'chars')
|
||||
|
||||
console.log('[chat-detail] 开始调用语音识别API...')
|
||||
const recognizeRes = await api.speech.recognize({
|
||||
audio: audioBase64,
|
||||
format: 'mp3'
|
||||
})
|
||||
console.log('[chat-detail] 语音识别响应:', JSON.stringify(recognizeRes).substring(0, 200))
|
||||
|
||||
wx.hideLoading()
|
||||
|
||||
let recognizedText = ''
|
||||
if (recognizeRes.success && recognizeRes.data && recognizeRes.data.text) {
|
||||
recognizedText = recognizeRes.data.text
|
||||
console.log('[chat-detail] 语音识别结果:', recognizedText)
|
||||
} else {
|
||||
recognizedText = '[语音消息]'
|
||||
console.log('[chat-detail] 语音识别失败,使用默认文字')
|
||||
}
|
||||
|
||||
const messages = this.data.messages.map(msg => {
|
||||
if (msg.id === newId) {
|
||||
return { ...msg, recognizing: false, recognizedText }
|
||||
}
|
||||
return msg
|
||||
})
|
||||
this.setData({ messages })
|
||||
|
||||
if (recognizedText && recognizedText !== '[语音消息]') {
|
||||
const canChatByFreeTime = !!(this.data.freeTime && this.data.freeTime.isActive)
|
||||
const canChatByVip = !!this.data.isVip
|
||||
|
||||
if (!isUnlocked && !canChatByVip && !canChatByFreeTime) {
|
||||
console.log('[chat-detail] 语音消息无聊天权限', { isUnlocked, isVip, canChatByFreeTime })
|
||||
this.setData({ showUnlockPopup: true })
|
||||
return
|
||||
}
|
||||
|
||||
this.pendingMessages.push(recognizedText)
|
||||
|
||||
if (!this.messageTimer) {
|
||||
this.startMessageTimer(characterId, this.data.conversationId, character, isUnlocked, remainingCount)
|
||||
}
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
wx.hideLoading()
|
||||
console.error('[chat-detail] 语音识别失败:', err)
|
||||
|
||||
const messages = this.data.messages.map(msg => {
|
||||
if (msg.id === newId) {
|
||||
return { ...msg, recognizing: false, recognizedText: '[语音消息]' }
|
||||
}
|
||||
return msg
|
||||
})
|
||||
this.setData({ messages })
|
||||
util.showError('语音识别失败')
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
onVoiceTouchCancel() {
|
||||
clearInterval(this.recordingTimer)
|
||||
this.setData({ isRecording: false })
|
||||
|
||||
|
||||
if (this.recorderManager) {
|
||||
this.recorderManager.stop()
|
||||
}
|
||||
|
|
@ -2058,7 +2064,7 @@ Page({
|
|||
*/
|
||||
onMessageLongPress(e) {
|
||||
const item = e.currentTarget.dataset.item
|
||||
|
||||
|
||||
wx.showActionSheet({
|
||||
itemList: ['复制', '删除'],
|
||||
success: (res) => {
|
||||
|
|
|
|||
|
|
@ -57,12 +57,12 @@
|
|||
</view>
|
||||
|
||||
<!-- 加密对话提示 -->
|
||||
<view class="encrypt-hint">
|
||||
<view class="encrypt-hint" wx:if="{{auditStatus === 0}}">
|
||||
<text>与 {{character.name}} 的加密对话</text>
|
||||
</view>
|
||||
|
||||
<!-- 聊天消息列表 -->
|
||||
<view class="chat-list">
|
||||
<view class="chat-list" wx:if="{{auditStatus === 0}}">
|
||||
<view
|
||||
class="chat-item {{item.isMe ? 'me' : 'other'}}"
|
||||
wx:for="{{messages}}"
|
||||
|
|
@ -150,7 +150,7 @@
|
|||
</view>
|
||||
|
||||
<!-- 正在输入提示 -->
|
||||
<view class="chat-item other" wx:if="{{isTyping}}">
|
||||
<view class="chat-item other" wx:if="{{isTyping && auditStatus === 0}}">
|
||||
<view class="avatar-wrap">
|
||||
<image wx:if="{{character.avatar}}" class="chat-avatar" src="{{character.avatar}}" mode="aspectFill"></image>
|
||||
<view wx:else class="avatar-placeholder">
|
||||
|
|
@ -177,8 +177,14 @@
|
|||
<!-- 面板打开时的透明遮罩层 - 点击关闭面板 -->
|
||||
<view class="panel-overlay" wx:if="{{showEmoji || showMorePanel}}" bindtap="onClosePanels"></view>
|
||||
|
||||
<!-- 底部输入区域 - Figma设计样式 -->
|
||||
<view class="bottom-input-area {{showEmoji || showMorePanel ? 'panel-open' : ''}}">
|
||||
<!-- 审核模式提示 -->
|
||||
<view class="audit-notice" wx:if="{{auditStatus === 1}}">
|
||||
<image src="/images/icon-bell.png" class="notice-icon" mode="aspectFit"></image>
|
||||
<text class="notice-text">当前处于审核模式</text>
|
||||
</view>
|
||||
|
||||
<!-- 底部输入区域 - Figma设计样式 - 审核时隐藏 -->
|
||||
<view class="bottom-input-area {{showEmoji || showMorePanel ? 'panel-open' : ''}}" wx:if="{{auditStatus === 0}}">
|
||||
<view class="input-container figma-input-container">
|
||||
<!-- 语音/键盘切换按钮 - Figma样式 -->
|
||||
<view class="figma-voice-btn" bindtap="onVoiceMode">
|
||||
|
|
|
|||
|
|
@ -1657,3 +1657,34 @@
|
|||
color: #99A1AF;
|
||||
letter-spacing: 0.5rpx;
|
||||
}
|
||||
|
||||
/* ==================== 审核模式样式 ==================== */
|
||||
|
||||
/* 审核提示 */
|
||||
.audit-notice {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 24rpx;
|
||||
padding: 48rpx;
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
border-radius: 24rpx;
|
||||
box-shadow: 0 20rpx 40rpx rgba(0, 0, 0, 0.1);
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.notice-icon {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.notice-text {
|
||||
font-size: 32rpx;
|
||||
color: #6B7280;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,31 +37,34 @@ Page({
|
|||
|
||||
// 总未读消息数
|
||||
totalUnread: 0,
|
||||
|
||||
|
||||
// 加载状态
|
||||
loading: true,
|
||||
error: null,
|
||||
auditStatus: 0,
|
||||
|
||||
|
||||
// 免费畅聊相关
|
||||
freeTime: null,
|
||||
countdownText: ''
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
// 从本地存储读取审核状态
|
||||
const auditStatus = wx.getStorageSync('auditStatus') || 0
|
||||
this.setData({ auditStatus })
|
||||
this.loadConversations()
|
||||
},
|
||||
|
||||
onShow() {
|
||||
wx.hideTabBar({ animation: false })
|
||||
const app = getApp()
|
||||
this.setData({
|
||||
auditStatus: app.globalData.auditStatus
|
||||
})
|
||||
|
||||
|
||||
// 从本地存储读取审核状态
|
||||
const auditStatus = wx.getStorageSync('auditStatus') || 0
|
||||
this.setData({ auditStatus })
|
||||
|
||||
// 检查免费畅聊时间
|
||||
this.checkFreeTime()
|
||||
|
||||
|
||||
// 每次显示时刷新列表
|
||||
// 增加延迟,确保标记已读API有时间完成(从聊天详情页返回时)
|
||||
if (!this.data.loading) {
|
||||
|
|
|
|||
|
|
@ -34,8 +34,8 @@
|
|||
</view>
|
||||
</view>
|
||||
|
||||
<!-- AI会话列表(支持滑动删除) -->
|
||||
<view class="swipe-container" wx:for="{{conversations}}" wx:key="id">
|
||||
<!-- AI会话列表(支持滑动删除,审核时隐藏) -->
|
||||
<view class="swipe-container" wx:for="{{conversations}}" wx:key="id" wx:if="{{auditStatus === 0}}">
|
||||
<view
|
||||
class="swipe-content {{item.swiped ? 'swiped' : ''}}"
|
||||
bindtouchstart="onTouchStart"
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
// 根据Figma设计实现
|
||||
|
||||
const api = require('../../utils/api')
|
||||
const config = require('../../config/index')
|
||||
const versionConfig = require('../../config/version')
|
||||
const app = getApp()
|
||||
|
||||
Page({
|
||||
|
|
@ -17,39 +19,8 @@ Page({
|
|||
swiperHeight: 400,
|
||||
currentBannerIndex: 0,
|
||||
|
||||
// 功能入口 - 使用正式环境图片URL
|
||||
categoryList: [
|
||||
{
|
||||
id: 1,
|
||||
name: '兴趣搭子',
|
||||
icon: '/images/icon-interest.png'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: '同城活动',
|
||||
icon: '/images/icon-city.png'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: '户外郊游',
|
||||
icon: '/images/icon-outdoor.png'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: '高端定制',
|
||||
icon: '/images/icon-travel.png'
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: '快乐学堂',
|
||||
icon: '/images/icon-checkin.png'
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: '单身聚会',
|
||||
icon: '/images/icon-love.png'
|
||||
}
|
||||
],
|
||||
// 功能入口 - 使用版本化配置
|
||||
categoryList: versionConfig.getCategoryList(),
|
||||
|
||||
// 滚动公告
|
||||
noticeList: [],
|
||||
|
|
@ -112,7 +83,7 @@ Page({
|
|||
* 处理图片URL,如果是相对路径则拼接域名,并设置清晰度为85
|
||||
*/
|
||||
processImageUrl(url) {
|
||||
if (!url) return ''
|
||||
if (!url || typeof url !== 'string') return ''
|
||||
let fullUrl = url
|
||||
if (!url.startsWith('http://') && !url.startsWith('https://')) {
|
||||
const baseUrl = 'https://ai-c.maimanji.com'
|
||||
|
|
@ -545,58 +516,17 @@ Page({
|
|||
* 分类点击
|
||||
*/
|
||||
onCategoryTap(e) {
|
||||
const { id, name } = e.currentTarget.dataset
|
||||
|
||||
// 兴趣搭子跳转到专门页面
|
||||
if (id === 1) {
|
||||
wx.navigateTo({
|
||||
url: '/pages/interest-partner/interest-partner'
|
||||
})
|
||||
return
|
||||
const { id, name, url } = e.currentTarget.dataset
|
||||
|
||||
// 从版本配置中获取分类信息
|
||||
const categoryList = versionConfig.getCategoryList()
|
||||
const category = categoryList.find(item => item.id === id)
|
||||
|
||||
if (category && category.url) {
|
||||
wx.navigateTo({ url: category.url })
|
||||
} else {
|
||||
wx.showToast({ title: `${name}功能开发中`, icon: 'none' })
|
||||
}
|
||||
|
||||
// 同城活动跳转到专门页面
|
||||
if (id === 2) {
|
||||
wx.navigateTo({
|
||||
url: '/pages/city-activities/city-activities'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 户外郊游跳转到专门页面
|
||||
if (id === 3) {
|
||||
wx.navigateTo({
|
||||
url: '/pages/outdoor-activities/outdoor-activities'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 定制主题跳转到专门页面
|
||||
if (id === 4) {
|
||||
wx.navigateTo({
|
||||
url: '/pages/theme-travel/theme-travel'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 快乐学堂跳转到专门页面
|
||||
if (id === 5) {
|
||||
wx.navigateTo({
|
||||
url: '/pages/happy-school/happy-school'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 单身聚会跳转到专门页面
|
||||
if (id === 6) {
|
||||
wx.navigateTo({
|
||||
url: '/pages/singles-party/singles-party'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
wx.showToast({ title: `${name}功能开发中`, icon: 'none' })
|
||||
// TODO: 跳转到对应分类页面
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -37,11 +37,12 @@
|
|||
|
||||
<!-- 功能入口 - 与服务页面统一的圆形图标风格 -->
|
||||
<view class="category-section">
|
||||
<view class="category-item"
|
||||
wx:for="{{categoryList}}"
|
||||
<view class="category-item"
|
||||
wx:for="{{categoryList}}"
|
||||
wx:key="id"
|
||||
data-id="{{item.id}}"
|
||||
data-name="{{item.name}}"
|
||||
data-url="{{item.url}}"
|
||||
bindtap="onCategoryTap">
|
||||
<!-- 图标容器:圆形图片 -->
|
||||
<view class="category-icon-container">
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
const api = require('../../utils/api')
|
||||
const auth = require('../../utils/auth')
|
||||
const config = require('../../config/index')
|
||||
|
||||
Page({
|
||||
|
|
@ -8,6 +7,7 @@ Page({
|
|||
navBarHeight: 44,
|
||||
totalNavHeight: 88,
|
||||
lovePoints: 0,
|
||||
isLoggedIn: false,
|
||||
gifts: [],
|
||||
giftsLoading: false,
|
||||
giftsError: '',
|
||||
|
|
@ -32,28 +32,31 @@ Page({
|
|||
const menuButton = wx.getMenuButtonBoundingClientRect()
|
||||
const navBarHeight = menuButton.height + (menuButton.top - statusBarHeight) * 2
|
||||
const totalNavHeight = statusBarHeight + navBarHeight
|
||||
|
||||
|
||||
this.setData({
|
||||
statusBarHeight,
|
||||
navBarHeight,
|
||||
totalNavHeight
|
||||
})
|
||||
|
||||
// 礼物商城无需登录即可访问
|
||||
this.loadGifts()
|
||||
|
||||
const isValid = await auth.ensureLogin({
|
||||
pageName: 'gift-shop',
|
||||
redirectUrl: '/pages/gift-shop/gift-shop'
|
||||
})
|
||||
// 检查登录状态并加载爱心值
|
||||
const app = getApp()
|
||||
const isLoggedIn = app.globalData.isLoggedIn
|
||||
this.setData({ isLoggedIn })
|
||||
|
||||
if (!isValid) return
|
||||
|
||||
await new Promise(resolve => setTimeout(resolve, 50))
|
||||
this.loadLovePoints()
|
||||
if (isLoggedIn) {
|
||||
this.loadLovePoints()
|
||||
}
|
||||
},
|
||||
|
||||
onShow() {
|
||||
const app = getApp()
|
||||
this.setData({ isLoggedIn: app.globalData.isLoggedIn })
|
||||
|
||||
// 仅在登录状态下刷新爱心值
|
||||
if (app.globalData.isLoggedIn) {
|
||||
this.loadLovePoints()
|
||||
}
|
||||
|
|
@ -121,7 +124,7 @@ Page({
|
|||
},
|
||||
|
||||
// 点击礼品卡片
|
||||
onGiftTap(e) {
|
||||
onGiftTap() {
|
||||
wx.showModal({
|
||||
title: '提示',
|
||||
content: '请联系在线客服',
|
||||
|
|
|
|||
|
|
@ -13,7 +13,8 @@
|
|||
<!-- 内容区域 -->
|
||||
<scroll-view scroll-y class="content-scroll" style="padding-top: {{totalNavHeight}}px;" enhanced show-scrollbar="{{false}}">
|
||||
<view class="content-wrap">
|
||||
<view class="love-card">
|
||||
<!-- 爱心值卡片 - 仅登录后显示 -->
|
||||
<view class="love-card" wx:if="{{isLoggedIn}}">
|
||||
<view class="love-card-bg"></view>
|
||||
<view class="love-card-blur"></view>
|
||||
<view class="love-card-bottom-shade"></view>
|
||||
|
|
|
|||
|
|
@ -85,31 +85,21 @@ Page({
|
|||
},
|
||||
|
||||
async onLoad() {
|
||||
// 获取系统信息
|
||||
const { statusBarHeight, navHeight, auditStatus } = app.globalData
|
||||
this.setData({ statusBarHeight, navHeight, auditStatus })
|
||||
|
||||
// 如果是审核状态,重定向到文娱页面
|
||||
if (auditStatus === 1) {
|
||||
const localAuditStatus = wx.getStorageSync('auditStatus') || 0
|
||||
const { statusBarHeight, navHeight } = app.globalData
|
||||
this.setData({ statusBarHeight, navHeight, auditStatus: localAuditStatus })
|
||||
|
||||
if (localAuditStatus === 1 || app.globalData.auditStatus === 1) {
|
||||
wx.switchTab({
|
||||
url: '/pages/entertainment/entertainment'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 加载首页素材 (Banner等)
|
||||
this.loadHomeAssets()
|
||||
|
||||
// 加载分享配置
|
||||
this.loadShareConfig()
|
||||
|
||||
// 加载角色列表
|
||||
this.loadCharacters()
|
||||
|
||||
// 加载用户爱心余额
|
||||
this.loadHeartBalance()
|
||||
|
||||
// 加载解锁配置
|
||||
this.loadUnlockConfig()
|
||||
},
|
||||
|
||||
|
|
@ -208,13 +198,15 @@ Page({
|
|||
// 隐藏默认tabbar
|
||||
wx.hideTabBar({ animation: false })
|
||||
|
||||
// 从本地存储读取审核状态
|
||||
const localAuditStatus = wx.getStorageSync('auditStatus') || 0
|
||||
const app = getApp()
|
||||
this.setData({
|
||||
auditStatus: app.globalData.auditStatus
|
||||
auditStatus: localAuditStatus
|
||||
})
|
||||
|
||||
// 如果是审核状态,重定向到文娱页面
|
||||
if (app.globalData.auditStatus === 1) {
|
||||
if (localAuditStatus === 1 || app.globalData.auditStatus === 1) {
|
||||
wx.switchTab({
|
||||
url: '/pages/entertainment/entertainment'
|
||||
})
|
||||
|
|
@ -230,13 +222,30 @@ Page({
|
|||
// 检查AI角色主动推送消息
|
||||
this.checkProactiveMessages()
|
||||
|
||||
// 检查注册奖励
|
||||
this.checkRegistrationReward()
|
||||
|
||||
// 检查 GF100 弹窗
|
||||
this.checkGf100Popup()
|
||||
},
|
||||
|
||||
onHide() {
|
||||
this.stopAudio()
|
||||
},
|
||||
|
||||
onUnload() {
|
||||
this.stopAudio()
|
||||
},
|
||||
|
||||
stopAudio() {
|
||||
if (this.audioContext) {
|
||||
try {
|
||||
this.audioContext.stop()
|
||||
this.audioContext.destroy()
|
||||
} catch (e) {}
|
||||
this.audioContext = null
|
||||
}
|
||||
wx.hideToast()
|
||||
},
|
||||
|
||||
onPullDownRefresh() {
|
||||
Promise.all([
|
||||
this.loadCharacters(),
|
||||
|
|
@ -534,16 +543,8 @@ Page({
|
|||
const nextIndex = currentIndex + 1
|
||||
|
||||
// 切换卡片时,如果正在播放语音,则停止播放
|
||||
if (isVoicePlaying && this.audioContext) {
|
||||
try {
|
||||
console.log('[index] 切换卡片,停止上一个角色的语音')
|
||||
this.audioContext.stop()
|
||||
} catch (e) {
|
||||
console.error('[index] 停止语音失败:', e)
|
||||
}
|
||||
}
|
||||
if (isVoicePlaying) this.stopAudio()
|
||||
|
||||
// 如果快到末尾,加载更多
|
||||
if (nextIndex >= profiles.length - 2) {
|
||||
this.loadMoreCharacters()
|
||||
}
|
||||
|
|
@ -552,7 +553,8 @@ Page({
|
|||
currentIndex: nextIndex,
|
||||
offsetX: 0,
|
||||
rotation: 0,
|
||||
swipeDirection: ''
|
||||
swipeDirection: '',
|
||||
isVoicePlaying: false
|
||||
})
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<!-- 首页 - 遇见页面 -->
|
||||
<view class="page-container">
|
||||
<view class="page-container" wx:if="{{auditStatus === 0}}">
|
||||
<!-- 顶部导航栏 -->
|
||||
<view class="unified-header">
|
||||
<view class="unified-header-left"></view>
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
<view class="tab-item {{currentTab === 'completed' ? 'active' : ''}}" bindtap="switchTab" data-tab="completed">已完成</view>
|
||||
</view>
|
||||
|
||||
<view class="wrap" style="padding-top: {{totalNavHeight + 80}}px; padding-bottom: 40rpx;">
|
||||
<view class="wrap" style="padding-top: {{totalNavHeight + 60}}px; padding-bottom: 40rpx;">
|
||||
<view class="card">
|
||||
<view class="list">
|
||||
<view wx:if="{{loading}}" class="loading">加载中...</view>
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@
|
|||
<view class="user-info">
|
||||
<view class="user-main">
|
||||
<text class="user-name">{{item.userName}}</text>
|
||||
<text class="user-level" wx:if="{{item.level !== '普通用户'}}">{{item.level}}</text>
|
||||
<text class="user-level">{{item.level}}</text>
|
||||
</view>
|
||||
<view class="user-sub">加入时间: {{item.joinedAt}}</view>
|
||||
</view>
|
||||
|
|
|
|||
|
|
@ -63,15 +63,14 @@
|
|||
}
|
||||
|
||||
.stats-value {
|
||||
font-size: 60rpx;
|
||||
font-size: 48rpx;
|
||||
font-weight: 800;
|
||||
margin-bottom: 12rpx;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.stats-label {
|
||||
font-size: 30rpx;
|
||||
opacity: 0.95;
|
||||
font-weight: 500;
|
||||
font-size: 24rpx;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
/* Amount Card */
|
||||
|
|
@ -158,116 +157,55 @@
|
|||
}
|
||||
|
||||
.purple-dot {
|
||||
width: 10rpx;
|
||||
height: 38rpx;
|
||||
width: 8rpx;
|
||||
height: 32rpx;
|
||||
background: #B06AB3;
|
||||
border-radius: 6rpx;
|
||||
border-radius: 4rpx;
|
||||
}
|
||||
|
||||
.panel-title {
|
||||
font-size: 38rpx;
|
||||
font-size: 32rpx;
|
||||
font-weight: 800;
|
||||
color: #111827;
|
||||
}
|
||||
|
||||
.referral-count {
|
||||
font-size: 38rpx;
|
||||
font-size: 32rpx;
|
||||
font-weight: 800;
|
||||
color: #B06AB3;
|
||||
}
|
||||
|
||||
.see-all {
|
||||
font-size: 32rpx;
|
||||
color: #B06AB3;
|
||||
font-weight: 700;
|
||||
.user-grid {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 32rpx; /* Space between items */
|
||||
}
|
||||
|
||||
.user-list {
|
||||
.user-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 32rpx;
|
||||
}
|
||||
|
||||
.user-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 32rpx 0;
|
||||
border-bottom: 2rpx solid #F3F4F6;
|
||||
}
|
||||
|
||||
.user-row:last-child {
|
||||
border-bottom: none;
|
||||
width: 120rpx;
|
||||
}
|
||||
|
||||
.user-avatar {
|
||||
width: 110rpx;
|
||||
height: 110rpx;
|
||||
width: 100rpx;
|
||||
height: 100rpx;
|
||||
border-radius: 50%;
|
||||
background: #F3F4F6;
|
||||
margin-right: 24rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.user-info {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.user-main {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
margin-bottom: 8rpx;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.user-name {
|
||||
font-size: 36rpx;
|
||||
font-weight: 700;
|
||||
color: #1F2937;
|
||||
max-width: 240rpx;
|
||||
font-size: 24rpx;
|
||||
color: #4B5563;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.user-level {
|
||||
font-size: 24rpx;
|
||||
color: #B06AB3;
|
||||
background: rgba(176, 106, 179, 0.1);
|
||||
padding: 4rpx 16rpx;
|
||||
border-radius: 20rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.user-sub {
|
||||
font-size: 28rpx;
|
||||
color: #4B5563;
|
||||
}
|
||||
|
||||
.user-stats {
|
||||
display: flex;
|
||||
gap: 24rpx;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.stat-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 100rpx;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 24rpx;
|
||||
color: #9CA3AF;
|
||||
margin-bottom: 6rpx;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 30rpx;
|
||||
font-weight: 700;
|
||||
color: #1F2937;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
|
|
@ -286,7 +224,7 @@
|
|||
.menu-item {
|
||||
background: #FFFFFF;
|
||||
border-radius: 24rpx;
|
||||
padding: 40rpx 32rpx;
|
||||
padding: 32rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
|
@ -296,12 +234,12 @@
|
|||
.menu-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 32rpx;
|
||||
gap: 24rpx;
|
||||
}
|
||||
|
||||
.icon-circle {
|
||||
width: 88rpx;
|
||||
height: 88rpx;
|
||||
width: 72rpx;
|
||||
height: 72rpx;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
@ -313,15 +251,15 @@
|
|||
.icon-circle.orange { background: rgba(245, 158, 11, 0.1); }
|
||||
|
||||
.menu-text {
|
||||
font-size: 34rpx;
|
||||
font-weight: 700;
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
color: #1F2937;
|
||||
}
|
||||
|
||||
.btn-reset {
|
||||
background: none;
|
||||
border: none;
|
||||
padding: 40rpx 32rpx; /* Match menu-item padding */
|
||||
padding: 32rpx; /* Match menu-item padding */
|
||||
margin: 0;
|
||||
line-height: normal;
|
||||
border-radius: 24rpx; /* Match menu-item border-radius */
|
||||
|
|
|
|||
|
|
@ -61,11 +61,11 @@
|
|||
<view class="list-container" wx:if="{{list.length > 0}}">
|
||||
<view class="list-item" wx:for="{{list}}" wx:key="userId" bindtap="viewOrders" data-item="{{item}}">
|
||||
<view class="user-info">
|
||||
<image src="{{item.userAvatar || defaultAvatar}}" class="user-avatar" mode="aspectFill"></image>
|
||||
<image src="{{item.userAvatar}}" class="user-avatar" mode="aspectFill"></image>
|
||||
<view class="user-details">
|
||||
<view class="user-name-row">
|
||||
<text class="user-name">{{item.userName}}</text>
|
||||
<text class="user-level" wx:if="{{item.levelText !== '普通用户'}}">{{item.levelText}}</text>
|
||||
<text class="user-level">{{item.levelText}}</text>
|
||||
</view>
|
||||
<view class="user-time">绑定时间: {{formatTime(item.boundAt)}}</view>
|
||||
<view class="user-meta">
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@
|
|||
}
|
||||
|
||||
.user-name {
|
||||
font-size: 36rpx;
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #1F2937;
|
||||
}
|
||||
|
|
@ -194,13 +194,13 @@
|
|||
}
|
||||
|
||||
.user-time {
|
||||
font-size: 28rpx;
|
||||
font-size: 24rpx;
|
||||
color: #9CA3AF;
|
||||
}
|
||||
|
||||
/* 列表项详情扩展 */
|
||||
.user-meta {
|
||||
font-size: 26rpx;
|
||||
font-size: 22rpx;
|
||||
color: #6B7280;
|
||||
margin-top: 8rpx;
|
||||
display: flex;
|
||||
|
|
@ -208,10 +208,10 @@
|
|||
}
|
||||
|
||||
.user-level {
|
||||
font-size: 24rpx;
|
||||
font-size: 20rpx;
|
||||
color: #B06AB3;
|
||||
background: rgba(176, 106, 179, 0.1);
|
||||
padding: 4rpx 16rpx;
|
||||
padding: 2rpx 12rpx;
|
||||
border-radius: 20rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@
|
|||
|
||||
<!-- 商家列表 -->
|
||||
<view class="provider-list">
|
||||
<view class="provider-card" wx:for="{{listData}}" wx:key="id" data-id="{{item.id}}" bindtap="onItemTap">
|
||||
<view class="provider-card" wx:for="{{listData}}" wx:key="id">
|
||||
<view class="provider-left">
|
||||
<view class="avatar-container">
|
||||
<view class="avatar-wrapper">
|
||||
|
|
|
|||
108
pages/version-debug/version-debug.js
Normal file
108
pages/version-debug/version-debug.js
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
const versionUtils = require('../../utils/version')
|
||||
const versionConfig = require('../../config/version')
|
||||
|
||||
Page({
|
||||
data: {
|
||||
currentVersion: '',
|
||||
versionName: '',
|
||||
versionList: [],
|
||||
categoryList: [],
|
||||
isV2OrAbove: false,
|
||||
useNewUI: false
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
this.loadVersionInfo()
|
||||
},
|
||||
|
||||
onShow() {
|
||||
this.loadVersionInfo()
|
||||
},
|
||||
|
||||
loadVersionInfo() {
|
||||
const currentVersion = versionUtils.getCurrentVersion()
|
||||
const versionInfo = versionUtils.getVersionInfo()
|
||||
const allVersions = versionConfig.getAllVersions()
|
||||
const categoryList = versionUtils.getCategoryList()
|
||||
const isV2OrAbove = versionUtils.isV2OrAbove()
|
||||
const useNewUI = versionUtils.getFeatureFlag('useNewUI')
|
||||
|
||||
const versionList = allVersions.map(v => {
|
||||
const info = versionConfig.getVersionInfo(v)
|
||||
return {
|
||||
version: v,
|
||||
name: info ? info.name : v,
|
||||
description: info ? info.description : ''
|
||||
}
|
||||
})
|
||||
|
||||
this.setData({
|
||||
currentVersion,
|
||||
versionName: versionInfo ? versionInfo.name : '',
|
||||
versionList,
|
||||
categoryList,
|
||||
isV2OrAbove,
|
||||
useNewUI
|
||||
})
|
||||
|
||||
versionUtils.logVersionInfo()
|
||||
},
|
||||
|
||||
switchVersion(e) {
|
||||
const { version } = e.currentTarget.dataset
|
||||
|
||||
if (version === this.data.currentVersion) {
|
||||
wx.showToast({ title: '已是该版本', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
wx.showModal({
|
||||
title: '切换版本',
|
||||
content: `确定要切换到 ${version} 版本吗?切换后页面将重新加载。`,
|
||||
confirmColor: '#b06ab3',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
this.doSwitchVersion(version)
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
doSwitchVersion(version) {
|
||||
wx.showLoading({ title: '切换中...' })
|
||||
|
||||
try {
|
||||
const allVersions = versionConfig.getAllVersions()
|
||||
|
||||
if (allVersions.includes(version)) {
|
||||
wx.setStorageSync('debugVersion', version)
|
||||
console.log(`[VersionDebug] 切换到版本: ${version}`)
|
||||
|
||||
setTimeout(() => {
|
||||
wx.hideLoading()
|
||||
wx.showToast({ title: '切换成功', icon: 'success' })
|
||||
|
||||
setTimeout(() => {
|
||||
wx.reLaunch({
|
||||
url: '/pages/version-debug/version-debug'
|
||||
})
|
||||
}, 1000)
|
||||
}, 500)
|
||||
} else {
|
||||
wx.hideLoading()
|
||||
wx.showToast({ title: '版本不存在', icon: 'none' })
|
||||
}
|
||||
} catch (err) {
|
||||
wx.hideLoading()
|
||||
console.error('切换版本失败', err)
|
||||
wx.showToast({ title: '切换失败', icon: 'none' })
|
||||
}
|
||||
},
|
||||
|
||||
onShareAppMessage() {
|
||||
return {
|
||||
title: '版本调试工具',
|
||||
path: '/pages/version-debug/version-debug'
|
||||
}
|
||||
}
|
||||
})
|
||||
4
pages/version-debug/version-debug.json
Normal file
4
pages/version-debug/version-debug.json
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"usingComponents": {},
|
||||
"navigationBarTitleText": "版本调试"
|
||||
}
|
||||
55
pages/version-debug/version-debug.wxml
Normal file
55
pages/version-debug/version-debug.wxml
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
<view class="debug-container">
|
||||
<view class="debug-header">版本调试工具</view>
|
||||
|
||||
<view class="version-info">
|
||||
<text class="label">当前版本:</text>
|
||||
<text class="value">{{currentVersion}}</text>
|
||||
</view>
|
||||
|
||||
<view class="version-info">
|
||||
<text class="label">版本名称:</text>
|
||||
<text class="value">{{versionName}}</text>
|
||||
</view>
|
||||
|
||||
<view class="section-title">切换版本</view>
|
||||
<view class="version-list">
|
||||
<view
|
||||
class="version-item {{item.version === currentVersion ? 'active' : ''}}"
|
||||
wx:for="{{versionList}}"
|
||||
wx:key="version"
|
||||
data-version="{{item.version}}"
|
||||
bindtap="switchVersion">
|
||||
<view class="version-name">{{item.name}}</view>
|
||||
<view class="version-desc">{{item.description}}</view>
|
||||
<view class="version-current" wx:if="{{item.version === currentVersion}}">当前版本</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="section-title">版本特性对比</view>
|
||||
<view class="feature-comparison">
|
||||
<view class="feature-row">
|
||||
<text class="feature-name">新功能入口</text>
|
||||
<text class="feature-value {{isV2OrAbove ? 'enabled' : 'disabled'}}">
|
||||
{{isV2OrAbove ? '显示' : '隐藏'}}
|
||||
</text>
|
||||
</view>
|
||||
<view class="feature-row">
|
||||
<text class="feature-name">新UI设计</text>
|
||||
<text class="feature-value {{useNewUI ? 'enabled' : 'disabled'}}">
|
||||
{{useNewUI ? '启用' : '停用'}}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="section-title">分类图标预览</view>
|
||||
<view class="icon-preview">
|
||||
<view class="icon-item" wx:for="{{categoryList}}" wx:key="id">
|
||||
<image class="icon-image" src="{{item.icon}}" mode="aspectFit"></image>
|
||||
<text class="icon-name">{{item.name}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="tips">
|
||||
<text>提示:切换版本后会重新加载页面</text>
|
||||
</view>
|
||||
</view>
|
||||
181
pages/version-debug/version-debug.wxss
Normal file
181
pages/version-debug/version-debug.wxss
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
.debug-container {
|
||||
min-height: 100vh;
|
||||
background: #f5f5f5;
|
||||
padding: 30rpx;
|
||||
}
|
||||
|
||||
.debug-header {
|
||||
font-size: 40rpx;
|
||||
font-weight: 700;
|
||||
color: #1D293D;
|
||||
text-align: center;
|
||||
padding: 30rpx 0;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.version-info {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background: #fff;
|
||||
padding: 24rpx 30rpx;
|
||||
border-radius: 16rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.version-info .label {
|
||||
font-size: 28rpx;
|
||||
color: #62748E;
|
||||
}
|
||||
|
||||
.version-info .value {
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
color: #b06ab3;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #1D293D;
|
||||
margin: 40rpx 0 20rpx;
|
||||
padding-left: 10rpx;
|
||||
border-left: 8rpx solid #b06ab3;
|
||||
}
|
||||
|
||||
.version-list {
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.version-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 30rpx;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
position: relative;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
|
||||
.version-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.version-item.active {
|
||||
background: #fdf2f8;
|
||||
}
|
||||
|
||||
.version-item.active::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 8rpx;
|
||||
background: #b06ab3;
|
||||
}
|
||||
|
||||
.version-name {
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
color: #1D293D;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.version-desc {
|
||||
font-size: 24rpx;
|
||||
color: #62748E;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.version-current {
|
||||
font-size: 22rpx;
|
||||
color: #b06ab3;
|
||||
background: #fdf2f8;
|
||||
padding: 8rpx 16rpx;
|
||||
border-radius: 20rpx;
|
||||
}
|
||||
|
||||
.feature-comparison {
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.feature-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 24rpx 30rpx;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.feature-row:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.feature-name {
|
||||
font-size: 28rpx;
|
||||
color: #1D293D;
|
||||
}
|
||||
|
||||
.feature-value {
|
||||
font-size: 26rpx;
|
||||
font-weight: 600;
|
||||
padding: 8rpx 20rpx;
|
||||
border-radius: 20rpx;
|
||||
}
|
||||
|
||||
.feature-value.enabled {
|
||||
color: #10b981;
|
||||
background: #ecfdf5;
|
||||
}
|
||||
|
||||
.feature-value.disabled {
|
||||
color: #6b7280;
|
||||
background: #f3f4f6;
|
||||
}
|
||||
|
||||
.icon-preview {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 20rpx;
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
.icon-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 180rpx;
|
||||
padding: 20rpx;
|
||||
background: #fafafa;
|
||||
border-radius: 12rpx;
|
||||
}
|
||||
|
||||
.icon-image {
|
||||
width: 128rpx;
|
||||
height: 128rpx;
|
||||
border-radius: 50%;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.icon-name {
|
||||
font-size: 24rpx;
|
||||
color: #1D293D;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.tips {
|
||||
text-align: center;
|
||||
margin-top: 40rpx;
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
.tips text {
|
||||
font-size: 24rpx;
|
||||
color: #62748E;
|
||||
}
|
||||
|
|
@ -1389,6 +1389,12 @@ const common = {
|
|||
*/
|
||||
getAuditStatus: () => request('/common/audit-status'),
|
||||
|
||||
/**
|
||||
* 获取系统配置
|
||||
* 返回 app_version 等配置信息,用于版本号对比
|
||||
*/
|
||||
getSystemConfig: () => request('/admin/system-config'),
|
||||
|
||||
/**
|
||||
* 获取品牌配置
|
||||
* 返回品牌故事、介绍等内容
|
||||
|
|
|
|||
55
utils/version.js
Normal file
55
utils/version.js
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
/**
|
||||
* 版本控制工具类
|
||||
* 用于在小程序中获取和管理版本相关信息
|
||||
*/
|
||||
|
||||
const versionConfig = require('../config/version')
|
||||
|
||||
function getCurrentVersion() {
|
||||
return versionConfig.getVersion()
|
||||
}
|
||||
|
||||
function getVersionInfo() {
|
||||
return versionConfig.getVersionInfo()
|
||||
}
|
||||
|
||||
function isV2OrAbove() {
|
||||
return versionConfig.isVersionOrAbove('2.0.0')
|
||||
}
|
||||
|
||||
function isV1() {
|
||||
const v = getCurrentVersion()
|
||||
return v.startsWith('1.')
|
||||
}
|
||||
|
||||
function getCategoryList() {
|
||||
return versionConfig.getCategoryList()
|
||||
}
|
||||
|
||||
function getFeatureFlag(featureName) {
|
||||
return versionConfig.getFeatureFlag(featureName)
|
||||
}
|
||||
|
||||
function logVersionInfo() {
|
||||
const version = getCurrentVersion()
|
||||
const info = getVersionInfo()
|
||||
const features = info ? info.features : {}
|
||||
|
||||
console.log('========== 小程序版本信息 ==========')
|
||||
console.log('当前版本:', version)
|
||||
console.log('版本名称:', info ? info.name : '未知')
|
||||
console.log('版本描述:', info ? info.description : '未知')
|
||||
console.log('分类数量:', getCategoryList().length)
|
||||
console.log('功能开关:', features)
|
||||
console.log('====================================')
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getCurrentVersion,
|
||||
getVersionInfo,
|
||||
isV2OrAbove,
|
||||
isV1,
|
||||
getCategoryList,
|
||||
getFeatureFlag,
|
||||
logVersionInfo
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user