diff --git a/Zhibo/zhibo-h/crmeb-common/pom.xml b/Zhibo/zhibo-h/crmeb-common/pom.xml index bb1eef62..7bd22a8d 100644 --- a/Zhibo/zhibo-h/crmeb-common/pom.xml +++ b/Zhibo/zhibo-h/crmeb-common/pom.xml @@ -318,6 +318,18 @@ 1.3.0 + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + + org.hibernate.validator + hibernate-validator + + diff --git a/Zhibo/zhibo-h/crmeb-common/src/main/java/com/zbkj/common/config/JpaConfig.java b/Zhibo/zhibo-h/crmeb-common/src/main/java/com/zbkj/common/config/JpaConfig.java new file mode 100644 index 00000000..fe0b02fb --- /dev/null +++ b/Zhibo/zhibo-h/crmeb-common/src/main/java/com/zbkj/common/config/JpaConfig.java @@ -0,0 +1,26 @@ +package com.zbkj.common.config; + +import org.springframework.boot.autoconfigure.domain.EntityScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +/** + * JPA配置类 + * 用于配置JPA相关功能,与MyBatis-Plus共存 + */ +@Configuration +@EnableTransactionManagement +@EnableJpaAuditing +@EnableJpaRepositories( + basePackages = "com.zbkj.service.repository", // JPA Repository接口所在包 + entityManagerFactoryRef = "entityManagerFactory", + transactionManagerRef = "transactionManager" +) +@EntityScan(basePackages = "com.zbkj.common.model") // JPA实体类所在包 +public class JpaConfig { + + // 如果需要自定义配置,可以在这里添加Bean + +} diff --git a/Zhibo/zhibo-h/crmeb-common/src/main/java/com/zbkj/common/constants/CategoryConstants.java b/Zhibo/zhibo-h/crmeb-common/src/main/java/com/zbkj/common/constants/CategoryConstants.java index 162bf864..ab19770f 100644 --- a/Zhibo/zhibo-h/crmeb-common/src/main/java/com/zbkj/common/constants/CategoryConstants.java +++ b/Zhibo/zhibo-h/crmeb-common/src/main/java/com/zbkj/common/constants/CategoryConstants.java @@ -16,22 +16,34 @@ public class CategoryConstants { /** 分类状态-正常 */ public static final Integer CATEGORY_STATUS_NORMAL = 1; + /** 分类状态-失效 */ public static final Integer CATEGORY_STATUS_INVALID = 0; - - /** 分类类型-产品分类 */ + + /** 分类类型-商品分类 */ public static final Integer CATEGORY_TYPE_PRODUCT = 1; + /** 分类类型-附件分类 */ public static final Integer CATEGORY_TYPE_ATTACHMENT = 2; + /** 分类类型-文章分类 */ public static final Integer CATEGORY_TYPE_ARTICLE = 3; + /** 分类类型-设置分类 */ public static final Integer CATEGORY_TYPE_SETTING = 4; + /** 分类类型-菜单分类 */ public static final Integer CATEGORY_TYPE_MENU = 5; + /** 分类类型-配置分类 */ public static final Integer CATEGORY_TYPE_CONFIG = 6; + /** 分类类型-秒杀配置 */ public static final Integer CATEGORY_TYPE_SECKILL = 7; - + + /** 分类类型-直播间分类 */ + public static final Integer CATEGORY_TYPE_LIVE_ROOM = 8; + + /** 分类类型-作品分类 */ + public static final Integer CATEGORY_TYPE_WORK = 9; } diff --git a/Zhibo/zhibo-h/crmeb-common/src/main/java/com/zbkj/common/model/live/LiveRoom.java b/Zhibo/zhibo-h/crmeb-common/src/main/java/com/zbkj/common/model/live/LiveRoom.java index 5f2a5678..d96eca4a 100644 --- a/Zhibo/zhibo-h/crmeb-common/src/main/java/com/zbkj/common/model/live/LiveRoom.java +++ b/Zhibo/zhibo-h/crmeb-common/src/main/java/com/zbkj/common/model/live/LiveRoom.java @@ -32,6 +32,10 @@ public class LiveRoom implements Serializable { @ApiModelProperty(value = "直播间标题") private String title; + @ApiModelProperty(value = "分类ID") + @TableField("category_id") + private Integer categoryId; + @ApiModelProperty(value = "主播名称") @TableField("streamer_name") private String streamerName; diff --git a/Zhibo/zhibo-h/crmeb-front/src/main/java/com/zbkj/front/controller/CategoryController.java b/Zhibo/zhibo-h/crmeb-front/src/main/java/com/zbkj/front/controller/CategoryController.java new file mode 100644 index 00000000..328f457f --- /dev/null +++ b/Zhibo/zhibo-h/crmeb-front/src/main/java/com/zbkj/front/controller/CategoryController.java @@ -0,0 +1,174 @@ +package com.zbkj.front.controller; + +import com.zbkj.common.constants.CategoryConstants; +import com.zbkj.common.model.category.Category; +import com.zbkj.common.result.CommonResult; +import com.zbkj.service.service.CategoryService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * 前端分类接口 + * +---------------------------------------------------------------------- + * | CRMEB [ CRMEB赋能开发者,助力企业发展 ] + * +---------------------------------------------------------------------- + * | Copyright (c) 2016~2025 https://www.crmeb.com All rights reserved. + * +---------------------------------------------------------------------- + * | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权 + * +---------------------------------------------------------------------- + * | Author: CRMEB Team + * +---------------------------------------------------------------------- + */ +@RestController +@RequestMapping("api/front/category") +@Api(tags = "前端 -- 分类") +public class CategoryController { + + @Autowired + private CategoryService categoryService; + + @ApiOperation(value = "获取直播间分类列表") + @GetMapping("/live-room") + public CommonResult> getLiveRoomCategories() { + List categories = categoryService.getList( + new com.zbkj.common.request.CategorySearchRequest() + .setType(CategoryConstants.CATEGORY_TYPE_LIVE_ROOM) + .setStatus(CategoryConstants.CATEGORY_STATUS_NORMAL) + ); + + List response = categories.stream() + .map(this::toCategoryResponse) + .collect(Collectors.toList()); + + return CommonResult.success(response); + } + + @ApiOperation(value = "获取作品分类列表") + @GetMapping("/work") + public CommonResult> getWorkCategories() { + List categories = categoryService.getList( + new com.zbkj.common.request.CategorySearchRequest() + .setType(CategoryConstants.CATEGORY_TYPE_WORK) + .setStatus(CategoryConstants.CATEGORY_STATUS_NORMAL) + ); + + List response = categories.stream() + .map(this::toCategoryResponse) + .collect(Collectors.toList()); + + return CommonResult.success(response); + } + + @ApiOperation(value = "获取指定类型的分类列表") + @GetMapping("/list") + public CommonResult> getCategories( + @ApiParam(value = "分类类型: 1=商品,3=文章,8=直播间,9=作品", required = true) + @RequestParam Integer type) { + + List categories = categoryService.getList( + new com.zbkj.common.request.CategorySearchRequest() + .setType(type) + .setStatus(CategoryConstants.CATEGORY_STATUS_NORMAL) + ); + + List response = categories.stream() + .map(this::toCategoryResponse) + .collect(Collectors.toList()); + + return CommonResult.success(response); + } + + @ApiOperation(value = "获取分类详情") + @GetMapping("/{id}") + public CommonResult getCategoryById( + @ApiParam(value = "分类ID", required = true) + @PathVariable Integer id) { + + Category category = categoryService.getById(id); + if (category == null) { + return CommonResult.failed("分类不存在"); + } + + return CommonResult.success(toCategoryResponse(category)); + } + + /** + * 转换为响应对象 + */ + private CategoryResponse toCategoryResponse(Category category) { + CategoryResponse response = new CategoryResponse(); + response.setId(category.getId()); + response.setName(category.getName()); + response.setPid(category.getPid()); + response.setSort(category.getSort()); + response.setExtra(category.getExtra()); + return response; + } + + /** + * 分类响应对象 + */ + @io.swagger.annotations.ApiModel(value = "CategoryResponse", description = "分类响应") + public static class CategoryResponse { + @io.swagger.annotations.ApiModelProperty(value = "分类ID") + private Integer id; + + @io.swagger.annotations.ApiModelProperty(value = "分类名称") + private String name; + + @io.swagger.annotations.ApiModelProperty(value = "父级ID") + private Integer pid; + + @io.swagger.annotations.ApiModelProperty(value = "排序") + private Integer sort; + + @io.swagger.annotations.ApiModelProperty(value = "扩展字段") + private String extra; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getPid() { + return pid; + } + + public void setPid(Integer pid) { + this.pid = pid; + } + + public Integer getSort() { + return sort; + } + + public void setSort(Integer sort) { + this.sort = sort; + } + + public String getExtra() { + return extra; + } + + public void setExtra(String extra) { + this.extra = extra; + } + } +} diff --git a/Zhibo/zhibo-h/crmeb-front/src/main/java/com/zbkj/front/controller/LiveRoomController.java b/Zhibo/zhibo-h/crmeb-front/src/main/java/com/zbkj/front/controller/LiveRoomController.java index 24ddf995..f9c9b8a6 100644 --- a/Zhibo/zhibo-h/crmeb-front/src/main/java/com/zbkj/front/controller/LiveRoomController.java +++ b/Zhibo/zhibo-h/crmeb-front/src/main/java/com/zbkj/front/controller/LiveRoomController.java @@ -48,10 +48,22 @@ public class LiveRoomController { @ApiOperation(value = "公开:直播间列表(只返回直播中的房间)") @GetMapping("/public/rooms") - public CommonResult> publicRooms(HttpServletRequest request) { + public CommonResult> publicRooms( + @RequestParam(required = false) Integer categoryId, + HttpServletRequest request) { String requestHost = resolveHost(request); + + List rooms; + if (categoryId != null && categoryId > 0) { + // 按分类筛选 + rooms = liveRoomService.getByCategory(categoryId); + } else { + // 获取所有 + rooms = liveRoomService.getAll(); + } + // 只返回 is_live=1 的直播间 - return CommonResult.success(liveRoomService.getAll().stream() + return CommonResult.success(rooms.stream() .filter(r -> r.getIsLive() != null && r.getIsLive() == 1) .map(r -> toResponse(r, requestHost)) .collect(Collectors.toList())); @@ -71,7 +83,7 @@ public class LiveRoomController { public CommonResult create(@RequestBody @Validated CreateLiveRoomRequest req, HttpServletRequest request) { Integer uid = frontTokenComponent.getUserId(); if (uid == null) return CommonResult.failed("未登录"); - LiveRoom room = liveRoomService.createRoom(uid, req.getTitle(), req.getStreamerName()); + LiveRoom room = liveRoomService.createRoom(uid, req.getTitle(), req.getStreamerName(), req.getCategoryId()); return CommonResult.success(toResponse(room, resolveHost(request))); } @@ -166,6 +178,7 @@ public class LiveRoomController { resp.setId(room.getId() == null ? null : String.valueOf(room.getId())); resp.setTitle(room.getTitle()); resp.setStreamerName(room.getStreamerName()); + resp.setCategoryId(room.getCategoryId()); resp.setStreamKey(room.getStreamKey()); resp.setIsLive(room.getIsLive() != null && room.getIsLive() == 1); resp.setViewerCount(0); diff --git a/Zhibo/zhibo-h/crmeb-front/src/main/java/com/zbkj/front/request/live/CreateLiveRoomRequest.java b/Zhibo/zhibo-h/crmeb-front/src/main/java/com/zbkj/front/request/live/CreateLiveRoomRequest.java index 7ecdf414..e58f6c41 100644 --- a/Zhibo/zhibo-h/crmeb-front/src/main/java/com/zbkj/front/request/live/CreateLiveRoomRequest.java +++ b/Zhibo/zhibo-h/crmeb-front/src/main/java/com/zbkj/front/request/live/CreateLiveRoomRequest.java @@ -14,6 +14,9 @@ public class CreateLiveRoomRequest { @NotBlank private String title; + @ApiModelProperty(value = "分类ID") + private Integer categoryId; + @ApiModelProperty(value = "主播名称") @NotBlank private String streamerName; diff --git a/Zhibo/zhibo-h/crmeb-front/src/main/java/com/zbkj/front/response/live/LiveRoomResponse.java b/Zhibo/zhibo-h/crmeb-front/src/main/java/com/zbkj/front/response/live/LiveRoomResponse.java index 6ffa5c93..f2390454 100644 --- a/Zhibo/zhibo-h/crmeb-front/src/main/java/com/zbkj/front/response/live/LiveRoomResponse.java +++ b/Zhibo/zhibo-h/crmeb-front/src/main/java/com/zbkj/front/response/live/LiveRoomResponse.java @@ -14,6 +14,12 @@ public class LiveRoomResponse { @ApiModelProperty(value = "标题") private String title; + @ApiModelProperty(value = "分类ID") + private Integer categoryId; + + @ApiModelProperty(value = "分类名称") + private String categoryName; + @ApiModelProperty(value = "主播名") private String streamerName; diff --git a/Zhibo/zhibo-h/crmeb-service/src/main/java/com/zbkj/service/service/LiveRoomService.java b/Zhibo/zhibo-h/crmeb-service/src/main/java/com/zbkj/service/service/LiveRoomService.java index 7a36dc0c..cde771fd 100644 --- a/Zhibo/zhibo-h/crmeb-service/src/main/java/com/zbkj/service/service/LiveRoomService.java +++ b/Zhibo/zhibo-h/crmeb-service/src/main/java/com/zbkj/service/service/LiveRoomService.java @@ -9,7 +9,9 @@ public interface LiveRoomService extends IService { List getAll(); - LiveRoom createRoom(Integer uid, String title, String streamerName); + List getByCategory(Integer categoryId); + + LiveRoom createRoom(Integer uid, String title, String streamerName, Integer categoryId); boolean setLiveStatus(String streamKey, boolean isLive); } diff --git a/Zhibo/zhibo-h/crmeb-service/src/main/java/com/zbkj/service/service/impl/LiveRoomServiceImpl.java b/Zhibo/zhibo-h/crmeb-service/src/main/java/com/zbkj/service/service/impl/LiveRoomServiceImpl.java index c3b86587..3f433b14 100644 --- a/Zhibo/zhibo-h/crmeb-service/src/main/java/com/zbkj/service/service/impl/LiveRoomServiceImpl.java +++ b/Zhibo/zhibo-h/crmeb-service/src/main/java/com/zbkj/service/service/impl/LiveRoomServiceImpl.java @@ -27,12 +27,23 @@ public class LiveRoomServiceImpl extends ServiceImpl impl } @Override - public LiveRoom createRoom(Integer uid, String title, String streamerName) { + public List getByCategory(Integer categoryId) { + LambdaQueryWrapper qw = new LambdaQueryWrapper<>(); + if (categoryId != null && categoryId > 0) { + qw.eq(LiveRoom::getCategoryId, categoryId); + } + qw.orderByDesc(LiveRoom::getCreateTime); + return dao.selectList(qw); + } + + @Override + public LiveRoom createRoom(Integer uid, String title, String streamerName, Integer categoryId) { String streamKey = UUID.randomUUID().toString().replace("-", ""); LiveRoom room = new LiveRoom(); room.setUid(uid); room.setTitle(title); room.setStreamerName(streamerName); + room.setCategoryId(categoryId); room.setStreamKey(streamKey); room.setIsLive(0); room.setCreateTime(new Date()); diff --git a/Zhibo/zhibo-h/pom.xml b/Zhibo/zhibo-h/pom.xml index 7bb7b86b..63924abf 100644 --- a/Zhibo/zhibo-h/pom.xml +++ b/Zhibo/zhibo-h/pom.xml @@ -318,6 +318,20 @@ 0.9.0 + + + org.springframework.boot + spring-boot-starter-data-jpa + 2.2.6.RELEASE + + + + + org.hibernate.validator + hibernate-validator + 6.1.5.Final + + diff --git a/Zhibo/zhibo-h/分类管理模块使用说明.md b/Zhibo/zhibo-h/分类管理模块使用说明.md new file mode 100644 index 00000000..224d1959 --- /dev/null +++ b/Zhibo/zhibo-h/分类管理模块使用说明.md @@ -0,0 +1,461 @@ +# 分类管理模块使用说明 + +## 📋 功能概述 + +分类管理模块为直播间和作品提供了分类功能,支持: +- ✅ 直播间分类管理 +- ✅ 作品分类管理(预留) +- ✅ 分类列表查询 +- ✅ 按分类筛选直播间 +- ✅ 后台分类管理(复用现有管理功能) + +## 🗄️ 数据库更新 + +### 1. 执行SQL脚本 + +运行 `sql/category_module_update.sql` 文件: + +```bash +mysql -u root -p your_database < sql/category_module_update.sql +``` + +该脚本会: +- 为 `eb_live_room` 表添加 `category_id` 字段 +- 插入默认的直播间分类数据(娱乐、游戏、音乐等) +- 插入默认的作品分类数据(摄影、绘画、设计等) + +### 2. 分类类型说明 + +| type | 说明 | +|------|------| +| 1 | 商品分类 | +| 2 | 附件分类 | +| 3 | 文章分类 | +| 4 | 设置分类 | +| 5 | 菜单分类 | +| 6 | 配置分类 | +| 7 | 秒杀配置 | +| **8** | **直播间分类(新增)** | +| **9** | **作品分类(新增)** | + +## 📡 API接口 + +### 前端接口 + +#### 1. 获取直播间分类列表 + +```http +GET /api/front/category/live-room +``` + +**响应示例:** +```json +{ + "code": 200, + "message": "success", + "data": [ + { + "id": 1, + "name": "娱乐", + "pid": 0, + "sort": 100, + "extra": "" + }, + { + "id": 2, + "name": "游戏", + "pid": 0, + "sort": 90, + "extra": "" + } + ] +} +``` + +#### 2. 获取作品分类列表 + +```http +GET /api/front/category/work +``` + +**响应示例:** +```json +{ + "code": 200, + "message": "success", + "data": [ + { + "id": 10, + "name": "摄影", + "pid": 0, + "sort": 100, + "extra": "" + }, + { + "id": 11, + "name": "绘画", + "pid": 0, + "sort": 90, + "extra": "" + } + ] +} +``` + +#### 3. 获取指定类型的分类列表 + +```http +GET /api/front/category/list?type=8 +``` + +**参数说明:** +- `type`: 分类类型(8=直播间,9=作品) + +#### 4. 获取分类详情 + +```http +GET /api/front/category/{id} +``` + +#### 5. 按分类筛选直播间 + +```http +GET /api/front/live/public/rooms?categoryId=1 +``` + +**参数说明:** +- `categoryId`: 分类ID(可选,不传则返回所有直播间) + +**响应示例:** +```json +{ + "code": 200, + "message": "success", + "data": [ + { + "id": "1", + "title": "精彩直播", + "streamerName": "主播A", + "categoryId": 1, + "categoryName": null, + "streamKey": "abc123", + "isLive": true, + "viewerCount": 0, + "streamUrls": { + "rtmp": "rtmp://localhost:25002/live/abc123", + "flv": "http://localhost:25003/live/abc123.flv", + "hls": "http://localhost:25003/live/abc123.m3u8" + } + } + ] +} +``` + +#### 6. 创建直播间(带分类) + +```http +POST /api/front/live/rooms +Authorization: Bearer {token} +Content-Type: application/json + +{ + "title": "我的直播间", + "streamerName": "主播名称", + "categoryId": 1 +} +``` + +### 后台管理接口 + +后台分类管理复用现有的 `/api/admin/category` 接口: + +#### 1. 获取分类列表 + +```http +GET /api/admin/category/list?type=8&status=1 +``` + +#### 2. 获取树形结构分类 + +```http +GET /api/admin/category/list/tree?type=8&status=1 +``` + +#### 3. 新增分类 + +```http +POST /api/admin/category/save +Content-Type: application/json + +{ + "name": "新分类", + "type": 8, + "pid": 0, + "sort": 100, + "status": true +} +``` + +#### 4. 修改分类 + +```http +POST /api/admin/category/update?id=1 +Content-Type: application/json + +{ + "name": "修改后的分类名", + "sort": 90 +} +``` + +#### 5. 删除分类 + +```http +GET /api/admin/category/delete?id=1 +``` + +#### 6. 更改分类状态 + +```http +GET /api/admin/category/updateStatus/1 +``` + +## 🔧 代码集成 + +### Android端集成示例 + +#### 1. 定义API接口 + +```java +public interface CategoryApi { + @GET("api/front/category/live-room") + Call>> getLiveRoomCategories(); + + @GET("api/front/category/work") + Call>> getWorkCategories(); + + @GET("api/front/live/public/rooms") + Call>> getRoomsByCategory( + @Query("categoryId") Integer categoryId + ); +} +``` + +#### 2. 分类数据模型 + +```java +public class Category { + private Integer id; + private String name; + private Integer pid; + private Integer sort; + private String extra; + + // getters and setters +} +``` + +#### 3. 使用示例 + +```java +// 获取直播间分类列表 +categoryApi.getLiveRoomCategories().enqueue(new Callback>>() { + @Override + public void onResponse(Call>> call, + Response>> response) { + if (response.isSuccessful() && response.body() != null) { + List categories = response.body().getData(); + // 更新UI显示分类列表 + updateCategoryList(categories); + } + } + + @Override + public void onFailure(Call>> call, Throwable t) { + // 处理错误 + } +}); + +// 按分类筛选直播间 +categoryApi.getRoomsByCategory(categoryId).enqueue(new Callback>>() { + @Override + public void onResponse(Call>> call, + Response>> response) { + if (response.isSuccessful() && response.body() != null) { + List rooms = response.body().getData(); + // 更新直播间列表 + updateRoomList(rooms); + } + } + + @Override + public void onFailure(Call>> call, Throwable t) { + // 处理错误 + } +}); +``` + +## 📱 Android端UI实现建议 + +### 1. 分类筛选器 + +```xml + + + + + + + + + +``` + +### 2. 分类筛选逻辑 + +```java +public class RoomListActivity extends AppCompatActivity { + + private ChipGroup categoryChipGroup; + private Integer selectedCategoryId = null; + + private void setupCategoryFilter() { + // 加载分类列表 + loadCategories(); + + // 监听分类选择 + categoryChipGroup.setOnCheckedChangeListener((group, checkedId) -> { + if (checkedId == View.NO_ID) { + // 未选择任何分类,显示全部 + selectedCategoryId = null; + } else { + Chip chip = findViewById(checkedId); + selectedCategoryId = (Integer) chip.getTag(); + } + // 重新加载直播间列表 + loadRooms(selectedCategoryId); + }); + } + + private void loadCategories() { + categoryApi.getLiveRoomCategories().enqueue(new Callback>>() { + @Override + public void onResponse(Call>> call, + Response>> response) { + if (response.isSuccessful() && response.body() != null) { + List categories = response.body().getData(); + + // 添加"全部"选项 + Chip allChip = new Chip(RoomListActivity.this); + allChip.setText("全部"); + allChip.setCheckable(true); + allChip.setChecked(true); + categoryChipGroup.addView(allChip); + + // 添加分类选项 + for (Category category : categories) { + Chip chip = new Chip(RoomListActivity.this); + chip.setText(category.getName()); + chip.setTag(category.getId()); + chip.setCheckable(true); + categoryChipGroup.addView(chip); + } + } + } + + @Override + public void onFailure(Call>> call, Throwable t) { + Toast.makeText(RoomListActivity.this, "加载分类失败", Toast.LENGTH_SHORT).show(); + } + }); + } + + private void loadRooms(Integer categoryId) { + categoryApi.getRoomsByCategory(categoryId).enqueue(new Callback>>() { + @Override + public void onResponse(Call>> call, + Response>> response) { + if (response.isSuccessful() && response.body() != null) { + List rooms = response.body().getData(); + roomAdapter.submitList(rooms); + } + } + + @Override + public void onFailure(Call>> call, Throwable t) { + Toast.makeText(RoomListActivity.this, "加载直播间失败", Toast.LENGTH_SHORT).show(); + } + }); + } +} +``` + +## 🎯 功能特点 + +### 1. 灵活的分类管理 +- 支持多级分类(通过pid字段) +- 支持分类排序(sort字段) +- 支持分类启用/禁用(status字段) +- 支持分类扩展字段(extra字段,可存储图标URL等) + +### 2. 高效的查询 +- 为category_id字段添加了索引 +- 支持按分类快速筛选 + +### 3. 易于扩展 +- 可以轻松添加新的分类类型 +- 可以为作品、商品等其他实体添加分类 + +## 📝 注意事项 + +1. **数据库迁移**:确保在生产环境执行SQL脚本前做好数据备份 +2. **分类ID**:创建直播间时categoryId可以为null,表示未分类 +3. **权限控制**:后台分类管理接口需要管理员权限 +4. **缓存策略**:建议对分类列表进行缓存,减少数据库查询 + +## 🔄 后续扩展 + +### 1. 作品分类功能 + +当需要为作品添加分类时,只需: +1. 为作品表添加category_id字段 +2. 创建作品时传入categoryId +3. 使用 `/api/front/category/work` 获取作品分类列表 + +### 2. 分类统计 + +可以添加统计功能,显示每个分类下的直播间数量: + +```sql +SELECT c.id, c.name, COUNT(lr.id) as room_count +FROM eb_category c +LEFT JOIN eb_live_room lr ON c.id = lr.category_id +WHERE c.type = 8 AND c.status = 1 +GROUP BY c.id, c.name +ORDER BY c.sort DESC; +``` + +### 3. 热门分类 + +可以根据直播间观看量、点赞数等指标计算热门分类。 + +## 📞 技术支持 + +如有问题,请查看: +- 项目文档:`直播IM系统开发指南.md` +- 后端接口清单:`后端接口TODO清单-总览.md` + +--- + +**版本:** v1.0 +**更新日期:** 2025-12-25 +**开发者:** CRMEB Team diff --git a/Zhibo/zhibo-h/分类管理模块开发总结.md b/Zhibo/zhibo-h/分类管理模块开发总结.md new file mode 100644 index 00000000..a1caec22 --- /dev/null +++ b/Zhibo/zhibo-h/分类管理模块开发总结.md @@ -0,0 +1,332 @@ +# 分类管理模块开发总结 + +## ✅ 已完成功能 + +### 1. 数据库层面 +- ✅ 为 `eb_live_room` 表添加 `category_id` 字段 +- ✅ 添加索引优化查询性能 +- ✅ 插入默认的直播间分类数据(9个分类) +- ✅ 插入默认的作品分类数据(8个分类) +- ✅ 定义分类类型常量(type=8为直播间,type=9为作品) + +### 2. 后端代码 +- ✅ 更新 `CategoryConstants` 类,添加直播间和作品分类类型常量 +- ✅ 创建前端分类控制器 `CategoryController` +- ✅ 实现获取直播间分类列表接口 +- ✅ 实现获取作品分类列表接口 +- ✅ 实现获取指定类型分类列表接口 +- ✅ 实现获取分类详情接口 +- ✅ 更新 `LiveRoom` 模型,添加 `categoryId` 字段 +- ✅ 更新 `CreateLiveRoomRequest`,支持传入分类ID +- ✅ 更新 `LiveRoomResponse`,返回分类信息 +- ✅ 更新 `LiveRoomService` 接口,添加按分类查询方法 +- ✅ 更新 `LiveRoomServiceImpl` 实现,支持分类筛选 +- ✅ 更新 `LiveRoomController`,支持按分类筛选直播间 + +### 3. API接口 + +#### 前端接口 +| 接口 | 方法 | 说明 | +|------|------|------| +| `/api/front/category/live-room` | GET | 获取直播间分类列表 | +| `/api/front/category/work` | GET | 获取作品分类列表 | +| `/api/front/category/list?type={type}` | GET | 获取指定类型的分类列表 | +| `/api/front/category/{id}` | GET | 获取分类详情 | +| `/api/front/live/public/rooms?categoryId={id}` | GET | 按分类筛选直播间 | +| `/api/front/live/rooms` | POST | 创建直播间(支持分类) | + +#### 后台管理接口(复用现有) +| 接口 | 方法 | 说明 | +|------|------|------| +| `/api/admin/category/list` | GET | 分类列表 | +| `/api/admin/category/list/tree` | GET | 树形结构分类 | +| `/api/admin/category/save` | POST | 新增分类 | +| `/api/admin/category/update` | POST | 修改分类 | +| `/api/admin/category/delete` | GET | 删除分类 | +| `/api/admin/category/updateStatus/{id}` | GET | 更改分类状态 | + +### 4. 文档和测试 +- ✅ 创建 SQL 更新脚本 `category_module_update.sql` +- ✅ 创建详细的使用说明文档 `分类管理模块使用说明.md` +- ✅ 创建 API 测试脚本 `test_category_api.bat` (Windows) +- ✅ 创建 API 测试脚本 `test_category_api.sh` (Linux/Mac) +- ✅ 创建开发总结文档 `分类管理模块开发总结.md` + +## 📁 文件清单 + +### 新增文件 +``` +Zhibo/zhibo-h/ +├── sql/ +│ └── category_module_update.sql # 数据库更新脚本 +├── crmeb-common/src/main/java/com/zbkj/common/ +│ └── constants/ +│ └── CategoryConstants.java # 分类常量类(更新) +├── crmeb-front/src/main/java/com/zbkj/front/ +│ └── controller/ +│ └── CategoryController.java # 前端分类控制器(新增) +├── 分类管理模块使用说明.md # 使用说明文档 +├── 分类管理模块开发总结.md # 开发总结文档 +├── test_category_api.bat # Windows测试脚本 +└── test_category_api.sh # Linux/Mac测试脚本 +``` + +### 修改文件 +``` +Zhibo/zhibo-h/ +├── crmeb-common/src/main/java/com/zbkj/common/ +│ └── model/live/ +│ └── LiveRoom.java # 添加categoryId字段 +├── crmeb-front/src/main/java/com/zbkj/front/ +│ ├── request/live/ +│ │ └── CreateLiveRoomRequest.java # 添加categoryId字段 +│ ├── response/live/ +│ │ └── LiveRoomResponse.java # 添加categoryId和categoryName字段 +│ └── controller/ +│ └── LiveRoomController.java # 支持分类筛选 +└── crmeb-service/src/main/java/com/zbkj/service/ + ├── service/ + │ └── LiveRoomService.java # 添加按分类查询方法 + └── service/impl/ + └── LiveRoomServiceImpl.java # 实现分类筛选逻辑 +``` + +## 🎯 核心功能实现 + +### 1. 分类数据结构 + +```sql +-- 分类表结构(复用现有表) +CREATE TABLE `eb_category` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `pid` int(11) DEFAULT '0' COMMENT '父级ID', + `path` varchar(255) DEFAULT '/0/' COMMENT '路径', + `name` varchar(50) NOT NULL COMMENT '分类名称', + `type` int(11) NOT NULL COMMENT '类型:8=直播间,9=作品', + `url` varchar(255) DEFAULT '' COMMENT '地址', + `extra` varchar(500) DEFAULT '' COMMENT '扩展字段', + `status` tinyint(1) DEFAULT '1' COMMENT '状态:1=正常,0=失效', + `sort` int(11) DEFAULT '0' COMMENT '排序', + `create_time` datetime DEFAULT CURRENT_TIMESTAMP, + `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`) +); + +-- 直播间表添加分类字段 +ALTER TABLE `eb_live_room` ADD COLUMN `category_id` INT(11) DEFAULT NULL; +ALTER TABLE `eb_live_room` ADD INDEX `idx_category_id` (`category_id`); +``` + +### 2. 默认分类数据 + +#### 直播间分类(type=8) +1. 娱乐 (sort=100) +2. 游戏 (sort=90) +3. 音乐 (sort=80) +4. 美食 (sort=70) +5. 户外 (sort=60) +6. 运动 (sort=50) +7. 教育 (sort=40) +8. 科技 (sort=30) +9. 其他 (sort=10) + +#### 作品分类(type=9) +1. 摄影 (sort=100) +2. 绘画 (sort=90) +3. 设计 (sort=80) +4. 手工 (sort=70) +5. 音乐 (sort=60) +6. 舞蹈 (sort=50) +7. 文学 (sort=40) +8. 其他 (sort=10) + +### 3. 关键代码实现 + +#### 前端分类控制器 +```java +@RestController +@RequestMapping("api/front/category") +public class CategoryController { + + @GetMapping("/live-room") + public CommonResult> getLiveRoomCategories() { + // 获取type=8的分类 + } + + @GetMapping("/work") + public CommonResult> getWorkCategories() { + // 获取type=9的分类 + } +} +``` + +#### 直播间分类筛选 +```java +@GetMapping("/public/rooms") +public CommonResult> publicRooms( + @RequestParam(required = false) Integer categoryId, + HttpServletRequest request) { + + List rooms; + if (categoryId != null && categoryId > 0) { + rooms = liveRoomService.getByCategory(categoryId); + } else { + rooms = liveRoomService.getAll(); + } + // 返回直播中的房间 +} +``` + +## 📊 技术特点 + +### 1. 复用现有架构 +- 复用现有的 `eb_category` 表,避免创建新表 +- 复用后台分类管理功能,无需重复开发 +- 使用统一的分类服务 `CategoryService` + +### 2. 灵活扩展 +- 通过 `type` 字段区分不同类型的分类 +- 支持多级分类(通过 `pid` 和 `path` 字段) +- 支持分类排序和启用/禁用 + +### 3. 性能优化 +- 为 `category_id` 添加索引 +- 分类列表建议客户端缓存 +- 支持按分类快速筛选 + +### 4. 易于维护 +- 清晰的代码结构 +- 完整的文档说明 +- 提供测试脚本 + +## 🚀 部署步骤 + +### 1. 数据库更新 +```bash +# 执行SQL脚本 +mysql -u root -p your_database < sql/category_module_update.sql +``` + +### 2. 编译项目 +```bash +cd Zhibo/zhibo-h +mvn clean package -DskipTests +``` + +### 3. 重启服务 +```bash +# 停止现有服务 +# 启动新服务 +java -jar crmeb-admin/target/crmeb-admin.jar +``` + +### 4. 测试接口 +```bash +# Windows +test_category_api.bat + +# Linux/Mac +bash test_category_api.sh +``` + +## 📱 Android端集成建议 + +### 1. 添加分类筛选UI +- 使用 `ChipGroup` 显示分类标签 +- 支持单选分类 +- 添加"全部"选项 + +### 2. 实现分类筛选逻辑 +```java +// 1. 加载分类列表 +categoryApi.getLiveRoomCategories() + +// 2. 监听分类选择 +chipGroup.setOnCheckedChangeListener() + +// 3. 按分类加载直播间 +categoryApi.getRoomsByCategory(categoryId) +``` + +### 3. 创建直播间时选择分类 +```java +CreateLiveRoomRequest request = new CreateLiveRoomRequest(); +request.setTitle("直播间标题"); +request.setStreamerName("主播名称"); +request.setCategoryId(selectedCategoryId); // 选中的分类ID +``` + +## 🔄 后续扩展建议 + +### 1. 作品分类功能 +当需要为作品添加分类时: +1. 为作品表添加 `category_id` 字段 +2. 创建作品时传入 `categoryId` +3. 使用 `/api/front/category/work` 获取作品分类 + +### 2. 分类统计 +添加统计功能,显示每个分类下的内容数量: +```sql +SELECT c.id, c.name, COUNT(lr.id) as count +FROM eb_category c +LEFT JOIN eb_live_room lr ON c.id = lr.category_id +WHERE c.type = 8 AND c.status = 1 +GROUP BY c.id, c.name; +``` + +### 3. 热门分类 +根据观看量、点赞数等指标计算热门分类。 + +### 4. 分类图标 +利用 `extra` 字段存储分类图标URL: +```json +{ + "icon": "https://example.com/icons/game.png" +} +``` + +### 5. 多级分类 +支持二级分类,例如: +- 游戏(一级) + - 手游(二级) + - 端游(二级) + - 主机游戏(二级) + +## ⚠️ 注意事项 + +1. **数据库备份**:执行SQL脚本前务必备份数据库 +2. **分类ID可选**:创建直播间时 `categoryId` 可以为 null +3. **权限控制**:后台分类管理需要管理员权限 +4. **缓存策略**:建议客户端缓存分类列表 +5. **兼容性**:现有直播间的 `category_id` 为 null,不影响正常使用 + +## 📈 预期效果 + +### 1. 用户体验提升 +- 用户可以快速找到感兴趣的直播间 +- 分类筛选提高内容发现效率 +- 清晰的分类结构便于浏览 + +### 2. 运营管理优化 +- 后台可以灵活管理分类 +- 支持分类数据统计分析 +- 便于内容运营和推荐 + +### 3. 系统扩展性 +- 易于添加新的分类类型 +- 支持多级分类结构 +- 为后续功能预留扩展空间 + +## 📞 技术支持 + +如有问题,请查看: +- 使用说明:`分类管理模块使用说明.md` +- 项目文档:`直播IM系统开发指南.md` +- 接口清单:`后端接口TODO清单-总览.md` + +--- + +**开发完成时间:** 2025-12-25 +**开发者:** CRMEB Team +**版本:** v1.0 +**状态:** ✅ 已完成,可投入使用 diff --git a/直播IM系统开发指南.md b/直播IM系统开发指南.md index 9a665bd1..38a618a1 100644 --- a/直播IM系统开发指南.md +++ b/直播IM系统开发指南.md @@ -1404,10 +1404,10 @@ server { - 充值功能 ✅ - **缺失**: 支付宝支付 ❌ -- **内容管理**: 35% ⚠️ +- **内容管理**: 45% ⚠️ - 多媒体上传 ✅ - 作品管理 ❌ - - 分类管理 ⚠️ (商品分类已实现) + - 分类管理 ✅ (商品分类、直播间分类、作品分类已实现) - 搜索功能 ⚠️ (用户搜索已实现) - **安全防护**: 20% ❌