清理:移动冗余文件
This commit is contained in:
parent
a2287bccd1
commit
1124ce7d82
|
|
@ -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"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🐛 常见问题
|
||||
|
||||
### 问题1:401 未登录
|
||||
|
||||
**原因**: Token未正确传递
|
||||
|
||||
**解决**:
|
||||
1. 检查 `ApiClient.java` 中的Token拦截器
|
||||
2. 确保Token格式正确:`Bearer {token}`
|
||||
3. 使用 `/activity/debug/token` 接口验证
|
||||
|
||||
### 问题2:404 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
|
||||
**状态**: 📝 待修改
|
||||
|
|
@ -20,4 +20,4 @@ APK: android-app/app/build/outputs/apk/release/
|
|||
前端: Zhibo/admin/dist/
|
||||
|
||||
|
||||
将前端访问的服务改成8083,本地改回8081
|
||||
将app部署改成8083,本地开发改成8081
|
||||
|
|
@ -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;
|
||||
|
|
@ -71,8 +71,8 @@ android {
|
|||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_21
|
||||
targetCompatibility = JavaVersion.VERSION_21
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,9 @@
|
|||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<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"
|
||||
android:maxSdkVersion="32" />
|
||||
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
|
||||
|
|
|
|||
|
|
@ -1749,16 +1749,16 @@ public class MainActivity extends AppCompatActivity {
|
|||
allBackendCategories.addAll(categories);
|
||||
|
||||
runOnUiThread(() -> {
|
||||
// 从"我的频道"加载用户保存的频道列表
|
||||
List<ChannelManagerAdapter.ChannelItem> myChannelList = loadMyChannels();
|
||||
|
||||
// 清空现有标签
|
||||
binding.categoryTabs.removeAllTabs();
|
||||
|
||||
// 只显示"我的频道"里的内容
|
||||
for (ChannelManagerAdapter.ChannelItem channel : myChannelList) {
|
||||
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 : 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);
|
||||
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;
|
||||
|
||||
runOnUiThread(() -> {
|
||||
// 从"我的频道"加载用户保存的频道列表
|
||||
List<ChannelManagerAdapter.ChannelItem> myChannelList = loadMyChannels();
|
||||
|
||||
// 清空现有标签
|
||||
binding.categoryTabs.removeAllTabs();
|
||||
|
||||
// 只显示"我的频道"里的内容
|
||||
for (ChannelManagerAdapter.ChannelItem channel : myChannelList) {
|
||||
if (channel != null && channel.getName() != null) {
|
||||
binding.categoryTabs.addTab(binding.categoryTabs.newTab().setText(channel.getName()));
|
||||
// 使用后端分类(如果已加载)
|
||||
if (!allBackendCategories.isEmpty()) {
|
||||
// 添加"推荐"作为第一个标签
|
||||
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();
|
||||
|
||||
Log.d(TAG, "useDefaultCategories() 使用我的频道,共 " + binding.categoryTabs.getTabCount() + " 个标签");
|
||||
Log.d(TAG, "useDefaultCategories() 使用默认分类,共 " + binding.categoryTabs.getTabCount() + " 个标签");
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -59,20 +59,13 @@ public class TianDiTuLocationService {
|
|||
this.context = context.getApplicationContext();
|
||||
this.locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 开始定位
|
||||
*/
|
||||
public void startLocation(OnLocationResultListener listener) {
|
||||
this.resultListener = listener;
|
||||
|
||||
// 测试模式:直接使用固定坐标(已禁用)
|
||||
// if (TEST_MODE) {
|
||||
// Log.d(TAG, "【测试模式】使用固定坐标 - 纬度: " + TEST_LATITUDE + ", 经度: " + TEST_LONGITUDE);
|
||||
// reverseGeocode(TEST_LONGITUDE, TEST_LATITUDE);
|
||||
// return;
|
||||
// }
|
||||
|
||||
// 检查权限
|
||||
if (!checkLocationPermission()) {
|
||||
if (resultListener != null) {
|
||||
|
|
@ -210,7 +203,7 @@ public class TianDiTuLocationService {
|
|||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 逆地理编码 - 将经纬度转换为地址
|
||||
*/
|
||||
|
|
@ -236,7 +229,6 @@ public class TianDiTuLocationService {
|
|||
Log.d(TAG, "坐标检查通过,在中国境内");
|
||||
|
||||
// 构建请求URL
|
||||
// 天地图逆地理编码API: http://api.tianditu.gov.cn/geocoder?postStr={'lon':116.397128,'lat':39.916527,'ver':1}&type=geocode&tk=您的密钥
|
||||
JSONObject postData = new JSONObject();
|
||||
postData.put("lon", longitude);
|
||||
postData.put("lat", latitude);
|
||||
|
|
|
|||
10
android-app/app/src/main/res/drawable/ic_back.xml
Normal file
10
android-app/app/src/main/res/drawable/ic_back.xml
Normal 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>
|
||||
13
android-app/app/src/main/res/drawable/ic_empty.xml
Normal file
13
android-app/app/src/main/res/drawable/ic_empty.xml
Normal 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>
|
||||
|
|
@ -5,12 +5,11 @@
|
|||
android:layout_height="match_parent"
|
||||
android:background="#000000">
|
||||
|
||||
<!-- 使用 OpenGlView 作为摄像头预览,支持 RootEncoder RTMP 推流和视频编码 -->
|
||||
<!-- keepAspectRatio=false 让预览填满整个屏幕 -->
|
||||
<!-- 使用 OpenGlView 作为摄像头预览,全屏填充显示 -->
|
||||
<com.pedro.rtplibrary.view.OpenGlView
|
||||
android:id="@+id/openGlView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
|
|
|
|||
|
|
@ -73,9 +73,12 @@
|
|||
|
||||
<FrameLayout
|
||||
android:id="@+id/playerContainer"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="220dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="200dp"
|
||||
android:layout_marginTop="14dp"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_marginEnd="32dp"
|
||||
android:background="#000000"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/streamerText">
|
||||
|
|
@ -83,7 +86,11 @@
|
|||
<androidx.media3.ui.PlayerView
|
||||
android:id="@+id/playerView"
|
||||
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>
|
||||
|
||||
<TextView
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
|
|
@ -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%';
|
||||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
|
|
@ -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='群组消息表';
|
||||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
|
|
@ -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 = '粉丝团管理';
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
-- 删除遗留的子菜单
|
||||
DELETE FROM eb_system_menu WHERE id = 664;
|
||||
|
||||
-- 验证删除结果 - 只应该剩下直播管理下的粉丝团管理(id=707)
|
||||
SELECT * FROM eb_system_menu WHERE name LIKE '%粉丝团%';
|
||||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
188
封禁系统功能说明.md
188
封禁系统功能说明.md
|
|
@ -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
|
||||
592
直播平台功能交互逻辑报告.md
592
直播平台功能交互逻辑报告.md
|
|
@ -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*
|
||||
|
|
@ -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路径
|
||||
371
观看历史功能-完成报告.md
371
观看历史功能-完成报告.md
|
|
@ -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分钟
|
||||
|
||||
---
|
||||
|
||||
**🎊 恭喜!观看历史功能已经完全修复并可以正常使用了!**
|
||||
177
观看历史功能-快速指南.md
177
观看历史功能-快速指南.md
|
|
@ -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. 测试API(Windows)
|
||||
```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`
|
||||
270
观看历史功能-最终修复方案.md
270
观看历史功能-最终修复方案.md
|
|
@ -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个参数名
|
||||
243
观看历史功能-最终总结.md
243
观看历史功能-最终总结.md
|
|
@ -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端修改
|
||||
217
观看历史功能-检查结果.md
217
观看历史功能-检查结果.md
|
|
@ -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路径正确,需要确认参数和后台服务
|
||||
122
观看历史功能实现说明.md
122
观看历史功能实现说明.md
|
|
@ -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)
|
||||
305
观看历史重复问题修复指南.md
305
观看历史重复问题修复指南.md
|
|
@ -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清理数据库
|
||||
Loading…
Reference in New Issue
Block a user