Browse Source

兽医相关功能优化

master
maotiantian 3 weeks ago
parent
commit
e4ebda0877
  1. 16
      chenhai-admin/src/main/java/com/chenhai/web/controller/system/SysMedicineRecommendationController.java
  2. 892
      chenhai-admin/src/main/java/com/chenhai/web/controller/system/SysVetAuditController.java
  3. 2
      chenhai-admin/src/main/java/com/chenhai/web/controller/vet/VetNotificationController.java
  4. 903
      chenhai-admin/src/main/java/com/chenhai/web/controller/vet/VetQualificationController.java
  5. 4
      chenhai-admin/src/main/java/com/chenhai/web/controller/vet/VetTrainingVideoController.java
  6. 219
      chenhai-admin/src/main/java/com/chenhai/web/controller/vet/VetUnifiedInfoController.java
  7. 275
      chenhai-system/src/main/java/com/chenhai/muhu/service/impl/MuhuConsultationFormsServiceImpl.java
  8. 34
      chenhai-system/src/main/java/com/chenhai/system/mapper/SysMedicineRecommendationMapper.java
  9. 39
      chenhai-system/src/main/java/com/chenhai/system/service/impl/SysMedicineRecommendationServiceImpl.java
  10. 93
      chenhai-system/src/main/java/com/chenhai/vet/domain/VetComments.java
  11. 109
      chenhai-system/src/main/java/com/chenhai/vet/domain/VetNotification.java
  12. 51
      chenhai-system/src/main/java/com/chenhai/vet/domain/VetPersonalInfo.java
  13. 276
      chenhai-system/src/main/java/com/chenhai/vet/domain/VetQualification.java
  14. 8
      chenhai-system/src/main/java/com/chenhai/vet/domain/dto/VetUnifiedInfoDTO.java
  15. 127
      chenhai-system/src/main/java/com/chenhai/vet/service/impl/VetCommentsServiceImpl.java
  16. 224
      chenhai-system/src/main/java/com/chenhai/vet/service/impl/VetKnowledgeServiceImpl.java
  17. 109
      chenhai-system/src/main/java/com/chenhai/vet/service/impl/VetNotificationServiceImpl.java
  18. 111
      chenhai-system/src/main/java/com/chenhai/vet/service/impl/VetPersonalInfoServiceImpl.java
  19. 1178
      chenhai-system/src/main/java/com/chenhai/vet/service/impl/VetQualificationServiceImpl.java
  20. 165
      chenhai-system/src/main/java/com/chenhai/vet/service/impl/VetTrainingVideoServiceImpl.java
  21. 453
      chenhai-system/src/main/java/com/chenhai/vet/service/impl/VetUnifiedInfoServiceImpl.java
  22. 144
      chenhai-system/src/main/resources/mapper/system/SysMedicineRecommendationMapper.xml
  23. 46
      chenhai-system/src/main/resources/mapper/vet/VetCommentsMapper.xml
  24. 52
      chenhai-system/src/main/resources/mapper/vet/VetKnowledgeMapper.xml
  25. 11
      chenhai-system/src/main/resources/mapper/vet/VetNotificationMapper.xml
  26. 24
      chenhai-system/src/main/resources/mapper/vet/VetPersonalInfoMapper.xml
  27. 2
      chenhai-system/src/main/resources/mapper/vet/VetQualificationMapper.xml
  28. 14
      chenhai-system/src/main/resources/mapper/vet/VetTrainingVideoMapper.xml
  29. 346
      chenhai-ui/src/views/system/recommendation/index.vue

16
chenhai-admin/src/main/java/com/chenhai/web/controller/system/SysMedicineRecommendationController.java

@ -23,7 +23,7 @@ import com.chenhai.common.core.page.TableDataInfo;
/** /**
* 药品推荐Controller * 药品推荐Controller
*
*
* @author ruoyi * @author ruoyi
* @date 2026-01-20 * @date 2026-01-20
*/ */
@ -37,7 +37,7 @@ public class SysMedicineRecommendationController extends BaseController
/** /**
* 查询药品推荐列表 * 查询药品推荐列表
*/ */
@PreAuthorize("@ss.hasPermi('system:recommendation:list') or @ss.hasRole('muhu')")
@PreAuthorize("@ss.hasPermi('system:recommendation:list') or @ss.hasRole('muhu') or @ss.hasRole('vet')")
@GetMapping("/list") @GetMapping("/list")
public TableDataInfo list(SysMedicineRecommendation sysMedicineRecommendation) public TableDataInfo list(SysMedicineRecommendation sysMedicineRecommendation)
{ {
@ -49,7 +49,7 @@ public class SysMedicineRecommendationController extends BaseController
/** /**
* 导出药品推荐列表 * 导出药品推荐列表
*/ */
@PreAuthorize("@ss.hasPermi('system:recommendation:export') or @ss.hasRole('muhu')")
@PreAuthorize("@ss.hasPermi('system:recommendation:export') or @ss.hasRole('muhu') or @ss.hasRole('vet')")
@Log(title = "药品推荐", businessType = BusinessType.EXPORT) @Log(title = "药品推荐", businessType = BusinessType.EXPORT)
@PostMapping("/export") @PostMapping("/export")
public void export(HttpServletResponse response, SysMedicineRecommendation sysMedicineRecommendation) public void export(HttpServletResponse response, SysMedicineRecommendation sysMedicineRecommendation)
@ -62,7 +62,7 @@ public class SysMedicineRecommendationController extends BaseController
/** /**
* 获取药品推荐详细信息 * 获取药品推荐详细信息
*/ */
@PreAuthorize("@ss.hasPermi('system:recommendation:query') or @ss.hasRole('muhu')")
@PreAuthorize("@ss.hasPermi('system:recommendation:query') or @ss.hasRole('muhu') or @ss.hasRole('vet')")
@GetMapping(value = "/{id}") @GetMapping(value = "/{id}")
public AjaxResult getInfo(@PathVariable("id") Long id) public AjaxResult getInfo(@PathVariable("id") Long id)
{ {
@ -72,7 +72,7 @@ public class SysMedicineRecommendationController extends BaseController
/** /**
* 新增药品推荐 * 新增药品推荐
*/ */
@PreAuthorize("@ss.hasPermi('system:recommendation:add') or @ss.hasRole('muhu')")
@PreAuthorize("@ss.hasPermi('system:recommendation:add') or @ss.hasRole('muhu') or @ss.hasRole('vet')")
@Log(title = "药品推荐", businessType = BusinessType.INSERT) @Log(title = "药品推荐", businessType = BusinessType.INSERT)
@PostMapping @PostMapping
public AjaxResult add(@RequestBody SysMedicineRecommendation sysMedicineRecommendation) public AjaxResult add(@RequestBody SysMedicineRecommendation sysMedicineRecommendation)
@ -83,7 +83,7 @@ public class SysMedicineRecommendationController extends BaseController
/** /**
* 修改药品推荐 * 修改药品推荐
*/ */
@PreAuthorize("@ss.hasPermi('system:recommendation:edit') or @ss.hasRole('muhu')")
@PreAuthorize("@ss.hasPermi('system:recommendation:edit') or @ss.hasRole('muhu') or @ss.hasRole('vet')")
@Log(title = "药品推荐", businessType = BusinessType.UPDATE) @Log(title = "药品推荐", businessType = BusinessType.UPDATE)
@PutMapping @PutMapping
public AjaxResult edit(@RequestBody SysMedicineRecommendation sysMedicineRecommendation) public AjaxResult edit(@RequestBody SysMedicineRecommendation sysMedicineRecommendation)
@ -94,9 +94,9 @@ public class SysMedicineRecommendationController extends BaseController
/** /**
* 删除药品推荐 * 删除药品推荐
*/ */
@PreAuthorize("@ss.hasPermi('system:recommendation:remove') or @ss.hasRole('muhu')")
@PreAuthorize("@ss.hasPermi('system:recommendation:remove') or @ss.hasRole('muhu') or @ss.hasRole('vet')")
@Log(title = "药品推荐", businessType = BusinessType.DELETE) @Log(title = "药品推荐", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable Long[] ids) public AjaxResult remove(@PathVariable Long[] ids)
{ {
return toAjax(sysMedicineRecommendationService.deleteSysMedicineRecommendationByIds(ids)); return toAjax(sysMedicineRecommendationService.deleteSysMedicineRecommendationByIds(ids));

892
chenhai-admin/src/main/java/com/chenhai/web/controller/system/SysVetAuditController.java

@ -6,21 +6,22 @@ import com.chenhai.common.core.domain.AjaxResult;
import com.chenhai.common.core.page.TableDataInfo; import com.chenhai.common.core.page.TableDataInfo;
import com.chenhai.common.enums.BusinessType; import com.chenhai.common.enums.BusinessType;
import com.chenhai.common.utils.SecurityUtils; import com.chenhai.common.utils.SecurityUtils;
import com.chenhai.common.utils.StringUtils;
import com.chenhai.common.utils.poi.ExcelUtil; import com.chenhai.common.utils.poi.ExcelUtil;
import com.chenhai.vet.domain.VetPersonalInfo; import com.chenhai.vet.domain.VetPersonalInfo;
import com.chenhai.vet.domain.VetQualification; import com.chenhai.vet.domain.VetQualification;
import com.chenhai.vet.service.IVetPersonalInfoService; import com.chenhai.vet.service.IVetPersonalInfoService;
import com.chenhai.vet.service.IVetQualificationService; import com.chenhai.vet.service.IVetQualificationService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
/** /**
* 兽医信息审核管理Controller * 兽医信息审核管理Controller
@ -30,14 +31,61 @@ import java.util.Map;
@RequestMapping("/sys/vet/audit") @RequestMapping("/sys/vet/audit")
public class SysVetAuditController extends BaseController public class SysVetAuditController extends BaseController
{ {
private static final Logger log = LoggerFactory.getLogger(SysVetAuditController.class);
@Autowired @Autowired
private IVetPersonalInfoService vetPersonalInfoService; private IVetPersonalInfoService vetPersonalInfoService;
@Autowired @Autowired
private IVetQualificationService vetQualificationService; private IVetQualificationService vetQualificationService;
// 请求去重缓存key = 用户ID + 操作类型 + 目标IDvalue = 时间戳
private final Map<String, Long> requestCache = new ConcurrentHashMap<>();
private static final long REQUEST_TIMEOUT = 3000; // 3秒内相同请求视为重复
/** /**
* 查询兽医信息列表审核管理专用
* 检查是否为重复请求
* @param userId 操作用户ID
* @param operationType 操作类型
* @param targetId 目标ID
* @return true=重复请求false=新请求
*/
private boolean isDuplicateRequest(Long userId, String operationType, Long targetId) {
if (userId == null || targetId == null) {
return false;
}
String key = userId + "_" + operationType + "_" + targetId;
Long lastTime = requestCache.get(key);
long now = System.currentTimeMillis();
if (lastTime != null && (now - lastTime) < REQUEST_TIMEOUT) {
log.warn("检测到重复请求 - 用户: {}, 操作: {}, 目标ID: {}, 间隔: {}ms",
userId, operationType, targetId, now - lastTime);
return true;
}
requestCache.put(key, now);
// 定期清理过期缓存每1000次请求清理一次避免内存泄漏
if (requestCache.size() > 1000) {
cleanExpiredCache();
}
return false;
}
/**
* 清理过期的请求缓存
*/
private void cleanExpiredCache() {
long now = System.currentTimeMillis();
requestCache.entrySet().removeIf(entry -> (now - entry.getValue()) > REQUEST_TIMEOUT);
log.debug("清理过期缓存完成,当前缓存大小: {}", requestCache.size());
}
/**
* 查询兽医信息列表审核管理专用- 包含综合审核状态
*/ */
@PreAuthorize("@ss.hasPermi('sys:vetAudit:list') or @ss.hasRole('muhu') or @ss.hasRole('vet')") @PreAuthorize("@ss.hasPermi('sys:vetAudit:list') or @ss.hasRole('muhu') or @ss.hasRole('vet')")
@GetMapping("/list") @GetMapping("/list")
@ -45,9 +93,59 @@ public class SysVetAuditController extends BaseController
{ {
startPage(); startPage();
List<VetPersonalInfo> list = vetPersonalInfoService.selectVetPersonalInfoList(vetPersonalInfo); List<VetPersonalInfo> list = vetPersonalInfoService.selectVetPersonalInfoList(vetPersonalInfo);
// 为每个兽医计算综合审核状态
for (VetPersonalInfo info : list) {
calculateOverallAuditStatus(info);
}
// ========== 新增在内存中按综合状态排序 ==========
// 排序规则待审核(0) > 已拒绝(2) > 已通过(1)
list.sort((a, b) -> {
String statusA = a.getOverallAuditStatus();
String statusB = b.getOverallAuditStatus();
int orderA = getAuditStatusOrder(statusA);
int orderB = getAuditStatusOrder(statusB);
if (orderA != orderB) {
return Integer.compare(orderA, orderB);
}
// 相同状态按创建时间倒序
Date timeA = a.getCreateTime();
Date timeB = b.getCreateTime();
if (timeA != null && timeB != null) {
return timeB.compareTo(timeA);
}
return 0;
});
// 用综合状态覆盖原来的审核状态用于前端显示
for (VetPersonalInfo info : list) {
if (StringUtils.isNotEmpty(info.getOverallAuditStatus())) {
info.setAuditStatus(info.getOverallAuditStatus());
}
}
return getDataTable(list); return getDataTable(list);
} }
/**
* 获取审核状态的排序权重
* @param status 审核状态
* @return 排序权重数字越小越靠前
*/
private int getAuditStatusOrder(String status) {
if ("0".equals(status)) {
return 1; // 待审核排最前
} else if ("2".equals(status)) {
return 2; // 已拒绝排中间
} else if ("1".equals(status)) {
return 3; // 已通过排最后
}
return 4;
}
/** /**
* 查询审核通过的兽医列表 * 查询审核通过的兽医列表
* 用于前台展示已认证兽医 * 用于前台展示已认证兽医
@ -60,7 +158,27 @@ public class SysVetAuditController extends BaseController
// 设置审核状态为已通过假设1表示审核通过请根据实际状态码调整 // 设置审核状态为已通过假设1表示审核通过请根据实际状态码调整
vetPersonalInfo.setAuditStatus("1"); vetPersonalInfo.setAuditStatus("1");
List<VetPersonalInfo> list = vetPersonalInfoService.selectVetPersonalInfoList(vetPersonalInfo); List<VetPersonalInfo> list = vetPersonalInfoService.selectVetPersonalInfoList(vetPersonalInfo);
return getDataTable(list);
// 为每个兽医计算综合审核状态
for (VetPersonalInfo info : list) {
calculateOverallAuditStatus(info);
// 注意这里不覆盖因为要筛选已通过的
}
// 过滤出综合状态为已通过的
List<VetPersonalInfo> filteredList = new ArrayList<>();
for (VetPersonalInfo info : list) {
if ("1".equals(info.getOverallAuditStatus())) {
filteredList.add(info);
}
}
TableDataInfo rspData = new TableDataInfo();
rspData.setCode(200);
rspData.setMsg("查询成功");
rspData.setRows(filteredList);
rspData.setTotal(filteredList.size());
return rspData;
} }
/** /**
@ -74,41 +192,230 @@ public class SysVetAuditController extends BaseController
if (fullInfo == null || fullInfo.isEmpty()) { if (fullInfo == null || fullInfo.isEmpty()) {
return AjaxResult.error("兽医信息不存在"); return AjaxResult.error("兽医信息不存在");
} }
// 计算综合审核状态
VetPersonalInfo vetInfo = (VetPersonalInfo) fullInfo.get("vetInfo");
if (vetInfo != null) {
calculateOverallAuditStatus(vetInfo);
// 用综合状态覆盖原来的审核状态
if (StringUtils.isNotEmpty(vetInfo.getOverallAuditStatus())) {
vetInfo.setAuditStatus(vetInfo.getOverallAuditStatus());
}
fullInfo.put("vetInfo", vetInfo);
fullInfo.put("overallAuditStatus", vetInfo.getOverallAuditStatus());
fullInfo.put("overallAuditStatusLabel", getAuditStatusLabel(vetInfo.getOverallAuditStatus()));
}
return AjaxResult.success(fullInfo); return AjaxResult.success(fullInfo);
} }
/** /**
* 获取兽医个人信息详细信息
* 获取兽医个人信息详细信息 - 包含综合审核状态
*/ */
@PreAuthorize("@ss.hasPermi('sys:vetAudit:userInfo')") @PreAuthorize("@ss.hasPermi('sys:vetAudit:userInfo')")
@GetMapping(value = "/{id}") @GetMapping(value = "/{id}")
public AjaxResult getInfo(@PathVariable("id") Long id) public AjaxResult getInfo(@PathVariable("id") Long id)
{ {
return success(vetPersonalInfoService.selectVetPersonalInfoById(id));
VetPersonalInfo info = vetPersonalInfoService.selectVetPersonalInfoById(id);
if (info != null) {
calculateOverallAuditStatus(info);
// 用综合状态覆盖原来的审核状态
if (StringUtils.isNotEmpty(info.getOverallAuditStatus())) {
info.setAuditStatus(info.getOverallAuditStatus());
}
}
return success(info);
} }
/** /**
* 兽医个人信息审核
* 兽医个人信息审核 - 支持同时处理个人信息和资质
* 兼容原有的单一审核和批量审核
*/ */
@Log(title = "兽医信息审核", businessType = BusinessType.UPDATE) @Log(title = "兽医信息审核", businessType = BusinessType.UPDATE)
@PreAuthorize("@ss.hasPermi('sys:vetAudit:auditVetPersonalInfo')") @PreAuthorize("@ss.hasPermi('sys:vetAudit:auditVetPersonalInfo')")
@PostMapping("/auditVetPersonalInfo") @PostMapping("/auditVetPersonalInfo")
public AjaxResult auditVetPersonalInfo(@RequestBody VetPersonalInfo vetPersonalInfo)
public AjaxResult auditVetPersonalInfo(@RequestBody Map<String, Object> requestData, HttpServletRequest request)
{ {
return toAjax(vetPersonalInfoService.auditVetPersonalInfo(vetPersonalInfo));
Long currentUserId = SecurityUtils.getUserId();
try {
// 批量审核结果收集
List<Map<String, Object>> auditResults = new ArrayList<>();
int successCount = 0;
int failCount = 0;
// 1. 处理个人信息审核
if (requestData.containsKey("personalInfo")) {
Map<String, Object> personalData = (Map<String, Object>) requestData.get("personalInfo");
Long targetId = ((Number) personalData.get("id")).longValue();
// 防重复提交检查
if (isDuplicateRequest(currentUserId, "personalInfo", targetId)) {
log.info("拦截重复的个人信息审核请求 - 用户: {}, 个人信息ID: {}", currentUserId, targetId);
Map<String, Object> result = new HashMap<>();
result.put("type", "personalInfo");
result.put("id", targetId);
result.put("success", true);
result.put("isDuplicate", true);
auditResults.add(result);
successCount++;
} else {
VetPersonalInfo vetPersonalInfo = new VetPersonalInfo();
vetPersonalInfo.setId(targetId);
vetPersonalInfo.setAuditStatus((String) personalData.get("auditStatus"));
vetPersonalInfo.setAuditDesc((String) personalData.get("auditDesc"));
int result = vetPersonalInfoService.auditVetPersonalInfo(vetPersonalInfo);
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("type", "personalInfo");
resultMap.put("id", targetId);
resultMap.put("success", result > 0);
if (result > 0) {
successCount++;
} else {
failCount++;
resultMap.put("error", "审核失败");
}
auditResults.add(resultMap);
}
} else if (requestData.containsKey("id")) {
// 兼容旧的单一数据格式
VetPersonalInfo vetPersonalInfo = new VetPersonalInfo();
vetPersonalInfo.setId(((Number) requestData.get("id")).longValue());
vetPersonalInfo.setAuditStatus((String) requestData.get("auditStatus"));
vetPersonalInfo.setAuditDesc((String) requestData.get("auditDesc"));
Long targetId = vetPersonalInfo.getId();
// 防重复提交检查
if (isDuplicateRequest(currentUserId, "personalInfo", targetId)) {
log.info("拦截重复的个人信息审核请求 - 用户: {}, 个人信息ID: {}", currentUserId, targetId);
Map<String, Object> result = new HashMap<>();
result.put("success", true);
result.put("id", targetId);
result.put("message", "处理成功");
result.put("isDuplicate", true);
return success(result);
}
int result = vetPersonalInfoService.auditVetPersonalInfo(vetPersonalInfo);
if (result > 0) {
VetPersonalInfo updatedInfo = vetPersonalInfoService.selectVetPersonalInfoById(vetPersonalInfo.getId());
if (updatedInfo != null) {
calculateOverallAuditStatus(updatedInfo);
if (StringUtils.isNotEmpty(updatedInfo.getOverallAuditStatus())) {
updatedInfo.setAuditStatus(updatedInfo.getOverallAuditStatus());
}
return success(updatedInfo);
}
}
return toAjax(result);
}
// 2. 处理资质审核
if (requestData.containsKey("qualifications")) {
List<Map<String, Object>> qualifications = (List<Map<String, Object>>) requestData.get("qualifications");
for (Map<String, Object> qualData : qualifications) {
Long targetId = ((Number) qualData.get("qualificationId")).longValue();
// 防重复提交检查
if (isDuplicateRequest(currentUserId, "qualification", targetId)) {
log.info("拦截重复的资质审核请求 - 用户: {}, 资质ID: {}", currentUserId, targetId);
Map<String, Object> result = new HashMap<>();
result.put("type", "qualification");
result.put("id", targetId);
result.put("success", true);
result.put("isDuplicate", true);
auditResults.add(result);
successCount++;
} else {
VetQualification qualification = new VetQualification();
qualification.setQualificationId(targetId);
qualification.setAuditStatus((String) qualData.get("auditStatus"));
qualification.setAuditOpinion((String) qualData.get("auditOpinion"));
qualification.setAuditTime(new Date());
int result = vetQualificationService.updateVetQualification(qualification);
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("type", "qualification");
resultMap.put("id", targetId);
resultMap.put("success", result > 0);
if (result > 0) {
successCount++;
} else {
failCount++;
resultMap.put("error", "审核失败");
}
auditResults.add(resultMap);
}
}
} else if (requestData.containsKey("qualificationId")) {
// 兼容旧的单一资质格式
VetQualification vetQualification = new VetQualification();
vetQualification.setQualificationId(((Number) requestData.get("qualificationId")).longValue());
vetQualification.setAuditStatus((String) requestData.get("auditStatus"));
vetQualification.setAuditOpinion((String) requestData.get("auditOpinion"));
vetQualification.setAuditTime(new Date());
Long targetId = vetQualification.getQualificationId();
// 防重复提交检查
if (isDuplicateRequest(currentUserId, "qualification", targetId)) {
log.info("拦截重复的资质审核请求 - 用户: {}, 资质ID: {}", currentUserId, targetId);
Map<String, Object> result = new HashMap<>();
result.put("success", true);
result.put("qualificationId", targetId);
result.put("message", "处理成功");
result.put("isDuplicate", true);
return success(result);
}
int result = vetQualificationService.updateVetQualification(vetQualification);
if (result > 0 && vetQualification.getUserId() != null) {
VetPersonalInfo vetInfo = vetPersonalInfoService.selectVetPersonalInfoByUserId(vetQualification.getUserId());
if (vetInfo != null) {
calculateOverallAuditStatus(vetInfo);
if (StringUtils.isNotEmpty(vetInfo.getOverallAuditStatus())) {
vetInfo.setAuditStatus(vetInfo.getOverallAuditStatus());
}
return success(vetInfo);
}
}
return toAjax(result);
}
// 返回批量审核结果
Map<String, Object> response = new HashMap<>();
response.put("successCount", successCount);
response.put("failCount", failCount);
response.put("total", successCount + failCount);
response.put("results", auditResults);
if (failCount == 0) {
response.put("message", "审核完成,共" + (successCount + failCount) + "条,全部成功");
} else {
response.put("message", "审核完成,成功" + successCount + "条,失败" + failCount + "条");
}
return success(response);
} catch (Exception e) {
log.error("审核失败", e);
return error("审核失败:" + e.getMessage());
}
} }
/** /**
* 查询兽医资质列表含证书信息
*/
/**
* 查询兽医资质列表含证书信息
* 查询兽医资质列表自动展开证书并包含综合状态
*/ */
@PreAuthorize("@ss.hasPermi('vet:qualification:list') or @ss.hasRole('manger')") @PreAuthorize("@ss.hasPermi('vet:qualification:list') or @ss.hasRole('manger')")
@GetMapping("/listQualification") @GetMapping("/listQualification")
public TableDataInfo listQualification(VetQualification vetQualification) public TableDataInfo listQualification(VetQualification vetQualification)
{ {
startPage();
Long userId = SecurityUtils.getUserId(); Long userId = SecurityUtils.getUserId();
// 管理员和manger角色可以查看所有数据 // 管理员和manger角色可以查看所有数据
@ -116,32 +423,549 @@ public class SysVetAuditController extends BaseController
vetQualification.setUserId(userId); vetQualification.setUserId(userId);
} }
List<VetQualification> list = vetQualificationService.selectVetQualificationList(vetQualification);
// 获取所有资质
List<VetQualification> qualifications = vetQualificationService.selectVetQualificationList(vetQualification);
// 将证书展开为独立记录
List<Map<String, Object>> expandedList = new ArrayList<>();
for (VetQualification qualification : qualifications) {
List<Map<String, Object>> certificates = qualification.getCertificates();
if (certificates != null && !certificates.isEmpty()) {
// 有证书展开每个证书
for (Map<String, Object> cert : certificates) {
Map<String, Object> record = new LinkedHashMap<>();
// 复制资质字段
record.put("qualificationId", qualification.getQualificationId());
record.put("userId", qualification.getUserId());
record.put("realName", qualification.getRealName());
record.put("idCard", qualification.getIdCard());
record.put("qualificationType", qualification.getQualificationType());
record.put("qualificationTypeLabel", qualification.getQualificationTypeLabel());
record.put("auditStatus", qualification.getAuditStatus());
record.put("auditStatusLabel", qualification.getAuditStatusLabel());
record.put("auditTime", qualification.getAuditTime());
record.put("auditOpinion", qualification.getAuditOpinion());
record.put("applyTime", qualification.getApplyTime());
record.put("createTime", qualification.getCreateTime());
record.put("createBy", qualification.getCreateBy());
record.put("updateTime", qualification.getUpdateTime());
record.put("updateBy", qualification.getUpdateBy());
record.put("scopeIds", qualification.getScopeIds());
record.put("scopeNames", qualification.getScopeNames());
record.put("scopeNamesLabel", qualification.getScopeNamesLabel());
// 复制证书字段
record.put("certId", cert.get("certId"));
record.put("certName", cert.get("certName"));
record.put("certStatus", cert.get("certStatus"));
record.put("certStatusLabel", cert.get("certStatusLabel"));
record.put("certImage", cert.get("certImage"));
record.put("certificateFiles", cert.get("certificateFiles"));
record.put("certificateNo", cert.get("certificateNo"));
record.put("issueDate", cert.get("issueDate"));
record.put("expireDate", cert.get("expireDate"));
record.put("issueOrg", cert.get("issueOrg"));
// 添加类型标识
record.put("recordType", "certificate");
expandedList.add(record);
}
} else {
// 没有证书返回资质本身
Map<String, Object> record = new LinkedHashMap<>();
// 复制资质字段
record.put("qualificationId", qualification.getQualificationId());
record.put("userId", qualification.getUserId());
record.put("realName", qualification.getRealName());
record.put("idCard", qualification.getIdCard());
record.put("qualificationType", qualification.getQualificationType());
record.put("qualificationTypeLabel", qualification.getQualificationTypeLabel());
record.put("auditStatus", qualification.getAuditStatus());
record.put("auditStatusLabel", qualification.getAuditStatusLabel());
record.put("auditTime", qualification.getAuditTime());
record.put("auditOpinion", qualification.getAuditOpinion());
record.put("applyTime", qualification.getApplyTime());
record.put("createTime", qualification.getCreateTime());
record.put("createBy", qualification.getCreateBy());
record.put("updateTime", qualification.getUpdateTime());
record.put("updateBy", qualification.getUpdateBy());
record.put("scopeIds", qualification.getScopeIds());
record.put("scopeNames", qualification.getScopeNames());
record.put("scopeNamesLabel", qualification.getScopeNamesLabel());
record.put("recordType", "qualification");
expandedList.add(record);
}
}
// 手动分页
int pageNum = 1;
int pageSize = 10;
// 调试日志
for (VetQualification qualification : list) {
System.out.println("===== 资质信息 =====");
System.out.println("qualificationId: " + qualification.getQualificationId());
System.out.println("auditStatus: " + qualification.getAuditStatus());
System.out.println("auditStatusLabel: " + qualification.getAuditStatusLabel());
System.out.println("certStatus: " + qualification.getCertStatus());
System.out.println("certStatusLabel: " + qualification.getCertStatusLabel());
System.out.println("scopeNames: " + qualification.getScopeNames());
System.out.println("certificateList size: " +
(qualification.getCertificateList() != null ? qualification.getCertificateList().size() : 0));
if (vetQualification.getParams() != null) {
if (vetQualification.getParams().get("pageNum") != null) {
pageNum = Integer.parseInt(vetQualification.getParams().get("pageNum").toString());
}
if (vetQualification.getParams().get("pageSize") != null) {
pageSize = Integer.parseInt(vetQualification.getParams().get("pageSize").toString());
}
} }
return getDataTable(list);
int total = expandedList.size();
int start = (pageNum - 1) * pageSize;
int end = Math.min(start + pageSize, total);
List<Map<String, Object>> pageList = start < total ? expandedList.subList(start, end) : new ArrayList<>();
TableDataInfo rspData = new TableDataInfo();
rspData.setCode(200);
rspData.setMsg("查询成功");
rspData.setRows(pageList);
rspData.setTotal(total);
return rspData;
} }
/** /**
* 资质证书审核接口
* 资质证书审核接口 - 支持证书ID数组批量审核
* 前端格式{"certId": [id1, id2, ...], "auditStatus": "1", "auditOpinion": ""}
*/ */
@Log(title = "兽医资质证书审核", businessType = BusinessType.UPDATE) @Log(title = "兽医资质证书审核", businessType = BusinessType.UPDATE)
@PreAuthorize("@ss.hasPermi('sys:vetAudit:qualificationAudit')") @PreAuthorize("@ss.hasPermi('sys:vetAudit:qualificationAudit')")
@PostMapping("/qualificationAudit") @PostMapping("/qualificationAudit")
public AjaxResult qualificationAudit(@RequestBody VetQualification vetQualification) {
vetQualification.setAuditTime(new Date());
return toAjax(vetQualificationService.updateVetQualification(vetQualification));
public AjaxResult qualificationAudit(@RequestBody Map<String, Object> requestData, HttpServletRequest request) {
Long currentUserId = SecurityUtils.getUserId();
try {
// 检查是否为证书ID数组格式
if (requestData.containsKey("certId") && requestData.get("certId") instanceof List) {
List<?> certIdList = (List<?>) requestData.get("certId");
String auditStatus = (String) requestData.get("auditStatus");
String auditOpinion = (String) requestData.get("auditOpinion");
if (certIdList == null || certIdList.isEmpty()) {
return error("证书ID列表不能为空");
}
log.info("批量审核证书 - 用户: {}, 证书数量: {}, 审核状态: {}",
currentUserId, certIdList.size(), auditStatus);
// 批量审核结果收集
List<Map<String, Object>> auditResults = new ArrayList<>();
int successCount = 0;
int failCount = 0;
for (Object certIdObj : certIdList) {
Long certId = null;
try {
if (certIdObj instanceof Number) {
certId = ((Number) certIdObj).longValue();
} else if (certIdObj instanceof String) {
certId = Long.parseLong((String) certIdObj);
} else {
throw new IllegalArgumentException("证书ID格式错误");
}
} catch (Exception e) {
log.warn("解析证书ID失败: {}", certIdObj);
Map<String, Object> resultItem = new HashMap<>();
resultItem.put("certId", certIdObj);
resultItem.put("success", false);
resultItem.put("error", "证书ID格式错误");
auditResults.add(resultItem);
failCount++;
continue;
}
// 防重复提交检查
if (isDuplicateRequest(currentUserId, "certificate", certId)) {
log.info("拦截重复的证书审核请求 - 用户: {}, 证书ID: {}", currentUserId, certId);
Map<String, Object> resultItem = new HashMap<>();
resultItem.put("certId", certId);
resultItem.put("success", true);
resultItem.put("isDuplicate", true);
auditResults.add(resultItem);
successCount++;
continue;
}
// 根据证书ID查找并更新证书
try {
VetQualification qualification = findQualificationByCertId(certId);
if (qualification == null) {
Map<String, Object> resultItem = new HashMap<>();
resultItem.put("certId", certId);
resultItem.put("success", false);
resultItem.put("error", "未找到该证书");
auditResults.add(resultItem);
failCount++;
continue;
}
// 更新证书的审核状态
boolean updated = updateCertificateStatus(qualification, certId, auditStatus, auditOpinion);
if (updated) {
// 更新资质
qualification.setUpdateBy(SecurityUtils.getUsername());
qualification.setUpdateTime(new Date());
int updateResult = vetQualificationService.updateVetQualification(qualification);
if (updateResult > 0) {
Map<String, Object> resultItem = new HashMap<>();
resultItem.put("certId", certId);
resultItem.put("qualificationId", qualification.getQualificationId());
resultItem.put("userId", qualification.getUserId());
resultItem.put("success", true);
auditResults.add(resultItem);
successCount++;
// 注意不需要手动更新兽医个人信息
// 因为 updateVetQualification 方法内部已经调用了 updateVetPersonalAuditStatus
// 它会自动更新兽医个人信息的审核状态
} else {
Map<String, Object> resultItem = new HashMap<>();
resultItem.put("certId", certId);
resultItem.put("success", false);
resultItem.put("error", "更新资质失败");
auditResults.add(resultItem);
failCount++;
}
} else {
Map<String, Object> resultItem = new HashMap<>();
resultItem.put("certId", certId);
resultItem.put("success", false);
resultItem.put("error", "未找到证书或更新失败");
auditResults.add(resultItem);
failCount++;
}
} catch (Exception e) {
log.error("审核证书失败 - certId: {}", certId, e);
Map<String, Object> resultItem = new HashMap<>();
resultItem.put("certId", certId);
resultItem.put("success", false);
resultItem.put("error", e.getMessage());
auditResults.add(resultItem);
failCount++;
}
}
// 返回批量审核结果
Map<String, Object> response = new HashMap<>();
response.put("successCount", successCount);
response.put("failCount", failCount);
response.put("total", successCount + failCount);
response.put("results", auditResults);
if (failCount == 0) {
response.put("message", "审核完成,共" + (successCount + failCount) + "条,全部成功");
} else {
response.put("message", "审核完成,成功" + successCount + "条,失败" + failCount + "条");
}
return success(response);
}
// 如果不是证书ID数组格式则调用原来的方法
return auditVetPersonalInfo(requestData, request);
} catch (Exception e) {
log.error("审核失败", e);
return error("审核失败:" + e.getMessage());
}
}
/**
* 根据证书ID查找包含该证书的资质
*/
private VetQualification findQualificationByCertId(Long certId) {
// 查询所有资质
VetQualification query = new VetQualification();
List<VetQualification> allQualifications = vetQualificationService.selectVetQualificationList(query);
for (VetQualification qualification : allQualifications) {
List<Map<String, Object>> certificates = qualification.getCertificates();
if (certificates != null) {
for (Map<String, Object> cert : certificates) {
Long currentCertId = extractCertId(cert.get("certId"));
if (currentCertId != null && currentCertId.equals(certId)) {
return qualification;
}
}
}
}
return null;
}
/**
* 更新证书的审核状态
*/
private boolean updateCertificateStatus(VetQualification qualification, Long certId, String auditStatus, String auditOpinion) {
List<Map<String, Object>> certificates = qualification.getCertificates();
if (certificates == null || certificates.isEmpty()) {
log.warn("资质没有证书列表 - qualificationId: {}", qualification.getQualificationId());
return false;
}
boolean found = false;
for (Map<String, Object> cert : certificates) {
Long currentCertId = extractCertId(cert.get("certId"));
if (currentCertId != null && currentCertId.equals(certId)) {
// 同时设置 auditStatus certStatus 字段
cert.put("auditStatus", auditStatus);
cert.put("certStatus", auditStatus);
if (auditOpinion != null) {
cert.put("auditOpinion", auditOpinion);
}
// 添加审核时间
cert.put("auditTime", new Date());
found = true;
log.info("找到并更新证书 - certId: {}, 新状态: {}, 字段已更新", certId, auditStatus);
break;
}
}
if (found) {
// 更新证书JSON
try {
com.fasterxml.jackson.databind.ObjectMapper mapper = new com.fasterxml.jackson.databind.ObjectMapper();
String newCertificatesJson = mapper.writeValueAsString(certificates);
qualification.setCertificatesJson(newCertificatesJson);
qualification.setCertificates(certificates);
log.info("证书JSON已更新 - qualificationId: {}, JSON长度: {}",
qualification.getQualificationId(), newCertificatesJson.length());
// 更新资质审核状态根据所有证书的审核状态
updateQualificationAuditStatus(qualification);
return true;
} catch (Exception e) {
log.error("更新证书JSON失败", e);
return false;
}
} else {
log.warn("未找到要更新的证书 - certId: {}, qualificationId: {}", certId, qualification.getQualificationId());
}
return found;
}
/**
* 从对象中提取证书ID
*/
private Long extractCertId(Object certIdObj) {
if (certIdObj == null) {
return null;
}
try {
if (certIdObj instanceof Number) {
return ((Number) certIdObj).longValue();
} else if (certIdObj instanceof String) {
return Long.parseLong((String) certIdObj);
}
} catch (Exception e) {
// 忽略
}
return null;
}
/**
* 根据证书审核状态更新资质的综合审核状态
*/
private void updateQualificationAuditStatus(VetQualification qualification) {
List<Map<String, Object>> certificates = qualification.getCertificates();
if (certificates == null || certificates.isEmpty()) {
log.warn("资质没有证书列表 - qualificationId: {}", qualification.getQualificationId());
return;
}
log.info("更新资质审核状态 - qualificationId: {}, 证书数量: {}",
qualification.getQualificationId(), certificates.size());
boolean allApproved = true;
boolean anyRejected = false;
boolean anyPending = false;
for (int i = 0; i < certificates.size(); i++) {
Map<String, Object> cert = certificates.get(i);
// 尝试多种方式获取审核状态
String certAuditStatus = null;
// 方式1: 直接获取 auditStatus
Object statusObj = cert.get("auditStatus");
if (statusObj != null) {
certAuditStatus = statusObj.toString();
}
// 方式2: 如果为空尝试从 certStatus 字段获取
if (certAuditStatus == null) {
Object certStatusObj = cert.get("certStatus");
if (certStatusObj != null) {
certAuditStatus = certStatusObj.toString();
log.info("证书 {} 使用 certStatus 字段: {}", i, certAuditStatus);
}
}
log.info("证书 {} - certId: {}, auditStatus: {}", i, cert.get("certId"), certAuditStatus);
if (certAuditStatus == null || "0".equals(certAuditStatus)) {
anyPending = true;
allApproved = false;
log.info("证书 {} 状态为待审核或未设置", i);
} else if ("2".equals(certAuditStatus)) {
anyRejected = true;
allApproved = false;
log.info("证书 {} 状态为已拒绝", i);
} else if ("1".equals(certAuditStatus)) {
// 已通过继续检查
log.info("证书 {} 状态为已通过", i);
} else {
anyPending = true;
allApproved = false;
log.info("证书 {} 状态未知: {}", i, certAuditStatus);
}
}
String qualStatus;
if (anyPending) {
qualStatus = "0";
} else if (anyRejected) {
qualStatus = "2";
} else if (allApproved) {
qualStatus = "1";
} else {
qualStatus = "0";
}
log.info("资质 {} 最终审核状态: {} (anyPending: {}, anyRejected: {}, allApproved: {})",
qualification.getQualificationId(), qualStatus, anyPending, anyRejected, allApproved);
qualification.setAuditStatus(qualStatus);
// 如果所有证书都审核通过且资质还没有审核时间则设置审核时间
if ("1".equals(qualStatus) && qualification.getAuditTime() == null) {
qualification.setAuditTime(new Date());
log.info("设置资质审核时间: {}", qualification.getAuditTime());
}
}
/**
* 计算兽医的综合审核状态
* 规则只要个人信息或任一资质证书为待审核综合状态就是待审核
*
* @param vetInfo 兽医个人信息
*/
private void calculateOverallAuditStatus(VetPersonalInfo vetInfo) {
if (vetInfo == null || vetInfo.getUserId() == null) {
return;
}
// 1. 获取个人信息审核状态
String personalAuditStatus = vetInfo.getAuditStatus();
// 2. 获取所有资质证书的审核状态
VetQualification query = new VetQualification();
query.setUserId(vetInfo.getUserId());
List<VetQualification> qualifications = vetQualificationService.selectVetQualificationList(query);
// 3. 统计各类审核状态
boolean hasPending = false;
boolean hasRejected = false;
int pendingCount = 0;
int approvedCount = 0;
int rejectedCount = 0;
// 检查个人信息
if ("0".equals(personalAuditStatus)) {
hasPending = true;
pendingCount++;
} else if ("2".equals(personalAuditStatus)) {
hasRejected = true;
rejectedCount++;
} else if ("1".equals(personalAuditStatus)) {
approvedCount++;
}
// 检查所有资质和证书
for (VetQualification qualification : qualifications) {
// 检查资质审核状态
String qualStatus = qualification.getAuditStatus();
if ("0".equals(qualStatus)) {
hasPending = true;
pendingCount++;
} else if ("2".equals(qualStatus)) {
hasRejected = true;
rejectedCount++;
} else if ("1".equals(qualStatus)) {
approvedCount++;
}
// 检查证书审核状态
List<Map<String, Object>> certificates = qualification.getCertificates();
if (certificates != null) {
for (Map<String, Object> cert : certificates) {
String certAuditStatus = (String) cert.get("auditStatus");
if (certAuditStatus != null) {
if ("0".equals(certAuditStatus)) {
hasPending = true;
pendingCount++;
} else if ("2".equals(certAuditStatus)) {
hasRejected = true;
rejectedCount++;
} else if ("1".equals(certAuditStatus)) {
approvedCount++;
}
}
}
}
}
// 4. 计算综合状态
String overallStatus;
if (hasPending) {
overallStatus = "0"; // 有待审核的综合状态为待审核
} else if (hasRejected) {
overallStatus = "2"; // 有拒绝的综合状态为拒绝
} else {
overallStatus = "1"; // 全部通过
}
// 5. 设置综合审核状态到返回对象
vetInfo.setOverallAuditStatus(overallStatus);
// 6. 添加扩展信息
Map<String, Object> params = vetInfo.getParams();
if (params == null) {
params = new HashMap<>();
}
params.put("personalAuditStatus", personalAuditStatus);
params.put("personalAuditStatusLabel", getAuditStatusLabel(personalAuditStatus));
params.put("qualificationPendingCount", pendingCount);
params.put("qualificationApprovedCount", approvedCount);
params.put("qualificationRejectedCount", rejectedCount);
params.put("totalAuditItems", pendingCount + approvedCount + rejectedCount);
params.put("overallAuditStatus", overallStatus);
params.put("overallAuditStatusLabel", getAuditStatusLabel(overallStatus));
vetInfo.setParams(params);
}
/**
* 获取审核状态标签
*/
private String getAuditStatusLabel(String status) {
if (status == null) {
return "未知";
}
switch (status) {
case "0": return "待审核";
case "1": return "已通过";
case "2": return "已拒绝";
default: return "未知";
}
} }
} }

2
chenhai-admin/src/main/java/com/chenhai/web/controller/vet/VetNotificationController.java

@ -235,4 +235,4 @@ public class VetNotificationController extends BaseController
boolean result = vetNotificationService.markAsRead(id); boolean result = vetNotificationService.markAsRead(id);
return toAjax(result ? 1 : 0); return toAjax(result ? 1 : 0);
} }
}
}

903
chenhai-admin/src/main/java/com/chenhai/web/controller/vet/VetQualificationController.java
File diff suppressed because it is too large
View File

4
chenhai-admin/src/main/java/com/chenhai/web/controller/vet/VetTrainingVideoController.java

@ -25,7 +25,7 @@ import org.springframework.web.multipart.MultipartFile;
/** /**
* 兽医培训视频Controller * 兽医培训视频Controller
*
*
* @author ruoyi * @author ruoyi
* @date 2026-01-28 * @date 2026-01-28
*/ */
@ -295,7 +295,7 @@ public class VetTrainingVideoController extends BaseController
Long userId = getCurrentUserId(); Long userId = getCurrentUserId();
try { try {
boolean success = vetTrainingVideoService.publishVideo(videoId, userId); boolean success = vetTrainingVideoService.publishVideo(videoId, userId);
return success ? success("视频已上架") : error("上架失败,请确保视频已通过审核");
return success ? success("视频已上架") : error("上架失败,必须得自己上架视频");
} catch (Exception e) { } catch (Exception e) {
return error("上架失败: " + e.getMessage()); return error("上架失败: " + e.getMessage());
} }

219
chenhai-admin/src/main/java/com/chenhai/web/controller/vet/VetUnifiedInfoController.java

@ -4,18 +4,24 @@ import com.chenhai.common.annotation.Log;
import com.chenhai.common.core.controller.BaseController; import com.chenhai.common.core.controller.BaseController;
import com.chenhai.common.core.domain.AjaxResult; import com.chenhai.common.core.domain.AjaxResult;
import com.chenhai.common.core.domain.entity.SysRole; import com.chenhai.common.core.domain.entity.SysRole;
import com.chenhai.common.core.domain.entity.SysUser;
import com.chenhai.common.core.domain.model.LoginUser; import com.chenhai.common.core.domain.model.LoginUser;
import com.chenhai.common.core.page.TableDataInfo; import com.chenhai.common.core.page.TableDataInfo;
import com.chenhai.common.core.redis.RedisCache;
import com.chenhai.common.enums.BusinessType; import com.chenhai.common.enums.BusinessType;
import com.chenhai.common.utils.SecurityUtils; import com.chenhai.common.utils.SecurityUtils;
import com.chenhai.common.utils.StringUtils; import com.chenhai.common.utils.StringUtils;
import com.chenhai.system.service.ISysUserService;
import com.chenhai.vet.domain.VetPersonalInfo; import com.chenhai.vet.domain.VetPersonalInfo;
import com.chenhai.vet.domain.VetQualification;
import com.chenhai.vet.domain.dto.VetUnifiedInfoDTO; import com.chenhai.vet.domain.dto.VetUnifiedInfoDTO;
import com.chenhai.vet.service.IVetPersonalInfoService; import com.chenhai.vet.service.IVetPersonalInfoService;
import com.chenhai.vet.service.IVetQualificationService;
import com.chenhai.vet.service.IVetUnifiedInfoService; import com.chenhai.vet.service.IVetUnifiedInfoService;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@ -56,6 +62,22 @@ public class VetUnifiedInfoController extends BaseController {
@Autowired @Autowired
private IVetPersonalInfoService vetPersonalInfoService; private IVetPersonalInfoService vetPersonalInfoService;
@Autowired
private IVetQualificationService vetQualificationService;
// 添加 JdbcTemplate 用于角色操作
@Autowired
private JdbcTemplate jdbcTemplate;
// 添加 RedisCache 用于刷新缓存
@Autowired
private RedisCache redisCache;
// 添加 SysUserService 用于刷新用户信息
@Autowired
private ISysUserService sysUserService;
// ==================== 新RESTful接口 ==================== // ==================== 新RESTful接口 ====================
/** /**
@ -64,7 +86,7 @@ public class VetUnifiedInfoController extends BaseController {
* *
* 替代/muhu/user/getUserInfo /vet/info/current * 替代/muhu/user/getUserInfo /vet/info/current
*/ */
@PreAuthorize("@ss.hasRole('muhu') or @ss.hasRole('vet')")
@PreAuthorize("@ss.hasRole('muhu') or @ss.hasRole('vet') or @ss.hasRole('vetnotshenhe')")
@GetMapping("/info") @GetMapping("/info")
public AjaxResult getCurrentUserInfo() { public AjaxResult getCurrentUserInfo() {
try { try {
@ -102,6 +124,12 @@ public class VetUnifiedInfoController extends BaseController {
if (unifiedInfo == null) { if (unifiedInfo == null) {
return error("用户信息不存在"); return error("用户信息不存在");
} }
// 身份证号脱敏处理
if (unifiedInfo != null && unifiedInfo.getIdCard() != null) {
unifiedInfo.setIdCard(desensitizeIdCard(unifiedInfo.getIdCard()));
}
return success(unifiedInfo); return success(unifiedInfo);
} catch (Exception e) { } catch (Exception e) {
log.error("获取用户信息失败", e); log.error("获取用户信息失败", e);
@ -109,6 +137,32 @@ public class VetUnifiedInfoController extends BaseController {
} }
} }
/**
* 身份证号脱敏
* @param idCard 身份证号
* @return 脱敏后的身份证号
*/
private String desensitizeIdCard(String idCard) {
if (idCard == null || idCard.isEmpty()) {
return idCard;
}
// 18位身份证保留前6位和后4位
if (idCard.length() == 18) {
return idCard.substring(0, 6) + "********" + idCard.substring(14);
}
// 15位身份证保留前6位和后4位
else if (idCard.length() == 15) {
return idCard.substring(0, 6) + "******" + idCard.substring(12);
}
// 其他长度保留前6位后面全部用*代替
else if (idCard.length() > 6) {
return idCard.substring(0, 6) + "******";
}
return idCard;
}
/** /**
* 新增兽医信息 * 新增兽医信息
* POST /vet/unified * POST /vet/unified
@ -170,18 +224,42 @@ public class VetUnifiedInfoController extends BaseController {
return error("兽医信息不存在,请先创建"); return error("兽医信息不存在,请先创建");
} }
// 获取原始数据用于比较
VetPersonalInfo original = vetPersonalInfoService.selectVetPersonalInfoById(existing.getId());
log.info("原始个人信息 - id: {}, title: {}, auditStatus: {}",
original.getId(), original.getTitle(), original.getAuditStatus());
log.info("新个人信息 - title: {}", vetInfo.getTitle());
// 设置用户ID // 设置用户ID
vetInfo.setUserId(currentUserId); vetInfo.setUserId(currentUserId);
vetInfo.setPersonalInfoId(existing.getId()); vetInfo.setPersonalInfoId(existing.getId());
// 判断个人信息是否有变化
boolean personalInfoChanged = isPersonalInfoChanged(original, vetInfo);
log.info("personalInfoChanged: {}", personalInfoChanged);
// 转换为Map调用service // 转换为Map调用service
Map<String, Object> requestData = convertDtoToMap(vetInfo); Map<String, Object> requestData = convertDtoToMap(vetInfo);
requestData.put("personalInfoId", existing.getId()); requestData.put("personalInfoId", existing.getId());
requestData.put("id", existing.getId()); requestData.put("id", existing.getId());
// 如果有任何变化在请求数据中设置 auditStatus = "0"
if (personalInfoChanged) {
requestData.put("auditStatus", "0");
log.info("检测到信息变化,将重置审核状态为待审核 - userId: {}", currentUserId);
} else {
log.info("未检测到信息变化,保持原审核状态");
}
// 调用保存方法 // 调用保存方法
vetUnifiedInfoService.saveVetInfo(requestData); vetUnifiedInfoService.saveVetInfo(requestData);
// 如果个人信息有变化同时将用户角色改为 vetnotshenhe兽医未审核
if (personalInfoChanged) {
changeUserRoleToVetUnapproved(currentUserId);
log.info("个人信息已修改,用户角色变更为兽医未审核 - userId: {}", currentUserId);
}
// 重新查询最新数据 // 重新查询最新数据
VetUnifiedInfoDTO result = vetUnifiedInfoService.getCurrentUserInfo(); VetUnifiedInfoDTO result = vetUnifiedInfoService.getCurrentUserInfo();
@ -194,6 +272,143 @@ public class VetUnifiedInfoController extends BaseController {
} }
} }
/**
* 将用户角色改为兽医未审核
*/
private void changeUserRoleToVetUnapproved(Long userId) {
try {
// 查询用户当前角色
String sql = "SELECT role_id FROM sys_user_role WHERE user_id = ?";
List<Long> roleIds = jdbcTemplate.queryForList(sql, Long.class, userId);
// 角色ID: 4=兽医(vet), 6=兽医未审核(vetnotshenhe)
boolean hasVetRole = roleIds.contains(4L);
boolean hasVetNotShenheRole = roleIds.contains(6L);
if (hasVetRole) {
// 删除兽医角色
jdbcTemplate.update("DELETE FROM sys_user_role WHERE user_id = ? AND role_id = 4", userId);
log.info("删除兽医角色 - userId: {}", userId);
}
if (!hasVetNotShenheRole) {
// 添加兽医未审核角色
jdbcTemplate.update("INSERT INTO sys_user_role (user_id, role_id) VALUES (?, 6)", userId);
log.info("添加兽医未审核角色 - userId: {}", userId);
}
// 刷新用户缓存
refreshUserCache(userId);
} catch (Exception e) {
log.error("修改用户角色失败", e);
}
}
/**
* 刷新用户缓存
*/
private void refreshUserCache(Long userId) {
try {
// 重新查询用户信息
LoginUser loginUser = SecurityUtils.getLoginUser();
if (loginUser != null && loginUser.getUserId().equals(userId)) {
SysUser updatedUser = sysUserService.selectUserById(userId);
if (updatedUser != null) {
loginUser.setUser(updatedUser);
// 刷新Redis缓存
String tokenKey = "login_tokens:" + loginUser.getToken();
redisCache.setCacheObject(tokenKey, loginUser);
log.info("用户缓存刷新成功 - userId: {}", userId);
}
}
} catch (Exception e) {
log.warn("刷新用户缓存失败", e);
}
}
/**
* 判断个人信息是否发生变化
*/
private boolean isPersonalInfoChanged(VetPersonalInfo original, VetUnifiedInfoDTO newInfo) {
if (original == null) {
return true;
}
// 比较个人信息字段
if (!StringUtils.equals(original.getRealName(), newInfo.getRealName())) return true;
if (!StringUtils.equals(original.getGender(), newInfo.getGender())) return true;
if (!StringUtils.equals(original.getIdCard(), newInfo.getIdCard())) return true;
if (!StringUtils.equals(original.getPhone(), newInfo.getPhone())) return true;
if (!StringUtils.equals(original.getIphone(), newInfo.getIphone())) return true;
if (!StringUtils.equals(original.getEmail(), newInfo.getEmail())) return true;
if (!StringUtils.equals(original.getSpecialty(), newInfo.getSpecialty())) return true;
if (!StringUtils.equals(original.getWorkExperience(), newInfo.getWorkExperience())) return true;
if (!StringUtils.equals(original.getHospital(), newInfo.getHospital())) return true;
if (!StringUtils.equals(original.getAddress(), newInfo.getAddress())) return true;
if (!StringUtils.equals(original.getIntroduction(), newInfo.getIntroduction())) return true;
if (!StringUtils.equals(original.getTitle(), newInfo.getTitle())) return true;
if (!StringUtils.equals(original.getExpertType(), newInfo.getExpertType())) return true;
if (!StringUtils.equals(original.getNickName(), newInfo.getNickName())) return true;
if (!StringUtils.equals(original.getAvatar(), newInfo.getAvatar())) return true;
// 比较生日
if (original.getBirthday() != null && newInfo.getBirthday() != null) {
if (!original.getBirthday().equals(newInfo.getBirthday())) return true;
} else if (original.getBirthday() != null || newInfo.getBirthday() != null) {
return true;
}
return false;
}
/**
* 判断资质信息是否发生变化
*/
private boolean isQualificationChanged(VetQualification original, VetUnifiedInfoDTO newInfo) {
if (original == null) {
return newInfo.getQualificationType() != null || newInfo.getScopeIds() != null;
}
// 比较资质字段
if (!StringUtils.equals(original.getQualificationType(), newInfo.getQualificationType())) return true;
if (!StringUtils.equals(original.getScopeIds(), newInfo.getScopeIds())) return true;
// 比较证书列表
List<VetQualification.CertificateInfo> originalCerts = original.getCertificateList();
List<VetQualification.CertificateInfo> newCerts = newInfo.getCertificates();
if (originalCerts == null && newCerts == null) return false;
if (originalCerts == null && newCerts != null && !newCerts.isEmpty()) return true;
if (originalCerts != null && newCerts == null) return true;
if (originalCerts != null && newCerts != null) {
if (originalCerts.size() != newCerts.size()) return true;
for (int i = 0; i < originalCerts.size(); i++) {
VetQualification.CertificateInfo oc = originalCerts.get(i);
VetQualification.CertificateInfo nc = newCerts.get(i);
if (!StringUtils.equals(oc.getCertName(), nc.getCertName())) return true;
if (!StringUtils.equals(oc.getCertificateNo(), nc.getCertificateNo())) return true;
if (!StringUtils.equals(oc.getIssueOrg(), nc.getIssueOrg())) return true;
if (oc.getIssueDate() != null && nc.getIssueDate() != null) {
if (!oc.getIssueDate().equals(nc.getIssueDate())) return true;
} else if (oc.getIssueDate() != null || nc.getIssueDate() != null) {
return true;
}
if (oc.getExpireDate() != null && nc.getExpireDate() != null) {
if (!oc.getExpireDate().equals(nc.getExpireDate())) return true;
} else if (oc.getExpireDate() != null || nc.getExpireDate() != null) {
return true;
}
}
}
return false;
}
/** /**
* 部分更新兽医信息 * 部分更新兽医信息
* PATCH /vet/unified/{userId} * PATCH /vet/unified/{userId}
@ -346,7 +561,7 @@ public class VetUnifiedInfoController extends BaseController {
List<SysRole> roles = loginUser.getUser().getRoles(); List<SysRole> roles = loginUser.getUser().getRoles();
for (SysRole role : roles) { for (SysRole role : roles) {
String roleKey = role.getRoleKey(); String roleKey = role.getRoleKey();
if ("muhu".equals(roleKey) || "manger".equals(roleKey)) {
if ("muhu".equals(roleKey) || "manger".equals(roleKey) || "admin".equals(roleKey)) {
isAdmin = true; isAdmin = true;
break; break;
} }

275
chenhai-system/src/main/java/com/chenhai/muhu/service/impl/MuhuConsultationFormsServiceImpl.java

@ -2,13 +2,19 @@ package com.chenhai.muhu.service.impl;
import java.util.List; import java.util.List;
import com.chenhai.common.core.domain.entity.SysUser;
import com.chenhai.common.core.domain.model.LoginUser; import com.chenhai.common.core.domain.model.LoginUser;
import com.chenhai.common.utils.SecurityUtils; import com.chenhai.common.utils.SecurityUtils;
import com.chenhai.common.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import com.chenhai.muhu.mapper.MuhuConsultationFormsMapper; import com.chenhai.muhu.mapper.MuhuConsultationFormsMapper;
import com.chenhai.muhu.domain.MuhuConsultationForms; import com.chenhai.muhu.domain.MuhuConsultationForms;
import com.chenhai.muhu.service.IMuhuConsultationFormsService; import com.chenhai.muhu.service.IMuhuConsultationFormsService;
import com.chenhai.system.service.ISysUserService;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
/** /**
@ -20,12 +26,20 @@ import org.springframework.transaction.annotation.Transactional;
@Service @Service
public class MuhuConsultationFormsServiceImpl implements IMuhuConsultationFormsService public class MuhuConsultationFormsServiceImpl implements IMuhuConsultationFormsService
{ {
private static final Logger log = LoggerFactory.getLogger(MuhuConsultationFormsServiceImpl.class);
@Autowired @Autowired
private MuhuConsultationFormsMapper muhuConsultationFormsMapper; private MuhuConsultationFormsMapper muhuConsultationFormsMapper;
@Autowired @Autowired
private com.chenhai.vet.mapper.VetCommentsMapper vetCommentsMapper; private com.chenhai.vet.mapper.VetCommentsMapper vetCommentsMapper;
@Autowired
private JdbcTemplate jdbcTemplate;
@Autowired
private ISysUserService sysUserService;
/** /**
* 查询问诊单 * 查询问诊单
* *
@ -41,6 +55,8 @@ public class MuhuConsultationFormsServiceImpl implements IMuhuConsultationFormsS
checkViewPermission(form); checkViewPermission(form);
// 修复回复数量 // 修复回复数量
fixReplyCountAndStatus(form); fixReplyCountAndStatus(form);
// 同步最新头像和昵称
syncLatestUserInfo(form);
} }
return form; return form;
} }
@ -84,9 +100,10 @@ public class MuhuConsultationFormsServiceImpl implements IMuhuConsultationFormsS
list.removeIf(form -> !form.getUserId().equals(loginUser.getUserId())); list.removeIf(form -> !form.getUserId().equals(loginUser.getUserId()));
} }
// 修复每个问诊单的回复数量和状态
// 修复每个问诊单的回复数量和状态并同步头像和昵称
for (MuhuConsultationForms form : list) { for (MuhuConsultationForms form : list) {
fixReplyCountAndStatus(form); fixReplyCountAndStatus(form);
syncLatestUserInfo(form);
} }
return list; return list;
@ -107,12 +124,25 @@ public class MuhuConsultationFormsServiceImpl implements IMuhuConsultationFormsS
if (loginUser != null) { if (loginUser != null) {
// 设置用户ID // 设置用户ID
muhuConsultationForms.setUserId(loginUser.getUserId()); muhuConsultationForms.setUserId(loginUser.getUserId());
// 设置发布者名称为用户昵称
if (muhuConsultationForms.getFarmerName() == null || muhuConsultationForms.getFarmerName().isEmpty()) {
// 获取用户最新信息
SysUser latestUser = getUserLatestInfo(loginUser.getUserId());
// 设置发布者名称为用户最新昵称
if (latestUser != null && StringUtils.isNotEmpty(latestUser.getNickName())) {
muhuConsultationForms.setFarmerName(latestUser.getNickName());
log.debug("设置问诊单发布者名称 - userId: {}, nickName: {}", loginUser.getUserId(), latestUser.getNickName());
} else if (muhuConsultationForms.getFarmerName() == null || muhuConsultationForms.getFarmerName().isEmpty()) {
muhuConsultationForms.setFarmerName(loginUser.getUser().getNickName()); muhuConsultationForms.setFarmerName(loginUser.getUser().getNickName());
} }
// 设置用户头像
if (muhuConsultationForms.getAvatar() == null || muhuConsultationForms.getAvatar().isEmpty()) {
// 设置用户头像 - 从用户表获取最新头像
String latestAvatar = getLatestUserAvatar(loginUser.getUserId());
if (StringUtils.isNotEmpty(latestAvatar)) {
muhuConsultationForms.setAvatar(latestAvatar);
log.debug("设置问诊单头像 - userId: {}, avatar: {}", loginUser.getUserId(), latestAvatar);
} else if (muhuConsultationForms.getAvatar() == null || muhuConsultationForms.getAvatar().isEmpty()) {
// 如果用户表没有头像使用登录用户对象的头像
muhuConsultationForms.setAvatar(loginUser.getUser().getAvatar()); muhuConsultationForms.setAvatar(loginUser.getUser().getAvatar());
} }
} }
@ -201,6 +231,55 @@ public class MuhuConsultationFormsServiceImpl implements IMuhuConsultationFormsS
return muhuConsultationFormsMapper.deleteMuhuConsultationFormsByFormId(formId); return muhuConsultationFormsMapper.deleteMuhuConsultationFormsByFormId(formId);
} }
/**
* 查询今日问诊单列表
*
* @param muhuConsultationForms 问诊单
* @return 问诊单
*/
@Override
public List<MuhuConsultationForms> selectTodayConsultationFormsList(MuhuConsultationForms muhuConsultationForms)
{
// 检查是否有admin权限
boolean isAdmin = SecurityUtils.hasRole("admin") || SecurityUtils.hasPermi("*:*:*");
// 检查是否是兽医角色
boolean isVet = SecurityUtils.hasRole("vet");
boolean isVetNotShenhe = SecurityUtils.hasRole("vetnotshenhe");
LoginUser loginUser = SecurityUtils.getLoginUser();
if (loginUser != null) {
// 如果是普通用户(muhu)且不是管理员只能查看自己的问诊单
if (SecurityUtils.hasRole("muhu") && !isAdmin) {
muhuConsultationForms.setUserId(loginUser.getUserId());
}
// 如果是兽医但未审核不能查看任何问诊单
else if (isVetNotShenhe && !isAdmin) {
// 未审核的兽医不能查看问诊单返回空列表
muhuConsultationForms.setUserId(-1L);
return muhuConsultationFormsMapper.selectTodayConsultationFormsList(muhuConsultationForms);
}
// 如果是已审核的兽医可以查看所有问诊单不需要设置userId
}
List<MuhuConsultationForms> list = muhuConsultationFormsMapper.selectTodayConsultationFormsList(muhuConsultationForms);
// 对于普通用户还需要在返回前再次过滤确保只返回自己的问诊单
if (loginUser != null && SecurityUtils.hasRole("muhu") && !isAdmin) {
list.removeIf(form -> !form.getUserId().equals(loginUser.getUserId()));
}
// 修复每个问诊单的回复数量和状态并同步头像和昵称
for (MuhuConsultationForms form : list) {
fixReplyCountAndStatus(form);
syncLatestUserInfo(form);
}
return list;
}
// ==================== 私有辅助方法 ====================
/** /**
* 修复回复数量和状态核心修复方法 * 修复回复数量和状态核心修复方法
* 确保问诊单的回复数量和状态一致 * 确保问诊单的回复数量和状态一致
@ -229,7 +308,7 @@ public class MuhuConsultationFormsServiceImpl implements IMuhuConsultationFormsS
} }
} catch (Exception e) { } catch (Exception e) {
// 忽略异常不影响主流程 // 忽略异常不影响主流程
e.printStackTrace();
log.warn("修复回复数量失败 - formId: {}", form.getFormId(), e);
} }
} }
@ -250,7 +329,7 @@ public class MuhuConsultationFormsServiceImpl implements IMuhuConsultationFormsS
// 返回数量 // 返回数量
return replies != null ? (long) replies.size() : 0L; return replies != null ? (long) replies.size() : 0L;
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace();
log.warn("获取回复数量失败 - formId: {}", formId, e);
return 0L; return 0L;
} }
} }
@ -291,48 +370,164 @@ public class MuhuConsultationFormsServiceImpl implements IMuhuConsultationFormsS
} }
/** /**
* 查询今日问诊单列表
*
* @param muhuConsultationForms 问诊单
* @return 问诊单
* 获取用户最新的信息昵称和头像
* @param userId 用户ID
* @return 用户信息
*/ */
@Override
public List<MuhuConsultationForms> selectTodayConsultationFormsList(MuhuConsultationForms muhuConsultationForms)
{
// 检查是否有admin权限
boolean isAdmin = SecurityUtils.hasRole("admin") || SecurityUtils.hasPermi("*:*:*");
private SysUser getUserLatestInfo(Long userId) {
if (userId == null) {
return null;
}
try {
return sysUserService.selectUserById(userId);
} catch (Exception e) {
log.warn("获取用户信息失败 - userId: {}", userId, e);
return null;
}
}
// 检查是否是兽医角色
boolean isVet = SecurityUtils.hasRole("vet");
boolean isVetNotShenhe = SecurityUtils.hasRole("vetnotshenhe");
/**
* 获取用户最新的昵称
* @param userId 用户ID
* @return 昵称
*/
private String getLatestUserNickName(Long userId) {
if (userId == null) {
return null;
}
try {
String sql = "SELECT nick_name FROM sys_user WHERE user_id = ?";
return jdbcTemplate.queryForObject(sql, String.class, userId);
} catch (Exception e) {
log.warn("获取用户昵称失败 - userId: {}", userId, e);
return null;
}
}
LoginUser loginUser = SecurityUtils.getLoginUser();
if (loginUser != null) {
// 如果是普通用户(muhu)且不是管理员只能查看自己的问诊单
if (SecurityUtils.hasRole("muhu") && !isAdmin) {
muhuConsultationForms.setUserId(loginUser.getUserId());
}
// 如果是兽医但未审核不能查看任何问诊单
else if (isVetNotShenhe && !isAdmin) {
// 未审核的兽医不能查看问诊单返回空列表
muhuConsultationForms.setUserId(-1L);
return muhuConsultationFormsMapper.selectTodayConsultationFormsList(muhuConsultationForms);
}
// 如果是已审核的兽医可以查看所有问诊单不需要设置userId
/**
* 获取用户最新的头像
* @param userId 用户ID
* @return 头像URL
*/
private String getLatestUserAvatar(Long userId) {
if (userId == null) {
return null;
} }
try {
String sql = "SELECT avatar FROM sys_user WHERE user_id = ?";
return jdbcTemplate.queryForObject(sql, String.class, userId);
} catch (Exception e) {
log.warn("获取用户头像失败 - userId: {}", userId, e);
return null;
}
}
List<MuhuConsultationForms> list = muhuConsultationFormsMapper.selectTodayConsultationFormsList(muhuConsultationForms);
/**
* 同步最新用户信息头像和昵称
* @param form 问诊单对象
*/
private void syncLatestUserInfo(MuhuConsultationForms form) {
if (form == null || form.getUserId() == null) {
return;
}
// 对于普通用户还需要在返回前再次过滤确保只返回自己的问诊单
if (loginUser != null && SecurityUtils.hasRole("muhu") && !isAdmin) {
list.removeIf(form -> !form.getUserId().equals(loginUser.getUserId()));
try {
// 获取用户最新信息
SysUser latestUser = getUserLatestInfo(form.getUserId());
if (latestUser != null) {
boolean hasChanges = false;
// 同步头像
if (StringUtils.isNotEmpty(latestUser.getAvatar())) {
if (!latestUser.getAvatar().equals(form.getAvatar())) {
form.setAvatar(latestUser.getAvatar());
hasChanges = true;
log.debug("同步问诊单头像 - formId: {}, userId: {}, 新头像: {}",
form.getFormId(), form.getUserId(), latestUser.getAvatar());
}
}
// 同步昵称
if (StringUtils.isNotEmpty(latestUser.getNickName())) {
if (!latestUser.getNickName().equals(form.getFarmerName())) {
form.setFarmerName(latestUser.getNickName());
hasChanges = true;
log.debug("同步问诊单昵称 - formId: {}, userId: {}, 新昵称: {}",
form.getFormId(), form.getUserId(), latestUser.getNickName());
}
}
if (!hasChanges) {
log.debug("问诊单用户信息无变化 - formId: {}, userId: {}", form.getFormId(), form.getUserId());
}
}
} catch (Exception e) {
log.warn("同步用户信息失败 - formId: {}, userId: {}", form.getFormId(), form.getUserId(), e);
} }
}
/**
* 批量同步所有问诊单的用户信息头像和昵称用于修复历史数据
* 可通过Controller调用此方法修复已有数据
*/
@Transactional
public void syncAllConsultationUserInfo() {
// 查询所有问诊单
MuhuConsultationForms query = new MuhuConsultationForms();
List<MuhuConsultationForms> list = muhuConsultationFormsMapper.selectMuhuConsultationFormsList(query);
log.info("开始批量同步问诊单用户信息,总记录数: {}", list.size());
int avatarSuccessCount = 0;
int nickNameSuccessCount = 0;
int failCount = 0;
// 修复每个问诊单的回复数量和状态
for (MuhuConsultationForms form : list) { for (MuhuConsultationForms form : list) {
fixReplyCountAndStatus(form);
if (form.getUserId() != null) {
try {
SysUser latestUser = getUserLatestInfo(form.getUserId());
if (latestUser != null) {
boolean needUpdate = false;
MuhuConsultationForms updateForm = new MuhuConsultationForms();
updateForm.setFormId(form.getFormId());
// 同步头像
if (StringUtils.isNotEmpty(latestUser.getAvatar())) {
if (!latestUser.getAvatar().equals(form.getAvatar())) {
updateForm.setAvatar(latestUser.getAvatar());
needUpdate = true;
avatarSuccessCount++;
log.info("同步头像成功 - formId: {}, userId: {}, 新头像: {}",
form.getFormId(), form.getUserId(), latestUser.getAvatar());
}
}
// 同步昵称
if (StringUtils.isNotEmpty(latestUser.getNickName())) {
if (!latestUser.getNickName().equals(form.getFarmerName())) {
updateForm.setFarmerName(latestUser.getNickName());
needUpdate = true;
nickNameSuccessCount++;
log.info("同步昵称成功 - formId: {}, userId: {}, 新昵称: {}",
form.getFormId(), form.getUserId(), latestUser.getNickName());
}
}
// 如果有变化更新数据库
if (needUpdate) {
int result = muhuConsultationFormsMapper.updateMuhuConsultationForms(updateForm);
if (result <= 0) {
failCount++;
}
}
}
} catch (Exception e) {
failCount++;
log.error("同步用户信息失败 - formId: {}, userId: {}", form.getFormId(), form.getUserId(), e);
}
}
} }
return list;
log.info("批量同步完成,头像更新: {} 条,昵称更新: {} 条,失败: {} 条",
avatarSuccessCount, nickNameSuccessCount, failCount);
} }
}
}

34
chenhai-system/src/main/java/com/chenhai/system/mapper/SysMedicineRecommendationMapper.java

@ -5,15 +5,15 @@ import com.chenhai.system.domain.SysMedicineRecommendation;
/** /**
* 药品推荐Mapper接口 * 药品推荐Mapper接口
*
*
* @author ruoyi * @author ruoyi
* @date 2026-01-20 * @date 2026-01-20
*/ */
public interface SysMedicineRecommendationMapper
public interface SysMedicineRecommendationMapper
{ {
/** /**
* 查询药品推荐 * 查询药品推荐
*
*
* @param id 药品推荐主键 * @param id 药品推荐主键
* @return 药品推荐 * @return 药品推荐
*/ */
@ -21,7 +21,7 @@ public interface SysMedicineRecommendationMapper
/** /**
* 查询药品推荐列表 * 查询药品推荐列表
*
*
* @param sysMedicineRecommendation 药品推荐 * @param sysMedicineRecommendation 药品推荐
* @return 药品推荐集合 * @return 药品推荐集合
*/ */
@ -29,7 +29,7 @@ public interface SysMedicineRecommendationMapper
/** /**
* 新增药品推荐 * 新增药品推荐
*
*
* @param sysMedicineRecommendation 药品推荐 * @param sysMedicineRecommendation 药品推荐
* @return 结果 * @return 结果
*/ */
@ -37,7 +37,7 @@ public interface SysMedicineRecommendationMapper
/** /**
* 修改药品推荐 * 修改药品推荐
*
*
* @param sysMedicineRecommendation 药品推荐 * @param sysMedicineRecommendation 药品推荐
* @return 结果 * @return 结果
*/ */
@ -45,7 +45,7 @@ public interface SysMedicineRecommendationMapper
/** /**
* 删除药品推荐 * 删除药品推荐
*
*
* @param id 药品推荐主键 * @param id 药品推荐主键
* @return 结果 * @return 结果
*/ */
@ -53,20 +53,18 @@ public interface SysMedicineRecommendationMapper
/** /**
* 批量删除药品推荐 * 批量删除药品推荐
*
*
* @param ids 需要删除的数据主键集合 * @param ids 需要删除的数据主键集合
* @return 结果 * @return 结果
*/ */
public int deleteSysMedicineRecommendationByIds(Long[] ids); public int deleteSysMedicineRecommendationByIds(Long[] ids);
// 添加专家查询方法声明
String getExpertNameById(Long expertId);
String getExpertExpertById(Long expertId);
String getExpertIntroductionById(Long expertId);
String getExpertAddressById(Long expertId);
String getExpertExpertiseAreaById(Long expertId);
String getExpertWorkExperienceById(Long expertId);
// 添加从 vet_personal_info 表查询兽医信息的方法声明
String getExpertAvatarByUserId(Long userId);
String getExpertRealNameByUserId(Long userId);
String getExpertTitleByUserId(Long userId);
String getExpertIntroductionByUserId(Long userId);
String getExpertAddressByUserId(Long userId);
String getExpertSpecialtyByUserId(Long userId);
String getExpertWorkExperienceByUserId(Long userId);
} }

39
chenhai-system/src/main/java/com/chenhai/system/service/impl/SysMedicineRecommendationServiceImpl.java

@ -1,6 +1,9 @@
package com.chenhai.system.service.impl; package com.chenhai.system.service.impl;
import java.util.List; import java.util.List;
import com.chenhai.common.core.domain.entity.SysUser;
import com.chenhai.common.utils.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import com.chenhai.system.mapper.SysMedicineRecommendationMapper; import com.chenhai.system.mapper.SysMedicineRecommendationMapper;
@ -9,19 +12,19 @@ import com.chenhai.system.service.ISysMedicineRecommendationService;
/** /**
* 药品推荐Service业务层处理 * 药品推荐Service业务层处理
*
*
* @author ruoyi * @author ruoyi
* @date 2026-01-20 * @date 2026-01-20
*/ */
@Service @Service
public class SysMedicineRecommendationServiceImpl implements ISysMedicineRecommendationService
public class SysMedicineRecommendationServiceImpl implements ISysMedicineRecommendationService
{ {
@Autowired @Autowired
private SysMedicineRecommendationMapper sysMedicineRecommendationMapper; private SysMedicineRecommendationMapper sysMedicineRecommendationMapper;
/** /**
* 查询药品推荐 * 查询药品推荐
*
*
* @param id 药品推荐主键 * @param id 药品推荐主键
* @return 药品推荐 * @return 药品推荐
*/ */
@ -33,31 +36,51 @@ public class SysMedicineRecommendationServiceImpl implements ISysMedicineRecomme
/** /**
* 查询药品推荐列表 * 查询药品推荐列表
*
* 兽医只能看到自己推荐的药品管理员和牧户可以看到所有
*
* @param sysMedicineRecommendation 药品推荐 * @param sysMedicineRecommendation 药品推荐
* @return 药品推荐 * @return 药品推荐
*/ */
@Override @Override
public List<SysMedicineRecommendation> selectSysMedicineRecommendationList(SysMedicineRecommendation sysMedicineRecommendation) public List<SysMedicineRecommendation> selectSysMedicineRecommendationList(SysMedicineRecommendation sysMedicineRecommendation)
{ {
// 获取当前登录用户
SysUser currentUser = SecurityUtils.getLoginUser().getUser();
// 判断是否为兽医角色
boolean isVet = currentUser.getRoles().stream()
.anyMatch(role -> "vet".equals(role.getRoleKey()));
// 如果是兽医设置expertId为当前用户ID只能看到自己推荐的
if (isVet) {
sysMedicineRecommendation.setExpertId(currentUser.getUserId());
}
return sysMedicineRecommendationMapper.selectSysMedicineRecommendationList(sysMedicineRecommendation); return sysMedicineRecommendationMapper.selectSysMedicineRecommendationList(sysMedicineRecommendation);
} }
/** /**
* 新增药品推荐 * 新增药品推荐
*
* 自动设置推荐人ID为当前登录用户
*
* @param sysMedicineRecommendation 药品推荐 * @param sysMedicineRecommendation 药品推荐
* @return 结果 * @return 结果
*/ */
@Override @Override
public int insertSysMedicineRecommendation(SysMedicineRecommendation sysMedicineRecommendation) public int insertSysMedicineRecommendation(SysMedicineRecommendation sysMedicineRecommendation)
{ {
// 获取当前登录用户
SysUser currentUser = SecurityUtils.getLoginUser().getUser();
// 自动设置推荐人ID为当前用户ID
sysMedicineRecommendation.setExpertId(currentUser.getUserId());
return sysMedicineRecommendationMapper.insertSysMedicineRecommendation(sysMedicineRecommendation); return sysMedicineRecommendationMapper.insertSysMedicineRecommendation(sysMedicineRecommendation);
} }
/** /**
* 修改药品推荐 * 修改药品推荐
*
*
* @param sysMedicineRecommendation 药品推荐 * @param sysMedicineRecommendation 药品推荐
* @return 结果 * @return 结果
*/ */
@ -69,7 +92,7 @@ public class SysMedicineRecommendationServiceImpl implements ISysMedicineRecomme
/** /**
* 批量删除药品推荐 * 批量删除药品推荐
*
*
* @param ids 需要删除的药品推荐主键 * @param ids 需要删除的药品推荐主键
* @return 结果 * @return 结果
*/ */
@ -81,7 +104,7 @@ public class SysMedicineRecommendationServiceImpl implements ISysMedicineRecomme
/** /**
* 删除药品推荐信息 * 删除药品推荐信息
*
*
* @param id 药品推荐主键 * @param id 药品推荐主键
* @return 结果 * @return 结果
*/ */

93
chenhai-system/src/main/java/com/chenhai/vet/domain/VetComments.java

@ -9,7 +9,7 @@ import com.chenhai.common.core.domain.BaseEntity;
/** /**
* 兽医回复对象 vet_comments * 兽医回复对象 vet_comments
*
*
* @author ruoyi * @author ruoyi
* @date 2026-01-07 * @date 2026-01-07
*/ */
@ -74,6 +74,17 @@ public class VetComments extends BaseEntity
@Excel(name = "头像") @Excel(name = "头像")
private String avatar; private String avatar;
/** ========== 新增字段 ========== */
/** 专家类型(从兽医个人信息表关联) */
@Excel(name = "专家类型")
private String expertType;
/** 擅长领域(从兽医个人信息表关联) */
@Excel(name = "擅长领域")
private String specialty;
// ==================== Getter and Setter ====================
public String getTitle() { public String getTitle() {
return title; return title;
} }
@ -98,12 +109,12 @@ public class VetComments extends BaseEntity
this.experience = experience; this.experience = experience;
} }
public void setId(Long id)
public void setId(Long id)
{ {
this.id = id; this.id = id;
} }
public Long getId()
public Long getId()
{ {
return id; return id;
} }
@ -128,72 +139,72 @@ public class VetComments extends BaseEntity
return replyName; return replyName;
} }
public void setContent(String content)
public void setContent(String content)
{ {
this.content = content; this.content = content;
} }
public String getContent()
public String getContent()
{ {
return content; return content;
} }
public void setImages(String images)
public void setImages(String images)
{ {
this.images = images; this.images = images;
} }
public String getImages()
public String getImages()
{ {
return images; return images;
} }
public void setIsSensitive(Integer isSensitive)
public void setIsSensitive(Integer isSensitive)
{ {
this.isSensitive = isSensitive; this.isSensitive = isSensitive;
} }
public Integer getIsSensitive()
public Integer getIsSensitive()
{ {
return isSensitive; return isSensitive;
} }
public void setSensitiveWords(String sensitiveWords)
public void setSensitiveWords(String sensitiveWords)
{ {
this.sensitiveWords = sensitiveWords; this.sensitiveWords = sensitiveWords;
} }
public String getSensitiveWords()
public String getSensitiveWords()
{ {
return sensitiveWords; return sensitiveWords;
} }
public void setCreatedAt(Date createdAt)
public void setCreatedAt(Date createdAt)
{ {
this.createdAt = createdAt; this.createdAt = createdAt;
} }
public Date getCreatedAt()
public Date getCreatedAt()
{ {
return createdAt; return createdAt;
} }
public void setUpdatedAt(Date updatedAt)
public void setUpdatedAt(Date updatedAt)
{ {
this.updatedAt = updatedAt; this.updatedAt = updatedAt;
} }
public Date getUpdatedAt()
public Date getUpdatedAt()
{ {
return updatedAt; return updatedAt;
} }
public void setUserId(Long userId)
public void setUserId(Long userId)
{ {
this.userId = userId; this.userId = userId;
} }
public Long getUserId()
public Long getUserId()
{ {
return userId; return userId;
} }
@ -208,23 +219,41 @@ public class VetComments extends BaseEntity
return avatar; return avatar;
} }
public String getExpertType() {
return expertType;
}
public void setExpertType(String expertType) {
this.expertType = expertType;
}
public String getSpecialty() {
return specialty;
}
public void setSpecialty(String specialty) {
this.specialty = specialty;
}
@Override @Override
public String toString() { public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("consultationId", getConsultationId())
.append("replyName", getReplyName())
.append("content", getContent())
.append("images", getImages())
.append("isSensitive", getIsSensitive())
.append("sensitiveWords", getSensitiveWords())
.append("createdAt", getCreatedAt())
.append("updatedAt", getUpdatedAt())
.append("userId", getUserId())
.append("title", getTitle())
.append("hospital", getHospital())
.append("experience", getExperience())
.append("avatar", getAvatar())
.toString();
.append("id", getId())
.append("consultationId", getConsultationId())
.append("replyName", getReplyName())
.append("content", getContent())
.append("images", getImages())
.append("isSensitive", getIsSensitive())
.append("sensitiveWords", getSensitiveWords())
.append("createdAt", getCreatedAt())
.append("updatedAt", getUpdatedAt())
.append("userId", getUserId())
.append("title", getTitle())
.append("hospital", getHospital())
.append("experience", getExperience())
.append("avatar", getAvatar())
.append("expertType", getExpertType())
.append("specialty", getSpecialty())
.toString();
} }
} }

109
chenhai-system/src/main/java/com/chenhai/vet/domain/VetNotification.java

@ -40,140 +40,139 @@ public class VetNotification extends BaseEntity
@Excel(name = "关联ID") @Excel(name = "关联ID")
private String relatedId; private String relatedId;
/** ========== 新增:证书ID ========== */
/** 证书ID */
@Excel(name = "证书ID")
private Long certId;
/** 是否已读 0:未读 1:已读 */ /** 是否已读 0:未读 1:已读 */
@Excel(name = "是否已读", dictType = "notification_is_read") @Excel(name = "是否已读", dictType = "notification_is_read")
private Integer isRead; private Integer isRead;
/** 是否已读标签(用于前端显示) */ /** 是否已读标签(用于前端显示) */
private String isReadLabel; // 添加这个字段
private String isReadLabel;
/** 提醒级别 1:低 2:中 3:高 */ /** 提醒级别 1:低 2:中 3:高 */
@Excel(name = "提醒级别", dictType = "notification_remindlevel") @Excel(name = "提醒级别", dictType = "notification_remindlevel")
private Integer remindLevel; private Integer remindLevel;
/** 提醒级别标签(用于前端显示) */ /** 提醒级别标签(用于前端显示) */
private String remindLevelLabel; private String remindLevelLabel;
public String getIsReadLabel() {
return isReadLabel;
}
public void setIsReadLabel(String isReadLabel) {
this.isReadLabel = isReadLabel;
}
public String getRemindLevelLabel() {
return remindLevelLabel;
}
public void setRemindLevelLabel(String remindLevelLabel) {
this.remindLevelLabel = remindLevelLabel;
}
/** 阅读时间 */ /** 阅读时间 */
@JsonFormat(pattern = "yyyy-MM-dd") @JsonFormat(pattern = "yyyy-MM-dd")
@Excel(name = "阅读时间", width = 30, dateFormat = "yyyy-MM-dd") @Excel(name = "阅读时间", width = 30, dateFormat = "yyyy-MM-dd")
private Date readTime; private Date readTime;
public void setId(Long id)
{
// ==================== Getter and Setter ====================
public void setId(Long id) {
this.id = id; this.id = id;
} }
public Long getId()
{
public Long getId() {
return id; return id;
} }
public void setUserId(Long userId)
{
public void setUserId(Long userId) {
this.userId = userId; this.userId = userId;
} }
public Long getUserId()
{
public Long getUserId() {
return userId; return userId;
} }
public void setTitle(String title)
{
public void setTitle(String title) {
this.title = title; this.title = title;
} }
public String getTitle()
{
public String getTitle() {
return title; return title;
} }
public void setContent(String content)
{
public void setContent(String content) {
this.content = content; this.content = content;
} }
public String getContent()
{
public String getContent() {
return content; return content;
} }
public void setType(String type)
{
public void setType(String type) {
this.type = type; this.type = type;
} }
public String getType()
{
public String getType() {
return type; return type;
} }
public void setRelatedId(String relatedId)
{
public void setRelatedId(String relatedId) {
this.relatedId = relatedId; this.relatedId = relatedId;
} }
public String getRelatedId()
{
public String getRelatedId() {
return relatedId; return relatedId;
} }
public void setIsRead(Integer isRead)
{
// ========== 新增certId getter/setter ==========
public Long getCertId() {
return certId;
}
public void setCertId(Long certId) {
this.certId = certId;
}
public void setIsRead(Integer isRead) {
this.isRead = isRead; this.isRead = isRead;
} }
public Integer getIsRead()
{
public Integer getIsRead() {
return isRead; return isRead;
} }
public void setRemindLevel(Integer remindLevel)
{
public String getIsReadLabel() {
return isReadLabel;
}
public void setIsReadLabel(String isReadLabel) {
this.isReadLabel = isReadLabel;
}
public void setRemindLevel(Integer remindLevel) {
this.remindLevel = remindLevel; this.remindLevel = remindLevel;
} }
public Integer getRemindLevel()
{
public Integer getRemindLevel() {
return remindLevel; return remindLevel;
} }
public void setReadTime(Date readTime)
{
public String getRemindLevelLabel() {
return remindLevelLabel;
}
public void setRemindLevelLabel(String remindLevelLabel) {
this.remindLevelLabel = remindLevelLabel;
}
public void setReadTime(Date readTime) {
this.readTime = readTime; this.readTime = readTime;
} }
public Date getReadTime()
{
public Date getReadTime() {
return readTime; return readTime;
} }
@Override @Override
public String toString() { public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId()) .append("id", getId())
.append("userId", getUserId()) .append("userId", getUserId())
.append("title", getTitle()) .append("title", getTitle())
.append("content", getContent()) .append("content", getContent())
.append("type", getType()) .append("type", getType())
.append("relatedId", getRelatedId()) .append("relatedId", getRelatedId())
.append("certId", getCertId())
.append("isRead", getIsRead()) .append("isRead", getIsRead())
.append("remindLevel", getRemindLevel()) .append("remindLevel", getRemindLevel())
.append("createTime", getCreateTime()) .append("createTime", getCreateTime())

51
chenhai-system/src/main/java/com/chenhai/vet/domain/VetPersonalInfo.java

@ -3,11 +3,13 @@ package com.chenhai.vet.domain;
import com.chenhai.common.annotation.Excel; import com.chenhai.common.annotation.Excel;
import com.chenhai.common.core.domain.BaseEntity; import com.chenhai.common.core.domain.BaseEntity;
import com.chenhai.common.core.domain.entity.SysUser; import com.chenhai.common.core.domain.entity.SysUser;
import com.chenhai.common.utils.StringUtils;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle; import org.apache.commons.lang3.builder.ToStringStyle;
import java.util.Date; import java.util.Date;
import java.util.Map;
/** /**
* 兽医个人信息对象 vet_personal_info * 兽医个人信息对象 vet_personal_info
@ -111,6 +113,12 @@ public class VetPersonalInfo extends BaseEntity
@Excel(name = "头像路径") @Excel(name = "头像路径")
private String avatar; private String avatar;
/** 综合审核状态(动态计算,不存数据库) */
private String overallAuditStatus;
/** 扩展参数(用于存储额外的统计信息) */
private Map<String, Object> params;
// 添加getter和setter // 添加getter和setter
public void setId(Long id) public void setId(Long id)
{ {
@ -330,6 +338,45 @@ public class VetPersonalInfo extends BaseEntity
this.avatar = avatar; this.avatar = avatar;
} }
public String getOverallAuditStatus() {
return overallAuditStatus;
}
public void setOverallAuditStatus(String overallAuditStatus) {
this.overallAuditStatus = overallAuditStatus;
}
public Map<String, Object> getParams() {
return params;
}
public void setParams(Map<String, Object> params) {
this.params = params;
}
/**
* 获取展示用的审核状态综合状态优先
*/
public String getDisplayAuditStatus() {
if (StringUtils.isNotEmpty(overallAuditStatus)) {
return overallAuditStatus;
}
return auditStatus;
}
/**
* 获取展示用的审核状态标签
*/
public String getDisplayAuditStatusLabel() {
String status = getDisplayAuditStatus();
if (status == null) return "未知";
switch (status) {
case "0": return "待审核";
case "1": return "已通过";
case "2": return "已拒绝";
default: return "未知";
}
}
@Override @Override
public String toString() { public String toString() {
@ -357,6 +404,8 @@ public class VetPersonalInfo extends BaseEntity
.append("nickName", getNickName()) .append("nickName", getNickName())
.append("avatar", getAvatar()) .append("avatar", getAvatar())
.append("user", getUser()) .append("user", getUser())
.append("overallAuditStatus", getOverallAuditStatus())
.append("params", getParams())
.toString(); .toString();
} }
}
}

276
chenhai-system/src/main/java/com/chenhai/vet/domain/VetQualification.java

@ -15,8 +15,6 @@ import org.slf4j.LoggerFactory;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.*; import java.util.*;
/** /**
* 兽医资质对象 vet_qualification合并证书功能 * 兽医资质对象 vet_qualification合并证书功能
* *
@ -62,12 +60,11 @@ public class VetQualification extends BaseEntity
private String certificateFiles; private String certificateFiles;
/** 申请时间 */ /** 申请时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "申请时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date applyTime; private Date applyTime;
/** 审核时间 */ /** 审核时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Excel(name = "审核时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss") @Excel(name = "审核时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date auditTime; private Date auditTime;
@ -139,12 +136,20 @@ public class VetQualification extends BaseEntity
private String scopeNamesLabel; private String scopeNamesLabel;
private String certStatusLabel; private String certStatusLabel;
/** 证书JSON字符串(数据库字段) */
/** 证书JSON字符串(数据库字段)- 添加 @JsonIgnore 隐藏此字段 */
@JsonIgnore
private String certificatesJson; private String certificatesJson;
/** 证书列表(从JSON解析而来) */
/** 证书列表(从JSON解析而来,用于前端展示) */
@JsonProperty("certificates")
private List<Map<String, Object>> certificates;
/** 证书列表(从JSON解析而来,用于业务逻辑) */
private transient List<CertificateInfo> certificateList; private transient List<CertificateInfo> certificateList;
// 日期格式化器
private static final SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd");
/** /**
* 证书信息内部类 * 证书信息内部类
*/ */
@ -294,6 +299,168 @@ public class VetQualification extends BaseEntity
} }
} }
// ==================== 新增的证书展示方法 ====================
/**
* 获取证书列表用于前端展示
* 确保返回的证书中包含 issueDate expireDate 字段
*/
@JsonProperty("certificates")
public List<Map<String, Object>> getCertificates() {
if (certificates != null) {
return certificates;
}
if (StringUtils.isEmpty(certificatesJson)) {
return new ArrayList<>();
}
try {
certificates = objectMapper.readValue(
certificatesJson,
objectMapper.getTypeFactory().constructCollectionType(List.class, Map.class)
);
// // 为每个证书补充日期字段
// SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
// for (Map<String, Object> cert : certificates) {
// // 如果 JSON 中没有 issueDate从主表获取注意使用 getter 方法
// if (!cert.containsKey("issueDate") || cert.get("issueDate") == null) {
// // 使用 getIssueDate() 方法而不是直接访问字段
// Date issueDateValue = getIssueDate();
// if (issueDateValue != null) {
// cert.put("issueDate", sdf.format(issueDateValue));
// System.out.println("从主表补充 issueDate: " + sdf.format(issueDateValue));
// }
// } else {
// Object issueDateObj = cert.get("issueDate");
// if (issueDateObj instanceof Date) {
// cert.put("issueDate", sdf.format((Date) issueDateObj));
// }
// }
//
// // 如果 JSON 中没有 expireDate从主表获取
// if (!cert.containsKey("expireDate") || cert.get("expireDate") == null) {
// Date expireDateValue = getExpireDate();
// if (expireDateValue != null) {
// cert.put("expireDate", sdf.format(expireDateValue));
// System.out.println("从主表补充 expireDate: " + sdf.format(expireDateValue));
// }
// } else {
// Object expireDateObj = cert.get("expireDate");
// if (expireDateObj instanceof Date) {
// cert.put("expireDate", sdf.format((Date) expireDateObj));
// }
// }
// }
return certificates;
} catch (Exception e) {
log.error("解析证书JSON失败", e);
return new ArrayList<>();
}
}
/**
* 设置证书列表
* 确保日期字段被正确保存到 JSON
*/
public void setCertificates(List<Map<String, Object>> certificates) {
this.certificates = certificates;
if (certificates != null && !certificates.isEmpty()) {
try {
List<Map<String, Object>> certMapList = new ArrayList<>();
for (Map<String, Object> cert : certificates) {
Map<String, Object> certMap = new HashMap<>();
certMap.put("certName", cert.get("certName"));
certMap.put("certificateNo", cert.get("certificateNo"));
certMap.put("issueOrg", cert.get("issueOrg"));
certMap.put("certificateFiles", cert.get("certificateFiles"));
// 处理发证日期
Object issueDateObj = cert.get("issueDate");
if (issueDateObj != null) {
if (issueDateObj instanceof Date) {
certMap.put("issueDate", dateFormatter.format((Date) issueDateObj));
} else {
certMap.put("issueDate", issueDateObj.toString());
}
}
// 处理到期日期
Object expireDateObj = cert.get("expireDate");
if (expireDateObj != null) {
if (expireDateObj instanceof Date) {
certMap.put("expireDate", dateFormatter.format((Date) expireDateObj));
} else {
certMap.put("expireDate", expireDateObj.toString());
}
}
// 处理证书ID
Object certIdObj = cert.get("certId");
if (certIdObj != null) {
if (certIdObj instanceof Number) {
certMap.put("certId", ((Number) certIdObj).longValue());
} else {
try {
certMap.put("certId", Long.parseLong(certIdObj.toString()));
} catch (Exception e) {
certMap.put("certId", generateSafeCertificateId());
}
}
} else {
certMap.put("certId", generateSafeCertificateId());
}
// 处理证书状态
if (cert.containsKey("certStatus") && cert.get("certStatus") != null) {
certMap.put("certStatus", cert.get("certStatus"));
}
certMapList.add(certMap);
}
this.certificatesJson = objectMapper.writeValueAsString(certMapList);
// 更新主表字段
Map<String, Object> firstCert = certMapList.get(0);
this.certName = (String) firstCert.get("certName");
this.certificateNo = (String) firstCert.get("certificateNo");
this.issueOrg = (String) firstCert.get("issueOrg");
this.certificateFiles = (String) firstCert.get("certificateFiles");
// 解析日期
String issueDateStr = (String) firstCert.get("issueDate");
if (issueDateStr != null && !issueDateStr.isEmpty()) {
try {
this.issueDate = dateFormatter.parse(issueDateStr);
} catch (Exception e) {}
}
String expireDateStr = (String) firstCert.get("expireDate");
if (expireDateStr != null && !expireDateStr.isEmpty()) {
try {
this.expireDate = dateFormatter.parse(expireDateStr);
} catch (Exception e) {}
}
if (firstCert.get("certId") instanceof Number) {
this.certId = ((Number) firstCert.get("certId")).longValue();
}
if (firstCert.get("certStatus") != null) {
this.certStatus = (String) firstCert.get("certStatus");
}
} catch (Exception e) {
log.error("序列化证书列表失败", e);
}
}
}
// ==================== 原有的证书列表方法 ====================
/** /**
* 获取证书列表 - 从certificatesJson解析 * 获取证书列表 - 从certificatesJson解析
*/ */
@ -321,14 +488,18 @@ public class VetQualification extends BaseEntity
if (issueDateObj instanceof String) { if (issueDateObj instanceof String) {
try { try {
cert.setIssueDate(new SimpleDateFormat("yyyy-MM-dd").parse((String) issueDateObj));
cert.setIssueDate(dateFormatter.parse((String) issueDateObj));
} catch (Exception e) {} } catch (Exception e) {}
} else if (issueDateObj instanceof Date) {
cert.setIssueDate((Date) issueDateObj);
} }
if (expireDateObj instanceof String) { if (expireDateObj instanceof String) {
try { try {
cert.setExpireDate(new SimpleDateFormat("yyyy-MM-dd").parse((String) expireDateObj));
cert.setExpireDate(dateFormatter.parse((String) expireDateObj));
} catch (Exception e) {} } catch (Exception e) {}
} else if (expireDateObj instanceof Date) {
cert.setExpireDate((Date) expireDateObj);
} }
cert.setQualificationId(this.qualificationId); cert.setQualificationId(this.qualificationId);
@ -347,7 +518,6 @@ public class VetQualification extends BaseEntity
} catch (Exception e) {} } catch (Exception e) {}
} }
// 修复这里确保ID不为null且不为0否则使用稳定ID生成器
if (certificateId == null || certificateId == 0) { if (certificateId == null || certificateId == 0) {
certificateId = generateSafeCertificateId(); certificateId = generateSafeCertificateId();
} }
@ -382,32 +552,23 @@ public class VetQualification extends BaseEntity
return certificateList; return certificateList;
} }
/** /**
* 生成安全的证书ID避免JavaScript精度丢失 * 生成安全的证书ID避免JavaScript精度丢失
*/ */
private Long generateSafeCertificateId() { private Long generateSafeCertificateId() {
// 当前毫秒时间戳13位
long timestamp = System.currentTimeMillis(); long timestamp = System.currentTimeMillis();
// 取时间戳的后12位确保在安全范围内
long id = timestamp % 1000000000000L; // 12位数字
// 加上1亿确保是9位数以上
long id = timestamp % 1000000000000L;
id += 100000000L; id += 100000000L;
// 双重检查确保不超过JavaScript安全上限
if (id > MAX_SAFE_ID) { if (id > MAX_SAFE_ID) {
// 如果超过取模回到安全范围
id = id % (MAX_SAFE_ID - 100000000L) + 100000000L; id = id % (MAX_SAFE_ID - 100000000L) + 100000000L;
} }
return id; return id;
} }
/** /**
* 设置证书列表并同步更新JSON字段 * 设置证书列表并同步更新JSON字段
*/ */
public void setCertificateList(List<CertificateInfo> certificateList) { public void setCertificateList(List<CertificateInfo> certificateList) {
this.certificateList = certificateList; this.certificateList = certificateList;
@ -423,16 +584,13 @@ public class VetQualification extends BaseEntity
certMap.put("certificateFiles", cert.getCertificateFiles()); certMap.put("certificateFiles", cert.getCertificateFiles());
if (cert.getIssueDate() != null) { if (cert.getIssueDate() != null) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
certMap.put("issueDate", sdf.format(cert.getIssueDate()));
certMap.put("issueDate", dateFormatter.format(cert.getIssueDate()));
} }
if (cert.getExpireDate() != null) { if (cert.getExpireDate() != null) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
certMap.put("expireDate", sdf.format(cert.getExpireDate()));
certMap.put("expireDate", dateFormatter.format(cert.getExpireDate()));
} }
// 确保每个证书都有ID
if (cert.getCertificateId() == null || cert.getCertificateId() == 0) { if (cert.getCertificateId() == null || cert.getCertificateId() == 0) {
cert.setCertificateId(generateSafeCertificateId()); cert.setCertificateId(generateSafeCertificateId());
} }
@ -448,6 +606,9 @@ public class VetQualification extends BaseEntity
this.certificatesJson = objectMapper.writeValueAsString(certMapList); this.certificatesJson = objectMapper.writeValueAsString(certMapList);
// 同时设置 certificates 字段供前端使用
this.certificates = certMapList;
// 更新主表字段 // 更新主表字段
if (!certificateList.isEmpty()) { if (!certificateList.isEmpty()) {
CertificateInfo firstCert = certificateList.get(0); CertificateInfo firstCert = certificateList.get(0);
@ -500,6 +661,8 @@ public class VetQualification extends BaseEntity
} }
} }
// ==================== 经营范围处理 ====================
@JsonProperty("scopeIds") @JsonProperty("scopeIds")
public void setScopeIdsFromJson(List<String> scopeIdList) { public void setScopeIdsFromJson(List<String> scopeIdList) {
if (scopeIdList != null && !scopeIdList.isEmpty()) { if (scopeIdList != null && !scopeIdList.isEmpty()) {
@ -526,6 +689,8 @@ public class VetQualification extends BaseEntity
this.scopeIds = scopeIds; this.scopeIds = scopeIds;
} }
// ==================== 基础 Getter/Setter ====================
public Long getQualificationId() { public Long getQualificationId() {
return qualificationId; return qualificationId;
} }
@ -750,6 +915,7 @@ public class VetQualification extends BaseEntity
this.certStatusLabel = certStatusLabel; this.certStatusLabel = certStatusLabel;
} }
@JsonIgnore
public String getCertificatesJson() { public String getCertificatesJson() {
return certificatesJson; return certificatesJson;
} }
@ -758,58 +924,6 @@ public class VetQualification extends BaseEntity
this.certificatesJson = certificatesJson; this.certificatesJson = certificatesJson;
} }
@JsonIgnore
public List<Map<String, Object>> getCertificates() {
if (StringUtils.isEmpty(certificatesJson)) {
return new ArrayList<>();
}
try {
return objectMapper.readValue(
certificatesJson,
objectMapper.getTypeFactory().constructCollectionType(List.class, Map.class)
);
} catch (Exception e) {
log.error("解析certificatesJson失败", e);
return new ArrayList<>();
}
}
/**
* 设置证书列表兼容性方法转换为certificatesJson存储
*/
public void setCertificates(List<Map<String, Object>> certificates) {
if (certificates != null && !certificates.isEmpty()) {
try {
this.certificatesJson = objectMapper.writeValueAsString(certificates);
// 更新主表字段
Map<String, Object> firstCert = certificates.get(0);
this.certName = (String) firstCert.get("certName");
this.certificateNo = (String) firstCert.get("certificateNo");
this.issueOrg = (String) firstCert.get("issueOrg");
this.certificateFiles = (String) firstCert.get("certificateFiles");
Object issueDateObj = firstCert.get("issueDate");
Object expireDateObj = firstCert.get("expireDate");
if (issueDateObj instanceof String) {
try {
this.issueDate = new SimpleDateFormat("yyyy-MM-dd").parse((String) issueDateObj);
} catch (Exception e) {}
}
if (expireDateObj instanceof String) {
try {
this.expireDate = new SimpleDateFormat("yyyy-MM-dd").parse((String) expireDateObj);
} catch (Exception e) {}
}
} catch (Exception e) {
log.error("序列化证书列表失败", e);
}
}
}
@Override @Override
public String toString() { public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
@ -842,8 +956,6 @@ public class VetQualification extends BaseEntity
.append("updateBy", getUpdateBy()) .append("updateBy", getUpdateBy())
.append("updateTime", getUpdateTime()) .append("updateTime", getUpdateTime())
.append("remark", getRemark()) .append("remark", getRemark())
.append("certificatesJson", getCertificatesJson())
.toString(); .toString();
} }
}
}

8
chenhai-system/src/main/java/com/chenhai/vet/domain/dto/VetUnifiedInfoDTO.java

@ -208,6 +208,10 @@ public class VetUnifiedInfoDTO {
} }
public String getGender() { public String getGender() {
// 如果性别是 "0" 或空字符串返回 null
if (gender == null || "0".equals(gender) || "".equals(gender.trim())) {
return null;
}
return gender; return gender;
} }
@ -240,6 +244,10 @@ public class VetUnifiedInfoDTO {
} }
public String getWorkExperience() { public String getWorkExperience() {
// 如果工作经验是 "0" 或空字符串返回 null
if (workExperience == null || "0".equals(workExperience) || "".equals(workExperience.trim())) {
return null;
}
return workExperience; return workExperience;
} }

127
chenhai-system/src/main/java/com/chenhai/vet/service/impl/VetCommentsServiceImpl.java

@ -1,6 +1,8 @@
package com.chenhai.vet.service.impl; package com.chenhai.vet.service.impl;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.HashMap;
import com.chenhai.common.core.domain.entity.SysUser; import com.chenhai.common.core.domain.entity.SysUser;
import com.chenhai.common.core.domain.model.LoginUser; import com.chenhai.common.core.domain.model.LoginUser;
@ -60,10 +62,8 @@ public class VetCommentsServiceImpl implements IVetCommentsService
comment.setImages(parseImagesFromJsonString(comment.getImages())); comment.setImages(parseImagesFromJsonString(comment.getImages()));
} }
// 如果查询时字段为空尝试填充兽医信息
if (comment != null && (StringUtils.isEmpty(comment.getTitle()) ||
StringUtils.isEmpty(comment.getHospital()) ||
StringUtils.isEmpty(comment.getExperience()))) {
// 尝试填充兽医信息包括专家类型和擅长领域
if (comment != null) {
fillVetInfoToComment(comment); fillVetInfoToComment(comment);
} }
return comment; return comment;
@ -125,7 +125,7 @@ public class VetCommentsServiceImpl implements IVetCommentsService
vetComments.setAvatar(loginUser.getUser().getAvatar()); vetComments.setAvatar(loginUser.getUser().getAvatar());
} }
// 自动填充兽医职称医院和经验信息到数据库字段中
// 自动填充兽医职称医院经验专家类型擅长领域信息到数据库字段中
vetComments = autoFillVetInfoToFields(vetComments, loginUser.getUserId()); vetComments = autoFillVetInfoToFields(vetComments, loginUser.getUserId());
} }
@ -386,8 +386,7 @@ public class VetCommentsServiceImpl implements IVetCommentsService
} }
/** /**
* 自动填充兽医职称医院和经验信息到数据库字段
* 这是主要方法将信息填充到实体的 titlehospitalexperience 字段中
* 自动填充兽医职称医院经验专家类型擅长领域信息到数据库字段
* *
* @param vetComments 兽医回复对象 * @param vetComments 兽医回复对象
* @param userId 兽医用户ID * @param userId 兽医用户ID
@ -399,6 +398,9 @@ public class VetCommentsServiceImpl implements IVetCommentsService
VetPersonalInfo vetInfo = vetPersonalInfoService.selectVetPersonalInfoByUserId(userId); VetPersonalInfo vetInfo = vetPersonalInfoService.selectVetPersonalInfoByUserId(userId);
if (vetInfo != null) { if (vetInfo != null) {
log.info("获取到兽医个人信息 - userId: {}, expertType: {}, specialty: {}",
userId, vetInfo.getExpertType(), vetInfo.getSpecialty());
// 直接设置到实体字段中 // 直接设置到实体字段中
if (StringUtils.isNotEmpty(vetInfo.getTitle())) { if (StringUtils.isNotEmpty(vetInfo.getTitle())) {
vetComments.setTitle(vetInfo.getTitle()); vetComments.setTitle(vetInfo.getTitle());
@ -412,9 +414,24 @@ public class VetCommentsServiceImpl implements IVetCommentsService
vetComments.setExperience(vetInfo.getWorkExperience()); vetComments.setExperience(vetInfo.getWorkExperience());
} }
log.info("已自动填充兽医信息到字段:职称={}, 医院={}, 经验={}",
vetInfo.getTitle(), vetInfo.getHospital(), vetInfo.getWorkExperience());
// ========== 关键填充专家类型和擅长领域 ==========
if (StringUtils.isNotEmpty(vetInfo.getExpertType())) {
vetComments.setExpertType(vetInfo.getExpertType());
log.info("已填充专家类型: {}", vetInfo.getExpertType());
} else {
log.warn("兽医专家类型为空 - userId: {}", userId);
}
if (StringUtils.isNotEmpty(vetInfo.getSpecialty())) {
vetComments.setSpecialty(vetInfo.getSpecialty());
log.info("已填充擅长领域: {}", vetInfo.getSpecialty());
} else {
log.warn("兽医擅长领域为空 - userId: {}", userId);
}
log.info("已自动填充兽医信息到字段:职称={}, 医院={}, 经验={}, 专家类型={}, 擅长领域={}",
vetComments.getTitle(), vetComments.getHospital(), vetComments.getExperience(),
vetComments.getExpertType(), vetComments.getSpecialty());
} else { } else {
log.warn("用户ID:{} 未找到兽医个人信息", userId); log.warn("用户ID:{} 未找到兽医个人信息", userId);
@ -428,8 +445,8 @@ public class VetCommentsServiceImpl implements IVetCommentsService
} }
/** /**
* 为已有的评论记录填充兽医信息
* 用于查询时如果发现字段为空从兽医表补充信息
* 为已有的评论记录填充兽医信息包括专家类型和擅长领域
* 用于查询时从兽医表补充信息
*/ */
private void fillVetInfoToComment(VetComments comment) { private void fillVetInfoToComment(VetComments comment) {
if (comment == null || comment.getUserId() == null) { if (comment == null || comment.getUserId() == null) {
@ -437,19 +454,15 @@ public class VetCommentsServiceImpl implements IVetCommentsService
} }
try { try {
// 如果字段已经存在跳过
if (StringUtils.isNotEmpty(comment.getTitle()) &&
StringUtils.isNotEmpty(comment.getHospital()) &&
StringUtils.isNotEmpty(comment.getExperience())) {
return;
}
// 获取兽医个人信息 // 获取兽医个人信息
VetPersonalInfo vetInfo = vetPersonalInfoService.selectVetPersonalInfoByUserId(comment.getUserId()); VetPersonalInfo vetInfo = vetPersonalInfoService.selectVetPersonalInfoByUserId(comment.getUserId());
if (vetInfo != null) { if (vetInfo != null) {
boolean needUpdate = false; boolean needUpdate = false;
log.info("填充兽医信息到评论 - 评论ID: {}, userId: {}, expertType: {}, specialty: {}",
comment.getId(), comment.getUserId(), vetInfo.getExpertType(), vetInfo.getSpecialty());
// 检查并填充缺失的字段 // 检查并填充缺失的字段
if (StringUtils.isEmpty(comment.getTitle()) && StringUtils.isNotEmpty(vetInfo.getTitle())) { if (StringUtils.isEmpty(comment.getTitle()) && StringUtils.isNotEmpty(vetInfo.getTitle())) {
comment.setTitle(vetInfo.getTitle()); comment.setTitle(vetInfo.getTitle());
@ -466,6 +479,19 @@ public class VetCommentsServiceImpl implements IVetCommentsService
needUpdate = true; needUpdate = true;
} }
// ========== 关键填充专家类型和擅长领域 ==========
if (StringUtils.isEmpty(comment.getExpertType()) && StringUtils.isNotEmpty(vetInfo.getExpertType())) {
comment.setExpertType(vetInfo.getExpertType());
needUpdate = true;
log.info("填充专家类型: {}", vetInfo.getExpertType());
}
if (StringUtils.isEmpty(comment.getSpecialty()) && StringUtils.isNotEmpty(vetInfo.getSpecialty())) {
comment.setSpecialty(vetInfo.getSpecialty());
needUpdate = true;
log.info("填充擅长领域: {}", vetInfo.getSpecialty());
}
// 如果补充了信息更新数据库 // 如果补充了信息更新数据库
if (needUpdate) { if (needUpdate) {
VetComments updateData = new VetComments(); VetComments updateData = new VetComments();
@ -473,10 +499,14 @@ public class VetCommentsServiceImpl implements IVetCommentsService
updateData.setTitle(comment.getTitle()); updateData.setTitle(comment.getTitle());
updateData.setHospital(comment.getHospital()); updateData.setHospital(comment.getHospital());
updateData.setExperience(comment.getExperience()); updateData.setExperience(comment.getExperience());
updateData.setExpertType(comment.getExpertType());
updateData.setSpecialty(comment.getSpecialty());
vetCommentsMapper.updateVetComments(updateData); vetCommentsMapper.updateVetComments(updateData);
log.info("已为历史回复记录补充兽医信息,评论ID:{}", comment.getId()); log.info("已为历史回复记录补充兽医信息,评论ID:{}", comment.getId());
} }
} else {
log.warn("未找到兽医个人信息 - userId: {}", comment.getUserId());
} }
} catch (Exception e) { } catch (Exception e) {
@ -485,7 +515,7 @@ public class VetCommentsServiceImpl implements IVetCommentsService
} }
/** /**
* 获取兽医信息标签用于前端显示
* 获取兽医信息标签用于前端显示- 包含专家类型和擅长领域
*/ */
public String getVetInfoTags(Long userId) { public String getVetInfoTags(Long userId) {
try { try {
@ -506,6 +536,16 @@ public class VetCommentsServiceImpl implements IVetCommentsService
tags.append("<span class='vet-tag vet-experience'>执业").append(vetInfo.getWorkExperience()).append("</span>"); tags.append("<span class='vet-tag vet-experience'>执业").append(vetInfo.getWorkExperience()).append("</span>");
} }
// 添加专家类型标签
if (StringUtils.isNotEmpty(vetInfo.getExpertType())) {
tags.append("<span class='vet-tag vet-expert-type'>").append(getExpertTypeLabel(vetInfo.getExpertType())).append("</span>");
}
// 添加擅长领域标签
if (StringUtils.isNotEmpty(vetInfo.getSpecialty())) {
tags.append("<span class='vet-tag vet-specialty'>擅长:").append(vetInfo.getSpecialty()).append("</span>");
}
return tags.toString(); return tags.toString();
} }
} catch (Exception e) { } catch (Exception e) {
@ -515,6 +555,47 @@ public class VetCommentsServiceImpl implements IVetCommentsService
return ""; return "";
} }
/**
* 获取专家类型标签
*/
private String getExpertTypeLabel(String expertType) {
if (StringUtils.isEmpty(expertType)) {
return "";
}
switch (expertType) {
case "资深专家":
return "🌟 资深专家";
case "高级专家":
return "⭐ 高级专家";
case "普通专家":
return "👨‍⚕️ 普通专家";
default:
return expertType;
}
}
/**
* 获取兽医完整信息Map用于前端显示
*/
public Map<String, String> getVetInfoMap(Long userId) {
Map<String, String> infoMap = new HashMap<>();
try {
VetPersonalInfo vetInfo = vetPersonalInfoService.selectVetPersonalInfoByUserId(userId);
if (vetInfo != null) {
infoMap.put("title", vetInfo.getTitle());
infoMap.put("hospital", vetInfo.getHospital());
infoMap.put("experience", vetInfo.getWorkExperience());
infoMap.put("expertType", vetInfo.getExpertType());
infoMap.put("specialty", vetInfo.getSpecialty());
infoMap.put("avatar", vetInfo.getAvatar());
infoMap.put("realName", vetInfo.getRealName());
}
} catch (Exception e) {
log.error("获取兽医信息失败,用户ID:{}", userId, e);
}
return infoMap;
}
/** /**
* 根据问诊单ID获取回复列表包含兽医信息 * 根据问诊单ID获取回复列表包含兽医信息
*/ */
@ -647,10 +728,12 @@ public class VetCommentsServiceImpl implements IVetCommentsService
vetComments.setAvatar(currentUser.getAvatar()); vetComments.setAvatar(currentUser.getAvatar());
} }
// 自动填充兽医信息如果字段为空
// 自动填充兽医信息如果字段为空- 包括专家类型和擅长领域
if (StringUtils.isEmpty(vetComments.getTitle()) || if (StringUtils.isEmpty(vetComments.getTitle()) ||
StringUtils.isEmpty(vetComments.getHospital()) || StringUtils.isEmpty(vetComments.getHospital()) ||
StringUtils.isEmpty(vetComments.getExperience())) {
StringUtils.isEmpty(vetComments.getExperience()) ||
StringUtils.isEmpty(vetComments.getExpertType()) ||
StringUtils.isEmpty(vetComments.getSpecialty())) {
autoFillVetInfoToFields(vetComments, currentUserId); autoFillVetInfoToFields(vetComments, currentUserId);
} }
} }
@ -732,4 +815,4 @@ public class VetCommentsServiceImpl implements IVetCommentsService
log.info("---"); log.info("---");
} }
} }
}
}

224
chenhai-system/src/main/java/com/chenhai/vet/service/impl/VetKnowledgeServiceImpl.java

@ -42,12 +42,94 @@ public class VetKnowledgeServiceImpl implements IVetKnowledgeService
} }
/** /**
* 查询兽医文章列表
* 查询兽医文章列表带数据权限过滤
* 管理员和muhu能看到所有vet只能看到自己的
*/ */
@Override @Override
public List<VetKnowledge> selectVetKnowledgeList(VetKnowledge vetKnowledge) public List<VetKnowledge> selectVetKnowledgeList(VetKnowledge vetKnowledge)
{ {
return vetKnowledgeMapper.selectVetKnowledgeList(vetKnowledge);
// 获取当前登录用户信息
LoginUser loginUser = SecurityUtils.getLoginUser();
if (loginUser == null || loginUser.getUser() == null) {
// 未登录返回空列表
return new ArrayList<>();
}
SysUser currentUser = loginUser.getUser();
Long userId = currentUser.getUserId();
// 判断角色权限
boolean isAdmin = SecurityUtils.hasRole("admin");
boolean isMuhu = SecurityUtils.hasRole("muhu");
boolean isManger = SecurityUtils.hasRole("manger");
boolean isVet = SecurityUtils.hasRole("vet");
// 管理员muhumanger可以看到所有文章不添加数据过滤
if (isAdmin || isMuhu || isManger) {
// 直接查询所有不添加用户过滤条件
return vetKnowledgeMapper.selectVetKnowledgeList(vetKnowledge);
}
// vet只能看到自己创建的文章
else if (isVet) {
// 设置创建人ID或创建人名称进行过滤
// 方式1通过用户ID过滤推荐如果表中有user_id字段
if (vetKnowledge.getUserId() == null) {
vetKnowledge.setUserId(userId);
}
// 方式2通过创建人名称过滤如果使用create_by字段
// String username = currentUser.getUserName();
// vetKnowledge.setCreateBy(username);
return vetKnowledgeMapper.selectVetKnowledgeList(vetKnowledge);
}
// 其他角色返回空列表
return new ArrayList<>();
}
/**
* 查询已发布且审核通过的兽医文章列表
* 只返回状态为已发布(1)且审核通过(2)的文章
* 权限控制muhu和vet可以看到已发布的文章
*/
@Override
public List<VetKnowledge> selectPublishedKnowledgeList(VetKnowledge vetKnowledge)
{
// 强制设置查询条件为已发布且审核通过
vetKnowledge.setArticleStatus("1"); // 已发布
vetKnowledge.setAuditStatus("2"); // 审核通过
// 获取当前登录用户信息
LoginUser loginUser = SecurityUtils.getLoginUser();
if (loginUser == null || loginUser.getUser() == null) {
// 未登录用户只能看到公开的已发布文章
return vetKnowledgeMapper.selectVetKnowledgeList(vetKnowledge);
}
SysUser currentUser = loginUser.getUser();
Long userId = currentUser.getUserId();
// 判断角色权限
boolean isAdmin = SecurityUtils.hasRole("admin");
boolean isMuhu = SecurityUtils.hasRole("muhu");
boolean isManger = SecurityUtils.hasRole("manger");
boolean isVet = SecurityUtils.hasRole("vet");
// 管理员muhumanger可以看到所有已发布的文章
if (isAdmin || isMuhu || isManger) {
return vetKnowledgeMapper.selectVetKnowledgeList(vetKnowledge);
}
// vet只能看到自己发布的已通过审核的文章
else if (isVet) {
// 添加用户过滤条件
vetKnowledge.setUserId(userId);
return vetKnowledgeMapper.selectVetKnowledgeList(vetKnowledge);
}
// 其他角色只能看到所有已发布的文章不添加用户过滤
else {
return vetKnowledgeMapper.selectVetKnowledgeList(vetKnowledge);
}
} }
/** /**
@ -86,6 +168,9 @@ public class VetKnowledgeServiceImpl implements IVetKnowledgeService
vetKnowledge.setNickName(currentUser.getUserName()); vetKnowledge.setNickName(currentUser.getUserName());
} }
// 设置创建人
vetKnowledge.setCreateBy(currentUser.getUserName());
// 5. 设置用户头像 // 5. 设置用户头像
String avatar = currentUser.getAvatar(); String avatar = currentUser.getAvatar();
if (avatar != null && !avatar.isEmpty()) { if (avatar != null && !avatar.isEmpty()) {
@ -101,6 +186,7 @@ public class VetKnowledgeServiceImpl implements IVetKnowledgeService
if (user != null) { if (user != null) {
vetKnowledge.setNickName(user.getNickName() != null ? user.getNickName() : user.getUserName()); vetKnowledge.setNickName(user.getNickName() != null ? user.getNickName() : user.getUserName());
vetKnowledge.setAvatar(user.getAvatar()); vetKnowledge.setAvatar(user.getAvatar());
vetKnowledge.setCreateBy(user.getUserName());
System.out.println("从数据库获取用户信息成功 - nickName: " + vetKnowledge.getNickName()); System.out.println("从数据库获取用户信息成功 - nickName: " + vetKnowledge.getNickName());
} }
} }
@ -174,17 +260,11 @@ public class VetKnowledgeServiceImpl implements IVetKnowledgeService
continue; continue;
} }
// 检查是否是自己的文章通过创建者判断
String createBy = article.getCreateBy();
String currentUsername = SecurityUtils.getUsername();
if (createBy == null || !createBy.equals(currentUsername)) {
// 如果不是自己的文章检查是否是管理员
if (!SecurityUtils.isAdmin(currentUserId)) { // 修改这里
failedCount++;
failedMessages.add("文章ID " + id + " 不是您发布的文章,无法删除");
continue;
}
// 检查是否有权限删除
if (!hasDeletePermission(article, currentUserId)) {
failedCount++;
failedMessages.add("文章ID " + id + " 没有权限删除");
continue;
} }
// 执行删除 // 执行删除
@ -231,15 +311,9 @@ public class VetKnowledgeServiceImpl implements IVetKnowledgeService
return AjaxResult.error("文章不存在"); return AjaxResult.error("文章不存在");
} }
// 检查是否是自己的文章通过创建者判断
String createBy = article.getCreateBy();
String currentUsername = SecurityUtils.getUsername();
if (createBy == null || !createBy.equals(currentUsername)) {
// 如果不是自己的文章检查是否是管理员
if (!SecurityUtils.isAdmin(currentUserId)) { // 修改这里
return AjaxResult.error("不是您发布的文章,无法删除");
}
// 检查是否有权限删除
if (!hasDeletePermission(article, currentUserId)) {
return AjaxResult.error("没有权限删除该文章");
} }
int result = vetKnowledgeMapper.deleteVetKnowledgeById(id); int result = vetKnowledgeMapper.deleteVetKnowledgeById(id);
@ -253,6 +327,39 @@ public class VetKnowledgeServiceImpl implements IVetKnowledgeService
return AjaxResult.error("删除失败: " + e.getMessage()); return AjaxResult.error("删除失败: " + e.getMessage());
} }
} }
/**
* 检查是否有删除权限
* @param article 文章对象
* @param currentUserId 当前用户ID
* @return true:有权限 false:无权限
*/
private boolean hasDeletePermission(VetKnowledge article, Long currentUserId) {
// 管理员muhumanger可以删除任何文章
if (SecurityUtils.hasRole("admin") ||
SecurityUtils.hasRole("muhu") ||
SecurityUtils.hasRole("manger")) {
return true;
}
// vet只能删除自己的文章
if (SecurityUtils.hasRole("vet")) {
Long articleUserId = article.getUserId();
if (articleUserId != null && articleUserId.equals(currentUserId)) {
return true;
}
// 兼容通过create_by字段判断
String createBy = article.getCreateBy();
String currentUsername = SecurityUtils.getUsername();
if (createBy != null && createBy.equals(currentUsername)) {
return true;
}
}
return false;
}
/** /**
* 提交审核将审核状态改为审核中 * 提交审核将审核状态改为审核中
*/ */
@ -265,6 +372,12 @@ public class VetKnowledgeServiceImpl implements IVetKnowledgeService
if (current == null) { if (current == null) {
return AjaxResult.error("文章不存在"); return AjaxResult.error("文章不存在");
} }
// 检查是否是自己的文章
if (!isOwner(current)) {
return AjaxResult.error("只能提交自己创建的文章进行审核");
}
// 只有草稿状态(0)且待审核状态(0)的文章才能提交审核 // 只有草稿状态(0)且待审核状态(0)的文章才能提交审核
if (!"0".equals(current.getArticleStatus())) { if (!"0".equals(current.getArticleStatus())) {
return AjaxResult.error("只有草稿状态的文章可以提交审核"); return AjaxResult.error("只有草稿状态的文章可以提交审核");
@ -301,17 +414,23 @@ public class VetKnowledgeServiceImpl implements IVetKnowledgeService
} }
/** /**
* 审核文章
* 审核文章只有管理员muhumanger可以审核
*/ */
@Override @Override
public AjaxResult auditVetKnowledge(Long id, String auditStatus, String auditComment) { public AjaxResult auditVetKnowledge(Long id, String auditStatus, String auditComment) {
try { try {
// 检查权限只有管理员muhumanger可以审核
if (!SecurityUtils.hasRole("admin") &&
!SecurityUtils.hasRole("muhu") &&
!SecurityUtils.hasRole("manger")) {
return AjaxResult.error("没有权限审核文章");
}
VetKnowledge current = vetKnowledgeMapper.selectVetKnowledgeById(id); VetKnowledge current = vetKnowledgeMapper.selectVetKnowledgeById(id);
if (current == null) { if (current == null) {
return AjaxResult.error("文章不存在"); return AjaxResult.error("文章不存在");
} }
// 只有审核中状态(1)才能进行审核 // 只有审核中状态(1)才能进行审核
if (!"1".equals(current.getAuditStatus())) { if (!"1".equals(current.getAuditStatus())) {
return AjaxResult.error("只有审核中状态的文章可以审核"); return AjaxResult.error("只有审核中状态的文章可以审核");
@ -354,6 +473,11 @@ public class VetKnowledgeServiceImpl implements IVetKnowledgeService
return AjaxResult.error("文章不存在"); return AjaxResult.error("文章不存在");
} }
// 检查是否是自己的文章
if (!isOwner(current)) {
return AjaxResult.error("只能发布自己创建的文章");
}
// 只有审核通过(2)且为草稿状态(0)的文章才能发布 // 只有审核通过(2)且为草稿状态(0)的文章才能发布
if (!"2".equals(current.getAuditStatus())) { if (!"2".equals(current.getAuditStatus())) {
return AjaxResult.error("只有审核通过的文章可以发布"); return AjaxResult.error("只有审核通过的文章可以发布");
@ -395,6 +519,12 @@ public class VetKnowledgeServiceImpl implements IVetKnowledgeService
if (current == null) { if (current == null) {
return AjaxResult.error("文章不存在"); return AjaxResult.error("文章不存在");
} }
// 检查是否是自己的文章
if (!isOwner(current)) {
return AjaxResult.error("只能上架自己创建的文章");
}
// 只有已下架状态(2)的文章才能上架 // 只有已下架状态(2)的文章才能上架
if (!"2".equals(current.getArticleStatus())) { if (!"2".equals(current.getArticleStatus())) {
return AjaxResult.error("只有已下架的文章可以上架"); return AjaxResult.error("只有已下架的文章可以上架");
@ -435,6 +565,11 @@ public class VetKnowledgeServiceImpl implements IVetKnowledgeService
return AjaxResult.error("文章不存在"); return AjaxResult.error("文章不存在");
} }
// 检查是否是自己的文章
if (!isOwner(current)) {
return AjaxResult.error("只能下架自己创建的文章");
}
// 只有已发布状态(1)的文章才能下架 // 只有已发布状态(1)的文章才能下架
if (!"1".equals(current.getArticleStatus())) { if (!"1".equals(current.getArticleStatus())) {
return AjaxResult.error("只有已发布的文章可以下架"); return AjaxResult.error("只有已发布的文章可以下架");
@ -473,18 +608,6 @@ public class VetKnowledgeServiceImpl implements IVetKnowledgeService
} }
} }
/**
* 查询已发布且审核通过的兽医文章列表
* 只返回状态为已发布(1)且审核通过(2)的文章
*/
@Override
public List<VetKnowledge> selectPublishedKnowledgeList(VetKnowledge vetKnowledge) {
// 强制设置查询条件为已发布且审核通过
vetKnowledge.setArticleStatus("1"); // 已发布
vetKnowledge.setAuditStatus("2"); // 审核通过
return vetKnowledgeMapper.selectVetKnowledgeList(vetKnowledge);
}
/** /**
* 增加文章查看次数 * 增加文章查看次数
*/ */
@ -506,4 +629,31 @@ public class VetKnowledgeServiceImpl implements IVetKnowledgeService
return 0; return 0;
} }
} }
}
/**
* 检查当前用户是否是文章所有者
*/
private boolean isOwner(VetKnowledge article) {
LoginUser loginUser = SecurityUtils.getLoginUser();
if (loginUser == null || loginUser.getUser() == null) {
return false;
}
Long currentUserId = loginUser.getUser().getUserId();
Long articleUserId = article.getUserId();
// 通过user_id判断
if (articleUserId != null && articleUserId.equals(currentUserId)) {
return true;
}
// 通过create_by判断
String createBy = article.getCreateBy();
String currentUsername = loginUser.getUsername();
if (createBy != null && createBy.equals(currentUsername)) {
return true;
}
return false;
}
}

109
chenhai-system/src/main/java/com/chenhai/vet/service/impl/VetNotificationServiceImpl.java

@ -138,46 +138,32 @@ public class VetNotificationServiceImpl implements VetNotificationService {
return false; return false;
} }
// 添加 markAllAsRead 方法
/*@Override
public void markAsRead(Long userId) {
try {
// 使用Mapper提供的方法批量标记为已读
int result = vetNotificationMapper.markAllNotificationsAsRead(userId);
log.info("用户ID={} 已将所有通知标记为已读,影响记录数={}", userId, result);
} catch (Exception e) {
log.error("标记所有通知为已读失败,用户ID={}", userId, e);
// 如果批量操作失败尝试逐条更新
fallbackMarkAllAsRead(userId);
}
@Override
public List<VetNotification> selectByUserId(Long userId) {
return vetNotificationMapper.selectVetNotificationByUserId(userId);
} }
*/
/**
* 回退方案逐条更新通知为已读
*/
private void fallbackMarkAllAsRead(Long userId) {
try {
VetNotification query = new VetNotification();
query.setUserId(userId);
List<VetNotification> notifications = vetNotificationMapper.selectVetNotificationList(query);
int count = 0;
for (VetNotification notification : notifications) {
if (notification.getIsRead() == 0) {
notification.setIsRead(1);
notification.setReadTime(new Date());
vetNotificationMapper.updateVetNotification(notification);
count++;
}
}
log.info("回退方案:用户ID={} 已成功标记{}个通知为已读", userId, count);
} catch (Exception e) {
log.error("回退方案标记通知为已读也失败,用户ID={}", userId, e);
}
@Override
public Map<String, Integer> getNotificationStats(Long userId) {
Map<String, Object> stats = vetNotificationMapper.selectNotificationStatsByUserId(userId);
return Map.of(
"unread", ((Number) stats.getOrDefault("unread", 0)).intValue(),
"read", ((Number) stats.getOrDefault("read", 0)).intValue()
);
}
@Override
public int getUnreadCount(Long userId) {
VetNotification query = new VetNotification();
query.setUserId(userId);
query.setIsRead(0);
List<VetNotification> unreadNotifications = vetNotificationMapper.selectVetNotificationList(query);
return unreadNotifications.size();
} }
/** /**
* 创建证书通知对象 * 创建证书通知对象
* 修改添加 certId 字段设置
*/ */
private VetNotification createCertificateNotification(VetQualification qualification, private VetNotification createCertificateNotification(VetQualification qualification,
VetQualification.CertificateInfo certificate, VetQualification.CertificateInfo certificate,
@ -191,6 +177,9 @@ public class VetNotificationServiceImpl implements VetNotificationService {
certificate.getCertificateId() != null ? certificate.getCertificateId() : 0L); certificate.getCertificateId() != null ? certificate.getCertificateId() : 0L);
notification.setRelatedId(relatedId); notification.setRelatedId(relatedId);
// ========== 关键修改单独设置 certId 字段 ==========
notification.setCertId(certificate.getCertificateId()); // 设置证书ID
notification.setType("CERT_EXPIRE_REMIND"); notification.setType("CERT_EXPIRE_REMIND");
notification.setTitle(title); notification.setTitle(title);
notification.setContent(content); notification.setContent(content);
@ -199,6 +188,9 @@ public class VetNotificationServiceImpl implements VetNotificationService {
notification.setCreateTime(new Date()); notification.setCreateTime(new Date());
notification.setCreateBy("system"); notification.setCreateBy("system");
log.debug("创建证书通知 - userId: {}, certId: {}, relatedId: {}",
qualification.getUserId(), certificate.getCertificateId(), relatedId);
return notification; return notification;
} }
@ -209,8 +201,8 @@ public class VetNotificationServiceImpl implements VetNotificationService {
try { try {
int result = vetNotificationMapper.insertVetNotification(notification); int result = vetNotificationMapper.insertVetNotification(notification);
if (result > 0) { if (result > 0) {
log.info("成功发送证书提醒通知:用户ID={}, 标题={}",
notification.getUserId(), notification.getTitle());
log.info("成功发送证书提醒通知:用户ID={}, 证书ID={}, 标题={}",
notification.getUserId(), notification.getCertId(), notification.getTitle());
} }
} catch (Exception e) { } catch (Exception e) {
log.error("发送证书提醒通知失败:错误信息={}", e.getMessage(), e); log.error("发送证书提醒通知失败:错误信息={}", e.getMessage(), e);
@ -254,28 +246,27 @@ public class VetNotificationServiceImpl implements VetNotificationService {
return sdf.format(date); return sdf.format(date);
} }
@Override
public List<VetNotification> selectByUserId(Long userId) {
return vetNotificationMapper.selectVetNotificationByUserId(userId);
}
@Override
public Map<String, Integer> getNotificationStats(Long userId) {
// 查询统计信息
Map<String, Object> stats = vetNotificationMapper.selectNotificationStatsByUserId(userId);
return Map.of(
"unread", ((Number) stats.getOrDefault("unread", 0)).intValue(),
"read", ((Number) stats.getOrDefault("read", 0)).intValue()
);
}
/**
* 回退方案逐条更新通知为已读
*/
private void fallbackMarkAllAsRead(Long userId) {
try {
VetNotification query = new VetNotification();
query.setUserId(userId);
List<VetNotification> notifications = vetNotificationMapper.selectVetNotificationList(query);
@Override
public int getUnreadCount(Long userId) {
VetNotification query = new VetNotification();
query.setUserId(userId);
query.setIsRead(0);
List<VetNotification> unreadNotifications = vetNotificationMapper.selectVetNotificationList(query);
return unreadNotifications.size();
int count = 0;
for (VetNotification notification : notifications) {
if (notification.getIsRead() == 0) {
notification.setIsRead(1);
notification.setReadTime(new Date());
vetNotificationMapper.updateVetNotification(notification);
count++;
}
}
log.info("回退方案:用户ID={} 已成功标记{}个通知为已读", userId, count);
} catch (Exception e) {
log.error("回退方案标记通知为已读也失败,用户ID={}", userId, e);
}
} }
}
}

111
chenhai-system/src/main/java/com/chenhai/vet/service/impl/VetPersonalInfoServiceImpl.java

@ -114,14 +114,14 @@ public class VetPersonalInfoServiceImpl implements IVetPersonalInfoService {
// 1. 先查询原始数据 // 1. 先查询原始数据
List<VetPersonalInfo> list = vetPersonalInfoMapper.selectVetPersonalInfoList(vetPersonalInfo); List<VetPersonalInfo> list = vetPersonalInfoMapper.selectVetPersonalInfoList(vetPersonalInfo);
// 2. 强制为每个记录同步头像
// 2. 强制为每个记录同步完整的用户信息头像昵称手机号邮箱性别
if (list != null && !list.isEmpty()) { if (list != null && !list.isEmpty()) {
for (VetPersonalInfo info : list) { for (VetPersonalInfo info : list) {
try { try {
// 直接调用同步方法
syncAvatarFromUser(info);
// 使用增强后的 fillUserInfo 方法同步所有用户信息
fillUserInfo(info);
} catch (Exception e) { } catch (Exception e) {
System.err.println("同步头像失败,ID: " + info.getId() + ", 错误: " + e.getMessage());
System.err.println("同步用户信息失败,ID: " + info.getId() + ", 错误: " + e.getMessage());
} }
} }
} }
@ -212,11 +212,16 @@ public class VetPersonalInfoServiceImpl implements IVetPersonalInfoService {
} }
} }
// 4. 设置创建者和更新者
// 4. 设置审核状态新注册默认待审核
if (StringUtils.isEmpty(vetPersonalInfo.getAuditStatus())) {
vetPersonalInfo.setAuditStatus("0"); // 默认待审核
}
// 5. 设置创建者和更新者
vetPersonalInfo.setCreateBy(loginUser.getUsername()); vetPersonalInfo.setCreateBy(loginUser.getUsername());
vetPersonalInfo.setUpdateBy(loginUser.getUsername()); vetPersonalInfo.setUpdateBy(loginUser.getUsername());
// 5. 从用户表获取信息优先使用用户表数据
// 6. 从用户表获取信息优先使用用户表数据
SysUser currentUser = sysUserService.selectUserById(loginUser.getUserId()); SysUser currentUser = sysUserService.selectUserById(loginUser.getUserId());
if (currentUser != null) { if (currentUser != null) {
// 头像强制使用用户表头像 // 头像强制使用用户表头像
@ -245,13 +250,11 @@ public class VetPersonalInfoServiceImpl implements IVetPersonalInfoService {
} }
} }
// 6. 设置创建时间和更新时间
// 7. 设置创建时间和更新时间
vetPersonalInfo.setCreateTime(DateUtils.getNowDate()); vetPersonalInfo.setCreateTime(DateUtils.getNowDate());
vetPersonalInfo.setUpdateTime(DateUtils.getNowDate()); vetPersonalInfo.setUpdateTime(DateUtils.getNowDate());
int result = vetPersonalInfoMapper.insertVetPersonalInfo(vetPersonalInfo); int result = vetPersonalInfoMapper.insertVetPersonalInfo(vetPersonalInfo);
// 7. 新增时不同步头像到用户表以用户表为准
return result; return result;
} else { } else {
throw new RuntimeException("用户未登录"); throw new RuntimeException("用户未登录");
@ -273,6 +276,9 @@ public class VetPersonalInfoServiceImpl implements IVetPersonalInfoService {
throw new RuntimeException("无权限修改其他用户的兽医信息"); throw new RuntimeException("无权限修改其他用户的兽医信息");
} }
// 检查信息是否发生变化
boolean infoChanged = isInfoChanged(existing, vetPersonalInfo);
String newAvatar = vetPersonalInfo.getAvatar(); String newAvatar = vetPersonalInfo.getAvatar();
String oldAvatar = existing != null ? existing.getAvatar() : null; String oldAvatar = existing != null ? existing.getAvatar() : null;
boolean avatarChanged = newAvatar != null && !newAvatar.equals(oldAvatar); boolean avatarChanged = newAvatar != null && !newAvatar.equals(oldAvatar);
@ -281,12 +287,23 @@ public class VetPersonalInfoServiceImpl implements IVetPersonalInfoService {
vetPersonalInfo.setUpdateBy(loginUser.getUsername()); vetPersonalInfo.setUpdateBy(loginUser.getUsername());
vetPersonalInfo.setUpdateTime(DateUtils.getNowDate()); vetPersonalInfo.setUpdateTime(DateUtils.getNowDate());
// 如果信息发生变化重置审核状态为待审核
if (infoChanged || avatarChanged) {
vetPersonalInfo.setAuditStatus("0");
System.out.println("兽医信息已修改,审核状态重置为待审核 - 兽医ID: " + vetPersonalInfo.getId());
}
int result = vetPersonalInfoMapper.updateVetPersonalInfo(vetPersonalInfo); int result = vetPersonalInfoMapper.updateVetPersonalInfo(vetPersonalInfo);
// 头像同步并刷新缓存 // 头像同步并刷新缓存
if (result > 0 && avatarChanged && StringUtils.isNotEmpty(newAvatar)) { if (result > 0 && avatarChanged && StringUtils.isNotEmpty(newAvatar)) {
syncAvatarToUserTable(loginUser.getUserId(), newAvatar); syncAvatarToUserTable(loginUser.getUserId(), newAvatar);
refreshUserCache(loginUser); // 刷新缓存
refreshUserCache(loginUser);
}
// ========== 新增如果修改了关键信息同时重置所有资质的审核状态 ==========
if (result > 0 && (infoChanged || avatarChanged)) {
resetQualificationsAuditStatus(vetPersonalInfo.getUserId());
} }
return result; return result;
@ -295,6 +312,54 @@ public class VetPersonalInfoServiceImpl implements IVetPersonalInfoService {
} }
} }
/**
* 重置用户所有资质的审核状态
*/
private void resetQualificationsAuditStatus(Long userId) {
try {
VetQualification query = new VetQualification();
query.setUserId(userId);
List<VetQualification> qualifications = vetQualificationMapper.selectVetQualificationList(query);
for (VetQualification qualification : qualifications) {
// 重置资质审核状态
qualification.setAuditStatus("0");
// qualification.setUpdateTime(new Date());
qualification.setUpdateBy(SecurityUtils.getUsername());
vetQualificationMapper.updateVetQualification(qualification);
}
System.out.println("已重置用户所有资质的审核状态 - 用户ID: " + userId + ", 数量: " + qualifications.size());
} catch (Exception e) {
System.err.println("重置资质审核状态失败: " + e.getMessage());
}
}
/**
* 判断兽医信息是否发生变化
*/
private boolean isInfoChanged(VetPersonalInfo existing, VetPersonalInfo newInfo) {
if (existing == null || newInfo == null) {
return true;
}
// 比较关键字段是否发生变化
if (!StringUtils.equals(existing.getNickName(), newInfo.getNickName())) return true;
if (!StringUtils.equals(existing.getRealName(), newInfo.getRealName())) return true;
if (!StringUtils.equals(existing.getGender(), newInfo.getGender())) return true;
if (!StringUtils.equals(existing.getPhone(), newInfo.getPhone())) return true;
if (!StringUtils.equals(existing.getEmail(), newInfo.getEmail())) return true;
if (!StringUtils.equals(existing.getIdCard(), newInfo.getIdCard())) return true;
// if (!StringUtils.equals(existing.getPracticeLicenseNo(), newInfo.getPracticeLicenseNo())) return true;
// if (!StringUtils.equals(existing.getHospitalName(), newInfo.getHospitalName())) return true;
// if (!StringUtils.equals(existing.getHospitalAddress(), newInfo.getHospitalAddress())) return true;
if (!StringUtils.equals(existing.getSpecialty(), newInfo.getSpecialty())) return true;
if (!StringUtils.equals(existing.getIntroduction(), newInfo.getIntroduction())) return true;
// if (existing.getYearsOfExperience() != newInfo.getYearsOfExperience()) return true;
return false;
}
/** /**
* 刷新用户缓存 - 使用RedisCache * 刷新用户缓存 - 使用RedisCache
*/ */
@ -541,8 +606,28 @@ public class VetPersonalInfoServiceImpl implements IVetPersonalInfoService {
*/ */
private void fillUserInfo(VetPersonalInfo vetInfo) { private void fillUserInfo(VetPersonalInfo vetInfo) {
if (vetInfo != null && vetInfo.getUserId() != null) { if (vetInfo != null && vetInfo.getUserId() != null) {
// 直接调用头像同步方法
syncAvatarFromUser(vetInfo);
SysUser user = sysUserService.selectUserById(vetInfo.getUserId());
if (user != null) {
// 只设置用户对象不更新数据库
vetInfo.setUser(user);
// 只同步到内存对象不更新数据库
if (StringUtils.isNotEmpty(user.getAvatar())) {
vetInfo.setAvatar(user.getAvatar());
}
if (StringUtils.isEmpty(vetInfo.getNickName()) && StringUtils.isNotEmpty(user.getNickName())) {
vetInfo.setNickName(user.getNickName());
}
if (StringUtils.isEmpty(vetInfo.getPhone()) && StringUtils.isNotEmpty(user.getPhonenumber())) {
vetInfo.setPhone(user.getPhonenumber());
}
if (StringUtils.isEmpty(vetInfo.getEmail()) && StringUtils.isNotEmpty(user.getEmail())) {
vetInfo.setEmail(user.getEmail());
}
if (StringUtils.isEmpty(vetInfo.getGender()) && StringUtils.isNotEmpty(user.getSex())) {
vetInfo.setGender(user.getSex());
}
}
} }
} }
@ -589,4 +674,4 @@ public class VetPersonalInfoServiceImpl implements IVetPersonalInfoService {
System.out.println("批量同步完成,成功: " + successCount + " 条"); System.out.println("批量同步完成,成功: " + successCount + " 条");
} }
}
}

1178
chenhai-system/src/main/java/com/chenhai/vet/service/impl/VetQualificationServiceImpl.java
File diff suppressed because it is too large
View File

165
chenhai-system/src/main/java/com/chenhai/vet/service/impl/VetTrainingVideoServiceImpl.java

@ -4,6 +4,8 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import com.chenhai.common.core.domain.AjaxResult; import com.chenhai.common.core.domain.AjaxResult;
import com.chenhai.common.core.domain.entity.SysUser;
import com.chenhai.common.core.domain.model.LoginUser;
import com.chenhai.common.utils.SecurityUtils; import com.chenhai.common.utils.SecurityUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -28,6 +30,7 @@ public class VetTrainingVideoServiceImpl implements IVetTrainingVideoService
// 添加 logger // 添加 logger
private static final Logger logger = LoggerFactory.getLogger(VetTrainingVideoServiceImpl.class); private static final Logger logger = LoggerFactory.getLogger(VetTrainingVideoServiceImpl.class);
@Autowired @Autowired
private VetTrainingVideoMapper vetTrainingVideoMapper; private VetTrainingVideoMapper vetTrainingVideoMapper;
@ -44,15 +47,44 @@ public class VetTrainingVideoServiceImpl implements IVetTrainingVideoService
} }
/** /**
* 查询兽医培训视频列表
*
* @param vetTrainingVideo 兽医培训视频
* @return 兽医培训视频
* 查询兽医培训视频列表带数据权限过滤
* 管理员和muhu能看到所有vet只能看到自己的
*/ */
@Override @Override
public List<VetTrainingVideo> selectVetTrainingVideoList(VetTrainingVideo vetTrainingVideo) public List<VetTrainingVideo> selectVetTrainingVideoList(VetTrainingVideo vetTrainingVideo)
{ {
return vetTrainingVideoMapper.selectVetTrainingVideoList(vetTrainingVideo);
// 获取当前登录用户信息
LoginUser loginUser = SecurityUtils.getLoginUser();
if (loginUser == null || loginUser.getUser() == null) {
// 未登录返回空列表
return new ArrayList<>();
}
SysUser currentUser = loginUser.getUser();
Long userId = currentUser.getUserId();
// 判断角色权限
boolean isAdmin = SecurityUtils.hasRole("admin");
boolean isMuhu = SecurityUtils.hasRole("muhu");
boolean isManger = SecurityUtils.hasRole("manger");
boolean isVet = SecurityUtils.hasRole("vet");
// 管理员muhumanger可以看到所有视频不添加数据过滤
if (isAdmin || isMuhu || isManger) {
// 直接查询所有不添加用户过滤条件
return vetTrainingVideoMapper.selectVetTrainingVideoList(vetTrainingVideo);
}
// vet只能看到自己创建的视频
else if (isVet) {
// 设置用户ID进行过滤
if (vetTrainingVideo.getUserId() == null) {
vetTrainingVideo.setUserId(userId);
}
return vetTrainingVideoMapper.selectVetTrainingVideoList(vetTrainingVideo);
}
// 其他角色返回空列表
return new ArrayList<>();
} }
/** /**
@ -70,9 +102,24 @@ public class VetTrainingVideoServiceImpl implements IVetTrainingVideoService
throw new RuntimeException("用户未登录"); throw new RuntimeException("用户未登录");
} }
// 获取当前登录用户信息设置发布者信息
LoginUser loginUser = SecurityUtils.getLoginUser();
if (loginUser != null && loginUser.getUser() != null) {
SysUser currentUser = loginUser.getUser();
// 设置发布者姓名昵称
String nickName = currentUser.getNickName();
if (nickName != null && !nickName.isEmpty()) {
vetTrainingVideo.setPublisherName(nickName);
} else {
vetTrainingVideo.setPublisherName(currentUser.getUserName());
}
// 设置发布者头像
vetTrainingVideo.setPublisherAvatar(currentUser.getAvatar());
}
vetTrainingVideo.setUserId(userId); // 确保设置用户ID vetTrainingVideo.setUserId(userId); // 确保设置用户ID
vetTrainingVideo.setStatus("0"); // 草稿原私有 vetTrainingVideo.setStatus("0"); // 草稿原私有
vetTrainingVideo.setAuditStatus("1"); // 待审核
vetTrainingVideo.setAuditStatus("0"); // 待审核
vetTrainingVideo.setDelFlag("0"); // 正常 vetTrainingVideo.setDelFlag("0"); // 正常
vetTrainingVideo.setCreateTime(DateUtils.getNowDate()); vetTrainingVideo.setCreateTime(DateUtils.getNowDate());
@ -148,14 +195,11 @@ public class VetTrainingVideoServiceImpl implements IVetTrainingVideoService
continue; continue;
} }
// 检查是否是自己的视频通过userId字段判断
if (!currentUserId.equals(video.getUserId())) {
// 如果不是自己的视频检查是否是管理员
if (!SecurityUtils.isAdmin(currentUserId)) { // 修改这里
failedCount++;
failedMessages.add("视频ID " + id + " 不是您发布的视频,无法删除");
continue;
}
// 检查是否有权限删除
if (!hasDeletePermission(video, currentUserId)) {
failedCount++;
failedMessages.add("视频ID " + id + " 没有权限删除");
continue;
} }
// 执行删除 // 执行删除
@ -205,12 +249,9 @@ public class VetTrainingVideoServiceImpl implements IVetTrainingVideoService
return AjaxResult.error("视频不存在"); return AjaxResult.error("视频不存在");
} }
// 检查是否是自己的视频通过userId字段判断
if (!currentUserId.equals(video.getUserId())) {
// 如果不是自己的视频检查是否是管理员
if (!SecurityUtils.isAdmin(currentUserId)) { // 修改这里
return AjaxResult.error("不是您发布的视频,无法删除");
}
// 检查是否有权限删除
if (!hasDeletePermission(video, currentUserId)) {
return AjaxResult.error("没有权限删除该视频");
} }
int result = vetTrainingVideoMapper.deleteVetTrainingVideoById(id); int result = vetTrainingVideoMapper.deleteVetTrainingVideoById(id);
@ -225,6 +266,46 @@ public class VetTrainingVideoServiceImpl implements IVetTrainingVideoService
} }
} }
/**
* 检查是否有删除权限
* @param video 视频对象
* @param currentUserId 当前用户ID
* @return true:有权限 false:无权限
*/
private boolean hasDeletePermission(VetTrainingVideo video, Long currentUserId) {
// 管理员muhumanger可以删除任何视频
if (SecurityUtils.hasRole("admin") ||
SecurityUtils.hasRole("muhu") ||
SecurityUtils.hasRole("manger")) {
return true;
}
// vet只能删除自己的视频
if (SecurityUtils.hasRole("vet")) {
Long videoUserId = video.getUserId();
if (videoUserId != null && videoUserId.equals(currentUserId)) {
return true;
}
}
return false;
}
/**
* 检查当前用户是否是视频所有者
*/
private boolean isOwner(VetTrainingVideo video) {
LoginUser loginUser = SecurityUtils.getLoginUser();
if (loginUser == null || loginUser.getUser() == null) {
return false;
}
Long currentUserId = loginUser.getUser().getUserId();
Long videoUserId = video.getUserId();
return videoUserId != null && videoUserId.equals(currentUserId);
}
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public int batchSubmitForAudit(List<Long> videoIds, Long userId) { public int batchSubmitForAudit(List<Long> videoIds, Long userId) {
@ -277,6 +358,14 @@ public class VetTrainingVideoServiceImpl implements IVetTrainingVideoService
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public int batchAuditVideo(List<Long> videoIds, String auditStatus, String auditOpinion, Long auditUserId) { public int batchAuditVideo(List<Long> videoIds, String auditStatus, String auditOpinion, Long auditUserId) {
// 检查权限只有管理员muhumanger可以审核
if (!SecurityUtils.hasRole("admin") &&
!SecurityUtils.hasRole("muhu") &&
!SecurityUtils.hasRole("manger")) {
logger.warn("用户 {} 没有审核权限", auditUserId);
return 0;
}
int successCount = 0; int successCount = 0;
// 验证审核状态值2-通过3-拒绝 // 验证审核状态值2-通过3-拒绝
@ -419,6 +508,14 @@ public class VetTrainingVideoServiceImpl implements IVetTrainingVideoService
@Override @Override
public boolean auditVideo(Long videoId, String auditStatus, String auditOpinion, Long auditUserId) { public boolean auditVideo(Long videoId, String auditStatus, String auditOpinion, Long auditUserId) {
// 检查权限只有管理员muhumanger可以审核
if (!SecurityUtils.hasRole("admin") &&
!SecurityUtils.hasRole("muhu") &&
!SecurityUtils.hasRole("manger")) {
logger.warn("用户 {} 没有审核权限", auditUserId);
return false;
}
try { try {
VetTrainingVideo video = vetTrainingVideoMapper.selectVetTrainingVideoById(videoId); VetTrainingVideo video = vetTrainingVideoMapper.selectVetTrainingVideoById(videoId);
@ -427,7 +524,7 @@ public class VetTrainingVideoServiceImpl implements IVetTrainingVideoService
} }
// 只有审核中状态(1)才能审核 // 只有审核中状态(1)才能审核
if (!"1".equals(video.getAuditStatus())) {
if (!"0".equals(video.getAuditStatus())) {
return false; return false;
} }
@ -532,10 +629,14 @@ public class VetTrainingVideoServiceImpl implements IVetTrainingVideoService
return false; return false;
} }
// // 验证权限只能操作自己的视频
// if (!userId.equals(video.getUserId())) {
// return false;
// }
// 检查是否是管理员
boolean isAdmin = checkUserIsAdmin(userId);
boolean isOwner = userId.equals(video.getUserId());
if (!isAdmin && !isOwner) {
logger.warn("下架失败:用户 {} 无权限操作视频 {}", userId, videoId);
return false;
}
// 状态验证只有已发布状态(1)的视频才能下架 // 状态验证只有已发布状态(1)的视频才能下架
if (!"1".equals(video.getStatus())) { if (!"1".equals(video.getStatus())) {
@ -600,6 +701,12 @@ public class VetTrainingVideoServiceImpl implements IVetTrainingVideoService
return false; return false;
} }
// 检查权限管理员或视频所有者
boolean isAdmin = checkUserIsAdmin(userId);
if (!isAdmin && !userId.equals(video.getUserId())) {
return false;
}
// 状态验证只有待审核状态才能取消审核 // 状态验证只有待审核状态才能取消审核
if (!"0".equals(video.getAuditStatus()) && !"1".equals(video.getAuditStatus())) { if (!"0".equals(video.getAuditStatus()) && !"1".equals(video.getAuditStatus())) {
return false; return false;
@ -624,12 +731,13 @@ public class VetTrainingVideoServiceImpl implements IVetTrainingVideoService
/** /**
* 查询公开视频列表已上架且已审核通过 * 查询公开视频列表已上架且已审核通过
* 公开接口不需要权限过滤所有用户都能看到已上架且审核通过的视频
*/ */
@Override @Override
public List<VetTrainingVideo> selectPublicVideoList(VetTrainingVideo vetTrainingVideo) { public List<VetTrainingVideo> selectPublicVideoList(VetTrainingVideo vetTrainingVideo) {
// 设置强制条件已上架且审核通过 // 设置强制条件已上架且审核通过
vetTrainingVideo.setStatus("1"); // 已上架 vetTrainingVideo.setStatus("1"); // 已上架
vetTrainingVideo.setAuditStatus("2"); // 审核通过注意这里是2
vetTrainingVideo.setAuditStatus("2"); // 审核通过
vetTrainingVideo.setDelFlag("0"); // 未删除 vetTrainingVideo.setDelFlag("0"); // 未删除
return vetTrainingVideoMapper.selectPublicVideoList(vetTrainingVideo); return vetTrainingVideoMapper.selectPublicVideoList(vetTrainingVideo);
@ -637,14 +745,15 @@ public class VetTrainingVideoServiceImpl implements IVetTrainingVideoService
/** /**
* 分页查询公开视频列表已上架且已审核通过 * 分页查询公开视频列表已上架且已审核通过
* 公开接口不需要权限过滤所有用户都能看到已上架且审核通过的视频
*/ */
@Override @Override
public List<VetTrainingVideo> selectPublicVideoPageList(VetTrainingVideo vetTrainingVideo) { public List<VetTrainingVideo> selectPublicVideoPageList(VetTrainingVideo vetTrainingVideo) {
// 设置强制条件已上架且审核通过 // 设置强制条件已上架且审核通过
vetTrainingVideo.setStatus("1"); // 已上架 vetTrainingVideo.setStatus("1"); // 已上架
vetTrainingVideo.setAuditStatus("2"); // 审核通过注意这里是2
vetTrainingVideo.setAuditStatus("2"); // 审核通过
vetTrainingVideo.setDelFlag("0"); // 未删除 vetTrainingVideo.setDelFlag("0"); // 未删除
return vetTrainingVideoMapper.selectVetTrainingVideoList(vetTrainingVideo); return vetTrainingVideoMapper.selectVetTrainingVideoList(vetTrainingVideo);
} }
}
}

453
chenhai-system/src/main/java/com/chenhai/vet/service/impl/VetUnifiedInfoServiceImpl.java

@ -15,6 +15,8 @@ import com.chenhai.vet.domain.VetQualification;
import com.chenhai.vet.domain.dto.VetUnifiedInfoDTO; import com.chenhai.vet.domain.dto.VetUnifiedInfoDTO;
import com.chenhai.vet.mapper.VetPersonalInfoMapper; import com.chenhai.vet.mapper.VetPersonalInfoMapper;
import com.chenhai.vet.mapper.VetQualificationMapper; import com.chenhai.vet.mapper.VetQualificationMapper;
import com.chenhai.vet.service.IVetPersonalInfoService;
import com.chenhai.vet.service.IVetQualificationService;
import com.chenhai.vet.service.IVetUnifiedInfoService; import com.chenhai.vet.service.IVetUnifiedInfoService;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -58,6 +60,12 @@ public class VetUnifiedInfoServiceImpl implements IVetUnifiedInfoService {
@Autowired @Autowired
private ObjectMapper objectMapper; private ObjectMapper objectMapper;
@Autowired
private IVetPersonalInfoService vetPersonalInfoService;
@Autowired
private IVetQualificationService vetQualificationService;
private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
@Override @Override
@ -315,16 +323,13 @@ public class VetUnifiedInfoServiceImpl implements IVetUnifiedInfoService {
VetPersonalInfo personalQuery = new VetPersonalInfo(); VetPersonalInfo personalQuery = new VetPersonalInfo();
if (query != null) { if (query != null) {
BeanUtils.copyProperties(query, personalQuery); BeanUtils.copyProperties(query, personalQuery);
// 确保 userId 被正确传递
if (query.getUserId() != null) { if (query.getUserId() != null) {
personalQuery.setUserId(query.getUserId()); personalQuery.setUserId(query.getUserId());
} }
} }
// MyBatis 分页插件会自动处理分页
List<VetPersonalInfo> personalList = vetPersonalInfoMapper.selectVetPersonalInfoList(personalQuery); List<VetPersonalInfo> personalList = vetPersonalInfoMapper.selectVetPersonalInfoList(personalQuery);
// 转换为统一DTO
return personalList.stream() return personalList.stream()
.map(info -> { .map(info -> {
VetUnifiedInfoDTO dto = new VetUnifiedInfoDTO(); VetUnifiedInfoDTO dto = new VetUnifiedInfoDTO();
@ -345,11 +350,55 @@ public class VetUnifiedInfoServiceImpl implements IVetUnifiedInfoService {
dto.setUserType(user.getUserType()); dto.setUserType(user.getUserType());
dto.setAreaCode(user.getAreaCode()); dto.setAreaCode(user.getAreaCode());
dto.setStatus(user.getStatus()); dto.setStatus(user.getStatus());
dto.setLoginDate(user.getLoginDate());
} else {
// 如果关联对象为空手动查询用户信息
try {
user = sysUserService.selectUserById(info.getUserId());
if (user != null) {
dto.setUserName(user.getUserName());
dto.setNickName(user.getNickName());
dto.setPhonenumber(user.getPhonenumber());
dto.setEmail(user.getEmail());
dto.setAvatar(user.getAvatar());
dto.setUserType(user.getUserType());
dto.setAreaCode(user.getAreaCode());
dto.setStatus(user.getStatus());
dto.setLoginDate(user.getLoginDate());
}
} catch (Exception e) {
log.warn("查询用户信息失败 - userId: {}", info.getUserId(), e);
}
} }
// 补充资质信息
// 补充资质信息包含认证信息
VetQualification qualification = vetQualificationMapper.selectVetQualificationByUserId(info.getUserId()); VetQualification qualification = vetQualificationMapper.selectVetQualificationByUserId(info.getUserId());
if (qualification != null) { if (qualification != null) {
// ========== 从资质表获取认证信息 ==========
// 设置真实姓名和身份证如果个人信息表中没有则从资质表获取
if (StringUtils.isEmpty(dto.getRealName()) && StringUtils.isNotEmpty(qualification.getRealName())) {
dto.setRealName(qualification.getRealName());
}
if (StringUtils.isEmpty(dto.getIdCard()) && StringUtils.isNotEmpty(qualification.getIdCard())) {
dto.setIdCard(qualification.getIdCard());
}
// 设置认证状态如果有真实姓名和身份证则视为已认证
if (StringUtils.isNotEmpty(qualification.getRealName()) && StringUtils.isNotEmpty(qualification.getIdCard())) {
dto.setAuthStatus("已认证");
dto.setAuthTime(qualification.getCreateTime()); // 可以使用创建时间作为认证时间
// 身份证脱敏
String idCard = qualification.getIdCard();
if (StringUtils.isNotEmpty(idCard) && idCard.length() >= 15) {
String masked = idCard.substring(0, 6) + "********" + idCard.substring(idCard.length() - 4);
dto.setMaskedIdCard(masked);
}
} else {
dto.setAuthStatus("未认证");
}
// ========== 资质信息 ==========
dto.setQualificationId(qualification.getQualificationId()); dto.setQualificationId(qualification.getQualificationId());
dto.setQualificationType(qualification.getQualificationType()); dto.setQualificationType(qualification.getQualificationType());
dto.setQualificationTypeLabel(qualification.getQualificationTypeLabel()); dto.setQualificationTypeLabel(qualification.getQualificationTypeLabel());
@ -362,15 +411,82 @@ public class VetUnifiedInfoServiceImpl implements IVetUnifiedInfoService {
dto.setAuditTime(qualification.getAuditTime()); dto.setAuditTime(qualification.getAuditTime());
dto.setAuditOpinion(qualification.getAuditOpinion()); dto.setAuditOpinion(qualification.getAuditOpinion());
// 补充主证书信息
dto.setCertName(qualification.getCertName());
dto.setCertificateNo(qualification.getCertificateNo());
dto.setIssueOrg(qualification.getIssueOrg());
dto.setCertificateFiles(qualification.getCertificateFiles());
dto.setIssueDate(qualification.getIssueDate());
dto.setExpireDate(qualification.getExpireDate());
dto.setCertStatus(qualification.getCertStatus());
dto.setCertStatusLabel(qualification.getCertStatusLabel());
dto.setCertId(qualification.getCertId());
dto.setRemindDays(qualification.getRemindDays());
dto.setCertificatesJson(qualification.getCertificatesJson());
// 补充证书统计信息
List<VetQualification.CertificateInfo> certList = qualification.getCertificateList();
if (certList != null && !certList.isEmpty()) {
dto.setTotalCertificates(certList.size());
Date today = new Date();
Calendar cal = Calendar.getInstance();
cal.setTime(today);
cal.add(Calendar.DAY_OF_YEAR, 30);
Date thirtyDaysLater = cal.getTime();
int normal = 0, expiring = 0, expired = 0;
for (VetQualification.CertificateInfo cert : certList) {
if (cert.getExpireDate() != null) {
if (cert.getExpireDate().before(today)) {
expired++;
} else if (cert.getExpireDate().before(thirtyDaysLater)) {
expiring++;
} else {
normal++;
}
} else {
normal++;
}
}
dto.setNormalCount(normal);
dto.setExpiringCount(expiring);
dto.setExpiredCount(expired);
// 设置警告级别
if (expired > 0) {
dto.setWarningLevel("DANGER");
} else if (expiring > 0) {
dto.setWarningLevel("WARNING");
} else {
dto.setWarningLevel("NORMAL");
}
} else {
dto.setTotalCertificates(0);
dto.setNormalCount(0);
dto.setExpiringCount(0);
dto.setExpiredCount(0);
dto.setWarningLevel("NORMAL");
}
dto.setHasQualification(true); dto.setHasQualification(true);
dto.setHasCertificates(qualification.getCertificateList() != null && !qualification.getCertificateList().isEmpty()); dto.setHasCertificates(qualification.getCertificateList() != null && !qualification.getCertificateList().isEmpty());
} else { } else {
dto.setHasQualification(false); dto.setHasQualification(false);
dto.setHasCertificates(false); dto.setHasCertificates(false);
dto.setTotalCertificates(0);
dto.setNormalCount(0);
dto.setExpiringCount(0);
dto.setExpiredCount(0);
dto.setWarningLevel("NORMAL");
dto.setAuthStatus("未认证");
} }
dto.setHasPersonalInfo(true);
// 计算信息完整度
dto.setCompleteness(calculateCompleteness(dto)); dto.setCompleteness(calculateCompleteness(dto));
dto.setHasPersonalInfo(true);
dto.setCanSubmitAudit(canSubmitAudit(dto));
return dto; return dto;
}) })
@ -431,22 +547,46 @@ public class VetUnifiedInfoServiceImpl implements IVetUnifiedInfoService {
VetPersonalInfo personalInfo = vetPersonalInfoMapper.selectVetPersonalInfoByUserId(userId); VetPersonalInfo personalInfo = vetPersonalInfoMapper.selectVetPersonalInfoByUserId(userId);
if (personalInfo != null) { if (personalInfo != null) {
// 使用BeanUtils.copyProperties但排除nickName和avatar字段 // 使用BeanUtils.copyProperties但排除nickName和avatar字段
// 这样就不会覆盖上面从sys_user获取的值
BeanUtils.copyProperties(personalInfo, dto, BeanUtils.copyProperties(personalInfo, dto,
"nickName", // 排除nickName使用sys_user的值 "nickName", // 排除nickName使用sys_user的值
"avatar"); // 排除avatar使用sys_user的值 "avatar"); // 排除avatar使用sys_user的值
dto.setPersonalInfoId(personalInfo.getId()); dto.setPersonalInfoId(personalInfo.getId());
dto.setPersonalEmail(personalInfo.getEmail()); dto.setPersonalEmail(personalInfo.getEmail());
dto.setPersonalNickName(personalInfo.getNickName()); // 兽医个人表的昵称放到单独字段
dto.setPersonalNickName(personalInfo.getNickName());
dto.setHasPersonalInfo(true); dto.setHasPersonalInfo(true);
} else { } else {
dto.setHasPersonalInfo(false); dto.setHasPersonalInfo(false);
} }
// 3. 获取资质信息
// 3. 获取资质信息包含认证信息
VetQualification qualification = vetQualificationMapper.selectVetQualificationByUserId(userId); VetQualification qualification = vetQualificationMapper.selectVetQualificationByUserId(userId);
if (qualification != null) { if (qualification != null) {
// ========== 从资质表获取认证信息 ==========
// 设置真实姓名和身份证如果个人信息表中没有则从资质表获取
if (StringUtils.isEmpty(dto.getRealName()) && StringUtils.isNotEmpty(qualification.getRealName())) {
dto.setRealName(qualification.getRealName());
}
if (StringUtils.isEmpty(dto.getIdCard()) && StringUtils.isNotEmpty(qualification.getIdCard())) {
dto.setIdCard(qualification.getIdCard());
}
// 设置认证状态如果有真实姓名和身份证则视为已认证
if (StringUtils.isNotEmpty(qualification.getRealName()) && StringUtils.isNotEmpty(qualification.getIdCard())) {
dto.setAuthStatus("已认证");
dto.setAuthTime(qualification.getCreateTime()); // 使用创建时间作为认证时间
// 身份证脱敏用于显示
String idCard = qualification.getIdCard();
if (StringUtils.isNotEmpty(idCard) && idCard.length() >= 15) {
String masked = idCard.substring(0, 6) + "********" + idCard.substring(idCard.length() - 4);
dto.setMaskedIdCard(masked);
}
} else {
dto.setAuthStatus("未认证");
}
// ========== 资质信息 ==========
dto.setQualificationId(qualification.getQualificationId()); dto.setQualificationId(qualification.getQualificationId());
dto.setQualificationType(qualification.getQualificationType()); dto.setQualificationType(qualification.getQualificationType());
dto.setQualificationTypeLabel(qualification.getQualificationTypeLabel()); dto.setQualificationTypeLabel(qualification.getQualificationTypeLabel());
@ -490,13 +630,17 @@ public class VetUnifiedInfoServiceImpl implements IVetUnifiedInfoService {
dto.setExpiringCount(0); dto.setExpiringCount(0);
dto.setExpiredCount(0); dto.setExpiredCount(0);
dto.setWarningLevel("NORMAL"); dto.setWarningLevel("NORMAL");
dto.setAuthStatus("未认证");
} }
// 4. 获取认证信息
// 4. 获取认证信息从sys_muhu_user表如果存在则覆盖
SysMuhuUser muhuUser = sysMuhuUserService.selectSysMuhuUserByUserId(userId); SysMuhuUser muhuUser = sysMuhuUserService.selectSysMuhuUserByUserId(userId);
if (muhuUser != null) { if (muhuUser != null) {
dto.setAuthStatus(muhuUser.getAuthStatus());
dto.setAuthTime(muhuUser.getAuthTime());
// 如果sys_muhu_user表有认证信息优先使用
if (StringUtils.isNotEmpty(muhuUser.getAuthStatus())) {
dto.setAuthStatus(muhuUser.getAuthStatus());
dto.setAuthTime(muhuUser.getAuthTime());
}
// 身份证脱敏 // 身份证脱敏
if (StringUtils.isNotEmpty(muhuUser.getIdCard()) && muhuUser.getIdCard().length() >= 15) { if (StringUtils.isNotEmpty(muhuUser.getIdCard()) && muhuUser.getIdCard().length() >= 15) {
@ -525,8 +669,8 @@ public class VetUnifiedInfoServiceImpl implements IVetUnifiedInfoService {
} }
// 添加日志方便调试 // 添加日志方便调试
log.debug("buildUnifiedInfo - userId: {}, nickName: {}, avatar: {}",
userId, dto.getNickName(), dto.getAvatar());
log.debug("buildUnifiedInfo - userId: {}, nickName: {}, avatar: {}, authStatus: {}",
userId, dto.getNickName(), dto.getAvatar(), dto.getAuthStatus());
return dto; return dto;
} }
@ -644,9 +788,9 @@ public class VetUnifiedInfoServiceImpl implements IVetUnifiedInfoService {
String idCard = (String) data.get("idCard"); String idCard = (String) data.get("idCard");
if (idCard != null && !idCard.trim().isEmpty()) { if (idCard != null && !idCard.trim().isEmpty()) {
idCard = idCard.trim().toUpperCase(); idCard = idCard.trim().toUpperCase();
if (!isValidIdCard(idCard)) {
throw new ServiceException("身份证号格式不正确");
}
// if (!isValidIdCard(idCard)) {
// throw new ServiceException("身份证号格式不正确");
// }
} }
// 手机号校验 // 手机号校验
@ -700,6 +844,7 @@ public class VetUnifiedInfoServiceImpl implements IVetUnifiedInfoService {
personalInfo = vetPersonalInfoMapper.selectVetPersonalInfoByUserId(userId); personalInfo = vetPersonalInfoMapper.selectVetPersonalInfoByUserId(userId);
} }
// 4. 检查是否有个人数据需要保存
boolean hasPersonalData = data.containsKey("realName") || data.containsKey("gender") boolean hasPersonalData = data.containsKey("realName") || data.containsKey("gender")
|| data.containsKey("birthday") || data.containsKey("idCard") || data.containsKey("birthday") || data.containsKey("idCard")
|| data.containsKey("specialty") || data.containsKey("workExperience") || data.containsKey("specialty") || data.containsKey("workExperience")
@ -714,14 +859,20 @@ public class VetUnifiedInfoServiceImpl implements IVetUnifiedInfoService {
return; return;
} }
// 如果 personalInfo 还是 null则创建新对象
if (personalInfo == null) { if (personalInfo == null) {
personalInfo = new VetPersonalInfo(); personalInfo = new VetPersonalInfo();
personalInfo.setUserId(userId); personalInfo.setUserId(userId);
personalInfo.setCreateBy(username); personalInfo.setCreateBy(username);
personalInfo.setCreateTime(new Date());
personalInfo.setAuditStatus("0"); // 新创建时默认为待审核
log.info("创建新的个人信息 - userId: {}", userId);
} }
// 更新兽医个人信息表的字段
if (data.containsKey("realName")) personalInfo.setRealName((String) data.get("realName"));
// 更新所有字段
if (data.containsKey("realName")) {
personalInfo.setRealName((String) data.get("realName"));
}
if (data.containsKey("gender")) { if (data.containsKey("gender")) {
Object genderObj = data.get("gender"); Object genderObj = data.get("gender");
if (genderObj == null || StringUtils.isEmpty(genderObj.toString())) { if (genderObj == null || StringUtils.isEmpty(genderObj.toString())) {
@ -745,19 +896,43 @@ public class VetUnifiedInfoServiceImpl implements IVetUnifiedInfoService {
} catch (Exception e) { } catch (Exception e) {
log.warn("解析生日日期失败: {}", birthdayObj); log.warn("解析生日日期失败: {}", birthdayObj);
} }
} else if (birthdayObj instanceof Date) {
personalInfo.setBirthday((Date) birthdayObj);
} }
} }
if (data.containsKey("idCard")) personalInfo.setIdCard((String) data.get("idCard"));
if (data.containsKey("specialty")) personalInfo.setSpecialty((String) data.get("specialty"));
if (data.containsKey("workExperience")) personalInfo.setWorkExperience((String) data.get("workExperience"));
if (data.containsKey("hospital")) personalInfo.setHospital((String) data.get("hospital"));
if (data.containsKey("address")) personalInfo.setAddress((String) data.get("address"));
if (data.containsKey("iphone")) personalInfo.setIphone((String) data.get("iphone"));
if (data.containsKey("introduction")) personalInfo.setIntroduction((String) data.get("introduction"));
if (data.containsKey("title")) personalInfo.setTitle((String) data.get("title"));
if (data.containsKey("phone")) personalInfo.setPhone((String) data.get("phone"));
if (data.containsKey("expertType")) personalInfo.setExpertType((String) data.get("expertType"));
if (data.containsKey("personalEmail")) personalInfo.setEmail((String) data.get("personalEmail"));
if (data.containsKey("idCard")) {
personalInfo.setIdCard((String) data.get("idCard"));
}
if (data.containsKey("specialty")) {
personalInfo.setSpecialty((String) data.get("specialty"));
}
if (data.containsKey("workExperience")) {
personalInfo.setWorkExperience((String) data.get("workExperience"));
}
if (data.containsKey("hospital")) {
personalInfo.setHospital((String) data.get("hospital"));
}
if (data.containsKey("address")) {
personalInfo.setAddress((String) data.get("address"));
}
if (data.containsKey("iphone")) {
personalInfo.setIphone((String) data.get("iphone"));
}
if (data.containsKey("introduction")) {
personalInfo.setIntroduction((String) data.get("introduction"));
}
if (data.containsKey("title")) {
personalInfo.setTitle((String) data.get("title"));
}
if (data.containsKey("phone")) {
personalInfo.setPhone((String) data.get("phone"));
}
if (data.containsKey("expertType")) {
personalInfo.setExpertType((String) data.get("expertType"));
}
if (data.containsKey("personalEmail")) {
personalInfo.setEmail((String) data.get("personalEmail"));
}
if (data.containsKey("personalNickName")) { if (data.containsKey("personalNickName")) {
personalInfo.setNickName((String) data.get("personalNickName")); personalInfo.setNickName((String) data.get("personalNickName"));
} }
@ -765,21 +940,30 @@ public class VetUnifiedInfoServiceImpl implements IVetUnifiedInfoService {
personalInfo.setAvatar((String) data.get("avatar")); personalInfo.setAvatar((String) data.get("avatar"));
} }
// 先保存兽医个人信息
// 关键如果请求中包含 auditStatus则使用它由Controller设置
if (data.containsKey("auditStatus")) {
personalInfo.setAuditStatus((String) data.get("auditStatus"));
log.info("设置审核状态为: {}", personalInfo.getAuditStatus());
}
personalInfo.setUpdateBy(username); personalInfo.setUpdateBy(username);
personalInfo.setUpdateTime(new Date()); personalInfo.setUpdateTime(new Date());
if (StringUtils.isEmpty(personalInfo.getAuditStatus())) {
personalInfo.setAuditStatus("0");
}
if (personalInfo.getId() != null) { if (personalInfo.getId() != null) {
vetPersonalInfoMapper.updateVetPersonalInfo(personalInfo);
log.info("兽医个人信息更新成功 - id: {}, userId: {}", personalInfo.getId(), userId);
int result = vetPersonalInfoMapper.updateVetPersonalInfo(personalInfo);
log.info("个人信息更新结果: {}, userId: {}, auditStatus: {}",
result, userId, personalInfo.getAuditStatus());
} else { } else {
personalInfo.setCreateTime(new Date());
vetPersonalInfoMapper.insertVetPersonalInfo(personalInfo);
log.info("兽医个人信息新增成功 - id: {}, userId: {}", personalInfo.getId(), userId);
personalInfo.setAuditStatus("0");
int result = vetPersonalInfoService.insertVetPersonalInfo(personalInfo);
log.info("个人信息新增结果: {}, userId: {}", result, userId);
} }
// 然后再同步更新用户表的字段如果有
// 使用单独的SQL更新避免触发角色删除
// 同步更新用户表的字段
if (data.containsKey("nickName")) { if (data.containsKey("nickName")) {
String newNickName = (String) data.get("nickName"); String newNickName = (String) data.get("nickName");
updateUserNickNameOnly(userId, newNickName); updateUserNickNameOnly(userId, newNickName);
@ -793,6 +977,90 @@ public class VetUnifiedInfoServiceImpl implements IVetUnifiedInfoService {
} }
} }
/**
* 判断个人信息是否发生变化
*/
private boolean isPersonalInfoChanged(VetPersonalInfo original, VetPersonalInfo newInfo) {
if (original == null || newInfo == null) {
return true;
}
// 比较所有字段
if (!StringUtils.equals(original.getRealName(), newInfo.getRealName())) {
log.debug("字段变化 - realName: {} -> {}", original.getRealName(), newInfo.getRealName());
return true;
}
if (!StringUtils.equals(original.getGender(), newInfo.getGender())) {
log.debug("字段变化 - gender: {} -> {}", original.getGender(), newInfo.getGender());
return true;
}
if (!StringUtils.equals(original.getIdCard(), newInfo.getIdCard())) {
log.debug("字段变化 - idCard: {} -> {}", original.getIdCard(), newInfo.getIdCard());
return true;
}
if (!StringUtils.equals(original.getPhone(), newInfo.getPhone())) {
log.debug("字段变化 - phone: {} -> {}", original.getPhone(), newInfo.getPhone());
return true;
}
if (!StringUtils.equals(original.getIphone(), newInfo.getIphone())) {
log.debug("字段变化 - iphone: {} -> {}", original.getIphone(), newInfo.getIphone());
return true;
}
if (!StringUtils.equals(original.getEmail(), newInfo.getEmail())) {
log.debug("字段变化 - email: {} -> {}", original.getEmail(), newInfo.getEmail());
return true;
}
if (!StringUtils.equals(original.getSpecialty(), newInfo.getSpecialty())) {
log.debug("字段变化 - specialty: {} -> {}", original.getSpecialty(), newInfo.getSpecialty());
return true;
}
if (!StringUtils.equals(original.getWorkExperience(), newInfo.getWorkExperience())) {
log.debug("字段变化 - workExperience: {} -> {}", original.getWorkExperience(), newInfo.getWorkExperience());
return true;
}
if (!StringUtils.equals(original.getHospital(), newInfo.getHospital())) {
log.debug("字段变化 - hospital: {} -> {}", original.getHospital(), newInfo.getHospital());
return true;
}
if (!StringUtils.equals(original.getAddress(), newInfo.getAddress())) {
log.debug("字段变化 - address: {} -> {}", original.getAddress(), newInfo.getAddress());
return true;
}
if (!StringUtils.equals(original.getIntroduction(), newInfo.getIntroduction())) {
log.debug("字段变化 - introduction: {} -> {}", original.getIntroduction(), newInfo.getIntroduction());
return true;
}
if (!StringUtils.equals(original.getTitle(), newInfo.getTitle())) {
log.debug("字段变化 - title: {} -> {}", original.getTitle(), newInfo.getTitle());
return true;
}
if (!StringUtils.equals(original.getExpertType(), newInfo.getExpertType())) {
log.debug("字段变化 - expertType: {} -> {}", original.getExpertType(), newInfo.getExpertType());
return true;
}
if (!StringUtils.equals(original.getNickName(), newInfo.getNickName())) {
log.debug("字段变化 - nickName: {} -> {}", original.getNickName(), newInfo.getNickName());
return true;
}
if (!StringUtils.equals(original.getAvatar(), newInfo.getAvatar())) {
log.debug("字段变化 - avatar: {} -> {}", original.getAvatar(), newInfo.getAvatar());
return true;
}
// 比较日期
if (original.getBirthday() != null && newInfo.getBirthday() != null) {
if (!original.getBirthday().equals(newInfo.getBirthday())) {
log.debug("字段变化 - birthday: {} -> {}", original.getBirthday(), newInfo.getBirthday());
return true;
}
} else if (original.getBirthday() != null || newInfo.getBirthday() != null) {
log.debug("字段变化 - birthday: {} -> {}", original.getBirthday(), newInfo.getBirthday());
return true;
}
return false;
}
/** /**
* 只更新用户表的昵称不影响角色 * 只更新用户表的昵称不影响角色
*/ */
@ -864,44 +1132,86 @@ public class VetUnifiedInfoServiceImpl implements IVetUnifiedInfoService {
return; // 没有资质数据不处理 return; // 没有资质数据不处理
} }
// 保存原始数据用于比较
VetQualification original = null;
if (qualification != null && qualification.getQualificationId() != null) {
original = vetQualificationMapper.selectVetQualificationByQualificationId(qualification.getQualificationId());
}
if (qualification == null) { if (qualification == null) {
qualification = new VetQualification(); qualification = new VetQualification();
qualification.setUserId(userId); qualification.setUserId(userId);
qualification.setCreateBy(username); qualification.setCreateBy(username);
qualification.setAuditStatus("0"); // 新建时默认为待审核
qualification.setCreateTime(new Date());
log.info("创建新的资质信息 - userId: {}", userId);
} }
// 记录是否有变化
boolean hasChanges = false;
// 更新基础信息 // 更新基础信息
if (data.containsKey("realName")) qualification.setRealName((String) data.get("realName"));
if (data.containsKey("idCard")) qualification.setIdCard((String) data.get("idCard"));
if (data.containsKey("qualificationType")) qualification.setQualificationType((String) data.get("qualificationType"));
if (data.containsKey("remindDays")) qualification.setRemindDays((Integer) data.get("remindDays"));
if (data.containsKey("realName")) {
String newValue = (String) data.get("realName");
if (!StringUtils.equals(qualification.getRealName(), newValue)) {
qualification.setRealName(newValue);
hasChanges = true;
}
}
if (data.containsKey("idCard")) {
String newValue = (String) data.get("idCard");
if (!StringUtils.equals(qualification.getIdCard(), newValue)) {
qualification.setIdCard(newValue);
hasChanges = true;
}
}
if (data.containsKey("qualificationType")) {
String newValue = (String) data.get("qualificationType");
if (!StringUtils.equals(qualification.getQualificationType(), newValue)) {
qualification.setQualificationType(newValue);
hasChanges = true;
}
}
if (data.containsKey("remindDays")) {
Integer newValue = (Integer) data.get("remindDays");
if (qualification.getRemindDays() == null || !qualification.getRemindDays().equals(newValue)) {
qualification.setRemindDays(newValue);
hasChanges = true;
}
}
// 处理经营范围 // 处理经营范围
if (data.containsKey("scopeIds")) { if (data.containsKey("scopeIds")) {
Object scopeIdsObj = data.get("scopeIds"); Object scopeIdsObj = data.get("scopeIds");
String newScopeIds = null;
if (scopeIdsObj instanceof List) { if (scopeIdsObj instanceof List) {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
List<String> scopeIdsList = (List<String>) scopeIdsObj; List<String> scopeIdsList = (List<String>) scopeIdsObj;
qualification.setScopeIds(String.join(",", scopeIdsList));
newScopeIds = String.join(",", scopeIdsList);
} else if (scopeIdsObj instanceof String) { } else if (scopeIdsObj instanceof String) {
qualification.setScopeIds((String) scopeIdsObj);
newScopeIds = (String) scopeIdsObj;
} }
// 获取经营范围名称
if (StringUtils.isNotEmpty(qualification.getScopeIds())) {
String scopeNames = getScopeNamesFromDict(qualification.getScopeIds());
qualification.setScopeNames(scopeNames);
if (!StringUtils.equals(qualification.getScopeIds(), newScopeIds)) {
qualification.setScopeIds(newScopeIds);
// 获取经营范围名称
if (StringUtils.isNotEmpty(qualification.getScopeIds())) {
String scopeNames = getScopeNamesFromDict(qualification.getScopeIds());
qualification.setScopeNames(scopeNames);
}
hasChanges = true;
} }
} }
// 处理证书列表 // 处理证书列表
boolean certificatesChanged = false;
if (data.containsKey("certificates")) { if (data.containsKey("certificates")) {
Object certificatesObj = data.get("certificates"); Object certificatesObj = data.get("certificates");
if (certificatesObj instanceof List) { if (certificatesObj instanceof List) {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
List<Map<String, Object>> certMaps = (List<Map<String, Object>>) certificatesObj; List<Map<String, Object>> certMaps = (List<Map<String, Object>>) certificatesObj;
List<VetQualification.CertificateInfo> certificateList = new ArrayList<>();
List<VetQualification.CertificateInfo> newCertificateList = new ArrayList<>();
for (Map<String, Object> certMap : certMaps) { for (Map<String, Object> certMap : certMaps) {
VetQualification.CertificateInfo cert = new VetQualification.CertificateInfo(); VetQualification.CertificateInfo cert = new VetQualification.CertificateInfo();
cert.setCertName((String) certMap.get("certName")); cert.setCertName((String) certMap.get("certName"));
@ -936,21 +1246,62 @@ public class VetUnifiedInfoServiceImpl implements IVetUnifiedInfoService {
cert.setCertificateId(generateCertificateId()); cert.setCertificateId(generateCertificateId());
} }
certificateList.add(cert);
newCertificateList.add(cert);
} }
qualification.setCertificateList(certificateList);
// 比较证书列表是否发生变化
List<VetQualification.CertificateInfo> originalCerts = qualification.getCertificateList();
if (originalCerts == null || originalCerts.size() != newCertificateList.size()) {
certificatesChanged = true;
} else {
for (int i = 0; i < originalCerts.size(); i++) {
VetQualification.CertificateInfo oc = originalCerts.get(i);
VetQualification.CertificateInfo nc = newCertificateList.get(i);
if (!StringUtils.equals(oc.getCertName(), nc.getCertName()) ||
!StringUtils.equals(oc.getCertificateNo(), nc.getCertificateNo()) ||
!StringUtils.equals(oc.getIssueOrg(), nc.getIssueOrg())) {
certificatesChanged = true;
break;
}
if (oc.getIssueDate() != null && nc.getIssueDate() != null && !oc.getIssueDate().equals(nc.getIssueDate())) {
certificatesChanged = true;
break;
}
if (oc.getExpireDate() != null && nc.getExpireDate() != null && !oc.getExpireDate().equals(nc.getExpireDate())) {
certificatesChanged = true;
break;
}
}
}
if (certificatesChanged) {
qualification.setCertificateList(newCertificateList);
hasChanges = true;
log.info("证书列表已修改 - userId: {}", userId);
}
} }
} }
// ========== 关键修改如果有任何变化重置审核状态 ==========
if (hasChanges) {
String oldStatus = qualification.getAuditStatus();
qualification.setAuditStatus("0");
qualification.setAuditOpinion(null);
qualification.setAuditTime(null);
qualification.setAuditorId(null);
log.info("资质信息已修改,审核状态重置为待审核 - userId: {}, 原状态: {}, 新状态: 0", userId, oldStatus);
}
qualification.setUpdateBy(username); qualification.setUpdateBy(username);
qualification.setUpdateTime(new Date()); qualification.setUpdateTime(new Date());
if (qualification.getQualificationId() != null) { if (qualification.getQualificationId() != null) {
vetQualificationMapper.updateVetQualification(qualification); vetQualificationMapper.updateVetQualification(qualification);
log.info("资质信息更新成功 - qualificationId: {}, userId: {}, hasChanges: {}",
qualification.getQualificationId(), userId, hasChanges);
} else { } else {
qualification.setCreateTime(new Date());
vetQualificationMapper.insertVetQualification(qualification); vetQualificationMapper.insertVetQualification(qualification);
log.info("资质信息新增成功 - userId: {}", userId);
} }
} }

144
chenhai-system/src/main/resources/mapper/system/SysMedicineRecommendationMapper.xml

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8" ?> <?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper <!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.chenhai.system.mapper.SysMedicineRecommendationMapper"> <mapper namespace="com.chenhai.system.mapper.SysMedicineRecommendationMapper">
<resultMap type="SysMedicineRecommendation" id="SysMedicineRecommendationResult"> <resultMap type="SysMedicineRecommendation" id="SysMedicineRecommendationResult">
<result property="id" column="id" /> <result property="id" column="id" />
<result property="medicineName" column="medicine_name" /> <result property="medicineName" column="medicine_name" />
@ -33,94 +33,94 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="latitude" column="latitude" /> <result property="latitude" column="latitude" />
<result property="images" column="images" /> <result property="images" column="images" />
<result property="imageUrl" column="image_url" /> <result property="imageUrl" column="image_url" />
<!-- 修改这里的关联查询,使用join方式(推荐) -->
<!-- 修改关联查询,从 vet_personal_info 表查询兽医信息 -->
<association property="expertAvatar" column="expert_id" <association property="expertAvatar" column="expert_id"
select="com.chenhai.system.mapper.SysMedicineRecommendationMapper.getExpertAvatarById" />
select="com.chenhai.system.mapper.SysMedicineRecommendationMapper.getExpertAvatarByUserId" />
<association property="expertName" column="expert_id" <association property="expertName" column="expert_id"
select="com.chenhai.system.mapper.SysMedicineRecommendationMapper.getExpertNameById" />
select="com.chenhai.system.mapper.SysMedicineRecommendationMapper.getExpertRealNameByUserId" />
<association property="expertExpert" column="expert_id" <association property="expertExpert" column="expert_id"
select="com.chenhai.system.mapper.SysMedicineRecommendationMapper.getExpertExpertById" />
select="com.chenhai.system.mapper.SysMedicineRecommendationMapper.getExpertTitleByUserId" />
<association property="expertIntroduction" column="expert_id" <association property="expertIntroduction" column="expert_id"
select="com.chenhai.system.mapper.SysMedicineRecommendationMapper.getExpertIntroductionById" />
select="com.chenhai.system.mapper.SysMedicineRecommendationMapper.getExpertIntroductionByUserId" />
<association property="expertAddress" column="expert_id" <association property="expertAddress" column="expert_id"
select="com.chenhai.system.mapper.SysMedicineRecommendationMapper.getExpertAddressById" />
select="com.chenhai.system.mapper.SysMedicineRecommendationMapper.getExpertAddressByUserId" />
<association property="expertExpertiseArea" column="expert_id" <association property="expertExpertiseArea" column="expert_id"
select="com.chenhai.system.mapper.SysMedicineRecommendationMapper.getExpertExpertiseAreaById" />
select="com.chenhai.system.mapper.SysMedicineRecommendationMapper.getExpertSpecialtyByUserId" />
<association property="expertWorkExperience" column="expert_id" <association property="expertWorkExperience" column="expert_id"
select="com.chenhai.system.mapper.SysMedicineRecommendationMapper.getExpertWorkExperienceById" />
select="com.chenhai.system.mapper.SysMedicineRecommendationMapper.getExpertWorkExperienceByUserId" />
</resultMap> </resultMap>
<!-- 或者保持原来的SELECT查询,但要修改关联查询的ID -->
<select id="getExpertAvatarById" parameterType="Long" resultType="String">
SELECT avatar FROM vet_experts WHERE expert_id = #{expertId}
<!-- 根据用户ID从 vet_personal_info 表查询兽医信息 -->
<select id="getExpertAvatarByUserId" parameterType="Long" resultType="String">
SELECT avatar FROM vet_personal_info WHERE user_id = #{expertId}
</select> </select>
<select id="getExpertNameById" parameterType="Long" resultType="String">
SELECT real_name FROM vet_experts WHERE expert_id = #{expertId}
<select id="getExpertRealNameByUserId" parameterType="Long" resultType="String">
SELECT real_name FROM vet_personal_info WHERE user_id = #{expertId}
</select> </select>
<select id="getExpertExpertById" parameterType="Long" resultType="String">
SELECT expert FROM vet_experts WHERE expert_id = #{expertId}
<select id="getExpertTitleByUserId" parameterType="Long" resultType="String">
SELECT title FROM vet_personal_info WHERE user_id = #{expertId}
</select> </select>
<select id="getExpertIntroductionById" parameterType="Long" resultType="String">
SELECT introduction FROM vet_experts WHERE expert_id = #{expertId}
<select id="getExpertIntroductionByUserId" parameterType="Long" resultType="String">
SELECT introduction FROM vet_personal_info WHERE user_id = #{expertId}
</select> </select>
<select id="getExpertAddressById" parameterType="Long" resultType="String">
SELECT address FROM vet_experts WHERE expert_id = #{expertId}
<select id="getExpertAddressByUserId" parameterType="Long" resultType="String">
SELECT address FROM vet_personal_info WHERE user_id = #{expertId}
</select> </select>
<select id="getExpertExpertiseAreaById" parameterType="Long" resultType="String">
SELECT expertise_area FROM vet_experts WHERE expert_id = #{expertId}
<select id="getExpertSpecialtyByUserId" parameterType="Long" resultType="String">
SELECT specialty FROM vet_personal_info WHERE user_id = #{expertId}
</select> </select>
<select id="getExpertWorkExperienceById" parameterType="Long" resultType="String">
SELECT work_experience FROM vet_experts WHERE expert_id = #{expertId}
<select id="getExpertWorkExperienceByUserId" parameterType="Long" resultType="String">
SELECT work_experience FROM vet_personal_info WHERE user_id = #{expertId}
</select> </select>
<!-- 修改基础查询SQL,添加专家表关联查询(更高效的方式) --> <!-- 修改基础查询SQL,添加专家表关联查询(更高效的方式) -->
<sql id="selectSysMedicineRecommendationVo"> <sql id="selectSysMedicineRecommendationVo">
select select
m.id,
m.medicine_name,
m.medicine_type,
m.specification,
m.price,
m.original_price,
m.sold_quantity,
m.indications,
m.usage_dosage,
m.precautions,
m.storage_method,
m.expiry_date,
m.created_at,
m.updated_at,
m.manufacturer,
m.sales_type,
m.expert_id,
m.recommend_reason,
m.recommend_time,
m.store_name,
m.store_address,
m.store_phone,
m.business_hours,
m.store_remark,
m.longitude,
m.latitude,
m.images,
m.image_url,
e.avatar as expert_avatar,
e.real_name as expert_name,
e.expert as expert_expert,
e.introduction as expert_introduction,
e.address as expert_address,
e.expertise_area as expertise_area,
e.work_experience as work_experience
m.id,
m.medicine_name,
m.medicine_type,
m.specification,
m.price,
m.original_price,
m.sold_quantity,
m.indications,
m.usage_dosage,
m.precautions,
m.storage_method,
m.expiry_date,
m.created_at,
m.updated_at,
m.manufacturer,
m.sales_type,
m.expert_id,
m.recommend_reason,
m.recommend_time,
m.store_name,
m.store_address,
m.store_phone,
m.business_hours,
m.store_remark,
m.longitude,
m.latitude,
m.images,
m.image_url,
v.avatar as expert_avatar,
v.real_name as expert_name,
v.title as expert_expert,
v.introduction as expert_introduction,
v.address as expert_address,
v.specialty as expertise_area,
v.work_experience as work_experience
from sys_medicine_recommendation m from sys_medicine_recommendation m
left join vet_experts e on m.expert_id = e.expert_id
left join sys_dict_data d on m.medicine_type = d.dict_value
and d.dict_type = 'medicine_type' <!-- 添加字典表JOIN -->
left join vet_personal_info v on m.expert_id = v.user_id
left join sys_dict_data d on m.medicine_type = d.dict_value
and d.dict_type = 'medicine_type'
</sql> </sql>
<select id="selectSysMedicineRecommendationList" parameterType="SysMedicineRecommendation" resultMap="SysMedicineRecommendationResult"> <select id="selectSysMedicineRecommendationList" parameterType="SysMedicineRecommendation" resultMap="SysMedicineRecommendationResult">
@ -157,8 +157,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
or m.manufacturer like concat('%', #{searchKeywords}, '%') or m.manufacturer like concat('%', #{searchKeywords}, '%')
or m.store_name like concat('%', #{searchKeywords}, '%') or m.store_name like concat('%', #{searchKeywords}, '%')
or m.usage_dosage like concat('%', #{searchKeywords}, '%') or m.usage_dosage like concat('%', #{searchKeywords}, '%')
or e.real_name like concat('%', #{searchKeywords}, '%')
or e.title like concat('%', #{searchKeywords}, '%')
or v.real_name like concat('%', #{searchKeywords}, '%')
or v.title like concat('%', #{searchKeywords}, '%')
) )
</if> </if>
</where> </where>
@ -166,12 +166,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
m.created_at DESC, m.created_at DESC,
m.id DESC m.id DESC
</select> </select>
<!-- 修复:明确指定表名 m.id -->
<select id="selectSysMedicineRecommendationById" parameterType="Long" resultMap="SysMedicineRecommendationResult"> <select id="selectSysMedicineRecommendationById" parameterType="Long" resultMap="SysMedicineRecommendationResult">
<include refid="selectSysMedicineRecommendationVo"/> <include refid="selectSysMedicineRecommendationVo"/>
where id = #{id}
where m.id = #{id}
</select> </select>
<!-- 其他 insert、update、delete 方法保持不变 -->
<insert id="insertSysMedicineRecommendation" parameterType="SysMedicineRecommendation" useGeneratedKeys="true" keyProperty="id"> <insert id="insertSysMedicineRecommendation" parameterType="SysMedicineRecommendation" useGeneratedKeys="true" keyProperty="id">
insert into sys_medicine_recommendation insert into sys_medicine_recommendation
<trim prefix="(" suffix=")" suffixOverrides=","> <trim prefix="(" suffix=")" suffixOverrides=",">
@ -202,7 +204,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="latitude != null">latitude,</if> <if test="latitude != null">latitude,</if>
<if test="images != null and images != ''">images,</if> <if test="images != null and images != ''">images,</if>
<if test="imageUrl != null and imageUrl != ''">image_url,</if> <if test="imageUrl != null and imageUrl != ''">image_url,</if>
</trim>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=","> <trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="medicineName != null and medicineName != ''">#{medicineName},</if> <if test="medicineName != null and medicineName != ''">#{medicineName},</if>
<if test="medicineType != null and medicineType != ''">#{medicineType},</if> <if test="medicineType != null and medicineType != ''">#{medicineType},</if>
@ -273,9 +275,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</delete> </delete>
<delete id="deleteSysMedicineRecommendationByIds" parameterType="String"> <delete id="deleteSysMedicineRecommendationByIds" parameterType="String">
delete from sys_medicine_recommendation where id in
delete from sys_medicine_recommendation where id in
<foreach item="id" collection="array" open="(" separator="," close=")"> <foreach item="id" collection="array" open="(" separator="," close=")">
#{id} #{id}
</foreach> </foreach>
</delete> </delete>
</mapper>
</mapper>

46
chenhai-system/src/main/resources/mapper/vet/VetCommentsMapper.xml

@ -19,28 +19,33 @@
<result property="hospital" column="hospital" /> <result property="hospital" column="hospital" />
<result property="experience" column="experience" /> <result property="experience" column="experience" />
<result property="avatar" column="avatar" /> <result property="avatar" column="avatar" />
<!-- 新增字段映射 -->
<result property="expertType" column="expert_type" />
<result property="specialty" column="specialty" />
</resultMap> </resultMap>
<sql id="selectVetCommentsVo"> <sql id="selectVetCommentsVo">
select select
id,
consultation_id,
reply_name,
content,
images,
is_sensitive,
sensitive_words,
created_at,
updated_at,
user_id,
<!-- 添加这三个字段 -->
title,
hospital,
experience,
avatar
id,
consultation_id,
reply_name,
content,
images,
is_sensitive,
sensitive_words,
created_at,
updated_at,
user_id,
title,
hospital,
experience,
avatar,
expert_type,
specialty
from vet_comments from vet_comments
</sql> </sql>
<select id="selectVetCommentsList" parameterType="VetComments" resultMap="VetCommentsResult"> <select id="selectVetCommentsList" parameterType="VetComments" resultMap="VetCommentsResult">
<include refid="selectVetCommentsVo"/> <include refid="selectVetCommentsVo"/>
<where> <where>
@ -81,6 +86,9 @@
<if test="hospital != null">hospital,</if> <if test="hospital != null">hospital,</if>
<if test="experience != null">experience,</if> <if test="experience != null">experience,</if>
<if test="avatar != null and avatar != ''">avatar,</if> <if test="avatar != null and avatar != ''">avatar,</if>
<!-- 新增字段 -->
<if test="expertType != null">expert_type,</if>
<if test="specialty != null">specialty,</if>
</trim> </trim>
<trim prefix="values (" suffix=")" suffixOverrides=","> <trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="consultationId != null">#{consultationId},</if> <if test="consultationId != null">#{consultationId},</if>
@ -96,6 +104,9 @@
<if test="hospital != null">#{hospital},</if> <if test="hospital != null">#{hospital},</if>
<if test="experience != null">#{experience},</if> <if test="experience != null">#{experience},</if>
<if test="avatar != null and avatar != ''">#{avatar},</if> <if test="avatar != null and avatar != ''">#{avatar},</if>
<!-- 新增字段 -->
<if test="expertType != null">#{expertType},</if>
<if test="specialty != null">#{specialty},</if>
</trim> </trim>
</insert> </insert>
@ -115,6 +126,9 @@
<if test="hospital != null">hospital = #{hospital},</if> <if test="hospital != null">hospital = #{hospital},</if>
<if test="experience != null">experience = #{experience},</if> <if test="experience != null">experience = #{experience},</if>
<if test="avatar != null and avatar != ''">avatar = #{avatar},</if> <if test="avatar != null and avatar != ''">avatar = #{avatar},</if>
<!-- 新增字段 -->
<if test="expertType != null">expert_type = #{expertType},</if>
<if test="specialty != null">specialty = #{specialty},</if>
</trim> </trim>
where id = #{id} where id = #{id}
</update> </update>
@ -140,4 +154,4 @@
update_time = NOW() update_time = NOW()
WHERE user_id = #{userId} WHERE user_id = #{userId}
</update> </update>
</mapper>
</mapper>

52
chenhai-system/src/main/resources/mapper/vet/VetKnowledgeMapper.xml

@ -73,16 +73,41 @@
<select id="selectVetKnowledgeList" parameterType="VetKnowledge" resultMap="VetKnowledgeResult"> <select id="selectVetKnowledgeList" parameterType="VetKnowledge" resultMap="VetKnowledgeResult">
<include refid="selectVetKnowledgeVo"/> <include refid="selectVetKnowledgeVo"/>
<where> <where>
<if test="title != null and title != ''"> and title like concat('%', #{title}, '%')</if>
<if test="content != null and content != ''"> and content like concat('%', #{content}, '%')</if>
<if test="category != null and category != ''"> and category = #{category}</if>
<if test="sensitiveWords != null and sensitiveWords != ''"> and sensitive_words like concat('%', #{sensitiveWords}, '%')</if>
<if test="articleStatus != null and articleStatus != ''"> and article_status = #{articleStatus}</if>
<if test="auditStatus != null and auditStatus != ''"> and audit_status = #{auditStatus}</if>
<if test="expertId != null and expertId != ''"> and expert_id = #{expertId}</if>
<if test="coverImage != null and coverImage != ''"> and cover_image = #{coverImage}</if>
<if test="subtitle != null and subtitle != ''"> and subtitle like concat('%', #{subtitle}, '%')</if>
<!-- 添加搜索条件 -->
<if test="title != null and title != ''">
and vk.title like concat('%', #{title}, '%')
</if>
<if test="content != null and content != ''">
and vk.content like concat('%', #{content}, '%')
</if>
<if test="category != null and category != ''">
and vk.category = #{category}
</if>
<if test="sensitiveWords != null and sensitiveWords != ''">
and vk.sensitive_words like concat('%', #{sensitiveWords}, '%')
</if>
<if test="articleStatus != null and articleStatus != ''">
and vk.article_status = #{articleStatus}
</if>
<if test="auditStatus != null and auditStatus != ''">
and vk.audit_status = #{auditStatus}
</if>
<if test="expertId != null">
and vk.expert_id = #{expertId}
</if>
<if test="coverImage != null and coverImage != ''">
and vk.cover_image = #{coverImage}
</if>
<if test="subtitle != null and subtitle != ''">
and vk.subtitle like concat('%', #{subtitle}, '%')
</if>
<!-- 关键修改:给 user_id 加上表别名 vk. -->
<if test="userId != null">
and vk.user_id = #{userId}
</if>
<if test="nickName != null and nickName != ''">
and vk.nick_name like concat('%', #{nickName}, '%')
</if>
<!-- 搜索条件也需要加表别名 -->
<if test="searchKey != null and searchKey != ''"> <if test="searchKey != null and searchKey != ''">
and ( and (
vk.title like concat('%', #{searchKey}, '%') vk.title like concat('%', #{searchKey}, '%')
@ -91,10 +116,9 @@
or ve.real_name like concat('%', #{searchKey}, '%') or ve.real_name like concat('%', #{searchKey}, '%')
) )
</if> </if>
<!-- 新增用户信息查询条件 -->
<if test="userId != null"> and user_id = #{userId}</if>
<if test="nickName != null and nickName != ''"> and nick_name like concat('%', #{nickName}, '%')</if>
</where> </where>
<!-- 添加排序:按创建时间倒序排列(最新在前) -->
ORDER BY vk.create_time DESC
</select> </select>
<select id="selectVetKnowledgeById" parameterType="Long" resultMap="VetKnowledgeResult"> <select id="selectVetKnowledgeById" parameterType="Long" resultMap="VetKnowledgeResult">
@ -190,4 +214,4 @@
#{id} #{id}
</foreach> </foreach>
</delete> </delete>
</mapper>
</mapper>

11
chenhai-system/src/main/resources/mapper/vet/VetNotificationMapper.xml

@ -17,6 +17,7 @@
<result property="readTime" column="read_time"/> <result property="readTime" column="read_time"/>
<result property="isReadLabel" column="is_read_label"/> <result property="isReadLabel" column="is_read_label"/>
<result property="remindLevelLabel" column="remind_level_label"/> <result property="remindLevelLabel" column="remind_level_label"/>
<result property="certId" column="cert_id"/>
</resultMap> </resultMap>
<sql id="selectVetNotificationVo"> <sql id="selectVetNotificationVo">
@ -31,6 +32,7 @@
n.remind_level, n.remind_level,
n.read_time, n.read_time,
n.create_time, n.create_time,
n.cert_id,
<!-- 添加字典标签 --> <!-- 添加字典标签 -->
(SELECT dict_label FROM sys_dict_data WHERE dict_type = 'notification_is_read' AND dict_value = CAST(n.is_read AS CHAR)) as is_read_label, (SELECT dict_label FROM sys_dict_data WHERE dict_type = 'notification_is_read' AND dict_value = CAST(n.is_read AS CHAR)) as is_read_label,
(SELECT dict_label FROM sys_dict_data WHERE dict_type = 'sys_notice_status' AND dict_value = CAST(n.remind_level AS CHAR)) as remind_level_label (SELECT dict_label FROM sys_dict_data WHERE dict_type = 'sys_notice_status' AND dict_value = CAST(n.remind_level AS CHAR)) as remind_level_label
@ -56,6 +58,7 @@
<if test="remindLevel != null"> and remind_level = #{remindLevel}</if> <if test="remindLevel != null"> and remind_level = #{remindLevel}</if>
<if test="createTime != null"> and create_time = #{createTime}</if> <if test="createTime != null"> and create_time = #{createTime}</if>
<if test="readTime != null"> and read_time = #{readTime}</if> <if test="readTime != null"> and read_time = #{readTime}</if>
<if test="certId != null"> and n.cert_id = #{certId}</if>
</where> </where>
order by create_time desc order by create_time desc
</select> </select>
@ -89,6 +92,7 @@
<if test="remindLevel != null">remind_level,</if> <if test="remindLevel != null">remind_level,</if>
<if test="createTime != null">create_time,</if> <if test="createTime != null">create_time,</if>
<if test="readTime != null">read_time,</if> <if test="readTime != null">read_time,</if>
<if test="certId != null">cert_id,</if>
</trim> </trim>
<trim prefix="values (" suffix=")" suffixOverrides=","> <trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="userId != null">#{userId},</if> <if test="userId != null">#{userId},</if>
@ -100,6 +104,7 @@
<if test="remindLevel != null">#{remindLevel},</if> <if test="remindLevel != null">#{remindLevel},</if>
<if test="createTime != null">#{createTime},</if> <if test="createTime != null">#{createTime},</if>
<if test="readTime != null">#{readTime},</if> <if test="readTime != null">#{readTime},</if>
<if test="certId != null">#{certId},</if>
</trim> </trim>
</insert> </insert>
@ -115,7 +120,8 @@
#{item.relatedId}, #{item.relatedId},
#{item.isRead}, #{item.isRead},
#{item.remindLevel}, #{item.remindLevel},
#{item.createTime}
#{item.createTime},
#{item.certId}
) )
</foreach> </foreach>
</insert> </insert>
@ -132,6 +138,7 @@
<if test="remindLevel != null">remind_level = #{remindLevel},</if> <if test="remindLevel != null">remind_level = #{remindLevel},</if>
<if test="createTime != null">create_time = #{createTime},</if> <if test="createTime != null">create_time = #{createTime},</if>
<if test="readTime != null">read_time = #{readTime},</if> <if test="readTime != null">read_time = #{readTime},</if>
<if test="certId != null">cert_id = #{certId},</if>
</trim> </trim>
where id = #{id} where id = #{id}
</update> </update>
@ -181,4 +188,4 @@
limit 1 limit 1
</select> </select>
</mapper>
</mapper>

24
chenhai-system/src/main/resources/mapper/vet/VetPersonalInfoMapper.xml

@ -39,6 +39,7 @@
<result property="nickName" column="u_nick_name"/> <result property="nickName" column="u_nick_name"/>
<result property="email" column="u_email"/> <result property="email" column="u_email"/>
<result property="avatar" column="u_avatar"/> <result property="avatar" column="u_avatar"/>
<result property="phonenumber" column="u_phonenumber"/>
</association> </association>
</resultMap> </resultMap>
@ -60,7 +61,8 @@
u.user_id as u_user_id, u.user_id as u_user_id,
u.nick_name as u_nick_name, u.nick_name as u_nick_name,
u.avatar as u_avatar, u.avatar as u_avatar,
u.email as u_email
u.email as u_email,
u.phonenumber as u_phonenumber
from vet_personal_info v from vet_personal_info v
left join sys_user u on v.user_id = u.user_id left join sys_user u on v.user_id = u.user_id
</sql> </sql>
@ -82,7 +84,6 @@
<if test="iphone != null and iphone != ''"> and v.iphone like concat('%', #{iphone}, '%')</if> <if test="iphone != null and iphone != ''"> and v.iphone like concat('%', #{iphone}, '%')</if>
<if test="expertType != null and expertType != ''"> and v.expert_type = #{expertType}</if> <if test="expertType != null and expertType != ''"> and v.expert_type = #{expertType}</if>
<if test="email != null and email != ''"> and v.email = #{email}</if> <if test="email != null and email != ''"> and v.email = #{email}</if>
<if test="specialty != null and specialty != ''"> and v.specialty like concat('%', #{specialty}, '%')</if>
<!-- 添加审核状态条件 --> <!-- 添加审核状态条件 -->
<if test="auditStatus != null and auditStatus != ''"> <if test="auditStatus != null and auditStatus != ''">
and v.audit_status = #{auditStatus} and v.audit_status = #{auditStatus}
@ -107,7 +108,15 @@
</if> </if>
</if> </if>
</where> </where>
order by v.create_time desc
<!-- 修改排序方式:使用 CASE WHEN 语句确保待审核优先 -->
order by
CASE v.audit_status
WHEN '0' THEN 1
WHEN '2' THEN 2
WHEN '1' THEN 3
ELSE 4
END ASC,
v.create_time DESC
</select> </select>
<!-- 根据ID查询(带用户信息) --> <!-- 根据ID查询(带用户信息) -->
@ -143,6 +152,7 @@
<if test="email != null and email != ''">email,</if> <if test="email != null and email != ''">email,</if>
<if test="nickName != null and nickName != ''">nick_name,</if> <if test="nickName != null and nickName != ''">nick_name,</if>
<if test="avatar != null and avatar != ''">avatar,</if> <if test="avatar != null and avatar != ''">avatar,</if>
audit_status,
<if test="createBy != null">create_by,</if> <if test="createBy != null">create_by,</if>
<if test="createTime != null">create_time,</if> <if test="createTime != null">create_time,</if>
<if test="updateBy != null">update_by,</if> <if test="updateBy != null">update_by,</if>
@ -166,6 +176,7 @@
<if test="email != null and email != ''">#{email},</if> <if test="email != null and email != ''">#{email},</if>
<if test="nickName != null and nickName != ''">#{nickName},</if> <if test="nickName != null and nickName != ''">#{nickName},</if>
<if test="avatar != null and avatar != ''">#{avatar},</if> <if test="avatar != null and avatar != ''">#{avatar},</if>
'0',
<if test="createBy != null">#{createBy},</if> <if test="createBy != null">#{createBy},</if>
<if test="createTime != null">#{createTime},</if> <if test="createTime != null">#{createTime},</if>
<if test="updateBy != null">#{updateBy},</if> <if test="updateBy != null">#{updateBy},</if>
@ -196,6 +207,13 @@
<if test="avatar != null and avatar != ''">avatar = #{avatar},</if> <if test="avatar != null and avatar != ''">avatar = #{avatar},</if>
<if test="updateBy != null">update_by = #{updateBy},</if> <if test="updateBy != null">update_by = #{updateBy},</if>
<if test="updateTime != null">update_time = #{updateTime},</if> <if test="updateTime != null">update_time = #{updateTime},</if>
<!-- ⭐ 关键:添加审核状态字段的更新 -->
<if test="auditStatus != null and auditStatus != ''">audit_status = #{auditStatus},</if>
<if test="auditTime != null">audit_time = #{auditTime},</if>
<if test="auditor != null">auditor = #{auditor},</if>
<if test="auditDesc != null">audit_desc = #{auditDesc},</if>
<if test="updateBy != null">update_by = #{updateBy},</if>
<if test="updateTime != null">update_time = #{updateTime},</if>
</trim> </trim>
where id = #{id} where id = #{id}
</update> </update>

2
chenhai-system/src/main/resources/mapper/vet/VetQualificationMapper.xml

@ -257,4 +257,4 @@
<include refid="selectVetQualificationVo"/> <include refid="selectVetQualificationVo"/>
where qualification_id = #{qualificationId} where qualification_id = #{qualificationId}
</select> </select>
</mapper>
</mapper>

14
chenhai-system/src/main/resources/mapper/vet/VetTrainingVideoMapper.xml

@ -3,7 +3,7 @@
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd"> "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.chenhai.vet.mapper.VetTrainingVideoMapper"> <mapper namespace="com.chenhai.vet.mapper.VetTrainingVideoMapper">
<resultMap type="VetTrainingVideo" id="VetTrainingVideoResult"> <resultMap type="VetTrainingVideo" id="VetTrainingVideoResult">
<result property="id" column="id" /> <result property="id" column="id" />
<result property="userId" column="user_id" /> <result property="userId" column="user_id" />
@ -107,8 +107,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</if> </if>
<if test="publishTime != null "> and v.publish_time = #{publishTime}</if> <if test="publishTime != null "> and v.publish_time = #{publishTime}</if>
</where> </where>
<!-- 按创建时间倒序排列,最新发布的在前 -->
ORDER BY v.create_time DESC
</select> </select>
<select id="selectVetTrainingVideoById" parameterType="Long" resultMap="VetTrainingVideoResult"> <select id="selectVetTrainingVideoById" parameterType="Long" resultMap="VetTrainingVideoResult">
<include refid="selectVetTrainingVideoVo"/> <include refid="selectVetTrainingVideoVo"/>
where id = #{id} where id = #{id}
@ -191,7 +193,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</delete> </delete>
<delete id="deleteVetTrainingVideoByIds" parameterType="String"> <delete id="deleteVetTrainingVideoByIds" parameterType="String">
delete from vet_training_video where id in
delete from vet_training_video where id in
<foreach item="id" collection="array" open="(" separator="," close=")"> <foreach item="id" collection="array" open="(" separator="," close=")">
#{id} #{id}
</foreach> </foreach>
@ -238,7 +240,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</if> </if>
<if test="publishTime != null "> and v.publish_time = #{publishTime}</if> <if test="publishTime != null "> and v.publish_time = #{publishTime}</if>
</where> </where>
<!-- 默认按创建时间倒序排列 -->
order by v.create_time desc
<!-- 按创建时间倒序排列,最新发布的在前 -->
ORDER BY v.create_time DESC
</select> </select>
</mapper>
</mapper>

346
chenhai-ui/src/views/system/recommendation/index.vue

@ -10,24 +10,6 @@
@keyup.enter.native="handleQuery" @keyup.enter.native="handleQuery"
/> />
</el-form-item> </el-form-item>
<!-- <el-form-item label="规格" prop="specification">-->
<!-- <el-input-->
<!-- v-model="queryParams.specification"-->
<!-- placeholder="请输入规格"-->
<!-- clearable-->
<!-- size="small"-->
<!-- @keyup.enter.native="handleQuery"-->
<!-- />-->
<!-- </el-form-item>-->
<!-- <el-form-item label="当前价格" prop="price">-->
<!-- <el-input-->
<!-- v-model="queryParams.price"-->
<!-- placeholder="请输入当前价格"-->
<!-- clearable-->
<!-- size="small"-->
<!-- @keyup.enter.native="handleQuery"-->
<!-- />-->
<!-- </el-form-item>-->
<el-form-item label="店铺名称" prop="storeName"> <el-form-item label="店铺名称" prop="storeName">
<el-input <el-input
v-model="queryParams.storeName" v-model="queryParams.storeName"
@ -98,7 +80,6 @@
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar> <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row> </el-row>
<el-table v-loading="loading" :data="recommendationList" @selection-change="handleSelectionChange"> <el-table v-loading="loading" :data="recommendationList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" /> <el-table-column type="selection" width="55" align="center" />
<el-table-column label="药品图片" align="center" prop="images" width="100"> <el-table-column label="药品图片" align="center" prop="images" width="100">
@ -112,11 +93,6 @@
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="药品名称" align="center" prop="medicineName" width="150" :show-overflow-tooltip="true"/> <el-table-column label="药品名称" align="center" prop="medicineName" width="150" :show-overflow-tooltip="true"/>
<!-- <el-table-column label="药品类型" align="center" prop="medicineType">-->
<!-- <template slot-scope="scope">-->
<!-- <dict-tag :options="dict.type.medicine_type" :value="scope.row.medicineType" :class="getTypeTagType(scope.row.medicineType)"/>-->
<!-- </template>-->
<!-- </el-table-column>-->
<el-table-column label="药品类型" align="center" prop="medicineType" width="100"> <el-table-column label="药品类型" align="center" prop="medicineType" width="100">
<template slot-scope="scope"> <template slot-scope="scope">
<el-tag <el-tag
@ -136,23 +112,7 @@
</div> </div>
</template> </template>
</el-table-column> </el-table-column>
<!-- <el-table-column label="当前价格" align="center" prop="price">-->
<!-- <template slot-scope="scope">-->
<!-- <span>¥{{ scope.row.price }}</span>-->
<!-- </template>-->
<!-- </el-table-column>-->
<!-- <el-table-column label="原价" align="center" prop="originalPrice">-->
<!-- <template slot-scope="scope">-->
<!-- <span v-if="scope.row.originalPrice">¥{{ scope.row.originalPrice }}</span>-->
<!-- <span v-else>-</span>-->
<!-- </template>-->
<!-- </el-table-column>-->
<el-table-column label="已售数量" align="center" prop="soldQuantity" /> <el-table-column label="已售数量" align="center" prop="soldQuantity" />
<!-- <el-table-column label="销售类型" align="center" prop="salesType">-->
<!-- <template slot-scope="scope">-->
<!-- <dict-tag :options="dict.type.sales_type" :value="scope.row.salesType"/>-->
<!-- </template>-->
<!-- </el-table-column>-->
<el-table-column label="销售类型" align="center" prop="salesType" width="100"> <el-table-column label="销售类型" align="center" prop="salesType" width="100">
<template slot-scope="scope"> <template slot-scope="scope">
<el-tag <el-tag
@ -166,11 +126,10 @@
<el-table-column label="适用症状" align="center" prop="indications" width="150" :show-overflow-tooltip="true"/> <el-table-column label="适用症状" align="center" prop="indications" width="150" :show-overflow-tooltip="true"/>
<el-table-column label="生产厂家" align="center" prop="manufacturer" width="150" :show-overflow-tooltip="true"/> <el-table-column label="生产厂家" align="center" prop="manufacturer" width="150" :show-overflow-tooltip="true"/>
<el-table-column label="专家推荐" align="center" width="100">
<el-table-column label="推荐" align="center" width="120">
<template slot-scope="scope"> <template slot-scope="scope">
<div v-if="scope.row.expertId"> <div v-if="scope.row.expertId">
<div style="font-weight: bold;">{{ scope.row.expertName }}</div>
<div style="font-size: 12px; color: #999;">{{ scope.row.expertExpert }}</div>
<div style="font-weight: bold;">{{ scope.row.expertName || '用户' }}</div>
</div> </div>
<span v-else style="color: #999;">-</span> <span v-else style="color: #999;">-</span>
</template> </template>
@ -264,6 +223,15 @@
<el-descriptions-item :span="2" label="生产厂家"> <el-descriptions-item :span="2" label="生产厂家">
{{ currentDetail.manufacturer || '--' }} {{ currentDetail.manufacturer || '--' }}
</el-descriptions-item> </el-descriptions-item>
<el-descriptions-item label="推荐人">
{{ currentDetail.expertName || '--' }}
</el-descriptions-item>
<el-descriptions-item label="推荐理由">
{{ currentDetail.recommendReason || '--' }}
</el-descriptions-item>
<el-descriptions-item label="推荐时间">
{{ currentDetail.recommendTime || '--' }}
</el-descriptions-item>
<el-descriptions-item label="推荐店铺"> <el-descriptions-item label="推荐店铺">
<div v-if="currentDetail.storeName"> <div v-if="currentDetail.storeName">
<div style="font-weight: bold;">{{ currentDetail.storeName }}</div> <div style="font-weight: bold;">{{ currentDetail.storeName }}</div>
@ -285,76 +253,11 @@
<el-form-item label="药品图片" prop="images"> <el-form-item label="药品图片" prop="images">
<image-upload :limit=1 v-model="form.images"/> <image-upload :limit=1 v-model="form.images"/>
</el-form-item> </el-form-item>
<!-- <el-form-item label="药品图片" prop="images">-->
<!-- <el-upload-->
<!-- ref="medicineUpload"-->
<!-- class="upload-demo"-->
<!-- :action="uploadUrl"-->
<!-- :headers="uploadHeaders"-->
<!-- :auto-upload="false"-->
<!-- :file-list="medicineFileList"-->
<!-- :on-change="handleMedicineFileChange"-->
<!-- :on-remove="handleMedicineFileRemove"-->
<!-- :on-success="handleMedicineUploadSuccess"-->
<!-- :before-upload="beforeAvatarUpload"-->
<!-- list-type="picture-card"-->
<!-- :limit="1"-->
<!-- accept=".jpg,.jpeg,.png,.gif,.bmp"-->
<!-- >-->
<!-- <i class="el-icon-plus"></i>-->
<!-- <div slot="tip" class="el-upload__tip" style="margin-top: 10px;">-->
<!-- 支持jpgjpegpnggifbmp格式单张图片不超过2MB只能上传1张-->
<!-- </div>-->
<!-- </el-upload>-->
<!-- </el-form-item>-->
<!-- <el-form-item label="药品图片" prop="images">-->
<!-- <image-upload-->
<!-- v-model="form.images"-->
<!-- :limit="10"-->
<!-- :file-size="2"-->
<!-- :is-show-tip="true"-->
<!-- :accept="['.jpg', '.jpeg', '.png', '.gif', '.bmp']"-->
<!-- help-text="支持jpg、jpeg、png、gif、bmp格式,单张图片不超过2MB,最多上传10张"-->
<!-- />-->
<!-- </el-form-item>-->
<!-- 轮播图片上传 --> <!-- 轮播图片上传 -->
<el-form-item label="轮播图片" prop="imageUrl"> <el-form-item label="轮播图片" prop="imageUrl">
<image-upload v-model="form.imageUrl"/> <image-upload v-model="form.imageUrl"/>
</el-form-item> </el-form-item>
<!-- <el-form-item label="轮播图片" prop="imageUrl">-->
<!-- <el-upload-->
<!-- ref="carouselUpload"-->
<!-- class="upload-demo"-->
<!-- :action="uploadUrl"-->
<!-- :headers="uploadHeaders"-->
<!-- :auto-upload="false"-->
<!-- :file-list="carouselFileList"-->
<!-- :on-change="handleCarouselFileChange"-->
<!-- :on-remove="handleCarouselFileRemove"-->
<!-- :on-success="handleCarouselUploadSuccess"-->
<!-- :before-upload="beforeAvatarUpload"-->
<!-- list-type="picture-card"-->
<!-- :limit="5"-->
<!-- multiple-->
<!-- accept=".jpg,.jpeg,.png,.gif,.bmp"-->
<!-- >-->
<!-- <i class="el-icon-plus"></i>-->
<!-- <div slot="tip" class="el-upload__tip" style="margin-top: 10px;">-->
<!-- 支持jpgjpegpnggifbmp格式单张图片不超过2MB最多上传5张用于首页轮播展示-->
<!-- </div>-->
<!-- </el-upload>-->
<!-- </el-form-item>-->
<!-- <el-form-item label="轮播图片" prop="imageUrl">-->
<!-- <image-upload-->
<!-- v-model="form.imageUrl"-->
<!-- :limit="10"-->
<!-- :file-size="2"-->
<!-- :is-show-tip="true"-->
<!-- :accept="['.jpg', '.jpeg', '.png', '.gif', '.bmp']"-->
<!-- help-text="支持jpg、jpeg、png、gif、bmp格式,单张图片不超过2MB,最多上传10张"-->
<!-- />-->
<!-- </el-form-item>-->
<el-row> <el-row>
<el-col :span="12"> <el-col :span="12">
@ -452,29 +355,20 @@
</el-form-item> </el-form-item>
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="专家推荐" name="expert">
<el-form-item label="推荐专家" prop="expertId">
<el-select
v-model="form.expertId"
placeholder="请选择推荐专家"
clearable
filterable
style="width: 100%;"
>
<el-option
v-for="expert in expertList"
:key="expert.expertId"
:label="expert.realName + ' - ' + expert.expert"
:value="expert.expertId"
/>
</el-select>
<el-tab-pane label="推荐信息" name="expert">
<el-form-item label="推荐人">
<el-input
v-model="currentUserName"
placeholder="当前登录用户"
disabled
/>
<div style="font-size: 12px; color: #999; margin-top: 5px;"> <div style="font-size: 12px; color: #999; margin-top: 5px;">
提示选择为您推荐药品的专家
提示推荐人自动为当前登录用户
</div> </div>
</el-form-item> </el-form-item>
<el-form-item label="推荐理由" prop="recommendReason"> <el-form-item label="推荐理由" prop="recommendReason">
<el-input v-model="form.recommendReason" type="textarea" placeholder="请输入专家推荐理由" rows="4" />
<el-input v-model="form.recommendReason" type="textarea" placeholder="请输入推荐理由" rows="4" />
</el-form-item> </el-form-item>
<el-form-item label="推荐时间" prop="recommendTime"> <el-form-item label="推荐时间" prop="recommendTime">
@ -533,7 +427,6 @@
<div style="font-size: 12px; color: #999; margin-top: 10px;"> <div style="font-size: 12px; color: #999; margin-top: 10px;">
<i class="el-icon-info"></i> 提示经纬度用于地图定位如不清楚可留空 <i class="el-icon-info"></i> 提示经纬度用于地图定位如不清楚可留空
</div> </div>
</el-tab-pane> </el-tab-pane>
</el-tabs> </el-tabs>
</el-form> </el-form>
@ -547,7 +440,6 @@
<script> <script>
import { listRecommendation, getRecommendation, delRecommendation, addRecommendation, updateRecommendation } from "@/api/system/recommendation"; import { listRecommendation, getRecommendation, delRecommendation, addRecommendation, updateRecommendation } from "@/api/system/recommendation";
import { listExperts } from "@/api/vet/experts";
import { getToken } from "@/utils/auth"; import { getToken } from "@/utils/auth";
export default { export default {
@ -555,48 +447,26 @@ export default {
dicts: ['medicine_type', 'sales_type'], dicts: ['medicine_type', 'sales_type'],
data() { data() {
return { return {
//
loading: true, loading: true,
detailLoading: false, detailLoading: false,
//
ids: [], ids: [],
//
single: true, single: true,
//
multiple: true, multiple: true,
//
showSearch: true, showSearch: true,
//
total: 0, total: 0,
//
recommendationList: [], recommendationList: [],
//
expertList: [],
//
title: "", title: "",
//
open: false, open: false,
detailViews: false, detailViews: false,
//
currentDetail: {}, currentDetail: {},
//
activeTab: "basic", activeTab: "basic",
//
currentUserName: '',
medicineFileList: [], medicineFileList: [],
// 5
carouselFileList: [], carouselFileList: [],
// URL
uploadUrl: process.env.VUE_APP_BASE_API + "/common/upload", uploadUrl: process.env.VUE_APP_BASE_API + "/common/upload",
//
uploadHeaders: { uploadHeaders: {
Authorization: 'Bearer ' + getToken() Authorization: 'Bearer ' + getToken()
}, },
//
queryParams: { queryParams: {
pageNum: 1, pageNum: 1,
pageSize: 10, pageSize: 10,
@ -619,8 +489,6 @@ export default {
storeName: undefined, storeName: undefined,
storeAddress: undefined, storeAddress: undefined,
}, },
//
form: { form: {
id: undefined, id: undefined,
medicineName: undefined, medicineName: undefined,
@ -639,8 +507,8 @@ export default {
expertId: undefined, expertId: undefined,
recommendReason: undefined, recommendReason: undefined,
recommendTime: undefined, recommendTime: undefined,
images: undefined, // URL
imageUrl: undefined, // URL
images: undefined,
imageUrl: undefined,
storeName: undefined, storeName: undefined,
storeAddress: undefined, storeAddress: undefined,
storePhone: undefined, storePhone: undefined,
@ -649,8 +517,6 @@ export default {
longitude: undefined, longitude: undefined,
latitude: undefined, latitude: undefined,
}, },
//
rules: { rules: {
medicineName: [ medicineName: [
{ required: true, message: "药品名称不能为空", trigger: "blur" } { required: true, message: "药品名称不能为空", trigger: "blur" }
@ -667,19 +533,19 @@ export default {
], ],
specification: [ specification: [
{ required: true, message: "规格不能为空", trigger: "blur" } { required: true, message: "规格不能为空", trigger: "blur" }
],
expertId:[
{ required: true, message: "推荐专家不能为空", trigger: "blur" }
] ]
} }
}; };
}, },
created() { created() {
this.getList(); this.getList();
this.getExpertList();
this.getCurrentUser();
}, },
methods: { methods: {
/** 查询药品推荐列表 */
getCurrentUser() {
const userInfo = this.$store.state.user.userInfo || JSON.parse(localStorage.getItem('userInfo') || '{}');
this.currentUserName = userInfo.realName || userInfo.userName || userInfo.nickName || '当前用户';
},
getList() { getList() {
this.loading = true; this.loading = true;
listRecommendation(this.queryParams).then(response => { listRecommendation(this.queryParams).then(response => {
@ -688,31 +554,9 @@ export default {
this.loading = false; this.loading = false;
}); });
}, },
/** 获取专家列表 */
getExpertList() {
listExperts({
pageNum: 1,
pageSize: 1000,
status: '0'
}).then(response => {
if (response.code === 200) {
this.expertList = response.rows || [];
}
}).catch(() => {
this.expertList = [
{ expertId: 1, realName: '张医生', title: '主任医师' },
{ expertId: 2, realName: '李医生', title: '副主任医师' }
];
});
},
// ========== ==========
//
beforeAvatarUpload(file) { beforeAvatarUpload(file) {
const isImage = /\.(jpg|jpeg|png|gif|bmp)$/i.test(file.name); const isImage = /\.(jpg|jpeg|png|gif|bmp)$/i.test(file.name);
const isLt2M = file.size / 1024 / 1024 < 2; const isLt2M = file.size / 1024 / 1024 < 2;
if (!isImage) { if (!isImage) {
this.$modal.msgError("只能上传图片格式文件!"); this.$modal.msgError("只能上传图片格式文件!");
return false; return false;
@ -723,9 +567,6 @@ export default {
} }
return true; return true;
}, },
// ========== ==========
// 1
handleMedicineFileChange(file, fileList) { handleMedicineFileChange(file, fileList) {
if (fileList.length > 1) { if (fileList.length > 1) {
this.$modal.msgWarning("药品图片只能上传1张"); this.$modal.msgWarning("药品图片只能上传1张");
@ -733,8 +574,6 @@ export default {
return; return;
} }
this.medicineFileList = fileList; this.medicineFileList = fileList;
// images
if (fileList.length > 0) { if (fileList.length > 0) {
const url = fileList[0].url || (fileList[0].response && fileList[0].response.url); const url = fileList[0].url || (fileList[0].response && fileList[0].response.url);
this.form.images = url || ''; this.form.images = url || '';
@ -742,28 +581,19 @@ export default {
this.form.images = ''; this.form.images = '';
} }
}, },
//
handleMedicineFileRemove(file, fileList) { handleMedicineFileRemove(file, fileList) {
this.medicineFileList = fileList; this.medicineFileList = fileList;
// images
this.form.images = ''; this.form.images = '';
}, },
//
handleMedicineUploadSuccess(response, file, fileList) { handleMedicineUploadSuccess(response, file, fileList) {
if (response.code === 200) { if (response.code === 200) {
const url = response.fileName || response.url; const url = response.fileName || response.url;
// images
this.form.images = url; this.form.images = url;
this.$modal.msgSuccess("药品图片上传成功"); this.$modal.msgSuccess("药品图片上传成功");
} else { } else {
this.$modal.msgError("药品图片上传失败: " + response.msg); this.$modal.msgError("药品图片上传失败: " + response.msg);
} }
}, },
// ========== ==========
// 5
handleCarouselFileChange(file, fileList) { handleCarouselFileChange(file, fileList) {
if (fileList.length > 5) { if (fileList.length > 5) {
this.$modal.msgWarning("最多只能上传5张轮播图片"); this.$modal.msgWarning("最多只能上传5张轮播图片");
@ -771,24 +601,16 @@ export default {
return; return;
} }
this.carouselFileList = fileList; this.carouselFileList = fileList;
// imageUrl URL
const urls = fileList.map(item => item.url || (item.response && item.response.url)).filter(url => url); const urls = fileList.map(item => item.url || (item.response && item.response.url)).filter(url => url);
this.form.imageUrl = urls.join(','); this.form.imageUrl = urls.join(',');
}, },
//
handleCarouselFileRemove(file, fileList) { handleCarouselFileRemove(file, fileList) {
this.carouselFileList = fileList; this.carouselFileList = fileList;
// imageUrl
const urls = fileList.map(item => item.url || (item.response && item.response.url)).filter(url => url); const urls = fileList.map(item => item.url || (item.response && item.response.url)).filter(url => url);
this.form.imageUrl = urls.join(','); this.form.imageUrl = urls.join(',');
}, },
//
handleCarouselUploadSuccess(response, file, fileList) { handleCarouselUploadSuccess(response, file, fileList) {
if (response.code === 200) { if (response.code === 200) {
// imageUrl
const urls = fileList.map(item => item.url || (item.response && item.response.url)).filter(url => url); const urls = fileList.map(item => item.url || (item.response && item.response.url)).filter(url => url);
this.form.imageUrl = urls.join(','); this.form.imageUrl = urls.join(',');
this.$modal.msgSuccess("轮播图片上传成功"); this.$modal.msgSuccess("轮播图片上传成功");
@ -796,25 +618,15 @@ export default {
this.$modal.msgError("轮播图片上传失败: " + response.msg); this.$modal.msgError("轮播图片上传失败: " + response.msg);
} }
}, },
// ========== ==========
uploadAllFiles() { uploadAllFiles() {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
//
const medicinePromise = this.uploadMedicineFile(); const medicinePromise = this.uploadMedicineFile();
//
const carouselPromise = this.uploadCarouselFiles(); const carouselPromise = this.uploadCarouselFiles();
Promise.all([medicinePromise, carouselPromise]) Promise.all([medicinePromise, carouselPromise])
.then(([medicineImage, carouselImages]) => { .then(([medicineImage, carouselImages]) => {
//
this.form.images = medicineImage; this.form.images = medicineImage;
this.form.imageUrl = carouselImages; this.form.imageUrl = carouselImages;
resolve({
images: medicineImage,
imageUrl: carouselImages
});
resolve({ images: medicineImage, imageUrl: carouselImages });
}) })
.catch(error => { .catch(error => {
this.$modal.msgError("文件上传失败: " + error.message); this.$modal.msgError("文件上传失败: " + error.message);
@ -822,33 +634,25 @@ export default {
}); });
}); });
}, },
//
uploadMedicineFile() { uploadMedicineFile() {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (this.medicineFileList.length === 0) { if (this.medicineFileList.length === 0) {
resolve(this.form.images || ''); resolve(this.form.images || '');
return; return;
} }
const fileToUpload = this.medicineFileList.find(file => file.raw); const fileToUpload = this.medicineFileList.find(file => file.raw);
if (!fileToUpload) { if (!fileToUpload) {
// 使URL
const existingUrl = this.medicineFileList[0]?.url || (this.medicineFileList[0]?.response && this.medicineFileList[0]?.response.url); const existingUrl = this.medicineFileList[0]?.url || (this.medicineFileList[0]?.response && this.medicineFileList[0]?.response.url);
const result = existingUrl || ''; const result = existingUrl || '';
this.form.images = result; this.form.images = result;
resolve(result); resolve(result);
return; return;
} }
const formData = new FormData(); const formData = new FormData();
formData.append('file', fileToUpload.raw); formData.append('file', fileToUpload.raw);
const xhr = new XMLHttpRequest(); const xhr = new XMLHttpRequest();
xhr.open('POST', this.uploadUrl, true); xhr.open('POST', this.uploadUrl, true);
xhr.setRequestHeader('Authorization', 'Bearer ' + getToken()); xhr.setRequestHeader('Authorization', 'Bearer ' + getToken());
xhr.onload = () => { xhr.onload = () => {
if (xhr.status === 200) { if (xhr.status === 200) {
try { try {
@ -867,43 +671,33 @@ export default {
reject(new Error('上传失败,状态码:' + xhr.status)); reject(new Error('上传失败,状态码:' + xhr.status));
} }
}; };
xhr.onerror = () => { xhr.onerror = () => {
reject(new Error('网络错误')); reject(new Error('网络错误'));
}; };
xhr.send(formData); xhr.send(formData);
}); });
}, },
//
uploadCarouselFiles() { uploadCarouselFiles() {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (this.carouselFileList.length === 0) { if (this.carouselFileList.length === 0) {
resolve(this.form.imageUrl || ''); resolve(this.form.imageUrl || '');
return; return;
} }
const filesToUpload = this.carouselFileList.filter(file => file.raw); const filesToUpload = this.carouselFileList.filter(file => file.raw);
if (filesToUpload.length === 0) { if (filesToUpload.length === 0) {
// 使URL
const existingUrls = this.carouselFileList.map(item => item.url || (item.response && item.response.url)).filter(url => url); const existingUrls = this.carouselFileList.map(item => item.url || (item.response && item.response.url)).filter(url => url);
const result = existingUrls.join(','); const result = existingUrls.join(',');
this.form.imageUrl = result; this.form.imageUrl = result;
resolve(result); resolve(result);
return; return;
} }
const uploadPromises = filesToUpload.map(file => { const uploadPromises = filesToUpload.map(file => {
return new Promise((uploadResolve, uploadReject) => { return new Promise((uploadResolve, uploadReject) => {
const formData = new FormData(); const formData = new FormData();
formData.append('file', file.raw); formData.append('file', file.raw);
const xhr = new XMLHttpRequest(); const xhr = new XMLHttpRequest();
xhr.open('POST', this.uploadUrl, true); xhr.open('POST', this.uploadUrl, true);
xhr.setRequestHeader('Authorization', 'Bearer ' + getToken()); xhr.setRequestHeader('Authorization', 'Bearer ' + getToken());
xhr.onload = () => { xhr.onload = () => {
if (xhr.status === 200) { if (xhr.status === 200) {
try { try {
@ -920,15 +714,12 @@ export default {
uploadReject(new Error('上传失败,状态码:' + xhr.status)); uploadReject(new Error('上传失败,状态码:' + xhr.status));
} }
}; };
xhr.onerror = () => { xhr.onerror = () => {
uploadReject(new Error('网络错误')); uploadReject(new Error('网络错误'));
}; };
xhr.send(formData); xhr.send(formData);
}); });
}); });
Promise.all(uploadPromises) Promise.all(uploadPromises)
.then(urls => { .then(urls => {
const existingUrls = this.carouselFileList.filter(file => !file.raw && file.url).map(file => file.url); const existingUrls = this.carouselFileList.filter(file => !file.raw && file.url).map(file => file.url);
@ -943,15 +734,10 @@ export default {
}); });
}); });
}, },
// ========== ==========
//
cancel() { cancel() {
this.open = false; this.open = false;
this.reset(); this.reset();
}, },
//
reset() { reset() {
this.form = { this.form = {
id: undefined, id: undefined,
@ -986,32 +772,23 @@ export default {
this.activeTab = "basic"; this.activeTab = "basic";
this.resetForm("form"); this.resetForm("form");
}, },
/** 搜索按钮操作 */
handleQuery() { handleQuery() {
this.queryParams.pageNum = 1; this.queryParams.pageNum = 1;
this.getList(); this.getList();
}, },
/** 重置按钮操作 */
resetQuery() { resetQuery() {
this.resetForm("queryForm"); this.resetForm("queryForm");
this.handleQuery(); this.handleQuery();
}, },
//
handleSelectionChange(selection) { handleSelectionChange(selection) {
this.ids = selection.map(item => item.id); this.ids = selection.map(item => item.id);
this.single = selection.length !== 1; this.single = selection.length !== 1;
this.multiple = !selection.length; this.multiple = !selection.length;
}, },
//
handleView(row) { handleView(row) {
this.detailViews = true; this.detailViews = true;
this.detailLoading = true; this.detailLoading = true;
this.currentDetail = {}; this.currentDetail = {};
const id = row.id; const id = row.id;
getRecommendation(id).then(response => { getRecommendation(id).then(response => {
if (response.code === 200) { if (response.code === 200) {
@ -1022,8 +799,6 @@ export default {
this.detailLoading = false; this.detailLoading = false;
}); });
}, },
/** 获取药品类型标签类型 */
getTypeTagType(type) { getTypeTagType(type) {
const map = { const map = {
"处方药": 'danger', "处方药": 'danger',
@ -1033,8 +808,6 @@ export default {
} }
return map[type] || '' return map[type] || ''
}, },
/** 获取销售类型标签类型 */
getSalesTagType(type) { getSalesTagType(type) {
const map = { const map = {
"热销": 'danger', "热销": 'danger',
@ -1044,54 +817,25 @@ export default {
} }
return map[type] || '' return map[type] || ''
}, },
/** 新增按钮操作 */
handleAdd() { handleAdd() {
this.reset(); this.reset();
this.open = true; this.open = true;
this.title = "添加药品推荐"; this.title = "添加药品推荐";
}, },
/** 修改按钮操作 */
// async handleUpdate(row) {
handleUpdate(row) { handleUpdate(row) {
this.reset(); this.reset();
const id = row.id || this.ids[0]; const id = row.id || this.ids[0];
getRecommendation(id).then(response => { getRecommendation(id).then(response => {
this.form = response.data; this.form = response.data;
// //
// if (this.form.images) {
// this.medicineFileList = [{
// name: 'medicine_image.jpg',
// url: this.form.images,
// status: 'success'
// }];
// }
//
// //
// if (this.form.imageUrl) {
// const imageUrls = this.form.imageUrl.split(',');
// this.carouselFileList = imageUrls.map((url, index) => ({
// name: `carousel_${index + 1}.jpg`,
// url: url.trim(),
// status: 'success'
// }));
// }
this.open = true; this.open = true;
this.title = "修改药品推荐"; this.title = "修改药品推荐";
}); });
}, },
/** 提交按钮 */
async submitForm() { async submitForm() {
this.$refs["form"].validate(async valid => { this.$refs["form"].validate(async valid => {
if (valid) { if (valid) {
try { try {
//
const { images, imageUrl } = await this.uploadAllFiles(); const { images, imageUrl } = await this.uploadAllFiles();
const formData = { const formData = {
...this.form, ...this.form,
price: this.form.price ? Number(this.form.price) : undefined, price: this.form.price ? Number(this.form.price) : undefined,
@ -1102,7 +846,6 @@ export default {
images: images, images: images,
imageUrl: imageUrl imageUrl: imageUrl
}; };
if (this.form.id !== undefined) { if (this.form.id !== undefined) {
updateRecommendation(formData).then(response => { updateRecommendation(formData).then(response => {
this.$modal.msgSuccess("修改成功"); this.$modal.msgSuccess("修改成功");
@ -1122,19 +865,15 @@ export default {
} }
}); });
}, },
/** 删除按钮操作 */
handleDelete(row) { handleDelete(row) {
const ids = row.id || this.ids; const ids = row.id || this.ids;
this.$modal.confirm('是否确认删除药品推荐编号为"' + ids + '"的数据项?').then(function() {
this.$modal.confirm('是否确认删除药品推荐编号为"' + ids + '"的数据项?').then(() => {
return delRecommendation(ids); return delRecommendation(ids);
}).then(() => { }).then(() => {
this.getList(); this.getList();
this.$modal.msgSuccess("删除成功"); this.$modal.msgSuccess("删除成功");
}).catch(() => {}); }).catch(() => {});
}, },
/** 导出按钮操作 */
handleExport() { handleExport() {
this.download('system/recommendation/export', { this.download('system/recommendation/export', {
...this.queryParams ...this.queryParams
@ -1148,15 +887,12 @@ export default {
::v-deep .el-descriptions-item__cell{ ::v-deep .el-descriptions-item__cell{
width: 90px; width: 90px;
} }
::v-deep .pagestyle .el-input{ ::v-deep .pagestyle .el-input{
width: auto !important; width: auto !important;
} }
::v-deep .el-descriptions-row th{ ::v-deep .el-descriptions-row th{
text-align: center !important;color: #7b7c7f; text-align: center !important;color: #7b7c7f;
} }
::v-deep .el-descriptions .is-bordered .el-descriptions-item__cell { ::v-deep .el-descriptions .is-bordered .el-descriptions-item__cell {
border: 1px solid #cac9c9; border: 1px solid #cac9c9;
padding: 12px 10px; padding: 12px 10px;
@ -1164,7 +900,6 @@ export default {
</style> </style>
<style lang="scss" scoped> <style lang="scss" scoped>
/* 图片上传样式 */
.upload-demo { .upload-demo {
width: 100%; width: 100%;
} }
@ -1177,96 +912,78 @@ export default {
width: 100px; width: 100px;
height: 100px; height: 100px;
} }
//
.price-cell { .price-cell {
.price-text { .price-text {
font-weight: bold; font-weight: bold;
color: #f56c6c; color: #f56c6c;
} }
.cost-price { .cost-price {
font-size: 12px; font-size: 12px;
color: #999; color: #999;
margin-top: 2px; margin-top: 2px;
} }
} }
/* 操作按钮 */
.info-btn { .info-btn {
padding: 6px 10px; padding: 6px 10px;
border-radius: 4px; border-radius: 4px;
margin: 0 10px; margin: 0 10px;
transition: all 0.3s ease; transition: all 0.3s ease;
} }
.view-btn:hover { .view-btn:hover {
background-color: rgb(216, 238, 248); background-color: rgb(216, 238, 248);
transform: translateY(-1px); transform: translateY(-1px);
} }
.alter-btn:hover{ .alter-btn:hover{
background-color: rgb(230, 255, 238); background-color: rgb(230, 255, 238);
transform: translateY(-1px); transform: translateY(-1px);
} }
.delete-btn:hover { .delete-btn:hover {
background-color: rgba(245, 108, 108, 0.1); background-color: rgba(245, 108, 108, 0.1);
transform: translateY(-1px); transform: translateY(-1px);
} }
// /
::v-deep .el-dialog { ::v-deep .el-dialog {
border-radius: 12px; border-radius: 12px;
overflow: hidden; overflow: hidden;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.12); box-shadow: 0 10px 40px rgba(0, 0, 0, 0.12);
animation: dialogFadeIn 0.3s ease; animation: dialogFadeIn 0.3s ease;
} }
::v-deep .el-dialog__header { ::v-deep .el-dialog__header {
background: linear-gradient(135deg, #2c7a4d 0%, #42b983 100%); background: linear-gradient(135deg, #2c7a4d 0%, #42b983 100%);
padding: 18px 24px; padding: 18px 24px;
border-bottom: none; border-bottom: none;
position: relative; position: relative;
} }
::v-deep .el-dialog__title { ::v-deep .el-dialog__title {
font-size: 17px; font-size: 17px;
font-weight: 600; font-weight: 600;
color: white; color: white;
letter-spacing: 0.5px; letter-spacing: 0.5px;
} }
::v-deep .el-dialog__headerbtn:hover .el-dialog__close { ::v-deep .el-dialog__headerbtn:hover .el-dialog__close {
color: #ffd04b; color: #ffd04b;
transform: rotate(90deg); transform: rotate(90deg);
} }
::v-deep .el-dialog__body { ::v-deep .el-dialog__body {
padding: 28px 24px 20px; padding: 28px 24px 20px;
background-color: #f8fafc; background-color: #f8fafc;
max-height: 70vh; max-height: 70vh;
overflow-y: auto; overflow-y: auto;
} }
::v-deep .el-form-item { ::v-deep .el-form-item {
margin-bottom: 20px; margin-bottom: 20px;
transition: all 0.3s; transition: all 0.3s;
} }
::v-deep .el-form-item__label { ::v-deep .el-form-item__label {
font-weight: 500; font-weight: 500;
color: #2d3748; color: #2d3748;
font-size: 14px; font-size: 14px;
transition: color 0.3s; transition: color 0.3s;
} }
::v-deep .el-input, ::v-deep .el-input,
::v-deep .el-textarea, ::v-deep .el-textarea,
::v-deep .el-select { ::v-deep .el-select {
width: 100%; width: 100%;
} }
::v-deep .el-input__inner, ::v-deep .el-input__inner,
::v-deep .el-textarea__inner { ::v-deep .el-textarea__inner {
border-radius: 8px; border-radius: 8px;
@ -1275,18 +992,15 @@ export default {
transition: all 0.3s; transition: all 0.3s;
background-color: #fcfdfe; background-color: #fcfdfe;
} }
::v-deep .el-input__inner:focus, ::v-deep .el-input__inner:focus,
::v-deep .el-textarea__inner:focus { ::v-deep .el-textarea__inner:focus {
border-color: #42B983; border-color: #42B983;
box-shadow: 0 0 0 3px rgb(230, 255, 238); box-shadow: 0 0 0 3px rgb(230, 255, 238);
background-color: white; background-color: white;
} }
::v-deep .el-select .el-input__inner { ::v-deep .el-select .el-input__inner {
padding-right: 35px; padding-right: 35px;
} }
::v-deep .el-dialog__footer { ::v-deep .el-dialog__footer {
padding: 20px 24px; padding: 20px 24px;
background-color: #f8fafc; background-color: #f8fafc;

Loading…
Cancel
Save