完成支付、电子面单、模板消息队列等功能

This commit is contained in:
hupeng
2023-07-25 23:45:57 +08:00
parent f8f699fe6a
commit 0ae51f9ee7
625 changed files with 8291 additions and 18630 deletions

View File

@ -33,6 +33,11 @@
<artifactId>yshop-module-infra-api</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>co.yixiang.boot</groupId>
<artifactId>yshop-module-member-api</artifactId>
<version>${revision}</version>
</dependency>
<!-- 业务组件 -->
<dependency>

View File

@ -16,7 +16,7 @@ public class MpAccountRespVO extends MpAccountBaseVO {
@Schema(description = "编号", required = true, example = "1024")
private Long id;
@Schema(description = "二维码图片URL", example = "https://www.iocoder.cn/1024.png")
@Schema(description = "二维码图片URL", example = "https://www.yixiang.co/1024.png")
private String qrCodeUrl;
@Schema(description = "创建时间", required = true)

View File

@ -1,5 +0,0 @@
### 请求 /mp/material/page 接口 => 成功
GET {{baseUrl}}/mp/material/page?permanent=true&pageNo=1&pageSize=10
Content-Type: application/json
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}

View File

@ -26,11 +26,11 @@ public class MpMaterialRespVO {
@Schema(description = "是否永久 true - 永久false - 临时", required = true, example = "true")
private Boolean permanent;
@Schema(description = "素材的 URL", required = true, example = "https://www.iocoder.cn/1.png")
@Schema(description = "素材的 URL", required = true, example = "https://www.yixiang.co/1.png")
private String url;
@Schema(description = "名字", example = "yunai.png")
@Schema(description = "名字", example = "yshop.png")
private String name;
@Schema(description = "公众号文件 URL 只有【永久素材】使用", example = "https://mmbiz.qpic.cn/xxx.mp3")

View File

@ -10,7 +10,7 @@ public class MpMaterialUploadRespVO {
@Schema(description = "素材的 media_id", required = true, example = "123")
private String mediaId;
@Schema(description = "素材的 URL", required = true, example = "https://www.iocoder.cn/1.png")
@Schema(description = "素材的 URL", required = true, example = "https://www.yixiang.co/1.png")
private String url;
}

View File

@ -1,50 +0,0 @@
### 请求 /mp/menu/save 接口 => 成功
POST {{baseUrl}}/mp/menu/save
Content-Type: application/json
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}
{
"accountId": "1",
"menus": [
{
"type":"click",
"name":"今日歌曲",
"menuKey":"V1001_TODAY_MUSIC"
},
{
"name":"搜索",
"type":"view",
"url":"https://www.soso.com/"
},
{
"name": "父按钮",
"children": [
{
"type":"click",
"name":"归去来兮",
"menuKey":"MUSIC"
},
{
"name":"不说",
"type":"view",
"url":"https://www.soso.com/"
}]
}]
}
### 请求 /mp/menu/save 接口 => 成功(清空)
POST {{baseUrl}}/mp/menu/save
Content-Type: application/json
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}
{
"accountId": "1",
"menus": []
}
### 请求 /mp/menu/list 接口 => 成功
GET {{baseUrl}}/mp/menu/list?accountId=1
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}

View File

@ -44,7 +44,7 @@ public class MpMenuBaseVO {
*/
private String type;
@Schema(description = "网页链接", example = "https://www.iocoder.cn/")
@Schema(description = "网页链接", example = "https://www.yixiang.co/")
@NotEmpty(message = "网页链接不能为空", groups = {ViewButtonGroup.class, MiniProgramButtonGroup.class})
@URL(message = "网页链接必须是 URL 格式")
private String url;
@ -75,7 +75,7 @@ public class MpMenuBaseVO {
@NotEmpty(message = "回复的消息 mediaId 不能为空",
groups = {ImageMessageGroup.class, VoiceMessageGroup.class, VideoMessageGroup.class})
private String replyMediaId;
@Schema(description = "回复的媒体 URL", example = "https://www.iocoder.cn/xxx.jpg")
@Schema(description = "回复的媒体 URL", example = "https://www.yixiang.co/xxx.jpg")
@NotEmpty(message = "回复的消息 mediaId 不能为空",
groups = {ImageMessageGroup.class, VoiceMessageGroup.class, VideoMessageGroup.class})
private String replyMediaUrl;
@ -83,7 +83,7 @@ public class MpMenuBaseVO {
@Schema(description = "缩略图的媒体 id", example = "123456")
@NotEmpty(message = "回复的消息 thumbMediaId 不能为空", groups = {MusicMessageGroup.class})
private String replyThumbMediaId;
@Schema(description = "缩略图的媒体 URL",example = "https://www.iocoder.cn/xxx.jpg")
@Schema(description = "缩略图的媒体 URL",example = "https://www.yixiang.co/xxx.jpg")
@NotEmpty(message = "回复的消息 thumbMedia 地址不能为空", groups = {MusicMessageGroup.class})
private String replyThumbMediaUrl;
@ -103,11 +103,11 @@ public class MpMenuBaseVO {
@Valid
private List<MpMessageDO.Article> replyArticles;
@Schema(description = "回复的音乐链接", example = "https://www.iocoder.cn/xxx.mp3")
@Schema(description = "回复的音乐链接", example = "https://www.yixiang.co/xxx.mp3")
@NotEmpty(message = "回复的音乐链接不能为空", groups = MusicMessageGroup.class)
@URL(message = "回复的高质量音乐链接格式不正确", groups = MusicMessageGroup.class)
private String replyMusicUrl;
@Schema(description = "高质量音乐链接", example = "https://www.iocoder.cn/xxx.mp3")
@Schema(description = "高质量音乐链接", example = "https://www.yixiang.co/xxx.mp3")
@NotEmpty(message = "回复的高质量音乐链接不能为空", groups = MusicMessageGroup.class)
@URL(message = "回复的高质量音乐链接格式不正确", groups = MusicMessageGroup.class)
private String replyHqMusicUrl;

View File

@ -1,5 +0,0 @@
### 请求 /mp/message/page 接口 => 成功
GET {{baseUrl}}/mp/auto-reply/page?accountId=1&pageNo=1&pageSize=10
Content-Type: application/json
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}

View File

@ -1,33 +0,0 @@
### 请求 /mp/message/page 接口 => 成功
GET {{baseUrl}}/mp/message/page?accountId=1&pageNo=1&pageSize=10
Content-Type: application/json
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}
### 请求 /mp/message/send 接口 => 成功(文本)
POST {{baseUrl}}/mp/message/send
Content-Type: application/json
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}
{
"userId": 3,
"type": "text",
"content": "测试消息"
}
### 请求 /mp/message/send 接口 => 成功(音乐)
POST {{baseUrl}}/mp/message/send
Content-Type: application/json
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}
{
"userId": 3,
"type": "music",
"title": "测试音乐标题",
"description": "测试音乐内容",
"musicUrl": "https://www.iocoder.cn/xx.mp3",
"hqMusicUrl": "https://www.iocoder.cn/xx_high.mp3",
"thumbMediaId": "s98Iveeg9vDVFwa9q0u8-zSfdKe3xIzAm7wCrFE4WKGPIo4d9qAhtC-n6qvnyWyH"
}

View File

@ -50,7 +50,7 @@ public class MpAutoReplyBaseVO {
@NotEmpty(message = "回复的消息 mediaId 不能为空",
groups = {ImageMessageGroup.class, VoiceMessageGroup.class, VideoMessageGroup.class})
private String responseMediaId;
@Schema(description = "回复的媒体 URL", example = "https://www.iocoder.cn/xxx.jpg")
@Schema(description = "回复的媒体 URL", example = "https://www.yixiang.co/xxx.jpg")
@NotEmpty(message = "回复的消息 mediaId 不能为空",
groups = {ImageMessageGroup.class, VoiceMessageGroup.class, VideoMessageGroup.class})
private String responseMediaUrl;
@ -58,7 +58,7 @@ public class MpAutoReplyBaseVO {
@Schema(description = "缩略图的媒体 id", example = "123456")
@NotEmpty(message = "回复的消息 thumbMediaId 不能为空", groups = {MusicMessageGroup.class})
private String responseThumbMediaId;
@Schema(description = "缩略图的媒体 URL",example = "https://www.iocoder.cn/xxx.jpg")
@Schema(description = "缩略图的媒体 URL",example = "https://www.yixiang.co/xxx.jpg")
@NotEmpty(message = "回复的消息 thumbMedia 地址不能为空", groups = {MusicMessageGroup.class})
private String responseThumbMediaUrl;
@ -78,11 +78,11 @@ public class MpAutoReplyBaseVO {
@Valid
private List<MpMessageDO.Article> responseArticles;
@Schema(description = "回复的音乐链接", example = "https://www.iocoder.cn/xxx.mp3")
@Schema(description = "回复的音乐链接", example = "https://www.yixiang.co/xxx.mp3")
@NotEmpty(message = "回复的音乐链接不能为空", groups = MusicMessageGroup.class)
@URL(message = "回复的高质量音乐链接格式不正确", groups = MusicMessageGroup.class)
private String responseMusicUrl;
@Schema(description = "高质量音乐链接", example = "https://www.iocoder.cn/xxx.mp3")
@Schema(description = "高质量音乐链接", example = "https://www.yixiang.co/xxx.mp3")
@NotEmpty(message = "回复的高质量音乐链接不能为空", groups = MusicMessageGroup.class)
@URL(message = "回复的高质量音乐链接格式不正确", groups = MusicMessageGroup.class)
private String responseHqMusicUrl;

View File

@ -41,7 +41,7 @@ public class MpMessageRespVO {
@Schema(description = "媒体素材的编号 消息类型为 image、voice、video 时,才有值", example = "1234567890")
private String mediaId;
@Schema(description = "媒体文件的 URL 消息类型为 image、voice、video 时,才有值", example = "https://www.iocoder.cn/xxx.png")
@Schema(description = "媒体文件的 URL 消息类型为 image、voice、video 时,才有值", example = "https://www.yixiang.co/xxx.png")
private String mediaUrl;
@Schema(description = "语音识别后文本 消息类型为 voice 时,才有值", example = "语音识别后文本")
@ -57,10 +57,10 @@ public class MpMessageRespVO {
@Schema(description = "缩略图的媒体 id 消息类型为 video、music 时,才有值", example = "1234567890")
private String thumbMediaId;
@Schema(description = "缩略图的媒体 URL 消息类型为 video、music 时,才有值", example = "https://www.iocoder.cn/xxx.png")
@Schema(description = "缩略图的媒体 URL 消息类型为 video、music 时,才有值", example = "https://www.yixiang.co/xxx.png")
private String thumbMediaUrl;
@Schema(description = "点击图文消息跳转链接 消息类型为 link 时,才有值", example = "https://www.iocoder.cn")
@Schema(description = "点击图文消息跳转链接 消息类型为 link 时,才有值", example = "https://www.yixiang.co")
private String url;
@Schema(description = "地理位置维度 消息类型为 location 时,才有值", example = "23.137466")
@ -83,9 +83,9 @@ public class MpMessageRespVO {
@TableField(typeHandler = MpMessageDO.ArticleTypeHandler.class)
private List<MpMessageDO.Article> articles;
@Schema(description = "音乐链接 消息类型为 music 时,才有值", example = "https://www.iocoder.cn/xxx.mp3")
@Schema(description = "音乐链接 消息类型为 music 时,才有值", example = "https://www.yixiang.co/xxx.mp3")
private String musicUrl;
@Schema(description = "高质量音乐链接 消息类型为 music 时,才有值", example = "https://www.iocoder.cn/xxx.mp3")
@Schema(description = "高质量音乐链接 消息类型为 music 时,才有值", example = "https://www.yixiang.co/xxx.mp3")
private String hqMusicUrl;
// ========= 事件推送 https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Receiving_event_pushes.html

View File

@ -49,10 +49,10 @@ public class MpMessageSendReqVO {
@NotNull(message = "图文消息不能为空", groups = NewsMessageGroup.class)
private List<MpMessageDO.Article> articles;
@Schema(description = "音乐链接 消息类型为 MUSIC 时", example = "https://www.iocoder.cn/music.mp3")
@Schema(description = "音乐链接 消息类型为 MUSIC 时", example = "https://www.yixiang.co/music.mp3")
private String musicUrl;
@Schema(description = "高质量音乐链接 消息类型为 MUSIC 时", example = "https://www.iocoder.cn/music.mp3")
@Schema(description = "高质量音乐链接 消息类型为 MUSIC 时", example = "https://www.yixiang.co/music.mp3")
private String hqMusicUrl;
}

View File

@ -1,54 +0,0 @@
### 请求 /mp/draft/page 接口 => 成功
GET {{baseUrl}}/mp/draft/page?accountId=1&pageNo=1&pageSize=10
Content-Type: application/json
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}
### 请求 /mp/draft/create 接口 => 成功
POST {{baseUrl}}/mp/draft/create?accountId=1
Content-Type: application/json
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}
{
"articles": [
{
"title": "我是标题",
"author": "我是作者",
"digest": "我是摘要",
"content": "我是内容",
"contentSourceUrl": "https://www.iocoder.cn",
"thumbMediaId": "r6ryvl6LrxBU0miaST4Y-pIcmK-zAAId-9TGgy-DrSLhjVuWbuT3ZBjk9K1yQ0Dn"
},
{
"title": "我是标题 2",
"author": "我是作者 2",
"digest": "我是摘要 2",
"content": "我是内容 2",
"contentSourceUrl": "https://www.iocoder.cn",
"thumbMediaId": "r6ryvl6LrxBU0miaST4Y-pIcmK-zAAId-9TGgy-DrSLhjVuWbuT3ZBjk9K1yQ0Dn"
}
]
}
### 请求 /mp/draft/create 接口 => 成功
PUT {{baseUrl}}/mp/draft/update?accountId=1&mediaId=r6ryvl6LrxBU0miaST4Y-q-G9pdsmZw0OYG4FzHQkKfpLfEwIH51wy2bxisx8PvW
Content-Type: application/json
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}
[{
"title": "我是标题OOO",
"author": "我是作者",
"digest": "我是摘要",
"content": "我是内容",
"contentSourceUrl": "https://www.iocoder.cn",
"thumbMediaId": "r6ryvl6LrxBU0miaST4Y-pIcmK-zAAId-9TGgy-DrSLhjVuWbuT3ZBjk9K1yQ0Dn"
}, {
"title": "我是标题XXX",
"author": "我是作者",
"digest": "我是摘要",
"content": "我是内容",
"contentSourceUrl": "https://www.iocoder.cn",
"thumbMediaId": "r6ryvl6LrxBU0miaST4Y-pIcmK-zAAId-9TGgy-DrSLhjVuWbuT3ZBjk9K1yQ0Dn"
}]

View File

@ -1,13 +0,0 @@
### 请求 /mp/free-publish/page 接口 => 成功
GET {{baseUrl}}/mp/free-publish/page?accountId=1&pageNo=1&pageSize=10
Content-Type: application/json
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}
### 请求 /mp/free-publish/submit 接口 => 成功
POST {{baseUrl}}/mp/free-publish/submit?accountId=1&mediaId=r6ryvl6LrxBU0miaST4Y-vilmd7iS51D8IPddxflWrau0hIQ2ovY8YanO5jlgUcM
Content-Type: application/json
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}
{}

View File

@ -1,39 +0,0 @@
### 请求 /mp/tag/create 接口 => 成功
POST {{baseUrl}}/mp/tag/create
Content-Type: application/json
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}
{
"accountId": "1",
"name": "测试"
}
### 请求 /mp/tag/update 接口 => 成功
PUT {{baseUrl}}/mp/tag/update
Content-Type: application/json
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}
{
"id": "3",
"name": "测试标签啦"
}
### 请求 /mp/tag/delete 接口 => 成功
DELETE {{baseUrl}}/mp/tag/delete?id=3
Content-Type: application/json
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}
### 请求 /mp/tag/page 接口 => 成功
GET {{baseUrl}}/mp/tag/page?accountId=1&pageNo=1&pageSize=10
Content-Type: application/json
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}
### 请求 /mp/tag/sync 接口 => 成功
POST {{baseUrl}}/mp/tag/sync?accountId=1
Content-Type: application/json
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}

View File

@ -1,18 +0,0 @@
### 请求 /mp/user/sync 接口 => 成功
POST {{baseUrl}}/mp/user/sync?accountId=1
Content-Type: application/json
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}
### 请求 /mp/user/update 接口 => 成功
PUT {{baseUrl}}/mp/user/update
Content-Type: application/json
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}
{
"id": "3",
"nickname": "test",
"remark": "测试备注",
"tagIds": [103, 104]
}

View File

@ -26,7 +26,7 @@ public class MpUserRespVO {
@Schema(description = "昵称", example = "yshop")
private String nickname;
@Schema(description = "头像地址", example = "https://www.iocoder.cn/1.png")
@Schema(description = "头像地址", example = "https://www.yixiang.co/1.png")
private String headImageUrl;
@Schema(description = "语言", example = "zh_CN")
private String language;

View File

@ -5,6 +5,8 @@ import cn.hutool.core.util.StrUtil;
import co.yixiang.yshop.framework.common.enums.CommonStatusEnum;
import co.yixiang.yshop.framework.common.pojo.PageResult;
import co.yixiang.yshop.framework.common.util.collection.CollectionUtils;
import co.yixiang.yshop.module.member.api.user.MemberUserApi;
import co.yixiang.yshop.module.member.api.user.dto.WechatUserDto;
import co.yixiang.yshop.module.mp.controller.admin.user.vo.MpUserPageReqVO;
import co.yixiang.yshop.module.mp.controller.admin.user.vo.MpUserUpdateReqVO;
import co.yixiang.yshop.module.mp.convert.user.MpUserConvert;
@ -55,6 +57,9 @@ public class MpUserServiceImpl implements MpUserService {
@Resource
private MpUserMapper mpUserMapper;
@Resource
private MemberUserApi memberUserApi;
@Override
public MpUserDO getUser(Long id) {
return mpUserMapper.selectById(id);
@ -85,6 +90,13 @@ public class MpUserServiceImpl implements MpUserService {
MpUserDO dbUser = mpUserMapper.selectByAppIdAndOpenid(appId, wxMpUser.getOpenId());
if (dbUser == null) {
mpUserMapper.insert(user);
WechatUserDto wechatUserDto = WechatUserDto.builder()
.openid(wxMpUser.getOpenId())
.nickname(wxMpUser.getLanguage())
.headimgurl(wxMpUser.getLanguage())
.build();
memberUserApi.saveWechatMember(wechatUserDto);
} else {
user.setId(dbUser.getId());
mpUserMapper.updateById(user);