diff --git a/src/components/ChatBox.vue b/src/components/ChatBox.vue
index 51ff02b..c101c9c 100644
--- a/src/components/ChatBox.vue
+++ b/src/components/ChatBox.vue
@@ -1,5 +1,5 @@
-
+
@@ -16,13 +16,9 @@
-
- ←
- 返回
-
清空
-
+
{{ currentCharacter.name }}
@@ -35,6 +31,7 @@
-
+
-
+
+
+
+
+
+
+
+
@@ -122,6 +137,9 @@ const connectTime = ref('');
const statusBarHeight = ref(0);
const navBarHeight = ref(0);
+// 下拉刷新相关
+const refresherTriggered = ref(false);
+
// 获取系统状态栏高度
const getSystemInfo = () => {
const systemInfo = uni.getSystemInfoSync();
@@ -139,7 +157,7 @@ onMounted(() => {
});
// 刷新设备状态
-const refreshDeviceStatus = () => {
+const refreshDeviceStatus = (isRefresh = false) => {
if (!userStore.isLoggedIn) {
uni.showToast({
title: '请先登录',
@@ -149,10 +167,12 @@ const refreshDeviceStatus = () => {
}
// 暂时注释掉API请求,使用本地模拟数据
- uni.showToast({
- title: '刷新成功(本地模拟)',
- icon: 'success'
- });
+ if (!isRefresh) {
+ uni.showToast({
+ title: '刷新成功(本地模拟)',
+ icon: 'success'
+ });
+ }
/* API请求已注释
uni.showLoading({
@@ -283,15 +303,42 @@ const goToLogin = () => {
url: '/pages/mine/mine'
});
};
+
+// 下拉刷新处理
+const onRefresh = async () => {
+ console.log('触发下拉刷新');
+ refresherTriggered.value = true;
+
+ try {
+ // 刷新设备状态
+ refreshDeviceStatus(true);
+
+ // 延迟显示刷新成功提示
+ setTimeout(() => {
+ uni.showToast({
+ title: '刷新成功',
+ icon: 'success',
+ duration: 1500
+ });
+ }, 300);
+ } finally {
+ // 刷新完成后,关闭刷新状态
+ setTimeout(() => {
+ refresherTriggered.value = false;
+ }, 500);
+ }
+};
diff --git a/src/pages/drama/index.vue b/src/pages/drama/index.vue
index 8d90e4b..5f35b16 100644
--- a/src/pages/drama/index.vue
+++ b/src/pages/drama/index.vue
@@ -24,11 +24,13 @@
+
@@ -36,13 +38,30 @@
+
+
+ {{ unreadCounts[item.roleId] }}
+
{{ item.tag }}
{{ item.title }}
-
-
+
+
@@ -54,13 +73,30 @@
+
+
+ {{ unreadCounts[item.roleId] }}
+
{{ item.tag }}
{{ item.title }}
-
-
+
+
@@ -117,6 +153,13 @@
import { ref, computed, onMounted } from 'vue';
import { useUserStore } from '@/stores/user.js';
import { roleAPI, getResourceUrl } from '@/utils/api.js';
+// 🔴 新增:导入未读消息管理模块
+import {
+ getAllUnreadCounts,
+ generateTestMessages,
+ clearUnreadMessages,
+ autoGenerateMessagesForRandomRoles
+} from '@/utils/unreadMessages.js';
const userStore = useUserStore();
const showLoginModal = ref(false);
@@ -125,10 +168,19 @@ const showLoginModal = ref(false);
const showDetailModal = ref(false);
const selectedItem = ref(null);
+// 下拉刷新相关
+const refresherTriggered = ref(false);
+
// 状态栏高度适配
const statusBarHeight = ref(0);
const navBarHeight = ref(0);
+// 🔴 新增:未读消息数量统计
+const unreadCounts = ref({});
+
+// 🔴 新增:是否首次加载标记
+const isFirstLoad = ref(true);
+
// 获取系统状态栏高度
const getSystemInfo = () => {
const systemInfo = uni.getSystemInfoSync();
@@ -320,11 +372,20 @@ const dramaList = ref([
const leftColumnItems = computed(() => dramaList.value.filter((_, index) => index % 2 === 0));
const rightColumnItems = computed(() => dramaList.value.filter((_, index) => index % 2 === 1));
+// 🔴 新增:加载未读消息数量
+const loadUnreadCounts = () => {
+ unreadCounts.value = getAllUnreadCounts();
+ console.log('📬 未读消息统计:', unreadCounts.value);
+};
+
// 加载角色列表数据
-const loadDramaList = async () => {
+const loadDramaList = async (isRefresh = false) => {
try {
- uni.showLoading({ title: '加载中...' });
- console.log('开始加载角色列表...');
+ // 如果不是下拉刷新,则显示loading提示
+ if (!isRefresh) {
+ uni.showLoading({ title: '加载中...' });
+ }
+ console.log('开始加载角色列表...', isRefresh ? '(下拉刷新)' : '');
const result = await roleAPI.getRoles();
console.log('API返回结果:', result);
@@ -379,32 +440,93 @@ const loadDramaList = async () => {
}));
console.log('角色列表加载成功,共', dramaList.value.length, '个角色');
+
+ // 如果是下拉刷新,显示成功提示
+ if (isRefresh) {
+ uni.showToast({
+ title: '刷新成功',
+ icon: 'success',
+ duration: 1500
+ });
+ }
} else {
console.error('获取角色列表失败:', result.error);
uni.showToast({
- title: '加载失败,请重试',
+ title: isRefresh ? '刷新失败,请重试' : '加载失败,请重试',
icon: 'none'
});
}
} catch (error) {
console.error('加载角色列表异常:', error);
uni.showToast({
- title: '加载异常,请重试',
+ title: isRefresh ? '刷新异常,请重试' : '加载异常,请重试',
icon: 'none'
});
} finally {
- uni.hideLoading();
+ if (!isRefresh) {
+ uni.hideLoading();
+ }
+ // 🔴 新增:加载完角色后刷新未读消息数量
+ loadUnreadCounts();
}
};
+// 下拉刷新处理
+const onRefresh = async () => {
+ console.log('触发下拉刷新');
+ refresherTriggered.value = true;
+
+ try {
+ await loadDramaList(true);
+ } finally {
+ // 刷新完成后,关闭刷新状态
+ setTimeout(() => {
+ refresherTriggered.value = false;
+ }, 500);
+ }
+};
+
+// 🔴 新增:自动生成随机角色消息
+const autoGenerateRandomMessages = () => {
+ console.log('🎲 准备自动生成消息,当前角色数量:', dramaList.value.length);
+
+ if (dramaList.value.length === 0) {
+ console.log('⚠️ 角色列表为空,无法生成消息');
+ return 0;
+ }
+
+ // 随机选择2个角色生成消息
+ const count = autoGenerateMessagesForRandomRoles(dramaList.value, 2, 1);
+
+ if (count > 0) {
+ console.log(`✨ 已为 ${count} 个随机角色生成主动消息`);
+ // 刷新未读消息数量
+ loadUnreadCounts();
+ } else {
+ console.log('⚠️ 未能生成消息');
+ }
+
+ return count;
+};
+
onMounted(() => {
getSystemInfo(); // 获取系统信息
userStore.init();
// 调用 API 加载角色列表
loadDramaList();
+ console.log('📱 进入角色列表页面');
+
+// 刷新未读消息数量
+loadUnreadCounts();
+
+// 延迟生成消息(等待角色列表加载完成)
+setTimeout(() => {
+ autoGenerateRandomMessages();
+}, 500);
});
+
// 方法
const handleUse = (item) => {
if (!item || !item.id) {
@@ -412,7 +534,7 @@ const handleUse = (item) => {
return;
}
uni.showLoading({ title: '正在设置角色...' });
-
+
// 构建完整的角色参数,包括模型和模板信息
const params = {
characterId: item.id,
@@ -428,15 +550,40 @@ const handleUse = (item) => {
temperature: item.temperature || '',
topP: item.topP || ''
};
-
+
const queryString = Object.keys(params)
.map(key => `${key}=${encodeURIComponent(params[key] || '')}`)
.join('&');
-
+
uni.hideLoading();
uni.navigateTo({ url: `/pages/role-chat/role-chat?${queryString}` });
};
+// 🔴 新增:长按角色卡生成测试消息(用于开发测试)
+const handleLongPress = (item) => {
+ uni.showActionSheet({
+ itemList: ['为该角色生成1条消息', '为该角色生成3条消息'],
+ success: (res) => {
+ const messageCount = res.tapIndex === 0 ? 1 : 3;
+
+ const success = generateTestMessages(item.roleId, item.roleName, messageCount);
+ if (success) {
+ loadUnreadCounts(); // 刷新未读消息数量
+ uni.showToast({
+ title: `✅ 已为"${item.roleName}"生成${messageCount}条消息`,
+ icon: 'success',
+ duration: 2000
+ });
+ } else {
+ uni.showToast({
+ title: '❌ 生成失败',
+ icon: 'none'
+ });
+ }
+ }
+ });
+};
+
const showLoginTip = () => { showLoginModal.value = true; };
const showDetail = (item) => { selectedItem.value = item; showDetailModal.value = true; };
const closeDetail = () => { showDetailModal.value = false; selectedItem.value = null; };
@@ -830,4 +977,36 @@ const goToLogin = () => { showLoginModal.value = false; uni.switchTab({ url: '/p
flex: 1;
padding: 16rpx 32rpx;
}
+
+/* 🔴 新增:未读消息红点样式 */
+.unread-badge {
+ position: absolute;
+ top: 12rpx;
+ right: 12rpx;
+ min-width: 36rpx;
+ height: 36rpx;
+ background: linear-gradient(135deg, #ff4d4f 0%, #ff7875 100%);
+ color: #ffffff;
+ font-size: 20rpx;
+ font-weight: bold;
+ border-radius: 18rpx;
+ padding: 0 8rpx;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ box-shadow: 0 4rpx 12rpx rgba(255, 77, 79, 0.6);
+ z-index: 10;
+ animation: badge-pulse 2s infinite;
+}
+
+@keyframes badge-pulse {
+ 0%, 100% {
+ transform: scale(1);
+ box-shadow: 0 4rpx 12rpx rgba(255, 77, 79, 0.6);
+ }
+ 50% {
+ transform: scale(1.1);
+ box-shadow: 0 6rpx 16rpx rgba(255, 77, 79, 0.8);
+ }
+}
diff --git a/src/pages/mine/mine.vue b/src/pages/mine/mine.vue
index f0846f1..dec9771 100644
--- a/src/pages/mine/mine.vue
+++ b/src/pages/mine/mine.vue
@@ -29,6 +29,10 @@
:style="{ marginTop: navBarHeight + 'px' }"
scroll-y="true"
:show-scrollbar="false"
+ refresher-enabled
+ :refresher-triggered="refresherTriggered"
+ @refresherrefresh="onRefresh"
+ refresher-background="rgba(26, 11, 46, 0.5)"
>
@@ -132,6 +136,9 @@ const userBalance = ref(0.00);
const statusBarHeight = ref(0);
const navBarHeight = ref(0);
+// 下拉刷新相关
+const refresherTriggered = ref(false);
+
// 登录按钮文本
const loginButtonText = computed(() => {
return '微信一键登录';
@@ -476,17 +483,39 @@ Token: ${currentToken || '无'}
};
// 加载用户余额
-const loadUserBalance = async () => {
+const loadUserBalance = async (isRefresh = false) => {
if (!isLoggedIn.value) return;
-
+
+ // 暂时注释掉API请求,使用本地模拟数据
+ console.log('loadUserBalance called, 使用模拟数据');
+ userBalance.value = 0.00; // 默认余额
+
+ if (isRefresh) {
+ console.log('余额刷新成功(本地模拟)');
+ }
+
+ /* API请求已注释
try {
const result = await rechargeAPI.getUserBalance();
if (result.success) {
userBalance.value = result.data.balance || 0;
+
+ // 如果是下拉刷新,显示成功提示
+ if (isRefresh) {
+ console.log('余额刷新成功');
+ }
}
} catch (error) {
console.error('获取用户余额失败:', error);
+ if (isRefresh) {
+ uni.showToast({
+ title: '余额刷新失败',
+ icon: 'none',
+ duration: 1500
+ });
+ }
}
+ */
};
// 跳转到充值页面
@@ -502,6 +531,39 @@ const goToHistory = () => {
url: '/pages/recharge/history'
});
};
+
+// 下拉刷新处理
+const onRefresh = async () => {
+ console.log('触发下拉刷新');
+ refresherTriggered.value = true;
+
+ try {
+ // 刷新用户信息
+ initUserInfo();
+
+ // 刷新用户余额
+ await loadUserBalance(true);
+
+ // 显示刷新成功提示
+ uni.showToast({
+ title: '刷新成功',
+ icon: 'success',
+ duration: 1500
+ });
+ } catch (error) {
+ console.error('刷新失败:', error);
+ uni.showToast({
+ title: '刷新失败',
+ icon: 'none',
+ duration: 1500
+ });
+ } finally {
+ // 刷新完成后,关闭刷新状态
+ setTimeout(() => {
+ refresherTriggered.value = false;
+ }, 500);
+ }
+};