feat: 支持微信通知

This commit is contained in:
橙子
2024-11-10 13:41:04 +08:00
parent 83fb93da11
commit 93dea4fa46
5 changed files with 145 additions and 46 deletions

View File

@@ -1,10 +1,12 @@
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Volo.Abp.Application.Services; using Volo.Abp.Application.Services;
using Volo.Abp.Caching;
using Volo.Abp.EventBus.Local; using Volo.Abp.EventBus.Local;
using Volo.Abp.Users; using Volo.Abp.Users;
using Yi.Framework.Bbs.Domain.Shared.Etos; using Yi.Framework.Bbs.Domain.Shared.Etos;
using Yi.Framework.DigitalCollectibles.Application.Contracts.Dtos.Account; 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.Consts;
using Yi.Framework.DigitalCollectibles.Domain.Shared.Enums; using Yi.Framework.DigitalCollectibles.Domain.Shared.Enums;
using Yi.Framework.DigitalCollectibles.Domain.Shared.Etos; using Yi.Framework.DigitalCollectibles.Domain.Shared.Etos;
@@ -25,6 +27,8 @@ public class WeChatMiniProgramAccountService : ApplicationService
private readonly IAuthService _authService; private readonly IAuthService _authService;
private readonly IAccountService _accountService; private readonly IAccountService _accountService;
private readonly ILocalEventBus _localEventBus; private readonly ILocalEventBus _localEventBus;
private readonly IDistributedCache<WeChatNoticeCacheItem> _noticeCache;
public WeChatMiniProgramAccountService(IWeChatMiniProgramManager weChatMiniProgramManager, IAuthService authService, public WeChatMiniProgramAccountService(IWeChatMiniProgramManager weChatMiniProgramManager, IAuthService authService,
IAccountService accountService, ILocalEventBus localEventBus) IAccountService accountService, ILocalEventBus localEventBus)
{ {
@@ -34,6 +38,32 @@ public class WeChatMiniProgramAccountService : ApplicationService
_localEventBus = localEventBus; _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> /// <summary>
/// 使用小程序jsCode登录意社区账号 /// 使用小程序jsCode登录意社区账号
/// </summary> /// </summary>
@@ -88,14 +118,15 @@ public class WeChatMiniProgramAccountService : ApplicationService
var openId = (await _weChatMiniProgramManager.Code2SessionAsync(new Code2SessionInput(input.JsCode))).openid; var openId = (await _weChatMiniProgramManager.Code2SessionAsync(new Code2SessionInput(input.JsCode))).openid;
//是否已经授权过绑定过auth //是否已经授权过绑定过auth
bool isAuthed =true; bool isAuthed = true;
//如果openId没有绑定过代表第一次进入否则就是临时账号进行绑定 //如果openId没有绑定过代表第一次进入否则就是临时账号进行绑定
var authInfo= await _authService.TryGetAuthInfoAsync(openId,AuthTypeConst.WeChatMiniProgram); var authInfo = await _authService.TryGetAuthInfoAsync(openId, AuthTypeConst.WeChatMiniProgram);
//从来没绑定过 //从来没绑定过
if (authInfo is null) if (authInfo is null)
{ {
isAuthed = false; isAuthed = false;
} }
//账号绑定,不管什么情况都将jscode与phone用户建立关系即可 //账号绑定,不管什么情况都将jscode与phone用户建立关系即可
await PostBindToAuthAsync(userInfo.User.Id, openId, userInfo.User.UserName); await PostBindToAuthAsync(userInfo.User.Id, openId, userInfo.User.UserName);
@@ -109,11 +140,9 @@ public class WeChatMiniProgramAccountService : ApplicationService
await _localEventBus.PublishAsync(new BindAccountEto await _localEventBus.PublishAsync(new BindAccountEto
{ {
NewUserId = userInfo.User.Id, NewUserId = userInfo.User.Id,
OldUserId =authInfo.UserId OldUserId = authInfo.UserId
},false); }, false);
} }
} }
private async Task PostBindToAuthAsync(Guid userId, string openId, string? name = null) private async Task PostBindToAuthAsync(Guid userId, string openId, string? name = null)
@@ -142,7 +171,7 @@ public class WeChatMiniProgramAccountService : ApplicationService
var userName = GenerateRandomString(6); var userName = GenerateRandomString(6);
await _accountService.PostTempRegisterAsync(new RegisterDto await _accountService.PostTempRegisterAsync(new RegisterDto
{ {
UserName =$"ls_{userName}", UserName = $"ls_{userName}",
Password = GenerateRandomString(20), Password = GenerateRandomString(20),
Nick = $"临时账号-{userName}" Nick = $"临时账号-{userName}"
}); });

View File

@@ -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.Domain.Services;
using Volo.Abp.EventBus; using Volo.Abp.EventBus;
using Yi.Framework.DigitalCollectibles.Domain.Shared.Caches;
using Yi.Framework.DigitalCollectibles.Domain.Shared.Consts; using Yi.Framework.DigitalCollectibles.Domain.Shared.Consts;
using Yi.Framework.DigitalCollectibles.Domain.Shared.Etos; using Yi.Framework.DigitalCollectibles.Domain.Shared.Etos;
using Yi.Framework.Rbac.Application.Contracts.IServices; using Yi.Framework.Rbac.Application.Contracts.IServices;
@@ -13,18 +16,30 @@ public class WeChatMiniProgramNoticeEventHandler : ILocalEventHandler<WeChatMini
{ {
private readonly IWeChatMiniProgramManager _weChatMiniProgramManager; private readonly IWeChatMiniProgramManager _weChatMiniProgramManager;
private readonly IAuthService _authService; private readonly IAuthService _authService;
private readonly ILogger<WeChatMiniProgramNoticeEventHandler> _logger;
private readonly IDistributedCache<WeChatNoticeCacheItem> _noticeCache;
public WeChatMiniProgramNoticeEventHandler(IWeChatMiniProgramManager weChatMiniProgramManager, public WeChatMiniProgramNoticeEventHandler(IWeChatMiniProgramManager weChatMiniProgramManager,
IAuthService authService) IAuthService authService, ILogger<WeChatMiniProgramNoticeEventHandler> logger, IDistributedCache<WeChatNoticeCacheItem> noticeCache)
{ {
_weChatMiniProgramManager = weChatMiniProgramManager; _weChatMiniProgramManager = weChatMiniProgramManager;
_authService = authService; _authService = authService;
_logger = logger;
_noticeCache = noticeCache;
} }
public async Task HandleEventAsync(WeChatMiniProgramNoticeEto eventData) public async Task HandleEventAsync(WeChatMiniProgramNoticeEto eventData)
{
//需要判断该用户是否已经订阅
var noticeCache= await _noticeCache.GetAsync($"MiniProgram:notice:{eventData.UserId}");
//判断用户是否点击了一次性消息订阅
if (noticeCache is not null)
{ {
var authInfo = await _authService.TryGetAuthInfoAsync(null, AuthTypeConst.WeChatMiniProgram, eventData.UserId); var authInfo = await _authService.TryGetAuthInfoAsync(null, AuthTypeConst.WeChatMiniProgram, eventData.UserId);
await SendAsync(authInfo.OpenId, eventData.Title); await SendAsync(authInfo.OpenId, eventData.Title);
//发送完成之后,删除缓存
await _noticeCache.RemoveAsync($"MiniProgram:notice:{eventData.UserId}");
}
} }
/// <summary> /// <summary>
@@ -32,6 +47,8 @@ public class WeChatMiniProgramNoticeEventHandler : ILocalEventHandler<WeChatMini
/// </summary> /// </summary>
/// <param name="userId"></param> /// <param name="userId"></param>
public async Task SendAsync(string openId, string title) public async Task SendAsync(string openId, string title)
{
try
{ {
//成功挖到矿,可以发消息给用户了 //成功挖到矿,可以发消息给用户了
await _weChatMiniProgramManager.SendSubscribeNoticeAsync(new SubscribeNoticeInput await _weChatMiniProgramManager.SendSubscribeNoticeAsync(new SubscribeNoticeInput
@@ -53,4 +70,10 @@ public class WeChatMiniProgramNoticeEventHandler : ILocalEventHandler<WeChatMini
} }
}); });
} }
catch (Exception e)
{
_logger.LogError($"微信通知提醒失败,错误信息:{e.Message},堆栈:{e.InnerException}");
}
}
} }

View File

@@ -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; }
}

View File

@@ -15,12 +15,14 @@
style="color: red;font-weight: bolder;font-size: large;">开始</el-menu-item> style="color: red;font-weight: bolder;font-size: large;">开始</el-menu-item>
<el-menu-item index="3" @click="enterWatermelon" <el-menu-item index="3" @click="enterWatermelon"
>数字藏品</el-menu-item> >数字藏品</el-menu-item>
<el-sub-menu index="4"> <el-menu-item index="4" @click="enterShop"
<template #title>学习</template> >商城</el-menu-item>
<el-menu-item index="3-1">前端</el-menu-item> <!-- <el-sub-menu index="4">-->
<el-menu-item index="3-2">后端</el-menu-item> <!-- <template #title>学习</template>-->
<el-menu-item index="3-3">运维</el-menu-item> <!-- <el-menu-item index="3-1">前端</el-menu-item>-->
</el-sub-menu> <!-- <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">--> <!-- <el-sub-menu index="5">-->
<!-- <template #title>问答</template>--> <!-- <template #title>问答</template>-->
@@ -232,7 +234,10 @@ const enterStart = () => {
} }
const enterWatermelon=()=>{ const enterWatermelon=()=>{
alert("即将发布,敬请期待~") alert("即将发布,敬请期待~")
}
const enterShop=()=>{
alert("真即将发布,敬请期待~")
} }
</script> </script>

View File

@@ -1,5 +1,6 @@
<script setup> <script setup>
import {computed, ref, watch} from "vue"; import {computed, ref, watch} from "vue";
import { dayjs } from 'element-plus'
const data=ref({}); const data=ref({});
const realData=ref({}); const realData=ref({});
const props = defineProps([ const props = defineProps([
@@ -37,18 +38,21 @@ const isConformToRule=computed(()=>{
</script> </script>
<template> <template >
<div class="shop-card" >
<el-card shadow="hover"> <el-card shadow="hover">
<template #header>{{data.name}}</template> <template #header>{{data.name}}</template>
<img <img
:src="data.imageUrl" :src="data.imageUrl"
style="width: 100%" style="width: 100%"
alt=""/> alt=""/>
简介{{data.describe}}
<ul> <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.money<data.needMoney}">所需钱钱{{data.needMoney}}</li>
<li :class="{'less-li': realData.value<data.needValue}">所需价值{{data.needValue}}</li> <li :class="{'less-li': realData.value<data.needValue}">所需价值{{data.needValue}}</li>
<li :class="{'less-li': realData.points<data.needPoints}">所需积分{{data.needPoints}}</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.limitNumber}}</li>
<li>剩余{{data.stockNumber}}</li> <li>剩余{{data.stockNumber}}</li>
</ul> </ul>
@@ -59,6 +63,7 @@ const isConformToRule=computed(()=>{
<el-button v-else :disabled="data.isLimit" type="success" @click="clickBuy">{{data.isLimit===true?"已申请":"申请购买"}} </el-button> <el-button v-else :disabled="data.isLimit" type="success" @click="clickBuy">{{data.isLimit===true?"已申请":"申请购买"}} </el-button>
</div> </div>
</el-card> </el-card>
</div>
</template> </template>
<style scoped lang="scss"> <style scoped lang="scss">
@@ -66,9 +71,35 @@ const isConformToRule=computed(()=>{
{ {
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;
margin-top: 20px; margin: 10px;
} }
.less-li{ .less-li{
color: red; 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> </style>