清理:移动冗余文件
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/
|
前端: 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 {
|
compileOptions {
|
||||||
sourceCompatibility = JavaVersion.VERSION_21
|
sourceCompatibility = JavaVersion.VERSION_17
|
||||||
targetCompatibility = JavaVersion.VERSION_21
|
targetCompatibility = JavaVersion.VERSION_17
|
||||||
}
|
}
|
||||||
|
|
||||||
buildFeatures {
|
buildFeatures {
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,9 @@
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.CAMERA" />
|
<uses-permission android:name="android.permission.CAMERA" />
|
||||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||||
|
<!-- 定位权限 -->
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
|
||||||
android:maxSdkVersion="32" />
|
android:maxSdkVersion="32" />
|
||||||
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
|
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
|
||||||
|
|
|
||||||
|
|
@ -1749,16 +1749,16 @@ public class MainActivity extends AppCompatActivity {
|
||||||
allBackendCategories.addAll(categories);
|
allBackendCategories.addAll(categories);
|
||||||
|
|
||||||
runOnUiThread(() -> {
|
runOnUiThread(() -> {
|
||||||
// 从"我的频道"加载用户保存的频道列表
|
|
||||||
List<ChannelManagerAdapter.ChannelItem> myChannelList = loadMyChannels();
|
|
||||||
|
|
||||||
// 清空现有标签
|
// 清空现有标签
|
||||||
binding.categoryTabs.removeAllTabs();
|
binding.categoryTabs.removeAllTabs();
|
||||||
|
|
||||||
// 只显示"我的频道"里的内容
|
// 添加"推荐"作为第一个标签
|
||||||
for (ChannelManagerAdapter.ChannelItem channel : myChannelList) {
|
binding.categoryTabs.addTab(binding.categoryTabs.newTab().setText("推荐"));
|
||||||
if (channel != null && channel.getName() != null) {
|
|
||||||
binding.categoryTabs.addTab(binding.categoryTabs.newTab().setText(channel.getName()));
|
// 直接使用后端返回的分类
|
||||||
|
for (com.example.livestreaming.net.CategoryResponse cat : categories) {
|
||||||
|
if (cat != null && cat.getName() != null) {
|
||||||
|
binding.categoryTabs.addTab(binding.categoryTabs.newTab().setText(cat.getName()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1766,7 +1766,7 @@ public class MainActivity extends AppCompatActivity {
|
||||||
String lastCategory = CategoryFilterManager.getLastCategory(this);
|
String lastCategory = CategoryFilterManager.getLastCategory(this);
|
||||||
restoreCategoryTabSelection();
|
restoreCategoryTabSelection();
|
||||||
|
|
||||||
Log.d(TAG, "updateCategoryTabs() 分类标签更新完成,共 " + binding.categoryTabs.getTabCount() + " 个标签(只显示我的频道)");
|
Log.d(TAG, "updateCategoryTabs() 分类标签更新完成,共 " + binding.categoryTabs.getTabCount() + " 个标签(直接使用后端分类)");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1777,23 +1777,33 @@ public class MainActivity extends AppCompatActivity {
|
||||||
if (binding == null || binding.categoryTabs == null) return;
|
if (binding == null || binding.categoryTabs == null) return;
|
||||||
|
|
||||||
runOnUiThread(() -> {
|
runOnUiThread(() -> {
|
||||||
// 从"我的频道"加载用户保存的频道列表
|
|
||||||
List<ChannelManagerAdapter.ChannelItem> myChannelList = loadMyChannels();
|
|
||||||
|
|
||||||
// 清空现有标签
|
// 清空现有标签
|
||||||
binding.categoryTabs.removeAllTabs();
|
binding.categoryTabs.removeAllTabs();
|
||||||
|
|
||||||
// 只显示"我的频道"里的内容
|
// 使用后端分类(如果已加载)
|
||||||
for (ChannelManagerAdapter.ChannelItem channel : myChannelList) {
|
if (!allBackendCategories.isEmpty()) {
|
||||||
if (channel != null && channel.getName() != null) {
|
// 添加"推荐"作为第一个标签
|
||||||
binding.categoryTabs.addTab(binding.categoryTabs.newTab().setText(channel.getName()));
|
binding.categoryTabs.addTab(binding.categoryTabs.newTab().setText("推荐"));
|
||||||
|
|
||||||
|
// 添加后端分类
|
||||||
|
for (com.example.livestreaming.net.CategoryResponse cat : allBackendCategories) {
|
||||||
|
if (cat != null && cat.getName() != null) {
|
||||||
|
binding.categoryTabs.addTab(binding.categoryTabs.newTab().setText(cat.getName()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// 后端分类未加载,使用硬编码默认值
|
||||||
|
binding.categoryTabs.addTab(binding.categoryTabs.newTab().setText("推荐"));
|
||||||
|
binding.categoryTabs.addTab(binding.categoryTabs.newTab().setText("娱乐"));
|
||||||
|
binding.categoryTabs.addTab(binding.categoryTabs.newTab().setText("游戏"));
|
||||||
|
binding.categoryTabs.addTab(binding.categoryTabs.newTab().setText("音乐"));
|
||||||
|
binding.categoryTabs.addTab(binding.categoryTabs.newTab().setText("户外"));
|
||||||
|
}
|
||||||
|
|
||||||
// 恢复上次选中的分类
|
// 恢复上次选中的分类
|
||||||
restoreCategoryTabSelection();
|
restoreCategoryTabSelection();
|
||||||
|
|
||||||
Log.d(TAG, "useDefaultCategories() 使用我的频道,共 " + binding.categoryTabs.getTabCount() + " 个标签");
|
Log.d(TAG, "useDefaultCategories() 使用默认分类,共 " + binding.categoryTabs.getTabCount() + " 个标签");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -66,13 +66,6 @@ public class TianDiTuLocationService {
|
||||||
public void startLocation(OnLocationResultListener listener) {
|
public void startLocation(OnLocationResultListener listener) {
|
||||||
this.resultListener = listener;
|
this.resultListener = listener;
|
||||||
|
|
||||||
// 测试模式:直接使用固定坐标(已禁用)
|
|
||||||
// if (TEST_MODE) {
|
|
||||||
// Log.d(TAG, "【测试模式】使用固定坐标 - 纬度: " + TEST_LATITUDE + ", 经度: " + TEST_LONGITUDE);
|
|
||||||
// reverseGeocode(TEST_LONGITUDE, TEST_LATITUDE);
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// 检查权限
|
// 检查权限
|
||||||
if (!checkLocationPermission()) {
|
if (!checkLocationPermission()) {
|
||||||
if (resultListener != null) {
|
if (resultListener != null) {
|
||||||
|
|
@ -236,7 +229,6 @@ public class TianDiTuLocationService {
|
||||||
Log.d(TAG, "坐标检查通过,在中国境内");
|
Log.d(TAG, "坐标检查通过,在中国境内");
|
||||||
|
|
||||||
// 构建请求URL
|
// 构建请求URL
|
||||||
// 天地图逆地理编码API: http://api.tianditu.gov.cn/geocoder?postStr={'lon':116.397128,'lat':39.916527,'ver':1}&type=geocode&tk=您的密钥
|
|
||||||
JSONObject postData = new JSONObject();
|
JSONObject postData = new JSONObject();
|
||||||
postData.put("lon", longitude);
|
postData.put("lon", longitude);
|
||||||
postData.put("lat", latitude);
|
postData.put("lat", latitude);
|
||||||
|
|
|
||||||
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:layout_height="match_parent"
|
||||||
android:background="#000000">
|
android:background="#000000">
|
||||||
|
|
||||||
<!-- 使用 OpenGlView 作为摄像头预览,支持 RootEncoder RTMP 推流和视频编码 -->
|
<!-- 使用 OpenGlView 作为摄像头预览,全屏填充显示 -->
|
||||||
<!-- keepAspectRatio=false 让预览填满整个屏幕 -->
|
|
||||||
<com.pedro.rtplibrary.view.OpenGlView
|
<com.pedro.rtplibrary.view.OpenGlView
|
||||||
android:id="@+id/openGlView"
|
android:id="@+id/openGlView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="0dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="0dp"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
|
|
||||||
|
|
@ -73,9 +73,12 @@
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:id="@+id/playerContainer"
|
android:id="@+id/playerContainer"
|
||||||
android:layout_width="0dp"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="220dp"
|
android:layout_height="200dp"
|
||||||
android:layout_marginTop="14dp"
|
android:layout_marginTop="14dp"
|
||||||
|
android:layout_marginStart="32dp"
|
||||||
|
android:layout_marginEnd="32dp"
|
||||||
|
android:background="#000000"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/streamerText">
|
app:layout_constraintTop_toBottomOf="@id/streamerText">
|
||||||
|
|
@ -83,7 +86,11 @@
|
||||||
<androidx.media3.ui.PlayerView
|
<androidx.media3.ui.PlayerView
|
||||||
android:id="@+id/playerView"
|
android:id="@+id/playerView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent" />
|
android:layout_height="match_parent"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
app:resize_mode="fit"
|
||||||
|
app:show_buffering="when_playing"
|
||||||
|
app:use_controller="true" />
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
|
|
||||||
|
|
@ -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