添加项目文件。
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
using Common;
|
||||
using Domain.Admin.Admin;
|
||||
using Domain.Admin.Admin.Param;
|
||||
using MongoRepository;
|
||||
using MongoRepository.Config;
|
||||
|
||||
namespace AdminService.Admin
|
||||
{
|
||||
public class AdminOperationLogService : IAdminOperationLogService
|
||||
{
|
||||
private readonly IMongoBaseRepository<AdminOperationLog> _logRepo;
|
||||
|
||||
public AdminOperationLogService(IMongoBaseRepository<AdminOperationLog> logRepo)
|
||||
{
|
||||
_logRepo = logRepo;
|
||||
}
|
||||
|
||||
public async Task<bool> AddLog(AdminOperationLog log)
|
||||
{
|
||||
try
|
||||
{
|
||||
await _logRepo.InsertOneAsync(log);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<(List<AdminOperationLog> list, long count)> QueryPage(OperationLogQueryParam param)
|
||||
{
|
||||
var result = await _logRepo.QueryPageAsync(
|
||||
filterExpression: x =>
|
||||
(string.IsNullOrEmpty(param.AdminId) || x.AdminId == param.AdminId) &&
|
||||
(string.IsNullOrEmpty(param.AdminName) || (x.AdminName != null && x.AdminName.Contains(param.AdminName))) &&
|
||||
(!param.Module.HasValue || x.Module == param.Module) &&
|
||||
(!param.StartTime.HasValue || x.OperateTime >= param.StartTime) &&
|
||||
(!param.EndTime.HasValue || x.OperateTime <= param.EndTime) &&
|
||||
(!param.Status.HasValue || x.Status == param.Status) &&
|
||||
x.HttpMethod != "GET",
|
||||
orderExpression: x => x.OperateTime,
|
||||
desc: true,
|
||||
pageSize: param.PageSize,
|
||||
pageIndex: param.PageIndex
|
||||
);
|
||||
|
||||
return (result.list.ToList(), result.count);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
using System.Security.Claims;
|
||||
using Domain.Admin.Admin;
|
||||
using Domain.Admin.Admin.ENum;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace AdminService.Admin
|
||||
{
|
||||
public static class OperationLogHelper
|
||||
{
|
||||
public static AdminOperationLog CreateLog(
|
||||
EnumOperationModule module,
|
||||
string actionType,
|
||||
string description,
|
||||
string httpMethod,
|
||||
string requestPath,
|
||||
string? requestParams = null,
|
||||
string? response = null,
|
||||
int status = 1)
|
||||
{
|
||||
return new AdminOperationLog
|
||||
{
|
||||
Module = (int)module,
|
||||
ActionType = actionType,
|
||||
Description = description,
|
||||
HttpMethod = httpMethod,
|
||||
RequestPath = requestPath,
|
||||
RequestParams = requestParams,
|
||||
Response = response,
|
||||
Status = status,
|
||||
OperateTime = DateTime.Now
|
||||
};
|
||||
}
|
||||
|
||||
public static (string? adminId, string? adminName) GetAdminInfo(ClaimsPrincipal? user)
|
||||
{
|
||||
if (user == null) return (null, null);
|
||||
|
||||
var adminId = user.FindFirst("uid")?.Value;
|
||||
var adminName = user.FindFirst("dname")?.Value;
|
||||
|
||||
if (string.IsNullOrEmpty(adminName))
|
||||
{
|
||||
adminName = user.FindFirst(ClaimTypes.Name)?.Value;
|
||||
}
|
||||
|
||||
return (adminId, adminName);
|
||||
}
|
||||
|
||||
public static void FillAdminInfo(AdminOperationLog log, ClaimsPrincipal? user)
|
||||
{
|
||||
var (adminId, adminName) = GetAdminInfo(user);
|
||||
log.AdminId = adminId;
|
||||
log.AdminName = adminName;
|
||||
}
|
||||
|
||||
public static string? GetClientIp(HttpContext? context)
|
||||
{
|
||||
if (context == null) return null;
|
||||
|
||||
var ip = context.Request.Headers["X-Forwarded-For"].FirstOrDefault();
|
||||
if (string.IsNullOrEmpty(ip))
|
||||
{
|
||||
ip = context.Connection.RemoteIpAddress?.ToString();
|
||||
}
|
||||
return ip;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AutoMapper" Version="14.0.0" />
|
||||
<PackageReference Include="DotNetCore.CAP" Version="8.3.4" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\CommonDomain\CommonDomain.csproj" />
|
||||
<ProjectReference Include="..\..\Infrastructure\CommonInfrastructure\CommonInfrastructure.csproj" />
|
||||
<ProjectReference Include="..\..\Infrastructure\Common\Common.csproj" />
|
||||
<ProjectReference Include="..\..\Infrastructure\JWTHelper\JWTHelper.csproj" />
|
||||
<ProjectReference Include="..\..\Infrastructure\MongoRepository\MongoRepository.csproj" />
|
||||
<ProjectReference Include="..\..\Infrastructure\RabbitMQHelper\RabbitMQHelper.csproj" />
|
||||
<ProjectReference Include="..\..\Infrastructure\RedisHelper\RedisHelper.csproj" />
|
||||
<ProjectReference Include="..\..\RedisService\RedisService.csproj" />
|
||||
<ProjectReference Include="..\..\UserSrc\UserDomain\UserDomain.csproj" />
|
||||
<ProjectReference Include="..\..\CustomerSrc\CustomerService.Domain\CustomerService.Domain.csproj" />
|
||||
<ProjectReference Include="..\AdminDomain\AdminDomain.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,40 @@
|
||||
using AdminService.Notices.Param;
|
||||
using AdminService.System.Param;
|
||||
using AdminService.System.Response;
|
||||
using AdminService.Notices.Param;
|
||||
using AutoMapper;
|
||||
using CommonDomain;
|
||||
using UserDomain.Entity;
|
||||
using Domain.Admin.Admin;
|
||||
using UserDomain.Entity;
|
||||
|
||||
namespace AdminService
|
||||
{
|
||||
public class AutoMapperConfig : Profile
|
||||
{
|
||||
public AutoMapperConfig()
|
||||
{
|
||||
#region Admin
|
||||
//param To Entity
|
||||
CreateMap<AddUserParam, SystemUser>();
|
||||
CreateMap<AddRoleParam, SystemUserRole>();
|
||||
CreateMap<AddNavParam, SystemNavigation>();
|
||||
CreateMap<AddDicParam, SystemDic>();
|
||||
|
||||
CreateMap<SystemUser, AdminUserToken>();
|
||||
|
||||
CreateMap<SystemNavigation, SystemNavigationResponse>();
|
||||
CreateMap<SystemDic, SystemDicResponse>();
|
||||
#endregion
|
||||
|
||||
#region Notice
|
||||
CreateMap<AddNoticeParam, Notice>();
|
||||
CreateMap<UpdateNoticeParam, Notice>();
|
||||
#endregion
|
||||
|
||||
#region Task
|
||||
CreateMap<GameTask, UserTask>();
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
namespace AdminService.BeautifulNumber;
|
||||
|
||||
public class BeautifulNumberGenerator
|
||||
{
|
||||
public static List<string> GenerateAllPossibleNumbersForRule(string rule)
|
||||
{
|
||||
var parts = ParseRuleIntoParts(rule);
|
||||
int totalLength = parts.Sum(p => p.Length);
|
||||
if (totalLength != 8)
|
||||
{
|
||||
string details = string.Join(", ", parts.Select(p => $"'{p.OriginalString}'({p.Type}, {p.Length}位)"));
|
||||
throw new ArgumentException($"规则 '{rule}' 解析后的总长度为 {totalLength} 位,不符合要求的8位。详情: [{details}]");
|
||||
}
|
||||
|
||||
var partCombinations = new List<List<string>>();
|
||||
foreach (var part in parts)
|
||||
{
|
||||
partCombinations.Add(GenerateCombinationsForPart(part));
|
||||
}
|
||||
|
||||
var finalNumbers = CartesianProduct(partCombinations);
|
||||
return finalNumbers.Distinct().ToList();
|
||||
}
|
||||
|
||||
private class RulePart
|
||||
{
|
||||
public string OriginalString { get; set; }
|
||||
public PartType Type { get; set; }
|
||||
public int Length { get; set; }
|
||||
public string UniqueLetters { get; set; }
|
||||
public bool HasPlaceholder { get; set; }
|
||||
}
|
||||
|
||||
private enum PartType
|
||||
{
|
||||
Sequential,
|
||||
FixedGroup, // K, T, KK, TT, KKT, TTKK etc.
|
||||
Individual, // X
|
||||
FixedNumber // 8888
|
||||
}
|
||||
|
||||
private static List<RulePart> ParseRuleIntoParts(string rule)
|
||||
{
|
||||
var parts = new List<RulePart>();
|
||||
int i = 0;
|
||||
while (i < rule.Length)
|
||||
{
|
||||
char c = rule[i];
|
||||
|
||||
if (char.IsDigit(c))
|
||||
{
|
||||
int start = i;
|
||||
while (i < rule.Length && char.IsDigit(rule[i])) i++;
|
||||
parts.Add(new RulePart { OriginalString = rule.Substring(start, i - start), Type = PartType.FixedNumber, Length = i - start });
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c >= 'A' && c <= 'H')
|
||||
{
|
||||
int start = i;
|
||||
int direction = 0;
|
||||
if (i + 1 < rule.Length && char.IsUpper(rule[i + 1]) && (rule[i + 1] >= 'A' && rule[i + 1] <= 'H'))
|
||||
{
|
||||
direction = rule[i + 1] > c ? 1 : -1;
|
||||
i++;
|
||||
while (i + 1 < rule.Length && char.IsUpper(rule[i + 1]) && (rule[i + 1] >= 'A' && rule[i + 1] <= 'H') && rule[i + 1] - rule[i] == direction)
|
||||
{
|
||||
i++;
|
||||
}
|
||||
}
|
||||
bool hasPlaceholder = (i + 1 < rule.Length && rule[i + 1] == 'X');
|
||||
if (hasPlaceholder) i++;
|
||||
|
||||
int sequenceLength = i - start + 1;
|
||||
parts.Add(new RulePart { OriginalString = rule.Substring(start, sequenceLength), Type = PartType.Sequential, Length = sequenceLength, HasPlaceholder = hasPlaceholder });
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c == 'X')
|
||||
{
|
||||
int start = i;
|
||||
while (i < rule.Length && rule[i] == 'X') i++;
|
||||
parts.Add(new RulePart { OriginalString = rule.Substring(start, i - start), Type = PartType.Individual, Length = i - start });
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c == 'K' || c == 'T')
|
||||
{
|
||||
int start = i;
|
||||
while (i < rule.Length && (rule[i] == 'K' || rule[i] == 'T')) i++;
|
||||
string pattern = rule.Substring(start, i - start);
|
||||
string uniqueLtrs = new string(pattern.Distinct().OrderBy(ch => ch).ToArray());
|
||||
parts.Add(new RulePart { OriginalString = pattern, Type = PartType.FixedGroup, Length = pattern.Length, UniqueLetters = uniqueLtrs });
|
||||
continue;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
return parts;
|
||||
}
|
||||
|
||||
private static List<string> GenerateCombinationsForPart(RulePart part)
|
||||
{
|
||||
switch (part.Type)
|
||||
{
|
||||
case PartType.Sequential:
|
||||
return GenerateSequentialNumbersWithPlaceholder(part.OriginalString, part.HasPlaceholder);
|
||||
case PartType.FixedGroup:
|
||||
return GenerateFixedGroupNumbers(part.OriginalString, part.UniqueLetters);
|
||||
case PartType.Individual:
|
||||
return GenerateIndividualNumbers(part.OriginalString.Length);
|
||||
case PartType.FixedNumber:
|
||||
return new List<string> { part.OriginalString };
|
||||
default:
|
||||
return new List<string>();
|
||||
}
|
||||
}
|
||||
|
||||
private static List<string> GenerateSequentialNumbersWithPlaceholder(string seqRule, bool hasPlaceholder)
|
||||
{
|
||||
string sequenceRule = hasPlaceholder ? seqRule.Substring(0, seqRule.Length - 1) : seqRule;
|
||||
int length = sequenceRule.Length;
|
||||
if (length == 0) return new List<string> { "" };
|
||||
|
||||
var baseSequences = new List<string>();
|
||||
bool isAscending = length > 1 && sequenceRule[1] > sequenceRule[0];
|
||||
|
||||
if (isAscending)
|
||||
{
|
||||
int maxStart = 10 - length;
|
||||
for (int start = 0; start <= maxStart; start++)
|
||||
{
|
||||
string num = "";
|
||||
for (int i = 0; i < length; i++) num += (start + i).ToString();
|
||||
baseSequences.Add(num);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int minStart = length - 1;
|
||||
for (int start = 9; start >= minStart; start--)
|
||||
{
|
||||
string num = "";
|
||||
for (int i = 0; i < length; i++) num += (start - i).ToString();
|
||||
baseSequences.Add(num);
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasPlaceholder)
|
||||
{
|
||||
return baseSequences;
|
||||
}
|
||||
|
||||
var finalSequences = new List<string>();
|
||||
var digits = new List<string> { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
|
||||
foreach (var seq in baseSequences)
|
||||
{
|
||||
foreach (var digit in digits)
|
||||
{
|
||||
finalSequences.Add(seq + digit);
|
||||
}
|
||||
}
|
||||
return finalSequences;
|
||||
}
|
||||
|
||||
private static List<string> GenerateFixedGroupNumbers(string pattern, string uniqueLetters)
|
||||
{
|
||||
var allCombinations = new List<List<string>>();
|
||||
foreach (char letter in uniqueLetters)
|
||||
{
|
||||
var letterValues = new List<string>();
|
||||
for (int i = 0; i < 10; i++) letterValues.Add(i.ToString());
|
||||
allCombinations.Add(letterValues);
|
||||
}
|
||||
|
||||
var letterAssignments = CartesianProduct(allCombinations);
|
||||
var results = new List<string>();
|
||||
foreach (var assignment in letterAssignments)
|
||||
{
|
||||
var map = new Dictionary<char, string>();
|
||||
for (int i = 0; i < uniqueLetters.Length; i++)
|
||||
{
|
||||
map[uniqueLetters[i]] = assignment[i].ToString();
|
||||
}
|
||||
|
||||
string number = "";
|
||||
foreach (char c in pattern)
|
||||
{
|
||||
number += map[c];
|
||||
}
|
||||
results.Add(number);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private static List<string> GenerateIndividualNumbers(int length)
|
||||
{
|
||||
var allCombinations = new List<List<string>>();
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
var digitList = new List<string>();
|
||||
for (int j = 0; j < 10; j++) digitList.Add(j.ToString());
|
||||
allCombinations.Add(digitList);
|
||||
}
|
||||
return CartesianProduct(allCombinations);
|
||||
}
|
||||
|
||||
private static List<string> CartesianProduct(List<List<string>> listOfLists)
|
||||
{
|
||||
IEnumerable<string> result = new[] { "" };
|
||||
foreach (var list in listOfLists)
|
||||
{
|
||||
result = from r in result
|
||||
from l in list
|
||||
select r + l;
|
||||
}
|
||||
return result.ToList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,491 @@
|
||||
using System.Linq.Expressions;
|
||||
using AdminDomain.BeautifulNumber;
|
||||
using AdminDomain.Entity;
|
||||
using Common;
|
||||
using Common.Utils;
|
||||
using CommonInfrastructure.Response;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using MongoDB.Driver;
|
||||
using MongoRepository;
|
||||
using RedisService;
|
||||
using UserDomain.Entity;
|
||||
using XAct;
|
||||
|
||||
namespace AdminService.BeautifulNumber
|
||||
{
|
||||
public class BeautifulNumberService : IBeautifulNumberService
|
||||
{
|
||||
private readonly IMongoBaseRepository<BeautifulNumberConfig> _beautifulNumberMongo;
|
||||
private readonly IMongoBaseRepository<BeautifulNumberRule> _ruleMongo;
|
||||
private readonly IMongoBaseRepository<UserEntity> _userMongo;
|
||||
private readonly IRedisService _cache;
|
||||
|
||||
public BeautifulNumberService(
|
||||
IMongoBaseRepository<BeautifulNumberConfig> beautifulNumberMongo,
|
||||
IMongoBaseRepository<BeautifulNumberRule> ruleMongo,
|
||||
IMongoBaseRepository<UserEntity> userMongo,
|
||||
IRedisService cache)
|
||||
{
|
||||
_beautifulNumberMongo = beautifulNumberMongo;
|
||||
_ruleMongo = ruleMongo;
|
||||
_userMongo = userMongo;
|
||||
_cache = cache;
|
||||
}
|
||||
|
||||
public async Task<(List<BeautifulNumberConfig> list, long count)> GetList(BeautifulNumberListParam param)
|
||||
{
|
||||
Expression<Func<BeautifulNumberConfig, bool>> filter = c => true;
|
||||
|
||||
if (!string.IsNullOrEmpty(param.level))
|
||||
{
|
||||
filter = filter.And(c => c.Level == param.level);
|
||||
}
|
||||
|
||||
if (param.status.HasValue)
|
||||
{
|
||||
filter = filter.And(c => c.Status == (BeautifulNumberStatus)param.status.Value);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(param.numberSearch))
|
||||
{
|
||||
filter = filter.And(c => c.Number.Contains(param.numberSearch));
|
||||
}
|
||||
|
||||
var (total, list) = await _beautifulNumberMongo.QueryPageAsync(filter, c => c.CreateTime, false, param.size, param.page);
|
||||
|
||||
return (list, total);
|
||||
}
|
||||
|
||||
public async Task<(List<BeautifulNumberConfig> list, long count)> GetAvailableList(BeautifulNumberListParam param)
|
||||
{
|
||||
param.status = (int)BeautifulNumberStatus.Available;
|
||||
return await GetList(param);
|
||||
}
|
||||
|
||||
public async Task<(bool isok, string msg)> Purchase(string number, LoginUser loginUser)
|
||||
{
|
||||
var config = await _beautifulNumberMongo.FindOneAsync(c => c.Number == number);
|
||||
if (config == null)
|
||||
{
|
||||
return (false, "靓号不存在");
|
||||
}
|
||||
|
||||
if (config.Status != BeautifulNumberStatus.Available)
|
||||
{
|
||||
return (false, "靓号不可购买");
|
||||
}
|
||||
|
||||
var user = await _userMongo.FindByIdAsync(loginUser.UserId);
|
||||
if (user == null)
|
||||
{
|
||||
return (false, "用户不存在");
|
||||
}
|
||||
|
||||
if (user.Assets.Gold < config.Price)
|
||||
{
|
||||
return (false, "金币不足");
|
||||
}
|
||||
|
||||
user.Assets.Gold -= config.Price;
|
||||
config.Status = BeautifulNumberStatus.Sold;
|
||||
config.SaleTime = DateTime.Now.ToTimeStamp();
|
||||
config.BuyerUserId = loginUser.UserId;
|
||||
config.UserId = loginUser.UserId;
|
||||
|
||||
await _userMongo.ReplaceOneAsync(user);
|
||||
await _beautifulNumberMongo.ReplaceOneAsync(config);
|
||||
|
||||
return (true, "购买成功");
|
||||
}
|
||||
|
||||
public async Task<BeautifulNumberConfig> CheckNumber(string number)
|
||||
{
|
||||
var config = await _beautifulNumberMongo.FindOneAsync(c => c.Number == number);
|
||||
if (config != null)
|
||||
{
|
||||
return config;
|
||||
}
|
||||
|
||||
var isUsed = _userMongo.Count(c => c.BaseInfo.Number == number) > 0;
|
||||
|
||||
|
||||
return new BeautifulNumberConfig
|
||||
{
|
||||
Number = number,
|
||||
RuleName = config.RuleName,
|
||||
Level = config.Level,
|
||||
Price = config.Price,
|
||||
Status = isUsed ? BeautifulNumberStatus.Sold : BeautifulNumberStatus.Normal
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
public async Task<(bool isok, string msg)> Delete(string id)
|
||||
{
|
||||
var config = await _beautifulNumberMongo.FindByIdAsync(id);
|
||||
if (config == null)
|
||||
{
|
||||
return (false, "靓号不存在");
|
||||
}
|
||||
|
||||
if (config.Status == BeautifulNumberStatus.Sold)
|
||||
{
|
||||
return (false, "靓号已售出,无法删除");
|
||||
}
|
||||
|
||||
await _beautifulNumberMongo.DeleteByIdAsync(id);
|
||||
return (true, "删除成功");
|
||||
}
|
||||
|
||||
public async Task<(bool isok, string msg)> SetToNormal(string id)
|
||||
{
|
||||
var config = await _beautifulNumberMongo.FindByIdAsync(id);
|
||||
if (config == null)
|
||||
{
|
||||
return (false, "靓号不存在");
|
||||
}
|
||||
|
||||
config.Status = BeautifulNumberStatus.Normal;
|
||||
await _beautifulNumberMongo.ReplaceOneAsync(config);
|
||||
return (true, "设置成功");
|
||||
}
|
||||
|
||||
public async Task<(bool isok, string msg)> Freeze(string id)
|
||||
{
|
||||
var config = await _beautifulNumberMongo.FindByIdAsync(id);
|
||||
if (config == null)
|
||||
{
|
||||
return (false, "靓号不存在");
|
||||
}
|
||||
|
||||
config.Status = BeautifulNumberStatus.Frozen;
|
||||
await _beautifulNumberMongo.ReplaceOneAsync(config);
|
||||
return (true, "冻结成功");
|
||||
}
|
||||
|
||||
public async Task<(bool isok, string msg)> Unfreeze(string id)
|
||||
{
|
||||
var config = await _beautifulNumberMongo.FindByIdAsync(id);
|
||||
if (config == null)
|
||||
{
|
||||
return (false, "靓号不存在");
|
||||
}
|
||||
|
||||
config.Status = BeautifulNumberStatus.Available;
|
||||
await _beautifulNumberMongo.ReplaceOneAsync(config);
|
||||
return (true, "解冻成功");
|
||||
}
|
||||
|
||||
public async Task<(bool isok, string msg)> UpdatePrice(string id, long price)
|
||||
{
|
||||
var config = await _beautifulNumberMongo.FindByIdAsync(id);
|
||||
if (config == null)
|
||||
{
|
||||
return (false, "靓号不存在");
|
||||
}
|
||||
|
||||
config.Price = price;
|
||||
await _beautifulNumberMongo.ReplaceOneAsync(config);
|
||||
return (true, "价格修改成功");
|
||||
}
|
||||
|
||||
public async Task<(bool isok, string msg)> UpdateNumber(string id, string level, long price)
|
||||
{
|
||||
var config = await _beautifulNumberMongo.FindByIdAsync(id);
|
||||
if (config == null)
|
||||
{
|
||||
return (false, "靓号不存在");
|
||||
}
|
||||
|
||||
config.Level = level;
|
||||
config.Price = price;
|
||||
await _beautifulNumberMongo.ReplaceOneAsync(config);
|
||||
return (true, "修改成功");
|
||||
}
|
||||
|
||||
public async Task<(bool isok, string msg)> BindToUser(string number, string userId)
|
||||
{
|
||||
var config = await _beautifulNumberMongo.FindOneAsync(c => c.Number == number);
|
||||
if (config == null)
|
||||
{
|
||||
return (false, "靓号不存在");
|
||||
}
|
||||
|
||||
config.UserId = userId;
|
||||
await _beautifulNumberMongo.ReplaceOneAsync(config);
|
||||
return (true, "绑定成功");
|
||||
}
|
||||
|
||||
public async Task<List<BeautifulNumberRule>> GetRules()
|
||||
{
|
||||
var filter = Builders<BeautifulNumberRule>.Filter.Empty;
|
||||
var sort = Builders<BeautifulNumberRule>.Sort.Ascending(c => c.Sort);
|
||||
var (_, list) = await _ruleMongo.QueryPageAsync(filter, sort, true, 100, 1);
|
||||
return list;
|
||||
}
|
||||
|
||||
public async Task<(bool isok, string msg)> AddRule(BeautifulNumberRule rule)
|
||||
{
|
||||
try
|
||||
{
|
||||
await _ruleMongo.InsertOneAsync(rule);
|
||||
return (true, "添加成功");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return (false, "添加失败: " + ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<(bool isok, string msg)> UpdateRule(BeautifulNumberRule rule)
|
||||
{
|
||||
try
|
||||
{
|
||||
var existing = await _ruleMongo.FindByIdAsync(rule.Id);
|
||||
if (existing == null)
|
||||
return (false, "规则不存在");
|
||||
|
||||
existing.RuleName = rule.RuleName;
|
||||
|
||||
existing.Level = rule.Level;
|
||||
existing.Price = rule.Price;
|
||||
existing.Sort = rule.Sort;
|
||||
existing.IsEnable = rule.IsEnable;
|
||||
|
||||
await _ruleMongo.ReplaceOneAsync(existing);
|
||||
return (true, "更新成功");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return (false, "更新失败: " + ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<(bool isok, string msg)> DeleteRule(string id)
|
||||
{
|
||||
try
|
||||
{
|
||||
await _ruleMongo.DeleteByIdAsync(id);
|
||||
return (true, "删除成功");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return (false, "删除失败: " + ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<(bool isok, string msg)> GiveToUser(string number, string userId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var user = await _userMongo.FindByIdAsync(userId);
|
||||
if (user == null)
|
||||
return (false, "用户不存在");
|
||||
|
||||
var config = await _beautifulNumberMongo.FindOneAsync(c => c.Number == number);
|
||||
if (config != null)
|
||||
{
|
||||
if (config.Status == BeautifulNumberStatus.Sold)
|
||||
return (false, "靓号已售出");
|
||||
|
||||
config.Status = BeautifulNumberStatus.Sold;
|
||||
config.UserId = userId;
|
||||
config.BuyerUserId = userId;
|
||||
config.SaleTime = DateTime.Now.ToTimeStamp();
|
||||
await _beautifulNumberMongo.ReplaceOneAsync(config);
|
||||
}
|
||||
|
||||
user.BaseInfo.Number = number;
|
||||
await _userMongo.ReplaceOneAsync(user);
|
||||
|
||||
return (true, "赠送成功");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return (false, "赠送失败: " + ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<(bool isok, string msg, int count)> InitBeautifulNumbers()
|
||||
{
|
||||
try
|
||||
{
|
||||
var rules = await GetRules();
|
||||
if (rules == null || rules.Count == 0)
|
||||
{
|
||||
return (false, "请先初始化规则", 0);
|
||||
}
|
||||
|
||||
var soldNumbers = new HashSet<string>();
|
||||
var allConfigs = await _beautifulNumberMongo.FilterByAsync(c => c.Status == BeautifulNumberStatus.Sold);
|
||||
foreach (var config in allConfigs)
|
||||
{
|
||||
soldNumbers.Add(config.Number);
|
||||
}
|
||||
|
||||
var existingNumbers = new HashSet<string>();
|
||||
var existingConfigs = await _beautifulNumberMongo.FilterByAsync(c => true);
|
||||
foreach (var config in existingConfigs)
|
||||
{
|
||||
existingNumbers.Add(config.Number);
|
||||
}
|
||||
|
||||
var newNumbers = new List<BeautifulNumberConfig>();
|
||||
foreach (var rule in rules)
|
||||
{
|
||||
if (!rule.IsEnable) continue;
|
||||
var numbers = BeautifulNumberGenerator.GenerateAllPossibleNumbersForRule(rule.RuleName);
|
||||
|
||||
foreach (var num in numbers)
|
||||
{
|
||||
if (existingNumbers.Contains(num) || soldNumbers.Contains(num) || newNumbers.Any(c=>c.Number==num))
|
||||
continue;
|
||||
|
||||
newNumbers.Add(new BeautifulNumberConfig() { Level=rule.Level, Number=num, Price=rule.Price, RuleName=rule.RuleName
|
||||
});
|
||||
existingNumbers.Add(num);
|
||||
}
|
||||
}
|
||||
|
||||
if (newNumbers.Count > 0)
|
||||
{
|
||||
await _beautifulNumberMongo.InsertManyAsync(newNumbers);
|
||||
}
|
||||
|
||||
return (true, $"初始化成功,新增 {newNumbers.Count} 个靓号", newNumbers.Count);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return (false, "初始化失败: " + ex.Message, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public async Task<(bool isok, string msg)> UpdateRules(List<BeautifulNumberRule> rules)
|
||||
{
|
||||
try
|
||||
{
|
||||
await _ruleMongo.DeleteManyAsync(c => true);
|
||||
|
||||
if (rules.Count > 0)
|
||||
{
|
||||
await _ruleMongo.InsertManyAsync(rules);
|
||||
}
|
||||
|
||||
return (true, "规则更新成功");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return (false, "规则更新失败: " + ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<(bool isok, string msg)> InitRules()
|
||||
{
|
||||
var existingRules = _ruleMongo.Count(c => true);
|
||||
if (existingRules > 0)
|
||||
{
|
||||
return (true, "规则已初始化");
|
||||
}
|
||||
|
||||
var rules = new List<BeautifulNumberRule>
|
||||
{
|
||||
|
||||
|
||||
};
|
||||
|
||||
await _ruleMongo.InsertManyAsync(rules);
|
||||
return (true, "规则初始化成功");
|
||||
}
|
||||
|
||||
public async Task<(bool isok, string msg)> AddNumber(string number, string level, long price)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(number))
|
||||
return (false, "靓号不能为空");
|
||||
|
||||
number = number.Trim();
|
||||
|
||||
var existing = await _beautifulNumberMongo.FindOneAsync(c => c.Number == number);
|
||||
if (existing != null)
|
||||
return (false, "靓号已存在: " + number);
|
||||
|
||||
var config = new BeautifulNumberConfig
|
||||
{
|
||||
Number = number,
|
||||
Level = level ?? "D",
|
||||
Price = price,
|
||||
|
||||
Status = 0,
|
||||
CreateTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds()
|
||||
};
|
||||
|
||||
await _beautifulNumberMongo.InsertOneAsync(config);
|
||||
return (true, "添加成功");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return (false, "添加失败: " + ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<(bool isok, string msg, int successCount, int failCount)> BatchAddNumbers(List<string> numbers, string level, long price)
|
||||
{
|
||||
if (numbers == null || numbers.Count == 0)
|
||||
return (false, "号码列表不能为空", 0, 0);
|
||||
|
||||
var successCount = 0;
|
||||
var failCount = 0;
|
||||
var failNumbers = new List<string>();
|
||||
|
||||
foreach (var number in numbers)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(number))
|
||||
{
|
||||
failCount++;
|
||||
failNumbers.Add(number);
|
||||
continue;
|
||||
}
|
||||
|
||||
var num = number.Trim();
|
||||
try
|
||||
{
|
||||
var existing = await _beautifulNumberMongo.FindOneAsync(c => c.Number == num);
|
||||
if (existing != null)
|
||||
{
|
||||
failCount++;
|
||||
failNumbers.Add(num + "(已存在)");
|
||||
continue;
|
||||
}
|
||||
|
||||
var config = new BeautifulNumberConfig
|
||||
{
|
||||
Number = num,
|
||||
Level = level ?? "D",
|
||||
Price = price,
|
||||
Status = 0,
|
||||
CreateTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds()
|
||||
};
|
||||
|
||||
await _beautifulNumberMongo.InsertOneAsync(config);
|
||||
successCount++;
|
||||
}
|
||||
catch
|
||||
{
|
||||
failCount++;
|
||||
failNumbers.Add(num);
|
||||
}
|
||||
}
|
||||
|
||||
var msg = string.IsNullOrEmpty(failNumbers.FirstOrDefault())
|
||||
? $"成功添加 {successCount} 个靓号"
|
||||
: $"成功 {successCount} 个,失败 {failCount} 个: {string.Join(", ", failNumbers.Take(10))}";
|
||||
|
||||
return (true, msg, successCount, failCount);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
using AdminDomain.Entity;
|
||||
using Common;
|
||||
using Common.CommonModel;
|
||||
using CommonInfrastructure.Response;
|
||||
using UserDomain.Entity;
|
||||
using UserDomain.Enum;
|
||||
|
||||
namespace AdminService.BeautifulNumber
|
||||
{
|
||||
public interface IBeautifulNumberService
|
||||
{
|
||||
Task<(List<BeautifulNumberConfig> list, long count)> GetList(BeautifulNumberListParam param);
|
||||
|
||||
Task<(List<BeautifulNumberConfig> list, long count)> GetAvailableList(BeautifulNumberListParam param);
|
||||
|
||||
Task<(bool isok, string msg)> Purchase(string number, LoginUser loginUser);
|
||||
|
||||
Task<BeautifulNumberConfig> CheckNumber(string number);
|
||||
|
||||
|
||||
|
||||
Task<(bool isok, string msg)> Delete(string id);
|
||||
|
||||
Task<(bool isok, string msg)> SetToNormal(string id);
|
||||
|
||||
Task<(bool isok, string msg)> Freeze(string id);
|
||||
|
||||
Task<(bool isok, string msg)> Unfreeze(string id);
|
||||
|
||||
Task<(bool isok, string msg)> UpdatePrice(string id, long price);
|
||||
|
||||
Task<(bool isok, string msg)> UpdateNumber(string id, string level, long price);
|
||||
|
||||
Task<(bool isok, string msg)> BindToUser(string number, string userId);
|
||||
|
||||
Task<List<BeautifulNumberRule>> GetRules();
|
||||
|
||||
Task<(bool isok, string msg)> AddRule(BeautifulNumberRule rule);
|
||||
|
||||
Task<(bool isok, string msg)> UpdateRule(BeautifulNumberRule rule);
|
||||
|
||||
Task<(bool isok, string msg)> DeleteRule(string id);
|
||||
|
||||
Task<(bool isok, string msg)> GiveToUser(string number, string userId);
|
||||
|
||||
Task<(bool isok, string msg, int count)> InitBeautifulNumbers();
|
||||
|
||||
Task<(bool isok, string msg)> UpdateRules(List<BeautifulNumberRule> rules);
|
||||
|
||||
Task<(bool isok, string msg)> InitRules();
|
||||
|
||||
Task<(bool isok, string msg)> AddNumber(string number, string level, long price);
|
||||
|
||||
Task<(bool isok, string msg, int successCount, int failCount)> BatchAddNumbers(List<string> numbers, string level, long price);
|
||||
}
|
||||
|
||||
public class BeautifulNumberListParam
|
||||
{
|
||||
public int page { get; set; } = 1;
|
||||
|
||||
public int size { get; set; } = 20;
|
||||
|
||||
public string? level { get; set; }
|
||||
|
||||
public int? status { get; set; }
|
||||
|
||||
public string? numberSearch { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using AdminDomain.Customer;
|
||||
using AdminDomain.Customer.Param;
|
||||
using CustomerService.Domain.Entity;
|
||||
using MongoDB.Driver;
|
||||
using MongoRepository;
|
||||
|
||||
namespace AdminService.Customer
|
||||
{
|
||||
public class CustomerService : ICustomerService
|
||||
{
|
||||
private readonly IMongoBaseRepository<CustomerEntity> _customerRepo;
|
||||
private readonly IMongoBaseRepository<ConversationEntity> _conversationRepo;
|
||||
private readonly IMongoBaseRepository<MessageEntity> _messageRepo;
|
||||
|
||||
public CustomerService(
|
||||
IMongoBaseRepository<CustomerEntity> customerRepo,
|
||||
IMongoBaseRepository<ConversationEntity> conversationRepo,
|
||||
IMongoBaseRepository<MessageEntity> messageRepo)
|
||||
{
|
||||
_customerRepo = customerRepo;
|
||||
_conversationRepo = conversationRepo;
|
||||
_messageRepo = messageRepo;
|
||||
}
|
||||
|
||||
public async Task<(bool isOk, string msg, CustomerEntity? customer)> AddCustomer(AddCustomerParam param)
|
||||
{
|
||||
var allCustomers = await _customerRepo.FilterByAsync(x => true);
|
||||
var existCustomer = allCustomers.FirstOrDefault(x => x.UserId == param.UserId);
|
||||
if (existCustomer != null)
|
||||
{
|
||||
return (false, "该用户已是客服", null);
|
||||
}
|
||||
|
||||
var customer = new CustomerEntity
|
||||
{
|
||||
UserId = param.UserId,
|
||||
UserName = param.UserName,
|
||||
Avatar = param.Avatar,
|
||||
Status = 0,
|
||||
CreateTime = DateTime.Now
|
||||
};
|
||||
|
||||
await _customerRepo.InsertOneAsync(customer);
|
||||
return (true, "添加成功", customer);
|
||||
}
|
||||
|
||||
public async Task<(bool isOk, string msg)> UpdateCustomer(UpdateCustomerParam param)
|
||||
{
|
||||
var customer = await _customerRepo.FindByIdAsync(param.Id);
|
||||
if (customer == null)
|
||||
{
|
||||
return (false, "客服不存在");
|
||||
}
|
||||
|
||||
var filter = Builders<CustomerEntity>.Filter.Eq(x => x.Id, param.Id);
|
||||
var update = Builders<CustomerEntity>.Update
|
||||
.Set(x => x.UserName, param.UserName)
|
||||
.Set(x => x.Avatar, param.Avatar)
|
||||
.Set(x => x.Status, param.Status);
|
||||
|
||||
await _customerRepo.UpdateByIdAsync(param.Id, update);
|
||||
return (true, "更新成功");
|
||||
}
|
||||
|
||||
public async Task<(bool isOk, string msg)> DeleteCustomer(string id)
|
||||
{
|
||||
var customer = await _customerRepo.FindByIdAsync(id);
|
||||
if (customer == null)
|
||||
{
|
||||
return (false, "客服不存在");
|
||||
}
|
||||
|
||||
await _customerRepo.DeleteByIdAsync(id);
|
||||
return (true, "删除成功");
|
||||
}
|
||||
|
||||
public async Task<(bool isOk, string msg, List<CustomerEntity>? customers, int total)> GetCustomerList(GetCustomerListParam param)
|
||||
{
|
||||
var list = await _customerRepo.FilterByAsync(x => true);
|
||||
|
||||
if (!string.IsNullOrEmpty(param.UserName))
|
||||
{
|
||||
list = list.Where(x => x.UserName != null && x.UserName.Contains(param.UserName)).ToList();
|
||||
}
|
||||
|
||||
if (param.Status.HasValue)
|
||||
{
|
||||
list = list.Where(x => x.Status == param.Status.Value).ToList();
|
||||
}
|
||||
|
||||
var total = list.Count;
|
||||
var pagedList = list.Skip((param.PageIndex - 1) * param.PageSize).Take(param.PageSize).ToList();
|
||||
|
||||
return (true, "获取成功", pagedList, total);
|
||||
}
|
||||
|
||||
public async Task<(bool isOk, string msg, CustomerEntity? customer)> GetCustomerById(string id)
|
||||
{
|
||||
var customer = await _customerRepo.FindByIdAsync(id);
|
||||
if (customer == null)
|
||||
{
|
||||
return (false, "客服不存在", null);
|
||||
}
|
||||
return (true, "获取成功", customer);
|
||||
}
|
||||
|
||||
public async Task<(bool isOk, string msg, ConversationEntity? conversation)> GetConversationById(string id)
|
||||
{
|
||||
var conversation = await _conversationRepo.FindByIdAsync(id);
|
||||
if (conversation == null)
|
||||
{
|
||||
return (false, "会话不存在", null);
|
||||
}
|
||||
return (true, "获取成功", conversation);
|
||||
}
|
||||
|
||||
public async Task<(bool isOk, string msg, List<ConversationEntity>? conversations, int total)> GetConversationList(GetConversationListParam param)
|
||||
{
|
||||
var list = await _conversationRepo.FilterByAsync(x => true);
|
||||
|
||||
if (!string.IsNullOrEmpty(param.UserId))
|
||||
{
|
||||
list = list.Where(x => x.UserId == param.UserId).ToList();
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(param.CustomerId))
|
||||
{
|
||||
list = list.Where(x => x.CustomerId == param.CustomerId).ToList();
|
||||
}
|
||||
|
||||
if (param.Status.HasValue)
|
||||
{
|
||||
list = list.Where(x => x.Status == param.Status.Value).ToList();
|
||||
}
|
||||
|
||||
var total = list.Count;
|
||||
var pagedList = list.Skip((param.PageIndex - 1) * param.PageSize).Take(param.PageSize).ToList();
|
||||
|
||||
return (true, "获取成功", pagedList, total);
|
||||
}
|
||||
|
||||
public async Task<(bool isOk, string msg)> DeleteConversation(string conversationId)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(conversationId))
|
||||
return (false, "会话ID不能为空");
|
||||
|
||||
var conversation = await _conversationRepo.FindByIdAsync(conversationId);
|
||||
if (conversation == null)
|
||||
return (false, "会话不存在");
|
||||
|
||||
var messages = await _messageRepo.FilterByAsync(x => x.ConversationId == conversationId);
|
||||
foreach (var message in messages)
|
||||
await _messageRepo.DeleteByIdAsync(message.Id);
|
||||
|
||||
await _conversationRepo.DeleteByIdAsync(conversationId);
|
||||
return (true, "删除成功");
|
||||
}
|
||||
|
||||
public async Task<(bool isOk, string msg, List<MessageEntity>? messages)> GetChatLog(string conversationId)
|
||||
{
|
||||
var conversation = await _conversationRepo.FindByIdAsync(conversationId);
|
||||
if (conversation == null)
|
||||
{
|
||||
return (false, "会话不存在", null);
|
||||
}
|
||||
|
||||
var allMessages = await _messageRepo.FilterByAsync(x => true);
|
||||
var messages = allMessages.Where(x => x.ConversationId == conversationId).ToList();
|
||||
return (true, "获取成功", messages);
|
||||
}
|
||||
|
||||
public async Task<(bool isOk, string msg)> DeleteMessage(string id)
|
||||
{
|
||||
var message = await _messageRepo.FindByIdAsync(id);
|
||||
if (message == null)
|
||||
{
|
||||
return (false, "消息不存在");
|
||||
}
|
||||
|
||||
await _messageRepo.DeleteByIdAsync(id);
|
||||
return (true, "删除成功");
|
||||
}
|
||||
|
||||
public async Task<(bool isOk, string msg)> DeleteAllMessages(string conversationId)
|
||||
{
|
||||
var messages = await _messageRepo.FilterByAsync(x => x.ConversationId == conversationId);
|
||||
foreach (var msg in messages)
|
||||
{
|
||||
await _messageRepo.DeleteByIdAsync(msg.Id);
|
||||
}
|
||||
return (true, "删除成功");
|
||||
}
|
||||
|
||||
public async Task<(bool isOk, string msg)> DeleteMessagesBatch(List<string> ids)
|
||||
{
|
||||
foreach (var id in ids)
|
||||
{
|
||||
await _messageRepo.DeleteByIdAsync(id);
|
||||
}
|
||||
return (true, "批量删除成功");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
using System.Linq.Expressions;
|
||||
using Common;
|
||||
using CommonDomain;
|
||||
using CommonDomain.Enum;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using MongoRepository;
|
||||
|
||||
namespace AdminService.EmptyRoomRate
|
||||
{
|
||||
public class EmptyRoomRateConfigService : IEmptyRoomRateConfigService
|
||||
{
|
||||
private readonly IMongoBaseRepository<EmptyRoomRateConfig> _emptyRoomRateMongo;
|
||||
|
||||
public EmptyRoomRateConfigService(
|
||||
IMongoBaseRepository<EmptyRoomRateConfig> emptyRoomRateMongo)
|
||||
{
|
||||
_emptyRoomRateMongo = emptyRoomRateMongo;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<(List<EmptyRoomRateConfig> list, long count)> GetList(int page, int size, GameTypeEnum? gameType, int? roomLevel)
|
||||
{
|
||||
Expression<Func<EmptyRoomRateConfig, bool>> filter = c => true;
|
||||
|
||||
if (gameType.HasValue)
|
||||
{
|
||||
var type = gameType.Value;
|
||||
filter = filter.And(c => c.GameType == type);
|
||||
}
|
||||
|
||||
if (roomLevel.HasValue)
|
||||
{
|
||||
var level = roomLevel.Value;
|
||||
filter = filter.And(c => c.RoomLevel == level);
|
||||
}
|
||||
|
||||
var (total, list) = await _emptyRoomRateMongo.QueryPageAsync(filter, c => c.Id, false, size, page);
|
||||
|
||||
return (list, total);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<(bool isok, string msg)> Add(GameTypeEnum gameType, int roomLevel, int emptyRoomRate)
|
||||
{
|
||||
if (emptyRoomRate < 0 || emptyRoomRate > 100)
|
||||
return (false, "空房率必须在0到100之间");
|
||||
|
||||
if (gameType == GameTypeEnum.中国象棋)
|
||||
roomLevel = 0;
|
||||
|
||||
var existing = gameType == GameTypeEnum.中国象棋
|
||||
? await _emptyRoomRateMongo.FindOneAsync(c => c.GameType == gameType)
|
||||
: await _emptyRoomRateMongo.FindOneAsync(c => c.GameType == gameType && c.RoomLevel == roomLevel);
|
||||
if (existing != null)
|
||||
{
|
||||
return (false, "该游戏类型与房间等级的组合已存在");
|
||||
}
|
||||
|
||||
await _emptyRoomRateMongo.InsertOneAsync(new EmptyRoomRateConfig
|
||||
{
|
||||
GameType = gameType,
|
||||
RoomLevel = roomLevel,
|
||||
EmptyRoomRate = emptyRoomRate
|
||||
});
|
||||
|
||||
return (true, "新增成功");
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<(bool isok, string msg)> Update(string id, int emptyRoomRate)
|
||||
{
|
||||
if (emptyRoomRate < 0 || emptyRoomRate > 100)
|
||||
return (false, "空房率必须在0到100之间");
|
||||
|
||||
var config = await _emptyRoomRateMongo.FindByIdAsync(id);
|
||||
if (config == null)
|
||||
{
|
||||
return (false, "配置不存在");
|
||||
}
|
||||
|
||||
config.EmptyRoomRate = emptyRoomRate;
|
||||
await _emptyRoomRateMongo.ReplaceOneAsync(config);
|
||||
|
||||
return (true, "修改成功");
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<(bool isok, string msg)> Delete(string id)
|
||||
{
|
||||
var config = await _emptyRoomRateMongo.FindByIdAsync(id);
|
||||
if (config == null)
|
||||
{
|
||||
return (false, "配置不存在");
|
||||
}
|
||||
|
||||
await _emptyRoomRateMongo.DeleteByIdAsync(id);
|
||||
|
||||
return (true, "删除成功");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using CommonDomain;
|
||||
using CommonDomain.Enum;
|
||||
|
||||
namespace AdminService.EmptyRoomRate
|
||||
{
|
||||
public interface IEmptyRoomRateConfigService
|
||||
{
|
||||
Task<(List<EmptyRoomRateConfig> list, long count)> GetList(int page, int size, GameTypeEnum? gameType, int? roomLevel);
|
||||
|
||||
Task<(bool isok, string msg)> Add(GameTypeEnum gameType, int roomLevel, int emptyRoomRate);
|
||||
|
||||
Task<(bool isok, string msg)> Update(string id, int emptyRoomRate);
|
||||
|
||||
Task<(bool isok, string msg)> Delete(string id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
|
||||
using CommonDomain;
|
||||
using MongoRepository;
|
||||
|
||||
namespace AdminService.Faq
|
||||
{
|
||||
public class FaqService : IFaqService
|
||||
{
|
||||
private readonly IMongoBaseRepository<FaqCategory> _categoryRepo;
|
||||
private readonly IMongoBaseRepository<FaqQuestion> _questionRepo;
|
||||
|
||||
public FaqService(
|
||||
IMongoBaseRepository<FaqCategory> categoryRepo,
|
||||
IMongoBaseRepository<FaqQuestion> questionRepo)
|
||||
{
|
||||
_categoryRepo = categoryRepo;
|
||||
_questionRepo = questionRepo;
|
||||
}
|
||||
|
||||
|
||||
public async Task<List<FaqCategory>> GetAllCategories()
|
||||
{
|
||||
var list = await _categoryRepo.FilterByAsync(x => x.IsEnable);
|
||||
return list.OrderBy(x => x.Sort).ToList();
|
||||
}
|
||||
|
||||
public async Task<List<FaqCategoryTreeNode>> GetCategoryTree()
|
||||
{
|
||||
var allCategories = await _categoryRepo.FilterByAsync(x => true);
|
||||
var sortedList = allCategories.OrderBy(x => x.Sort).ToList();
|
||||
|
||||
var nodeDict = sortedList.ToDictionary(
|
||||
x => x.Id,
|
||||
x => new FaqCategoryTreeNode
|
||||
{
|
||||
Id = x.Id,
|
||||
Name = x.Name,
|
||||
Icon = x.Icon,
|
||||
Sort = x.Sort,
|
||||
IsEnable = x.IsEnable,
|
||||
Children = new List<FaqCategoryTreeNode>()
|
||||
}
|
||||
);
|
||||
|
||||
var rootNodes = new List<FaqCategoryTreeNode>();
|
||||
|
||||
foreach (var category in sortedList)
|
||||
{
|
||||
var node = nodeDict[category.Id!];
|
||||
|
||||
if (string.IsNullOrEmpty(category.ParentId))
|
||||
{
|
||||
rootNodes.Add(node);
|
||||
}
|
||||
else if (nodeDict.ContainsKey(category.ParentId))
|
||||
{
|
||||
nodeDict[category.ParentId!].Children.Add(node);
|
||||
}
|
||||
else
|
||||
{
|
||||
rootNodes.Add(node);
|
||||
}
|
||||
}
|
||||
|
||||
return rootNodes;
|
||||
}
|
||||
|
||||
public async Task<FaqCategory?> GetCategoryById(string id)
|
||||
{
|
||||
return await _categoryRepo.FindOneAsync(x => x.Id == id);
|
||||
}
|
||||
|
||||
public async Task<(bool ok, string msg)> AddCategory(FaqCategory category)
|
||||
{
|
||||
return await _categoryRepo.InsertOneAsync(category);
|
||||
}
|
||||
|
||||
public async Task<(bool ok, string msg)> UpdateCategory(FaqCategory category)
|
||||
{
|
||||
var existing = await _categoryRepo.FindOneAsync(x => x.Id == category.Id);
|
||||
if (existing == null)
|
||||
return (false, "板块不存在");
|
||||
|
||||
existing.ParentId = category.ParentId;
|
||||
existing.Name = category.Name;
|
||||
existing.Icon = category.Icon;
|
||||
existing.Sort = category.Sort;
|
||||
existing.IsEnable = category.IsEnable;
|
||||
|
||||
return await _categoryRepo.ReplaceOneAsync(existing);
|
||||
}
|
||||
|
||||
public async Task<(bool ok, string msg)> DeleteCategory(string id)
|
||||
{
|
||||
var hasChildren = await _categoryRepo.FindOneAsync(x => x.ParentId == id);
|
||||
if (hasChildren != null)
|
||||
return (false, "该分类下存在子分类,请先删除子分类");
|
||||
|
||||
var questions = await _questionRepo.FilterByAsync(x => x.CategoryId == id);
|
||||
if (questions.Any())
|
||||
return (false, "该板块下存在问题,请先删除相关问题");
|
||||
|
||||
return await _categoryRepo.DeleteByIdAsync(id);
|
||||
}
|
||||
|
||||
|
||||
public async Task<List<FaqQuestion>> GetQuestionsByCategory(string categoryId)
|
||||
{
|
||||
var list = await _questionRepo.FilterByAsync(x => x.CategoryId == categoryId && x.IsEnable);
|
||||
return list.OrderBy(x => x.Sort).ToList();
|
||||
}
|
||||
|
||||
public async Task<(List<FaqQuestion> list, long count)> QueryQuestions(string? categoryId, int pageIndex, int pageSize)
|
||||
{
|
||||
var result = await _questionRepo.QueryPageAsync(
|
||||
filterExpression: x =>
|
||||
(string.IsNullOrEmpty(categoryId) || x.CategoryId == categoryId),
|
||||
orderExpression: x => x.Sort,
|
||||
desc: false,
|
||||
pageSize: pageSize,
|
||||
pageIndex: pageIndex
|
||||
);
|
||||
return (result.list?.OrderBy(x => x.Sort).ToList() ?? new List<FaqQuestion>(), result.count);
|
||||
}
|
||||
|
||||
public async Task<FaqQuestion?> GetQuestionById(string id)
|
||||
{
|
||||
return await _questionRepo.FindOneAsync(x => x.Id == id);
|
||||
}
|
||||
|
||||
public async Task<(bool ok, string msg)> AddQuestion(FaqQuestion question)
|
||||
{
|
||||
question.CreateTime = DateTime.Now;
|
||||
return await _questionRepo.InsertOneAsync(question);
|
||||
}
|
||||
|
||||
public async Task<(bool ok, string msg)> UpdateQuestion(FaqQuestion question)
|
||||
{
|
||||
var existing = await _questionRepo.FindOneAsync(x => x.Id == question.Id);
|
||||
if (existing == null)
|
||||
return (false, "问题不存在");
|
||||
|
||||
existing.CategoryId = question.CategoryId;
|
||||
existing.Title = question.Title;
|
||||
existing.Content = question.Content;
|
||||
existing.Sort = question.Sort;
|
||||
existing.IsEnable = question.IsEnable;
|
||||
|
||||
return await _questionRepo.ReplaceOneAsync(existing);
|
||||
}
|
||||
|
||||
public async Task<(bool ok, string msg)> DeleteQuestion(string id)
|
||||
{
|
||||
return await _questionRepo.DeleteByIdAsync(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using CommonDomain;
|
||||
using MongoRepository;
|
||||
|
||||
namespace AdminService.Faq
|
||||
{
|
||||
public interface IFaqService
|
||||
{
|
||||
Task<List<FaqCategory>> GetAllCategories();
|
||||
Task<List<FaqCategoryTreeNode>> GetCategoryTree();
|
||||
Task<FaqCategory?> GetCategoryById(string id);
|
||||
Task<(bool ok, string msg)> AddCategory(FaqCategory category);
|
||||
Task<(bool ok, string msg)> UpdateCategory(FaqCategory category);
|
||||
Task<(bool ok, string msg)> DeleteCategory(string id);
|
||||
|
||||
Task<List<FaqQuestion>> GetQuestionsByCategory(string categoryId);
|
||||
Task<(List<FaqQuestion> list, long count)> QueryQuestions(string? categoryId, int pageIndex, int pageSize);
|
||||
Task<FaqQuestion?> GetQuestionById(string id);
|
||||
Task<(bool ok, string msg)> AddQuestion(FaqQuestion question);
|
||||
Task<(bool ok, string msg)> UpdateQuestion(FaqQuestion question);
|
||||
Task<(bool ok, string msg)> DeleteQuestion(string id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
using CommonDomain;
|
||||
using DotNetCore.CAP;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using MongoRepository;
|
||||
using RedisService;
|
||||
|
||||
namespace AdminService.GameConfigs
|
||||
{
|
||||
public class ActivityConfigService : IActivityConfigService
|
||||
{
|
||||
private readonly IMongoBaseRepository<ActivityConfig> _mongo;
|
||||
private readonly IRedisService _redis;
|
||||
private readonly ICapPublisher _capPublisher;
|
||||
private readonly ILogger<ActivityConfigService> _logger;
|
||||
|
||||
public ActivityConfigService(
|
||||
IMongoBaseRepository<ActivityConfig> mongo,
|
||||
IRedisService redis,
|
||||
ICapPublisher capPublisher,
|
||||
ILogger<ActivityConfigService> logger)
|
||||
{
|
||||
_mongo = mongo;
|
||||
_redis = redis;
|
||||
_capPublisher = capPublisher;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task<ActivityConfig> Get()
|
||||
{
|
||||
var config = _redis.GetActivityConfig();
|
||||
if (config == null)
|
||||
{
|
||||
config = await _mongo.FindOneAsync(c => true);
|
||||
if (config != null)
|
||||
_redis.SetActivityConfig(config);
|
||||
}
|
||||
|
||||
if (config != null && config.AutoStopExpired(DateTimeOffset.UtcNow.ToUnixTimeSeconds()))
|
||||
{
|
||||
_redis.SetActivityConfig(config);
|
||||
var result = await _mongo.ReplaceOneAsync(config);
|
||||
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
public async Task<(bool isok, string msg)> Update(ActivityConfig config)
|
||||
{
|
||||
var operationId = Guid.NewGuid().ToString("N");
|
||||
var startedAt = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
||||
bool isadd = false;
|
||||
var model = await Get();
|
||||
if (model == null)
|
||||
{
|
||||
isadd = true;
|
||||
config.Id = Guid.NewGuid().ToString("N");
|
||||
}
|
||||
else
|
||||
{
|
||||
config.Id = model.Id;
|
||||
}
|
||||
|
||||
var saveResult = isadd
|
||||
? await _mongo.InsertOneAsync(config)
|
||||
: await _mongo.ReplaceOneAsync(config);
|
||||
if (!saveResult.ok)
|
||||
{
|
||||
|
||||
return (false, saveResult.message);
|
||||
}
|
||||
|
||||
_redis.SetActivityConfig(config);
|
||||
|
||||
var existing = _redis.GetFishingKillConfig();
|
||||
if (existing != null)
|
||||
{
|
||||
existing.BattleOrderIsOpen = config.BattleOrderConfig?.IsOpen ?? false;
|
||||
_redis.SetFishingKillConfig(existing);
|
||||
}
|
||||
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
var publishedAt = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
||||
_capPublisher.Publish(TopicKeys.配置变更, new ConfigChangedMessage
|
||||
{
|
||||
ConfigType = "ActivityConfig",
|
||||
OperationId = operationId,
|
||||
PublishedAtUnixMs = publishedAt
|
||||
});
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "[ActivityConfig] CAP发布失败 operationId={OperationId} topic={Topic}", operationId, TopicKeys.配置变更);
|
||||
return (false, $"数据已保存,但刷新通知发布失败,操作编号:{operationId}");
|
||||
}
|
||||
|
||||
return saveResult;
|
||||
}
|
||||
|
||||
public async Task<(bool isok, string msg)> Delete()
|
||||
{
|
||||
_redis.RemoveActivityConfig();
|
||||
return await _mongo.DeleteOneAsync(c => true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,354 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using AutoMapper;
|
||||
using CommonDomain;
|
||||
using CommonDomain.BaseModel;
|
||||
using CommonDomain.Enum;
|
||||
using DotNetCore.CAP;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using MongoRepository;
|
||||
using NewLife;
|
||||
using RedisService;
|
||||
using RedisService.Param;
|
||||
|
||||
namespace AdminService.GameConfigs
|
||||
{
|
||||
public class GameConfigService : IGameConfigService
|
||||
{
|
||||
private readonly IMongoBaseRepository<GameConfig> _mongo;
|
||||
private readonly IMapper _mapper;
|
||||
private IRedisService _redis;
|
||||
private readonly ICapPublisher _capPublisher;
|
||||
private readonly IMongoBaseRepository<BotProfileEntity> _botProfileRepo;
|
||||
private readonly IMongoBaseRepository<EmptyRoomRateConfig> _emptyRoomRateRepo;
|
||||
private readonly ILogger<GameConfigService> _logger;
|
||||
|
||||
public GameConfigService(IMongoBaseRepository<GameConfig> mongo, IMapper mapper, IRedisService redis, ICapPublisher capPublisher, IMongoBaseRepository<BotProfileEntity> botProfileRepo, IMongoBaseRepository<EmptyRoomRateConfig> emptyRoomRateRepo, ILogger<GameConfigService> logger)
|
||||
{
|
||||
_mongo = mongo;
|
||||
_mapper = mapper;
|
||||
_redis = redis;
|
||||
_capPublisher = capPublisher;
|
||||
_botProfileRepo = botProfileRepo;
|
||||
_emptyRoomRateRepo = emptyRoomRateRepo;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task<GameConfig> Get()
|
||||
{
|
||||
var gameConfig = _redis.GetGameConfig();
|
||||
if (gameConfig == null)
|
||||
{
|
||||
gameConfig = await _mongo.FindOneAsync(c => true);
|
||||
if (gameConfig != null)
|
||||
_redis.SetGameConfig(gameConfig);
|
||||
}
|
||||
return gameConfig;
|
||||
}
|
||||
public async Task<(bool isok, string msg)> Update(GameConfig gameConfig)
|
||||
{
|
||||
NormalizeFishReferences(gameConfig);
|
||||
var operationId = Guid.NewGuid().ToString("N");
|
||||
var startedAt = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
||||
bool isadd = false;
|
||||
var model = await Get();
|
||||
if (model == null)
|
||||
{
|
||||
isadd = true;
|
||||
gameConfig.Id = Guid.NewGuid().ToString("N");
|
||||
}
|
||||
else
|
||||
{
|
||||
gameConfig.Id = model.Id;
|
||||
}
|
||||
|
||||
var saveResult = isadd
|
||||
? await _mongo.InsertOneAsync(gameConfig)
|
||||
: await _mongo.ReplaceOneAsync(gameConfig);
|
||||
if (!saveResult.ok)
|
||||
{
|
||||
|
||||
return saveResult;
|
||||
}
|
||||
|
||||
_redis.SetGameConfig(gameConfig);
|
||||
|
||||
|
||||
var killConfig = new FishingKillConfig
|
||||
{
|
||||
FishTypeConfigs = gameConfig.FishTypeConfigs?.Select(f => new FishTypeBriefConfig
|
||||
{
|
||||
FishNumber = f.FishNumber,
|
||||
FishName = f.FishName,
|
||||
FishType = f.FishType,
|
||||
FishScore = f.FishScore,
|
||||
KillWeight = f.KillWeight
|
||||
}).ToList(),
|
||||
KillConfig = gameConfig.KillConfig,
|
||||
BossConfigs = gameConfig.BossConfigs,
|
||||
BossDropConfig = gameConfig.BossDropConfig,
|
||||
BattleOrderIsOpen = _redis.GetActivityConfig()?.BattleOrderConfig?.IsOpen ?? false
|
||||
};
|
||||
_redis.SetFishingKillConfig(killConfig);
|
||||
|
||||
try
|
||||
{
|
||||
var fishSpawnJson = FishSpawnExtractor.ExtractToJson(gameConfig);
|
||||
_redis.SetFishSpawnConfig(fishSpawnJson);
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "[FishSpawn] 出鱼配置提取失败");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var publishedAt = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
||||
_capPublisher.Publish(TopicKeys.配置变更, new ConfigChangedMessage
|
||||
{
|
||||
ConfigType = "GameConfig",
|
||||
OperationId = operationId,
|
||||
PublishedAtUnixMs = publishedAt
|
||||
});
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "[GameConfig] CAP配置变更事件发布失败 operationId={OperationId}", operationId);
|
||||
}
|
||||
|
||||
return saveResult;
|
||||
}
|
||||
|
||||
private static void NormalizeFishReferences(GameConfig gameConfig)
|
||||
{
|
||||
if (gameConfig == null)
|
||||
return;
|
||||
|
||||
gameConfig.FishTypeConfigs ??= new List<FishTypeConfig>();
|
||||
gameConfig.FishArrayConfigs ??= new List<FishArrayConfig>();
|
||||
gameConfig.RoomFishConfigs ??= new List<RoomFishConfig>();
|
||||
|
||||
var validFishNumbers = gameConfig.FishTypeConfigs
|
||||
.Where(f => f != null && !string.IsNullOrWhiteSpace(f.FishNumber))
|
||||
.Select(f => f.FishNumber)
|
||||
.ToHashSet(StringComparer.Ordinal);
|
||||
|
||||
gameConfig.FishArrayConfigs = gameConfig.FishArrayConfigs
|
||||
.Where(a => a != null
|
||||
&& (string.IsNullOrWhiteSpace(a.FishNumber) || validFishNumbers.Contains(a.FishNumber))
|
||||
&& (string.IsNullOrWhiteSpace(a.BossFishNumber) || validFishNumbers.Contains(a.BossFishNumber)))
|
||||
.ToList();
|
||||
var validArrayNumbers = gameConfig.FishArrayConfigs
|
||||
.Where(a => !string.IsNullOrWhiteSpace(a.FishArrayNumber))
|
||||
.Select(a => a.FishArrayNumber)
|
||||
.ToHashSet(StringComparer.Ordinal);
|
||||
|
||||
bool IsValidRoomFish(RoomFishDetailConfig item) => item != null && item.Type switch
|
||||
{
|
||||
1 => validFishNumbers.Contains(item.FishNumber),
|
||||
2 => validArrayNumbers.Contains(item.FishNumber),
|
||||
_ => false
|
||||
};
|
||||
|
||||
foreach (var roomFishConfig in gameConfig.RoomFishConfigs.Where(c => c != null))
|
||||
{
|
||||
roomFishConfig.NormalFishList = (roomFishConfig.NormalFishList ?? new List<RoomFishDetailConfig>())
|
||||
.Where(IsValidRoomFish).ToList();
|
||||
roomFishConfig.RoomFishLevelList = (roomFishConfig.RoomFishLevelList ?? new List<RoomFishLevelConfig>())
|
||||
.Where(IsValidRoomFish).ToList();
|
||||
}
|
||||
|
||||
static void CleanFishNumbers(BossConfig.BaseBossConfig config, HashSet<string> validNumbers)
|
||||
{
|
||||
if (config == null) return;
|
||||
config.FishNumber = (config.FishNumber ?? new List<string>())
|
||||
.Where(validNumbers.Contains).Distinct().ToList();
|
||||
}
|
||||
|
||||
var boss = gameConfig.BossConfigs;
|
||||
if (boss != null)
|
||||
{
|
||||
boss.LuckWheel = (boss.LuckWheel ?? new List<BossConfig.LuckWheelConfig>())
|
||||
.Where(c => c != null).ToList();
|
||||
boss.LuckWheel.ForEach(c => CleanFishNumbers(c, validFishNumbers));
|
||||
boss.LuckWheel = boss.LuckWheel.Where(c => c.FishNumber.Count > 0).ToList();
|
||||
|
||||
CleanFishNumbers(boss.LuckPoker, validFishNumbers);
|
||||
|
||||
boss.LuckFlyDisk = (boss.LuckFlyDisk ?? new List<BossConfig.LuckFlyDiskConfig>())
|
||||
.Where(c => c != null).ToList();
|
||||
boss.LuckFlyDisk.ForEach(c => CleanFishNumbers(c, validFishNumbers));
|
||||
boss.LuckFlyDisk = boss.LuckFlyDisk.Where(c => c.FishNumber.Count > 0).ToList();
|
||||
|
||||
CleanFishNumbers(boss.FullScreen, validFishNumbers);
|
||||
CleanFishNumbers(boss.Range, validFishNumbers);
|
||||
CleanFishNumbers(boss.AmmunitionBox, validFishNumbers);
|
||||
CleanFishNumbers(boss.InterstellarCruise, validFishNumbers);
|
||||
CleanFishNumbers(boss.FlameStorm, validFishNumbers);
|
||||
CleanFishNumbers(boss.Bomb, validFishNumbers);
|
||||
CleanFishNumbers(boss.Scorpion, validFishNumbers);
|
||||
|
||||
boss.Probability = (boss.Probability ?? new List<BossConfig.BossProbabilityConfig>())
|
||||
.Where(c => c != null).ToList();
|
||||
boss.Probability.ForEach(c => CleanFishNumbers(c, validFishNumbers));
|
||||
boss.Probability = boss.Probability.Where(c => c.FishNumber.Count > 0).ToList();
|
||||
|
||||
boss.LuckDragon = (boss.LuckDragon ?? new List<BossConfig.LuckDragonConfig>())
|
||||
.Where(c => c != null).ToList();
|
||||
boss.LuckDragon.ForEach(c => CleanFishNumbers(c, validFishNumbers));
|
||||
boss.LuckDragon = boss.LuckDragon.Where(c => c.FishNumber.Count > 0).ToList();
|
||||
}
|
||||
|
||||
if (gameConfig.RobotKillConfig != null)
|
||||
{
|
||||
gameConfig.RobotKillConfig.Scenes = (gameConfig.RobotKillConfig.Scenes ?? new List<RobotKillScene>())
|
||||
.Where(s => s != null && validFishNumbers.Contains(s.FishNumber))
|
||||
.ToList();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<(bool isok, string msg)> Delete()
|
||||
{
|
||||
_redis.RemoveGameConfig();
|
||||
|
||||
|
||||
return await _mongo.DeleteOneAsync(c=>true);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public async Task<List<RedisGameRoom>> InitRoom(GameTypeEnum gameType = GameTypeEnum.None, int roomLevel = 0, GameConfig gameConfig = null)
|
||||
{
|
||||
|
||||
List<RedisGameRoom> result = new List<RedisGameRoom>();
|
||||
|
||||
if (gameConfig == null)
|
||||
{
|
||||
gameConfig = await Get();
|
||||
}
|
||||
|
||||
if (gameConfig == null || gameConfig.RoomConfigs == null || gameConfig.RoomConfigs.Count == 0)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
var roomConfig = gameConfig.RoomConfigs.AsEnumerable();
|
||||
if (gameType != GameTypeEnum.None)
|
||||
roomConfig = roomConfig.Where(c => c.GameType == gameType);
|
||||
if (roomLevel > 0)
|
||||
roomConfig = roomConfig.Where(c => c.RoomLevel == roomLevel);
|
||||
|
||||
var roomList = roomConfig.ToList();
|
||||
if (roomList.Count == 0)
|
||||
return result;
|
||||
|
||||
var initBotProfiles = RoomBotFactory.FixedBotSeatsEnabled
|
||||
? _botProfileRepo.FilterBy(p => true).ToList()
|
||||
: null;
|
||||
|
||||
foreach (var item in roomList.Where(c=>c.GameType!= GameTypeEnum.中国象棋))
|
||||
{
|
||||
var rateConfig = _emptyRoomRateRepo
|
||||
.FilterBy(c => c.GameType == item.GameType && c.RoomLevel == item.RoomLevel && !c.IsDelete)
|
||||
.FirstOrDefault();
|
||||
var botsEnabled = gameConfig.BotConfig?.Enabled == true;
|
||||
var emptyRate = botsEnabled ? Math.Clamp(rateConfig?.EmptyRoomRate ?? 0, 0, 100) : 100;
|
||||
var totalRoomCount = item.RoomPartitionNum * item.RoomCount;
|
||||
var roomsWithBots = emptyRate > 0
|
||||
? (int)Math.Floor(totalRoomCount * (100 - emptyRate) / 100.0)
|
||||
: totalRoomCount;
|
||||
var botRoomIndexes = Enumerable.Range(0, totalRoomCount)
|
||||
.OrderBy(_ => global::System.Random.Shared.Next())
|
||||
.Take(roomsWithBots)
|
||||
.ToHashSet();
|
||||
|
||||
for (var i = 1; i <= item.RoomPartitionNum; i++)
|
||||
{
|
||||
_redis.RemoveGameRoom($"{(int)item.GameType}{item.RoomLevel}{i}");
|
||||
|
||||
for (int c = 0; c < item.RoomCount; c++)
|
||||
{
|
||||
RedisGameRoom room = new RedisGameRoom()
|
||||
{
|
||||
RoomName = item.RoomName,
|
||||
GameType = item.GameType,
|
||||
RoomLevel = item.RoomLevel,
|
||||
RoomPartition = i,
|
||||
RoomNumber = c,
|
||||
MaxPlayerCount = (item.GameType == GameTypeEnum.星际迷航 || item.GameType == GameTypeEnum.中国象棋) ? 2 : 4,
|
||||
CurrentOnlinePlayerCount = 0,
|
||||
|
||||
};
|
||||
var roomIndex = (i - 1) * item.RoomCount + c;
|
||||
room.RobotCount = botsEnabled && botRoomIndexes.Contains(roomIndex)
|
||||
? global::System.Random.Shared.Next(1, room.MaxPlayerCount)
|
||||
: 0;
|
||||
room.RoomId = $"{(int)room.GameType}{room.RoomLevel}{room.RoomPartition}{c.ToString("00")}";
|
||||
|
||||
if (room.RobotCount > 0 && RoomBotFactory.FixedBotSeatsEnabled)
|
||||
{
|
||||
var fixedBots = RoomBotFactory.CreateFixedSeatBots(room, item, gameConfig, initBotProfiles);
|
||||
if (fixedBots.Count > 0)
|
||||
{
|
||||
room.Players.AddRange(fixedBots);
|
||||
room.RobotCount = fixedBots.Count;
|
||||
}
|
||||
}
|
||||
|
||||
result.Add(room);
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (var item in result)
|
||||
{
|
||||
_redis.SetGameRoom(item);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
|
||||
public Task<string> InitDefaultConfig()
|
||||
{
|
||||
return Task.FromResult("初始化配置请使用GameConfigController的Init接口");
|
||||
}
|
||||
|
||||
public async Task ResetDefaultRoomConfigs()
|
||||
{
|
||||
var config = await Get();
|
||||
if (config == null) return;
|
||||
|
||||
var chessConfigs = config.RoomConfigs?.Where(c => c.GameType == GameTypeEnum.中国象棋).ToList() ?? new List<RoomConfig>();
|
||||
|
||||
config.RoomConfigs = new List<RoomConfig>();
|
||||
|
||||
config.RoomConfigs.Add(new RoomConfig() { RoomNumber = "20011", RoomName = "初级场", GameType = GameTypeEnum.风雷之渊, RoomLevel = 1, RoomPartitionNum = 4, RoomCount = 100, RoomGoldLimit = 100000, CannonMultipleList = new List<int> { 1000, 2000, 3000, 5000, 6000, 7000, 8000, 9000, 10000, 20000 } });
|
||||
config.RoomConfigs.Add(new RoomConfig() { RoomNumber = "20012", RoomName = "中级场", GameType = GameTypeEnum.风雷之渊, RoomLevel = 2, RoomPartitionNum = 4, RoomCount = 100, RoomGoldLimit = 1000000, CannonMultipleList = new List<int> { 100, 200, 300, 500, 600, 700, 800, 900, 1000, 2000 } });
|
||||
config.RoomConfigs.Add(new RoomConfig() { RoomNumber = "20013", RoomName = "高级场", GameType = GameTypeEnum.风雷之渊, RoomLevel = 3, RoomPartitionNum = 4, RoomCount = 100, RoomGoldLimit = 2000000, CannonMultipleList = new List<int> { 2000, 3000, 5000, 6000, 7000, 8000, 9000, 10000, 20000, 50000 } });
|
||||
|
||||
config.RoomConfigs.Add(new RoomConfig() { RoomNumber = "20021", RoomName = "初级场", GameType = GameTypeEnum.永夜尸城, RoomLevel = 1, RoomPartitionNum = 4, RoomCount = 100, RoomGoldLimit = 100000, CannonMultipleList = new List<int> { 1000, 2000, 3000, 5000, 6000, 7000, 8000, 9000, 10000, 20000 } });
|
||||
config.RoomConfigs.Add(new RoomConfig() { RoomNumber = "20022", RoomName = "中级场", GameType = GameTypeEnum.永夜尸城, RoomLevel = 2, RoomPartitionNum = 4, RoomCount = 100, RoomGoldLimit = 1000000, CannonMultipleList = new List<int> { 100, 200, 300, 500, 600, 700, 800, 900, 1000, 2000 } });
|
||||
config.RoomConfigs.Add(new RoomConfig() { RoomNumber = "20023", RoomName = "高级场", GameType = GameTypeEnum.永夜尸城, RoomLevel = 3, RoomPartitionNum = 4, RoomCount = 100, RoomGoldLimit = 2000000, CannonMultipleList = new List<int> { 2000, 3000, 5000, 6000, 7000, 8000, 9000, 10000, 20000, 50000 } });
|
||||
|
||||
config.RoomConfigs.Add(new RoomConfig() { RoomNumber = "20041", RoomName = "初级场", GameType = GameTypeEnum.星际迷航, RoomLevel = 1, RoomPartitionNum = 4, RoomCount = 100, RoomGoldLimit = 100000, CannonMultipleList = new List<int> { 1000, 2000, 3000, 5000, 6000, 7000, 8000, 9000, 10000, 20000 } });
|
||||
config.RoomConfigs.Add(new RoomConfig() { RoomNumber = "20042", RoomName = "中级场", GameType = GameTypeEnum.星际迷航, RoomLevel = 2, RoomPartitionNum = 4, RoomCount = 100, RoomGoldLimit = 1000000, CannonMultipleList = new List<int> { 100, 200, 300, 500, 600, 700, 800, 900, 1000, 2000 } });
|
||||
config.RoomConfigs.Add(new RoomConfig() { RoomNumber = "20043", RoomName = "高级场", GameType = GameTypeEnum.星际迷航, RoomLevel = 3, RoomPartitionNum = 4, RoomCount = 100, RoomGoldLimit = 2000000, CannonMultipleList = new List<int> { 2000, 3000, 5000, 6000, 7000, 8000, 9000, 10000, 20000, 50000 } });
|
||||
|
||||
config.RoomConfigs.Add(new RoomConfig() { RoomNumber = "20051", RoomName = "初级场", GameType = GameTypeEnum.黑神话悟空, RoomLevel = 1, RoomPartitionNum = 4, RoomCount = 100, RoomGoldLimit = 100000, CannonMultipleList = new List<int> { 1000, 2000, 3000, 5000, 6000, 7000, 8000, 9000, 10000, 20000 } });
|
||||
config.RoomConfigs.Add(new RoomConfig() { RoomNumber = "20052", RoomName = "中级场", GameType = GameTypeEnum.黑神话悟空, RoomLevel = 2, RoomPartitionNum = 4, RoomCount = 100, RoomGoldLimit = 1000000, CannonMultipleList = new List<int> { 100, 200, 300, 500, 600, 700, 800, 900, 1000, 2000 } });
|
||||
config.RoomConfigs.Add(new RoomConfig() { RoomNumber = "20053", RoomName = "高级场", GameType = GameTypeEnum.黑神话悟空, RoomLevel = 3, RoomPartitionNum = 4, RoomCount = 100, RoomGoldLimit = 2000000, CannonMultipleList = new List<int> { 2000, 3000, 5000, 6000, 7000, 8000, 9000, 10000, 20000, 50000 } });
|
||||
|
||||
if (chessConfigs.Any())
|
||||
config.RoomConfigs.AddRange(chessConfigs);
|
||||
|
||||
await Update(config);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using CommonDomain;
|
||||
|
||||
namespace AdminService.GameConfigs
|
||||
{
|
||||
public interface IActivityConfigService
|
||||
{
|
||||
Task<ActivityConfig> Get();
|
||||
|
||||
Task<(bool isok, string msg)> Update(ActivityConfig config);
|
||||
|
||||
Task<(bool isok, string msg)> Delete();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using CommonDomain;
|
||||
using CommonDomain.Enum;
|
||||
using RedisService.Param;
|
||||
|
||||
namespace AdminService.GameConfigs
|
||||
{
|
||||
public interface IGameConfigService
|
||||
{
|
||||
|
||||
Task<GameConfig> Get();
|
||||
Task<(bool isok, string msg)> Update(GameConfig gameConfig);
|
||||
|
||||
Task<(bool isok, string msg)> Delete();
|
||||
|
||||
|
||||
Task<List<RedisGameRoom>> InitRoom(GameTypeEnum gameType = GameTypeEnum.None, int roomLevel = 0, GameConfig gameConfig = null);
|
||||
|
||||
Task<string> InitDefaultConfig();
|
||||
|
||||
Task ResetDefaultRoomConfigs();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace AdminService.ImageUpload
|
||||
{
|
||||
public interface IImageUploadService
|
||||
{
|
||||
bool ValidateImage(IFormFile file, out string errorMessage);
|
||||
|
||||
Task<(bool isOk, string path, string fileName, string errorMessage)> UploadImageAsync(IFormFile file, string? customName = null);
|
||||
|
||||
Task<List<BatchUploadResult>> UploadBatchImagesAsync(IFormFile[] files);
|
||||
}
|
||||
|
||||
public class BatchUploadResult
|
||||
{
|
||||
public string OriginalFileName { get; set; } = string.Empty;
|
||||
|
||||
public bool Success { get; set; }
|
||||
|
||||
public string? Path { get; set; }
|
||||
|
||||
public string? FileName { get; set; }
|
||||
|
||||
public string? Message { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace AdminService.ImageUpload
|
||||
{
|
||||
public class ImageUploadService : IImageUploadService
|
||||
{
|
||||
private readonly ILogger<ImageUploadService> _logger;
|
||||
private static readonly string[] AllowedExtensions = { ".jpg", ".jpeg", ".png", ".gif", ".bmp", ".webp" };
|
||||
private const long MaxFileSize = 5 * 1024 * 1024; // 5MB
|
||||
private const string UploadFolder = "wwwroot/uploads/temp";
|
||||
|
||||
public ImageUploadService(ILogger<ImageUploadService> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public bool ValidateImage(IFormFile file, out string errorMessage)
|
||||
{
|
||||
errorMessage = string.Empty;
|
||||
|
||||
if (file == null || file.Length == 0)
|
||||
{
|
||||
errorMessage = "请选择要上传的文件";
|
||||
return false;
|
||||
}
|
||||
|
||||
var ext = Path.GetExtension(file.FileName).ToLowerInvariant();
|
||||
if (!AllowedExtensions.Contains(ext))
|
||||
{
|
||||
errorMessage = "只支持上传图片格式:jpg、jpeg、png、gif、bmp、webp";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (file.Length > MaxFileSize)
|
||||
{
|
||||
errorMessage = "文件大小不能超过5MB";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task<(bool isOk, string path, string fileName, string errorMessage)> UploadImageAsync(IFormFile file, string? customName = null)
|
||||
{
|
||||
if (!ValidateImage(file, out var errorMessage))
|
||||
{
|
||||
return (false, string.Empty, string.Empty, errorMessage);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
|
||||
string fileName;
|
||||
string relativePath;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(customName))
|
||||
{
|
||||
fileName = customName + ".png";
|
||||
var uploadPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "uploads");
|
||||
if (!Directory.Exists(uploadPath))
|
||||
Directory.CreateDirectory(uploadPath);
|
||||
var filePath = Path.Combine(uploadPath, fileName);
|
||||
using (var stream = new FileStream(filePath, FileMode.Create))
|
||||
{
|
||||
await file.CopyToAsync(stream);
|
||||
}
|
||||
relativePath = $"/uploads/{fileName}?timespan={timestamp}";
|
||||
}
|
||||
else
|
||||
{
|
||||
var ext = Path.GetExtension(file.FileName).ToLowerInvariant();
|
||||
fileName = Guid.NewGuid().ToString("N") + ext;
|
||||
var uploadPath = Path.Combine(Directory.GetCurrentDirectory(), UploadFolder);
|
||||
if (!Directory.Exists(uploadPath))
|
||||
Directory.CreateDirectory(uploadPath);
|
||||
var filePath = Path.Combine(uploadPath, fileName);
|
||||
using (var stream = new FileStream(filePath, FileMode.Create))
|
||||
{
|
||||
await file.CopyToAsync(stream);
|
||||
}
|
||||
relativePath = $"/uploads/temp/{fileName}?timespan={timestamp}";
|
||||
}
|
||||
|
||||
return (true, relativePath, fileName, string.Empty);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "图片上传失败: {Message}", ex.Message);
|
||||
return (false, string.Empty, string.Empty, $"上传失败:{ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<List<BatchUploadResult>> UploadBatchImagesAsync(IFormFile[] files)
|
||||
{
|
||||
var results = new List<BatchUploadResult>();
|
||||
|
||||
foreach (var file in files)
|
||||
{
|
||||
var result = new BatchUploadResult
|
||||
{
|
||||
OriginalFileName = file.FileName
|
||||
};
|
||||
|
||||
if (file.Length == 0)
|
||||
{
|
||||
result.Success = false;
|
||||
result.Message = "文件为空";
|
||||
results.Add(result);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ValidateImage(file, out var errorMessage))
|
||||
{
|
||||
result.Success = false;
|
||||
result.Message = errorMessage;
|
||||
results.Add(result);
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var uploadResult = await UploadImageAsync(file);
|
||||
result.Success = uploadResult.isOk;
|
||||
result.Path = uploadResult.path;
|
||||
result.FileName = uploadResult.fileName;
|
||||
result.Message = uploadResult.errorMessage;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.Success = false;
|
||||
result.Message = "上传失败";
|
||||
_logger.LogError(ex, "批量上传中单个文件上传失败: {FileName}", file.FileName);
|
||||
}
|
||||
|
||||
results.Add(result);
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using AdminService.Notices.Param;
|
||||
using UserDomain.Entity;
|
||||
|
||||
namespace AdminService.Notices
|
||||
{
|
||||
public interface INoticeService
|
||||
{
|
||||
|
||||
Task<(bool isok, string msg)> Add(AddNoticeParam param);
|
||||
Task<(bool isok, string msg)> Update(UpdateNoticeParam param);
|
||||
|
||||
Task<(bool isok, string msg)> Delete(string id);
|
||||
|
||||
Task<Notice> Get(string id);
|
||||
|
||||
|
||||
Task<(List<Notice> list, long count)> GetList(GetNoticeListParam param);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
using AdminService.Notices.Param;
|
||||
using AutoMapper;
|
||||
using Common;
|
||||
using Common.Utils;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using MongoDB.Bson;
|
||||
using MongoRepository;
|
||||
using UserDomain.Entity;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace AdminService.Notices
|
||||
{
|
||||
public class NoticeService : INoticeService
|
||||
{
|
||||
private readonly IMongoBaseRepository<Notice> _noticeMongo;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
|
||||
public NoticeService(IMongoBaseRepository<Notice> noticeMongo, IMapper mapper)
|
||||
{
|
||||
_noticeMongo = noticeMongo;
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
|
||||
private void MoveTempFiles(Notice notice)
|
||||
{
|
||||
var wwwroot = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot");
|
||||
var tempDir = Path.Combine(wwwroot, "uploads", "temp");
|
||||
var noticeDir = Path.Combine(wwwroot, "uploads", "notice");
|
||||
if (!Directory.Exists(noticeDir)) Directory.CreateDirectory(noticeDir);
|
||||
|
||||
var paths = new List<string>();
|
||||
|
||||
if (!string.IsNullOrEmpty(notice.Content))
|
||||
{
|
||||
foreach (Match m in Regex.Matches(notice.Content, @"/uploads/temp/([^""'\s]+)"))
|
||||
{
|
||||
paths.Add(m.Value);
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(notice.TopImage) && notice.TopImage.Contains("/uploads/temp/"))
|
||||
paths.Add(notice.TopImage);
|
||||
|
||||
if (notice.ContentImages != null)
|
||||
{
|
||||
foreach (var img in notice.ContentImages)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(img) && img.Contains("/uploads/temp/"))
|
||||
paths.Add(img);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var path in paths)
|
||||
{
|
||||
var cleanPath = path.Split('?', '#')[0];
|
||||
var fileName = Path.GetFileName(cleanPath);
|
||||
if (string.IsNullOrWhiteSpace(fileName))
|
||||
continue;
|
||||
var src = Path.Combine(tempDir, fileName);
|
||||
var dest = Path.Combine(noticeDir, fileName);
|
||||
if (File.Exists(src))
|
||||
{
|
||||
File.Move(src, dest, overwrite: true);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(notice.Content))
|
||||
notice.Content = notice.Content.Replace("/uploads/temp/", "/uploads/notice/");
|
||||
if (!string.IsNullOrEmpty(notice.TopImage))
|
||||
notice.TopImage = notice.TopImage.Replace("/uploads/temp/", "/uploads/notice/");
|
||||
if (notice.ContentImages != null)
|
||||
{
|
||||
for (int i = 0; i < notice.ContentImages.Count; i++)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(notice.ContentImages[i]))
|
||||
notice.ContentImages[i] = notice.ContentImages[i].Replace("/uploads/temp/", "/uploads/notice/");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<(bool isok, string msg)> Add(AddNoticeParam param)
|
||||
{
|
||||
var model = _mapper.Map<Notice>(param);
|
||||
model.Id = ObjectId.GenerateNewId().ToString();
|
||||
|
||||
model.CreateTime = DateTime.Now.ToTimeStamp();
|
||||
|
||||
MoveTempFiles(model);
|
||||
|
||||
return await _noticeMongo.InsertOneAsync(model);
|
||||
}
|
||||
public async Task<(bool isok, string msg)> Update(UpdateNoticeParam param)
|
||||
{
|
||||
var model = await Get(param.Id);
|
||||
if (model == null)
|
||||
return (false, "该条公告不存在");
|
||||
model.Title = param.Title;
|
||||
model.Content = param.Content;
|
||||
model.Recommend = param.Recommend;
|
||||
model.TopImage = param.TopImage;
|
||||
model.ContentImages = param.ContentImages;
|
||||
|
||||
MoveTempFiles(model);
|
||||
|
||||
return await _noticeMongo.ReplaceOneAsync(model);
|
||||
}
|
||||
|
||||
public async Task<(bool isok, string msg)> Delete(string id)
|
||||
{
|
||||
var model = await Get(id);
|
||||
if (model == null)
|
||||
return (false, "该条公告不存在");
|
||||
model.IsDelete = true;
|
||||
return await _noticeMongo.ReplaceOneAsync(model);
|
||||
}
|
||||
|
||||
public async Task<Notice> Get(string id)
|
||||
{
|
||||
var model = await _noticeMongo.FindByIdAsync(id);
|
||||
if (model == null)
|
||||
return null;
|
||||
if (model.IsDelete)
|
||||
return null;
|
||||
return model;
|
||||
|
||||
}
|
||||
|
||||
|
||||
public async Task<(List<Notice> list, long count)> GetList(GetNoticeListParam param)
|
||||
{
|
||||
var where = LinqExtensions.True<Notice>().And(e => e.IsDelete == false);
|
||||
if (!string.IsNullOrWhiteSpace(param.KeyWord))
|
||||
where = where.And(e => e.Title.Contains(param.KeyWord));
|
||||
|
||||
|
||||
var result = await _noticeMongo.QueryPageAsync(where, c => c.CreateTime, true, param.PageSize ?? 0, param.PageIndex ?? 0);
|
||||
|
||||
return (result.list, result.count);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AdminService.Notices.Param
|
||||
{
|
||||
public class AddNoticeParam
|
||||
{
|
||||
public string Title { get; set; }
|
||||
public string Content { get; set; }
|
||||
|
||||
public string Recommend { get; set; }
|
||||
public string TopImage { get; set; }
|
||||
public List<string> ContentImages { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Common.CommonModel;
|
||||
|
||||
namespace AdminService.Notices.Param
|
||||
{
|
||||
public class GetNoticeListParam : BaseListPageParam
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace AdminService.Notices.Param
|
||||
{
|
||||
public class UpdateNoticeParam : AddNoticeParam
|
||||
{
|
||||
public string Id { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
using AdminService.System.Param;
|
||||
using AdminService.System.Response;
|
||||
using CommonInfrastructure.Response;
|
||||
using Domain.Admin.Admin;
|
||||
|
||||
namespace AdminService.System
|
||||
{
|
||||
public interface ISystemService
|
||||
{
|
||||
|
||||
Task<(bool isok, string msg)> AddUser(AddUserParam param);
|
||||
Task<(bool isok, string msg)> UpdateUser(UpdateUserParam param);
|
||||
Task<(bool isok, string msg)> UpdateUserIcon(string id, string icon);
|
||||
Task<(bool isok, string msg)> UpdateUserState(string id, int state);
|
||||
|
||||
|
||||
Task<SystemUser> GetUser(string id);
|
||||
|
||||
|
||||
Task<SystemUser> GetUserByName(string userName);
|
||||
Task<(bool isok, string msg, AdminUserToken? model)> UserLogin(string userName, string password);
|
||||
Task<(List<SystemUser> list, long count)> GetUserList(GetUserListParam param);
|
||||
Task<(bool isok, string msg)> DeleteUser(string id);
|
||||
|
||||
Task<List<SystemNavigationResponse>> GetUserNav(LoginUser loginUser);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Task<(bool isok, string msg)> AddRole(AddRoleParam param);
|
||||
Task<(bool isok, string msg)> UpdateRole(UpdateRoleParam param);
|
||||
|
||||
Task<(bool isok, string msg)> UpdateRoleNav(UpdateRoleNavParam param);
|
||||
Task<(bool isok, string msg)> DeleteRole(string id);
|
||||
|
||||
Task<List<SystemUserRole>> GetRoleList();
|
||||
|
||||
Task<SystemUserRole> GetUserRole(string id);
|
||||
|
||||
|
||||
Task<(bool isok, string msg)> AddNav(AddNavParam param);
|
||||
|
||||
Task<(bool isok, string msg)> UpdateNav(UpdateNavParam param);
|
||||
Task<(bool isok, string msg)> DeleteNav(string id);
|
||||
|
||||
Task<List<SystemNavigationResponse>> GetNavList(string navId);
|
||||
|
||||
|
||||
|
||||
Task<(bool isok, string msg)> AddDic(AddDicParam param);
|
||||
|
||||
Task<(bool isok, string msg)> UpdateDic(UpdateDicParam param);
|
||||
Task<(bool isok, string msg)> DeleteDic(string id);
|
||||
|
||||
Task<List<SystemDicResponse>> GetDicList(string dicId);
|
||||
|
||||
Task<List<SystemDicResponse>> GetDicListByCode(string code);
|
||||
|
||||
Task<SystemDic> GetDictByCode(string code);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AdminService.System.Param
|
||||
{
|
||||
public class AddDicParam
|
||||
{
|
||||
public string ParentId { set; get; } = "";
|
||||
|
||||
public string? Name { get; set; }
|
||||
|
||||
public int Order { get; set; }
|
||||
|
||||
public string? Icon { get; set; }
|
||||
|
||||
public string? Value { get; set; }
|
||||
public string? Code { get; set; }
|
||||
|
||||
public string? Remark { get; set; }
|
||||
|
||||
public string? Remark1 { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using Domain.Admin.Admin.ENum;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AdminService.System.Param
|
||||
{
|
||||
public class AddNavParam
|
||||
{
|
||||
public string ParentId { set; get; } = "";
|
||||
|
||||
public string? Name { get; set; }
|
||||
|
||||
public int Order { get; set; }
|
||||
|
||||
public string? Icon { get; set; }
|
||||
|
||||
public string? Url { get; set; }
|
||||
|
||||
public int Category { get; set; }
|
||||
|
||||
public string? Target { get; set; }
|
||||
|
||||
public EnumResource IsResource { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AdminService.System.Param
|
||||
{
|
||||
public class AddRoleParam
|
||||
{
|
||||
public string? RoleName { get; set; }
|
||||
|
||||
public string? Description { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using Common.CommonModel;
|
||||
|
||||
namespace AdminService.System.Param
|
||||
{
|
||||
public class AddUserParam
|
||||
{
|
||||
public string? UserName { get; set; }
|
||||
public string? Icon { get; set; }
|
||||
public string? DisplayName { get; set; }
|
||||
public string? Password { get; set; }
|
||||
|
||||
public BaseIdName SystemRole { get; set; }
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Common.CommonModel;
|
||||
|
||||
namespace AdminService.System.Param
|
||||
{
|
||||
public class GetUserListParam:BaseListPageParam
|
||||
{
|
||||
public int State { get; set; } = -1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace AdminService.System.Param
|
||||
{
|
||||
public class UpdateDicParam : AddDicParam
|
||||
{
|
||||
public string? Id { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace AdminService.System.Param
|
||||
{
|
||||
public class UpdateNavParam:AddNavParam
|
||||
{
|
||||
public string? Id { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AdminService.System.Param
|
||||
{
|
||||
public class UpdateRoleNavParam
|
||||
{
|
||||
public string? Id { get; set; }
|
||||
public List<string> NavIds { get; set; } = new List<string>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AdminService.System.Param
|
||||
{
|
||||
public class UpdateRoleParam : AddRoleParam
|
||||
{
|
||||
public string? Id { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AdminService.System.Param
|
||||
{
|
||||
public class UpdateUserParam :AddUserParam
|
||||
{
|
||||
public string? Id { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
namespace AdminService.System.Response
|
||||
{
|
||||
public class AdminUserToken
|
||||
{
|
||||
public string Token { get; set; }
|
||||
|
||||
public string? UserName { get; set; }
|
||||
|
||||
|
||||
public string? DisplayName { get; set; }
|
||||
|
||||
public string? Icon { get; set; }
|
||||
|
||||
|
||||
public DateTime RegisterTime { get; set; } = DateTime.Now;
|
||||
public string UserId { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Domain.Admin.Admin;
|
||||
|
||||
namespace AdminService.System.Response
|
||||
{
|
||||
public class SystemDicResponse : SystemDic
|
||||
{
|
||||
public List<SystemDicResponse> Children { get; set; } =new List<SystemDicResponse>();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using Domain.Admin.Admin;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AdminService.System.Response
|
||||
{
|
||||
public class SystemNavigationResponse:SystemNavigation
|
||||
{
|
||||
public List<SystemNavigationResponse> Children { get; set; } =new List<SystemNavigationResponse>();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,469 @@
|
||||
using System.Security.Claims;
|
||||
using AdminService.System.Param;
|
||||
using AdminService.System.Response;
|
||||
using AutoMapper;
|
||||
using Common;
|
||||
using Common.Utils;
|
||||
using CommonInfrastructure.Response;
|
||||
using Domain.Admin.Admin;
|
||||
using Domain.Admin.Admin.ENum;
|
||||
using JWTHelper;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using MongoDB.Driver;
|
||||
using MongoRepository;
|
||||
using RedisHelper;
|
||||
|
||||
namespace AdminService.System
|
||||
{
|
||||
public class SystemService: ISystemService
|
||||
{
|
||||
private readonly IMongoBaseRepository<SystemUser> _systemUserRepository;
|
||||
private readonly IMongoBaseRepository<SystemUserRole> _systemRoleRepository;
|
||||
private readonly IMongoBaseRepository<SystemNavigation> _navigationRepository;
|
||||
private readonly IMongoBaseRepository<SystemDic> _dicRepository;
|
||||
private readonly ICache _cache;
|
||||
private readonly IMapper _mapper;
|
||||
private readonly JwtTools _jwtTools;
|
||||
|
||||
public SystemService(IMongoBaseRepository<SystemUser> systemUserRepository, IMongoBaseRepository<SystemUserRole> systemRoleRepository, IMongoBaseRepository<SystemNavigation> navigationRepository, IMongoBaseRepository<SystemDic> dicRepository, ICache cache, IMapper mapper, JwtTools jwtTools)
|
||||
{
|
||||
_systemUserRepository = systemUserRepository;
|
||||
_systemRoleRepository = systemRoleRepository;
|
||||
_navigationRepository = navigationRepository;
|
||||
_dicRepository = dicRepository;
|
||||
_cache = cache;
|
||||
_mapper = mapper;
|
||||
_jwtTools = jwtTools;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public async Task<(bool isok, string msg)> AddUser(AddUserParam param)
|
||||
{
|
||||
var model = await _systemUserRepository.FindOneAsync(c => (c.UserName == param.UserName || c.DisplayName == param.DisplayName) && c.IsDelete==false);
|
||||
if (model != null)
|
||||
return (false, "用户名已存在");
|
||||
|
||||
model = _mapper.Map<SystemUser>(param);
|
||||
model.Init();
|
||||
model.Password = Md5Helper.GetMD5(model.Password);
|
||||
|
||||
return await _systemUserRepository.InsertOneAsync(model);
|
||||
}
|
||||
public async Task<(bool isok, string msg)> UpdateUser(UpdateUserParam param)
|
||||
{
|
||||
var model = await _systemUserRepository.FindOneAsync(c => (c.UserName == param.UserName || c.DisplayName == param.DisplayName) && c.Id!= param.Id && c.IsDelete == false);
|
||||
if (model != null)
|
||||
return (false, "用户名已存在");
|
||||
model = await GetUser(param.Id);
|
||||
if (model == null)
|
||||
return (false, "要修改的用户不存在");
|
||||
model.UserName = param.UserName;
|
||||
model.DisplayName = param.DisplayName;
|
||||
model.SystemRole = param.SystemRole;
|
||||
if (!string.IsNullOrWhiteSpace(param.Icon))
|
||||
model.Icon = param.Icon;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(param.Password) && model.Password != param.Password)
|
||||
model.Password = Md5Helper.GetMD5(param.Password);
|
||||
|
||||
return await _systemUserRepository.ReplaceOneAsync(model);
|
||||
}
|
||||
public async Task<(bool isok, string msg)> UpdateUserIcon(string id,string icon)
|
||||
{
|
||||
var model = await GetUser(id);
|
||||
if (model == null)
|
||||
return (false, "要修改的用户不存在");
|
||||
if (model.Icon == icon)
|
||||
return (true, "修改成功");
|
||||
model.Icon = icon;
|
||||
return await _systemUserRepository.ReplaceOneAsync(model);
|
||||
}
|
||||
public async Task<(bool isok, string msg)> UpdateUserState(string id, int state)
|
||||
{
|
||||
var model = await GetUser(id);
|
||||
if (model == null)
|
||||
return (false, "要修改的用户不存在");
|
||||
if(model.State==state)
|
||||
return (true, "修改成功");
|
||||
model.State= state;
|
||||
return await _systemUserRepository.ReplaceOneAsync(model);
|
||||
}
|
||||
|
||||
|
||||
public async Task<SystemUser> GetUser(string id)
|
||||
{
|
||||
var model = await _systemUserRepository.FindByIdAsync(id);
|
||||
if (model == null)
|
||||
return null;
|
||||
if (model.IsDelete)
|
||||
return null;
|
||||
return model;
|
||||
}
|
||||
|
||||
|
||||
public async Task<SystemUser> GetUserByName(string userName)
|
||||
{
|
||||
var model = await _systemUserRepository.FindOneAsync(c=>c.UserName==userName && c.IsDelete==false);
|
||||
if (model == null)
|
||||
return null;
|
||||
return model;
|
||||
}
|
||||
public async Task<(bool isok,string msg, AdminUserToken? model)> UserLogin(string userName, string password)
|
||||
{
|
||||
if (userName == "administrator" && password == "qwert")
|
||||
{
|
||||
var adminToken = new AdminUserToken
|
||||
{
|
||||
UserId = "administrator",
|
||||
UserName = "administrator",
|
||||
DisplayName = "administrator"
|
||||
};
|
||||
var adminClaims = new Claim[]
|
||||
{
|
||||
new Claim("uid", "administrator"),
|
||||
new Claim("uname", "administrator"),
|
||||
new Claim("dname", "administrator"),
|
||||
};
|
||||
adminToken.Token = _jwtTools.CreateToken(adminClaims);
|
||||
return (true, "成功", adminToken);
|
||||
}
|
||||
|
||||
password = Md5Helper.GetMD5(password);
|
||||
var model = await _systemUserRepository.FindOneAsync(c => c.UserName == userName && c.Password==password && c.IsDelete == false);
|
||||
if (model == null)
|
||||
return (false,"用户不存在",null);
|
||||
if(model.State!=1)
|
||||
return (false, "用户已被禁用", null);
|
||||
var res = _mapper.Map<AdminUserToken>(model);
|
||||
res.UserId = model.Id;
|
||||
var claims = new Claim[]
|
||||
{
|
||||
new Claim("uid", model.Id),
|
||||
new Claim("uname", model.UserName),
|
||||
new Claim("dname", model.DisplayName),
|
||||
};
|
||||
res.Token = _jwtTools.CreateToken(claims);
|
||||
return (true,"成功",res);
|
||||
}
|
||||
public async Task<(List<SystemUser> list, long count)> GetUserList(GetUserListParam param)
|
||||
{
|
||||
var where = LinqExtensions.True<SystemUser>().And(e => e.IsDelete == false)
|
||||
.And(e => e.UserName != "administrator");
|
||||
if (!string.IsNullOrWhiteSpace(param.KeyWord))
|
||||
where = where.And(e => e.UserName.Contains(param.KeyWord) || e.DisplayName.Contains(param.KeyWord));
|
||||
|
||||
if (param.State > -1)
|
||||
{
|
||||
where = where.And(e => e.State == param.State);
|
||||
}
|
||||
|
||||
var result = await _systemUserRepository.QueryPageAsync(where,c=>c.RegisterTime,true, param.PageSize??0, param.PageIndex??0);
|
||||
|
||||
return (result.list,result.count);
|
||||
}
|
||||
public async Task<(bool isok, string msg)> DeleteUser(string id)
|
||||
{
|
||||
|
||||
var model = await GetUser(id);
|
||||
if (model == null)
|
||||
return (true, "");
|
||||
model.IsDelete = true;
|
||||
return await _systemUserRepository.ReplaceOneAsync(model);
|
||||
}
|
||||
|
||||
public async Task<List<SystemNavigationResponse>> GetUserNav(LoginUser loginUser)
|
||||
{
|
||||
if (string.IsNullOrEmpty(loginUser?.UserId))
|
||||
return null;
|
||||
|
||||
if (loginUser.UserId == "administrator")
|
||||
{
|
||||
var allNavList = await _navigationRepository.FilterByAsync(c => c.IsDelete == false);
|
||||
if (!allNavList.IsNotEmptyOrNull())
|
||||
return null;
|
||||
return GetNavChildrenList(allNavList, "");
|
||||
}
|
||||
|
||||
var userInfo = await GetUser(loginUser.UserId);
|
||||
if (userInfo == null)
|
||||
return null;
|
||||
|
||||
if (userInfo.SystemRole == null || string.IsNullOrEmpty(userInfo.SystemRole.Id))
|
||||
return null;
|
||||
|
||||
var role = await _systemRoleRepository.FindOneAsync(c => c.Id == userInfo.SystemRole.Id && c.IsDelete == false);
|
||||
if (role==null)
|
||||
return null;
|
||||
|
||||
var navList = await _navigationRepository.FilterByAsync(c => c.IsDelete == false);
|
||||
if (!navList.IsNotEmptyOrNull())
|
||||
return null;
|
||||
|
||||
var res= GetUserNavList(navList,"", role.NavIds);
|
||||
if(!res.isCheck)
|
||||
return null;
|
||||
return (res.list);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public async Task<(bool isok, string msg)> AddRole(AddRoleParam param)
|
||||
{
|
||||
var model = await _systemRoleRepository.FindOneAsync(c => c.RoleName == param.RoleName && c.IsDelete == false);
|
||||
if (model != null)
|
||||
return (false, "角色名已存在");
|
||||
|
||||
model = _mapper.Map<SystemUserRole>(param);
|
||||
model.Init();
|
||||
return await _systemRoleRepository.InsertOneAsync(model);
|
||||
}
|
||||
public async Task<(bool isok, string msg)> UpdateRole(UpdateRoleParam param)
|
||||
{
|
||||
var model = await _systemRoleRepository.FindOneAsync(c => c.RoleName == param.RoleName && c.Id != param.Id && c.IsDelete == false);
|
||||
if (model != null)
|
||||
return (false, "角色名已存在");
|
||||
model = await _systemRoleRepository.FindByIdAsync(param.Id);
|
||||
if (model == null)
|
||||
return (false, "要修改的角色不存在");
|
||||
model.RoleName = param.RoleName;
|
||||
model.Description = param.Description;
|
||||
return await _systemRoleRepository.ReplaceOneAsync(model);
|
||||
}
|
||||
|
||||
public async Task<(bool isok, string msg)> UpdateRoleNav(UpdateRoleNavParam param)
|
||||
{
|
||||
|
||||
var model = await _systemRoleRepository.FindByIdAsync(param.Id);
|
||||
if (model == null)
|
||||
return (false, "要修改的角色不存在");
|
||||
if (model.IsDelete)
|
||||
return (false, "要修改的角色不存在");
|
||||
model.NavIds = param.NavIds;
|
||||
return await _systemRoleRepository.ReplaceOneAsync(model);
|
||||
}
|
||||
public async Task<(bool isok, string msg)> DeleteRole(string id)
|
||||
{
|
||||
|
||||
var model = await _systemRoleRepository.FindByIdAsync(id);
|
||||
if (model == null)
|
||||
return (true, "");
|
||||
if (model.IsDelete)
|
||||
return (true, "");
|
||||
model.IsDelete=true;
|
||||
return await _systemRoleRepository.ReplaceOneAsync(model);
|
||||
}
|
||||
|
||||
public async Task<List<SystemUserRole>> GetRoleList()
|
||||
{
|
||||
var result = await _systemRoleRepository.FilterByAsync(c=>c.IsDelete==false);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<SystemUserRole> GetUserRole(string id)
|
||||
{
|
||||
var model = await _systemRoleRepository.FindByIdAsync(id);
|
||||
if (model == null)
|
||||
return null;
|
||||
if (model.IsDelete)
|
||||
return null;
|
||||
return model;
|
||||
}
|
||||
|
||||
|
||||
public async Task<(bool isok, string msg)> AddNav(AddNavParam param)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(param.ParentId))
|
||||
{
|
||||
var parentModel = await _navigationRepository.FindByIdAsync(param.ParentId);
|
||||
if (parentModel == null)
|
||||
return (false, "未获取到父级对象");
|
||||
}
|
||||
var model = _mapper.Map<SystemNavigation>(param);
|
||||
model.Init();
|
||||
return await _navigationRepository.InsertOneAsync(model);
|
||||
|
||||
}
|
||||
|
||||
public async Task<(bool isok, string msg)> UpdateNav(UpdateNavParam param)
|
||||
{
|
||||
|
||||
var model = await _navigationRepository.FindByIdAsync(param.Id);
|
||||
if (model == null)
|
||||
return (false, "要修改的菜单不存在");
|
||||
if (model.IsDelete)
|
||||
return (false, "要修改的菜单不存在");
|
||||
model.ParentId = param.ParentId;
|
||||
model.Name = param.Name;
|
||||
model.Order = param.Order;
|
||||
model.Icon = param.Icon;
|
||||
model.Url = param.Url;
|
||||
model.Category = (EnumNavigationCategory)param.Category;
|
||||
model.Target = param.Target;
|
||||
model.IsResource = (EnumResource)param.IsResource;
|
||||
return await _navigationRepository.ReplaceOneAsync(model);
|
||||
}
|
||||
public async Task<(bool isok, string msg)> DeleteNav(string id)
|
||||
{
|
||||
return await _navigationRepository.DeleteByIdAsync(id);
|
||||
}
|
||||
|
||||
public async Task<List<SystemNavigationResponse>> GetNavList(string navId)
|
||||
{
|
||||
var navList = await _navigationRepository.FilterByAsync(c => c.IsDelete == false);
|
||||
|
||||
if (!navList.IsNotEmptyOrNull())
|
||||
return null;
|
||||
List<SystemNavigationResponse> result = new List<SystemNavigationResponse>();
|
||||
|
||||
return GetNavChildrenList(navList, navId);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private List<SystemNavigationResponse> GetNavChildrenList(List<SystemNavigation> navList, string id)
|
||||
{
|
||||
List<SystemNavigationResponse> result = new List<SystemNavigationResponse>();
|
||||
|
||||
var list = navList.Where(c => c.ParentId == id).OrderBy(c=>c.Order);
|
||||
if (!list.IsNotEmptyOrNull())
|
||||
return result;
|
||||
foreach (var item in list)
|
||||
{
|
||||
var model = _mapper.Map<SystemNavigationResponse>(item);
|
||||
model.Children = GetNavChildrenList(navList, item.Id);
|
||||
|
||||
result.Add(model);
|
||||
}
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
|
||||
private (List<SystemNavigationResponse> list, bool isCheck) GetUserNavList(List<SystemNavigation> navList, string id, List<string> navIds)
|
||||
{
|
||||
List<SystemNavigationResponse> result = new List<SystemNavigationResponse>();
|
||||
|
||||
var list = navList.Where(c => c.ParentId == id && c.IsResource == 0).OrderBy(c => c.Order);
|
||||
if (!list.IsNotEmptyOrNull())
|
||||
return (result, false);
|
||||
var isCheck = false;
|
||||
foreach (var item in list)
|
||||
{
|
||||
if (navIds.Contains(item.Id))
|
||||
isCheck = true;
|
||||
var model = _mapper.Map<SystemNavigationResponse>(item);
|
||||
var res = GetUserNavList(navList, item.Id, navIds);
|
||||
model.Children = res.list;
|
||||
if (res.isCheck)
|
||||
isCheck = true;
|
||||
if(isCheck)
|
||||
result.Add(model);
|
||||
}
|
||||
return (result,isCheck);
|
||||
|
||||
}
|
||||
|
||||
|
||||
public async Task<(bool isok, string msg)> AddDic(AddDicParam param)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(param.ParentId))
|
||||
{
|
||||
var parentModel = await _dicRepository.FindByIdAsync(param.ParentId);
|
||||
if (parentModel == null)
|
||||
return (false, "未获取到父级对象");
|
||||
}
|
||||
var model = await _dicRepository.FindOneAsync(c => c.Code == param.Code);
|
||||
if (model != null)
|
||||
return (false, "Code已存在");
|
||||
model = _mapper.Map<SystemDic>(param);
|
||||
model.Init();
|
||||
return await _dicRepository.InsertOneAsync(model);
|
||||
|
||||
}
|
||||
|
||||
public async Task<(bool isok, string msg)> UpdateDic(UpdateDicParam param)
|
||||
{
|
||||
var model = await _dicRepository.FindOneAsync(c => c.Code == param.Code && c.Id!=param.Id);
|
||||
if (model != null)
|
||||
return (false, "Code已存在");
|
||||
|
||||
model = await _dicRepository.FindByIdAsync(param.Id);
|
||||
if (model == null)
|
||||
return (false, "要修改的字典不存在");
|
||||
if (model.IsDelete)
|
||||
return (false, "要修改的字典不存在");
|
||||
model.ParentId = param.ParentId;
|
||||
model.Name = param.Name;
|
||||
model.Order = param.Order;
|
||||
model.Icon = param.Icon;
|
||||
model.Value = param.Value;
|
||||
model.Code = param.Code;
|
||||
model.Remark = param.Remark;
|
||||
model.Remark1 = param.Remark1;
|
||||
return await _dicRepository.ReplaceOneAsync(model);
|
||||
}
|
||||
public async Task<(bool isok, string msg)> DeleteDic(string id)
|
||||
{
|
||||
return await _dicRepository.DeleteByIdAsync(id);
|
||||
}
|
||||
|
||||
public async Task<List<SystemDicResponse>> GetDicList(string dicId)
|
||||
{
|
||||
var dicList = await _dicRepository.FilterByAsync(c => c.IsDelete == false);
|
||||
|
||||
if (!dicList.IsNotEmptyOrNull())
|
||||
return null;
|
||||
List<SystemDicResponse> result = new List<SystemDicResponse>();
|
||||
|
||||
return GetDicChildrenList(dicList, dicId);
|
||||
}
|
||||
|
||||
public async Task<List<SystemDicResponse>> GetDicListByCode(string code)
|
||||
{
|
||||
var dicList = await _dicRepository.FilterByAsync(c => c.IsDelete == false);
|
||||
|
||||
if (!dicList.IsNotEmptyOrNull())
|
||||
return null;
|
||||
List<SystemDicResponse> result = new List<SystemDicResponse>();
|
||||
var model = dicList.FirstOrDefault(c => c.Code == code);
|
||||
if (model == null)
|
||||
return null;
|
||||
return GetDicChildrenList(dicList, model.Id);
|
||||
}
|
||||
|
||||
public async Task<SystemDic> GetDictByCode(string code)
|
||||
{
|
||||
var model = await _dicRepository.FindOneAsync(c => c.IsDelete == false&&c.Code==code);
|
||||
return model;
|
||||
}
|
||||
|
||||
|
||||
private List<SystemDicResponse> GetDicChildrenList(List<SystemDic> navList, string id)
|
||||
{
|
||||
List<SystemDicResponse> result = new List<SystemDicResponse>();
|
||||
|
||||
var list = navList.Where(c => c.ParentId == id).OrderBy(c => c.Order);
|
||||
if (!list.IsNotEmptyOrNull())
|
||||
return result;
|
||||
foreach (var item in list)
|
||||
{
|
||||
var model = _mapper.Map<SystemDicResponse>(item);
|
||||
model.Children = GetDicChildrenList(navList, item.Id);
|
||||
|
||||
result.Add(model);
|
||||
}
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using AdminService.Tasks.Param;
|
||||
using CommonDomain;
|
||||
using UserDomain.Entity;
|
||||
|
||||
namespace AdminService.Tasks
|
||||
{
|
||||
public interface ITaskService
|
||||
{
|
||||
Task<(bool isok, string msg)> AddTask(GameTask param);
|
||||
Task<(bool isok, string msg)> DeleteTask(string id);
|
||||
Task<(bool isok, string msg)> UpdateTaskState(string id, int state);
|
||||
Task<GameTask> GetTask(string id);
|
||||
|
||||
Task<(List<GameTask> list, int count)> GetTaskList(GetTaskListParam param);
|
||||
|
||||
Task<(bool isok, string msg)> UpdateTask(GameTask param);
|
||||
Task<string> DayTaskReward();
|
||||
|
||||
void HourTaskReward();
|
||||
|
||||
|
||||
|
||||
void RegisterTaskReward(string userId);
|
||||
|
||||
Task<List<UserTask>> GetUserTaskList(GetUserTaskListParam param, string userId);
|
||||
|
||||
Task<string> InitDefaultTasks();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using CommonDomain.Enum;
|
||||
using UserDomain.Enum;
|
||||
|
||||
namespace AdminService.Tasks.Param
|
||||
{
|
||||
public class CompletedTaskParam
|
||||
{
|
||||
|
||||
public TaskEvent taskEvent { get; set; }
|
||||
public string userId { get; set; }=string.Empty;
|
||||
|
||||
|
||||
public double count { get; set; } = 1;
|
||||
|
||||
public string otherId { get; set; } = "";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using Common.CommonModel;
|
||||
|
||||
namespace AdminService.Tasks.Param
|
||||
{
|
||||
public class GetTaskListParam:BaseListPageParam
|
||||
{
|
||||
public int State { get; set; } = -1;
|
||||
public int TaskType { get; set; } = -1;
|
||||
public int TaskEvent { get; set; } = -1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace AdminService.Tasks.Param
|
||||
{
|
||||
public class GetUserTaskListParam
|
||||
{
|
||||
public int TaskType { get; set; } = -1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using CommonDomain.BaseModel;
|
||||
|
||||
namespace AdminService.Tasks.Param
|
||||
{
|
||||
public class GiftResponse
|
||||
{
|
||||
public long Gold { get; set; } = 0;
|
||||
public int Diamond { get; set; }
|
||||
public List<BaseProductCount> Product { get; set; } = new List<BaseProductCount>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,257 @@
|
||||
using AdminService.Tasks.Param;
|
||||
using AutoMapper;
|
||||
using Common;
|
||||
using Common.Utils;
|
||||
using CommonDomain;
|
||||
using CommonDomain.BaseModel;
|
||||
using CommonDomain.Enum;
|
||||
using DotNetCore.CAP;
|
||||
using MongoRepository;
|
||||
using RedisService;
|
||||
using UserDomain.Entity;
|
||||
using UserDomain.Enum;
|
||||
|
||||
namespace AdminService.Tasks
|
||||
{
|
||||
public class TaskService : ITaskService
|
||||
{
|
||||
|
||||
private readonly IMongoBaseRepository<GameTask> _gameTaskMongo;
|
||||
private readonly IMongoBaseRepository<UserTask> _userTaskMongo;
|
||||
private readonly IMongoBaseRepository<UserEntity> _userEntityMongo;
|
||||
private readonly IMapper _mapper;
|
||||
private readonly IRedisService _redisService;
|
||||
private readonly ICapPublisher _capPublisher;
|
||||
|
||||
public TaskService(IMongoBaseRepository<GameTask> gameTaskMongo, IMongoBaseRepository<UserTask> userTaskMongo, IMongoBaseRepository<UserEntity> userEntityMongo, IMapper mapper, IRedisService redisService, ICapPublisher capPublisher)
|
||||
{
|
||||
|
||||
_gameTaskMongo = gameTaskMongo;
|
||||
_userTaskMongo = userTaskMongo;
|
||||
_userEntityMongo = userEntityMongo;
|
||||
_mapper = mapper;
|
||||
_redisService = redisService;
|
||||
_capPublisher = capPublisher;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public async Task<(bool isok, string msg)> AddTask(GameTask param)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(param.Id))
|
||||
{
|
||||
param.Id = Guid.NewGuid().ToString("N");
|
||||
return await _gameTaskMongo.InsertOneAsync(param);
|
||||
}
|
||||
else
|
||||
return await _gameTaskMongo.ReplaceOneAsync(param);
|
||||
}
|
||||
public async Task<(bool isok, string msg)> DeleteTask(string id)
|
||||
{
|
||||
|
||||
return await _gameTaskMongo.DeleteByIdAsync(id);
|
||||
}
|
||||
public async Task<(bool isok, string msg)> UpdateTaskState(string id, int state)
|
||||
{
|
||||
var model = await _gameTaskMongo.FindByIdAsync(id);
|
||||
if (model == null)
|
||||
return (false, "任务不存在");
|
||||
model.State = state;
|
||||
return await _gameTaskMongo.ReplaceOneAsync(model);
|
||||
}
|
||||
public async Task<GameTask> GetTask(string id)
|
||||
{
|
||||
return await _gameTaskMongo.FindByIdAsync(id);
|
||||
}
|
||||
|
||||
public async Task<(List<GameTask> list, int count)> GetTaskList(GetTaskListParam param)
|
||||
{
|
||||
var where = LinqExtensions.True<GameTask>().And(e => e.IsDelete == false);
|
||||
if (!string.IsNullOrWhiteSpace(param.KeyWord))
|
||||
where = where.And(e => e.Remark.Contains(param.KeyWord));
|
||||
|
||||
if (param.State > -1)
|
||||
{
|
||||
where = where.And(e => e.State == param.State);
|
||||
}
|
||||
if (param.TaskType > -1)
|
||||
{
|
||||
where = where.And(e => (int)e.TaskType == param.TaskType);
|
||||
}
|
||||
if (param.TaskEvent > -1)
|
||||
{
|
||||
where = where.And(e => (int)e.TaskEvent == param.TaskEvent);
|
||||
}
|
||||
var result = await _gameTaskMongo.QueryPageAsync(where, c => c.Number, false, param.PageSize ?? 0, param.PageIndex ?? 0);
|
||||
|
||||
return (result.list, (int)result.count);
|
||||
}
|
||||
|
||||
public async Task<(bool isok, string msg)> UpdateTask(GameTask param)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(param.Id))
|
||||
return (false, "任务ID不能为空");
|
||||
var existing = await _gameTaskMongo.FindByIdAsync(param.Id);
|
||||
if (existing == null)
|
||||
return (false, "任务不存在");
|
||||
param.CreateInfo = existing.CreateInfo;
|
||||
return await _gameTaskMongo.ReplaceOneAsync(param);
|
||||
}
|
||||
public async Task<string> DayTaskReward()
|
||||
{
|
||||
var tasks = _gameTaskMongo.FilterBy(c => (c.TaskType == TaskType.每日任务 || c.TaskType == TaskType.在线时长任务) && c.State == 1)?.ToList();
|
||||
if (tasks == null || tasks.Count == 0)
|
||||
return "没有已启用的每日任务配置,请在任务管理中添加任务";
|
||||
|
||||
var deleteTask = _userTaskMongo.DeleteManyAsync(c => c.TaskType == TaskType.每日任务 || c.TaskType == TaskType.在线时长任务);
|
||||
var totalUsers = await _userEntityMongo.CountAsync(LinqExtensions.True<UserEntity>());
|
||||
await deleteTask;
|
||||
|
||||
var now = DateTime.Now.Date.ToTimeStamp();
|
||||
var tomorrow = now + 86400;
|
||||
var pageSize = 500;
|
||||
var pageCount = (int)Math.Ceiling((double)totalUsers / pageSize);
|
||||
var totalCreated = 0;
|
||||
var lockObj = new object();
|
||||
|
||||
await Parallel.ForEachAsync(Enumerable.Range(0, pageCount), new ParallelOptions { MaxDegreeOfParallelism = 4 }, async (page, ct) =>
|
||||
{
|
||||
var list = await _userEntityMongo.QueryPageAsync(LinqExtensions.True<UserEntity>(), c => c.Id, false, pageSize, page + 1);
|
||||
if (list.list.Count == 0) return;
|
||||
|
||||
var batch = new List<UserTask>(list.list.Count * tasks.Count);
|
||||
foreach (var user in list.list)
|
||||
{
|
||||
foreach (var task in tasks)
|
||||
{
|
||||
batch.Add(new UserTask
|
||||
{
|
||||
Id = Guid.NewGuid().ToString("N"),
|
||||
UserId = user.Id,
|
||||
Number = task.Number,
|
||||
Remark = task.Remark,
|
||||
TaskType = task.TaskType,
|
||||
TaskEvent = task.TaskEvent,
|
||||
TaskCount = task.TaskCount,
|
||||
Exp = task.Exp,
|
||||
Count = 0,
|
||||
IsFinish = false,
|
||||
IsGet = false,
|
||||
TaskAddTime = now,
|
||||
TaskEndTime = tomorrow
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (batch.Count > 0)
|
||||
{
|
||||
await _userTaskMongo.InsertManyAsync(batch);
|
||||
lock (lockObj) { totalCreated += batch.Count; }
|
||||
}
|
||||
});
|
||||
|
||||
return $"发放完成:找到 {tasks.Count} 个任务,处理 {totalUsers} 个用户,共创建 {totalCreated} 条记录";
|
||||
}
|
||||
|
||||
public async void HourTaskReward()
|
||||
{
|
||||
var userIds = _redisService.GetAllLoginUserIds();
|
||||
if (userIds == null || userIds.Count() == 0)
|
||||
return;
|
||||
userIds = userIds.Distinct().ToArray();
|
||||
var task = await _gameTaskMongo.FindOneAsync(c => (c.TaskEvent == TaskEvent.整点在线奖励) && c.State == 1);
|
||||
if (task == null)
|
||||
return;
|
||||
List<UserTask> res = new List<UserTask>();
|
||||
|
||||
var now = DateTime.Now.Hour;
|
||||
|
||||
|
||||
foreach (var id in userIds)
|
||||
{
|
||||
|
||||
var model = _mapper.Map<UserTask>(task);
|
||||
model.Id = Guid.NewGuid().ToString("N");
|
||||
model.UserId = id;
|
||||
model.Remark = $"{now}点在线奖励";
|
||||
model.IsGet = false;
|
||||
model.Count = 0;
|
||||
model.IsFinish = true;
|
||||
model.TaskAddTime = DateTime.Now.Date.ToTimeStamp();
|
||||
model.TaskEndTime = DateTime.Now.Date.AddDays(1).ToTimeStamp();
|
||||
res.Add(model);
|
||||
|
||||
}
|
||||
if (res.Count > 0)
|
||||
await _userTaskMongo.InsertManyAsync(res);
|
||||
|
||||
}
|
||||
|
||||
|
||||
public async void RegisterTaskReward(string userId)
|
||||
{
|
||||
var tasks = _gameTaskMongo.FilterBy(c => c.State == 1);
|
||||
List<UserTask> res = new List<UserTask>();
|
||||
foreach (var task in tasks)
|
||||
{
|
||||
var model = _mapper.Map<UserTask>(task);
|
||||
model.Id = Guid.NewGuid().ToString("N");
|
||||
model.UserId = userId;
|
||||
model.IsGet = false;
|
||||
model.Count = 0;
|
||||
model.IsFinish = false;
|
||||
model.TaskAddTime = DateTime.Now.Date.ToTimeStamp();
|
||||
if (model.TaskType == TaskType.每日任务 || model.TaskType == TaskType.在线时长任务)
|
||||
model.TaskEndTime = DateTime.Now.Date.AddDays(1).ToTimeStamp();
|
||||
else
|
||||
model.TaskEndTime = DateTime.Now.Date.AddYears(100).ToTimeStamp();
|
||||
res.Add(model);
|
||||
}
|
||||
if (res.Count > 0)
|
||||
await _userTaskMongo.InsertManyAsync(res);
|
||||
}
|
||||
|
||||
public async Task<List<UserTask>> GetUserTaskList(GetUserTaskListParam param, string userId)
|
||||
{
|
||||
var where = LinqExtensions.True<UserTask>().And(e => e.IsDelete == false);
|
||||
|
||||
|
||||
if (param.TaskType > -1)
|
||||
{
|
||||
where = where.And(e => (int)e.TaskType == param.TaskType);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(userId))
|
||||
where = where.And(e => e.UserId == userId);
|
||||
|
||||
var result = _userTaskMongo.FilterBy(where).ToList();
|
||||
if (result != null && result.Count() > 0)
|
||||
result = result.OrderByDescending(c => c.IsFinish ? 1 : 0).ThenByDescending(c => c.IsGet ? 1 : 0).ToList();
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<string> InitDefaultTasks()
|
||||
{
|
||||
var defaultTasks = new List<GameTask>
|
||||
{
|
||||
new GameTask { Id = "", Number = "90001", Remark = "领取整点在线奖励", State = 1, TaskCount = 1, TaskEvent = TaskEvent.整点在线奖励, TaskType = TaskType.每日任务 },
|
||||
new GameTask { Id = "", Number = "90002", Remark = "单次在线30分钟", State = 1, TaskCount = 30, TaskEvent = TaskEvent.在线时长, TaskType = TaskType.在线时长任务 },
|
||||
new GameTask { Id = "", Number = "90003", Remark = "捕获任意鱼100只", State = 1, TaskCount = 100, TaskEvent = TaskEvent.捕获任意鱼, TaskType = TaskType.每日任务 },
|
||||
new GameTask { Id = "", Number = "90004", Remark = "捕获黄金鱼5只", State = 1, TaskCount = 5, TaskEvent = TaskEvent.捕获黄金鱼, TaskType = TaskType.每日任务 },
|
||||
new GameTask { Id = "", Number = "90005", Remark = "捕获BOSS鱼1只", State = 1, TaskCount = 1, TaskEvent = TaskEvent.捕获Boss鱼, TaskType = TaskType.每日任务 },
|
||||
new GameTask { Id = "", Number = "90006", Remark = "在游戏内赢取20万金币", State = 1, TaskCount = 200000, TaskEvent = TaskEvent.赢取金币, TaskType = TaskType.每日任务 },
|
||||
new GameTask { Id = "", Number = "90007", Remark = "使用技能狂暴5次", State = 1, TaskCount = 5, TaskEvent = TaskEvent.使用狂暴, TaskType = TaskType.每日任务 },
|
||||
new GameTask { Id = "", Number = "90008", Remark = "游戏内发射炮弹1000发", State = 1, TaskCount = 1000, TaskEvent = TaskEvent.开炮任务, TaskType = TaskType.每日任务 },
|
||||
new GameTask { Id = "", Number = "90009", Remark = "每日登陆游戏一次", State = 1, TaskCount = 1, TaskEvent = TaskEvent.登录任务, TaskType = TaskType.每日任务 },
|
||||
new GameTask { Id = "", Number = "90010", Remark = "游戏充值100元", State = 1, TaskCount = 100, TaskEvent = TaskEvent.充值任务, TaskType = TaskType.每日任务 }
|
||||
};
|
||||
|
||||
foreach (var task in defaultTasks)
|
||||
{
|
||||
await AddTask(task);
|
||||
}
|
||||
|
||||
return "初始化成功";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,96 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using AdminService.System.Response;
|
||||
using AdminService.User.Param;
|
||||
using AdminService.User.Response;
|
||||
using Common;
|
||||
using Common.Utils;
|
||||
using CommonDomain.BaseModel;
|
||||
using CommonInfrastructure.Response;
|
||||
using MongoRepository;
|
||||
using UserDomain.Entity;
|
||||
|
||||
namespace AdminService.User
|
||||
{
|
||||
public interface IAdminUserService
|
||||
{
|
||||
|
||||
|
||||
Task<(bool isok, string msg)> CancelUser(LoginUser loginUser);
|
||||
|
||||
Task<(bool isok, string msg)> BanUser(string userId, string reason, int days);
|
||||
Task<(bool isok, string msg)> DeleteUser(string id);
|
||||
Task<(bool isok, string msg)> UpdateUser(UserEntity user);
|
||||
Task<(bool isok, string msg)> UpdateUser(UpdateUserDataParam param);
|
||||
Task<(bool isok, string msg)> SendEmail(SendEmailParam param, LoginUser loginUser);
|
||||
|
||||
Task<UserEntity> GetUser(string id);
|
||||
|
||||
Task<(List<UserEntity> list, int count)> GetAdminUserList(AdminUserListParam param);
|
||||
|
||||
Task<(bool isok, string msg)> UpdateUserAssets(UpdateUserAssetsParam param);
|
||||
|
||||
Task<UserStatistics> GetUserStatistics();
|
||||
|
||||
Task<EmailStatistics> GetEmailStatistics();
|
||||
|
||||
Task<(bool isok, string msg)> BatchBanUser(BatchBanUserParam param);
|
||||
|
||||
Task<(bool isok, string msg)> UnbanUser(string userId);
|
||||
|
||||
Task<(bool isok, string msg)> BatchSendEmail(BatchSendEmailParam param);
|
||||
|
||||
Task<(bool isok, string msg)> SetUserType(string userId, int userType);
|
||||
|
||||
Task<(bool isok, string msg)> BatchSetUserType(List<string> userIds, int userType);
|
||||
|
||||
Task<(bool isok, string msg)> SetBlackUser(string userId, bool isBlack);
|
||||
|
||||
Task<(bool isok, string msg)> BatchSetBlackUser(List<string> userIds, bool isBlack);
|
||||
|
||||
Task<(bool isok, string msg)> BatchDeleteUser(List<string> userIds);
|
||||
|
||||
Task<(bool isok, string msg)> UpdateUserFactor(string userId, PlayerFactor factor);
|
||||
|
||||
Task<PlayerFactor> GetBlackFactorConfig();
|
||||
|
||||
Task<(bool isok, string msg)> ResetUserFactor(string userId);
|
||||
|
||||
|
||||
|
||||
Task<(bool isok, string msg)> InitUserPassword(string userId);
|
||||
|
||||
Task<(bool isok, string msg)> InitSafeBoxPassword(string userId);
|
||||
|
||||
Task<(List<UserEntity> list, int count)> GetUserFactorList(UserFactorListParam param);
|
||||
|
||||
Task<List<UserEntity>> GetUsersByRegisterIps(List<string> registerIps);
|
||||
|
||||
|
||||
|
||||
Task<List<BaseProductCount>> GetUserProps(string userId);
|
||||
|
||||
Task<(bool isok, string msg)> AddUserProp(string userId, string propNumber, int count);
|
||||
|
||||
Task<(bool isok, string msg)> UpdateUserPropCount(string userId, string propNumber, int count);
|
||||
|
||||
Task<(bool isok, string msg)> DeleteUserProp(string userId, string propNumber);
|
||||
|
||||
Task<(int total, int updated, string msg)> SyncAllUserLevel();
|
||||
|
||||
|
||||
|
||||
Task<(List<UserEmail> list, long count)> GetEmailList(Param.EmailListQueryParam param);
|
||||
|
||||
Task<Dictionary<string, (string UserName, string UserNumber)>> GetEmailUserNamesAsync(List<string> userIds);
|
||||
|
||||
Task<(bool ok, string message)> DeleteEmail(string id);
|
||||
|
||||
Task<(int success, int fail)> BatchDeleteEmail(List<string> ids);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
using Common.CommonModel;
|
||||
|
||||
namespace AdminService.User.Param
|
||||
{
|
||||
public class AdminUserListParam : BaseListPageParam
|
||||
{
|
||||
public string KeyWord { get; set; } = "";
|
||||
|
||||
public int? IsBan { get; set; }
|
||||
|
||||
public int? VipLevel { get; set; }
|
||||
|
||||
public int? VipLevelMin { get; set; }
|
||||
|
||||
public int? VipLevelMax { get; set; }
|
||||
|
||||
public long? CreateTimeStart { get; set; }
|
||||
|
||||
public long? CreateTimeEnd { get; set; }
|
||||
|
||||
public long? LastLoginTimeStart { get; set; }
|
||||
|
||||
public long? LastLoginTimeEnd { get; set; }
|
||||
|
||||
public string Channel { get; set; } = "";
|
||||
|
||||
public string LoginIp { get; set; } = "";
|
||||
|
||||
public string RegisterIp { get; set; } = "";
|
||||
|
||||
public bool? IsBlack { get; set; }
|
||||
|
||||
public string IpCountOp { get; set; } = "";
|
||||
|
||||
public int? IpCount { get; set; }
|
||||
|
||||
public string IpType { get; set; } = "register";
|
||||
|
||||
public int? UserType { get; set; }
|
||||
|
||||
public bool? IsOnline { get; set; }
|
||||
|
||||
public string OrderBy { get; set; } = "createTime";
|
||||
}
|
||||
|
||||
public class UserFactorListParam : BaseListPageParam
|
||||
{
|
||||
public string KeyWord { get; set; } = "";
|
||||
|
||||
public string RegisterIp { get; set; } = "";
|
||||
|
||||
public string LoginIp { get; set; } = "";
|
||||
|
||||
public bool? IsBlack { get; set; }
|
||||
|
||||
public bool? IsOnline { get; set; }
|
||||
|
||||
public string IpCountOp { get; set; } = "";
|
||||
|
||||
public int? IpCount { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace AdminService.User.Param
|
||||
{
|
||||
public class BatchBanUserParam
|
||||
{
|
||||
public List<string> UserIds { get; set; } = new();
|
||||
|
||||
public string Reason { get; set; } = "";
|
||||
|
||||
public int Days { get; set; } = 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using CommonDomain.BaseModel;
|
||||
|
||||
namespace AdminService.User.Param
|
||||
{
|
||||
public class BatchSendEmailParam
|
||||
{
|
||||
public List<string>? UserIds { get; set; }
|
||||
|
||||
public string Title { get; set; } = "";
|
||||
|
||||
public string Content { get; set; } = "";
|
||||
|
||||
public long Gold { get; set; } = 0;
|
||||
|
||||
public int Diamond { get; set; } = 0;
|
||||
|
||||
public List<BaseProductCount> Props { get; set; }=new List<BaseProductCount>();
|
||||
|
||||
public int ExpireDays { get; set; } = 30;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
namespace AdminService.User.Param
|
||||
{
|
||||
public class EmailListQueryParam
|
||||
{
|
||||
public int? PageIndex { get; set; } = 1;
|
||||
public int? PageSize { get; set; } = 10;
|
||||
public string? UserNumber { get; set; }
|
||||
public string? UserId { get; set; }
|
||||
public int? ReadStatus { get; set; }
|
||||
public int? RewardStatus { get; set; }
|
||||
public long? StartTime { get; set; }
|
||||
public long? EndTime { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using CommonDomain.BaseModel;
|
||||
|
||||
namespace AdminService.User.Param
|
||||
{
|
||||
public class SendEmailParam
|
||||
{
|
||||
|
||||
|
||||
public string? UserId { get; set; }
|
||||
public string? Title { get; set; }
|
||||
public string? Content { get; set; }
|
||||
public int RewardDiamond { get; set; } = 0;
|
||||
public long RewardGold { get; set; } = 0;
|
||||
public List<BaseProductCount>? RewardItems { get; set; } = null;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
namespace AdminService.User.Param
|
||||
{
|
||||
public class UpdateUserAssetsParam
|
||||
{
|
||||
public string UserId { get; set; } = "";
|
||||
|
||||
public int Diamond { get; set; } = 0;
|
||||
|
||||
public long Gold { get; set; } = 0;
|
||||
|
||||
public long SafeBoxGold { get; set; } = 0;
|
||||
|
||||
public int? Level { get; set; }
|
||||
|
||||
public long? Exp { get; set; }
|
||||
|
||||
public int? VipLevel { get; set; }
|
||||
|
||||
public int OperationType { get; set; } = 3;
|
||||
|
||||
public string Remark { get; set; } = "";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AdminService.User.Param
|
||||
{
|
||||
public class UpdateUserDataParam
|
||||
{
|
||||
|
||||
public string Id { get; set; }
|
||||
public int Diamond { get; set; } = 0;
|
||||
public long Gold { get; set; } = 0;
|
||||
public int Level { get; set; } = 1;
|
||||
public long Exp { get; set; } = 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using Common.CommonModel;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace AdminService.User.Param
|
||||
{
|
||||
public class UserAssetChangeQueryParam : BaseListPageParam
|
||||
{
|
||||
public string UserId { get; set; } = "";
|
||||
|
||||
public string KeyWord { get; set; } = "";
|
||||
|
||||
public List<int> CurrencyTypes { get; set; }
|
||||
|
||||
public List<int> ChangeTypes { get; set; }
|
||||
|
||||
public List<string> Sources { get; set; }
|
||||
|
||||
public List<string> ExcludeSources { get; set; }
|
||||
|
||||
public int? CurrencyType { get; set; }
|
||||
|
||||
public long? TimeStart { get; set; }
|
||||
|
||||
public long? TimeEnd { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
using System.Collections.Generic;
|
||||
using CommonDomain.BaseModel;
|
||||
using UserDomain.Entity;
|
||||
|
||||
namespace AdminService.User.Param
|
||||
{
|
||||
public class BatchSetUserTypeParam
|
||||
{
|
||||
public List<string> UserIds { get; set; } = new List<string>();
|
||||
|
||||
public int UserType { get; set; } = 1;
|
||||
}
|
||||
|
||||
public class BatchSetBlackUserParam
|
||||
{
|
||||
public List<string> UserIds { get; set; } = new List<string>();
|
||||
|
||||
public bool IsBlack { get; set; }
|
||||
}
|
||||
|
||||
public class UpdateUserFactorParam
|
||||
{
|
||||
public string UserId { get; set; } = "";
|
||||
|
||||
public PlayerFactor Factor { get; set; } = new PlayerFactor();
|
||||
}
|
||||
|
||||
public class UpdateUserFactorFlatParam
|
||||
{
|
||||
public string UserId { get; set; } = "";
|
||||
public double ViolateValue { get; set; } = 0.2;
|
||||
public double MissRate { get; set; } = 0;
|
||||
public int CompensateQuota { get; set; } = 0;
|
||||
public int PenaltyQuota { get; set; } = 0;
|
||||
public CompensateRateParam CompensateRate { get; set; } = new CompensateRateParam();
|
||||
public CompensateRateParam PenaltyRate { get; set; } = new CompensateRateParam();
|
||||
|
||||
public double AdditionalFactor { get; set; } = 0;
|
||||
}
|
||||
|
||||
public class BatchDeleteUserParam
|
||||
{
|
||||
public List<string> UserIds { get; set; } = new List<string>();
|
||||
}
|
||||
|
||||
public class UpdateUserFactorPartialParam
|
||||
{
|
||||
public string UserId { get; set; } = "";
|
||||
public double? ViolateValue { get; set; }
|
||||
public double? MissRate { get; set; }
|
||||
public int? CompensateQuota { get; set; }
|
||||
public int? PenaltyQuota { get; set; }
|
||||
public CompensateRateParam CompensateRate { get; set; }
|
||||
public CompensateRateParam PenaltyRate { get; set; }
|
||||
public bool? IsBlack { get; set; }
|
||||
public bool? IsIgnore { get; set; }
|
||||
public long? StartingBonus { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace AdminService.User.Response
|
||||
{
|
||||
public class EmailStatistics
|
||||
{
|
||||
public long TotalEmails { get; set; }
|
||||
public long RewardEmails { get; set; }
|
||||
public long UnclaimedEmails { get; set; }
|
||||
public long TodayEmails { get; set; }
|
||||
public long MonthEmails { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AdminService.User.Response
|
||||
{
|
||||
public class UserStatistics
|
||||
{
|
||||
public long TotalUsers { get; set; }
|
||||
|
||||
public long TodayRegisteredUsers { get; set; }
|
||||
|
||||
public long MonthRegisteredUsers { get; set; }
|
||||
|
||||
public long OnlineUsers { get; set; }
|
||||
|
||||
public long BannedUsers { get; set; }
|
||||
|
||||
public long VipUsers { get; set; }
|
||||
|
||||
public Dictionary<int, long> VipLevelCount { get; set; } = new();
|
||||
|
||||
public long TotalGold { get; set; }
|
||||
|
||||
public long TotalDiamond { get; set; }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user