feat: 支持微信通知
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Volo.Abp.Application.Services;
|
||||
using Volo.Abp.Caching;
|
||||
using Volo.Abp.EventBus.Local;
|
||||
using Volo.Abp.Users;
|
||||
using Yi.Framework.Bbs.Domain.Shared.Etos;
|
||||
using Yi.Framework.DigitalCollectibles.Application.Contracts.Dtos.Account;
|
||||
using Yi.Framework.DigitalCollectibles.Domain.Shared.Caches;
|
||||
using Yi.Framework.DigitalCollectibles.Domain.Shared.Consts;
|
||||
using Yi.Framework.DigitalCollectibles.Domain.Shared.Enums;
|
||||
using Yi.Framework.DigitalCollectibles.Domain.Shared.Etos;
|
||||
@@ -25,6 +27,8 @@ public class WeChatMiniProgramAccountService : ApplicationService
|
||||
private readonly IAuthService _authService;
|
||||
private readonly IAccountService _accountService;
|
||||
private readonly ILocalEventBus _localEventBus;
|
||||
private readonly IDistributedCache<WeChatNoticeCacheItem> _noticeCache;
|
||||
|
||||
public WeChatMiniProgramAccountService(IWeChatMiniProgramManager weChatMiniProgramManager, IAuthService authService,
|
||||
IAccountService accountService, ILocalEventBus localEventBus)
|
||||
{
|
||||
@@ -34,6 +38,32 @@ public class WeChatMiniProgramAccountService : ApplicationService
|
||||
_localEventBus = localEventBus;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置用户一次性订阅状态
|
||||
/// </summary>
|
||||
[HttpPut("wechat/mini-program/notice/subscribe")]
|
||||
[Authorize]
|
||||
public async Task PutSubscribeNoticeStateAsync()
|
||||
{
|
||||
var userId = CurrentUser.GetId();
|
||||
await _noticeCache.SetAsync($"MiniProgram:notice:{userId}", new WeChatNoticeCacheItem(true));
|
||||
}
|
||||
|
||||
[HttpGet("wechat/mini-program/notice")]
|
||||
[Authorize]
|
||||
public async Task<bool> GetSubscribeNoticeStateAsync()
|
||||
{
|
||||
var userId = CurrentUser.GetId();
|
||||
var notice = await _noticeCache.GetAsync($"MiniProgram:notice:{userId}");
|
||||
if (notice is not null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 使用小程序jsCode登录意社区账号
|
||||
/// </summary>
|
||||
@@ -88,14 +118,15 @@ public class WeChatMiniProgramAccountService : ApplicationService
|
||||
var openId = (await _weChatMiniProgramManager.Code2SessionAsync(new Code2SessionInput(input.JsCode))).openid;
|
||||
|
||||
//是否已经授权过绑定过auth
|
||||
bool isAuthed =true;
|
||||
//如果openId没有绑定过,代表第一次进入,否则就是临时账号进行绑定
|
||||
var authInfo= await _authService.TryGetAuthInfoAsync(openId,AuthTypeConst.WeChatMiniProgram);
|
||||
//从来没绑定过
|
||||
if (authInfo is null)
|
||||
{
|
||||
isAuthed = false;
|
||||
}
|
||||
bool isAuthed = true;
|
||||
//如果openId没有绑定过,代表第一次进入,否则就是临时账号进行绑定
|
||||
var authInfo = await _authService.TryGetAuthInfoAsync(openId, AuthTypeConst.WeChatMiniProgram);
|
||||
//从来没绑定过
|
||||
if (authInfo is null)
|
||||
{
|
||||
isAuthed = false;
|
||||
}
|
||||
|
||||
//账号绑定,不管什么情况,都将jscode与phone用户建立关系即可
|
||||
await PostBindToAuthAsync(userInfo.User.Id, openId, userInfo.User.UserName);
|
||||
|
||||
@@ -109,11 +140,9 @@ public class WeChatMiniProgramAccountService : ApplicationService
|
||||
await _localEventBus.PublishAsync(new BindAccountEto
|
||||
{
|
||||
NewUserId = userInfo.User.Id,
|
||||
OldUserId =authInfo.UserId
|
||||
},false);
|
||||
OldUserId = authInfo.UserId
|
||||
}, false);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private async Task PostBindToAuthAsync(Guid userId, string openId, string? name = null)
|
||||
@@ -142,7 +171,7 @@ public class WeChatMiniProgramAccountService : ApplicationService
|
||||
var userName = GenerateRandomString(6);
|
||||
await _accountService.PostTempRegisterAsync(new RegisterDto
|
||||
{
|
||||
UserName =$"ls_{userName}",
|
||||
UserName = $"ls_{userName}",
|
||||
Password = GenerateRandomString(20),
|
||||
Nick = $"临时账号-{userName}"
|
||||
});
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
using Volo.Abp.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Volo.Abp.Caching;
|
||||
using Volo.Abp.DependencyInjection;
|
||||
using Volo.Abp.Domain.Services;
|
||||
using Volo.Abp.EventBus;
|
||||
using Yi.Framework.DigitalCollectibles.Domain.Shared.Caches;
|
||||
using Yi.Framework.DigitalCollectibles.Domain.Shared.Consts;
|
||||
using Yi.Framework.DigitalCollectibles.Domain.Shared.Etos;
|
||||
using Yi.Framework.Rbac.Application.Contracts.IServices;
|
||||
@@ -13,18 +16,30 @@ public class WeChatMiniProgramNoticeEventHandler : ILocalEventHandler<WeChatMini
|
||||
{
|
||||
private readonly IWeChatMiniProgramManager _weChatMiniProgramManager;
|
||||
private readonly IAuthService _authService;
|
||||
|
||||
private readonly ILogger<WeChatMiniProgramNoticeEventHandler> _logger;
|
||||
private readonly IDistributedCache<WeChatNoticeCacheItem> _noticeCache;
|
||||
public WeChatMiniProgramNoticeEventHandler(IWeChatMiniProgramManager weChatMiniProgramManager,
|
||||
IAuthService authService)
|
||||
IAuthService authService, ILogger<WeChatMiniProgramNoticeEventHandler> logger, IDistributedCache<WeChatNoticeCacheItem> noticeCache)
|
||||
{
|
||||
_weChatMiniProgramManager = weChatMiniProgramManager;
|
||||
_authService = authService;
|
||||
_logger = logger;
|
||||
_noticeCache = noticeCache;
|
||||
}
|
||||
|
||||
public async Task HandleEventAsync(WeChatMiniProgramNoticeEto eventData)
|
||||
{
|
||||
var authInfo = await _authService.TryGetAuthInfoAsync(null, AuthTypeConst.WeChatMiniProgram, eventData.UserId);
|
||||
await SendAsync(authInfo.OpenId, eventData.Title);
|
||||
//需要判断该用户是否已经订阅
|
||||
var noticeCache= await _noticeCache.GetAsync($"MiniProgram:notice:{eventData.UserId}");
|
||||
//判断用户是否点击了一次性消息订阅
|
||||
if (noticeCache is not null)
|
||||
{
|
||||
var authInfo = await _authService.TryGetAuthInfoAsync(null, AuthTypeConst.WeChatMiniProgram, eventData.UserId);
|
||||
await SendAsync(authInfo.OpenId, eventData.Title);
|
||||
//发送完成之后,删除缓存
|
||||
await _noticeCache.RemoveAsync($"MiniProgram:notice:{eventData.UserId}");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -33,24 +48,32 @@ public class WeChatMiniProgramNoticeEventHandler : ILocalEventHandler<WeChatMini
|
||||
/// <param name="userId"></param>
|
||||
public async Task SendAsync(string openId, string title)
|
||||
{
|
||||
//成功挖到矿,可以发消息给用户了
|
||||
await _weChatMiniProgramManager.SendSubscribeNoticeAsync(new SubscribeNoticeInput
|
||||
try
|
||||
{
|
||||
touser = openId,
|
||||
data = new Dictionary<string, keyValueItem>()
|
||||
//成功挖到矿,可以发消息给用户了
|
||||
await _weChatMiniProgramManager.SendSubscribeNoticeAsync(new SubscribeNoticeInput
|
||||
{
|
||||
//活动名称
|
||||
{ "thing9", new keyValueItem("恭喜挖到新的数字藏品") },
|
||||
touser = openId,
|
||||
data = new Dictionary<string, keyValueItem>()
|
||||
{
|
||||
//活动名称
|
||||
{ "thing9", new keyValueItem("恭喜挖到新的数字藏品") },
|
||||
|
||||
//奖品名称
|
||||
{ "thing1", new keyValueItem(title) },
|
||||
//奖品名称
|
||||
{ "thing1", new keyValueItem(title) },
|
||||
|
||||
//中奖时间
|
||||
{ "date5", new keyValueItem(DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")) },
|
||||
//中奖时间
|
||||
{ "date5", new keyValueItem(DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")) },
|
||||
|
||||
//温馨提醒
|
||||
{ "thing4", new keyValueItem("点击前往小程序,可在仓库或者记录中查看") },
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError($"微信通知提醒失败,错误信息:{e.Message},堆栈:{e.InnerException}");
|
||||
}
|
||||
|
||||
//温馨提醒
|
||||
{ "thing4", new keyValueItem("点击前往小程序,可在仓库或者记录中查看") },
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace Yi.Framework.DigitalCollectibles.Domain.Shared.Caches;
|
||||
|
||||
public class WeChatNoticeCacheItem
|
||||
{
|
||||
public WeChatNoticeCacheItem(bool isSubscribe)
|
||||
{
|
||||
IsSubscribe = isSubscribe;
|
||||
}
|
||||
|
||||
public bool IsSubscribe { get; set; }
|
||||
}
|
||||
@@ -15,12 +15,14 @@
|
||||
style="color: red;font-weight: bolder;font-size: large;">开始</el-menu-item>
|
||||
<el-menu-item index="3" @click="enterWatermelon"
|
||||
>数字藏品</el-menu-item>
|
||||
<el-sub-menu index="4">
|
||||
<template #title>学习</template>
|
||||
<el-menu-item index="3-1">前端</el-menu-item>
|
||||
<el-menu-item index="3-2">后端</el-menu-item>
|
||||
<el-menu-item index="3-3">运维</el-menu-item>
|
||||
</el-sub-menu>
|
||||
<el-menu-item index="4" @click="enterShop"
|
||||
>商城</el-menu-item>
|
||||
<!-- <el-sub-menu index="4">-->
|
||||
<!-- <template #title>学习</template>-->
|
||||
<!-- <el-menu-item index="3-1">前端</el-menu-item>-->
|
||||
<!-- <el-menu-item index="3-2">后端</el-menu-item>-->
|
||||
<!-- <el-menu-item index="3-3">运维</el-menu-item>-->
|
||||
<!-- </el-sub-menu>-->
|
||||
|
||||
<!-- <el-sub-menu index="5">-->
|
||||
<!-- <template #title>问答</template>-->
|
||||
@@ -232,7 +234,10 @@ const enterStart = () => {
|
||||
}
|
||||
|
||||
const enterWatermelon=()=>{
|
||||
alert("即将发布,敬请期待~")
|
||||
alert("真即将发布,敬请期待~")
|
||||
}
|
||||
const enterShop=()=>{
|
||||
alert("真即将发布,敬请期待~")
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script setup>
|
||||
import {computed, ref, watch} from "vue";
|
||||
import { dayjs } from 'element-plus'
|
||||
const data=ref({});
|
||||
const realData=ref({});
|
||||
const props = defineProps([
|
||||
@@ -37,18 +38,21 @@ const isConformToRule=computed(()=>{
|
||||
</script>
|
||||
|
||||
|
||||
<template>
|
||||
<template >
|
||||
<div class="shop-card" >
|
||||
<el-card shadow="hover">
|
||||
<template #header>{{data.name}}</template>
|
||||
<img
|
||||
:src="data.imageUrl"
|
||||
style="width: 100%"
|
||||
alt=""/>
|
||||
简介:{{data.describe}}
|
||||
|
||||
<ul>
|
||||
<li style="font-size: smaller;color: #7c8188;margin-bottom: 5px">简介:{{data.describe}}</li>
|
||||
<li :class="{'less-li': realData.money<data.needMoney}">所需钱钱:{{data.needMoney}}</li>
|
||||
<li :class="{'less-li': realData.value<data.needValue}">所需价值:{{data.needValue}}</li>
|
||||
<li :class="{'less-li': realData.points<data.needPoints}">所需积分:{{data.needPoints}}</li>
|
||||
<li >到期时间:{{dayjs(data.endTime).format("YYYY/MM/DD")}}</li>
|
||||
<li>限购数量:{{data.limitNumber}}</li>
|
||||
<li>剩余:{{data.stockNumber}}</li>
|
||||
</ul>
|
||||
@@ -59,6 +63,7 @@ const isConformToRule=computed(()=>{
|
||||
<el-button v-else :disabled="data.isLimit" type="success" @click="clickBuy">{{data.isLimit===true?"已申请":"申请购买"}} </el-button>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@@ -66,9 +71,35 @@ const isConformToRule=computed(()=>{
|
||||
{
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-top: 20px;
|
||||
margin: 10px;
|
||||
}
|
||||
.less-li{
|
||||
color: red;
|
||||
}
|
||||
img{
|
||||
height: 100px;
|
||||
width: 100%;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
}
|
||||
.shop-card :deep(.el-card__body) {
|
||||
padding: 0 2px 0 0!important;
|
||||
}
|
||||
.shop-card :deep(.el-card__header)
|
||||
{
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 5px;
|
||||
//color: red;
|
||||
font-weight: bolder;
|
||||
|
||||
}
|
||||
ul{
|
||||
padding: 10px;
|
||||
}
|
||||
.shop-card :deep(.el-divider)
|
||||
{
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user