Compare commits
2 Commits
88ffbbc0a3
...
7b6bb822fa
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7b6bb822fa | ||
|
|
1ae572a083 |
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
|
return this.globalData.isLoggedIn
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* 加载审核状态
|
|
||||||
*/
|
|
||||||
async loadAuditStatus() {
|
async loadAuditStatus() {
|
||||||
|
const localAppVersion = config.APP_VERSION || ''
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await api.common.getAuditStatus()
|
const res = await api.common.getAuditStatus()
|
||||||
if (res.code === 0 && res.data) {
|
if (res.code === 0 && res.data) {
|
||||||
this.globalData.auditStatus = Number(res.data.auditStatus || 0)
|
const serverAppVersion = res.data.app_version || res.data.appVersion || ''
|
||||||
console.log('获取审核状态成功:', this.globalData.auditStatus)
|
|
||||||
|
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) {
|
} catch (err) {
|
||||||
console.error('获取审核状态失败', 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: 正式环境
|
// development: 本地开发 staging: 测试环境 production: 正式环境
|
||||||
const CURRENT_ENV = 'production'
|
const CURRENT_ENV = 'production'
|
||||||
|
|
||||||
|
// 硬编码版本号 - 用于审核开关对比
|
||||||
|
const APP_VERSION = '1.0'
|
||||||
|
|
||||||
// 导出配置
|
// 导出配置
|
||||||
const config = {
|
const config = {
|
||||||
...ENV[CURRENT_ENV],
|
...ENV[CURRENT_ENV],
|
||||||
ENV: CURRENT_ENV,
|
ENV: CURRENT_ENV,
|
||||||
|
APP_VERSION: APP_VERSION,
|
||||||
|
|
||||||
// 存储键名
|
// 存储键名
|
||||||
STORAGE_KEYS: {
|
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({
|
Page({
|
||||||
data: {
|
data: {
|
||||||
statusBarHeight: 20,
|
statusBarHeight: 20,
|
||||||
|
|
@ -25,7 +27,8 @@ Page({
|
||||||
wx.showLoading({ title: '加载中...' });
|
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 CACHE_DURATION = 60 * 60 * 1000; // 1小时
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
|
|
||||||
|
|
@ -38,9 +41,12 @@ Page({
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 从配置文件获取API域名
|
||||||
|
const baseUrl = String(config.API_BASE_URL || '').replace(/\/api$/, '')
|
||||||
|
|
||||||
// 网络请求
|
// 网络请求
|
||||||
wx.request({
|
wx.request({
|
||||||
url: `https://ai-c.maimanji.com/api/agreements?code=${code}`,
|
url: `${baseUrl}/api/agreements?code=${code}`,
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
success: (res) => {
|
success: (res) => {
|
||||||
wx.hideLoading();
|
wx.hideLoading();
|
||||||
|
|
@ -52,7 +58,7 @@ Page({
|
||||||
});
|
});
|
||||||
|
|
||||||
// 写入缓存
|
// 写入缓存
|
||||||
wx.setStorageSync(`agreement_${code}`, {
|
wx.setStorageSync(cacheKey, {
|
||||||
data: data,
|
data: data,
|
||||||
timestamp: now
|
timestamp: now
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,10 @@ Page({
|
||||||
data: {
|
data: {
|
||||||
statusBarHeight: 44,
|
statusBarHeight: 44,
|
||||||
navHeight: 96,
|
navHeight: 96,
|
||||||
|
|
||||||
|
// 审核状态
|
||||||
|
auditStatus: 0,
|
||||||
|
|
||||||
// 角色信息
|
// 角色信息
|
||||||
characterId: '',
|
characterId: '',
|
||||||
conversationId: '',
|
conversationId: '',
|
||||||
|
|
@ -128,25 +131,28 @@ Page({
|
||||||
},
|
},
|
||||||
|
|
||||||
onLoad(options) {
|
onLoad(options) {
|
||||||
|
// 从本地存储读取审核状态
|
||||||
|
const auditStatus = wx.getStorageSync('auditStatus') || 0
|
||||||
const { statusBarHeight, navHeight } = app.globalData
|
const { statusBarHeight, navHeight } = app.globalData
|
||||||
|
|
||||||
// 初始化消息处理相关变量
|
// 初始化消息处理相关变量
|
||||||
this.pendingMessages = []
|
this.pendingMessages = []
|
||||||
this.messageTimer = null
|
this.messageTimer = null
|
||||||
this.isProcessing = false
|
this.isProcessing = false
|
||||||
|
|
||||||
// 获取参数
|
// 获取参数
|
||||||
const characterId = options.id || ''
|
const characterId = options.id || ''
|
||||||
const conversationId = options.conversationId || ''
|
const conversationId = options.conversationId || ''
|
||||||
const characterName = decodeURIComponent(options.name || '')
|
const characterName = decodeURIComponent(options.name || '')
|
||||||
|
|
||||||
// 设置用户头像
|
// 设置用户头像
|
||||||
const userInfo = app.globalData.userInfo
|
const userInfo = app.globalData.userInfo
|
||||||
const myAvatar = imageUrl.getAvatarUrl(userInfo?.avatar)
|
const myAvatar = imageUrl.getAvatarUrl(userInfo?.avatar)
|
||||||
|
|
||||||
this.setData({
|
this.setData({
|
||||||
statusBarHeight,
|
statusBarHeight,
|
||||||
navHeight,
|
navHeight,
|
||||||
|
auditStatus,
|
||||||
characterId,
|
characterId,
|
||||||
conversationId,
|
conversationId,
|
||||||
myAvatar,
|
myAvatar,
|
||||||
|
|
@ -163,6 +169,10 @@ Page({
|
||||||
},
|
},
|
||||||
|
|
||||||
onShow() {
|
onShow() {
|
||||||
|
// 从本地存储读取审核状态
|
||||||
|
const auditStatus = wx.getStorageSync('auditStatus') || 0
|
||||||
|
this.setData({ auditStatus })
|
||||||
|
|
||||||
// 每次显示页面时,刷新一次配额状态,确保免费畅聊时间等状态是最新的
|
// 每次显示页面时,刷新一次配额状态,确保免费畅聊时间等状态是最新的
|
||||||
if (!this.data.loading) {
|
if (!this.data.loading) {
|
||||||
this.loadQuotaStatus()
|
this.loadQuotaStatus()
|
||||||
|
|
@ -1927,127 +1937,123 @@ Page({
|
||||||
|
|
||||||
onVoiceTouchEnd() {
|
onVoiceTouchEnd() {
|
||||||
clearInterval(this.recordingTimer)
|
clearInterval(this.recordingTimer)
|
||||||
|
|
||||||
const { voiceCancelHint, recordingDuration, characterId, character, isUnlocked, remainingCount } = this.data
|
const { voiceCancelHint, recordingDuration, characterId, character, isUnlocked, remainingCount } = this.data
|
||||||
|
|
||||||
this.setData({ isRecording: false })
|
this.setData({ isRecording: false })
|
||||||
|
|
||||||
if (this.recorderManager) {
|
if (this.recorderManager) {
|
||||||
this.recorderManager.stop()
|
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() {
|
onVoiceTouchCancel() {
|
||||||
clearInterval(this.recordingTimer)
|
clearInterval(this.recordingTimer)
|
||||||
this.setData({ isRecording: false })
|
this.setData({ isRecording: false })
|
||||||
|
|
||||||
if (this.recorderManager) {
|
if (this.recorderManager) {
|
||||||
this.recorderManager.stop()
|
this.recorderManager.stop()
|
||||||
}
|
}
|
||||||
|
|
@ -2058,7 +2064,7 @@ Page({
|
||||||
*/
|
*/
|
||||||
onMessageLongPress(e) {
|
onMessageLongPress(e) {
|
||||||
const item = e.currentTarget.dataset.item
|
const item = e.currentTarget.dataset.item
|
||||||
|
|
||||||
wx.showActionSheet({
|
wx.showActionSheet({
|
||||||
itemList: ['复制', '删除'],
|
itemList: ['复制', '删除'],
|
||||||
success: (res) => {
|
success: (res) => {
|
||||||
|
|
|
||||||
|
|
@ -57,12 +57,12 @@
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 加密对话提示 -->
|
<!-- 加密对话提示 -->
|
||||||
<view class="encrypt-hint">
|
<view class="encrypt-hint" wx:if="{{auditStatus === 0}}">
|
||||||
<text>与 {{character.name}} 的加密对话</text>
|
<text>与 {{character.name}} 的加密对话</text>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 聊天消息列表 -->
|
<!-- 聊天消息列表 -->
|
||||||
<view class="chat-list">
|
<view class="chat-list" wx:if="{{auditStatus === 0}}">
|
||||||
<view
|
<view
|
||||||
class="chat-item {{item.isMe ? 'me' : 'other'}}"
|
class="chat-item {{item.isMe ? 'me' : 'other'}}"
|
||||||
wx:for="{{messages}}"
|
wx:for="{{messages}}"
|
||||||
|
|
@ -150,7 +150,7 @@
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 正在输入提示 -->
|
<!-- 正在输入提示 -->
|
||||||
<view class="chat-item other" wx:if="{{isTyping}}">
|
<view class="chat-item other" wx:if="{{isTyping && auditStatus === 0}}">
|
||||||
<view class="avatar-wrap">
|
<view class="avatar-wrap">
|
||||||
<image wx:if="{{character.avatar}}" class="chat-avatar" src="{{character.avatar}}" mode="aspectFill"></image>
|
<image wx:if="{{character.avatar}}" class="chat-avatar" src="{{character.avatar}}" mode="aspectFill"></image>
|
||||||
<view wx:else class="avatar-placeholder">
|
<view wx:else class="avatar-placeholder">
|
||||||
|
|
@ -177,8 +177,14 @@
|
||||||
<!-- 面板打开时的透明遮罩层 - 点击关闭面板 -->
|
<!-- 面板打开时的透明遮罩层 - 点击关闭面板 -->
|
||||||
<view class="panel-overlay" wx:if="{{showEmoji || showMorePanel}}" bindtap="onClosePanels"></view>
|
<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">
|
<view class="input-container figma-input-container">
|
||||||
<!-- 语音/键盘切换按钮 - Figma样式 -->
|
<!-- 语音/键盘切换按钮 - Figma样式 -->
|
||||||
<view class="figma-voice-btn" bindtap="onVoiceMode">
|
<view class="figma-voice-btn" bindtap="onVoiceMode">
|
||||||
|
|
|
||||||
|
|
@ -1657,3 +1657,34 @@
|
||||||
color: #99A1AF;
|
color: #99A1AF;
|
||||||
letter-spacing: 0.5rpx;
|
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,
|
totalUnread: 0,
|
||||||
|
|
||||||
// 加载状态
|
// 加载状态
|
||||||
loading: true,
|
loading: true,
|
||||||
error: null,
|
error: null,
|
||||||
auditStatus: 0,
|
auditStatus: 0,
|
||||||
|
|
||||||
// 免费畅聊相关
|
// 免费畅聊相关
|
||||||
freeTime: null,
|
freeTime: null,
|
||||||
countdownText: ''
|
countdownText: ''
|
||||||
},
|
},
|
||||||
|
|
||||||
onLoad() {
|
onLoad() {
|
||||||
|
// 从本地存储读取审核状态
|
||||||
|
const auditStatus = wx.getStorageSync('auditStatus') || 0
|
||||||
|
this.setData({ auditStatus })
|
||||||
this.loadConversations()
|
this.loadConversations()
|
||||||
},
|
},
|
||||||
|
|
||||||
onShow() {
|
onShow() {
|
||||||
wx.hideTabBar({ animation: false })
|
wx.hideTabBar({ animation: false })
|
||||||
const app = getApp()
|
|
||||||
this.setData({
|
// 从本地存储读取审核状态
|
||||||
auditStatus: app.globalData.auditStatus
|
const auditStatus = wx.getStorageSync('auditStatus') || 0
|
||||||
})
|
this.setData({ auditStatus })
|
||||||
|
|
||||||
// 检查免费畅聊时间
|
// 检查免费畅聊时间
|
||||||
this.checkFreeTime()
|
this.checkFreeTime()
|
||||||
|
|
||||||
// 每次显示时刷新列表
|
// 每次显示时刷新列表
|
||||||
// 增加延迟,确保标记已读API有时间完成(从聊天详情页返回时)
|
// 增加延迟,确保标记已读API有时间完成(从聊天详情页返回时)
|
||||||
if (!this.data.loading) {
|
if (!this.data.loading) {
|
||||||
|
|
|
||||||
|
|
@ -34,8 +34,8 @@
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- AI会话列表(支持滑动删除) -->
|
<!-- AI会话列表(支持滑动删除,审核时隐藏) -->
|
||||||
<view class="swipe-container" wx:for="{{conversations}}" wx:key="id">
|
<view class="swipe-container" wx:for="{{conversations}}" wx:key="id" wx:if="{{auditStatus === 0}}">
|
||||||
<view
|
<view
|
||||||
class="swipe-content {{item.swiped ? 'swiped' : ''}}"
|
class="swipe-content {{item.swiped ? 'swiped' : ''}}"
|
||||||
bindtouchstart="onTouchStart"
|
bindtouchstart="onTouchStart"
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@
|
||||||
// 根据Figma设计实现
|
// 根据Figma设计实现
|
||||||
|
|
||||||
const api = require('../../utils/api')
|
const api = require('../../utils/api')
|
||||||
|
const config = require('../../config/index')
|
||||||
|
const versionConfig = require('../../config/version')
|
||||||
const app = getApp()
|
const app = getApp()
|
||||||
|
|
||||||
Page({
|
Page({
|
||||||
|
|
@ -17,39 +19,8 @@ Page({
|
||||||
swiperHeight: 400,
|
swiperHeight: 400,
|
||||||
currentBannerIndex: 0,
|
currentBannerIndex: 0,
|
||||||
|
|
||||||
// 功能入口 - 使用正式环境图片URL
|
// 功能入口 - 使用版本化配置
|
||||||
categoryList: [
|
categoryList: versionConfig.getCategoryList(),
|
||||||
{
|
|
||||||
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'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
|
|
||||||
// 滚动公告
|
// 滚动公告
|
||||||
noticeList: [],
|
noticeList: [],
|
||||||
|
|
@ -112,7 +83,7 @@ Page({
|
||||||
* 处理图片URL,如果是相对路径则拼接域名,并设置清晰度为85
|
* 处理图片URL,如果是相对路径则拼接域名,并设置清晰度为85
|
||||||
*/
|
*/
|
||||||
processImageUrl(url) {
|
processImageUrl(url) {
|
||||||
if (!url) return ''
|
if (!url || typeof url !== 'string') return ''
|
||||||
let fullUrl = url
|
let fullUrl = url
|
||||||
if (!url.startsWith('http://') && !url.startsWith('https://')) {
|
if (!url.startsWith('http://') && !url.startsWith('https://')) {
|
||||||
const baseUrl = 'https://ai-c.maimanji.com'
|
const baseUrl = 'https://ai-c.maimanji.com'
|
||||||
|
|
@ -545,58 +516,17 @@ Page({
|
||||||
* 分类点击
|
* 分类点击
|
||||||
*/
|
*/
|
||||||
onCategoryTap(e) {
|
onCategoryTap(e) {
|
||||||
const { id, name } = e.currentTarget.dataset
|
const { id, name, url } = e.currentTarget.dataset
|
||||||
|
|
||||||
// 兴趣搭子跳转到专门页面
|
// 从版本配置中获取分类信息
|
||||||
if (id === 1) {
|
const categoryList = versionConfig.getCategoryList()
|
||||||
wx.navigateTo({
|
const category = categoryList.find(item => item.id === id)
|
||||||
url: '/pages/interest-partner/interest-partner'
|
|
||||||
})
|
if (category && category.url) {
|
||||||
return
|
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-section">
|
||||||
<view class="category-item"
|
<view class="category-item"
|
||||||
wx:for="{{categoryList}}"
|
wx:for="{{categoryList}}"
|
||||||
wx:key="id"
|
wx:key="id"
|
||||||
data-id="{{item.id}}"
|
data-id="{{item.id}}"
|
||||||
data-name="{{item.name}}"
|
data-name="{{item.name}}"
|
||||||
|
data-url="{{item.url}}"
|
||||||
bindtap="onCategoryTap">
|
bindtap="onCategoryTap">
|
||||||
<!-- 图标容器:圆形图片 -->
|
<!-- 图标容器:圆形图片 -->
|
||||||
<view class="category-icon-container">
|
<view class="category-icon-container">
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
const api = require('../../utils/api')
|
const api = require('../../utils/api')
|
||||||
const auth = require('../../utils/auth')
|
|
||||||
const config = require('../../config/index')
|
const config = require('../../config/index')
|
||||||
|
|
||||||
Page({
|
Page({
|
||||||
|
|
@ -8,6 +7,7 @@ Page({
|
||||||
navBarHeight: 44,
|
navBarHeight: 44,
|
||||||
totalNavHeight: 88,
|
totalNavHeight: 88,
|
||||||
lovePoints: 0,
|
lovePoints: 0,
|
||||||
|
isLoggedIn: false,
|
||||||
gifts: [],
|
gifts: [],
|
||||||
giftsLoading: false,
|
giftsLoading: false,
|
||||||
giftsError: '',
|
giftsError: '',
|
||||||
|
|
@ -32,28 +32,31 @@ Page({
|
||||||
const menuButton = wx.getMenuButtonBoundingClientRect()
|
const menuButton = wx.getMenuButtonBoundingClientRect()
|
||||||
const navBarHeight = menuButton.height + (menuButton.top - statusBarHeight) * 2
|
const navBarHeight = menuButton.height + (menuButton.top - statusBarHeight) * 2
|
||||||
const totalNavHeight = statusBarHeight + navBarHeight
|
const totalNavHeight = statusBarHeight + navBarHeight
|
||||||
|
|
||||||
this.setData({
|
this.setData({
|
||||||
statusBarHeight,
|
statusBarHeight,
|
||||||
navBarHeight,
|
navBarHeight,
|
||||||
totalNavHeight
|
totalNavHeight
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 礼物商城无需登录即可访问
|
||||||
this.loadGifts()
|
this.loadGifts()
|
||||||
|
|
||||||
const isValid = await auth.ensureLogin({
|
// 检查登录状态并加载爱心值
|
||||||
pageName: 'gift-shop',
|
const app = getApp()
|
||||||
redirectUrl: '/pages/gift-shop/gift-shop'
|
const isLoggedIn = app.globalData.isLoggedIn
|
||||||
})
|
this.setData({ isLoggedIn })
|
||||||
|
|
||||||
if (!isValid) return
|
if (isLoggedIn) {
|
||||||
|
this.loadLovePoints()
|
||||||
await new Promise(resolve => setTimeout(resolve, 50))
|
}
|
||||||
this.loadLovePoints()
|
|
||||||
},
|
},
|
||||||
|
|
||||||
onShow() {
|
onShow() {
|
||||||
const app = getApp()
|
const app = getApp()
|
||||||
|
this.setData({ isLoggedIn: app.globalData.isLoggedIn })
|
||||||
|
|
||||||
|
// 仅在登录状态下刷新爱心值
|
||||||
if (app.globalData.isLoggedIn) {
|
if (app.globalData.isLoggedIn) {
|
||||||
this.loadLovePoints()
|
this.loadLovePoints()
|
||||||
}
|
}
|
||||||
|
|
@ -121,12 +124,21 @@ Page({
|
||||||
},
|
},
|
||||||
|
|
||||||
// 点击礼品卡片
|
// 点击礼品卡片
|
||||||
onGiftTap(e) {
|
onGiftTap() {
|
||||||
wx.showModal({
|
wx.showModal({
|
||||||
title: '提示',
|
title: '联系客服',
|
||||||
content: '请下载app端进行兑换',
|
content: '请添加客服:mmj20259999',
|
||||||
showCancel: false,
|
confirmText: '复制',
|
||||||
confirmText: '知道了'
|
success: (res) => {
|
||||||
|
if (res.confirm) {
|
||||||
|
wx.setClipboardData({
|
||||||
|
data: 'mmj20259999',
|
||||||
|
success: () => {
|
||||||
|
wx.showToast({ title: '已复制', icon: 'success' })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,8 @@
|
||||||
<!-- 内容区域 -->
|
<!-- 内容区域 -->
|
||||||
<scroll-view scroll-y class="content-scroll" style="padding-top: {{totalNavHeight}}px;" enhanced show-scrollbar="{{false}}">
|
<scroll-view scroll-y class="content-scroll" style="padding-top: {{totalNavHeight}}px;" enhanced show-scrollbar="{{false}}">
|
||||||
<view class="content-wrap">
|
<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-bg"></view>
|
||||||
<view class="love-card-blur"></view>
|
<view class="love-card-blur"></view>
|
||||||
<view class="love-card-bottom-shade"></view>
|
<view class="love-card-bottom-shade"></view>
|
||||||
|
|
|
||||||
|
|
@ -85,31 +85,21 @@ Page({
|
||||||
},
|
},
|
||||||
|
|
||||||
async onLoad() {
|
async onLoad() {
|
||||||
// 获取系统信息
|
const localAuditStatus = wx.getStorageSync('auditStatus') || 0
|
||||||
const { statusBarHeight, navHeight, auditStatus } = app.globalData
|
const { statusBarHeight, navHeight } = app.globalData
|
||||||
this.setData({ statusBarHeight, navHeight, auditStatus })
|
this.setData({ statusBarHeight, navHeight, auditStatus: localAuditStatus })
|
||||||
|
|
||||||
// 如果是审核状态,重定向到文娱页面
|
if (localAuditStatus === 1 || app.globalData.auditStatus === 1) {
|
||||||
if (auditStatus === 1) {
|
|
||||||
wx.switchTab({
|
wx.switchTab({
|
||||||
url: '/pages/entertainment/entertainment'
|
url: '/pages/entertainment/entertainment'
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 加载首页素材 (Banner等)
|
|
||||||
this.loadHomeAssets()
|
this.loadHomeAssets()
|
||||||
|
|
||||||
// 加载分享配置
|
|
||||||
this.loadShareConfig()
|
this.loadShareConfig()
|
||||||
|
|
||||||
// 加载角色列表
|
|
||||||
this.loadCharacters()
|
this.loadCharacters()
|
||||||
|
|
||||||
// 加载用户爱心余额
|
|
||||||
this.loadHeartBalance()
|
this.loadHeartBalance()
|
||||||
|
|
||||||
// 加载解锁配置
|
|
||||||
this.loadUnlockConfig()
|
this.loadUnlockConfig()
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -208,13 +198,15 @@ Page({
|
||||||
// 隐藏默认tabbar
|
// 隐藏默认tabbar
|
||||||
wx.hideTabBar({ animation: false })
|
wx.hideTabBar({ animation: false })
|
||||||
|
|
||||||
|
// 从本地存储读取审核状态
|
||||||
|
const localAuditStatus = wx.getStorageSync('auditStatus') || 0
|
||||||
const app = getApp()
|
const app = getApp()
|
||||||
this.setData({
|
this.setData({
|
||||||
auditStatus: app.globalData.auditStatus
|
auditStatus: localAuditStatus
|
||||||
})
|
})
|
||||||
|
|
||||||
// 如果是审核状态,重定向到文娱页面
|
// 如果是审核状态,重定向到文娱页面
|
||||||
if (app.globalData.auditStatus === 1) {
|
if (localAuditStatus === 1 || app.globalData.auditStatus === 1) {
|
||||||
wx.switchTab({
|
wx.switchTab({
|
||||||
url: '/pages/entertainment/entertainment'
|
url: '/pages/entertainment/entertainment'
|
||||||
})
|
})
|
||||||
|
|
@ -230,13 +222,30 @@ Page({
|
||||||
// 检查AI角色主动推送消息
|
// 检查AI角色主动推送消息
|
||||||
this.checkProactiveMessages()
|
this.checkProactiveMessages()
|
||||||
|
|
||||||
// 检查注册奖励
|
|
||||||
this.checkRegistrationReward()
|
this.checkRegistrationReward()
|
||||||
|
|
||||||
// 检查 GF100 弹窗
|
|
||||||
this.checkGf100Popup()
|
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() {
|
onPullDownRefresh() {
|
||||||
Promise.all([
|
Promise.all([
|
||||||
this.loadCharacters(),
|
this.loadCharacters(),
|
||||||
|
|
@ -534,16 +543,8 @@ Page({
|
||||||
const nextIndex = currentIndex + 1
|
const nextIndex = currentIndex + 1
|
||||||
|
|
||||||
// 切换卡片时,如果正在播放语音,则停止播放
|
// 切换卡片时,如果正在播放语音,则停止播放
|
||||||
if (isVoicePlaying && this.audioContext) {
|
if (isVoicePlaying) this.stopAudio()
|
||||||
try {
|
|
||||||
console.log('[index] 切换卡片,停止上一个角色的语音')
|
|
||||||
this.audioContext.stop()
|
|
||||||
} catch (e) {
|
|
||||||
console.error('[index] 停止语音失败:', e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果快到末尾,加载更多
|
|
||||||
if (nextIndex >= profiles.length - 2) {
|
if (nextIndex >= profiles.length - 2) {
|
||||||
this.loadMoreCharacters()
|
this.loadMoreCharacters()
|
||||||
}
|
}
|
||||||
|
|
@ -552,7 +553,8 @@ Page({
|
||||||
currentIndex: nextIndex,
|
currentIndex: nextIndex,
|
||||||
offsetX: 0,
|
offsetX: 0,
|
||||||
rotation: 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">
|
||||||
<view class="unified-header-left"></view>
|
<view class="unified-header-left"></view>
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
<view class="tab-item {{currentTab === 'completed' ? 'active' : ''}}" bindtap="switchTab" data-tab="completed">已完成</view>
|
<view class="tab-item {{currentTab === 'completed' ? 'active' : ''}}" bindtap="switchTab" data-tab="completed">已完成</view>
|
||||||
</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="card">
|
||||||
<view class="list">
|
<view class="list">
|
||||||
<view wx:if="{{loading}}" class="loading">加载中...</view>
|
<view wx:if="{{loading}}" class="loading">加载中...</view>
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@
|
||||||
<view class="user-info">
|
<view class="user-info">
|
||||||
<view class="user-main">
|
<view class="user-main">
|
||||||
<text class="user-name">{{item.userName}}</text>
|
<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>
|
||||||
<view class="user-sub">加入时间: {{item.joinedAt}}</view>
|
<view class="user-sub">加入时间: {{item.joinedAt}}</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
|
||||||
|
|
@ -63,15 +63,14 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.stats-value {
|
.stats-value {
|
||||||
font-size: 60rpx;
|
font-size: 48rpx;
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
margin-bottom: 12rpx;
|
margin-bottom: 8rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stats-label {
|
.stats-label {
|
||||||
font-size: 30rpx;
|
font-size: 24rpx;
|
||||||
opacity: 0.95;
|
opacity: 0.9;
|
||||||
font-weight: 500;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Amount Card */
|
/* Amount Card */
|
||||||
|
|
@ -158,116 +157,55 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.purple-dot {
|
.purple-dot {
|
||||||
width: 10rpx;
|
width: 8rpx;
|
||||||
height: 38rpx;
|
height: 32rpx;
|
||||||
background: #B06AB3;
|
background: #B06AB3;
|
||||||
border-radius: 6rpx;
|
border-radius: 4rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.panel-title {
|
.panel-title {
|
||||||
font-size: 38rpx;
|
font-size: 32rpx;
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
color: #111827;
|
color: #111827;
|
||||||
}
|
}
|
||||||
|
|
||||||
.referral-count {
|
.referral-count {
|
||||||
font-size: 38rpx;
|
font-size: 32rpx;
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
color: #B06AB3;
|
color: #B06AB3;
|
||||||
}
|
}
|
||||||
|
|
||||||
.see-all {
|
.user-grid {
|
||||||
font-size: 32rpx;
|
display: flex;
|
||||||
color: #B06AB3;
|
flex-wrap: wrap;
|
||||||
font-weight: 700;
|
gap: 32rpx; /* Space between items */
|
||||||
}
|
}
|
||||||
|
|
||||||
.user-list {
|
.user-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 32rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.user-row {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 32rpx 0;
|
width: 120rpx;
|
||||||
border-bottom: 2rpx solid #F3F4F6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.user-row:last-child {
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.user-avatar {
|
.user-avatar {
|
||||||
width: 110rpx;
|
width: 100rpx;
|
||||||
height: 110rpx;
|
height: 100rpx;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background: #F3F4F6;
|
background: #F3F4F6;
|
||||||
margin-right: 24rpx;
|
margin-bottom: 12rpx;
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.user-info {
|
|
||||||
flex: 1;
|
|
||||||
min-width: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.user-main {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 16rpx;
|
|
||||||
margin-bottom: 8rpx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.user-name {
|
.user-name {
|
||||||
font-size: 36rpx;
|
font-size: 24rpx;
|
||||||
font-weight: 700;
|
color: #4B5563;
|
||||||
color: #1F2937;
|
width: 100%;
|
||||||
max-width: 240rpx;
|
text-align: center;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
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 {
|
.empty-state {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
@ -286,7 +224,7 @@
|
||||||
.menu-item {
|
.menu-item {
|
||||||
background: #FFFFFF;
|
background: #FFFFFF;
|
||||||
border-radius: 24rpx;
|
border-radius: 24rpx;
|
||||||
padding: 40rpx 32rpx;
|
padding: 32rpx;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|
@ -296,12 +234,12 @@
|
||||||
.menu-left {
|
.menu-left {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 32rpx;
|
gap: 24rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-circle {
|
.icon-circle {
|
||||||
width: 88rpx;
|
width: 72rpx;
|
||||||
height: 88rpx;
|
height: 72rpx;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
@ -313,15 +251,15 @@
|
||||||
.icon-circle.orange { background: rgba(245, 158, 11, 0.1); }
|
.icon-circle.orange { background: rgba(245, 158, 11, 0.1); }
|
||||||
|
|
||||||
.menu-text {
|
.menu-text {
|
||||||
font-size: 34rpx;
|
font-size: 30rpx;
|
||||||
font-weight: 700;
|
font-weight: 600;
|
||||||
color: #1F2937;
|
color: #1F2937;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-reset {
|
.btn-reset {
|
||||||
background: none;
|
background: none;
|
||||||
border: none;
|
border: none;
|
||||||
padding: 40rpx 32rpx; /* Match menu-item padding */
|
padding: 32rpx; /* Match menu-item padding */
|
||||||
margin: 0;
|
margin: 0;
|
||||||
line-height: normal;
|
line-height: normal;
|
||||||
border-radius: 24rpx; /* Match menu-item border-radius */
|
border-radius: 24rpx; /* Match menu-item border-radius */
|
||||||
|
|
|
||||||
|
|
@ -61,11 +61,11 @@
|
||||||
<view class="list-container" wx:if="{{list.length > 0}}">
|
<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="list-item" wx:for="{{list}}" wx:key="userId" bindtap="viewOrders" data-item="{{item}}">
|
||||||
<view class="user-info">
|
<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-details">
|
||||||
<view class="user-name-row">
|
<view class="user-name-row">
|
||||||
<text class="user-name">{{item.userName}}</text>
|
<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>
|
||||||
<view class="user-time">绑定时间: {{formatTime(item.boundAt)}}</view>
|
<view class="user-time">绑定时间: {{formatTime(item.boundAt)}}</view>
|
||||||
<view class="user-meta">
|
<view class="user-meta">
|
||||||
|
|
|
||||||
|
|
@ -137,7 +137,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.user-name {
|
.user-name {
|
||||||
font-size: 36rpx;
|
font-size: 32rpx;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #1F2937;
|
color: #1F2937;
|
||||||
}
|
}
|
||||||
|
|
@ -194,13 +194,13 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.user-time {
|
.user-time {
|
||||||
font-size: 28rpx;
|
font-size: 24rpx;
|
||||||
color: #9CA3AF;
|
color: #9CA3AF;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 列表项详情扩展 */
|
/* 列表项详情扩展 */
|
||||||
.user-meta {
|
.user-meta {
|
||||||
font-size: 26rpx;
|
font-size: 22rpx;
|
||||||
color: #6B7280;
|
color: #6B7280;
|
||||||
margin-top: 8rpx;
|
margin-top: 8rpx;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
@ -208,10 +208,10 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.user-level {
|
.user-level {
|
||||||
font-size: 24rpx;
|
font-size: 20rpx;
|
||||||
color: #B06AB3;
|
color: #B06AB3;
|
||||||
background: rgba(176, 106, 179, 0.1);
|
background: rgba(176, 106, 179, 0.1);
|
||||||
padding: 4rpx 16rpx;
|
padding: 2rpx 12rpx;
|
||||||
border-radius: 20rpx;
|
border-radius: 20rpx;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@
|
||||||
|
|
||||||
<!-- 商家列表 -->
|
<!-- 商家列表 -->
|
||||||
<view class="provider-list">
|
<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="provider-left">
|
||||||
<view class="avatar-container">
|
<view class="avatar-container">
|
||||||
<view class="avatar-wrapper">
|
<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'),
|
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