mirror of
https://gitee.com/huangge1199_admin/vue-pro.git
synced 2024-11-22 07:11:52 +08:00
mp:完善微信公众号的消息
This commit is contained in:
parent
6fc0b3fc54
commit
68ef11ee87
@ -15,8 +15,8 @@ public interface ErrorCodeConstants {
|
|||||||
ErrorCode ACCOUNT_CLEAR_QUOTA_FAIL = new ErrorCode(1006000001, "清空公众号的 API 配额失败,原因:{}");
|
ErrorCode ACCOUNT_CLEAR_QUOTA_FAIL = new ErrorCode(1006000001, "清空公众号的 API 配额失败,原因:{}");
|
||||||
|
|
||||||
// ========== 公众号统计 1006001000============
|
// ========== 公众号统计 1006001000============
|
||||||
ErrorCode STATISTICS_GET_USER_SUMMARY_FAIL = new ErrorCode(1006001000, "获取用户增减数据失败,原因:{}");
|
ErrorCode STATISTICS_GET_USER_SUMMARY_FAIL = new ErrorCode(1006001000, "获取粉丝增减数据失败,原因:{}");
|
||||||
ErrorCode STATISTICS_GET_USER_CUMULATE_FAIL = new ErrorCode(1006001001, "获得用户累计数据失败,原因:{}");
|
ErrorCode STATISTICS_GET_USER_CUMULATE_FAIL = new ErrorCode(1006001001, "获得粉丝累计数据失败,原因:{}");
|
||||||
ErrorCode STATISTICS_GET_UPSTREAM_MESSAGE_FAIL = new ErrorCode(1006001002, "获得消息发送概况数据失败,原因:{}");
|
ErrorCode STATISTICS_GET_UPSTREAM_MESSAGE_FAIL = new ErrorCode(1006001002, "获得消息发送概况数据失败,原因:{}");
|
||||||
ErrorCode STATISTICS_GET_INTERFACE_SUMMARY_FAIL = new ErrorCode(1006001003, "获得接口分析数据失败,原因:{}");
|
ErrorCode STATISTICS_GET_INTERFACE_SUMMARY_FAIL = new ErrorCode(1006001003, "获得接口分析数据失败,原因:{}");
|
||||||
|
|
||||||
@ -28,8 +28,8 @@ public interface ErrorCodeConstants {
|
|||||||
ErrorCode TAG_GET_FAIL = new ErrorCode(1006002001, "获得标签失败,原因:{}");
|
ErrorCode TAG_GET_FAIL = new ErrorCode(1006002001, "获得标签失败,原因:{}");
|
||||||
|
|
||||||
// ========== 公众号粉丝 1006003000============
|
// ========== 公众号粉丝 1006003000============
|
||||||
ErrorCode USER_NOT_EXISTS = new ErrorCode(1006003000, "用户不存在");
|
ErrorCode USER_NOT_EXISTS = new ErrorCode(1006003000, "粉丝不存在");
|
||||||
ErrorCode USER_UPDATE_TAG_FAIL = new ErrorCode(1006003001, "更新用户标签失败,原因:{}");
|
ErrorCode USER_UPDATE_TAG_FAIL = new ErrorCode(1006003001, "更新粉丝标签失败,原因:{}");
|
||||||
|
|
||||||
// ========== 公众号素材 1006004000============
|
// ========== 公众号素材 1006004000============
|
||||||
ErrorCode MATERIAL_NOT_EXISTS = new ErrorCode(1006004000, "素材不存在");
|
ErrorCode MATERIAL_NOT_EXISTS = new ErrorCode(1006004000, "素材不存在");
|
||||||
|
@ -12,8 +12,8 @@ import lombok.Getter;
|
|||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public enum MpMessageSendFromEnum {
|
public enum MpMessageSendFromEnum {
|
||||||
|
|
||||||
USER_TO_MP(1, "用户发送给公众号"),
|
USER_TO_MP(1, "粉丝发送给公众号"),
|
||||||
MP_TO_USER(2, "公众号发给用户"),
|
MP_TO_USER(2, "公众号发给粉丝"),
|
||||||
;
|
;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -14,7 +14,7 @@ import java.util.List;
|
|||||||
import static cn.iocoder.yudao.module.mp.framework.mp.core.util.MpUtils.*;
|
import static cn.iocoder.yudao.module.mp.framework.mp.core.util.MpUtils.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 微信菜单 Base VO,提供给添加、修改、详细的子 VO 使用
|
* 公众号菜单 Base VO,提供给添加、修改、详细的子 VO 使用
|
||||||
* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
|
* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
|
@ -1,34 +1,26 @@
|
|||||||
package cn.iocoder.yudao.module.mp.controller.admin.menu.vo;
|
package cn.iocoder.yudao.module.mp.controller.admin.menu.vo;
|
||||||
|
|
||||||
import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO;
|
|
||||||
import io.swagger.annotations.ApiModel;
|
import io.swagger.annotations.ApiModel;
|
||||||
import io.swagger.annotations.ApiModelProperty;
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
|
||||||
import javax.validation.constraints.NotNull;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
// TODO swagger 文档
|
@ApiModel("管理后台 - 公众号菜单 Response VO")
|
||||||
@ApiModel("管理后台 - 微信菜单 Response VO")
|
|
||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
public class MpMenuRespVO extends MpMenuBaseVO {
|
public class MpMenuRespVO extends MpMenuBaseVO {
|
||||||
|
|
||||||
@ApiModelProperty(value = "主键", required = true)
|
@ApiModelProperty(value = "主键", required = true, example = "1024")
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
@ApiModelProperty(value = "公众号账号的编号", required = true, example = "2048")
|
@ApiModelProperty(value = "公众号账号的编号", required = true, example = "2048")
|
||||||
@NotNull(message = "公众号账号的编号不能为空")
|
|
||||||
private Long accountId;
|
private Long accountId;
|
||||||
|
|
||||||
/**
|
@ApiModelProperty(value = "公众号 appId", required = true, example = "wx1234567890ox")
|
||||||
* 微信公众号 appid
|
|
||||||
*
|
|
||||||
* 冗余 {@link MpAccountDO#getAppId()}
|
|
||||||
*/
|
|
||||||
private String appId;
|
private String appId;
|
||||||
|
|
||||||
@ApiModelProperty(value = "创建时间", required = true)
|
@ApiModelProperty(value = "创建时间", required = true)
|
||||||
|
@ -9,7 +9,6 @@ import javax.validation.constraints.NotEmpty;
|
|||||||
import javax.validation.constraints.NotNull;
|
import javax.validation.constraints.NotNull;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
// TODO 芋艿:swagger 文档
|
|
||||||
@ApiModel("管理后台 - 公众号菜单保存 Request VO")
|
@ApiModel("管理后台 - 公众号菜单保存 Request VO")
|
||||||
@Data
|
@Data
|
||||||
public class MpMenuSaveReqVO {
|
public class MpMenuSaveReqVO {
|
||||||
@ -22,9 +21,13 @@ public class MpMenuSaveReqVO {
|
|||||||
@Valid
|
@Valid
|
||||||
private List<Menu> menus;
|
private List<Menu> menus;
|
||||||
|
|
||||||
|
@ApiModel("管理后台 - 公众号菜单保存时的每个菜单")
|
||||||
@Data
|
@Data
|
||||||
public static class Menu extends MpMenuBaseVO {
|
public static class Menu extends MpMenuBaseVO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 子菜单数组
|
||||||
|
*/
|
||||||
private List<Menu> children;
|
private List<Menu> children;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ public class MpAutoReplyController {
|
|||||||
|
|
||||||
@GetMapping("/get")
|
@GetMapping("/get")
|
||||||
@ApiOperation("获得公众号自动回复")
|
@ApiOperation("获得公众号自动回复")
|
||||||
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024")
|
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
|
||||||
@PreAuthorize("@ss.hasPermission('mp:auto-reply:query')")
|
@PreAuthorize("@ss.hasPermission('mp:auto-reply:query')")
|
||||||
public CommonResult<MpAutoReplyRespVO> getAutoReply(@RequestParam("id") Long id) {
|
public CommonResult<MpAutoReplyRespVO> getAutoReply(@RequestParam("id") Long id) {
|
||||||
MpAutoReplyDO autoReply = mpAutoReplyService.getAutoReply(id);
|
MpAutoReplyDO autoReply = mpAutoReplyService.getAutoReply(id);
|
||||||
|
@ -29,10 +29,10 @@ public class MpMessageController {
|
|||||||
private MpMessageService mpMessageService;
|
private MpMessageService mpMessageService;
|
||||||
|
|
||||||
@GetMapping("/page")
|
@GetMapping("/page")
|
||||||
@ApiOperation("获得粉丝消息分页")
|
@ApiOperation("获得公众号消息分页")
|
||||||
@PreAuthorize("@ss.hasPermission('mp:message:query')")
|
@PreAuthorize("@ss.hasPermission('mp:message:query')")
|
||||||
public CommonResult<PageResult<MpMessageRespVO>> getWxFansMsgPage(@Valid MpMessagePageReqVO pageVO) {
|
public CommonResult<PageResult<MpMessageRespVO>> getMessagePage(@Valid MpMessagePageReqVO pageVO) {
|
||||||
PageResult<MpMessageDO> pageResult = mpMessageService.getWxFansMsgPage(pageVO);
|
PageResult<MpMessageDO> pageResult = mpMessageService.getMessagePage(pageVO);
|
||||||
return success(MpMessageConvert.INSTANCE.convertPage(pageResult));
|
return success(MpMessageConvert.INSTANCE.convertPage(pageResult));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,8 +14,8 @@ import javax.validation.constraints.NotNull;
|
|||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
public class MpAutoReplyCreateReqVO extends MpAutoReplyBaseVO {
|
public class MpAutoReplyCreateReqVO extends MpAutoReplyBaseVO {
|
||||||
|
|
||||||
@ApiModelProperty(value = "微信公众号 ID", required = true, example = "1024")
|
@ApiModelProperty(value = "公众号账号的编号", required = true, example = "1024")
|
||||||
@NotNull(message = "微信公众号 ID不能为空")
|
@NotNull(message = "公众号账号的编号不能为空")
|
||||||
private Long accountId;
|
private Long accountId;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -17,9 +17,9 @@ public class MpAutoReplyRespVO extends MpAutoReplyBaseVO {
|
|||||||
@ApiModelProperty(value = "主键", required = true, example = "1024")
|
@ApiModelProperty(value = "主键", required = true, example = "1024")
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
@ApiModelProperty(value = "微信公众号 ID", required = true, example = "1024")
|
@ApiModelProperty(value = "公众号账号的编号", required = true, example = "1024")
|
||||||
private Long accountId;
|
private Long accountId;
|
||||||
@ApiModelProperty(value = "微信公众号 appid", required = true, example = "wx1234567890")
|
@ApiModelProperty(value = "公众号 appId", required = true, example = "wx1234567890")
|
||||||
private String appId;
|
private String appId;
|
||||||
|
|
||||||
@ApiModelProperty(value = "创建时间", required = true)
|
@ApiModelProperty(value = "创建时间", required = true)
|
||||||
|
@ -1,193 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.mp.controller.admin.message.vo.message;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO;
|
|
||||||
import cn.iocoder.yudao.module.mp.dal.dataobject.message.MpMessageDO;
|
|
||||||
import cn.iocoder.yudao.module.mp.dal.dataobject.user.MpUserDO;
|
|
||||||
import cn.iocoder.yudao.module.mp.enums.message.MpMessageSendFromEnum;
|
|
||||||
import com.baomidou.mybatisplus.annotation.TableField;
|
|
||||||
import lombok.Data;
|
|
||||||
import me.chanjar.weixin.common.api.WxConsts;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
// TODO 芋艿:VO 的注解
|
|
||||||
/**
|
|
||||||
* 粉丝消息 Base VO,提供给添加、修改、详细的子 VO 使用
|
|
||||||
* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class MpMessageBaseVO {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 微信公众号消息 id
|
|
||||||
*/
|
|
||||||
private Long msgId;
|
|
||||||
/**
|
|
||||||
* 微信公众号 ID
|
|
||||||
*
|
|
||||||
* 关联 {@link MpAccountDO#getId()}
|
|
||||||
*/
|
|
||||||
private Long accountId;
|
|
||||||
/**
|
|
||||||
* 微信公众号 appid
|
|
||||||
*
|
|
||||||
* 冗余 {@link MpAccountDO#getAppId()}
|
|
||||||
*/
|
|
||||||
private String appId;
|
|
||||||
/**
|
|
||||||
* 微信用户编号
|
|
||||||
*
|
|
||||||
* 关联 {@link MpUserDO#getId()}
|
|
||||||
*/
|
|
||||||
private Long userId;
|
|
||||||
/**
|
|
||||||
* 用户标识
|
|
||||||
*
|
|
||||||
* 冗余 {@link MpUserDO#getOpenid()}
|
|
||||||
*/
|
|
||||||
private String openid;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 消息类型
|
|
||||||
*
|
|
||||||
* 枚举 {@link WxConsts.XmlMsgType}
|
|
||||||
*/
|
|
||||||
private String type;
|
|
||||||
/**
|
|
||||||
* 消息来源
|
|
||||||
*
|
|
||||||
* 枚举 {@link MpMessageSendFromEnum}
|
|
||||||
*/
|
|
||||||
private Integer sendFrom;
|
|
||||||
|
|
||||||
// ========= 普通消息内容 https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Receiving_standard_messages.html
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 消息内容
|
|
||||||
*
|
|
||||||
* 消息类型为 {@link WxConsts.XmlMsgType} 的 TEXT
|
|
||||||
*/
|
|
||||||
private String content;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 通过素材管理中的接口上传多媒体文件,得到的 id
|
|
||||||
*
|
|
||||||
* 消息类型为 {@link WxConsts.XmlMsgType} 的 IMAGE、VOICE、VIDEO
|
|
||||||
*/
|
|
||||||
private String mediaId;
|
|
||||||
/**
|
|
||||||
* 媒体文件的 URL
|
|
||||||
*/
|
|
||||||
private String mediaUrl;
|
|
||||||
/**
|
|
||||||
* 语音识别后文本
|
|
||||||
*
|
|
||||||
* 消息类型为 {@link WxConsts.XmlMsgType} 的 VOICE
|
|
||||||
*/
|
|
||||||
private String recognition;
|
|
||||||
/**
|
|
||||||
* 语音格式,如 amr,speex 等
|
|
||||||
*
|
|
||||||
* 消息类型为 {@link WxConsts.XmlMsgType} 的 VOICE
|
|
||||||
*/
|
|
||||||
private String format;
|
|
||||||
/**
|
|
||||||
* 标题
|
|
||||||
*
|
|
||||||
* 消息类型为 {@link WxConsts.XmlMsgType} 的 VIDEO、MUSIC、LINK
|
|
||||||
*/
|
|
||||||
private String title;
|
|
||||||
/**
|
|
||||||
* 描述
|
|
||||||
*
|
|
||||||
* 消息类型为 {@link WxConsts.XmlMsgType} 的 VIDEO、MUSIC
|
|
||||||
*/
|
|
||||||
private String description;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 缩略图的媒体 id,通过素材管理中的接口上传多媒体文件,得到的 id
|
|
||||||
*
|
|
||||||
* 消息类型为 {@link WxConsts.XmlMsgType} 的 VIDEO
|
|
||||||
*/
|
|
||||||
private String thumbMediaId;
|
|
||||||
/**
|
|
||||||
* 缩略图的媒体 URL
|
|
||||||
*
|
|
||||||
* 消息类型为 {@link WxConsts.XmlMsgType} 的 VIDEO
|
|
||||||
*/
|
|
||||||
private String thumbMediaUrl;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 点击图文消息跳转链接
|
|
||||||
*
|
|
||||||
* 消息类型为 {@link WxConsts.XmlMsgType} 的 LINK
|
|
||||||
*/
|
|
||||||
private String url;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 地理位置维度
|
|
||||||
*
|
|
||||||
* 消息类型为 {@link WxConsts.XmlMsgType} 的 LOCATION
|
|
||||||
*/
|
|
||||||
private Double locationX;
|
|
||||||
/**
|
|
||||||
* 地理位置经度
|
|
||||||
*
|
|
||||||
* 消息类型为 {@link WxConsts.XmlMsgType} 的 LOCATION
|
|
||||||
*/
|
|
||||||
private Double locationY;
|
|
||||||
/**
|
|
||||||
* 地图缩放大小
|
|
||||||
*
|
|
||||||
* 消息类型为 {@link WxConsts.XmlMsgType} 的 LOCATION
|
|
||||||
*/
|
|
||||||
private Double scale;
|
|
||||||
/**
|
|
||||||
* 详细地址
|
|
||||||
*
|
|
||||||
* 消息类型为 {@link WxConsts.XmlMsgType} 的 LOCATION
|
|
||||||
*
|
|
||||||
* 例如说杨浦区黄兴路 221-4 号临
|
|
||||||
*/
|
|
||||||
private String label;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 图文消息数组
|
|
||||||
*
|
|
||||||
* 消息类型为 {@link WxConsts.XmlMsgType} 的 NEWS
|
|
||||||
*/
|
|
||||||
@TableField(typeHandler = MpMessageDO.ArticleTypeHandler.class)
|
|
||||||
private List<MpMessageDO.Article> articles;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 音乐链接
|
|
||||||
*
|
|
||||||
* 消息类型为 {@link WxConsts.XmlMsgType} 的 MUSIC
|
|
||||||
*/
|
|
||||||
private String musicUrl;
|
|
||||||
/**
|
|
||||||
* 高质量音乐链接
|
|
||||||
*
|
|
||||||
* WIFI 环境优先使用该链接播放音乐
|
|
||||||
*
|
|
||||||
* 消息类型为 {@link WxConsts.XmlMsgType} 的 MUSIC
|
|
||||||
*/
|
|
||||||
private String hqMusicUrl;
|
|
||||||
|
|
||||||
// ========= 事件推送 https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Receiving_event_pushes.html
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 事件类型
|
|
||||||
*
|
|
||||||
* 枚举 {@link WxConsts.EventType}
|
|
||||||
*/
|
|
||||||
private String event;
|
|
||||||
/**
|
|
||||||
* 事件 Key
|
|
||||||
*
|
|
||||||
* 1. {@link WxConsts.EventType} 的 SCAN:qrscene_ 为前缀,后面为二维码的参数值
|
|
||||||
* 2. {@link WxConsts.EventType} 的 CLICK:与自定义菜单接口中 KEY 值对应
|
|
||||||
*/
|
|
||||||
private String eventKey;
|
|
||||||
|
|
||||||
}
|
|
@ -4,23 +4,31 @@ import lombok.*;
|
|||||||
|
|
||||||
import io.swagger.annotations.*;
|
import io.swagger.annotations.*;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||||
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
|
||||||
@ApiModel("管理后台 - 粉丝消息分页 Request VO")
|
import javax.validation.constraints.NotNull;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||||
|
|
||||||
|
@ApiModel("管理后台 - 公众号消息分页 Request VO")
|
||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
public class MpMessagePageReqVO extends PageParam {
|
public class MpMessagePageReqVO extends PageParam {
|
||||||
|
|
||||||
@ApiModelProperty(value = "用户标识")
|
@ApiModelProperty(value = "公众号账号的编号", required = true, example = "1024")
|
||||||
private String openId;
|
@NotNull(message = "公众号账号的编号不能为空")
|
||||||
|
|
||||||
@ApiModelProperty(value = "昵称")
|
|
||||||
private String nickname;
|
|
||||||
|
|
||||||
@ApiModelProperty(value = "微信账号ID")
|
|
||||||
private Long accountId;
|
private Long accountId;
|
||||||
|
|
||||||
@ApiModelProperty(value = "消息类型")
|
@ApiModelProperty(value = "消息类型", example = "text", notes = "参见 WxConsts.XmlMsgType 枚举")
|
||||||
private String type;
|
private String type;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "公众号粉丝标识", example = "o6_bmjrPTlm6_2sgVt7hMZOPfL2M")
|
||||||
|
private String openid;
|
||||||
|
|
||||||
|
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||||
|
@ApiModelProperty(value = "创建时间")
|
||||||
|
private LocalDateTime[] createTime;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,103 @@
|
|||||||
package cn.iocoder.yudao.module.mp.controller.admin.message.vo.message;
|
package cn.iocoder.yudao.module.mp.controller.admin.message.vo.message;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.module.mp.dal.dataobject.message.MpMessageDO;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
import io.swagger.annotations.ApiModel;
|
import io.swagger.annotations.ApiModel;
|
||||||
import io.swagger.annotations.ApiModelProperty;
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import me.chanjar.weixin.common.api.WxConsts;
|
||||||
import lombok.ToString;
|
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@ApiModel("管理后台 - 粉丝消息 Response VO")
|
@ApiModel("管理后台 - 公众号消息 Response VO")
|
||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = true)
|
public class MpMessageRespVO {
|
||||||
@ToString(callSuper = true)
|
|
||||||
public class MpMessageRespVO extends MpMessageBaseVO {
|
|
||||||
|
|
||||||
@ApiModelProperty(value = "主键", required = true)
|
@ApiModelProperty(value = "主键", required = true, example = "1024")
|
||||||
private Integer id;
|
private Integer id;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "微信公众号消息 id", required = true, example = "23953173569869169")
|
||||||
|
private Long msgId;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "公众号账号的编号", required = true, example = "1")
|
||||||
|
private Long accountId;
|
||||||
|
@ApiModelProperty(value = "公众号账号的 appid", required = true, example = "wx1234567890")
|
||||||
|
private String appId;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "公众号粉丝编号", required = true, example = "2048")
|
||||||
|
private Long userId;
|
||||||
|
@ApiModelProperty(value = "公众号粉丝标志", required = true, example = "o6_bmjrPTlm6_2sgVt7hMZOPfL2M")
|
||||||
|
private String openid;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "消息类型", required = true, example = "text", notes = "参见 WxConsts.XmlMsgType 枚举")
|
||||||
|
private String type;
|
||||||
|
@ApiModelProperty(value = "消息来源", required = true, example = "1", notes = "参见 MpMessageSendFromEnum 枚举")
|
||||||
|
private Integer sendFrom;
|
||||||
|
|
||||||
|
// ========= 普通消息内容 https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Receiving_standard_messages.html
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "消息内容", example = "你好呀", notes = "消息类型为 text 时,才有值")
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "媒体素材的编号", example = "1234567890", notes = "消息类型为 image、voice、video 时,才有值")
|
||||||
|
private String mediaId;
|
||||||
|
@ApiModelProperty(value = "媒体文件的 URL", example = "https://www.iocoder.cn/xxx.png",
|
||||||
|
notes = "消息类型为 image、voice、video 时,才有值")
|
||||||
|
private String mediaUrl;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "语音识别后文本", example = "语音识别后文本", notes = "消息类型为 voice 时,才有值")
|
||||||
|
private String recognition;
|
||||||
|
@ApiModelProperty(value = "语音格式", example = "amr", notes = "消息类型为 voice 时,才有值")
|
||||||
|
private String format;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "标题", example = "我是标题", notes = "消息类型为 video、music、link 时,才有值")
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "描述", example = "我是描述", notes = "消息类型为 video、music 时,才有值")
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "缩略图的媒体 id", example = "1234567890", notes = "消息类型为 video、music 时,才有值")
|
||||||
|
private String thumbMediaId;
|
||||||
|
@ApiModelProperty(value = "缩略图的媒体 URL", example = "https://www.iocoder.cn/xxx.png",
|
||||||
|
notes = "消息类型为 video、music 时,才有值")
|
||||||
|
private String thumbMediaUrl;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "点击图文消息跳转链接", example = "https://www.iocoder.cn", notes = "消息类型为 link 时,才有值")
|
||||||
|
private String url;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "地理位置维度", example = "23.137466", notes = "消息类型为 location 时,才有值")
|
||||||
|
private Double locationX;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "地理位置经度", example = "113.352425", notes = "消息类型为 location 时,才有值")
|
||||||
|
private Double locationY;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "地图缩放大小", example = "13", notes = "消息类型为 location 时,才有值")
|
||||||
|
private Double scale;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "详细地址", example = "杨浦区黄兴路 221-4 号临", notes = "消息类型为 location 时,才有值")
|
||||||
|
private String label;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图文消息数组
|
||||||
|
*
|
||||||
|
* 消息类型为 {@link WxConsts.XmlMsgType} 的 NEWS
|
||||||
|
*/
|
||||||
|
@TableField(typeHandler = MpMessageDO.ArticleTypeHandler.class)
|
||||||
|
private List<MpMessageDO.Article> articles;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "音乐链接", example = "https://www.iocoder.cn/xxx.mp3", notes = "消息类型为 music 时,才有值")
|
||||||
|
private String musicUrl;
|
||||||
|
@ApiModelProperty(value = "高质量音乐链接", example = "https://www.iocoder.cn/xxx.mp3", notes = "消息类型为 music 时,才有值")
|
||||||
|
private String hqMusicUrl;
|
||||||
|
|
||||||
|
// ========= 事件推送 https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Receiving_event_pushes.html
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "事件类型", example = "subscribe", notes = "参见 WxConsts.EventType 枚举")
|
||||||
|
private String event;
|
||||||
|
@ApiModelProperty(value = "事件 Key", example = "qrscene_123456", notes = "参见 WxConsts.EventType 枚举")
|
||||||
|
private String eventKey;
|
||||||
|
|
||||||
@ApiModelProperty(value = "创建时间", required = true)
|
@ApiModelProperty(value = "创建时间", required = true)
|
||||||
private Date createTime;
|
private Date createTime;
|
||||||
|
|
||||||
|
@ -4,7 +4,6 @@ package cn.iocoder.yudao.module.mp.controller.admin.open.vo;
|
|||||||
import io.swagger.annotations.ApiModel;
|
import io.swagger.annotations.ApiModel;
|
||||||
import io.swagger.annotations.ApiModelProperty;
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
|
||||||
|
|
||||||
import javax.validation.constraints.NotEmpty;
|
import javax.validation.constraints.NotEmpty;
|
||||||
|
|
||||||
@ -26,8 +25,8 @@ public class MpOpenHandleMessageReqVO {
|
|||||||
@NotEmpty(message = "随机数不能为空")
|
@NotEmpty(message = "随机数不能为空")
|
||||||
private String nonce;
|
private String nonce;
|
||||||
|
|
||||||
@ApiModelProperty(value = "用户 openid", required = true, example = "oz-Jdtyn-WGm4C4I5Z-nvBMO_ZfY")
|
@ApiModelProperty(value = "粉丝 openid", required = true, example = "oz-Jdtyn-WGm4C4I5Z-nvBMO_ZfY")
|
||||||
@NotEmpty(message = "用户 openid 不能为空")
|
@NotEmpty(message = "粉丝 openid 不能为空")
|
||||||
private String openid;
|
private String openid;
|
||||||
|
|
||||||
@ApiModelProperty(value = "消息加密类型", example = "aes")
|
@ApiModelProperty(value = "消息加密类型", example = "aes")
|
||||||
|
@ -31,7 +31,7 @@ public class MpStatisticsController {
|
|||||||
private MpStatisticsService mpStatisticsService;
|
private MpStatisticsService mpStatisticsService;
|
||||||
|
|
||||||
@GetMapping("/user-summary")
|
@GetMapping("/user-summary")
|
||||||
@ApiOperation("获得用户增减数据")
|
@ApiOperation("获得粉丝增减数据")
|
||||||
@PreAuthorize("@ss.hasPermission('mp:statistics:query')")
|
@PreAuthorize("@ss.hasPermission('mp:statistics:query')")
|
||||||
public CommonResult<List<MpStatisticsUserSummaryRespVO>> getUserSummary(MpStatisticsGetReqVO getReqVO) {
|
public CommonResult<List<MpStatisticsUserSummaryRespVO>> getUserSummary(MpStatisticsGetReqVO getReqVO) {
|
||||||
List<WxDataCubeUserSummary> list = mpStatisticsService.getUserSummary(
|
List<WxDataCubeUserSummary> list = mpStatisticsService.getUserSummary(
|
||||||
@ -40,7 +40,7 @@ public class MpStatisticsController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/user-cumulate")
|
@GetMapping("/user-cumulate")
|
||||||
@ApiOperation("获得用户累计数据")
|
@ApiOperation("获得粉丝累计数据")
|
||||||
@PreAuthorize("@ss.hasPermission('mp:statistics:query')")
|
@PreAuthorize("@ss.hasPermission('mp:statistics:query')")
|
||||||
public CommonResult<List<MpStatisticsUserCumulateRespVO>> getUserCumulate(MpStatisticsGetReqVO getReqVO) {
|
public CommonResult<List<MpStatisticsUserCumulateRespVO>> getUserCumulate(MpStatisticsGetReqVO getReqVO) {
|
||||||
List<WxDataCubeUserCumulate> list = mpStatisticsService.getUserCumulate(
|
List<WxDataCubeUserCumulate> list = mpStatisticsService.getUserCumulate(
|
||||||
|
@ -13,7 +13,7 @@ public class MpStatisticsInterfaceSummaryRespVO {
|
|||||||
@ApiModelProperty(value = "日期", required = true)
|
@ApiModelProperty(value = "日期", required = true)
|
||||||
private Date refDate;
|
private Date refDate;
|
||||||
|
|
||||||
@ApiModelProperty(value = "通过服务器配置地址获得消息后,被动回复用户消息的次数", required = true, example = "10")
|
@ApiModelProperty(value = "通过服务器配置地址获得消息后,被动回复粉丝消息的次数", required = true, example = "10")
|
||||||
private Integer callbackCount;
|
private Integer callbackCount;
|
||||||
|
|
||||||
@ApiModelProperty(value = "上述动作的失败次数", required = true, example = "20")
|
@ApiModelProperty(value = "上述动作的失败次数", required = true, example = "20")
|
||||||
|
@ -6,14 +6,14 @@ import lombok.Data;
|
|||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
@ApiModel("管理后台 - 某一天的用户增减数据 Response VO")
|
@ApiModel("管理后台 - 某一天的粉丝增减数据 Response VO")
|
||||||
@Data
|
@Data
|
||||||
public class MpStatisticsUpstreamMessageRespVO {
|
public class MpStatisticsUpstreamMessageRespVO {
|
||||||
|
|
||||||
@ApiModelProperty(value = "日期", required = true)
|
@ApiModelProperty(value = "日期", required = true)
|
||||||
private Date refDate;
|
private Date refDate;
|
||||||
|
|
||||||
@ApiModelProperty(value = "上行发送了(向公众号发送了)消息的用户数", required = true, example = "10")
|
@ApiModelProperty(value = "上行发送了(向公众号发送了)消息的粉丝数", required = true, example = "10")
|
||||||
private Integer messageUser;
|
private Integer messageUser;
|
||||||
|
|
||||||
@ApiModelProperty(value = "上行发送了消息的消息总数", required = true, example = "20")
|
@ApiModelProperty(value = "上行发送了消息的消息总数", required = true, example = "20")
|
||||||
|
@ -13,7 +13,7 @@ public class MpStatisticsUserCumulateRespVO {
|
|||||||
@ApiModelProperty(value = "日期", required = true)
|
@ApiModelProperty(value = "日期", required = true)
|
||||||
private Date refDate;
|
private Date refDate;
|
||||||
|
|
||||||
@ApiModelProperty(value = "累计用户量", required = true, example = "10")
|
@ApiModelProperty(value = "累计粉丝量", required = true, example = "10")
|
||||||
private Integer cumulateUser;
|
private Integer cumulateUser;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -6,20 +6,20 @@ import lombok.Data;
|
|||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
@ApiModel("管理后台 - 某一天的用户增减数据 Response VO")
|
@ApiModel("管理后台 - 某一天的粉丝增减数据 Response VO")
|
||||||
@Data
|
@Data
|
||||||
public class MpStatisticsUserSummaryRespVO {
|
public class MpStatisticsUserSummaryRespVO {
|
||||||
|
|
||||||
@ApiModelProperty(value = "日期", required = true)
|
@ApiModelProperty(value = "日期", required = true)
|
||||||
private Date refDate;
|
private Date refDate;
|
||||||
|
|
||||||
@ApiModelProperty(value = "用户来源", required = true, example = "0")
|
@ApiModelProperty(value = "粉丝来源", required = true, example = "0")
|
||||||
private Integer userSource;
|
private Integer userSource;
|
||||||
|
|
||||||
@ApiModelProperty(value = "新关注的用户数量", required = true, example = "10")
|
@ApiModelProperty(value = "新关注的粉丝数量", required = true, example = "10")
|
||||||
private Integer newUser;
|
private Integer newUser;
|
||||||
|
|
||||||
@ApiModelProperty(value = "取消关注的用户数量", required = true, example = "20")
|
@ApiModelProperty(value = "取消关注的粉丝数量", required = true, example = "20")
|
||||||
private Integer cancelUser;
|
private Integer cancelUser;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -19,10 +19,10 @@ public class MpUserPageReqVO extends PageParam {
|
|||||||
@NotNull(message = "公众号账号的编号不能为空")
|
@NotNull(message = "公众号账号的编号不能为空")
|
||||||
private Long accountId;
|
private Long accountId;
|
||||||
|
|
||||||
@ApiModelProperty(value = "公众号用户标识", example = "o6_bmjrPTlm6_2sgVt7hMZOPfL2M", notes = "模糊匹配")
|
@ApiModelProperty(value = "公众号粉丝标识", example = "o6_bmjrPTlm6_2sgVt7hMZOPfL2M", notes = "模糊匹配")
|
||||||
private String openid;
|
private String openid;
|
||||||
|
|
||||||
@ApiModelProperty(value = "公众号用户昵称", example = "芋艿", notes = "模糊匹配")
|
@ApiModelProperty(value = "公众号粉丝昵称", example = "芋艿", notes = "模糊匹配")
|
||||||
private String nickname;
|
private String nickname;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ public class MpUserRespVO {
|
|||||||
@ApiModelProperty(value = "编号", required = true, example = "1024")
|
@ApiModelProperty(value = "编号", required = true, example = "1024")
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
@ApiModelProperty(value = "公众号用户标识", required = true, example = "o6_bmjrPTlm6_2sgVt7hMZOPfL2M")
|
@ApiModelProperty(value = "公众号粉丝标识", required = true, example = "o6_bmjrPTlm6_2sgVt7hMZOPfL2M")
|
||||||
private String openid;
|
private String openid;
|
||||||
|
|
||||||
@ApiModelProperty(value = "关注状态", required = true, example = "1", notes = "参见 CommonStatusEnum 枚举")
|
@ApiModelProperty(value = "关注状态", required = true, example = "1", notes = "参见 CommonStatusEnum 枚举")
|
||||||
|
@ -32,13 +32,13 @@ public class MpMaterialDO extends BaseDO {
|
|||||||
@TableId
|
@TableId
|
||||||
private Long id;
|
private Long id;
|
||||||
/**
|
/**
|
||||||
* 微信公众号 ID
|
* 公众号账号的编号
|
||||||
*
|
*
|
||||||
* 关联 {@link MpAccountDO#getId()}
|
* 关联 {@link MpAccountDO#getId()}
|
||||||
*/
|
*/
|
||||||
private Long accountId;
|
private Long accountId;
|
||||||
/**
|
/**
|
||||||
* 微信公众号 appid
|
* 公众号 appId
|
||||||
*
|
*
|
||||||
* 冗余 {@link MpAccountDO#getAppId()}
|
* 冗余 {@link MpAccountDO#getAppId()}
|
||||||
*/
|
*/
|
||||||
@ -71,8 +71,8 @@ public class MpMaterialDO extends BaseDO {
|
|||||||
*
|
*
|
||||||
* 永久素材:非空
|
* 永久素材:非空
|
||||||
* 临时素材:可能为空。
|
* 临时素材:可能为空。
|
||||||
* 1. 为空的情况:用户主动发送的图片、语音等
|
* 1. 为空的情况:粉丝主动发送的图片、语音等
|
||||||
* 2. 非空的情况:主动发送给用户的图片、语音等
|
* 2. 非空的情况:主动发送给粉丝的图片、语音等
|
||||||
*/
|
*/
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ import me.chanjar.weixin.common.api.WxConsts.MenuButtonType;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 微信菜单 DO
|
* 公众号菜单 DO
|
||||||
*
|
*
|
||||||
* @author 芋道源码
|
* @author 芋道源码
|
||||||
*/
|
*/
|
||||||
@ -38,13 +38,13 @@ public class MpMenuDO extends BaseDO {
|
|||||||
@TableId
|
@TableId
|
||||||
private Long id;
|
private Long id;
|
||||||
/**
|
/**
|
||||||
* 微信公众号 ID
|
* 公众号账号的编号
|
||||||
*
|
*
|
||||||
* 关联 {@link MpAccountDO#getId()}
|
* 关联 {@link MpAccountDO#getId()}
|
||||||
*/
|
*/
|
||||||
private Long accountId;
|
private Long accountId;
|
||||||
/**
|
/**
|
||||||
* 微信公众号 appid
|
* 公众号 appId
|
||||||
*
|
*
|
||||||
* 冗余 {@link MpAccountDO#getAppId()}
|
* 冗余 {@link MpAccountDO#getAppId()}
|
||||||
*/
|
*/
|
||||||
@ -77,7 +77,7 @@ public class MpMenuDO extends BaseDO {
|
|||||||
/**
|
/**
|
||||||
* 网页链接
|
* 网页链接
|
||||||
*
|
*
|
||||||
* 用户点击菜单可打开链接,不超过 1024 字节
|
* 粉丝点击菜单可打开链接,不超过 1024 字节
|
||||||
*
|
*
|
||||||
* 类型为 {@link WxConsts.XmlMsgType} 的 VIEW、MINIPROGRAM
|
* 类型为 {@link WxConsts.XmlMsgType} 的 VIEW、MINIPROGRAM
|
||||||
*/
|
*/
|
||||||
@ -146,13 +146,13 @@ public class MpMenuDO extends BaseDO {
|
|||||||
private String replyDescription;
|
private String replyDescription;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 缩略图的媒体 id,通过素材管理中的接口上传多媒体文件,得到的 id
|
* 回复的缩略图的媒体 id,通过素材管理中的接口上传多媒体文件,得到的 id
|
||||||
*
|
*
|
||||||
* 消息类型为 {@link WxConsts.XmlMsgType} 的 MUSIC、VIDEO
|
* 消息类型为 {@link WxConsts.XmlMsgType} 的 MUSIC、VIDEO
|
||||||
*/
|
*/
|
||||||
private String replyThumbMediaId;
|
private String replyThumbMediaId;
|
||||||
/**
|
/**
|
||||||
* 缩略图的媒体 URL
|
* 回复的缩略图的媒体 URL
|
||||||
*
|
*
|
||||||
* 消息类型为 {@link WxConsts.XmlMsgType} 的 MUSIC、VIDEO
|
* 消息类型为 {@link WxConsts.XmlMsgType} 的 MUSIC、VIDEO
|
||||||
*/
|
*/
|
||||||
|
@ -40,13 +40,13 @@ public class MpAutoReplyDO extends BaseDO {
|
|||||||
@TableId
|
@TableId
|
||||||
private Long id;
|
private Long id;
|
||||||
/**
|
/**
|
||||||
* 微信公众号 ID
|
* 公众号账号的编号
|
||||||
*
|
*
|
||||||
* 关联 {@link MpAccountDO#getId()}
|
* 关联 {@link MpAccountDO#getId()}
|
||||||
*/
|
*/
|
||||||
private Long accountId;
|
private Long accountId;
|
||||||
/**
|
/**
|
||||||
* 微信公众号 appid
|
* 公众号 appId
|
||||||
*
|
*
|
||||||
* 冗余 {@link MpAccountDO#getAppId()}
|
* 冗余 {@link MpAccountDO#getAppId()}
|
||||||
*/
|
*/
|
||||||
@ -125,6 +125,19 @@ public class MpAutoReplyDO extends BaseDO {
|
|||||||
*/
|
*/
|
||||||
private String responseDescription;
|
private String responseDescription;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 回复的缩略图的媒体 id,通过素材管理中的接口上传多媒体文件,得到的 id
|
||||||
|
*
|
||||||
|
* 消息类型为 {@link WxConsts.XmlMsgType} 的 MUSIC、VIDEO
|
||||||
|
*/
|
||||||
|
private String responseThumbMediaId;
|
||||||
|
/**
|
||||||
|
* 回复的缩略图的媒体 URL
|
||||||
|
*
|
||||||
|
* 消息类型为 {@link WxConsts.XmlMsgType} 的 MUSIC、VIDEO
|
||||||
|
*/
|
||||||
|
private String responseThumbMediaUrl;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 回复的图文消息
|
* 回复的图文消息
|
||||||
*
|
*
|
||||||
@ -133,4 +146,19 @@ public class MpAutoReplyDO extends BaseDO {
|
|||||||
@TableField(typeHandler = MpMessageDO.ArticleTypeHandler.class)
|
@TableField(typeHandler = MpMessageDO.ArticleTypeHandler.class)
|
||||||
private List<MpMessageDO.Article> responseArticles;
|
private List<MpMessageDO.Article> responseArticles;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 回复的音乐链接
|
||||||
|
*
|
||||||
|
* 消息类型为 {@link WxConsts.XmlMsgType} 的 MUSIC
|
||||||
|
*/
|
||||||
|
private String responseMusicUrl;
|
||||||
|
/**
|
||||||
|
* 回复的高质量音乐链接
|
||||||
|
*
|
||||||
|
* WIFI 环境优先使用该链接播放音乐
|
||||||
|
*
|
||||||
|
* 消息类型为 {@link WxConsts.XmlMsgType} 的 MUSIC
|
||||||
|
*/
|
||||||
|
private String responseHqMusicUrl;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -40,25 +40,25 @@ public class MpMessageDO extends BaseDO {
|
|||||||
*/
|
*/
|
||||||
private Long msgId;
|
private Long msgId;
|
||||||
/**
|
/**
|
||||||
* 微信公众号 ID
|
* 公众号账号的 ID
|
||||||
*
|
*
|
||||||
* 关联 {@link MpAccountDO#getId()}
|
* 关联 {@link MpAccountDO#getId()}
|
||||||
*/
|
*/
|
||||||
private Long accountId;
|
private Long accountId;
|
||||||
/**
|
/**
|
||||||
* 微信公众号 appid
|
* 公众号 appid
|
||||||
*
|
*
|
||||||
* 冗余 {@link MpAccountDO#getAppId()}
|
* 冗余 {@link MpAccountDO#getAppId()}
|
||||||
*/
|
*/
|
||||||
private String appId;
|
private String appId;
|
||||||
/**
|
/**
|
||||||
* 微信用户编号
|
* 公众号粉丝的编号
|
||||||
*
|
*
|
||||||
* 关联 {@link MpUserDO#getId()}
|
* 关联 {@link MpUserDO#getId()}
|
||||||
*/
|
*/
|
||||||
private Long userId;
|
private Long userId;
|
||||||
/**
|
/**
|
||||||
* 用户标识
|
* 公众号粉丝标志
|
||||||
*
|
*
|
||||||
* 冗余 {@link MpUserDO#getOpenid()}
|
* 冗余 {@link MpUserDO#getOpenid()}
|
||||||
*/
|
*/
|
||||||
@ -87,7 +87,7 @@ public class MpMessageDO extends BaseDO {
|
|||||||
private String content;
|
private String content;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通过素材管理中的接口上传多媒体文件,得到的 id
|
* 媒体文件的编号
|
||||||
*
|
*
|
||||||
* 消息类型为 {@link WxConsts.XmlMsgType} 的 IMAGE、VOICE、VIDEO
|
* 消息类型为 {@link WxConsts.XmlMsgType} 的 IMAGE、VOICE、VIDEO
|
||||||
*/
|
*/
|
||||||
|
@ -43,13 +43,13 @@ public class MpTagDO extends BaseDO {
|
|||||||
private Integer count;
|
private Integer count;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 微信公众号 ID
|
* 公众号账号的编号
|
||||||
*
|
*
|
||||||
* 关联 {@link MpAccountDO#getId()}
|
* 关联 {@link MpAccountDO#getId()}
|
||||||
*/
|
*/
|
||||||
private Long accountId;
|
private Long accountId;
|
||||||
/**
|
/**
|
||||||
* 微信公众号 appid
|
* 公众号 appId
|
||||||
*
|
*
|
||||||
* 冗余 {@link MpAccountDO#getAppId()}
|
* 冗余 {@link MpAccountDO#getAppId()}
|
||||||
*/
|
*/
|
||||||
|
@ -35,7 +35,7 @@ public class MpUserDO extends BaseDO {
|
|||||||
@TableId
|
@TableId
|
||||||
private Long id;
|
private Long id;
|
||||||
/**
|
/**
|
||||||
* 用户标识
|
* 粉丝标识
|
||||||
*/
|
*/
|
||||||
private String openid;
|
private String openid;
|
||||||
/**
|
/**
|
||||||
@ -95,13 +95,13 @@ public class MpUserDO extends BaseDO {
|
|||||||
private List<Long> tagIds;
|
private List<Long> tagIds;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 微信公众号 ID
|
* 公众号账号的编号
|
||||||
*
|
*
|
||||||
* 关联 {@link MpAccountDO#getId()}
|
* 关联 {@link MpAccountDO#getId()}
|
||||||
*/
|
*/
|
||||||
private Long accountId;
|
private Long accountId;
|
||||||
/**
|
/**
|
||||||
* 微信公众号 appid
|
* 公众号 appId
|
||||||
*
|
*
|
||||||
* 冗余 {@link MpAccountDO#getAppId()}
|
* 冗余 {@link MpAccountDO#getAppId()}
|
||||||
*/
|
*/
|
||||||
|
@ -13,9 +13,9 @@ public interface MpMessageMapper extends BaseMapperX<MpMessageDO> {
|
|||||||
default PageResult<MpMessageDO> selectPage(MpMessagePageReqVO reqVO) {
|
default PageResult<MpMessageDO> selectPage(MpMessagePageReqVO reqVO) {
|
||||||
return selectPage(reqVO, new LambdaQueryWrapperX<MpMessageDO>()
|
return selectPage(reqVO, new LambdaQueryWrapperX<MpMessageDO>()
|
||||||
.eqIfPresent(MpMessageDO::getAccountId, reqVO.getAccountId())
|
.eqIfPresent(MpMessageDO::getAccountId, reqVO.getAccountId())
|
||||||
.eqIfPresent(MpMessageDO::getOpenid, reqVO.getOpenId())
|
|
||||||
// .likeIfPresent(MpMessageDO::getNickname, reqVO.getNickname())
|
|
||||||
.eqIfPresent(MpMessageDO::getType, reqVO.getType())
|
.eqIfPresent(MpMessageDO::getType, reqVO.getType())
|
||||||
|
.eqIfPresent(MpMessageDO::getOpenid, reqVO.getOpenid())
|
||||||
|
.betweenIfPresent(MpMessageDO::getCreateTime, reqVO.getCreateTime())
|
||||||
.orderByDesc(MpMessageDO::getId));
|
.orderByDesc(MpMessageDO::getId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,7 +103,6 @@ public class DefaultMpServiceFactory implements MpServiceFactory {
|
|||||||
|
|
||||||
private WxMpService buildMpService(MpAccountDO account) {
|
private WxMpService buildMpService(MpAccountDO account) {
|
||||||
// 第一步,创建 WxMpRedisConfigImpl 对象
|
// 第一步,创建 WxMpRedisConfigImpl 对象
|
||||||
// TODO 芋艿:需要确认下,redis key 的存储结构
|
|
||||||
WxMpRedisConfigImpl configStorage = new WxMpRedisConfigImpl(
|
WxMpRedisConfigImpl configStorage = new WxMpRedisConfigImpl(
|
||||||
redisTemplateWxRedisOps, mpProperties.getConfigStorage().getKeyPrefix());
|
redisTemplateWxRedisOps, mpProperties.getConfigStorage().getKeyPrefix());
|
||||||
configStorage.setAppId(account.getAppId());
|
configStorage.setAppId(account.getAppId());
|
||||||
|
@ -18,7 +18,7 @@ import static me.chanjar.weixin.common.api.WxConsts.MenuButtonType;
|
|||||||
/**
|
/**
|
||||||
* 自定义菜单的事件处理器
|
* 自定义菜单的事件处理器
|
||||||
*
|
*
|
||||||
* 逻辑:用户点击菜单时,触发对应的回复
|
* 逻辑:粉丝点击菜单时,触发对应的回复
|
||||||
*
|
*
|
||||||
* @author 芋道源码
|
* @author 芋道源码
|
||||||
*/
|
*/
|
||||||
|
@ -20,8 +20,7 @@ public class KfSessionHandler implements WxMpMessageHandler {
|
|||||||
@Override
|
@Override
|
||||||
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context,
|
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context,
|
||||||
WxMpService wxMpService, WxSessionManager sessionManager) {
|
WxMpService wxMpService, WxSessionManager sessionManager) {
|
||||||
// TODO 对会话做处理
|
throw new UnsupportedOperationException("未实现该处理,请自行重写");
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ public class NullHandler implements WxMpMessageHandler {
|
|||||||
@Override
|
@Override
|
||||||
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context,
|
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context,
|
||||||
WxMpService wxMpService, WxSessionManager sessionManager) {
|
WxMpService wxMpService, WxSessionManager sessionManager) {
|
||||||
return null;
|
throw new UnsupportedOperationException("未实现该处理,请自行重写");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -17,9 +17,9 @@ import java.util.Map;
|
|||||||
public class ScanHandler implements WxMpMessageHandler {
|
public class ScanHandler implements WxMpMessageHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMpXmlMessage, Map<String, Object> map,
|
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMpXmlMessage, Map<String, Object> context,
|
||||||
WxMpService wxMpService, WxSessionManager wxSessionManager) throws WxErrorException {
|
WxMpService wxMpService, WxSessionManager wxSessionManager) throws WxErrorException {
|
||||||
// 扫码事件处理
|
throw new UnsupportedOperationException("未实现该处理,请自行重写");
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -16,11 +16,9 @@ import java.util.Map;
|
|||||||
public class StoreCheckNotifyHandler implements WxMpMessageHandler {
|
public class StoreCheckNotifyHandler implements WxMpMessageHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
|
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context,
|
||||||
Map<String, Object> context, WxMpService wxMpService,
|
WxMpService wxMpService, WxSessionManager sessionManager) {
|
||||||
WxSessionManager sessionManager) {
|
throw new UnsupportedOperationException("未实现该处理,请自行重写");
|
||||||
// TODO 处理门店审核事件
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ import java.util.Map;
|
|||||||
*
|
*
|
||||||
* 触发操作:打开微信公众号 -> 点击 + 号 -> 选择「语音」
|
* 触发操作:打开微信公众号 -> 点击 + 号 -> 选择「语音」
|
||||||
*
|
*
|
||||||
* 逻辑:用户上传地理位置时,也可以触发自动回复
|
* 逻辑:粉丝上传地理位置时,也可以触发自动回复
|
||||||
*
|
*
|
||||||
* @author 芋道源码
|
* @author 芋道源码
|
||||||
*/
|
*/
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
package cn.iocoder.yudao.module.mp.service.handler.user;
|
package cn.iocoder.yudao.module.mp.service.handler.user;
|
||||||
|
|
||||||
import cn.iocoder.yudao.module.mp.dal.dataobject.user.MpUserDO;
|
|
||||||
import cn.iocoder.yudao.module.mp.framework.mp.core.context.MpContextHolder;
|
import cn.iocoder.yudao.module.mp.framework.mp.core.context.MpContextHolder;
|
||||||
import cn.iocoder.yudao.module.mp.service.account.MpAccountService;
|
|
||||||
import cn.iocoder.yudao.module.mp.service.message.MpAutoReplyService;
|
import cn.iocoder.yudao.module.mp.service.message.MpAutoReplyService;
|
||||||
import cn.iocoder.yudao.module.mp.service.user.MpUserService;
|
import cn.iocoder.yudao.module.mp.service.user.MpUserService;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@ -13,7 +11,6 @@ import me.chanjar.weixin.mp.api.WxMpService;
|
|||||||
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
|
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
|
||||||
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
|
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
|
||||||
import me.chanjar.weixin.mp.bean.result.WxMpUser;
|
import me.chanjar.weixin.mp.bean.result.WxMpUser;
|
||||||
import org.springframework.context.annotation.Lazy;
|
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
@ -36,16 +33,16 @@ public class SubscribeHandler implements WxMpMessageHandler {
|
|||||||
@Override
|
@Override
|
||||||
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context,
|
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context,
|
||||||
WxMpService weixinService, WxSessionManager sessionManager) throws WxErrorException {
|
WxMpService weixinService, WxSessionManager sessionManager) throws WxErrorException {
|
||||||
// 第一步,从公众号平台,获取用户信息
|
// 第一步,从公众号平台,获取粉丝信息
|
||||||
log.info("[handle][用户({}) 关注]", wxMessage.getFromUser());
|
log.info("[handle][粉丝({}) 关注]", wxMessage.getFromUser());
|
||||||
WxMpUser wxMpUser = null;
|
WxMpUser wxMpUser = null;
|
||||||
try {
|
try {
|
||||||
wxMpUser = weixinService.getUserService().userInfo(wxMessage.getFromUser());
|
wxMpUser = weixinService.getUserService().userInfo(wxMessage.getFromUser());
|
||||||
} catch (WxErrorException e) {
|
} catch (WxErrorException e) {
|
||||||
log.error("[handle][用户({})] 获取用户信息失败!", wxMessage.getFromUser(), e);
|
log.error("[handle][粉丝({})] 获取粉丝信息失败!", wxMessage.getFromUser(), e);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 第二步,保存用户信息
|
// 第二步,保存粉丝信息
|
||||||
mpUserService.saveUser(MpContextHolder.getAppId(), wxMpUser);
|
mpUserService.saveUser(MpContextHolder.getAppId(), wxMpUser);
|
||||||
|
|
||||||
// 第三步,回复关注的欢迎语
|
// 第三步,回复关注的欢迎语
|
||||||
|
@ -31,7 +31,7 @@ public class UnsubscribeHandler implements WxMpMessageHandler {
|
|||||||
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
|
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
|
||||||
Map<String, Object> context, WxMpService wxMpService,
|
Map<String, Object> context, WxMpService wxMpService,
|
||||||
WxSessionManager sessionManager) {
|
WxSessionManager sessionManager) {
|
||||||
log.info("[handle][用户({}) 取消关注]", wxMessage.getFromUser());
|
log.info("[handle][粉丝({}) 取消关注]", wxMessage.getFromUser());
|
||||||
mpUserService.updateUserUnsubscribe(MpContextHolder.getAppId(), wxMessage.getFromUser());
|
mpUserService.updateUserUnsubscribe(MpContextHolder.getAppId(), wxMessage.getFromUser());
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -29,11 +29,11 @@ public interface MpMenuService {
|
|||||||
void deleteMenuByAccountId(Long accountId);
|
void deleteMenuByAccountId(Long accountId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用户点击菜单按钮时,回复对应的消息
|
* 粉丝点击菜单按钮时,回复对应的消息
|
||||||
*
|
*
|
||||||
* @param appId 公众号 AppId
|
* @param appId 公众号 AppId
|
||||||
* @param key 菜单按钮的标识
|
* @param key 菜单按钮的标识
|
||||||
* @param openid 用户的 openid
|
* @param openid 粉丝的 openid
|
||||||
* @return 消息
|
* @return 消息
|
||||||
*/
|
*/
|
||||||
WxMpXmlOutMessage reply(String appId, String key, String openid);
|
WxMpXmlOutMessage reply(String appId, String key, String openid);
|
||||||
|
@ -64,7 +64,7 @@ public interface MpAutoReplyService {
|
|||||||
WxMpXmlOutMessage replyForMessage(String appId, WxMpXmlMessage wxMessage);
|
WxMpXmlOutMessage replyForMessage(String appId, WxMpXmlMessage wxMessage);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 当用户关注时,自动回复
|
* 当粉丝关注时,自动回复
|
||||||
*
|
*
|
||||||
* @param appId 微信公众号 appId
|
* @param appId 微信公众号 appId
|
||||||
* @param wxMessage 消息
|
* @param wxMessage 消息
|
||||||
|
@ -136,7 +136,7 @@ public class MpAutoReplyServiceImpl implements MpAutoReplyService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deleteAutoReply(Long id) {
|
public void deleteAutoReply(Long id) {
|
||||||
// 校验用户存在
|
// 校验粉丝存在
|
||||||
validateAutoReplyExists(id);
|
validateAutoReplyExists(id);
|
||||||
|
|
||||||
// 删除自动回复
|
// 删除自动回复
|
||||||
|
@ -11,23 +11,22 @@ import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
|
|||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 粉丝消息 Service 接口
|
* 公众号消息 Service 接口
|
||||||
*
|
*
|
||||||
* @author 芋道源码
|
* @author 芋道源码
|
||||||
*/
|
*/
|
||||||
public interface MpMessageService {
|
public interface MpMessageService {
|
||||||
|
|
||||||
// TODO 芋艿:方法名要优化下
|
|
||||||
/**
|
/**
|
||||||
* 获得粉丝消息分页
|
* 获得公众号消息分页
|
||||||
*
|
*
|
||||||
* @param pageReqVO 分页查询
|
* @param pageReqVO 分页查询
|
||||||
* @return 粉丝消息分页
|
* @return 公众号消息分页
|
||||||
*/
|
*/
|
||||||
PageResult<MpMessageDO> getWxFansMsgPage(MpMessagePageReqVO pageReqVO);
|
PageResult<MpMessageDO> getMessagePage(MpMessagePageReqVO pageReqVO);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 从公众号,接收到用户消息
|
* 从公众号,接收到粉丝消息
|
||||||
*
|
*
|
||||||
* @param appId 微信公众号 appId
|
* @param appId 微信公众号 appId
|
||||||
* @param wxMessage 消息
|
* @param wxMessage 消息
|
||||||
@ -35,7 +34,7 @@ public interface MpMessageService {
|
|||||||
void receiveMessage(String appId, WxMpXmlMessage wxMessage);
|
void receiveMessage(String appId, WxMpXmlMessage wxMessage);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 使用公众号,给用户回复消息
|
* 使用公众号,给粉丝回复消息
|
||||||
*
|
*
|
||||||
* 例如说:自动回复、客服消息、菜单回复消息等场景
|
* 例如说:自动回复、客服消息、菜单回复消息等场景
|
||||||
*
|
*
|
||||||
@ -47,7 +46,7 @@ public interface MpMessageService {
|
|||||||
WxMpXmlOutMessage sendOutMessage(@Valid MpMessageSendOutReqBO sendReqBO);
|
WxMpXmlOutMessage sendOutMessage(@Valid MpMessageSendOutReqBO sendReqBO);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 使用公众号,给用户发送【客服】消息
|
* 使用公众号,给粉丝发送【客服】消息
|
||||||
*
|
*
|
||||||
* 注意,该方法会真实发送消息
|
* 注意,该方法会真实发送消息
|
||||||
*
|
*
|
||||||
|
@ -63,7 +63,7 @@ public class MpMessageServiceImpl implements MpMessageService {
|
|||||||
private Validator validator;
|
private Validator validator;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PageResult<MpMessageDO> getWxFansMsgPage(MpMessagePageReqVO pageReqVO) {
|
public PageResult<MpMessageDO> getMessagePage(MpMessagePageReqVO pageReqVO) {
|
||||||
return mpMessageMapper.selectPage(pageReqVO);
|
return mpMessageMapper.selectPage(pageReqVO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ import java.util.List;
|
|||||||
/**
|
/**
|
||||||
* 公众号消息发送 Request BO
|
* 公众号消息发送 Request BO
|
||||||
*
|
*
|
||||||
* 为什么要有该 BO 呢?在自动回复、客服消息、菜单回复消息等场景,都涉及到 MP 给用户发送消息,所以使用该 BO 统一承接
|
* 为什么要有该 BO 呢?在自动回复、客服消息、菜单回复消息等场景,都涉及到 MP 给粉丝发送消息,所以使用该 BO 统一承接
|
||||||
*
|
*
|
||||||
* @author 芋道源码
|
* @author 芋道源码
|
||||||
*/
|
*/
|
||||||
@ -27,9 +27,9 @@ public class MpMessageSendOutReqBO {
|
|||||||
@NotEmpty(message = "公众号 appId 不能为空")
|
@NotEmpty(message = "公众号 appId 不能为空")
|
||||||
private String appId;
|
private String appId;
|
||||||
/**
|
/**
|
||||||
* 公众号用户 openid
|
* 公众号粉丝 openid
|
||||||
*/
|
*/
|
||||||
@NotEmpty(message = "公众号用户 openid 不能为空")
|
@NotEmpty(message = "公众号粉丝 openid 不能为空")
|
||||||
private String openid;
|
private String openid;
|
||||||
|
|
||||||
// ========== 消息内容 ==========
|
// ========== 消息内容 ==========
|
||||||
|
@ -16,20 +16,20 @@ import java.util.List;
|
|||||||
public interface MpStatisticsService {
|
public interface MpStatisticsService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取用户增减数据
|
* 获取粉丝增减数据
|
||||||
*
|
*
|
||||||
* @param accountId 公众号账号编号
|
* @param accountId 公众号账号编号
|
||||||
* @param date 时间区间
|
* @param date 时间区间
|
||||||
* @return 用户增减数据
|
* @return 粉丝增减数据
|
||||||
*/
|
*/
|
||||||
List<WxDataCubeUserSummary> getUserSummary(Long accountId, LocalDateTime[] date);
|
List<WxDataCubeUserSummary> getUserSummary(Long accountId, LocalDateTime[] date);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取用户累计数据
|
* 获取粉丝累计数据
|
||||||
*
|
*
|
||||||
* @param accountId 公众号账号编号
|
* @param accountId 公众号账号编号
|
||||||
* @param date 时间区间
|
* @param date 时间区间
|
||||||
* @return 用户累计数据
|
* @return 粉丝累计数据
|
||||||
*/
|
*/
|
||||||
List<WxDataCubeUserCumulate> getUserCumulate(Long accountId, LocalDateTime[] date);
|
List<WxDataCubeUserCumulate> getUserCumulate(Long accountId, LocalDateTime[] date);
|
||||||
|
|
||||||
|
@ -99,11 +99,11 @@ public class MpUserServiceImpl implements MpUserService {
|
|||||||
// for 循环,避免递归出意外问题,导致死循环
|
// for 循环,避免递归出意外问题,导致死循环
|
||||||
String nextOpenid = null;
|
String nextOpenid = null;
|
||||||
for (int i = 0; i < Short.MAX_VALUE; i++) {
|
for (int i = 0; i < Short.MAX_VALUE; i++) {
|
||||||
log.info("[syncUser][第({}) 次加载公众号用户列表,nextOpenid({})]", i, nextOpenid);
|
log.info("[syncUser][第({}) 次加载公众号粉丝列表,nextOpenid({})]", i, nextOpenid);
|
||||||
try {
|
try {
|
||||||
nextOpenid = syncUser0(account, nextOpenid);
|
nextOpenid = syncUser0(account, nextOpenid);
|
||||||
} catch (WxErrorException e) {
|
} catch (WxErrorException e) {
|
||||||
log.error("[syncUser][第({}) 次同步用户异常]", i, e);
|
log.error("[syncUser][第({}) 次同步粉丝异常]", i, e);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// 如果 nextOpenid 为空,表示已经同步完毕
|
// 如果 nextOpenid 为空,表示已经同步完毕
|
||||||
@ -114,17 +114,17 @@ public class MpUserServiceImpl implements MpUserService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String syncUser0(MpAccountDO account, String nextOpenid) throws WxErrorException {
|
private String syncUser0(MpAccountDO account, String nextOpenid) throws WxErrorException {
|
||||||
// 第一步,从公众号流式加载用户
|
// 第一步,从公众号流式加载粉丝
|
||||||
WxMpService mpService = mpServiceFactory.getRequiredMpService(account.getId());
|
WxMpService mpService = mpServiceFactory.getRequiredMpService(account.getId());
|
||||||
WxMpUserList wxUserList = mpService.getUserService().userList(nextOpenid);
|
WxMpUserList wxUserList = mpService.getUserService().userList(nextOpenid);
|
||||||
if (CollUtil.isEmpty(wxUserList.getOpenids())) {
|
if (CollUtil.isEmpty(wxUserList.getOpenids())) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 第二步,分批加载用户信息
|
// 第二步,分批加载粉丝信息
|
||||||
List<List<String>> openidsList = CollUtil.split(wxUserList.getOpenids(), 100);
|
List<List<String>> openidsList = CollUtil.split(wxUserList.getOpenids(), 100);
|
||||||
for (List<String> openids : openidsList) {
|
for (List<String> openids : openidsList) {
|
||||||
log.info("[syncUser][批量加载用户信息,openids({})]", openids);
|
log.info("[syncUser][批量加载粉丝信息,openids({})]", openids);
|
||||||
List<WxMpUser> wxUsers = mpService.getUserService().userInfoList(openids);
|
List<WxMpUser> wxUsers = mpService.getUserService().userInfoList(openids);
|
||||||
batchSaveUser(account, wxUsers);
|
batchSaveUser(account, wxUsers);
|
||||||
}
|
}
|
||||||
@ -137,7 +137,7 @@ public class MpUserServiceImpl implements MpUserService {
|
|||||||
if (CollUtil.isEmpty(wxUsers)) {
|
if (CollUtil.isEmpty(wxUsers)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 1. 获得数据库已保存的用户列表
|
// 1. 获得数据库已保存的粉丝列表
|
||||||
List<MpUserDO> dbUsers = mpUserMapper.selectListByAppIdAndOpenid(account.getAppId(),
|
List<MpUserDO> dbUsers = mpUserMapper.selectListByAppIdAndOpenid(account.getAppId(),
|
||||||
CollectionUtils.convertList(wxUsers, WxMpUser::getOpenId));
|
CollectionUtils.convertList(wxUsers, WxMpUser::getOpenId));
|
||||||
Map<String, MpUserDO> openId2Users = CollectionUtils.convertMap(dbUsers, MpUserDO::getOpenid);
|
Map<String, MpUserDO> openId2Users = CollectionUtils.convertMap(dbUsers, MpUserDO::getOpenid);
|
||||||
|
@ -9,7 +9,7 @@ export function getDraftPage(query) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建草稿
|
// 创建公众号草稿
|
||||||
export function createDraft(accountId, articles) {
|
export function createDraft(accountId, articles) {
|
||||||
return request({
|
return request({
|
||||||
url: '/mp/draft/create?accountId=' + accountId,
|
url: '/mp/draft/create?accountId=' + accountId,
|
||||||
@ -20,7 +20,7 @@ export function createDraft(accountId, articles) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新草稿
|
// 更新公众号草稿
|
||||||
export function updateDraft(accountId, mediaId, articles) {
|
export function updateDraft(accountId, mediaId, articles) {
|
||||||
return request({
|
return request({
|
||||||
url: '/mp/draft/update?accountId=' + accountId + '&mediaId=' + mediaId,
|
url: '/mp/draft/update?accountId=' + accountId + '&mediaId=' + mediaId,
|
||||||
@ -29,7 +29,7 @@ export function updateDraft(accountId, mediaId, articles) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除草稿
|
// 删除公众号草稿
|
||||||
export function deleteDraft(accountId, mediaId) {
|
export function deleteDraft(accountId, mediaId) {
|
||||||
return request({
|
return request({
|
||||||
url: '/mp/draft/delete?accountId=' + accountId + '&mediaId=' + mediaId,
|
url: '/mp/draft/delete?accountId=' + accountId + '&mediaId=' + mediaId,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import request from '@/utils/request'
|
import request from '@/utils/request'
|
||||||
|
|
||||||
// 获得粉丝消息分页
|
// 获得公众号消息分页
|
||||||
export function getMessagePage(query) {
|
export function getMessagePage(query) {
|
||||||
return request({
|
return request({
|
||||||
url: '/mp/message/page',
|
url: '/mp/message/page',
|
||||||
|
@ -60,6 +60,7 @@ export const DICT_TYPE = {
|
|||||||
|
|
||||||
// ========== MP 模块 ==========
|
// ========== MP 模块 ==========
|
||||||
MP_AUTO_REPLY_REQUEST_MATCH: 'mp_auto_reply_request_match', // 自动回复请求匹配类型
|
MP_AUTO_REPLY_REQUEST_MATCH: 'mp_auto_reply_request_match', // 自动回复请求匹配类型
|
||||||
|
MP_MESSAGE_TYPE: 'mp_message_type', // 消息类型
|
||||||
|
|
||||||
// ========== MALL - PRODUCT 模块 ==========
|
// ========== MALL - PRODUCT 模块 ==========
|
||||||
PRODUCT_SPU_STATUS: 'product_spu_status', // 商品 SPU 状态
|
PRODUCT_SPU_STATUS: 'product_spu_status', // 商品 SPU 状态
|
||||||
|
@ -50,49 +50,12 @@ SOFTWARE.
|
|||||||
</el-col>
|
</el-col>
|
||||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList" />
|
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList" />
|
||||||
</el-row>
|
</el-row>
|
||||||
<!-- 列表 -->
|
<!-- tab 项 -->
|
||||||
<el-tab-pane name="1">
|
<el-tab-pane name="1">
|
||||||
<span slot="label"><i class="el-icon-star-off"></i> 关注时回复</span>
|
<span slot="label"><i class="el-icon-star-off"></i> 关注时回复</span>
|
||||||
<el-table v-loading="loading" :data="list">
|
|
||||||
<el-table-column label="回复消息类型" align="center" prop="responseMessageType"/>
|
|
||||||
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
|
|
||||||
<template slot-scope="scope">
|
|
||||||
<span>{{ parseTime(scope.row.createTime) }}</span>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
|
||||||
<template slot-scope="scope">
|
|
||||||
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
|
|
||||||
v-hasPermi="['mp:auto-reply:update']">修改
|
|
||||||
</el-button>
|
|
||||||
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
|
|
||||||
v-hasPermi="['mp:auto-reply:delete']">删除
|
|
||||||
</el-button>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
</el-table>
|
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane name="2">
|
<el-tab-pane name="2">
|
||||||
<span slot="label"><i class="el-icon-chat-line-round"></i> 消息回复</span>
|
<span slot="label"><i class="el-icon-chat-line-round"></i> 消息回复</span>
|
||||||
<el-table v-loading="loading" :data="list">
|
|
||||||
<el-table-column label="请求消息类型" align="center" prop="requestMessageType"/>
|
|
||||||
<el-table-column label="回复消息类型" align="center" prop="responseMessageType"/>
|
|
||||||
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
|
|
||||||
<template slot-scope="scope">
|
|
||||||
<span>{{ parseTime(scope.row.createTime) }}</span>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
|
||||||
<template slot-scope="scope">
|
|
||||||
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
|
|
||||||
v-hasPermi="['mp:auto-reply:update']">修改
|
|
||||||
</el-button>
|
|
||||||
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
|
|
||||||
v-hasPermi="['mp:auto-reply:delete']">删除
|
|
||||||
</el-button>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
</el-table>
|
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane name="3">
|
<el-tab-pane name="3">
|
||||||
<span slot="label"><i class="el-icon-news"></i> 关键词回复</span>
|
<span slot="label"><i class="el-icon-news"></i> 关键词回复</span>
|
||||||
@ -101,13 +64,42 @@ SOFTWARE.
|
|||||||
|
|
||||||
<!-- 列表 -->
|
<!-- 列表 -->
|
||||||
<el-table v-loading="loading" :data="list">
|
<el-table v-loading="loading" :data="list">
|
||||||
<el-table-column label="关键词" align="center" prop="requestKeyword"/>
|
<el-table-column label="请求消息类型" align="center" prop="requestMessageType" v-if="type === '2'" />
|
||||||
<el-table-column label="匹配类型" align="center" prop="requestMatch">
|
<el-table-column label="关键词" align="center" prop="requestKeyword" v-if="type === '3'" />
|
||||||
|
<el-table-column label="匹配类型" align="center" prop="requestMatch" v-if="type === '3'">
|
||||||
<template v-slot="scope">
|
<template v-slot="scope">
|
||||||
<dict-tag :type="DICT_TYPE.MP_AUTO_REPLY_REQUEST_MATCH" :value="scope.row.requestMatch"/>
|
<dict-tag :type="DICT_TYPE.MP_AUTO_REPLY_REQUEST_MATCH" :value="scope.row.requestMatch"/>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="回复消息类型" align="center" prop="responseMessageType"/>
|
<el-table-column label="回复消息类型" align="center">
|
||||||
|
<template v-slot="scope">
|
||||||
|
<dict-tag :type="DICT_TYPE.MP_MESSAGE_TYPE" :value="scope.row.responseMessageType"/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="回复内容" align="center">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<div v-if="scope.row.responseMessageType === 'text'">{{ scope.row.responseContent }}</div>
|
||||||
|
<div v-else-if="scope.row.responseMessageType === 'voice'">
|
||||||
|
<wx-voice-player :url="scope.row.responseMediaUrl" />
|
||||||
|
</div>
|
||||||
|
<div v-else-if="scope.row.responseMessageType === 'image'">
|
||||||
|
<a target="_blank" :href="scope.row.responseMediaUrl">
|
||||||
|
<img :src="scope.row.responseMediaUrl" style="width: 100px">
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="scope.row.responseMessageType === 'video' || scope.row.responseMessageType === 'shortvideo'">
|
||||||
|
<wx-video-player :url="scope.row.responseMediaUrl" style="margin-top: 10px" />
|
||||||
|
</div>
|
||||||
|
<div v-else-if="scope.row.responseMessageType === 'news'">
|
||||||
|
<wx-news :articles="scope.row.responseArticles" />
|
||||||
|
</div>
|
||||||
|
<div v-else-if="scope.row.responseMessageType === 'music'">
|
||||||
|
<wx-music :title="scope.row.responseTitle" :description="scope.row.responseDescription"
|
||||||
|
:thumb-media-url="scope.row.responseThumbMediaUrl"
|
||||||
|
:music-url="scope.row.responseMusicUrl" :hq-music-url="scope.row.responseHqMusicUrl" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
|
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<span>{{ parseTime(scope.row.createTime) }}</span>
|
<span>{{ parseTime(scope.row.createTime) }}</span>
|
||||||
@ -130,9 +122,9 @@ SOFTWARE.
|
|||||||
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
|
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
|
||||||
<el-form-item label="消息类型" prop="requestMessageType" v-if="type === '2'">
|
<el-form-item label="消息类型" prop="requestMessageType" v-if="type === '2'">
|
||||||
<el-select v-model="form.requestMessageType" placeholder="请选择">
|
<el-select v-model="form.requestMessageType" placeholder="请选择">
|
||||||
<el-option v-for="item in dictData.get('wx_req_type')" :key="item.value" :label="item.label"
|
<el-option v-for="dict in this.getDictDatas(DICT_TYPE.MP_MESSAGE_TYPE)"
|
||||||
:value="item.value" :disabled="item.disabled" v-if="item.value !== 'event'">
|
:key="dict.value" :label="dict.label" :value="dict.value"
|
||||||
</el-option>
|
v-if="requestMessageTypes.includes(dict.value)"/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="匹配类型" prop="requestMatch" v-if="type === '3'">
|
<el-form-item label="匹配类型" prop="requestMatch" v-if="type === '3'">
|
||||||
@ -157,6 +149,12 @@ SOFTWARE.
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import WxVideoPlayer from '@/views/mp/components/wx-video-play/main.vue';
|
||||||
|
import WxVoicePlayer from '@/views/mp/components/wx-voice-play/main.vue';
|
||||||
|
import WxMsg from '@/views/mp/components/wx-msg/main.vue';
|
||||||
|
import WxLocation from '@/views/mp/components/wx-location/main.vue';
|
||||||
|
import WxMusic from '@/views/mp/components/wx-music/main.vue';
|
||||||
|
import WxNews from '@/views/mp/components/wx-news/main.vue';
|
||||||
import WxReplySelect from '@/views/mp/components/wx-reply/main.vue'
|
import WxReplySelect from '@/views/mp/components/wx-reply/main.vue'
|
||||||
import { getSimpleAccounts } from "@/api/mp/account";
|
import { getSimpleAccounts } from "@/api/mp/account";
|
||||||
import { createAutoReply, deleteAutoReply, getAutoReply, getAutoReplyPage, updateAutoReply } from "@/api/mp/autoReply";
|
import { createAutoReply, deleteAutoReply, getAutoReply, getAutoReplyPage, updateAutoReply } from "@/api/mp/autoReply";
|
||||||
@ -164,12 +162,20 @@ import { createAutoReply, deleteAutoReply, getAutoReply, getAutoReplyPage, updat
|
|||||||
export default {
|
export default {
|
||||||
name: 'mpAutoReply',
|
name: 'mpAutoReply',
|
||||||
components: {
|
components: {
|
||||||
|
WxVideoPlayer,
|
||||||
|
WxVoicePlayer,
|
||||||
|
WxMsg,
|
||||||
|
WxLocation,
|
||||||
|
WxMusic,
|
||||||
|
WxNews,
|
||||||
WxReplySelect
|
WxReplySelect
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
// tab 类型(1、关注时回复;2、消息回复;3、关键词回复)
|
// tab 类型(1、关注时回复;2、消息回复;3、关键词回复)
|
||||||
type: '3',
|
type: '3',
|
||||||
|
// 允许选择的请求消息类型
|
||||||
|
requestMessageTypes: ['text', 'image', 'voice', 'video', 'shortvideo', 'location', 'link'],
|
||||||
// 遮罩层
|
// 遮罩层
|
||||||
loading: true,
|
loading: true,
|
||||||
// 显示搜索条件
|
// 显示搜索条件
|
||||||
@ -202,8 +208,6 @@ export default {
|
|||||||
},
|
},
|
||||||
hackResetWxReplySelect: false, // 重置 WxReplySelect 组件,解决无法清除的问题
|
hackResetWxReplySelect: false, // 重置 WxReplySelect 组件,解决无法清除的问题
|
||||||
|
|
||||||
dictData: new Map(),
|
|
||||||
|
|
||||||
// 公众号账号列表
|
// 公众号账号列表
|
||||||
accounts: []
|
accounts: []
|
||||||
}
|
}
|
||||||
@ -218,33 +222,6 @@ export default {
|
|||||||
// 加载数据
|
// 加载数据
|
||||||
this.getList();
|
this.getList();
|
||||||
})
|
})
|
||||||
|
|
||||||
// TODO 芋艿:字典数据,一起搞
|
|
||||||
this.dictData.set('wx_req_type',[{
|
|
||||||
value: 'text',
|
|
||||||
label: '文本'
|
|
||||||
},{
|
|
||||||
value: 'image',
|
|
||||||
label: '图片'
|
|
||||||
},{
|
|
||||||
value: 'voice',
|
|
||||||
label: '语音'
|
|
||||||
},{
|
|
||||||
value: 'video',
|
|
||||||
label: '视频'
|
|
||||||
},{
|
|
||||||
value: 'shortvideo',
|
|
||||||
label: '小视频'
|
|
||||||
},{
|
|
||||||
value: 'location',
|
|
||||||
label: '地理位置'
|
|
||||||
},{
|
|
||||||
value: 'link',
|
|
||||||
label: '链接消息'
|
|
||||||
},{
|
|
||||||
value: 'event',
|
|
||||||
label: '事件推送'
|
|
||||||
}])
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
/** 查询列表 */
|
/** 查询列表 */
|
||||||
@ -295,7 +272,8 @@ export default {
|
|||||||
this.open = true
|
this.open = true
|
||||||
this.title = '新增自动回复';
|
this.title = '新增自动回复';
|
||||||
this.objData = {
|
this.objData = {
|
||||||
type : 'text'
|
type : 'text',
|
||||||
|
accountId: this.queryParams.accountId,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/** 修改按钮操作 */
|
/** 修改按钮操作 */
|
||||||
|
@ -9,13 +9,13 @@
|
|||||||
<div class="msg-main">
|
<div class="msg-main">
|
||||||
<div class="msg-div" :id="'msg-div' + nowStr">
|
<div class="msg-div" :id="'msg-div' + nowStr">
|
||||||
<!-- 加载更多 -->
|
<!-- 加载更多 -->
|
||||||
<div v-loading="tableLoading"></div>
|
<div v-loading="loading"></div>
|
||||||
<div v-if="!tableLoading">
|
<div v-if="!loading">
|
||||||
<div class="el-table__empty-block" v-if="loadMore" @click="loadingMore"><span class="el-table__empty-text">点击加载更多</span></div>
|
<div class="el-table__empty-block" v-if="loadMore" @click="loadingMore"><span class="el-table__empty-text">点击加载更多</span></div>
|
||||||
<div class="el-table__empty-block" v-if="!loadMore"><span class="el-table__empty-text">没有更多了</span></div>
|
<div class="el-table__empty-block" v-if="!loadMore"><span class="el-table__empty-text">没有更多了</span></div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 消息列表 -->
|
<!-- 消息列表 -->
|
||||||
<div class="execution" v-for="item in tableData" :key='item.id'>
|
<div class="execution" v-for="item in list" :key='item.id'>
|
||||||
<div class="avue-comment" :class="item.sendFrom === 2 ? 'avue-comment--reverse' : ''">
|
<div class="avue-comment" :class="item.sendFrom === 2 ? 'avue-comment--reverse' : ''">
|
||||||
<div class="avatar-div">
|
<div class="avatar-div">
|
||||||
<img :src="item.sendFrom === 1 ? user.avatar : mp.avatar" class="avue-comment__avatar">
|
<img :src="item.sendFrom === 1 ? user.avatar : mp.avatar" class="avue-comment__avatar">
|
||||||
@ -124,20 +124,20 @@ import { getUser } from "@/api/mp/user";
|
|||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
userId: {
|
userId: {
|
||||||
type: String,
|
type: Number,
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
nowStr: new Date().getTime(), // 当前的时间戳,用于每次消息加载后,回到原位置;具体见 :id="'msg-div' + nowStr" 处
|
nowStr: new Date().getTime(), // 当前的时间戳,用于每次消息加载后,回到原位置;具体见 :id="'msg-div' + nowStr" 处
|
||||||
sendLoading: false, // 发送消息是否加载中
|
loading: false, // 消息列表是否正在加载中
|
||||||
tableLoading: false, // 消息列表是否正在加载中
|
|
||||||
loadMore: true, // 是否可以加载更多
|
loadMore: true, // 是否可以加载更多
|
||||||
tableData: [], // 消息列表
|
list: [], // 消息列表
|
||||||
page: {
|
queryParams: {
|
||||||
pageNo: 1, // 当前页数
|
pageNo: 1, // 当前页数
|
||||||
pageSize: 14, // 每页显示多少条
|
pageSize: 14, // 每页显示多少条
|
||||||
|
accountId: undefined,
|
||||||
},
|
},
|
||||||
user: { // 由于微信不再提供昵称,直接使用“用户”展示
|
user: { // 由于微信不再提供昵称,直接使用“用户”展示
|
||||||
nickname: '用户',
|
nickname: '用户',
|
||||||
@ -148,6 +148,9 @@ import { getUser } from "@/api/mp/user";
|
|||||||
nickname: '公众号',
|
nickname: '公众号',
|
||||||
avatar: require("@/assets/images/wechat.png"),
|
avatar: require("@/assets/images/wechat.png"),
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// ========= 消息发送 =========
|
||||||
|
sendLoading: false, // 发送消息是否加载中
|
||||||
objData: { // 微信发送消息
|
objData: { // 微信发送消息
|
||||||
type: 'text',
|
type: 'text',
|
||||||
},
|
},
|
||||||
@ -156,14 +159,19 @@ import { getUser } from "@/api/mp/user";
|
|||||||
created() {
|
created() {
|
||||||
// 获得用户信息
|
// 获得用户信息
|
||||||
getUser(this.userId).then(response => {
|
getUser(this.userId).then(response => {
|
||||||
this.user.nickname = response.data.nickname | this.user.nickname;
|
this.user.nickname = response.data.nickname && response.data.nickname.length > 0 ?
|
||||||
this.user.avatar = response.data.avatar | this.user.avatar;
|
response.data.nickname : this.user.nickname;
|
||||||
|
this.user.avatar = response.data.avatar && this.user.avatar.length > 0 ?
|
||||||
|
response.data.avatar : this.user.avatar;
|
||||||
|
this.user.accountId = response.data.accountId;
|
||||||
// 设置公众号账号编号
|
// 设置公众号账号编号
|
||||||
|
this.queryParams.accountId = response.data.accountId;
|
||||||
this.objData.accountId = response.data.accountId;
|
this.objData.accountId = response.data.accountId;
|
||||||
})
|
|
||||||
|
|
||||||
// 加载消息
|
// 加载消息
|
||||||
this.refreshChange()
|
console.log(this.queryParams)
|
||||||
|
this.refreshChange()
|
||||||
|
})
|
||||||
},
|
},
|
||||||
methods:{
|
methods:{
|
||||||
sendMsg(){
|
sendMsg(){
|
||||||
@ -190,7 +198,7 @@ import { getUser } from "@/api/mp/user";
|
|||||||
})).then(response => {
|
})).then(response => {
|
||||||
this.sendLoading = false
|
this.sendLoading = false
|
||||||
// 添加到消息列表,并滚动
|
// 添加到消息列表,并滚动
|
||||||
this.tableData = [...this.tableData , ...[response.data] ]
|
this.list = [...this.list , ...[response.data] ]
|
||||||
this.scrollToBottom()
|
this.scrollToBottom()
|
||||||
// 重置 objData 状态
|
// 重置 objData 状态
|
||||||
this.$refs['replySelect'].deleteObj(); // 重置,避免 tab 的数据未清理
|
this.$refs['replySelect'].deleteObj(); // 重置,避免 tab 的数据未清理
|
||||||
@ -199,15 +207,16 @@ import { getUser } from "@/api/mp/user";
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
loadingMore() {
|
loadingMore() {
|
||||||
this.page.pageNo++
|
this.queryParams.pageNo++
|
||||||
this.getPage(this.page)
|
this.getPage(this.queryParams)
|
||||||
},
|
},
|
||||||
getPage(page, params) {
|
getPage(page, params) {
|
||||||
this.tableLoading = true
|
this.loading = true
|
||||||
getMessagePage(Object.assign({
|
getMessagePage(Object.assign({
|
||||||
pageNo: page.pageNo,
|
pageNo: page.pageNo,
|
||||||
pageSize: page.pageSize,
|
pageSize: page.pageSize,
|
||||||
userId: this.userId
|
userId: this.userId,
|
||||||
|
accountId: page.accountId,
|
||||||
}, params)).then(response => {
|
}, params)).then(response => {
|
||||||
// 计算当前的滚动高度
|
// 计算当前的滚动高度
|
||||||
const msgDiv = document.getElementById('msg-div' + this.nowStr);
|
const msgDiv = document.getElementById('msg-div' + this.nowStr);
|
||||||
@ -218,16 +227,16 @@ import { getUser } from "@/api/mp/user";
|
|||||||
|
|
||||||
// 处理数据
|
// 处理数据
|
||||||
const data = response.data.list.reverse();
|
const data = response.data.list.reverse();
|
||||||
this.tableData = [...data, ...this.tableData]
|
this.list = [...data, ...this.list]
|
||||||
this.tableLoading = false
|
this.loading = false
|
||||||
if (data.length < this.page.pageSize || data.length === 0){
|
if (data.length < this.queryParams.pageSize || data.length === 0){
|
||||||
this.loadMore = false
|
this.loadMore = false
|
||||||
}
|
}
|
||||||
this.page.pageNo = page.pageNo
|
this.queryParams.pageNo = page.pageNo
|
||||||
this.page.pageSize = page.pageSize
|
this.queryParams.pageSize = page.pageSize
|
||||||
|
|
||||||
// 滚动到原来的位置
|
// 滚动到原来的位置
|
||||||
if(this.page.pageNo === 1) { // 定位到消息底部
|
if(this.queryParams.pageNo === 1) { // 定位到消息底部
|
||||||
this.scrollToBottom()
|
this.scrollToBottom()
|
||||||
} else if (data.length !== 0) { // 定位滚动条
|
} else if (data.length !== 0) { // 定位滚动条
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
@ -242,7 +251,7 @@ import { getUser } from "@/api/mp/user";
|
|||||||
* 刷新回调
|
* 刷新回调
|
||||||
*/
|
*/
|
||||||
refreshChange() {
|
refreshChange() {
|
||||||
this.getPage(this.page)
|
this.getPage(this.queryParams)
|
||||||
},
|
},
|
||||||
/** 定位到消息底部 */
|
/** 定位到消息底部 */
|
||||||
scrollToBottom: function () {
|
scrollToBottom: function () {
|
||||||
@ -267,6 +276,8 @@ import { getUser } from "@/api/mp/user";
|
|||||||
height: 50vh;
|
height: 50vh;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
background-color: #eaeaea;
|
background-color: #eaeaea;
|
||||||
|
margin-left: 10px;
|
||||||
|
margin-right: 10px;
|
||||||
}
|
}
|
||||||
.msg-send {
|
.msg-send {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
|
@ -66,8 +66,8 @@ SOFTWARE.
|
|||||||
<div class="menu_bottom menu_addicon" v-if="this.menuList.length < 3" @click="addMenu"><i class="el-icon-plus"></i></div>
|
<div class="menu_bottom menu_addicon" v-if="this.menuList.length < 3" @click="addMenu"><i class="el-icon-plus"></i></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="save_div">
|
<div class="save_div">
|
||||||
<el-button class="save_btn" type="success" size="small" @click="handleSave">保存并发布菜单</el-button>
|
<el-button class="save_btn" type="success" size="small" @click="handleSave" v-hasPermi="['mp:menu:save']">保存并发布菜单</el-button>
|
||||||
<el-button class="save_btn" type="danger" size="small" @click="handleDelete">清空菜单</el-button>
|
<el-button class="save_btn" type="danger" size="small" @click="handleDelete" v-hasPermi="['mp:menu:delete']">清空菜单</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!--右边配置-->
|
<!--右边配置-->
|
||||||
|
@ -8,18 +8,19 @@
|
|||||||
<el-option v-for="item in accounts" :key="parseInt(item.id)" :label="item.name" :value="parseInt(item.id)" />
|
<el-option v-for="item in accounts" :key="parseInt(item.id)" :label="item.name" :value="parseInt(item.id)" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<!-- 等待处理 -->
|
<!-- TODO 等待处理 -->
|
||||||
<el-form-item label="消息类型" prop="msgType">
|
<el-form-item label="消息类型" prop="type">
|
||||||
<el-select v-model="queryParams.msgType" placeholder="请选择消息类型" clearable size="small">
|
<el-select v-model="queryParams.type" placeholder="请选择消息类型" clearable size="small">
|
||||||
<el-option label="请选择字典生成" value=""/>
|
<el-option v-for="dict in this.getDictDatas(DICT_TYPE.MP_MESSAGE_TYPE)"
|
||||||
|
:key="dict.value" :label="dict.label" :value="dict.value"/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="用户标识" prop="openid">
|
<el-form-item label="用户标识" prop="openid">
|
||||||
<el-input v-model="queryParams.openid" placeholder="请输入用户标识" clearable @keyup.enter.native="handleQuery"/>
|
<el-input v-model="queryParams.openid" placeholder="请输入用户标识" clearable @keyup.enter.native="handleQuery"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="创建时间">
|
<el-form-item label="创建时间" prop="createTime">
|
||||||
<el-date-picker v-model="dateRangeCreateTime" style="width: 240px" value-format="yyyy-MM-dd"
|
<el-date-picker v-model="queryParams.createTime" style="width: 240px" value-format="yyyy-MM-dd HH:mm:ss" type="daterange"
|
||||||
type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"/>
|
range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" :default-time="['00:00:00', '23:59:59']" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
|
<el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
|
||||||
@ -42,12 +43,11 @@
|
|||||||
<el-table-column label="消息类型" align="center" prop="type" width="80"/>
|
<el-table-column label="消息类型" align="center" prop="type" width="80"/>
|
||||||
<el-table-column label="发送方" align="center" prop="sendFrom" width="80">
|
<el-table-column label="发送方" align="center" prop="sendFrom" width="80">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-tag v-if="scope.row.sendFrom === 1" type="success">用户</el-tag>
|
<el-tag v-if="scope.row.sendFrom === 1" type="success">粉丝</el-tag>
|
||||||
<el-tag v-else type="info">公众号</el-tag>
|
<el-tag v-else type="info">公众号</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="用户标识" align="center" prop="openid" width="300" />
|
<el-table-column label="用户标识" align="center" prop="openid" width="300" />
|
||||||
<!-- TODO 芋艿:发送/接收 -->
|
|
||||||
<el-table-column label="内容" prop="content">
|
<el-table-column label="内容" prop="content">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<!-- 【事件】区域 -->
|
<!-- 【事件】区域 -->
|
||||||
@ -118,10 +118,9 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<!-- TODO 芋艿:增加消息按钮 -->
|
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleSend(scope.row)"
|
||||||
<!-- <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"-->
|
v-hasPermi="['mp:message:send']">消息
|
||||||
<!-- v-hasPermi="['mp:message:update']">修改-->
|
</el-button>
|
||||||
<!-- </el-button>-->
|
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
@ -129,24 +128,26 @@
|
|||||||
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
|
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
|
||||||
@pagination="getList"/>
|
@pagination="getList"/>
|
||||||
|
|
||||||
<el-dialog title="用户消息" :visible.sync="open" width="40%">
|
<!-- 发送消息的弹窗 -->
|
||||||
<wx-msg user-id="3" v-if="true" />
|
<el-dialog title="粉丝消息列表" :visible.sync="open" width="50%">
|
||||||
|
<wx-msg :user-id="userId" v-if="open" />
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { getMessagePage } from "@/api/mp/message";
|
|
||||||
import WxVideoPlayer from '@/views/mp/components/wx-video-play/main.vue';
|
import WxVideoPlayer from '@/views/mp/components/wx-video-play/main.vue';
|
||||||
import WxVoicePlayer from '@/views/mp/components/wx-voice-play/main.vue';
|
import WxVoicePlayer from '@/views/mp/components/wx-voice-play/main.vue';
|
||||||
import WxMsg from '@/views/mp/components/wx-msg/main.vue';
|
import WxMsg from '@/views/mp/components/wx-msg/main.vue';
|
||||||
import WxLocation from '@/views/mp/components/wx-location/main.vue';
|
import WxLocation from '@/views/mp/components/wx-location/main.vue';
|
||||||
import WxMusic from '@/views/mp/components/wx-music/main.vue';
|
import WxMusic from '@/views/mp/components/wx-music/main.vue';
|
||||||
import WxNews from '@/views/mp/components/wx-news/main.vue';
|
import WxNews from '@/views/mp/components/wx-news/main.vue';
|
||||||
|
import { getMessagePage } from "@/api/mp/message";
|
||||||
|
import { getSimpleAccounts } from "@/api/mp/account";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "WxFansMsg",
|
name: "MpMessage",
|
||||||
components: {
|
components: {
|
||||||
WxVideoPlayer,
|
WxVideoPlayer,
|
||||||
WxVoicePlayer,
|
WxVoicePlayer,
|
||||||
@ -167,76 +168,52 @@ export default {
|
|||||||
total: 0,
|
total: 0,
|
||||||
// 粉丝消息列表
|
// 粉丝消息列表
|
||||||
list: [],
|
list: [],
|
||||||
// 弹出层标题
|
|
||||||
title: "",
|
|
||||||
// 是否显示弹出层
|
// 是否显示弹出层
|
||||||
open: true,
|
open: false,
|
||||||
// 查询参数
|
// 查询参数
|
||||||
dateRangeCreateTime: [],
|
|
||||||
queryParams: {
|
queryParams: {
|
||||||
pageNo: 1,
|
pageNo: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
openid: null,
|
openid: null,
|
||||||
nickname: null,
|
accountId: null,
|
||||||
headimgUrl: null,
|
type: null,
|
||||||
wxAccountId: null,
|
createTime: []
|
||||||
msgType: null,
|
|
||||||
content: null,
|
|
||||||
resContent: null,
|
|
||||||
isRes: null,
|
|
||||||
mediaId: null,
|
|
||||||
picUrl: null,
|
|
||||||
picPath: null,
|
|
||||||
},
|
},
|
||||||
// 表单参数
|
// 操作的用户编号
|
||||||
form: {},
|
userId: 0,
|
||||||
// 表单校验
|
|
||||||
rules: {},
|
|
||||||
|
|
||||||
// 公众号账号列表
|
// 公众号账号列表
|
||||||
accounts: []
|
accounts: []
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.getList();
|
getSimpleAccounts().then(response => {
|
||||||
|
this.accounts = response.data;
|
||||||
|
// 默认选中第一个
|
||||||
|
if (this.accounts.length > 0) {
|
||||||
|
this.queryParams.accountId = this.accounts[0].id;
|
||||||
|
}
|
||||||
|
// 加载数据
|
||||||
|
this.getList();
|
||||||
|
})
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
/** 查询列表 */
|
/** 查询列表 */
|
||||||
getList() {
|
getList() {
|
||||||
|
// 如果没有选中公众号账号,则进行提示。
|
||||||
|
if (!this.queryParams.accountId) {
|
||||||
|
this.$message.error('未选中公众号,无法查询消息')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
// 处理查询参数
|
|
||||||
let params = {...this.queryParams};
|
|
||||||
this.addBeginAndEndTime(params, this.dateRangeCreateTime, 'createTime');
|
|
||||||
// 执行查询
|
// 执行查询
|
||||||
getMessagePage(params).then(response => {
|
getMessagePage(this.queryParams).then(response => {
|
||||||
this.list = response.data.list;
|
this.list = response.data.list;
|
||||||
this.total = response.data.total;
|
this.total = response.data.total;
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
/** 取消按钮 */
|
|
||||||
cancel() {
|
|
||||||
this.open = false;
|
|
||||||
this.reset();
|
|
||||||
},
|
|
||||||
/** 表单重置 */
|
|
||||||
reset() {
|
|
||||||
this.form = {
|
|
||||||
id: undefined,
|
|
||||||
openid: undefined,
|
|
||||||
nickname: undefined,
|
|
||||||
headimgUrl: undefined,
|
|
||||||
wxAccountId: undefined,
|
|
||||||
msgType: undefined,
|
|
||||||
content: undefined,
|
|
||||||
resContent: undefined,
|
|
||||||
isRes: undefined,
|
|
||||||
mediaId: undefined,
|
|
||||||
picUrl: undefined,
|
|
||||||
picPath: undefined,
|
|
||||||
};
|
|
||||||
this.resetForm("form");
|
|
||||||
},
|
|
||||||
/** 搜索按钮操作 */
|
/** 搜索按钮操作 */
|
||||||
handleQuery() {
|
handleQuery() {
|
||||||
this.queryParams.pageNo = 1;
|
this.queryParams.pageNo = 1;
|
||||||
@ -244,10 +221,17 @@ export default {
|
|||||||
},
|
},
|
||||||
/** 重置按钮操作 */
|
/** 重置按钮操作 */
|
||||||
resetQuery() {
|
resetQuery() {
|
||||||
this.dateRangeCreateTime = [];
|
|
||||||
this.resetForm("queryForm");
|
this.resetForm("queryForm");
|
||||||
|
// 默认选中第一个
|
||||||
|
if (this.accounts.length > 0) {
|
||||||
|
this.queryParams.accountId = this.accounts[0].id;
|
||||||
|
}
|
||||||
this.handleQuery();
|
this.handleQuery();
|
||||||
},
|
},
|
||||||
|
handleSend(row) {
|
||||||
|
this.userId = row.userId;
|
||||||
|
this.open = true;
|
||||||
|
},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
@ -77,7 +77,7 @@ require('echarts/lib/component/legend')
|
|||||||
import { getInterfaceSummary, getUserSummary, getUserCumulate, getUpstreamMessage} from '@/api/mp/statistics'
|
import { getInterfaceSummary, getUserSummary, getUserCumulate, getUpstreamMessage} from '@/api/mp/statistics'
|
||||||
import { datePickerOptions } from "@/utils/constants";
|
import { datePickerOptions } from "@/utils/constants";
|
||||||
import {addTime, beginOfDay, betweenDay, endOfDay, formatDate} from "@/utils/dateUtils";
|
import {addTime, beginOfDay, betweenDay, endOfDay, formatDate} from "@/utils/dateUtils";
|
||||||
import {getSimpleAccounts} from "@/api/mp/account";
|
import { getSimpleAccounts } from "@/api/mp/account";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'mpStatistics',
|
name: 'mpStatistics',
|
||||||
|
Loading…
Reference in New Issue
Block a user