Commit 76ebc4a4 by zhangxingmin

push

parent ed1e4e0a
......@@ -5,4 +5,7 @@
<list />
</option>
</component>
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>
\ No newline at end of file
......@@ -29,12 +29,6 @@
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Boot Starter WebSocket -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
......
package com.yd.communication.api.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
\ No newline at end of file
package com.yd.communication.api.controller;
import com.yd.common.result.Result;
import com.yd.communication.api.service.ApiCoSessionService;
import com.yd.communication.feign.client.ApiCoSessionFeignClient;
import com.yd.communication.feign.request.CreateRequest;
import com.yd.communication.feign.request.EndSessionRequest;
import com.yd.communication.feign.request.JoinRequest;
import com.yd.communication.feign.request.TransferControlRequest;
import com.yd.communication.feign.response.CommonResponse;
import com.yd.communication.feign.response.CreateResponse;
import com.yd.communication.feign.response.JoinResponse;
import com.yd.communication.feign.response.SessionDetailResponse;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
/**
* 协同会话信息
*
* @author zxm
* @since 2026-07-28
*/
@RestController
@RequestMapping("/coSession")
@Validated
public class ApiCoSessionController implements ApiCoSessionFeignClient {
@Resource
private ApiCoSessionService apiCoSessionService;
/**
* 客户创建会话(生成共享码)
* @param request
* @return
*/
public Result<CreateResponse> create(CreateRequest request) {
return apiCoSessionService.create(request);
}
/**
* 顾问加入会话(输入共享码加入房间,可以多次加入)
* @param request
* @return
*/
@PostMapping("/join")
public Result<JoinResponse> join(JoinRequest request) {
return apiCoSessionService.join(request);
}
/**
* 获取会话详情
* @param bizId
* @return
*/
public Result<SessionDetailResponse> get(String bizId) {
return apiCoSessionService.get(bizId);
}
/**
* 结束协同会话(关闭共享,仅客户可调用)
* @return
*/
public Result<CommonResponse> end(EndSessionRequest request) {
return apiCoSessionService.end(request);
}
/**
* 切换控制权(仅参与者(顾问)可调用)
* @param request
* @return
*/
public Result<CommonResponse> transferControl(TransferControlRequest request) {
return apiCoSessionService.transferControl(request);
}
}
package com.yd.communication.api.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* <p>
* 协同-会话表(通用) 前端控制器
* </p>
*
* @author zxm
* @since 2026-07-28
*/
@RestController
@RequestMapping("/coSession")
public class CoSessionController {
}
package com.yd.communication.api.service;
import com.yd.common.result.Result;
import com.yd.communication.feign.dto.RoomRedisInfoDTO;
import com.yd.communication.feign.request.CreateRequest;
import com.yd.communication.feign.request.EndSessionRequest;
import com.yd.communication.feign.request.JoinRequest;
import com.yd.communication.feign.request.TransferControlRequest;
import com.yd.communication.feign.response.CommonResponse;
import com.yd.communication.feign.response.CreateResponse;
import com.yd.communication.feign.response.JoinResponse;
import com.yd.communication.feign.response.SessionDetailResponse;
import com.yd.communication.service.model.CoSession;
public interface ApiCoSessionService {
Result<CreateResponse> create(CreateRequest request);
Result<JoinResponse> join(JoinRequest request);
Result<SessionDetailResponse> get(String bizId);
Result<CommonResponse> end(EndSessionRequest request);
Result<CommonResponse> transferControl(TransferControlRequest request);
RoomRedisInfoDTO getCurrentController(String roomId);
void updateCurrentPage(String roomId, String newPageJson, String operatorId);
CoSession getByRoomId(String roomId);
}
package com.yd.communication.feign.client;
import com.yd.common.result.Result;
import com.yd.communication.feign.fallback.ApiCoSessionFeignFallbackFactory;
import com.yd.communication.feign.request.CreateRequest;
import com.yd.communication.feign.request.EndSessionRequest;
import com.yd.communication.feign.request.JoinRequest;
import com.yd.communication.feign.request.TransferControlRequest;
import com.yd.communication.feign.response.CommonResponse;
import com.yd.communication.feign.response.CreateResponse;
import com.yd.communication.feign.response.JoinResponse;
import com.yd.communication.feign.response.SessionDetailResponse;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
/**
* 通信服务-协同会话信息 Feign 客户端
*
* @author zxm
* @date 2026-07-28
*/
@FeignClient(name = "yd-communication-api", path = "/communication/api/coSession", fallbackFactory = ApiCoSessionFeignFallbackFactory.class)
public interface ApiCoSessionFeignClient {
/**
* 客户创建协同会话(生成共享码)
*
* @param request 创建会话请求
* @return 会话信息
*/
@PostMapping("/create")
Result<CreateResponse> create(@Validated @RequestBody CreateRequest request);
/**
* 顾问加入协同会话(输入共享码)
*
* @param request 加入会话请求
* @return 会话详情
*/
@PostMapping("/join")
Result<JoinResponse> join(@Validated @RequestBody JoinRequest request);
/**
* 获取协同会话详情
*
* @param bizId 会话业务ID
* @return 完整会话信息
*/
@GetMapping("/{bizId}")
Result<SessionDetailResponse> get(@PathVariable("bizId") String bizId);
/**
* 结束协同会话(关闭共享,仅客户可调用)
*
*/
@PostMapping("/end")
Result<CommonResponse> end(@Validated @RequestBody EndSessionRequest request);
/**
* 切换控制权(仅参与者(顾问)可调用)
* @param request
* @return
*/
@PostMapping("/control/transfer")
Result<CommonResponse> transferControl(@Validated @RequestBody TransferControlRequest request);
}
\ No newline at end of file
package com.yd.communication.feign.constant;
/**
* redis的key前缀常量
*/
public class RedisConstants {
/**
* 协同房间缓存信息redis前缀
*/
public static final String ROOM_KEY_PREFIX = "room:";
}
package com.yd.communication.feign.dto;
import lombok.Data;
/**
* 存储当前房间内的一些缓存字段信息
*/
@Data
public class RoomRedisInfoDTO {
/**
* 控制权持有者类型:owner(资源所有者类型)/participant(参与者类型)
*/
private String controlHolderType;
/**
* 控制权持有者ID(具体人的ID)
*/
private String controlHolderId;
/**
* 资源所有者的登录用户ID
*/
private String userId;
/**
* 资源所有者的登录token信息
*/
private String token;
}
package com.yd.communication.feign.enums;
/**
* 协同会话状态枚举
*/
public enum CoSessionStatusEnum {
DKS("待开始","1"),
JXZ("进行中","2"),
YJS("已结束","3"),
YCS("已超时","4"),
;
//字典项标签(名称)
private String itemLabel;
//字典项值
private String itemValue;
//构造函数
CoSessionStatusEnum(String itemLabel, String itemValue) {
this.itemLabel = itemLabel;
this.itemValue = itemValue;
}
public String getItemLabel() {
return itemLabel;
}
public String getItemValue() {
return itemValue;
}
}
package com.yd.communication.feign.enums;
/**
* 控制权持有者类型枚举
*/
public enum ControlHolderTypeEnum {
OWNER("资源所有者类型","owner"),
PARTICIPANT("参与者类型","participant"),
;
//字典项标签(名称)
private String itemLabel;
//字典项值
private String itemValue;
//构造函数
ControlHolderTypeEnum(String itemLabel, String itemValue) {
this.itemLabel = itemLabel;
this.itemValue = itemValue;
}
public String getItemLabel() {
return itemLabel;
}
public String getItemValue() {
return itemValue;
}
}
package com.yd.communication.feign.enums;
import com.yd.communication.feign.constant.RedisConstants;
import java.util.concurrent.TimeUnit;
/**
* redis枚举
*/
public enum RedisEnum {
//协同房间缓存信息redis参数
ROOM(RedisConstants.ROOM_KEY_PREFIX,600000000,TimeUnit.MINUTES),
;
//缓存key前缀
private String prefix;
//缓存过期时长
private Integer timeout;
//缓存过期时长单位
private TimeUnit timeUnit;
RedisEnum(String prefix, Integer timeout, TimeUnit timeUnit) {
this.prefix = prefix;
this.timeout = timeout;
this.timeUnit = timeUnit;
}
public String getPrefix() {
return prefix;
}
public Integer getTimeout() {
return timeout;
}
public TimeUnit getTimeUnit() {
return timeUnit;
}
}
package com.yd.communication.feign.fallback;
import com.yd.common.result.Result;
import com.yd.communication.feign.client.ApiCoSessionFeignClient;
import com.yd.communication.feign.request.CreateRequest;
import com.yd.communication.feign.request.EndSessionRequest;
import com.yd.communication.feign.request.JoinRequest;
import com.yd.communication.feign.request.TransferControlRequest;
import com.yd.communication.feign.response.CommonResponse;
import com.yd.communication.feign.response.CreateResponse;
import com.yd.communication.feign.response.JoinResponse;
import com.yd.communication.feign.response.SessionDetailResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.openfeign.FallbackFactory;
import org.springframework.stereotype.Component;
/**
* 通信服务-协同会话信息Feign降级处理
*/
@Slf4j
@Component
public class ApiCoSessionFeignFallbackFactory implements FallbackFactory<ApiCoSessionFeignClient> {
@Override
public ApiCoSessionFeignClient create(Throwable cause) {
return new ApiCoSessionFeignClient() {
@Override
public Result<CreateResponse> create(CreateRequest request) {
return null;
}
@Override
public Result<JoinResponse> join(JoinRequest request) {
return null;
}
@Override
public Result<SessionDetailResponse> get(String bizId) {
return null;
}
@Override
public Result<CommonResponse> end(EndSessionRequest request) {
return null;
}
@Override
public Result<CommonResponse> transferControl(TransferControlRequest request) {
return null;
}
};
}
}
package com.yd.communication.feign.request;
import lombok.Data;
import javax.validation.constraints.NotBlank;
/**
* 创建协同会话请求对象
* 客户调用此接口生成共享码,开启协同讲解
*/
@Data
public class CreateRequest {
/**
* 协同作用域
* single: 单个资源(如单份报告、资讯)
* global: 全局协同(如小程序全局协同,切换页面自动跟随)
*/
@NotBlank(message = "协同作用域不能为空")
private String scope;
/**
* 资源类型
* 用于区分不同的业务资源类型
* 可选值:report(报告)、news(资讯)、mini_program(小程序)等
*/
@NotBlank(message = "资源类型不能为空")
private String resourceType;
/**
* 资源业务ID
* 具体资源的唯一标识
* 如:report-报告ID、news-资讯ID、mini_program-小程序应用标识
*/
@NotBlank(message = "资源业务ID不能为空")
private String resourceId;
/**
* 资源初始化JSON串
* 创建会话时记录当前所在页面的完整信息,后续不做修改,用于历史追溯
* 示例:{"url":"https://mini.xxx.com/pages/index/index?userId=xxx"}
*/
@NotBlank(message = "资源初始化JSON串不能为空")
private String resourceInit;
/**
* 资源所有者ID(即客户ID)
* 报告/资源的归属人,通常为发起协同的客户
*/
@NotBlank(message = "资源所有者ID不能为空")
private String ownerId;
/**
* 资源所有者类型
* 默认:customer(客户)
* 可扩展:member(会员)、user(普通用户)等
*/
@NotBlank(message = "资源所有者类型不能为空")
private String ownerType;
/**
* 资源所有者的登录用户ID
*/
@NotBlank(message = "资源所有者的登录用户ID不能为空")
private String userId;
/**
* 资源所有者的登录token信息
*/
@NotBlank(message = "资源所有者的登录token信息不能为空")
private String token;
}
\ No newline at end of file
package com.yd.communication.feign.request;
import lombok.Data;
@Data
public class EndSessionRequest {
/**
* 房间号不能为空
*/
private String roomId;
}
package com.yd.communication.feign.request;
import lombok.Data;
import javax.validation.constraints.NotBlank;
/**
* 加入协同会话请求对象
* 顾问输入房间号和共享码加入协同
*/
@Data
public class JoinRequest {
// /**
// * 协同房间号(房间ID)
// * 客户创建会话时生成的唯一房间标识
// * 示例:room_abc12345
// */
// private String roomId;
/**
* 协同房间密码(共享码)
* 客户生成共享会话时返回的6位数字密码
* 顾问需要输入此密码才能加入协同
*/
@NotBlank(message = "房间密码不能为空")
private String roomPwd;
/**
* 参与者ID(即顾问ID)
* 加入协同的顾问/专家的唯一标识
*/
@NotBlank(message = "参与者ID不能为空")
private String participantId;
/**
* 参与者类型
* 默认:consultant(顾问)
* 可扩展:expert(专家)、trainer(培训师)等
*/
@NotBlank(message = "参与者类型不能为空")
private String participantType;
}
\ No newline at end of file
package com.yd.communication.feign.request;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
@Data
public class TransferControlRequest {
/**
* 操作类型:1-开启客户操作 2-关闭客户操作
*/
@NotNull(message = "操作类型不能为空")
private Integer oprType;
/**
* 房间号
*/
@NotBlank(message = "房间号不能为空")
private String roomId;
}
package com.yd.communication.feign.response;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 通用操作响应对象
* 用于结束会话、切换控制权等无需返回业务数据的操作
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CommonResponse {
/**
* 操作结果消息
*/
private String message;
}
\ No newline at end of file
package com.yd.communication.feign.response;
import lombok.Data;
/**
* 创建协同会话响应对象
*/
@Data
public class CreateResponse {
/**
* 会话唯一业务ID
*/
private String sessionBizId;
/**
* 房间号
*/
private String roomId;
/**
* 共享码(6位数字)
*/
private String roomPwd;
/**
* 会话状态:0-进行中,1-已结束,2-已超时
*/
private String status;
}
\ No newline at end of file
package com.yd.communication.feign.response;
import lombok.Data;
import javax.validation.constraints.NotBlank;
/**
* 加入协同会话响应对象
*/
@Data
public class JoinResponse {
/**
* 会话唯一业务ID
*/
private String sessionBizId;
/**
* 房间号
*/
private String roomId;
/**
* 资源初始化JSON(用于初始加载)
*/
private String resourceInit;
/**
* 控制权持有者类型:owner-客户,participant-顾问
*/
private String controlHolderType;
/**
* 控制权持有者ID
*/
private String controlHolderId;
/**
* 资源所有者的登录用户ID
*/
private String userId;
/**
* 资源所有者的登录token信息
*/
private String token;
}
\ No newline at end of file
package com.yd.communication.feign.response;
import lombok.Data;
import java.time.LocalDateTime;
/**
* 协同会话详情响应对象
*/
@Data
public class SessionDetailResponse {
/**
* 数据库主键
*/
private Long id;
/**
* 协同-会话表唯一业务ID
*/
private String coSessionBizId;
/**
* 会话编号
*/
private String coSessionNo;
/**
* 协同作用域:single-单资源,global-全域
*/
private String scope;
/**
* 资源类型:report/news/mini_program
*/
private String resourceType;
/**
* 资源业务ID(如报告ID、小程序标识等)
*/
private String resourceId;
/**
* 资源初始化JSON(创建时页面快照)
*/
private String resourceInit;
/**
* 所有者类型:customer-客户
*/
private String ownerType;
/**
* 所有者ID(客户ID)
*/
private String ownerId;
/**
* 参与者类型:consultant-顾问
*/
private String participantType;
/**
* 参与者ID(顾问ID)
*/
private String participantId;
/**
* 房间号
*/
private String roomId;
/**
* 控制权持有者类型:owner-客户,participant-顾问
*/
private String controlHolderType;
/**
* 控制权持有者ID
*/
private String controlHolderId;
/**
* 会话状态:0-进行中,1-已结束,2-已超时
*/
private String status;
/**
* 会话开始时间
*/
private LocalDateTime startTime;
/**
* 会话结束时间
*/
private LocalDateTime endTime;
/**
* 当前页面JSON(实时更新)
*/
private String currentPage;
/**
* 页面访问历史轨迹(JSON数组)
*/
private String pageHistory;
}
\ No newline at end of file
......@@ -50,6 +50,12 @@
<artifactId>freemarker</artifactId>
</dependency>
<!-- Spring Boot Starter WebSocket -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>com.yd</groupId>
<artifactId>yd-communication-feign</artifactId>
......
......@@ -2,6 +2,10 @@ package com.yd.communication.service.dao;
import com.yd.communication.service.model.CoSession;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Update;
import java.time.LocalDateTime;
/**
* <p>
......@@ -13,4 +17,14 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
*/
public interface CoSessionMapper extends BaseMapper<CoSession> {
@Update("UPDATE co_session SET status = #{status}, end_time = #{endTime} WHERE room_id = #{roomId}")
int updateStatusAndEndTimeByRoomId(@Param("roomId") String roomId,
@Param("status") Integer status,
@Param("endTime") LocalDateTime endTime);
@Update("UPDATE co_session SET current_page = #{currentPage}, page_history = #{pageHistory}, updater_id = #{updaterId} WHERE room_id = #{roomId}")
int updateCurrentPageAndHistory(@Param("roomId") String roomId,
@Param("currentPage") String currentPage,
@Param("pageHistory") String pageHistory,
@Param("updaterId") String updaterId);
}
......@@ -121,10 +121,10 @@ public class CoSession implements Serializable {
private String controlHolderId;
/**
* 0-进行中,1-已结束,2-已超时
* 1-待开始,2-进行中,3-已结束,4-已超时
*/
@TableField("status")
private Integer status;
private String status;
/**
* 开始时间
......@@ -185,4 +185,5 @@ public class CoSession implements Serializable {
*/
@TableField("update_time")
private LocalDateTime updateTime;
}
......@@ -49,7 +49,7 @@ public class RecordingTask implements Serializable {
private String taskId;
/**
* 业务类型:co-session/meeting
* 业务类型:co_session/meeting
*/
@TableField("biz_type")
private String bizType;
......@@ -85,10 +85,10 @@ public class RecordingTask implements Serializable {
private String layout;
/**
* 0-初始化,1-录制中,2-已停止,3-失败,4-已归档
* 1-初始化,2-录制中,3-已停止,4-失败,5-已归档
*/
@TableField("status")
private Integer status;
private String status;
/**
* 录制开始时间
......
......@@ -13,4 +13,7 @@ import com.baomidou.mybatisplus.extension.service.IService;
*/
public interface ICoOperationLogService extends IService<CoOperationLog> {
void log(String bizId, String operatorId, String operatorType,
String operatorName, String action, String content,
String deviceNumber, String ip);
}
......@@ -2,6 +2,7 @@ package com.yd.communication.service.service;
import com.yd.communication.service.model.CoSession;
import com.baomidou.mybatisplus.extension.service.IService;
import org.springframework.transaction.annotation.Transactional;
/**
* <p>
......@@ -13,4 +14,15 @@ import com.baomidou.mybatisplus.extension.service.IService;
*/
public interface ICoSessionService extends IService<CoSession> {
/**
* 根据房间ID获取会话(WebSocket 使用)
*/
CoSession getByRoomId(String roomId);
/**
* 根据业务ID获取会话
*/
CoSession getByBizId(String bizId);
int updateCurrentPageAndHistory(String roomId, String currentPage, String pageHistory, String updaterId);
}
......@@ -13,4 +13,7 @@ import com.baomidou.mybatisplus.extension.service.IService;
*/
public interface IRecordingTaskService extends IService<RecordingTask> {
String startRecording(String bizId, String roomId);
void stopRecording(String taskId);
}
package com.yd.communication.service.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yd.communication.service.model.CoDesensitizationRule;
import com.yd.communication.service.dao.CoDesensitizationRuleMapper;
import com.yd.communication.service.service.ICoDesensitizationRuleService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
/**
* <p>
* 协同-脱敏设置表(通用) 服务实现类
......@@ -14,7 +22,83 @@ import org.springframework.stereotype.Service;
* @author zxm
* @since 2026-07-28
*/
@Slf4j
@Service
public class CoDesensitizationRuleServiceImpl extends ServiceImpl<CoDesensitizationRuleMapper, CoDesensitizationRule> implements ICoDesensitizationRuleService {
@Resource
private CoDesensitizationRuleMapper ruleMapper;
private final ObjectMapper objectMapper = new ObjectMapper();
public String applyDesensitization(String rawData, String resourceType, String resourceId) {
// 获取规则(先特定资源,再默认)
LambdaQueryWrapper<CoDesensitizationRule> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(CoDesensitizationRule::getResourceType, resourceType)
.eq(CoDesensitizationRule::getEnabled, 1)
.orderByAsc(CoDesensitizationRule::getSortOrder);
List<CoDesensitizationRule> rules;
// 先查特定资源
wrapper.eq(CoDesensitizationRule::getResourceId, resourceId);
rules = ruleMapper.selectList(wrapper);
if (rules.isEmpty()) {
// 查默认规则
wrapper.clear();
wrapper.eq(CoDesensitizationRule::getResourceType, resourceType)
.eq(CoDesensitizationRule::getIsDefault, 1)
.eq(CoDesensitizationRule::getEnabled, 1)
.orderByAsc(CoDesensitizationRule::getSortOrder);
rules = ruleMapper.selectList(wrapper);
}
if (rules.isEmpty()) {
return rawData;
}
try {
JsonNode root = objectMapper.readTree(rawData);
for (CoDesensitizationRule rule : rules) {
String fieldPath = rule.getFieldPath();
// 简单处理:假设路径是$.xxx,直接取字段
String fieldName = fieldPath.replace("$.", "");
if (root.has(fieldName)) {
String original = root.get(fieldName).asText();
String masked = maskValue(original, rule.getMaskType(), rule.getMaskConfig());
// 由于JsonNode不可变,简单返回,生产需构建新节点
}
}
return objectMapper.writeValueAsString(root);
} catch (Exception e) {
log.error("脱敏失败", e);
return rawData;
}
}
private String maskValue(String original, String maskType, String maskConfig) {
try {
JsonNode config = objectMapper.readTree(maskConfig != null ? maskConfig : "{}");
int prefix = config.has("prefix") ? config.get("prefix").asInt() : 0;
int suffix = config.has("suffix") ? config.get("suffix").asInt() : 0;
String replaceChar = config.has("replace_char") ? config.get("replace_char").asText() : "*";
switch (maskType) {
case "mask":
case "partial":
if (original.length() <= prefix + suffix) return original;
int middle = original.length() - prefix - suffix;
return original.substring(0, prefix) +
// replaceChar.repeat(middle) +
original.substring(original.length() - suffix);
case "hide":
return "****";
case "replace":
return config.has("replace_char") ? config.get("replace_char").asText() : "***";
default:
return original;
}
} catch (Exception e) {
return original;
}
}
}
......@@ -4,6 +4,7 @@ import com.yd.communication.service.model.CoOperationLog;
import com.yd.communication.service.dao.CoOperationLogMapper;
import com.yd.communication.service.service.ICoOperationLogService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
......@@ -14,7 +15,28 @@ import org.springframework.stereotype.Service;
* @author zxm
* @since 2026-07-28
*/
@Slf4j
@Service
public class CoOperationLogServiceImpl extends ServiceImpl<CoOperationLogMapper, CoOperationLog> implements ICoOperationLogService {
@Override
public void log(String bizId, String operatorId, String operatorType,
String operatorName, String action, String content,
String deviceNumber, String ip) {
CoOperationLog log = new CoOperationLog();
log.setBizType("co_session");
log.setBizId(bizId);
log.setOperatorId(operatorId);
log.setOperatorType(operatorType);
log.setOperatorName(operatorName);
log.setAction(action);
log.setActionCategory("control");
log.setContent(content);
log.setOperatorDeviceNumber(deviceNumber);
log.setOperatorIp(ip);
log.setCreatorId(operatorId);
log.setUpdaterId(operatorId);
this.save(log);
}
}
......@@ -2,9 +2,11 @@ package com.yd.communication.service.service.impl;
import com.yd.communication.service.model.CoSession;
import com.yd.communication.service.dao.CoSessionMapper;
import com.yd.communication.service.service.ICoSessionService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yd.communication.service.service.ICoSessionService;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
/**
* <p>
......@@ -15,6 +17,34 @@ import org.springframework.stereotype.Service;
* @since 2026-07-28
*/
@Service
@Slf4j
public class CoSessionServiceImpl extends ServiceImpl<CoSessionMapper, CoSession> implements ICoSessionService {
/**
* 根据房间ID获取会话(WebSocket 使用)
*/
@Override
public CoSession getByRoomId(String roomId) {
LambdaQueryWrapper<CoSession> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(CoSession::getRoomId, roomId)
.eq(CoSession::getIsDeleted, 0);
return this.getOne(wrapper);
}
/**
* 根据业务ID获取会话
*/
@Override
public CoSession getByBizId(String bizId) {
return this.lambdaQuery()
.eq(CoSession::getCoSessionBizId,bizId)
.last(" limit 1 ")
.one();
}
@Override
public int updateCurrentPageAndHistory(String roomId,String currentPage,String pageHistory,String updaterId){
return baseMapper.updateCurrentPageAndHistory(roomId,currentPage,pageHistory,updaterId);
}
}
package com.yd.communication.service.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.yd.common.enums.CommonEnum;
import com.yd.common.utils.RandomStringGenerator;
import com.yd.communication.service.model.RecordingTask;
import com.yd.communication.service.dao.RecordingTaskMapper;
import com.yd.communication.service.service.IRecordingTaskService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.UUID;
/**
* <p>
......@@ -14,7 +20,72 @@ import org.springframework.stereotype.Service;
* @author zxm
* @since 2026-07-28
*/
@Slf4j
@Service
public class RecordingTaskServiceImpl extends ServiceImpl<RecordingTaskMapper, RecordingTask> implements IRecordingTaskService {
/**
* 初始化录制信息(协同生成共享码的时候就初始化信息)
* @param bizId
* @param roomId
* @return
*/
@Override
public String startRecording(String bizId, String roomId) {
//任务ID
String taskId = "agora_" + System.currentTimeMillis();
RecordingTask task = new RecordingTask();
//录制任务表唯一业务ID
task.setRecordingTaskBizId(RandomStringGenerator.generateBizId16(CommonEnum.UID_TYPE_RECORDING_TASK.getCode()));
//任务编号
task.setTaskNo("R" + System.currentTimeMillis());
task.setTaskId(taskId);
//关联的任务类型: 协同会话
task.setBizType("co_session");
//关联的任务类型表的ID: 协同会话表唯一业务ID
task.setBizId(bizId);
//房间号
task.setRoomId(roomId);
//RTC频道名
task.setChannel("channel_" + roomId);
//录制模式
task.setRecordingMode("mix");
//布局
task.setLayout("grid");
//1-初始化
task.setStatus("1");
task.setStartTime(LocalDateTime.now());
task.setCreatorId("system");
this.save(task);
log.info("启动录制成功, taskId={}, roomId={}", taskId, roomId);
return taskId;
}
@Override
public void stopRecording(String taskId) {
LambdaQueryWrapper<RecordingTask> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(RecordingTask::getTaskId, taskId);
RecordingTask task = this.getOne(wrapper);
if (task == null) {
throw new RuntimeException("录制任务不存在");
}
// 模拟停止录制
task.setStatus("3");
task.setStopTime(LocalDateTime.now());
task.setFileUrl("https://oss.example.com/recordings/" + taskId + ".mp4");
task.setFileDuration(120);
task.setFileSize(1024000L);
task.setFileMd5(UUID.randomUUID().toString().substring(0, 32));
task.setFileFormat("mp4");
task.setStorageType("oss");
task.setStorageBucket("coordination-recordings");
task.setStoragePath("/recordings/" + taskId + ".mp4");
task.setUpdaterId("system");
this.updateById(task);
log.info("停止录制成功, taskId={}", taskId);
}
}
package com.yd.communication.service.utils;
import java.security.SecureRandom;
public class RandomUtil {
private static final SecureRandom random = new SecureRandom();
public static String generateNumericCode(int length) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < length; i++) {
sb.append(random.nextInt(10));
}
return sb.toString();
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment