diff --git a/src/main/java/com/example/caseData/controller/CaseClinicalVideoController.java b/src/main/java/com/example/caseData/controller/CaseClinicalVideoController.java index 282cec6..b458675 100644 --- a/src/main/java/com/example/caseData/controller/CaseClinicalVideoController.java +++ b/src/main/java/com/example/caseData/controller/CaseClinicalVideoController.java @@ -392,4 +392,26 @@ public class CaseClinicalVideoController { resultMap.put("data", resultPage.getRecords()); return Response.success(resultMap); } + + /** + * 临床病例库-视频-同步app视频 + */ + @PostMapping("/app/clinical/video") + public Response AddClinicalVideoComment( + @Validated() + @RequestBody addClinicalVideoComment request + ) { + +// +// try { +// boolean res = caseClinicalVideoService.AddClinicalVideoComment(userId,request); +// if (!res){ +// return Response.error("操作失败"); +// } +// } catch (BusinessException e) { +// return Response.error(e.getMessage()); +// } + + return Response.success(); + } } diff --git a/src/main/java/com/example/caseData/controller/CaseExchangeController.java b/src/main/java/com/example/caseData/controller/CaseExchangeController.java index 147968f..2f32bb9 100644 --- a/src/main/java/com/example/caseData/controller/CaseExchangeController.java +++ b/src/main/java/com/example/caseData/controller/CaseExchangeController.java @@ -367,6 +367,60 @@ public class CaseExchangeController { return Response.success(); } + /** + * 病例交流-修改 + */ + @PutMapping("/exchange/{exchange_id}") + public Response UpdateCaseExchange( + @Validated() + @RequestBody updateCaseExchange request, + @PathVariable("exchange_id") String exchangeId + ) { + String userId = (String) httpServletRequest.getAttribute("userId"); + + if (userId == null) { + return Response.error("操作失败"); + } + + try { + boolean res = caseExchangeService.UpdateCaseExchange(userId,exchangeId,request); + if (!res){ + return Response.error("操作失败"); + } + } catch (BusinessException e) { + return Response.error(e.getMessage()); + } + + return Response.success(); + } + + /** + * 病例交流-删除 + */ + @DeleteMapping("/exchange/{exchange_id}") + public Response DeleteCaseExchange( + @PathVariable("exchange_id") String exchangeId + ) { + + String userId = (String) httpServletRequest.getAttribute("userId"); + + if (userId == null) { + return Response.error("操作失败"); + } + + try { + boolean res = caseExchangeService.DeleteCaseExchange(exchangeId,userId); + if (!res){ + return Response.error("操作失败"); + } + } catch (BusinessException e) { + return Response.error(e.getMessage()); + } + + return Response.success(); + } + + /** * 病例交流-收藏 */ diff --git a/src/main/java/com/example/caseData/controller/ClinicalController.java b/src/main/java/com/example/caseData/controller/ClinicalController.java index bd4d316..32c3396 100644 --- a/src/main/java/com/example/caseData/controller/ClinicalController.java +++ b/src/main/java/com/example/caseData/controller/ClinicalController.java @@ -70,8 +70,6 @@ public class ClinicalController extends BaseController { @Resource private StatsCaseClinicalLabelDao statsCaseClinicalLabelDao; - - /** * 临床病例库-搜索-文章 */ diff --git a/src/main/java/com/example/caseData/extend/app/Base.java b/src/main/java/com/example/caseData/extend/app/Base.java index 9dce823..3f66551 100644 --- a/src/main/java/com/example/caseData/extend/app/Base.java +++ b/src/main/java/com/example/caseData/extend/app/Base.java @@ -2,9 +2,13 @@ package com.example.caseData.extend.app; import cn.hutool.http.HttpRequest; import cn.hutool.http.HttpResponse; +import com.example.caseData.exception.BusinessException; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.servlet.http.HttpServletRequest; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.IOUtils; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; @@ -119,4 +123,45 @@ public class Base { return response.body(); } } + + /** + * 校验签名 + * @param request 请求对象 + * @param secretKey 密钥 + * @param mapper ObjectMapper 实例(用于 JSON 反序列化) + */ + public static void checkSign(HttpServletRequest request, String secretKey, ObjectMapper mapper) { + try { + String appId = request.getHeader("appId"); + String sign = request.getHeader("sign"); + + if (appId == null || appId.isEmpty()) { + throw new BusinessException("-1", "请求未授权"); + } + if (sign == null || sign.isEmpty()) { + throw new BusinessException("-1", "缺少签名"); + } + + // 读取请求体 + String body = IOUtils.toString(request.getInputStream(), StandardCharsets.UTF_8); + if (body == null || body.isEmpty()) { + throw new BusinessException("-1", "请求体为空"); + } + + // 使用 TypeReference 明确泛型类型,避免警告 + Map params = mapper.readValue(body, new TypeReference>() {}); + + // 生成签名 + String serverSign = Base.genSignature(params, secretKey); + + if (!sign.equals(serverSign)) { + throw new BusinessException("-1", "签名错误"); + } + + } catch (BusinessException e) { + throw e; + } catch (Exception e) { + throw new BusinessException("-1", "签名校验失败:" + e.getMessage()); + } + } } diff --git a/src/main/java/com/example/caseData/middlewares/AuthInterceptor.java b/src/main/java/com/example/caseData/middlewares/AuthInterceptor.java index 17fdea8..b511695 100644 --- a/src/main/java/com/example/caseData/middlewares/AuthInterceptor.java +++ b/src/main/java/com/example/caseData/middlewares/AuthInterceptor.java @@ -3,10 +3,21 @@ package com.example.caseData.middlewares; import com.example.caseData.dao.UserDao; import com.example.caseData.exception.BusinessException; import com.example.caseData.model.UserModel; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import org.apache.commons.codec.digest.HmacUtils; import org.jetbrains.annotations.NotNull; import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.io.BufferedReader; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.*; @Component public class AuthInterceptor extends BaseInterceptor { @@ -20,7 +31,6 @@ public class AuthInterceptor extends BaseInterceptor { public boolean preHandle(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler) throws Exception { // 放行白名单路径 if (isWhiteListed(request)) { - // 在白名单 return true; } @@ -46,4 +56,6 @@ public class AuthInterceptor extends BaseInterceptor { return true; // 如果权限验证通过,则继续处理请求 } + + } diff --git a/src/main/java/com/example/caseData/middlewares/BaseInterceptor.java b/src/main/java/com/example/caseData/middlewares/BaseInterceptor.java index 6520afe..8ad4408 100644 --- a/src/main/java/com/example/caseData/middlewares/BaseInterceptor.java +++ b/src/main/java/com/example/caseData/middlewares/BaseInterceptor.java @@ -16,7 +16,8 @@ public abstract class BaseInterceptor implements HandlerInterceptor { "GET:/api/index/clinical", // 首页-临床病例库 "POST:/api/login/mobile", // 登陆 "POST:/api/code/phone", // 获取验证码 - "POST:/api/login/hcp" // 登陆-hcp + "POST:/api/login/hcp", // 登陆-hcp + "POST:/api/app/clinical/video" // 视频同步 ); /** diff --git a/src/main/java/com/example/caseData/model/CaseClinicalArticleModel.java b/src/main/java/com/example/caseData/model/CaseClinicalArticleModel.java index 8468c44..c69ffd0 100644 --- a/src/main/java/com/example/caseData/model/CaseClinicalArticleModel.java +++ b/src/main/java/com/example/caseData/model/CaseClinicalArticleModel.java @@ -25,6 +25,12 @@ public class CaseClinicalArticleModel { @TableField("article_status") private Integer articleStatus; + /** + * 删除状态(0:否 1:是) + */ + @TableField("delete_status") + private Integer deleteStatus; + /** * 阅读量 */ diff --git a/src/main/java/com/example/caseData/model/CaseClinicalVideoModel.java b/src/main/java/com/example/caseData/model/CaseClinicalVideoModel.java index b37129e..8d2d67c 100644 --- a/src/main/java/com/example/caseData/model/CaseClinicalVideoModel.java +++ b/src/main/java/com/example/caseData/model/CaseClinicalVideoModel.java @@ -28,6 +28,12 @@ public class CaseClinicalVideoModel { @TableField("video_status") private Integer videoStatus; + /** + * 删除状态(0:否 1:是) + */ + @TableField("delete_status") + private Integer deleteStatus; + /** * 阅读量 */ diff --git a/src/main/java/com/example/caseData/model/CaseExchangeModel.java b/src/main/java/com/example/caseData/model/CaseExchangeModel.java index 758b021..ecf8691 100644 --- a/src/main/java/com/example/caseData/model/CaseExchangeModel.java +++ b/src/main/java/com/example/caseData/model/CaseExchangeModel.java @@ -37,6 +37,12 @@ public class CaseExchangeModel { @TableField("exchange_status") private Integer exchangeStatus; + /** + * 删除状态(0:否 1:是) + */ + @TableField("delete_status") + private Integer deleteStatus; + /** * 是否被精选(0:否 1:是) */ diff --git a/src/main/java/com/example/caseData/request/caseExchangeRequest/updateCaseExchange.java b/src/main/java/com/example/caseData/request/caseExchangeRequest/updateCaseExchange.java new file mode 100644 index 0000000..50a4666 --- /dev/null +++ b/src/main/java/com/example/caseData/request/caseExchangeRequest/updateCaseExchange.java @@ -0,0 +1,86 @@ +package com.example.caseData.request.caseExchangeRequest; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.Size; +import lombok.Data; + +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +@Data +public class updateCaseExchange { + /** + * 标题 + */ + @NotEmpty(message = "请输入标题") + @JsonProperty("exchange_title") + private String exchangeTitle; + + /** + * 内容 + */ + @NotEmpty(message = "请输入内容") + @JsonProperty("exchange_content") + private String exchangeContent; + + /** + * 总结 + */ + @JsonProperty("exchange_summary") + private String exchangeSummary; + + /** + * 投票 + */ + @JsonProperty("case_exchange_vote") + private CaseExchangeVoteRequest caseExchangeVote; + + /** + * 标签 + */ + @JsonProperty("case_exchange_label") + private List caseExchangeLabel; + + /** + * 投票 + */ + @JsonIgnoreProperties(ignoreUnknown = true) + @Data + public static class CaseExchangeVoteRequest { + @JsonProperty("vote_title") + @NotEmpty(message = "请输入投票标题") + private String voteTitle; // 选项标题 + + @JsonProperty("valid_day") + @Size(min = 1, max = 20, message = "有效期在1-20天内") + private Integer validDay; // 投票有效期天数 + + @JsonProperty("case_exchange_vote_option") + private List caseExchangeVoteOption; + } + + /** + * 投票选项 + */ + @JsonIgnoreProperties(ignoreUnknown = true) + @Data + public static class CaseExchangeVoteOptionRequest { + @JsonProperty("option_value") + private String optionValue; // 选项 + } + + /** + * 标签 + */ + @JsonIgnoreProperties(ignoreUnknown = true) + @Data + public static class CaseExchangeLabelRequest { + @JsonProperty("app_iden") + private String appIden; // app唯一标识 + + @JsonProperty("label_name") + private String labelName; // 标签名称 + } +} diff --git a/src/main/java/com/example/caseData/service/CaseClinicalVideoService.java b/src/main/java/com/example/caseData/service/CaseClinicalVideoService.java index d3268aa..eb8ed16 100644 --- a/src/main/java/com/example/caseData/service/CaseClinicalVideoService.java +++ b/src/main/java/com/example/caseData/service/CaseClinicalVideoService.java @@ -3,16 +3,21 @@ package com.example.caseData.service; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.example.caseData.dao.*; import com.example.caseData.exception.BusinessException; +import com.example.caseData.extend.app.Base; import com.example.caseData.model.*; import com.example.caseData.model.UserCollectClinicalVideoModel; import com.example.caseData.request.CaseClinicalVideoRequest.addClinicalVideoComment; import com.example.caseData.utils.Replace; import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; +import org.apache.commons.io.IOUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.interceptor.TransactionAspectSupport; +import java.nio.charset.StandardCharsets; import java.util.List; +import java.util.Map; import java.util.Objects; //import static com.baomidou.mybatisplus.extension.toolkit.Db.removeById; diff --git a/src/main/java/com/example/caseData/service/CaseExchangeService.java b/src/main/java/com/example/caseData/service/CaseExchangeService.java index 70f9408..25866e8 100644 --- a/src/main/java/com/example/caseData/service/CaseExchangeService.java +++ b/src/main/java/com/example/caseData/service/CaseExchangeService.java @@ -6,6 +6,7 @@ import com.example.caseData.exception.BusinessException; import com.example.caseData.model.*; import com.example.caseData.request.caseExchangeRequest.addCaseExchange; import com.example.caseData.request.caseExchangeRequest.addCaseExchangeComment; +import com.example.caseData.request.caseExchangeRequest.updateCaseExchange; import com.example.caseData.utils.JwtUtil; import com.example.caseData.utils.RegularUtil; import com.example.caseData.utils.Replace; @@ -199,6 +200,153 @@ public class CaseExchangeService { return true; } + /** + * 修改-病例交流 + * @param userId 用户id + * @param exchangeId 病例交流id + * @return bool + */ + @Transactional + public boolean UpdateCaseExchange(String userId,String exchangeId, updateCaseExchange r){ + // 获取病例交流数据 + CaseExchangeModel caseExchange = caseExchangeDao.selectById(exchangeId); + if (caseExchange == null){ + throw new BusinessException("非法操作"); + } + + if (!Objects.equals(caseExchange.getUserId(), Long.valueOf(userId))){ + throw new BusinessException("非法操作"); + } + + // 标签 + if (r.getCaseExchangeLabel() != null && !r.getCaseExchangeLabel().isEmpty()){ + for (updateCaseExchange.CaseExchangeLabelRequest caseExchangeLabelRequest : r.getCaseExchangeLabel()){ + if (caseExchangeLabelRequest.getAppIden() == null){ + throw new BusinessException("操作失败"); + } + + if (caseExchangeLabelRequest.getLabelName() == null){ + throw new BusinessException("操作失败"); + } + } + } + + // 处理违法内容 + BasicSensitiveWordService.FilterResult result = basicSensitiveWordService.filter(r.getExchangeContent()); + if (result.hasSensitive == 1){ + throw new BusinessException("内容中存在敏感词,请修改后提交"); + } + + if (r.getExchangeSummary() != null){ + result = basicSensitiveWordService.filter(r.getExchangeSummary()); + if (result.hasSensitive == 1){ + throw new BusinessException("总结中存在敏感词,请修改后提交"); + } + } + + // 匹配预览视频 + List videoUrls = regularUtil.extractOssVideosUrls(r.getExchangeContent()); + videoUrls.replaceAll(Replace::removeOssDomain); + String exchangeContentVideo = String.join(",", videoUrls); + + String exchangeContentImage = ""; + if (exchangeContentVideo.isEmpty()){ + // 匹配预览图片 + List imageUrls = regularUtil.extractOssImageUrls(r.getExchangeContent()); + imageUrls.replaceAll(Replace::removeOssDomain); + exchangeContentImage = String.join(",", imageUrls); + }else{ + exchangeContentImage = ""; + } + + // 修改病例交流 + caseExchange.setExchangeTitle(r.getExchangeTitle()); + caseExchange.setExchangeStatus(1); + caseExchange.setExchangeContent(r.getExchangeContent()); + caseExchange.setExchangeSummary(r.getExchangeSummary()); + caseExchange.setExchangeContentVideo(exchangeContentVideo); + caseExchange.setExchangeContentImage(exchangeContentImage); + caseExchangeDao.updateById(caseExchange); + + // 删除标签 + LambdaQueryWrapper labelQueryWrapper = new LambdaQueryWrapper<>(); + labelQueryWrapper.eq(CaseExchangeLabelModel::getExchangeId, exchangeId); + int res = caseExchangeLabelDao.delete(labelQueryWrapper); + if (res <= 0){ + throw new BusinessException("操作失败"); + } + + // 新增标签 + if (r.getCaseExchangeLabel() != null && !r.getCaseExchangeLabel().isEmpty()){ + // 验证标签数据-暂时无法验证,病例库不存标签库 + List caseExchangeLabel = r.getCaseExchangeLabel(); + for (updateCaseExchange.CaseExchangeLabelRequest label : caseExchangeLabel ){ + CaseExchangeLabelModel caseExchangeLabelData = new CaseExchangeLabelModel(); + caseExchangeLabelData.setExchangeId(caseExchange.getExchangeId()); + caseExchangeLabelData.setAppIden(label.getAppIden()); + caseExchangeLabelData.setLabelName(label.getLabelName()); + res = caseExchangeLabelDao.insert(caseExchangeLabelData); + if (res <= 0){ + throw new BusinessException("操作失败"); + } + } + } + + return true; + } + + + /** + * 删除-病例交流 + * @param exchangeId 病例交流id + * @param userId 用户id + * @return bool + */ + @Transactional + public boolean DeleteCaseExchange(String exchangeId, String userId){ + // 获取病例交流数据 + CaseExchangeModel caseExchange = caseExchangeDao.selectById(exchangeId); + if (caseExchange == null) { + return false; + } + + if (!Objects.equals(caseExchange.getUserId(), Long.valueOf(userId))){ + throw new BusinessException("非法操作"); + } + + // 修改病例交流删除状态 + caseExchange.setDeleteStatus(1); + caseExchangeDao.updateById(caseExchange); + + // 处理统计数据 + boolean r = DecCaseExchangeStats(exchangeId,4,1); + if (!r){ + TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); + return false; + } + + r = DecCaseExchangeStats(exchangeId,1,caseExchange.getReadNum()); + if (!r){ + TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); + return false; + } + + r = DecCaseExchangeStats(exchangeId,2,caseExchange.getCollectNum()); + if (!r){ + TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); + return false; + } + + r = DecCaseExchangeStats(exchangeId,3,caseExchange.getCommentNum()); + if (!r){ + TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); + return false; + } + + return true; + } + + /** * 新增收藏-病例交流 * @param exchangeId 病例交流id @@ -260,7 +408,7 @@ public class CaseExchangeService { } // 减少文章的统计字段 - boolean r = DecCaseExchangeStats(exchangeId,2); + boolean r = DecCaseExchangeStats(exchangeId,2,1); if (!r){ TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); return false; @@ -364,7 +512,7 @@ public class CaseExchangeService { } // 减少统计字段 - boolean r = DecCaseExchangeStats(String.valueOf(comment.getExchangeId()),2); + boolean r = DecCaseExchangeStats(String.valueOf(comment.getExchangeId()),1,1); if (!r){ TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); return false; @@ -580,10 +728,10 @@ public class CaseExchangeService { /** * 减少病例交流统计字段 * @param exchangeId 病例id - * @param type 类型:1:阅读量 2:收藏量 3:评论数 + * @param type 类型:1:阅读量 2:收藏量 3:评论数 4:数量 */ @Transactional - public boolean DecCaseExchangeStats(String exchangeId,Integer type){ + public boolean DecCaseExchangeStats(String exchangeId,Integer type,Integer num){ try { // 获取病例数据 CaseExchangeModel caseExchange = caseExchangeDao.selectById(exchangeId); @@ -601,37 +749,46 @@ public class CaseExchangeService { // 阅读量 if (type == 1){ // 总 - statsCaseExchangeDao.dec(1L,"exchange_read_num",1); + statsCaseExchangeDao.dec(1L,"exchange_read_num",num); // 单 - caseExchangeDao.dec(Long.valueOf(exchangeId),"read_num",1); + caseExchangeDao.dec(Long.valueOf(exchangeId),"read_num",num); // 用户 - statsCaseExchangeUserDao.dec(statsCaseExchangeUser.getUserId(),"exchange_read_num",1); + statsCaseExchangeUserDao.dec(statsCaseExchangeUser.getUserId(),"exchange_read_num",num); } // 收藏量 if (type == 2){ // 总 - statsCaseExchangeDao.dec(1L,"exchange_collect_num",1); + statsCaseExchangeDao.dec(1L,"exchange_collect_num",num); // 单 - caseExchangeDao.dec(Long.valueOf(exchangeId),"collect_num",1); + caseExchangeDao.dec(Long.valueOf(exchangeId),"collect_num",num); // 用户 - statsCaseExchangeUserDao.dec(statsCaseExchangeUser.getUserId(),"exchange_collect_num",1); + statsCaseExchangeUserDao.dec(statsCaseExchangeUser.getUserId(),"exchange_collect_num",num); } // 评论数 if (type == 3){ // 总 - statsCaseExchangeDao.dec(1L,"exchange_comment_num",1); + statsCaseExchangeDao.dec(1L,"exchange_comment_num",num); // 单 - caseExchangeDao.dec(Long.valueOf(exchangeId),"comment_num",1); + caseExchangeDao.dec(Long.valueOf(exchangeId),"comment_num",num); // 用户 - statsCaseExchangeUserDao.dec(statsCaseExchangeUser.getUserId(),"exchange_comment_num",1); + statsCaseExchangeUserDao.dec(statsCaseExchangeUser.getUserId(),"exchange_comment_num",num); + } + + // 数量 + if (type == 4){ + // 总 + statsCaseExchangeDao.dec(1L,"exchange_num",num); + + // 用户 + statsCaseExchangeUserDao.dec(statsCaseExchangeUser.getUserId(),"exchange_num",num); } return true; diff --git a/src/main/java/com/example/caseData/service/IndexService.java b/src/main/java/com/example/caseData/service/IndexService.java index e61bc85..62652e4 100644 --- a/src/main/java/com/example/caseData/service/IndexService.java +++ b/src/main/java/com/example/caseData/service/IndexService.java @@ -85,7 +85,7 @@ public class IndexService { caseClinicalArticleQueryWrapper = new LambdaQueryWrapper<>(); caseClinicalArticleQueryWrapper.eq(CaseClinicalArticleModel::getArticleStatus, 1) // 上线状态 .orderByDesc(CaseClinicalArticleModel::getReadNum) // 按阅读量倒序 - .last("LIMIT 2"); // 只取2条记录 + .last("LIMIT 3"); // 只取2条记录 List mostReadArticles = caseClinicalArticleDao.selectList(caseClinicalArticleQueryWrapper); for (CaseClinicalArticleModel article : mostReadArticles) { // 根据文章ID查找作者 @@ -118,7 +118,7 @@ public class IndexService { // 医院病例库推荐-2条 LambdaQueryWrapper statsCaseClinicalHospitalModelQueryWrapper = new LambdaQueryWrapper<>(); statsCaseClinicalHospitalModelQueryWrapper.orderByDesc(StatsCaseClinicalHospitalModel::getArticleNum) // 按文章数量倒序 - .last("LIMIT 2"); // 只取2条记录 + .last("LIMIT 3"); // 只取2条记录 List statsCaseClinicalHospitals = statsCaseClinicalHospitalDao.selectList(statsCaseClinicalHospitalModelQueryWrapper); for (StatsCaseClinicalHospitalModel hospital : statsCaseClinicalHospitals) { // 查询医院基础数据