refactor: 拆分微信API到独立项目并迁移相关代码

1.  新增WeChatApi独立项目,将原WebApi中的微信相关控制器迁移至新项目
2.  新增后台权限管理相关实体、服务接口和基础控制器
3.  完善管理员用户服务,增加角色关联查询和赋值逻辑
4.  修复WebApi Swagger文档过滤微信API版本的问题
5.  更新解决方案文件,添加新的微信API项目引用
6.  新增微信API基础配置文件和项目属性配置
This commit is contained in:
glz
2026-07-06 14:21:21 +08:00
parent f8874ff60c
commit a04b4be7e5
32 changed files with 1669 additions and 158 deletions

View File

@ -0,0 +1,139 @@
using Microsoft.AspNetCore.Mvc;
using QYZH.InteractiveMagazine.IService;
using QYZH.InteractiveMagazine.Models.Common;
using QYZH.InteractiveMagazine.Models.Dto;
using QYZH.InteractiveMagazine.Models.Enum;
namespace QYZH.InteractiveMagazine.WebApi.Controllers;
/// <summary>
/// 后台权限管理
/// </summary>
[ApiController]
[Route("api/[controller]")]
[ApiExplorerSettings(GroupName = nameof(ApiVersionEnum.Platform))]
public class PermissionController(IAdminPermissionService adminPermissionService) : BaseController
{
/// <summary>
/// 创建菜单
/// </summary>
[HttpPost("menus")]
public async Task<BaseResponse<AdminMenuOutput>> CreateMenuAsync([FromBody] AdminMenuInput input)
{
var result = await adminPermissionService.CreateMenuAsync(input);
return Success(result);
}
/// <summary>
/// 更新菜单
/// </summary>
[HttpPut("menus/{id}")]
public async Task<BaseResponse<AdminMenuOutput>> UpdateMenuAsync(long id, [FromBody] AdminMenuInput input)
{
var result = await adminPermissionService.UpdateMenuAsync(id, input);
return Success(result);
}
/// <summary>
/// 删除菜单
/// </summary>
[HttpDelete("menus/{id}")]
public async Task<BaseResponse<object>> DeleteMenuAsync(long id)
{
await adminPermissionService.DeleteMenuAsync(id);
return Success(new object());
}
/// <summary>
/// 获取菜单树
/// </summary>
[HttpPost("menus/tree")]
public async Task<BaseResponse<List<AdminMenuOutput>>> GetMenuTreeAsync([FromBody] AdminMenuQueryInput input)
{
var result = await adminPermissionService.GetMenuTreeAsync(input);
return Success(result);
}
/// <summary>
/// 获取当前管理员菜单树
/// </summary>
[HttpGet("menus/current")]
public async Task<BaseResponse<List<AdminMenuOutput>>> GetCurrentMenuTreeAsync()
{
var userId = GetCurrentUserId();
BusinessException.ThrowIf(userId == null, "未获取到用户信息", ResultCode.DENY);
var result = await adminPermissionService.GetAdminUserMenuTreeAsync(userId!.Value);
return Success(result);
}
/// <summary>
/// 创建角色
/// </summary>
[HttpPost("roles")]
public async Task<BaseResponse<AdminRoleOutput>> CreateRoleAsync([FromBody] AdminRoleInput input)
{
var result = await adminPermissionService.CreateRoleAsync(input);
return Success(result);
}
/// <summary>
/// 更新角色
/// </summary>
[HttpPut("roles/{id}")]
public async Task<BaseResponse<AdminRoleOutput>> UpdateRoleAsync(long id, [FromBody] AdminRoleInput input)
{
var result = await adminPermissionService.UpdateRoleAsync(id, input);
return Success(result);
}
/// <summary>
/// 删除角色
/// </summary>
[HttpDelete("roles/{id}")]
public async Task<BaseResponse<object>> DeleteRoleAsync(long id)
{
await adminPermissionService.DeleteRoleAsync(id);
return Success(new object());
}
/// <summary>
/// 获取角色详情
/// </summary>
[HttpGet("roles/{id}")]
public async Task<BaseResponse<AdminRoleOutput>> GetRoleByIdAsync(long id)
{
var result = await adminPermissionService.GetRoleByIdAsync(id);
return Success(result);
}
/// <summary>
/// 获取角色分页列表
/// </summary>
[HttpPost("roles/list")]
public async Task<BaseResponse<PageListModel<AdminRoleOutput>>> GetRoleListAsync([FromBody] AdminRoleQueryInput input)
{
var result = await adminPermissionService.GetRoleListAsync(input);
return Success(result);
}
/// <summary>
/// 分配角色菜单
/// </summary>
[HttpPut("roles/{roleId}/menus")]
public async Task<BaseResponse<object>> AssignRoleMenusAsync(long roleId, [FromBody] AssignRoleMenusInput input)
{
await adminPermissionService.AssignRoleMenusAsync(roleId, input);
return Success(new object());
}
/// <summary>
/// 分配管理员角色
/// </summary>
[HttpPut("users/{adminUserId}/roles")]
public async Task<BaseResponse<object>> AssignAdminUserRolesAsync(long adminUserId, [FromBody] AssignAdminUserRolesInput input)
{
await adminPermissionService.AssignAdminUserRolesAsync(adminUserId, input);
return Success(new object());
}
}

View File

@ -1,52 +0,0 @@
using Microsoft.AspNetCore.Mvc;
using QYZH.InteractiveMagazine.IService;
using QYZH.InteractiveMagazine.Models.Dto;
using QYZH.InteractiveMagazine.Models.Dto.Bag;
namespace QYZH.InteractiveMagazine.WebApi.Controllers.WeChat;
/// <summary>
/// 小程序背包控制器
/// </summary>
public class BagController(IWxMallService mallService, ILogger<BagController> logger) : WeChatBaseController
{
/// <summary>
/// 获取背包物品列表
/// </summary>
/// <param name="itemType">物品类型筛选(可选): MakeUpCard, PetBg</param>
[HttpGet("items")]
public async Task<BaseResponse<List<UserBagOutput>>> GetBagItems([FromQuery] string? itemType = null)
{
var userId = GetCurrentUserId();
if (userId == 0) return Fail("未获取到用户信息") as dynamic;
var items = await mallService.GetBagItemsAsync(userId, itemType);
return Success(items);
}
/// <summary>
/// 使用背包物品(补签卡等消耗品)
/// </summary>
[HttpPost("useItem")]
public async Task<BaseResponse<UseItemOutput>> UseItem([FromBody] UseItemInput input)
{
var userId = GetCurrentUserId();
if (userId == 0) return Fail("未获取到用户信息") as dynamic;
var result = await mallService.UseItemAsync(userId, input);
return Success(result);
}
/// <summary>
/// 宠物换肤
/// </summary>
[HttpPost("equipSkin")]
public async Task<BaseResponse<object>> EquipSkin([FromBody] EquipSkinInput input)
{
var userId = GetCurrentUserId();
if (userId == 0) return Fail("未获取到用户信息") as dynamic;
await mallService.EquipSkinAsync(userId, input);
return Success<object>(null!, input.SkinId == 0 ? "已恢复默认皮肤" : "换肤成功");
}
}

View File

@ -1,144 +0,0 @@
using Microsoft.AspNetCore.Mvc;
using QYZH.InteractiveMagazine.IService;
using QYZH.InteractiveMagazine.Models.Common;
using QYZH.InteractiveMagazine.Models.Dto;
using QYZH.InteractiveMagazine.Models.Dto.CheckIn;
namespace QYZH.InteractiveMagazine.WebApi.Controllers.WeChat;
/// <summary>
/// 签到控制器
/// </summary>
public class CheckInController : WeChatBaseController
{
private readonly ICheckInService _checkInService;
private readonly ILogger<CheckInController> _logger;
public CheckInController(ICheckInService checkInService, ILogger<CheckInController> logger)
{
_checkInService = checkInService;
_logger = logger;
}
/// <summary>
/// 用户签到
/// </summary>
/// <returns>签到结果(含奖励详情和余额)</returns>
[HttpPost("checkIn")]
public async Task<BaseResponse<CheckInOutput>> CheckInAsync()
{
try
{
var userId = GetCurrentUserId();
if (userId == 0)
{
return BaseResponse<CheckInOutput>.Fail(ResultCode.DENY, "未获取到用户信息");
}
var result = await _checkInService.CheckInAsync(userId);
return Success(result, "签到成功");
}
catch (BusinessException ex)
{
_logger.LogWarning(ex, "签到业务异常: {Message}", ex.Message);
return BaseResponse<CheckInOutput>.Fail(ex.Message);
}
catch (Exception ex)
{
_logger.LogError(ex, "签到系统异常");
return BaseResponse<CheckInOutput>.Fail("签到失败,请稍后重试");
}
}
/// <summary>
/// 获取签到信息(今日状态、连续天数、最近记录)
/// </summary>
/// <returns>签到信息</returns>
[HttpGet("info")]
public async Task<BaseResponse<CheckInInfoOutput>> GetCheckInInfoAsync()
{
try
{
var userId = GetCurrentUserId();
if (userId == 0)
{
return BaseResponse<CheckInInfoOutput>.Fail(ResultCode.DENY, "未获取到用户信息");
}
var result = await _checkInService.GetCheckInInfoAsync(userId);
return Success(result);
}
catch (BusinessException ex)
{
_logger.LogWarning(ex, "获取签到信息业务异常: {Message}", ex.Message);
return BaseResponse<CheckInInfoOutput>.Fail(ex.Message);
}
catch (Exception ex)
{
_logger.LogError(ex, "获取签到信息系统异常");
return BaseResponse<CheckInInfoOutput>.Fail("获取签到信息失败,请稍后重试");
}
}
/// <summary>
/// 补签(消耗补签卡,补签历史漏签日期)
/// </summary>
/// <param name="input">补签输入(目标日期)</param>
/// <returns>补签结果(含奖励详情和余额)</returns>
[HttpPost("makeUp")]
public async Task<BaseResponse<CheckInOutput>> MakeUpCheckInAsync([FromBody] MakeUpCheckInInput input)
{
try
{
var userId = GetCurrentUserId();
if (userId == 0)
{
return BaseResponse<CheckInOutput>.Fail(ResultCode.DENY, "未获取到用户信息");
}
var result = await _checkInService.MakeUpCheckInAsync(userId, input.TargetDate);
return Success(result, "补签成功");
}
catch (BusinessException ex)
{
_logger.LogWarning(ex, "补签业务异常: {Message}", ex.Message);
return BaseResponse<CheckInOutput>.Fail(ex.Message);
}
catch (Exception ex)
{
_logger.LogError(ex, "补签系统异常");
return BaseResponse<CheckInOutput>.Fail("补签失败,请稍后重试");
}
}
/// <summary>
/// 获取可补签的日期列表(历史漏签日期)
/// </summary>
/// <param name="days">往前查看天数默认30天</param>
/// <returns>漏签日期列表</returns>
[HttpGet("missedDates")]
public async Task<BaseResponse<List<DateTime>>> GetMissedDatesAsync([FromQuery] int days = 30)
{
try
{
var userId = GetCurrentUserId();
if (userId == 0)
{
return BaseResponse<List<DateTime>>.Fail(ResultCode.DENY, "未获取到用户信息");
}
var result = await _checkInService.GetMissedDatesAsync(userId, days);
return Success(result);
}
catch (BusinessException ex)
{
_logger.LogWarning(ex, "获取可补签日期业务异常: {Message}", ex.Message);
return BaseResponse<List<DateTime>>.Fail(ex.Message);
}
catch (Exception ex)
{
_logger.LogError(ex, "获取可补签日期系统异常");
return BaseResponse<List<DateTime>>.Fail("获取可补签日期失败,请稍后重试");
}
}
}

View File

@ -1,129 +0,0 @@
using Microsoft.AspNetCore.Mvc;
using QYZH.InteractiveMagazine.IService;
using QYZH.InteractiveMagazine.Models.Common;
using QYZH.InteractiveMagazine.Models.Dto;
namespace QYZH.InteractiveMagazine.WebApi.Controllers.WeChat;
/// <summary>
/// 小程序社区控制器
/// </summary>
public class CommunityController(IWeChatCommunityService communityService, ILogger<CommunityController> logger) : WeChatBaseController
{
/// <summary>
/// 获取社区Feed流翻页
/// </summary>
/// <param name="cursor">游标上一页最后一条消息ID首次不传</param>
[HttpGet("feed")]
public async Task<BaseResponse<WxFeedOutput>> GetFeed([FromQuery] long? cursor = null)
{
try
{
var userId = GetCurrentUserId();
if (userId == 0)
{
return BaseResponse<WxFeedOutput>.Fail(ResultCode.DENY, "未获取到用户信息");
}
var result = await communityService.GetFeedAsync(userId, cursor);
return Success(result);
}
catch (BusinessException ex)
{
logger.LogWarning(ex, "获取社区Feed业务异常: {Message}", ex.Message);
return BaseResponse<WxFeedOutput>.Fail(ex.Message);
}
catch (Exception ex)
{
logger.LogError(ex, "获取社区Feed系统异常");
return BaseResponse<WxFeedOutput>.Fail("获取社区内容失败,请稍后重试");
}
}
/// <summary>
/// 下拉刷新社区Feed
/// </summary>
[HttpGet("refresh")]
public async Task<BaseResponse<WxFeedOutput>> RefreshFeed()
{
try
{
var userId = GetCurrentUserId();
if (userId == 0)
{
return BaseResponse<WxFeedOutput>.Fail(ResultCode.DENY, "未获取到用户信息");
}
var result = await communityService.RefreshFeedAsync(userId);
return Success(result);
}
catch (BusinessException ex)
{
logger.LogWarning(ex, "刷新社区Feed业务异常: {Message}", ex.Message);
return BaseResponse<WxFeedOutput>.Fail(ex.Message);
}
catch (Exception ex)
{
logger.LogError(ex, "刷新社区Feed系统异常");
return BaseResponse<WxFeedOutput>.Fail("刷新社区内容失败,请稍后重试");
}
}
/// <summary>
/// 点赞
/// </summary>
[HttpPost("like")]
public async Task<BaseResponse<WxLikeOutput>> Like([FromBody] WxLikeInput input)
{
try
{
var userId = GetCurrentUserId();
if (userId == 0)
{
return BaseResponse<WxLikeOutput>.Fail(ResultCode.DENY, "未获取到用户信息");
}
var result = await communityService.LikeAsync(userId, input);
return Success(result, "点赞成功");
}
catch (BusinessException ex)
{
logger.LogWarning(ex, "点赞业务异常: {Message}", ex.Message);
return BaseResponse<WxLikeOutput>.Fail(ex.Message);
}
catch (Exception ex)
{
logger.LogError(ex, "点赞系统异常,参数:{Input}", input);
return BaseResponse<WxLikeOutput>.Fail("点赞失败,请稍后重试");
}
}
/// <summary>
/// 取消点赞
/// </summary>
[HttpPost("unlike")]
public async Task<BaseResponse<WxLikeOutput>> Unlike([FromBody] WxLikeInput input)
{
try
{
var userId = GetCurrentUserId();
if (userId == 0)
{
return BaseResponse<WxLikeOutput>.Fail(ResultCode.DENY, "未获取到用户信息");
}
var result = await communityService.UnlikeAsync(userId, input.MessageId);
return Success(result, "已取消点赞");
}
catch (BusinessException ex)
{
logger.LogWarning(ex, "取消点赞业务异常: {Message}", ex.Message);
return BaseResponse<WxLikeOutput>.Fail(ex.Message);
}
catch (Exception ex)
{
logger.LogError(ex, "取消点赞系统异常,参数:{Input}", input);
return BaseResponse<WxLikeOutput>.Fail("取消点赞失败,请稍后重试");
}
}
}

View File

@ -1,90 +0,0 @@
using Microsoft.AspNetCore.Mvc;
using QYZH.InteractiveMagazine.IService;
using QYZH.InteractiveMagazine.Models.Common;
using QYZH.InteractiveMagazine.Models.Dto;
namespace QYZH.InteractiveMagazine.WebApi.Controllers.WeChat;
/// <summary>
/// 小程序期刊管理控制器
/// </summary>
public class JournalController : WeChatBaseController
{
private readonly IUserJournalService _userJournalService;
private readonly ILogger<JournalController> _logger;
/// <summary>
/// 初始化小程序期刊控制器
/// </summary>
/// <param name="userJournalService">用户期刊关联服务</param>
/// <param name="logger">日志服务</param>
public JournalController(
IUserJournalService userJournalService,
ILogger<JournalController> logger)
{
_userJournalService = userJournalService;
_logger = logger;
}
/// <summary>
/// 用户扫码绑定期刊
/// </summary>
/// <param name="input">绑定输入JournalId、JournalInstanceId 从扫码内容解析Type 默认 Subscribe</param>
/// <returns>绑定结果</returns>
[HttpPost("bind")]
public async Task<BaseResponse<BindJournalOutput>> BindAsync([FromBody] BindJournalInput input)
{
try
{
var userId = GetCurrentUserId();
if (userId == 0)
{
return BaseResponse<BindJournalOutput>.Fail(ResultCode.DENY, "未获取到用户信息");
}
var result = await _userJournalService.BindJournalAsync(userId, input);
return Success(result, "绑定期刊成功");
}
catch (BusinessException ex)
{
_logger.LogWarning(ex, "绑定期刊业务异常: {Message}", ex.Message);
return BaseResponse<BindJournalOutput>.Fail(ex.Message);
}
catch (Exception ex)
{
_logger.LogError(ex, "绑定期刊系统异常,参数:{Input}", input);
return BaseResponse<BindJournalOutput>.Fail("绑定期刊失败,请稍后重试");
}
}
/// <summary>
/// 获取当前用户的期刊绑定列表
/// </summary>
/// <param name="input">查询条件期刊Id、实例Id、关联类型</param>
/// <returns>分页结果</returns>
[HttpPost("list")]
public async Task<BaseResponse<PageListModel<BindJournalOutput>>> GetListAsync([FromBody] UserJournalQueryInput input)
{
try
{
var userId = GetCurrentUserId();
if (userId == 0)
{
return BaseResponse<PageListModel<BindJournalOutput>>.Fail(ResultCode.DENY, "未获取到用户信息");
}
var result = await _userJournalService.GetUserJournalsAsync(userId, input);
return Success(result);
}
catch (BusinessException ex)
{
_logger.LogWarning(ex, "查询期刊绑定列表业务异常: {Message}", ex.Message);
return BaseResponse<PageListModel<BindJournalOutput>>.Fail(ex.Message);
}
catch (Exception ex)
{
_logger.LogError(ex, "查询期刊绑定列表系统异常");
return BaseResponse<PageListModel<BindJournalOutput>>.Fail("查询期刊绑定列表失败,请稍后重试");
}
}
}

View File

@ -1,70 +0,0 @@
using Microsoft.AspNetCore.Mvc;
using QYZH.InteractiveMagazine.IService;
using QYZH.InteractiveMagazine.Models.Dto;
using QYZH.InteractiveMagazine.Models.Dto.Mall;
namespace QYZH.InteractiveMagazine.WebApi.Controllers.WeChat;
/// <summary>
/// 小程序商城控制器
/// </summary>
public class MallController(IWxMallService mallService, ILogger<MallController> logger) : WeChatBaseController
{
/// <summary>
/// 获取商城商品列表
/// </summary>
/// <param name="type">商品类型筛选(可选): MakeUpCard, PetBg</param>
[HttpGet("products")]
public async Task<BaseResponse<List<WxProductOutput>>> GetProducts([FromQuery] string? type = null)
{
var userId = GetCurrentUserId();
if (userId == 0) return Fail("未获取到用户信息") as dynamic;
var products = await mallService.GetProductsAsync(userId, type);
return Success(products);
}
/// <summary>
/// 获取商品详情
/// </summary>
/// <param name="id">商品Id</param>
[HttpGet("product/{id}")]
public async Task<BaseResponse<WxProductOutput>> GetProductDetail(long id)
{
var userId = GetCurrentUserId();
if (userId == 0) return Fail("未获取到用户信息") as dynamic;
var product = await mallService.GetProductDetailAsync(userId, id);
if (product == null)
return BaseResponse<WxProductOutput>.Fail(ResultCode.DENY, "商品不存在或已下架");
return Success(product);
}
/// <summary>
/// 积分兑换商品
/// </summary>
[HttpPost("exchange")]
public async Task<BaseResponse<ExchangeOutput>> Exchange([FromBody] ExchangeInput input)
{
var userId = GetCurrentUserId();
if (userId == 0) return Fail("未获取到用户信息") as dynamic;
var result = await mallService.ExchangeAsync(userId, input);
return Success(result);
}
/// <summary>
/// 获取我的兑换记录
/// </summary>
/// <param name="limit">返回数量默认20</param>
[HttpGet("exchangeRecords")]
public async Task<BaseResponse<List<ExchangeRecordOutput>>> GetExchangeRecords([FromQuery] int limit = 20)
{
var userId = GetCurrentUserId();
if (userId == 0) return Fail("未获取到用户信息") as dynamic;
var records = await mallService.GetExchangeRecordsAsync(userId, limit);
return Success(records);
}
}

View File

@ -1,99 +0,0 @@
using Microsoft.AspNetCore.Mvc;
using QYZH.InteractiveMagazine.IService;
using QYZH.InteractiveMagazine.Models.Common;
using QYZH.InteractiveMagazine.Models.Dto;
namespace QYZH.InteractiveMagazine.WebApi.Controllers.WeChat;
/// <summary>
/// 小程序勋章控制器
/// </summary>
public class MedalController(IMedalService medalService, ILogger<MedalController> logger) : WeChatBaseController
{
/// <summary>
/// 获取所有勋章列表(含当前用户拥有状态)
/// </summary>
[HttpGet("all")]
public async Task<BaseResponse<List<WxMedalListOutput>>> GetAllMedals()
{
try
{
var userId = GetCurrentUserId();
if (userId == 0)
{
return BaseResponse<List<WxMedalListOutput>>.Fail(ResultCode.DENY, "未获取到用户信息");
}
var result = await medalService.GetAllMedalsAsync(userId);
return Success(result);
}
catch (BusinessException ex)
{
logger.LogWarning(ex, "获取勋章列表业务异常: {Message}", ex.Message);
return BaseResponse<List<WxMedalListOutput>>.Fail(ex.Message);
}
catch (Exception ex)
{
logger.LogError(ex, "获取勋章列表系统异常");
return BaseResponse<List<WxMedalListOutput>>.Fail("获取勋章列表失败,请稍后重试");
}
}
/// <summary>
/// 获取用户已拥有的勋章列表
/// </summary>
[HttpGet("my")]
public async Task<BaseResponse<List<WxUserMedalOutput>>> GetUserMedals()
{
try
{
var userId = GetCurrentUserId();
if (userId == 0)
{
return BaseResponse<List<WxUserMedalOutput>>.Fail(ResultCode.DENY, "未获取到用户信息");
}
var result = await medalService.GetUserMedalsAsync(userId);
return Success(result);
}
catch (BusinessException ex)
{
logger.LogWarning(ex, "获取用户勋章列表业务异常: {Message}", ex.Message);
return BaseResponse<List<WxUserMedalOutput>>.Fail(ex.Message);
}
catch (Exception ex)
{
logger.LogError(ex, "获取用户勋章列表系统异常");
return BaseResponse<List<WxUserMedalOutput>>.Fail("获取用户勋章列表失败,请稍后重试");
}
}
/// <summary>
/// 激活/获得勋章
/// </summary>
[HttpPost("activate")]
public async Task<BaseResponse<object>> ActivateMedal([FromBody] WxMedalActivateInput input)
{
try
{
var userId = GetCurrentUserId();
if (userId == 0)
{
return BaseResponse<object>.Fail(ResultCode.DENY, "未获取到用户信息");
}
await medalService.ActivateMedalAsync(userId, input);
return Success<object>(null!, "勋章激活成功");
}
catch (BusinessException ex)
{
logger.LogWarning(ex, "激活勋章业务异常: {Message}", ex.Message);
return BaseResponse<object>.Fail(ex.Message);
}
catch (Exception ex)
{
logger.LogError(ex, "激活勋章系统异常,参数:{Input}", input);
return BaseResponse<object>.Fail("激活勋章失败,请稍后重试");
}
}
}

View File

@ -1,114 +0,0 @@
using Microsoft.AspNetCore.Mvc;
using QYZH.InteractiveMagazine.IService;
using QYZH.InteractiveMagazine.Models.Common;
using QYZH.InteractiveMagazine.Models.Dto;
using QYZH.InteractiveMagazine.Models.Dto.Pet;
namespace QYZH.InteractiveMagazine.WebApi.Controllers.WeChat;
/// <summary>
/// 小程序宠物管理控制器
/// </summary>
public class PetController : WeChatBaseController
{
private readonly IPetService _petService;
private readonly ILogger<PetController> _logger;
public PetController(IPetService petService, ILogger<PetController> logger)
{
_petService = petService;
_logger = logger;
}
/// <summary>
/// 获取当前用户的宠物信息
/// </summary>
[HttpGet("mine")]
public async Task<BaseResponse<PetOutput>> GetMyPetAsync()
{
try
{
var userId = GetCurrentUserId();
if (userId == 0)
{
return BaseResponse<PetOutput>.Fail(ResultCode.DENY, "未获取到用户信息");
}
var pet = await _petService.GetPetByUserIdAsync(userId);
if (pet == null)
{
return BaseResponse<PetOutput>.Fail("未找到宠物信息");
}
return Success(pet);
}
catch (BusinessException ex)
{
_logger.LogWarning(ex, "获取宠物信息业务异常: {Message}", ex.Message);
return BaseResponse<PetOutput>.Fail(ex.Message);
}
catch (Exception ex)
{
_logger.LogError(ex, "获取宠物信息系统异常");
return BaseResponse<PetOutput>.Fail("获取宠物信息失败,请稍后重试");
}
}
/// <summary>
/// 喂养宠物(增加成长值,触发进化检查)
/// </summary>
[HttpPost("feed")]
public async Task<BaseResponse<FeedPetOutput>> FeedPetAsync([FromBody] FeedPetInput input)
{
try
{
var userId = GetCurrentUserId();
if (userId == 0)
{
return BaseResponse<FeedPetOutput>.Fail(ResultCode.DENY, "未获取到用户信息");
}
var result = await _petService.FeedPetAsync(userId, input);
return Success(result, "喂养成功");
}
catch (BusinessException ex)
{
_logger.LogWarning(ex, "喂养宠物业务异常: {Message}", ex.Message);
return BaseResponse<FeedPetOutput>.Fail(ex.Message);
}
catch (Exception ex)
{
_logger.LogError(ex, "喂养宠物系统异常,参数:{@Input}", input);
return BaseResponse<FeedPetOutput>.Fail("喂养宠物失败,请稍后重试");
}
}
/// <summary>
/// 获取宠物喂养记录列表
/// </summary>
[HttpGet("records/{petId}")]
public async Task<BaseResponse<PageListModel<FeedingRecordOutput>>> GetFeedingRecordsAsync(long petId, [FromQuery] PageQueryModel pageQuery)
{
try
{
var userId = GetCurrentUserId();
if (userId == 0)
{
return BaseResponse<PageListModel<FeedingRecordOutput>>.Fail(ResultCode.DENY, "未获取到用户信息");
}
var result = await _petService.GetFeedingRecordsAsync(userId, petId, pageQuery);
return Success(result);
}
catch (BusinessException ex)
{
_logger.LogWarning(ex, "查询喂养记录业务异常: {Message}", ex.Message);
return BaseResponse<PageListModel<FeedingRecordOutput>>.Fail(ex.Message);
}
catch (Exception ex)
{
_logger.LogError(ex, "查询喂养记录系统异常");
return BaseResponse<PageListModel<FeedingRecordOutput>>.Fail("查询喂养记录失败,请稍后重试");
}
}
}

View File

@ -1,268 +0,0 @@
using Microsoft.AspNetCore.Mvc;
using QYZH.InteractiveMagazine.IService;
using QYZH.InteractiveMagazine.Models.Common;
using QYZH.InteractiveMagazine.Models.Dto;
using QYZH.InteractiveMagazine.Models.Dto.UserAnswerTaskService;
using System.ComponentModel.DataAnnotations;
namespace QYZH.InteractiveMagazine.WebApi.Controllers.WeChat;
/// <summary>
/// 小程序首页控制器
/// </summary>
public class UserAnswerTaskController : WeChatBaseController
{
private readonly IUserAnswerTaskService _userAnswerTaskService;
private readonly ILogger<UserAnswerTaskController> _logger;
/// <summary>
/// 构造函数
/// </summary>
public UserAnswerTaskController(
IUserAnswerTaskService userAnswerTaskService,
ILogger<UserAnswerTaskController> logger)
{
_userAnswerTaskService = userAnswerTaskService;
_logger = logger;
}
private const long ConstUserId = 821752253853766;
/// <summary>
/// 获取当前用户的期刊学习进度列表
/// </summary>
/// <returns>按期刊分组的学习进度数据</returns>
[HttpGet("progress")]
public async Task<BaseResponse<List<JournalProgressOutput>>> GetProgressAsync()
{
try
{
var userId = GetCurrentUserId();
if (userId == 0)
{
return BaseResponse<List<JournalProgressOutput>>.Fail(ResultCode.DENY, "未获取到用户信息");
}
var result = await _userAnswerTaskService.GetJournalProgressAsync(userId);
return Success(result);
}
catch (Exception ex)
{
_logger.LogError(ex, "获取学习进度失败UserId: {UserId}", GetCurrentUserId());
return BaseResponse<List<JournalProgressOutput>>.Fail("获取学习进度失败,请稍后重试");
}
}
/// <summary>
/// 获取目录列表(按一级目录分组,二级目录含完成状态)
/// </summary>
/// <param name="journalId">期刊Id</param>
/// <returns>按一级目录分组的目录列表</returns>
[HttpGet("catalog-list/{journalId:long}")]
public async Task<BaseResponse<List<CatalogListOutput>>> GetCatalogListAsync([Required(ErrorMessage = "参数错误")] long journalId)
{
try
{
var userId = GetCurrentUserId();
if (userId == 0)
{
return BaseResponse<List<CatalogListOutput>>.Fail(ResultCode.DENY, "未获取到用户信息");
}
if (journalId <= 0)
{
return BaseResponse<List<CatalogListOutput>>.Fail(ResultCode.PARAM_ERROR, "期刊Id不能为空");
}
var result = await _userAnswerTaskService.GetCatalogListAsync(journalId, userId);
return Success(result);
}
catch (Exception ex)
{
_logger.LogError(ex, "获取目录列表失败JournalId: {JournalId}, UserId: {UserId}", journalId, GetCurrentUserId());
return BaseResponse<List<CatalogListOutput>>.Fail("获取目录列表失败,请稍后重试");
}
}
/// <summary>
/// 获取一级目录概览(含二级目录详情、页码范围、任务完成状态)
/// </summary>
/// <param name="catalogId">一级目录Id</param>
/// <returns>一级目录概览数据</returns>
[HttpGet("catalog-overview/{catalogId:long}")]
public async Task<BaseResponse<CatalogOverviewOutput>> GetCatalogOverviewAsync([Required(ErrorMessage = "参数错误")] long catalogId)
{
try
{
var userId = GetCurrentUserId();
if (userId == 0)
{
return BaseResponse<CatalogOverviewOutput>.Fail(ResultCode.DENY, "未获取到用户信息");
}
if (catalogId <= 0)
{
return BaseResponse<CatalogOverviewOutput>.Fail(ResultCode.PARAM_ERROR, "目录Id不能为空");
}
var result = await _userAnswerTaskService.GetCatalogOverviewAsync(catalogId, userId);
if (result == null)
{
return BaseResponse<CatalogOverviewOutput>.Fail("未找到该目录");
}
return Success(result);
}
catch (Exception ex)
{
_logger.LogError(ex, "获取目录概览失败CatalogId: {CatalogId}, UserId: {UserId}", catalogId, GetCurrentUserId());
return BaseResponse<CatalogOverviewOutput>.Fail("获取目录概览失败,请稍后重试");
}
}
/// <summary>
/// 获取用户答题任务列表
/// </summary>
/// <param name="catalogId">二级目录Id</param>
/// <returns>答题任务列表</returns>
[HttpGet("task-list/{catalogId:long}")]
public async Task<BaseResponse<UserAnswerTaskListOutput>> GetTaskListAsync([Required(ErrorMessage = "参数错误")] long catalogId)
{
try
{
var userId = GetCurrentUserId();
if (userId == 0)
{
return BaseResponse<UserAnswerTaskListOutput>.Fail(ResultCode.DENY, "未获取到用户信息");
}
if (catalogId <= 0)
{
return BaseResponse<UserAnswerTaskListOutput>.Fail(ResultCode.PARAM_ERROR, "目录Id不能为空");
}
var result = await _userAnswerTaskService.GetUserAnswerTaskListAsync(catalogId, userId);
if (result == null)
{
return BaseResponse<UserAnswerTaskListOutput>.Fail("未找到该目录");
}
return Success(result);
}
catch (Exception ex)
{
_logger.LogError(ex, "获取任务列表失败CatalogId: {CatalogId}, UserId: {UserId}", catalogId, GetCurrentUserId());
return BaseResponse<UserAnswerTaskListOutput>.Fail("获取任务列表失败,请稍后重试");
}
}
/// <summary>
/// 获取跨页题目详情
/// </summary>
/// <param name="groupId">任务分组ID</param>
/// <returns>跨页题目详情</returns>
[HttpGet("cross-page-task/{groupId:long}")]
public async Task<BaseResponse<CrossPageTaskOutput>> GetCrossPageTaskAsync([Required(ErrorMessage ="参数错误")] long groupId)
{
try
{
var userId = GetCurrentUserId();
if (userId == 0)
{
return BaseResponse<CrossPageTaskOutput>.Fail(ResultCode.DENY, "未获取到用户信息");
}
if (groupId <= 0)
{
return BaseResponse<CrossPageTaskOutput>.Fail(ResultCode.PARAM_ERROR, "任务Id不能为空");
}
var result = await _userAnswerTaskService.GetCrossPageTaskAsync(groupId, userId);
if (result == null)
{
return BaseResponse<CrossPageTaskOutput>.Fail("未找到该任务");
}
return Success(result);
}
catch (Exception ex)
{
_logger.LogError(ex, "获取跨页题目失败JournalPageTaskGroupId: {groupId}, UserId: {UserId}", groupId, GetCurrentUserId());
return BaseResponse<CrossPageTaskOutput>.Fail("获取跨页题目失败,请稍后重试");
}
}
/// <summary>
/// 领取任务积分
/// </summary>
/// <param name="groupId">任务分组IdGroupId</param>
/// <returns>领取结果</returns>
[HttpPost("claim-points/{groupId:long}")]
public async Task<BaseResponse<ClaimTaskPointsOutput>> ClaimTaskPointsAsync([Required(ErrorMessage = "参数错误")] long groupId)
{
try
{
var userId = GetCurrentUserId();
if (userId == 0)
{
return BaseResponse<ClaimTaskPointsOutput>.Fail(ResultCode.DENY, "未获取到用户信息");
}
if (groupId <= 0)
{
return BaseResponse<ClaimTaskPointsOutput>.Fail(ResultCode.PARAM_ERROR, "任务分组Id不能为空");
}
var result = await _userAnswerTaskService.ClaimTaskPointsAsync(groupId, userId);
return Success(result);
}
catch (BusinessException ex)
{
_logger.LogWarning(ex, "领取任务积分业务异常groupId: {groupId}, UserId: {UserId}", groupId, GetCurrentUserId());
return BaseResponse<ClaimTaskPointsOutput>.Fail(ex.Message);
}
catch (Exception ex)
{
_logger.LogError(ex, "领取任务积分失败groupId: {groupId}, UserId: {UserId}", groupId, GetCurrentUserId());
return BaseResponse<ClaimTaskPointsOutput>.Fail("领取任务积分失败,请稍后重试");
}
}
/// <summary>
/// 批量领取任务积分(一键领取)
/// </summary>
/// <param name="input">批量领取参数</param>
/// <returns>批量领取结果</returns>
[HttpPost("batch-claim-points")]
public async Task<BaseResponse<BatchClaimPointsOutput>> BatchClaimPointsAsync([FromBody] BatchClaimPointsInput input)
{
try
{
var userId = GetCurrentUserId();
if (userId == 0)
{
return BaseResponse<BatchClaimPointsOutput>.Fail(ResultCode.DENY, "未获取到用户信息");
}
if (input == null || input.GroupIds == null || input.GroupIds.Count == 0)
{
return BaseResponse<BatchClaimPointsOutput>.Fail(ResultCode.PARAM_ERROR, "任务分组Id列表不能为空");
}
var result = await _userAnswerTaskService.BatchClaimPointsAsync(input, userId);
return Success(result);
}
catch (BusinessException ex)
{
_logger.LogWarning(ex, "批量领取积分业务异常UserId: {UserId}", GetCurrentUserId());
return BaseResponse<BatchClaimPointsOutput>.Fail(ex.Message);
}
catch (Exception ex)
{
_logger.LogError(ex, "批量领取积分失败UserId: {UserId}", GetCurrentUserId());
return BaseResponse<BatchClaimPointsOutput>.Fail("批量领取积分失败,请稍后重试");
}
}
}

View File

@ -1,185 +0,0 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using QYZH.InteractiveMagazine.IService;
using QYZH.InteractiveMagazine.Models.Common;
using QYZH.InteractiveMagazine.Models.Dto;
using QYZH.InteractiveMagazine.Models.WeChat;
namespace QYZH.InteractiveMagazine.WebApi.Controllers.WeChat;
/// <summary>
/// 微信小程序认证控制器
/// </summary>
public class WeChatAuthController : WeChatBaseController
{
private readonly IWeChatAuthService _weChatAuthService;
private readonly ILogger<WeChatAuthController> _logger;
public WeChatAuthController(IWeChatAuthService weChatAuthService, ILogger<WeChatAuthController> logger)
{
_weChatAuthService = weChatAuthService;
_logger = logger;
}
/// <summary>
/// 微信小程序登录(首次仅创建 WxUser不自动创建 User
/// </summary>
/// <param name="input">登录输入(含微信 code 和可选的手机号 code</param>
/// <returns>登录结果(含 Token 和用户列表)</returns>
[AllowAnonymous]
[HttpPost("login")]
public async Task<BaseResponse<WeChatLoginOutput>> LoginAsync([FromBody] WeChatLoginInput input)
{
try
{
var result = await _weChatAuthService.LoginAsync(input);
return Success(result);
}
catch (BusinessException ex)
{
_logger.LogWarning(ex, "微信登录业务异常: {Message}", ex.Message);
return BaseResponse<WeChatLoginOutput>.Fail(ex.Message);
}
catch (Exception ex)
{
_logger.LogError(ex, "微信登录系统异常");
return BaseResponse<WeChatLoginOutput>.Fail("微信登录失败,请稍后重试");
}
}
/// <summary>
/// 微信小程序快捷登录(通过 OpenId 直接登录,用户需已存在)
/// </summary>
/// <param name="input">快捷登录输入(含 OpenId</param>
/// <returns>登录结果(含 Token 和用户列表)</returns>
[AllowAnonymous]
[HttpPost("quickLogin")]
public async Task<BaseResponse<WeChatLoginOutput>> QuickLoginAsync([FromBody] WeChatQuickLoginInput input)
{
try
{
var result = await _weChatAuthService.QuickLoginAsync(input);
return Success(result);
}
catch (BusinessException ex)
{
_logger.LogWarning(ex, "微信快捷登录业务异常: {Message}", ex.Message);
return BaseResponse<WeChatLoginOutput>.Fail(ex.Message);
}
catch (Exception ex)
{
_logger.LogError(ex, "微信快捷登录系统异常");
return BaseResponse<WeChatLoginOutput>.Fail("快捷登录失败,请稍后重试");
}
}
/// <summary>
/// 切换用户(同一 WxUser 下切换 User 身份)
/// </summary>
[HttpPost("switchUser")]
public async Task<BaseResponse<WeChatSwitchUserOutput>> SwitchUserAsync([FromBody] WeChatSwitchUserInput input)
{
try
{
var wxUserId = GetCurrentWxUserId();
if (wxUserId == null)
return BaseResponse<WeChatSwitchUserOutput>.Fail(ResultCode.DENY, "未获取到用户信息");
var currentUserId = GetCurrentUserId();
var result = await _weChatAuthService.SwitchUserAsync(wxUserId.Value, currentUserId, input);
return Success(result);
}
catch (BusinessException ex)
{
_logger.LogWarning(ex, "切换用户业务异常: {Message}", ex.Message);
return BaseResponse<WeChatSwitchUserOutput>.Fail(ex.Message);
}
catch (Exception ex)
{
_logger.LogError(ex, "切换用户系统异常");
return BaseResponse<WeChatSwitchUserOutput>.Fail("切换用户失败,请稍后重试");
}
}
/// <summary>
/// 获取当前微信用户下的所有用户列表
/// </summary>
[HttpGet("users")]
public async Task<BaseResponse<List<WxUserOutput>>> GetUsersAsync()
{
try
{
var wxUserId = GetCurrentWxUserId();
if (wxUserId == null)
return BaseResponse<List<WxUserOutput>>.Fail(ResultCode.DENY, "未获取到用户信息");
var result = await _weChatAuthService.GetUsersAsync(wxUserId.Value);
return Success(result);
}
catch (BusinessException ex)
{
_logger.LogWarning(ex, "获取用户列表业务异常: {Message}", ex.Message);
return BaseResponse<List<WxUserOutput>>.Fail(ex.Message);
}
catch (Exception ex)
{
_logger.LogError(ex, "获取用户列表系统异常");
return BaseResponse<List<WxUserOutput>>.Fail("获取用户列表失败,请稍后重试");
}
}
/// <summary>
/// 在当前微信用户下新增用户(子用户/角色)
/// </summary>
[HttpPost("createUser")]
public async Task<BaseResponse<WxUserOutput>> CreateUserAsync([FromBody] CreateChildUserInput input)
{
try
{
var wxUserId = GetCurrentWxUserId();
if (wxUserId == null)
return BaseResponse<WxUserOutput>.Fail(ResultCode.DENY, "未获取到用户信息");
var result = await _weChatAuthService.CreateUserAsync(wxUserId.Value, input);
return Success(result);
}
catch (BusinessException ex)
{
_logger.LogWarning(ex, "新增用户业务异常: {Message}", ex.Message);
return BaseResponse<WxUserOutput>.Fail(ex.Message);
}
catch (Exception ex)
{
_logger.LogError(ex, "新增用户系统异常");
return BaseResponse<WxUserOutput>.Fail("新增用户失败,请稍后重试");
}
}
/// <summary>
/// 修改家长名字WxUser.Name
/// </summary>
[HttpPost("updateName")]
public async Task<BaseResponse<WxUserInfoOutput>> UpdateWxUserNameAsync([FromBody] UpdateWxUserNameInput input)
{
try
{
var wxUserId = GetCurrentWxUserId();
if (wxUserId == null)
return BaseResponse<WxUserInfoOutput>.Fail(ResultCode.DENY, "未获取到用户信息");
var result = await _weChatAuthService.UpdateWxUserNameAsync(wxUserId.Value, input);
return Success(result, "修改成功");
}
catch (BusinessException ex)
{
_logger.LogWarning(ex, "修改家长名字业务异常: {Message}", ex.Message);
return BaseResponse<WxUserInfoOutput>.Fail(ex.Message);
}
catch (Exception ex)
{
_logger.LogError(ex, "修改家长名字系统异常");
return BaseResponse<WxUserInfoOutput>.Fail("修改家长名字失败,请稍后重试");
}
}
}

View File

@ -1,78 +0,0 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using QYZH.InteractiveMagazine.Infrastructure.Auth;
using QYZH.InteractiveMagazine.Models.Dto;
using QYZH.InteractiveMagazine.Models.Enum;
using System.Security.Claims;
namespace QYZH.InteractiveMagazine.WebApi.Controllers.WeChat;
/// <summary>
/// 小程序基础控制器
/// </summary>
[Authorize]
[ApiController]
[Route("wechat/api/[controller]")]
[ApiExplorerSettings(GroupName = nameof(ApiVersionEnum.Wechat))]
public abstract class WeChatBaseController : ControllerBase
{
/// <summary>
/// 获取当前激活用户IDUsers.Id来自 JWT NameIdentifier
/// </summary>
/// <returns>User ID无激活用户时为 0</returns>
protected long GetCurrentUserId()
{
var userIdClaim = User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier);
if (userIdClaim != null && long.TryParse(userIdClaim.Value, out var userId))
{
return userId;
}
return 0;
}
/// <summary>
/// 获取当前微信用户IDWxUser.Id来自 JWT WxUserId claim
/// </summary>
/// <returns>WxUser ID</returns>
protected long? GetCurrentWxUserId()
{
var wxUserIdClaim = User.Claims.FirstOrDefault(c => c.Type == JwtHelper.WxUserIdClaimType);
if (wxUserIdClaim != null && long.TryParse(wxUserIdClaim.Value, out var wxUserId))
{
return wxUserId;
}
return null;
}
/// <summary>
/// 获取当前用户名
/// </summary>
/// <returns>用户名</returns>
protected string? GetCurrentUserName()
{
return User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Name)?.Value;
}
/// <summary>
/// 成功响应
/// </summary>
/// <typeparam name="T">数据类型</typeparam>
/// <param name="data">数据</param>
/// <param name="message">提示信息</param>
/// <returns>统一响应对象</returns>
protected BaseResponse<T> Success<T>(T data, string message = "操作成功")
{
return BaseResponse<T>.Success(data, message);
}
/// <summary>
/// 失败响应
/// </summary>
/// <param name="message">提示信息</param>
/// <param name="code">状态码</param>
/// <returns>统一响应对象</returns>
protected BaseResponse<object> Fail(string message, int code = 500)
{
return BaseResponse<object>.Fail(ResultCode.GLOBAL_ERROR, message);
}
}