Browse Source

合并资质上传和证书管理

master
ChaiNingQi 1 month ago
parent
commit
8e44b17119
  1. 318
      chenhai-admin/src/main/java/com/chenhai/web/controller/vet/VetCertificateController.java
  2. 233
      chenhai-admin/src/main/java/com/chenhai/web/controller/vet/VetExperienceArticleController.java
  3. 3
      chenhai-admin/src/main/java/com/chenhai/web/controller/vet/VetPersonalInfoController.java
  4. 104
      chenhai-admin/src/main/java/com/chenhai/web/controller/vet/VetProductController.java
  5. 177
      chenhai-admin/src/main/java/com/chenhai/web/controller/vet/VetQualificationController.java
  6. 100
      chenhai-system/src/main/java/com/chenhai/vet/CertificateRemindTask.java
  7. 212
      chenhai-system/src/main/java/com/chenhai/vet/domain/VetCertificate.java
  8. 447
      chenhai-system/src/main/java/com/chenhai/vet/domain/VetProduct.java
  9. 263
      chenhai-system/src/main/java/com/chenhai/vet/domain/VetQualification.java
  10. 62
      chenhai-system/src/main/java/com/chenhai/vet/mapper/VetCertificateMapper.java
  11. 61
      chenhai-system/src/main/java/com/chenhai/vet/mapper/VetProductMapper.java
  12. 25
      chenhai-system/src/main/java/com/chenhai/vet/mapper/VetQualificationMapper.java
  13. 72
      chenhai-system/src/main/java/com/chenhai/vet/service/IVetCertificateService.java
  14. 4
      chenhai-system/src/main/java/com/chenhai/vet/service/IVetExperienceArticleService.java
  15. 6
      chenhai-system/src/main/java/com/chenhai/vet/service/IVetPersonalInfoService.java
  16. 61
      chenhai-system/src/main/java/com/chenhai/vet/service/IVetProductService.java
  17. 48
      chenhai-system/src/main/java/com/chenhai/vet/service/IVetQualificationService.java
  18. 6
      chenhai-system/src/main/java/com/chenhai/vet/service/VetNotificationService.java
  19. 349
      chenhai-system/src/main/java/com/chenhai/vet/service/impl/VetCertificateServiceImpl.java
  20. 25
      chenhai-system/src/main/java/com/chenhai/vet/service/impl/VetExperienceArticleServiceImpl.java
  21. 88
      chenhai-system/src/main/java/com/chenhai/vet/service/impl/VetNotificationServiceImpl.java
  22. 160
      chenhai-system/src/main/java/com/chenhai/vet/service/impl/VetPersonalInfoServiceImpl.java
  23. 93
      chenhai-system/src/main/java/com/chenhai/vet/service/impl/VetProductServiceImpl.java
  24. 264
      chenhai-system/src/main/java/com/chenhai/vet/service/impl/VetQualificationServiceImpl.java
  25. 122
      chenhai-system/src/main/resources/mapper/vet/VetCertificateMapper.xml
  26. 9
      chenhai-system/src/main/resources/mapper/vet/VetExperienceArticleMapper.xml
  27. 186
      chenhai-system/src/main/resources/mapper/vet/VetProductMapper.xml
  28. 116
      chenhai-system/src/main/resources/mapper/vet/VetQualificationMapper.xml
  29. 54
      chenhai-ui/src/api/vet/certificate.js
  30. 44
      chenhai-ui/src/api/vet/product.js
  31. 10
      chenhai-ui/src/api/vet/qualification.js
  32. 427
      chenhai-ui/src/views/vet/certificate/index.vue
  33. 27
      chenhai-ui/src/views/vet/comments/index.vue
  34. 244
      chenhai-ui/src/views/vet/info/index.vue
  35. 552
      chenhai-ui/src/views/vet/product/index.vue
  36. 520
      chenhai-ui/src/views/vet/qualification/index.vue

318
chenhai-admin/src/main/java/com/chenhai/web/controller/vet/VetCertificateController.java

@ -1,318 +0,0 @@
package com.chenhai.web.controller.vet;
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.VetCertificate;
import com.chenhai.vet.service.IVetCertificateService;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.propertyeditors.CustomNumberEditor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
/**
* 兽医执业证书Controller
*
* @author ruoyi
* @date 2025-12-29
*/
@RestController
@RequestMapping("/vet/certificate")
public class VetCertificateController extends BaseController
{
@Autowired
private IVetCertificateService vetCertificateService;
/**
* 初始化数据绑定处理空字符串转换问题
* 防止前端传递空字符串导致Long类型绑定失败
*/
@InitBinder
public void initBinder(WebDataBinder binder) {
// 处理Long类型字段的空字符串问题
binder.registerCustomEditor(Long.class, new CustomNumberEditor(Long.class, true) {
@Override
public void setAsText(String text) throws IllegalArgumentException {
if (text == null || text.trim().isEmpty()) {
setValue(null); // 将空字符串转换为null
} else {
try {
setValue(Long.parseLong(text.trim()));
} catch (NumberFormatException e) {
setValue(null); // 转换失败也设为null
}
}
}
@Override
public String getAsText() {
Object value = getValue();
return (value != null ? value.toString() : "");
}
});
}
/**
* 获取当前用户ID
*/
private Long getCurrentUserId() {
return SecurityUtils.getUserId();
}
/**
* 检查是否为管理员
*/
private boolean isAdmin() {
return SecurityUtils.isAdmin(getCurrentUserId());
}
/**
* 检查用户是否有权限访问该证书
*/
private boolean canAccessCertificate(Long certificateId) {
if (isAdmin()) {
return true;
}
Long currentUserId = getCurrentUserId();
if (currentUserId == null) {
return false;
}
VetCertificate certificate = vetCertificateService.selectVetCertificateById(certificateId);
return certificate != null && currentUserId.equals(certificate.getUserId());
}
/**
* 查询兽医执业证书列表证书管理页面使用
* 管理员查看所有证书
* 普通用户查看自己的证书
*/
@PreAuthorize("@ss.hasPermi('vet:certificate:list')")
@GetMapping("/list")
public TableDataInfo list(VetCertificate vetCertificate)
{
startPage();
Long currentUserId = getCurrentUserId();
if (currentUserId == null) {
return getDataTable(List.of());
}
// 管理员可以查看所有普通用户只能查看自己的
if (!isAdmin()) {
vetCertificate.setUserId(currentUserId);
}
// 管理员不设置userId查看所有
List<VetCertificate> list = vetCertificateService.selectVetCertificateList(vetCertificate);
return getDataTable(list);
}
/**
* 用户详情页查询证书专用于用户详情页
* 查看指定用户的证书列表
*/
@PreAuthorize("@ss.hasPermi('vet:certificate:list')")
@GetMapping("/listForDetail")
public TableDataInfo listForDetail(@RequestParam(value = "userId", required = false) Long userId)
{
startPage();
Long currentUserId = getCurrentUserId();
if (currentUserId == null) {
return getDataTable(List.of());
}
// 如果没有传userId返回空
if (userId == null) {
return getDataTable(List.of());
}
// 权限检查管理员或查看自己
if (!isAdmin() && !userId.equals(currentUserId)) {
return getDataTable(List.of());
}
VetCertificate query = new VetCertificate();
query.setUserId(userId);
List<VetCertificate> list = vetCertificateService.selectVetCertificateList(query);
return getDataTable(list);
}
/**
* 导出兽医执业证书列表
*/
@PreAuthorize("@ss.hasPermi('vet:certificate:export')")
@Log(title = "兽医执业证书", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(HttpServletResponse response, VetCertificate vetCertificate)
{
List<VetCertificate> list = vetCertificateService.selectVetCertificateList(vetCertificate);
ExcelUtil<VetCertificate> util = new ExcelUtil<VetCertificate>(VetCertificate.class);
util.exportExcel(response, list, "兽医执业证书数据");
}
/**
* 获取兽医执业证书详细信息
*/
@PreAuthorize("@ss.hasPermi('vet:certificate:query')")
@GetMapping(value = "/{id}")
public AjaxResult getInfo(@PathVariable("id") Long id)
{
// 权限检查
if (!canAccessCertificate(id)) {
return error("没有权限查看此证书");
}
return success(vetCertificateService.selectVetCertificateById(id));
}
/**
* 新增兽医执业证书
*/
@PreAuthorize("@ss.hasPermi('vet:certificate:add')")
@Log(title = "兽医执业证书", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@RequestBody VetCertificate vetCertificate)
{
// 自动设置当前用户ID
Long currentUserId = getCurrentUserId();
if (currentUserId == null) {
return error("用户未登录");
}
// 权限检查普通用户只能给自己添加证书
if (!isAdmin() && vetCertificate.getUserId() != null &&
!vetCertificate.getUserId().equals(currentUserId)) {
return error("没有权限为其他用户添加证书");
}
// 设置用户ID和创建人
vetCertificate.setUserId(currentUserId);
vetCertificate.setCreateBy(SecurityUtils.getUsername());
return toAjax(vetCertificateService.insertVetCertificate(vetCertificate));
}
/**
* 修改兽医执业证书
*/
@PreAuthorize("@ss.hasPermi('vet:certificate:edit')")
@Log(title = "兽医执业证书", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody VetCertificate vetCertificate)
{
// 权限检查
if (!canAccessCertificate(vetCertificate.getId())) {
return error("没有权限修改此证书");
}
// 如果是普通用户确保不能修改用户ID
if (!isAdmin()) {
Long currentUserId = getCurrentUserId();
if (currentUserId != null && vetCertificate.getUserId() != null &&
!vetCertificate.getUserId().equals(currentUserId)) {
return error("不能修改证书所属用户");
}
}
return toAjax(vetCertificateService.updateVetCertificate(vetCertificate));
}
/**
* 删除兽医执业证书
*/
@PreAuthorize("@ss.hasPermi('vet:certificate:remove')")
@Log(title = "兽医执业证书", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable Long[] ids)
{
// 权限检查检查是否所有证书都可以删除
if (!isAdmin()) {
for (Long id : ids) {
if (!canAccessCertificate(id)) {
return error("没有权限删除证书ID: " + id);
}
}
}
return toAjax(vetCertificateService.deleteVetCertificateByIds(ids));
}
/**
* 根据用户ID获取证书列表兼容旧版本建议前端迁移到listForDetail
*/
@GetMapping("/user/{userId}")
public AjaxResult getByUserId(@PathVariable Long userId)
{
Long currentUserId = getCurrentUserId();
// 权限检查
if (!isAdmin() && !userId.equals(currentUserId)) {
return error("没有权限查看其他用户的证书");
}
List<VetCertificate> list = vetCertificateService.selectCertificatesByUserId(userId);
return success(list);
}
/**
* 获取即将过期的证书
*/
@GetMapping("/expiring/{userId}")
public AjaxResult getExpiringCertificates(@PathVariable Long userId)
{
Long currentUserId = getCurrentUserId();
// 权限检查
if (!isAdmin() && !userId.equals(currentUserId)) {
return error("没有权限查看其他用户的证书");
}
List<VetCertificate> list = vetCertificateService.selectExpiringCertificates(userId);
return success(list);
}
/**
* 获取证书统计信息
*/
@GetMapping("/statistics/{userId}")
public AjaxResult getStatistics(@PathVariable Long userId)
{
Long currentUserId = getCurrentUserId();
// 权限检查
if (!isAdmin() && !userId.equals(currentUserId)) {
return error("没有权限查看其他用户的统计信息");
}
Map<String, Object> statistics = vetCertificateService.getCertificateStatistics(userId);
return success(statistics);
}
/**
* 手动触发证书检查
*/
@PostMapping("/manual-check/{userId}")
public AjaxResult manualCheck(@PathVariable Long userId)
{
Long currentUserId = getCurrentUserId();
// 权限检查
if (!isAdmin() && !userId.equals(currentUserId)) {
return error("没有权限为其他用户检查证书");
}
vetCertificateService.manualCheckCertificates(userId);
return success("证书检查完成");
}
}

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

@ -1,5 +1,5 @@
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;
@ -17,6 +17,8 @@ import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
/**
* 兽医经验分享Controller
@ -31,6 +33,11 @@ public class VetExperienceArticleController extends BaseController {
@Autowired // 确保有这个注解
private VetArticleCategoryMapper vetArticleCategoryMapper;
/**
* 简单收藏管理使用Map存储
*/
private static final Map<Long, Set<Long>> COLLECTION_STORE = new ConcurrentHashMap<>();
/**
* 查询兽医经验文章列表
@ -97,6 +104,8 @@ public class VetExperienceArticleController extends BaseController {
return AjaxResult.success(options);
}
/**
* 根据分类查询文章
*/
@ -118,6 +127,102 @@ public class VetExperienceArticleController extends BaseController {
}
/**
* 获取文章标签选项
*/
@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) {
startPage();
// 标签映射
String tagName = getTagNameByDictValue(dictValue);
if (tagName == null || tagName.isEmpty()) {
return getDataTable(new ArrayList<>());
}
VetExperienceArticle query = new VetExperienceArticle();
query.setStatus("1");
query.setTags(tagName);
List<VetExperienceArticle> list = vetExperienceArticleService.selectVetExperienceArticleList(query);
return getDataTable(list);
}
/**
* 辅助方法创建选项
*/
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) {
startPage();
VetExperienceArticle query = new VetExperienceArticle();
query.setStatus("1");
query.setTags(tagName);
List<VetExperienceArticle> list = vetExperienceArticleService.selectVetExperienceArticleList(query);
return getDataTable(list);
}
/**
* 获取所有兽医已发布的文章
@ -245,6 +350,88 @@ public class VetExperienceArticleController extends BaseController {
return getDataTable(list);
}
/**
* 获取我的收藏文章列表
*/
@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<>());
}
// 查询文章详情
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()));
return getDataTable(result);
}
/**
* 获取我的文章简单统计直接在Controller实现
*/
@GetMapping("/my/simpleStats")
public AjaxResult getMySimpleStats() {
// 获取当前用户ID - 使用系统的方法
Long currentUserId = SecurityUtils.getUserId();
System.out.println("当前用户ID: " + currentUserId); // 调试用
if (currentUserId == null) {
// 如果是开发测试可以使用临时用户ID
currentUserId = 1L; // 测试用
System.out.println("使用测试用户ID: " + currentUserId);
}
// 查询当前用户已发布的文章
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);
}
/**
* 点赞文章
*/
@ -258,11 +445,39 @@ public class VetExperienceArticleController extends BaseController {
* 收藏文章
*/
@PostMapping("/forum/{id}/collect")
public AjaxResult collectArticle(@PathVariable Long id) {
int result = vetExperienceArticleService.incrementCollectCount(id);
return toAjax(result);
}
public AjaxResult collectArticle(@PathVariable("id") Long id) {
Long currentUserId = getUserId();
if (currentUserId == null) {
return error("请先登录");
}
// 检查文章是否存在
VetExperienceArticle article = vetExperienceArticleService.selectVetExperienceArticleById(id);
if (article == null) {
return error("文章不存在");
}
// 不能收藏自己的文章
if (currentUserId.equals(article.getUserId())) {
return error("不能收藏自己的文章");
}
// 获取用户的收藏列表
Set<Long> myCollections = COLLECTION_STORE.computeIfAbsent(currentUserId, k -> new HashSet<>());
// 检查是否已收藏
if (myCollections.contains(id)) {
return error("已收藏过该文章");
}
// 添加收藏
myCollections.add(id);
// 增加文章收藏数
vetExperienceArticleService.incrementCollectCount(id);
return success("收藏成功");
}
/**
* 搜索文章
*/
@ -293,16 +508,16 @@ public class VetExperienceArticleController extends BaseController {
/**
* 获取热门标签
*/
@GetMapping("/forum/hotTags")
/*@GetMapping("/forum/hotTags")
public AjaxResult getHotTags(@RequestParam(value = "limit", defaultValue = "15") Integer limit) {
List<Map<String, Object>> hotTags = vetExperienceArticleService.selectHotTags(limit);
return success(hotTags);
}
}*/
/**
* 2. 根据标签搜索文章带分页
*/
@GetMapping("/listByTag")
/* @GetMapping("/listByTag")
public TableDataInfo listByTag(@RequestParam("tag") String tag,
@RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum,
@RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize) {
@ -315,7 +530,7 @@ public class VetExperienceArticleController extends BaseController {
List<VetExperienceArticle> list = vetExperienceArticleService.selectVetExperienceArticleList(query);
return getDataTable(list);
}
}*/
/**

3
chenhai-admin/src/main/java/com/chenhai/web/controller/vet/VetPersonalInfoController.java

@ -99,7 +99,8 @@ public class VetPersonalInfoController extends BaseController
return error("无权查看他人信息");
}
Map<String, Object> fullInfo = vetPersonalInfoService.getVetFullInfo(id);
/*Map<String, Object> fullInfo = vetPersonalInfoService.getVetFullInfo(id);*/
Map<String, Object> fullInfo = vetPersonalInfoService.getVetFullInfoWithQualifications(id);
if (fullInfo == null || fullInfo.isEmpty()) {
return error("兽医信息不存在");
}

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

@ -0,0 +1,104 @@
package com.chenhai.web.controller.vet;
import java.util.List;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.chenhai.common.annotation.Log;
import com.chenhai.common.core.controller.BaseController;
import com.chenhai.common.core.domain.AjaxResult;
import com.chenhai.common.enums.BusinessType;
import com.chenhai.vet.domain.VetProduct;
import com.chenhai.vet.service.IVetProductService;
import com.chenhai.common.utils.poi.ExcelUtil;
import com.chenhai.common.core.page.TableDataInfo;
/**
* 兽医产品信息Controller
*
* @author ruoyi
* @date 2026-01-15
*/
@RestController
@RequestMapping("/vet/product")
public class VetProductController extends BaseController
{
@Autowired
private IVetProductService vetProductService;
/**
* 查询兽医产品信息列表
*/
@PreAuthorize("@ss.hasPermi('vet:product:list')")
@GetMapping("/list")
public TableDataInfo list(VetProduct vetProduct)
{
startPage();
List<VetProduct> list = vetProductService.selectVetProductList(vetProduct);
return getDataTable(list);
}
/**
* 导出兽医产品信息列表
*/
@PreAuthorize("@ss.hasPermi('vet:product:export')")
@Log(title = "兽医产品信息", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(HttpServletResponse response, VetProduct vetProduct)
{
List<VetProduct> list = vetProductService.selectVetProductList(vetProduct);
ExcelUtil<VetProduct> util = new ExcelUtil<VetProduct>(VetProduct.class);
util.exportExcel(response, list, "兽医产品信息数据");
}
/**
* 获取兽医产品信息详细信息
*/
@PreAuthorize("@ss.hasPermi('vet:product:query')")
@GetMapping(value = "/{id}")
public AjaxResult getInfo(@PathVariable("id") Long id)
{
return success(vetProductService.selectVetProductById(id));
}
/**
* 新增兽医产品信息
*/
@PreAuthorize("@ss.hasPermi('vet:product:add')")
@Log(title = "兽医产品信息", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@RequestBody VetProduct vetProduct)
{
return toAjax(vetProductService.insertVetProduct(vetProduct));
}
/**
* 修改兽医产品信息
*/
@PreAuthorize("@ss.hasPermi('vet:product:edit')")
@Log(title = "兽医产品信息", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody VetProduct vetProduct)
{
return toAjax(vetProductService.updateVetProduct(vetProduct));
}
/**
* 删除兽医产品信息
*/
@PreAuthorize("@ss.hasPermi('vet:product:remove')")
@Log(title = "兽医产品信息", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable Long[] ids)
{
return toAjax(vetProductService.deleteVetProductByIds(ids));
}
}

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

@ -29,7 +29,7 @@ import java.util.*;
import static com.chenhai.framework.datasource.DynamicDataSourceContextHolder.log;
/**
* 兽医资质控制器
* 兽医资质控制器合并证书功能
*
* @author 自定义
*/
@ -43,11 +43,9 @@ public class VetQualificationController extends BaseController
@Autowired
private JdbcTemplate jdbcTemplate;
// 注入若依配置的文件上传根路径需在application.yml配置ruoyi.profile=D:/ruoyi/uploadPath
@Value("${chenhai.profile}")
private String uploadRootPath;
// 资质文件存储子路径便于分类管理
private static final String QUALIFICATION_FILE_PATH = "/vet/qualification/";
/**
@ -92,8 +90,6 @@ public class VetQualificationController extends BaseController
/**
* 上传资质文件关联兽医资质ID
* @param file 上传的文件
* @return 文件上传结果包含访问路径存储路径等
*/
@PreAuthorize("@ss.hasPermi('vet:qualification:edit')")
@Log(title = "兽医资质文件上传", businessType = BusinessType.UPDATE)
@ -107,45 +103,37 @@ public class VetQualificationController extends BaseController
String originalFileName = file.getOriginalFilename();
String ext = FileUtils.getExtension(originalFileName).toLowerCase();
// 文件类型验证
String[] allowedExts = {"jpg", "png", "pdf", "doc", "docx", "xls", "xlsx"};
boolean isAllowed = FileUtils.isAllowedExtension(originalFileName, allowedExts);
if (!isAllowed) {
return AjaxResult.error("文件类型不允许");
}
// 🔥 关键使用配置的路径
String basePath = uploadRootPath; // D:/ymtx/uploadPath
String basePath = uploadRootPath;
String subPath = "vet/qualification";
String datePath = new SimpleDateFormat("yyyy/MM/dd").format(new Date());
String fullPath = basePath + File.separator + subPath + File.separator + datePath;
// 创建目录
File destDir = new File(fullPath);
if (!destDir.exists()) {
destDir.mkdirs();
}
// 生成唯一文件名
String uuid = UUID.randomUUID().toString().replace("-", "");
String fileName = uuid + "_" + originalFileName;
String filePath = fullPath + File.separator + fileName;
// 保存文件
File destFile = new File(filePath);
file.transferTo(destFile);
// 🔥 返回可访问的URL注意路径格式
// 前端访问路径/profile/vet/qualification/yyyy/MM/dd/xxx.jpg
String fileUrl = "/" + subPath + "/" + datePath + "/" + fileName;
// 下载链接Spring有默认的下载控制器 /common/download?fileName=xxx
String downloadUrl = "/common/download?fileName=" + URLEncoder.encode(fileUrl, "UTF-8");
Map<String, Object> data = new HashMap<>();
data.put("fileName", originalFileName);
data.put("fileUrl", fileUrl); // 前端显示用
data.put("downloadUrl", downloadUrl); // 下载用
data.put("filePath", fileUrl); // 提交到资质表用存储相对路径
data.put("fileUrl", fileUrl);
data.put("downloadUrl", downloadUrl);
data.put("filePath", fileUrl);
data.put("fileSize", file.getSize());
data.put("uuid", uuid);
@ -157,11 +145,8 @@ public class VetQualificationController extends BaseController
}
}
/**
* 查询兽医资质列表
* 查询兽医资质列表含证书信息
*/
@PreAuthorize("@ss.hasPermi('vet:qualification:list')")
@GetMapping("/list")
@ -176,6 +161,52 @@ public class VetQualificationController extends BaseController
return getDataTable(list);
}
/**
* 查询即将过期的资质证书
*/
@PreAuthorize("@ss.hasPermi('vet:qualification:list')")
@GetMapping("/listExpiring")
public TableDataInfo listExpiring(VetQualification vetQualification)
{
startPage();
Long userId = SecurityUtils.getUserId();
if (!SecurityUtils.isAdmin(userId)) {
vetQualification.setUserId(userId);
}
vetQualification.setExpiringOnly(true);
List<VetQualification> list = vetQualificationService.selectVetQualificationList(vetQualification);
return getDataTable(list);
}
/**
* 用户详情页查询资质证书
*/
@PreAuthorize("@ss.hasPermi('vet:qualification:list')")
@GetMapping("/listForDetail")
public TableDataInfo listForDetail(@RequestParam(value = "userId", required = false) Long userId)
{
startPage();
Long currentUserId = SecurityUtils.getUserId();
if (currentUserId == null) {
return getDataTable(List.of());
}
if (userId == null) {
return getDataTable(List.of());
}
// 权限检查管理员或查看自己
if (!SecurityUtils.isAdmin(currentUserId) && !userId.equals(currentUserId)) {
return getDataTable(List.of());
}
VetQualification query = new VetQualification();
query.setUserId(userId);
List<VetQualification> list = vetQualificationService.selectVetQualificationList(query);
return getDataTable(list);
}
/**
* 登录后检查是否需要填写资质
*/
@ -213,7 +244,6 @@ public class VetQualificationController extends BaseController
return AjaxResult.success(result);
}
/**
* 获取经营范围详情
*/
@ -246,7 +276,18 @@ public class VetQualificationController extends BaseController
@GetMapping(value = "/{qualificationId}")
public AjaxResult getInfo(@PathVariable("qualificationId") Long qualificationId)
{
return success(vetQualificationService.selectVetQualificationByQualificationId(qualificationId));
VetQualification qualification = vetQualificationService.selectVetQualificationByQualificationId(qualificationId);
if (qualification == null) {
return AjaxResult.error("资质信息不存在");
}
// 权限检查管理员或查看自己
Long currentUserId = SecurityUtils.getUserId();
if (!SecurityUtils.isAdmin(currentUserId) && !qualification.getUserId().equals(currentUserId)) {
return AjaxResult.error("没有权限查看此资质");
}
return success(qualification);
}
/**
@ -262,6 +303,12 @@ public class VetQualificationController extends BaseController
try {
vetQualification.setUserId(sysUserId);
vetQualification.setCreateBy(username);
// 设置默认提醒天数
if (vetQualification.getRemindDays() == null) {
vetQualification.setRemindDays(30);
}
return toAjax(vetQualificationService.insertVetQualification(vetQualification));
} catch (DataIntegrityViolationException e) {
if (e.getMessage().contains("foreign key constraint")) {
@ -289,6 +336,15 @@ 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());
if (existing == null || !existing.getUserId().equals(currentUserId)) {
return error("没有权限修改此资质");
}
}
return toAjax(vetQualificationService.updateVetQualification(vetQualification));
}
@ -300,6 +356,17 @@ 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) {
VetQualification existing = vetQualificationService.selectVetQualificationByQualificationId(id);
if (existing == null || !existing.getUserId().equals(currentUserId)) {
return error("没有权限删除资质ID: " + id);
}
}
}
return toAjax(vetQualificationService.deleteVetQualificationByQualificationIds(qualificationIds));
}
@ -350,4 +417,68 @@ public class VetQualificationController extends BaseController
vetQualification.setAuditTime(new Date());
return toAjax(vetQualificationService.updateVetQualification(vetQualification));
}
/**
* 根据用户ID获取资质证书列表
*/
@GetMapping("/user/{userId}")
public AjaxResult getByUserId(@PathVariable Long userId) {
Long currentUserId = SecurityUtils.getUserId();
// 权限检查
if (!SecurityUtils.isAdmin(currentUserId) && !userId.equals(currentUserId)) {
return error("没有权限查看其他用户的资质");
}
List<VetQualification> list = vetQualificationService.selectQualificationsByUserId(userId);
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);
}
/**
* 获取证书统计信息
*/
@GetMapping("/statistics/{userId}")
public AjaxResult getStatistics(@PathVariable Long userId) {
Long currentUserId = SecurityUtils.getUserId();
// 权限检查
if (!SecurityUtils.isAdmin(currentUserId) && !userId.equals(currentUserId)) {
return error("没有权限查看其他用户的统计信息");
}
Map<String, Object> statistics = vetQualificationService.getCertificateStatistics(userId);
return success(statistics);
}
/**
* 手动触发证书检查
*/
@PostMapping("/manual-check/{userId}")
public AjaxResult manualCheck(@PathVariable Long userId) {
Long currentUserId = SecurityUtils.getUserId();
// 权限检查
if (!SecurityUtils.isAdmin(currentUserId) && !userId.equals(currentUserId)) {
return error("没有权限为其他用户检查证书");
}
vetQualificationService.manualCheckCertificates(userId);
return success("证书检查完成");
}
}

100
chenhai-system/src/main/java/com/chenhai/vet/CertificateRemindTask.java

@ -1,8 +1,8 @@
package com.chenhai.vet;
import com.chenhai.vet.domain.VetCertificate;
import com.chenhai.vet.domain.VetQualification;
import com.chenhai.vet.domain.VetNotification;
import com.chenhai.vet.mapper.VetCertificateMapper;
import com.chenhai.vet.mapper.VetQualificationMapper;
import com.chenhai.vet.mapper.VetNotificationMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
@ -20,63 +20,74 @@ import java.util.List;
public class CertificateRemindTask {
@Autowired
private VetCertificateMapper vetCertificateMapper;
private VetQualificationMapper vetQualificationMapper;
@Autowired
private VetNotificationMapper vetNotificationMapper;
// 测试每分钟执行 | 正式每天上午9点 @Scheduled(cron = "0 0 9 * * ?")
//@Scheduled(cron = "0 */1 * * * ?")
@Scheduled(cron = "0 0 9 * * ?")
// 每天上午9点执行
@Scheduled(cron = "0 0 9 * * ?")/*
@Scheduled(cron = "0 * * * * ?")*/
public void dailyCertificateCheck() {
/* log.info("开始检查证书过期情况...");*/
try {
List<VetCertificate> certificates = vetCertificateMapper.selectVetCertificateList(new VetCertificate());
// 查询所有包含证书信息的资质
VetQualification query = new VetQualification();
query.setCertName("");
List<VetQualification> qualifications = vetQualificationMapper.selectVetQualificationList(query);
// 过滤出有证书信息的记录
List<VetQualification> certificates = qualifications.stream()
.filter(q -> q.getCertName() != null && !q.getCertName().isEmpty())
.toList();
certificates.forEach(this::checkAndSendReminder);
/* log.info("证书检查完成,共检查{}个证书", certificates.size());*/
} catch (Exception e) {
/*log.error("证书检查任务执行失败", e);*/
e.printStackTrace();
}
}
/**
* 检查单个证书并发送提醒
*/
private void checkAndSendReminder(VetCertificate certificate) {
if (certificate == null || certificate.getExpireDate() == null) {
private void checkAndSendReminder(VetQualification qualification) {
if (qualification == null || qualification.getExpireDate() == null) {
return;
}
long daysRemaining = calculateDayDifference(new Date(), certificate.getExpireDate());
long daysRemaining = calculateDayDifference(new Date(), qualification.getExpireDate());
updateCertificateStatus(certificate, daysRemaining);
updateCertificateStatus(qualification, daysRemaining);
if (!shouldSendReminder(certificate, daysRemaining) || hasRecentReminder(certificate, daysRemaining)) {
if (!shouldSendReminder(qualification, daysRemaining) || hasRecentReminder(qualification, daysRemaining)) {
return;
}
sendReminder(certificate, daysRemaining);
sendReminder(qualification, daysRemaining);
}
/**
* 发送提醒
*/
private void sendReminder(VetCertificate certificate, long daysRemaining) {
VetNotification notification = createBaseNotification(certificate);
/**
* 发送提醒
*/
private void sendReminder(VetQualification qualification, long daysRemaining) {
VetNotification notification = createBaseNotification(qualification);
if (daysRemaining <= 0) {
// 只发送过期当天的提醒
if (daysRemaining == 0) {
setExpiredContent(notification, certificate, 0);
setExpiredContent(notification, qualification, 0);
notification.setRemindLevel(3); // 最高级别
vetNotificationMapper.insertVetNotification(notification);
}
// 过期后不再提醒
return;
} else if (daysRemaining <= 7) {
setCountdownContent(notification, certificate, daysRemaining);
setCountdownContent(notification, qualification, daysRemaining);
notification.setRemindLevel(daysRemaining <= 3 ? 3 : 2);
} else if (daysRemaining == 15 || daysRemaining == 30) {
setPreExpireContent(notification, certificate, daysRemaining);
setPreExpireContent(notification, qualification, daysRemaining);
notification.setRemindLevel(daysRemaining == 30 ? 1 : 2);
} else {
return;
@ -88,10 +99,10 @@ public class CertificateRemindTask {
/**
* 创建基础通知对象
*/
private VetNotification createBaseNotification(VetCertificate certificate) {
private VetNotification createBaseNotification(VetQualification qualification) {
VetNotification notification = new VetNotification();
notification.setUserId(certificate.getUserId());
notification.setRelatedId(certificate.getId().toString());
notification.setUserId(qualification.getUserId());
notification.setRelatedId(qualification.getQualificationId().toString());
notification.setType("CERT_EXPIRE_REMIND");
notification.setIsRead(0);
notification.setCreateTime(new Date());
@ -101,35 +112,36 @@ public class CertificateRemindTask {
/**
* 设置过期内容
*/
private void setExpiredContent(VetNotification notification, VetCertificate certificate, long daysExpired) {
private void setExpiredContent(VetNotification notification, VetQualification qualification, long daysExpired) {
if (daysExpired == 0) {
notification.setTitle("🚨 证书今天过期!");
notification.setContent(String.format("您的《%s》证书今天已过期!请立即更新。", certificate.getCertName()));
notification.setContent(String.format("您的《%s》证书今天已过期!请立即更新。", qualification.getCertName()));
}
// 移除过期多天的提醒
}
/**
* 设置倒计时内容
*/
private void setCountdownContent(VetNotification notification, VetCertificate certificate, long daysRemaining) {
private void setCountdownContent(VetNotification notification, VetQualification qualification, long daysRemaining) {
notification.setTitle("⚠️ 证书还剩" + daysRemaining + "天过期");
notification.setContent(String.format("您的《%s》证书还剩%d天过期,请及时更新。", certificate.getCertName(), daysRemaining));
notification.setContent(String.format("您的《%s》证书还剩%d天过期,请及时更新。", qualification.getCertName(), daysRemaining));
}
/**
* 设置预过期内容
*/
private void setPreExpireContent(VetNotification notification, VetCertificate certificate, long daysRemaining) {
private void setPreExpireContent(VetNotification notification, VetQualification qualification, long daysRemaining) {
String timeText = daysRemaining == 30 ? "30天" : "15天";
notification.setTitle("📅 证书还剩" + timeText + "过期");
notification.setContent(String.format("您的《%s》证书将在%s后过期,请提前准备更新。", certificate.getCertName(), timeText));
notification.setContent(String.format("您的《%s》证书将在%s后过期,请提前准备更新。", qualification.getCertName(), timeText));
}
/**
* 判断是否需要发送提醒
*/
private boolean shouldSendReminder(VetCertificate certificate, long daysRemaining) {
String status = certificate.getStatus();
private boolean shouldSendReminder(VetQualification qualification, long daysRemaining) {
String status = qualification.getCertStatus();
if ("2".equals(status)) { // 已过期
// 只在过期的第一天提醒daysRemaining = 0 刚刚过期时
@ -150,7 +162,7 @@ public class CertificateRemindTask {
/**
* 检查最近是否已发送过提醒
*/
private boolean hasRecentReminder(VetCertificate certificate, long daysRemaining) {
private boolean hasRecentReminder(VetQualification qualification, long daysRemaining) {
try {
Calendar cal = Calendar.getInstance();
cal.set(Calendar.HOUR_OF_DAY, 0);
@ -164,7 +176,7 @@ public class CertificateRemindTask {
// 检查今天是否已发送
VetNotification query = new VetNotification();
query.setRelatedId(certificate.getId().toString());
query.setRelatedId(qualification.getQualificationId().toString());
query.setType("CERT_EXPIRE_REMIND");
List<VetNotification> notifications = vetNotificationMapper.selectVetNotificationList(query);
@ -182,16 +194,13 @@ public class CertificateRemindTask {
}
// 生成当前应该发送的通知标题
String expectedTitle = generateExpectedTitle(certificate, daysRemaining);
String expectedTitle = generateExpectedTitle(qualification, daysRemaining);
// 检查今天是否已有相同标题的通知
boolean hasSameTitleToday = todayNotifications.stream()
.anyMatch(n -> expectedTitle.equals(n.getTitle()));
if (hasSameTitleToday) {
// 如果今天已有相同标题的通知跳过
/*log.debug("今天已发送过相同提醒,跳过: 证书ID={}, 标题={}",
certificate.getId(), expectedTitle);*/
return true;
}
@ -209,14 +218,12 @@ public class CertificateRemindTask {
.anyMatch(n -> expectedTitle.equals(n.getTitle()));
if (hasSameTitleRecent) {
/*log.debug("最近7天内已发送过相同提醒,跳过: 证书ID={}", certificate.getId());*/
return true;
}
}
return false;
} catch (Exception e) {
/*log.warn("检查近期提醒失败: {}", e.getMessage());*/
return false;
}
}
@ -224,7 +231,7 @@ public class CertificateRemindTask {
/**
* 生成预期的通知标题
*/
private String generateExpectedTitle(VetCertificate certificate, long daysRemaining) {
private String generateExpectedTitle(VetQualification qualification, long daysRemaining) {
if (daysRemaining <= 0) {
long daysExpired = -daysRemaining;
if (daysExpired == 0) {
@ -244,17 +251,18 @@ public class CertificateRemindTask {
/**
* 更新证书状态
*/
private void updateCertificateStatus(VetCertificate certificate, long daysRemaining) {
private void updateCertificateStatus(VetQualification qualification, long daysRemaining) {
try {
String newStatus = daysRemaining <= 0 ? "2" :
daysRemaining <= 30 ? "1" : "0";
if (!newStatus.equals(certificate.getStatus())) {
certificate.setStatus(newStatus);
/*log.debug("更新证书状态: 证书ID={}, 新状态={}", certificate.getId(), newStatus);*/
if (!newStatus.equals(qualification.getCertStatus())) {
qualification.setCertStatus(newStatus);
// 更新数据库中的状态
vetQualificationMapper.updateVetQualification(qualification);
}
} catch (Exception e) {
/*log.warn("更新证书状态失败: {}", e.getMessage());*/
e.printStackTrace();
}
}

212
chenhai-system/src/main/java/com/chenhai/vet/domain/VetCertificate.java

@ -1,212 +0,0 @@
package com.chenhai.vet.domain;
import com.chenhai.common.annotation.Excel;
import com.chenhai.common.core.domain.BaseEntity;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import java.util.Date;
/**
* 兽医执业证书对象 vet_certificate
*
* @author ruoyi
* @date 2025-12-29
*/
public class VetCertificate extends BaseEntity
{
private static final long serialVersionUID = 1L;
/** 主键ID */
private Long id;
/** 用户ID */
@Excel(name = "用户ID")
private Long userId;
/** 证书名称 */
@Excel(name = "证书名称")
private String certName;
/** 证书编号 */
@Excel(name = "证书编号")
private String certNumber;
/** 证书类型 */
@Excel(name = "证书类型")
private String certType;
/** 发证机构 */
@Excel(name = "发证机构")
private String issueOrg;
/** 发证日期 */
@JsonFormat(pattern = "yyyy-MM-dd")
@Excel(name = "发证日期", width = 30, dateFormat = "yyyy-MM-dd")
private Date issueDate;
/** 到期日期 */
@JsonFormat(pattern = "yyyy-MM-dd")
@Excel(name = "到期日期", width = 30, dateFormat = "yyyy-MM-dd")
private Date expireDate;
/** 证书图片 */
@Excel(name = "证书图片")
private String certImage;
/** 状态(0正常 1即将过期 2已过期) */
@Excel(name = "状态", dictType = "certificate_status")
private String status;
/** 提前提醒天数 */
@Excel(name = "提前提醒天数")
private Integer remindDays;
/** 上次提醒时间 */
@JsonFormat(pattern = "yyyy-MM-dd")
@Excel(name = "上次提醒时间", width = 30, dateFormat = "yyyy-MM-dd")
private Date lastRemindTime;
public void setId(Long id)
{
this.id = id;
}
public Long getId()
{
return id;
}
public void setUserId(Long userId)
{
this.userId = userId;
}
public Long getUserId()
{
return userId;
}
public void setCertName(String certName)
{
this.certName = certName;
}
public String getCertName()
{
return certName;
}
public void setCertNumber(String certNumber)
{
this.certNumber = certNumber;
}
public String getCertNumber()
{
return certNumber;
}
public void setCertType(String certType)
{
this.certType = certType;
}
public String getCertType()
{
return certType;
}
public void setIssueOrg(String issueOrg)
{
this.issueOrg = issueOrg;
}
public String getIssueOrg()
{
return issueOrg;
}
public void setIssueDate(Date issueDate)
{
this.issueDate = issueDate;
}
public Date getIssueDate()
{
return issueDate;
}
public void setExpireDate(Date expireDate)
{
this.expireDate = expireDate;
}
public Date getExpireDate()
{
return expireDate;
}
public void setCertImage(String certImage)
{
this.certImage = certImage;
}
public String getCertImage()
{
return certImage;
}
public void setStatus(String status)
{
this.status = status;
}
public String getStatus()
{
return status;
}
public void setRemindDays(Integer remindDays)
{
this.remindDays = remindDays;
}
public Integer getRemindDays()
{
return remindDays;
}
public void setLastRemindTime(Date lastRemindTime)
{
this.lastRemindTime = lastRemindTime;
}
public Date getLastRemindTime()
{
return lastRemindTime;
}
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("userId", getUserId())
.append("certName", getCertName())
.append("certNumber", getCertNumber())
.append("certType", getCertType())
.append("issueOrg", getIssueOrg())
.append("issueDate", getIssueDate())
.append("expireDate", getExpireDate())
.append("certImage", getCertImage())
.append("status", getStatus())
.append("remindDays", getRemindDays())
.append("lastRemindTime", getLastRemindTime())
.append("createBy", getCreateBy())
.append("createTime", getCreateTime())
.append("updateBy", getUpdateBy())
.append("updateTime", getUpdateTime())
.toString();
}
}

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

@ -0,0 +1,447 @@
package com.chenhai.vet.domain;
import java.math.BigDecimal;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.chenhai.common.annotation.Excel;
import com.chenhai.common.core.domain.BaseEntity;
/**
* 兽医产品信息对象 vet_product
*
* @author ruoyi
* @date 2026-01-15
*/
public class VetProduct extends BaseEntity
{
private static final long serialVersionUID = 1L;
/** 主键ID */
private Long id;
/** 产品名称 */
@Excel(name = "产品名称")
private String name;
/** 产品类型:medicine-兽药/vaccine-疫苗/supplement-保健品 */
@Excel(name = "产品类型:medicine-兽药/vaccine-疫苗/supplement-保健品")
private String type;
/** 产品分类 */
@Excel(name = "产品分类")
private String category;
/** 规格 */
@Excel(name = "规格")
private String specification;
/** 单位 */
@Excel(name = "单位")
private String unit;
/** 生产厂家 */
@Excel(name = "生产厂家")
private String manufacturer;
/** 批准文号 */
@Excel(name = "批准文号")
private String approvalNumber;
/** 主要成分 */
@Excel(name = "主要成分")
private String ingredients;
/** 适应症 */
@Excel(name = "适应症")
private String indications;
/** 用法用量 */
@Excel(name = "用法用量")
private String usageDosage;
/** 销售价格 */
@Excel(name = "销售价格")
private BigDecimal price;
/** 成本价 */
@Excel(name = "成本价")
private BigDecimal costPrice;
/** 库存数量 */
@Excel(name = "库存数量")
private Long stock;
/** 最低库存预警 */
@Excel(name = "最低库存预警")
private Long minStock;
/** 主图URL */
@Excel(name = "主图URL")
private String mainImage;
/** 多张图片URL,JSON格式 */
@Excel(name = "多张图片URL,JSON格式")
private String images;
/** 适用动物:如犬、猫、猪等 */
@Excel(name = "适用动物:如犬、猫、猪等")
private String treatAnimals;
/** 治疗疾病 */
@Excel(name = "治疗疾病")
private String treatDiseases;
/** 治疗方案/内容 */
@Excel(name = "治疗方案/内容")
private String treatmentContent;
/** 治疗周期 */
@Excel(name = "治疗周期")
private String treatmentDuration;
/** 注意事项 */
@Excel(name = "注意事项")
private String precautions;
/** 状态:0-草稿/1-上架/2-下架 */
@Excel(name = "状态:0-草稿/1-上架/2-下架")
private String status;
/** 删除标识:0-正常/1-删除 */
@Excel(name = "删除标识:0-正常/1-删除")
private Integer isDeleted;
/** 诊所ID */
@Excel(name = "诊所ID")
private Long clinicId;
/** 兽医ID */
@Excel(name = "兽医ID")
private Long userId;
/** 创建时间 */
@JsonFormat(pattern = "yyyy-MM-dd")
@Excel(name = "创建时间", width = 30, dateFormat = "yyyy-MM-dd")
private Date createdAt;
/** 更新时间 */
@JsonFormat(pattern = "yyyy-MM-dd")
@Excel(name = "更新时间", width = 30, dateFormat = "yyyy-MM-dd")
private Date updatedAt;
public void setId(Long id)
{
this.id = id;
}
public Long getId()
{
return id;
}
public void setName(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
public void setType(String type)
{
this.type = type;
}
public String getType()
{
return type;
}
public void setCategory(String category)
{
this.category = category;
}
public String getCategory()
{
return category;
}
public void setSpecification(String specification)
{
this.specification = specification;
}
public String getSpecification()
{
return specification;
}
public void setUnit(String unit)
{
this.unit = unit;
}
public String getUnit()
{
return unit;
}
public void setManufacturer(String manufacturer)
{
this.manufacturer = manufacturer;
}
public String getManufacturer()
{
return manufacturer;
}
public void setApprovalNumber(String approvalNumber)
{
this.approvalNumber = approvalNumber;
}
public String getApprovalNumber()
{
return approvalNumber;
}
public void setIngredients(String ingredients)
{
this.ingredients = ingredients;
}
public String getIngredients()
{
return ingredients;
}
public void setIndications(String indications)
{
this.indications = indications;
}
public String getIndications()
{
return indications;
}
public void setUsageDosage(String usageDosage)
{
this.usageDosage = usageDosage;
}
public String getUsageDosage()
{
return usageDosage;
}
public void setPrice(BigDecimal price)
{
this.price = price;
}
public BigDecimal getPrice()
{
return price;
}
public void setCostPrice(BigDecimal costPrice)
{
this.costPrice = costPrice;
}
public BigDecimal getCostPrice()
{
return costPrice;
}
public void setStock(Long stock)
{
this.stock = stock;
}
public Long getStock()
{
return stock;
}
public void setMinStock(Long minStock)
{
this.minStock = minStock;
}
public Long getMinStock()
{
return minStock;
}
public void setMainImage(String mainImage)
{
this.mainImage = mainImage;
}
public String getMainImage()
{
return mainImage;
}
public void setImages(String images)
{
this.images = images;
}
public String getImages()
{
return images;
}
public void setTreatAnimals(String treatAnimals)
{
this.treatAnimals = treatAnimals;
}
public String getTreatAnimals()
{
return treatAnimals;
}
public void setTreatDiseases(String treatDiseases)
{
this.treatDiseases = treatDiseases;
}
public String getTreatDiseases()
{
return treatDiseases;
}
public void setTreatmentContent(String treatmentContent)
{
this.treatmentContent = treatmentContent;
}
public String getTreatmentContent()
{
return treatmentContent;
}
public void setTreatmentDuration(String treatmentDuration)
{
this.treatmentDuration = treatmentDuration;
}
public String getTreatmentDuration()
{
return treatmentDuration;
}
public void setPrecautions(String precautions)
{
this.precautions = precautions;
}
public String getPrecautions()
{
return precautions;
}
public void setStatus(String status)
{
this.status = status;
}
public String getStatus()
{
return status;
}
public void setIsDeleted(Integer isDeleted)
{
this.isDeleted = isDeleted;
}
public Integer getIsDeleted()
{
return isDeleted;
}
public void setClinicId(Long clinicId)
{
this.clinicId = clinicId;
}
public Long getClinicId()
{
return clinicId;
}
public void setUserId(Long userId)
{
this.userId = userId;
}
public Long getUserId()
{
return userId;
}
public void setCreatedAt(Date createdAt)
{
this.createdAt = createdAt;
}
public Date getCreatedAt()
{
return createdAt;
}
public void setUpdatedAt(Date updatedAt)
{
this.updatedAt = updatedAt;
}
public Date getUpdatedAt()
{
return updatedAt;
}
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("name", getName())
.append("type", getType())
.append("category", getCategory())
.append("specification", getSpecification())
.append("unit", getUnit())
.append("manufacturer", getManufacturer())
.append("approvalNumber", getApprovalNumber())
.append("ingredients", getIngredients())
.append("indications", getIndications())
.append("usageDosage", getUsageDosage())
.append("price", getPrice())
.append("costPrice", getCostPrice())
.append("stock", getStock())
.append("minStock", getMinStock())
.append("mainImage", getMainImage())
.append("images", getImages())
.append("treatAnimals", getTreatAnimals())
.append("treatDiseases", getTreatDiseases())
.append("treatmentContent", getTreatmentContent())
.append("treatmentDuration", getTreatmentDuration())
.append("precautions", getPrecautions())
.append("status", getStatus())
.append("isDeleted", getIsDeleted())
.append("clinicId", getClinicId())
.append("userId", getUserId())
.append("createdAt", getCreatedAt())
.append("updatedAt", getUpdatedAt())
.toString();
}
}

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

@ -14,7 +14,7 @@ import java.util.List;
import java.util.ArrayList;
/**
* 兽医资质对象 vet_qualification
* 兽医资质对象 vet_qualification合并证书功能
*
* @author ruoyi
* @date 2025-12-26
@ -26,8 +26,8 @@ public class VetQualification extends BaseEntity
/** 资质ID */
private Long qualificationId;
/** 兽医ID */
@Excel(name = "兽医ID")
/** 系统用户ID */
@Excel(name = "用户ID")
private Long userId;
/** 真实姓名 */
@ -51,13 +51,13 @@ public class VetQualification extends BaseEntity
private String certificateFiles;
/** 申请时间 */
@JsonFormat(pattern = "yyyy-MM-dd")
@Excel(name = "申请时间", width = 30, dateFormat = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "申请时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date applyTime;
/** 审核时间 */
@JsonFormat(pattern = "yyyy-MM-dd")
@Excel(name = "审核时间", width = 30, dateFormat = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "审核时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date auditTime;
/** 审核状态(0待审核 1通过 2拒绝) */
@ -79,14 +79,58 @@ public class VetQualification extends BaseEntity
@Excel(name = "经营范围名称", dictType = "scope_names")
private String scopeNames;
// 新增证书相关字段
/** 证书名称 */
@Excel(name = "证书名称")
private String certName;
/** 证书类型 */
@Excel(name = "证书类型")
private String certType;
/** 发证机构 */
@Excel(name = "发证机构")
private String issueOrg;
/** 发证日期 */
@JsonFormat(pattern = "yyyy-MM-dd")
@Excel(name = "发证日期", width = 30, dateFormat = "yyyy-MM-dd")
private Date issueDate;
/** 到期日期 */
@JsonFormat(pattern = "yyyy-MM-dd")
@Excel(name = "到期日期", width = 30, dateFormat = "yyyy-MM-dd")
private Date expireDate;
/** 证书图片 */
private String certImage;
/** 证书状态(0正常 1即将过期 2已过期) */
@Excel(name = "证书状态", dictType = "certificate_status")
private String certStatus;
/** 提前提醒天数 */
@Excel(name = "提前提醒天数")
private Integer remindDays;
/** 上次提醒时间 */
@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 反序列化时使用的方法
@JsonProperty("scopeIds")
public void setScopeIdsFromJson(List<String> scopeIdList) {
// 自动转换为逗号分隔的字符串
if (scopeIdList != null && !scopeIdList.isEmpty()) {
this.scopeIds = String.join(",", scopeIdList);
} else {
@ -125,126 +169,103 @@ public class VetQualification extends BaseEntity
setScopeIdsFromJson(scopeIdList);
}
public void setQualificationId(Long qualificationId)
{
this.qualificationId = qualificationId;
}
public Long getQualificationId()
{
// getter setter 方法
public Long getQualificationId() {
return qualificationId;
}
public void setUserId(Long userId)
{
this.userId = userId;
public void setQualificationId(Long qualificationId) {
this.qualificationId = qualificationId;
}
public Long getUserId()
{
public Long getUserId() {
return userId;
}
public void setRealName(String realName)
{
this.realName = realName;
public void setUserId(Long userId) {
this.userId = userId;
}
public String getRealName()
{
public String getRealName() {
return realName;
}
public void setIdCard(String idCard)
{
this.idCard = idCard;
public void setRealName(String realName) {
this.realName = realName;
}
public String getIdCard()
{
public String getIdCard() {
return idCard;
}
public void setQualificationType(String qualificationType)
{
this.qualificationType = qualificationType;
public void setIdCard(String idCard) {
this.idCard = idCard;
}
public String getQualificationType()
{
public String getQualificationType() {
return qualificationType;
}
public void setCertificateNo(String certificateNo)
{
this.certificateNo = certificateNo;
public void setQualificationType(String qualificationType) {
this.qualificationType = qualificationType;
}
public String getCertificateNo()
{
public String getCertificateNo() {
return certificateNo;
}
public void setCertificateFiles(String certificateFiles)
{
this.certificateFiles = certificateFiles;
public void setCertificateNo(String certificateNo) {
this.certificateNo = certificateNo;
}
public String getCertificateFiles()
{
public String getCertificateFiles() {
return certificateFiles;
}
public void setApplyTime(Date applyTime)
{
this.applyTime = applyTime;
public void setCertificateFiles(String certificateFiles) {
this.certificateFiles = certificateFiles;
}
public Date getApplyTime()
{
public Date getApplyTime() {
return applyTime;
}
public void setAuditTime(Date auditTime)
{
this.auditTime = auditTime;
public void setApplyTime(Date applyTime) {
this.applyTime = applyTime;
}
public Date getAuditTime()
{
public Date getAuditTime() {
return auditTime;
}
public void setAuditStatus(String auditStatus)
{
this.auditStatus = auditStatus;
public void setAuditTime(Date auditTime) {
this.auditTime = auditTime;
}
public String getAuditStatus()
{
public String getAuditStatus() {
return auditStatus;
}
public void setAuditOpinion(String auditOpinion)
{
this.auditOpinion = auditOpinion;
public void setAuditStatus(String auditStatus) {
this.auditStatus = auditStatus;
}
public String getAuditOpinion()
{
public String getAuditOpinion() {
return auditOpinion;
}
public void setAuditorId(Long auditorId)
{
this.auditorId = auditorId;
public void setAuditOpinion(String auditOpinion) {
this.auditOpinion = auditOpinion;
}
public Long getAuditorId()
{
public Long getAuditorId() {
return auditorId;
}
public void setAuditorId(Long auditorId) {
this.auditorId = auditorId;
}
public String getScopeNames() {
return scopeNames;
}
@ -253,6 +274,87 @@ public class VetQualification extends BaseEntity
this.scopeNames = scopeNames;
}
// 新增证书字段的 getter setter
public String getCertName() {
return certName;
}
public void setCertName(String certName) {
this.certName = certName;
}
public String getCertType() {
return certType;
}
public void setCertType(String certType) {
this.certType = certType;
}
public String getIssueOrg() {
return issueOrg;
}
public void setIssueOrg(String issueOrg) {
this.issueOrg = issueOrg;
}
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 getCertImage() {
return certImage;
}
public void setCertImage(String certImage) {
this.certImage = certImage;
}
public String getCertStatus() {
return certStatus;
}
public void setCertStatus(String certStatus) {
this.certStatus = certStatus;
}
public Integer getRemindDays() {
return remindDays;
}
public void setRemindDays(Integer remindDays) {
this.remindDays = remindDays;
}
public Date getLastRemindTime() {
return lastRemindTime;
}
public void setLastRemindTime(Date lastRemindTime) {
this.lastRemindTime = lastRemindTime;
}
public Boolean getExpiringOnly() {
return expiringOnly;
}
public void setExpiringOnly(Boolean expiringOnly) {
this.expiringOnly = expiringOnly;
}
public String getQualificationTypeLabel() {
return qualificationTypeLabel;
}
@ -277,6 +379,14 @@ public class VetQualification extends BaseEntity
this.scopeNamesLabel = scopeNamesLabel;
}
public String getCertStatusLabel() {
return certStatusLabel;
}
public void setCertStatusLabel(String certStatusLabel) {
this.certStatusLabel = certStatusLabel;
}
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
@ -292,13 +402,22 @@ public class VetQualification extends BaseEntity
.append("auditStatus", getAuditStatus())
.append("auditOpinion", getAuditOpinion())
.append("auditorId", getAuditorId())
.append("scopeIds", getScopeIds())
.append("scopeNames", getScopeNames())
.append("certName", getCertName())
.append("certType", getCertType())
.append("issueOrg", getIssueOrg())
.append("issueDate", getIssueDate())
.append("expireDate", getExpireDate())
.append("certImage", getCertImage())
.append("certStatus", getCertStatus())
.append("remindDays", getRemindDays())
.append("lastRemindTime", getLastRemindTime())
.append("createBy", getCreateBy())
.append("createTime", getCreateTime())
.append("updateBy", getUpdateBy())
.append("updateTime", getUpdateTime())
.append("remark", getRemark())
.append("scopeIds", getScopeIds())
.append("scopeNames", getScopeNames())
.toString();
}
}

62
chenhai-system/src/main/java/com/chenhai/vet/mapper/VetCertificateMapper.java

@ -1,62 +0,0 @@
package com.chenhai.vet.mapper;
import com.chenhai.vet.domain.VetCertificate;
import java.util.List;
/**
* 兽医执业证书Mapper接口
*
* @author ruoyi
* @date 2025-12-29
*/
public interface VetCertificateMapper
{
/**
* 查询兽医执业证书
*
* @param id 兽医执业证书主键
* @return 兽医执业证书
*/
public VetCertificate selectVetCertificateById(Long id);
/**
* 查询兽医执业证书列表
*
* @param vetCertificate 兽医执业证书
* @return 兽医执业证书集合
*/
public List<VetCertificate> selectVetCertificateList(VetCertificate vetCertificate);
/**
* 新增兽医执业证书
*
* @param vetCertificate 兽医执业证书
* @return 结果
*/
public int insertVetCertificate(VetCertificate vetCertificate);
/**
* 修改兽医执业证书
*
* @param vetCertificate 兽医执业证书
* @return 结果
*/
public int updateVetCertificate(VetCertificate vetCertificate);
/**
* 删除兽医执业证书
*
* @param id 兽医执业证书主键
* @return 结果
*/
public int deleteVetCertificateById(Long id);
/**
* 批量删除兽医执业证书
*
* @param ids 需要删除的数据主键集合
* @return 结果
*/
public int deleteVetCertificateByIds(Long[] ids);
}

61
chenhai-system/src/main/java/com/chenhai/vet/mapper/VetProductMapper.java

@ -0,0 +1,61 @@
package com.chenhai.vet.mapper;
import java.util.List;
import com.chenhai.vet.domain.VetProduct;
/**
* 兽医产品信息Mapper接口
*
* @author ruoyi
* @date 2026-01-15
*/
public interface VetProductMapper
{
/**
* 查询兽医产品信息
*
* @param id 兽医产品信息主键
* @return 兽医产品信息
*/
public VetProduct selectVetProductById(Long id);
/**
* 查询兽医产品信息列表
*
* @param vetProduct 兽医产品信息
* @return 兽医产品信息集合
*/
public List<VetProduct> selectVetProductList(VetProduct vetProduct);
/**
* 新增兽医产品信息
*
* @param vetProduct 兽医产品信息
* @return 结果
*/
public int insertVetProduct(VetProduct vetProduct);
/**
* 修改兽医产品信息
*
* @param vetProduct 兽医产品信息
* @return 结果
*/
public int updateVetProduct(VetProduct vetProduct);
/**
* 删除兽医产品信息
*
* @param id 兽医产品信息主键
* @return 结果
*/
public int deleteVetProductById(Long id);
/**
* 批量删除兽医产品信息
*
* @param ids 需要删除的数据主键集合
* @return 结果
*/
public int deleteVetProductByIds(Long[] ids);
}

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

@ -2,22 +2,21 @@ package com.chenhai.vet.mapper;
import com.chenhai.vet.domain.VetQualification;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Update;
import java.util.List;
/**
* 兽医资质Mapper接口
*
*
* @author ruoyi
* @date 2025-12-26
*/
@Mapper
public interface VetQualificationMapper
public interface VetQualificationMapper
{
/**
* 查询兽医资质
*
*
* @param qualificationId 兽医资质主键
* @return 兽医资质
*/
@ -25,7 +24,7 @@ public interface VetQualificationMapper
/**
* 查询兽医资质列表
*
*
* @param vetQualification 兽医资质
* @return 兽医资质集合
*/
@ -33,7 +32,7 @@ public interface VetQualificationMapper
/**
* 新增兽医资质
*
*
* @param vetQualification 兽医资质
* @return 结果
*/
@ -41,7 +40,7 @@ public interface VetQualificationMapper
/**
* 修改兽医资质
*
*
* @param vetQualification 兽医资质
* @return 结果
*/
@ -49,7 +48,7 @@ public interface VetQualificationMapper
/**
* 删除兽医资质
*
*
* @param qualificationId 兽医资质主键
* @return 结果
*/
@ -57,11 +56,15 @@ public interface VetQualificationMapper
/**
* 批量删除兽医资质
*
*
* @param qualificationIds 需要删除的数据主键集合
* @return 结果
*/
public int deleteVetQualificationByQualificationIds(Long[] qualificationIds);
public int submit(Long qualificationId);
}
/**
* 根据兽医ID查询资质证书
*/
List<VetQualification> selectQualificationsByUserId(Long userId);
}

72
chenhai-system/src/main/java/com/chenhai/vet/service/IVetCertificateService.java

@ -1,72 +0,0 @@
package com.chenhai.vet.service;
import com.chenhai.vet.domain.VetCertificate;
import java.util.List;
import java.util.Map;
/**
* 兽医执业证书Service接口
*/
public interface IVetCertificateService
{
/**
* 查询兽医执业证书
*/
VetCertificate selectVetCertificateById(Long id);
/**
* 查询兽医执业证书列表
*/
List<VetCertificate> selectVetCertificateList(VetCertificate vetCertificate);
/**
* 新增兽医执业证书
*/
int insertVetCertificate(VetCertificate vetCertificate);
/**
* 修改兽医执业证书
*/
int updateVetCertificate(VetCertificate vetCertificate);
/**
* 批量删除兽医执业证书
*/
int deleteVetCertificateByIds(Long[] ids);
/**
* 删除兽医执业证书信息
*/
int deleteVetCertificateById(Long id);
/**
* 根据用户ID查询证书列表
*/
List<VetCertificate> selectCertificatesByUserId(Long userId);
/**
* 获取即将过期的证书30天内
*/
List<VetCertificate> selectExpiringCertificates(Long userId);
/**
* 检查并发送证书过期提醒
*/
void checkAndSendCertificateReminders();
/**
* 手动触发证书检查
*/
void manualCheckCertificates(Long userId);
/**
* 获取证书统计信息
*/
Map<String, Object> getCertificateStatistics(Long userId);
}

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

@ -111,7 +111,9 @@ public interface IVetExperienceArticleService
/**
* 获取热门标签
*/
List<Map<String, Object>> selectHotTags(Integer limit);
/* List<Map<String, Object>> selectHotTags(Integer limit);*/
List<VetExperienceArticle> selectArticlesByTag(String tag);
List<VetExperienceArticle> selectMyCollections(Long userId);
}

6
chenhai-system/src/main/java/com/chenhai/vet/service/IVetPersonalInfoService.java

@ -76,5 +76,11 @@ public interface IVetPersonalInfoService
*/
VetPersonalInfo selectVetPersonalInfoByUserId(Long userId);
Map<String, Object> getVetFullInfoWithQualifications(Long id);
Map<String, Object> getVetFullInfoWithQualificationsByUserId(Long userId);
}

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

@ -0,0 +1,61 @@
package com.chenhai.vet.service;
import java.util.List;
import com.chenhai.vet.domain.VetProduct;
/**
* 兽医产品信息Service接口
*
* @author ruoyi
* @date 2026-01-15
*/
public interface IVetProductService
{
/**
* 查询兽医产品信息
*
* @param id 兽医产品信息主键
* @return 兽医产品信息
*/
public VetProduct selectVetProductById(Long id);
/**
* 查询兽医产品信息列表
*
* @param vetProduct 兽医产品信息
* @return 兽医产品信息集合
*/
public List<VetProduct> selectVetProductList(VetProduct vetProduct);
/**
* 新增兽医产品信息
*
* @param vetProduct 兽医产品信息
* @return 结果
*/
public int insertVetProduct(VetProduct vetProduct);
/**
* 修改兽医产品信息
*
* @param vetProduct 兽医产品信息
* @return 结果
*/
public int updateVetProduct(VetProduct vetProduct);
/**
* 批量删除兽医产品信息
*
* @param ids 需要删除的兽医产品信息主键集合
* @return 结果
*/
public int deleteVetProductByIds(Long[] ids);
/**
* 删除兽医产品信息信息
*
* @param id 兽医产品信息主键
* @return 结果
*/
public int deleteVetProductById(Long id);
}

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

@ -3,18 +3,19 @@ package com.chenhai.vet.service;
import com.chenhai.vet.domain.VetQualification;
import java.util.List;
import java.util.Map;
/**
* 兽医资质Service接口
*
* 兽医资质Service接口合并证书功能
*
* @author ruoyi
* @date 2025-12-26
*/
public interface IVetQualificationService
public interface IVetQualificationService
{
/**
* 查询兽医资质
*
*
* @param qualificationId 兽医资质主键
* @return 兽医资质
*/
@ -22,7 +23,7 @@ public interface IVetQualificationService
/**
* 查询兽医资质列表
*
*
* @param vetQualification 兽医资质
* @return 兽医资质集合
*/
@ -30,7 +31,7 @@ public interface IVetQualificationService
/**
* 新增兽医资质
*
*
* @param vetQualification 兽医资质
* @return 结果
*/
@ -38,7 +39,7 @@ public interface IVetQualificationService
/**
* 修改兽医资质
*
*
* @param vetQualification 兽医资质
* @return 结果
*/
@ -46,7 +47,7 @@ public interface IVetQualificationService
/**
* 批量删除兽医资质
*
*
* @param qualificationIds 需要删除的兽医资质主键集合
* @return 结果
*/
@ -54,10 +55,37 @@ public interface IVetQualificationService
/**
* 删除兽医资质信息
*
*
* @param qualificationId 兽医资质主键
* @return 结果
*/
public int deleteVetQualificationByQualificationId(Long qualificationId);
}
// 新增的证书相关方法
/**
* 根据用户ID查询资质证书列表
*/
List<VetQualification> selectQualificationsByUserId(Long userId);
/**
* 获取即将过期的资质证书30天内
*/
List<VetQualification> selectExpiringQualifications(Long userId);
/**
* 检查并发送证书过期提醒
*/
void checkAndSendCertificateReminders();
/**
* 手动触发证书检查
*/
void manualCheckCertificates(Long userId);
/**
* 获取证书统计信息
*/
Map<String, Object> getCertificateStatistics(Long userId);
}

6
chenhai-system/src/main/java/com/chenhai/vet/service/VetNotificationService.java

@ -1,8 +1,8 @@
// VetNotificationService.java
package com.chenhai.vet.service;
import com.chenhai.vet.domain.VetCertificate;
import com.chenhai.vet.domain.VetNotification;
import com.chenhai.vet.domain.VetQualification;
import java.util.List;
import java.util.Map;
@ -46,7 +46,7 @@ public interface VetNotificationService {
/**
* 发送证书过期提醒通知
*/
void sendCertificateExpireRemind(VetCertificate certificate);
void sendCertificateExpireRemind(VetQualification qualification);
/**
* 标记通知为已读
@ -57,5 +57,7 @@ public interface VetNotificationService {
Map<String, Integer> getNotificationStats(Long userId);
int getUnreadCount(Long userId);
}

349
chenhai-system/src/main/java/com/chenhai/vet/service/impl/VetCertificateServiceImpl.java

@ -1,349 +0,0 @@
package com.chenhai.vet.service.impl;
import com.chenhai.common.utils.DateUtils;
import com.chenhai.vet.domain.VetCertificate;
import com.chenhai.vet.mapper.VetCertificateMapper;
import com.chenhai.vet.service.IVetCertificateService;
import com.chenhai.vet.service.VetNotificationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 兽医执业证书Service业务层处理
*/
@Service
public class VetCertificateServiceImpl implements IVetCertificateService
{
@Autowired
private VetCertificateMapper vetCertificateMapper;
@Autowired
private VetNotificationService vetNotificationService;
@Override
public VetCertificate selectVetCertificateById(Long id)
{
return vetCertificateMapper.selectVetCertificateById(id);
}
@Override
public List<VetCertificate> selectVetCertificateList(VetCertificate vetCertificate)
{
return vetCertificateMapper.selectVetCertificateList(vetCertificate);
}
@Override
public int insertVetCertificate(VetCertificate vetCertificate)
{
vetCertificate.setCreateTime(DateUtils.getNowDate());
// 验证并设置证书状态
updateCertificateStatus(vetCertificate);
// 设置默认提醒天数
if (vetCertificate.getRemindDays() == null) {
vetCertificate.setRemindDays(30);
}
return vetCertificateMapper.insertVetCertificate(vetCertificate);
}
@Override
public int updateVetCertificate(VetCertificate vetCertificate)
{
vetCertificate.setUpdateTime(DateUtils.getNowDate());
// 验证并更新证书状态
updateCertificateStatus(vetCertificate);
return vetCertificateMapper.updateVetCertificate(vetCertificate);
}
@Override
public int deleteVetCertificateByIds(Long[] ids)
{
return vetCertificateMapper.deleteVetCertificateByIds(ids);
}
@Override
public int deleteVetCertificateById(Long id)
{
return vetCertificateMapper.deleteVetCertificateById(id);
}
@Override
public List<VetCertificate> selectCertificatesByUserId(Long userId)
{
VetCertificate query = new VetCertificate();
query.setUserId(userId);
return vetCertificateMapper.selectVetCertificateList(query);
}
@Override
public List<VetCertificate> selectExpiringCertificates(Long userId)
{
Date today = new Date();
Calendar calendar = Calendar.getInstance();
calendar.setTime(today);
calendar.add(Calendar.DAY_OF_YEAR, 30);
Date thirtyDaysLater = calendar.getTime();
// 先获取用户所有证书
List<VetCertificate> allCertificates = selectCertificatesByUserId(userId);
// 过滤出即将过期的证书
return allCertificates.stream()
.filter(cert -> cert.getExpireDate() != null &&
!cert.getExpireDate().before(today) &&
!cert.getExpireDate().after(thirtyDaysLater))
.toList();
}
@Override
public void checkAndSendCertificateReminders()
{
Date today = new Date();
Calendar calendar = Calendar.getInstance();
calendar.setTime(today);
calendar.add(Calendar.DAY_OF_YEAR, 30);
Date thresholdDate = calendar.getTime(); // 30天后过期
calendar.setTime(today);
calendar.add(Calendar.DAY_OF_YEAR, -7);
Date remindDate = calendar.getTime(); // 7天前提醒过的不再提醒
// 查询所有证书
VetCertificate query = new VetCertificate();
List<VetCertificate> allCertificates = vetCertificateMapper.selectVetCertificateList(query);
int successCount = 0;
int failCount = 0;
for (VetCertificate certificate : allCertificates) {
try {
// 检查证书是否需要提醒
if (shouldSendRemind(certificate, today, thresholdDate, remindDate)) {
// 调用通知服务发送站内信
vetNotificationService.sendCertificateExpireRemind(certificate);
// 更新最后提醒时间
certificate.setLastRemindTime(new Date());
vetCertificateMapper.updateVetCertificate(certificate);
successCount++;
// 保留原来的日志输出
/* System.out.println("发送证书提醒:证书ID=" + certificate.getId() +
", 证书名称=" + certificate.getCertName());*/
}
} catch (Exception e) {
failCount++;
e.printStackTrace();
}
}
/*// 添加统计日志
System.out.println("证书提醒任务完成:成功 " + successCount + " 条,失败 " + failCount + " 条");*/
}
/**
* 判断是否需要发送提醒
*/
private boolean shouldSendRemind(VetCertificate certificate, Date today,
Date thresholdDate, Date remindDate) {
if (certificate.getExpireDate() == null) {
return false;
}
// 检查是否即将过期30天内
if (certificate.getExpireDate().after(thresholdDate)) {
return false;
}
// 检查是否已提醒过7天内
if (certificate.getLastRemindTime() != null) {
Calendar cal = Calendar.getInstance();
cal.setTime(certificate.getLastRemindTime());
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
Date lastRemindDateOnly = cal.getTime();
if (!lastRemindDateOnly.before(remindDate)) {
return false;
}
}
return true;
}
/**
* 发送证书过期提醒
*//*
private void sendCertificateExpireRemind(VetCertificate certificate) {
Date today = new Date();
long daysBetween = calculateDayDifference(today, certificate.getExpireDate());
String title;
String content;
int remindLevel;
if (daysBetween <= 0) {
title = "证书已过期";
content = String.format("您的《%s》证书已于%s过期!请立即更新证书。",
certificate.getCertName(), formatDate(certificate.getExpireDate()));
remindLevel = 3;
} else if (daysBetween <= 7) {
title = "证书即将过期(7天内)";
content = String.format("您的《%s》证书将在%d天后过期,请尽快更新!",
certificate.getCertName(), daysBetween);
remindLevel = 3;
} else {
title = "证书即将过期(30天内)";
content = String.format("您的《%s》证书将在%d天后过期,请及时更新。",
certificate.getCertName(), daysBetween);
remindLevel = 2;
}
System.out.println("发送证书提醒:" + title + " - " + content);
}
*/
/**
* 计算两个日期之间的天数差自己实现不依赖DateUtils
*/
private long calculateDayDifference(Date startDate, Date endDate) {
if (startDate == null || endDate == null) {
return 0L;
}
// 清除时间部分只比较日期
Calendar startCal = Calendar.getInstance();
startCal.setTime(startDate);
startCal.set(Calendar.HOUR_OF_DAY, 0);
startCal.set(Calendar.MINUTE, 0);
startCal.set(Calendar.SECOND, 0);
startCal.set(Calendar.MILLISECOND, 0);
Calendar endCal = Calendar.getInstance();
endCal.setTime(endDate);
endCal.set(Calendar.HOUR_OF_DAY, 0);
endCal.set(Calendar.MINUTE, 0);
endCal.set(Calendar.SECOND, 0);
endCal.set(Calendar.MILLISECOND, 0);
long diff = endCal.getTimeInMillis() - startCal.getTimeInMillis();
return diff / (1000 * 60 * 60 * 24);
}
/**
* 格式化日期为字符串
*/
private String formatDate(Date date) {
if (date == null) {
return "";
}
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH) + 1; // 月份从0开始
int day = calendar.get(Calendar.DAY_OF_MONTH);
return String.format("%d-%02d-%02d", year, month, day);
}
/**
* 更新证书状态
*/
private void updateCertificateStatus(VetCertificate certificate) {
if (certificate.getExpireDate() == null) {
certificate.setStatus("0"); // 默认正常
return;}
Date today = new Date();
Calendar calendar = Calendar.getInstance();
calendar.setTime(today);
calendar.add(Calendar.DAY_OF_YEAR, 30);
Date thirtyDaysLater = calendar.getTime();
if (certificate.getExpireDate().before(today)) {
certificate.setStatus("2"); // 已过期
} else if (certificate.getExpireDate().before(thirtyDaysLater)) {
certificate.setStatus("1"); // 即将过期
} else {
certificate.setStatus("0"); // 正常
}
}
@Override
public void manualCheckCertificates(Long userId) {
List<VetCertificate> certificates = selectCertificatesByUserId(userId);
for (VetCertificate certificate : certificates) {
updateCertificateStatus(certificate);
vetCertificateMapper.updateVetCertificate(certificate);
}
}
@Override
public Map<String, Object> getCertificateStatistics(Long userId) {
Map<String, Object> statistics = new HashMap<>();
List<VetCertificate> certificates = selectCertificatesByUserId(userId);
Date today = new Date();
long total = certificates.size();
long expiring = 0; // 30天内过期
long expired = 0; // 已过期
int expiringSoon = 0; // 7天内过期
Calendar calendar = Calendar.getInstance();
calendar.setTime(today);
calendar.add(Calendar.DAY_OF_YEAR, 30);
Date thirtyDaysLater = calendar.getTime();
calendar.setTime(today);
calendar.add(Calendar.DAY_OF_YEAR, 7);
Date sevenDaysLater = calendar.getTime();
for (VetCertificate cert : certificates) {
if (cert.getExpireDate() != null) {
if (cert.getExpireDate().before(today)) {
expired++;
} else if (cert.getExpireDate().before(thirtyDaysLater)) {
expiring++;
// 7天内过期
if (cert.getExpireDate().before(sevenDaysLater)) {
expiringSoon++;
}
}
}
}
long normal = total - expiring - expired;
statistics.put("total", total);
statistics.put("normal", normal);
statistics.put("expiring", expiring);
statistics.put("expired", expired);
statistics.put("expiringSoon", expiringSoon);
// 设置警告级别
if (expired > 0) {
statistics.put("warningLevel", "DANGER");
} else if (expiring > 0 || expiringSoon > 0) {
statistics.put("warningLevel", "WARNING");
} else {
statistics.put("warningLevel", "NORMAL");
}
return statistics;
}
}

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

@ -1,6 +1,7 @@
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;
@ -225,7 +226,7 @@ public class VetExperienceArticleServiceImpl implements IVetExperienceArticleSer
return vetExperienceArticleMapper.selectArticlesByTag(tag.trim());
}
@Override
/* @Override
public List<Map<String, Object>> selectHotTags(Integer limit) {
// 从所有文章中提取标签并统计热度
VetExperienceArticle query = new VetExperienceArticle();
@ -258,6 +259,28 @@ public class VetExperienceArticleServiceImpl implements IVetExperienceArticleSer
});
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());
}
}

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

@ -1,8 +1,8 @@
// 更简单的版本完全使用 Date
package com.chenhai.vet.service.impl;
import com.chenhai.vet.domain.VetCertificate;
import com.chenhai.vet.domain.VetNotification;
import com.chenhai.vet.domain.VetQualification;
import com.chenhai.vet.mapper.VetNotificationMapper;
import com.chenhai.vet.service.VetNotificationService;
import lombok.RequiredArgsConstructor;
@ -60,14 +60,65 @@ public class VetNotificationServiceImpl implements VetNotificationService {
}
@Override
public void sendCertificateExpireRemind(VetCertificate certificate) {
log.info("证书提醒记录: 证书ID={}, 名称={}, 过期时间={}",
certificate.getId(), certificate.getCertName(),
formatDate(certificate.getExpireDate()));
}
public void sendCertificateExpireRemind(VetQualification qualification) {
if (qualification == null) {
log.warn("证书提醒:传入的资质对象为空");
return;
}
log.info("证书提醒记录: 资质ID={}, 证书名称={}, 过期时间={}",
qualification.getQualificationId(), qualification.getCertName(),
formatDate(qualification.getExpireDate()));
// 计算剩余天数
long daysRemaining = calculateDayDifference(new Date(), qualification.getExpireDate());
// 根据剩余天数设置提醒内容和级别
String title;
String content;
int remindLevel;
if (daysRemaining <= 0) {
title = "证书已过期";
content = String.format("您的《%s》证书已于%s过期!请立即更新证书。",
qualification.getCertName(), formatDate(qualification.getExpireDate()));
remindLevel = 3;
} else if (daysRemaining <= 7) {
title = "证书即将过期(7天内)";
content = String.format("您的《%s》证书将在%d天后过期,请尽快更新!",
qualification.getCertName(), daysRemaining);
remindLevel = 3;
} else {
title = "证书即将过期(30天内)";
content = String.format("您的《%s》证书将在%d天后过期,请及时更新。",
qualification.getCertName(), daysRemaining);
remindLevel = 2;
}
// 创建通知
VetNotification notification = new VetNotification();
notification.setUserId(qualification.getUserId());
notification.setRelatedId(qualification.getQualificationId().toString());
notification.setType("CERT_EXPIRE_REMIND");
notification.setTitle(title);
notification.setContent(content);
notification.setRemindLevel(remindLevel);
notification.setIsRead(0);
notification.setCreateTime(new Date());
notification.setCreateBy("system");
// 保存通知
try {
int result = vetNotificationMapper.insertVetNotification(notification);
if (result > 0) {
log.info("成功发送证书提醒通知:用户ID={}, 资质ID={}, 标题={}",
qualification.getUserId(), qualification.getQualificationId(), title);
}
} catch (Exception e) {
log.error("发送证书提醒通知失败:资质ID={}, 错误信息={}",
qualification.getQualificationId(), e.getMessage(), e);
}
}
@Override
public boolean markAsRead(Long notificationId) {
@ -81,6 +132,20 @@ public class VetNotificationServiceImpl implements VetNotificationService {
return false;
}
/*@Override
public void markAllAsRead(Long userId) {
VetNotification query = new VetNotification();
query.setUserId(userId);
List<VetNotification> notifications = vetNotificationMapper.selectVetNotificationList(query);
for (VetNotification notification : notifications) {
if (notification.getIsRead() == 0) {
notification.setIsRead(1);
notification.setReadTime(new Date());
vetNotificationMapper.updateVetNotification(notification);
}
}
}*/
/**
* 计算两个日期之间的天数差忽略时间部分
@ -134,4 +199,13 @@ public class VetNotificationServiceImpl implements VetNotificationService {
"read", ((Number) stats.getOrDefault("read", 0)).intValue()
);
}
@Override
public int getUnreadCount(Long userId) {
VetNotification query = new VetNotification();
query.setUserId(userId);
query.setIsRead(0);
List<VetNotification> unreadNotifications = vetNotificationMapper.selectVetNotificationList(query);
return unreadNotifications.size();
}
}

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

@ -4,10 +4,10 @@ import com.chenhai.common.core.domain.entity.SysUser;
import com.chenhai.common.core.domain.model.LoginUser;
import com.chenhai.common.utils.DateUtils;
import com.chenhai.common.utils.SecurityUtils;
import com.chenhai.vet.domain.VetCertificate;
import com.chenhai.vet.domain.VetPersonalInfo;
import com.chenhai.vet.domain.VetQualification;
import com.chenhai.vet.mapper.VetPersonalInfoMapper;
import com.chenhai.vet.mapper.VetCertificateMapper;
import com.chenhai.vet.mapper.VetQualificationMapper;
import com.chenhai.vet.service.IVetPersonalInfoService;
import com.chenhai.system.service.ISysUserService;
import org.springframework.beans.factory.annotation.Autowired;
@ -31,7 +31,7 @@ public class VetPersonalInfoServiceImpl implements IVetPersonalInfoService {
private VetPersonalInfoMapper vetPersonalInfoMapper;
@Autowired
private VetCertificateMapper vetCertificateMapper;
private VetQualificationMapper vetQualificationMapper;
@Autowired
private ISysUserService sysUserService;
@ -47,6 +47,51 @@ public class VetPersonalInfoServiceImpl implements IVetPersonalInfoService {
return info;
}
@Override
public Map<String, Object> getVetFullInfoWithQualifications(Long id) {
// 1. 获取兽医基本信息
VetPersonalInfo vetInfo = vetPersonalInfoMapper.selectVetPersonalInfoById(id);
if (vetInfo == null) {
return null;
}
// 2. 获取资质证书信息从资质表查询
List<VetQualification> qualifications = vetQualificationMapper.selectQualificationsByUserId(vetInfo.getUserId());
// 3. 获取用户信息
SysUser user = sysUserService.selectUserById(vetInfo.getUserId());
// 4. 组装返回结果
Map<String, Object> result = new HashMap<>();
result.put("vetInfo", vetInfo);
result.put("qualifications", qualifications); // 这里包含证书信息
result.put("userInfo", user);
return result;
}
@Override
public Map<String, Object> getVetFullInfoWithQualificationsByUserId(Long userId) {
// 1. 根据用户ID获取兽医信息
VetPersonalInfo vetInfo = vetPersonalInfoMapper.selectVetPersonalInfoByUserId(userId);
if (vetInfo == null) {
return null;
}
// 2. 获取资质证书信息
List<VetQualification> qualifications = vetQualificationMapper.selectQualificationsByUserId(userId);
// 3. 获取用户信息
SysUser user = sysUserService.selectUserById(userId);
// 4. 组装返回结果
Map<String, Object> result = new HashMap<>();
result.put("vetInfo", vetInfo);
result.put("qualifications", qualifications);
result.put("userInfo", user);
return result;
}
/**
* 查询兽医个人信息列表包含用户信息
*/
@ -60,6 +105,8 @@ public class VetPersonalInfoServiceImpl implements IVetPersonalInfoService {
return list;
}
/**
* 新增兽医个人信息
*/
@ -166,7 +213,7 @@ public class VetPersonalInfoServiceImpl implements IVetPersonalInfoService {
}
/**
* 获取兽医的完整信息包含证书详情和用户信息
* 获取兽医的完整信息包含资质详情和用户信息
*/
@Override
public Map<String, Object> getVetFullInfo(Long vetId) {
@ -179,23 +226,30 @@ public class VetPersonalInfoServiceImpl implements IVetPersonalInfoService {
}
result.put("personalInfo", personalInfo);
// 2. 获取证书列表
VetCertificate certificateQuery = new VetCertificate();
certificateQuery.setUserId(personalInfo.getUserId());
List<VetCertificate> certificates = vetCertificateMapper.selectVetCertificateList(certificateQuery);
// 2. 获取资质列表包含证书信息
VetQualification qualificationQuery = new VetQualification();
qualificationQuery.setUserId(personalInfo.getUserId());
List<VetQualification> qualifications = vetQualificationMapper.selectVetQualificationList(qualificationQuery);
result.put("qualifications", qualifications);
// 3. 过滤出有证书信息的资质
List<VetQualification> certificates = qualifications.stream()
.filter(q -> q.getCertName() != null && !q.getCertName().isEmpty())
.toList();
result.put("certificates", certificates);
// 3. 证书统计信息
if (certificates != null && !certificates.isEmpty()) {
// 4. 证书统计信息
if (!certificates.isEmpty()) {
result.put("certificateCount", certificates.size());
result.put("certificateNames", certificates.stream()
.map(VetCertificate::getCertName)
.map(VetQualification::getCertName)
.filter(name -> name != null && !name.isEmpty())
.collect(Collectors.joining(", ")));
// 按状态统计
long validCount = certificates.stream().filter(cert -> "0".equals(cert.getStatus())).count();
long expiringCount = certificates.stream().filter(cert -> "1".equals(cert.getStatus())).count();
long expiredCount = certificates.stream().filter(cert -> "2".equals(cert.getStatus())).count();
long validCount = certificates.stream().filter(cert -> "0".equals(cert.getCertStatus())).count();
long expiringCount = certificates.stream().filter(cert -> "1".equals(cert.getCertStatus())).count();
long expiredCount = certificates.stream().filter(cert -> "2".equals(cert.getCertStatus())).count();
Map<String, Long> statusStats = new HashMap<>();
statusStats.put("valid", validCount);
@ -207,11 +261,29 @@ public class VetPersonalInfoServiceImpl implements IVetPersonalInfoService {
result.put("certificateNames", "");
}
// 5. 资质统计信息
if (!qualifications.isEmpty()) {
result.put("qualificationCount", qualifications.size());
// 按审核状态统计
long pendingCount = qualifications.stream().filter(q -> "0".equals(q.getAuditStatus())).count();
long approvedCount = qualifications.stream().filter(q -> "1".equals(q.getAuditStatus())).count();
long rejectedCount = qualifications.stream().filter(q -> "2".equals(q.getAuditStatus())).count();
Map<String, Long> auditStats = new HashMap<>();
auditStats.put("pending", pendingCount);
auditStats.put("approved", approvedCount);
auditStats.put("rejected", rejectedCount);
result.put("auditStats", auditStats);
} else {
result.put("qualificationCount", 0);
}
return result;
}
/**
* 根据用户ID获取兽医信息包含证书和用户信息
* 根据用户ID获取兽医信息包含资质和用户信息
*/
@Override
public Map<String, Object> getVetFullInfoByUserId(Long userId) {
@ -231,19 +303,57 @@ public class VetPersonalInfoServiceImpl implements IVetPersonalInfoService {
result.put("personalInfo", personalInfo);
result.put("userInfo", personalInfo.getUser());
// 2. 获取证书列表
VetCertificate certificateQuery = new VetCertificate();
certificateQuery.setUserId(userId);
List<VetCertificate> certificates = vetCertificateMapper.selectVetCertificateList(certificateQuery);
// 2. 获取资质列表包含证书信息
VetQualification qualificationQuery = new VetQualification();
qualificationQuery.setUserId(userId);
List<VetQualification> qualifications = vetQualificationMapper.selectVetQualificationList(qualificationQuery);
result.put("qualifications", qualifications);
// 3. 过滤出有证书信息的资质
List<VetQualification> certificates = qualifications.stream()
.filter(q -> q.getCertName() != null && !q.getCertName().isEmpty())
.toList();
result.put("certificates", certificates);
// 3. 证书统计信息
if (certificates != null && !certificates.isEmpty()) {
result.put("certificateCount", certificates.size());
result.put("certificateNames", certificates.stream()
.map(VetCertificate::getCertName)
.collect(Collectors.joining(", ")));
// 4. 统计信息
if (!qualifications.isEmpty()) {
result.put("qualificationCount", qualifications.size());
// 证书统计
if (!certificates.isEmpty()) {
result.put("certificateCount", certificates.size());
result.put("certificateNames", certificates.stream()
.map(VetQualification::getCertName)
.filter(name -> name != null && !name.isEmpty())
.collect(Collectors.joining(", ")));
// 证书状态统计
long validCount = certificates.stream().filter(cert -> "0".equals(cert.getCertStatus())).count();
long expiringCount = certificates.stream().filter(cert -> "1".equals(cert.getCertStatus())).count();
long expiredCount = certificates.stream().filter(cert -> "2".equals(cert.getCertStatus())).count();
Map<String, Long> certStats = new HashMap<>();
certStats.put("valid", validCount);
certStats.put("expiring", expiringCount);
certStats.put("expired", expiredCount);
result.put("certStats", certStats);
} else {
result.put("certificateCount", 0);
result.put("certificateNames", "");
}
// 资质审核状态统计
long pendingCount = qualifications.stream().filter(q -> "0".equals(q.getAuditStatus())).count();
long approvedCount = qualifications.stream().filter(q -> "1".equals(q.getAuditStatus())).count();
long rejectedCount = qualifications.stream().filter(q -> "2".equals(q.getAuditStatus())).count();
Map<String, Long> auditStats = new HashMap<>();
auditStats.put("pending", pendingCount);
auditStats.put("approved", approvedCount);
auditStats.put("rejected", rejectedCount);
result.put("auditStats", auditStats);
} else {
result.put("qualificationCount", 0);
result.put("certificateCount", 0);
result.put("certificateNames", "");
}

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

@ -0,0 +1,93 @@
package com.chenhai.vet.service.impl;
import java.util.List;
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;
/**
* 兽医产品信息Service业务层处理
*
* @author ruoyi
* @date 2026-01-15
*/
@Service
public class VetProductServiceImpl implements IVetProductService
{
@Autowired
private VetProductMapper vetProductMapper;
/**
* 查询兽医产品信息
*
* @param id 兽医产品信息主键
* @return 兽医产品信息
*/
@Override
public VetProduct selectVetProductById(Long id)
{
return vetProductMapper.selectVetProductById(id);
}
/**
* 查询兽医产品信息列表
*
* @param vetProduct 兽医产品信息
* @return 兽医产品信息
*/
@Override
public List<VetProduct> selectVetProductList(VetProduct vetProduct)
{
return vetProductMapper.selectVetProductList(vetProduct);
}
/**
* 新增兽医产品信息
*
* @param vetProduct 兽医产品信息
* @return 结果
*/
@Override
public int insertVetProduct(VetProduct vetProduct)
{
return vetProductMapper.insertVetProduct(vetProduct);
}
/**
* 修改兽医产品信息
*
* @param vetProduct 兽医产品信息
* @return 结果
*/
@Override
public int updateVetProduct(VetProduct vetProduct)
{
return vetProductMapper.updateVetProduct(vetProduct);
}
/**
* 批量删除兽医产品信息
*
* @param ids 需要删除的兽医产品信息主键
* @return 结果
*/
@Override
public int deleteVetProductByIds(Long[] ids)
{
return vetProductMapper.deleteVetProductByIds(ids);
}
/**
* 删除兽医产品信息信息
*
* @param id 兽医产品信息主键
* @return 结果
*/
@Override
public int deleteVetProductById(Long id)
{
return vetProductMapper.deleteVetProductById(id);
}
}

264
chenhai-system/src/main/java/com/chenhai/vet/service/impl/VetQualificationServiceImpl.java

@ -1,25 +1,31 @@
package com.chenhai.vet.service.impl;
import com.chenhai.common.utils.DateUtils;
import com.chenhai.common.utils.StringUtils;
import com.chenhai.vet.domain.VetQualification;
import com.chenhai.vet.mapper.VetQualificationMapper;
import com.chenhai.vet.service.IVetQualificationService;
import com.chenhai.vet.service.VetNotificationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.*;
/**
* 兽医资质Service业务层处理合并证书功能
*/
@Service
public class VetQualificationServiceImpl implements IVetQualificationService {
public class VetQualificationServiceImpl implements IVetQualificationService
{
@Autowired
private VetQualificationMapper vetQualificationMapper;
// 修复2给JdbcTemplate加注入注解
@Autowired
private JdbcTemplate jdbcTemplate;
@Autowired
private VetNotificationService vetNotificationService;
/**
* 查询兽医资质列表
@ -34,6 +40,9 @@ public class VetQualificationServiceImpl implements IVetQualificationService {
String scopeNames = getScopeNamesFromDict(qualification.getScopeIds());
qualification.setScopeNames(scopeNames);
}
// 更新证书状态
updateCertificateStatus(qualification);
}
return list;
}
@ -73,9 +82,6 @@ public class VetQualificationServiceImpl implements IVetQualificationService {
if (StringUtils.isEmpty(certificateFilesJson)) {
return "";
}
// 如果certificateFiles是JSON数组字符串这里可以根据需要处理
// 简单处理直接存储为字符串或解析JSON后存储
return certificateFilesJson;
} catch (Exception e) {
return certificateFilesJson;
@ -87,7 +93,12 @@ public class VetQualificationServiceImpl implements IVetQualificationService {
*/
@Override
public VetQualification selectVetQualificationByQualificationId(Long qualificationId) {
return vetQualificationMapper.selectVetQualificationByQualificationId(qualificationId);
VetQualification qualification = vetQualificationMapper.selectVetQualificationByQualificationId(qualificationId);
if (qualification != null) {
// 更新证书状态
updateCertificateStatus(qualification);
}
return qualification;
}
/**
@ -96,11 +107,11 @@ public class VetQualificationServiceImpl implements IVetQualificationService {
@Override
public int insertVetQualification(VetQualification vetQualification) {
if (vetQualification.getAuditStatus() == null) {
vetQualification.setAuditStatus("2");
vetQualification.setAuditStatus(null);
}
if (vetQualification.getCertificateFiles() == null ||
vetQualification.getCertificateFiles().isEmpty()) {
vetQualification.setCertificateFiles("default.pdf"); // 默认值
vetQualification.setCertificateFiles("default.pdf");
}
if (vetQualification.getScopeIds() != null && !vetQualification.getScopeIds().isEmpty()) {
@ -108,6 +119,14 @@ public class VetQualificationServiceImpl implements IVetQualificationService {
vetQualification.setScopeNames(scopeNames);
}
// 设置默认提醒天数
if (vetQualification.getRemindDays() == null) {
vetQualification.setRemindDays(30);
}
// 验证并设置证书状态
updateCertificateStatus(vetQualification);
return vetQualificationMapper.insertVetQualification(vetQualification);
}
@ -126,6 +145,9 @@ public class VetQualificationServiceImpl implements IVetQualificationService {
vetQualification.setScopeNames(scopeNames);
}
// 验证并更新证书状态
updateCertificateStatus(vetQualification);
return vetQualificationMapper.updateVetQualification(vetQualification);
}
@ -145,39 +167,205 @@ public class VetQualificationServiceImpl implements IVetQualificationService {
return vetQualificationMapper.deleteVetQualificationByQualificationId(qualificationId);
}
private void createCertificateFromQualification(VetQualification qualification) {
try {
// 检查是否已存在证书
String checkSql = "SELECT COUNT(*) FROM vet_certificate WHERE qualification_id = ?";
Integer count = jdbcTemplate.queryForObject(checkSql, Integer.class,
qualification.getQualificationId());
if (count != null && count > 0) {
System.out.println("资质ID " + qualification.getQualificationId() + " 已存在证书,跳过创建");
return;
/**
* 根据用户ID查询资质证书列表
*/
@Override
public List<VetQualification> selectQualificationsByUserId(Long userId) {
VetQualification query = new VetQualification();
query.setUserId(userId);
return selectVetQualificationList(query);
}
/**
* 获取即将过期的资质证书30天内
*/
@Override
public List<VetQualification> selectExpiringQualifications(Long userId) {
Date today = new Date();
Calendar calendar = Calendar.getInstance();
calendar.setTime(today);
calendar.add(Calendar.DAY_OF_YEAR, 30);
Date thirtyDaysLater = calendar.getTime();
// 先获取用户所有资质证书
List<VetQualification> allQualifications = selectQualificationsByUserId(userId);
// 过滤出即将过期的证书
return allQualifications.stream()
.filter(qual -> qual.getExpireDate() != null &&
!qual.getExpireDate().before(today) &&
!qual.getExpireDate().after(thirtyDaysLater))
.toList();
}
/**
* 检查并发送证书过期提醒
*/
@Override
public void checkAndSendCertificateReminders() {
Date today = new Date();
Calendar calendar = Calendar.getInstance();
calendar.setTime(today);
calendar.add(Calendar.DAY_OF_YEAR, 30);
Date thresholdDate = calendar.getTime(); // 30天后过期
calendar.setTime(today);
calendar.add(Calendar.DAY_OF_YEAR, -7);
Date remindDate = calendar.getTime(); // 7天前提醒过的不再提醒
// 查询所有资质证书
VetQualification query = new VetQualification();
List<VetQualification> allQualifications = vetQualificationMapper.selectVetQualificationList(query);
int successCount = 0;
int failCount = 0;
for (VetQualification qualification : allQualifications) {
try {
// 检查证书是否需要提醒
if (shouldSendRemind(qualification, today, thresholdDate, remindDate)) {
// 调用通知服务发送站内信
vetNotificationService.sendCertificateExpireRemind(qualification);
// 更新最后提醒时间
qualification.setLastRemindTime(new Date());
vetQualificationMapper.updateVetQualification(qualification);
successCount++;
}
} catch (Exception e) {
failCount++;
e.printStackTrace();
}
}
}
/**
* 判断是否需要发送提醒
*/
private boolean shouldSendRemind(VetQualification qualification, Date today,
Date thresholdDate, Date remindDate) {
if (qualification.getExpireDate() == null) {
return false;
}
String sql = "INSERT INTO vet_certificate (" +
"user_id, cert_number, " +
"create_by, create_time, " +
"qualification_id" +
") VALUES (?, ?, ?, NOW(), ?)";
// 检查是否即将过期30天内
if (qualification.getExpireDate().after(thresholdDate)) {
return false;
}
jdbcTemplate.update(sql,
qualification.getUserId(),
qualification.getCertificateNo(),
qualification.getCreateBy(),
qualification.getQualificationId()
);
// 检查是否已提醒过7天内
if (qualification.getLastRemindTime() != null) {
Calendar cal = Calendar.getInstance();
cal.setTime(qualification.getLastRemindTime());
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
Date lastRemindDateOnly = cal.getTime();
System.out.println("✅ 审核通过,已创建证书编号:" + qualification.getCertificateNo());
System.out.println("ℹ️ 证书名称、类型、发证机构等信息请在证书管理页面完善");
if (!lastRemindDateOnly.before(remindDate)) {
return false;
}
}
} catch (Exception e) {
System.err.println("❌ 创建证书失败:" + e.getMessage());
e.printStackTrace();
return true;
}
/**
* 更新证书状态
*/
private void updateCertificateStatus(VetQualification qualification) {
if (qualification.getExpireDate() == null) {
qualification.setCertStatus("0");
return;
}
Date today = new Date();
Calendar calendar = Calendar.getInstance();
calendar.setTime(today);
calendar.add(Calendar.DAY_OF_YEAR, 30);
Date thirtyDaysLater = calendar.getTime();
if (qualification.getExpireDate().before(today)) {
qualification.setCertStatus("2"); // 已过期
} else if (qualification.getExpireDate().before(thirtyDaysLater)) {
qualification.setCertStatus("1"); // 即将过期
} else {
qualification.setCertStatus("0"); // 正常
}
}
/**
* 手动检查证书
*/
@Override
public void manualCheckCertificates(Long userId) {
List<VetQualification> qualifications = selectQualificationsByUserId(userId);
for (VetQualification qualification : qualifications) {
updateCertificateStatus(qualification);
vetQualificationMapper.updateVetQualification(qualification);
}
}
}
/**
* 获取证书统计信息
*/
@Override
public Map<String, Object> getCertificateStatistics(Long userId) {
Map<String, Object> statistics = new HashMap<>();
List<VetQualification> qualifications = selectQualificationsByUserId(userId);
Date today = new Date();
long total = qualifications.size();
long expiring = 0; // 30天内过期
long expired = 0; // 已过期
int expiringSoon = 0; // 7天内过期
Calendar calendar = Calendar.getInstance();
calendar.setTime(today);
calendar.add(Calendar.DAY_OF_YEAR, 30);
Date thirtyDaysLater = calendar.getTime();
calendar.setTime(today);
calendar.add(Calendar.DAY_OF_YEAR, 7);
Date sevenDaysLater = calendar.getTime();
for (VetQualification qual : qualifications) {
if (qual.getExpireDate() != null) {
if (qual.getExpireDate().before(today)) {
expired++;
} else if (qual.getExpireDate().before(thirtyDaysLater)) {
expiring++;
// 7天内过期
if (qual.getExpireDate().before(sevenDaysLater)) {
expiringSoon++;
}
}
}
}
long normal = total - expiring - expired;
statistics.put("total", total);
statistics.put("normal", normal);
statistics.put("expiring", expiring);
statistics.put("expired", expired);
statistics.put("expiringSoon", expiringSoon);
// 设置警告级别
if (expired > 0) {
statistics.put("warningLevel", "DANGER");
} else if (expiring > 0 || expiringSoon > 0) {
statistics.put("warningLevel", "WARNING");
} else {
statistics.put("warningLevel", "NORMAL");
}
return statistics;
}
}

122
chenhai-system/src/main/resources/mapper/vet/VetCertificateMapper.xml

@ -1,122 +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.VetCertificateMapper">
<resultMap type="VetCertificate" id="VetCertificateResult">
<result property="id" column="id" />
<result property="userId" column="user_id" />
<result property="certName" column="cert_name" />
<result property="certNumber" column="cert_number" />
<result property="certType" column="cert_type" />
<result property="issueOrg" column="issue_org" />
<result property="issueDate" column="issue_date" />
<result property="expireDate" column="expire_date" />
<result property="certImage" column="cert_image" />
<result property="status" column="status" />
<result property="remindDays" column="remind_days" />
<result property="lastRemindTime" column="last_remind_time" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
<result property="updateBy" column="update_by" />
<result property="updateTime" column="update_time" />
</resultMap>
<sql id="selectVetCertificateVo">
select id, user_id, cert_name, cert_number, cert_type, issue_org, issue_date, expire_date, cert_image, status, remind_days, last_remind_time, create_by, create_time, update_by, update_time from vet_certificate
</sql>
<select id="selectVetCertificateList" parameterType="VetCertificate" resultMap="VetCertificateResult">
<include refid="selectVetCertificateVo"/>
<where>
<if test="userId != null "> and user_id = #{userId}</if>
<if test="certName != null and certName != ''"> and cert_name like concat('%', #{certName}, '%')</if>
<if test="certNumber != null and certNumber != ''"> and cert_number = #{certNumber}</if>
<if test="certType != null and certType != ''"> and cert_type = #{certType}</if>
<if test="issueOrg != null and issueOrg != ''"> and issue_org = #{issueOrg}</if>
<if test="issueDate != null "> and issue_date = #{issueDate}</if>
<if test="expireDate != null "> and expire_date = #{expireDate}</if>
<if test="certImage != null and certImage != ''"> and cert_image = #{certImage}</if>
<if test="status != null and status != ''"> and status = #{status}</if>
<if test="remindDays != null "> and remind_days = #{remindDays}</if>
<if test="lastRemindTime != null "> and last_remind_time = #{lastRemindTime}</if>
</where>
</select>
<select id="selectVetCertificateById" parameterType="Long" resultMap="VetCertificateResult">
<include refid="selectVetCertificateVo"/>
where id = #{id}
</select>
<insert id="insertVetCertificate" parameterType="VetCertificate" useGeneratedKeys="true" keyProperty="id">
insert into vet_certificate
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="userId != null">user_id,</if>
<if test="certName != null">cert_name,</if>
<if test="certNumber != null">cert_number,</if>
<if test="certType != null">cert_type,</if>
<if test="issueOrg != null">issue_org,</if>
<if test="issueDate != null">issue_date,</if>
<if test="expireDate != null">expire_date,</if>
<if test="certImage != null">cert_image,</if>
<if test="status != null">status,</if>
<if test="remindDays != null">remind_days,</if>
<if test="lastRemindTime != null">last_remind_time,</if>
<if test="createBy != null">create_by,</if>
<if test="createTime != null">create_time,</if>
<if test="updateBy != null">update_by,</if>
<if test="updateTime != null">update_time,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="userId != null">#{userId},</if>
<if test="certName != null">#{certName},</if>
<if test="certNumber != null">#{certNumber},</if>
<if test="certType != null">#{certType},</if>
<if test="issueOrg != null">#{issueOrg},</if>
<if test="issueDate != null">#{issueDate},</if>
<if test="expireDate != null">#{expireDate},</if>
<if test="certImage != null">#{certImage},</if>
<if test="status != null">#{status},</if>
<if test="remindDays != null">#{remindDays},</if>
<if test="lastRemindTime != null">#{lastRemindTime},</if>
<if test="createBy != null">#{createBy},</if>
<if test="createTime != null">#{createTime},</if>
<if test="updateBy != null">#{updateBy},</if>
<if test="updateTime != null">#{updateTime},</if>
</trim>
</insert>
<update id="updateVetCertificate" parameterType="VetCertificate">
update vet_certificate
<trim prefix="SET" suffixOverrides=",">
<if test="userId != null">user_id = #{userId},</if>
<if test="certName != null">cert_name = #{certName},</if>
<if test="certNumber != null">cert_number = #{certNumber},</if>
<if test="certType != null">cert_type = #{certType},</if>
<if test="issueOrg != null">issue_org = #{issueOrg},</if>
<if test="issueDate != null">issue_date = #{issueDate},</if>
<if test="expireDate != null">expire_date = #{expireDate},</if>
<if test="certImage != null">cert_image = #{certImage},</if>
<if test="status != null">status = #{status},</if>
<if test="remindDays != null">remind_days = #{remindDays},</if>
<if test="lastRemindTime != null">last_remind_time = #{lastRemindTime},</if>
<if test="createBy != null">create_by = #{createBy},</if>
<if test="createTime != null">create_time = #{createTime},</if>
<if test="updateBy != null">update_by = #{updateBy},</if>
<if test="updateTime != null">update_time = #{updateTime},</if>
</trim>
where id = #{id}
</update>
<delete id="deleteVetCertificateById" parameterType="Long">
delete from vet_certificate where id = #{id}
</delete>
<delete id="deleteVetCertificateByIds" parameterType="String">
delete from vet_certificate where id in
<foreach item="id" collection="array" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
</mapper>

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

@ -54,6 +54,15 @@
<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="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
</select>

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

@ -0,0 +1,186 @@
<?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.VetProductMapper">
<resultMap type="VetProduct" id="VetProductResult">
<result property="id" column="id" />
<result property="name" column="name" />
<result property="type" column="type" />
<result property="category" column="category" />
<result property="specification" column="specification" />
<result property="unit" column="unit" />
<result property="manufacturer" column="manufacturer" />
<result property="approvalNumber" column="approval_number" />
<result property="ingredients" column="ingredients" />
<result property="indications" column="indications" />
<result property="usageDosage" column="usage_dosage" />
<result property="price" column="price" />
<result property="costPrice" column="cost_price" />
<result property="stock" column="stock" />
<result property="minStock" column="min_stock" />
<result property="mainImage" column="main_image" />
<result property="images" column="images" />
<result property="treatAnimals" column="treat_animals" />
<result property="treatDiseases" column="treat_diseases" />
<result property="treatmentContent" column="treatment_content" />
<result property="treatmentDuration" column="treatment_duration" />
<result property="precautions" column="precautions" />
<result property="status" column="status" />
<result property="isDeleted" column="is_deleted" />
<result property="clinicId" column="clinic_id" />
<result property="userId" column="user_id" />
<result property="createdAt" column="created_at" />
<result property="updatedAt" column="updated_at" />
</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, vet_id, created_at, updated_at from vet_product
</sql>
<select id="selectVetProductList" parameterType="VetProduct" resultMap="VetProductResult">
<include refid="selectVetProductVo"/>
<where>
<if test="name != null and name != ''"> and name like concat('%', #{name}, '%')</if>
<if test="type != null and type != ''"> and type = #{type}</if>
<if test="category != null and category != ''"> and category = #{category}</if>
<if test="specification != null and specification != ''"> and specification = #{specification}</if>
<if test="unit != null and unit != ''"> and unit = #{unit}</if>
<if test="manufacturer != null and manufacturer != ''"> and manufacturer = #{manufacturer}</if>
<if test="approvalNumber != null and approvalNumber != ''"> and approval_number = #{approvalNumber}</if>
<if test="ingredients != null and ingredients != ''"> and ingredients = #{ingredients}</if>
<if test="indications != null and indications != ''"> and indications = #{indications}</if>
<if test="usageDosage != null and usageDosage != ''"> and usage_dosage = #{usageDosage}</if>
<if test="price != null "> and price = #{price}</if>
<if test="costPrice != null "> and cost_price = #{costPrice}</if>
<if test="stock != null "> and stock = #{stock}</if>
<if test="minStock != null "> and min_stock = #{minStock}</if>
<if test="mainImage != null and mainImage != ''"> and main_image = #{mainImage}</if>
<if test="images != null and images != ''"> and images = #{images}</if>
<if test="treatAnimals != null and treatAnimals != ''"> and treat_animals = #{treatAnimals}</if>
<if test="treatDiseases != null and treatDiseases != ''"> and treat_diseases = #{treatDiseases}</if>
<if test="treatmentContent != null and treatmentContent != ''"> and treatment_content = #{treatmentContent}</if>
<if test="treatmentDuration != null and treatmentDuration != ''"> and treatment_duration = #{treatmentDuration}</if>
<if test="precautions != null and precautions != ''"> and precautions = #{precautions}</if>
<if test="status != null and status != ''"> and status = #{status}</if>
<if test="isDeleted != null "> and is_deleted = #{isDeleted}</if>
<if test="clinicId != null "> and clinic_id = #{clinicId}</if>
<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>
</where>
</select>
<select id="selectVetProductById" parameterType="Long" resultMap="VetProductResult">
<include refid="selectVetProductVo"/>
where id = #{id}
</select>
<insert id="insertVetProduct" parameterType="VetProduct" useGeneratedKeys="true" keyProperty="id">
insert into vet_product
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="name != null and name != ''">name,</if>
<if test="type != null and type != ''">type,</if>
<if test="category != null">category,</if>
<if test="specification != null">specification,</if>
<if test="unit != null">unit,</if>
<if test="manufacturer != null">manufacturer,</if>
<if test="approvalNumber != null">approval_number,</if>
<if test="ingredients != null">ingredients,</if>
<if test="indications != null">indications,</if>
<if test="usageDosage != null">usage_dosage,</if>
<if test="price != null">price,</if>
<if test="costPrice != null">cost_price,</if>
<if test="stock != null">stock,</if>
<if test="minStock != null">min_stock,</if>
<if test="mainImage != null">main_image,</if>
<if test="images != null">images,</if>
<if test="treatAnimals != null">treat_animals,</if>
<if test="treatDiseases != null">treat_diseases,</if>
<if test="treatmentContent != null">treatment_content,</if>
<if test="treatmentDuration != null">treatment_duration,</if>
<if test="precautions != null">precautions,</if>
<if test="status != null">status,</if>
<if test="isDeleted != null">is_deleted,</if>
<if test="clinicId != null">clinic_id,</if>
<if test="userId != null">user_id,</if>
<if test="createdAt != null">created_at,</if>
<if test="updatedAt != null">updated_at,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="name != null and name != ''">#{name},</if>
<if test="type != null and type != ''">#{type},</if>
<if test="category != null">#{category},</if>
<if test="specification != null">#{specification},</if>
<if test="unit != null">#{unit},</if>
<if test="manufacturer != null">#{manufacturer},</if>
<if test="approvalNumber != null">#{approvalNumber},</if>
<if test="ingredients != null">#{ingredients},</if>
<if test="indications != null">#{indications},</if>
<if test="usageDosage != null">#{usageDosage},</if>
<if test="price != null">#{price},</if>
<if test="costPrice != null">#{costPrice},</if>
<if test="stock != null">#{stock},</if>
<if test="minStock != null">#{minStock},</if>
<if test="mainImage != null">#{mainImage},</if>
<if test="images != null">#{images},</if>
<if test="treatAnimals != null">#{treatAnimals},</if>
<if test="treatDiseases != null">#{treatDiseases},</if>
<if test="treatmentContent != null">#{treatmentContent},</if>
<if test="treatmentDuration != null">#{treatmentDuration},</if>
<if test="precautions != null">#{precautions},</if>
<if test="status != null">#{status},</if>
<if test="isDeleted != null">#{isDeleted},</if>
<if test="clinicId != null">#{clinicId},</if>
<if test="userId != null">#{userId},</if>
<if test="createdAt != null">#{createdAt},</if>
<if test="updatedAt != null">#{updatedAt},</if>
</trim>
</insert>
<update id="updateVetProduct" parameterType="VetProduct">
update vet_product
<trim prefix="SET" suffixOverrides=",">
<if test="name != null and name != ''">name = #{name},</if>
<if test="type != null and type != ''">type = #{type},</if>
<if test="category != null">category = #{category},</if>
<if test="specification != null">specification = #{specification},</if>
<if test="unit != null">unit = #{unit},</if>
<if test="manufacturer != null">manufacturer = #{manufacturer},</if>
<if test="approvalNumber != null">approval_number = #{approvalNumber},</if>
<if test="ingredients != null">ingredients = #{ingredients},</if>
<if test="indications != null">indications = #{indications},</if>
<if test="usageDosage != null">usage_dosage = #{usageDosage},</if>
<if test="price != null">price = #{price},</if>
<if test="costPrice != null">cost_price = #{costPrice},</if>
<if test="stock != null">stock = #{stock},</if>
<if test="minStock != null">min_stock = #{minStock},</if>
<if test="mainImage != null">main_image = #{mainImage},</if>
<if test="images != null">images = #{images},</if>
<if test="treatAnimals != null">treat_animals = #{treatAnimals},</if>
<if test="treatDiseases != null">treat_diseases = #{treatDiseases},</if>
<if test="treatmentContent != null">treatment_content = #{treatmentContent},</if>
<if test="treatmentDuration != null">treatment_duration = #{treatmentDuration},</if>
<if test="precautions != null">precautions = #{precautions},</if>
<if test="status != null">status = #{status},</if>
<if test="isDeleted != null">is_deleted = #{isDeleted},</if>
<if test="clinicId != null">clinic_id = #{clinicId},</if>
<if test="userId != null">user_id = #{userId},</if>
<if test="createdAt != null">created_at = #{createdAt},</if>
<if test="updatedAt != null">updated_at = #{updatedAt},</if>
</trim>
where id = #{id}
</update>
<delete id="deleteVetProductById" parameterType="Long">
delete from vet_product where id = #{id}
</delete>
<delete id="deleteVetProductByIds" parameterType="String">
delete from vet_product where id in
<foreach item="id" collection="array" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
</mapper>

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

@ -1,9 +1,9 @@
<?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">
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.chenhai.vet.mapper.VetQualificationMapper">
<resultMap type="VetQualification" id="VetQualificationResult">
<result property="qualificationId" column="qualification_id" />
<result property="userId" column="user_id" />
@ -25,46 +25,69 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="remark" column="remark" />
<result property="scopeIds" column="scope_ids" />
<result property="scopeNames" column="scope_names" />
<!-- 新增证书字段 -->
<result property="certName" column="cert_name" />
<result property="certType" column="cert_type" />
<result property="issueOrg" column="issue_org" />
<result property="issueDate" column="issue_date" />
<result property="expireDate" column="expire_date" />
<result property="certImage" column="cert_image" />
<result property="certStatus" column="cert_status" />
<result property="certStatusLabel" column="cert_status_label"/>
<result property="remindDays" column="remind_days" />
<result property="lastRemindTime" column="last_remind_time" />
</resultMap>
<!-- <sql id="selectVetQualificationVo">
select qualification_id, vet_id, real_name, id_card, qualification_type, certificate_no, certificate_files, apply_time, audit_time, audit_status, audit_opinion, auditor_id, create_by, create_time, update_by, update_time, remark ,scope_ids ,scope_names from vet_qualification
</sql>-->
<sql id="selectVetQualificationVo">
select
vq.*,
<!-- 资质类型:从字典表获取标签 -->
sd1.dict_label as qualification_type_label,
<!-- 证书状态:从字典表获取标签 -->
sd2.dict_label as cert_status_label,
<!-- 经营范围:从字典表获取 -->
<!-- 注意:这里需要处理多个scope_ids的情况 -->
vq.scope_names as scope_names
from vet_qualification vq
left join sys_dict_data sd1 on sd1.dict_value = vq.qualification_type
and sd1.dict_type = 'qualification_type'
left join sys_dict_data sd2 on sd2.dict_value = vq.cert_status
and sd2.dict_type = 'certificate_status'
</sql>
<select id="selectVetQualificationList" parameterType="VetQualification" resultMap="VetQualificationResult">
<include refid="selectVetQualificationVo"/>
<where>
<if test="userId != null "> and user_id = #{userId}</if>
<if test="realName != null and realName != ''"> and real_name like concat('%', #{realName}, '%')</if>
<if test="idCard != null and idCard != ''"> and id_card = #{idCard}</if>
<if test="qualificationType != null and qualificationType != ''"> and qualification_type = #{qualificationType}</if>
<if test="certificateNo != null and certificateNo != ''"> and certificate_no = #{certificateNo}</if>
<if test="certificateFiles != null and certificateFiles != ''"> and certificate_files = #{certificateFiles}</if>
<if test="applyTime != null "> and apply_time = #{applyTime}</if>
<if test="auditTime != null "> and audit_time = #{auditTime}</if>
<if test="auditStatus != null and auditStatus != ''"> and audit_status = #{auditStatus}</if>
<if test="auditOpinion != null and auditOpinion != ''"> and audit_opinion = #{auditOpinion}</if>
<if test="auditorId != null "> and auditor_id = #{auditorId}</if>
<if test="scopeNames !=null">and scope_names=#{scopeNames}</if>
<where>
<if test="userId != null "> and vq.user_id = #{userId}</if>
<if test="realName != null and realName != ''"> and vq.real_name like concat('%', #{realName}, '%')</if>
<if test="idCard != null and idCard != ''"> and vq.id_card = #{idCard}</if>
<if test="qualificationType != null and qualificationType != ''"> and vq.qualification_type = #{qualificationType}</if>
<if test="certificateNo != null and certificateNo != ''"> and vq.certificate_no = #{certificateNo}</if>
<if test="certificateFiles != null and certificateFiles != ''"> and vq.certificate_files = #{certificateFiles}</if>
<if test="applyTime != null "> and vq.apply_time = #{applyTime}</if>
<if test="auditTime != null "> and vq.audit_time = #{auditTime}</if>
<if test="auditStatus != null and auditStatus != ''"> and vq.audit_status = #{auditStatus}</if>
<if test="auditOpinion != null and auditOpinion != ''"> and vq.audit_opinion = #{auditOpinion}</if>
<if test="auditorId != null "> and vq.auditor_id = #{auditorId}</if>
<if test="scopeNames !=null and scopeNames != ''">and vq.scope_names = #{scopeNames}</if>
<!-- 新增证书查询条件 -->
<if test="certName != null and certName != ''"> and vq.cert_name like concat('%', #{certName}, '%')</if>
<if test="certType != null and certType != ''"> and vq.cert_type = #{certType}</if>
<if test="issueOrg != null and issueOrg != ''"> and vq.issue_org = #{issueOrg}</if>
<if test="issueDate != null "> and vq.issue_date = #{issueDate}</if>
<if test="expireDate != null "> and vq.expire_date = #{expireDate}</if>
<if test="certStatus != null and certStatus != ''"> and vq.cert_status = #{certStatus}</if>
<!-- 查询即将过期 -->
<if test="expiringOnly != null and expiringOnly">
and vq.expire_date between curdate() and date_add(curdate(), interval 30 day)
and vq.cert_name is not null and vq.cert_name != ''
</if>
</where>
order by vq.qualification_id desc
</select>
<select id="selectVetQualificationByQualificationId" parameterType="Long" resultMap="VetQualificationResult">
<include refid="selectVetQualificationVo"/>
where qualification_id = #{qualificationId}
where vq.qualification_id = #{qualificationId}
</select>
<insert id="insertVetQualification" parameterType="VetQualification" useGeneratedKeys="true" keyProperty="qualificationId">
@ -88,7 +111,17 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="remark != null">remark,</if>
<if test="scopeIds != null and scopeIds != ''">scope_ids,</if>
<if test="scopeNames != null and scopeNames != ''">scope_names,</if>
</trim>
<!-- 新增证书字段 -->
<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>
<if test="issueDate != null">issue_date,</if>
<if test="expireDate != null">expire_date,</if>
<if test="certImage != null and certImage != ''">cert_image,</if>
<if test="certStatus != null and certStatus != ''">cert_status,</if>
<if test="remindDays != null">remind_days,</if>
<if test="lastRemindTime != null">last_remind_time,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="userId != null">#{userId},</if>
<if test="realName != null and realName != ''">#{realName},</if>
@ -108,7 +141,17 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="remark != null">#{remark},</if>
<if test="scopeIds != null and scopeIds != ''">#{scopeIds},</if>
<if test="scopeNames != null and scopeNames != ''">#{scopeNames},</if>
</trim>
<!-- 新增证书字段 -->
<if test="certName != null and certName != ''">#{certName},</if>
<if test="certType != null and certType != ''">#{certType},</if>
<if test="issueOrg != null and issueOrg != ''">#{issueOrg},</if>
<if test="issueDate != null">#{issueDate},</if>
<if test="expireDate != null">#{expireDate},</if>
<if test="certImage != null and certImage != ''">#{certImage},</if>
<if test="certStatus != null and certStatus != ''">#{certStatus},</if>
<if test="remindDays != null">#{remindDays},</if>
<if test="lastRemindTime != null">#{lastRemindTime},</if>
</trim>
</insert>
<update id="updateVetQualification" parameterType="VetQualification">
@ -122,16 +165,24 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<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>
<if test="auditStatus != null">audit_status = #{auditStatus},</if>
<if test="auditStatus != null and auditStatus != ''">audit_status = #{auditStatus},</if>
<if test="auditOpinion != null">audit_opinion = #{auditOpinion},</if>
<if test="auditorId != null">auditor_id = #{auditorId},</if>
<if test="createBy != null">create_by = #{createBy},</if>
<if test="createTime != null">create_time = #{createTime},</if>
<if test="updateBy != null">update_by = #{updateBy},</if>
<if test="updateTime != null">update_time = #{updateTime},</if>
<if test="remark != null">remark = #{remark},</if>
<if test="scopeIds != null">scope_ids = #{scopeIds},</if>
<if test="scopeNames != null">scope_names = #{scopeNames},</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>
<if test="issueDate != null">issue_date = #{issueDate},</if>
<if test="expireDate != null">expire_date = #{expireDate},</if>
<if test="certImage != null">cert_image = #{certImage},</if>
<if test="certStatus != null and certStatus != ''">cert_status = #{certStatus},</if>
<if test="remindDays != null">remind_days = #{remindDays},</if>
<if test="lastRemindTime != null">last_remind_time = #{lastRemindTime},</if>
</trim>
where qualification_id = #{qualificationId}
</update>
@ -141,10 +192,17 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</delete>
<delete id="deleteVetQualificationByQualificationIds" parameterType="String">
delete from vet_qualification where qualification_id in
delete from vet_qualification where qualification_id in
<foreach item="qualificationId" collection="array" open="(" separator="," close=")">
#{qualificationId}
</foreach>
</delete>
<!-- 根据用户ID查询资质列表 -->
<select id="selectQualificationsByUserId" parameterType="Long" resultMap="VetQualificationResult">
SELECT * FROM vet_qualification
WHERE user_id = #{userId}
ORDER BY create_time DESC
</select>
</mapper>

54
chenhai-ui/src/api/vet/certificate.js

@ -1,54 +0,0 @@
import request from '@/utils/request'
// 查询兽医执业证书列表
export function listCertificate(query) {
return request({
url: '/vet/certificate/list',
method: 'get',
params: query
})
}
// 查询证书
export function listForDetail(userId) {
return request({
url: '/vet/certificate/listForDetail',
method: 'get',
params: { userId: userId }
})
}
// 查询兽医执业证书详细
export function getCertificate(id) {
return request({
url: '/vet/certificate/' + id,
method: 'get'
})
}
// 新增兽医执业证书
export function addCertificate(data) {
return request({
url: '/vet/certificate',
method: 'post',
data: data
})
}
// 修改兽医执业证书
export function updateCertificate(data) {
return request({
url: '/vet/certificate',
method: 'put',
data: data
})
}
// 删除兽医执业证书
export function delCertificate(id) {
return request({
url: '/vet/certificate/' + id,
method: 'delete'
})
}

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

@ -0,0 +1,44 @@
import request from '@/utils/request'
// 查询兽医产品信息列表
export function listProduct(query) {
return request({
url: '/vet/product/list',
method: 'get',
params: query
})
}
// 查询兽医产品信息详细
export function getProduct(id) {
return request({
url: '/vet/product/' + id,
method: 'get'
})
}
// 新增兽医产品信息
export function addProduct(data) {
return request({
url: '/vet/product',
method: 'post',
data: data
})
}
// 修改兽医产品信息
export function updateProduct(data) {
return request({
url: '/vet/product',
method: 'put',
data: data
})
}
// 删除兽医产品信息
export function delProduct(id) {
return request({
url: '/vet/product/' + id,
method: 'delete'
})
}

10
chenhai-ui/src/api/vet/qualification.js

@ -95,3 +95,13 @@ export function delQualification(qualificationId) {
method: 'delete'
})
}
export function submitQualification(data) {
return request({
url: '/vet/qualification/submit',
method: 'post',
data: data
})
}

427
chenhai-ui/src/views/vet/certificate/index.vue

@ -1,427 +0,0 @@
<template>
<div class="app-container">
<!-- 搜索部分 -->
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="100px">
<!-- <el-form-item label="用户ID" prop="userId">-->
<!-- <el-input-->
<!-- v-model="queryParams.userId"-->
<!-- placeholder="请输入用户ID"-->
<!-- clearable-->
<!-- @keyup.enter.native="handleQuery"-->
<!-- />-->
<!-- </el-form-item>-->
<el-form-item label="证书名称" prop="certName">
<el-input
v-model="queryParams.certName"
placeholder="请输入证书名称"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="证书编号" prop="certNumber">
<el-input
v-model="queryParams.certNumber"
placeholder="请输入证书编号"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="发证机构" prop="issueOrg">
<el-input
v-model="queryParams.issueOrg"
placeholder="请输入发证机构"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="发证日期" prop="issueDate">
<el-date-picker clearable
v-model="queryParams.issueDate"
type="date"
value-format="yyyy-MM-dd"
placeholder="请选择发证日期">
</el-date-picker>
</el-form-item>
<el-form-item label="到期日期" prop="expireDate">
<el-date-picker clearable
v-model="queryParams.expireDate"
type="date"
value-format="yyyy-MM-dd"
placeholder="请选择到期日期">
</el-date-picker>
</el-form-item>
<el-form-item label="提前提醒天数" prop="remindDays">
<el-input
v-model="queryParams.remindDays"
placeholder="请输入提前提醒天数"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<!-- <el-form-item label="上次提醒时间" prop="lastRemindTime">-->
<!-- <el-date-picker clearable-->
<!-- v-model="queryParams.lastRemindTime"-->
<!-- type="date"-->
<!-- value-format="yyyy-MM-dd"-->
<!-- placeholder="请选择上次提醒时间">-->
<!-- </el-date-picker>-->
<!-- </el-form-item>-->
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="el-icon-plus"
size="mini"
@click="handleAdd"
v-hasPermi="['vet:certificate:add']"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="el-icon-edit"
size="mini"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['vet:certificate:edit']"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="el-icon-delete"
size="mini"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['vet:certificate:remove']"
>删除</el-button>
</el-col>
<!-- <el-col :span="1.5">-->
<!-- <el-button-->
<!-- type="warning"-->
<!-- plain-->
<!-- icon="el-icon-download"-->
<!-- size="mini"-->
<!-- @click="handleExport"-->
<!-- v-hasPermi="['system:certificate:export']"-->
<!-- >导出</el-button>-->
<!-- </el-col>-->
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<!-- 表格部分 -->
<el-table v-loading="loading" :data="certificateList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<!-- <el-table-column label="主键ID" align="center" prop="id" />-->
<!-- <el-table-column label="用户ID" align="center" prop="userId" />-->
<el-table-column label="证书名称" align="center" prop="certName" />
<el-table-column label="证书编号" align="center" prop="certNumber" />
<el-table-column label="证书类型" align="center" prop="certType" />
<el-table-column label="发证机构" align="center" prop="issueOrg" />
<el-table-column label="发证日期" align="center" prop="issueDate" width="180">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.issueDate, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="到期日期" align="center" prop="expireDate" width="180">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.expireDate, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="证书图片" align="center" prop="certImage" width="100">
<template slot-scope="scope">
<image-preview :src="scope.row.certImage" :width="50" :height="50"/>
</template>
</el-table-column>
<el-table-column label="状态" align="center" prop="status" />
<el-table-column label="提前提醒天数" align="center" prop="remindDays" />
<el-table-column label="上次提醒时间" align="center" prop="lastRemindTime" width="180">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.lastRemindTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" fixed="right" width="180">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-edit"
style="color: #42B983"
class = "certificate-btn alter-btn"
@click="handleUpdate(scope.row)"
v-hasPermi="['vet:certificate:edit']"
>修改</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-delete"
style="color: #f28888"
class = "certificate-btn delete-btn"
@click="handleDelete(scope.row)"
v-hasPermi="['vet:certificate:remove']"
>删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total>0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
<!-- 添加或修改兽医执业证书对话框 -->
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<!-- <el-form-item label="用户ID" prop="userId">-->
<!-- <el-input v-model="form.userId" placeholder="请输入用户ID" />-->
<!-- </el-form-item>-->
<el-form-item label="证书名称" prop="certName">
<el-input v-model="form.certName" placeholder="请输入证书名称" />
</el-form-item>
<el-form-item label="证书编号" prop="certNumber">
<el-input v-model="form.certNumber" placeholder="请输入证书编号" />
</el-form-item>
<el-form-item label="发证机构" prop="issueOrg">
<el-input v-model="form.issueOrg" placeholder="请输入发证机构" />
</el-form-item>
<el-form-item label="发证日期" prop="issueDate">
<el-date-picker clearable
v-model="form.issueDate"
type="date"
value-format="yyyy-MM-dd"
placeholder="请选择发证日期">
</el-date-picker>
</el-form-item>
<el-form-item label="到期日期" prop="expireDate">
<el-date-picker clearable
v-model="form.expireDate"
type="date"
value-format="yyyy-MM-dd"
placeholder="请选择到期日期">
</el-date-picker>
</el-form-item>
<el-form-item label="证书图片" prop="certImage">
<image-upload v-model="form.certImage"/>
</el-form-item>
<el-form-item label="提前提醒天数" prop="remindDays">
<el-input v-model="form.remindDays" placeholder="请输入提前提醒天数" />
</el-form-item>
<el-form-item label="上次提醒时间" prop="lastRemindTime">
<el-date-picker clearable
v-model="form.lastRemindTime"
type="date"
value-format="yyyy-MM-dd"
placeholder="请选择上次提醒时间">
</el-date-picker>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>-
</el-dialog>
</div>
</template>
<script>
import { listCertificate, getCertificate, delCertificate, addCertificate, updateCertificate, listForDetail } from "@/api/vet/certificate"
export default {
name: "Certificate",
props: {
formList: Object,
certificateList: Array
},
data() {
return {
//
loading: true,
//
ids: [],
//
single: true,
//
multiple: true,
//
showSearch: true,
//
total: 0,
//
// certificateList: [],
//
title: "",
//
open: false,
//
queryParams: {
pageNum: 1,
pageSize: 10,
userId: null,
certName: null,
certNumber: null,
certType: null,
issueOrg: null,
issueDate: null,
expireDate: null,
certImage: null,
status: null,
remindDays: null,
lastRemindTime: null,
},
//
form: {},
//
rules: {
userId: [
{ required: true, message: "用户ID不能为空", trigger: "blur" }
],
}
}
},
created() {
this.getList()
},
methods: {
/** 查询兽医执业证书列表 */
getList() {
this.loading = false
listForDetail(this.queryParams).then(response => {
// this.certificateList = response.rows
this.total = response.total
this.loading = false
})
},
//
cancel() {
this.open = false
this.reset()
},
//
reset() {
this.form = {
id: null,
userId: null,
certName: null,
certNumber: null,
certType: null,
issueOrg: null,
issueDate: null,
expireDate: null,
certImage: null,
status: null,
remindDays: null,
lastRemindTime: null,
createBy: null,
createTime: null,
updateBy: null,
updateTime: null
}
this.resetForm("form")
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1
this.getList()
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm")
this.handleQuery()
},
//
handleSelectionChange(selection) {
this.ids = selection.map(item => item.id)
this.single = selection.length!==1
this.multiple = !selection.length
},
/** 新增按钮操作 */
handleAdd() {
this.reset()
this.open = true
this.title = "添加兽医执业证书"
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset()
const id = row.id || this.ids
getCertificate(id).then(response => {
this.form = response.data
this.open = true
this.title = "修改兽医执业证书"
})
},
/** 提交按钮 */
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.id != null) {
updateCertificate(this.form).then(response => {
this.$modal.msgSuccess("修改成功")
this.open = false
this.getList()
})
} else {
addCertificate(this.form).then(response => {
this.$modal.msgSuccess("新增成功")
this.open = false
this.getList()
})
}
}
})
},
/** 删除按钮操作 */
handleDelete(row) {
const ids = row.id || this.ids
this.$modal.confirm('是否确认删除兽医执业证书编号为"' + ids + '"的数据项?').then(function() {
return delCertificate(ids)
}).then(() => {
this.getList()
this.$modal.msgSuccess("删除成功")
}).catch(() => {})
},
/** 导出按钮操作 */
handleExport() {
this.download('system/certificate/export', {
...this.queryParams
}, `certificate_${new Date().getTime()}.xlsx`)
}
}
}
</script>
<style scoped lang="scss">
/* 操作按钮样式 */
.certificate-btn {
padding: 6px 10px;
border-radius: 4px;
margin: 0 10px;
transition: all 0.3s ease;
}
.alter-btn:hover{
background-color: rgb(230, 255, 238);
transform: translateY(-1px);
}
.delete-btn:hover {
background-color: rgba(245, 108, 108, 0.1);
transform: translateY(-1px);
}
</style>

27
chenhai-ui/src/views/vet/comments/index.vue

@ -177,7 +177,7 @@ export default {
}
},
created() {
this.queryParams.consultationId = Number(this.consultationId)
this.queryParams.consultationId = this.parseConsultationId(this.consultationId)
this.getList()
},
methods: {
@ -279,7 +279,32 @@ export default {
this.download('vet/comments/export', {
...this.queryParams
}, `comments_${new Date().getTime()}.xlsx`)
},
parseConsultationId(id) {
if (id == null || id === '' || id === undefined) {
return null
}
// "NaN"
if (id === 'NaN' || id === 'nan' || id === 'Nan') {
console.warn('检测到无效的consultationId: NaN')
return null
}
//
const num = Number(id)
//
if (!isNaN(num) && Number.isInteger(num) && num > 0) {
return num
}
console.error('无效的consultationId:', id)
return null
}
}
}
</script>

244
chenhai-ui/src/views/vet/info/index.vue

@ -42,14 +42,6 @@
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<!-- <el-form-item label="联系地址" prop="address">-->
<!-- <el-input-->
<!-- v-model="queryParams.address"-->
<!-- placeholder="请输入联系地址"-->
<!-- clearable-->
<!-- @keyup.enter.native="handleQuery"-->
<!-- />-->
<!-- </el-form-item>-->
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
@ -89,16 +81,6 @@
v-hasPermi="['vet:info:remove']"
>删除</el-button>
</el-col>
<!-- <el-col :span="1.5">-->
<!-- <el-button-->
<!-- type="warning"-->
<!-- plain-->
<!-- icon="el-icon-download"-->
<!-- size="mini"-->
<!-- @click="handleExport"-->
<!-- v-hasPermi="['system:info:export']"-->
<!-- >导出</el-button>-->
<!-- </el-col>-->
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
@ -126,13 +108,13 @@
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" fixed="right" width="180">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-view"
style="color: #e6a23c"
class = "info-btn view-btn"
@click="handleView(scope.row)"
v-hasPermi="['vet:info:view']"
size="mini"
type="text"
icon="el-icon-view"
style="color: #e6a23c"
class = "info-btn view-btn"
@click="handleView(scope.row)"
v-hasPermi="['vet:info:view']"
>详情</el-button>
<el-button
size="mini"
@ -167,21 +149,21 @@
<!-- 添加或修改兽医个人信息对话框 -->
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<!-- <el-form-item label="用户ID" prop="userId">
<el-input v-model="form.userId" placeholder="请输入用户ID" />
</el-form-item>-->
<el-form-item label="真实姓名" prop="realName">
<el-input v-model="form.realName" placeholder="请输入真实姓名" />
</el-form-item>
<el-form-item label="性别" prop="gender">
<el-input v-model="form.gender" placeholder="请输入性别" />
<el-select v-model="form.gender" placeholder="请选择性别" clearable>
<el-option label="男" value="男" />
<el-option label="女" value="女" />
</el-select>
</el-form-item>
<el-form-item label="出生日期" prop="birthday">
<el-date-picker clearable
v-model="form.birthday"
type="date"
value-format="yyyy-MM-dd"
placeholder="请选择出生日期">
v-model="form.birthday"
type="date"
value-format="yyyy-MM-dd"
placeholder="请选择出生日期">
</el-date-picker>
</el-form-item>
<el-form-item label="职称" prop="title">
@ -224,26 +206,81 @@
</el-dialog>
<!-- 详情对话框 -->
<el-dialog :title="title" :visible.sync="flag" width="1000px" append-to-body>
<Certificate
:form-list="form"
:certificateList="certificateList"
>
</Certificate>
<el-dialog :title="detailTitle" :visible.sync="detailVisible" width="800px" append-to-body>
<div v-if="detailData" style="padding: 20px;">
<!-- 显示兽医基本信息 -->
<el-descriptions title="兽医基本信息" :column="2" border>
<el-descriptions-item label="真实姓名">{{ detailData.realName || '-' }}</el-descriptions-item>
<el-descriptions-item label="性别">{{ detailData.gender || '-' }}</el-descriptions-item>
<el-descriptions-item label="出生日期">{{ detailData.birthday || '-' }}</el-descriptions-item>
<el-descriptions-item label="身份证号">{{ detailData.idCard || '-' }}</el-descriptions-item>
<el-descriptions-item label="擅长领域">{{ detailData.specialty || '-' }}</el-descriptions-item>
<el-descriptions-item label="工作经验">{{ detailData.workExperience ? detailData.workExperience + '年' : '-' }}</el-descriptions-item>
<el-descriptions-item label="职称">{{ detailData.title || '-' }}</el-descriptions-item>
<el-descriptions-item label="联系电话">{{ detailData.phone || '-' }}</el-descriptions-item>
<el-descriptions-item label="电子邮箱">{{ detailData.email || '-' }}</el-descriptions-item>
<el-descriptions-item label="专家类型">
<dict-tag :options="dict.type.expert_type" :value="detailData.expertType"/>
</el-descriptions-item>
<el-descriptions-item label="所属医院">{{ detailData.hospital || '-' }}</el-descriptions-item>
<el-descriptions-item label="联系地址" :span="2">{{ detailData.address || '-' }}</el-descriptions-item>
<el-descriptions-item label="个人简介" :span="2">{{ detailData.introduction || '-' }}</el-descriptions-item>
</el-descriptions>
<!-- 显示资质证书信息 -->
<div style="margin-top: 30px;">
<h3 style="margin-bottom: 15px; color: #333;">资质证书信息</h3>
<el-alert
v-if="!certificateList || certificateList.length === 0"
title="暂无资质证书"
type="info"
:closable="false"
style="margin-bottom: 20px;"
/>
<el-table v-else :data="certificateList" border style="width: 100%">
<!-- <el-table-column prop="qualificationName" label="资质名称" align="center" width="180"></el-table-column>-->
<el-table-column prop="certName" label="证书名称" align="center" width="180"></el-table-column>
<el-table-column prop="certificateNo" label="证书编号" align="center" width="200"></el-table-column>
<el-table-column prop="issueDate" label="颁发日期" align="center" width="120">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.issueDate, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column prop="expireDate" label="到期日期" align="center" width="120">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.expireDate, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column prop="auditStatus" label="审核状态" align="center" width="100">
<template slot-scope="scope">
<el-tag :type="getAuditStatusTagType(scope.row.auditStatus)">
{{ getAuditStatusText(scope.row.auditStatus) }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="certStatus" label="证书状态" align="center" width="100">
<template slot-scope="scope">
<el-tag :type="getCertStatusTagType(scope.row.certStatus)">
{{ getCertStatusText(scope.row.certStatus) }}
</el-tag>
</template>
</el-table-column>
</el-table>
</div>
</div>
<div slot="footer" class="dialog-footer">
<el-button @click="closeDetail"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { listInfo, getInfo, getfull, delInfo, addInfo, updateInfo } from "@/api/vet/info"
import Certificate from "../certificate/index.vue"
export default {
name: "Info",
dicts: ['expert_type'],
components:{
Certificate,
},
data() {
return {
//
@ -260,15 +297,20 @@ export default {
total: 0,
//
infoList: [],
//
//
certificateList: [],
//
title: "",
//
//
detailTitle: "",
// /
open: false,
flag: false,
//
detailVisible: false,
//
detailData: null,
//
queryParams: {
pageNum: 1,
@ -288,9 +330,15 @@ export default {
form: {},
//
rules: {
userId: [
{ required: true, message: "用户ID不能为空", trigger: "blur" }
realName: [
{ required: true, message: "真实姓名不能为空", trigger: "blur" }
],
gender: [
{ required: true, message: "性别不能为空", trigger: "change" }
],
idCard: [
{ required: true, message: "身份证号不能为空", trigger: "blur" }
]
}
}
},
@ -312,6 +360,12 @@ export default {
this.open = false
this.reset()
},
//
closeDetail() {
this.detailVisible = false
this.detailData = null
this.certificateList = []
},
//
reset() {
this.form = {
@ -326,14 +380,16 @@ export default {
hospital: null,
address: null,
introduction: null,
title: null,
phone: null,
email: null,
expertType: null,
createBy: null,
createTime: null,
updateBy: null,
updateTime: null
}
this.resetForm("form")
this.chCkApplyItemsList = []
},
/** 搜索按钮操作 */
handleQuery() {
@ -353,15 +409,43 @@ export default {
},
/** 详情按钮操作 */
handleView(row) {
this.reset();
this.detailVisible = true
this.detailTitle = "兽医详情信息"
const id = row.id || this.ids
getfull(id).then(response => {
this.flag = true
this.form = response.data.personalInfo;
this.certificateList = response.data.certificates;
});
},
if (response.code === 200) {
const data = response.data
console.log('详情返回数据:', data) //
//
// data.vetInfo
if (data.vetInfo) {
this.detailData = data.vetInfo
// 使 qualifications
this.certificateList = data.qualifications || []
} else if (data.personalInfo) {
//
this.detailData = data.personalInfo
this.certificateList = data.certificates || data.qualifications || []
} else {
// 使 data
this.detailData = data
this.certificateList = data.qualifications || []
}
//
if (this.certificateList.length === 0) {
console.log('没有证书数据')
}
} else {
this.$message.error(response.msg || '获取详情失败')
}
}).catch(error => {
console.error('获取详情失败:', error)
this.$message.error('获取详情失败')
})
},
/** 新增按钮操作 */
handleAdd() {
this.reset()
@ -408,11 +492,45 @@ export default {
this.$modal.msgSuccess("删除成功")
}).catch(() => {})
},
/** 导出按钮操作 */
handleExport() {
this.download('system/info/export', {
...this.queryParams
}, `info_${new Date().getTime()}.xlsx`)
//
getAuditStatusText(status) {
const statusMap = {
'0': '待审核',
'1': '审核通过',
'2': '审核不通过'
}
return statusMap[status] || '未知'
},
//
getAuditStatusTagType(status) {
const typeMap = {
'0': 'warning',
'1': 'success',
'2': 'danger'
}
return typeMap[status] || 'info'
},
//
getCertStatusText(status) {
const statusMap = {
'0': '有效',
'1': '即将过期',
'2': '已过期'
}
return statusMap[status] || '未知'
},
//
getCertStatusTagType(status) {
const typeMap = {
'0': 'success',
'1': 'warning',
'2': 'danger'
}
return typeMap[status] || 'info'
}
}
}
@ -425,7 +543,6 @@ export default {
border-radius: 4px;
margin: 0 10px;
transition: all 0.3s ease;
}
.view-btn:hover{
@ -442,5 +559,4 @@ export default {
background-color: rgba(245, 108, 108, 0.1);
transform: translateY(-1px);
}
</style>

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

@ -0,0 +1,552 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="产品名称" prop="name">
<el-input
v-model="queryParams.name"
placeholder="请输入产品名称"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="产品分类" prop="category">
<el-input
v-model="queryParams.category"
placeholder="请输入产品分类"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="规格" prop="specification">
<el-input
v-model="queryParams.specification"
placeholder="请输入规格"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="单位" prop="unit">
<el-input
v-model="queryParams.unit"
placeholder="请输入单位"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="生产厂家" prop="manufacturer">
<el-input
v-model="queryParams.manufacturer"
placeholder="请输入生产厂家"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="批准文号" prop="approvalNumber">
<el-input
v-model="queryParams.approvalNumber"
placeholder="请输入批准文号"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="销售价格" prop="price">
<el-input
v-model="queryParams.price"
placeholder="请输入销售价格"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="成本价" prop="costPrice">
<el-input
v-model="queryParams.costPrice"
placeholder="请输入成本价"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="库存数量" prop="stock">
<el-input
v-model="queryParams.stock"
placeholder="请输入库存数量"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="最低库存预警" prop="minStock">
<el-input
v-model="queryParams.minStock"
placeholder="请输入最低库存预警"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="治疗周期" prop="treatmentDuration">
<el-input
v-model="queryParams.treatmentDuration"
placeholder="请输入治疗周期"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="删除标识:0-正常/1-删除" prop="isDeleted">
<el-input
v-model="queryParams.isDeleted"
placeholder="请输入删除标识:0-正常/1-删除"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="诊所ID" prop="clinicId">
<el-input
v-model="queryParams.clinicId"
placeholder="请输入诊所ID"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="兽医ID" prop="vetId">
<el-input
v-model="queryParams.vetId"
placeholder="请输入兽医ID"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="创建时间" prop="createdAt">
<el-date-picker clearable
v-model="queryParams.createdAt"
type="date"
value-format="yyyy-MM-dd"
placeholder="请选择创建时间">
</el-date-picker>
</el-form-item>
<el-form-item label="更新时间" prop="updatedAt">
<el-date-picker clearable
v-model="queryParams.updatedAt"
type="date"
value-format="yyyy-MM-dd"
placeholder="请选择更新时间">
</el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="el-icon-plus"
size="mini"
@click="handleAdd"
v-hasPermi="['vet:product:add']"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="el-icon-edit"
size="mini"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['vet:product:edit']"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="el-icon-delete"
size="mini"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['vet:product:remove']"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="el-icon-download"
size="mini"
@click="handleExport"
v-hasPermi="['vet:product:export']"
>导出</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="productList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="主键ID" align="center" prop="id" />
<el-table-column label="产品名称" align="center" prop="name" />
<el-table-column label="产品类型:medicine-兽药/vaccine-疫苗/supplement-保健品" align="center" prop="type" />
<el-table-column label="产品分类" align="center" prop="category" />
<el-table-column label="规格" align="center" prop="specification" />
<el-table-column label="单位" align="center" prop="unit" />
<el-table-column label="生产厂家" align="center" prop="manufacturer" />
<el-table-column label="批准文号" align="center" prop="approvalNumber" />
<el-table-column label="主要成分" align="center" prop="ingredients" />
<el-table-column label="适应症" align="center" prop="indications" />
<el-table-column label="用法用量" align="center" prop="usageDosage" />
<el-table-column label="销售价格" align="center" prop="price" />
<el-table-column label="成本价" align="center" prop="costPrice" />
<el-table-column label="库存数量" align="center" prop="stock" />
<el-table-column label="最低库存预警" align="center" prop="minStock" />
<el-table-column label="主图URL" align="center" prop="mainImage" width="100">
<template slot-scope="scope">
<image-preview :src="scope.row.mainImage" :width="50" :height="50"/>
</template>
</el-table-column>
<el-table-column label="多张图片URL,JSON格式" align="center" prop="images" />
<el-table-column label="适用动物:如犬、猫、猪等" align="center" prop="treatAnimals" />
<el-table-column label="治疗疾病" align="center" prop="treatDiseases" />
<el-table-column label="治疗方案/内容" align="center" prop="treatmentContent" />
<el-table-column label="治疗周期" align="center" prop="treatmentDuration" />
<el-table-column label="注意事项" align="center" prop="precautions" />
<el-table-column label="状态:0-草稿/1-上架/2-下架" align="center" prop="status" />
<el-table-column label="删除标识:0-正常/1-删除" align="center" prop="isDeleted" />
<el-table-column label="诊所ID" align="center" prop="clinicId" />
<el-table-column label="兽医ID" align="center" prop="vetId" />
<el-table-column label="创建时间" align="center" prop="createdAt" width="180">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.createdAt, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="更新时间" align="center" prop="updatedAt" width="180">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.updatedAt, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['vet:product:edit']"
>修改</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
v-hasPermi="['vet:product:remove']"
>删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total>0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
<!-- 添加或修改兽医产品信息对话框 -->
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-form-item label="产品名称" prop="name">
<el-input v-model="form.name" placeholder="请输入产品名称" />
</el-form-item>
<el-form-item label="产品分类" prop="category">
<el-input v-model="form.category" placeholder="请输入产品分类" />
</el-form-item>
<el-form-item label="规格" prop="specification">
<el-input v-model="form.specification" placeholder="请输入规格" />
</el-form-item>
<el-form-item label="单位" prop="unit">
<el-input v-model="form.unit" placeholder="请输入单位" />
</el-form-item>
<el-form-item label="生产厂家" prop="manufacturer">
<el-input v-model="form.manufacturer" placeholder="请输入生产厂家" />
</el-form-item>
<el-form-item label="批准文号" prop="approvalNumber">
<el-input v-model="form.approvalNumber" placeholder="请输入批准文号" />
</el-form-item>
<el-form-item label="主要成分" prop="ingredients">
<el-input v-model="form.ingredients" type="textarea" placeholder="请输入内容" />
</el-form-item>
<el-form-item label="适应症" prop="indications">
<el-input v-model="form.indications" type="textarea" placeholder="请输入内容" />
</el-form-item>
<el-form-item label="用法用量" prop="usageDosage">
<el-input v-model="form.usageDosage" type="textarea" placeholder="请输入内容" />
</el-form-item>
<el-form-item label="销售价格" prop="price">
<el-input v-model="form.price" placeholder="请输入销售价格" />
</el-form-item>
<el-form-item label="成本价" prop="costPrice">
<el-input v-model="form.costPrice" placeholder="请输入成本价" />
</el-form-item>
<el-form-item label="库存数量" prop="stock">
<el-input v-model="form.stock" placeholder="请输入库存数量" />
</el-form-item>
<el-form-item label="最低库存预警" prop="minStock">
<el-input v-model="form.minStock" placeholder="请输入最低库存预警" />
</el-form-item>
<el-form-item label="主图URL" prop="mainImage">
<image-upload v-model="form.mainImage"/>
</el-form-item>
<el-form-item label="多张图片URL,JSON格式" prop="images">
<el-input v-model="form.images" type="textarea" placeholder="请输入内容" />
</el-form-item>
<el-form-item label="适用动物:如犬、猫、猪等" prop="treatAnimals">
<el-input v-model="form.treatAnimals" type="textarea" placeholder="请输入内容" />
</el-form-item>
<el-form-item label="治疗疾病" prop="treatDiseases">
<el-input v-model="form.treatDiseases" type="textarea" placeholder="请输入内容" />
</el-form-item>
<el-form-item label="治疗方案/内容">
<editor v-model="form.treatmentContent" :min-height="192"/>
</el-form-item>
<el-form-item label="治疗周期" prop="treatmentDuration">
<el-input v-model="form.treatmentDuration" placeholder="请输入治疗周期" />
</el-form-item>
<el-form-item label="注意事项" prop="precautions">
<el-input v-model="form.precautions" type="textarea" placeholder="请输入内容" />
</el-form-item>
<el-form-item label="删除标识:0-正常/1-删除" prop="isDeleted">
<el-input v-model="form.isDeleted" placeholder="请输入删除标识:0-正常/1-删除" />
</el-form-item>
<el-form-item label="诊所ID" prop="clinicId">
<el-input v-model="form.clinicId" placeholder="请输入诊所ID" />
</el-form-item>
<el-form-item label="兽医ID" prop="vetId">
<el-input v-model="form.vetId" placeholder="请输入兽医ID" />
</el-form-item>
<el-form-item label="创建时间" prop="createdAt">
<el-date-picker clearable
v-model="form.createdAt"
type="date"
value-format="yyyy-MM-dd"
placeholder="请选择创建时间">
</el-date-picker>
</el-form-item>
<el-form-item label="更新时间" prop="updatedAt">
<el-date-picker clearable
v-model="form.updatedAt"
type="date"
value-format="yyyy-MM-dd"
placeholder="请选择更新时间">
</el-date-picker>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { listProduct, getProduct, delProduct, addProduct, updateProduct } from "@/api/vet/product"
export default {
name: "Product",
data() {
return {
//
loading: true,
//
ids: [],
//
single: true,
//
multiple: true,
//
showSearch: true,
//
total: 0,
//
productList: [],
//
title: "",
//
open: false,
//
queryParams: {
pageNum: 1,
pageSize: 10,
name: null,
type: null,
category: null,
specification: null,
unit: null,
manufacturer: null,
approvalNumber: null,
ingredients: null,
indications: null,
usageDosage: null,
price: null,
costPrice: null,
stock: null,
minStock: null,
mainImage: null,
images: null,
treatAnimals: null,
treatDiseases: null,
treatmentContent: null,
treatmentDuration: null,
precautions: null,
status: null,
isDeleted: null,
clinicId: null,
vetId: null,
createdAt: null,
updatedAt: null
},
//
form: {},
//
rules: {
name: [
{ required: true, message: "产品名称不能为空", trigger: "blur" }
],
type: [
{ required: true, message: "产品类型:medicine-兽药/vaccine-疫苗/supplement-保健品不能为空", trigger: "change" }
],
price: [
{ required: true, message: "销售价格不能为空", trigger: "blur" }
],
clinicId: [
{ required: true, message: "诊所ID不能为空", trigger: "blur" }
],
vetId: [
{ required: true, message: "兽医ID不能为空", trigger: "blur" }
],
}
}
},
created() {
this.getList()
},
methods: {
/** 查询兽医产品信息列表 */
getList() {
this.loading = true
listProduct(this.queryParams).then(response => {
this.productList = response.rows
this.total = response.total
this.loading = false
})
},
//
cancel() {
this.open = false
this.reset()
},
//
reset() {
this.form = {
id: null,
name: null,
type: null,
category: null,
specification: null,
unit: null,
manufacturer: null,
approvalNumber: null,
ingredients: null,
indications: null,
usageDosage: null,
price: null,
costPrice: null,
stock: null,
minStock: null,
mainImage: null,
images: null,
treatAnimals: null,
treatDiseases: null,
treatmentContent: null,
treatmentDuration: null,
precautions: null,
status: null,
isDeleted: null,
clinicId: null,
vetId: null,
createdAt: null,
updatedAt: null
}
this.resetForm("form")
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1
this.getList()
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm")
this.handleQuery()
},
//
handleSelectionChange(selection) {
this.ids = selection.map(item => item.id)
this.single = selection.length!==1
this.multiple = !selection.length
},
/** 新增按钮操作 */
handleAdd() {
this.reset()
this.open = true
this.title = "添加兽医产品信息"
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset()
const id = row.id || this.ids
getProduct(id).then(response => {
this.form = response.data
this.open = true
this.title = "修改兽医产品信息"
})
},
/** 提交按钮 */
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.id != null) {
updateProduct(this.form).then(response => {
this.$modal.msgSuccess("修改成功")
this.open = false
this.getList()
})
} else {
addProduct(this.form).then(response => {
this.$modal.msgSuccess("新增成功")
this.open = false
this.getList()
})
}
}
})
},
/** 删除按钮操作 */
handleDelete(row) {
const ids = row.id || this.ids
this.$modal.confirm('是否确认删除兽医产品信息编号为"' + ids + '"的数据项?').then(function() {
return delProduct(ids)
}).then(() => {
this.getList()
this.$modal.msgSuccess("删除成功")
}).catch(() => {})
},
/** 导出按钮操作 */
handleExport() {
this.download('vet/product/export', {
...this.queryParams
}, `product_${new Date().getTime()}.xlsx`)
}
}
}
</script>

520
chenhai-ui/src/views/vet/qualification/index.vue

@ -1,30 +1,22 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<!-- <el-form-item label="兽医ID" prop="vetId">-->
<!-- <el-input-->
<!-- v-model="queryParams.vetId"-->
<!-- placeholder="请输入兽医ID"-->
<!-- clearable-->
<!-- @keyup.enter.native="handleQuery"-->
<!-- />-->
<!-- </el-form-item>-->
<!-- <el-form-item label="真实姓名" prop="realName">-->
<!-- <el-input-->
<!-- v-model="queryParams.realName"-->
<!-- placeholder="请输入真实姓名"-->
<!-- clearable-->
<!-- @keyup.enter.native="handleQuery"-->
<!-- />-->
<!-- </el-form-item>-->
<!-- <el-form-item label="身份证号" prop="idCard">-->
<!-- <el-input-->
<!-- v-model="queryParams.idCard"-->
<!-- placeholder="请输入身份证号"-->
<!-- clearable-->
<!-- @keyup.enter.native="handleQuery"-->
<!-- />-->
<!-- </el-form-item>-->
<el-form-item label="真实姓名" prop="realName">
<el-input
v-model="queryParams.realName"
placeholder="请输入真实姓名"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="身份证号" prop="idCard">
<el-input
v-model="queryParams.idCard"
placeholder="请输入身份证号"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="资质类型" prop="qualificationType">
<el-input
v-model="queryParams.qualificationType"
@ -41,30 +33,16 @@
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<!-- <el-form-item label="申请时间" prop="applyTime">-->
<!-- <el-date-picker clearable-->
<!-- v-model="queryParams.applyTime"-->
<!-- type="date"-->
<!-- value-format="yyyy-MM-dd"-->
<!-- placeholder="请选择申请时间">-->
<!-- </el-date-picker>-->
<!-- </el-form-item>-->
<!-- <el-form-item label="审核时间" prop="auditTime">-->
<!-- <el-date-picker clearable-->
<!-- v-model="queryParams.auditTime"-->
<!-- type="date"-->
<!-- value-format="yyyy-MM-dd"-->
<!-- placeholder="请选择审核时间">-->
<!-- </el-date-picker>-->
<!-- </el-form-item>-->
<!-- <el-form-item label="审核人ID" prop="auditorId">-->
<!-- <el-input-->
<!-- v-model="queryParams.auditorId"-->
<!-- placeholder="请输入审核人ID"-->
<!-- clearable-->
<!-- @keyup.enter.native="handleQuery"-->
<!-- />-->
<!-- </el-form-item>-->
<el-form-item label="审核状态" prop="auditStatus">
<el-select v-model="queryParams.auditStatus" placeholder="审核状态" clearable style="width: 100px">
<el-option
v-for="dict in dict.type.qualification_shenhe"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
@ -119,54 +97,181 @@
<el-table v-loading="loading" :data="qualificationList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<!-- <el-table-column label="资质ID" align="center" prop="qualificationId" />-->
<!-- <el-table-column label="兽医ID" align="center" prop="vetId" />-->
<!-- <el-table-column label="真实姓名" align="center" prop="realName" />-->
<!-- <el-table-column label="身份证号" align="center" prop="idCard" />-->
<!-- <el-table-column label="资质类型" align="center" prop="qualificationType" />-->
<el-table-column label="资质ID" align="center" prop="qualificationId" v-if="false" />
<el-table-column label="真实姓名" align="center" prop="realName" />
<el-table-column label="身份证号" align="center" prop="idCard" />
<el-table-column label="资质类型" align="center" prop="qualificationType" width="120">
<template slot-scope="scope">
<el-tag
v-if="scope.row.qualificationType"
:type="getQualificationTypeTagType(scope.row.qualificationType)"
>
{{ formatQualificationType(scope.row.qualificationType) }}
</el-tag>
<span v-else>-</span>
<span>{{ formatQualificationType(scope.row.qualificationType) }}</span>
</template>
</el-table-column>
<el-table-column label="证书编号" align="center" prop="certificateNo" />
<el-table-column label="证书文件" align="center" prop="certificateFiles" />
<!-- 新增的证书字段 -->
<el-table-column label="证书名称" align="center" prop="certName" width="150">
<template slot-scope="scope">
<span v-if="scope.row.certName">{{ scope.row.certName }}</span>
<span v-else style="color: #909399">-</span>
</template>
</el-table-column>
<el-table-column label="发证机构" align="center" prop="issueOrg" width="150">
<template slot-scope="scope">
<span v-if="scope.row.issueOrg">{{ scope.row.issueOrg }}</span>
<span v-else style="color: #909399">-</span>
</template>
</el-table-column>
<el-table-column label="到期日期" align="center" prop="expireDate" width="180">
<template slot-scope="scope">
<span v-if="scope.row.expireDate">{{ parseTime(scope.row.expireDate, '{y}-{m}-{d}') }}</span>
<span v-else style="color: #909399">-</span>
</template>
</el-table-column>
<el-table-column label="证书状态" align="center" prop="certStatus" width="100">
<template slot-scope="scope">
<el-tag :type="getCertStatusType(scope.row.certStatus)" size="small">
{{ getCertStatusLabel(scope.row.certStatus) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="申请时间" align="center" prop="applyTime" width="180">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.applyTime, '{y}-{m}-{d}') }}</span>
<span v-if="scope.row.applyTime">{{ parseTime(scope.row.applyTime, '{y}-{m}-{d}') }}</span>
<span v-else style="color: #909399">-</span>
</template>
</el-table-column>
<el-table-column label="审核时间" align="center" prop="auditTime" width="180">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.auditTime, '{y}-{m}-{d}') }}</span>
<span v-if="scope.row.auditTime">{{ parseTime(scope.row.auditTime, '{y}-{m}-{d}') }}</span>
<span v-else style="color: #909399">-</span>
</template>
</el-table-column>
<el-table-column label="审核状态" align="center" prop="auditStatus" width="100">
<template slot-scope="scope">
<!-- 使用 qualification_shenhe 字典显示审核状态 -->
<dict-tag :options="dict.type.qualification_shenhe" :value="scope.row.auditStatus"/>
</template>
</el-table-column>
<el-table-column label="审核状态" align="center" prop="auditStatus" />
<!-- <el-table-column label="审核意见" align="center" prop="auditOpinion" />-->
<!-- <el-table-column label="审核人ID" align="center" prop="auditorId" />-->
<el-table-column label="备注" align="center" prop="remark" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" fixed="right" width="180">
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" fixed="right" width="250">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['vet:qualification:edit']"
>修改</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
v-hasPermi="['vet:qualification:remove']"
>删除</el-button>
<!-- 调试信息查看实际状态值 -->
<!-- <span style="color: red; font-size: 10px; margin-right: 5px;">状态:{{ scope.row.auditStatus }}</span> -->
<!-- 情况1没有审核状态nullundefined或状态为3待提交 -->
<template v-if="!scope.row.auditStatus || scope.row.auditStatus === '' || scope.row.auditStatus === '3'">
<el-button
size="mini"
type="text"
icon="el-icon-edit"
style="color: #42B983"
@click="handleUpdate(scope.row)"
v-hasPermi="['vet:qualification:edit']"
>修改</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-s-check"
style="color: #409EFF"
@click="handleSubmitAudit(scope.row)"
v-hasPermi="['vet:qualification:edit']"
>提交审核</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-delete"
style="color: #f56c6c"
@click="handleDelete(scope.row)"
v-hasPermi="['vet:qualification:remove']"
>删除</el-button>
</template>
<!-- 情况2审核状态为待审核(0) -->
<template v-else-if="scope.row.auditStatus === '0'">
<span style="color: #E6A23C; font-size: 12px;">
<i class="el-icon-time" style="margin-right: 3px;"></i>审核中
</span>
<!-- <el-button
size="mini"
type="text"
style="color: #909399; margin-left: 10px;"
disabled
>不可操作</el-button>-->
</template>
<!-- 情况3审核状态为通过(1) -->
<template v-else-if="scope.row.auditStatus === '1'">
<span style="color: #67C23A; font-size: 12px;">
<i class="el-icon-success" style="margin-right: 3px;"></i>已通过
</span>
<el-button
size="mini"
type="text"
icon="el-icon-view"
style="color: #909399; margin-left: 10px;"
@click="handleView(scope.row)"
v-hasPermi="['vet:qualification:query']"
>查看</el-button>
</template>
<!-- 情况4审核状态为拒绝(2) -->
<template v-else-if="scope.row.auditStatus === '2'">
<span style="color: #F56C6C; font-size: 12px;">
<i class="el-icon-error" style="margin-right: 3px;"></i>已拒绝
</span>
<el-button
size="mini"
type="text"
icon="el-icon-edit"
style="color: #42B983; margin-left: 10px;"
@click="handleUpdate(scope.row)"
v-hasPermi="['vet:qualification:edit']"
>修改</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-s-check"
style="color: #409EFF"
@click="handleSubmitAudit(scope.row)"
v-hasPermi="['vet:qualification:edit']"
>重新提交</el-button>
</template>
<!-- 情况5其他未知状态 -->
<template v-else>
<span style="color: #909399; font-size: 12px; margin-right: 10px;">
状态: {{ scope.row.auditStatus }}
</span>
<el-button
size="mini"
type="text"
icon="el-icon-edit"
style="color: #42B983"
@click="handleUpdate(scope.row)"
v-hasPermi="['vet:qualification:edit']"
>修改</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-s-check"
style="color: #409EFF"
@click="handleSubmitAudit(scope.row)"
v-hasPermi="['vet:qualification:edit']"
>提交</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-delete"
style="color: #f56c6c"
@click="handleDelete(scope.row)"
v-hasPermi="['vet:qualification:remove']"
>删除</el-button>
</template>
</template>
</el-table-column>
</el-table>
@ -182,48 +287,59 @@
<!-- 添加或修改兽医资质对话框 -->
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<!-- <el-form-item label="兽医ID" prop="vetId">
<el-input v-model="form.vetId" placeholder="请输入兽医ID" />
</el-form-item>-->
<!-- <el-form-item label="真实姓名" prop="realName">-->
<!-- <el-input v-model="form.realName" placeholder="请输入真实姓名" />-->
<!-- </el-form-item>-->
<!-- <el-form-item label="身份证号" prop="idCard">-->
<!-- <el-input v-model="form.idCard" placeholder="请输入身份证号" />-->
<!-- </el-form-item>-->
<el-form-item label="资质类型" proper="qualificationType" >
<el-input v-model="form.qualificationType" placeholder="请输入资质类型" />
<el-form-item label="真实姓名" prop="realName">
<el-input v-model="form.realName" placeholder="请输入真实姓名" />
</el-form-item>
<el-form-item label="身份证号" prop="idCard">
<el-input v-model="form.idCard" placeholder="请输入身份证号" />
</el-form-item>
<el-form-item label="资质类型" prop="qualificationType">
<el-select v-model="form.qualificationType" placeholder="请选择资质类型" style="width: 100%">
<el-option label="兽医资格证" value="veterinarian" />
<el-option label="兽药师资格证" value="pharmacist" />
</el-select>
</el-form-item>
<el-form-item label="证书编号" prop="certificateNo">
<el-input v-model="form.certificateNo" placeholder="请输入证书编号" />
</el-form-item>
<el-form-item label="证书文件" prop="certificateFiles">
<el-input v-model="form.certificateFiles" type="textarea" placeholder="请输入内容" />
<!-- 新增的证书字段 -->
<el-form-item label="证书名称" prop="certName">
<el-input v-model="form.certName" placeholder="请输入证书名称" />
</el-form-item>
<el-form-item label="申请时间" prop="applyTime">
<el-form-item label="发证机构" prop="issueOrg">
<el-input v-model="form.issueOrg" placeholder="请输入发证机构" />
</el-form-item>
<el-form-item label="发证日期" prop="issueDate">
<el-date-picker clearable
v-model="form.applyTime"
type="date"
value-format="yyyy-MM-dd"
placeholder="请选择申请时间">
v-model="form.issueDate"
type="date"
value-format="yyyy-MM-dd"
placeholder="请选择发证日期"
style="width: 100%">
</el-date-picker>
</el-form-item>
<el-form-item label="审核时间" prop="auditTime">
<el-form-item label="到期日期" prop="expireDate">
<el-date-picker clearable
v-model="form.auditTime"
type="date"
value-format="yyyy-MM-dd"
placeholder="请选择审核时间">
v-model="form.expireDate"
type="date"
value-format="yyyy-MM-dd"
placeholder="请选择到期日期"
style="width: 100%">
</el-date-picker>
</el-form-item>
<el-form-item label="审核意见" prop="auditOpinion">
<el-input v-model="form.auditOpinion" type="textarea" placeholder="请输入内容" />
<el-form-item label="证书图片" prop="certImage">
<image-upload v-model="form.certImage"/>
</el-form-item>
<el-form-item label="审核人ID" prop="auditorId">
<el-input v-model="form.auditorId" placeholder="请输入审核人ID" />
<el-form-item label="提前提醒天数" prop="remindDays">
<el-input v-model="form.remindDays" placeholder="请输入提前提醒天数" />
</el-form-item>
<el-form-item label="证书文件" prop="certificateFiles">
<el-input v-model="form.certificateFiles" type="textarea" placeholder="请输入内容" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
<el-input v-model="form.remark" type="textarea" placeholder="请输入备注" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
@ -236,9 +352,11 @@
<script>
import { listQualification, getQualification, delQualification, addQualification, updateQualification } from "@/api/vet/qualification"
import { submitQualification } from "@/api/vet/qualification"
export default {
name: "Qualification",
dicts: ['qualification_shenhe', 'expert_type'], // qualification_shenhe
data() {
return {
//
@ -263,26 +381,21 @@ export default {
queryParams: {
pageNum: 1,
pageSize: 10,
vetId: null,
realName: null,
idCard: null,
qualificationType: null,
certificateNo: null,
certificateFiles: null,
scope_names: null,
applyTime: null,
auditTime: null,
auditStatus: null,
auditOpinion: null,
auditorId: null,
//
certName: null,
issueOrg: null,
expireDate: null,
certStatus: null,
},
//
form: {},
//
rules: {
vetId: [
{ required: true, message: "兽医ID不能为空", trigger: "blur" }
],
realName: [
{ required: true, message: "真实姓名不能为空", trigger: "blur" }
],
@ -294,17 +407,11 @@ export default {
],
certificateNo: [
{ required: true, message: "证书编号不能为空", trigger: "blur" }
],
certificateFiles: [
{ required: true, message: "证书文件不能为空", trigger: "blur" }
],
]
}
}
},
created() {
this.getDicts("qualification_type").then(response => {
this.qualificationTypeOptions = response.data
}),
this.getList()
},
methods: {
@ -312,36 +419,121 @@ export default {
getList() {
this.loading = true
listQualification(this.queryParams).then(response => {
console.log('资质列表数据:', response.rows) //
this.qualificationList = response.rows
this.total = response.total
this.loading = false
})
},
//
formatQualificationType(value) {
if (!value) return '-'
const dict = this.qualificationTypeOptions.find(item => item.dictValue === value)
return dict ? dict.dictLabel : value
/** 获取证书状态标签 */
getCertStatusLabel(status) {
const map = {
'0': '正常',
'1': '即将过期',
'2': '已过期'
}
return map[status] || status || '-'
},
/** 获取证书状态标签类型 */
getCertStatusType(status) {
const map = {
'0': 'success',
'1': 'warning',
'2': 'danger'
}
return map[status] || 'info'
},
/** 获取审核状态标签(备用方法,主要用字典) */
getAuditStatusLabel(status) {
const map = {
'0': '待审核',
'1': '通过',
'2': '拒绝',
'3': '待提交'
}
return map[status] || status || '-'
},
getQualificationTypeTagType(value) {
const typeMap = {
/** 获取审核状态标签类型(备用方法) */
getAuditStatusType(status) {
const map = {
'0': 'info',
'1': 'success',
'2': 'info',
'3': 'warning',
'4': 'danger'
'2': 'danger',
'3': 'warning'
}
return typeMap[value] || 'primary'
return map[status] || 'info'
},
/** 格式化资质类型显示 */
formatQualificationType(value) {
if (value === 'veterinarian') return '兽医资格证'
if (value === 'pharmacist') return '兽药师资格证'
return value
},
/** 提交审核操作 */
handleSubmitAudit(row) {
this.$modal.confirm('确认提交 "' + row.realName + '" 的资质进行审核?').then(() => {
//
const submitData = {
qualificationId: row.qualificationId,
realName: row.realName,
idCard: row.idCard,
qualificationType: row.qualificationType,
certificateNo: row.certificateNo,
certName: row.certName,
issueOrg: row.issueOrg,
issueDate: row.issueDate,
expireDate: row.expireDate,
certImage: row.certImage,
certificateFiles: row.certificateFiles,
remark: row.remark,
// (0)
auditStatus: '0'
}
return submitQualification(submitData)
}).then(response => {
if (response.code === 200) {
this.$modal.msgSuccess("提交审核成功")
this.getList()
} else {
this.$modal.msgError(response.msg || "提交审核失败")
}
}).catch(() => {})
},
/** 查看详情 - 极简版 */
handleView(row) {
// 使 this.$alert
this.$alert(`
<table style="width:100%;">
<tr><td style="padding:5px;">姓名</td><td>${row.realName || '-'}</td></tr>
<tr><td style="padding:5px;">身份证</td><td>${row.idCard || '-'}</td></tr>
<tr><td style="padding:5px;">证书编号</td><td>${row.certificateNo || '-'}</td></tr>
<tr><td style="padding:5px;">审核状态</td><td>${this.getDictLabel('qualification_shenhe', row.auditStatus) || '-'}</td></tr>
</table>
`, '资质详情', {
dangerouslyUseHTMLString: true,
confirmButtonText: '关闭',
width: '450px'
})
},
//
cancel() {
this.open = false
this.reset()
},
//
reset() {
this.form = {
qualificationId: null,
vetId: null,
userId: null,
realName: null,
idCard: null,
qualificationType: null,
@ -349,39 +541,54 @@ export default {
certificateFiles: null,
applyTime: null,
auditTime: null,
auditStatus: null,
auditStatus: null, // null
auditOpinion: null,
auditorId: null,
createBy: null,
createTime: null,
updateBy: null,
updateTime: null,
remark: null
remark: null,
//
certName: null,
certType: null,
issueOrg: null,
issueDate: null,
expireDate: null,
certImage: null,
certStatus: null,
remindDays: 30,
lastRemindTime: null,
scopeIds: null,
scopeNames: null
}
this.resetForm("form")
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1
this.getList()
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm")
this.handleQuery()
},
//
handleSelectionChange(selection) {
this.ids = selection.map(item => item.qualificationId)
this.single = selection.length!==1
this.multiple = !selection.length
},
/** 新增按钮操作 */
handleAdd() {
this.reset()
this.open = true
this.title = "添加兽医资质"
// null
this.form.auditStatus = null
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset()
@ -392,18 +599,23 @@ export default {
this.title = "修改兽医资质"
})
},
/** 提交按钮 */
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.qualificationId != null) {
updateQualification(this.form).then(response => {
console.log('修改返回数据:', response) //
this.$modal.msgSuccess("修改成功")
this.open = false
this.getList()
})
} else {
// null
this.form.auditStatus = null
addQualification(this.form).then(response => {
console.log('新增返回数据:', response) //
this.$modal.msgSuccess("新增成功")
this.open = false
this.getList()
@ -412,6 +624,7 @@ export default {
}
})
},
/** 删除按钮操作 */
handleDelete(row) {
const qualificationIds = row.qualificationId || this.ids
@ -422,12 +635,31 @@ export default {
this.$modal.msgSuccess("删除成功")
}).catch(() => {})
},
/** 导出按钮操作 */
handleExport() {
this.download('vet/qualification/export', {
...this.queryParams
}, `qualification_${new Date().getTime()}.xlsx`)
},
/** 根据字典值获取标签 */
getDictLabel(dictType, value) {
const dict = this.dict.type[dictType]
if (dict && value) {
const item = dict.find(item => item.value === value)
return item ? item.label : value
}
return value || '-'
}
}
}
</script>
<style scoped>
/* 操作按钮样式优化 */
.el-button--text {
padding: 6px 10px;
margin: 0 2px;
}
</style>
Loading…
Cancel
Save