清理:移动冗余文件

This commit is contained in:
xiao12feng8 2026-01-06 10:25:40 +08:00
parent a2287bccd1
commit 1124ce7d82
36 changed files with 70 additions and 4043 deletions

View File

@ -1,285 +0,0 @@
# Android端API路径修复指南
## 🎯 目标
将Android端的观看历史API调用路径修改为与zhibo-h后台匹配。
---
## 📝 需要修改的文件
### 文件1: ApiService.java
**位置**: `android-app/app/src/main/java/com/zbkj/front/net/ApiService.java`
#### 修改内容
找到以下接口定义并修改:
```java
// ==================== 用户活动记录 ====================
/**
* 获取观看历史
*/
@GET("api/front/activity/view/history") // ← 修改这里view-history 改为 view/history
Call<ApiResponse<PageResponse<Map<String, Object>>>> getViewHistory(
@Query("targetType") String targetType, // ← 修改这里type 改为 targetType
@Query("page") int page,
@Query("pageSize") int pageSize);
/**
* 清除观看历史
*/
@DELETE("api/front/activity/view/history") // ← 修改这里view-history 改为 view/history
Call<ApiResponse<String>> clearViewHistory(@Query("targetType") String targetType); // ← 修改这里type 改为 targetType
/**
* 获取点赞记录
*/
@GET("api/front/activity/like/records") // ← 修改这里like-records 改为 like/records
Call<ApiResponse<PageResponse<Map<String, Object>>>> getLikeRecords(
@Query("targetType") String targetType, // ← 修改这里type 改为 targetType
@Query("page") int page,
@Query("pageSize") int pageSize);
/**
* 获取收藏的作品
*/
@GET("api/front/activity/collect/works") // ← 修改这里collected-works 改为 collect/works
Call<ApiResponse<PageResponse<Map<String, Object>>>> getCollectedWorks(
@Query("page") int page,
@Query("pageSize") int pageSize);
/**
* 获取关注记录
*/
@GET("api/front/activity/follow/records") // ← 修改这里follow-records 改为 follow/records
Call<ApiResponse<PageResponse<Map<String, Object>>>> getFollowRecords(
@Query("page") int page,
@Query("pageSize") int pageSize);
/**
* 记录观看历史(新版)
*/
@POST("api/front/activity/view/record") // ← 修改这里record-view 改为 view/record
Call<ApiResponse<Map<String, Object>>> recordViewHistoryNew(@Body Map<String, Object> body);
/**
* 调试Token
*/
@GET("api/front/activity/debug/token") // ← 修改这里debug-token 改为 debug/token
Call<ApiResponse<Map<String, Object>>> debugToken();
```
---
### 文件2: RoomDetailActivity.java
**位置**: `android-app/app/src/main/java/com/zbkj/front/livestreaming/RoomDetailActivity.java`
#### 修改内容
找到 `recordWatchHistory()` 方法,确保参数名正确:
```java
private void recordWatchHistory() {
try {
if (!AuthHelper.isLoggedIn(this)) {
return; // 未登录用户不记录
}
if (TextUtils.isEmpty(roomId)) {
return;
}
ApiService apiService = ApiClient.getService(getApplicationContext());
// 使用新的统一观看历史API
java.util.Map<String, Object> body = new java.util.HashMap<>();
body.put("targetType", "room"); // ✅ 正确targetType
body.put("targetId", roomId);
body.put("targetTitle", "直播间");
body.put("duration", 0); // ✅ 正确duration不是viewDuration
Call<ApiResponse<java.util.Map<String, Object>>> call = apiService.recordViewHistoryNew(body);
call.enqueue(new Callback<ApiResponse<java.util.Map<String, Object>>>() {
@Override
public void onResponse(Call<ApiResponse<java.util.Map<String, Object>>> call,
Response<ApiResponse<java.util.Map<String, Object>>> response) {
if (response.isSuccessful() && response.body() != null && response.body().isOk()) {
android.util.Log.d("RoomDetail", "观看历史记录成功");
// 房间信息加载后更新观看历史
updateWatchHistoryWithRoomInfo();
} else {
android.util.Log.w("RoomDetail", "记录观看历史失败: " +
(response.body() != null ? response.body().getMessage() : "unknown"));
}
}
@Override
public void onFailure(Call<ApiResponse<java.util.Map<String, Object>>> call, Throwable t) {
// 忽略错误,不影响直播观看
android.util.Log.w("RoomDetail", "记录观看历史失败: " + t.getMessage());
}
});
} catch (Exception e) {
// 忽略所有异常,不影响直播观看
android.util.Log.w("RoomDetail", "记录观看历史失败: " + e.getMessage());
}
}
```
找到 `updateWatchHistoryWithRoomInfo()` 方法,确保参数名正确:
```java
private void updateWatchHistoryWithRoomInfo() {
if (room == null || !AuthHelper.isLoggedIn(this)) {
return;
}
try {
ApiService apiService = ApiClient.getService(getApplicationContext());
java.util.Map<String, Object> body = new java.util.HashMap<>();
body.put("targetType", "room"); // ✅ 正确targetType
body.put("targetId", roomId);
body.put("targetTitle", room.getTitle() != null ? room.getTitle() : "直播间");
body.put("duration", 0); // ✅ 正确duration不是viewDuration
apiService.recordViewHistoryNew(body).enqueue(new Callback<ApiResponse<java.util.Map<String, Object>>>() {
@Override
public void onResponse(Call<ApiResponse<java.util.Map<String, Object>>> call,
Response<ApiResponse<java.util.Map<String, Object>>> response) {
if (response.isSuccessful() && response.body() != null && response.body().isOk()) {
android.util.Log.d("RoomDetail", "观看历史更新成功");
}
}
@Override
public void onFailure(Call<ApiResponse<java.util.Map<String, Object>>> call, Throwable t) {
// 忽略错误
}
});
} catch (Exception e) {
// 忽略所有异常
}
}
```
---
## 🔍 修改对比表
| 功能 | 旧路径(错误) | 新路径(正确) | 参数变化 |
|------|--------------|--------------|---------|
| 记录观看历史 | `/activity/record-view` | `/activity/view/record` | - |
| 获取观看历史 | `/activity/view-history` | `/activity/view/history` | `type``targetType` |
| 清除观看历史 | `/activity/view-history` | `/activity/view/history` | `type``targetType` |
| 获取点赞记录 | `/activity/like-records` | `/activity/like/records` | `type``targetType` |
| 获取收藏记录 | `/activity/collected-works` | `/activity/collect/works` | - |
| 获取关注记录 | `/activity/follow-records` | `/activity/follow/records` | - |
| Token调试 | `/activity/debug-token` | `/activity/debug/token` | - |
---
## ✅ 修改检查清单
- [ ] 修改 `ApiService.java` 中的所有API路径
- [ ] 修改 `ApiService.java` 中的参数名(`type` → `targetType`
- [ ] 检查 `RoomDetailActivity.java` 中的参数名(`duration` 不是 `viewDuration`
- [ ] 重新编译Android应用
- [ ] 测试记录观看历史功能
- [ ] 测试查看观看历史功能
- [ ] 检查日志输出
---
## 🧪 测试步骤
### 1. 编译应用
```bash
cd android-app
./gradlew assembleDebug
```
### 2. 安装并运行
```bash
adb install -r app/build/outputs/apk/debug/app-debug.apk
```
### 3. 测试流程
1. **登录应用**
- 确保使用有效的账号登录
2. **进入直播间**
- 选择任意直播间进入
- 查看Logcat日志搜索 "观看历史"
3. **检查日志**
```
RoomDetail: 观看历史记录成功
RoomDetail: 观看历史更新成功
```
4. **查看历史记录**
- 返回首页
- 进入"我的" → "我的记录"
- 切换到"观看历史"标签页
- 应该能看到刚才观看的直播间
### 4. 调试Token如果有问题
使用Postman或curl测试
```bash
curl -X GET "http://1.15.149.240:8081/api/front/activity/debug/token" \
-H "Authorization: Bearer YOUR_TOKEN"
```
---
## 🐛 常见问题
### 问题1401 未登录
**原因**: Token未正确传递
**解决**:
1. 检查 `ApiClient.java` 中的Token拦截器
2. 确保Token格式正确`Bearer {token}`
3. 使用 `/activity/debug/token` 接口验证
### 问题2404 Not Found
**原因**: API路径错误
**解决**:
1. 检查 `ApiService.java` 中的路径是否正确
2. 确保使用 `/` 而不是 `-`
3. 检查后台服务是否运行在8081端口
### 问题3参数错误
**原因**: 参数名不匹配
**解决**:
1. 确保使用 `targetType` 而不是 `type`
2. 确保使用 `duration` 而不是 `viewDuration`
3. 检查后台日志
---
## 📚 相关文档
- [观看历史功能-zhibo-h后台说明.md](./观看历史功能-zhibo-h后台说明.md)
- [观看历史功能-快速指南.md](./观看历史功能-快速指南.md)
---
**最后更新**: 2026-01-05
**状态**: 📝 待修改

View File

@ -20,4 +20,4 @@ APK: android-app/app/build/outputs/apk/release/
前端: Zhibo/admin/dist/ 前端: Zhibo/admin/dist/
前端访问的服务改成8083本地改回8081 app部署改成8083本地开发改成8081

View File

@ -1,19 +0,0 @@
-- 添加社会动态测试数据
-- 先检查表是否存在
SELECT COUNT(*) as count FROM eb_dynamic;
-- 插入测试数据(使用已有用户)
INSERT INTO `eb_dynamic` (`uid`, `nickname`, `avatar`, `content`, `images`, `location`, `like_count`, `comment_count`, `share_count`, `view_count`, `is_top`, `status`, `create_time`) VALUES
(41, '夏至已至', 'https://thirdwx.qlogo.cn/mmopen/vi_32/Q0j4TwGTfTKq2CRmib1mpu4hOFYtPNLkpU5ILwYTYsvVYB0WYQ0hL4sKAGicicO0OicYCT1/132', '今天天气真好,出来直播啦!大家快来看我~', '["https://picsum.photos/400/300?random=101"]', '北京市', 128, 32, 8, 560, 0, 1, NOW() - INTERVAL 2 HOUR),
(42, '测试用户', '', '分享一下我的日常生活,希望大家喜欢❤️', '["https://picsum.photos/400/300?random=102","https://picsum.photos/400/300?random=103"]', '上海市', 256, 45, 12, 890, 0, 1, NOW() - INTERVAL 5 HOUR),
(43, 'xiaofeng', '', '新的一天新的开始今晚8点准时开播不见不散~', '["https://picsum.photos/400/300?random=104"]', '广州市', 89, 18, 5, 320, 0, 1, NOW() - INTERVAL 1 DAY),
(100, '吉惟同学', 'https://img.zcool.cn/community/01a9a65d143edaa8012187f447cfef.jpg', '周末愉快!有没有想一起玩游戏的小伙伴?', '[]', '深圳市', 167, 28, 9, 450, 1, 1, NOW() - INTERVAL 3 HOUR),
(101, '国瑞哥', 'https://img.zcool.cn/community/01b72057a7e0790000018c1bf4fce0.png', '感谢大家的支持,粉丝破万啦!撒花🎉', '["https://picsum.photos/400/300?random=105","https://picsum.photos/400/300?random=106","https://picsum.photos/400/300?random=107"]', '成都市', 512, 89, 35, 1580, 0, 1, NOW() - INTERVAL 6 HOUR),
(102, '玖书小姐姐', '', '今天学了一首新歌,晚上直播间唱给大家听~', '["https://picsum.photos/400/300?random=108"]', '杭州市', 78, 15, 3, 210, 0, 1, NOW() - INTERVAL 8 HOUR);
-- 查看插入的数据
SELECT d.*, u.avatar as user_avatar
FROM eb_dynamic d
LEFT JOIN eb_user u ON d.uid = u.uid
ORDER BY d.id DESC
LIMIT 10;

View File

@ -71,8 +71,8 @@ android {
} }
compileOptions { compileOptions {
sourceCompatibility = JavaVersion.VERSION_21 sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_21 targetCompatibility = JavaVersion.VERSION_17
} }
buildFeatures { buildFeatures {

View File

@ -4,6 +4,9 @@
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.RECORD_AUDIO" />
<!-- 定位权限 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32" /> android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />

View File

@ -1749,16 +1749,16 @@ public class MainActivity extends AppCompatActivity {
allBackendCategories.addAll(categories); allBackendCategories.addAll(categories);
runOnUiThread(() -> { runOnUiThread(() -> {
// "我的频道"加载用户保存的频道列表
List<ChannelManagerAdapter.ChannelItem> myChannelList = loadMyChannels();
// 清空现有标签 // 清空现有标签
binding.categoryTabs.removeAllTabs(); binding.categoryTabs.removeAllTabs();
// 只显示"我的频道"里的内容 // 添加"推荐"作为第一个标签
for (ChannelManagerAdapter.ChannelItem channel : myChannelList) { binding.categoryTabs.addTab(binding.categoryTabs.newTab().setText("推荐"));
if (channel != null && channel.getName() != null) {
binding.categoryTabs.addTab(binding.categoryTabs.newTab().setText(channel.getName())); // 直接使用后端返回的分类
for (com.example.livestreaming.net.CategoryResponse cat : categories) {
if (cat != null && cat.getName() != null) {
binding.categoryTabs.addTab(binding.categoryTabs.newTab().setText(cat.getName()));
} }
} }
@ -1766,7 +1766,7 @@ public class MainActivity extends AppCompatActivity {
String lastCategory = CategoryFilterManager.getLastCategory(this); String lastCategory = CategoryFilterManager.getLastCategory(this);
restoreCategoryTabSelection(); restoreCategoryTabSelection();
Log.d(TAG, "updateCategoryTabs() 分类标签更新完成,共 " + binding.categoryTabs.getTabCount() + " 个标签(只显示我的频道"); Log.d(TAG, "updateCategoryTabs() 分类标签更新完成,共 " + binding.categoryTabs.getTabCount() + " 个标签(直接使用后端分类");
}); });
} }
@ -1777,23 +1777,33 @@ public class MainActivity extends AppCompatActivity {
if (binding == null || binding.categoryTabs == null) return; if (binding == null || binding.categoryTabs == null) return;
runOnUiThread(() -> { runOnUiThread(() -> {
// "我的频道"加载用户保存的频道列表
List<ChannelManagerAdapter.ChannelItem> myChannelList = loadMyChannels();
// 清空现有标签 // 清空现有标签
binding.categoryTabs.removeAllTabs(); binding.categoryTabs.removeAllTabs();
// 只显示"我的频道"里的内容 // 使用后端分类如果已加载
for (ChannelManagerAdapter.ChannelItem channel : myChannelList) { if (!allBackendCategories.isEmpty()) {
if (channel != null && channel.getName() != null) { // 添加"推荐"作为第一个标签
binding.categoryTabs.addTab(binding.categoryTabs.newTab().setText(channel.getName())); binding.categoryTabs.addTab(binding.categoryTabs.newTab().setText("推荐"));
// 添加后端分类
for (com.example.livestreaming.net.CategoryResponse cat : allBackendCategories) {
if (cat != null && cat.getName() != null) {
binding.categoryTabs.addTab(binding.categoryTabs.newTab().setText(cat.getName()));
}
} }
} else {
// 后端分类未加载使用硬编码默认值
binding.categoryTabs.addTab(binding.categoryTabs.newTab().setText("推荐"));
binding.categoryTabs.addTab(binding.categoryTabs.newTab().setText("娱乐"));
binding.categoryTabs.addTab(binding.categoryTabs.newTab().setText("游戏"));
binding.categoryTabs.addTab(binding.categoryTabs.newTab().setText("音乐"));
binding.categoryTabs.addTab(binding.categoryTabs.newTab().setText("户外"));
} }
// 恢复上次选中的分类 // 恢复上次选中的分类
restoreCategoryTabSelection(); restoreCategoryTabSelection();
Log.d(TAG, "useDefaultCategories() 使用我的频道,共 " + binding.categoryTabs.getTabCount() + " 个标签"); Log.d(TAG, "useDefaultCategories() 使用默认分类,共 " + binding.categoryTabs.getTabCount() + " 个标签");
}); });
} }

View File

@ -59,20 +59,13 @@ public class TianDiTuLocationService {
this.context = context.getApplicationContext(); this.context = context.getApplicationContext();
this.locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); this.locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
} }
/** /**
* 开始定位 * 开始定位
*/ */
public void startLocation(OnLocationResultListener listener) { public void startLocation(OnLocationResultListener listener) {
this.resultListener = listener; this.resultListener = listener;
// 测试模式直接使用固定坐标已禁用
// if (TEST_MODE) {
// Log.d(TAG, "【测试模式】使用固定坐标 - 纬度: " + TEST_LATITUDE + ", 经度: " + TEST_LONGITUDE);
// reverseGeocode(TEST_LONGITUDE, TEST_LATITUDE);
// return;
// }
// 检查权限 // 检查权限
if (!checkLocationPermission()) { if (!checkLocationPermission()) {
if (resultListener != null) { if (resultListener != null) {
@ -210,7 +203,7 @@ public class TianDiTuLocationService {
return null; return null;
} }
} }
/** /**
* 逆地理编码 - 将经纬度转换为地址 * 逆地理编码 - 将经纬度转换为地址
*/ */
@ -236,7 +229,6 @@ public class TianDiTuLocationService {
Log.d(TAG, "坐标检查通过,在中国境内"); Log.d(TAG, "坐标检查通过,在中国境内");
// 构建请求URL // 构建请求URL
// 天地图逆地理编码API: http://api.tianditu.gov.cn/geocoder?postStr={'lon':116.397128,'lat':39.916527,'ver':1}&type=geocode&tk=您的密钥
JSONObject postData = new JSONObject(); JSONObject postData = new JSONObject();
postData.put("lon", longitude); postData.put("lon", longitude);
postData.put("lat", latitude); postData.put("lat", latitude);

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#000000">
<path
android:fillColor="@android:color/white"
android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z"/>
</vector>

View File

@ -0,0 +1,13 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="120dp"
android:height="120dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#CCCCCC">
<path
android:fillColor="@android:color/white"
android:pathData="M19,5v14H5V5h14m0,-2H5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5c0,-1.1 -0.9,-2 -2,-2z"/>
<path
android:fillColor="@android:color/white"
android:pathData="M12,12m-3,0a3,3 0,1 1,6 0a3,3 0,1 1,-6 0"/>
</vector>

View File

@ -5,12 +5,11 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="#000000"> android:background="#000000">
<!-- 使用 OpenGlView 作为摄像头预览,支持 RootEncoder RTMP 推流和视频编码 --> <!-- 使用 OpenGlView 作为摄像头预览,全屏填充显示 -->
<!-- keepAspectRatio=false 让预览填满整个屏幕 -->
<com.pedro.rtplibrary.view.OpenGlView <com.pedro.rtplibrary.view.OpenGlView
android:id="@+id/openGlView" android:id="@+id/openGlView"
android:layout_width="match_parent" android:layout_width="0dp"
android:layout_height="match_parent" android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"

View File

@ -73,9 +73,12 @@
<FrameLayout <FrameLayout
android:id="@+id/playerContainer" android:id="@+id/playerContainer"
android:layout_width="0dp" android:layout_width="match_parent"
android:layout_height="220dp" android:layout_height="200dp"
android:layout_marginTop="14dp" android:layout_marginTop="14dp"
android:layout_marginStart="32dp"
android:layout_marginEnd="32dp"
android:background="#000000"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/streamerText"> app:layout_constraintTop_toBottomOf="@id/streamerText">
@ -83,7 +86,11 @@
<androidx.media3.ui.PlayerView <androidx.media3.ui.PlayerView
android:id="@+id/playerView" android:id="@+id/playerView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" /> android:layout_height="match_parent"
android:layout_gravity="center"
app:resize_mode="fit"
app:show_buffering="when_playing"
app:use_controller="true" />
</FrameLayout> </FrameLayout>
<TextView <TextView

View File

@ -1,133 +0,0 @@
-- ============================================
-- 粉丝团系统完整检查与完善脚本
-- 执行此脚本以检查和完善粉丝团功能
-- ============================================
-- ==================== 第一部分:检查表结构 ====================
-- 1. 检查粉丝团表是否存在及结构
SELECT '=== 1. 粉丝团表结构 ===' as info;
DESC eb_fan_group;
-- 2. 检查粉丝团成员表结构
SELECT '=== 2. 粉丝团成员表结构 ===' as info;
DESC eb_fan_group_member;
-- 3. 检查群组消息表结构
SELECT '=== 3. 群组消息表结构 ===' as info;
DESC eb_group_message;
-- ==================== 第二部分:检查现有数据 ====================
-- 4. 查看当前粉丝团数据
SELECT '=== 4. 当前粉丝团列表 ===' as info;
SELECT
fg.id,
fg.name,
fg.anchor_id,
fg.anchor_name,
u.nickname as anchor_real_name,
u.avatar as anchor_avatar,
fg.badge,
fg.badge_color,
fg.member_count,
fg.status,
fg.create_time
FROM eb_fan_group fg
LEFT JOIN eb_user u ON fg.anchor_id = u.uid
ORDER BY fg.id;
-- 5. 查看粉丝团成员数据
SELECT '=== 5. 粉丝团成员列表 ===' as info;
SELECT
m.id,
m.group_id as fan_group_id,
fg.name as fan_group_name,
m.uid,
m.nickname as member_nickname,
u.nickname as real_nickname,
u.avatar,
m.level,
m.intimacy,
m.status,
m.join_time
FROM eb_fan_group_member m
LEFT JOIN eb_fan_group fg ON m.group_id = fg.id
LEFT JOIN eb_user u ON m.uid = u.uid
WHERE m.status = 1
ORDER BY m.group_id, m.level DESC, m.intimacy DESC;
-- 6. 查看群组消息
SELECT '=== 6. 粉丝团聊天消息 ===' as info;
SELECT
gm.id,
gm.group_id,
fg.name as fan_group_name,
gm.sender_id,
u.nickname as sender_name,
gm.content,
gm.message_type,
gm.is_deleted,
gm.create_time
FROM eb_group_message gm
LEFT JOIN eb_fan_group fg ON gm.group_id = fg.id
LEFT JOIN eb_user u ON gm.sender_id = u.uid
WHERE gm.is_deleted = 0
ORDER BY gm.group_id, gm.create_time DESC
LIMIT 50;
-- ==================== 第三部分:数据统计 ====================
-- 7. 粉丝团统计
SELECT '=== 7. 粉丝团统计 ===' as info;
SELECT
COUNT(*) as total_fan_groups,
SUM(CASE WHEN status = 1 THEN 1 ELSE 0 END) as active_fan_groups,
SUM(member_count) as total_members
FROM eb_fan_group;
-- 8. 各粉丝团成员数量对比(实际 vs 记录)
SELECT '=== 8. 成员数量校验 ===' as info;
SELECT
fg.id,
fg.name,
fg.member_count as recorded_count,
COUNT(m.id) as actual_count,
CASE
WHEN fg.member_count = COUNT(m.id) THEN '✓ 一致'
ELSE '✗ 不一致'
END as status
FROM eb_fan_group fg
LEFT JOIN eb_fan_group_member m ON fg.id = m.group_id AND m.status = 1
GROUP BY fg.id, fg.name, fg.member_count;
-- ==================== 第四部分:数据修复 ====================
-- 9. 修复粉丝团成员数量(如果不一致)
SELECT '=== 9. 修复成员数量 ===' as info;
UPDATE eb_fan_group fg SET member_count = (
SELECT COUNT(*) FROM eb_fan_group_member m WHERE m.group_id = fg.id AND m.status = 1
);
-- 10. 更新粉丝团主播名称(从用户表同步)
SELECT '=== 10. 同步主播名称 ===' as info;
UPDATE eb_fan_group fg
JOIN eb_user u ON fg.anchor_id = u.uid
SET fg.anchor_name = u.nickname
WHERE fg.anchor_name IS NULL OR fg.anchor_name = '' OR fg.anchor_name != u.nickname;
-- ==================== 第五部分:验证修复结果 ====================
-- 11. 再次检查成员数量
SELECT '=== 11. 修复后成员数量校验 ===' as info;
SELECT
fg.id,
fg.name,
fg.anchor_name,
fg.member_count as recorded_count,
COUNT(m.id) as actual_count
FROM eb_fan_group fg
LEFT JOIN eb_fan_group_member m ON fg.id = m.group_id AND m.status = 1
GROUP BY fg.id, fg.name, fg.anchor_name, fg.member_count;
SELECT '=== 粉丝团检查完成 ===' as info;

View File

@ -1,44 +0,0 @@
-- 检查粉丝团表是否存在
SHOW TABLES LIKE 'eb_fan_group%';
-- 检查粉丝团表结构
DESC eb_fan_group;
-- 检查粉丝团数据
SELECT * FROM eb_fan_group LIMIT 10;
-- 检查粉丝团成员表
DESC eb_fan_group_member;
-- 检查粉丝团成员数据
SELECT * FROM eb_fan_group_member LIMIT 10;
-- 如果没有数据,插入测试数据
INSERT INTO eb_fan_group (id, name, anchor_id, anchor_name, avatar, member_count, level, description, create_time, update_time)
SELECT 1, '测试粉丝团1', 121, '主播小明', 'https://example.com/avatar1.jpg', 100, 3, '这是一个测试粉丝团', NOW(), NOW()
WHERE NOT EXISTS (SELECT 1 FROM eb_fan_group WHERE id = 1);
INSERT INTO eb_fan_group (id, name, anchor_id, anchor_name, avatar, member_count, level, description, create_time, update_time)
SELECT 2, '星光粉丝团', 122, '主播小红', 'https://example.com/avatar2.jpg', 250, 5, '星光闪耀的粉丝团', NOW(), NOW()
WHERE NOT EXISTS (SELECT 1 FROM eb_fan_group WHERE id = 2);
INSERT INTO eb_fan_group (id, name, anchor_id, anchor_name, avatar, member_count, level, description, create_time, update_time)
SELECT 3, '梦想家族', 123, '主播小华', 'https://example.com/avatar3.jpg', 500, 8, '追逐梦想的大家庭', NOW(), NOW()
WHERE NOT EXISTS (SELECT 1 FROM eb_fan_group WHERE id = 3);
-- 插入粉丝团成员测试数据
INSERT INTO eb_fan_group_member (id, group_id, user_id, nickname, avatar, level, intimacy, join_time, create_time)
SELECT 1, 1, 101, '粉丝A', 'https://example.com/fan1.jpg', 2, 1000, NOW(), NOW()
WHERE NOT EXISTS (SELECT 1 FROM eb_fan_group_member WHERE id = 1);
INSERT INTO eb_fan_group_member (id, group_id, user_id, nickname, avatar, level, intimacy, join_time, create_time)
SELECT 2, 1, 102, '粉丝B', 'https://example.com/fan2.jpg', 3, 2500, NOW(), NOW()
WHERE NOT EXISTS (SELECT 1 FROM eb_fan_group_member WHERE id = 2);
INSERT INTO eb_fan_group_member (id, group_id, user_id, nickname, avatar, level, intimacy, join_time, create_time)
SELECT 3, 2, 103, '粉丝C', 'https://example.com/fan3.jpg', 1, 500, NOW(), NOW()
WHERE NOT EXISTS (SELECT 1 FROM eb_fan_group_member WHERE id = 3);
-- 验证插入结果
SELECT * FROM eb_fan_group;
SELECT * FROM eb_fan_group_member;

View File

@ -1,35 +0,0 @@
-- 检查粉丝团菜单是否存在
SELECT '=== 检查粉丝团菜单 ===' as info;
SELECT id, pid, name, path, component, perms, sort, is_show
FROM eb_system_menu
WHERE name LIKE '%粉丝团%' OR path LIKE '%fanGroup%' OR path LIKE '%fan-group%';
-- 如果不存在,添加粉丝团菜单
-- 首先找到"社交管理"或"直播管理"的父菜单ID
SELECT '=== 查找父菜单 ===' as info;
SELECT id, name, path FROM eb_system_menu WHERE name IN ('社交管理', '直播管理', '用户管理') AND pid = 0;
-- 添加粉丝团菜单(如果不存在)
-- 注意需要根据实际的父菜单ID调整pid值
INSERT INTO eb_system_menu (pid, name, icon, path, component, perms, menu_type, sort, is_show, create_time, update_time)
SELECT
(SELECT id FROM eb_system_menu WHERE name = '社交管理' AND pid = 0 LIMIT 1) as pid,
'粉丝团管理' as name,
'el-icon-star-on' as icon,
'/fanGroup/list' as path,
'fanGroup/list/index' as component,
'admin:fan:group:list' as perms,
'C' as menu_type,
10 as sort,
1 as is_show,
NOW() as create_time,
NOW() as update_time
WHERE NOT EXISTS (
SELECT 1 FROM eb_system_menu WHERE path = '/fanGroup/list'
);
-- 验证菜单
SELECT '=== 验证粉丝团菜单 ===' as info;
SELECT id, pid, name, path, component, perms, sort, is_show
FROM eb_system_menu
WHERE name LIKE '%粉丝团%' OR path LIKE '%fanGroup%';

View File

@ -1,43 +0,0 @@
-- =====================================================
-- 举报表检查和测试数据脚本
-- =====================================================
-- 1. 检查表是否存在
SELECT '=== 检查举报表 ===' as step;
SHOW TABLES LIKE 'eb_report';
-- 2. 查看表结构
SELECT '=== 表结构 ===' as step;
DESCRIBE eb_report;
-- 3. 查看现有数据
SELECT '=== 现有数据 ===' as step;
SELECT COUNT(*) as total FROM eb_report;
-- 4. 查看详细数据
SELECT * FROM eb_report ORDER BY id DESC LIMIT 10;
-- 5. 如果没有数据,插入测试数据
INSERT IGNORE INTO `eb_report`
(`uid`, `nickname`, `target_type`, `target_id`, `target_name`, `reason_type`, `reason`, `images`, `status`, `create_time`)
VALUES
(121, '测试用户1', 1, 122, '被举报用户A', 1, '该用户发布色情低俗内容', '[]', 0, NOW()),
(121, '测试用户1', 2, 1, '违规直播间', 2, '直播间存在广告骚扰行为', '[]', 0, NOW()),
(122, '测试用户2', 3, 1, '违规动态', 5, '动态内容存在人身攻击', '[]', 0, DATE_SUB(NOW(), INTERVAL 1 DAY)),
(123, '测试用户3', 1, 124, '被举报用户B', 6, '该用户涉嫌欺诈骗钱', '[]', 2, DATE_SUB(NOW(), INTERVAL 2 DAY));
-- 6. 再次查看数据
SELECT '=== 插入后数据 ===' as step;
SELECT r.*,
CASE r.target_type WHEN 1 THEN '用户' WHEN 2 THEN '房间' WHEN 3 THEN '动态' WHEN 4 THEN '评论' ELSE '其他' END as type_text,
CASE r.status WHEN 0 THEN '待处理' WHEN 1 THEN '处理中' WHEN 2 THEN '已处理' WHEN 3 THEN '已忽略' ELSE '未知' END as status_text
FROM eb_report r
ORDER BY r.id DESC;
-- 7. 统计
SELECT '=== 统计 ===' as step;
SELECT
COUNT(*) as total,
SUM(CASE WHEN status = 0 THEN 1 ELSE 0 END) as pending,
SUM(CASE WHEN status = 2 THEN 1 ELSE 0 END) as processed
FROM eb_report;

View File

@ -1,56 +0,0 @@
-- =====================================================
-- 敏感词表检查和初始化脚本
-- 请在 Navicat 中逐步执行以下SQL
-- =====================================================
-- ========== 第1步检查表是否存在 ==========
SELECT '=== 检查表是否存在 ===' as step;
SHOW TABLES LIKE 'eb_sensitive_word';
-- ========== 第2步如果表不存在创建表 ==========
CREATE TABLE IF NOT EXISTS `eb_sensitive_word` (
`id` int UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`word` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '敏感词',
`category` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'default' COMMENT '分类',
`level` tinyint NOT NULL DEFAULT 1 COMMENT '级别 1=轻度 2=中度 3=重度',
`action` tinyint NOT NULL DEFAULT 1 COMMENT '处理方式 1=替换 2=拦截 3=警告',
`replace_text` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '***' COMMENT '替换文本',
`status` tinyint NOT NULL DEFAULT 1 COMMENT '状态 0=禁用 1=启用',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE KEY `uk_word` (`word`) USING BTREE,
KEY `idx_category` (`category`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '敏感词表' ROW_FORMAT = DYNAMIC;
-- ========== 第3步查看表结构 ==========
SELECT '=== 表结构 ===' as step;
DESCRIBE eb_sensitive_word;
-- ========== 第4步查看现有数据数量 ==========
SELECT '=== 现有数据数量 ===' as step;
SELECT COUNT(*) as total FROM eb_sensitive_word;
-- ========== 第5步插入测试数据如果没有数据 ==========
-- 使用 INSERT IGNORE 避免重复插入
INSERT IGNORE INTO `eb_sensitive_word` (`word`, `category`, `level`, `action`, `replace_text`, `status`, `create_time`) VALUES
('测试敏感词1', 'default', 1, 1, '***', 1, NOW()),
('测试敏感词2', 'default', 2, 1, '***', 1, NOW()),
('广告', 'spam', 1, 1, '**', 1, NOW()),
('推广', 'spam', 1, 1, '**', 1, NOW()),
('加微信', 'spam', 2, 2, '***', 1, NOW()),
('加QQ', 'spam', 2, 2, '***', 1, NOW()),
('色情', 'illegal', 3, 2, '***', 1, NOW()),
('赌博', 'illegal', 3, 2, '***', 1, NOW()),
('诈骗', 'illegal', 3, 2, '***', 1, NOW()),
('违法', 'illegal', 2, 2, '***', 1, NOW());
-- ========== 第6步查看所有数据 ==========
SELECT '=== 敏感词数据列表 ===' as step;
SELECT * FROM eb_sensitive_word ORDER BY id DESC;
-- ========== 第7步最终统计 ==========
SELECT '=== 最终统计 ===' as step;
SELECT COUNT(*) as total_count FROM eb_sensitive_word;
SELECT COUNT(*) as enabled_count FROM eb_sensitive_word WHERE status = 1;
SELECT COUNT(*) as disabled_count FROM eb_sensitive_word WHERE status = 0;

View File

@ -1,77 +0,0 @@
-- ============================================
-- 完善粉丝团系统数据库
-- ============================================
-- 1. 查看粉丝团表结构
DESC eb_fan_group;
-- 2. 查看粉丝团成员表结构
DESC eb_fan_group_member;
-- 3. 查看当前粉丝团数据
SELECT * FROM eb_fan_group;
-- 4. 插入粉丝团成员测试数据
-- 为粉丝团1星光粉丝团主播121添加成员
INSERT INTO eb_fan_group_member (group_id, uid, nickname, level, intimacy, status, join_time)
SELECT 1, 122, '用户小红', 3, 2500, 1, DATE_SUB(NOW(), INTERVAL 10 DAY)
WHERE NOT EXISTS (SELECT 1 FROM eb_fan_group_member WHERE group_id = 1 AND uid = 122);
INSERT INTO eb_fan_group_member (group_id, uid, nickname, level, intimacy, status, join_time)
SELECT 1, 123, '用户小华', 2, 1200, 1, DATE_SUB(NOW(), INTERVAL 7 DAY)
WHERE NOT EXISTS (SELECT 1 FROM eb_fan_group_member WHERE group_id = 1 AND uid = 123);
INSERT INTO eb_fan_group_member (group_id, uid, nickname, level, intimacy, status, join_time)
SELECT 1, 124, '用户阿杰', 1, 500, 1, DATE_SUB(NOW(), INTERVAL 3 DAY)
WHERE NOT EXISTS (SELECT 1 FROM eb_fan_group_member WHERE group_id = 1 AND uid = 124);
-- 为粉丝团2梦想家族主播122添加成员
INSERT INTO eb_fan_group_member (group_id, uid, nickname, level, intimacy, status, join_time)
SELECT 2, 121, '主播小明', 5, 8000, 1, DATE_SUB(NOW(), INTERVAL 20 DAY)
WHERE NOT EXISTS (SELECT 1 FROM eb_fan_group_member WHERE group_id = 2 AND uid = 121);
INSERT INTO eb_fan_group_member (group_id, uid, nickname, level, intimacy, status, join_time)
SELECT 2, 125, '用户小美', 4, 5500, 1, DATE_SUB(NOW(), INTERVAL 15 DAY)
WHERE NOT EXISTS (SELECT 1 FROM eb_fan_group_member WHERE group_id = 2 AND uid = 125);
INSERT INTO eb_fan_group_member (group_id, uid, nickname, level, intimacy, status, join_time)
SELECT 2, 126, '用户大壮', 2, 1800, 1, DATE_SUB(NOW(), INTERVAL 5 DAY)
WHERE NOT EXISTS (SELECT 1 FROM eb_fan_group_member WHERE group_id = 2 AND uid = 126);
-- 为粉丝团3快乐大本营主播123添加成员
INSERT INTO eb_fan_group_member (group_id, uid, nickname, level, intimacy, status, join_time)
SELECT 3, 127, '快乐粉丝A', 3, 3200, 1, DATE_SUB(NOW(), INTERVAL 12 DAY)
WHERE NOT EXISTS (SELECT 1 FROM eb_fan_group_member WHERE group_id = 3 AND uid = 127);
INSERT INTO eb_fan_group_member (group_id, uid, nickname, level, intimacy, status, join_time)
SELECT 3, 128, '快乐粉丝B', 2, 1500, 1, DATE_SUB(NOW(), INTERVAL 8 DAY)
WHERE NOT EXISTS (SELECT 1 FROM eb_fan_group_member WHERE group_id = 3 AND uid = 128);
-- 5. 更新粉丝团成员数量
UPDATE eb_fan_group fg SET member_count = (
SELECT COUNT(*) FROM eb_fan_group_member m WHERE m.group_id = fg.id AND m.status = 1
);
-- 6. 验证数据
SELECT '粉丝团列表' as info;
SELECT id, name, anchor_name, member_count, badge, status FROM eb_fan_group;
SELECT '粉丝团成员' as info;
SELECT m.*, fg.name as group_name
FROM eb_fan_group_member m
LEFT JOIN eb_fan_group fg ON m.group_id = fg.id
ORDER BY m.group_id, m.level DESC;
-- 7. 创建群组消息表(如果不存在)
CREATE TABLE IF NOT EXISTS eb_group_message (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键ID',
group_id BIGINT UNSIGNED NOT NULL COMMENT '群组ID',
sender_id INT UNSIGNED NOT NULL COMMENT '发送者ID',
content TEXT COMMENT '消息内容',
message_type VARCHAR(20) DEFAULT 'text' COMMENT '消息类型',
is_deleted TINYINT DEFAULT 0 COMMENT '是否删除',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (id),
KEY idx_group_id (group_id),
KEY idx_sender_id (sender_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='群组消息表';

View File

@ -1,80 +0,0 @@
-- ============================================
-- 粉丝团系统完整设置脚本
-- 执行此脚本以完善粉丝团功能
-- ============================================
-- 1. 查看当前粉丝团数据
SELECT '=== 当前粉丝团 ===' as info;
SELECT id, name, anchor_id, anchor_name, member_count, badge, status FROM eb_fan_group;
-- 2. 查看粉丝团成员表结构
SELECT '=== 成员表结构 ===' as info;
DESC eb_fan_group_member;
-- 3. 插入粉丝团成员测试数据(如果不存在)
-- 粉丝团1的成员
INSERT IGNORE INTO eb_fan_group_member (group_id, uid, nickname, level, intimacy, status, join_time)
VALUES
(1, 122, '用户小红', 3, 2500, 1, DATE_SUB(NOW(), INTERVAL 10 DAY)),
(1, 123, '用户小华', 2, 1200, 1, DATE_SUB(NOW(), INTERVAL 7 DAY)),
(1, 124, '用户阿杰', 1, 500, 1, DATE_SUB(NOW(), INTERVAL 3 DAY));
-- 粉丝团2的成员
INSERT IGNORE INTO eb_fan_group_member (group_id, uid, nickname, level, intimacy, status, join_time)
VALUES
(2, 121, '主播小明', 5, 8000, 1, DATE_SUB(NOW(), INTERVAL 20 DAY)),
(2, 125, '用户小美', 4, 5500, 1, DATE_SUB(NOW(), INTERVAL 15 DAY)),
(2, 126, '用户大壮', 2, 1800, 1, DATE_SUB(NOW(), INTERVAL 5 DAY));
-- 粉丝团3的成员
INSERT IGNORE INTO eb_fan_group_member (group_id, uid, nickname, level, intimacy, status, join_time)
VALUES
(3, 127, '快乐粉丝A', 3, 3200, 1, DATE_SUB(NOW(), INTERVAL 12 DAY)),
(3, 128, '快乐粉丝B', 2, 1500, 1, DATE_SUB(NOW(), INTERVAL 8 DAY));
-- 4. 更新粉丝团成员数量
UPDATE eb_fan_group fg SET member_count = (
SELECT COUNT(*) FROM eb_fan_group_member m WHERE m.group_id = fg.id AND m.status = 1
);
-- 5. 创建群组消息表(如果不存在)
CREATE TABLE IF NOT EXISTS eb_group_message (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键ID',
group_id BIGINT UNSIGNED NOT NULL COMMENT '群组ID',
sender_id INT UNSIGNED NOT NULL COMMENT '发送者ID',
content TEXT COMMENT '消息内容',
message_type VARCHAR(20) DEFAULT 'text' COMMENT '消息类型',
is_deleted TINYINT DEFAULT 0 COMMENT '是否删除',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (id),
KEY idx_group_id (group_id),
KEY idx_sender_id (sender_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='群组消息表';
-- 6. 插入一些测试聊天消息
INSERT IGNORE INTO eb_group_message (id, group_id, sender_id, content, message_type, create_time)
VALUES
(1, 1, 122, '大家好,我是新来的粉丝!', 'text', DATE_SUB(NOW(), INTERVAL 2 DAY)),
(2, 1, 123, '欢迎欢迎!', 'text', DATE_SUB(NOW(), INTERVAL 2 DAY)),
(3, 1, 121, '感谢大家的支持!', 'text', DATE_SUB(NOW(), INTERVAL 1 DAY)),
(4, 2, 125, '今晚直播太精彩了!', 'text', DATE_SUB(NOW(), INTERVAL 1 DAY)),
(5, 2, 126, '同意!期待下次直播', 'text', DATE_SUB(NOW(), INTERVAL 1 DAY));
-- 7. 验证最终数据
SELECT '=== 粉丝团列表 ===' as info;
SELECT id, name, anchor_name, member_count, badge, badge_color, status, create_time FROM eb_fan_group;
SELECT '=== 粉丝团成员 ===' as info;
SELECT m.id, m.group_id, fg.name as group_name, m.uid, m.nickname, m.level, m.intimacy, m.status, m.join_time
FROM eb_fan_group_member m
LEFT JOIN eb_fan_group fg ON m.group_id = fg.id
ORDER BY m.group_id, m.level DESC;
SELECT '=== 聊天消息 ===' as info;
SELECT gm.id, gm.group_id, fg.name as group_name, gm.sender_id, gm.content, gm.create_time
FROM eb_group_message gm
LEFT JOIN eb_fan_group fg ON gm.group_id = fg.id
WHERE gm.is_deleted = 0
ORDER BY gm.create_time DESC;
SELECT '=== 设置完成 ===' as info;

View File

@ -1,120 +0,0 @@
-- ============================================
-- 粉丝团真实数据设置
-- 确保成员来自真实用户,消息与成员对应
-- ============================================
-- 1. 先查看系统中的真实用户
SELECT '=== 系统真实用户 ===' as info;
SELECT uid, nickname, avatar, phone FROM eb_user WHERE is_del = 0 LIMIT 20;
-- 2. 查看当前粉丝团
SELECT '=== 当前粉丝团 ===' as info;
SELECT id, name, anchor_id, anchor_name, member_count FROM eb_fan_group;
-- 3. 清空测试数据,重新基于真实用户创建
DELETE FROM eb_fan_group_member;
DELETE FROM eb_group_message;
-- 4. 为每个粉丝团添加真实用户作为成员
-- 粉丝团1 (anchor_id=121) 的成员 - 从真实用户中选取(排除主播自己)
INSERT INTO eb_fan_group_member (group_id, uid, nickname, level, intimacy, status, join_time)
SELECT 1, u.uid, u.nickname,
FLOOR(1 + RAND() * 5) as level, -- 随机等级1-5
FLOOR(100 + RAND() * 5000) as intimacy, -- 随机亲密度
1,
DATE_SUB(NOW(), INTERVAL FLOOR(RAND() * 30) DAY)
FROM eb_user u
WHERE u.uid != 121 AND u.is_del = 0 AND u.nickname IS NOT NULL AND u.nickname != ''
ORDER BY RAND()
LIMIT 5;
-- 粉丝团2 (anchor_id=122) 的成员
INSERT INTO eb_fan_group_member (group_id, uid, nickname, level, intimacy, status, join_time)
SELECT 2, u.uid, u.nickname,
FLOOR(1 + RAND() * 5) as level,
FLOOR(100 + RAND() * 5000) as intimacy,
1,
DATE_SUB(NOW(), INTERVAL FLOOR(RAND() * 30) DAY)
FROM eb_user u
WHERE u.uid != 122 AND u.is_del = 0 AND u.nickname IS NOT NULL AND u.nickname != ''
AND u.uid NOT IN (SELECT uid FROM eb_fan_group_member WHERE group_id = 1)
ORDER BY RAND()
LIMIT 5;
-- 粉丝团3 (anchor_id=123) 的成员
INSERT INTO eb_fan_group_member (group_id, uid, nickname, level, intimacy, status, join_time)
SELECT 3, u.uid, u.nickname,
FLOOR(1 + RAND() * 5) as level,
FLOOR(100 + RAND() * 5000) as intimacy,
1,
DATE_SUB(NOW(), INTERVAL FLOOR(RAND() * 30) DAY)
FROM eb_user u
WHERE u.uid != 123 AND u.is_del = 0 AND u.nickname IS NOT NULL AND u.nickname != ''
AND u.uid NOT IN (SELECT uid FROM eb_fan_group_member WHERE group_id IN (1,2))
ORDER BY RAND()
LIMIT 3;
-- 5. 更新粉丝团成员数量
UPDATE eb_fan_group fg SET member_count = (
SELECT COUNT(*) FROM eb_fan_group_member m WHERE m.group_id = fg.id AND m.status = 1
);
-- 6. 为粉丝团添加真实成员的聊天消息
-- 粉丝团1的消息由该粉丝团的真实成员发送
INSERT INTO eb_group_message (group_id, sender_id, content, message_type, create_time)
SELECT 1, m.uid,
CASE FLOOR(RAND() * 5)
WHEN 0 THEN '大家好,很高兴加入粉丝团!'
WHEN 1 THEN '主播今天直播太精彩了!'
WHEN 2 THEN '支持主播,冲冲冲!'
WHEN 3 THEN '期待下次直播~'
ELSE '粉丝团的氛围真好!'
END,
'text',
DATE_SUB(NOW(), INTERVAL FLOOR(RAND() * 7) DAY)
FROM eb_fan_group_member m
WHERE m.group_id = 1 AND m.status = 1
LIMIT 3;
-- 粉丝团2的消息
INSERT INTO eb_group_message (group_id, sender_id, content, message_type, create_time)
SELECT 2, m.uid,
CASE FLOOR(RAND() * 5)
WHEN 0 THEN '新人报到!'
WHEN 1 THEN '主播唱歌太好听了!'
WHEN 2 THEN '今天的游戏直播太刺激了'
WHEN 3 THEN '大家晚上好~'
ELSE '感谢主播的精彩表演!'
END,
'text',
DATE_SUB(NOW(), INTERVAL FLOOR(RAND() * 7) DAY)
FROM eb_fan_group_member m
WHERE m.group_id = 2 AND m.status = 1
LIMIT 3;
-- 7. 验证数据完整性
SELECT '=== 粉丝团成员(关联真实用户)===' as info;
SELECT m.id, m.group_id, fg.name as fan_group_name,
m.uid, m.nickname, u.nickname as real_nickname, u.avatar,
m.level, m.intimacy, m.join_time
FROM eb_fan_group_member m
LEFT JOIN eb_fan_group fg ON m.group_id = fg.id
LEFT JOIN eb_user u ON m.uid = u.uid
WHERE m.status = 1
ORDER BY m.group_id, m.level DESC;
SELECT '=== 聊天消息(关联真实发送者)===' as info;
SELECT gm.id, gm.group_id, fg.name as fan_group_name,
gm.sender_id, u.nickname as sender_name, u.avatar as sender_avatar,
gm.content, gm.create_time
FROM eb_group_message gm
LEFT JOIN eb_fan_group fg ON gm.group_id = fg.id
LEFT JOIN eb_user u ON gm.sender_id = u.uid
WHERE gm.is_deleted = 0
ORDER BY gm.group_id, gm.create_time DESC;
SELECT '=== 粉丝团统计 ===' as info;
SELECT fg.id, fg.name, fg.anchor_name, fg.member_count,
(SELECT COUNT(*) FROM eb_fan_group_member m WHERE m.group_id = fg.id AND m.status = 1) as actual_members,
(SELECT COUNT(*) FROM eb_group_message gm WHERE gm.group_id = fg.id AND gm.is_deleted = 0) as message_count
FROM eb_fan_group fg;

View File

@ -1,60 +0,0 @@
-- ============================================
-- 粉丝团系统完整性检查脚本
-- ============================================
-- 1. 检查表结构
SELECT '=== 1. 检查表结构 ===' as info;
-- 检查eb_fan_group表
SELECT 'eb_fan_group表字段:' as info;
SHOW COLUMNS FROM eb_fan_group;
-- 检查eb_fan_group_member表
SELECT 'eb_fan_group_member表字段:' as info;
SHOW COLUMNS FROM eb_fan_group_member;
-- 检查eb_group_message表
SELECT 'eb_group_message表字段:' as info;
SHOW COLUMNS FROM eb_group_message;
-- 2. 检查数据完整性
SELECT '=== 2. 数据统计 ===' as info;
SELECT
(SELECT COUNT(*) FROM eb_fan_group) as total_fan_groups,
(SELECT COUNT(*) FROM eb_fan_group WHERE status = 1) as active_fan_groups,
(SELECT COUNT(*) FROM eb_fan_group_member WHERE status = 1) as total_members,
(SELECT COUNT(*) FROM eb_group_message WHERE is_deleted = 0) as total_messages;
-- 3. 检查粉丝团列表
SELECT '=== 3. 粉丝团列表 ===' as info;
SELECT
fg.id,
fg.name,
fg.anchor_id,
fg.anchor_name,
fg.badge,
fg.member_count,
(SELECT COUNT(*) FROM eb_fan_group_member m WHERE m.group_id = fg.id AND m.status = 1) as actual_members,
(SELECT COUNT(*) FROM eb_group_message gm WHERE gm.group_id = fg.id AND gm.is_deleted = 0) as message_count,
fg.status,
fg.create_time
FROM eb_fan_group fg
ORDER BY fg.id;
-- 4. 修复成员数量不一致
SELECT '=== 4. 修复成员数量 ===' as info;
UPDATE eb_fan_group fg SET member_count = (
SELECT COUNT(*) FROM eb_fan_group_member m WHERE m.group_id = fg.id AND m.status = 1
);
-- 5. 检查管理端菜单
SELECT '=== 5. 检查管理端菜单 ===' as info;
SELECT id, pid, name, path, component, is_show
FROM eb_system_menu
WHERE name LIKE '%粉丝团%' OR path LIKE '%fanGroup%' OR path LIKE '%fan%group%';
-- 6. 如果菜单不存在,查找合适的父菜单
SELECT '=== 6. 可用的父菜单 ===' as info;
SELECT id, name, path FROM eb_system_menu WHERE pid = 0 AND is_show = 1 ORDER BY sort;
SELECT '=== 检查完成 ===' as info;

View File

@ -1,45 +0,0 @@
-- 修复客服联系方式分组表
-- 检查表是否存在,如果不存在则创建
-- 先检查表是否存在
SELECT COUNT(*) as table_exists FROM information_schema.tables
WHERE table_schema = DATABASE() AND table_name = 'eb_customer_service_group';
-- 如果表存在但字段名不对,需要修改
-- 检查是否有 name 字段
SET @has_name := (SELECT COUNT(*) FROM information_schema.columns
WHERE table_schema = DATABASE()
AND table_name = 'eb_customer_service_group'
AND column_name = 'name');
-- 检查是否有 group_name 字段
SET @has_group_name := (SELECT COUNT(*) FROM information_schema.columns
WHERE table_schema = DATABASE()
AND table_name = 'eb_customer_service_group'
AND column_name = 'group_name');
-- 如果有 name 但没有 group_name重命名字段
-- ALTER TABLE eb_customer_service_group CHANGE COLUMN `name` `group_name` varchar(64) NOT NULL DEFAULT '' COMMENT '用户组名称';
-- 或者直接重建表(更安全)
DROP TABLE IF EXISTS `eb_customer_service_group`;
CREATE TABLE `eb_customer_service_group` (
`id` int UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`group_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '用户组名称',
`avatar` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '用户头像',
`contact` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '联系电话或微信',
`contact_type` tinyint NOT NULL DEFAULT 1 COMMENT '联系类型 1=电话 2=微信',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '客服联系方式分组表' ROW_FORMAT = DYNAMIC;
-- 插入测试数据
INSERT INTO `eb_customer_service_group` (`group_name`, `avatar`, `contact`, `contact_type`, `create_time`) VALUES
('官方客服', 'https://img.zcool.cn/community/01a9a65d143edaa8012187f447cfef.jpg', '400-888-8888', 1, NOW()),
('技术支持', 'https://img.zcool.cn/community/01b72057a7e0790000018c1bf4fce0.png', 'tech_support_wx', 2, NOW()),
('商务合作', '', '13800138000', 1, NOW()),
('投诉建议', '', 'complaint_wx', 2, NOW());
-- 查看数据
SELECT * FROM eb_customer_service_group;

View File

@ -1,11 +0,0 @@
-- 插入粉丝团测试数据
INSERT INTO eb_fan_group (anchor_id, anchor_name, name, badge, badge_color, member_count, status, create_time, update_time)
VALUES
(121, '主播小明', '星光粉丝团', '星光', '#FF6B6B', 156, 1, NOW(), NOW()),
(122, '主播小红', '梦想家族', '梦想', '#4ECDC4', 328, 1, NOW(), NOW()),
(123, '主播小华', '快乐大本营', '快乐', '#45B7D1', 89, 1, NOW(), NOW()),
(124, '主播阿杰', '王者军团', '王者', '#96CEB4', 512, 1, NOW(), NOW()),
(125, '主播小美', '甜蜜蜜', '甜蜜', '#FFEAA7', 245, 1, NOW(), NOW());
-- 验证插入结果
SELECT * FROM eb_fan_group;

View File

@ -1,13 +0,0 @@
-- 移除"粉丝团管理"一级导航菜单
-- 先查看当前菜单
SELECT id, name, pid, sort, is_show FROM eb_system_menu WHERE name = '粉丝团管理';
-- 方法1隐藏菜单推荐可恢复
UPDATE eb_system_menu SET is_show = 0 WHERE name = '粉丝团管理' AND pid = 0;
-- 方法2如果要彻底删除先删除子菜单再删除父菜单
-- DELETE FROM eb_system_menu WHERE pid = (SELECT id FROM (SELECT id FROM eb_system_menu WHERE name = '粉丝团管理' AND pid = 0) AS t);
-- DELETE FROM eb_system_menu WHERE name = '粉丝团管理' AND pid = 0;
-- 验证结果
SELECT id, name, pid, is_show FROM eb_system_menu WHERE name = '粉丝团管理';

View File

@ -1,5 +0,0 @@
-- 删除遗留的子菜单
DELETE FROM eb_system_menu WHERE id = 664;
-- 验证删除结果 - 只应该剩下直播管理下的粉丝团管理(id=707)
SELECT * FROM eb_system_menu WHERE name LIKE '%粉丝团%';

View File

@ -1,200 +0,0 @@
-- ============================================
-- 粉丝团测试数据设置脚本
-- 基于真实用户创建粉丝团测试数据
-- ============================================
-- ==================== 第一部分:创建表(如果不存在)====================
-- 1. 创建粉丝团表
CREATE TABLE IF NOT EXISTS eb_fan_group (
id INT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '粉丝团ID',
anchor_id INT UNSIGNED NOT NULL COMMENT '主播ID',
anchor_name VARCHAR(100) DEFAULT NULL COMMENT '主播名称',
group_id BIGINT UNSIGNED DEFAULT NULL COMMENT '关联群组ID',
name VARCHAR(100) NOT NULL COMMENT '粉丝团名称',
badge VARCHAR(50) DEFAULT '粉丝' COMMENT '粉丝徽章',
badge_color VARCHAR(20) DEFAULT '#FF6B9D' COMMENT '徽章颜色',
member_count INT DEFAULT 0 COMMENT '成员数量',
status TINYINT DEFAULT 1 COMMENT '状态 1-正常 0-禁用',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (id),
KEY idx_anchor_id (anchor_id),
KEY idx_status (status)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='粉丝团表';
-- 2. 创建粉丝团成员表
CREATE TABLE IF NOT EXISTS eb_fan_group_member (
id INT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '成员ID',
group_id INT UNSIGNED NOT NULL COMMENT '粉丝团ID',
uid INT UNSIGNED NOT NULL COMMENT '用户ID',
nickname VARCHAR(100) DEFAULT NULL COMMENT '用户昵称',
level INT DEFAULT 1 COMMENT '粉丝等级 1-10',
intimacy INT DEFAULT 0 COMMENT '亲密度',
status TINYINT DEFAULT 1 COMMENT '状态 1-正常 0-退出',
join_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '加入时间',
PRIMARY KEY (id),
UNIQUE KEY uk_group_uid (group_id, uid),
KEY idx_uid (uid),
KEY idx_level (level)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='粉丝团成员表';
-- 3. 创建群组消息表
CREATE TABLE IF NOT EXISTS eb_group_message (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '消息ID',
group_id INT UNSIGNED NOT NULL COMMENT '粉丝团ID',
sender_id INT UNSIGNED NOT NULL COMMENT '发送者ID',
content TEXT COMMENT '消息内容',
message_type VARCHAR(20) DEFAULT 'text' COMMENT '消息类型 text/image/gift',
is_deleted TINYINT DEFAULT 0 COMMENT '是否删除',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (id),
KEY idx_group_id (group_id),
KEY idx_sender_id (sender_id),
KEY idx_create_time (create_time)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='群组消息表';
-- ==================== 第二部分:查看可用用户 ====================
SELECT '=== 可用用户列表前20个===' as info;
SELECT uid, nickname, avatar, phone FROM eb_user WHERE status = 1 LIMIT 20;
-- ==================== 第三部分:创建粉丝团(如果不存在)====================
-- 为用户100创建粉丝团如果不存在
INSERT INTO eb_fan_group (anchor_id, anchor_name, name, badge, badge_color, member_count, status, create_time)
SELECT 100, u.nickname, CONCAT(u.nickname, '的粉丝团'), '星光', '#FF6B9D', 0, 1, NOW()
FROM eb_user u
WHERE u.uid = 100 AND u.status = 1
AND NOT EXISTS (SELECT 1 FROM eb_fan_group WHERE anchor_id = 100);
-- 为用户101创建粉丝团如果不存在
INSERT INTO eb_fan_group (anchor_id, anchor_name, name, badge, badge_color, member_count, status, create_time)
SELECT 101, u.nickname, CONCAT(u.nickname, '的粉丝团'), '梦想', '#6B9DFF', 0, 1, NOW()
FROM eb_user u
WHERE u.uid = 101 AND u.status = 1
AND NOT EXISTS (SELECT 1 FROM eb_fan_group WHERE anchor_id = 101);
-- 为用户102创建粉丝团如果不存在
INSERT INTO eb_fan_group (anchor_id, anchor_name, name, badge, badge_color, member_count, status, create_time)
SELECT 102, u.nickname, CONCAT(u.nickname, '的粉丝团'), '快乐', '#9DFF6B', 0, 1, NOW()
FROM eb_user u
WHERE u.uid = 102 AND u.status = 1
AND NOT EXISTS (SELECT 1 FROM eb_fan_group WHERE anchor_id = 102);
-- ==================== 第四部分:添加粉丝团成员 ====================
-- 获取粉丝团ID
SET @fg1 = (SELECT id FROM eb_fan_group WHERE anchor_id = 100 LIMIT 1);
SET @fg2 = (SELECT id FROM eb_fan_group WHERE anchor_id = 101 LIMIT 1);
SET @fg3 = (SELECT id FROM eb_fan_group WHERE anchor_id = 102 LIMIT 1);
-- 为粉丝团1添加成员从真实用户中选取
INSERT IGNORE INTO eb_fan_group_member (group_id, uid, nickname, level, intimacy, status, join_time)
SELECT @fg1, u.uid, u.nickname,
FLOOR(1 + RAND() * 5) as level,
FLOOR(100 + RAND() * 5000) as intimacy,
1, DATE_SUB(NOW(), INTERVAL FLOOR(RAND() * 30) DAY)
FROM eb_user u
WHERE u.uid NOT IN (100, 101, 102)
AND u.status = 1
AND u.nickname IS NOT NULL
AND u.nickname != ''
AND @fg1 IS NOT NULL
ORDER BY RAND()
LIMIT 5;
-- 为粉丝团2添加成员
INSERT IGNORE INTO eb_fan_group_member (group_id, uid, nickname, level, intimacy, status, join_time)
SELECT @fg2, u.uid, u.nickname,
FLOOR(1 + RAND() * 5) as level,
FLOOR(100 + RAND() * 5000) as intimacy,
1, DATE_SUB(NOW(), INTERVAL FLOOR(RAND() * 30) DAY)
FROM eb_user u
WHERE u.uid NOT IN (100, 101, 102)
AND u.status = 1
AND u.nickname IS NOT NULL
AND u.nickname != ''
AND u.uid NOT IN (SELECT uid FROM eb_fan_group_member WHERE group_id = @fg1)
AND @fg2 IS NOT NULL
ORDER BY RAND()
LIMIT 4;
-- 为粉丝团3添加成员
INSERT IGNORE INTO eb_fan_group_member (group_id, uid, nickname, level, intimacy, status, join_time)
SELECT @fg3, u.uid, u.nickname,
FLOOR(1 + RAND() * 5) as level,
FLOOR(100 + RAND() * 5000) as intimacy,
1, DATE_SUB(NOW(), INTERVAL FLOOR(RAND() * 30) DAY)
FROM eb_user u
WHERE u.uid NOT IN (100, 101, 102)
AND u.status = 1
AND u.nickname IS NOT NULL
AND u.nickname != ''
AND u.uid NOT IN (SELECT uid FROM eb_fan_group_member WHERE group_id IN (@fg1, @fg2))
AND @fg3 IS NOT NULL
ORDER BY RAND()
LIMIT 3;
-- ==================== 第五部分:添加聊天消息 ====================
-- 为粉丝团1添加消息
INSERT INTO eb_group_message (group_id, sender_id, content, message_type, create_time)
SELECT @fg1, m.uid,
CASE FLOOR(RAND() * 5)
WHEN 0 THEN '大家好,我是新来的粉丝!'
WHEN 1 THEN '今天的直播太精彩了!'
WHEN 2 THEN '支持主播!'
WHEN 3 THEN '期待下次直播~'
ELSE '主播加油!'
END,
'text',
DATE_SUB(NOW(), INTERVAL FLOOR(RAND() * 7) DAY)
FROM eb_fan_group_member m
WHERE m.group_id = @fg1 AND m.status = 1 AND @fg1 IS NOT NULL
LIMIT 5;
-- 为粉丝团2添加消息
INSERT INTO eb_group_message (group_id, sender_id, content, message_type, create_time)
SELECT @fg2, m.uid,
CASE FLOOR(RAND() * 5)
WHEN 0 THEN '欢迎新成员!'
WHEN 1 THEN '直播间见!'
WHEN 2 THEN '主播唱歌真好听'
WHEN 3 THEN '什么时候开播?'
ELSE '粉丝团万岁!'
END,
'text',
DATE_SUB(NOW(), INTERVAL FLOOR(RAND() * 7) DAY)
FROM eb_fan_group_member m
WHERE m.group_id = @fg2 AND m.status = 1 AND @fg2 IS NOT NULL
LIMIT 4;
-- ==================== 第六部分:更新成员数量 ====================
UPDATE eb_fan_group fg SET member_count = (
SELECT COUNT(*) FROM eb_fan_group_member m WHERE m.group_id = fg.id AND m.status = 1
);
-- ==================== 第七部分:验证数据 ====================
SELECT '=== 粉丝团列表 ===' as info;
SELECT id, name, anchor_id, anchor_name, badge, badge_color, member_count, status, create_time
FROM eb_fan_group ORDER BY id;
SELECT '=== 粉丝团成员 ===' as info;
SELECT m.id, m.group_id, fg.name as fan_group_name, m.uid, m.nickname, m.level, m.intimacy, m.join_time
FROM eb_fan_group_member m
LEFT JOIN eb_fan_group fg ON m.group_id = fg.id
WHERE m.status = 1
ORDER BY m.group_id, m.level DESC;
SELECT '=== 聊天消息 ===' as info;
SELECT gm.id, gm.group_id, fg.name as fan_group_name, gm.sender_id, u.nickname as sender_name, gm.content, gm.create_time
FROM eb_group_message gm
LEFT JOIN eb_fan_group fg ON gm.group_id = fg.id
LEFT JOIN eb_user u ON gm.sender_id = u.uid
WHERE gm.is_deleted = 0
ORDER BY gm.group_id, gm.create_time DESC
LIMIT 20;
SELECT '=== 数据设置完成 ===' as info;

View File

@ -1,19 +0,0 @@
-- 更新签到记录测试数据
-- 确保 eb_user_signin_record 表数据正确
-- 更新现有记录的 continuous_days 字段随机1-7天
UPDATE eb_user_signin_record
SET continuous_days = FLOOR(1 + RAND() * 7)
WHERE continuous_days IS NULL OR continuous_days = 0;
-- 确保 reward_value 有值(根据连续天数计算)
UPDATE eb_user_signin_record
SET reward_value = continuous_days * 10
WHERE reward_value IS NULL OR reward_value = 0;
-- 查看更新后的数据
SELECT r.*, u.avatar as user_avatar, u.nickname as db_nickname
FROM eb_user_signin_record r
LEFT JOIN eb_user u ON r.uid = u.uid
ORDER BY r.id DESC
LIMIT 20;

View File

@ -1,188 +0,0 @@
# 封禁系统功能说明
## 功能概述
封禁系统提供用户封禁、房间封禁和黑名单管理功能,支持管理后台和移动端双端实时同步。
## 功能模块
### 1. 用户封禁(管理员功能)
管理员可以对违规用户进行封禁处理:
- **永久封禁**:用户账号永久禁用,无法登录
- **临时封禁**:设置封禁天数,到期自动解除
- **解除封禁**:手动解除用户封禁状态
- **封禁原因**:记录封禁原因,便于追溯
**封禁影响**
- 被封禁用户无法登录
- 被封禁用户无法发送弹幕
- 被封禁用户无法赠送礼物
- 被封禁用户无法发送私信
**API接口**
- `GET /api/admin/ban/user/list` - 获取用户封禁列表
- `POST /api/admin/ban/user/add` - 封禁用户
- `POST /api/admin/ban/user/unban/{id}` - 解除封禁
- `POST /api/admin/ban/user/delete/{id}` - 删除记录
- `GET /api/admin/ban/user/check/{userId}` - 检查封禁状态
### 2. 房间封禁(管理员功能)
管理员可以对违规直播间进行封禁处理:
- **永久封禁**:直播间永久关闭
- **临时封禁**:设置封禁天数,到期自动解除
- **解除封禁**:手动解除房间封禁状态
- **封禁原因**:记录封禁原因
**封禁影响**
- 被封禁房间无法进入
- 进入时显示封禁提示
**API接口**
- `GET /api/admin/ban/room/list` - 获取房间封禁列表
- `POST /api/admin/ban/room/add` - 封禁房间
- `POST /api/admin/ban/room/unban/{id}` - 解除封禁
- `POST /api/admin/ban/room/delete/{id}` - 删除记录
- `GET /api/admin/ban/room/check/{roomId}` - 检查封禁状态
### 3. 用户黑名单(用户功能)
用户可以将其他用户加入黑名单:
- **添加黑名单**:屏蔽指定用户
- **移除黑名单**:解除屏蔽
- **黑名单列表**:查看已屏蔽的用户
- **互动限制**:被拉黑用户无法发送消息、评论等
**黑名单影响**
- 双方无法发送私信
- 双方无法创建会话
- 拉黑时自动删除好友关系
**移动端API接口**
- `GET /api/front/ban/check/me` - 检查当前用户封禁状态
- `GET /api/front/ban/check/user/{userId}` - 检查指定用户封禁状态
- `GET /api/front/ban/check/room/{roomId}` - 检查房间封禁状态
- `GET /api/front/ban/blacklist/list` - 获取我的黑名单
- `POST /api/front/ban/blacklist/add` - 添加到黑名单
- `POST /api/front/ban/blacklist/remove` - 从黑名单移除
- `GET /api/front/ban/blacklist/check/{targetUserId}` - 检查黑名单状态
## 数据库表结构
### eb_user_ban用户封禁表
| 字段 | 类型 | 说明 |
|------|------|------|
| id | bigint | 主键 |
| user_id | int | 被封禁用户ID |
| ban_type | varchar(20) | 封禁类型permanent/temporary |
| reason | varchar(500) | 封禁原因 |
| duration_days | int | 封禁天数 |
| expire_time | datetime | 到期时间 |
| operator_id | int | 操作人ID |
| status | tinyint | 状态1-生效0-已解除 |
### eb_room_ban房间封禁表
| 字段 | 类型 | 说明 |
|------|------|------|
| id | bigint | 主键 |
| room_id | int | 被封禁房间ID |
| ban_type | varchar(20) | 封禁类型 |
| reason | varchar(500) | 封禁原因 |
| duration_days | int | 封禁天数 |
| expire_time | datetime | 到期时间 |
| operator_id | int | 操作人ID |
| status | tinyint | 状态 |
### eb_user_blacklist用户黑名单表
| 字段 | 类型 | 说明 |
|------|------|------|
| id | bigint | 主键 |
| user_id | int | 用户ID发起拉黑 |
| blocked_user_id | int | 被拉黑用户ID |
| blocker_nickname | varchar(100) | 拉黑者昵称 |
| blocked_nickname | varchar(100) | 被拉黑者昵称 |
| create_time | datetime | 创建时间 |
### eb_room_blacklist房间黑名单表
| 字段 | 类型 | 说明 |
|------|------|------|
| id | bigint | 主键 |
| room_id | int | 房间ID |
| room_name | varchar(200) | 房间名称 |
| blocked_user_id | int | 被拉黑用户ID |
| blocked_user_nickname | varchar(100) | 被拉黑用户昵称 |
| reason | varchar(500) | 拉黑原因 |
| create_time | datetime | 创建时间 |
## 封禁检查点
### 后端检查点
1. **登录时** - LoginServiceImpl.login() / phoneLogin()
2. **发送弹幕时** - LiveRoomController.sendMessage()
3. **赠送礼物时** - LiveRoomController.sendGift()
4. **发送私信时** - ConversationServiceImpl.sendMessage()
5. **创建会话时** - ConversationServiceImpl.getOrCreateConversation()
6. **开播时** - LiveRoomController.create()
### 移动端检查点
1. **进入直播间时** - RoomDetailActivity.checkRoomBanStatus()
2. **用户主页拉黑** - UserProfileActivity.addToBlacklist()
3. **设置页黑名单管理** - BlacklistActivity
## 双端同步机制
1. **管理后台封禁用户** → 用户状态更新 → 移动端登录时检测到封禁状态 → 显示封禁提示,阻止登录
2. **管理后台封禁房间** → 房间状态更新 → 移动端进入房间时检测到封禁状态 → 显示封禁提示,退出房间
3. **移动端添加黑名单** → 数据库更新 → 管理后台可查看黑名单记录
4. **管理后台解除封禁** → 用户/房间状态恢复 → 移动端可正常使用
## 文件清单
### 后端文件
- `Zhibo/zhibo-h/crmeb-admin/src/main/java/com/zbkj/admin/controller/BanController.java` - 管理后台封禁控制器
- `Zhibo/zhibo-h/crmeb-front/src/main/java/com/zbkj/front/controller/BanFrontController.java` - 移动端封禁控制器
- `Zhibo/zhibo-h/crmeb-admin/src/main/java/com/zbkj/admin/controller/BlacklistController.java` - 管理后台黑名单控制器
- `Zhibo/zhibo-h/crmeb-front/src/main/java/com/zbkj/front/service/impl/LoginServiceImpl.java` - 登录服务(含封禁检查)
- `Zhibo/zhibo-h/crmeb-service/src/main/java/com/zbkj/service/service/impl/ConversationServiceImpl.java` - 会话服务(含黑名单检查)
- `Zhibo/zhibo-h/crmeb-front/src/main/java/com/zbkj/front/controller/LiveRoomController.java` - 直播间控制器(含封禁检查)
### 管理后台前端文件
- `Zhibo/admin/src/views/ban/userBan.vue` - 用户封禁管理页面
- `Zhibo/admin/src/views/ban/roomBan.vue` - 房间封禁管理页面
- `Zhibo/admin/src/views/blacklist/user.vue` - 用户黑名单页面
- `Zhibo/admin/src/views/blacklist/room.vue` - 房间黑名单页面
- `Zhibo/admin/src/api/ban.js` - 封禁API
- `Zhibo/admin/src/api/blacklist.js` - 黑名单API
### Android文件
- `android-app/app/src/main/java/com/example/livestreaming/BlacklistActivity.java` - 黑名单管理页面
- `android-app/app/src/main/java/com/example/livestreaming/UserProfileActivity.java` - 用户主页(含拉黑功能)
- `android-app/app/src/main/java/com/example/livestreaming/RoomDetailActivity.java` - 直播间详情(含房间封禁检查)
- `android-app/app/src/main/java/com/example/livestreaming/net/ApiService.java` - API接口定义
### SQL脚本
- `ban_system_tables.sql` - 创建数据库表
- `add_ban_menus.sql` - 添加菜单配置
## 部署步骤
1. **执行数据库脚本**
```bash
mysql -u root -p zhibo < ban_system_tables.sql
mysql -u root -p zhibo < add_ban_menus.sql
```
2. **部署后端**
```bash
deploy_ban_system.bat
```
3. **部署管理后台前端**
- 重新编译部署前端
4. **编译Android App**
- 重新编译APK

View File

@ -1,592 +0,0 @@
# 直播平台功能交互逻辑报告
## 概述
本报告详细描述直播平台三大核心模块的功能交互逻辑:
1. **敏感词管理** - 内容安全过滤系统
2. **消息/粉丝团/群组** - 社交通讯系统
3. **封禁系统** - 用户与房间管理
---
## 一、敏感词管理模块
### 1.1 功能概述
敏感词管理用于过滤平台内的违规内容,保障平台内容安全。
### 1.2 数据表结构
**表名**: `eb_sensitive_word`
| 字段 | 类型 | 说明 |
|------|------|------|
| id | int | 主键ID |
| word | varchar(128) | 敏感词内容 |
| category | varchar(32) | 分类(default/spam/illegal) |
| level | tinyint | 级别(1轻度/2中度/3重度) |
| action | tinyint | 处理方式(1替换/2拦截/3警告) |
| replace_text | varchar(32) | 替换文本(默认***) |
| status | tinyint | 状态(0禁用/1启用) |
| create_time | datetime | 创建时间 |
| update_time | datetime | 更新时间 |
### 1.3 管理端功能
**API路径**: `/api/admin/sensitive/word`
| 接口 | 方法 | 功能 |
|------|------|------|
| /list | GET | 敏感词列表(支持分页、关键词搜索、时间筛选) |
| /add | POST | 添加敏感词 |
| /update | POST | 更新敏感词 |
| /delete/{id} | POST | 删除敏感词 |
| /status/{id} | POST | 切换启用/禁用状态 |
### 1.4 交互流程图
```
┌─────────────────────────────────────────────────────────────────┐
│ 敏感词管理流程 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 管理员 │───▶│ 添加敏感词│───▶│ 存入数据库│ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 用户发送 │───▶│ 内容检测 │───▶│ 匹配敏感词│───▶│ 执行处理 │ │
│ │ 消息/弹幕│ │ │ │ │ │ (替换/拦截)│ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
```
### 1.5 应用场景
敏感词过滤应用于以下场景:
- 直播间弹幕消息
- 私聊消息内容
- 粉丝团群聊消息
- 动态发布内容
- 用户昵称/签名
---
## 二、消息/粉丝团/群组模块
### 2.1 私聊消息系统
#### 2.1.1 数据表结构
**会话表**: `eb_conversation`
| 字段 | 类型 | 说明 |
|------|------|------|
| id | bigint | 会话ID |
| user1_id | int | 用户1 ID |
| user2_id | int | 用户2 ID |
| last_message | varchar(255) | 最后一条消息预览 |
| last_message_time | datetime | 最后消息时间 |
| user1_unread_count | int | 用户1未读数 |
| user2_unread_count | int | 用户2未读数 |
| user1_deleted | tinyint | 用户1是否删除 |
| user2_deleted | tinyint | 用户2是否删除 |
**私聊消息表**: `eb_private_message`
| 字段 | 类型 | 说明 |
|------|------|------|
| id | bigint | 消息ID |
| conversation_id | bigint | 会话ID |
| sender_id | int | 发送者ID |
| receiver_id | int | 接收者ID |
| content | text | 消息内容 |
| message_type | varchar(20) | 消息类型(text/image/voice) |
| media_url | varchar(500) | 媒体URL |
| status | varchar(20) | 状态(sent/read) |
| is_recalled | tinyint | 是否撤回 |
#### 2.1.2 移动端API
**路径**: `/api/front/chat`
| 接口 | 方法 | 功能 |
|------|------|------|
| /conversations | GET | 获取会话列表 |
| /conversations/{id} | GET | 获取会话详情 |
| /conversations/{id}/messages | GET | 获取消息列表 |
| /conversations/{id}/messages | POST | 发送消息 |
| /conversations/{id}/read | POST | 标记已读 |
| /messages/{id}/recall | POST | 撤回消息(2分钟内) |
#### 2.1.3 管理端API
**路径**: `/api/admin/chat`
| 接口 | 方法 | 功能 |
|------|------|------|
| /conversations | GET | 会话列表(支持搜索) |
| /conversations/{id}/messages | GET | 查看会话消息 |
| /conversations/{id} | DELETE | 删除会话 |
| /messages/{id} | DELETE | 删除单条消息 |
| /statistics | GET | 私聊统计数据 |
#### 2.1.4 私聊交互流程
```
┌─────────────────────────────────────────────────────────────────────────┐
│ 私聊消息发送流程 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
│ │ 用户A │──▶│ 检查黑名单 │──▶│ 敏感词过滤 │──▶│ 保存消息 │ │
│ │ 发消息 │ │ │ │ │ │ │ │
│ └────────┘ └────────────┘ └────────────┘ └────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌────────────┐ ┌────────────┐ │
│ │ 黑名单拦截 │ │ 更新会话 │ │
│ │ 返回错误 │ │ 推送通知 │ │
│ └────────────┘ └────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────┐ │
│ │ 用户B收到 │ │
│ │ 消息通知 │ │
│ └────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
```
### 2.2 粉丝团系统
#### 2.2.1 数据表结构
**粉丝团表**: `eb_fan_group`
| 字段 | 类型 | 说明 |
|------|------|------|
| id | int | 粉丝团ID |
| anchor_id | int | 主播ID |
| anchor_name | varchar(64) | 主播昵称 |
| name | varchar(64) | 粉丝团名称 |
| badge | varchar(32) | 粉丝团徽章 |
| badge_color | varchar(16) | 徽章颜色 |
| member_count | int | 成员数量 |
| level | int | 粉丝团等级 |
| status | tinyint | 状态(0解散/1正常) |
**粉丝团成员表**: `eb_fan_group_member`
| 字段 | 类型 | 说明 |
|------|------|------|
| id | int | 成员记录ID |
| group_id | int | 粉丝团ID |
| uid | int | 用户ID |
| nickname | varchar(64) | 成员昵称 |
| level | int | 成员等级(1-10) |
| intimacy | int | 亲密度 |
| status | tinyint | 状态 |
| join_time | datetime | 加入时间 |
**群聊消息表**: `eb_group_message`
| 字段 | 类型 | 说明 |
|------|------|------|
| id | bigint | 消息ID |
| group_id | int | 粉丝团ID |
| sender_id | int | 发送者ID |
| content | text | 消息内容 |
| message_type | varchar(20) | 消息类型 |
| is_deleted | tinyint | 是否删除 |
#### 2.2.2 管理端API
**路径**: `/api/admin/fan/group`
| 接口 | 方法 | 功能 |
|------|------|------|
| /list | GET | 粉丝团列表 |
| /detail/{id} | GET | 粉丝团详情 |
| /delete/{id} | POST | 删除粉丝团 |
| /batch-delete | POST | 批量删除 |
| /status/{id} | POST | 修改状态(解散/恢复) |
| /update/{id} | POST | 修改粉丝团信息 |
| /member/list | GET | 成员列表 |
| /member/delete/{id} | POST | 删除成员 |
| /member/update-level/{id} | POST | 修改成员等级 |
| /message/list | GET | 聊天记录列表 |
| /message/delete/{id} | POST | 删除聊天记录 |
| /statistics | GET | 统计数据 |
#### 2.2.3 粉丝团交互流程
```
┌─────────────────────────────────────────────────────────────────────────┐
│ 粉丝团系统流程 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ 【创建粉丝团】 │
│ ┌────────┐ ┌────────────┐ ┌────────────┐ │
│ │ 主播 │──▶│ 设置名称 │──▶│ 创建粉丝团 │ │
│ │ 开播 │ │ 徽章/颜色 │ │ │ │
│ └────────┘ └────────────┘ └────────────┘ │
│ │
│ 【加入粉丝团】 │
│ ┌────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
│ │ 用户 │──▶│ 查看粉丝团 │──▶│ 支付加入费 │──▶│ 成为成员 │ │
│ │ │ │ 信息 │ │ (可选) │ │ 等级=1 │ │
│ └────────┘ └────────────┘ └────────────┘ └────────────┘ │
│ │
│ 【等级提升】 │
│ ┌────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
│ │ 成员 │──▶│ 送礼/互动 │──▶│ 增加亲密度 │──▶│ 等级提升 │ │
│ │ │ │ │ │ │ │ (1-10级) │ │
│ └────────┘ └────────────┘ └────────────┘ └────────────┘ │
│ │
│ 【群聊功能】 │
│ ┌────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
│ │ 成员 │──▶│ 发送消息 │──▶│ 敏感词过滤 │──▶│ 群内广播 │ │
│ │ │ │ │ │ │ │ │ │
│ └────────┘ └────────────┘ └────────────┘ └────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
```
---
## 三、封禁系统模块
### 3.1 系统概述
封禁系统分为两大类:
1. **平台封禁** - 管理员对用户/房间的封禁eb_user_ban / eb_room_ban
2. **用户黑名单** - 用户间的互相拉黑eb_user_blacklist / eb_room_blacklist
### 3.2 数据表结构
#### 3.2.1 用户封禁表 `eb_user_ban`
| 字段 | 类型 | 说明 |
|------|------|------|
| id | bigint | 记录ID |
| user_id | int | 被封禁用户ID |
| ban_type | varchar(20) | 封禁类型(permanent永久/temporary临时) |
| reason | varchar(500) | 封禁原因 |
| duration_days | int | 封禁天数(临时封禁) |
| expire_time | datetime | 解封时间 |
| operator_id | int | 操作员ID |
| status | tinyint | 状态(0已解封/1封禁中) |
#### 3.2.2 房间封禁表 `eb_room_ban`
| 字段 | 类型 | 说明 |
|------|------|------|
| id | bigint | 记录ID |
| room_id | int | 被封禁房间ID |
| ban_type | varchar(20) | 封禁类型 |
| reason | varchar(500) | 封禁原因 |
| duration_days | int | 封禁天数 |
| expire_time | datetime | 解封时间 |
| operator_id | int | 操作员ID |
| status | tinyint | 状态 |
#### 3.2.3 用户黑名单表 `eb_user_blacklist`
| 字段 | 类型 | 说明 |
|------|------|------|
| id | int | 记录ID |
| user_id | int | 拉黑发起者ID |
| blocked_user_id | int | 被拉黑用户ID |
| blocker_nickname | varchar(64) | 发起者昵称 |
| blocked_nickname | varchar(64) | 被拉黑者昵称 |
| create_time | datetime | 创建时间 |
#### 3.2.4 房间黑名单表 `eb_room_blacklist`
| 字段 | 类型 | 说明 |
|------|------|------|
| id | int | 记录ID |
| room_id | int | 房间ID |
| room_name | varchar(128) | 房间名称 |
| blocked_user_id | int | 被拉黑用户ID |
| blocked_user_nickname | varchar(64) | 被拉黑用户昵称 |
| operator_id | int | 操作者ID(主播) |
| create_time | datetime | 创建时间 |
### 3.3 管理端API
#### 3.3.1 封禁管理 `/api/admin/ban`
| 接口 | 方法 | 功能 |
|------|------|------|
| /user/list | GET | 用户封禁列表 |
| /user/add | POST | 封禁用户 |
| /user/unban/{id} | POST | 解除用户封禁 |
| /user/delete/{id} | POST | 删除封禁记录 |
| /user/batch-delete | POST | 批量删除 |
| /user/check/{userId} | GET | 检查用户封禁状态 |
| /room/list | GET | 房间封禁列表 |
| /room/add | POST | 封禁房间 |
| /room/unban/{id} | POST | 解除房间封禁 |
| /room/delete/{id} | POST | 删除封禁记录 |
| /room/batch-delete | POST | 批量删除 |
| /room/check/{roomId} | GET | 检查房间封禁状态 |
#### 3.3.2 黑名单管理 `/api/admin/blacklist`
| 接口 | 方法 | 功能 |
|------|------|------|
| /user/list | GET | 用户黑名单列表 |
| /user/delete/{id} | POST | 删除用户黑名单记录 |
| /user/batch-delete | POST | 批量删除 |
| /room/list | GET | 房间黑名单列表 |
| /room/delete/{id} | POST | 删除房间黑名单记录 |
| /room/batch-delete | POST | 批量删除 |
### 3.4 移动端API
**路径**: `/api/front/ban`
| 接口 | 方法 | 功能 |
|------|------|------|
| /check/me | GET | 检查当前用户封禁状态 |
| /check/user/{userId} | GET | 检查指定用户封禁状态 |
| /check/room/{roomId} | GET | 检查房间封禁状态 |
| /blacklist/list | GET | 获取我的黑名单列表 |
| /blacklist/add | POST | 添加用户到黑名单 |
| /blacklist/remove | POST | 从黑名单移除用户 |
| /blacklist/check/{targetUserId} | GET | 检查黑名单状态 |
### 3.5 封禁检查触发点
封禁状态检查在以下场景自动触发:
| 场景 | 检查内容 | 实现位置 |
|------|----------|----------|
| 用户登录 | 检查用户是否被封禁 | LoginServiceImpl.checkUserBanStatus() |
| 发送私聊消息 | 检查双方黑名单状态 | ConversationServiceImpl.checkBlacklistStatus() |
| 发送直播间弹幕 | 检查用户封禁状态 | LiveRoomController.checkUserBanStatus() |
| 赠送礼物 | 检查用户封禁状态 | LiveRoomController.sendGift() |
| 进入直播间 | 检查房间封禁状态 | Android RoomDetailActivity |
### 3.6 封禁系统交互流程
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ 封禁系统完整流程 │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ 【管理员封禁用户】 │
│ ┌────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
│ │ 管理员 │──▶│ 选择用户 │──▶│ 设置封禁 │──▶│ 更新用户 │ │
│ │ │ │ 填写原因 │ │ 类型/时长 │ │ status=0 │ │
│ └────────┘ └────────────┘ └────────────┘ └────────────┘ │
│ │
│ 【用户登录检查】 │
│ ┌────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
│ │ 用户 │──▶│ 提交登录 │──▶│ 检查封禁表 │──▶│ 封禁中? │ │
│ │ 登录 │ │ │ │ │ │ │ │
│ └────────┘ └────────────┘ └────────────┘ └─────┬──────┘ │
│ │ │
│ ┌──────────────────┼──────────────────┐ │
│ ▼ ▼ │ │
│ ┌──────────┐ ┌──────────┐ │ │
│ │ 是:拒绝 │ │ 否:允许 │ │ │
│ │ 返回原因 │ │ 登录成功 │ │ │
│ └──────────┘ └──────────┘ │ │
│ │
│ 【用户拉黑用户】 │
│ ┌────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
│ │ 用户A │──▶│ 点击拉黑 │──▶│ 添加黑名单 │──▶│ 删除好友 │ │
│ │ │ │ 用户B │ │ 记录 │ │ 关系 │ │
│ └────────┘ └────────────┘ └────────────┘ └────────────┘ │
│ │
│ 【私聊黑名单检查】 │
│ ┌────────┐ ┌────────────┐ ┌────────────┐ │
│ │ 用户A │──▶│ 发送消息 │──▶│ 检查黑名单 │ │
│ │ 发消息 │ │ 给用户B │ │ │ │
│ └────────┘ └────────────┘ └─────┬──────┘ │
│ │ │
│ ┌──────────────────┼──────────────────┐ │
│ ▼ ▼ ▼ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ A拉黑了B │ │ B拉黑了A │ │ 无黑名单 │ │
│ │ 提示:您已│ │ 提示:对方│ │ 正常发送 │ │
│ │ 拉黑对方 │ │ 已拉黑您 │ │ │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ │
│ 【房间封禁检查】 │
│ ┌────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
│ │ 用户 │──▶│ 进入直播间 │──▶│ 检查房间 │──▶│ 封禁中? │ │
│ │ │ │ │ │ 封禁状态 │ │ │ │
│ └────────┘ └────────────┘ └────────────┘ └─────┬──────┘ │
│ │ │
│ ┌──────────────────┼──────────────────┐ │
│ ▼ ▼ │ │
│ ┌──────────┐ ┌──────────┐ │ │
│ │ 是:禁止 │ │ 否:允许 │ │ │
│ │ 进入房间 │ │ 进入观看 │ │ │
│ └──────────┘ └──────────┘ │ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
```
---
## 四、三大模块联动关系
### 4.1 模块交互图
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ 三大模块联动关系 │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────┐ │
│ │ 敏感词管理 │ │
│ │ │ │
│ │ • 内容过滤规则 │ │
│ │ • 违规词库维护 │ │
│ └────────┬────────┘ │
│ │ │
│ ┌────────────┼────────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────────────────┐ ┌─────────────────────┐ ┌─────────────────────┐ │
│ │ 私聊消息 │ │ 粉丝团群聊 │ │ 直播间弹幕 │ │
│ │ │ │ │ │ │ │
│ │ • 发送前过滤敏感词 │ │ • 发送前过滤敏感词 │ │ • 发送前过滤敏感词 │ │
│ │ • 检查黑名单状态 │ │ • 检查成员状态 │ │ • 检查用户封禁 │ │
│ │ • 检查用户封禁 │ │ • 检查用户封禁 │ │ • 检查房间封禁 │ │
│ └──────────┬──────────┘ └──────────┬──────────┘ └──────────┬──────────┘ │
│ │ │ │ │
│ └────────────────────────┼────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────┐ │
│ │ 封禁系统 │ │
│ │ │ │
│ │ • 用户封禁管理 │ │
│ │ • 房间封禁管理 │ │
│ │ • 用户黑名单 │ │
│ │ • 房间黑名单 │ │
│ └─────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
```
### 4.2 完整消息发送流程
```
用户发送消息
┌────────────────┐
│ 1. 用户登录检查 │ ──── 检查 eb_user_ban 表
└───────┬────────┘
│ 通过
┌────────────────┐
│ 2. 封禁状态检查 │ ──── 检查用户是否被平台封禁
└───────┬────────┘
│ 通过
┌────────────────┐
│ 3. 黑名单检查 │ ──── 检查 eb_user_blacklist 表
└───────┬────────┘ (私聊场景)
│ 通过
┌────────────────┐
│ 4. 敏感词过滤 │ ──── 检查 eb_sensitive_word 表
└───────┬────────┘
│ 通过/替换
┌────────────────┐
│ 5. 消息入库 │ ──── 保存到对应消息表
└───────┬────────┘
┌────────────────┐
│ 6. 推送通知 │ ──── WebSocket/推送服务
└────────────────┘
```
---
## 五、代码实现位置汇总
### 5.1 后端代码
| 模块 | 文件路径 | 说明 |
|------|----------|------|
| 敏感词管理 | `crmeb-admin/.../SensitiveWordController.java` | 管理端敏感词CRUD |
| 私聊管理 | `crmeb-admin/.../ChatManagementController.java` | 管理端私聊管理 |
| 私聊服务 | `crmeb-service/.../ConversationServiceImpl.java` | 私聊业务逻辑+黑名单检查 |
| 粉丝团管理 | `crmeb-admin/.../FanGroupController.java` | 管理端粉丝团管理 |
| 封禁管理 | `crmeb-admin/.../BanController.java` | 管理端封禁管理 |
| 黑名单管理 | `crmeb-admin/.../BlacklistController.java` | 管理端黑名单管理 |
| 移动端封禁 | `crmeb-front/.../BanFrontController.java` | 移动端封禁API |
| 登录服务 | `crmeb-front/.../LoginServiceImpl.java` | 登录时封禁检查 |
| 直播间控制 | `crmeb-front/.../LiveRoomController.java` | 弹幕/礼物封禁检查 |
### 5.2 前端代码
| 模块 | 文件路径 | 说明 |
|------|----------|------|
| 敏感词页面 | `admin/src/views/sensitiveWord/list/index.vue` | 敏感词管理页面 |
| 敏感词API | `admin/src/api/sensitiveWord.js` | 敏感词API接口 |
| 粉丝团页面 | `admin/src/views/fanGroup/list/index.vue` | 粉丝团管理页面 |
| 粉丝团API | `admin/src/api/fanGroup.js` | 粉丝团API接口 |
| 封禁页面 | `admin/src/views/ban/` | 封禁管理页面 |
| 黑名单页面 | `admin/src/views/blacklist/` | 黑名单管理页面 |
### 5.3 Android代码
| 模块 | 文件路径 | 说明 |
|------|----------|------|
| API接口 | `ApiService.java` | 封禁/黑名单API定义 |
| 直播间 | `RoomDetailActivity.java` | 进入房间封禁检查 |
| 粉丝团聊天 | `GroupChatActivity.java` | 粉丝团群聊功能 |
| 消息列表 | `MessagesActivity.java` | 消息列表页面 |
---
## 六、待完善功能建议
### 6.1 敏感词模块
1. **实时过滤服务** - 目前敏感词表已建立,建议实现统一的敏感词过滤服务类
2. **分类管理** - 支持按分类(spam/illegal/abuse)管理敏感词
3. **批量导入** - 支持Excel/TXT批量导入敏感词
4. **过滤日志** - 记录敏感词触发日志,便于分析
### 6.2 消息模块
1. **消息撤回通知** - 撤回消息时通知对方
2. **消息已读回执** - 显示消息已读状态
3. **群聊@功能** - 粉丝团群聊支持@成员
4. **消息搜索** - 支持历史消息搜索
### 6.3 封禁模块
1. **封禁申诉** - 用户可提交封禁申诉
2. **自动解封** - 临时封禁到期自动解封定时任务
3. **封禁通知** - 封禁/解封时推送通知给用户
4. **封禁统计** - 封禁数据统计报表
---
## 七、总结
本报告详细描述了直播平台三大核心模块的功能设计和交互逻辑:
1. **敏感词管理** - 提供内容安全过滤能力,保障平台内容合规
2. **消息/粉丝团/群组** - 构建完整的社交通讯体系,增强用户粘性
3. **封禁系统** - 提供多层次的用户管理能力,维护平台秩序
三大模块相互配合,形成完整的平台安全和社交体系。
---
*报告生成时间: 2026-01-05*

View File

@ -1,277 +0,0 @@
# 观看历史功能 - zhibo-h后台实现说明
## 📌 重要说明
**zhibo-h后台项目已经实现了完整的观看历史功能**
不需要在 `live-streaming` 项目中实现,所有功能都在 `Zhibo/zhibo-h` 项目中。
---
## ✅ 已实现的功能
### 后台实现zhibo-h项目
#### 1. UserActivityRecordController
**位置**: `Zhibo/zhibo-h/crmeb-front/src/main/java/com/zbkj/front/controller/UserActivityRecordController.java`
**API路由**: `/api/front/activity`
**功能列表**:
| 功能 | 方法 | 路径 | 说明 |
|------|------|------|------|
| 记录观看历史 | POST | `/activity/view/record` | 记录用户观看直播间/作品 |
| 获取观看历史 | GET | `/activity/view/history` | 分页获取观看历史列表 |
| 删除单条历史 | DELETE | `/activity/view/history/{historyId}` | 删除指定的观看历史 |
| 清空观看历史 | DELETE | `/activity/view/history` | 清空用户的观看历史 |
| 获取点赞记录 | GET | `/activity/like/records` | 获取点赞记录列表 |
| 获取关注记录 | GET | `/activity/follow/records` | 获取关注记录列表 |
| 获取收藏记录 | GET | `/activity/collect/works` | 获取收藏的作品列表 |
| Token调试 | GET | `/activity/debug/token` | 调试Token状态 |
#### 2. WatchHistoryController备用
**位置**: `Zhibo/zhibo-h/crmeb-front/src/main/java/com/zbkj/front/controller/WatchHistoryController.java`
**API路由**: `/api/front/watch`
---
## 🔧 Android端需要调整的地方
### 当前问题
Android端的 `RoomDetailActivity.java` 中调用的API路径是
```java
POST /api/front/activity/record-view
```
但是zhibo-h后台的实际路径是
```java
POST /api/front/activity/view/record
```
### 解决方案
#### 方案1修改Android端API调用推荐
修改 `android-app/app/src/main/java/com/example/livestreaming/net/ApiService.java`
```java
// 当前(错误)
@POST("api/front/activity/record-view")
Call<ApiResponse<Map<String, Object>>> recordViewHistoryNew(@Body Map<String, Object> body);
// 修改为(正确)
@POST("api/front/activity/view/record")
Call<ApiResponse<Map<String, Object>>> recordViewHistoryNew(@Body Map<String, Object> body);
```
同时修改获取观看历史的API
```java
// 当前(错误)
@GET("api/front/activity/view-history")
Call<ApiResponse<PageResponse<Map<String, Object>>>> getViewHistory(
@Query("type") String type,
@Query("page") int page,
@Query("pageSize") int pageSize);
// 修改为(正确)
@GET("api/front/activity/view/history")
Call<ApiResponse<PageResponse<Map<String, Object>>>> getViewHistory(
@Query("targetType") String targetType, // 参数名改为targetType
@Query("page") int page,
@Query("pageSize") int pageSize);
```
#### 方案2在后台添加兼容路由不推荐
`UserActivityRecordController` 中添加兼容的路由映射,但这会增加维护成本。
---
## 📊 API接口详细说明
### 1. 记录观看历史
**请求**:
```http
POST /api/front/activity/view/record
Content-Type: application/json
Authorization: Bearer {token}
{
"targetType": "room", // 类型room-直播间, work-作品, profile-用户主页
"targetId": "room-123", // 目标ID
"targetTitle": "精彩直播间", // 标题
"duration": 120 // 观看时长(秒)
}
```
**响应**:
```json
{
"code": 200,
"message": "success",
"data": {
"success": true,
"message": "记录成功"
}
}
```
### 2. 获取观看历史
**请求**:
```http
GET /api/front/activity/view/history?targetType=room&page=1&pageSize=20
Authorization: Bearer {token}
```
**响应**:
```json
{
"code": 200,
"message": "success",
"data": {
"list": [
{
"id": 1,
"userId": 43,
"targetType": "room",
"targetId": "8",
"targetTitle": "火影忍者",
"createTime": "2026-01-05 10:00:00",
"updateTime": "2026-01-05 10:30:00"
}
],
"total": 10,
"pageNum": 1,
"pageSize": 20
}
}
```
### 3. 清空观看历史
**请求**:
```http
DELETE /api/front/activity/view/history?targetType=room
Authorization: Bearer {token}
```
**响应**:
```json
{
"code": 200,
"message": "清空成功",
"data": null
}
```
---
## 🗄️ 数据库表结构
观看历史数据存储在数据库表中不是JSON文件
**表名**: `eb_user_activity_record``eb_watch_history`
**字段**:
- `id` - 主键
- `user_id` - 用户ID
- `target_type` - 目标类型room/work/profile
- `target_id` - 目标ID
- `target_title` - 目标标题
- `duration` - 观看时长
- `create_time` - 创建时间
- `update_time` - 更新时间
---
## ✅ 优势
使用zhibo-h后台的优势
1. **统一管理**: 所有用户数据都在同一个数据库中
2. **完整功能**: 不仅有观看历史,还有点赞、关注、收藏等记录
3. **数据持久化**: 使用MySQL数据库不是JSON文件
4. **已经实现**: 代码已经写好只需要调整Android端的API路径
5. **日志完善**: 有详细的日志记录,方便调试
---
## 🚀 快速修复步骤
### 步骤1修改Android端ApiService.java
找到文件:`android-app/app/src/main/java/com/example/livestreaming/net/ApiService.java`
修改以下接口:
```java
// 记录观看历史(新版)
@POST("api/front/activity/view/record") // 修改路径
Call<ApiResponse<Map<String, Object>>> recordViewHistoryNew(@Body Map<String, Object> body);
// 获取观看历史
@GET("api/front/activity/view/history") // 修改路径
Call<ApiResponse<PageResponse<Map<String, Object>>>> getViewHistory(
@Query("targetType") String targetType, // 修改参数名
@Query("page") int page,
@Query("pageSize") int pageSize);
// 清除观看历史
@DELETE("api/front/activity/view/history") // 修改路径
Call<ApiResponse<String>> clearViewHistory(@Query("targetType") String targetType);
```
### 步骤2修改RoomDetailActivity.java
找到 `recordWatchHistory()` 方法,确保参数名正确:
```java
body.put("targetType", "room"); // 确保是targetType不是type
body.put("targetId", roomId);
body.put("targetTitle", "直播间");
body.put("duration", 0); // 确保是duration不是viewDuration
```
### 步骤3测试
1. 重新编译Android应用
2. 登录应用
3. 进入直播间
4. 查看日志确认API调用成功
5. 进入"我的记录" -> "观看历史"查看
---
## 📝 注意事项
1. ⚠️ **不要修改live-streaming项目**所有功能都在zhibo-h中
2. ⚠️ **确保后台服务运行**zhibo-h后台需要在8081端口运行
3. ⚠️ **Token认证**确保Android端正确传递Token
4. ⚠️ **参数名称**:注意参数名是 `targetType``duration`,不是 `type``viewDuration`
---
## 🔍 调试方法
如果遇到问题,可以使用调试接口:
```http
GET /api/front/activity/debug/token
Authorization: Bearer {token}
```
这个接口会返回:
- Token状态
- 用户ID
- 是否登录
---
**最后更新**: 2026-01-05
**状态**: ✅ 后台已实现需要调整Android端API路径

View File

@ -1,371 +0,0 @@
# 观看历史功能 - 完成报告
## ✅ 修复完成!
观看历史功能已经完全修复,可以正常使用了!
---
## 🎯 问题总结
### 发现的问题
`RoomDetailActivity.java``updateWatchHistoryWithRoomInfo()` 方法中,参数名使用错误:
```java
// ❌ 错误
body.put("viewDuration", 0);
// ✅ 正确
body.put("duration", 0);
```
### 修复内容
**修改文件**: `android-app/app/src/main/java/com/example/livestreaming/RoomDetailActivity.java`
**修改位置**: 第1172行左右
**修改内容**: 将 `viewDuration` 改为 `duration`
---
## ✅ 检查结果
### API路径 - 完全正确 ✅
| 功能 | API路径 | 状态 |
|------|---------|------|
| 记录观看历史 | `POST /api/front/activity/view/record` | ✅ |
| 获取观看历史 | `GET /api/front/activity/view/history` | ✅ |
| 清除观看历史 | `DELETE /api/front/activity/view/history` | ✅ |
| 获取点赞记录 | `GET /api/front/activity/like/records` | ✅ |
| 获取关注记录 | `GET /api/front/activity/follow/records` | ✅ |
| 获取收藏记录 | `GET /api/front/activity/collect/works` | ✅ |
| Token调试 | `GET /api/front/activity/debug/token` | ✅ |
### 参数名 - 完全正确 ✅
| 参数 | 状态 |
|------|------|
| `targetType` | ✅ |
| `targetId` | ✅ |
| `targetTitle` | ✅ |
| `duration` | ✅ (已修复) |
| `coverImage` | ✅ |
| `streamerName` | ✅ |
### 代码质量 - 无错误 ✅
- ✅ 编译检查通过
- ✅ 无语法错误
- ✅ 无类型错误
---
## 🏗️ 架构说明
### 后台实现zhibo-h项目
```
Zhibo/zhibo-h/
├── crmeb-front/
│ └── controller/
│ └── UserActivityRecordController.java ✅ 已实现
├── crmeb-service/
│ └── service/
│ └── UserActivityRecordService.java ✅ 已实现
└── 数据库表: eb_user_activity_record ✅ 已创建
```
### Android端实现
```
android-app/
└── app/src/main/java/com/example/livestreaming/
├── net/
│ └── ApiService.java ✅ API定义正确
├── RoomDetailActivity.java ✅ 已修复
└── MyRecordsActivity.java ✅ 显示功能已实现
```
---
## 🚀 功能说明
### 1. 自动记录观看历史
**触发时机**: 用户进入直播间时
**记录内容**:
- 直播间ID
- 直播间标题
- 主播名称
- 封面图片
- 观看时长
**实现方法**:
- `recordWatchHistory()` - 进入时记录基本信息
- `updateWatchHistoryWithRoomInfo()` - 房间信息加载后更新详细信息
### 2. 查看观看历史
**入口**: "我的" → "我的记录" → "观看历史"标签页
**显示内容**:
- 直播间封面
- 直播间标题
- 主播名称
- 观看时间
- 直播状态(直播中/已结束)
**功能**:
- 点击可跳转到对应的直播间
- 支持分页加载
- 按最后观看时间倒序排列
### 3. 其他记录功能
同时支持:
- ✅ 点赞记录
- ✅ 收藏记录
- ✅ 关注记录
---
## 📊 数据流程
```
用户进入直播间
recordWatchHistory() 被调用
发送 POST /api/front/activity/view/record
后台 UserActivityRecordController 接收
UserActivityRecordService 处理业务逻辑
保存到数据库 eb_user_activity_record
房间信息加载完成
updateWatchHistoryWithRoomInfo() 被调用
更新观看历史的详细信息
用户可以在"我的记录"中查看
```
---
## 🧪 测试指南
### 1. 编译应用
```bash
cd android-app
./gradlew assembleDebug
```
### 2. 安装应用
```bash
adb install -r app/build/outputs/apk/debug/app-debug.apk
```
### 3. 测试步骤
1. **登录应用**
- 使用有效的账号登录
2. **进入直播间**
- 选择任意直播间进入
- 等待几秒钟
3. **查看日志**
```bash
adb logcat | grep -E "RoomDetail|观看历史"
```
**期望看到**:
```
RoomDetail: 观看历史记录成功
RoomDetail: 房间加载成功: 火影忍者
RoomDetail: 观看历史更新成功
```
4. **查看观看历史**
- 返回首页
- 进入"我的" → "我的记录"
- 切换到"观看历史"标签页
- 应该能看到刚才观看的直播间
5. **测试跳转**
- 点击历史记录
- 应该能跳转到对应的直播间
---
## 🔍 调试方法
### 使用调试接口
```bash
# 1. 测试Token状态
curl -X GET "http://1.15.149.240:8081/api/front/activity/debug/token" \
-H "Authorization: Bearer YOUR_TOKEN"
# 2. 测试记录观看历史
curl -X POST "http://1.15.149.240:8081/api/front/activity/view/record" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_TOKEN" \
-d '{
"targetType": "room",
"targetId": "8",
"targetTitle": "火影忍者",
"duration": 120
}'
# 3. 测试获取观看历史
curl -X GET "http://1.15.149.240:8081/api/front/activity/view/history?page=1&pageSize=20" \
-H "Authorization: Bearer YOUR_TOKEN"
```
### 查看后台日志
```bash
# 实时查看日志
tail -f Zhibo/zhibo-h/crmeb_front_log/log_info.log | grep "观看历史"
# 查看错误日志
tail -f Zhibo/zhibo-h/crmeb_front_log/log_error.log
```
---
## 📝 相关文档
已创建的文档:
1. ✅ `观看历史功能-zhibo-h后台说明.md` - 后台API详细说明
2. ✅ `Android端API路径修复指南.md` - 修复指南(已过时)
3. ✅ `观看历史功能-最终修复方案.md` - 修复方案
4. ✅ `观看历史功能-检查结果.md` - 检查结果
5. ✅ `观看历史功能-完成报告.md` - 本文档
不需要使用的文档基于live-streaming
- ⚠️ `观看历史功能-快速指南.md`
- ⚠️ `观看历史功能实现说明.md`
- ⚠️ `live-streaming/test-view-history.md`
---
## ⚠️ 注意事项
### 1. 后台服务
确保zhibo-h后台服务正在运行
- 本地开发http://localhost:8081
- 生产环境http://1.15.149.240:8083
### 2. 数据库
确保数据库表 `eb_user_activity_record` 已创建
### 3. Token认证
确保Android端正确传递Token
- 格式:`Bearer {token}` 或直接 `{token}`
- 位置:请求头 `Authorization``Authori-zation`
### 4. 不要使用live-streaming
- ❌ 不要使用 `live-streaming/server/routes/viewHistory.js`
- ❌ 不要使用 `live-streaming/server/store/viewHistoryStore.js`
- ✅ 所有功能都在 `zhibo-h` 项目中
---
## 🎉 总结
### 修改内容
**只修改了1个参数名**`viewDuration` → `duration`
### 修改结果
- ✅ 编译通过
- ✅ 无语法错误
- ✅ API路径正确
- ✅ 参数名正确
- ✅ 功能完整
### 预期效果
1. ✅ 进入直播间自动记录观看历史
2. ✅ 房间信息加载后更新详细信息
3. ✅ 在"我的记录"页面显示观看历史
4. ✅ 点击可跳转到对应的直播间
5. ✅ 显示直播状态(直播中/已结束)
6. ✅ 支持分页加载
7. ✅ 按时间倒序排列
---
## 📞 技术支持
如果遇到问题:
1. **检查后台日志**
```bash
tail -f Zhibo/zhibo-h/crmeb_front_log/log_info.log | grep "观看历史"
```
2. **检查Android日志**
```bash
adb logcat | grep -E "RoomDetail|观看历史"
```
3. **使用调试接口**
```bash
curl -X GET "http://1.15.149.240:8081/api/front/activity/debug/token" \
-H "Authorization: Bearer YOUR_TOKEN"
```
---
**完成时间**: 2026-01-05
**修改文件**: 1个
**修改行数**: 1行
**修改内容**: 1个参数名
**状态**: ✅ 完成,可以测试使用
---
## 🚀 下一步
1. **编译应用**
```bash
cd android-app
./gradlew assembleDebug
```
2. **安装测试**
```bash
adb install -r app/build/outputs/apk/debug/app-debug.apk
```
3. **测试功能**
- 登录 → 进入直播间 → 查看"我的记录"
4. **验证成功**
- 观看历史能正常显示
- 点击能跳转到直播间
- 显示直播状态正确
**预计测试时间**: 5分钟
---
**🎊 恭喜!观看历史功能已经完全修复并可以正常使用了!**

View File

@ -1,177 +0,0 @@
# 观看历史功能 - 快速指南
## 🎯 功能说明
用户在观看直播时,系统会自动记录观看历史,并可以在"我的记录"页面查看历史记录。
## ✅ 已实现的功能
### 后台功能
- ✅ 自动记录用户观看直播间的历史
- ✅ 支持分页查询观看历史
- ✅ 支持按类型过滤(直播间/作品/用户主页)
- ✅ 自动去重(同一用户观看同一内容会更新记录)
- ✅ 记录观看次数和最后观看时间
- ✅ 数据持久化存储
### Android端功能
- ✅ 进入直播间自动记录观看历史
- ✅ 在"我的记录"页面显示观看历史
- ✅ 点击历史记录可跳转到对应直播间
- ✅ 显示直播间封面、标题、主播名称等信息
- ✅ 显示直播状态(直播中/已结束)
## 📁 新增/修改的文件
### 后台文件
```
live-streaming/
├── server/
│ ├── store/
│ │ └── viewHistoryStore.js [新增] 观看历史数据存储
│ ├── routes/
│ │ └── viewHistory.js [新增] 观看历史API路由
│ └── index.js [修改] 添加路由
├── data/
│ └── viewHistory.json [自动生成] 数据存储文件
└── test-api.bat [新增] API测试脚本
```
### Android端文件
```
android-app/app/src/main/java/com/example/livestreaming/
└── RoomDetailActivity.java [修改] 添加观看历史记录功能
```
## 🚀 快速测试
### 1. 启动后台服务
```bash
cd live-streaming
npm install
npm start
```
### 2. 测试APIWindows
```bash
cd live-streaming
test-api.bat
```
### 3. Android端测试
1. 启动Android应用
2. 登录账号
3. 进入任意直播间
4. 返回首页 -> "我的" -> "我的记录"
5. 查看"观看历史"标签页
## 📊 API接口
### 记录观看历史
```
POST /api/front/activity/record-view
Headers: Authorization: {userId}
Body: {
"targetType": "room",
"targetId": "room-id",
"targetTitle": "直播间标题",
"coverImage": "封面URL",
"streamerName": "主播名称",
"viewDuration": 120
}
```
### 获取观看历史
```
GET /api/front/activity/view-history?page=1&pageSize=20&type=room
Headers: Authorization: {userId}
```
### 清除观看历史
```
DELETE /api/front/activity/view-history?type=room
Headers: Authorization: {userId}
```
## 💡 使用场景
1. **用户观看直播**
- 用户进入直播间 → 自动记录观看历史
- 用户再次进入同一直播间 → 更新观看时间和次数
2. **查看历史记录**
- 用户打开"我的记录" → 查看"观看历史"标签
- 显示最近观看的直播间列表
- 点击可快速进入直播间
3. **数据统计**
- 记录用户观看次数
- 记录最后观看时间
- 支持按时间排序
## 🔧 技术细节
### 数据存储格式
```json
{
"id": 1704441600000,
"userId": 1,
"targetType": "room",
"targetId": "room-123",
"targetTitle": "精彩直播间",
"coverImage": "https://example.com/cover.jpg",
"streamerName": "主播名称",
"viewDuration": 120,
"createTime": "2024-01-05T10:00:00.000Z",
"updateTime": "2024-01-05T10:02:00.000Z",
"viewCount": 3
}
```
### 认证方式
- 使用 `Authorization` 请求头传递用户ID
- 格式:`Authorization: {userId}` 或 `Authorization: Bearer {userId}`
- 未登录用户不记录观看历史
## 📝 注意事项
1. ⚠️ 用户必须登录才能记录观看历史
2. ⚠️ 数据目前存储在JSON文件中生产环境建议使用数据库
3. ⚠️ 观看历史仅用户本人可见
4. ⚠️ 同一用户观看同一内容会更新记录而不是创建新记录
## 🎨 界面展示
### 我的记录页面
```
┌─────────────────────────────────┐
│ ← 我的记录 │
├─────────────────────────────────┤
│ 观看历史 | 点赞记录 | 收藏记录 | 关注记录 │
├─────────────────────────────────┤
│ ┌─────────────────────────────┐ │
│ │ [封面图] 精彩直播间 [直播中] │ │
│ │ 主播:测试主播 │ │
│ │ 2024-01-05 10:00 │ │
│ └─────────────────────────────┘ │
│ ┌─────────────────────────────┐ │
│ │ [封面图] 游戏直播间 │ │
│ │ 主播:游戏主播 │ │
│ │ 2024-01-04 20:30 │ │
│ └─────────────────────────────┘ │
└─────────────────────────────────┘
```
## 🔮 后续优化建议
1. 添加观看时长的实时更新
2. 支持用户手动删除单条历史
3. 添加时间筛选功能(今天/本周/本月)
4. 支持导出观看历史
5. 添加隐私设置开关
6. 迁移到数据库存储
## 📚 相关文档
- 详细实现说明:`观看历史功能实现说明.md`
- API测试指南`live-streaming/test-view-history.md`

View File

@ -1,270 +0,0 @@
# 观看历史功能 - 最终修复方案
## 🎯 问题定位
经过详细检查,发现了**唯一需要修复的问题**
### ❌ 问题:参数名不一致
`RoomDetailActivity.java``updateWatchHistoryWithRoomInfo()` 方法中:
```java
body.put("viewDuration", 0); // ❌ 错误:应该是 duration
```
而后台期望的参数名是:
```java
Integer duration = body.get("duration") // ✅ 正确
```
---
## ✅ 其他检查结果
### API路径 - 完全正确 ✅
| 功能 | Android端 | 后台 | 状态 |
|------|----------|------|------|
| 记录观看历史 | `/activity/view/record` | `/activity/view/record` | ✅ |
| 获取观看历史 | `/activity/view/history` | `/activity/view/history` | ✅ |
| 清除观看历史 | `/activity/view/history` | `/activity/view/history` | ✅ |
| 获取点赞记录 | `/activity/like/records` | `/activity/like/records` | ✅ |
| 获取关注记录 | `/activity/follow/records` | `/activity/follow/records` | ✅ |
| 获取收藏记录 | `/activity/collect/works` | `/activity/collect/works` | ✅ |
### 参数名 - 部分正确 ⚠️
| 方法 | 参数 | 状态 |
|------|------|------|
| `recordWatchHistory()` | `duration` | ✅ 正确 |
| `updateWatchHistoryWithRoomInfo()` | `viewDuration` | ❌ 错误 |
---
## 🔧 修复方案
### 需要修改的文件
**文件**: `android-app/app/src/main/java/com/example/livestreaming/RoomDetailActivity.java`
**位置**: `updateWatchHistoryWithRoomInfo()` 方法
### 修改内容
找到第1172行左右的代码
```java
// ❌ 修改前(错误)
body.put("viewDuration", 0);
// ✅ 修改后(正确)
body.put("duration", 0);
```
### 完整的修改代码
```java
private void updateWatchHistoryWithRoomInfo() {
if (room == null || !AuthHelper.isLoggedIn(this)) {
return;
}
try {
ApiService apiService = ApiClient.getService(getApplicationContext());
java.util.Map<String, Object> body = new java.util.HashMap<>();
body.put("targetType", "room");
body.put("targetId", roomId);
body.put("targetTitle", room.getTitle() != null ? room.getTitle() : "直播间");
body.put("coverImage", room.getCoverImage());
body.put("streamerName", room.getStreamerName());
body.put("duration", 0); // ✅ 修改这里viewDuration → duration
apiService.recordViewHistoryNew(body).enqueue(new Callback<ApiResponse<java.util.Map<String, Object>>>() {
@Override
public void onResponse(Call<ApiResponse<java.util.Map<String, Object>>> call,
Response<ApiResponse<java.util.Map<String, Object>>> response) {
if (response.isSuccessful() && response.body() != null && response.body().isOk()) {
android.util.Log.d("RoomDetail", "观看历史更新成功");
}
}
@Override
public void onFailure(Call<ApiResponse<java.util.Map<String, Object>>> call, Throwable t) {
// 忽略错误
}
});
} catch (Exception e) {
// 忽略所有异常
}
}
```
---
## 📝 修改步骤
### 步骤1打开文件
```bash
# 使用你喜欢的编辑器打开文件
code android-app/app/src/main/java/com/example/livestreaming/RoomDetailActivity.java
```
### 步骤2查找并修改
1. 搜索 `viewDuration`
2. 找到 `updateWatchHistoryWithRoomInfo()` 方法中的这一行
3. 将 `viewDuration` 改为 `duration`
### 步骤3保存并编译
```bash
cd android-app
./gradlew assembleDebug
```
### 步骤4安装测试
```bash
adb install -r app/build/outputs/apk/debug/app-debug.apk
```
---
## 🧪 测试步骤
### 1. 启动应用并登录
确保使用有效的账号登录
### 2. 进入直播间
选择任意直播间进入
### 3. 查看日志
使用adb logcat查看日志
```bash
adb logcat | grep -E "RoomDetail|观看历史"
```
**期望看到的日志**:
```
RoomDetail: 观看历史记录成功
RoomDetail: 房间加载成功: 火影忍者
RoomDetail: 观看历史更新成功 ← 这个是关键
```
### 4. 查看观看历史
1. 返回首页
2. 进入"我的" → "我的记录"
3. 切换到"观看历史"标签页
4. 应该能看到刚才观看的直播间
---
## 🔍 后台验证
### 检查后台日志
```bash
# 查看zhibo-h后台日志
tail -f Zhibo/zhibo-h/crmeb_front_log/log_info.log | grep "观看历史"
```
**期望看到的日志**:
```
【观看历史API】参数: userId=43, targetType=room, page=1, pageSize=20
【观看历史API】成功: userId=43, total=1, listSize=1
```
### 使用调试接口
```bash
# 测试Token状态
curl -X GET "http://1.15.149.240:8081/api/front/activity/debug/token" \
-H "Authorization: Bearer YOUR_TOKEN"
# 测试记录观看历史
curl -X POST "http://1.15.149.240:8081/api/front/activity/view/record" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_TOKEN" \
-d '{
"targetType": "room",
"targetId": "8",
"targetTitle": "火影忍者",
"duration": 120
}'
# 测试获取观看历史
curl -X GET "http://1.15.149.240:8081/api/front/activity/view/history?page=1&pageSize=20" \
-H "Authorization: Bearer YOUR_TOKEN"
```
---
## 📊 修改对比
### 修改前
```java
// recordWatchHistory() 方法
body.put("duration", 0); // ✅ 正确
// updateWatchHistoryWithRoomInfo() 方法
body.put("viewDuration", 0); // ❌ 错误
```
### 修改后
```java
// recordWatchHistory() 方法
body.put("duration", 0); // ✅ 正确
// updateWatchHistoryWithRoomInfo() 方法
body.put("duration", 0); // ✅ 正确
```
---
## ✅ 修改检查清单
- [x] ✅ API路径正确无需修改
- [x] ✅ `targetType` 参数名正确(无需修改)
- [x] ✅ `recordWatchHistory()` 中的 `duration` 正确(无需修改)
- [ ] ⚠️ `updateWatchHistoryWithRoomInfo()` 中的 `viewDuration` 需要改为 `duration`
---
## 🎉 预期结果
修改完成后:
1. ✅ 进入直播间时自动记录观看历史
2. ✅ 房间信息加载后更新观看历史(包含标题、封面、主播名称)
3. ✅ 在"我的记录"页面能看到观看历史
4. ✅ 点击历史记录能跳转到对应的直播间
5. ✅ 显示直播间的实时状态(直播中/已结束)
---
## 💡 总结
**只需要修改一个参数名,从 `viewDuration` 改为 `duration`,功能就能完全正常工作!**
- ✅ API路径完全正确
- ✅ 参数名99%正确
- ⚠️ 需要修改1个参数名`viewDuration` → `duration`
**预计修改时间**: 1分钟
**预计测试时间**: 5分钟
**总计**: 6分钟即可完成
---
**最后更新**: 2026-01-05
**状态**: 🔧 需要修改1个参数名

View File

@ -1,243 +0,0 @@
# 观看历史功能 - 最终总结
## 🎉 重要发现
**zhibo-h后台项目已经完整实现了观看历史功能**
不需要在 `live-streaming` 项目中添加任何代码。
---
## ✅ 当前状态
### 后台zhibo-h
- ✅ **已完成**:观看历史功能已在 `UserActivityRecordController.java` 中实现
- ✅ **已完成**:数据库表已创建
- ✅ **已完成**Service层已实现
- ✅ **已完成**:包含观看历史、点赞记录、关注记录、收藏记录等完整功能
### Android端
- ⚠️ **需要修改**API路径不匹配
- ⚠️ **需要修改**:参数名称不匹配
---
## 🔧 需要做的修改
### 唯一需要修改的地方Android端API路径
**文件**: `android-app/app/src/main/java/com/zbkj/front/net/ApiService.java`
**修改内容**:
| 旧路径 | 新路径 | 说明 |
|--------|--------|------|
| `/activity/record-view` | `/activity/view/record` | 记录观看历史 |
| `/activity/view-history` | `/activity/view/history` | 获取观看历史 |
| `/activity/like-records` | `/activity/like/records` | 获取点赞记录 |
| `/activity/follow-records` | `/activity/follow/records` | 获取关注记录 |
| `/activity/collected-works` | `/activity/collect/works` | 获取收藏记录 |
**参数名修改**:
- `type``targetType`
- `viewDuration``duration`
---
## 📁 项目结构说明
```
Zhibo/zhibo-h/ ← 主后台项目Spring Boot
├── crmeb-front/ ← 前端API模块
│ └── src/main/java/com/zbkj/front/
│ └── controller/
│ ├── UserActivityRecordController.java ← 观看历史等功能 ✅
│ └── WatchHistoryController.java ← 备用实现 ✅
├── crmeb-service/ ← 业务逻辑层
│ └── src/main/java/com/zbkj/service/
│ └── service/
│ └── UserActivityRecordService.java ← Service实现 ✅
└── crmeb-common/ ← 公共模块
live-streaming/ ← 独立的Node.js项目
├── server/
│ ├── routes/
│ │ └── viewHistory.js ← ❌ 不需要使用
│ └── store/
│ └── viewHistoryStore.js ← ❌ 不需要使用
└── ...
```
---
## 🚀 快速修复步骤
### 步骤1修改ApiService.java
打开文件:`android-app/app/src/main/java/com/zbkj/front/net/ApiService.java`
找到并修改以下接口:
```java
// 记录观看历史
@POST("api/front/activity/view/record") // 修改路径
Call<ApiResponse<Map<String, Object>>> recordViewHistoryNew(@Body Map<String, Object> body);
// 获取观看历史
@GET("api/front/activity/view/history") // 修改路径
Call<ApiResponse<PageResponse<Map<String, Object>>>> getViewHistory(
@Query("targetType") String targetType, // 修改参数名
@Query("page") int page,
@Query("pageSize") int pageSize);
```
### 步骤2重新编译
```bash
cd android-app
./gradlew assembleDebug
```
### 步骤3测试
1. 安装应用
2. 登录账号
3. 进入直播间
4. 查看"我的记录" → "观看历史"
---
## 📊 API对比
### zhibo-h后台正确
```
POST /api/front/activity/view/record 记录观看历史
GET /api/front/activity/view/history 获取观看历史
DELETE /api/front/activity/view/history 清空观看历史
GET /api/front/activity/like/records 获取点赞记录
GET /api/front/activity/follow/records 获取关注记录
GET /api/front/activity/collect/works 获取收藏记录
```
### live-streaming不使用
```
POST /api/front/activity/record-view ❌ 不使用
GET /api/front/activity/view-history ❌ 不使用
DELETE /api/front/activity/view-history ❌ 不使用
```
---
## 💡 为什么不使用live-streaming
1. **数据隔离**: live-streaming使用JSON文件存储zhibo-h使用MySQL数据库
2. **功能完整**: zhibo-h已经实现了完整的用户活动记录功能
3. **统一管理**: 所有用户数据都在zhibo-h中便于管理
4. **已经实现**: zhibo-h的代码已经写好并测试通过
---
## 🗄️ 数据存储
### zhibo-h使用
- **存储方式**: MySQL数据库
- **表名**: `eb_user_activity_record`
- **优势**:
- 数据持久化
- 支持复杂查询
- 支持事务
- 易于备份
### live-streaming不使用
- **存储方式**: JSON文件
- **文件**: `live-streaming/data/viewHistory.json`
- **缺点**:
- 并发性能差
- 不支持复杂查询
- 数据容易丢失
---
## 📝 文档清单
已创建的文档:
1. ✅ `观看历史功能-zhibo-h后台说明.md` - 后台实现详细说明
2. ✅ `Android端API路径修复指南.md` - Android端修改指南
3. ✅ `观看历史功能-最终总结.md` - 本文档
4. ⚠️ `观看历史功能-快速指南.md` - 基于live-streaming的指南不使用
5. ⚠️ `观看历史功能实现说明.md` - 基于live-streaming的说明不使用
---
## ⚠️ 注意事项
1. **不要修改live-streaming项目**
- 已创建的 `viewHistoryStore.js``viewHistory.js` 不需要使用
- 可以保留作为参考,但不要在生产环境中使用
2. **只修改Android端**
- 只需要修改 `ApiService.java` 中的API路径
- 确保参数名正确(`targetType` 和 `duration`
3. **确保后台运行**
- zhibo-h后台需要运行在8081端口本地或8083端口生产
- 检查数据库连接是否正常
4. **Token认证**
- 确保Android端正确传递Token
- 使用 `/activity/debug/token` 接口验证Token状态
---
## 🎯 下一步行动
### 立即执行
1. [ ] 修改 `ApiService.java` 中的API路径
2. [ ] 重新编译Android应用
3. [ ] 测试观看历史功能
### 可选操作
1. [ ] 删除或归档 `live-streaming/server/routes/viewHistory.js`
2. [ ] 删除或归档 `live-streaming/server/store/viewHistoryStore.js`
3. [ ] 更新 `live-streaming/server/index.js`,移除观看历史路由
---
## 📞 技术支持
如果遇到问题:
1. **检查后台日志**
- 位置:`Zhibo/zhibo-h/crmeb_front_log/`
- 搜索关键词:"观看历史"、"UserActivityRecord"
2. **检查Android日志**
- 使用Logcat搜索"RoomDetail"、"观看历史"
3. **使用调试接口**
```bash
curl -X GET "http://1.15.149.240:8081/api/front/activity/debug/token" \
-H "Authorization: Bearer YOUR_TOKEN"
```
---
## ✨ 总结
**观看历史功能已经在zhibo-h后台完整实现只需要修改Android端的API路径即可使用**
- ✅ 后台:完全实现,无需修改
- ⚠️ Android需要修改API路径
- ❌ live-streaming不需要使用
**预计修改时间**: 10分钟
**预计测试时间**: 5分钟
**总计**: 15分钟即可完成
---
**最后更新**: 2026-01-05
**状态**: ✅ 已分析完成等待Android端修改

View File

@ -1,217 +0,0 @@
# 观看历史功能 - 检查结果
## ✅ 好消息API路径已经正确
经过检查,发现 `ApiService.java` 中的API路径**已经是正确的**
---
## 📊 当前API配置正确
### ApiService.java 中的定义
```java
// ==================== 用户活动记录 ====================
/**
* 获取观看历史
*/
@GET("api/front/activity/view/history") // ✅ 正确
Call<ApiResponse<PageResponse<Map<String, Object>>>> getViewHistory(
@Query("targetType") String targetType, // ✅ 正确
@Query("page") int page,
@Query("pageSize") int pageSize);
/**
* 清除观看历史
*/
@DELETE("api/front/activity/view/history") // ✅ 正确
Call<ApiResponse<String>> clearViewHistory(@Query("targetType") String targetType); // ✅ 正确
/**
* 获取点赞记录
*/
@GET("api/front/activity/like/records") // ✅ 正确
Call<ApiResponse<PageResponse<Map<String, Object>>>> getLikeRecords(
@Query("targetType") String targetType, // ✅ 正确
@Query("page") int page,
@Query("pageSize") int pageSize);
/**
* 获取收藏的作品
*/
@GET("api/front/activity/collect/works") // ✅ 正确
Call<ApiResponse<PageResponse<Map<String, Object>>>> getCollectedWorks(
@Query("page") int page,
@Query("pageSize") int pageSize);
/**
* 获取关注记录
*/
@GET("api/front/activity/follow/records") // ✅ 正确
Call<ApiResponse<PageResponse<Map<String, Object>>>> getFollowRecords(
@Query("page") int page,
@Query("pageSize") int pageSize);
/**
* 记录观看历史(新版)
*/
@POST("api/front/activity/view/record") // ✅ 正确
Call<ApiResponse<Map<String, Object>>> recordViewHistoryNew(@Body Map<String, Object> body);
/**
* 调试Token
*/
@GET("api/front/activity/debug/token") // ✅ 正确
Call<ApiResponse<Map<String, Object>>> debugToken();
```
---
## ✅ 对比结果
| 功能 | ApiService.java | zhibo-h后台 | 状态 |
|------|----------------|-------------|------|
| 记录观看历史 | `/activity/view/record` | `/activity/view/record` | ✅ 匹配 |
| 获取观看历史 | `/activity/view/history` | `/activity/view/history` | ✅ 匹配 |
| 清除观看历史 | `/activity/view/history` | `/activity/view/history` | ✅ 匹配 |
| 获取点赞记录 | `/activity/like/records` | `/activity/like/records` | ✅ 匹配 |
| 获取关注记录 | `/activity/follow/records` | `/activity/follow/records` | ✅ 匹配 |
| 获取收藏记录 | `/activity/collect/works` | `/activity/collect/works` | ✅ 匹配 |
| 参数名 | `targetType` | `targetType` | ✅ 匹配 |
---
## 🔍 需要检查的地方
虽然API路径正确但还需要检查以下几点
### 1. RoomDetailActivity.java 中的参数
检查 `recordWatchHistory()``updateWatchHistoryWithRoomInfo()` 方法中的参数名:
**需要确认的参数**:
- ✅ `targetType` (不是 `type`)
- ✅ `targetId`
- ✅ `targetTitle`
- ⚠️ **`duration`** (不是 `viewDuration`)
### 2. 后台服务状态
确认zhibo-h后台服务
- [ ] 是否正在运行
- [ ] 端口是否正确8081本地8083生产
- [ ] 数据库连接是否正常
### 3. Token认证
确认Token传递
- [ ] Android端是否正确传递Token
- [ ] Token格式是否正确`Bearer {token}`
- [ ] Token是否有效
---
## 🔧 需要修改的地方
### RoomDetailActivity.java
检查参数名是否正确,特别是 `duration` 字段:
```java
// 当前代码(需要确认)
body.put("targetType", "room"); // ✅ 正确
body.put("targetId", roomId); // ✅ 正确
body.put("targetTitle", "直播间"); // ✅ 正确
body.put("duration", 0); // ⚠️ 需要确认是duration还是viewDuration
```
**后台期望的参数名**根据UserActivityRecordController.java:
```java
String targetType = body.get("targetType")
String targetId = body.get("targetId")
String targetTitle = body.get("targetTitle")
Integer duration = body.get("duration") // ← 注意是duration
```
---
## 📝 检查清单
### API路径
- [x] ✅ `getViewHistory` 路径正确
- [x] ✅ `clearViewHistory` 路径正确
- [x] ✅ `getLikeRecords` 路径正确
- [x] ✅ `getFollowRecords` 路径正确
- [x] ✅ `getCollectedWorks` 路径正确
- [x] ✅ `recordViewHistoryNew` 路径正确
- [x] ✅ `debugToken` 路径正确
### 参数名
- [x] ✅ `targetType` 参数名正确
- [x] ✅ `page` 参数名正确
- [x] ✅ `pageSize` 参数名正确
### 需要确认
- [ ] ⚠️ RoomDetailActivity中使用的是 `duration` 还是 `viewDuration`
- [ ] ⚠️ 后台服务是否运行
- [ ] ⚠️ Token是否正确传递
---
## 🚀 下一步行动
### 1. 检查RoomDetailActivity.java
查看 `recordWatchHistory()` 方法中的参数:
```bash
# 搜索关键代码
grep -n "body.put" RoomDetailActivity.java | grep -E "duration|viewDuration"
```
### 2. 测试API连接
使用curl测试后台API
```bash
# 测试调试接口
curl -X GET "http://1.15.149.240:8081/api/front/activity/debug/token" \
-H "Authorization: Bearer YOUR_TOKEN"
# 测试记录观看历史
curl -X POST "http://1.15.149.240:8081/api/front/activity/view/record" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_TOKEN" \
-d '{
"targetType": "room",
"targetId": "8",
"targetTitle": "测试直播间",
"duration": 120
}'
```
### 3. 查看后台日志
检查zhibo-h的日志文件
```bash
tail -f Zhibo/zhibo-h/crmeb_front_log/log_info.log | grep "观看历史"
```
---
## 💡 结论
**API路径配置完全正确**
现在需要:
1. ✅ 确认RoomDetailActivity中的参数名特别是`duration`
2. ✅ 确认后台服务正在运行
3. ✅ 测试功能是否正常工作
如果参数名也正确,那么功能应该已经可以正常使用了!
---
**检查时间**: 2026-01-05
**状态**: ✅ API路径正确需要确认参数和后台服务

View File

@ -1,122 +0,0 @@
# 观看历史功能实现说明
## 功能概述
已成功实现观看历史记录功能,用户在观看直播时会自动记录观看历史,并可以在"我的记录"页面查看。
## 实现的功能
### 1. 后台功能
#### 新增文件
- `live-streaming/server/store/viewHistoryStore.js` - 观看历史数据存储
- `live-streaming/server/routes/viewHistory.js` - 观看历史API路由
#### 修改文件
- `live-streaming/server/index.js` - 添加观看历史路由
#### API接口
1. **记录观看历史**
- 接口:`POST /api/front/activity/record-view`
- 功能:记录用户观看直播间、作品等内容
- 参数:
```json
{
"targetType": "room", // 类型room/work/profile
"targetId": "room-id", // 目标ID
"targetTitle": "直播间标题",
"coverImage": "封面图片URL",
"streamerName": "主播名称",
"viewDuration": 120 // 观看时长(秒)
}
```
2. **获取观看历史**
- 接口:`GET /api/front/activity/view-history`
- 功能:分页获取用户的观看历史
- 参数:`page`, `pageSize`, `type`(可选,过滤类型)
3. **清除观看历史**
- 接口:`DELETE /api/front/activity/view-history`
- 功能:清除用户的观看历史
- 参数:`type`(可选,清除指定类型)
4. **删除单条记录**
- 接口:`DELETE /api/front/activity/view-history/:id`
- 功能:删除指定的观看历史记录
### 2. Android端功能
#### 修改文件
- `android-app/app/src/main/java/com/example/livestreaming/RoomDetailActivity.java`
#### 实现功能
1. **自动记录观看历史**
- 用户进入直播间时自动记录
- 房间信息加载后更新详细信息
- 未登录用户不记录
2. **显示观看历史**
- 在"我的记录"页面的"观看历史"标签页显示
- 支持点击跳转到对应的直播间
- 显示直播间封面、标题、主播名称、观看时间等信息
## 数据存储
观看历史数据保存在:`live-streaming/data/viewHistory.json`
数据格式:
```json
[
{
"id": 1704441600000,
"userId": 1,
"targetType": "room",
"targetId": "room-123",
"targetTitle": "精彩直播间",
"coverImage": "https://example.com/cover.jpg",
"streamerName": "主播名称",
"viewDuration": 120,
"createTime": "2024-01-05T10:00:00.000Z",
"updateTime": "2024-01-05T10:02:00.000Z",
"viewCount": 3
}
]
```
## 特性说明
1. **自动去重**:同一用户观看同一内容会更新记录而不是创建新记录
2. **观看次数统计**:记录用户观看同一内容的次数
3. **时间排序**:按最后观看时间倒序排列
4. **分页支持**:支持分页加载,避免一次加载过多数据
5. **类型过滤**:支持按类型(直播间/作品/用户主页)过滤
6. **实时状态**:直播间的在线状态会实时更新
## 使用方式
### 用户端操作
1. 登录应用
2. 进入任意直播间观看
3. 系统自动记录观看历史
4. 进入"我的" -> "我的记录"
5. 切换到"观看历史"标签页查看
### 开发者测试
参考 `live-streaming/test-view-history.md` 文件中的测试步骤
## 注意事项
1. 用户必须登录才能记录观看历史
2. 观看历史仅在用户端可见,不会公开
3. 数据持久化存储在本地JSON文件中
4. 生产环境建议使用数据库存储
## 后续优化建议
1. 添加观看时长的实时更新(目前仅记录初始值)
2. 支持用户手动删除单条观看历史
3. 添加观看历史的时间筛选功能
4. 支持导出观看历史数据
5. 添加隐私设置(是否记录观看历史)
6. 迁移到数据库存储MySQL/PostgreSQL

View File

@ -1,305 +0,0 @@
# 观看历史重复问题修复指南
## 🎯 问题描述
1. **观看历史出现重复记录** - 同一个直播间显示多次
2. **界面布局需要优化** - 封面在左边,标题、主播名、观看时间在右边
---
## ✅ 已完成的修复
### 1. 优化布局文件
**文件**: `android-app/app/src/main/res/layout/item_record.xml`
**修改内容**:
- ✅ 封面图从80dp增大到100dp更清晰
- ✅ 封面固定在左边,使用 `layout_constraintStart_toStartOf="parent"`
- ✅ 右侧内容区域标题2行、主播名、观看时间
- ✅ 移除底部分割线,使用卡片间距
- ✅ 增加卡片阴影效果
**布局结构**:
```
┌─────────────────────────────────────────┐
│ ┌────────┐ 标题标题标题标题标题标题 │
│ │ │ 标题标题标题 │
│ │ 封面 │ [直播间] 主播名称 │
│ │ │ │
│ │ 100x100│ 2024-01-05 15:30 │
│ └────────┘ │
└─────────────────────────────────────────┘
```
### 2. 创建数据库清理脚本
**文件**: `Zhibo/zhibo-h/sql/fix_duplicate_view_history.sql`
**功能**:
- ✅ 查看重复数据
- ✅ 删除重复记录,保留最新的一条
- ✅ 添加唯一索引,防止将来再次出现重复
---
## 🔧 修复步骤
### 步骤1清理数据库中的重复数据
#### 方法1使用SQL脚本推荐
```bash
# 连接到数据库
mysql -u root -p zhibo
# 执行清理脚本
source Zhibo/zhibo-h/sql/fix_duplicate_view_history.sql
```
#### 方法2手动执行SQL
```sql
-- 1. 查看重复数据
SELECT
user_id,
target_type,
target_id,
COUNT(*) as count
FROM eb_view_history
GROUP BY user_id, target_type, target_id
HAVING COUNT(*) > 1;
-- 2. 删除重复数据,保留最新的一条
DELETE FROM eb_view_history
WHERE id NOT IN (
SELECT * FROM (
SELECT MAX(id) as id
FROM eb_view_history
GROUP BY user_id, target_type, target_id
) AS temp
);
-- 3. 添加唯一索引,防止将来再次出现重复
ALTER TABLE eb_view_history
ADD UNIQUE INDEX idx_user_target (user_id, target_type, target_id);
```
### 步骤2重新编译Android应用
```bash
cd android-app
./gradlew assembleDebug
```
### 步骤3安装并测试
```bash
# 安装应用
adb install -r app/build/outputs/apk/debug/app-debug.apk
# 清除应用数据(可选,确保使用新布局)
adb shell pm clear com.example.livestreaming
```
---
## 🔍 验证修复
### 1. 验证数据库
```sql
-- 检查是否还有重复数据
SELECT
user_id,
target_type,
target_id,
COUNT(*) as count
FROM eb_view_history
GROUP BY user_id, target_type, target_id
HAVING COUNT(*) > 1;
-- 应该返回空结果
-- 查看唯一索引是否创建成功
SHOW INDEX FROM eb_view_history WHERE Key_name = 'idx_user_target';
```
### 2. 验证应用界面
1. **打开应用**
2. **登录账号**
3. **进入"我的" → "我的记录" → "观看历史"**
4. **检查**:
- ✅ 没有重复记录
- ✅ 封面在左边100x100dp
- ✅ 标题在右边最多2行
- ✅ 主播名称显示正确
- ✅ 观看时间显示正确
- ✅ 直播中标签显示在封面右上角
---
## 📊 布局对比
### 修改前
```
┌─────────────────────────────────────────┐
│ ┌──────┐ 标题标题标题标题标题标题标题 │
│ │ │ [直播间] 主播名称 │
│ │ 封面 │ ❤ 1.2万 │
│ │ 80x80│ 2024-01-04 · 观看32分钟 │
│ └──────┘ │
│ ───────────────────────────────────── │ ← 分割线
└─────────────────────────────────────────┘
```
### 修改后
```
┌─────────────────────────────────────────┐
│ ┌────────┐ 标题标题标题标题标题标题 │
│ │ │ 标题标题标题 │
│ │ 封面 │ [直播间] 主播名称 │
│ │ │ │
│ │ 100x100│ 2024-01-05 15:30 │
│ └────────┘ │
└─────────────────────────────────────────┘
```
**改进点**:
- ✅ 封面更大80dp → 100dp
- ✅ 标题可以显示2行
- ✅ 布局更清晰,信息层次分明
- ✅ 移除分割线,使用卡片间距
- ✅ 增加阴影效果
---
## 🐛 问题排查
### 问题1数据库清理失败
**错误**: `You can't specify target table 'eb_view_history' for update in FROM clause`
**解决**: 使用子查询的临时表
```sql
DELETE FROM eb_view_history
WHERE id NOT IN (
SELECT * FROM (
SELECT MAX(id) as id
FROM eb_view_history
GROUP BY user_id, target_type, target_id
) AS temp -- 必须使用临时表
);
```
### 问题2唯一索引创建失败
**错误**: `Duplicate entry '43-room-8' for key 'idx_user_target'`
**原因**: 数据库中仍有重复数据
**解决**: 先执行删除重复数据的SQL再创建索引
### 问题3布局没有更新
**原因**: Android Studio缓存
**解决**:
```bash
# 清理缓存
cd android-app
./gradlew clean
# 重新编译
./gradlew assembleDebug
# 卸载旧版本
adb uninstall com.example.livestreaming
# 安装新版本
adb install app/build/outputs/apk/debug/app-debug.apk
```
---
## 📝 后台去重逻辑说明
后台已经实现了去重逻辑(`UserActivityRecordServiceImpl.java`
```java
// 检查是否已存在相同记录(同一用户、同一目标)
String checkSql = "SELECT id FROM eb_view_history WHERE user_id = ? AND target_type = ? AND target_id = ?";
List<Map<String, Object>> existing = jdbcTemplate.queryForList(checkSql, userId, targetType, targetId);
if (!existing.isEmpty()) {
// 更新已有记录
String updateSql = "UPDATE eb_view_history SET target_title = ?, view_duration = COALESCE(view_duration, 0) + ?, " +
"update_time = NOW() WHERE user_id = ? AND target_type = ? AND target_id = ?";
jdbcTemplate.update(updateSql, targetTitle, duration != null ? duration : 0, userId, targetType, targetId);
} else {
// 插入新记录
String insertSql = "INSERT INTO eb_view_history (user_id, target_type, target_id, target_title, view_duration, create_time, update_time) " +
"VALUES (?, ?, ?, ?, ?, NOW(), NOW())";
jdbcTemplate.update(insertSql, userId, targetType, targetId, targetTitle, duration != null ? duration : 0);
}
```
**工作原理**:
1. 每次记录观看历史时,先检查是否已存在
2. 如果存在,更新记录(更新时间、累加观看时长)
3. 如果不存在,插入新记录
4. 唯一索引确保不会插入重复数据
---
## ✅ 预期效果
修复完成后:
1. **数据库**:
- ✅ 每个用户对每个直播间只有一条记录
- ✅ 有唯一索引防止重复
- ✅ 记录按最后观看时间排序
2. **应用界面**:
- ✅ 观看历史列表无重复
- ✅ 封面在左边100x100dp
- ✅ 标题在右边最多2行
- ✅ 主播名称清晰显示
- ✅ 观看时间格式正确
- ✅ 直播中标签显示在封面上
3. **用户体验**:
- ✅ 界面更清晰美观
- ✅ 信息层次分明
- ✅ 点击可跳转到直播间
- ✅ 下拉刷新正常工作
---
## 📞 技术支持
如果遇到问题:
1. **检查数据库**
```sql
SELECT * FROM eb_view_history WHERE user_id = 43 ORDER BY update_time DESC;
```
2. **检查后台日志**
```bash
tail -f Zhibo/zhibo-h/crmeb_front_log/log_info.log | grep "观看历史"
```
3. **检查Android日志**
```bash
adb logcat | grep -E "MyRecords|观看历史"
```
---
**完成时间**: 2026-01-05
**修改文件**: 2个布局文件 + SQL脚本
**状态**: ✅ 已完成需要执行SQL清理数据库