Resolve stash conflicts: merge local changes with IM-gift branch

This commit is contained in:
cxytw 2026-01-04 19:24:42 +08:00
parent d234b91836
commit 86c37cd688
23 changed files with 983 additions and 327 deletions

View File

@ -1,53 +1,69 @@
import request from '@/utils/request'
import request from '@/utils/request';
// 房间拉黑列表
export function roomBlacklistListApi(params) {
return request({
url: '/admin/blacklist/room/list',
method: 'get',
params
})
}
// ==================== 用户黑名单(用户间拉黑) ====================
// 删除房间拉黑记录
export function roomBlacklistDeleteApi(id) {
return request({
url: `/admin/blacklist/room/delete/${id}`,
method: 'post'
})
}
// 批量删除房间拉黑记录
export function roomBlacklistBatchDeleteApi(ids) {
return request({
url: '/admin/blacklist/room/batch-delete',
method: 'post',
data: { ids }
})
}
// 用户拉黑列表
/**
* 获取用户黑名单列表
*/
export function userBlacklistListApi(params) {
return request({
url: '/admin/blacklist/user/list',
method: 'get',
params
})
});
}
// 删除用户拉黑记录
/**
* 删除用户黑名单记录
*/
export function userBlacklistDeleteApi(id) {
return request({
url: `/admin/blacklist/user/delete/${id}`,
method: 'post'
})
});
}
// 批量删除用户拉黑记录
/**
* 批量删除用户黑名单记录
*/
export function userBlacklistBatchDeleteApi(ids) {
return request({
url: '/admin/blacklist/user/batch-delete',
method: 'post',
data: { ids }
})
data: ids
});
}
// ==================== 房间黑名单(直播间对用户的拉黑) ====================
/**
* 获取房间黑名单列表
*/
export function roomBlacklistListApi(params) {
return request({
url: '/admin/blacklist/room/list',
method: 'get',
params
});
}
/**
* 删除房间黑名单记录
*/
export function roomBlacklistDeleteApi(id) {
return request({
url: `/admin/blacklist/room/delete/${id}`,
method: 'post'
});
}
/**
* 批量删除房间黑名单记录
*/
export function roomBlacklistBatchDeleteApi(ids) {
return request({
url: '/admin/blacklist/room/batch-delete',
method: 'post',
data: ids
});
}

View File

@ -10,7 +10,7 @@ import request from '@/utils/request';
*/
export function getFollowRecords(params) {
return request({
url: '/admin/user/follow/records',
url: '/admin/user/activity/follow',
method: 'get',
params
});
@ -22,7 +22,7 @@ export function getFollowRecords(params) {
*/
export function getLikeRecords(params) {
return request({
url: '/admin/user/like/records',
url: '/admin/user/activity/like',
method: 'get',
params
});
@ -34,7 +34,7 @@ export function getLikeRecords(params) {
*/
export function getViewHistory(params) {
return request({
url: '/admin/user/view/history',
url: '/admin/user/activity/view',
method: 'get',
params
});
@ -46,7 +46,7 @@ export function getViewHistory(params) {
*/
export function getCollectedWorks(params) {
return request({
url: '/admin/user/collect/works',
url: '/admin/user/activity/collect',
method: 'get',
params
});

View File

@ -75,6 +75,19 @@ const socialManageRouter = {
name: 'GroupList',
meta: { title: '群组管理', icon: '' },
},
// 拉黑管理
{
path: 'blacklist/user',
component: () => import('@/views/blacklist/user'),
name: 'BlacklistUserSocial',
meta: { title: '用户拉黑', icon: '' },
},
{
path: 'blacklist/room',
component: () => import('@/views/blacklist/room'),
name: 'BlacklistRoomSocial',
meta: { title: '房间拉黑', icon: '' },
},
],
};

View File

@ -88,6 +88,19 @@ const userManageRouter = {
name: 'BlacklistUser',
meta: { title: '用户拉黑', icon: '' },
},
// 封禁管理
{
path: 'ban/user',
component: () => import('@/views/ban/userBan'),
name: 'UserBan',
meta: { title: '用户封禁', icon: '' },
},
{
path: 'ban/room',
component: () => import('@/views/ban/roomBan'),
name: 'RoomBan',
meta: { title: '房间封禁', icon: '' },
},
],
};

View File

@ -713,6 +713,19 @@ export default {
::v-deep .el-tabs__nav .el-tabs__item:nth-of-type(1) {
padding-left: 20px !important;
}
::v-deep .el-tabs__nav-wrap {
overflow: visible !important;
}
::v-deep .el-tabs__nav-scroll {
overflow-x: auto !important;
}
::v-deep .el-tabs__nav {
white-space: nowrap !important;
}
::v-deep .el-tabs--border-card > .el-tabs__header .el-tabs__item {
padding: 0 15px !important;
font-size: 13px !important;
}
.block {
padding: 0 35px;
}

View File

@ -117,4 +117,28 @@ public class BlacklistController {
int rows = jdbcTemplate.update(sql, id);
return rows > 0 ? CommonResult.success("删除成功") : CommonResult.failed("删除失败");
}
@ApiOperation(value = "批量删除用户拉黑记录")
@RequestMapping(value = "/user/batch-delete", method = RequestMethod.POST)
public CommonResult<String> batchDeleteUserBlacklist(@RequestBody java.util.List<Integer> ids) {
if (ids == null || ids.isEmpty()) {
return CommonResult.failed("请选择要删除的记录");
}
String placeholders = String.join(",", java.util.Collections.nCopies(ids.size(), "?"));
String sql = "DELETE FROM eb_user_blacklist WHERE id IN (" + placeholders + ")";
int rows = jdbcTemplate.update(sql, ids.toArray());
return rows > 0 ? CommonResult.success("批量删除成功") : CommonResult.failed("删除失败");
}
@ApiOperation(value = "批量删除房间拉黑记录")
@RequestMapping(value = "/room/batch-delete", method = RequestMethod.POST)
public CommonResult<String> batchDeleteRoomBlacklist(@RequestBody java.util.List<Integer> ids) {
if (ids == null || ids.isEmpty()) {
return CommonResult.failed("请选择要删除的记录");
}
String placeholders = String.join(",", java.util.Collections.nCopies(ids.size(), "?"));
String sql = "DELETE FROM eb_room_blacklist WHERE id IN (" + placeholders + ")";
int rows = jdbcTemplate.update(sql, ids.toArray());
return rows > 0 ? CommonResult.success("批量删除成功") : CommonResult.failed("删除失败");
}
}

View File

@ -8,12 +8,9 @@ import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
@ -22,14 +19,11 @@ import java.util.Map;
*/
@Slf4j
@RestController
@RequestMapping("api/admin/user")
@RequestMapping("api/admin/user/activity")
@Api(tags = "用户活动记录")
@Validated
public class UserActivityController {
@Autowired
private JdbcTemplate jdbcTemplate;
@Autowired
private UserActivityRecordService userActivityRecordService;
@ -37,13 +31,15 @@ public class UserActivityController {
* 获取用户的关注记录
*/
@ApiOperation(value = "获取用户关注记录")
@GetMapping("/follow/records")
@GetMapping("/follow")
public CommonResult<CommonPage<Map<String, Object>>> getFollowRecords(
@RequestParam Integer userId,
@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer limit) {
try {
log.info("获取用户关注记录: userId={}, page={}, limit={}", userId, page, limit);
CommonPage<Map<String, Object>> result = userActivityRecordService.getFollowRecords(userId, page, limit);
log.info("关注记录结果: total={}, listSize={}", result.getTotal(), result.getList().size());
return CommonResult.success(result);
} catch (Exception e) {
log.error("获取用户关注记录失败: userId={}", userId, e);
@ -55,7 +51,7 @@ public class UserActivityController {
* 获取用户的点赞记录
*/
@ApiOperation(value = "获取用户点赞记录")
@GetMapping("/like/records")
@GetMapping("/like")
public CommonResult<CommonPage<Map<String, Object>>> getLikeRecords(
@RequestParam Integer userId,
@ApiParam(value = "目标类型room-直播间, work-作品, wish-心愿")
@ -63,7 +59,9 @@ public class UserActivityController {
@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer limit) {
try {
log.info("获取用户点赞记录: userId={}, targetType={}, page={}, limit={}", userId, targetType, page, limit);
CommonPage<Map<String, Object>> result = userActivityRecordService.getLikeRecords(userId, targetType, page, limit);
log.info("点赞记录结果: total={}, listSize={}", result.getTotal(), result.getList().size());
return CommonResult.success(result);
} catch (Exception e) {
log.error("获取用户点赞记录失败: userId={}", userId, e);
@ -75,7 +73,7 @@ public class UserActivityController {
* 获取用户的查看历史
*/
@ApiOperation(value = "获取用户查看历史")
@GetMapping("/view/history")
@GetMapping("/view")
public CommonResult<CommonPage<Map<String, Object>>> getViewHistory(
@RequestParam Integer userId,
@ApiParam(value = "目标类型room-直播间, work-作品, profile-用户主页")
@ -83,7 +81,9 @@ public class UserActivityController {
@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer limit) {
try {
log.info("获取用户查看历史: userId={}, targetType={}, page={}, limit={}", userId, targetType, page, limit);
CommonPage<Map<String, Object>> result = userActivityRecordService.getViewHistory(userId, targetType, page, limit);
log.info("查看历史结果: total={}, listSize={}", result.getTotal(), result.getList().size());
return CommonResult.success(result);
} catch (Exception e) {
log.error("获取用户查看历史失败: userId={}", userId, e);
@ -95,13 +95,15 @@ public class UserActivityController {
* 获取用户收藏的作品
*/
@ApiOperation(value = "获取用户收藏的作品")
@GetMapping("/collect/works")
@GetMapping("/collect")
public CommonResult<CommonPage<Map<String, Object>>> getCollectedWorks(
@RequestParam Integer userId,
@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer limit) {
try {
log.info("获取用户收藏作品: userId={}, page={}, limit={}", userId, page, limit);
CommonPage<Map<String, Object>> result = userActivityRecordService.getCollectedWorks(userId, page, limit);
log.info("收藏作品结果: total={}, listSize={}", result.getTotal(), result.getList().size());
return CommonResult.success(result);
} catch (Exception e) {
log.error("获取用户收藏作品失败: userId={}", userId, e);
@ -113,7 +115,7 @@ public class UserActivityController {
* 获取用户活动统计
*/
@ApiOperation(value = "获取用户活动统计")
@GetMapping("/activity/stats")
@GetMapping("/stats")
public CommonResult<Map<String, Object>> getUserActivityStats(@RequestParam Integer userId) {
try {
Map<String, Object> stats = userActivityRecordService.getUserActivityStats(userId);

View File

@ -158,11 +158,24 @@ public class FrontTokenComponent {
public Integer getUserId() {
HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
String token = getToken(request);
String rawToken = request.getHeader(Constants.HEADER_AUTHORIZATION_KEY);
if (StrUtil.isEmpty(token)) {
System.out.println("[FrontTokenComponent] getUserId: token为空, rawToken=" + rawToken);
return null;
// throw new CrmebException("登录信息已过期,请重新登录!");
}
return redisUtil.get(getTokenKey(token));
String redisKey = getTokenKey(token);
Integer userId = redisUtil.get(redisKey);
boolean exists = redisUtil.exists(redisKey);
System.out.println("[FrontTokenComponent] getUserId: rawToken=" + (rawToken != null ? rawToken.substring(0, Math.min(20, rawToken.length())) + "..." : "null")
+ ", processedToken=" + token.substring(0, Math.min(20, token.length())) + "..."
+ ", redisKey=" + redisKey
+ ", exists=" + exists
+ ", userId=" + userId);
return userId;
}
//路由在此处则返回true无论用户是否登录都可以访问

View File

@ -75,15 +75,32 @@ public class UserActivityRecordController {
@ApiParam(value = "目标类型room-直播间, work-作品, profile-用户主页")
@RequestParam(required = false) String targetType,
@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "20") Integer pageSize) {
@RequestParam(defaultValue = "20") Integer pageSize,
javax.servlet.http.HttpServletRequest request) {
// 调试打印请求头中的Token
String authToken = request.getHeader("Authori-zation");
String authToken2 = request.getHeader("Authorization");
log.info("【观看历史API】请求头: Authori-zation={}, Authorization={}",
authToken != null ? authToken.substring(0, Math.min(20, authToken.length())) + "..." : "null",
authToken2 != null ? authToken2.substring(0, Math.min(20, authToken2.length())) + "..." : "null");
Integer userId = userService.getUserId();
if (userId == null) {
log.info("【观看历史API】参数: userId={}, targetType={}, page={}, pageSize={}", userId, targetType, page, pageSize);
if (userId == null || userId == 0) {
log.warn("【观看历史API】用户未登录: userId={}, Token={}", userId, authToken);
return CommonResult.failed("请先登录");
}
CommonPage<Map<String, Object>> result = userActivityRecordService.getViewHistory(userId, targetType, page, pageSize);
return CommonResult.success(result);
try {
CommonPage<Map<String, Object>> result = userActivityRecordService.getViewHistory(userId, targetType, page, pageSize);
log.info("【观看历史API】成功: userId={}, total={}, listSize={}", userId, result.getTotal(), result.getList().size());
return CommonResult.success(result);
} catch (Exception e) {
log.error("【观看历史API】异常: userId={}", userId, e);
return CommonResult.failed("获取观看历史失败: " + e.getMessage());
}
}
/**
@ -130,15 +147,28 @@ public class UserActivityRecordController {
@ApiParam(value = "目标类型room-直播间, work-作品, wish-心愿,不传则获取全部")
@RequestParam(required = false) String targetType,
@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "20") Integer pageSize) {
@RequestParam(defaultValue = "20") Integer pageSize,
javax.servlet.http.HttpServletRequest request) {
String authToken = request.getHeader("Authori-zation");
log.info("【点赞记录API】请求头: {}", authToken != null ? authToken.substring(0, Math.min(20, authToken.length())) + "..." : "null");
Integer userId = userService.getUserId();
if (userId == null) {
log.info("【点赞记录API】参数: userId={}, targetType={}, page={}, pageSize={}", userId, targetType, page, pageSize);
if (userId == null || userId == 0) {
log.warn("【点赞记录API】用户未登录: userId={}", userId);
return CommonResult.failed("请先登录");
}
CommonPage<Map<String, Object>> result = userActivityRecordService.getLikeRecords(userId, targetType, page, pageSize);
return CommonResult.success(result);
try {
CommonPage<Map<String, Object>> result = userActivityRecordService.getLikeRecords(userId, targetType, page, pageSize);
log.info("【点赞记录API】成功: userId={}, total={}, listSize={}", userId, result.getTotal(), result.getList().size());
return CommonResult.success(result);
} catch (Exception e) {
log.error("【点赞记录API】异常: userId={}", userId, e);
return CommonResult.failed("获取点赞记录失败: " + e.getMessage());
}
}
/**
@ -204,15 +234,28 @@ public class UserActivityRecordController {
@GetMapping("/follow/records")
public CommonResult<CommonPage<Map<String, Object>>> getFollowRecords(
@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "20") Integer pageSize) {
@RequestParam(defaultValue = "20") Integer pageSize,
javax.servlet.http.HttpServletRequest request) {
String authToken = request.getHeader("Authori-zation");
log.info("【关注记录API】请求头: {}", authToken != null ? authToken.substring(0, Math.min(20, authToken.length())) + "..." : "null");
Integer userId = userService.getUserId();
if (userId == null) {
log.info("【关注记录API】参数: userId={}, page={}, pageSize={}", userId, page, pageSize);
if (userId == null || userId == 0) {
log.warn("【关注记录API】用户未登录: userId={}", userId);
return CommonResult.failed("请先登录");
}
CommonPage<Map<String, Object>> result = userActivityRecordService.getFollowRecords(userId, page, pageSize);
return CommonResult.success(result);
try {
CommonPage<Map<String, Object>> result = userActivityRecordService.getFollowRecords(userId, page, pageSize);
log.info("【关注记录API】成功: userId={}, total={}, listSize={}", userId, result.getTotal(), result.getList().size());
return CommonResult.success(result);
} catch (Exception e) {
log.error("【关注记录API】异常: userId={}", userId, e);
return CommonResult.failed("获取关注记录失败: " + e.getMessage());
}
}
// ==================== 收藏记录 ====================
@ -224,19 +267,55 @@ public class UserActivityRecordController {
@GetMapping("/collect/works")
public CommonResult<CommonPage<Map<String, Object>>> getCollectedWorks(
@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "20") Integer pageSize) {
@RequestParam(defaultValue = "20") Integer pageSize,
javax.servlet.http.HttpServletRequest request) {
String authToken = request.getHeader("Authori-zation");
log.info("【收藏记录API】请求头: {}", authToken != null ? authToken.substring(0, Math.min(20, authToken.length())) + "..." : "null");
Integer userId = userService.getUserId();
if (userId == null) {
log.info("【收藏记录API】参数: userId={}, page={}, pageSize={}", userId, page, pageSize);
if (userId == null || userId == 0) {
log.warn("【收藏记录API】用户未登录: userId={}", userId);
return CommonResult.failed("请先登录");
}
CommonPage<Map<String, Object>> result = userActivityRecordService.getCollectedWorks(userId, page, pageSize);
return CommonResult.success(result);
try {
CommonPage<Map<String, Object>> result = userActivityRecordService.getCollectedWorks(userId, page, pageSize);
log.info("【收藏记录API】成功: userId={}, total={}, listSize={}", userId, result.getTotal(), result.getList().size());
return CommonResult.success(result);
} catch (Exception e) {
log.error("【收藏记录API】异常: userId={}", userId, e);
return CommonResult.failed("获取收藏记录失败: " + e.getMessage());
}
}
// ==================== 统计信息 ====================
/**
* 调试接口验证Token状态
*/
@ApiOperation(value = "调试验证Token状态")
@GetMapping("/debug/token")
public CommonResult<Map<String, Object>> debugToken(javax.servlet.http.HttpServletRequest request) {
Map<String, Object> result = new java.util.HashMap<>();
String authToken = request.getHeader("Authori-zation");
String authToken2 = request.getHeader("Authorization");
result.put("header_Authori-zation", authToken);
result.put("header_Authorization", authToken2);
Integer userId = userService.getUserId();
result.put("userId", userId);
result.put("isLoggedIn", userId != null && userId > 0);
log.info("【Token调试】Authori-zation={}, Authorization={}, userId={}", authToken, authToken2, userId);
return CommonResult.success(result);
}
/**
* 获取用户活动统计
*/

View File

@ -33,9 +33,16 @@ public class FrontTokenInterceptor implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
response.setCharacterEncoding("UTF-8");
String token = frontTokenComponent.getToken(request);
String uri = com.zbkj.common.utils.RequestUtil.getUri(request);
// 调试日志
String rawToken = request.getHeader("Authori-zation");
System.out.println("[FrontTokenInterceptor] URI=" + uri + ", rawToken=" + (rawToken != null ? rawToken.substring(0, Math.min(20, rawToken.length())) + "..." : "null") + ", processedToken=" + (token != null ? token.substring(0, Math.min(20, token.length())) + "..." : "null"));
if(token == null || token.isEmpty()){
//判断路由部分路由不管用户是否登录都可以访问
boolean result = frontTokenComponent.checkRouter(RequestUtil.getUri(request));
boolean result = frontTokenComponent.checkRouter(uri);
System.out.println("[FrontTokenInterceptor] Token为空, checkRouter=" + result);
if(result){
return true;
}
@ -44,6 +51,7 @@ public class FrontTokenInterceptor implements HandlerInterceptor {
}
Boolean result = frontTokenComponent.check(token, request);
System.out.println("[FrontTokenInterceptor] Token验证结果: " + result);
if(!result){
response.getWriter().write(JSONObject.toJSONString(CommonResult.failed(CommonResultCode.PERMISSION_EXPIRATION)));
return false;

View File

@ -55,7 +55,10 @@ public class UserActivityRecordServiceImpl implements UserActivityRecordService
@Override
public CommonPage<Map<String, Object>> getViewHistory(Integer userId, String targetType,
Integer page, Integer pageSize) {
if (userId == null) {
log.info("【getViewHistory】开始查询: userId={}, targetType={}, page={}, pageSize={}", userId, targetType, page, pageSize);
if (userId == null || userId == 0) {
log.warn("【getViewHistory】userId为空或0返回空页面");
return emptyPage(page, pageSize);
}
try {
@ -81,16 +84,20 @@ public class UserActivityRecordServiceImpl implements UserActivityRecordService
// 查询总数
Integer total = jdbcTemplate.queryForObject(countSql.toString(), Integer.class, params.toArray());
log.info("【getViewHistory】查询总数: userId={}, total={}", userId, total);
// 查询列表
params.add(pageSize);
params.add(offset);
List<Map<String, Object>> list = jdbcTemplate.queryForList(querySql.toString(), params.toArray());
log.info("【getViewHistory】查询列表: userId={}, listSize={}", userId, list.size());
// 补充目标详情
enrichViewHistoryDetails(list);
return buildPage(list, total != null ? total : 0, page, pageSize);
CommonPage<Map<String, Object>> result = buildPage(list, total != null ? total : 0, page, pageSize);
log.info("【getViewHistory】返回结果: userId={}, total={}, listSize={}", userId, result.getTotal(), result.getList().size());
return result;
} catch (Exception e) {
log.error("获取观看历史失败: userId={}", userId, e);
return emptyPage(page, pageSize);
@ -199,45 +206,71 @@ public class UserActivityRecordServiceImpl implements UserActivityRecordService
}
/**
* 获取全部点赞记录联合查询
* 获取全部点赞记录分别查询后合并更健壮
*/
private CommonPage<Map<String, Object>> getAllLikeRecords(Integer userId, Integer page, Integer pageSize) {
try {
List<Map<String, Object>> allRecords = new ArrayList<>();
// 1. 查询直播间点赞
try {
String roomSql = "SELECT 'room' as targetType, CAST(room_id AS CHAR) as targetId, lr.title as targetTitle, " +
"lr.cover_image as coverImage, lr.streamer_name as streamerName, lr.is_live as isLive, " +
"rl.create_time as createTime " +
"FROM eb_live_room_like rl " +
"LEFT JOIN eb_live_room lr ON rl.room_id = lr.id " +
"WHERE rl.user_id = ?";
List<Map<String, Object>> roomLikes = jdbcTemplate.queryForList(roomSql, userId);
allRecords.addAll(roomLikes);
} catch (Exception e) {
log.debug("查询直播间点赞失败,表可能不存在: {}", e.getMessage());
}
// 2. 查询作品点赞
try {
String workSql = "SELECT 'work' as targetType, CAST(wr.works_id AS CHAR) as targetId, w.title as targetTitle, " +
"w.cover_image as coverImage, NULL as streamerName, NULL as isLive, " +
"wr.create_time as createTime " +
"FROM eb_works_relation wr " +
"LEFT JOIN eb_works w ON wr.works_id = w.id " +
"WHERE wr.uid = ? AND wr.type = 1";
List<Map<String, Object>> workLikes = jdbcTemplate.queryForList(workSql, userId);
allRecords.addAll(workLikes);
} catch (Exception e) {
log.debug("查询作品点赞失败,表可能不存在: {}", e.getMessage());
}
// 3. 查询心愿点赞
try {
String wishSql = "SELECT 'wish' as targetType, CAST(wl.wish_id AS CHAR) as targetId, ws.content as targetTitle, " +
"NULL as coverImage, NULL as streamerName, NULL as isLive, " +
"wl.create_time as createTime " +
"FROM eb_wish_like wl " +
"LEFT JOIN eb_wishtree_wish ws ON wl.wish_id = ws.id " +
"WHERE wl.user_id = ?";
List<Map<String, Object>> wishLikes = jdbcTemplate.queryForList(wishSql, userId);
allRecords.addAll(wishLikes);
} catch (Exception e) {
log.debug("查询心愿点赞失败,表可能不存在: {}", e.getMessage());
}
// 按时间排序
allRecords.sort((a, b) -> {
Object timeA = a.get("createTime");
Object timeB = b.get("createTime");
if (timeA == null && timeB == null) return 0;
if (timeA == null) return 1;
if (timeB == null) return -1;
return timeB.toString().compareTo(timeA.toString());
});
// 分页
int total = allRecords.size();
int offset = (page - 1) * pageSize;
int end = Math.min(offset + pageSize, total);
List<Map<String, Object>> pagedList = offset < total ? allRecords.subList(offset, end) : new ArrayList<>();
// 统计各类点赞总数
int roomLikes = countTableRows("eb_live_room_like", "user_id", userId);
int workLikes = countTableRows("eb_works_relation", "uid", userId, "type", "like");
int wishLikes = countTableRows("eb_wish_like", "user_id", userId);
int total = roomLikes + workLikes + wishLikes;
// 联合查询
String sql = "(" +
"SELECT 'room' as targetType, CAST(room_id AS CHAR) as targetId, lr.title as targetTitle, " +
"lr.cover_image as coverImage, lr.streamer_name as streamerName, lr.is_live as isLive, " +
"rl.create_time as createTime " +
"FROM eb_live_room_like rl " +
"LEFT JOIN eb_live_room lr ON rl.room_id = lr.id " +
"WHERE rl.user_id = ?" +
") UNION ALL (" +
"SELECT 'work' as targetType, CAST(wr.works_id AS CHAR) as targetId, w.title as targetTitle, " +
"w.cover_image as coverImage, NULL as streamerName, NULL as isLive, " +
"wr.create_time as createTime " +
"FROM eb_works_relation wr " +
"LEFT JOIN eb_works w ON wr.works_id = w.id " +
"WHERE wr.uid = ? AND wr.type = 'like'" +
") UNION ALL (" +
"SELECT 'wish' as targetType, CAST(wl.wish_id AS CHAR) as targetId, ws.content as targetTitle, " +
"NULL as coverImage, NULL as streamerName, NULL as isLive, " +
"wl.create_time as createTime " +
"FROM eb_wish_like wl " +
"LEFT JOIN eb_wishtree_wish ws ON wl.wish_id = ws.id " +
"WHERE wl.user_id = ?" +
") ORDER BY createTime DESC LIMIT ? OFFSET ?";
List<Map<String, Object>> list = jdbcTemplate.queryForList(sql, userId, userId, userId, pageSize, offset);
return buildPage(list, total, page, pageSize);
return buildPage(pagedList, total, page, pageSize);
} catch (Exception e) {
log.error("获取全部点赞记录失败: userId={}", userId, e);
return emptyPage(page, pageSize);
@ -282,7 +315,7 @@ public class UserActivityRecordServiceImpl implements UserActivityRecordService
try {
int offset = (page - 1) * pageSize;
String countSql = "SELECT COUNT(*) FROM eb_works_relation WHERE uid = ? AND type = 'like'";
String countSql = "SELECT COUNT(*) FROM eb_works_relation WHERE uid = ? AND type = 1";
Integer total = jdbcTemplate.queryForObject(countSql, Integer.class, userId);
String sql = "SELECT wr.id, wr.works_id as workId, w.title, w.description, " +
@ -293,7 +326,7 @@ public class UserActivityRecordServiceImpl implements UserActivityRecordService
"FROM eb_works_relation wr " +
"LEFT JOIN eb_works w ON wr.works_id = w.id " +
"LEFT JOIN eb_user u ON w.user_id = u.uid " +
"WHERE wr.uid = ? AND wr.type = 'like' " +
"WHERE wr.uid = ? AND wr.type = 1 " +
"ORDER BY wr.create_time DESC LIMIT ? OFFSET ?";
List<Map<String, Object>> list = jdbcTemplate.queryForList(sql, userId, pageSize, offset);
@ -350,15 +383,15 @@ public class UserActivityRecordServiceImpl implements UserActivityRecordService
try {
int offset = (page - 1) * pageSize;
String countSql = "SELECT COUNT(*) FROM eb_follow_record WHERE follower_id = ? AND follow_status = 1";
String countSql = "SELECT COUNT(*) FROM eb_follow_record WHERE follower_id = ? AND (follow_status = 1 OR follow_status = '关注')";
Integer total = jdbcTemplate.queryForObject(countSql, Integer.class, userId);
String sql = "SELECT fr.id, fr.followed_id as followedId, fr.followed_nickname as followedNickname, " +
"u.avatar as followedAvatar, u.phone, " +
"fr.create_time as followTime " +
"u.avatar as followedAvatar, u.phone, fr.follow_status as followStatus, " +
"fr.create_time as createTime " +
"FROM eb_follow_record fr " +
"LEFT JOIN eb_user u ON fr.followed_id = u.uid " +
"WHERE fr.follower_id = ? AND fr.follow_status = 1 " +
"WHERE fr.follower_id = ? AND (fr.follow_status = 1 OR fr.follow_status = '关注') " +
"ORDER BY fr.create_time DESC LIMIT ? OFFSET ?";
List<Map<String, Object>> list = jdbcTemplate.queryForList(sql, userId, pageSize, offset);
@ -380,7 +413,7 @@ public class UserActivityRecordServiceImpl implements UserActivityRecordService
try {
int offset = (page - 1) * pageSize;
String countSql = "SELECT COUNT(*) FROM eb_works_relation WHERE uid = ? AND type = 'collect'";
String countSql = "SELECT COUNT(*) FROM eb_works_relation WHERE uid = ? AND type = 2";
Integer total = jdbcTemplate.queryForObject(countSql, Integer.class, userId);
String sql = "SELECT wr.id, wr.works_id as workId, w.title, w.description, " +
@ -391,7 +424,7 @@ public class UserActivityRecordServiceImpl implements UserActivityRecordService
"FROM eb_works_relation wr " +
"LEFT JOIN eb_works w ON wr.works_id = w.id " +
"LEFT JOIN eb_user u ON w.user_id = u.uid " +
"WHERE wr.uid = ? AND wr.type = 'collect' " +
"WHERE wr.uid = ? AND wr.type = 2 " +
"ORDER BY wr.create_time DESC LIMIT ? OFFSET ?";
List<Map<String, Object>> list = jdbcTemplate.queryForList(sql, userId, pageSize, offset);
@ -423,13 +456,13 @@ public class UserActivityRecordServiceImpl implements UserActivityRecordService
stats.put("likedWorkCount", countTableRows("eb_works_relation", "uid", userId, "type", "like"));
// 收藏作品数
stats.put("collectedWorkCount", countTableRows("eb_works_relation", "uid", userId, "type", "collect"));
stats.put("collectedWorkCount", countTableRows("eb_works_relation", "uid", userId, "type", 2));
// 关注数
stats.put("followingCount", countTableRows("eb_follow_record", "follower_id", userId, "follow_status", 1));
stats.put("followingCount", countFollowRecords("follower_id", userId));
// 粉丝数
stats.put("followerCount", countTableRows("eb_follow_record", "followed_id", userId, "follow_status", 1));
stats.put("followerCount", countFollowRecords("followed_id", userId));
// 搜索历史数
stats.put("searchHistoryCount", countTableRows("eb_search_history", "user_id", userId, "is_deleted", 0));
@ -465,6 +498,17 @@ public class UserActivityRecordServiceImpl implements UserActivityRecordService
}
}
private int countFollowRecords(String column, Object value) {
try {
String sql = "SELECT COUNT(*) FROM eb_follow_record WHERE " + column + " = ? AND (follow_status = 1 OR follow_status = '关注')";
Integer count = jdbcTemplate.queryForObject(sql, Integer.class, value);
return count != null ? count : 0;
} catch (Exception e) {
log.debug("统计关注记录失败");
return 0;
}
}
private CommonPage<Map<String, Object>> emptyPage(Integer page, Integer pageSize) {
CommonPage<Map<String, Object>> result = new CommonPage<>();
result.setList(new ArrayList<>());

View File

@ -55,6 +55,10 @@
android:name="com.example.livestreaming.SettingsPageActivity"
android:exported="false" />
<activity
android:name="com.example.livestreaming.BlacklistActivity"
android:exported="false" />
<activity
android:name="com.example.livestreaming.NotificationSettingsActivity"
android:exported="false" />

View File

@ -2,16 +2,21 @@ package com.example.livestreaming;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.cardview.widget.CardView;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
@ -21,12 +26,17 @@ import androidx.viewpager2.adapter.FragmentStateAdapter;
import androidx.viewpager2.widget.ViewPager2;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.resource.bitmap.CenterCrop;
import com.bumptech.glide.load.resource.bitmap.CircleCrop;
import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
import com.example.livestreaming.net.ApiClient;
import com.example.livestreaming.net.ApiResponse;
import com.example.livestreaming.net.AuthStore;
import com.example.livestreaming.net.PageResponse;
import com.google.android.material.tabs.TabLayout;
import com.google.android.material.tabs.TabLayoutMediator;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@ -37,10 +47,11 @@ import retrofit2.Response;
/**
* 我的记录页面 - 整合观看历史点赞记录收藏记录
* 我的记录页面 - 整合观看历史点赞记录收藏记录关注记录
*/
public class MyRecordsActivity extends AppCompatActivity {
private static final String TAG = "MyRecords";
private TabLayout tabLayout;
private ViewPager2 viewPager;
private ImageView backButton;
@ -66,7 +77,6 @@ public class MyRecordsActivity extends AppCompatActivity {
initViews();
setupViewPager();
// 处理跳转到指定Tab
int tabIndex = getIntent().getIntExtra("tabIndex", 0);
if (tabIndex >= 0 && tabIndex < tabTitles.length) {
viewPager.setCurrentItem(tabIndex, false);
@ -77,24 +87,16 @@ public class MyRecordsActivity extends AppCompatActivity {
backButton = findViewById(R.id.backButton);
tabLayout = findViewById(R.id.tabLayout);
viewPager = findViewById(R.id.viewPager);
backButton.setOnClickListener(v -> finish());
}
private void setupViewPager() {
RecordsPagerAdapter adapter = new RecordsPagerAdapter(this);
viewPager.setAdapter(adapter);
new TabLayoutMediator(tabLayout, viewPager, (tab, position) -> {
tab.setText(tabTitles[position]);
}).attach();
new TabLayoutMediator(tabLayout, viewPager, (tab, position) -> tab.setText(tabTitles[position])).attach();
}
/**
* ViewPager适配器
*/
private static class RecordsPagerAdapter extends FragmentStateAdapter {
public RecordsPagerAdapter(@NonNull FragmentActivity fragmentActivity) {
super(fragmentActivity);
}
@ -103,25 +105,19 @@ public class MyRecordsActivity extends AppCompatActivity {
@Override
public Fragment createFragment(int position) {
switch (position) {
case 0:
return RecordListFragment.newInstance("view");
case 1:
return RecordListFragment.newInstance("like");
case 2:
return RecordListFragment.newInstance("collect");
case 3:
return RecordListFragment.newInstance("follow");
default:
return RecordListFragment.newInstance("view");
case 0: return RecordListFragment.newInstance("view");
case 1: return RecordListFragment.newInstance("like");
case 2: return RecordListFragment.newInstance("collect");
case 3: return RecordListFragment.newInstance("follow");
default: return RecordListFragment.newInstance("view");
}
}
@Override
public int getItemCount() {
return 4;
}
public int getItemCount() { return 4; }
}
/**
* 记录列表Fragment
*/
@ -134,6 +130,9 @@ public class MyRecordsActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private View loadingView;
private View emptyView;
private ImageView ivEmptyIcon;
private TextView tvEmptyTitle;
private TextView tvEmptySubtitle;
private RecordAdapter adapter;
private final List<Map<String, Object>> records = new ArrayList<>();
@ -165,19 +164,53 @@ public class MyRecordsActivity extends AppCompatActivity {
recyclerView = view.findViewById(R.id.recyclerView);
loadingView = view.findViewById(R.id.loadingView);
emptyView = view.findViewById(R.id.emptyView);
ivEmptyIcon = view.findViewById(R.id.ivEmptyIcon);
tvEmptyTitle = view.findViewById(R.id.tvEmptyTitle);
tvEmptySubtitle = view.findViewById(R.id.tvEmptySubtitle);
setupEmptyState();
setupRecyclerView();
setupSwipeRefresh();
// 先调试Token状态
debugToken();
loadRecords();
return view;
}
private void setupEmptyState() {
int iconRes, titleRes;
String subtitle;
switch (recordType) {
case "like":
iconRes = R.drawable.ic_favorite_24;
titleRes = R.string.app_name;
tvEmptyTitle.setText("暂无点赞记录");
subtitle = "给喜欢的内容点个赞吧";
break;
case "collect":
iconRes = R.drawable.ic_star_24;
tvEmptyTitle.setText("暂无收藏记录");
subtitle = "收藏喜欢的作品方便下次观看";
break;
case "follow":
iconRes = R.drawable.ic_person_add_24;
tvEmptyTitle.setText("暂无关注记录");
subtitle = "关注感兴趣的主播和用户吧";
break;
default:
iconRes = R.drawable.ic_history_24;
tvEmptyTitle.setText("暂无观看记录");
subtitle = "去发现精彩直播和作品吧";
}
ivEmptyIcon.setImageResource(iconRes);
tvEmptySubtitle.setText(subtitle);
}
private void setupRecyclerView() {
adapter = new RecordAdapter(recordType, item -> {
// 点击跳转
handleItemClick(item);
});
adapter = new RecordAdapter(recordType, this::handleItemClick);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
recyclerView.setAdapter(adapter);
@ -200,6 +233,7 @@ public class MyRecordsActivity extends AppCompatActivity {
}
private void setupSwipeRefresh() {
swipeRefreshLayout.setColorSchemeResources(R.color.colorPrimary);
swipeRefreshLayout.setOnRefreshListener(() -> {
currentPage = 1;
hasMore = true;
@ -207,6 +241,36 @@ public class MyRecordsActivity extends AppCompatActivity {
});
}
/**
* 调试验证Token状态
*/
private void debugToken() {
if (getContext() == null) return;
String localToken = AuthStore.getToken(getContext());
String localUserId = AuthStore.getUserId(getContext());
Log.d(TAG, "【Token调试】本地Token: " + (localToken != null ? localToken.substring(0, Math.min(20, localToken.length())) + "..." : "null"));
Log.d(TAG, "【Token调试】本地UserId: " + localUserId);
ApiClient.getService(getContext()).debugToken().enqueue(new Callback<ApiResponse<Map<String, Object>>>() {
@Override
public void onResponse(Call<ApiResponse<Map<String, Object>>> call, Response<ApiResponse<Map<String, Object>>> response) {
if (response.isSuccessful() && response.body() != null) {
Map<String, Object> data = response.body().getData();
Log.d(TAG, "【Token调试】服务端响应: " + data);
} else {
Log.e(TAG, "【Token调试】请求失败: " + response.code());
}
}
@Override
public void onFailure(Call<ApiResponse<Map<String, Object>>> call, Throwable t) {
Log.e(TAG, "【Token调试】网络错误: " + t.getMessage());
}
});
}
private void loadRecords() {
if (isLoading || getContext() == null) return;
isLoading = true;
@ -217,6 +281,11 @@ public class MyRecordsActivity extends AppCompatActivity {
emptyView.setVisibility(View.GONE);
}
String userId = AuthStore.getUserId(getContext());
String token = AuthStore.getToken(getContext());
Log.d(TAG, "加载记录: type=" + recordType + ", page=" + currentPage + ", userId=" + userId);
Log.d(TAG, "Token状态: " + (token != null ? "存在, 长度=" + token.length() + ", 前20字符=" + token.substring(0, Math.min(20, token.length())) : "null"));
Call<ApiResponse<PageResponse<Map<String, Object>>>> call;
switch (recordType) {
case "view":
@ -235,6 +304,11 @@ public class MyRecordsActivity extends AppCompatActivity {
call = ApiClient.getService(getContext()).getViewHistory(null, currentPage, 20);
}
// 打印完整的请求信息
Log.d(TAG, "请求URL: " + call.request().url());
Log.d(TAG, "请求头Authori-zation: " + call.request().header("Authori-zation"));
Log.d(TAG, "请求头Authorization: " + call.request().header("Authorization"));
call.enqueue(new Callback<ApiResponse<PageResponse<Map<String, Object>>>>() {
@Override
public void onResponse(Call<ApiResponse<PageResponse<Map<String, Object>>>> call,
@ -243,16 +317,40 @@ public class MyRecordsActivity extends AppCompatActivity {
loadingView.setVisibility(View.GONE);
swipeRefreshLayout.setRefreshing(false);
if (response.isSuccessful() && response.body() != null && response.body().isOk()) {
PageResponse<Map<String, Object>> data = response.body().getData();
if (data != null && data.getList() != null) {
if (currentPage == 1) {
records.clear();
}
records.addAll(data.getList());
adapter.setData(new ArrayList<>(records));
hasMore = data.getList().size() >= 20;
Log.d(TAG, "响应: code=" + response.code() + ", success=" + response.isSuccessful());
if (response.isSuccessful() && response.body() != null) {
ApiResponse<PageResponse<Map<String, Object>>> apiResponse = response.body();
Log.d(TAG, "业务码: " + apiResponse.getCode() + ", msg=" + apiResponse.getMessage());
if (apiResponse.getCode() != null && (apiResponse.getCode() == 401 || apiResponse.getCode() == 402)) {
handleTokenExpired();
return;
}
if (apiResponse.isOk()) {
PageResponse<Map<String, Object>> data = apiResponse.getData();
if (data != null && data.getList() != null) {
Log.d(TAG, "数据: total=" + data.getTotal() + ", size=" + data.getList().size());
if (currentPage == 1) {
records.clear();
}
records.addAll(data.getList());
adapter.setData(new ArrayList<>(records));
hasMore = data.getList().size() >= 20;
}
} else {
Log.e(TAG, "业务错误: " + apiResponse.getMessage());
if (getContext() != null) {
Toast.makeText(getContext(), apiResponse.getMessage(), Toast.LENGTH_SHORT).show();
}
}
} else {
if (response.code() == 401 || response.code() == 402) {
handleTokenExpired();
return;
}
Log.e(TAG, "HTTP错误: " + response.code());
}
updateEmptyState();
}
@ -263,13 +361,27 @@ public class MyRecordsActivity extends AppCompatActivity {
loadingView.setVisibility(View.GONE);
swipeRefreshLayout.setRefreshing(false);
updateEmptyState();
Log.e(TAG, "网络错误: " + t.getMessage(), t);
if (getContext() != null) {
Toast.makeText(getContext(), "加载失败", Toast.LENGTH_SHORT).show();
Toast.makeText(getContext(), "加载失败: " + t.getMessage(), Toast.LENGTH_SHORT).show();
}
}
});
}
private void handleTokenExpired() {
if (getContext() != null) {
Toast.makeText(getContext(), "登录已过期,请重新登录", Toast.LENGTH_SHORT).show();
AuthStore.clearAll(getContext());
Intent loginIntent = new Intent(getContext(), LoginActivity.class);
loginIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(loginIntent);
if (getActivity() != null) {
getActivity().finish();
}
}
}
private void loadMore() {
currentPage++;
loadRecords();
@ -285,33 +397,50 @@ public class MyRecordsActivity extends AppCompatActivity {
}
}
private void handleItemClick(Map<String, Object> item) {
if (getContext() == null) return;
String targetType = (String) item.get("targetType");
if (targetType == null) {
// 根据记录类型判断
if ("follow".equals(recordType)) {
// 跳转到用户主页
Object followedId = item.get("followedId");
if (followedId != null) {
Intent intent = new Intent(getContext(), UserProfileReadOnlyActivity.class);
intent.putExtra("userId", ((Number) followedId).intValue());
startActivity(intent);
}
} else if ("collect".equals(recordType) || "like".equals(recordType)) {
// 跳转到作品详情
String targetType = getStringValue(item, "targetType");
if ("follow".equals(recordType)) {
Object followedId = item.get("followedId");
if (followedId != null) {
Intent intent = new Intent(getContext(), UserProfileReadOnlyActivity.class);
intent.putExtra("userId", ((Number) followedId).intValue());
startActivity(intent);
}
return;
}
if ("collect".equals(recordType)) {
Object workId = item.get("workId");
if (workId != null) {
Intent intent = new Intent(getContext(), WorkDetailActivity.class);
intent.putExtra("workId", ((Number) workId).longValue());
startActivity(intent);
}
return;
}
if (targetType == null || targetType.isEmpty()) {
if ("like".equals(recordType)) {
Object workId = item.get("workId");
Object roomId = item.get("roomId");
if (workId != null) {
Intent intent = new Intent(getContext(), WorkDetailActivity.class);
intent.putExtra("workId", ((Number) workId).longValue());
startActivity(intent);
} else if (roomId != null) {
Intent intent = new Intent(getContext(), RoomDetailActivity.class);
intent.putExtra(RoomDetailActivity.EXTRA_ROOM_ID, String.valueOf(roomId));
startActivity(intent);
}
}
return;
}
String targetId = String.valueOf(item.get("targetId"));
String targetId = getStringValue(item, "targetId");
switch (targetType) {
case "room":
Intent roomIntent = new Intent(getContext(), RoomDetailActivity.class);
@ -330,8 +459,14 @@ public class MyRecordsActivity extends AppCompatActivity {
break;
}
}
private String getStringValue(Map<String, Object> item, String key) {
Object value = item.get(key);
return value != null ? value.toString() : "";
}
}
/**
* 记录列表适配器
*/
@ -368,86 +503,213 @@ public class MyRecordsActivity extends AppCompatActivity {
Map<String, Object> item = data.get(position);
holder.bind(item, recordType);
holder.itemView.setOnClickListener(v -> {
if (listener != null) {
listener.onItemClick(item);
}
if (listener != null) listener.onItemClick(item);
});
}
@Override
public int getItemCount() {
return data.size();
}
public int getItemCount() { return data.size(); }
static class ViewHolder extends RecyclerView.ViewHolder {
TextView tvTitle;
TextView tvSubtitle;
TextView tvTime;
ImageView ivIcon;
CardView cardCover;
ImageView ivCover, ivPlayIcon, ivVerified, ivLike, ivCollect;
TextView tvTitle, tvTypeTag, tvSubtitle, tvTime, tvLiveStatus;
TextView tvLikeCount, tvCollectCount, btnFollow;
LinearLayout layoutSubtitle, layoutStats;
ViewHolder(@NonNull View itemView) {
super(itemView);
cardCover = itemView.findViewById(R.id.cardCover);
ivCover = itemView.findViewById(R.id.ivCover);
ivPlayIcon = itemView.findViewById(R.id.ivPlayIcon);
ivVerified = itemView.findViewById(R.id.ivVerified);
ivLike = itemView.findViewById(R.id.ivLike);
ivCollect = itemView.findViewById(R.id.ivCollect);
tvTitle = itemView.findViewById(R.id.tvTitle);
tvTypeTag = itemView.findViewById(R.id.tvTypeTag);
tvSubtitle = itemView.findViewById(R.id.tvSubtitle);
tvTime = itemView.findViewById(R.id.tvTime);
ivIcon = itemView.findViewById(R.id.ivIcon);
tvLiveStatus = itemView.findViewById(R.id.tvLiveStatus);
tvLikeCount = itemView.findViewById(R.id.tvLikeCount);
tvCollectCount = itemView.findViewById(R.id.tvCollectCount);
btnFollow = itemView.findViewById(R.id.btnFollow);
layoutSubtitle = itemView.findViewById(R.id.layoutSubtitle);
layoutStats = itemView.findViewById(R.id.layoutStats);
}
void bind(Map<String, Object> item, String recordType) {
String title = "";
String subtitle = "";
String time = "";
String imageUrl = "";
resetViews();
switch (recordType) {
case "view":
title = getStringValue(item, "targetTitle", "title");
String targetType = (String) item.get("targetType");
subtitle = "room".equals(targetType) ? "直播间" :
"work".equals(targetType) ? "作品" : "用户主页";
time = formatTime(item.get("updateTime"));
imageUrl = getStringValue(item, "coverImage", "avatar");
bindViewHistory(item);
break;
case "like":
title = getStringValue(item, "targetTitle", "roomTitle", "title", "content");
String likeType = (String) item.get("targetType");
subtitle = "room".equals(likeType) ? "直播间" :
"work".equals(likeType) ? "作品" : "心愿";
time = formatTime(item.get("createTime"), item.get("likeTime"));
imageUrl = getStringValue(item, "coverImage");
bindLikeRecord(item);
break;
case "collect":
title = getStringValue(item, "title");
subtitle = "作品 · " + getStringValue(item, "authorName");
time = formatTime(item.get("collectTime"));
imageUrl = getStringValue(item, "coverImage");
bindCollectRecord(item);
break;
case "follow":
title = getStringValue(item, "followedNickname");
subtitle = "已关注";
time = formatTime(item.get("followTime"));
imageUrl = getStringValue(item, "followedAvatar");
bindFollowRecord(item);
break;
}
tvTitle.setText(title.isEmpty() ? "未知" : title);
tvSubtitle.setText(subtitle);
tvTime.setText(time);
// 加载图片
if (!imageUrl.isEmpty()) {
Glide.with(itemView.getContext())
.load(imageUrl)
.placeholder(R.drawable.ic_history_24)
.error(R.drawable.ic_history_24)
.centerCrop()
.into(ivIcon);
} else {
ivIcon.setImageResource(R.drawable.ic_history_24);
}
}
private String getStringValue(Map<String, Object> item, String... keys) {
private void resetViews() {
ivPlayIcon.setVisibility(View.GONE);
tvLiveStatus.setVisibility(View.GONE);
ivVerified.setVisibility(View.GONE);
layoutStats.setVisibility(View.GONE);
btnFollow.setVisibility(View.GONE);
ivCollect.setVisibility(View.GONE);
tvCollectCount.setVisibility(View.GONE);
cardCover.setRadius(dpToPx(8));
}
private void bindViewHistory(Map<String, Object> item) {
String targetType = getString(item, "targetType");
String title = getString(item, "targetTitle", "title", "nickname");
String imageUrl = getString(item, "coverImage", "avatar");
String time = formatTime(item.get("updateTime"));
tvTitle.setText(title.isEmpty() ? "未知内容" : title);
if ("room".equals(targetType)) {
tvTypeTag.setText("直播间");
tvTypeTag.setBackgroundResource(R.drawable.bg_tag_room);
tvSubtitle.setText(getString(item, "streamerName"));
ivPlayIcon.setVisibility(View.VISIBLE);
Object isLive = item.get("isLive");
if (isLive != null && (Boolean.TRUE.equals(isLive) || "1".equals(isLive.toString()))) {
tvLiveStatus.setVisibility(View.VISIBLE);
}
Object duration = item.get("viewDuration");
if (duration != null) {
int seconds = ((Number) duration).intValue();
time += " · 观看" + (seconds >= 60 ? (seconds / 60) + "分钟" : seconds + "");
}
} else if ("work".equals(targetType)) {
tvTypeTag.setText("作品");
tvTypeTag.setBackgroundResource(R.drawable.bg_tag_work);
tvSubtitle.setText(getString(item, "authorName"));
ivPlayIcon.setVisibility(View.VISIBLE);
} else if ("profile".equals(targetType)) {
tvTypeTag.setText("用户主页");
tvTypeTag.setBackgroundResource(R.drawable.bg_tag_profile);
tvSubtitle.setText("");
cardCover.setRadius(dpToPx(28));
}
tvTime.setText(time);
loadImage(imageUrl, "profile".equals(targetType));
}
private void bindLikeRecord(Map<String, Object> item) {
String targetType = getString(item, "targetType");
String title = getString(item, "targetTitle", "roomTitle", "title", "content");
String imageUrl = getString(item, "coverImage");
String time = formatTime(item.get("createTime"), item.get("likeTime"));
tvTitle.setText(title.isEmpty() ? "未知内容" : title);
layoutStats.setVisibility(View.VISIBLE);
if ("room".equals(targetType) || item.get("roomId") != null) {
tvTypeTag.setText("直播间");
tvTypeTag.setBackgroundResource(R.drawable.bg_tag_room);
tvSubtitle.setText(getString(item, "streamerName"));
Object isLive = item.get("isLive");
if (isLive != null && (Boolean.TRUE.equals(isLive) || "1".equals(isLive.toString()))) {
tvLiveStatus.setVisibility(View.VISIBLE);
}
tvLikeCount.setText(formatCount(item.get("likeCount")));
} else if ("work".equals(targetType) || item.get("workId") != null) {
tvTypeTag.setText("作品");
tvTypeTag.setBackgroundResource(R.drawable.bg_tag_work);
tvSubtitle.setText(getString(item, "authorName"));
ivPlayIcon.setVisibility(View.VISIBLE);
tvLikeCount.setText(formatCount(item.get("likeCount")));
} else if ("wish".equals(targetType) || item.get("wishId") != null) {
tvTypeTag.setText("心愿");
tvTypeTag.setBackgroundResource(R.drawable.bg_tag_wish);
tvTypeTag.setTextColor(ContextCompat.getColor(itemView.getContext(), R.color.text_primary));
tvSubtitle.setText(getString(item, "authorName"));
tvLikeCount.setText(formatCount(item.get("likeCount")));
}
tvTime.setText(time);
loadImage(imageUrl, false);
}
private void bindCollectRecord(Map<String, Object> item) {
String title = getString(item, "title");
String authorName = getString(item, "authorName");
String imageUrl = getString(item, "coverImage");
String time = "收藏于 " + formatTime(item.get("collectTime"));
tvTitle.setText(title.isEmpty() ? "未知作品" : title);
tvTypeTag.setText("作品");
tvTypeTag.setBackgroundResource(R.drawable.bg_tag_work);
tvSubtitle.setText(authorName);
ivPlayIcon.setVisibility(View.VISIBLE);
layoutStats.setVisibility(View.VISIBLE);
tvLikeCount.setText(formatCount(item.get("likeCount")));
ivCollect.setVisibility(View.VISIBLE);
tvCollectCount.setVisibility(View.VISIBLE);
tvCollectCount.setText(formatCount(item.get("collectCount")));
tvTime.setText(time);
loadImage(imageUrl, false);
}
private void bindFollowRecord(Map<String, Object> item) {
String nickname = getString(item, "followedNickname");
String avatar = getString(item, "followedAvatar");
String time = "关注于 " + formatTime(item.get("createTime"));
tvTitle.setText(nickname.isEmpty() ? "未知用户" : nickname);
tvTypeTag.setVisibility(View.GONE);
tvSubtitle.setText("");
cardCover.setRadius(dpToPx(28));
btnFollow.setVisibility(View.VISIBLE);
tvTime.setText(time);
loadImage(avatar, true);
}
private void loadImage(String url, boolean isCircle) {
Context context = itemView.getContext();
if (url == null || url.isEmpty()) {
ivCover.setImageResource(isCircle ? R.drawable.ic_default_avatar : R.drawable.ic_live_tv_24);
return;
}
if (isCircle) {
Glide.with(context)
.load(url)
.placeholder(R.drawable.ic_default_avatar)
.error(R.drawable.ic_default_avatar)
.transform(new CircleCrop())
.into(ivCover);
} else {
Glide.with(context)
.load(url)
.placeholder(R.drawable.bg_cover_rounded_8)
.error(R.drawable.ic_live_tv_24)
.transform(new CenterCrop(), new RoundedCorners(dpToPx(8)))
.into(ivCover);
}
}
private String getString(Map<String, Object> item, String... keys) {
for (String key : keys) {
Object value = item.get(key);
if (value != null && !value.toString().isEmpty()) {
@ -469,6 +731,20 @@ public class MyRecordsActivity extends AppCompatActivity {
}
return "";
}
private String formatCount(Object count) {
if (count == null) return "0";
long num = ((Number) count).longValue();
if (num >= 10000) {
return new DecimalFormat("#.#").format(num / 10000.0) + "";
}
return String.valueOf(num);
}
private int dpToPx(int dp) {
float density = itemView.getContext().getResources().getDisplayMetrics().density;
return Math.round(dp * density);
}
}
}
}

View File

@ -928,12 +928,12 @@ public class ProfileActivity extends AppCompatActivity {
com.example.livestreaming.net.ApiResponse<com.example.livestreaming.net.PageResponse<java.util.Map<String, Object>>> apiResponse = response.body();
if (apiResponse.getCode() == 200 && apiResponse.getData() != null) {
com.example.livestreaming.net.PageResponse<java.util.Map<String, Object>> pageData = apiResponse.getData();
int total = pageData.getTotal();
Long total = pageData.getTotal();
// 更新快捷操作区域的收藏数
android.widget.TextView likedRoomsCountText = findViewById(R.id.likedRoomsCount);
if (likedRoomsCountText != null) {
likedRoomsCountText.setText(total + "个直播间");
likedRoomsCountText.setText((total != null ? total : 0) + "个直播间");
}
}
}

View File

@ -963,7 +963,7 @@ public class RoomDetailActivity extends AppCompatActivity {
java.util.Map<String, Object> body = new java.util.HashMap<>();
body.put("targetType", "room");
body.put("targetId", roomId);
body.put("targetTitle", roomTitle != null ? roomTitle : "直播间");
body.put("targetTitle", room != null && room.getTitle() != null ? room.getTitle() : "直播间");
body.put("duration", 0); // 初始时长为0后续可更新
Call<ApiResponse<java.util.Map<String, Object>>> call = apiService.recordViewHistoryNew(body);

View File

@ -614,36 +614,8 @@ public class SettingsPageActivity extends AppCompatActivity {
}
private void showBlacklistDialog() {
// TODO: 接入后端接口 - 获取黑名单列表
// 接口路径: GET /api/users/{userId}/blacklist
// 请求参数:
// - userId: 用户ID从token中获取
// - page (可选): 页码
// - pageSize (可选): 每页数量
// 返回数据格式: ApiResponse<List<User>>
// User对象应包含: id, name, avatarUrl, addToBlacklistTime等字段
// TODO: 接入后端接口 - 添加用户到黑名单
// 接口路径: POST /api/users/{userId}/blacklist
// 请求参数:
// - userId: 用户ID从token中获取
// - targetUserId: 要屏蔽的用户ID
// 返回数据格式: ApiResponse<{success: boolean}>
// TODO: 接入后端接口 - 从黑名单移除用户
// 接口路径: DELETE /api/users/{userId}/blacklist/{targetUserId}
// 请求参数:
// - userId: 用户ID从token中获取
// - targetUserId: 要解除屏蔽的用户ID路径参数
// 返回数据格式: ApiResponse<{success: boolean}>
new AlertDialog.Builder(this)
.setTitle("黑名单管理")
.setMessage("黑名单功能允许您屏蔽不想看到的用户。\n\n" +
"功能说明:\n" +
"• 被加入黑名单的用户无法给您发送消息\n" +
"• 您将不会看到被屏蔽用户的直播和动态\n" +
"• 可以随时解除屏蔽\n\n" +
"注意:此功能需要登录后使用,目前功能正在开发中,敬请期待。")
.setPositiveButton("确定", null)
.show();
// 跳转到黑名单管理页面
BlacklistActivity.start(this);
}
private void showPermissionManagementDialog() {

View File

@ -165,8 +165,10 @@ public final class ApiClient {
}
public static ApiService getService(@Nullable Context context) {
// 始终更新 appContext确保 Token 拦截器能获取到正确的 Context
if (context != null) {
appContext = context.getApplicationContext();
Log.d(TAG, "更新 appContext: " + appContext);
}
String desiredBaseUrl = resolveActiveBaseUrl(appContext);
if (service != null && !TextUtils.isEmpty(activeBaseUrl) && TextUtils.equals(activeBaseUrl, desiredBaseUrl)) {
@ -189,6 +191,9 @@ public final class ApiClient {
String t = token.trim();
req.header("Authori-zation", t);
req.header("Authorization", t);
Log.d(TAG, "添加Token到请求头: " + t.substring(0, Math.min(20, t.length())) + "...");
} else {
Log.w(TAG, "Token为空未添加到请求头! ctx=" + (ctx != null ? "存在" : "null"));
}
return chain.proceed(req.build());
};

View File

@ -812,6 +812,12 @@ public interface ApiService {
@GET("api/front/activity/stats")
Call<ApiResponse<Map<String, Object>>> getUserActivityStats();
/**
* 调试验证Token状态
*/
@GET("api/front/activity/debug/token")
Call<ApiResponse<Map<String, Object>>> debugToken();
/**
* 获取搜索历史
*/

View File

@ -6,7 +6,7 @@ public class PageResponse<T> {
private List<T> list;
private Integer page;
private Integer limit;
private Integer total;
private Long total; // 改为Long类型与后端CommonPage一致
private Integer totalPage;
public List<T> getList() { return list; }
@ -18,8 +18,8 @@ public class PageResponse<T> {
public Integer getLimit() { return limit; }
public void setLimit(Integer limit) { this.limit = limit; }
public Integer getTotal() { return total; }
public void setTotal(Integer total) { this.total = total; }
public Long getTotal() { return total; }
public void setTotal(Long total) { this.total = total; }
public Integer getTotalPage() { return totalPage; }
public void setTotalPage(Integer totalPage) { this.totalPage = totalPage; }

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white">
@ -30,14 +31,15 @@
<ProgressBar
android:layout_width="48dp"
android:layout_height="48dp" />
android:layout_height="48dp"
android:indeterminateTint="@color/colorPrimary" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="加载中..."
android:textColor="#999999"
android:textColor="@color/text_hint"
android:textSize="14sp" />
</LinearLayout>
@ -51,18 +53,29 @@
android:visibility="gone">
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
android:alpha="0.4"
android:src="@drawable/ic_history_24" />
android:id="@+id/ivEmptyIcon"
android:layout_width="80dp"
android:layout_height="80dp"
android:src="@drawable/ic_history_24"
app:tint="@color/colorPrimary" />
<TextView
android:id="@+id/tvEmptyTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="暂无记录"
android:textColor="#999999"
android:textColor="@color/text_primary"
android:textSize="16sp" />
<TextView
android:id="@+id/tvEmptySubtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="去发现精彩直播和作品吧"
android:textColor="@color/text_hint"
android:textSize="13sp" />
</LinearLayout>
</FrameLayout>

View File

@ -1,23 +1,64 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:minHeight="96dp"
android:paddingStart="16dp"
android:paddingTop="12dp"
android:paddingEnd="16dp"
android:paddingBottom="12dp">
<ImageView
android:id="@+id/ivIcon"
android:layout_width="48dp"
android:layout_height="48dp"
android:background="#F5F5F5"
android:scaleType="centerCrop"
<!-- 封面图/头像 -->
<androidx.cardview.widget.CardView
android:id="@+id/cardCover"
android:layout_width="80dp"
android:layout_height="80dp"
app:cardCornerRadius="8dp"
app:cardElevation="0dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:id="@+id/ivCover"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/bg_cover_rounded_8"
android:scaleType="centerCrop"
tools:src="@drawable/ic_live_tv_24" />
<!-- 播放图标覆盖层 -->
<ImageView
android:id="@+id/ivPlayIcon"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center"
android:background="@drawable/bg_circle_semi_transparent"
android:padding="4dp"
android:src="@drawable/ic_play_circle_24"
android:visibility="gone"
app:tint="@android:color/white" />
</androidx.cardview.widget.CardView>
<!-- 直播中标签 -->
<TextView
android:id="@+id/tvLiveStatus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:layout_marginEnd="4dp"
android:background="@drawable/bg_tag_live"
android:text="直播中"
android:textColor="@android:color/white"
android:textSize="9sp"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="@id/cardCover"
app:layout_constraintTop_toTopOf="@id/cardCover"
tools:visibility="visible" />
<!-- 主标题 -->
<TextView
android:id="@+id/tvTitle"
android:layout_width="0dp"
@ -26,40 +67,152 @@
android:layout_marginEnd="8dp"
android:ellipsize="end"
android:maxLines="1"
android:text="标题"
android:textColor="#333333"
android:textColor="@color/text_primary"
android:textSize="15sp"
android:textStyle="bold"
app:layout_constraintEnd_toStartOf="@id/tvTime"
app:layout_constraintStart_toEndOf="@id/ivIcon"
app:layout_constraintTop_toTopOf="@id/ivIcon" />
app:layout_constraintEnd_toStartOf="@id/btnFollow"
app:layout_constraintStart_toEndOf="@id/cardCover"
app:layout_constraintTop_toTopOf="@id/cardCover"
tools:text="周末音乐派对直播间" />
<TextView
android:id="@+id/tvSubtitle"
<!-- 类型标签 + 副标题 -->
<LinearLayout
android:id="@+id/layoutSubtitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginTop="4dp"
android:layout_marginTop="6dp"
android:layout_marginEnd="8dp"
android:gravity="center_vertical"
android:orientation="horizontal"
app:layout_constraintEnd_toStartOf="@id/btnFollow"
app:layout_constraintStart_toEndOf="@id/cardCover"
app:layout_constraintTop_toBottomOf="@id/tvTitle">
<!-- 类型标签 -->
<TextView
android:id="@+id/tvTypeTag"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/bg_tag_room"
android:textColor="@android:color/white"
android:textSize="10sp"
tools:text="直播间" />
<!-- 副标题(作者/主播名) -->
<TextView
android:id="@+id/tvSubtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="6dp"
android:ellipsize="end"
android:maxLines="1"
android:textColor="@color/text_secondary"
android:textSize="13sp"
tools:text="小美主播" />
<!-- 认证图标 -->
<ImageView
android:id="@+id/ivVerified"
android:layout_width="14dp"
android:layout_height="14dp"
android:layout_marginStart="4dp"
android:src="@drawable/ic_verified"
android:visibility="gone"
app:tint="@color/colorPrimary" />
</LinearLayout>
<!-- 统计信息(点赞数/收藏数) -->
<LinearLayout
android:id="@+id/layoutStats"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginTop="6dp"
android:layout_marginEnd="8dp"
android:gravity="center_vertical"
android:orientation="horizontal"
android:visibility="gone"
app:layout_constraintEnd_toStartOf="@id/btnFollow"
app:layout_constraintStart_toEndOf="@id/cardCover"
app:layout_constraintTop_toBottomOf="@id/layoutSubtitle"
tools:visibility="visible">
<!-- 点赞数 -->
<ImageView
android:id="@+id/ivLike"
android:layout_width="14dp"
android:layout_height="14dp"
android:src="@drawable/ic_favorite_24"
app:tint="@color/like_pink" />
<TextView
android:id="@+id/tvLikeCount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="2dp"
android:textColor="@color/text_hint"
android:textSize="12sp"
tools:text="1.2万" />
<!-- 收藏数 -->
<ImageView
android:id="@+id/ivCollect"
android:layout_width="14dp"
android:layout_height="14dp"
android:layout_marginStart="12dp"
android:src="@drawable/ic_star_24"
android:visibility="gone"
app:tint="@color/star_gold" />
<TextView
android:id="@+id/tvCollectCount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="2dp"
android:textColor="@color/text_hint"
android:textSize="12sp"
android:visibility="gone"
tools:text="5678" />
</LinearLayout>
<!-- 时间 -->
<TextView
android:id="@+id/tvTime"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginTop="6dp"
android:layout_marginEnd="8dp"
android:ellipsize="end"
android:maxLines="1"
android:text="副标题"
android:textColor="#999999"
android:textSize="13sp"
app:layout_constraintEnd_toStartOf="@id/tvTime"
app:layout_constraintStart_toEndOf="@id/ivIcon"
app:layout_constraintTop_toBottomOf="@id/tvTitle" />
android:textColor="@color/text_hint"
android:textSize="12sp"
app:layout_constraintBottom_toBottomOf="@id/cardCover"
app:layout_constraintEnd_toStartOf="@id/btnFollow"
app:layout_constraintStart_toEndOf="@id/cardCover"
tools:text="2024-01-04 · 观看32分钟" />
<!-- 关注按钮(仅关注记录显示) -->
<TextView
android:id="@+id/tvTime"
android:id="@+id/btnFollow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="时间"
android:textColor="#BBBBBB"
android:background="@drawable/bg_btn_followed"
android:paddingStart="12dp"
android:paddingTop="4dp"
android:paddingEnd="12dp"
android:paddingBottom="4dp"
android:text="已关注"
android:textColor="@android:color/white"
android:textSize="12sp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/tvTitle" />
app:layout_constraintTop_toTopOf="parent"
tools:visibility="visible" />
<!-- 分割线 -->
<View
android:layout_width="0dp"
android:layout_height="1dp"

View File

@ -1,7 +1,7 @@
<resources>
<color name="colorPrimary">#FF6B9D</color>
<color name="colorPrimaryDark">#C06C84</color>
<color name="colorAccent">#FF6B9D</color>
<color name="colorPrimary">#FF6B6B</color>
<color name="colorPrimaryDark">#E55A5A</color>
<color name="colorAccent">#FF6B6B</color>
<color name="purple_500">#6200EE</color>
<color name="purple_700">#3700B3</color>
@ -22,4 +22,13 @@
<color name="text_hint">#9E9E9E</color>
<color name="background_color">#F5F5F5</color>
<color name="background_light">#FAFAFA</color>
<!-- 记录标签颜色 -->
<color name="tag_room">#FF6B6B</color>
<color name="tag_work">#FF8A80</color>
<color name="tag_profile">#FFAB91</color>
<color name="tag_wish">#FFD54F</color>
<color name="tag_live">#FF4757</color>
<color name="like_pink">#E91E63</color>
<color name="star_gold">#FFD54F</color>
</resources>

View File

@ -1,39 +1,32 @@
-- 对比正常工作的菜单和礼物菜单
-- 对比工作正常的菜单和封禁菜单的配置
-- 查看用户管理下所有菜单的配置
-- 1. 查看直播管理菜单(这个应该是正常工作的)
SELECT
m.id,
m.pid,
m.name as '菜单名',
m.component as '组件路径',
m.menu_type as '类型',
m.icon,
m.perms as '权限标识'
FROM eb_system_menu m
WHERE m.name = '直播管理' OR m.pid = (SELECT id FROM eb_system_menu WHERE name = '直播管理' LIMIT 1)
ORDER BY m.pid, m.sort;
-- 1. 首先找到用户管理的父菜单ID
SELECT id, pid, `name`, perms, component, menu_type, sort, is_show
FROM eb_system_menu
WHERE `name` = '用户管理'
ORDER BY id;
-- 2. 查看礼物打赏菜单
SELECT
m.id,
m.pid,
m.name as '菜单名',
m.component as '组件路径',
m.menu_type as '类型',
m.icon,
m.perms as '权限标识'
FROM eb_system_menu m
WHERE m.name = '礼物打赏' OR m.pid = (SELECT id FROM eb_system_menu WHERE name = '礼物打赏' LIMIT 1)
ORDER BY m.pid, m.sort;
-- 2. 查看用户管理下的所有子菜单
SELECT id, pid, `name`, perms, component, menu_type, sort, is_show
FROM eb_system_menu
WHERE pid IN (SELECT id FROM eb_system_menu WHERE `name` = '用户管理')
ORDER BY sort, id;
-- 3. 查看用户管理菜单(另一个正常工作的)
SELECT
m.id,
m.pid,
m.name as '菜单名',
m.component as '组件路径',
m.menu_type as '类型'
FROM eb_system_menu m
WHERE m.name = '用户管理' OR m.pid = (SELECT id FROM eb_system_menu WHERE name = '用户管理' LIMIT 1)
ORDER BY m.pid, m.sort
LIMIT 5;
-- 3. 查看黑名单相关菜单(这些是工作正常的)
SELECT id, pid, `name`, perms, component, menu_type, sort, is_show
FROM eb_system_menu
WHERE `name` LIKE '%拉黑%' OR `name` LIKE '%黑名单%'
ORDER BY id;
-- 4. 查看封禁相关菜单
SELECT id, pid, `name`, perms, component, menu_type, sort, is_show
FROM eb_system_menu
WHERE `name` LIKE '%封禁%'
ORDER BY id;
-- 5. 查看用户列表菜单(作为参考)
SELECT id, pid, `name`, perms, component, menu_type, sort, is_show
FROM eb_system_menu
WHERE `name` = '用户列表'
ORDER BY id;