Browse Source

商家信息功能和经验分享功能

master
ChaiNingQi 2 weeks ago
parent
commit
0c0f0c239f
  1. 104
      chenhai-admin/src/main/java/com/chenhai/web/controller/vet/MerchantInfoController.java
  2. 307
      chenhai-admin/src/main/java/com/chenhai/web/controller/vet/VetExperienceArticleController.java
  3. 6
      chenhai-admin/src/main/java/com/chenhai/web/controller/vet/VetKnowledgeController.java
  4. 3
      chenhai-admin/src/main/java/com/chenhai/web/controller/vet/VetNotificationController.java
  5. 6
      chenhai-admin/src/main/java/com/chenhai/web/controller/vet/VetPersonalInfoController.java
  6. 31
      chenhai-admin/src/main/java/com/chenhai/web/controller/vet/VetProductController.java
  7. 77
      chenhai-admin/src/main/java/com/chenhai/web/controller/vet/VetQualificationController.java
  8. 1
      chenhai-admin/src/main/java/com/chenhai/web/controller/vet/VetTrainingVideoController.java
  9. 396
      chenhai-system/src/main/java/com/chenhai/vet/CertificateRemindTask.java
  10. 146
      chenhai-system/src/main/java/com/chenhai/vet/domain/MerchantInfo.java
  11. 110
      chenhai-system/src/main/java/com/chenhai/vet/domain/VetExperienceArticle.java
  12. 61
      chenhai-system/src/main/java/com/chenhai/vet/mapper/MerchantInfoMapper.java
  13. 2
      chenhai-system/src/main/java/com/chenhai/vet/mapper/VetExperienceArticleMapper.java
  14. 2
      chenhai-system/src/main/java/com/chenhai/vet/mapper/VetQualificationMapper.java
  15. 61
      chenhai-system/src/main/java/com/chenhai/vet/service/IMerchantInfoService.java
  16. 10
      chenhai-system/src/main/java/com/chenhai/vet/service/IVetExperienceArticleService.java
  17. 8
      chenhai-system/src/main/java/com/chenhai/vet/service/IVetProductService.java
  18. 2
      chenhai-system/src/main/java/com/chenhai/vet/service/IVetQualificationService.java
  19. 93
      chenhai-system/src/main/java/com/chenhai/vet/service/impl/MerchantInfoServiceImpl.java
  20. 49
      chenhai-system/src/main/java/com/chenhai/vet/service/impl/VetExperienceArticleServiceImpl.java
  21. 1
      chenhai-system/src/main/java/com/chenhai/vet/service/impl/VetKnowledgeServiceImpl.java
  22. 142
      chenhai-system/src/main/java/com/chenhai/vet/service/impl/VetNotificationServiceImpl.java
  23. 23
      chenhai-system/src/main/java/com/chenhai/vet/service/impl/VetProductServiceImpl.java
  24. 150
      chenhai-system/src/main/java/com/chenhai/vet/service/impl/VetQualificationServiceImpl.java
  25. 86
      chenhai-system/src/main/resources/mapper/vet/MerchantInfoMapper.xml
  26. 137
      chenhai-system/src/main/resources/mapper/vet/VetExperienceArticleMapper.xml
  27. 5
      chenhai-system/src/main/resources/mapper/vet/VetQualificationMapper.xml
  28. 44
      chenhai-ui/src/api/vet/merchant.js
  29. 362
      chenhai-ui/src/views/vet/merchant/index.vue

104
chenhai-admin/src/main/java/com/chenhai/web/controller/vet/MerchantInfoController.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.MerchantInfo;
import com.chenhai.vet.service.IMerchantInfoService;
import com.chenhai.common.utils.poi.ExcelUtil;
import com.chenhai.common.core.page.TableDataInfo;
/**
* 商家信息Controller
*
* @author ruoyi
* @date 2026-02-04
*/
@RestController
@RequestMapping("/vet/merchant")
public class MerchantInfoController extends BaseController
{
@Autowired
private IMerchantInfoService merchantInfoService;
/**
* 查询商家信息列表
*/
@PreAuthorize("@ss.hasPermi('vet:merchant:list')")
@GetMapping("/list")
public TableDataInfo list(MerchantInfo merchantInfo)
{
startPage();
List<MerchantInfo> list = merchantInfoService.selectMerchantInfoList(merchantInfo);
return getDataTable(list);
}
/**
* 导出商家信息列表
*/
@PreAuthorize("@ss.hasPermi('vet:merchant:export')")
@Log(title = "商家信息", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(HttpServletResponse response, MerchantInfo merchantInfo)
{
List<MerchantInfo> list = merchantInfoService.selectMerchantInfoList(merchantInfo);
ExcelUtil<MerchantInfo> util = new ExcelUtil<MerchantInfo>(MerchantInfo.class);
util.exportExcel(response, list, "商家信息数据");
}
/**
* 获取商家信息详细信息
*/
@PreAuthorize("@ss.hasPermi('vet:merchant:query')")
@GetMapping(value = "/{shopId}")
public AjaxResult getInfo(@PathVariable("shopId") Long shopId)
{
return success(merchantInfoService.selectMerchantInfoByShopId(shopId));
}
/**
* 新增商家信息
*/
@PreAuthorize("@ss.hasPermi('vet:merchant:add')")
@Log(title = "商家信息", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@RequestBody MerchantInfo merchantInfo)
{
return toAjax(merchantInfoService.insertMerchantInfo(merchantInfo));
}
/**
* 修改商家信息
*/
@PreAuthorize("@ss.hasPermi('vet:merchant:edit')")
@Log(title = "商家信息", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody MerchantInfo merchantInfo)
{
return toAjax(merchantInfoService.updateMerchantInfo(merchantInfo));
}
/**
* 删除商家信息
*/
@PreAuthorize("@ss.hasPermi('vet:merchant:remove')")
@Log(title = "商家信息", businessType = BusinessType.DELETE)
@DeleteMapping("/{shopIds}")
public AjaxResult remove(@PathVariable Long[] shopIds)
{
return toAjax(merchantInfoService.deleteMerchantInfoByShopIds(shopIds));
}
}

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

@ -8,15 +8,17 @@ import com.chenhai.common.enums.BusinessType;
import com.chenhai.common.utils.SecurityUtils;
import com.chenhai.vet.domain.VetExperienceArticle;
import com.chenhai.vet.service.IVetExperienceArticleService;
import jakarta.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
/**
* 兽医经验文章论坛Controller列表样式
* 兽医经验文章论坛Controller
*/
@RestController
@RequestMapping("/vet/article")
@ -31,9 +33,41 @@ public class VetExperienceArticleController extends BaseController {
// 简单收藏管理
private static final Map<Long, Set<Long>> COLLECTION_STORE = new ConcurrentHashMap<>();
/**
* 初始化浏览记录表
*/
@PostConstruct
public void initViewLogTable() {
try {
String checkSql = "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = 'article_view_log'";
Integer tableExists = jdbcTemplate.queryForObject(checkSql, Integer.class);
if (tableExists == null || tableExists == 0) {
String createTableSql = "CREATE TABLE article_view_log (" +
"id BIGINT AUTO_INCREMENT PRIMARY KEY," +
"article_id BIGINT NOT NULL," +
"user_id BIGINT," +
"view_time DATETIME NOT NULL," +
"INDEX idx_article_id (article_id)," +
"INDEX idx_user_id (user_id)," +
"INDEX idx_view_time (view_time)" +
")";
jdbcTemplate.execute(createTableSql);
System.out.println("文章浏览记录表创建成功");
}
} catch (Exception e) {
System.err.println("初始化浏览记录表失败: " + e.getMessage());
}
}
/**
* 查询所有文章列表论坛首页
*/
@PreAuthorize("@ss.hasRole('muhu')or @ss.hasRole('vet')")
@Log(title = "兽医经验文章", businessType = BusinessType.OTHER)
@GetMapping("/list")
public TableDataInfo list(VetExperienceArticle vetExperienceArticle) {
// 默认只查询已发布的文章
@ -48,6 +82,8 @@ public class VetExperienceArticleController extends BaseController {
/**
* 查询我的文章列表个人中心
*/
@PreAuthorize("@ss.hasRole('muhu') or @ss.hasRole('vet')")
@Log(title = "兽医经验文章", businessType = BusinessType.OTHER)
@GetMapping("/myList")
public TableDataInfo myList(VetExperienceArticle vetExperienceArticle) {
Long userId = SecurityUtils.getUserId();
@ -79,41 +115,192 @@ public class VetExperienceArticleController extends BaseController {
/**
* 查看文章详情包含相关文章
*/
@PreAuthorize("@ss.hasPermi('vet:article:query') or @ss.hasRole('muhu')or @ss.hasRole('vet')")
@GetMapping(value = "/{id}")
public AjaxResult getInfo(@PathVariable("id") Long id) {
// 增加浏览数
vetExperienceArticleService.incrementViewCount(id);
// 1. 先获取文章信息
VetExperienceArticle article = vetExperienceArticleService.selectVetExperienceArticleById(id);
if (article == null) {
return error("文章不存在");
}
// 获取相关文章同一分类的其他文章
List<VetExperienceArticle> relatedArticles = vetExperienceArticleService.selectRelatedArticles(
id, article.getCategoryId(), 4);
// 2. 增加观看次数在文章表中直接更新
if (article.getViewCount() == null) {
article.setViewCount(0L);
}
article.setViewCount(article.getViewCount() + 1);
// 获取作者其他文章
List<VetExperienceArticle> authorArticles = vetExperienceArticleService.selectArticlesByUserId(
article.getUserId(), 5);
// 3. 更新文章浏览量
vetExperienceArticleService.updateVetExperienceArticle(article);
Map<String, Object> result = new HashMap<>();
result.put("article", article);
result.put("relatedArticles", relatedArticles);
result.put("authorArticles", authorArticles);
// 4. 重新获取更新后的文章信息确保获取最新的viewCount
VetExperienceArticle updatedArticle = vetExperienceArticleService.selectVetExperienceArticleById(id);
// 判断是否是当前用户
Long currentUserId = SecurityUtils.getUserId();
result.put("isOwner", currentUserId != null && currentUserId.equals(article.getUserId()));
result.put("isCollected", currentUserId != null &&
COLLECTION_STORE.getOrDefault(currentUserId, Collections.emptySet()).contains(id));
return success(updatedArticle);
}
/**
* 记录文章浏览到新表 - 新增方法
*/
private void recordArticleView(Long articleId, Long userId) {
try {
// 通用去重任何用户1小时内只记录一次
String checkSql;
Object[] params;
if (userId != null) {
checkSql = "SELECT COUNT(*) FROM article_view_log WHERE article_id = ? AND user_id = ? AND view_time > DATE_SUB(NOW(), INTERVAL 1 HOUR)";
params = new Object[]{articleId, userId};
} else {
checkSql = "SELECT COUNT(*) FROM article_view_log WHERE article_id = ? AND user_id IS NULL AND view_time > DATE_SUB(NOW(), INTERVAL 1 HOUR)";
params = new Object[]{articleId};
}
Integer recentViews = jdbcTemplate.queryForObject(checkSql, Integer.class, params);
if (recentViews != null && recentViews > 0) {
return; // 1小时内已浏览过
}
// 记录到浏览记录表
String insertSql = "INSERT INTO article_view_log (article_id, user_id, view_time) VALUES (?, ?, NOW())";
jdbcTemplate.update(insertSql, articleId, userId);
return success(result);
} catch (Exception e) {
System.err.println("记录浏览失败: " + e.getMessage());
}
}
/**
* 获取文章详细浏览统计 - 修正版
*/
private Map<String, Object> getArticleViewStats(Long articleId) {
Map<String, Object> stats = new HashMap<>();
try {
// 1. 总浏览量
String totalSql = "SELECT COUNT(*) FROM article_view_log WHERE article_id = ?";
Integer totalViews = jdbcTemplate.queryForObject(totalSql, Integer.class, articleId);
stats.put("totalViews", totalViews != null ? totalViews : 0);
// 2. 独立访客数
String uniqueSql = "SELECT COUNT(DISTINCT user_id) FROM article_view_log WHERE article_id = ? AND user_id IS NOT NULL";
Integer uniqueViewers = jdbcTemplate.queryForObject(uniqueSql, Integer.class, articleId);
stats.put("uniqueViewers", uniqueViewers != null ? uniqueViewers : 0);
// 3. 今日浏览量
String todaySql = "SELECT COUNT(*) FROM article_view_log WHERE article_id = ? AND DATE(view_time) = CURDATE()";
Integer todayViews = jdbcTemplate.queryForObject(todaySql, Integer.class, articleId);
stats.put("todayViews", todayViews != null ? todayViews : 0);
// 4. 本周浏览量
String weekSql = "SELECT COUNT(*) FROM article_view_log WHERE article_id = ? AND YEARWEEK(view_time, 1) = YEARWEEK(CURDATE(), 1)";
Integer weekViews = jdbcTemplate.queryForObject(weekSql, Integer.class, articleId);
stats.put("weekViews", weekViews != null ? weekViews : 0);
// 5. 最近7天浏览趋势简化版只返回近7天总览
String trendSql = "SELECT COUNT(*) as view_count " +
"FROM article_view_log " +
"WHERE article_id = ? AND view_time >= DATE_SUB(CURDATE(), INTERVAL 7 DAY)";
Integer weekTrend = jdbcTemplate.queryForObject(trendSql, Integer.class, articleId);
stats.put("weekTrend", weekTrend != null ? weekTrend : 0);
} catch (Exception e) {
// 出错时返回默认值
stats.put("totalViews", 0);
stats.put("uniqueViewers", 0);
stats.put("todayViews", 0);
stats.put("weekViews", 0);
stats.put("weekTrend", 0);
}
return stats;
}
/**
* 根据用户角色判断身份
*/
private String getUserRoleType(Long userId) {
if (userId == null) {
return "user"; // 默认普通用户
}
try {
// 查询用户拥有的角色ID
String sql = "SELECT role_id FROM sys_user_role WHERE user_id = ?";
List<Long> roleIds = jdbcTemplate.query(sql,
new Object[]{userId},
(rs, rowNum) -> rs.getLong("role_id"));
// 检查是否有兽医角色role_id = 4
for (Long roleId : roleIds) {
if (roleId != null && roleId == 4) {
return "vet"; // 兽医
}
}
// 检查是否有牧户角色role_id = 3
for (Long roleId : roleIds) {
if (roleId != null && roleId == 3) {
return "muhu"; // 牧户
}
}
} catch (Exception e) {
System.err.println("查询用户角色失败: " + e.getMessage());
}
return "user"; // 默认普通用户
}
/**
* 获取用户角色显示名称
*/
private String getUserRoleDisplayName(String roleType) {
switch (roleType) {
case "vet":
return "兽医";
case "muhu":
return "牧户";
default:
return "用户";
}
}
/**
* 获取文章详细浏览统计独立接口- 新增接口
*/
@PreAuthorize("@ss.hasRole('muhu')or @ss.hasRole('vet')")
@Log(title = "兽医经验文章", businessType = BusinessType.OTHER)
@GetMapping("/{id}/viewStats")
public AjaxResult getViewStats(@PathVariable("id") Long id) {
Map<String, Object> stats = getArticleViewStats(id);
stats.put("articleId", id);
return success(stats);
}
/**
* 修正文章浏览数手动同步- 新增接口
*/
@PreAuthorize("@ss.hasRole('muhu')or @ss.hasRole('vet')")
@Log(title = "兽医经验文章", businessType = BusinessType.UPDATE)
@PostMapping("/{id}/syncViewCount")
public AjaxResult syncViewCount(@PathVariable Long id) {
try {
Map<String, Object> stats = getArticleViewStats(id);
stats.put("articleId", id);
return success("浏览统计信息").put("data", stats);
} catch (Exception e) {
return error("获取统计失败: " + e.getMessage());
}
}
/**
* 发布新文章论坛发布
*/
@PreAuthorize("@ss.hasRole('muhu')or @ss.hasRole('vet')")
@Log(title = "发布经验文章", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@RequestBody VetExperienceArticle article) {
@ -123,11 +310,37 @@ public class VetExperienceArticleController extends BaseController {
// 设置作者信息
article.setUserId(currentUserId);
article.setVetName(currentUsername);
try {
String userAvatarSql = "SELECT avatar FROM sys_user WHERE user_id = ?";
String userAvatar = jdbcTemplate.queryForObject(userAvatarSql, String.class, currentUserId);
if (userAvatar != null) {
article.setVetAvatar(userAvatar);
}
// 获取用户昵称作为显示名称
String nickNameSql = "SELECT COALESCE(nick_name, user_name) FROM sys_user WHERE user_id = ?";
String displayName = jdbcTemplate.queryForObject(nickNameSql, String.class, currentUserId);
if (displayName != null) {
article.setVetName(displayName);
}
} catch (Exception e) {
System.err.println("获取用户信息失败: " + e.getMessage());
}
// 默认状态为已发布
if (article.getStatus() == null) {
article.setStatus("1");
}
String userRole = getUserRoleType(currentUserId);
article.setUserRole(userRole);
article.setUserType(getUserRoleDisplayName(userRole));
// 如果是兽医可以设置更多信息
/* if ("vet".equals(userRole)) {
article.setVetTitle("执业兽医");
// 可以查询兽医的详细信息
}*/
// 设置发布时间
if (article.getPublishTime() == null && "1".equals(article.getStatus())) {
@ -135,12 +348,25 @@ public class VetExperienceArticleController extends BaseController {
}
int result = vetExperienceArticleService.insertVetExperienceArticle(article);
return toAjax(result).put("articleId", article.getId());
VetExperienceArticle savedArticle = vetExperienceArticleService.selectVetExperienceArticleById(article.getId());
Map<String, Object> response = new HashMap<>();
response.put("articleId", article.getId());
response.put("userRole", savedArticle.getUserRole());
response.put("userType", savedArticle.getUserType());
response.put("title", savedArticle.getTitle());
response.put("status", savedArticle.getStatus());
response.put("publishTime", savedArticle.getPublishTime());
response.put("vetName", savedArticle.getVetName()); // 添加姓名
response.put("vetAvatar", savedArticle.getVetAvatar()); // 添加头像
return success("发布成功").put("data", response);
}
/**
* 修改文章
*/
@PreAuthorize("@ss.hasRole('muhu')or @ss.hasRole('vet')")
@Log(title = "修改经验文章", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody VetExperienceArticle vetExperienceArticle) {
@ -158,6 +384,7 @@ public class VetExperienceArticleController extends BaseController {
/**
* 删除文章
*/
@PreAuthorize("@ss.hasRole('muhu')or @ss.hasRole('vet')")
@Log(title = "删除经验文章", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable Long[] ids) {
@ -170,13 +397,13 @@ public class VetExperienceArticleController extends BaseController {
return error("没有权限删除他人文章");
}
}
return toAjax(vetExperienceArticleService.deleteVetExperienceArticleByIds(ids));
}
/**
* 点赞文章
*/
@PreAuthorize("@ss.hasRole('muhu')or @ss.hasRole('vet')")
@Log(title = "点赞文章", businessType = BusinessType.UPDATE)
@PostMapping("/{id}/like")
public AjaxResult likeArticle(@PathVariable Long id) {
@ -187,13 +414,14 @@ public class VetExperienceArticleController extends BaseController {
/**
* 收藏文章
*/
@PreAuthorize("@ss.hasRole('muhu')or @ss.hasRole('vet')")
@Log(title = "收藏文章", businessType = BusinessType.OTHER)
@PostMapping("/{id}/collect")
public AjaxResult collectArticle(@PathVariable Long id) {
Long currentUserId = SecurityUtils.getUserId();
if (currentUserId == null) {
return error("请先登录");
}
// 检查文章是否存在
VetExperienceArticle article = vetExperienceArticleService.selectVetExperienceArticleById(id);
if (article == null) {
@ -225,6 +453,8 @@ public class VetExperienceArticleController extends BaseController {
/**
* 获取我的收藏文章列表
*/
@PreAuthorize("@ss.hasRole('muhu')or @ss.hasRole('vet')")
@Log(title = "兽医经验文章", businessType = BusinessType.OTHER)
@GetMapping("/myCollections")
public TableDataInfo getMyCollections() {
Long currentUserId = SecurityUtils.getUserId();
@ -257,6 +487,8 @@ public class VetExperienceArticleController extends BaseController {
/**
* 获取论坛统计信息
*/
@PreAuthorize("@ss.hasRole('muhu')or @ss.hasRole('vet')")
@Log(title = "兽医经验文章", businessType = BusinessType.OTHER)
@GetMapping("/statistics")
public AjaxResult getStatistics() {
return success(vetExperienceArticleService.selectForumStatistics());
@ -266,6 +498,8 @@ public class VetExperienceArticleController extends BaseController {
/**
* 获取最新文章
*/
@PreAuthorize("@ss.hasRole('muhu')or @ss.hasRole('vet')")
@Log(title = "兽医经验文章", businessType = BusinessType.OTHER)
@GetMapping("/latest")
public AjaxResult getLatestArticles(@RequestParam(defaultValue = "10") Integer limit) {
List<VetExperienceArticle> articles = vetExperienceArticleService.selectLatestArticles(limit);
@ -276,6 +510,8 @@ public class VetExperienceArticleController extends BaseController {
/**
* 获取分类选项
*/
@PreAuthorize("@ss.hasRole('muhu')or @ss.hasRole('vet')")
@Log(title = "兽医经验文章", businessType = BusinessType.OTHER)
@GetMapping("/options")
public AjaxResult getCategoryOptions() {
// 直接从字典表查询
@ -297,6 +533,8 @@ public class VetExperienceArticleController extends BaseController {
/**
* 获取标签选项
*/
@PreAuthorize("@ss.hasRole('muhu')or @ss.hasRole('vet')")
@Log(title = "兽医经验文章", businessType = BusinessType.OTHER)
@GetMapping("/tags/options")
public AjaxResult getTagOptions() {
List<Map<String, Object>> options = new ArrayList<>();
@ -316,4 +554,27 @@ public class VetExperienceArticleController extends BaseController {
return success(options);
}
/**
* 草稿列表接口我的草稿
*/
@PreAuthorize("@ss.hasRole('muhu')or @ss.hasRole('vet')")
@Log(title = "兽医经验文章", businessType = BusinessType.OTHER)
@GetMapping("/draftList")
public TableDataInfo getMyDrafts() {
Long userId = SecurityUtils.getUserId();
if (userId == null) {
throw new RuntimeException("用户未登录");
}
// 创建查询对象只查询草稿状态的文章
VetExperienceArticle query = new VetExperienceArticle();
query.setUserId(userId);
query.setStatus("0"); // 0表示草稿状态
startPage();
List<VetExperienceArticle> drafts = vetExperienceArticleService.selectVetExperienceArticleList(query);
return getDataTable(drafts);
}
}

6
chenhai-admin/src/main/java/com/chenhai/web/controller/vet/VetKnowledgeController.java

@ -1,6 +1,8 @@
package com.chenhai.web.controller.vet;
import java.util.List;
import com.chenhai.common.utils.SecurityUtils;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired;
@ -38,7 +40,7 @@ public class VetKnowledgeController extends BaseController
/**
* 查询兽医文章列表
*/
@PreAuthorize("@ss.hasPermi('vet:knowledge:list') or @ss.hasRole('muhu')")
@PreAuthorize("@ss.hasPermi('vet:knowledge:list') or @ss.hasRole('muhu') or @ss.hasRole('vet')")
@GetMapping("/list")
public TableDataInfo list(VetKnowledge vetKnowledge)
{
@ -108,7 +110,7 @@ public class VetKnowledgeController extends BaseController
/**
* 提交审核
*/
@PreAuthorize("@ss.hasPermi('vet:knowledge:submit') or @ss.hasRole('muhu')")
@PreAuthorize("@ss.hasPermi('vet:knowledge:submit') or @ss.hasRole('muhu')or @ss.hasRole('vet')")
@Log(title = "兽医文章", businessType = BusinessType.UPDATE)
@PutMapping("/submit/{id}")
public AjaxResult submitForAudit(@PathVariable Long id) {

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

@ -73,6 +73,7 @@ public class VetNotificationController extends BaseController
/**
* 获取通知统计信息用于首页卡片
*/
@Log(title = "兽医通知", businessType = BusinessType.OTHER)
@PreAuthorize("@ss.hasPermi('vet:notification:query')")
@GetMapping("/stats/card")
public AjaxResult getNotificationCardStats() {
@ -131,6 +132,7 @@ public class VetNotificationController extends BaseController
/**
* 查询兽医通知列表
*/
@Log(title = "兽医通知", businessType = BusinessType.OTHER)
@PreAuthorize("@ss.hasPermi('vet:notification:list')")
@GetMapping("/list")
public TableDataInfo list(VetNotification vetNotification)
@ -167,6 +169,7 @@ public class VetNotificationController extends BaseController
/**
* 获取兽医通知详细信息
*/
@Log(title = "兽医通知", businessType = BusinessType.OTHER)
@PreAuthorize("@ss.hasPermi('vet:notification:query')")
@GetMapping(value = "/{id}")
public AjaxResult getInfo(@PathVariable("id") Long id)

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

@ -66,6 +66,7 @@ public class VetPersonalInfoController extends BaseController
/**
* 查询兽医个人信息列表
*/
@Log(title = "兽医个人信息", businessType = BusinessType.OTHER)
@PreAuthorize("@ss.hasPermi('vet:info:list')")
@GetMapping("/list")
public TableDataInfo list(VetPersonalInfo vetPersonalInfo)
@ -85,6 +86,7 @@ public class VetPersonalInfoController extends BaseController
/**
* 获取兽医完整信息包含证书详情和用户信息
*/
@Log(title = "兽医个人信息", businessType = BusinessType.OTHER)
@PreAuthorize("@ss.hasPermi('vet:info:view')")
@GetMapping("/full/{id}")
public AjaxResult getFullInfo(@PathVariable("id") Long id)
@ -126,6 +128,7 @@ public class VetPersonalInfoController extends BaseController
/**
* 获取当前登录用户的兽医完整信息
*/
@Log(title = "兽医个人信息", businessType = BusinessType.OTHER)
@PreAuthorize("@ss.hasPermi('vet:info:query')")
@GetMapping("/full/current")
public AjaxResult getCurrentFullInfo()
@ -171,6 +174,7 @@ public class VetPersonalInfoController extends BaseController
/**
* 获取兽医个人信息详细信息带用户信息
*/
@Log(title = "兽医个人信息", businessType = BusinessType.OTHER)
@PreAuthorize("@ss.hasPermi('vet:info:query')")
@GetMapping(value = "/{id}")
public AjaxResult getInfo(@PathVariable("id") Long id)
@ -191,6 +195,7 @@ public class VetPersonalInfoController extends BaseController
/**
* 根据用户ID获取兽医信息
*/
@Log(title = "兽医个人信息", businessType = BusinessType.OTHER)
@PreAuthorize("@ss.hasPermi('vet:info:query')")
@GetMapping(value = "/byUserId/{userId}")
public AjaxResult getInfoByUserId(@PathVariable("userId") Long userId)
@ -294,6 +299,7 @@ public class VetPersonalInfoController extends BaseController
/**
* 获取当前登录用户的兽医信息快捷方法
*/
@Log(title = "兽医个人信息", businessType = BusinessType.OTHER)
@PreAuthorize("@ss.hasPermi('vet:info:query')")
@GetMapping("/current")
public AjaxResult getCurrentInfo()

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

@ -39,11 +39,24 @@ public class VetProductController extends BaseController
/**
* 查询兽医产品信息列表
*/
@Log(title = "兽医产品信息", businessType = BusinessType.OTHER)
@PreAuthorize("@ss.hasPermi('vet:product:list')")
@GetMapping("/list")
public TableDataInfo list(VetProduct vetProduct)
{
startPage();
/* // 如果是普通用户只查看自己的产品
if (!SecurityUtils.isAdmin()) {
try {
Long userId = SecurityUtils.getUserId();
vetProduct.setUserId(userId);
} catch (Exception e) {
// 如果获取不到用户ID设置一个不存在的ID
vetProduct.setUserId(-1L);
}
}*/
List<VetProduct> list = vetProductService.selectVetProductList(vetProduct);
return getDataTable(list);
}
@ -64,6 +77,7 @@ public class VetProductController extends BaseController
/**
* 获取兽医产品信息详细信息
*/
@Log(title = "兽医产品信息", businessType = BusinessType.OTHER)
@PreAuthorize("@ss.hasPermi('vet:product:query')")
@GetMapping(value = "/{id}")
public AjaxResult getInfo(@PathVariable("id") Long id)
@ -159,11 +173,26 @@ public class VetProductController extends BaseController
/**
* 取消审核
*/
@PreAuthorize("@ss.hasPermi('vet:product:edit')")
/* @PreAuthorize("@ss.hasPermi('vet:product:edit')")*/
@Log(title = "兽医产品信息", businessType = BusinessType.UPDATE)
@PostMapping("/cancelAudit/{id}")
public AjaxResult cancelAudit(@PathVariable("id") Long id)
{
return toAjax(vetProductService.cancelAudit(id));
}
/**
* 管理员查询所有产品信息列表用于审核
*/
@Log(title = "产品审核", businessType = BusinessType.OTHER)
@PreAuthorize("@ss.hasPermi('vet:product:audit:list')")
@GetMapping("/audit/list")
public TableDataInfo auditList(VetProduct vetProduct)
{
startPage();
// 管理员查看所有产品列表用于审核
List<VetProduct> list = vetProductService.selectAllVetProductList(vetProduct);
return getDataTable(list);
}
}

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

@ -5,6 +5,7 @@ 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.exception.ServiceException;
import com.chenhai.common.utils.SecurityUtils;
import com.chenhai.vet.domain.VetQualification;
import com.chenhai.vet.service.IVetQualificationService;
@ -39,6 +40,7 @@ public class VetQualificationController extends BaseController
/**
* 获取资质类型选项下拉框用
*/
@Log(title = "兽医资质", businessType = BusinessType.OTHER)
@GetMapping("/type/options")
public AjaxResult getQualificationTypeOptions() {
String sql = "SELECT dict_value as value, dict_label as label " +
@ -59,6 +61,7 @@ public class VetQualificationController extends BaseController
/**
* 获取经营范围选项下拉框用
*/
@Log(title = "兽医资质", businessType = BusinessType.OTHER)
@GetMapping("/scope/options")
public AjaxResult getScopeOptions() {
String sql = "SELECT dict_value as value, dict_label as label " +
@ -79,6 +82,7 @@ public class VetQualificationController extends BaseController
/**
* 查询兽医资质列表含证书信息
*/
@Log(title = "兽医资质", businessType = BusinessType.OTHER)
@PreAuthorize("@ss.hasPermi('vet:qualification:list')")
@GetMapping("/list")
public TableDataInfo list(VetQualification vetQualification)
@ -95,6 +99,7 @@ public class VetQualificationController extends BaseController
/**
* 查询即将过期的资质证书
*/
@Log(title = "兽医资质", businessType = BusinessType.OTHER)
@PreAuthorize("@ss.hasPermi('vet:qualification:list')")
@GetMapping("/listExpiring")
public TableDataInfo listExpiring(VetQualification vetQualification)
@ -112,6 +117,7 @@ public class VetQualificationController extends BaseController
/**
* 查询用户的证书列表展开每个证书
*/
@Log(title = "兽医资质", businessType = BusinessType.OTHER)
@PreAuthorize("@ss.hasPermi('vet:qualification:list')")
@GetMapping("/certificate/list")
public TableDataInfo getCertificateList(VetQualification vetQualification)
@ -156,10 +162,74 @@ public class VetQualificationController extends BaseController
return getDataTable(certificateList);
}
/**
* 查看指定资质的证书列表
*/
@Log(title = "兽医资质", businessType = BusinessType.OTHER)
@PreAuthorize("@ss.hasPermi('vet:qualification:list')")
@GetMapping("/certificate/{qualificationId}/list")
public TableDataInfo getCertificateByQualificationId(@PathVariable Long qualificationId)
{
Long userId = SecurityUtils.getUserId();
// 创建查询条件
VetQualification query = new VetQualification();
query.setQualificationId(qualificationId);
// 查询指定资质
List<VetQualification> qualifications = vetQualificationService.selectVetQualificationList(query);
if (qualifications == null || qualifications.isEmpty()) {
return getDataTable(new ArrayList<>());
}
VetQualification qualification = qualifications.get(0);
// 权限验证非管理员只能查看自己的资质
if (!SecurityUtils.isAdmin(userId) && !qualification.getUserId().equals(userId)) {
throw new ServiceException("无权查看此资质的证书");
}
// 处理分页
startPage();
// 只处理当前资质的证书
List<Map<String, Object>> certificateList = new ArrayList<>();
List<VetQualification.CertificateInfo> certList = qualification.getCertificateList();
if (certList != null && !certList.isEmpty()) {
for (VetQualification.CertificateInfo cert : certList) {
Map<String, Object> certMap = new HashMap<>();
certMap.put("qualificationId", qualification.getQualificationId());
certMap.put("realName", qualification.getRealName());
certMap.put("certName", cert.getCertName());
certMap.put("certificateNo", cert.getCertificateNo());
certMap.put("issueDate", cert.getIssueDate());
certMap.put("expireDate", cert.getExpireDate());
certMap.put("issueOrg", cert.getIssueOrg());
certMap.put("certificateFiles", cert.getCertificateFiles());
certMap.put("certStatus", cert.getCertStatus());
certMap.put("certStatusLabel", getCertStatusLabel(cert.getCertStatus()));
if (cert.getCertId() != null) {
certMap.put("certId", String.valueOf(cert.getCertId()));
}
else if (qualification.getCertId() != null) {
certMap.put("certId", String.valueOf(qualification.getCertId()));
}
certificateList.add(certMap);
}
}
// 手动分页处理
return getDataTable(certificateList);
}
/**
* 根据证书ID查询证书详细信息
* 证书信息存储在资质的certificatesJson字段中通过数据库JSON查询获取
*/
@Log(title = "兽医资质", businessType = BusinessType.OTHER)
@GetMapping("/certificate/{certId}")
public AjaxResult getCertificateByCertId(@PathVariable("certId") Long certId)
{
@ -217,6 +287,7 @@ public class VetQualificationController extends BaseController
/**
* 登录后检查是否需要填写资质
*/
@Log(title = "兽医资质", businessType = BusinessType.OTHER)
@GetMapping("/checkNeedQualification")
public AjaxResult checkNeedQualification() {
Long userId = SecurityUtils.getUserId();
@ -270,6 +341,7 @@ public class VetQualificationController extends BaseController
/**
* 获取兽医资质详细信息
*/
@Log(title = "兽医资质", businessType = BusinessType.OTHER)
@PreAuthorize("@ss.hasPermi('vet:qualification:query')")
@GetMapping(value = "/{qualificationId}")
public AjaxResult getInfo(@PathVariable("qualificationId") Long qualificationId)
@ -297,6 +369,7 @@ public class VetQualificationController extends BaseController
{
Long sysUserId = SecurityUtils.getUserId();
String username = SecurityUtils.getUsername();
try {
vetQualification.setUserId(sysUserId);
vetQualification.setCreateBy(username);
@ -445,6 +518,7 @@ public class VetQualificationController extends BaseController
/**
* 根据用户ID获取资质证书列表
*/
@Log(title = "兽医资质", businessType = BusinessType.OTHER)
@GetMapping("/user/{userId}")
public AjaxResult getByUserId(@PathVariable Long userId) {
Long currentUserId = SecurityUtils.getUserId();
@ -460,6 +534,7 @@ public class VetQualificationController extends BaseController
/**
* 获取证书统计信息
*/
@Log(title = "兽医资质", businessType = BusinessType.OTHER)
@GetMapping("/statistics/{userId}")
public AjaxResult getStatistics(@PathVariable Long userId) {
Long currentUserId = SecurityUtils.getUserId();
@ -475,6 +550,7 @@ public class VetQualificationController extends BaseController
/**
* 手动触发证书检查
*/
@Log(title = "兽医资质", businessType = BusinessType.OTHER)
@PostMapping("/manual-check/{userId}")
public AjaxResult manualCheck(@PathVariable Long userId) {
Long currentUserId = SecurityUtils.getUserId();
@ -741,7 +817,6 @@ public class VetQualificationController extends BaseController
} catch (Exception e) {
log.warn("提取Long值失败: {}", obj, e);
}
return null;
}
}

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

@ -51,6 +51,7 @@ public class VetTrainingVideoController extends BaseController
/**
* 查询兽医培训视频列表
*/
@PreAuthorize("@ss.hasPermi('vet:training:list') or @ss.hasRole('muhu')")
@GetMapping("/list")
public TableDataInfo list(VetTrainingVideo vetTrainingVideo)

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

@ -4,15 +4,15 @@ import com.chenhai.vet.domain.VetQualification;
import com.chenhai.vet.domain.VetNotification;
import com.chenhai.vet.mapper.VetQualificationMapper;
import com.chenhai.vet.mapper.VetNotificationMapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.text.SimpleDateFormat;
import java.util.*;
@Component
@EnableScheduling
@ -25,69 +25,197 @@ public class CertificateRemindTask {
@Autowired
private VetNotificationMapper vetNotificationMapper;
private final ObjectMapper objectMapper = new ObjectMapper();
// 每天上午9点执行
@Scheduled(cron = "0 0 9 * * ?")/*
@Scheduled(cron = "0 * * * * ?")*/
/*@Scheduled(cron = "0 0 9 * * ?")*/
@Scheduled(cron = "0 */1 * * * ?")
public void dailyCertificateCheck() {
try {
// 查询所有包含证书信息的资质
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();
// 查询所有资质记录
List<VetQualification> qualifications = vetQualificationMapper.selectVetQualificationList(new VetQualification());
certificates.forEach(this::checkAndSendReminder);
for (VetQualification qualification : qualifications) {
try {
// 检查该资质下的所有证书包括JSON中的
checkAllCertificates(qualification);
} catch (Exception e) {
e.printStackTrace();
// 静默处理单个资质检查失败
}
}
} catch (Exception e) {
// 静默处理整体任务失败
}
}
/**
* 检查所有证书主表字段 + JSON字段
*/
private void checkAllCertificates(VetQualification qualification) {
if (qualification == null) {
return;
}
// 1. 先检查主表字段的证书
checkMainCertificate(qualification);
// 2. 再检查JSON字段中的证书
checkJsonCertificates(qualification);
}
/**
* 检查主表字段中的证书信息
*/
private void checkMainCertificate(VetQualification qualification) {
if (qualification.getExpireDate() == null ||
qualification.getCertName() == null ||
qualification.getCertName().isEmpty()) {
return;
}
Date expireDate = qualification.getExpireDate();
long daysRemaining = calculateDayDifference(new Date(), expireDate);
// 检查是否需要发送提醒
if (shouldSendReminder(daysRemaining) &&
!hasRecentReminderForCertificate(qualification, null, daysRemaining)) {
sendReminderForCertificate(qualification,
qualification.getCertName(),
qualification.getCertificateNo(),
expireDate,
null, // 主表证书没有单独的certId
daysRemaining);
}
}
/**
* 检查单个证书并发送提醒
* 检查JSON字段中的证书
*/
private void checkAndSendReminder(VetQualification qualification) {
if (qualification == null || qualification.getExpireDate() == null) {
private void checkJsonCertificates(VetQualification qualification) {
if (qualification.getCertificatesJson() == null ||
qualification.getCertificatesJson().isEmpty() ||
"[]".equals(qualification.getCertificatesJson().trim())) {
return;
}
long daysRemaining = calculateDayDifference(new Date(), qualification.getExpireDate());
try {
// 尝试解析JSON
List<Map<String, Object>> certificates = parseCertificatesJson(qualification.getCertificatesJson());
for (Map<String, Object> certMap : certificates) {
try {
checkSingleJsonCertificate(qualification, certMap);
} catch (Exception e) {
// 继续检查下一个证书
}
}
} catch (Exception e) {
// JSON解析失败静默处理
}
}
/**
* 检查单个JSON证书
*/
private void checkSingleJsonCertificate(VetQualification qualification, Map<String, Object> certMap) {
try {
// 获取证书基本信息
String certName = getStringValue(certMap, "certName");
String certificateNo = getStringValue(certMap, "certificateNo");
Object expireDateObj = certMap.get("expireDate");
Object certIdObj = certMap.get("certId");
updateCertificateStatus(qualification, daysRemaining);
if (certName == null || certName.isEmpty() || expireDateObj == null) {
return;
}
if (!shouldSendReminder(qualification, daysRemaining) || hasRecentReminder(qualification, daysRemaining)) {
// 解析过期日期
Date expireDate = parseDate(expireDateObj);
if (expireDate == null) {
return;
}
sendReminder(qualification, daysRemaining);
// 解析证书ID
Long certId = parseLong(certIdObj);
long daysRemaining = calculateDayDifference(new Date(), expireDate);
// 检查是否需要发送提醒
if (shouldSendReminder(daysRemaining) &&
!hasRecentReminderForCertificate(qualification, certId, daysRemaining)) {
sendReminderForCertificate(qualification, certName, certificateNo, expireDate, certId, daysRemaining);
}
} catch (Exception e) {
// 单个证书检查失败继续下一个
}
}
/**
* 解析证书JSON
*/
private List<Map<String, Object>> parseCertificatesJson(String certificatesJson) throws Exception {
if (certificatesJson == null || certificatesJson.isEmpty()) {
return new ArrayList<>();
}
// 先尝试清理JSON
String cleanedJson = cleanJsonString(certificatesJson);
return objectMapper.readValue(
cleanedJson,
objectMapper.getTypeFactory().constructCollectionType(List.class, Map.class)
);
}
/**
* 发送提醒
* 清理JSON字符串
*/
private String cleanJsonString(String json) {
if (json == null || json.isEmpty()) {
return "[]";
}
String cleaned = json.trim();
// 确保是数组格式
if (!cleaned.startsWith("[") && cleaned.startsWith("{")) {
cleaned = "[" + cleaned + "]";
}
// 修复常见的JSON格式问题
cleaned = cleaned.replace("'", "\"");
cleaned = cleaned.replace("\\", "\\\\");
cleaned = cleaned.replace("\n", "").replace("\r", "").replace("\t", "");
return cleaned;
}
/**
* 发送提醒
* 发送单个证书提醒
*/
private void sendReminder(VetQualification qualification, long daysRemaining) {
VetNotification notification = createBaseNotification(qualification);
private void sendReminderForCertificate(VetQualification qualification,
String certName,
String certificateNo,
Date expireDate,
Long certId,
long daysRemaining) {
VetNotification notification = createCertificateNotification(qualification, certId);
if (daysRemaining <= 0) {
// 只发送过期当天的提醒
// 过期提醒
if (daysRemaining == 0) {
setExpiredContent(notification, qualification, 0);
notification.setRemindLevel(3); // 最高级别
setExpiredContent(notification, certName, certificateNo, expireDate, 0);
notification.setRemindLevel(3);
vetNotificationMapper.insertVetNotification(notification);
}
// 过期后不再提醒
return;
} else if (daysRemaining <= 7) {
setCountdownContent(notification, qualification, daysRemaining);
// 7天内过期
setCountdownContent(notification, certName, certificateNo, expireDate, daysRemaining);
notification.setRemindLevel(daysRemaining <= 3 ? 3 : 2);
} else if (daysRemaining == 15 || daysRemaining == 30) {
setPreExpireContent(notification, qualification, daysRemaining);
// 15天或30天提醒
setPreExpireContent(notification, certName, certificateNo, expireDate, daysRemaining);
notification.setRemindLevel(daysRemaining == 30 ? 1 : 2);
} else {
return;
@ -97,12 +225,19 @@ public class CertificateRemindTask {
}
/**
* 创建基础通知对象
* 创建证书通知
*/
private VetNotification createBaseNotification(VetQualification qualification) {
private VetNotification createCertificateNotification(VetQualification qualification, Long certId) {
VetNotification notification = new VetNotification();
notification.setUserId(qualification.getUserId());
notification.setRelatedId(qualification.getQualificationId().toString());
// 构建关联ID资质ID:证书ID如果证书ID为空只使用资质ID
String relatedId = qualification.getQualificationId().toString();
if (certId != null && certId != 0) {
relatedId = qualification.getQualificationId() + ":" + certId;
}
notification.setRelatedId(relatedId);
notification.setType("CERT_EXPIRE_REMIND");
notification.setIsRead(0);
notification.setCreateTime(new Date());
@ -112,57 +247,59 @@ public class CertificateRemindTask {
/**
* 设置过期内容
*/
private void setExpiredContent(VetNotification notification, VetQualification qualification, long daysExpired) {
private void setExpiredContent(VetNotification notification, String certName, String certificateNo, Date expireDate, long daysExpired) {
if (daysExpired == 0) {
notification.setTitle("🚨 证书今天过期!");
notification.setContent(String.format("您的《%s》证书今天已过期!请立即更新。", qualification.getCertName()));
String content = String.format("您的《%s》证书今天已过期!请立即更新。", certName);
if (certificateNo != null && !certificateNo.isEmpty()) {
content = String.format("您的《%s》证书(编号:%s)今天已过期!请立即更新。", certName, certificateNo);
}
notification.setContent(content);
}
// 移除过期多天的提醒
}
/**
* 设置倒计时内容
*/
private void setCountdownContent(VetNotification notification, VetQualification qualification, long daysRemaining) {
private void setCountdownContent(VetNotification notification, String certName, String certificateNo, Date expireDate, long daysRemaining) {
notification.setTitle("⚠️ 证书还剩" + daysRemaining + "天过期");
notification.setContent(String.format("您的《%s》证书还剩%d天过期,请及时更新。", qualification.getCertName(), daysRemaining));
String content = String.format("您的《%s》证书还剩%d天过期,请及时更新。", certName, daysRemaining);
if (certificateNo != null && !certificateNo.isEmpty()) {
content = String.format("您的《%s》证书(编号:%s)还剩%d天过期,请及时更新。", certName, certificateNo, daysRemaining);
}
notification.setContent(content);
}
/**
* 设置预过期内容
*/
private void setPreExpireContent(VetNotification notification, VetQualification qualification, long daysRemaining) {
private void setPreExpireContent(VetNotification notification, String certName, String certificateNo, Date expireDate, long daysRemaining) {
String timeText = daysRemaining == 30 ? "30天" : "15天";
notification.setTitle("📅 证书还剩" + timeText + "过期");
notification.setContent(String.format("您的《%s》证书将在%s后过期,请提前准备更新。", qualification.getCertName(), timeText));
String content = String.format("您的《%s》证书将在%s后过期,请提前准备更新。", certName, timeText);
if (certificateNo != null && !certificateNo.isEmpty()) {
content = String.format("您的《%s》证书(编号:%s)将在%s后过期,请提前准备更新。", certName, certificateNo, timeText);
}
notification.setContent(content);
}
/**
* 判断是否需要发送提醒
*/
private boolean shouldSendReminder(VetQualification qualification, long daysRemaining) {
String status = qualification.getCertStatus();
if ("2".equals(status)) { // 已过期
// 只在过期的第一天提醒daysRemaining = 0 刚刚过期时
return daysRemaining == 0; // 只提醒过期当天
}
if ("1".equals(status)) { // 即将过期
return daysRemaining == 30 || daysRemaining == 15 || (daysRemaining >= 1 && daysRemaining <= 7);
}
if ("0".equals(status)) { // 正常
return daysRemaining == 30 || daysRemaining == 15;
}
return false;
private boolean shouldSendReminder(long daysRemaining) {
// 只在这些天数发送提醒
return daysRemaining == 0 ||
daysRemaining == 7 ||
daysRemaining == 3 ||
daysRemaining == 1 ||
daysRemaining == 15 ||
daysRemaining == 30;
}
/**
* 检查最近是否已发送过提醒
*/
private boolean hasRecentReminder(VetQualification qualification, long daysRemaining) {
private boolean hasRecentReminderForCertificate(VetQualification qualification, Long certId, long daysRemaining) {
try {
Calendar cal = Calendar.getInstance();
cal.set(Calendar.HOUR_OF_DAY, 0);
@ -174,102 +311,125 @@ public class CertificateRemindTask {
cal.add(Calendar.DAY_OF_MONTH, 1);
Date endOfDay = cal.getTime();
// 检查今天是否已发送
// 构建查询条件
VetNotification query = new VetNotification();
query.setRelatedId(qualification.getQualificationId().toString());
// 构建关联ID
String relatedId = qualification.getQualificationId().toString();
if (certId != null && certId != 0) {
relatedId = qualification.getQualificationId() + ":" + certId;
}
query.setRelatedId(relatedId);
query.setType("CERT_EXPIRE_REMIND");
List<VetNotification> notifications = vetNotificationMapper.selectVetNotificationList(query);
// 获取今天的所有通知
List<VetNotification> todayNotifications = notifications.stream()
.filter(n -> n.getCreateTime() != null &&
n.getCreateTime().after(startOfDay) &&
n.getCreateTime().before(endOfDay))
.toList();
// 如果没有今天的通知直接返回
if (todayNotifications.isEmpty()) {
return !todayNotifications.isEmpty();
} catch (Exception e) {
return false;
}
// 生成当前应该发送的通知标题
String expectedTitle = generateExpectedTitle(qualification, daysRemaining);
// 检查今天是否已有相同标题的通知
boolean hasSameTitleToday = todayNotifications.stream()
.anyMatch(n -> expectedTitle.equals(n.getTitle()));
if (hasSameTitleToday) {
return true;
}
// 已过期证书检查最近7天是否有相同标题的通知
if (daysRemaining <= 0) {
cal.add(Calendar.DAY_OF_MONTH, -7);
Date sevenDaysAgo = cal.getTime();
List<VetNotification> recentNotifications = notifications.stream()
.filter(n -> n.getCreateTime() != null &&
n.getCreateTime().after(sevenDaysAgo))
.toList();
/**
* 从Map获取字符串值
*/
private String getStringValue(Map<String, Object> map, String key) {
Object value = map.get(key);
return value != null ? value.toString() : null;
}
boolean hasSameTitleRecent = recentNotifications.stream()
.anyMatch(n -> expectedTitle.equals(n.getTitle()));
/**
* 解析Long值
*/
private Long parseLong(Object obj) {
if (obj == null) {
return null;
}
if (hasSameTitleRecent) {
return true;
try {
if (obj instanceof Number) {
return ((Number) obj).longValue();
} else if (obj instanceof String) {
String str = ((String) obj).trim();
if (str.isEmpty()) {
return null;
}
// 处理包含下划线的ID
if (str.contains("_")) {
str = str.split("_")[0];
}
return Long.parseLong(str);
}
return false;
} catch (Exception e) {
return false;
// 静默处理解析失败
}
return null;
}
/**
* 生成预期的通知标题
* 解析日期
*/
private String generateExpectedTitle(VetQualification qualification, long daysRemaining) {
if (daysRemaining <= 0) {
long daysExpired = -daysRemaining;
if (daysExpired == 0) {
return "🚨 证书今天过期!";
} else {
return "🚨 证书已过期" + daysExpired + "天";
private Date parseDate(Object dateObj) {
if (dateObj == null) {
return null;
}
} else if (daysRemaining <= 7) {
return "⚠️ 证书还剩" + daysRemaining + "天过期";
} else if (daysRemaining == 15 || daysRemaining == 30) {
return "📅 证书还剩" + daysRemaining + "天过期";
} else {
return ""; // 其他情况不发送
try {
if (dateObj instanceof Date) {
return (Date) dateObj;
} else if (dateObj instanceof String) {
String dateStr = ((String) dateObj).trim();
// 尝试常见格式
SimpleDateFormat[] formats = {
new SimpleDateFormat("yyyy-MM-dd"),
new SimpleDateFormat("yyyy/MM/dd"),
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"),
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss")
};
for (SimpleDateFormat sdf : formats) {
try {
return sdf.parse(dateStr);
} catch (Exception e) {
// 继续尝试下一个格式
}
}
/**
* 更新证书状态
*/
private void updateCertificateStatus(VetQualification qualification, long daysRemaining) {
// 尝试解析为时间戳
try {
String newStatus = daysRemaining <= 0 ? "2" :
daysRemaining <= 30 ? "1" : "0";
if (!newStatus.equals(qualification.getCertStatus())) {
qualification.setCertStatus(newStatus);
// 更新数据库中的状态
vetQualificationMapper.updateVetQualification(qualification);
long timestamp = Long.parseLong(dateStr);
return new Date(timestamp);
} catch (NumberFormatException e) {
// 不是时间戳格式
}
} else if (dateObj instanceof Long) {
return new Date((Long) dateObj);
} else if (dateObj instanceof Integer) {
return new Date(((Integer) dateObj).longValue() * 1000L);
}
} catch (Exception e) {
e.printStackTrace();
// 静默处理解析失败
}
return null;
}
/**
* 计算天数差忽略时间部分
*/
private long calculateDayDifference(Date startDate, Date endDate) {
if (startDate == null || endDate == null) {
return 0;
}
Calendar startCal = Calendar.getInstance();
startCal.setTime(startDate);
resetTime(startCal);

146
chenhai-system/src/main/java/com/chenhai/vet/domain/MerchantInfo.java

@ -0,0 +1,146 @@
package com.chenhai.vet.domain;
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;
/**
* 商家信息对象 merchant_info
*
* @author ruoyi
* @date 2026-02-04
*/
public class MerchantInfo extends BaseEntity
{
private static final long serialVersionUID = 1L;
/** 店铺ID,主键 */
private Long shopId;
/** 店铺名称 */
@Excel(name = "店铺名称")
private String shopName;
/** 店铺地址 */
@Excel(name = "店铺地址")
private String shopAddress;
/** 联系电话 */
@Excel(name = "联系电话")
private String phone;
/** 关联用户ID(店主) */
@Excel(name = "关联用户ID", readConverterExp = "店=主")
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;
/** 是否启用(1启用,0禁用) */
@Excel(name = "是否启用", readConverterExp = "1=启用,0禁用")
private Integer isActive;
public void setShopId(Long shopId)
{
this.shopId = shopId;
}
public Long getShopId()
{
return shopId;
}
public void setShopName(String shopName)
{
this.shopName = shopName;
}
public String getShopName()
{
return shopName;
}
public void setShopAddress(String shopAddress)
{
this.shopAddress = shopAddress;
}
public String getShopAddress()
{
return shopAddress;
}
public void setPhone(String phone)
{
this.phone = phone;
}
public String getPhone()
{
return phone;
}
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;
}
public void setIsActive(Integer isActive)
{
this.isActive = isActive;
}
public Integer getIsActive()
{
return isActive;
}
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
.append("shopId", getShopId())
.append("shopName", getShopName())
.append("shopAddress", getShopAddress())
.append("phone", getPhone())
.append("userId", getUserId())
.append("createdAt", getCreatedAt())
.append("updatedAt", getUpdatedAt())
.append("isActive", getIsActive())
.toString();
}
}

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

@ -1,7 +1,10 @@
package com.chenhai.vet.domain;
import java.util.Date;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonInclude;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.chenhai.common.annotation.Excel;
@ -80,6 +83,9 @@ public class VetExperienceArticle extends BaseEntity
@Excel(name = "状态", dictType = "article_status")
private String status;
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
private String searchKey;
/** 审核状态(0待审核 1审核中 2审核通过 3审核驳回 4敏感内容驳回) */
private String auditStatus;
@ -96,7 +102,6 @@ public class VetExperienceArticle extends BaseEntity
/** 审核人姓名 */
private String auditorName;
/** 是否包含敏感词(0否 1是) */
@Excel(name = "是否包含敏感词", readConverterExp = "0=否,1=是")
private String isSensitive;
@ -112,7 +117,7 @@ public class VetExperienceArticle extends BaseEntity
/** 浏览次数 */
@Excel(name = "浏览次数")
private Integer viewCount;
private Long viewCount;
/** 点赞数 */
@Excel(name = "点赞数")
@ -122,17 +127,37 @@ public class VetExperienceArticle extends BaseEntity
@Excel(name = "收藏数")
private Integer collectCount;
// 确保有对应的getter和setter
public Integer getViewCount() {
return viewCount;
/** 用户角色 */
private String userRole;
/** 用户类型(显示用) */
private String userType;
/** 浏览统计信息(从article_view_log表查询) */
@JsonInclude(JsonInclude.Include.NON_NULL)
private Map<String, Object> viewStats;
/** 今日浏览量(计算字段) */
private Integer todayViewCount;
public String getUserRole() {
return userRole;
}
public void setViewCount(Integer viewCount) {
this.viewCount = viewCount;
public void setUserRole(String userRole) {
this.userRole = userRole;
}
public String getUserType() {
return userType;
}
public void setUserType(String userType) {
this.userType = userType;
}
public Integer getLikeCount() {
return likeCount;
return likeCount != null ? likeCount : 0;
}
public void setLikeCount(Integer likeCount) {
@ -140,7 +165,7 @@ public class VetExperienceArticle extends BaseEntity
}
public Integer getCollectCount() {
return collectCount;
return collectCount != null ? collectCount : 0;
}
public void setCollectCount(Integer collectCount) {
@ -337,6 +362,67 @@ public class VetExperienceArticle extends BaseEntity
return publishTime;
}
// 修复添加返回语句
public Long getViewCount() {
return viewCount != null ? viewCount : 0L;
}
public void setViewCount(Long viewCount) {
this.viewCount = viewCount;
}
public Map<String, Object> getViewStats() {
return viewStats;
}
public void setViewStats(Map<String, Object> viewStats) {
this.viewStats = viewStats;
}
public Integer getTodayViewCount() {
return todayViewCount != null ? todayViewCount : 0;
}
public void setTodayViewCount(Integer todayViewCount) {
this.todayViewCount = todayViewCount;
}
public String getSearchKey() {
return searchKey;
}
public void setSearchKey(String searchKey) {
this.searchKey = searchKey;
}
/**
* 获取总浏览数从viewStats中获取
*/
public Integer getTotalViewCount() {
if (viewStats != null && viewStats.containsKey("totalViews")) {
Object total = viewStats.get("totalViews");
if (total instanceof Integer) {
return (Integer) total;
} else if (total instanceof Long) {
return ((Long) total).intValue();
}
}
return getViewCount() != null ? getViewCount().intValue() : 0;
}
/**
* 获取今日浏览数从viewStats中获取
*/
public Integer getTodayViews() {
if (viewStats != null && viewStats.containsKey("todayViews")) {
Object today = viewStats.get("todayViews");
if (today instanceof Integer) {
return (Integer) today;
}
}
return getTodayViewCount() != null ? getTodayViewCount() : 0;
}
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
@ -359,6 +445,12 @@ public class VetExperienceArticle extends BaseEntity
.append("isSensitive", getIsSensitive())
.append("sensitiveWords", getSensitiveWords())
.append("publishTime", getPublishTime())
.append("viewCount", getViewCount())
.append("likeCount", getLikeCount())
.append("collectCount", getCollectCount())
.append("userRole", getUserRole())
.append("userType", getUserType())
.append("todayViewCount", getTodayViewCount())
.append("createBy", getCreateBy())
.append("createTime", getCreateTime())
.append("updateBy", getUpdateBy())

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

@ -0,0 +1,61 @@
package com.chenhai.vet.mapper;
import java.util.List;
import com.chenhai.vet.domain.MerchantInfo;
/**
* 商家信息Mapper接口
*
* @author ruoyi
* @date 2026-02-04
*/
public interface MerchantInfoMapper
{
/**
* 查询商家信息
*
* @param shopId 商家信息主键
* @return 商家信息
*/
public MerchantInfo selectMerchantInfoByShopId(Long shopId);
/**
* 查询商家信息列表
*
* @param merchantInfo 商家信息
* @return 商家信息集合
*/
public List<MerchantInfo> selectMerchantInfoList(MerchantInfo merchantInfo);
/**
* 新增商家信息
*
* @param merchantInfo 商家信息
* @return 结果
*/
public int insertMerchantInfo(MerchantInfo merchantInfo);
/**
* 修改商家信息
*
* @param merchantInfo 商家信息
* @return 结果
*/
public int updateMerchantInfo(MerchantInfo merchantInfo);
/**
* 删除商家信息
*
* @param shopId 商家信息主键
* @return 结果
*/
public int deleteMerchantInfoByShopId(Long shopId);
/**
* 批量删除商家信息
*
* @param shopIds 需要删除的数据主键集合
* @return 结果
*/
public int deleteMerchantInfoByShopIds(Long[] shopIds);
}

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

@ -75,7 +75,7 @@ public interface VetExperienceArticleMapper
* @param id 文章主键
* @return 结果
*/
public int incrementViewCount(Long id);
/* public int incrementViewCount(Long id);*/
/**
* 增加点赞数

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

@ -71,4 +71,6 @@ public interface VetQualificationMapper
Map<String, Object> selectCertificateByCertId(@Param("certId") Long certId, @Param("userId") Long userId);
VetQualification selectVetQualificationById(Long qualificationId);
}

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

@ -0,0 +1,61 @@
package com.chenhai.vet.service;
import java.util.List;
import com.chenhai.vet.domain.MerchantInfo;
/**
* 商家信息Service接口
*
* @author ruoyi
* @date 2026-02-04
*/
public interface IMerchantInfoService
{
/**
* 查询商家信息
*
* @param shopId 商家信息主键
* @return 商家信息
*/
public MerchantInfo selectMerchantInfoByShopId(Long shopId);
/**
* 查询商家信息列表
*
* @param merchantInfo 商家信息
* @return 商家信息集合
*/
public List<MerchantInfo> selectMerchantInfoList(MerchantInfo merchantInfo);
/**
* 新增商家信息
*
* @param merchantInfo 商家信息
* @return 结果
*/
public int insertMerchantInfo(MerchantInfo merchantInfo);
/**
* 修改商家信息
*
* @param merchantInfo 商家信息
* @return 结果
*/
public int updateMerchantInfo(MerchantInfo merchantInfo);
/**
* 批量删除商家信息
*
* @param shopIds 需要删除的商家信息主键集合
* @return 结果
*/
public int deleteMerchantInfoByShopIds(Long[] shopIds);
/**
* 删除商家信息信息
*
* @param shopId 商家信息主键
* @return 结果
*/
public int deleteMerchantInfoByShopId(Long shopId);
}

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

@ -68,13 +68,6 @@ public interface IVetExperienceArticleService
*/
List<VetExperienceArticle> selectLatestArticles(Integer limit);
/**
* 获取热门文章按浏览数排序
*
* @param limit 限制数量
* @return 文章集合
*/
List<VetExperienceArticle> selectHotArticles(Integer limit);
/**
* 根据用户ID获取文章
@ -101,7 +94,7 @@ public interface IVetExperienceArticleService
* @param id 文章ID
* @return 结果
*/
int incrementViewCount(Long id);
/* int incrementViewCount(Long id);*/
/**
* 增加点赞数
@ -132,4 +125,5 @@ public interface IVetExperienceArticleService
* @return 文章集合
*/
List<VetExperienceArticle> searchArticles(String keyword);
}

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

@ -102,4 +102,12 @@ public interface IVetProductService
*/
public int cancelAudit(Long id);
/**
* 管理员查询所有兽医产品信息列表用于审核
*
* @param vetProduct 兽医产品信息
* @return 兽医产品信息集合
*/
public List<VetProduct> selectAllVetProductList(VetProduct vetProduct);
}

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

@ -98,4 +98,6 @@ public interface IVetQualificationService
*/
Map<String, Object> selectCertificateWithQualificationByCertId(Long certId, Long userId);
VetQualification selectVetQualificationById(Long qualificationId);
}

93
chenhai-system/src/main/java/com/chenhai/vet/service/impl/MerchantInfoServiceImpl.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.MerchantInfoMapper;
import com.chenhai.vet.domain.MerchantInfo;
import com.chenhai.vet.service.IMerchantInfoService;
/**
* 商家信息Service业务层处理
*
* @author ruoyi
* @date 2026-02-04
*/
@Service
public class MerchantInfoServiceImpl implements IMerchantInfoService
{
@Autowired
private MerchantInfoMapper merchantInfoMapper;
/**
* 查询商家信息
*
* @param shopId 商家信息主键
* @return 商家信息
*/
@Override
public MerchantInfo selectMerchantInfoByShopId(Long shopId)
{
return merchantInfoMapper.selectMerchantInfoByShopId(shopId);
}
/**
* 查询商家信息列表
*
* @param merchantInfo 商家信息
* @return 商家信息
*/
@Override
public List<MerchantInfo> selectMerchantInfoList(MerchantInfo merchantInfo)
{
return merchantInfoMapper.selectMerchantInfoList(merchantInfo);
}
/**
* 新增商家信息
*
* @param merchantInfo 商家信息
* @return 结果
*/
@Override
public int insertMerchantInfo(MerchantInfo merchantInfo)
{
return merchantInfoMapper.insertMerchantInfo(merchantInfo);
}
/**
* 修改商家信息
*
* @param merchantInfo 商家信息
* @return 结果
*/
@Override
public int updateMerchantInfo(MerchantInfo merchantInfo)
{
return merchantInfoMapper.updateMerchantInfo(merchantInfo);
}
/**
* 批量删除商家信息
*
* @param shopIds 需要删除的商家信息主键
* @return 结果
*/
@Override
public int deleteMerchantInfoByShopIds(Long[] shopIds)
{
return merchantInfoMapper.deleteMerchantInfoByShopIds(shopIds);
}
/**
* 删除商家信息信息
*
* @param shopId 商家信息主键
* @return 结果
*/
@Override
public int deleteMerchantInfoByShopId(Long shopId)
{
return merchantInfoMapper.deleteMerchantInfoByShopId(shopId);
}
}

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

@ -4,10 +4,13 @@ import java.util.*;
import com.chenhai.common.utils.DateUtils;
import com.github.pagehelper.PageHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import com.chenhai.vet.mapper.VetExperienceArticleMapper;
import com.chenhai.vet.domain.VetExperienceArticle;
import com.chenhai.vet.service.IVetExperienceArticleService;
import org.springframework.transaction.annotation.Transactional;
/**
* 兽医经验文章Service业务层处理
@ -20,6 +23,8 @@ public class VetExperienceArticleServiceImpl implements IVetExperienceArticleSer
{
@Autowired
private VetExperienceArticleMapper vetExperienceArticleMapper;
@Autowired
private JdbcTemplate jdbcTemplate;
/**
* 查询兽医经验文章
@ -28,11 +33,9 @@ public class VetExperienceArticleServiceImpl implements IVetExperienceArticleSer
* @return 兽医经验文章
*/
@Override
public VetExperienceArticle selectVetExperienceArticleById(Long id)
{
public VetExperienceArticle selectVetExperienceArticleById(Long id) {
return vetExperienceArticleMapper.selectVetExperienceArticleById(id);
}
/**
* 查询兽医经验文章列表
*
@ -112,23 +115,6 @@ public class VetExperienceArticleServiceImpl implements IVetExperienceArticleSer
return vetExperienceArticleMapper.selectArticlesByCondition(params);
}
/**
* 获取热门文章按浏览数排序
*
* @param limit 限制数量
* @return 文章集合
*/
@Override
public List<VetExperienceArticle> selectHotArticles(Integer limit) {
PageHelper.clearPage();
Map<String, Object> params = new HashMap<>();
params.put("status", "1");
params.put("orderBy", "view_count");
params.put("orderType", "desc");
params.put("limit", limit != null ? limit : 10);
return vetExperienceArticleMapper.selectArticlesByCondition(params);
}
/**
* 根据用户ID获取文章
*
@ -169,16 +155,6 @@ public class VetExperienceArticleServiceImpl implements IVetExperienceArticleSer
return vetExperienceArticleMapper.selectArticlesByCondition(params);
}
/**
* 增加浏览数
*
* @param id 文章ID
* @return 结果
*/
@Override
public int incrementViewCount(Long id) {
return vetExperienceArticleMapper.incrementViewCount(id);
}
/**
* 增加点赞数
@ -229,11 +205,14 @@ public class VetExperienceArticleServiceImpl implements IVetExperienceArticleSer
statistics.put("totalAuthors", authorIds.size());
// 统计总浏览数
int totalViews = 0;
for (VetExperienceArticle article : allArticles) {
totalViews += article.getViewCount() != null ? article.getViewCount() : 0;
}
statistics.put("totalViews", totalViews);
String totalViewsSql = "SELECT COUNT(*) FROM article_view_log";
Integer totalViews = jdbcTemplate.queryForObject(totalViewsSql, Integer.class);
statistics.put("totalViews", totalViews != null ? totalViews : 0);
// 今日浏览量
String todaySql = "SELECT COUNT(*) FROM article_view_log WHERE DATE(view_time) = CURDATE()";
Integer todayViews = jdbcTemplate.queryForObject(todaySql, Integer.class);
statistics.put("todayViews", todayViews != null ? todayViews : 0);
// 统计总点赞数
int totalLikes = 0;

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

@ -1,5 +1,6 @@
package com.chenhai.vet.service.impl;
import java.util.ArrayList;
import java.util.List;
import com.chenhai.common.core.domain.AjaxResult;

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

@ -1,4 +1,3 @@
// 更简单的版本完全使用 Date
package com.chenhai.vet.service.impl;
import com.chenhai.vet.domain.VetNotification;
@ -66,12 +65,25 @@ public class VetNotificationServiceImpl implements VetNotificationService {
return;
}
log.info("证书提醒记录: 资质ID={}, 证书名称={}, 过期时间={}",
qualification.getQualificationId(), qualification.getCertName(),
formatDate(qualification.getExpireDate()));
log.info("证书提醒记录: 资质ID={}, 证书数量={}",
qualification.getQualificationId(),
qualification.getCertificateList() != null ? qualification.getCertificateList().size() : 0);
// 获取所有证书
List<VetQualification.CertificateInfo> certificates = qualification.getCertificateList();
if (certificates == null || certificates.isEmpty()) {
log.warn("资质ID={} 没有证书信息", qualification.getQualificationId());
return;
}
// 对每个证书发送提醒
for (VetQualification.CertificateInfo certificate : certificates) {
if (certificate.getExpireDate() == null) {
continue;
}
// 计算剩余天数
long daysRemaining = calculateDayDifference(new Date(), qualification.getExpireDate());
long daysRemaining = calculateDayDifference(new Date(), certificate.getExpireDate());
// 根据剩余天数设置提醒内容和级别
String title;
@ -79,44 +91,38 @@ public class VetNotificationServiceImpl implements VetNotificationService {
int remindLevel;
if (daysRemaining <= 0) {
// 只发送过期当天的提醒
if (daysRemaining == 0) {
title = "证书已过期";
content = String.format("您的《%s》证书已于%s过期!请立即更新证书。",
qualification.getCertName(), formatDate(qualification.getExpireDate()));
content = String.format("您的《%s》证书(编号:%s)已于%s过期!请立即更新证书。",
certificate.getCertName(), certificate.getCertificateNo(),
formatDate(certificate.getExpireDate()));
remindLevel = 3;
// 创建通知
VetNotification notification = createCertificateNotification(qualification, certificate,
title, content, remindLevel);
saveNotification(notification);
}
} else if (daysRemaining <= 7) {
title = "证书即将过期(7天内)";
content = String.format("您的《%s》证书将在%d天后过期,请尽快更新!",
qualification.getCertName(), daysRemaining);
content = String.format("您的《%s》证书(编号:%s)将在%d天后过期,请尽快更新!",
certificate.getCertName(), certificate.getCertificateNo(), daysRemaining);
remindLevel = 3;
} else {
VetNotification notification = createCertificateNotification(qualification, certificate,
title, content, remindLevel);
saveNotification(notification);
} else if (daysRemaining <= 30) {
title = "证书即将过期(30天内)";
content = String.format("您的《%s》证书将在%d天后过期,请及时更新。",
qualification.getCertName(), daysRemaining);
content = String.format("您的《%s》证书(编号:%s)将在%d天后过期,请及时更新。",
certificate.getCertName(), certificate.getCertificateNo(), 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);
VetNotification notification = createCertificateNotification(qualification, certificate,
title, content, remindLevel);
saveNotification(notification);
}
} catch (Exception e) {
log.error("发送证书提醒通知失败:资质ID={}, 错误信息={}",
qualification.getQualificationId(), e.getMessage(), e);
}
}
@ -132,20 +138,84 @@ public class VetNotificationServiceImpl implements VetNotificationService {
return false;
}
// 添加 markAllAsRead 方法
/*@Override
public void markAllAsRead(Long userId) {
public void markAsRead(Long userId) {
try {
// 使用Mapper提供的方法批量标记为已读
int result = vetNotificationMapper.markAllNotificationsAsRead(userId);
log.info("用户ID={} 已将所有通知标记为已读,影响记录数={}", userId, result);
} catch (Exception e) {
log.error("标记所有通知为已读失败,用户ID={}", userId, e);
// 如果批量操作失败尝试逐条更新
fallbackMarkAllAsRead(userId);
}
}
*/
/**
* 回退方案逐条更新通知为已读
*/
private void fallbackMarkAllAsRead(Long userId) {
try {
VetNotification query = new VetNotification();
query.setUserId(userId);
List<VetNotification> notifications = vetNotificationMapper.selectVetNotificationList(query);
int count = 0;
for (VetNotification notification : notifications) {
if (notification.getIsRead() == 0) {
notification.setIsRead(1);
notification.setReadTime(new Date());
vetNotificationMapper.updateVetNotification(notification);
count++;
}
}
log.info("回退方案:用户ID={} 已成功标记{}个通知为已读", userId, count);
} catch (Exception e) {
log.error("回退方案标记通知为已读也失败,用户ID={}", userId, e);
}
}
/**
* 创建证书通知对象
*/
private VetNotification createCertificateNotification(VetQualification qualification,
VetQualification.CertificateInfo certificate,
String title, String content, int remindLevel) {
VetNotification notification = new VetNotification();
notification.setUserId(qualification.getUserId());
// 关联ID包含资质ID和证书ID
String relatedId = String.format("%d:%d",
qualification.getQualificationId(),
certificate.getCertificateId() != null ? certificate.getCertificateId() : 0L);
notification.setRelatedId(relatedId);
notification.setType("CERT_EXPIRE_REMIND");
notification.setTitle(title);
notification.setContent(content);
notification.setRemindLevel(remindLevel);
notification.setIsRead(0);
notification.setCreateTime(new Date());
notification.setCreateBy("system");
return notification;
}
/**
* 保存通知
*/
private void saveNotification(VetNotification notification) {
try {
int result = vetNotificationMapper.insertVetNotification(notification);
if (result > 0) {
log.info("成功发送证书提醒通知:用户ID={}, 标题={}",
notification.getUserId(), notification.getTitle());
}
} catch (Exception e) {
log.error("发送证书提醒通知失败:错误信息={}", e.getMessage(), e);
}
}
}*/
/**
* 计算两个日期之间的天数差忽略时间部分

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

@ -45,6 +45,15 @@ public class VetProductServiceImpl implements IVetProductService
@Override
public List<VetProduct> selectVetProductList(VetProduct vetProduct)
{
// 获取当前登录用户ID
try {
Long userId = SecurityUtils.getUserId();
// 设置查询条件只查询当前用户的产品
vetProduct.setUserId(userId);
} catch (Exception e) {
// 如果获取不到用户ID设置一个不存在的ID确保查询不到数据
vetProduct.setUserId(-1L);
}
return vetProductMapper.selectVetProductList(vetProduct);
}
@ -249,4 +258,18 @@ public class VetProductServiceImpl implements IVetProductService
return vetProductMapper.insertVetProduct(vetProduct);
}
/**
* 管理员查询所有兽医产品信息列表用于审核
*/
@Override
public List<VetProduct> selectAllVetProductList(VetProduct vetProduct)
{
// 管理员查询时不清除用户ID但可以查询所有数据
// 这里不设置用户ID让SQL查询所有产品
if (vetProduct != null) {
vetProduct.setUserId(null); // 清除用户ID条件
}
return vetProductMapper.selectVetProductList(vetProduct);
}
}

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

@ -70,12 +70,23 @@ public class VetQualificationServiceImpl implements IVetQualificationService {
*/
@Override
public int insertVetQualification(VetQualification vetQualification) {
// 准备保存前的处理
prepareQualificationForSave(vetQualification);
return vetQualificationMapper.insertVetQualification(vetQualification);
// 执行插入
int result = vetQualificationMapper.insertVetQualification(vetQualification);
// 成功插入后为用户分配兽医未审核角色
if (result > 0 && vetQualification.getUserId() != null) {
assignVetUnapprovedRole(vetQualification.getUserId());
}
return result;
}
/**
* 修改兽医资质
* 修改兽医资质 - 处理审核状态变更时的角色切换
*/
@Override
public int updateVetQualification(VetQualification vetQualification) {
@ -83,11 +94,18 @@ public class VetQualificationServiceImpl implements IVetQualificationService {
throw new ServiceException("资质ID不能为空");
}
VetQualification existing = vetQualificationMapper.selectVetQualificationByQualificationId(vetQualification.getQualificationId());
// 获取更新前的资质信息
VetQualification existing = vetQualificationMapper.selectVetQualificationByQualificationId(
vetQualification.getQualificationId()
);
if (existing == null) {
throw new ServiceException("资质信息不存在");
}
String oldStatus = existing.getAuditStatus();
String newStatus = vetQualification.getAuditStatus();
Long userId = existing.getUserId();
// 更新基本信息
updateBasicQualificationInfo(existing, vetQualification);
@ -101,9 +119,128 @@ public class VetQualificationServiceImpl implements IVetQualificationService {
// 更新证书状态
updateCertificateStatus(existing);
return vetQualificationMapper.updateVetQualification(existing);
int result = vetQualificationMapper.updateVetQualification(existing);
// 处理审核通过时的角色变更
if (result > 0 && userId != null && newStatus != null) {
handleRoleChangeOnAudit(userId, oldStatus, newStatus);
}
return result;
}
/**
* 为用户分配兽医未审核角色
*/
private void assignVetUnapprovedRole(Long userId) {
try {
// 检查是否已有兽医未审核角色
String checkSql = "SELECT COUNT(*) FROM sys_user_role WHERE user_id = ? AND role_id = 6";
Integer count = jdbcTemplate.queryForObject(checkSql, Integer.class, userId);
// 如果没有则分配兽医未审核角色
if (count == null || count == 0) {
String insertSql = "INSERT INTO sys_user_role (user_id, role_id) VALUES (?, 6)";
jdbcTemplate.update(insertSql, userId);
}
} catch (Exception e) {
// 忽略异常不影响主要业务
}
}
/**
* 处理审核状态变更时的角色切换
*/
private void handleRoleChangeOnAudit(Long userId, String oldStatus, String newStatus) {
try {
// 1. 审核通过状态变为1
if ("1".equals(newStatus)) {
changeRoleToVet(userId);
}
// 2. 审核不通过或待审核状态变为2或0且之前是通过状态
else if (("0".equals(newStatus) || "2".equals(newStatus)) && "1".equals(oldStatus)) {
changeRoleToVetUnapproved(userId);
}
} catch (Exception e) {
// 角色切换失败不影响主要业务
}
}
/**
* 切换为兽医角色审核通过
*/
private void changeRoleToVet(Long userId) {
try {
// 1. 先删除兽医未审核角色
String deleteUnapprovedSql = "DELETE FROM sys_user_role WHERE user_id = ? AND role_id = 6";
jdbcTemplate.update(deleteUnapprovedSql, userId);
// 2. 检查是否已有兽医角色
String checkVetSql = "SELECT COUNT(*) FROM sys_user_role WHERE user_id = ? AND role_id = 4";
Integer vetCount = jdbcTemplate.queryForObject(checkVetSql, Integer.class, userId);
// 3. 如果没有兽医角色则添加
if (vetCount == null || vetCount == 0) {
String addVetSql = "INSERT INTO sys_user_role (user_id, role_id) VALUES (?, 4)";
jdbcTemplate.update(addVetSql, userId);
}
} catch (Exception e) {
// 忽略异常
}
}
/* *//**
* 发送重新登录通知
*//*
private void sendReloginNotification(Long userId) {
try {
log.info("用户 {} 角色已变更,建议重新登录以刷新权限", userId);
String message = "您的兽医资质已审核通过,角色已更新为兽医。请重新登录系统以使用新角色的功能。";
log.info("通知消息: {}", message);
} catch (Exception e) {
log.warn("发送通知失败: {}", e.getMessage());
}
}*/
/**
* 清除用户权限缓存可选
*/
private void clearUserAuthorizationCache(Long userId) {
try {
// 根据你的缓存实现来清理
// 例如如果使用Redis清理对应的缓存key
} catch (Exception e) {
// 忽略异常
}
}
/**
* 切换为兽医未审核角色审核不通过或待审核
*/
private void changeRoleToVetUnapproved(Long userId) {
try {
// 1. 先删除兽医角色
String deleteVetSql = "DELETE FROM sys_user_role WHERE user_id = ? AND role_id = 4";
jdbcTemplate.update(deleteVetSql, userId);
// 2. 检查是否已有兽医未审核角色
String checkSql = "SELECT COUNT(*) FROM sys_user_role WHERE user_id = ? AND role_id = 6";
Integer unapprovedCount = jdbcTemplate.queryForObject(checkSql, Integer.class, userId);
// 3. 如果没有兽医未审核角色则添加
if (unapprovedCount == null || unapprovedCount == 0) {
String addSql = "INSERT INTO sys_user_role (user_id, role_id) VALUES (?, 6)";
jdbcTemplate.update(addSql, userId);
}
} catch (Exception e) {
// 忽略异常
}
}
/**
* 批量删除兽医资质
*/
@ -1019,4 +1156,9 @@ public class VetQualificationServiceImpl implements IVetQualificationService {
long diff = expireDate.getTime() - new Date().getTime();
return (int) (diff / (1000 * 60 * 60 * 24));
}
@Override
public VetQualification selectVetQualificationById(Long qualificationId) {
return vetQualificationMapper.selectVetQualificationById(qualificationId);
}
}

86
chenhai-system/src/main/resources/mapper/vet/MerchantInfoMapper.xml

@ -0,0 +1,86 @@
<?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.MerchantInfoMapper">
<resultMap type="MerchantInfo" id="MerchantInfoResult">
<result property="shopId" column="shop_id" />
<result property="shopName" column="shop_name" />
<result property="shopAddress" column="shop_address" />
<result property="phone" column="phone" />
<result property="userId" column="user_id" />
<result property="createdAt" column="created_at" />
<result property="updatedAt" column="updated_at" />
<result property="isActive" column="is_active" />
</resultMap>
<sql id="selectMerchantInfoVo">
select shop_id, shop_name, shop_address, phone, user_id, created_at, updated_at, is_active from merchant_info
</sql>
<select id="selectMerchantInfoList" parameterType="MerchantInfo" resultMap="MerchantInfoResult">
<include refid="selectMerchantInfoVo"/>
<where>
<if test="shopName != null and shopName != ''"> and shop_name like concat('%', #{shopName}, '%')</if>
<if test="shopAddress != null and shopAddress != ''"> and shop_address = #{shopAddress}</if>
<if test="phone != null and phone != ''"> and phone = #{phone}</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>
<if test="isActive != null "> and is_active = #{isActive}</if>
</where>
</select>
<select id="selectMerchantInfoByShopId" parameterType="Long" resultMap="MerchantInfoResult">
<include refid="selectMerchantInfoVo"/>
where shop_id = #{shopId}
</select>
<insert id="insertMerchantInfo" parameterType="MerchantInfo" useGeneratedKeys="true" keyProperty="shopId">
insert into merchant_info
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="shopName != null and shopName != ''">shop_name,</if>
<if test="shopAddress != null and shopAddress != ''">shop_address,</if>
<if test="phone != null">phone,</if>
<if test="userId != null">user_id,</if>
<if test="createdAt != null">created_at,</if>
<if test="updatedAt != null">updated_at,</if>
<if test="isActive != null">is_active,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="shopName != null and shopName != ''">#{shopName},</if>
<if test="shopAddress != null and shopAddress != ''">#{shopAddress},</if>
<if test="phone != null">#{phone},</if>
<if test="userId != null">#{userId},</if>
<if test="createdAt != null">#{createdAt},</if>
<if test="updatedAt != null">#{updatedAt},</if>
<if test="isActive != null">#{isActive},</if>
</trim>
</insert>
<update id="updateMerchantInfo" parameterType="MerchantInfo">
update merchant_info
<trim prefix="SET" suffixOverrides=",">
<if test="shopName != null and shopName != ''">shop_name = #{shopName},</if>
<if test="shopAddress != null and shopAddress != ''">shop_address = #{shopAddress},</if>
<if test="phone != null">phone = #{phone},</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>
<if test="isActive != null">is_active = #{isActive},</if>
</trim>
where shop_id = #{shopId}
</update>
<delete id="deleteMerchantInfoByShopId" parameterType="Long">
delete from merchant_info where shop_id = #{shopId}
</delete>
<delete id="deleteMerchantInfoByShopIds" parameterType="String">
delete from merchant_info where shop_id in
<foreach item="shopId" collection="array" open="(" separator="," close=")">
#{shopId}
</foreach>
</delete>
</mapper>

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

@ -29,95 +29,137 @@
<result property="publishTime" column="publish_time"/>
<result property="createTime" column="create_time"/>
<result property="updateTime" column="update_time"/>
<result property="userRole" column="user_role"/>
<result property="userType" column="user_type"/>
</resultMap>
<!-- 修改基础查询语句,始终从用户表获取用户信息 -->
<sql id="selectVetExperienceArticleVo">
select id, title, content, summary, cover_image, images, user_id, vet_name, vet_avatar, vet_title,
category_id, category_name, tags, view_count, like_count, collect_count,
is_top, is_featured, status, is_sensitive, sensitive_words, publish_time, create_time, update_time
from vet_experience_article
select
a.id,
a.title,
a.content, <!-- 富文本内容 -->
a.summary,
a.cover_image,
a.images,
a.user_id,
<!-- 始终从用户表获取用户信息 -->
COALESCE(u.nick_name, u.user_name) as vet_name, <!-- 用户姓名 -->
u.avatar as vet_avatar, <!-- 用户头像 -->
a.vet_title,
a.category_id,
a.category_name,
a.tags,
a.view_count,
a.like_count,
a.collect_count,
a.is_top,
a.is_featured,
a.status,
a.is_sensitive,
a.sensitive_words,
a.publish_time,
a.create_time,
a.update_time,
a.user_role,
a.user_type
from vet_experience_article a
left join sys_user u on a.user_id = u.user_id
</sql>
<!-- 查询兽医经验文章 -->
<select id="selectVetExperienceArticleById" parameterType="Long" resultMap="VetExperienceArticleResult">
<include refid="selectVetExperienceArticleVo"/>
where id = #{id}
where a.id = #{id} <!-- 添加表别名 a. -->
</select>
<!-- 查询兽医经验文章列表 -->
<!-- 查询兽医经验文章列表(已包含关联用户表) -->
<select id="selectVetExperienceArticleList" parameterType="VetExperienceArticle" resultMap="VetExperienceArticleResult">
<include refid="selectVetExperienceArticleVo"/>
<where>
<if test="title != null and title != ''"> and title like concat('%', #{title}, '%')</if>
<if test="userId != null"> and user_id = #{userId}</if>
<if test="vetName != null and vetName != ''"> and vet_name like concat('%', #{vetName}, '%')</if>
<if test="categoryId != null"> and category_id = #{categoryId}</if>
<if test="categoryName != null and categoryName != ''"> and category_name like concat('%', #{categoryName}, '%')</if>
<if test="status != null and status != ''"> and status = #{status}</if>
<if test="isTop != null and isTop != ''"> and is_top = #{isTop}</if>
<if test="isFeatured != null and isFeatured != ''"> and is_featured = #{isFeatured}</if>
<if test="isSensitive != null and isSensitive != ''"> and is_sensitive = #{isSensitive}</if>
<if test="title != null and title != ''"> and a.title like concat('%', #{title}, '%')</if>
<if test="userId != null"> and a.user_id = #{userId}</if>
<if test="vetName != null and vetName != ''"> and (a.vet_name like concat('%', #{vetName}, '%') or u.nick_name like concat('%', #{vetName}, '%'))</if>
<if test="categoryId != null"> and a.category_id = #{categoryId}</if>
<if test="categoryName != null and categoryName != ''"> and a.category_name like concat('%', #{categoryName}, '%')</if>
<if test="status != null and status != ''"> and a.status = #{status}</if>
<if test="isTop != null and isTop != ''"> and a.is_top = #{isTop}</if>
<if test="isFeatured != null and isFeatured != ''"> and a.is_featured = #{isFeatured}</if>
<if test="isSensitive != null and isSensitive != ''"> and a.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})
a.tags = #{tags}
or a.tags like concat(#{tags}, ',%')
or a.tags like concat('%,', #{tags}, ',%')
or a.tags like concat('%,', #{tags})
)
</if>
<if test="searchKey != null and searchKey != ''">
<bind name="searchKeyLike" value="'%' + searchKey + '%'" />
and (
a.title like #{searchKeyLike}
or a.content like #{searchKeyLike}
or a.summary like #{searchKeyLike}
or a.tags like #{searchKeyLike}
or a.category_name like #{searchKeyLike}
or a.vet_name like #{searchKeyLike}
or u.nick_name like #{searchKeyLike}
)
</if>
<if test="viewCount != null and viewCount != ''"> and a.view_count = #{viewCount}</if>
</where>
order by publish_time desc
order by a.publish_time desc
</select>
<!-- 根据条件查询文章列表(论坛专用) -->
<select id="selectArticlesByCondition" parameterType="map" resultMap="VetExperienceArticleResult">
<include refid="selectVetExperienceArticleVo"/>
<where>
status = #{status}
a.status = #{status}
<if test="keyword != null and keyword != ''">
and (
title like concat('%', #{keyword}, '%')
or content like concat('%', #{keyword}, '%')
or summary like concat('%', #{keyword}, '%')
or tags like concat('%', #{keyword}, '%')
a.title like concat('%', #{keyword}, '%')
or a.content like concat('%', #{keyword}, '%')
or a.summary like concat('%', #{keyword}, '%')
or a.tags like concat('%', #{keyword}, '%')
)
</if>
<if test="userId != null"> and user_id = #{userId}</if>
<if test="categoryId != null"> and category_id = #{categoryId}</if>
<if test="excludeId != null"> and id != #{excludeId}</if>
<if test="userId != null"> and a.user_id = #{userId}</if>
<if test="categoryId != null"> and a.category_id = #{categoryId}</if>
<if test="excludeId != null"> and a.id != #{excludeId}</if>
</where>
<!-- 先ORDER BY,后LIMIT -->
order by
<!-- ORDER BY必须在WHERE子句之后,LIMIT之前 -->
<choose>
<when test="orderBy != null and orderType != null">
${orderBy} ${orderType}
order by a.${orderBy} ${orderType}
</when>
<otherwise>
publish_time desc
order by a.publish_time desc
</otherwise>
</choose>
<!-- <if test="limit != null and limit > 0">
limit #{limit}
</if>-->
<!-- LIMIT必须在ORDER BY之后 -->
<!-- <if test="limit != null and limit > 0">-->
<!-- limit #{limit}-->
<!-- </if>-->
</select>
<!-- 搜索文章 -->
<select id="searchArticles" resultMap="VetExperienceArticleResult">
<include refid="selectVetExperienceArticleVo"/>
where status = #{status}
and (title like concat('%', #{keyword}, '%')
or content like concat('%', #{keyword}, '%')
or summary like concat('%', #{keyword}, '%'))
order by publish_time desc
where a.status = #{status}
and (a.title like concat('%', #{keyword}, '%')
or a.content like concat('%', #{keyword}, '%')
or a.summary like concat('%', #{keyword}, '%'))
order by a.publish_time desc
</select>
<!-- 增加浏览数 -->
<!-- &lt;!&ndash; 增加浏览数 &ndash;&gt;
<update id="incrementViewCount" parameterType="Long">
update vet_experience_article
set view_count = ifnull(view_count, 0) + 1,
update_time = now()
where id = #{id}
</update>
</update>-->
<!-- 增加点赞数 -->
<update id="incrementLikeCount" parameterType="Long">
@ -160,7 +202,9 @@
<if test="isSensitive != null">is_sensitive,</if>
<if test="sensitiveWords != null">sensitive_words,</if>
<if test="publishTime != null">publish_time,</if>
create_time,
<if test="userRole != null and userRole != ''">user_role,</if>
<if test="userType != null and userType != ''">user_type,</if>
create_time, <!-- 固定字段放在最后 -->
<if test="updateTime != null">update_time,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
@ -185,7 +229,9 @@
<if test="isSensitive != null">#{isSensitive},</if>
<if test="sensitiveWords != null">#{sensitiveWords},</if>
<if test="publishTime != null">#{publishTime},</if>
now(),
<if test="userRole != null and userRole != ''">#{userRole},</if>
<if test="userType != null and userType != ''">#{userType},</if>
now(), <!-- 对应create_time -->
<if test="updateTime != null">#{updateTime},</if>
</trim>
</insert>
@ -215,11 +261,12 @@
<if test="isSensitive != null">is_sensitive = #{isSensitive},</if>
<if test="sensitiveWords != null">sensitive_words = #{sensitiveWords},</if>
<if test="publishTime != null">publish_time = #{publishTime},</if>
<if test="userRole != null and userRole != ''">user_role = #{userRole},</if>
<if test="userType != null and userType != ''">user_type = #{userType},</if>
update_time = now(),
</trim>
where id = #{id}
</update>
<!-- 删除兽医经验文章 -->
<delete id="deleteVetExperienceArticleById" parameterType="Long">
delete from vet_experience_article where id = #{id}

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

@ -246,4 +246,9 @@
</if>
LIMIT 1
</select>
<select id="selectVetQualificationById" parameterType="Long" resultMap="VetQualificationResult">
<include refid="selectVetQualificationVo"/>
where qualification_id = #{qualificationId}
</select>
</mapper>

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

@ -0,0 +1,44 @@
import request from '@/utils/request'
// 查询商家信息列表
export function listMerchant(query) {
return request({
url: '/vet/merchant/list',
method: 'get',
params: query
})
}
// 查询商家信息详细
export function getMerchant(shopId) {
return request({
url: '/vet/merchant/' + shopId,
method: 'get'
})
}
// 新增商家信息
export function addMerchant(data) {
return request({
url: '/vet/merchant',
method: 'post',
data: data
})
}
// 修改商家信息
export function updateMerchant(data) {
return request({
url: '/vet/merchant',
method: 'put',
data: data
})
}
// 删除商家信息
export function delMerchant(shopId) {
return request({
url: '/vet/merchant/' + shopId,
method: 'delete'
})
}

362
chenhai-ui/src/views/vet/merchant/index.vue

@ -0,0 +1,362 @@
<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="shopName">
<el-input
v-model="queryParams.shopName"
placeholder="请输入店铺名称"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="店铺地址" prop="shopAddress">
<el-input
v-model="queryParams.shopAddress"
placeholder="请输入店铺地址"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="联系电话" prop="phone">
<el-input
v-model="queryParams.phone"
placeholder="请输入联系电话"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<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="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 label="是否启用" prop="isActive">
<el-input
v-model="queryParams.isActive"
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>
</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:merchant: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:merchant: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:merchant: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:merchant:export']"
>导出</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="merchantList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="店铺ID,主键" align="center" prop="shopId" />
<el-table-column label="店铺名称" align="center" prop="shopName" />
<el-table-column label="店铺地址" align="center" prop="shopAddress" />
<el-table-column label="联系电话" align="center" prop="phone" />
<el-table-column label="关联用户ID" align="center" prop="userId" />
<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" prop="isActive" />
<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:merchant:edit']"
>修改</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
v-hasPermi="['vet:merchant: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="shopName">
<el-input v-model="form.shopName" placeholder="请输入店铺名称" />
</el-form-item>
<el-form-item label="店铺地址" prop="shopAddress">
<el-input v-model="form.shopAddress" placeholder="请输入店铺地址" />
</el-form-item>
<el-form-item label="联系电话" prop="phone">
<el-input v-model="form.phone" placeholder="请输入联系电话" />
</el-form-item>
<el-form-item label="关联用户ID" prop="userId">
<el-input v-model="form.userId" 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-item label="是否启用" prop="isActive">
<el-input v-model="form.isActive" placeholder="请输入是否启用" />
</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 { listMerchant, getMerchant, delMerchant, addMerchant, updateMerchant } from "@/api/vet/merchant"
export default {
name: "Merchant",
data() {
return {
//
loading: true,
//
ids: [],
//
single: true,
//
multiple: true,
//
showSearch: true,
//
total: 0,
//
merchantList: [],
//
title: "",
//
open: false,
//
queryParams: {
pageNum: 1,
pageSize: 10,
shopName: null,
shopAddress: null,
phone: null,
userId: null,
createdAt: null,
updatedAt: null,
isActive: null
},
//
form: {},
//
rules: {
shopName: [
{ required: true, message: "店铺名称不能为空", trigger: "blur" }
],
shopAddress: [
{ required: true, message: "店铺地址不能为空", trigger: "blur" }
],
userId: [
{ required: true, message: "关联用户ID不能为空", trigger: "blur" }
],
createdAt: [
{ required: true, message: "创建时间不能为空", trigger: "blur" }
],
updatedAt: [
{ required: true, message: "更新时间不能为空", trigger: "blur" }
],
}
}
},
created() {
this.getList()
},
methods: {
/** 查询商家信息列表 */
getList() {
this.loading = true
listMerchant(this.queryParams).then(response => {
this.merchantList = response.rows
this.total = response.total
this.loading = false
})
},
//
cancel() {
this.open = false
this.reset()
},
//
reset() {
this.form = {
shopId: null,
shopName: null,
shopAddress: null,
phone: null,
userId: null,
createdAt: null,
updatedAt: null,
isActive: 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.shopId)
this.single = selection.length!==1
this.multiple = !selection.length
},
/** 新增按钮操作 */
handleAdd() {
this.reset()
this.open = true
this.title = "添加商家信息"
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset()
const shopId = row.shopId || this.ids
getMerchant(shopId).then(response => {
this.form = response.data
this.open = true
this.title = "修改商家信息"
})
},
/** 提交按钮 */
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.shopId != null) {
updateMerchant(this.form).then(response => {
this.$modal.msgSuccess("修改成功")
this.open = false
this.getList()
})
} else {
addMerchant(this.form).then(response => {
this.$modal.msgSuccess("新增成功")
this.open = false
this.getList()
})
}
}
})
},
/** 删除按钮操作 */
handleDelete(row) {
const shopIds = row.shopId || this.ids
this.$modal.confirm('是否确认删除商家信息编号为"' + shopIds + '"的数据项?').then(function() {
return delMerchant(shopIds)
}).then(() => {
this.getList()
this.$modal.msgSuccess("删除成功")
}).catch(() => {})
},
/** 导出按钮操作 */
handleExport() {
this.download('vet/merchant/export', {
...this.queryParams
}, `merchant_${new Date().getTime()}.xlsx`)
}
}
}
</script>
Loading…
Cancel
Save