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;
import com.chenhai.common.utils.DictUtils;
import com.chenhai.common.annotation.Log;
import com.chenhai.common.core.controller.BaseController;
import com.chenhai.common.core.domain.AjaxResult;
import com.chenhai.common.core.page.TableDataInfo;
import com.chenhai.common.enums.BusinessType;
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.mapper.VetArticleCategoryMapper;
import com.chenhai.vet.service.IVetExperienceArticleService;
import jakarta.servlet.http.HttpServletResponse;
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 java.util.*;
import java.util.concurrent.ConcurrentHashMap;
/**
* 兽医经验分享Controller
* 兽医经验文章论坛Controller列表样式
*/
@RestController
@RequestMapping("/vet/article")
@ -30,423 +25,171 @@ public class VetExperienceArticleController extends BaseController {
@Autowired
private IVetExperienceArticleService vetExperienceArticleService;
@Autowired // 确保有这个注解
private VetArticleCategoryMapper vetArticleCategoryMapper;
@Autowired
private JdbcTemplate jdbcTemplate;
/**
* 简单收藏管理使用Map存储
*/
// 简单收藏管理
private static final Map<Long, Set<Long>> COLLECTION_STORE = new ConcurrentHashMap<>();
/**
* 查询兽医经验文章列表
* 查询所有文章列表论坛首页
*/
@GetMapping("/list")
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();
// 创建查询对象
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);
}
/**
* 获取文章标签选项
*/
@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();
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();
VetExperienceArticle query = new VetExperienceArticle();
query.setStatus("1");
query.setTags(tagName);
List<VetExperienceArticle> list = vetExperienceArticleService.selectVetExperienceArticleList(query);
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);
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<>();
result.put("article", article);
result.put("isOwner", isOwner);
result.put("relatedArticles", relatedArticles);
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);
}
/**
* 发布新文章论坛发布接口
* 发布新文章论坛发布
*/
/*@PreAuthorize("@ss.hasPermi('vet:article:add')")*/
@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();
// 设置作者信息
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();
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) {
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) {
return error("请先登录");
}
@ -467,113 +210,110 @@ public class VetExperienceArticleController extends BaseController {
// 检查是否已收藏
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();
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;
import java.util.List;
import com.chenhai.common.utils.SecurityUtils;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.access.prepost.PreAuthorize;
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.enums.BusinessType;
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.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.Value;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.access.prepost.PreAuthorize;
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 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")
public class VetQualificationController extends BaseController
{
private static final Logger log = LoggerFactory.getLogger(VetQualificationController.class);
@Autowired
private IVetQualificationService vetQualificationService;
@Autowired
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);
}
/**
* 查询兽医资质列表含证书信息
*/
@ -123,32 +110,108 @@ public class VetQualificationController extends BaseController
}
/**
* 用户详情页查询资质证书
* 查询用户的证书列表展开每个证书
*/
@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();
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()) {
result.put("needPopup", true);
result.put("message", "请先填写兽医资质信息");
result.put("status", "empty");
} else {
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("message", "您的资质审核不通过,请重新填写");
result.put("status", "rejected");
} else {
result.put("needPopup", false);
result.put("message", "请先提交资质审核");
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("资质信息不存在");
}
// 权限检查管理员或查看自己
Long currentUserId = SecurityUtils.getUserId();
if (!SecurityUtils.isAdmin(currentUserId) && !qualification.getUserId().equals(currentUserId)) {
return AjaxResult.error("没有权限查看此资质");
@ -248,7 +301,6 @@ public class VetQualificationController extends BaseController
vetQualification.setUserId(sysUserId);
vetQualification.setCreateBy(username);
// 设置默认提醒天数
if (vetQualification.getRemindDays() == null) {
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())";
jdbcTemplate.update(sql, sysUserId, username);
} catch (Exception e) {
// 忽略异常
}
}
@ -280,7 +331,6 @@ public class VetQualificationController extends BaseController
@PutMapping
public AjaxResult edit(@RequestBody VetQualification vetQualification)
{
// 检查权限普通用户只能修改自己的资质
Long currentUserId = SecurityUtils.getUserId();
if (!SecurityUtils.isAdmin(currentUserId)) {
VetQualification existing = vetQualificationService.selectVetQualificationByQualificationId(vetQualification.getQualificationId());
@ -300,7 +350,6 @@ public class VetQualificationController extends BaseController
@DeleteMapping("/{qualificationIds}")
public AjaxResult remove(@PathVariable Long[] qualificationIds)
{
// 检查权限
Long currentUserId = SecurityUtils.getUserId();
if (!SecurityUtils.isAdmin(currentUserId)) {
for (Long id : qualificationIds) {
@ -319,39 +368,70 @@ public class VetQualificationController extends BaseController
*/
@Log(title = "兽医资质", businessType = BusinessType.UPDATE)
@PostMapping("/submit")
public AjaxResult submitQualification(@RequestBody VetQualification vetQualification) {
public AjaxResult submitQualification(@RequestBody Object requestBody) {
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 {
// 新增资质记录并提交审核
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) {
log.error("提交资质失败", e);
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) {
Long currentUserId = SecurityUtils.getUserId();
// 权限检查
if (!SecurityUtils.isAdmin(currentUserId) && !userId.equals(currentUserId)) {
return error("没有权限查看其他用户的资质");
}
@ -378,22 +457,6 @@ public class VetQualificationController extends BaseController
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) {
Long currentUserId = SecurityUtils.getUserId();
// 权限检查
if (!SecurityUtils.isAdmin(currentUserId) && !userId.equals(currentUserId)) {
return error("没有权限查看其他用户的统计信息");
}
@ -417,7 +479,6 @@ public class VetQualificationController extends BaseController
public AjaxResult manualCheck(@PathVariable Long userId) {
Long currentUserId = SecurityUtils.getUserId();
// 权限检查
if (!SecurityUtils.isAdmin(currentUserId) && !userId.equals(currentUserId)) {
return error("没有权限为其他用户检查证书");
}
@ -425,4 +486,262 @@ public class VetQualificationController extends BaseController
vetQualificationService.manualCheckCertificates(userId);
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;
/** 标签(逗号分隔) */
@Excel(name = "标签", readConverterExp = "逗=号分隔")
@Excel(name = "标签", dictType = "vet_experience_tag")
private String tags;
/** 是否置顶(0否 1是) */
@ -77,9 +77,26 @@ public class VetExperienceArticle extends BaseEntity
private String isFeatured;
/** 状态(0草稿 1已发布 2审核中 3已驳回) */
@Excel(name = "状态", readConverterExp = "0=草稿,1=已发布,2=审核中,3=已驳回")
@Excel(name = "状态", dictType = "article_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是) */
@Excel(name = "是否包含敏感词", readConverterExp = "0=否,1=是")
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 = "产品名称")
private String name;
/** 产品类型:medicine-兽药/vaccine-疫苗/supplement-保健品 */
@Excel(name = "产品类型:medicine-兽药/vaccine-疫苗/supplement-保健品")
/** 产品类型(字典:vet_product_type) */
@Excel(name = "产品类型", dictType = "medicine_type")
private String type;
/** 产品分类 */
@Excel(name = "产品分类")
/** 产品分类(字典:vet_product_category) */
@Excel(name = "产品分类", dictType = "vet_product_category")
private String category;
/** 规格 */
@Excel(name = "规格")
private String specification;
@ -105,8 +106,8 @@ public class VetProduct extends BaseEntity
@Excel(name = "注意事项")
private String precautions;
/** 状态:0-草稿/1-上架/2-下架 */
@Excel(name = "状态:0-草稿/1-上架/2-下架")
/** 上架状态(字典:vet_product_status) */
@Excel(name = "上架状态", dictType = "sys_publish_status")
private String status;
/** 删除标识:0-正常/1-删除 */
@ -131,6 +132,21 @@ public class VetProduct extends BaseEntity
@Excel(name = "更新时间", width = 30, dateFormat = "yyyy-MM-dd")
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)
{
this.id = id;
@ -411,6 +427,38 @@ public class VetProduct extends BaseEntity
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
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
@ -442,6 +490,10 @@ public class VetProduct extends BaseEntity
.append("userId", getUserId())
.append("createdAt", getCreatedAt())
.append("updatedAt", getUpdatedAt())
.append("auditStatus", getAuditStatus())
.append("auditOpinion", getAuditOpinion())
.append("auditUserId", getAuditUserId())
.append("auditTime", getAuditTime())
.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.core.domain.BaseEntity;
import com.chenhai.common.utils.StringUtils;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
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.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合并证书功能
@ -22,6 +26,13 @@ import java.util.ArrayList;
public class VetQualification extends BaseEntity
{
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 */
private Long qualificationId;
@ -60,7 +71,7 @@ public class VetQualification extends BaseEntity
@Excel(name = "审核时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date auditTime;
/** 审核状态(0待审核 1通过 2拒绝 ) */
/** 审核状态(0待审核 1通过 2拒绝) */
@Excel(name = "审核状态", dictType = "qualification_shenhe")
private String auditStatus;
@ -79,7 +90,8 @@ public class VetQualification extends BaseEntity
@Excel(name = "经营范围名称", dictType = "scope_names")
private String scopeNames;
// 新增证书相关字段
/** 证书ID(数据库字段) */
private Long certId;
/** 证书名称 */
@Excel(name = "证书名称")
@ -118,17 +130,376 @@ public class VetQualification extends BaseEntity
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date lastRemindTime;
// 查询条件字段非数据库字段
/** 是否查询即将过期 */
private Boolean expiringOnly;
// 显示标签字段
/** 显示标签字段 */
private String qualificationTypeLabel;
private String auditStatusLabel;
private String scopeNamesLabel;
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")
public void setScopeIdsFromJson(List<String> scopeIdList) {
if (scopeIdList != null && !scopeIdList.isEmpty()) {
@ -138,7 +509,6 @@ public class VetQualification extends BaseEntity
}
}
// 序列化为 JSON 时使用的方法
@JsonProperty("scopeIds")
public List<String> getScopeIdsAsList() {
if (scopeIds != null && !scopeIds.trim().isEmpty()) {
@ -147,29 +517,15 @@ public class VetQualification extends BaseEntity
return new ArrayList<>();
}
// 数据库操作的 getterJackson 忽略
@JsonIgnore
public String getScopeIds() {
return scopeIds;
}
// 数据库操作的 setter
public void setScopeIds(String 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() {
return qualificationId;
}
@ -274,7 +630,14 @@ public class VetQualification extends BaseEntity
this.scopeNames = scopeNames;
}
// 新增证书字段的 getter setter
public Long getCertId() {
return certId;
}
public void setCertId(Long certId) {
this.certId = certId;
}
public String getCertName() {
return certName;
}
@ -387,6 +750,66 @@ public class VetQualification extends BaseEntity
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
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
@ -404,6 +827,7 @@ public class VetQualification extends BaseEntity
.append("auditorId", getAuditorId())
.append("scopeIds", getScopeIds())
.append("scopeNames", getScopeNames())
.append("certId", getCertId())
.append("certName", getCertName())
.append("certType", getCertType())
.append("issueOrg", getIssueOrg())
@ -418,6 +842,8 @@ public class VetQualification extends BaseEntity
.append("updateBy", getUpdateBy())
.append("updateTime", getUpdateTime())
.append("remark", getRemark())
.append("certificatesJson", getCertificatesJson())
.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.Map;
import com.chenhai.vet.domain.VetExperienceArticle;
import org.apache.ibatis.annotations.Param;
/**
* 兽医经验文章Mapper接口
*
*
* @author ruoyi
* @date 2026-01-06
*/
public interface VetExperienceArticleMapper
public interface VetExperienceArticleMapper
{
/**
* 查询兽医经验文章
*
*
* @param id 兽医经验文章主键
* @return 兽医经验文章
*/
@ -24,7 +23,7 @@ public interface VetExperienceArticleMapper
/**
* 查询兽医经验文章列表
*
*
* @param vetExperienceArticle 兽医经验文章
* @return 兽医经验文章集合
*/
@ -32,7 +31,7 @@ public interface VetExperienceArticleMapper
/**
* 新增兽医经验文章
*
*
* @param vetExperienceArticle 兽医经验文章
* @return 结果
*/
@ -40,7 +39,7 @@ public interface VetExperienceArticleMapper
/**
* 修改兽医经验文章
*
*
* @param vetExperienceArticle 兽医经验文章
* @return 结果
*/
@ -48,7 +47,7 @@ public interface VetExperienceArticleMapper
/**
* 删除兽医经验文章
*
*
* @param id 兽医经验文章主键
* @return 结果
*/
@ -56,39 +55,50 @@ public interface VetExperienceArticleMapper
/**
* 批量删除兽医经验文章
*
*
* @param ids 需要删除的数据主键集合
* @return 结果
*/
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 org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
/**
* 兽医资质Mapper接口
@ -67,4 +69,6 @@ public interface VetQualificationMapper
*/
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.Map;
import com.chenhai.vet.domain.VetExperienceArticle;
/**
* 兽医经验文章Service接口
*
*
* @author ruoyi
* @date 2026-01-06
*/
public interface IVetExperienceArticleService
public interface IVetExperienceArticleService
{
/**
* 查询兽医经验文章
*
*
* @param id 兽医经验文章主键
* @return 兽医经验文章
*/
@ -23,7 +22,7 @@ public interface IVetExperienceArticleService
/**
* 查询兽医经验文章列表
*
*
* @param vetExperienceArticle 兽医经验文章
* @return 兽医经验文章集合
*/
@ -31,7 +30,7 @@ public interface IVetExperienceArticleService
/**
* 新增兽医经验文章
*
*
* @param vetExperienceArticle 兽医经验文章
* @return 结果
*/
@ -39,7 +38,7 @@ public interface IVetExperienceArticleService
/**
* 修改兽医经验文章
*
*
* @param vetExperienceArticle 兽医经验文章
* @return 结果
*/
@ -47,7 +46,7 @@ public interface IVetExperienceArticleService
/**
* 批量删除兽医经验文章
*
*
* @param ids 需要删除的兽医经验文章主键集合
* @return 结果
*/
@ -55,65 +54,82 @@ public interface IVetExperienceArticleService
/**
* 删除兽医经验文章信息
*
*
* @param id 兽医经验文章主键
* @return 结果
*/
public int deleteVetExperienceArticleById(Long id);
/**
* 获取推荐文章精选+置顶
*/
List<VetExperienceArticle> selectFeaturedArticles(Integer limit);
List<VetExperienceArticle> searchArticles(String keyword);
/**
* 获取最新文章
*
* @param limit 限制数量
* @return 文章集合
*/
List<VetExperienceArticle> selectLatestArticles(Integer limit);
/**
* 获取热门文章按浏览数排序
*
* @param limit 限制数量
* @return 文章集合
*/
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);
/**
* 增加浏览数
*
* @param id 文章ID
* @return 结果
*/
int incrementViewCount(Long id);
/**
* 增加点赞数
*
* @param id 文章ID
* @return 结果
*/
int incrementLikeCount(Long id);
/**
* 增加收藏数
*
* @param id 文章ID
* @return 结果
*/
int incrementCollectCount(Long id);
/**
* 获取论坛统计信息
*
* @return 统计信息
*/
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);
/**
* 提交审核
*
* @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);
/**
* 提交资质审核新方法处理复杂数据结构
*/
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;
import java.util.*;
import java.util.stream.Collectors;
import com.chenhai.common.utils.DateUtils;
import com.github.pagehelper.PageHelper;
import org.springframework.beans.factory.annotation.Autowired;
@ -13,19 +11,19 @@ import com.chenhai.vet.service.IVetExperienceArticleService;
/**
* 兽医经验文章Service业务层处理
*
*
* @author ruoyi
* @date 2026-01-06
*/
@Service
public class VetExperienceArticleServiceImpl implements IVetExperienceArticleService
public class VetExperienceArticleServiceImpl implements IVetExperienceArticleService
{
@Autowired
private VetExperienceArticleMapper vetExperienceArticleMapper;
/**
* 查询兽医经验文章
*
*
* @param id 兽医经验文章主键
* @return 兽医经验文章
*/
@ -37,7 +35,7 @@ public class VetExperienceArticleServiceImpl implements IVetExperienceArticleSer
/**
* 查询兽医经验文章列表
*
*
* @param vetExperienceArticle 兽医经验文章
* @return 兽医经验文章
*/
@ -49,7 +47,7 @@ public class VetExperienceArticleServiceImpl implements IVetExperienceArticleSer
/**
* 新增兽医经验文章
*
*
* @param vetExperienceArticle 兽医经验文章
* @return 结果
*/
@ -62,7 +60,7 @@ public class VetExperienceArticleServiceImpl implements IVetExperienceArticleSer
/**
* 修改兽医经验文章
*
*
* @param vetExperienceArticle 兽医经验文章
* @return 结果
*/
@ -75,7 +73,7 @@ public class VetExperienceArticleServiceImpl implements IVetExperienceArticleSer
/**
* 批量删除兽医经验文章
*
*
* @param ids 需要删除的兽医经验文章主键
* @return 结果
*/
@ -87,7 +85,7 @@ public class VetExperienceArticleServiceImpl implements IVetExperienceArticleSer
/**
* 删除兽医经验文章信息
*
*
* @param id 兽医经验文章主键
* @return 结果
*/
@ -97,190 +95,178 @@ public class VetExperienceArticleServiceImpl implements IVetExperienceArticleSer
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
public List<VetExperienceArticle> selectLatestArticles(Integer limit) {
PageHelper.clearPage();
Map<String, Object> params = new HashMap<>();
params.put("status", 1);
params.put("status", "1");
params.put("orderBy", "publish_time");
params.put("orderType", "desc");
params.put("limit", limit != null ? limit : 10);
return vetExperienceArticleMapper.selectArticlesByCondition(params);
}
/**
* 获取热门文章按浏览数排序
*
* @param limit 限制数量
* @return 文章集合
*/
@Override
public List<VetExperienceArticle> selectHotArticles(Integer limit) {
PageHelper.clearPage();
Map<String, Object> params = new HashMap<>();
params.put("status", 1);
params.put("status", "1");
params.put("orderBy", "view_count");
params.put("orderType", "desc");
params.put("limit", limit != null ? limit : 10);
return vetExperienceArticleMapper.selectArticlesByCondition(params);
}
/**
* 根据用户ID获取文章
*
* @param userId 用户ID
* @param limit 限制数量
* @return 文章集合
*/
@Override
public List<VetExperienceArticle> selectArticlesByVetId(Long vetId, Integer limit) {
public List<VetExperienceArticle> selectArticlesByUserId(Long userId, Integer limit) {
PageHelper.clearPage();
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("orderType", "desc");
params.put("limit", limit != null ? limit : 5);
return vetExperienceArticleMapper.selectArticlesByCondition(params);
}
/**
* 获取相关文章
*
* @param excludeId 排除的文章ID
* @param categoryId 分类ID
* @param limit 限制数量
* @return 文章集合
*/
@Override
public List<VetExperienceArticle> selectRelatedArticles(Long excludeId, Long categoryId, Integer limit) {
PageHelper.clearPage();
Map<String, Object> params = new HashMap<>();
params.put("status", "1");
params.put("excludeId", excludeId);
params.put("categoryId", categoryId);
params.put("status", 1);
params.put("orderBy", "publish_time");
params.put("orderType", "desc");
params.put("limit", limit != null ? limit : 4);
return vetExperienceArticleMapper.selectArticlesByCondition(params);
}
/**
* 增加浏览数
*
* @param id 文章ID
* @return 结果
*/
@Override
public int incrementViewCount(Long id) {
return vetExperienceArticleMapper.incrementViewCount(id);
}
/**
* 增加点赞数
*
* @param id 文章ID
* @return 结果
*/
@Override
public int incrementLikeCount(Long id) {
return vetExperienceArticleMapper.incrementLikeCount(id);
}
/**
* 增加收藏数
*
* @param id 文章ID
* @return 结果
*/
@Override
public int incrementCollectCount(Long id) {
return vetExperienceArticleMapper.incrementCollectCount(id);
}
/**
* 获取论坛统计信息
*
* @return 统计信息
*/
@Override
public Map<String, Object> selectForumStatistics() {
PageHelper.clearPage();
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());
// 获取兽医总数去重
Set<Long> vetIds = new HashSet<>();
// 统计作者总数去重
Set<Long> authorIds = new HashSet<>();
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;
for (VetExperienceArticle article : allArticles) {
totalViews += article.getViewCount() != null ? article.getViewCount() : 0;
}
statistics.put("totalViews", totalViews);
// 获取总点赞数
// 统计总点赞数
int totalLikes = 0;
for (VetExperienceArticle article : allArticles) {
totalLikes += article.getLikeCount() != null ? article.getLikeCount() : 0;
}
statistics.put("totalLikes", totalLikes);
// 统计总收藏数
int totalCollects = 0;
for (VetExperienceArticle article : allArticles) {
totalCollects += article.getCollectCount() != null ? article.getCollectCount() : 0;
}
statistics.put("totalCollects", totalCollects);
return statistics;
}
/**
* 根据标签筛选文章简单实现
* 搜索文章
*
* @param keyword 关键词
* @return 文章集合
*/
@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;
import java.util.Date;
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.stereotype.Service;
import com.chenhai.vet.mapper.VetProductMapper;
import com.chenhai.vet.domain.VetProduct;
import com.chenhai.vet.service.IVetProductService;
import org.springframework.transaction.annotation.Transactional;
/**
* 兽医产品信息Service业务层处理
@ -50,11 +54,11 @@ public class VetProductServiceImpl implements IVetProductService
* @param vetProduct 兽医产品信息
* @return 结果
*/
@Override
/* @Override
public int insertVetProduct(VetProduct vetProduct)
{
return vetProductMapper.insertVetProduct(vetProduct);
}
}*/
/**
* 修改兽医产品信息
@ -91,4 +95,158 @@ public class VetProductServiceImpl implements IVetProductService
{
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>
<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
</sql>
<!-- 查询兽医经验文章 -->
<select id="selectVetExperienceArticleById" parameterType="Long" resultMap="VetExperienceArticleResult">
<include refid="selectVetExperienceArticleVo"/>
where id = #{id}
</select>
<!-- 查询兽医经验文章列表 -->
<select id="selectVetExperienceArticleList" parameterType="VetExperienceArticle" resultMap="VetExperienceArticleResult">
<include refid="selectVetExperienceArticleVo"/>
<where>
@ -51,26 +54,23 @@
<if test="categoryId != null"> and category_id = #{categoryId}</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="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 != ''">
and (
tags = #{tags}
or tags like concat(#{tags}, ',%')
or tags like concat('%,', #{tags}, ',%')
or tags like concat('%,', #{tags})
or tags like concat('%', #{tags}, '%')
)
</if>
</where>
order by create_time desc
order by publish_time desc
</select>
<!-- 根据条件查询文章(论坛专用) -->
<!-- 根据条件查询文章列表(论坛专用) -->
<select id="selectArticlesByCondition" parameterType="map" resultMap="VetExperienceArticleResult">
<!-- 关键:使用PageHelper的特殊注释 -->
/* keepOrder */
<include refid="selectVetExperienceArticleVo"/>
<where>
status = #{status}
@ -84,73 +84,58 @@
</if>
<if test="userId != null"> and user_id = #{userId}</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>
</where>
<!-- 必须放在最后 -->
ORDER BY
<!-- 先ORDER BY,后LIMIT -->
order by
<choose>
<when test="orderBy != null and orderType != null">
${orderBy} ${orderType}
</when>
<otherwise>
publish_time DESC
publish_time desc
</otherwise>
</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 id="searchArticles" parameterType="map" resultMap="VetExperienceArticleResult">
<!-- 搜索文章 -->
<select id="searchArticles" resultMap="VetExperienceArticleResult">
<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
</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>
<!-- 增加浏览数 -->
<update id="incrementViewCount" parameterType="Long">
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}
</update>
<!-- 增加点赞数 -->
<update id="incrementLikeCount" parameterType="Long">
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}
</update>
<!-- 增加收藏数 -->
<update id="incrementCollectCount" parameterType="Long">
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}
</update>
<!-- 新增兽医经验文章 -->
<insert id="insertVetExperienceArticle" parameterType="VetExperienceArticle" useGeneratedKeys="true" keyProperty="id">
insert into vet_experience_article
<trim prefix="(" suffix=")" suffixOverrides=",">
@ -175,7 +160,7 @@
<if test="isSensitive != null">is_sensitive,</if>
<if test="sensitiveWords != null">sensitive_words,</if>
<if test="publishTime != null">publish_time,</if>
<if test="createTime != null">create_time,</if>
create_time,
<if test="updateTime != null">update_time,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
@ -200,11 +185,12 @@
<if test="isSensitive != null">#{isSensitive},</if>
<if test="sensitiveWords != null">#{sensitiveWords},</if>
<if test="publishTime != null">#{publishTime},</if>
<if test="createTime != null">#{createTime},</if>
now(),
<if test="updateTime != null">#{updateTime},</if>
</trim>
</insert>
<!-- 修改兽医经验文章 -->
<update id="updateVetExperienceArticle" parameterType="VetExperienceArticle">
update vet_experience_article
<trim prefix="SET" suffixOverrides=",">
@ -229,27 +215,21 @@
<if test="isSensitive != null">is_sensitive = #{isSensitive},</if>
<if test="sensitiveWords != null">sensitive_words = #{sensitiveWords},</if>
<if test="publishTime != null">publish_time = #{publishTime},</if>
<if test="updateTime != null">update_time = #{updateTime},</if>
update_time = now(),
</trim>
where id = #{id}
</update>
<!-- 删除兽医经验文章 -->
<delete id="deleteVetExperienceArticleById" parameterType="Long">
delete from vet_experience_article where id = #{id}
</delete>
<!-- 批量删除兽医经验文章 -->
<delete id="deleteVetExperienceArticleByIds" parameterType="Long">
delete from vet_experience_article where id in
<foreach item="id" collection="array" open="(" separator="," close=")">
#{id}
</foreach>
</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>

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="createdAt" column="created_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>
<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>
<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="createdAt != null "> and created_at = #{createdAt}</if>
<if test="updatedAt != null "> and updated_at = #{updatedAt}</if>
<if test="auditStatus != null and auditStatus != ''"> and audit_status = #{auditStatus}</if>
</where>
</select>
@ -107,6 +112,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="userId != null">user_id,</if>
<if test="createdAt != null">created_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 prefix="values (" suffix=")" suffixOverrides=",">
<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="createdAt != null">#{createdAt},</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>
</insert>
@ -169,6 +182,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="userId != null">user_id = #{userId},</if>
<if test="createdAt != null">created_at = #{createdAt},</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>
where id = #{id}
</update>

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

@ -26,6 +26,7 @@
<result property="scopeIds" column="scope_ids" />
<result property="scopeNames" column="scope_names" />
<!-- 新增证书字段 -->
<result property="certId" column="cert_id" />
<result property="certName" column="cert_name" />
<result property="certType" column="cert_type" />
<result property="issueOrg" column="issue_org" />
@ -36,6 +37,7 @@
<result property="certStatusLabel" column="cert_status_label"/>
<result property="remindDays" column="remind_days" />
<result property="lastRemindTime" column="last_remind_time" />
<result property="certificatesJson" column="certificates_json"/>
</resultMap>
<sql id="selectVetQualificationVo">
@ -69,6 +71,8 @@
<if test="auditOpinion != null and auditOpinion != ''"> and vq.audit_opinion = #{auditOpinion}</if>
<if test="auditorId != null "> and vq.auditor_id = #{auditorId}</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="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="idCard != null and idCard != ''">id_card,</if>
<if test="qualificationType != null and qualificationType != ''">qualification_type,</if>
<!-- ⚠️ 修改:让certificate_no成为可选字段 -->
<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="applyTime != null">apply_time,</if>
<if test="auditTime != null">audit_time,</if>
@ -112,6 +121,7 @@
<if test="scopeIds != null and scopeIds != ''">scope_ids,</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="certType != null and certType != ''">cert_type,</if>
<if test="issueOrg != null and issueOrg != ''">issue_org,</if>
@ -127,7 +137,12 @@
<if test="realName != null and realName != ''">#{realName},</if>
<if test="idCard != null and idCard != ''">#{idCard},</if>
<if test="qualificationType != null and qualificationType != ''">#{qualificationType},</if>
<!-- ⚠️ 修改:让certificate_no成为可选字段 -->
<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="applyTime != null">#{applyTime},</if>
<if test="auditTime != null">#{auditTime},</if>
@ -142,6 +157,7 @@
<if test="scopeIds != null and scopeIds != ''">#{scopeIds},</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="certType != null and certType != ''">#{certType},</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="qualificationType != null and qualificationType != ''">qualification_type = #{qualificationType},</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="applyTime != null">apply_time = #{applyTime},</if>
<if test="auditTime != null">audit_time = #{auditTime},</if>
@ -174,6 +194,7 @@
<if test="scopeIds != null">scope_ids = #{scopeIds},</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="certType != null">cert_type = #{certType},</if>
<if test="issueOrg != null">issue_org = #{issueOrg},</if>
@ -205,4 +226,24 @@
ORDER BY create_time DESC
</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>

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

@ -42,3 +42,44 @@ export function delProduct(id) {
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"
>
<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-form-item>
<el-form-item label="状态" prop="status">
@ -42,6 +61,20 @@
<el-option label="下架" value="2" />
</el-select>
</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-button type="primary" icon="el-icon-search" @click="handleQuery">
搜索
@ -147,17 +180,12 @@
</div>
<div class="product-info">
<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>
</template>
</el-table-column>
<!-- 其他列保持不变 -->
<!-- 产品类型 -->
<el-table-column
label="类型"
prop="type"
@ -174,12 +202,22 @@
</template>
</el-table-column>
<!-- 产品分类 -->
<el-table-column
label="分类"
prop="category"
width="100"
width="120"
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
label="规格"
@ -233,6 +271,22 @@
</template>
</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
label="生产厂家"
prop="manufacturer"
@ -255,11 +309,12 @@
<el-table-column
label="操作"
align="center"
width="250"
width="300"
fixed="right"
class-name="small-padding fixed-width"
>
<template slot-scope="scope">
<!-- 详情按钮 -->
<el-button
size="mini"
type="text"
@ -268,15 +323,20 @@
>
详情
</el-button>
<!-- 编辑按钮仅在草稿/审核驳回/敏感内容驳回状态显示 -->
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['vet:product:edit']"
v-if="scope.row.status === '0' && scope.row.auditStatus === '3'"
>
编辑
</el-button>
<!-- 删除按钮 -->
<el-button
size="mini"
type="text"
@ -287,6 +347,70 @@
>
删除
</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>
</el-table-column>
</el-table>
@ -389,9 +513,10 @@
<el-col :span="12">
<el-form-item label="产品类型" prop="type">
<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-form-item>
</el-col>
@ -400,7 +525,16 @@
<el-row :gutter="20">
<el-col :span="12">
<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-col>
<el-col :span="12">
@ -654,7 +788,9 @@
</el-tag>
</el-descriptions-item>
<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 label="规格">
{{ currentDetail.specification || '--' }}
@ -673,6 +809,11 @@
{{ getStatusText(currentDetail.status) }}
</el-tag>
</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="销售价格">
<span style="color: #f56c6c; font-weight: bold;">¥{{ currentDetail.price || '0.00' }}</span>
</el-descriptions-item>
@ -727,7 +868,7 @@
</template>
<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'
export default {
@ -764,7 +905,9 @@ export default {
pageSize: 10,
name: null,
type: null,
category: null,
status: null,
auditStatus: null,
},
form: {
@ -798,7 +941,9 @@ export default {
clinicId: null,
userId: null,
createdAt: null,
updatedAt: null
updatedAt: null,
auditStatus: null,
auditOpinion: null
},
rules: {
@ -808,6 +953,9 @@ export default {
type: [
{ required: true, message: "产品类型不能为空", trigger: "change" }
],
category: [
{ required: true, message: "产品分类不能为空", trigger: "change" }
],
price: [
{ required: true, message: "销售价格不能为空", trigger: "blur" },
{ pattern: /^\d+(\.\d{1,2})?$/, message: '请输入正确的价格格式' }
@ -892,6 +1040,8 @@ export default {
treatmentDuration: data.treatmentDuration || data.treatment_duration,
precautions: data.precautions,
status: data.status,
auditStatus: data.auditStatus || data.audit_status,
auditOpinion: data.auditOpinion || data.audit_opinion,
createdAt: data.createdAt || data.created_at,
updatedAt: data.updatedAt || data.updated_at
}
@ -947,6 +1097,8 @@ export default {
treatmentDuration: item.treatmentDuration,
precautions: item.precautions,
status: item.status,
auditStatus: item.auditStatus || item.audit_status,
auditOpinion: item.auditOpinion || item.audit_opinion,
isDeleted: item.isDeleted,
clinicId: item.clinicId,
userId: item.userId,
@ -965,12 +1117,6 @@ export default {
updatedAt: item.updatedAt !== undefined ? item.updatedAt : (item.updated_at || new Date())
}
console.log('产品图片信息:', {
mainImage: processedItem.mainImage,
imageList: processedItem.imageList,
images: processedItem.images
})
return processedItem
})
@ -1035,8 +1181,6 @@ export default {
getFullImageUrl(url) {
if (!url) return ''
console.log('原始图片路径:', url)
// URL
if (url.startsWith('http://') || url.startsWith('https://')) {
return url
@ -1132,12 +1276,75 @@ export default {
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() {
this.open = false
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() {
this.form = {
@ -1170,7 +1377,9 @@ export default {
clinicId: null,
userId: this.getCurrentUserId(),
createdAt: null,
updatedAt: null
updatedAt: null,
auditStatus: null,
auditOpinion: null
}
this.activeTab = 'basic'
this.resetForm("form")
@ -1239,6 +1448,8 @@ export default {
treatmentDuration: data.treatmentDuration || data.treatment_duration,
precautions: data.precautions,
status: String(data.status || '0'),
auditStatus: data.auditStatus || data.audit_status,
auditOpinion: data.auditOpinion || data.audit_opinion,
isDeleted: data.isDeleted || data.is_deleted,
clinicId: data.clinicId || data.clinic_id,
userId: data.userId || data.user_id,
@ -1349,9 +1560,10 @@ export default {
/** 获取产品类型文本 */
getTypeText(type) {
const map = {
medicine: '兽药',
vaccine: '疫苗',
supplement: '保健品'
"0": '处方药',
"1": '非处方药',
"2": '中成药',
"3": '保健品'
}
return map[type] || type
},
@ -1359,13 +1571,44 @@ export default {
/** 获取产品类型标签类型 */
getTypeTagType(type) {
const map = {
medicine: 'danger',
vaccine: 'warning',
supplement: 'success'
"0": 'danger', // -
"1": 'warning', // -
"2": 'success', // - 绿
"3": 'primary' // -
}
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) {
const map = {
@ -1386,6 +1629,28 @@ export default {
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) {
if (!stock || stock === 0) return 'stock-out'
@ -1802,4 +2067,16 @@ export default {
.el-row {
margin-bottom: 10px;
}
//
.operation-buttons {
display: flex;
flex-wrap: wrap;
gap: 5px;
.el-button {
margin: 0 !important;
padding: 4px 6px;
}
}
</style>
Loading…
Cancel
Save