Browse Source

资质上传和产品信息功能

master
ChaiNingQi 3 weeks ago
parent
commit
e5cc01382f
  1. 588
      chenhai-admin/src/main/java/com/chenhai/web/controller/vet/VetExperienceArticleController.java
  2. 63
      chenhai-admin/src/main/java/com/chenhai/web/controller/vet/VetProductController.java
  3. 557
      chenhai-admin/src/main/java/com/chenhai/web/controller/vet/VetQualificationController.java
  4. 66
      chenhai-system/src/main/java/com/chenhai/vet/domain/BusinessScopeConstants.java
  5. 112
      chenhai-system/src/main/java/com/chenhai/vet/domain/VetArticleCategory.java
  6. 21
      chenhai-system/src/main/java/com/chenhai/vet/domain/VetExperienceArticle.java
  7. 64
      chenhai-system/src/main/java/com/chenhai/vet/domain/VetProduct.java
  8. 476
      chenhai-system/src/main/java/com/chenhai/vet/domain/VetQualification.java
  9. 13
      chenhai-system/src/main/java/com/chenhai/vet/mapper/VetArticleCategoryMapper.java
  10. 54
      chenhai-system/src/main/java/com/chenhai/vet/mapper/VetExperienceArticleMapper.java
  11. 4
      chenhai-system/src/main/java/com/chenhai/vet/mapper/VetQualificationMapper.java
  12. 68
      chenhai-system/src/main/java/com/chenhai/vet/service/IVetExperienceArticleService.java
  13. 43
      chenhai-system/src/main/java/com/chenhai/vet/service/IVetProductService.java
  14. 10
      chenhai-system/src/main/java/com/chenhai/vet/service/IVetQualificationService.java
  15. 212
      chenhai-system/src/main/java/com/chenhai/vet/service/impl/VetExperienceArticleServiceImpl.java
  16. 162
      chenhai-system/src/main/java/com/chenhai/vet/service/impl/VetProductServiceImpl.java
  17. 1019
      chenhai-system/src/main/java/com/chenhai/vet/service/impl/VetQualificationServiceImpl.java
  18. 34
      chenhai-system/src/main/resources/mapper/vet/VetArticleCategoryMapper.xml
  19. 90
      chenhai-system/src/main/resources/mapper/vet/VetExperienceArticleMapper.xml
  20. 19
      chenhai-system/src/main/resources/mapper/vet/VetProductMapper.xml
  21. 41
      chenhai-system/src/main/resources/mapper/vet/VetQualificationMapper.xml
  22. 41
      chenhai-ui/src/api/vet/product.js
  23. 2546
      chenhai-ui/src/views/vet/article/index.vue
  24. 345
      chenhai-ui/src/views/vet/product/index.vue

588
chenhai-admin/src/main/java/com/chenhai/web/controller/vet/VetExperienceArticleController.java

@ -1,27 +1,22 @@
package com.chenhai.web.controller.vet; package com.chenhai.web.controller.vet;
import com.chenhai.common.utils.DictUtils;
import com.chenhai.common.annotation.Log; 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.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.poi.ExcelUtil;
import com.chenhai.vet.domain.VetArticleCategory;
import com.chenhai.vet.domain.VetExperienceArticle; import com.chenhai.vet.domain.VetExperienceArticle;
import com.chenhai.vet.mapper.VetArticleCategoryMapper;
import com.chenhai.vet.service.IVetExperienceArticleService; import com.chenhai.vet.service.IVetExperienceArticleService;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
/** /**
* 兽医经验分享Controller
* 兽医经验文章论坛Controller列表样式
*/ */
@RestController @RestController
@RequestMapping("/vet/article") @RequestMapping("/vet/article")
@ -30,423 +25,171 @@ public class VetExperienceArticleController extends BaseController {
@Autowired @Autowired
private IVetExperienceArticleService vetExperienceArticleService; private IVetExperienceArticleService vetExperienceArticleService;
@Autowired // 确保有这个注解
private VetArticleCategoryMapper vetArticleCategoryMapper;
@Autowired
private JdbcTemplate jdbcTemplate;
/**
* 简单收藏管理使用Map存储
*/
// 简单收藏管理
private static final Map<Long, Set<Long>> COLLECTION_STORE = new ConcurrentHashMap<>(); private static final Map<Long, Set<Long>> COLLECTION_STORE = new ConcurrentHashMap<>();
/** /**
* 查询兽医经验文章列表
* 查询所有文章列表论坛首页
*/ */
@GetMapping("/list") @GetMapping("/list")
public TableDataInfo list(VetExperienceArticle vetExperienceArticle) { public TableDataInfo list(VetExperienceArticle vetExperienceArticle) {
startPage();
List<VetExperienceArticle> list = vetExperienceArticleService.selectVetExperienceArticleList(vetExperienceArticle);
return getDataTable(list);
}
/**
* 获取文章详细信息
*/
@GetMapping(value = "/{id}")
public AjaxResult getInfo(@PathVariable("id") Long id) {
return success(vetExperienceArticleService.selectVetExperienceArticleById(id));
}
/**
* 修改兽医经验文章
*/
@PreAuthorize("@ss.hasPermi('vet:article:edit')")
@Log(title = "兽医经验文章", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody VetExperienceArticle vetExperienceArticle) {
return toAjax(vetExperienceArticleService.updateVetExperienceArticle(vetExperienceArticle));
}
/**
* 删除兽医经验文章
*/
@PreAuthorize("@ss.hasPermi('vet:article:remove')")
@Log(title = "兽医经验文章", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable Long[] ids) {
return toAjax(vetExperienceArticleService.deleteVetExperienceArticleByIds(ids));
}
@GetMapping("/options")
public AjaxResult getCategoryOptions() {
VetArticleCategory query = new VetArticleCategory();
query.setStatus("0");
List<VetArticleCategory> categories = vetArticleCategoryMapper.selectVetArticleCategoryList(query);
// 排序如果sortOrder为null放到最后
if (categories != null) {
categories.sort((c1, c2) -> {
Integer order1 = c1.getSortOrder() != null ? c1.getSortOrder() : 999;
Integer order2 = c2.getSortOrder() != null ? c2.getSortOrder() : 999;
return order1.compareTo(order2);
});
}
List<Map<String, Object>> options = new ArrayList<>();
for (VetArticleCategory category : categories) {
Map<String, Object> option = new LinkedHashMap<>();
option.put("value", category.getId());
option.put("label", category.getName());
options.add(option);
// 默认只查询已发布的文章
if (vetExperienceArticle.getStatus() == null) {
vetExperienceArticle.setStatus("1");
} }
return AjaxResult.success(options);
}
/**
* 根据分类查询文章
*/
@GetMapping("/{categoryId}/articles")
public TableDataInfo getArticlesByCategory(
@PathVariable Long categoryId,
@RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum,
@RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize) {
startPage(); startPage();
// 创建查询对象
VetExperienceArticle query = new VetExperienceArticle();
query.setStatus("1"); // 只查询已发布的文章
query.setCategoryId(categoryId); // 设置分类ID
List<VetExperienceArticle> list = vetExperienceArticleService.selectVetExperienceArticleList(query);
List<VetExperienceArticle> list = vetExperienceArticleService.selectVetExperienceArticleList(vetExperienceArticle);
return getDataTable(list); return getDataTable(list);
} }
/**
* 获取文章标签选项
*/
@GetMapping("/tags/options")
public AjaxResult getTagOptions() {
List<Map<String, Object>> options = new ArrayList<>();
// 根据你提供的字典数据写死
options.add(createOption("1", "疫苗"));
options.add(createOption("2", "传染病"));
options.add(createOption("3", "防治"));
options.add(createOption("4", "养殖"));
options.add(createOption("5", "饲养管理"));
options.add(createOption("6", "繁殖"));
options.add(createOption("7", "牛羊"));
options.add(createOption("8", "药物使用"));
options.add(createOption("9", "特殊病例"));
return success(options);
}
/** /**
* 根据标签值查询文章
* 查询我的文章列表个人中心
*/ */
@GetMapping("/tags/{dictValue}/articles")
public TableDataInfo getArticlesByTag(
@PathVariable String dictValue,
@RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum,
@RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize) {
@GetMapping("/myList")
public TableDataInfo myList(VetExperienceArticle vetExperienceArticle) {
Long userId = SecurityUtils.getUserId();
System.out.println("【DEBUG】当前用户ID: " + userId);
startPage();
// 标签映射
String tagName = getTagNameByDictValue(dictValue);
if (tagName == null || tagName.isEmpty()) {
return getDataTable(new ArrayList<>());
if (userId == null) {
throw new RuntimeException("用户未登录");
} }
// 创建新的查询对象确保参数正确设置
VetExperienceArticle query = new VetExperienceArticle(); VetExperienceArticle query = new VetExperienceArticle();
query.setStatus("1");
query.setTags(tagName);
query.setUserId(userId); // 强制设置用户ID
List<VetExperienceArticle> list = vetExperienceArticleService.selectVetExperienceArticleList(query);
return getDataTable(list);
}
// 传递其他查询条件
query.setStatus(vetExperienceArticle.getStatus());
query.setTitle(vetExperienceArticle.getTitle());
query.setCategoryId(vetExperienceArticle.getCategoryId());
query.setCategoryName(vetExperienceArticle.getCategoryName());
query.setTags(vetExperienceArticle.getTags());
/**
* 辅助方法创建选项
*/
private Map<String, Object> createOption(String value, String label) {
Map<String, Object> option = new HashMap<>();
option.put("value", value);
option.put("label", label);
return option;
}
/**
* 根据字典值获取标签名称
*/
private String getTagNameByDictValue(String dictValue) {
// 写死映射
Map<String, String> tagMap = new HashMap<>();
tagMap.put("1", "疫苗");
tagMap.put("2", "传染病");
tagMap.put("3", "防治");
tagMap.put("4", "养殖");
tagMap.put("5", "饲养管理");
tagMap.put("6", "繁殖");
tagMap.put("7", "牛羊");
tagMap.put("8", "药物使用");
tagMap.put("9", "特殊病例");
return tagMap.get(dictValue);
}
/**
* 备用直接使用标签名称查询的接口
*/
@GetMapping("/tags/byName/articles")
public TableDataInfo getArticlesByTagName(
@RequestParam("tagName") String tagName,
@RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum,
@RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize) {
System.out.println("【DEBUG】查询条件: " + query);
startPage(); startPage();
VetExperienceArticle query = new VetExperienceArticle();
query.setStatus("1");
query.setTags(tagName);
List<VetExperienceArticle> list = vetExperienceArticleService.selectVetExperienceArticleList(query); List<VetExperienceArticle> list = vetExperienceArticleService.selectVetExperienceArticleList(query);
return getDataTable(list); return getDataTable(list);
} }
/** /**
* 获取所有兽医已发布的文章
* 查看文章详情包含相关文章
*/ */
@GetMapping("/forum/home")
public AjaxResult getForumHome() {
Map<String, Object> forumData = new HashMap<>();
// 1. 推荐文章精选+置顶
List<VetExperienceArticle> featuredArticles = vetExperienceArticleService.selectFeaturedArticles(8);
forumData.put("featuredArticles", featuredArticles);
// 2. 最新文章
List<VetExperienceArticle> latestArticles = vetExperienceArticleService.selectLatestArticles(10);
forumData.put("latestArticles", latestArticles);
// 3. 热门文章按浏览数
List<VetExperienceArticle> hotArticles = vetExperienceArticleService.selectHotArticles(10);
forumData.put("hotArticles", hotArticles);
// 4. 文章统计
Map<String, Object> statistics = vetExperienceArticleService.selectForumStatistics();
forumData.put("statistics", statistics);
return success(forumData);
}
@GetMapping(value = "/{id}")
public AjaxResult getInfo(@PathVariable("id") Long id) {
// 增加浏览数
vetExperienceArticleService.incrementViewCount(id);
/**
* 浏览文章详情论坛模式
* 增加浏览数可以查看所有兽医的文章
*/
@GetMapping("/forum/detail/{id}")
public AjaxResult getForumArticleDetail(@PathVariable Long id) {
// 1. 获取文章详情
VetExperienceArticle article = vetExperienceArticleService.selectVetExperienceArticleById(id); VetExperienceArticle article = vetExperienceArticleService.selectVetExperienceArticleById(id);
if (article == null || !"1".equals(article.getStatus())) {
return error("文章不存在或未发布");
if (article == null) {
return error("文章不存在");
} }
// 2. 增加浏览数
vetExperienceArticleService.incrementViewCount(id);
// 3. 判断是否是当前用户发布的文章
Long currentUserId = getUserId();
boolean isOwner = currentUserId != null && currentUserId.equals(article.getUserId());
// 4. 获取相关文章
List<VetExperienceArticle> relatedArticles = vetExperienceArticleService.selectRelatedArticles(id, article.getCategoryId(), 4);
// 获取相关文章同一分类的其他文章
List<VetExperienceArticle> relatedArticles = vetExperienceArticleService.selectRelatedArticles(
id, article.getCategoryId(), 4);
// 5. 获取作者的其他文章
List<VetExperienceArticle> authorArticles = vetExperienceArticleService.selectArticlesByVetId(article.getUserId(), 5);
// 获取作者其他文章
List<VetExperienceArticle> authorArticles = vetExperienceArticleService.selectArticlesByUserId(
article.getUserId(), 5);
Map<String, Object> result = new HashMap<>(); Map<String, Object> result = new HashMap<>();
result.put("article", article); result.put("article", article);
result.put("isOwner", isOwner);
result.put("relatedArticles", relatedArticles); result.put("relatedArticles", relatedArticles);
result.put("authorArticles", authorArticles); result.put("authorArticles", authorArticles);
// 判断是否是当前用户
Long currentUserId = SecurityUtils.getUserId();
result.put("isOwner", currentUserId != null && currentUserId.equals(article.getUserId()));
result.put("isCollected", currentUserId != null &&
COLLECTION_STORE.getOrDefault(currentUserId, Collections.emptySet()).contains(id));
return success(result); return success(result);
} }
/** /**
* 发布新文章论坛发布接口
* 发布新文章论坛发布
*/ */
/*@PreAuthorize("@ss.hasPermi('vet:article:add')")*/
@Log(title = "发布经验文章", businessType = BusinessType.INSERT) @Log(title = "发布经验文章", businessType = BusinessType.INSERT)
@PostMapping("/forum/publish")
public AjaxResult publishForumArticle(@RequestBody VetExperienceArticle article) {
Long currentUserId = getUserId();
@PostMapping
public AjaxResult add(@RequestBody VetExperienceArticle article) {
Long currentUserId = SecurityUtils.getUserId();
String currentUsername = SecurityUtils.getUsername(); String currentUsername = SecurityUtils.getUsername();
// 设置作者信息 // 设置作者信息
article.setUserId(currentUserId); article.setUserId(currentUserId);
article.setVetName(currentUsername); // 暂时用用户名可以根据需要从用户表获取真实姓名
// 设置文章状态为已发布
article.setStatus("1");
article.setPublishTime(new Date());
// 敏感词检查
Map<String, Object> sensitiveCheck = checkSensitiveWords(article);
if ((Boolean) sensitiveCheck.get("hasSensitive")) {
// 包含敏感词标记但不阻止发布
article.setIsSensitive("1");
article.setSensitiveWords((String) sensitiveCheck.get("sensitiveWords"));
int result = vetExperienceArticleService.insertVetExperienceArticle(article);
if (result > 0) {
return success("文章发布成功,但包含敏感词,请注意修改。")
.put("articleId", article.getId())
.put("hasSensitive", true)
.put("sensitiveWords", sensitiveCheck.get("sensitiveWords"));
}
} else {
article.setIsSensitive("0");
article.setSensitiveWords(null);
article.setVetName(currentUsername);
int result = vetExperienceArticleService.insertVetExperienceArticle(article);
return toAjax(result).put("articleId", article.getId());
// 默认状态为已发布
if (article.getStatus() == null) {
article.setStatus("1");
} }
return error("发布失败");
}
/**
* 获取当前用户的文章
*/
/* @PreAuthorize("@ss.hasPermi('vet:article:my')")*/
@GetMapping("/forum/myArticles")
public TableDataInfo getMyForumArticles(
@RequestParam(value = "status", required = false) String status) {
Long currentUserId = getUserId();
VetExperienceArticle query = new VetExperienceArticle();
query.setUserId(currentUserId);
if (status != null && !status.isEmpty()) {
query.setStatus(status);
// 设置发布时间
if (article.getPublishTime() == null && "1".equals(article.getStatus())) {
article.setPublishTime(new Date());
} }
startPage();
List<VetExperienceArticle> list = vetExperienceArticleService.selectVetExperienceArticleList(query);
return getDataTable(list);
int result = vetExperienceArticleService.insertVetExperienceArticle(article);
return toAjax(result).put("articleId", article.getId());
} }
/** /**
* 获取我的收藏文章列表
* 修改文章
*/ */
@GetMapping("/forum/myCollections")
public TableDataInfo getMyCollections() {
Long currentUserId = getUserId();
if (currentUserId == null) {
return getDataTable(new ArrayList<>());
}
// 获取我的收藏文章ID
Set<Long> articleIds = COLLECTION_STORE.get(currentUserId);
if (articleIds == null || articleIds.isEmpty()) {
return getDataTable(new ArrayList<>());
}
@Log(title = "修改经验文章", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody VetExperienceArticle vetExperienceArticle) {
// 只有作者可以修改自己的文章
Long currentUserId = SecurityUtils.getUserId();
VetExperienceArticle original = vetExperienceArticleService.selectVetExperienceArticleById(vetExperienceArticle.getId());
// 查询文章详情
List<VetExperienceArticle> result = new ArrayList<>();
for (Long articleId : articleIds) {
VetExperienceArticle article = vetExperienceArticleService.selectVetExperienceArticleById(articleId);
if (article != null && "1".equals(article.getStatus())) {
result.add(article);
}
if (original == null || !original.getUserId().equals(currentUserId)) {
return error("没有权限修改此文章");
} }
// 按ID倒序模拟按收藏时间倒序
result.sort((a1, a2) -> a2.getId().compareTo(a1.getId()));
return getDataTable(result);
return toAjax(vetExperienceArticleService.updateVetExperienceArticle(vetExperienceArticle));
} }
/** /**
* 获取我的文章简单统计直接在Controller实现
* 删除文章
*/ */
@GetMapping("/my/simpleStats")
public AjaxResult getMySimpleStats() {
// 获取当前用户ID - 使用系统的方法
@Log(title = "删除经验文章", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable Long[] ids) {
// 只能删除自己的文章
Long currentUserId = SecurityUtils.getUserId(); Long currentUserId = SecurityUtils.getUserId();
System.out.println("当前用户ID: " + currentUserId); // 调试用
if (currentUserId == null) {
// 如果是开发测试可以使用临时用户ID
currentUserId = 1L; // 测试用
System.out.println("使用测试用户ID: " + currentUserId);
for (Long id : ids) {
VetExperienceArticle article = vetExperienceArticleService.selectVetExperienceArticleById(id);
if (article != null && !article.getUserId().equals(currentUserId)) {
return error("没有权限删除他人文章");
}
} }
// 查询当前用户已发布的文章
VetExperienceArticle query = new VetExperienceArticle();
query.setUserId(currentUserId);
query.setStatus("1"); // 只查询已发布的
System.out.println("查询条件: userId=" + currentUserId + ", status=1");
List<VetExperienceArticle> myArticles = vetExperienceArticleService.selectVetExperienceArticleList(query);
System.out.println("查询到文章数量: " + myArticles.size());
// 统计
Map<String, Object> stats = new HashMap<>();
stats.put("publishedCount", myArticles.size());
// 使用stream简化统计
int totalLikes = myArticles.stream()
.mapToInt(a -> a.getLikeCount() != null ? a.getLikeCount() : 0)
.sum();
int totalCollects = myArticles.stream()
.mapToInt(a -> a.getCollectCount() != null ? a.getCollectCount() : 0)
.sum();
int totalViews = myArticles.stream()
.mapToInt(a -> a.getViewCount() != null ? a.getViewCount() : 0)
.sum();
stats.put("totalLikes", totalLikes);
stats.put("totalCollects", totalCollects);
stats.put("totalViews", totalViews);
stats.put("userId", currentUserId);
return success(stats);
return toAjax(vetExperienceArticleService.deleteVetExperienceArticleByIds(ids));
} }
/** /**
* 点赞文章 * 点赞文章
*/ */
@PostMapping("/forum/{id}/like")
@Log(title = "点赞文章", businessType = BusinessType.UPDATE)
@PostMapping("/{id}/like")
public AjaxResult likeArticle(@PathVariable Long id) { public AjaxResult likeArticle(@PathVariable Long id) {
int result = vetExperienceArticleService.incrementLikeCount(id); int result = vetExperienceArticleService.incrementLikeCount(id);
return toAjax(result);
return toAjax(result).put("message", "点赞成功");
} }
/** /**
* 收藏文章 * 收藏文章
*/ */
@PostMapping("/forum/{id}/collect")
public AjaxResult collectArticle(@PathVariable("id") Long id) {
Long currentUserId = getUserId();
@PostMapping("/{id}/collect")
public AjaxResult collectArticle(@PathVariable Long id) {
Long currentUserId = SecurityUtils.getUserId();
if (currentUserId == null) { if (currentUserId == null) {
return error("请先登录"); return error("请先登录");
} }
@ -467,113 +210,110 @@ public class VetExperienceArticleController extends BaseController {
// 检查是否已收藏 // 检查是否已收藏
if (myCollections.contains(id)) { if (myCollections.contains(id)) {
return error("已收藏过该文章");
// 取消收藏
myCollections.remove(id);
return success("已取消收藏");
} else {
// 添加收藏
myCollections.add(id);
// 增加文章收藏数
vetExperienceArticleService.incrementCollectCount(id);
return success("收藏成功");
} }
// 添加收藏
myCollections.add(id);
// 增加文章收藏数
vetExperienceArticleService.incrementCollectCount(id);
return success("收藏成功");
} }
/** /**
* 搜索文章
* 获取我的收藏文章列表
*/ */
@GetMapping("/forum/search")
public TableDataInfo searchForumArticles(
@RequestParam(value = "keyword", required = false) String keyword,
@RequestParam(value = "categoryId", required = false) Long categoryId,
@RequestParam(value = "tag", required = false) String tag) {
VetExperienceArticle query = new VetExperienceArticle();
query.setStatus("1"); // 只搜索已发布的文章
@GetMapping("/myCollections")
public TableDataInfo getMyCollections() {
Long currentUserId = SecurityUtils.getUserId();
if (currentUserId == null) {
return getDataTable(new ArrayList<>());
}
if (keyword != null && !keyword.trim().isEmpty()) {
query.setTitle(keyword.trim());
// 获取我的收藏文章ID
Set<Long> articleIds = COLLECTION_STORE.get(currentUserId);
if (articleIds == null || articleIds.isEmpty()) {
return getDataTable(new ArrayList<>());
} }
if (categoryId != null) {
query.setCategoryId(categoryId);
// 查询文章详情
List<VetExperienceArticle> result = new ArrayList<>();
for (Long articleId : articleIds) {
VetExperienceArticle article = vetExperienceArticleService.selectVetExperienceArticleById(articleId);
if (article != null && "1".equals(article.getStatus())) {
result.add(article);
}
} }
// 按收藏时间倒序这里用ID倒序模拟
result.sort((a1, a2) -> a2.getId().compareTo(a1.getId()));
startPage(); startPage();
List<VetExperienceArticle> list = vetExperienceArticleService.selectVetExperienceArticleList(query);
/*List<VetExperienceArticle> list = vetExperienceArticleService.searchArticles(keyword);*/
return getDataTable(list);
return getDataTable(result);
} }
/** /**
* 获取热门标签
* 获取论坛统计信息
*/ */
/*@GetMapping("/forum/hotTags")
public AjaxResult getHotTags(@RequestParam(value = "limit", defaultValue = "15") Integer limit) {
List<Map<String, Object>> hotTags = vetExperienceArticleService.selectHotTags(limit);
return success(hotTags);
}*/
@GetMapping("/statistics")
public AjaxResult getStatistics() {
return success(vetExperienceArticleService.selectForumStatistics());
}
/** /**
* 2. 根据标签搜索文章带分页
* 获取最新文章
*/ */
/* @GetMapping("/listByTag")
public TableDataInfo listByTag(@RequestParam("tag") String tag,
@RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum,
@RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize) {
startPage();
// 创建查询对象
VetExperienceArticle query = new VetExperienceArticle();
query.setStatus("1"); // 只查已发布的
query.setTags(tag); // 设置标签条件
List<VetExperienceArticle> list = vetExperienceArticleService.selectVetExperienceArticleList(query);
return getDataTable(list);
}*/
@GetMapping("/latest")
public AjaxResult getLatestArticles(@RequestParam(defaultValue = "10") Integer limit) {
List<VetExperienceArticle> articles = vetExperienceArticleService.selectLatestArticles(limit);
return success(articles);
}
/** /**
* 新增文章 - 调整为论坛发布模式
* 获取分类选项
*/ */
/* @PreAuthorize("@ss.hasPermi('vet:article:add')")*/
@Log(title = "兽医经验文章", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@RequestBody VetExperienceArticle vetExperienceArticle) {
// 调用论坛发布接口
return publishForumArticle(vetExperienceArticle);
}
@GetMapping("/options")
public AjaxResult getCategoryOptions() {
// 直接从字典表查询
String sql = "SELECT dict_value as value, dict_label as label, dict_sort as sortOrder " +
"FROM sys_dict_data " +
"WHERE dict_type = 'vet_experience_category' AND status = '0' " +
"ORDER BY dict_sort ASC";
List<Map<String, Object>> options = jdbcTemplate.query(sql, (rs, rowNum) -> {
Map<String, Object> option = new HashMap<>();
option.put("value", rs.getString("value")); // 字典值作为value
option.put("label", rs.getString("label")); // 字典标签作为label
option.put("sortOrder", rs.getInt("sortOrder")); // 排序字段
return option;
});
return success(options);
}
/** /**
* 敏感词检查方法
* 获取标签选项
*/ */
private Map<String, Object> checkSensitiveWords(VetExperienceArticle article) {
Map<String, Object> result = new HashMap<>();
result.put("hasSensitive", false);
result.put("sensitiveWords", "");
@GetMapping("/tags/options")
public AjaxResult getTagOptions() {
List<Map<String, Object>> options = new ArrayList<>();
// TODO: 实现敏感词检查逻辑
// 可以调用专门的敏感词服务
// List<String> sensitiveWords = sensitiveWordService.detect(article.getTitle() + " " + article.getContent());
String[][] tagData = {
{"疫苗", "疫苗"}, {"传染病", "传染病"}, {"防治", "防治"},
{"养殖", "养殖"}, {"饲养管理", "饲养管理"}, {"繁殖", "繁殖"},
{"牛羊", "牛羊"}, {"药物使用", "药物使用"}, {"特殊病例", "特殊病例"}
};
// 示例逻辑
if (article.getTitle() != null && article.getTitle().contains("敏感词示例")) {
result.put("hasSensitive", true);
result.put("sensitiveWords", "敏感词示例");
for (String[] tag : tagData) {
Map<String, Object> option = new HashMap<>();
option.put("label", tag[0]);
option.put("value", tag[1]);
options.add(option);
} }
return result;
}
/**
* 导出兽医经验文章列表
*/
/* @PreAuthorize("@ss.hasPermi('vet:article:export')")*/
@Log(title = "兽医经验文章", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(HttpServletResponse response, VetExperienceArticle vetExperienceArticle) {
List<VetExperienceArticle> list = vetExperienceArticleService.selectVetExperienceArticleList(vetExperienceArticle);
ExcelUtil<VetExperienceArticle> util = new ExcelUtil<>(VetExperienceArticle.class);
util.exportExcel(response, list, "兽医经验文章数据");
return success(options);
} }
} }

63
chenhai-admin/src/main/java/com/chenhai/web/controller/vet/VetProductController.java

@ -1,6 +1,8 @@
package com.chenhai.web.controller.vet; package com.chenhai.web.controller.vet;
import java.util.List; import java.util.List;
import com.chenhai.common.utils.SecurityUtils;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -103,4 +105,65 @@ public class VetProductController extends BaseController
} }
/**
* 提交审核
*/
@PreAuthorize("@ss.hasPermi('vet:product:submit')")
@Log(title = "兽医产品信息", businessType = BusinessType.UPDATE)
@PostMapping("/submitAudit/{id}")
public AjaxResult submitForAudit(@PathVariable("id") Long id)
{
return toAjax(vetProductService.submitForAudit(id));
}
/**
* 审核产品
*/
@PreAuthorize("@ss.hasPermi('vet:product:audit')")
@Log(title = "兽医产品信息", businessType = BusinessType.UPDATE)
@PostMapping("/audit")
public AjaxResult auditProduct(@RequestBody VetProduct vetProduct)
{
Long auditUserId = SecurityUtils.getUserId();
return toAjax(vetProductService.auditProduct(
vetProduct.getId(),
vetProduct.getAuditStatus(),
vetProduct.getAuditOpinion(),
auditUserId
));
}
/**
* 上架产品
*/
@PreAuthorize("@ss.hasPermi('vet:product:publish')")
@Log(title = "兽医产品信息", businessType = BusinessType.UPDATE)
@PostMapping("/publish/{id}")
public AjaxResult publishProduct(@PathVariable("id") Long id)
{
return toAjax(vetProductService.publishProduct(id));
}
/**
* 下架产品
*/
@PreAuthorize("@ss.hasPermi('vet:product:offline')")
@Log(title = "兽医产品信息", businessType = BusinessType.UPDATE)
@PostMapping("/offline/{id}")
public AjaxResult offlineProduct(@PathVariable("id") Long id)
{
return toAjax(vetProductService.offlineProduct(id));
}
/**
* 取消审核
*/
@PreAuthorize("@ss.hasPermi('vet:product:edit')")
@Log(title = "兽医产品信息", businessType = BusinessType.UPDATE)
@PostMapping("/cancelAudit/{id}")
public AjaxResult cancelAudit(@PathVariable("id") Long id)
{
return toAjax(vetProductService.cancelAudit(id));
}
} }

557
chenhai-admin/src/main/java/com/chenhai/web/controller/vet/VetQualificationController.java

@ -6,27 +6,19 @@ 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.file.FileUtils;
import com.chenhai.common.utils.poi.ExcelUtil;
import com.chenhai.vet.domain.BusinessScopeConstants;
import com.chenhai.vet.domain.VetQualification; import com.chenhai.vet.domain.VetQualification;
import com.chenhai.vet.service.IVetQualificationService; import com.chenhai.vet.service.IVetQualificationService;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.DataIntegrityViolationException; import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.jdbc.core.JdbcTemplate; 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.*;
import org.springframework.web.multipart.MultipartFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.*; import java.util.*;
import static com.chenhai.framework.datasource.DynamicDataSourceContextHolder.log;
import java.text.SimpleDateFormat;
/** /**
* 兽医资质控制器合并证书功能 * 兽医资质控制器合并证书功能
@ -37,17 +29,13 @@ import static com.chenhai.framework.datasource.DynamicDataSourceContextHolder.lo
@RequestMapping("/vet/qualification") @RequestMapping("/vet/qualification")
public class VetQualificationController extends BaseController public class VetQualificationController extends BaseController
{ {
private static final Logger log = LoggerFactory.getLogger(VetQualificationController.class);
@Autowired @Autowired
private IVetQualificationService vetQualificationService; private IVetQualificationService vetQualificationService;
@Autowired @Autowired
private JdbcTemplate jdbcTemplate; private JdbcTemplate jdbcTemplate;
@Value("${chenhai.profile}")
private String uploadRootPath;
private static final String QUALIFICATION_FILE_PATH = "/vet/qualification/";
/** /**
* 获取资质类型选项下拉框用 * 获取资质类型选项下拉框用
*/ */
@ -88,7 +76,6 @@ public class VetQualificationController extends BaseController
return AjaxResult.success(options); return AjaxResult.success(options);
} }
/** /**
* 查询兽医资质列表含证书信息 * 查询兽医资质列表含证书信息
*/ */
@ -123,32 +110,108 @@ public class VetQualificationController extends BaseController
} }
/** /**
* 用户详情页查询资质证书
* 查询用户的证书列表展开每个证书
*/ */
@PreAuthorize("@ss.hasPermi('vet:qualification:list')") @PreAuthorize("@ss.hasPermi('vet:qualification:list')")
@GetMapping("/listForDetail")
public TableDataInfo listForDetail(@RequestParam(value = "userId", required = false) Long userId)
@GetMapping("/certificate/list")
public TableDataInfo getCertificateList(VetQualification vetQualification)
{ {
startPage(); startPage();
Long currentUserId = SecurityUtils.getUserId();
Long userId = SecurityUtils.getUserId();
if (!SecurityUtils.isAdmin(userId)) {
vetQualification.setUserId(userId);
}
if (currentUserId == null) {
return getDataTable(List.of());
List<VetQualification> qualifications = vetQualificationService.selectVetQualificationList(vetQualification);
List<Map<String, Object>> certificateList = new ArrayList<>();
for (VetQualification qualification : qualifications) {
List<VetQualification.CertificateInfo> certList = qualification.getCertificateList();
if (certList != null && !certList.isEmpty()) {
for (VetQualification.CertificateInfo cert : certList) {
Map<String, Object> certMap = new HashMap<>();
certMap.put("qualificationId", qualification.getQualificationId());
certMap.put("realName", qualification.getRealName());
certMap.put("certName", cert.getCertName());
certMap.put("certificateNo", cert.getCertificateNo());
certMap.put("issueDate", cert.getIssueDate());
certMap.put("expireDate", cert.getExpireDate());
certMap.put("issueOrg", cert.getIssueOrg());
certMap.put("certificateFiles", cert.getCertificateFiles());
certMap.put("certStatus", cert.getCertStatus());
certMap.put("certStatusLabel", getCertStatusLabel(cert.getCertStatus()));
if (cert.getCertId() != null) {
certMap.put("certId", String.valueOf(cert.getCertId())); // 转为String
}
else if (qualification.getCertId() != null) {
certMap.put("certId", String.valueOf(qualification.getCertId())); // 转为String
}
certificateList.add(certMap);
}
}
} }
return getDataTable(certificateList);
}
/**
* 根据证书ID查询证书详细信息
* 证书信息存储在资质的certificatesJson字段中通过数据库JSON查询获取
*/
@GetMapping("/certificate/{certId}")
public AjaxResult getCertificateByCertId(@PathVariable("certId") Long certId)
{
try {
Long currentUserId = SecurityUtils.getUserId();
boolean isAdmin = SecurityUtils.isAdmin(currentUserId);
Map<String, Object> certificateInfo = vetQualificationService
.selectCertificateWithQualificationByCertId(certId, isAdmin ? null : currentUserId);
if (certificateInfo == null || certificateInfo.isEmpty()) {
return AjaxResult.error("证书不存在或没有权限查看");
}
Object expireDateObj = certificateInfo.get("expireDate");
if (expireDateObj instanceof Date) {
Date expireDate = (Date) expireDateObj;
String certStatus = calculateCertStatus(expireDate);
String certStatusLabel = getCertStatusLabel(certStatus);
certificateInfo.put("certStatus", certStatus);
certificateInfo.put("certStatusLabel", certStatusLabel);
}
return AjaxResult.success(certificateInfo);
if (userId == null) {
return getDataTable(List.of());
} catch (Exception e) {
return AjaxResult.error("查询证书失败:" + e.getMessage());
} }
}
// 权限检查管理员或查看自己
if (!SecurityUtils.isAdmin(currentUserId) && !userId.equals(currentUserId)) {
return getDataTable(List.of());
/**
* 计算证书状态
*/
private String calculateCertStatus(Date expireDate) {
if (expireDate == null) {
return "0";
} }
VetQualification query = new VetQualification();
query.setUserId(userId);
List<VetQualification> list = vetQualificationService.selectVetQualificationList(query);
return getDataTable(list);
Date today = new Date();
Calendar calendar = Calendar.getInstance();
calendar.setTime(today);
calendar.add(Calendar.DAY_OF_YEAR, 30);
Date thirtyDaysLater = calendar.getTime();
if (expireDate.before(today)) {
return "2";
} else if (expireDate.before(thirtyDaysLater)) {
return "1";
} else {
return "0";
}
} }
/** /**
@ -165,52 +228,43 @@ public class VetQualificationController extends BaseController
if (list.isEmpty()) { if (list.isEmpty()) {
result.put("needPopup", true); result.put("needPopup", true);
result.put("message", "请先填写兽医资质信息"); result.put("message", "请先填写兽医资质信息");
result.put("status", "empty");
} else { } else {
VetQualification qualification = list.get(0); VetQualification qualification = list.get(0);
if ("0".equals(qualification.getAuditStatus())) {
result.put("needPopup", false);
result.put("message", "您的资质正在审核中,请耐心等待");
result.put("status", "pending");
} else if ("1".equals(qualification.getAuditStatus())) {
result.put("needPopup", false);
result.put("message", "您的资质已审核通过");
result.put("status", "approved");
} else if ("2".equals(qualification.getAuditStatus())) {
String auditStatus = qualification.getAuditStatus();
boolean needPopup = auditStatus == null;
if (auditStatus == null) {
result.put("needPopup", true); result.put("needPopup", true);
result.put("message", "您的资质审核不通过,请重新填写");
result.put("status", "rejected");
} else {
result.put("needPopup", false);
result.put("message", "请先提交资质审核"); result.put("message", "请先提交资质审核");
result.put("status", "needSubmit"); result.put("status", "needSubmit");
} else {
result.put("needPopup", false);
switch (auditStatus) {
case "0":
case "3":
result.put("message", "您的资质正在审核中,请耐心等待");
result.put("status", "pending");
break;
case "1":
result.put("message", "您的资质已审核通过");
result.put("status", "approved");
break;
case "2":
result.put("message", "您的资质审核不通过");
result.put("status", "rejected");
break;
default:
result.put("message", "您的资质已提交审核");
result.put("status", "submitted");
break;
}
} }
} }
return AjaxResult.success(result);
}
/**
* 获取经营范围详情
*/
@GetMapping("/scope/detail/{scopeId}")
public AjaxResult getScopeDetail(@PathVariable String scopeId) {
Map<String, Object> detail = new HashMap<>();
detail.put("scopeId", scopeId);
detail.put("scopeName", BusinessScopeConstants.getScopeName(scopeId));
detail.put("requiredQualifications", BusinessScopeConstants.getRequiredQualifications(scopeId));
return AjaxResult.success(detail);
}
/**
* 导出兽医资质列表
*/
@PreAuthorize("@ss.hasPermi('vet:qualification:export')")
@Log(title = "兽医资质", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(HttpServletResponse response, VetQualification vetQualification)
{
List<VetQualification> list = vetQualificationService.selectVetQualificationList(vetQualification);
ExcelUtil<VetQualification> util = new ExcelUtil<VetQualification>(VetQualification.class);
util.exportExcel(response, list, "兽医资质数据");
return AjaxResult.success(result);
} }
/** /**
@ -225,7 +279,6 @@ public class VetQualificationController extends BaseController
return AjaxResult.error("资质信息不存在"); return AjaxResult.error("资质信息不存在");
} }
// 权限检查管理员或查看自己
Long currentUserId = SecurityUtils.getUserId(); Long currentUserId = SecurityUtils.getUserId();
if (!SecurityUtils.isAdmin(currentUserId) && !qualification.getUserId().equals(currentUserId)) { if (!SecurityUtils.isAdmin(currentUserId) && !qualification.getUserId().equals(currentUserId)) {
return AjaxResult.error("没有权限查看此资质"); return AjaxResult.error("没有权限查看此资质");
@ -248,7 +301,6 @@ public class VetQualificationController extends BaseController
vetQualification.setUserId(sysUserId); vetQualification.setUserId(sysUserId);
vetQualification.setCreateBy(username); vetQualification.setCreateBy(username);
// 设置默认提醒天数
if (vetQualification.getRemindDays() == null) { if (vetQualification.getRemindDays() == null) {
vetQualification.setRemindDays(30); vetQualification.setRemindDays(30);
} }
@ -268,7 +320,6 @@ public class VetQualificationController extends BaseController
String sql = "INSERT IGNORE INTO vet_user (sys_user_id, username, create_time) VALUES (?, ?, NOW())"; String sql = "INSERT IGNORE INTO vet_user (sys_user_id, username, create_time) VALUES (?, ?, NOW())";
jdbcTemplate.update(sql, sysUserId, username); jdbcTemplate.update(sql, sysUserId, username);
} catch (Exception e) { } catch (Exception e) {
// 忽略异常
} }
} }
@ -280,7 +331,6 @@ public class VetQualificationController extends BaseController
@PutMapping @PutMapping
public AjaxResult edit(@RequestBody VetQualification vetQualification) public AjaxResult edit(@RequestBody VetQualification vetQualification)
{ {
// 检查权限普通用户只能修改自己的资质
Long currentUserId = SecurityUtils.getUserId(); Long currentUserId = SecurityUtils.getUserId();
if (!SecurityUtils.isAdmin(currentUserId)) { if (!SecurityUtils.isAdmin(currentUserId)) {
VetQualification existing = vetQualificationService.selectVetQualificationByQualificationId(vetQualification.getQualificationId()); VetQualification existing = vetQualificationService.selectVetQualificationByQualificationId(vetQualification.getQualificationId());
@ -300,7 +350,6 @@ public class VetQualificationController extends BaseController
@DeleteMapping("/{qualificationIds}") @DeleteMapping("/{qualificationIds}")
public AjaxResult remove(@PathVariable Long[] qualificationIds) public AjaxResult remove(@PathVariable Long[] qualificationIds)
{ {
// 检查权限
Long currentUserId = SecurityUtils.getUserId(); Long currentUserId = SecurityUtils.getUserId();
if (!SecurityUtils.isAdmin(currentUserId)) { if (!SecurityUtils.isAdmin(currentUserId)) {
for (Long id : qualificationIds) { for (Long id : qualificationIds) {
@ -319,39 +368,70 @@ public class VetQualificationController extends BaseController
*/ */
@Log(title = "兽医资质", businessType = BusinessType.UPDATE) @Log(title = "兽医资质", businessType = BusinessType.UPDATE)
@PostMapping("/submit") @PostMapping("/submit")
public AjaxResult submitQualification(@RequestBody VetQualification vetQualification) {
public AjaxResult submitQualification(@RequestBody Object requestBody) {
try { try {
Long userId = SecurityUtils.getUserId();
String username = SecurityUtils.getUsername();
// 设置必要字段
vetQualification.setUserId(userId);
vetQualification.setCreateBy(username);
vetQualification.setAuditStatus("0"); // 设置为待审核状态
vetQualification.setApplyTime(new Date()); // 设置申请时间
int result;
// 如果已有资质ID则为更新操作重新提交审核
if (vetQualification.getQualificationId() != null) {
vetQualification.setUpdateBy(username);
result = vetQualificationService.updateVetQualification(vetQualification);
if (requestBody instanceof Map) {
@SuppressWarnings("unchecked")
Map<String, Object> requestData = (Map<String, Object>) requestBody;
return processNewFormat(requestData);
} else { } else {
// 新增资质记录并提交审核
result = vetQualificationService.insertVetQualification(vetQualification);
}
ObjectMapper mapper = new ObjectMapper();
Map<String, Object> requestData = mapper.convertValue(requestBody, Map.class);
if (result > 0) {
return AjaxResult.success("资质提交成功,等待审核", vetQualification);
} else {
return AjaxResult.error("资质提交失败");
if (requestData.containsKey("realName") && requestData.containsKey("certificates")) {
return processNewFormat(requestData);
} else {
return processOldFormat(requestBody);
}
} }
} catch (Exception e) { } catch (Exception e) {
log.error("提交资质失败", e);
return AjaxResult.error("提交失败:" + e.getMessage()); return AjaxResult.error("提交失败:" + e.getMessage());
} }
} }
private AjaxResult processNewFormat(Map<String, Object> requestData) {
Long userId = SecurityUtils.getUserId();
int result = vetQualificationService.submitQualification(requestData);
if (result > 0) {
return AjaxResult.success("资质提交成功,等待审核");
} else {
return AjaxResult.error("资质提交失败");
}
}
private AjaxResult processOldFormat(Object requestBody) {
VetQualification vetQualification;
if (requestBody instanceof VetQualification) {
vetQualification = (VetQualification) requestBody;
} else {
ObjectMapper mapper = new ObjectMapper();
vetQualification = mapper.convertValue(requestBody, VetQualification.class);
}
Long userId = SecurityUtils.getUserId();
String username = SecurityUtils.getUsername();
vetQualification.setUserId(userId);
vetQualification.setCreateBy(username);
vetQualification.setAuditStatus("0");
vetQualification.setApplyTime(new Date());
int result;
if (vetQualification.getQualificationId() != null) {
vetQualification.setUpdateBy(username);
result = vetQualificationService.updateVetQualification(vetQualification);
} else {
result = vetQualificationService.insertVetQualification(vetQualification);
}
if (result > 0) {
return AjaxResult.success("资质提交成功,等待审核", vetQualification);
} else {
return AjaxResult.error("资质提交失败");
}
}
/** /**
* 审核操作 * 审核操作
*/ */
@ -369,7 +449,6 @@ public class VetQualificationController extends BaseController
public AjaxResult getByUserId(@PathVariable Long userId) { public AjaxResult getByUserId(@PathVariable Long userId) {
Long currentUserId = SecurityUtils.getUserId(); Long currentUserId = SecurityUtils.getUserId();
// 权限检查
if (!SecurityUtils.isAdmin(currentUserId) && !userId.equals(currentUserId)) { if (!SecurityUtils.isAdmin(currentUserId) && !userId.equals(currentUserId)) {
return error("没有权限查看其他用户的资质"); return error("没有权限查看其他用户的资质");
} }
@ -378,22 +457,6 @@ public class VetQualificationController extends BaseController
return success(list); return success(list);
} }
/**
* 获取即将过期的资质证书
*/
@GetMapping("/expiring/{userId}")
public AjaxResult getExpiringQualifications(@PathVariable Long userId) {
Long currentUserId = SecurityUtils.getUserId();
// 权限检查
if (!SecurityUtils.isAdmin(currentUserId) && !userId.equals(currentUserId)) {
return error("没有权限查看其他用户的证书");
}
List<VetQualification> list = vetQualificationService.selectExpiringQualifications(userId);
return success(list);
}
/** /**
* 获取证书统计信息 * 获取证书统计信息
*/ */
@ -401,7 +464,6 @@ public class VetQualificationController extends BaseController
public AjaxResult getStatistics(@PathVariable Long userId) { public AjaxResult getStatistics(@PathVariable Long userId) {
Long currentUserId = SecurityUtils.getUserId(); Long currentUserId = SecurityUtils.getUserId();
// 权限检查
if (!SecurityUtils.isAdmin(currentUserId) && !userId.equals(currentUserId)) { if (!SecurityUtils.isAdmin(currentUserId) && !userId.equals(currentUserId)) {
return error("没有权限查看其他用户的统计信息"); return error("没有权限查看其他用户的统计信息");
} }
@ -417,7 +479,6 @@ public class VetQualificationController extends BaseController
public AjaxResult manualCheck(@PathVariable Long userId) { public AjaxResult manualCheck(@PathVariable Long userId) {
Long currentUserId = SecurityUtils.getUserId(); Long currentUserId = SecurityUtils.getUserId();
// 权限检查
if (!SecurityUtils.isAdmin(currentUserId) && !userId.equals(currentUserId)) { if (!SecurityUtils.isAdmin(currentUserId) && !userId.equals(currentUserId)) {
return error("没有权限为其他用户检查证书"); return error("没有权限为其他用户检查证书");
} }
@ -425,4 +486,262 @@ public class VetQualificationController extends BaseController
vetQualificationService.manualCheckCertificates(userId); vetQualificationService.manualCheckCertificates(userId);
return success("证书检查完成"); return success("证书检查完成");
} }
/**
* 获取证书状态标签
*/
private String getCertStatusLabel(String certStatus) {
if ("0".equals(certStatus)) return "正常";
else if ("1".equals(certStatus)) return "即将过期";
else if ("2".equals(certStatus)) return "已过期";
else return "未知";
}
/**
* 修改单个证书信息并提交审核根据证书ID修改单个证书
*/
@Log(title = "兽医资质证书", businessType = BusinessType.UPDATE)
@PostMapping("/certificate/updateAndSubmit")
public AjaxResult updateCertificateAndSubmit(@RequestBody Map<String, Object> requestData) {
try {
log.info("修改单个证书并提交审核请求数据: {}", requestData);
// 1. 获取证书ID要修改的证书
// 1. 获取字符串格式的ID
String certIdStr = null;
Object certIdObj = requestData.get("certId");
if (certIdObj != null) {
certIdStr = certIdObj.toString();
}
if (certIdStr == null || certIdStr.trim().isEmpty()) {
return AjaxResult.error("证书ID不能为空");
}
// 2. 字符串转Long
Long certId;
try {
certId = Long.parseLong(certIdStr);
} catch (NumberFormatException e) {
log.error("证书ID格式错误: {}", certIdStr, e);
return AjaxResult.error("证书ID格式错误");
}
// 3. 继续原有逻辑使用Long类型的certId
Long qualificationId = extractLongFromObject(requestData.get("qualificationId"));
if (qualificationId == null) {
return AjaxResult.error("资质ID不能为空");
}
// 3. 查询整个资质信息
VetQualification existingQualification = vetQualificationService.selectVetQualificationByQualificationId(qualificationId);
if (existingQualification == null) {
return AjaxResult.error("资质信息不存在");
}
// 4. 权限检查
Long currentUserId = SecurityUtils.getUserId();
if (!SecurityUtils.isAdmin(currentUserId) && !existingQualification.getUserId().equals(currentUserId)) {
return AjaxResult.error("无权操作此证书");
}
// 5. 获取现有证书列表
List<VetQualification.CertificateInfo> certificateList = existingQualification.getCertificateList();
if (certificateList == null || certificateList.isEmpty()) {
return AjaxResult.error("该资质没有证书信息");
}
// 6. 查找并更新指定证书
boolean certificateFound = false;
for (VetQualification.CertificateInfo cert : certificateList) {
if (cert.getCertificateId() != null && cert.getCertificateId().equals(certId)) {
// 更新证书信息
updateSingleCertificate(cert, requestData);
certificateFound = true;
break;
}
}
if (!certificateFound) {
return AjaxResult.error("未找到要修改的证书");
}
// 7. 创建更新对象
VetQualification updateQualification = new VetQualification();
updateQualification.setQualificationId(qualificationId);
// 8. 更新基础信息如果有的话
updateBasicInfo(requestData, updateQualification);
// 9. 更新证书列表到JSON
updateCertificatesToJson(certificateList, updateQualification);
// 10. 更新主表字段使用第一个证书的信息
if (!certificateList.isEmpty()) {
VetQualification.CertificateInfo firstCert = certificateList.get(0);
updateQualification.setCertName(firstCert.getCertName());
updateQualification.setCertificateNo(firstCert.getCertificateNo());
updateQualification.setIssueOrg(firstCert.getIssueOrg());
updateQualification.setCertificateFiles(firstCert.getCertificateFiles());
updateQualification.setIssueDate(firstCert.getIssueDate());
updateQualification.setExpireDate(firstCert.getExpireDate());
}
// 11. 设置审核状态为"待审核"
updateQualification.setAuditStatus("0");
updateQualification.setAuditOpinion(null);
updateQualification.setApplyTime(new Date());
// 12. 设置更新人信息
updateQualification.setUpdateBy(SecurityUtils.getUsername());
updateQualification.setUpdateTime(new Date());
// 13. 执行更新
int result = vetQualificationService.updateVetQualification(updateQualification);
if (result > 0) {
log.info("单个证书修改并提交审核成功,certId: {}, qualificationId: {}", certId, qualificationId);
return AjaxResult.success("证书修改成功,资质已提交审核");
} else {
return AjaxResult.error("操作失败,请稍后重试");
}
} catch (Exception e) {
log.error("修改单个证书并提交审核失败", e);
return AjaxResult.error("操作失败: " + e.getMessage());
}
}
/**
* 更新单个证书信息
*/
private void updateSingleCertificate(VetQualification.CertificateInfo cert, Map<String, Object> requestData) {
if (requestData.containsKey("certName")) {
cert.setCertName((String) requestData.get("certName"));
}
if (requestData.containsKey("certificateNo")) {
cert.setCertificateNo((String) requestData.get("certificateNo"));
}
if (requestData.containsKey("issueOrg")) {
cert.setIssueOrg((String) requestData.get("issueOrg"));
}
if (requestData.containsKey("certificateFiles")) {
cert.setCertificateFiles((String) requestData.get("certificateFiles"));
}
if (requestData.containsKey("issueDate")) {
Object issueDateObj = requestData.get("issueDate");
if (issueDateObj instanceof String) {
try {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
cert.setIssueDate(sdf.parse((String) issueDateObj));
} catch (Exception e) {
log.warn("解析发证日期失败: {}", issueDateObj);
}
}
}
if (requestData.containsKey("expireDate")) {
Object expireDateObj = requestData.get("expireDate");
if (expireDateObj instanceof String) {
try {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
cert.setExpireDate(sdf.parse((String) expireDateObj));
} catch (Exception e) {
log.warn("解析到期日期失败: {}", expireDateObj);
}
}
}
}
/**
* 更新基础信息
*/
private void updateBasicInfo(Map<String, Object> requestData, VetQualification updateQualification) {
if (requestData.containsKey("realName")) {
updateQualification.setRealName((String) requestData.get("realName"));
}
if (requestData.containsKey("idCard")) {
updateQualification.setIdCard((String) requestData.get("idCard"));
}
if (requestData.containsKey("qualificationType")) {
updateQualification.setQualificationType((String) requestData.get("qualificationType"));
}
if (requestData.containsKey("scopeIds")) {
Object scopeIdsObj = requestData.get("scopeIds");
if (scopeIdsObj instanceof List) {
@SuppressWarnings("unchecked")
List<String> scopeIdsList = (List<String>) scopeIdsObj;
updateQualification.setScopeIds(String.join(",", scopeIdsList));
} else if (scopeIdsObj instanceof String) {
updateQualification.setScopeIds((String) scopeIdsObj);
}
}
}
/**
* 更新证书列表到JSON
*/
private void updateCertificatesToJson(List<VetQualification.CertificateInfo> certificateList, VetQualification updateQualification) {
try {
List<Map<String, Object>> certMaps = new ArrayList<>();
for (VetQualification.CertificateInfo cert : certificateList) {
Map<String, Object> certMap = new HashMap<>();
certMap.put("certName", cert.getCertName());
certMap.put("certificateNo", cert.getCertificateNo());
certMap.put("issueOrg", cert.getIssueOrg());
certMap.put("certificateFiles", cert.getCertificateFiles());
if (cert.getIssueDate() != null) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
certMap.put("issueDate", sdf.format(cert.getIssueDate()));
}
if (cert.getExpireDate() != null) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
certMap.put("expireDate", sdf.format(cert.getExpireDate()));
}
if (cert.getCertificateId() != null) {
certMap.put("certId", cert.getCertificateId());
}
if (cert.getCertStatus() != null) {
certMap.put("certStatus", cert.getCertStatus());
}
certMaps.add(certMap);
}
ObjectMapper mapper = new ObjectMapper();
String certificatesJson = mapper.writeValueAsString(certMaps);
updateQualification.setCertificatesJson(certificatesJson);
} catch (Exception e) {
log.error("更新证书JSON失败", e);
throw new RuntimeException("更新证书JSON失败");
}
}
/**
* 从对象中提取Long值
*/
private Long extractLongFromObject(Object obj) {
if (obj == null) {
return null;
}
try {
if (obj instanceof Number) {
return ((Number) obj).longValue();
} else if (obj instanceof String) {
String str = ((String) obj).trim();
if (!str.isEmpty()) {
return Long.parseLong(str);
}
}
} catch (Exception e) {
log.warn("提取Long值失败: {}", obj, e);
}
return null;
}
} }

66
chenhai-system/src/main/java/com/chenhai/vet/domain/BusinessScopeConstants.java

@ -1,66 +0,0 @@
package com.chenhai.vet.domain;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* 经营范围常量
*/
public class BusinessScopeConstants {
// 经营范围映射
public static final Map<String, String> SCOPE_MAP = new LinkedHashMap<String, String>() {{
put("1", "畜禽诊疗");
put("2", "宠物诊疗");
put("3", "动物防疫");
put("4", "检疫检验");
put("5", "兽药经营");
put("6", "饲料经营");
put("7", "畜牧技术咨询");
put("8", "畜禽养殖");
put("9", "宠物美容");
put("10", "宠物寄养");
}};
// 所需资质映射
public static final Map<String, String> REQUIRED_QUALIFICATIONS = new LinkedHashMap<String, String>() {{
put("1", "执业兽医资格证、动物诊疗许可证");
put("2", "执业兽医资格证、动物诊疗许可证、宠物诊疗许可证");
put("3", "执业兽医资格证、动物防疫员证");
put("4", "官方兽医资格证、检疫员证");
put("5", "兽药经营许可证、GSP证书");
put("6", "饲料经营许可证");
put("7", "高级畜牧师证、技术顾问证书");
put("8", "养殖场备案证、动物防疫合格证");
put("9", "宠物美容师资格证");
put("10", "动物防疫合格证、寄养场所备案证");
}};
/**
* 根据ID获取经营范围名称
*/
public static String getScopeName(String scopeId) {
return SCOPE_MAP.get(scopeId);
}
/**
* 根据ID获取所需资质
*/
public static String getRequiredQualifications(String scopeId) {
return REQUIRED_QUALIFICATIONS.get(scopeId);
}
/**
* 获取所有经营范围选项
*/
public static Map<String, String> getAllScopes() {
return SCOPE_MAP;
}
/**
* 验证经营范围ID是否有效
*/
public static boolean isValidScopeId(String scopeId) {
return SCOPE_MAP.containsKey(scopeId);
}
}

112
chenhai-system/src/main/java/com/chenhai/vet/domain/VetArticleCategory.java

@ -1,112 +0,0 @@
package com.chenhai.vet.domain;
import com.chenhai.common.annotation.Excel;
import com.chenhai.common.core.domain.BaseEntity;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
/**
* 文章分类对象 vet_article_category
*/
public class VetArticleCategory extends BaseEntity {
private static final long serialVersionUID = 1L;
/** 分类ID */
private Long id;
/** 分类名称 */
@Excel(name = "分类名称")
private String name;
/** 分类描述 */
@Excel(name = "分类描述")
private String description;
/** 分类图标 */
private String icon;
/** 排序 */
@Excel(name = "排序")
private Integer sortOrder;
/** 状态(0正常 1停用) */
@Excel(name = "状态", readConverterExp = "0=正常,1=停用")
private String status;
/** 文章数量(统计字段) */
private Integer articleCount;
// getter/setter 方法...
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getIcon() {
return icon;
}
public void setIcon(String icon) {
this.icon = icon;
}
public Integer getSortOrder() {
return sortOrder;
}
public void setSortOrder(Integer sortOrder) {
this.sortOrder = sortOrder;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public Integer getArticleCount() {
return articleCount;
}
public void setArticleCount(Integer articleCount) {
this.articleCount = articleCount;
}
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("name", getName())
.append("description", getDescription())
.append("icon", getIcon())
.append("sortOrder", getSortOrder())
.append("status", getStatus())
.append("articleCount", getArticleCount())
.append("createBy", getCreateBy())
.append("createTime", getCreateTime())
.append("updateBy", getUpdateBy())
.append("updateTime", getUpdateTime())
.toString();
}
}

21
chenhai-system/src/main/java/com/chenhai/vet/domain/VetExperienceArticle.java

@ -65,7 +65,7 @@ public class VetExperienceArticle extends BaseEntity
private String categoryName; private String categoryName;
/** 标签(逗号分隔) */ /** 标签(逗号分隔) */
@Excel(name = "标签", readConverterExp = "逗=号分隔")
@Excel(name = "标签", dictType = "vet_experience_tag")
private String tags; private String tags;
/** 是否置顶(0否 1是) */ /** 是否置顶(0否 1是) */
@ -77,9 +77,26 @@ public class VetExperienceArticle extends BaseEntity
private String isFeatured; private String isFeatured;
/** 状态(0草稿 1已发布 2审核中 3已驳回) */ /** 状态(0草稿 1已发布 2审核中 3已驳回) */
@Excel(name = "状态", readConverterExp = "0=草稿,1=已发布,2=审核中,3=已驳回")
@Excel(name = "状态", dictType = "article_status")
private String status; private String status;
/** 审核状态(0待审核 1审核中 2审核通过 3审核驳回 4敏感内容驳回) */
private String auditStatus;
/** 审核意见 */
private String auditOpinion;
/** 审核时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date auditTime;
/** 审核人ID */
private Long auditorId;
/** 审核人姓名 */
private String auditorName;
/** 是否包含敏感词(0否 1是) */ /** 是否包含敏感词(0否 1是) */
@Excel(name = "是否包含敏感词", readConverterExp = "0=否,1=是") @Excel(name = "是否包含敏感词", readConverterExp = "0=否,1=是")
private String isSensitive; private String isSensitive;

64
chenhai-system/src/main/java/com/chenhai/vet/domain/VetProduct.java

@ -25,14 +25,15 @@ public class VetProduct extends BaseEntity
@Excel(name = "产品名称") @Excel(name = "产品名称")
private String name; private String name;
/** 产品类型:medicine-兽药/vaccine-疫苗/supplement-保健品 */
@Excel(name = "产品类型:medicine-兽药/vaccine-疫苗/supplement-保健品")
/** 产品类型(字典:vet_product_type) */
@Excel(name = "产品类型", dictType = "medicine_type")
private String type; private String type;
/** 产品分类 */
@Excel(name = "产品分类")
/** 产品分类(字典:vet_product_category) */
@Excel(name = "产品分类", dictType = "vet_product_category")
private String category; private String category;
/** 规格 */ /** 规格 */
@Excel(name = "规格") @Excel(name = "规格")
private String specification; private String specification;
@ -105,8 +106,8 @@ public class VetProduct extends BaseEntity
@Excel(name = "注意事项") @Excel(name = "注意事项")
private String precautions; private String precautions;
/** 状态:0-草稿/1-上架/2-下架 */
@Excel(name = "状态:0-草稿/1-上架/2-下架")
/** 上架状态(字典:vet_product_status) */
@Excel(name = "上架状态", dictType = "sys_publish_status")
private String status; private String status;
/** 删除标识:0-正常/1-删除 */ /** 删除标识:0-正常/1-删除 */
@ -131,6 +132,21 @@ public class VetProduct extends BaseEntity
@Excel(name = "更新时间", width = 30, dateFormat = "yyyy-MM-dd") @Excel(name = "更新时间", width = 30, dateFormat = "yyyy-MM-dd")
private Date updatedAt; private Date updatedAt;
/** 审核状态(字典:audit_status) */
@Excel(name = "审核状态", dictType = "audit_status")
private String auditStatus;
/** 审核意见 */
@Excel(name = "审核意见")
private String auditOpinion;
/** 审核人ID */
private Long auditUserId;
/** 审核时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date auditTime;
public void setId(Long id) public void setId(Long id)
{ {
this.id = id; this.id = id;
@ -411,6 +427,38 @@ public class VetProduct extends BaseEntity
return updatedAt; return updatedAt;
} }
public String getAuditStatus() {
return auditStatus;
}
public void setAuditStatus(String auditStatus) {
this.auditStatus = auditStatus;
}
public String getAuditOpinion() {
return auditOpinion;
}
public void setAuditOpinion(String auditOpinion) {
this.auditOpinion = auditOpinion;
}
public Long getAuditUserId() {
return auditUserId;
}
public void setAuditUserId(Long auditUserId) {
this.auditUserId = auditUserId;
}
public Date getAuditTime() {
return auditTime;
}
public void setAuditTime(Date auditTime) {
this.auditTime = auditTime;
}
@Override @Override
public String toString() { public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
@ -442,6 +490,10 @@ public class VetProduct extends BaseEntity
.append("userId", getUserId()) .append("userId", getUserId())
.append("createdAt", getCreatedAt()) .append("createdAt", getCreatedAt())
.append("updatedAt", getUpdatedAt()) .append("updatedAt", getUpdatedAt())
.append("auditStatus", getAuditStatus())
.append("auditOpinion", getAuditOpinion())
.append("auditUserId", getAuditUserId())
.append("auditTime", getAuditTime())
.toString(); .toString();
} }
} }

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

@ -2,16 +2,20 @@ 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.utils.StringUtils;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
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 org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.ArrayList;
/** /**
* 兽医资质对象 vet_qualification合并证书功能 * 兽医资质对象 vet_qualification合并证书功能
@ -22,6 +26,13 @@ import java.util.ArrayList;
public class VetQualification extends BaseEntity public class VetQualification extends BaseEntity
{ {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static final Logger log = LoggerFactory.getLogger(VetQualification.class);
private static final ObjectMapper objectMapper = new ObjectMapper();
private static final Object idLock = new Object();
private static long lastGeneratedId = System.currentTimeMillis();
private static final long MAX_SAFE_ID = 9007199254740991L; // JavaScript最大安全整数
private static final long MIN_SAFE_ID = 100000000L; // 最小8位数
/** 资质ID */ /** 资质ID */
private Long qualificationId; private Long qualificationId;
@ -60,7 +71,7 @@ public class VetQualification extends BaseEntity
@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;
/** 审核状态(0待审核 1通过 2拒绝 ) */
/** 审核状态(0待审核 1通过 2拒绝) */
@Excel(name = "审核状态", dictType = "qualification_shenhe") @Excel(name = "审核状态", dictType = "qualification_shenhe")
private String auditStatus; private String auditStatus;
@ -79,7 +90,8 @@ public class VetQualification extends BaseEntity
@Excel(name = "经营范围名称", dictType = "scope_names") @Excel(name = "经营范围名称", dictType = "scope_names")
private String scopeNames; private String scopeNames;
// 新增证书相关字段
/** 证书ID(数据库字段) */
private Long certId;
/** 证书名称 */ /** 证书名称 */
@Excel(name = "证书名称") @Excel(name = "证书名称")
@ -118,17 +130,376 @@ public class VetQualification extends BaseEntity
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date lastRemindTime; private Date lastRemindTime;
// 查询条件字段非数据库字段
/** 是否查询即将过期 */ /** 是否查询即将过期 */
private Boolean expiringOnly; private Boolean expiringOnly;
// 显示标签字段
/** 显示标签字段 */
private String qualificationTypeLabel; private String qualificationTypeLabel;
private String auditStatusLabel; private String auditStatusLabel;
private String scopeNamesLabel; private String scopeNamesLabel;
private String certStatusLabel; private String certStatusLabel;
// JSON 反序列化时使用的方法
/** 证书JSON字符串(数据库字段) */
private String certificatesJson;
/** 证书列表(从JSON解析而来) */
private transient List<CertificateInfo> certificateList;
/**
* 证书信息内部类
*/
public static class CertificateInfo {
private Long certificateId;
private String certName;
private String certificateNo;
@JsonFormat(pattern = "yyyy-MM-dd")
private Date issueDate;
@JsonFormat(pattern = "yyyy-MM-dd")
private Date expireDate;
private String issueOrg;
private String certificateFiles;
private String certStatus;
private String certStatusLabel;
private String auditStatus;
private String auditStatusLabel;
private Long qualificationId;
private String realName;
public CertificateInfo() {}
public CertificateInfo(String certName, String certificateNo, Date issueDate,
Date expireDate, String issueOrg, String certificateFiles) {
this.certName = certName;
this.certificateNo = certificateNo;
this.issueDate = issueDate;
this.expireDate = expireDate;
this.issueOrg = issueOrg;
this.certificateFiles = certificateFiles;
}
@JsonIgnore
public Long getCertId() {
return certificateId;
}
public void setCertId(Long certId) {
this.certificateId = certId;
}
public Long getCertificateId() {
return certificateId;
}
public void setCertificateId(Long certificateId) {
this.certificateId = certificateId;
}
public String getCertName() {
return certName;
}
public void setCertName(String certName) {
this.certName = certName;
}
public String getCertificateNo() {
return certificateNo;
}
public void setCertificateNo(String certificateNo) {
this.certificateNo = certificateNo;
}
public Date getIssueDate() {
return issueDate;
}
public void setIssueDate(Date issueDate) {
this.issueDate = issueDate;
}
public Date getExpireDate() {
return expireDate;
}
public void setExpireDate(Date expireDate) {
this.expireDate = expireDate;
}
public String getIssueOrg() {
return issueOrg;
}
public void setIssueOrg(String issueOrg) {
this.issueOrg = issueOrg;
}
public String getCertificateFiles() {
return certificateFiles;
}
public void setCertificateFiles(String certificateFiles) {
this.certificateFiles = certificateFiles;
}
public String getCertStatus() {
return certStatus;
}
public void setCertStatus(String certStatus) {
this.certStatus = certStatus;
}
public String getCertStatusLabel() {
return certStatusLabel;
}
public void setCertStatusLabel(String certStatusLabel) {
this.certStatusLabel = certStatusLabel;
}
public String getAuditStatus() {
return auditStatus;
}
public void setAuditStatus(String auditStatus) {
this.auditStatus = auditStatus;
}
public String getAuditStatusLabel() {
return auditStatusLabel;
}
public void setAuditStatusLabel(String auditStatusLabel) {
this.auditStatusLabel = auditStatusLabel;
}
public Long getQualificationId() {
return qualificationId;
}
public void setQualificationId(Long qualificationId) {
this.qualificationId = qualificationId;
}
public String getRealName() {
return realName;
}
public void setRealName(String realName) {
this.realName = realName;
}
}
/**
* 获取证书列表 - 从certificatesJson解析
*/
@JsonIgnore
public List<CertificateInfo> getCertificateList() {
if (certificateList == null) {
certificateList = new ArrayList<>();
if (StringUtils.isNotEmpty(certificatesJson)) {
try {
List<Map<String, Object>> certMaps = objectMapper.readValue(
certificatesJson,
objectMapper.getTypeFactory().constructCollectionType(List.class, Map.class)
);
for (Map<String, Object> certMap : certMaps) {
CertificateInfo cert = new CertificateInfo();
cert.setCertName((String) certMap.get("certName"));
cert.setCertificateNo((String) certMap.get("certificateNo"));
cert.setIssueOrg((String) certMap.get("issueOrg"));
cert.setCertificateFiles((String) certMap.get("certificateFiles"));
Object issueDateObj = certMap.get("issueDate");
Object expireDateObj = certMap.get("expireDate");
if (issueDateObj instanceof String) {
try {
cert.setIssueDate(new SimpleDateFormat("yyyy-MM-dd").parse((String) issueDateObj));
} catch (Exception e) {}
}
if (expireDateObj instanceof String) {
try {
cert.setExpireDate(new SimpleDateFormat("yyyy-MM-dd").parse((String) expireDateObj));
} catch (Exception e) {}
}
cert.setQualificationId(this.qualificationId);
cert.setRealName(this.realName);
Long certificateId = null;
Object certIdObj = certMap.get("certId");
if (certIdObj != null) {
try {
if (certIdObj instanceof Number) {
certificateId = ((Number) certIdObj).longValue();
} else if (certIdObj instanceof String) {
certificateId = Long.parseLong((String) certIdObj);
}
} catch (Exception e) {}
}
// 修复这里确保ID不为null且不为0否则使用稳定ID生成器
if (certificateId == null || certificateId == 0) {
certificateId = generateSafeCertificateId();
}
cert.setCertificateId(certificateId);
certificateList.add(cert);
}
} catch (Exception e) {
log.error("解析certificatesJson失败: {}", certificatesJson, e);
}
} else if (StringUtils.isNotEmpty(certName) || StringUtils.isNotEmpty(certificateNo)) {
CertificateInfo cert = new CertificateInfo();
cert.setCertName(certName);
cert.setCertificateNo(certificateNo);
cert.setIssueDate(issueDate);
cert.setExpireDate(expireDate);
cert.setIssueOrg(issueOrg);
cert.setCertificateFiles(certificateFiles);
cert.setQualificationId(this.qualificationId);
cert.setRealName(this.realName);
Long certificateId = this.certId;
if (certificateId == null || certificateId == 0) {
certificateId = generateSafeCertificateId();
}
cert.setCertificateId(certificateId);
certificateList.add(cert);
}
updateCertificateStatus();
}
return certificateList;
}
/**
* 生成安全的证书ID避免JavaScript精度丢失
*/
private Long generateSafeCertificateId() {
// 当前毫秒时间戳13位
long timestamp = System.currentTimeMillis();
// 取时间戳的后12位确保在安全范围内
long id = timestamp % 1000000000000L; // 12位数字
// 加上1亿确保是9位数以上
id += 100000000L;
// 双重检查确保不超过JavaScript安全上限
if (id > MAX_SAFE_ID) {
// 如果超过取模回到安全范围
id = id % (MAX_SAFE_ID - 100000000L) + 100000000L;
}
return id;
}
/**
* 设置证书列表并同步更新JSON字段
*/
public void setCertificateList(List<CertificateInfo> certificateList) {
this.certificateList = certificateList;
if (certificateList != null && !certificateList.isEmpty()) {
try {
List<Map<String, Object>> certMapList = new ArrayList<>();
for (CertificateInfo cert : certificateList) {
Map<String, Object> certMap = new HashMap<>();
certMap.put("certName", cert.getCertName());
certMap.put("certificateNo", cert.getCertificateNo());
certMap.put("issueOrg", cert.getIssueOrg());
certMap.put("certificateFiles", cert.getCertificateFiles());
if (cert.getIssueDate() != null) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
certMap.put("issueDate", sdf.format(cert.getIssueDate()));
}
if (cert.getExpireDate() != null) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
certMap.put("expireDate", sdf.format(cert.getExpireDate()));
}
// 确保每个证书都有ID
if (cert.getCertificateId() == null || cert.getCertificateId() == 0) {
cert.setCertificateId(generateSafeCertificateId());
}
certMap.put("certId", cert.getCertificateId());
if (cert.getCertStatus() != null) {
certMap.put("certStatus", cert.getCertStatus());
}
certMapList.add(certMap);
}
this.certificatesJson = objectMapper.writeValueAsString(certMapList);
// 更新主表字段
if (!certificateList.isEmpty()) {
CertificateInfo firstCert = certificateList.get(0);
this.certName = firstCert.getCertName();
this.certificateNo = firstCert.getCertificateNo();
this.issueDate = firstCert.getIssueDate();
this.expireDate = firstCert.getExpireDate();
this.issueOrg = firstCert.getIssueOrg();
this.certificateFiles = firstCert.getCertificateFiles();
this.certStatus = firstCert.getCertStatus();
if (firstCert.getCertificateId() != null) {
this.certId = firstCert.getCertificateId();
}
}
} catch (Exception e) {
log.error("序列化证书列表失败", e);
}
}
}
/**
* 更新证书状态
*/
public void updateCertificateStatus() {
if (certificateList != null) {
for (CertificateInfo cert : certificateList) {
if (cert.getExpireDate() != null) {
Date today = new Date();
Calendar calendar = Calendar.getInstance();
calendar.setTime(today);
calendar.add(Calendar.DAY_OF_YEAR, 30);
Date thirtyDaysLater = calendar.getTime();
if (cert.getExpireDate().before(today)) {
cert.setCertStatus("2");
cert.setCertStatusLabel("已过期");
} else if (cert.getExpireDate().before(thirtyDaysLater)) {
cert.setCertStatus("1");
cert.setCertStatusLabel("即将过期");
} else {
cert.setCertStatus("0");
cert.setCertStatusLabel("正常");
}
} else {
cert.setCertStatus("0");
cert.setCertStatusLabel("正常");
}
}
}
}
@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()) {
@ -138,7 +509,6 @@ public class VetQualification extends BaseEntity
} }
} }
// 序列化为 JSON 时使用的方法
@JsonProperty("scopeIds") @JsonProperty("scopeIds")
public List<String> getScopeIdsAsList() { public List<String> getScopeIdsAsList() {
if (scopeIds != null && !scopeIds.trim().isEmpty()) { if (scopeIds != null && !scopeIds.trim().isEmpty()) {
@ -147,29 +517,15 @@ public class VetQualification extends BaseEntity
return new ArrayList<>(); return new ArrayList<>();
} }
// 数据库操作的 getterJackson 忽略
@JsonIgnore @JsonIgnore
public String getScopeIds() { public String getScopeIds() {
return scopeIds; return scopeIds;
} }
// 数据库操作的 setter
public void setScopeIds(String scopeIds) { public void setScopeIds(String scopeIds) {
this.scopeIds = scopeIds; this.scopeIds = scopeIds;
} }
// 为了方便添加一个获取列表的方法不映射到 JSON
@JsonIgnore
public List<String> getScopeIdList() {
return getScopeIdsAsList();
}
// 为了方便添加一个设置列表的方法不映射到 JSON
public void setScopeIdList(List<String> scopeIdList) {
setScopeIdsFromJson(scopeIdList);
}
// getter setter 方法
public Long getQualificationId() { public Long getQualificationId() {
return qualificationId; return qualificationId;
} }
@ -274,7 +630,14 @@ public class VetQualification extends BaseEntity
this.scopeNames = scopeNames; this.scopeNames = scopeNames;
} }
// 新增证书字段的 getter setter
public Long getCertId() {
return certId;
}
public void setCertId(Long certId) {
this.certId = certId;
}
public String getCertName() { public String getCertName() {
return certName; return certName;
} }
@ -387,6 +750,66 @@ public class VetQualification extends BaseEntity
this.certStatusLabel = certStatusLabel; this.certStatusLabel = certStatusLabel;
} }
public String getCertificatesJson() {
return certificatesJson;
}
public void setCertificatesJson(String 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)
@ -404,6 +827,7 @@ public class VetQualification extends BaseEntity
.append("auditorId", getAuditorId()) .append("auditorId", getAuditorId())
.append("scopeIds", getScopeIds()) .append("scopeIds", getScopeIds())
.append("scopeNames", getScopeNames()) .append("scopeNames", getScopeNames())
.append("certId", getCertId())
.append("certName", getCertName()) .append("certName", getCertName())
.append("certType", getCertType()) .append("certType", getCertType())
.append("issueOrg", getIssueOrg()) .append("issueOrg", getIssueOrg())
@ -418,6 +842,8 @@ 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();
} }
} }

13
chenhai-system/src/main/java/com/chenhai/vet/mapper/VetArticleCategoryMapper.java

@ -1,13 +0,0 @@
package com.chenhai.vet.mapper;
import com.chenhai.vet.domain.VetArticleCategory;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface VetArticleCategoryMapper {
/**
* 这个方法名必须和XML中的id完全一致
*/
List<VetArticleCategory> selectVetArticleCategoryList(VetArticleCategory vetArticleCategory);
}

54
chenhai-system/src/main/java/com/chenhai/vet/mapper/VetExperienceArticleMapper.java

@ -2,21 +2,20 @@ package com.chenhai.vet.mapper;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import com.chenhai.vet.domain.VetExperienceArticle; import com.chenhai.vet.domain.VetExperienceArticle;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
/** /**
* 兽医经验文章Mapper接口 * 兽医经验文章Mapper接口
*
*
* @author ruoyi * @author ruoyi
* @date 2026-01-06 * @date 2026-01-06
*/ */
public interface VetExperienceArticleMapper
public interface VetExperienceArticleMapper
{ {
/** /**
* 查询兽医经验文章 * 查询兽医经验文章
*
*
* @param id 兽医经验文章主键 * @param id 兽医经验文章主键
* @return 兽医经验文章 * @return 兽医经验文章
*/ */
@ -24,7 +23,7 @@ public interface VetExperienceArticleMapper
/** /**
* 查询兽医经验文章列表 * 查询兽医经验文章列表
*
*
* @param vetExperienceArticle 兽医经验文章 * @param vetExperienceArticle 兽医经验文章
* @return 兽医经验文章集合 * @return 兽医经验文章集合
*/ */
@ -32,7 +31,7 @@ public interface VetExperienceArticleMapper
/** /**
* 新增兽医经验文章 * 新增兽医经验文章
*
*
* @param vetExperienceArticle 兽医经验文章 * @param vetExperienceArticle 兽医经验文章
* @return 结果 * @return 结果
*/ */
@ -40,7 +39,7 @@ public interface VetExperienceArticleMapper
/** /**
* 修改兽医经验文章 * 修改兽医经验文章
*
*
* @param vetExperienceArticle 兽医经验文章 * @param vetExperienceArticle 兽医经验文章
* @return 结果 * @return 结果
*/ */
@ -48,7 +47,7 @@ public interface VetExperienceArticleMapper
/** /**
* 删除兽医经验文章 * 删除兽医经验文章
*
*
* @param id 兽医经验文章主键 * @param id 兽医经验文章主键
* @return 结果 * @return 结果
*/ */
@ -56,39 +55,50 @@ public interface VetExperienceArticleMapper
/** /**
* 批量删除兽医经验文章 * 批量删除兽医经验文章
*
*
* @param ids 需要删除的数据主键集合 * @param ids 需要删除的数据主键集合
* @return 结果 * @return 结果
*/ */
public int deleteVetExperienceArticleByIds(Long[] ids); public int deleteVetExperienceArticleByIds(Long[] ids);
/** /**
* 根据条件查询文章支持排序和限制条数
* 根据条件查询文章列表论坛专用
*
* @param params 查询参数
* @return 文章集合
*/ */
List<VetExperienceArticle> selectArticlesByCondition(Map<String, Object> params);
List<VetExperienceArticle> searchArticles(@Param("keyword") String keyword,
@Param("status") String status);
public List<VetExperienceArticle> selectArticlesByCondition(Map<String, Object> params);
/** /**
* 增加浏览数 * 增加浏览数
*
* @param id 文章主键
* @return 结果
*/ */
int incrementViewCount(@Param("id") Long id);
public int incrementViewCount(Long id);
/** /**
* 增加点赞数 * 增加点赞数
*
* @param id 文章主键
* @return 结果
*/ */
int incrementLikeCount(@Param("id") Long id);
public int incrementLikeCount(Long id);
/** /**
* 增加收藏数 * 增加收藏数
*
* @param id 文章主键
* @return 结果
*/ */
int incrementCollectCount(@Param("id") Long id);
public int incrementCollectCount(Long id);
/** /**
* 根据标签筛选文章
* 搜索文章
*
* @param keyword 关键词
* @param status 文章状态
* @return 文章集合
*/ */
List<VetExperienceArticle> selectArticlesByTag(@Param("tag") String tag);
}
public List<VetExperienceArticle> searchArticles(@Param("keyword") String keyword, @Param("status") String status);
}

4
chenhai-system/src/main/java/com/chenhai/vet/mapper/VetQualificationMapper.java

@ -2,8 +2,10 @@ package com.chenhai.vet.mapper;
import com.chenhai.vet.domain.VetQualification; import com.chenhai.vet.domain.VetQualification;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* 兽医资质Mapper接口 * 兽医资质Mapper接口
@ -67,4 +69,6 @@ public interface VetQualificationMapper
*/ */
List<VetQualification> selectQualificationsByUserId(Long userId); List<VetQualification> selectQualificationsByUserId(Long userId);
Map<String, Object> selectCertificateByCertId(@Param("certId") Long certId, @Param("userId") Long userId);
} }

68
chenhai-system/src/main/java/com/chenhai/vet/service/IVetExperienceArticleService.java

@ -2,20 +2,19 @@ package com.chenhai.vet.service;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import com.chenhai.vet.domain.VetExperienceArticle; import com.chenhai.vet.domain.VetExperienceArticle;
/** /**
* 兽医经验文章Service接口 * 兽医经验文章Service接口
*
*
* @author ruoyi * @author ruoyi
* @date 2026-01-06 * @date 2026-01-06
*/ */
public interface IVetExperienceArticleService
public interface IVetExperienceArticleService
{ {
/** /**
* 查询兽医经验文章 * 查询兽医经验文章
*
*
* @param id 兽医经验文章主键 * @param id 兽医经验文章主键
* @return 兽医经验文章 * @return 兽医经验文章
*/ */
@ -23,7 +22,7 @@ public interface IVetExperienceArticleService
/** /**
* 查询兽医经验文章列表 * 查询兽医经验文章列表
*
*
* @param vetExperienceArticle 兽医经验文章 * @param vetExperienceArticle 兽医经验文章
* @return 兽医经验文章集合 * @return 兽医经验文章集合
*/ */
@ -31,7 +30,7 @@ public interface IVetExperienceArticleService
/** /**
* 新增兽医经验文章 * 新增兽医经验文章
*
*
* @param vetExperienceArticle 兽医经验文章 * @param vetExperienceArticle 兽医经验文章
* @return 结果 * @return 结果
*/ */
@ -39,7 +38,7 @@ public interface IVetExperienceArticleService
/** /**
* 修改兽医经验文章 * 修改兽医经验文章
*
*
* @param vetExperienceArticle 兽医经验文章 * @param vetExperienceArticle 兽医经验文章
* @return 结果 * @return 结果
*/ */
@ -47,7 +46,7 @@ public interface IVetExperienceArticleService
/** /**
* 批量删除兽医经验文章 * 批量删除兽医经验文章
*
*
* @param ids 需要删除的兽医经验文章主键集合 * @param ids 需要删除的兽医经验文章主键集合
* @return 结果 * @return 结果
*/ */
@ -55,65 +54,82 @@ public interface IVetExperienceArticleService
/** /**
* 删除兽医经验文章信息 * 删除兽医经验文章信息
*
*
* @param id 兽医经验文章主键 * @param id 兽医经验文章主键
* @return 结果 * @return 结果
*/ */
public int deleteVetExperienceArticleById(Long id); public int deleteVetExperienceArticleById(Long id);
/**
* 获取推荐文章精选+置顶
*/
List<VetExperienceArticle> selectFeaturedArticles(Integer limit);
List<VetExperienceArticle> searchArticles(String keyword);
/** /**
* 获取最新文章 * 获取最新文章
*
* @param limit 限制数量
* @return 文章集合
*/ */
List<VetExperienceArticle> selectLatestArticles(Integer limit); List<VetExperienceArticle> selectLatestArticles(Integer limit);
/** /**
* 获取热门文章按浏览数排序 * 获取热门文章按浏览数排序
*
* @param limit 限制数量
* @return 文章集合
*/ */
List<VetExperienceArticle> selectHotArticles(Integer limit); List<VetExperienceArticle> selectHotArticles(Integer limit);
/** /**
* 根据兽医ID获取文章
* 根据用户ID获取文章
*
* @param userId 用户ID
* @param limit 限制数量
* @return 文章集合
*/ */
List<VetExperienceArticle> selectArticlesByVetId(Long vetId, Integer limit);
List<VetExperienceArticle> selectArticlesByUserId(Long userId, Integer limit);
/** /**
* 获取相关文章 * 获取相关文章
*
* @param excludeId 排除的文章ID
* @param categoryId 分类ID
* @param limit 限制数量
* @return 文章集合
*/ */
List<VetExperienceArticle> selectRelatedArticles(Long excludeId, Long categoryId, Integer limit); List<VetExperienceArticle> selectRelatedArticles(Long excludeId, Long categoryId, Integer limit);
/** /**
* 增加浏览数 * 增加浏览数
*
* @param id 文章ID
* @return 结果
*/ */
int incrementViewCount(Long id); int incrementViewCount(Long id);
/** /**
* 增加点赞数 * 增加点赞数
*
* @param id 文章ID
* @return 结果
*/ */
int incrementLikeCount(Long id); int incrementLikeCount(Long id);
/** /**
* 增加收藏数 * 增加收藏数
*
* @param id 文章ID
* @return 结果
*/ */
int incrementCollectCount(Long id); int incrementCollectCount(Long id);
/** /**
* 获取论坛统计信息 * 获取论坛统计信息
*
* @return 统计信息
*/ */
Map<String, Object> selectForumStatistics(); Map<String, Object> selectForumStatistics();
/** /**
* 获取热门标签
* 搜索文章
*
* @param keyword 关键词
* @return 文章集合
*/ */
/* List<Map<String, Object>> selectHotTags(Integer limit);*/
List<VetExperienceArticle> selectArticlesByTag(String tag);
List<VetExperienceArticle> selectMyCollections(Long userId);
}
List<VetExperienceArticle> searchArticles(String keyword);
}

43
chenhai-system/src/main/java/com/chenhai/vet/service/IVetProductService.java

@ -59,4 +59,47 @@ public interface IVetProductService
*/ */
public int deleteVetProductById(Long id); public int deleteVetProductById(Long id);
/**
* 提交审核
*
* @param id 产品ID
* @return 结果
*/
public int submitForAudit(Long id);
/**
* 审核产品
*
* @param id 产品ID
* @param auditStatus 审核状态
* @param auditOpinion 审核意见
* @param auditUserId 审核人ID
* @return 结果
*/
public int auditProduct(Long id, String auditStatus, String auditOpinion, Long auditUserId);
/**
* 上架产品
*
* @param id 产品ID
* @return 结果
*/
public int publishProduct(Long id);
/**
* 下架产品
*
* @param id 产品ID
* @return 结果
*/
public int offlineProduct(Long id);
/**
* 取消审核
*
* @param id 产品ID
* @return 结果
*/
public int cancelAudit(Long id);
} }

10
chenhai-system/src/main/java/com/chenhai/vet/service/IVetQualificationService.java

@ -88,4 +88,14 @@ public interface IVetQualificationService
*/ */
Map<String, Object> getCertificateStatistics(Long userId); Map<String, Object> getCertificateStatistics(Long userId);
/**
* 提交资质审核新方法处理复杂数据结构
*/
int submitQualification(Map<String, Object> requestData);
/**
* 根据证书ID查询证书及所属资质信息
*/
Map<String, Object> selectCertificateWithQualificationByCertId(Long certId, Long userId);
} }

212
chenhai-system/src/main/java/com/chenhai/vet/service/impl/VetExperienceArticleServiceImpl.java

@ -1,8 +1,6 @@
package com.chenhai.vet.service.impl; package com.chenhai.vet.service.impl;
import java.util.*; import java.util.*;
import java.util.stream.Collectors;
import com.chenhai.common.utils.DateUtils; import com.chenhai.common.utils.DateUtils;
import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageHelper;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -13,19 +11,19 @@ import com.chenhai.vet.service.IVetExperienceArticleService;
/** /**
* 兽医经验文章Service业务层处理 * 兽医经验文章Service业务层处理
*
*
* @author ruoyi * @author ruoyi
* @date 2026-01-06 * @date 2026-01-06
*/ */
@Service @Service
public class VetExperienceArticleServiceImpl implements IVetExperienceArticleService
public class VetExperienceArticleServiceImpl implements IVetExperienceArticleService
{ {
@Autowired @Autowired
private VetExperienceArticleMapper vetExperienceArticleMapper; private VetExperienceArticleMapper vetExperienceArticleMapper;
/** /**
* 查询兽医经验文章 * 查询兽医经验文章
*
*
* @param id 兽医经验文章主键 * @param id 兽医经验文章主键
* @return 兽医经验文章 * @return 兽医经验文章
*/ */
@ -37,7 +35,7 @@ public class VetExperienceArticleServiceImpl implements IVetExperienceArticleSer
/** /**
* 查询兽医经验文章列表 * 查询兽医经验文章列表
*
*
* @param vetExperienceArticle 兽医经验文章 * @param vetExperienceArticle 兽医经验文章
* @return 兽医经验文章 * @return 兽医经验文章
*/ */
@ -49,7 +47,7 @@ public class VetExperienceArticleServiceImpl implements IVetExperienceArticleSer
/** /**
* 新增兽医经验文章 * 新增兽医经验文章
*
*
* @param vetExperienceArticle 兽医经验文章 * @param vetExperienceArticle 兽医经验文章
* @return 结果 * @return 结果
*/ */
@ -62,7 +60,7 @@ public class VetExperienceArticleServiceImpl implements IVetExperienceArticleSer
/** /**
* 修改兽医经验文章 * 修改兽医经验文章
*
*
* @param vetExperienceArticle 兽医经验文章 * @param vetExperienceArticle 兽医经验文章
* @return 结果 * @return 结果
*/ */
@ -75,7 +73,7 @@ public class VetExperienceArticleServiceImpl implements IVetExperienceArticleSer
/** /**
* 批量删除兽医经验文章 * 批量删除兽医经验文章
*
*
* @param ids 需要删除的兽医经验文章主键 * @param ids 需要删除的兽医经验文章主键
* @return 结果 * @return 结果
*/ */
@ -87,7 +85,7 @@ public class VetExperienceArticleServiceImpl implements IVetExperienceArticleSer
/** /**
* 删除兽医经验文章信息 * 删除兽医经验文章信息
*
*
* @param id 兽医经验文章主键 * @param id 兽医经验文章主键
* @return 结果 * @return 结果
*/ */
@ -97,190 +95,178 @@ public class VetExperienceArticleServiceImpl implements IVetExperienceArticleSer
return vetExperienceArticleMapper.deleteVetExperienceArticleById(id); return vetExperienceArticleMapper.deleteVetExperienceArticleById(id);
} }
@Override
public List<VetExperienceArticle> selectFeaturedArticles(Integer limit) {
PageHelper.clearPage();
Map<String, Object> params = new HashMap<>();
params.put("status", 1);
params.put("isFeatured", 1);
params.put("limit", limit != null ? limit : 8);
return vetExperienceArticleMapper.selectArticlesByCondition(params);
}
@Override
public List<VetExperienceArticle> searchArticles(String keyword) {
PageHelper.clearPage();
Map<String, Object> params = new HashMap<>();
params.put("keyword", keyword);
params.put("status", 1);
return vetExperienceArticleMapper.selectArticlesByCondition(params);
}
/**
* 获取最新文章
*
* @param limit 限制数量
* @return 文章集合
*/
@Override @Override
public List<VetExperienceArticle> selectLatestArticles(Integer limit) { public List<VetExperienceArticle> selectLatestArticles(Integer limit) {
PageHelper.clearPage(); PageHelper.clearPage();
Map<String, Object> params = new HashMap<>(); Map<String, Object> params = new HashMap<>();
params.put("status", 1);
params.put("status", "1");
params.put("orderBy", "publish_time"); params.put("orderBy", "publish_time");
params.put("orderType", "desc"); params.put("orderType", "desc");
params.put("limit", limit != null ? limit : 10); params.put("limit", limit != null ? limit : 10);
return vetExperienceArticleMapper.selectArticlesByCondition(params); return vetExperienceArticleMapper.selectArticlesByCondition(params);
} }
/**
* 获取热门文章按浏览数排序
*
* @param limit 限制数量
* @return 文章集合
*/
@Override @Override
public List<VetExperienceArticle> selectHotArticles(Integer limit) { public List<VetExperienceArticle> selectHotArticles(Integer limit) {
PageHelper.clearPage(); PageHelper.clearPage();
Map<String, Object> params = new HashMap<>(); Map<String, Object> params = new HashMap<>();
params.put("status", 1);
params.put("status", "1");
params.put("orderBy", "view_count"); params.put("orderBy", "view_count");
params.put("orderType", "desc"); params.put("orderType", "desc");
params.put("limit", limit != null ? limit : 10); params.put("limit", limit != null ? limit : 10);
return vetExperienceArticleMapper.selectArticlesByCondition(params); return vetExperienceArticleMapper.selectArticlesByCondition(params);
} }
/**
* 根据用户ID获取文章
*
* @param userId 用户ID
* @param limit 限制数量
* @return 文章集合
*/
@Override @Override
public List<VetExperienceArticle> selectArticlesByVetId(Long vetId, Integer limit) {
public List<VetExperienceArticle> selectArticlesByUserId(Long userId, Integer limit) {
PageHelper.clearPage(); PageHelper.clearPage();
Map<String, Object> params = new HashMap<>(); Map<String, Object> params = new HashMap<>();
params.put("vetId", vetId);
params.put("status", 1);
params.put("status", "1");
params.put("userId", userId);
params.put("orderBy", "publish_time"); params.put("orderBy", "publish_time");
params.put("orderType", "desc"); params.put("orderType", "desc");
params.put("limit", limit != null ? limit : 5); params.put("limit", limit != null ? limit : 5);
return vetExperienceArticleMapper.selectArticlesByCondition(params); return vetExperienceArticleMapper.selectArticlesByCondition(params);
} }
/**
* 获取相关文章
*
* @param excludeId 排除的文章ID
* @param categoryId 分类ID
* @param limit 限制数量
* @return 文章集合
*/
@Override @Override
public List<VetExperienceArticle> selectRelatedArticles(Long excludeId, Long categoryId, Integer limit) { public List<VetExperienceArticle> selectRelatedArticles(Long excludeId, Long categoryId, Integer limit) {
PageHelper.clearPage(); PageHelper.clearPage();
Map<String, Object> params = new HashMap<>(); Map<String, Object> params = new HashMap<>();
params.put("status", "1");
params.put("excludeId", excludeId); params.put("excludeId", excludeId);
params.put("categoryId", categoryId); params.put("categoryId", categoryId);
params.put("status", 1);
params.put("orderBy", "publish_time"); params.put("orderBy", "publish_time");
params.put("orderType", "desc"); params.put("orderType", "desc");
params.put("limit", limit != null ? limit : 4); params.put("limit", limit != null ? limit : 4);
return vetExperienceArticleMapper.selectArticlesByCondition(params); return vetExperienceArticleMapper.selectArticlesByCondition(params);
} }
/**
* 增加浏览数
*
* @param id 文章ID
* @return 结果
*/
@Override @Override
public int incrementViewCount(Long id) { public int incrementViewCount(Long id) {
return vetExperienceArticleMapper.incrementViewCount(id); return vetExperienceArticleMapper.incrementViewCount(id);
} }
/**
* 增加点赞数
*
* @param id 文章ID
* @return 结果
*/
@Override @Override
public int incrementLikeCount(Long id) { public int incrementLikeCount(Long id) {
return vetExperienceArticleMapper.incrementLikeCount(id); return vetExperienceArticleMapper.incrementLikeCount(id);
} }
/**
* 增加收藏数
*
* @param id 文章ID
* @return 结果
*/
@Override @Override
public int incrementCollectCount(Long id) { public int incrementCollectCount(Long id) {
return vetExperienceArticleMapper.incrementCollectCount(id); return vetExperienceArticleMapper.incrementCollectCount(id);
} }
/**
* 获取论坛统计信息
*
* @return 统计信息
*/
@Override @Override
public Map<String, Object> selectForumStatistics() { public Map<String, Object> selectForumStatistics() {
PageHelper.clearPage();
Map<String, Object> statistics = new HashMap<>(); Map<String, Object> statistics = new HashMap<>();
// 获取文章总数
VetExperienceArticle countQuery = new VetExperienceArticle();
countQuery.setStatus("1");
List<VetExperienceArticle> allArticles = vetExperienceArticleMapper.selectVetExperienceArticleList(countQuery);
// 获取所有已发布文章
VetExperienceArticle query = new VetExperienceArticle();
query.setStatus("1");
List<VetExperienceArticle> allArticles = vetExperienceArticleMapper.selectVetExperienceArticleList(query);
// 统计文章总数
statistics.put("totalArticles", allArticles.size()); statistics.put("totalArticles", allArticles.size());
// 获取兽医总数去重
Set<Long> vetIds = new HashSet<>();
// 统计作者总数去重
Set<Long> authorIds = new HashSet<>();
for (VetExperienceArticle article : allArticles) { for (VetExperienceArticle article : allArticles) {
vetIds.add(article.getUserId());
if (article.getUserId() != null) {
authorIds.add(article.getUserId());
}
} }
statistics.put("totalVets", vetIds.size());
statistics.put("totalAuthors", authorIds.size());
// 获取总浏览数
// 统计总浏览数
int totalViews = 0; int totalViews = 0;
for (VetExperienceArticle article : allArticles) { for (VetExperienceArticle article : allArticles) {
totalViews += article.getViewCount() != null ? article.getViewCount() : 0; totalViews += article.getViewCount() != null ? article.getViewCount() : 0;
} }
statistics.put("totalViews", totalViews); statistics.put("totalViews", totalViews);
// 获取总点赞数
// 统计总点赞数
int totalLikes = 0; int totalLikes = 0;
for (VetExperienceArticle article : allArticles) { for (VetExperienceArticle article : allArticles) {
totalLikes += article.getLikeCount() != null ? article.getLikeCount() : 0; totalLikes += article.getLikeCount() != null ? article.getLikeCount() : 0;
} }
statistics.put("totalLikes", totalLikes); statistics.put("totalLikes", totalLikes);
// 统计总收藏数
int totalCollects = 0;
for (VetExperienceArticle article : allArticles) {
totalCollects += article.getCollectCount() != null ? article.getCollectCount() : 0;
}
statistics.put("totalCollects", totalCollects);
return statistics; return statistics;
} }
/** /**
* 根据标签筛选文章简单实现
* 搜索文章
*
* @param keyword 关键词
* @return 文章集合
*/ */
@Override @Override
public List<VetExperienceArticle> selectArticlesByTag(String tag) {
if (tag == null || tag.trim().isEmpty()) {
return new ArrayList<>();
}
return vetExperienceArticleMapper.selectArticlesByTag(tag.trim());
}
/* @Override
public List<Map<String, Object>> selectHotTags(Integer limit) {
// 从所有文章中提取标签并统计热度
VetExperienceArticle query = new VetExperienceArticle();
query.setStatus("1");
List<VetExperienceArticle> allArticles = vetExperienceArticleMapper.selectVetExperienceArticleList(query);
Map<String, Integer> tagCount = new HashMap<>();
for (VetExperienceArticle article : allArticles) {
if (article.getTags() != null && !article.getTags().trim().isEmpty()) {
String[] tags = article.getTags().split(",");
for (String tag : tags) {
tag = tag.trim();
if (!tag.isEmpty()) {
tagCount.put(tag, tagCount.getOrDefault(tag, 0) + 1);
}
}
}
}
// 转换为List并按热度排序
List<Map<String, Object>> hotTags = new ArrayList<>();
tagCount.entrySet().stream()
.sorted(Map.Entry.<String, Integer>comparingByValue().reversed())
.limit(limit != null ? limit : 15)
.forEach(entry -> {
Map<String, Object> tagInfo = new HashMap<>();
tagInfo.put("name", entry.getKey());
tagInfo.put("count", entry.getValue());
hotTags.add(tagInfo);
});
return hotTags;
}*/
@Override
public List<VetExperienceArticle> selectMyCollections(Long userId) {
// 这里需要根据实际业务逻辑实现
// 由于你的系统中没有专门的收藏表这里提供一个临时方案
// 方案1模拟数据临时使用
VetExperienceArticle query = new VetExperienceArticle();
query.setStatus("1"); // 只查询已发布的文章
List<VetExperienceArticle> allArticles = vetExperienceArticleMapper.selectVetExperienceArticleList(query);
// 临时逻辑假设收藏的文章是点赞数较高的文章
return allArticles.stream()
.sorted((a1, a2) -> {
Integer likes1 = a1.getLikeCount() != null ? a1.getLikeCount() : 0;
Integer likes2 = a2.getLikeCount() != null ? a2.getLikeCount() : 0;
return likes2.compareTo(likes1);
})
.limit(20) // 限制数量
.collect(Collectors.toList());
public List<VetExperienceArticle> searchArticles(String keyword) {
PageHelper.clearPage();
Map<String, Object> params = new HashMap<>();
params.put("status", "1");
params.put("keyword", keyword);
params.put("orderBy", "publish_time");
params.put("orderType", "desc");
params.put("limit", 20);
return vetExperienceArticleMapper.selectArticlesByCondition(params);
} }
}
}

162
chenhai-system/src/main/java/com/chenhai/vet/service/impl/VetProductServiceImpl.java

@ -1,12 +1,16 @@
package com.chenhai.vet.service.impl; package com.chenhai.vet.service.impl;
import java.util.Date;
import java.util.List; import java.util.List;
import com.chenhai.common.utils.SecurityUtils;
import com.chenhai.vet.domain.VetTrainingVideo;
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.vet.mapper.VetProductMapper; import com.chenhai.vet.mapper.VetProductMapper;
import com.chenhai.vet.domain.VetProduct; import com.chenhai.vet.domain.VetProduct;
import com.chenhai.vet.service.IVetProductService; import com.chenhai.vet.service.IVetProductService;
import org.springframework.transaction.annotation.Transactional;
/** /**
* 兽医产品信息Service业务层处理 * 兽医产品信息Service业务层处理
@ -50,11 +54,11 @@ public class VetProductServiceImpl implements IVetProductService
* @param vetProduct 兽医产品信息 * @param vetProduct 兽医产品信息
* @return 结果 * @return 结果
*/ */
@Override
/* @Override
public int insertVetProduct(VetProduct vetProduct) public int insertVetProduct(VetProduct vetProduct)
{ {
return vetProductMapper.insertVetProduct(vetProduct); return vetProductMapper.insertVetProduct(vetProduct);
}
}*/
/** /**
* 修改兽医产品信息 * 修改兽医产品信息
@ -91,4 +95,158 @@ public class VetProductServiceImpl implements IVetProductService
{ {
return vetProductMapper.deleteVetProductById(id); return vetProductMapper.deleteVetProductById(id);
} }
/**
* 提交审核
*/
@Override
@Transactional
public int submitForAudit(Long id) {
VetProduct product = vetProductMapper.selectVetProductById(id);
if (product == null) {
throw new RuntimeException("产品不存在");
}
// 只有草稿状态的产品可以提交审核
if (!"0".equals(product.getStatus())) {
throw new RuntimeException("只有草稿状态的产品可以提交审核");
}
// 检查当前审核状态 - 只有待审核状态可以提交审核
String currentAuditStatus = product.getAuditStatus();
if (!"0".equals(currentAuditStatus)) {
throw new RuntimeException("只有待审核状态的产品可以提交审核");
}
product.setAuditStatus("1"); // 设置为审核中状态
product.setUpdatedAt(new Date());
return vetProductMapper.updateVetProduct(product);
}
/**
* 审核产品
*/
@Override
@Transactional
public int auditProduct(Long id, String auditStatus, String auditOpinion, Long auditUserId) {
VetProduct product = vetProductMapper.selectVetProductById(id);
if (product == null) {
throw new RuntimeException("产品不存在");
}
// 只有审核中状态可以完成审核
if (!"1".equals(product.getAuditStatus())) {
throw new RuntimeException("只有审核中状态的产品可以完成审核");
}
// 验证审核状态的合法性2,3
if (!("2".equals(auditStatus) || "3".equals(auditStatus))) {
throw new RuntimeException("无效的审核状态,只能设置为审核通过或审核拒绝");
}
product.setAuditStatus(auditStatus);
product.setAuditOpinion(auditOpinion);
product.setAuditUserId(auditUserId);
product.setAuditTime(new Date());
product.setUpdatedAt(new Date());
return vetProductMapper.updateVetProduct(product);
}
/**
* 上架产品
*/
@Override
@Transactional
public int publishProduct(Long id) {
VetProduct product = vetProductMapper.selectVetProductById(id);
if (product == null) {
throw new RuntimeException("产品不存在");
}
// 只有审核通过且草稿状态的产品可以上架
if (!"2".equals(product.getAuditStatus())) {
throw new RuntimeException("只有审核通过的产品可以上架");
}
if (!"0".equals(product.getStatus())) {
throw new RuntimeException("产品状态不正确");
}
product.setStatus("1"); // 上架
product.setUpdatedAt(new Date());
return vetProductMapper.updateVetProduct(product);
}
/**
* 下架产品
*/
@Override
@Transactional
public int offlineProduct(Long id) {
VetProduct product = vetProductMapper.selectVetProductById(id);
if (product == null) {
throw new RuntimeException("产品不存在");
}
// 只有已上架的产品可以下架
if (!"1".equals(product.getStatus())) {
throw new RuntimeException("只有已上架的产品可以下架");
}
product.setStatus("0"); // 下架
product.setUpdatedAt(new Date());
return vetProductMapper.updateVetProduct(product);
}
/**
* 取消审核
*/
@Override
@Transactional
public int cancelAudit(Long id) {
VetProduct product = vetProductMapper.selectVetProductById(id);
if (product == null) {
throw new RuntimeException("产品不存在");
}
// 只有草稿状态且审核中状态可以取消审核
if (!"0".equals(product.getStatus()) || !"1".equals(product.getAuditStatus())) {
throw new RuntimeException("只有草稿且审核中状态的产品可以取消审核");
}
product.setAuditStatus("0"); // 设置回待审核状态
product.setAuditOpinion(null);
product.setAuditUserId(null);
product.setAuditTime(null);
product.setUpdatedAt(new Date());
return vetProductMapper.updateVetProduct(product);
}
// 修改 insertVetProduct 方法修改默认值设置
@Override
@Transactional
public int insertVetProduct(VetProduct vetProduct)
{
// 设置默认值
vetProduct.setStatus("0"); // 默认草稿状态
vetProduct.setAuditStatus("0"); // 新增产品默认待审核状态
vetProduct.setIsDeleted(0);
vetProduct.setCreatedAt(new Date());
vetProduct.setUpdatedAt(new Date());
// 设置当前用户ID
try {
Long userId = SecurityUtils.getUserId();
vetProduct.setUserId(userId);
} catch (Exception e) {
vetProduct.setUserId(1L);
}
return vetProductMapper.insertVetProduct(vetProduct);
}
} }

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

34
chenhai-system/src/main/resources/mapper/vet/VetArticleCategoryMapper.xml

@ -1,34 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.chenhai.vet.mapper.VetArticleCategoryMapper">
<resultMap type="com.chenhai.vet.domain.VetArticleCategory" id="VetArticleCategoryResult">
<result property="id" column="id"/>
<result property="name" column="name"/>
<result property="description" column="description"/>
<result property="icon" column="icon"/>
<result property="sortOrder" column="sort_order"/>
<result property="status" column="status"/>
<result property="articleCount" column="article_count"/>
<result property="createTime" column="create_time"/>
<result property="updateTime" column="update_time"/>
</resultMap>
<sql id="selectVetArticleCategoryVo">
select id, name, description, icon, sort_order, status, create_time, update_time
from vet_article_category
</sql>
<!-- 这个方法名必须和Mapper接口中的方法名完全一致 -->
<select id="selectVetArticleCategoryList" parameterType="com.chenhai.vet.domain.VetArticleCategory" resultMap="VetArticleCategoryResult">
<include refid="selectVetArticleCategoryVo"/>
<where>
<if test="name != null and name != ''"> and name like concat('%', #{name}, '%')</if>
<if test="status != null and status != ''"> and status = #{status}</if>
</where>
order by sort_order asc
</select>
</mapper>

90
chenhai-system/src/main/resources/mapper/vet/VetExperienceArticleMapper.xml

@ -32,16 +32,19 @@
</resultMap> </resultMap>
<sql id="selectVetExperienceArticleVo"> <sql id="selectVetExperienceArticleVo">
select id, title, content, summary, cover_image, images, user_id, vet_name, vet_avatar, vet_title, category_id, category_name, tags, view_count, like_count, collect_count, is_top, is_featured, status, is_sensitive, sensitive_words, publish_time, create_time, update_time
select id, title, content, summary, cover_image, images, user_id, vet_name, vet_avatar, vet_title,
category_id, category_name, tags, view_count, like_count, collect_count,
is_top, is_featured, status, is_sensitive, sensitive_words, publish_time, create_time, update_time
from vet_experience_article from vet_experience_article
</sql> </sql>
<!-- 查询兽医经验文章 -->
<select id="selectVetExperienceArticleById" parameterType="Long" resultMap="VetExperienceArticleResult"> <select id="selectVetExperienceArticleById" parameterType="Long" resultMap="VetExperienceArticleResult">
<include refid="selectVetExperienceArticleVo"/> <include refid="selectVetExperienceArticleVo"/>
where id = #{id} where id = #{id}
</select> </select>
<!-- 查询兽医经验文章列表 -->
<select id="selectVetExperienceArticleList" parameterType="VetExperienceArticle" resultMap="VetExperienceArticleResult"> <select id="selectVetExperienceArticleList" parameterType="VetExperienceArticle" resultMap="VetExperienceArticleResult">
<include refid="selectVetExperienceArticleVo"/> <include refid="selectVetExperienceArticleVo"/>
<where> <where>
@ -51,26 +54,23 @@
<if test="categoryId != null"> and category_id = #{categoryId}</if> <if test="categoryId != null"> and category_id = #{categoryId}</if>
<if test="categoryName != null and categoryName != ''"> and category_name like concat('%', #{categoryName}, '%')</if> <if test="categoryName != null and categoryName != ''"> and category_name like concat('%', #{categoryName}, '%')</if>
<if test="status != null and status != ''"> and status = #{status}</if> <if test="status != null and status != ''"> and status = #{status}</if>
<if test="isTop != null"> and is_top = #{isTop}</if>
<if test="isFeatured != null"> and is_featured = #{isFeatured}</if>
<if test="isSensitive != null"> and is_sensitive = #{isSensitive}</if>
<if test="isTop != null and isTop != ''"> and is_top = #{isTop}</if>
<if test="isFeatured != null and isFeatured != ''"> and is_featured = #{isFeatured}</if>
<if test="isSensitive != null and isSensitive != ''"> and is_sensitive = #{isSensitive}</if>
<if test="tags != null and tags != ''"> <if test="tags != null and tags != ''">
and ( and (
tags = #{tags} tags = #{tags}
or tags like concat(#{tags}, ',%') or tags like concat(#{tags}, ',%')
or tags like concat('%,', #{tags}, ',%') or tags like concat('%,', #{tags}, ',%')
or tags like concat('%,', #{tags}) or tags like concat('%,', #{tags})
or tags like concat('%', #{tags}, '%')
) )
</if> </if>
</where> </where>
order by create_time desc
order by publish_time desc
</select> </select>
<!-- 根据条件查询文章(论坛专用) -->
<!-- 根据条件查询文章列表(论坛专用) -->
<select id="selectArticlesByCondition" parameterType="map" resultMap="VetExperienceArticleResult"> <select id="selectArticlesByCondition" parameterType="map" resultMap="VetExperienceArticleResult">
<!-- 关键:使用PageHelper的特殊注释 -->
/* keepOrder */
<include refid="selectVetExperienceArticleVo"/> <include refid="selectVetExperienceArticleVo"/>
<where> <where>
status = #{status} status = #{status}
@ -84,73 +84,58 @@
</if> </if>
<if test="userId != null"> and user_id = #{userId}</if> <if test="userId != null"> and user_id = #{userId}</if>
<if test="categoryId != null"> and category_id = #{categoryId}</if> <if test="categoryId != null"> and category_id = #{categoryId}</if>
<if test="isFeatured != null"> and is_featured = #{isFeatured}</if>
<if test="isTop != null"> and is_top = #{isTop}</if>
<if test="excludeId != null"> and id != #{excludeId}</if> <if test="excludeId != null"> and id != #{excludeId}</if>
</where> </where>
<!-- 必须放在最后 -->
ORDER BY
<!-- 先ORDER BY,后LIMIT -->
order by
<choose> <choose>
<when test="orderBy != null and orderType != null"> <when test="orderBy != null and orderType != null">
${orderBy} ${orderType} ${orderBy} ${orderType}
</when> </when>
<otherwise> <otherwise>
publish_time DESC
publish_time desc
</otherwise> </otherwise>
</choose> </choose>
<!-- &lt;!&ndash; LIMIT必须紧跟在ORDER BY后面 &ndash;&gt;
<if test="limit != null and limit > 0">
LIMIT #{limit}
</if>-->
<!-- <if test="limit != null and limit > 0">
limit #{limit}
</if>-->
</select> </select>
<!--<select id="searchArticles" parameterType="map" resultMap="VetExperienceArticleResult">
<!-- 搜索文章 -->
<select id="searchArticles" resultMap="VetExperienceArticleResult">
<include refid="selectVetExperienceArticleVo"/> <include refid="selectVetExperienceArticleVo"/>
<where>
status = #{status}
<if test="keyword != null and keyword != ''">
and (
title like concat('%', #{keyword}, '%')
or content like concat('%', #{keyword}, '%')
or summary like concat('%', #{keyword}, '%')
or tags like concat('%', #{keyword}, '%')
)
</if>
</where>
where status = #{status}
and (title like concat('%', #{keyword}, '%')
or content like concat('%', #{keyword}, '%')
or summary like concat('%', #{keyword}, '%'))
order by publish_time desc order by publish_time desc
</select>-->
<!-- VetExperienceArticleMapper.xml -->
<select id="searchArticles" resultType="com.chenhai.vet.domain.VetExperienceArticle">
SELECT * FROM vet_experience_article
WHERE status = #{status}
AND (title LIKE CONCAT('%', #{keyword}, '%') OR content LIKE CONCAT('%', #{keyword}, '%') OR summary LIKE CONCAT('%', #{keyword}, '%'))
</select> </select>
<!-- 增加浏览数 --> <!-- 增加浏览数 -->
<update id="incrementViewCount" parameterType="Long"> <update id="incrementViewCount" parameterType="Long">
update vet_experience_article update vet_experience_article
set view_count = view_count + 1,
update_time = sysdate()
set view_count = ifnull(view_count, 0) + 1,
update_time = now()
where id = #{id} where id = #{id}
</update> </update>
<!-- 增加点赞数 --> <!-- 增加点赞数 -->
<update id="incrementLikeCount" parameterType="Long"> <update id="incrementLikeCount" parameterType="Long">
update vet_experience_article update vet_experience_article
set like_count = like_count + 1,
update_time = sysdate()
set like_count = ifnull(like_count, 0) + 1,
update_time = now()
where id = #{id} where id = #{id}
</update> </update>
<!-- 增加收藏数 --> <!-- 增加收藏数 -->
<update id="incrementCollectCount" parameterType="Long"> <update id="incrementCollectCount" parameterType="Long">
update vet_experience_article update vet_experience_article
set collect_count = collect_count + 1,
update_time = sysdate()
set collect_count = ifnull(collect_count, 0) + 1,
update_time = now()
where id = #{id} where id = #{id}
</update> </update>
<!-- 新增兽医经验文章 -->
<insert id="insertVetExperienceArticle" parameterType="VetExperienceArticle" useGeneratedKeys="true" keyProperty="id"> <insert id="insertVetExperienceArticle" parameterType="VetExperienceArticle" useGeneratedKeys="true" keyProperty="id">
insert into vet_experience_article insert into vet_experience_article
<trim prefix="(" suffix=")" suffixOverrides=","> <trim prefix="(" suffix=")" suffixOverrides=",">
@ -175,7 +160,7 @@
<if test="isSensitive != null">is_sensitive,</if> <if test="isSensitive != null">is_sensitive,</if>
<if test="sensitiveWords != null">sensitive_words,</if> <if test="sensitiveWords != null">sensitive_words,</if>
<if test="publishTime != null">publish_time,</if> <if test="publishTime != null">publish_time,</if>
<if test="createTime != null">create_time,</if>
create_time,
<if test="updateTime != null">update_time,</if> <if test="updateTime != null">update_time,</if>
</trim> </trim>
<trim prefix="values (" suffix=")" suffixOverrides=","> <trim prefix="values (" suffix=")" suffixOverrides=",">
@ -200,11 +185,12 @@
<if test="isSensitive != null">#{isSensitive},</if> <if test="isSensitive != null">#{isSensitive},</if>
<if test="sensitiveWords != null">#{sensitiveWords},</if> <if test="sensitiveWords != null">#{sensitiveWords},</if>
<if test="publishTime != null">#{publishTime},</if> <if test="publishTime != null">#{publishTime},</if>
<if test="createTime != null">#{createTime},</if>
now(),
<if test="updateTime != null">#{updateTime},</if> <if test="updateTime != null">#{updateTime},</if>
</trim> </trim>
</insert> </insert>
<!-- 修改兽医经验文章 -->
<update id="updateVetExperienceArticle" parameterType="VetExperienceArticle"> <update id="updateVetExperienceArticle" parameterType="VetExperienceArticle">
update vet_experience_article update vet_experience_article
<trim prefix="SET" suffixOverrides=","> <trim prefix="SET" suffixOverrides=",">
@ -229,27 +215,21 @@
<if test="isSensitive != null">is_sensitive = #{isSensitive},</if> <if test="isSensitive != null">is_sensitive = #{isSensitive},</if>
<if test="sensitiveWords != null">sensitive_words = #{sensitiveWords},</if> <if test="sensitiveWords != null">sensitive_words = #{sensitiveWords},</if>
<if test="publishTime != null">publish_time = #{publishTime},</if> <if test="publishTime != null">publish_time = #{publishTime},</if>
<if test="updateTime != null">update_time = #{updateTime},</if>
update_time = now(),
</trim> </trim>
where id = #{id} where id = #{id}
</update> </update>
<!-- 删除兽医经验文章 -->
<delete id="deleteVetExperienceArticleById" parameterType="Long"> <delete id="deleteVetExperienceArticleById" parameterType="Long">
delete from vet_experience_article where id = #{id} delete from vet_experience_article where id = #{id}
</delete> </delete>
<!-- 批量删除兽医经验文章 -->
<delete id="deleteVetExperienceArticleByIds" parameterType="Long"> <delete id="deleteVetExperienceArticleByIds" parameterType="Long">
delete from vet_experience_article where id in delete from vet_experience_article 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>
<select id="selectArticlesByTag" parameterType="String" resultMap="VetExperienceArticleResult">
<include refid="selectVetExperienceArticleVo"/>
WHERE status = '1' <!-- 只查询已发布的文章 -->
AND tags LIKE CONCAT('%', #{tag}, '%')
ORDER BY publish_time DESC
LIMIT 20 <!-- 限制返回20条 -->
</select>
</mapper> </mapper>

19
chenhai-system/src/main/resources/mapper/vet/VetProductMapper.xml

@ -33,10 +33,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="userId" column="user_id" /> <result property="userId" column="user_id" />
<result property="createdAt" column="created_at" /> <result property="createdAt" column="created_at" />
<result property="updatedAt" column="updated_at" /> <result property="updatedAt" column="updated_at" />
<result property="auditStatus" column="audit_status" />
<result property="auditOpinion" column="audit_opinion" />
<result property="auditUserId" column="audit_user_id" />
<result property="auditTime" column="audit_time" />
</resultMap> </resultMap>
<sql id="selectVetProductVo"> <sql id="selectVetProductVo">
select id, name, type, category, specification, unit, manufacturer, approval_number, ingredients, indications, usage_dosage, price, cost_price, stock, min_stock, main_image, images, treat_animals, treat_diseases, treatment_content, treatment_duration, precautions, status, is_deleted, clinic_id, user_id, created_at, updated_at from vet_product
select id, name, type, category, specification, unit, manufacturer, approval_number, ingredients, indications, usage_dosage, price, cost_price, stock, min_stock, main_image, images, treat_animals, treat_diseases, treatment_content, treatment_duration, precautions, status, is_deleted, clinic_id, user_id, created_at, updated_at,audit_status, audit_opinion, audit_user_id, audit_time from vet_product
</sql> </sql>
<select id="selectVetProductList" parameterType="VetProduct" resultMap="VetProductResult"> <select id="selectVetProductList" parameterType="VetProduct" resultMap="VetProductResult">
@ -69,6 +73,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="userId != null "> and user_id = #{userId}</if> <if test="userId != null "> and user_id = #{userId}</if>
<if test="createdAt != null "> and created_at = #{createdAt}</if> <if test="createdAt != null "> and created_at = #{createdAt}</if>
<if test="updatedAt != null "> and updated_at = #{updatedAt}</if> <if test="updatedAt != null "> and updated_at = #{updatedAt}</if>
<if test="auditStatus != null and auditStatus != ''"> and audit_status = #{auditStatus}</if>
</where> </where>
</select> </select>
@ -107,6 +112,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="userId != null">user_id,</if> <if test="userId != null">user_id,</if>
<if test="createdAt != null">created_at,</if> <if test="createdAt != null">created_at,</if>
<if test="updatedAt != null">updated_at,</if> <if test="updatedAt != null">updated_at,</if>
<if test="auditStatus != null">audit_status,</if>
<if test="auditOpinion != null">audit_opinion,</if>
<if test="auditUserId != null">audit_user_id,</if>
<if test="auditTime != null">audit_time,</if>
</trim> </trim>
<trim prefix="values (" suffix=")" suffixOverrides=","> <trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="name != null and name != ''">#{name},</if> <if test="name != null and name != ''">#{name},</if>
@ -136,6 +145,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="userId != null">#{userId},</if> <if test="userId != null">#{userId},</if>
<if test="createdAt != null">#{createdAt},</if> <if test="createdAt != null">#{createdAt},</if>
<if test="updatedAt != null">#{updatedAt},</if> <if test="updatedAt != null">#{updatedAt},</if>
<if test="auditStatus != null">#{auditStatus},</if>
<if test="auditOpinion != null">#{auditOpinion},</if>
<if test="auditUserId != null">#{auditUserId},</if>
<if test="auditTime != null">#{auditTime},</if>
</trim> </trim>
</insert> </insert>
@ -169,6 +182,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="userId != null">user_id = #{userId},</if> <if test="userId != null">user_id = #{userId},</if>
<if test="createdAt != null">created_at = #{createdAt},</if> <if test="createdAt != null">created_at = #{createdAt},</if>
<if test="updatedAt != null">updated_at = #{updatedAt},</if> <if test="updatedAt != null">updated_at = #{updatedAt},</if>
<if test="auditStatus != null">audit_status = #{auditStatus},</if>
<if test="auditOpinion != null">audit_opinion = #{auditOpinion},</if>
<if test="auditUserId != null">audit_user_id = #{auditUserId},</if>
<if test="auditTime != null">audit_time = #{auditTime},</if>
</trim> </trim>
where id = #{id} where id = #{id}
</update> </update>

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

@ -26,6 +26,7 @@
<result property="scopeIds" column="scope_ids" /> <result property="scopeIds" column="scope_ids" />
<result property="scopeNames" column="scope_names" /> <result property="scopeNames" column="scope_names" />
<!-- 新增证书字段 --> <!-- 新增证书字段 -->
<result property="certId" column="cert_id" />
<result property="certName" column="cert_name" /> <result property="certName" column="cert_name" />
<result property="certType" column="cert_type" /> <result property="certType" column="cert_type" />
<result property="issueOrg" column="issue_org" /> <result property="issueOrg" column="issue_org" />
@ -36,6 +37,7 @@
<result property="certStatusLabel" column="cert_status_label"/> <result property="certStatusLabel" column="cert_status_label"/>
<result property="remindDays" column="remind_days" /> <result property="remindDays" column="remind_days" />
<result property="lastRemindTime" column="last_remind_time" /> <result property="lastRemindTime" column="last_remind_time" />
<result property="certificatesJson" column="certificates_json"/>
</resultMap> </resultMap>
<sql id="selectVetQualificationVo"> <sql id="selectVetQualificationVo">
@ -69,6 +71,8 @@
<if test="auditOpinion != null and auditOpinion != ''"> and vq.audit_opinion = #{auditOpinion}</if> <if test="auditOpinion != null and auditOpinion != ''"> and vq.audit_opinion = #{auditOpinion}</if>
<if test="auditorId != null "> and vq.auditor_id = #{auditorId}</if> <if test="auditorId != null "> and vq.auditor_id = #{auditorId}</if>
<if test="scopeNames !=null and scopeNames != ''">and vq.scope_names = #{scopeNames}</if> <if test="scopeNames !=null and scopeNames != ''">and vq.scope_names = #{scopeNames}</if>
<!-- 证书ID查询条件 -->
<if test="certId != null "> and vq.cert_id = #{certId}</if>
<!-- 新增证书查询条件 --> <!-- 新增证书查询条件 -->
<if test="certName != null and certName != ''"> and vq.cert_name like concat('%', #{certName}, '%')</if> <if test="certName != null and certName != ''"> and vq.cert_name like concat('%', #{certName}, '%')</if>
<if test="certType != null and certType != ''"> and vq.cert_type = #{certType}</if> <if test="certType != null and certType != ''"> and vq.cert_type = #{certType}</if>
@ -97,7 +101,12 @@
<if test="realName != null and realName != ''">real_name,</if> <if test="realName != null and realName != ''">real_name,</if>
<if test="idCard != null and idCard != ''">id_card,</if> <if test="idCard != null and idCard != ''">id_card,</if>
<if test="qualificationType != null and qualificationType != ''">qualification_type,</if> <if test="qualificationType != null and qualificationType != ''">qualification_type,</if>
<!-- ⚠️ 修改:让certificate_no成为可选字段 -->
<if test="certificateNo != null and certificateNo != ''">certificate_no,</if> <if test="certificateNo != null and certificateNo != ''">certificate_no,</if>
<!-- 添加证书JSON字段 -->
<if test="certificatesJson != null and certificatesJson != ''">certificates_json,</if>
<if test="certificateFiles != null and certificateFiles != ''">certificate_files,</if> <if test="certificateFiles != null and certificateFiles != ''">certificate_files,</if>
<if test="applyTime != null">apply_time,</if> <if test="applyTime != null">apply_time,</if>
<if test="auditTime != null">audit_time,</if> <if test="auditTime != null">audit_time,</if>
@ -112,6 +121,7 @@
<if test="scopeIds != null and scopeIds != ''">scope_ids,</if> <if test="scopeIds != null and scopeIds != ''">scope_ids,</if>
<if test="scopeNames != null and scopeNames != ''">scope_names,</if> <if test="scopeNames != null and scopeNames != ''">scope_names,</if>
<!-- 新增证书字段 --> <!-- 新增证书字段 -->
<if test="certId != null">cert_id,</if>
<if test="certName != null and certName != ''">cert_name,</if> <if test="certName != null and certName != ''">cert_name,</if>
<if test="certType != null and certType != ''">cert_type,</if> <if test="certType != null and certType != ''">cert_type,</if>
<if test="issueOrg != null and issueOrg != ''">issue_org,</if> <if test="issueOrg != null and issueOrg != ''">issue_org,</if>
@ -127,7 +137,12 @@
<if test="realName != null and realName != ''">#{realName},</if> <if test="realName != null and realName != ''">#{realName},</if>
<if test="idCard != null and idCard != ''">#{idCard},</if> <if test="idCard != null and idCard != ''">#{idCard},</if>
<if test="qualificationType != null and qualificationType != ''">#{qualificationType},</if> <if test="qualificationType != null and qualificationType != ''">#{qualificationType},</if>
<!-- ⚠️ 修改:让certificate_no成为可选字段 -->
<if test="certificateNo != null and certificateNo != ''">#{certificateNo},</if> <if test="certificateNo != null and certificateNo != ''">#{certificateNo},</if>
<!-- 证书JSON值 -->
<if test="certificatesJson != null and certificatesJson != ''">#{certificatesJson},</if>
<if test="certificateFiles != null and certificateFiles != ''">#{certificateFiles},</if> <if test="certificateFiles != null and certificateFiles != ''">#{certificateFiles},</if>
<if test="applyTime != null">#{applyTime},</if> <if test="applyTime != null">#{applyTime},</if>
<if test="auditTime != null">#{auditTime},</if> <if test="auditTime != null">#{auditTime},</if>
@ -142,6 +157,7 @@
<if test="scopeIds != null and scopeIds != ''">#{scopeIds},</if> <if test="scopeIds != null and scopeIds != ''">#{scopeIds},</if>
<if test="scopeNames != null and scopeNames != ''">#{scopeNames},</if> <if test="scopeNames != null and scopeNames != ''">#{scopeNames},</if>
<!-- 新增证书字段 --> <!-- 新增证书字段 -->
<if test="certId != null">#{certId},</if>
<if test="certName != null and certName != ''">#{certName},</if> <if test="certName != null and certName != ''">#{certName},</if>
<if test="certType != null and certType != ''">#{certType},</if> <if test="certType != null and certType != ''">#{certType},</if>
<if test="issueOrg != null and issueOrg != ''">#{issueOrg},</if> <if test="issueOrg != null and issueOrg != ''">#{issueOrg},</if>
@ -162,6 +178,10 @@
<if test="idCard != null and idCard != ''">id_card = #{idCard},</if> <if test="idCard != null and idCard != ''">id_card = #{idCard},</if>
<if test="qualificationType != null and qualificationType != ''">qualification_type = #{qualificationType},</if> <if test="qualificationType != null and qualificationType != ''">qualification_type = #{qualificationType},</if>
<if test="certificateNo != null and certificateNo != ''">certificate_no = #{certificateNo},</if> <if test="certificateNo != null and certificateNo != ''">certificate_no = #{certificateNo},</if>
<!-- 添加证书JSON字段 -->
<if test="certificatesJson != null">certificates_json = #{certificatesJson},</if>
<if test="certificateFiles != null and certificateFiles != ''">certificate_files = #{certificateFiles},</if> <if test="certificateFiles != null and certificateFiles != ''">certificate_files = #{certificateFiles},</if>
<if test="applyTime != null">apply_time = #{applyTime},</if> <if test="applyTime != null">apply_time = #{applyTime},</if>
<if test="auditTime != null">audit_time = #{auditTime},</if> <if test="auditTime != null">audit_time = #{auditTime},</if>
@ -174,6 +194,7 @@
<if test="scopeIds != null">scope_ids = #{scopeIds},</if> <if test="scopeIds != null">scope_ids = #{scopeIds},</if>
<if test="scopeNames != null">scope_names = #{scopeNames},</if> <if test="scopeNames != null">scope_names = #{scopeNames},</if>
<!-- 新增证书字段 --> <!-- 新增证书字段 -->
<if test="certId != null">cert_id = #{certId},</if>
<if test="certName != null">cert_name = #{certName},</if> <if test="certName != null">cert_name = #{certName},</if>
<if test="certType != null">cert_type = #{certType},</if> <if test="certType != null">cert_type = #{certType},</if>
<if test="issueOrg != null">issue_org = #{issueOrg},</if> <if test="issueOrg != null">issue_org = #{issueOrg},</if>
@ -205,4 +226,24 @@
ORDER BY create_time DESC ORDER BY create_time DESC
</select> </select>
<select id="selectCertificateByCertId" resultType="java.util.HashMap">
SELECT
q.*,
#{certId} as cert_id
FROM vet_qualification q
WHERE
q.certificates_json IS NOT NULL
AND q.certificates_json != ''
<!-- 搜索certId,考虑不同的JSON格式 -->
AND (
q.certificates_json LIKE CONCAT('%', '"certId":', #{certId}, '%')
OR q.certificates_json LIKE CONCAT('%', '"certId":"', #{certId}, '"%')
OR q.certificates_json LIKE CONCAT('%', '"certificateId":', #{certId}, '%')
OR q.certificates_json LIKE CONCAT('%', '"certificateId":"', #{certId}, '"%')
)
<if test="userId != null">
AND q.user_id = #{userId}
</if>
LIMIT 1
</select>
</mapper> </mapper>

41
chenhai-ui/src/api/vet/product.js

@ -42,3 +42,44 @@ export function delProduct(id) {
method: 'delete' method: 'delete'
}) })
} }
// 提交审核
export function submitAudit(id) {
return request({
url: '/vet/product/submitAudit/' + id,
method: 'post'
})
}
// 审核产品
export function auditProduct(data) {
return request({
url: '/vet/product/audit',
method: 'post',
data: data
})
}
// 上架产品
export function publishProduct(id) {
return request({
url: '/vet/product/publish/' + id,
method: 'post'
})
}
// 下架产品
export function offlineProduct(id) {
return request({
url: '/vet/product/offline/' + id,
method: 'post'
})
}
// 取消审核
export function cancelAudit(id) {
return request({
url: '/vet/product/cancelAudit/' + id,
method: 'post'
})
}

2546
chenhai-ui/src/views/vet/article/index.vue
File diff suppressed because it is too large
View File

345
chenhai-ui/src/views/vet/product/index.vue

@ -24,9 +24,28 @@
style="width: 120px" style="width: 120px"
> >
<el-option label="全部" value="" /> <el-option label="全部" value="" />
<el-option label="兽药" value="medicine" />
<el-option label="疫苗" value="vaccine" />
<el-option label="保健品" value="supplement" />
<el-option label="处方药" value="0" />
<el-option label="非处方药" value="1" />
<el-option label="中成药" value="2" />
<el-option label="保健品" value="3" />
</el-select>
</el-form-item>
<el-form-item label="产品分类" prop="category">
<el-select
v-model="queryParams.category"
placeholder="请选择分类"
clearable
style="width: 120px"
>
<el-option label="全部" value="" />
<el-option label="抗生素类" value="0" />
<el-option label="抗寄生虫类" value="1" />
<el-option label="疫苗类" value="2" />
<el-option label="消毒剂类" value="3" />
<el-option label="营养补充类" value="4" />
<el-option label="外科用药" value="5" />
<el-option label="诊断试剂" value="6" />
<el-option label="中药制剂" value="7" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="状态" prop="status"> <el-form-item label="状态" prop="status">
@ -42,6 +61,20 @@
<el-option label="下架" value="2" /> <el-option label="下架" value="2" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="审核状态" prop="auditStatus">
<el-select
v-model="queryParams.auditStatus"
placeholder="请选择审核状态"
clearable
style="width: 120px"
>
<el-option label="全部" value="" />
<el-option label="待审核" value="0" />
<el-option label="审核通过" value="1" />
<el-option label="审核拒绝" value="2" />
<el-option label="无需审核" value="3" />
</el-select>
</el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary" icon="el-icon-search" @click="handleQuery"> <el-button type="primary" icon="el-icon-search" @click="handleQuery">
搜索 搜索
@ -147,17 +180,12 @@
</div> </div>
<div class="product-info"> <div class="product-info">
<span class="name-text">{{ scope.row.name }}</span> <span class="name-text">{{ scope.row.name }}</span>
<!-- 调试信息 -->
<div v-if="showDebugInfo" style="font-size: 12px; color: #999; margin-top: 4px;">
<div>主图: {{ scope.row.mainImage || '无' }}</div>
<div>图片数量: {{ getImageCount(scope.row) }}</div>
</div>
</div> </div>
</div> </div>
</template> </template>
</el-table-column> </el-table-column>
<!-- 其他列保持不变 -->
<!-- 产品类型 -->
<el-table-column <el-table-column
label="类型" label="类型"
prop="type" prop="type"
@ -174,12 +202,22 @@
</template> </template>
</el-table-column> </el-table-column>
<!-- 产品分类 -->
<el-table-column <el-table-column
label="分类" label="分类"
prop="category" prop="category"
width="100"
width="120"
align="center" align="center"
/>
>
<template slot-scope="scope">
<el-tag
:type="getCategoryTagType(scope.row.category)"
size="small"
>
{{ getCategoryText(scope.row.category) }}
</el-tag>
</template>
</el-table-column>
<el-table-column <el-table-column
label="规格" label="规格"
@ -233,6 +271,22 @@
</template> </template>
</el-table-column> </el-table-column>
<el-table-column
label="审核状态"
prop="auditStatus"
width="120"
align="center"
>
<template slot-scope="scope">
<el-tag
:type="getAuditStatusTagType(scope.row.auditStatus)"
size="small"
>
{{ getAuditStatusText(scope.row.auditStatus) }}
</el-tag>
</template>
</el-table-column>
<el-table-column <el-table-column
label="生产厂家" label="生产厂家"
prop="manufacturer" prop="manufacturer"
@ -255,11 +309,12 @@
<el-table-column <el-table-column
label="操作" label="操作"
align="center" align="center"
width="250"
width="300"
fixed="right" fixed="right"
class-name="small-padding fixed-width" class-name="small-padding fixed-width"
> >
<template slot-scope="scope"> <template slot-scope="scope">
<!-- 详情按钮 -->
<el-button <el-button
size="mini" size="mini"
type="text" type="text"
@ -268,15 +323,20 @@
> >
详情 详情
</el-button> </el-button>
<!-- 编辑按钮仅在草稿/审核驳回/敏感内容驳回状态显示 -->
<el-button <el-button
size="mini" size="mini"
type="text" type="text"
icon="el-icon-edit" icon="el-icon-edit"
@click="handleUpdate(scope.row)" @click="handleUpdate(scope.row)"
v-hasPermi="['vet:product:edit']" v-hasPermi="['vet:product:edit']"
v-if="scope.row.status === '0' && scope.row.auditStatus === '3'"
> >
编辑 编辑
</el-button> </el-button>
<!-- 删除按钮 -->
<el-button <el-button
size="mini" size="mini"
type="text" type="text"
@ -287,6 +347,70 @@
> >
删除 删除
</el-button> </el-button>
<!-- 提交审核按钮草稿状态显示 -->
<el-button
size="mini"
type="text"
icon="el-icon-s-promotion"
style="color: #1890ff"
@click="handleSubmitAudit(scope.row)"
v-hasPermi="['vet:product:submit']"
v-if="scope.row.status === '0' && scope.row.auditStatus === '0'"
>
提交审核
</el-button>
<!-- 上架按钮审核通过且未上架状态显示 -->
<el-button
size="mini"
type="text"
icon="el-icon-top"
style="color: #52c41a"
@click="handlePublish(scope.row)"
v-hasPermi="['vet:product:publish']"
v-if="scope.row.auditStatus === '2' && scope.row.status === '0'"
>
上架
</el-button>
<!-- 下架按钮已上架状态显示 -->
<el-button
size="mini"
type="text"
icon="el-icon-bottom"
style="color: #faad14"
@click="handleOffline(scope.row)"
v-hasPermi="['vet:product:offline']"
v-if="scope.row.status === '1'"
>
下架
</el-button>
<!-- 取消审核按钮待审核状态且编辑权限显示 -->
<el-button
size="mini"
type="text"
icon="el-icon-close"
style="color: #ff4d4f"
@click="handleCancelAudit(scope.row)"
v-hasPermi="['vet:product:edit']"
v-if="scope.row.status === '0' && scope.row.auditStatus === '1'"
>
取消审核
</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-s-promotion"
style="color: #1890ff"
@click="handleResubmitAudit(scope.row)"
v-hasPermi="['vet:product:submit']"
v-if="scope.row.status === '0' && scope.row.auditStatus === '3'"
>
重新提交
</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@ -389,9 +513,10 @@
<el-col :span="12"> <el-col :span="12">
<el-form-item label="产品类型" prop="type"> <el-form-item label="产品类型" prop="type">
<el-select v-model="form.type" placeholder="请选择产品类型" style="width: 100%"> <el-select v-model="form.type" placeholder="请选择产品类型" style="width: 100%">
<el-option label="兽药" value="medicine" />
<el-option label="疫苗" value="vaccine" />
<el-option label="保健品" value="supplement" />
<el-option label="处方药" value="0" />
<el-option label="非处方药" value="1" />
<el-option label="中成药" value="2" />
<el-option label="保健品" value="3" />
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
@ -400,7 +525,16 @@
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="产品分类" prop="category"> <el-form-item label="产品分类" prop="category">
<el-input v-model="form.category" placeholder="请输入产品分类" />
<el-select v-model="form.category" placeholder="请选择产品分类" style="width: 100%">
<el-option label="抗生素类" value="0" />
<el-option label="抗寄生虫类" value="1" />
<el-option label="疫苗类" value="2" />
<el-option label="消毒剂类" value="3" />
<el-option label="营养补充类" value="4" />
<el-option label="外科用药" value="5" />
<el-option label="诊断试剂" value="6" />
<el-option label="中药制剂" value="7" />
</el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
@ -654,7 +788,9 @@
</el-tag> </el-tag>
</el-descriptions-item> </el-descriptions-item>
<el-descriptions-item label="产品分类"> <el-descriptions-item label="产品分类">
{{ currentDetail.category || '--' }}
<el-tag :type="getCategoryTagType(currentDetail.category)" size="small">
{{ getCategoryText(currentDetail.category) }}
</el-tag>
</el-descriptions-item> </el-descriptions-item>
<el-descriptions-item label="规格"> <el-descriptions-item label="规格">
{{ currentDetail.specification || '--' }} {{ currentDetail.specification || '--' }}
@ -673,6 +809,11 @@
{{ getStatusText(currentDetail.status) }} {{ getStatusText(currentDetail.status) }}
</el-tag> </el-tag>
</el-descriptions-item> </el-descriptions-item>
<el-descriptions-item label="审核状态">
<el-tag :type="getAuditStatusTagType(currentDetail.auditStatus)" size="small">
{{ getAuditStatusText(currentDetail.auditStatus) }}
</el-tag>
</el-descriptions-item>
<el-descriptions-item label="销售价格"> <el-descriptions-item label="销售价格">
<span style="color: #f56c6c; font-weight: bold;">¥{{ currentDetail.price || '0.00' }}</span> <span style="color: #f56c6c; font-weight: bold;">¥{{ currentDetail.price || '0.00' }}</span>
</el-descriptions-item> </el-descriptions-item>
@ -727,7 +868,7 @@
</template> </template>
<script> <script>
import { listProduct, getProduct, delProduct, addProduct, updateProduct } from "@/api/vet/product"
import { listProduct, getProduct, delProduct, addProduct, updateProduct, submitAudit, publishProduct, offlineProduct, cancelAudit } from "@/api/vet/product"
import { getToken } from '@/utils/auth' import { getToken } from '@/utils/auth'
export default { export default {
@ -764,7 +905,9 @@ export default {
pageSize: 10, pageSize: 10,
name: null, name: null,
type: null, type: null,
category: null,
status: null, status: null,
auditStatus: null,
}, },
form: { form: {
@ -798,7 +941,9 @@ export default {
clinicId: null, clinicId: null,
userId: null, userId: null,
createdAt: null, createdAt: null,
updatedAt: null
updatedAt: null,
auditStatus: null,
auditOpinion: null
}, },
rules: { rules: {
@ -808,6 +953,9 @@ export default {
type: [ type: [
{ required: true, message: "产品类型不能为空", trigger: "change" } { required: true, message: "产品类型不能为空", trigger: "change" }
], ],
category: [
{ required: true, message: "产品分类不能为空", trigger: "change" }
],
price: [ price: [
{ required: true, message: "销售价格不能为空", trigger: "blur" }, { required: true, message: "销售价格不能为空", trigger: "blur" },
{ pattern: /^\d+(\.\d{1,2})?$/, message: '请输入正确的价格格式' } { pattern: /^\d+(\.\d{1,2})?$/, message: '请输入正确的价格格式' }
@ -892,6 +1040,8 @@ export default {
treatmentDuration: data.treatmentDuration || data.treatment_duration, treatmentDuration: data.treatmentDuration || data.treatment_duration,
precautions: data.precautions, precautions: data.precautions,
status: data.status, status: data.status,
auditStatus: data.auditStatus || data.audit_status,
auditOpinion: data.auditOpinion || data.audit_opinion,
createdAt: data.createdAt || data.created_at, createdAt: data.createdAt || data.created_at,
updatedAt: data.updatedAt || data.updated_at updatedAt: data.updatedAt || data.updated_at
} }
@ -947,6 +1097,8 @@ export default {
treatmentDuration: item.treatmentDuration, treatmentDuration: item.treatmentDuration,
precautions: item.precautions, precautions: item.precautions,
status: item.status, status: item.status,
auditStatus: item.auditStatus || item.audit_status,
auditOpinion: item.auditOpinion || item.audit_opinion,
isDeleted: item.isDeleted, isDeleted: item.isDeleted,
clinicId: item.clinicId, clinicId: item.clinicId,
userId: item.userId, userId: item.userId,
@ -965,12 +1117,6 @@ export default {
updatedAt: item.updatedAt !== undefined ? item.updatedAt : (item.updated_at || new Date()) updatedAt: item.updatedAt !== undefined ? item.updatedAt : (item.updated_at || new Date())
} }
console.log('产品图片信息:', {
mainImage: processedItem.mainImage,
imageList: processedItem.imageList,
images: processedItem.images
})
return processedItem return processedItem
}) })
@ -1035,8 +1181,6 @@ export default {
getFullImageUrl(url) { getFullImageUrl(url) {
if (!url) return '' if (!url) return ''
console.log('原始图片路径:', url)
// URL // URL
if (url.startsWith('http://') || url.startsWith('https://')) { if (url.startsWith('http://') || url.startsWith('https://')) {
return url return url
@ -1132,12 +1276,75 @@ export default {
return true return true
}, },
/** 提交审核 */
handleSubmitAudit(row) {
this.$modal.confirm('确认提交审核吗?提交后产品将进入待审核状态,不可编辑。').then(() => {
return submitAudit(row.id)
}).then(() => {
this.$modal.msgSuccess("提交审核成功")
this.getList()
}).catch(() => {})
},
/** 上架产品 */
handlePublish(row) {
this.$modal.confirm('确认上架该产品吗?').then(() => {
return publishProduct(row.id)
}).then(() => {
this.$modal.msgSuccess("上架成功")
this.getList()
}).catch(() => {})
},
/** 下架产品 */
handleOffline(row) {
this.$modal.confirm('确认下架该产品吗?').then(() => {
return offlineProduct(row.id)
}).then(() => {
this.$modal.msgSuccess("下架成功")
this.getList()
}).catch(() => {})
},
/** 取消审核 */
handleCancelAudit(row) {
this.$modal.confirm('确认取消审核吗?取消后产品将恢复为草稿状态,可以编辑。').then(() => {
return cancelAudit(row.id)
}).then(() => {
this.$modal.msgSuccess("取消审核成功")
this.getList()
}).catch(() => {})
},
/** 取消按钮 */ /** 取消按钮 */
cancel() { cancel() {
this.open = false this.open = false
this.reset() this.reset()
}, },
//
handleResubmitAudit(row) {
this.$modal.confirm('确认重新提交审核吗?').then(() => {
//
const updateData = {
id: row.id,
auditStatus: '0',
auditOpinion: null,
auditUserId: null,
auditTime: null
}
//
return updateProduct(updateData)
}).then(() => {
//
return submitAudit(row.id)
}).then(() => {
this.$modal.msgSuccess("重新提交审核成功")
this.getList()
}).catch(() => {})
},
/** 表单重置 */ /** 表单重置 */
reset() { reset() {
this.form = { this.form = {
@ -1170,7 +1377,9 @@ export default {
clinicId: null, clinicId: null,
userId: this.getCurrentUserId(), userId: this.getCurrentUserId(),
createdAt: null, createdAt: null,
updatedAt: null
updatedAt: null,
auditStatus: null,
auditOpinion: null
} }
this.activeTab = 'basic' this.activeTab = 'basic'
this.resetForm("form") this.resetForm("form")
@ -1239,6 +1448,8 @@ export default {
treatmentDuration: data.treatmentDuration || data.treatment_duration, treatmentDuration: data.treatmentDuration || data.treatment_duration,
precautions: data.precautions, precautions: data.precautions,
status: String(data.status || '0'), status: String(data.status || '0'),
auditStatus: data.auditStatus || data.audit_status,
auditOpinion: data.auditOpinion || data.audit_opinion,
isDeleted: data.isDeleted || data.is_deleted, isDeleted: data.isDeleted || data.is_deleted,
clinicId: data.clinicId || data.clinic_id, clinicId: data.clinicId || data.clinic_id,
userId: data.userId || data.user_id, userId: data.userId || data.user_id,
@ -1349,9 +1560,10 @@ export default {
/** 获取产品类型文本 */ /** 获取产品类型文本 */
getTypeText(type) { getTypeText(type) {
const map = { const map = {
medicine: '兽药',
vaccine: '疫苗',
supplement: '保健品'
"0": '处方药',
"1": '非处方药',
"2": '中成药',
"3": '保健品'
} }
return map[type] || type return map[type] || type
}, },
@ -1359,13 +1571,44 @@ export default {
/** 获取产品类型标签类型 */ /** 获取产品类型标签类型 */
getTypeTagType(type) { getTypeTagType(type) {
const map = { const map = {
medicine: 'danger',
vaccine: 'warning',
supplement: 'success'
"0": 'danger', // -
"1": 'warning', // -
"2": 'success', // - 绿
"3": 'primary' // -
} }
return map[type] || '' return map[type] || ''
}, },
/** 获取产品分类文本 */
getCategoryText(category) {
const map = {
"0": '抗生素类',
"1": '抗寄生虫类',
"2": '疫苗类',
"3": '消毒剂类',
"4": '营养补充类',
"5": '外科用药',
"6": '诊断试剂',
"7": '中药制剂'
}
return map[category] || category
},
/** 获取产品分类标签类型 */
getCategoryTagType(category) {
const map = {
"0": 'danger', // -
"1": 'warning', // -
"2": 'success', // - 绿
"3": 'primary', // -
"4": 'info', // -
"5": '', // -
"6": 'warning', // -
"7": 'success' // - 绿
}
return map[category] || ''
},
/** 获取状态文本 */ /** 获取状态文本 */
getStatusText(status) { getStatusText(status) {
const map = { const map = {
@ -1386,6 +1629,28 @@ export default {
return map[status] || '' return map[status] || ''
}, },
/** 获取审核状态文本 */
getAuditStatusText(auditStatus) {
const map = {
"0": '待审核',
"1": '审核中',
"2": '审核通过',
"3": '审核拒绝'
}
return map[auditStatus] || auditStatus
},
/** 获取审核状态标签类型 */
getAuditStatusTagType(auditStatus) {
const map = {
"0": 'warning',
"1": 'primary',
"2": 'success',
"3": 'danger'
}
return map[auditStatus] || ''
},
/** 获取库存状态样式 */ /** 获取库存状态样式 */
getStockStatusClass(stock, minStock) { getStockStatusClass(stock, minStock) {
if (!stock || stock === 0) return 'stock-out' if (!stock || stock === 0) return 'stock-out'
@ -1802,4 +2067,16 @@ export default {
.el-row { .el-row {
margin-bottom: 10px; margin-bottom: 10px;
} }
//
.operation-buttons {
display: flex;
flex-wrap: wrap;
gap: 5px;
.el-button {
margin: 0 !important;
padding: 4px 6px;
}
}
</style> </style>
Loading…
Cancel
Save