From 981497099a41ed8c7a28d4cf81f0851f1dfe3b44 Mon Sep 17 00:00:00 2001 From: zxf <1532322479@qq.com> Date: Sat, 13 Jun 2026 14:08:47 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BF=AE=E6=94=B9=E8=8F=9C=E5=8D=95?= =?UTF-8?q?=E7=82=B9=E8=B5=9E=E7=9B=B8=E5=85=B3=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- admin/src/api/wechat.js | 13 +++++ .../views/pm/complaint/suggestion/index.vue | 33 +++++++++++- .../controller/WeChatAdminController.java | 51 ++++++++++++++++++ .../PmDailyMenuDtlLikeController.java | 54 ++++++++++--------- .../entity/PmDailyMenuDtlLike.java | 7 ++- .../front/controller/WeChatController.java | 3 ++ 6 files changed, 134 insertions(+), 27 deletions(-) create mode 100644 admin/src/api/wechat.js diff --git a/admin/src/api/wechat.js b/admin/src/api/wechat.js new file mode 100644 index 0000000..52e6a1b --- /dev/null +++ b/admin/src/api/wechat.js @@ -0,0 +1,13 @@ +import request from '@/utils/request' + +/** + * 发送一次性订阅消息 + * @param params + */ +export function sendSubscribeMessageApi(params) { + return request({ + url: `admin/wechat/subscribe/message/send`, + method: 'POST', + params + }) +} diff --git a/admin/src/views/pm/complaint/suggestion/index.vue b/admin/src/views/pm/complaint/suggestion/index.vue index 2f9869b..398c159 100644 --- a/admin/src/views/pm/complaint/suggestion/index.vue +++ b/admin/src/views/pm/complaint/suggestion/index.vue @@ -191,6 +191,7 @@ import * as api from '@/api/pmcomplaintsuggestion.js' import * as ownerApi from '@/api/pmowner.js' import * as houseApi from '@/api/pmhouse.js' + import * as wechatApi from '@/api/wechat.js' import DictTag from '@/components/DictTag' export default { dicts: ['owner_type', 'cs_type', 'submit_channel', 'suggestion_status'], @@ -367,12 +368,12 @@ }, // 处理投诉/建议,将状态修改为已处理(3) handleComplaint (id) { - this.$confirm('确定要将该投诉/建议标记为已处理吗?', '提示', { + this.$confirm('确定要将该投诉/建议标记为已处理吗?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => { - // 调用更新状态API + // 调用更新状态 API api.pmcomplaintsuggestionUpdateApi({ id: id, status: '3' @@ -384,6 +385,34 @@ }) }).catch(() => {}) }, + // 测试微信推送消息 + testWechatMessage () { + this.$confirm('确定要发送测试微信消息吗?(固定测试用户:obahy2fytF_nhWznyc4ihUzQtPZ0)', '提示', { + confirmButtonText: '确定', + cancelButtonText: '取消', + type: 'warning' + }).then(() => { + // 调用微信推送 API + const params = { + unionId: 'obahy2fytF_nhWznyc4ihUzQtPZ0', + templateId: 'TEMPLATE_ID', // 请替换为实际的订阅消息模板 ID + scene: '1000', + title: '测试通知', + content: '这是一条测试消息,请忽略。' + } + + // 使用 API 文件 + wechatApi.sendSubscribeMessageApi(params).then(res => { + if (res.code === 200) { + this.$message.success('发送成功,请查看微信!') + } else { + this.$message.error(res.message || '发送失败') + } + }).catch(err => { + this.$message.error('发送失败:' + (err.message || '未知错误')) + }) + }).catch(() => {}) + }, } } diff --git a/crmeb/crmeb-admin/src/main/java/com/zbkj/admin/controller/WeChatAdminController.java b/crmeb/crmeb-admin/src/main/java/com/zbkj/admin/controller/WeChatAdminController.java index 675ddc9..6ca31b1 100644 --- a/crmeb/crmeb-admin/src/main/java/com/zbkj/admin/controller/WeChatAdminController.java +++ b/crmeb/crmeb-admin/src/main/java/com/zbkj/admin/controller/WeChatAdminController.java @@ -1,10 +1,20 @@ +/* + * @Author: zxf 1532322479@qq.com + * @Date: 2025-06-21 12:18:44 + * @LastEditors: zxf 1532322479@qq.com + * @LastEditTime: 2026-05-20 14:48:26 + * @FilePath: \crmebTwo\crmeb\crmeb-admin\src\main\java\com\zbkj\admin\controller\WeChatAdminController.java + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ package com.zbkj.admin.controller; import com.zbkj.common.response.CommonResult; import com.zbkj.common.response.WeChatJsSdkConfigResponse; +import com.zbkj.service.service.WechatFansService; import com.zbkj.service.service.WechatNewService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -14,6 +24,8 @@ import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +import javax.annotation.security.PermitAll; + /** * 微信 -- 开放平台 admin * +---------------------------------------------------------------------- @@ -35,6 +47,9 @@ public class WeChatAdminController { @Autowired private WechatNewService wechatNewService; + @Autowired + private WechatFansService wechatFansService; + /** * 获取微信公众号js配置 */ @@ -45,4 +60,40 @@ public class WeChatAdminController { public CommonResult configJs(@RequestParam(value = "url") String url) { return CommonResult.success(wechatNewService.getJsSdkConfig(url)); } + + /** + * 发送一次性订阅消息 + * 通过unionId获取公众号openId,然后发送订阅消息 + */ + @ApiOperation(value = "发送一次性订阅消息") + @RequestMapping(value = "/subscribe/message/send", method = RequestMethod.POST) + @PermitAll + @ApiImplicitParams({ + @ApiImplicitParam(name = "unionId", value = "用户unionId", dataType = "String", required = true), + @ApiImplicitParam(name = "templateId", value = "订阅消息模板ID", dataType = "String", required = true), + @ApiImplicitParam(name = "scene", value = "订阅场景值", dataType = "String", required = true), + @ApiImplicitParam(name = "title", value = "消息标题(15字以内)", dataType = "String", required = true), + @ApiImplicitParam(name = "content", value = "消息内容(200字以内)", dataType = "String", required = true), + @ApiImplicitParam(name = "url", value = "跳转链接(需ICP备案)", dataType = "String") + }) + public CommonResult sendSubscribeMessage(@RequestParam(value = "unionId") String unionId, + @RequestParam(value = "templateId") String templateId, + @RequestParam(value = "scene") String scene, + @RequestParam(value = "title") String title, + @RequestParam(value = "content") String content, + @RequestParam(value = "url", required = false) String url){ + // 通过unionId获取公众号openId + String openId = wechatFansService.getOpenIdByUnionId(unionId); + if (openId == null) { + return CommonResult.failed("未找到该用户的公众号openId"); + } + + // 发送订阅消息 + boolean success = wechatFansService.sendSubscribeMessage(openId, templateId, scene, title, content, url); + if (success) { + return CommonResult.success(true, "发送成功"); + } else { + return CommonResult.failed("发送失败"); + } + } } diff --git a/crmeb/crmeb-admin/src/main/java/com/zbkj/modules/autogencode/controller/PmDailyMenuDtlLikeController.java b/crmeb/crmeb-admin/src/main/java/com/zbkj/modules/autogencode/controller/PmDailyMenuDtlLikeController.java index 6fab293..2e95bf8 100644 --- a/crmeb/crmeb-admin/src/main/java/com/zbkj/modules/autogencode/controller/PmDailyMenuDtlLikeController.java +++ b/crmeb/crmeb-admin/src/main/java/com/zbkj/modules/autogencode/controller/PmDailyMenuDtlLikeController.java @@ -229,7 +229,7 @@ public class PmDailyMenuDtlLikeController { return CommonResult.failed("菜单明细不存在"); } - // 通过PmDailyMenu 获取菜单日期 + // 通过PmDailyMenu 获取菜单日期和餐别 PmDailyMenu menu = pmDailyMenuService.getById(menuDtl.getMenuId()); if (menu == null) { return CommonResult.failed("菜单不存在"); @@ -240,6 +240,11 @@ public class PmDailyMenuDtlLikeController { return CommonResult.failed("菜单日期不存在"); } + String mealType = menu.getMealType(); + if (StrUtil.isBlank(mealType)) { + return CommonResult.failed("餐别不存在"); + } + // 检查是否已经对该菜单明细进行过评价 LambdaQueryWrapper existQueryWrapper = new LambdaQueryWrapper<>(); existQueryWrapper.eq(PmDailyMenuDtlLike::getUserId, userId); @@ -252,16 +257,17 @@ public class PmDailyMenuDtlLikeController { return CommonResult.failed("已经对该菜品进行过" + ("1".equals(likeType) ? "点赞" : "点踩")); } - // 检查用户在该日期的评价次数 + // 检查用户在该日期、该餐别的评价次数 LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(PmDailyMenuDtlLike::getUserId, userId); queryWrapper.eq(PmDailyMenuDtlLike::getMenuDate, menuDate); + queryWrapper.eq(PmDailyMenuDtlLike::getMealType, mealType); queryWrapper.eq(PmDailyMenuDtlLike::getLikeType, likeType); queryWrapper.eq(PmDailyMenuDtlLike::getDelFlag, "0"); int count = pmDailyMenuDtlLikeService.count(queryWrapper); if (count >= 3) { - return CommonResult.failed("同一日期内" + ("1".equals(likeType) ? "点赞" : "点踩") + "次数已达上限(3次)"); + return CommonResult.failed("同一日期同一餐别内" + ("1".equals(likeType) ? "点赞" : "点踩") + "次数已达上限(3次)"); } // 保存点赞/点踩记录 @@ -269,6 +275,7 @@ public class PmDailyMenuDtlLikeController { like.setMenuDtlId(menuDtlId); like.setUserId(userId); like.setMenuDate(menuDate); + like.setMealType(mealType); like.setLikeType(likeType); like.setRemark(remark); like.setDelFlag("0"); @@ -454,33 +461,32 @@ public class PmDailyMenuDtlLikeController { }); } - // 计算总记录数 + // 分页处理 int total = rankingList.size(); - - // 实现真正的分页 - int startIndex = (page - 1) * limit; - int endIndex = Math.min(startIndex + limit, total); - List pageList; - if (startIndex >= total) { - pageList = new ArrayList<>(); - } else { - pageList = rankingList.subList(startIndex, endIndex); + int fromIndex = (page - 1) * limit; + int toIndex = Math.min(fromIndex + limit, total); + + if (fromIndex >= total) { + // 如果起始索引超出范围,返回空列表 + CommonPage emptyPage = new CommonPage<>(); + emptyPage.setList(new ArrayList<>()); + emptyPage.setTotal((long) total); + emptyPage.setPage(page); + emptyPage.setLimit(limit); + return CommonResult.success(emptyPage); } - // 构建分页对象 - CommonPage pageResult = new CommonPage<>(); - pageResult.setList(pageList); - pageResult.setTotal((long) total); - pageResult.setPage(page); - pageResult.setLimit(limit); - - return CommonResult.success(pageResult); + List pageList = rankingList.subList(fromIndex, toIndex); + CommonPage resultPage = new CommonPage<>(); + resultPage.setList(pageList); + resultPage.setTotal((long) total); + resultPage.setPage(page); + resultPage.setLimit(limit); + + return CommonResult.success(resultPage); } catch (Exception e) { e.printStackTrace(); return CommonResult.failed("查询失败:" + e.getMessage()); } } - } - - diff --git a/crmeb/crmeb-admin/src/main/java/com/zbkj/modules/autogencode/entity/PmDailyMenuDtlLike.java b/crmeb/crmeb-admin/src/main/java/com/zbkj/modules/autogencode/entity/PmDailyMenuDtlLike.java index f15d196..d1bf756 100644 --- a/crmeb/crmeb-admin/src/main/java/com/zbkj/modules/autogencode/entity/PmDailyMenuDtlLike.java +++ b/crmeb/crmeb-admin/src/main/java/com/zbkj/modules/autogencode/entity/PmDailyMenuDtlLike.java @@ -120,11 +120,16 @@ public class PmDailyMenuDtlLike implements Serializable { @ApiModelProperty(value = "备注") private String remark; + /** + * 餐别(冗余字段,方便按餐别统计) + */ + @ApiModelProperty(value = "餐别") + private String mealType; + /** * 用户名称(虚拟字段) */ @ApiModelProperty(value = "用户名称") @TableField(exist = false) private String userName; - } diff --git a/crmeb/crmeb-front/src/main/java/com/zbkj/front/controller/WeChatController.java b/crmeb/crmeb-front/src/main/java/com/zbkj/front/controller/WeChatController.java index d6efd6f..bddabd8 100644 --- a/crmeb/crmeb-front/src/main/java/com/zbkj/front/controller/WeChatController.java +++ b/crmeb/crmeb-front/src/main/java/com/zbkj/front/controller/WeChatController.java @@ -16,11 +16,13 @@ import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParams; import io.swagger.annotations.ApiOperation; +import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import javax.annotation.security.PermitAll; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -148,6 +150,7 @@ public class WeChatController { */ @ApiOperation(value = "发送一次性订阅消息") @RequestMapping(value = "/subscribe/message/send", method = RequestMethod.POST) + @PermitAll @ApiImplicitParams({ @ApiImplicitParam(name = "unionId", value = "用户unionId", dataType = "String", required = true), @ApiImplicitParam(name = "templateId", value = "订阅消息模板ID", dataType = "String", required = true),