初始提交

This commit is contained in:
wanyongkang
2020-10-07 20:25:03 +08:00
commit d318014316
3809 changed files with 263103 additions and 0 deletions

View File

@@ -0,0 +1,54 @@
using Hncore.Infrastructure.WebApi;
using Hncore.Pass.Vpn.Request.Product;
using Hncore.Pass.Vpn.Response.Product;
using Hncore.Pass.Vpn.Service;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using System;
using System.IO;
using System.Threading.Tasks;
namespace Hncore.Pass.Vpn.Controllers
{
[ApiVersion("1.0")]
[Route("api/course/v{version:apiVersion}/agent/[action]")]
public class AgentController : HncoreControllerBase
{
private AgentService m_AgentService;
IConfiguration m_Configuration;
public AgentController(AgentService _AgentService,IConfiguration configuration)
{
m_AgentService = _AgentService;
m_Configuration = configuration;
}
[HttpPost]
public async Task<ApiResult> Login([FromBody] AgentLoginRequest request)
{
return await m_AgentService.Login(request);
}
[HttpGet]
public async Task<ApiResult> GetCode([FromQuery] int productId)
{
var ret = await m_AgentService.GetCode(productId);
if (ret.Item1 != null)
{
var file = $"codes/{Guid.NewGuid().ToString("N")}.jpg";
var wwwrootFile = $"wwwroot/{file}";
using (FileStream fs = new FileStream(wwwrootFile, FileMode.Create))
{
await fs.WriteAsync(ret.Item1, 0, ret.Item1.Length);
}
return Success(new CodeResponse()
{
Key = ret.Item2,
CodeImage = $"{m_Configuration["Service_BaseUrl"]}{file}"
});
}
return Success(new CodeResponse()
{
Key = "",
CodeImage = ""
});
}
}
}

View File

@@ -0,0 +1,108 @@
using Hncore.Infrastructure.EntitiesExtension;
using Hncore.Infrastructure.Extension;
using Hncore.Infrastructure.WebApi;
using Hncore.Pass.Vpn.Domain;
using Hncore.Pass.Vpn.Service;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Linq.Expressions;
using System.Threading.Tasks;
namespace Hncore.Pass.Vpn.Controllers
{
[ApiVersion("1.0")]
[Route("api/course/v{version:apiVersion}/article/[action]")]
public class ArticleController : HncoreControllerBase
{
private ArticleService m_ArticleService;
public ArticleController(ArticleService _ArticleService)
{
m_ArticleService = _ArticleService;
}
/// <summary>
/// 添加
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[HttpPost]
public async Task<ApiResult> Post([FromBody]ArticleEntity request)
{
request.TenantId = this.Request.GetManageUserInfo().TenantId;
await m_ArticleService.Add(request);
return Success();
}
/// <summary>
/// 修改
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[HttpPost]
public async Task<ApiResult> Put([FromBody]ArticleEntity request)
{
await m_ArticleService.Update(request);
return Success();
}
/// <summary>
/// 删除
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpPost]
public async Task<ApiResult> Delete([FromQuery]int id)
{
var flag = await m_ArticleService.DeleteById(id);
if (flag)
return Success();
else
return Error("删除失败");
}
/// <summary>
/// 详情
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[HttpGet]
public async Task<ApiResult> Get([FromQuery]int id)
{
var data = await m_ArticleService.GetById(id);
return Success(data);
}
/// <summary>
/// 分页查询
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[HttpGet]
public async Task<ApiResult> Page([FromQuery]PageRequestBase request)
{
Expression<Func<ArticleEntity, bool>> expr = m => 1 == 1;
if (request.KeyWord.Has())
{
expr = expr.And(m => m.Title.Contains(request.KeyWord)
|| m.SubTitle.Contains(request.KeyWord)
|| m.Keyword.Contains(request.KeyWord));
}
var ret = await m_ArticleService.Page(request.PageIndex, request.PageSize, expr,true);
var data = ret.ToApiResult();
return data;
}
[HttpPost]
public async Task<ApiResult> Audit([FromQuery] int id)
{
var entity = await m_ArticleService.GetById(id);
entity.Publish = entity.Publish == 1 ? 0 : 1;
await m_ArticleService.Update(entity);
return Success(entity.Publish);
}
}
}

View File

@@ -0,0 +1,397 @@
using Hncore.Infrastructure.Common;
using Hncore.Infrastructure.EntitiesExtension;
using Hncore.Infrastructure.Extension;
using Hncore.Infrastructure.WebApi;
using Hncore.Pass.Vpn.Domain;
using Hncore.Pass.Vpn.Model;
using Hncore.Pass.Vpn.Request.Product;
using Hncore.Pass.Vpn.Service;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
namespace Hncore.Pass.Vpn.Controllers
{
[ApiVersion("1.0")]
[Route("api/course/v{version:apiVersion}/productaccount/[action]")]
public class ProductAccountController : HncoreControllerBase
{
private ProductAccountService m_AccountService;
private UserService m_UserService;
private AgentService m_agentService;
private ProductPackageService m_PackageService;
private ProductService m_ProductService;
public ProductAccountController(ProductAccountService _AccountServic
, UserService _UserService
, AgentService _agentService
, ProductPackageService _PackageService
, ProductService _ProductService)
{
m_AccountService = _AccountServic;
m_UserService = _UserService;
m_agentService = _agentService;
m_PackageService = _PackageService;
m_ProductService = _ProductService;
}
/// <summary>
/// 添加
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[HttpPost]
public async Task<ApiResult> Post([FromBody]ProductAccountEntity request)
{
request.TenantId = this.Request.GetManageUserInfo().TenantId;
await m_AccountService.Add(request);
return Success();
}
/// <summary>
/// 修改
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[HttpPost]
public async Task<ApiResult> Put([FromBody]ProductAccountEntity request)
{
await m_AccountService.Update(request);
return Success();
}
/// <summary>
/// 删除
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpPost]
public async Task<ApiResult> Delete([FromQuery]int id)
{
var flag = await m_AccountService.DeleteById(id);
if (flag)
return Success();
else
return Error("删除失败");
}
/// <summary>
/// 删除
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpPost]
public async Task<ApiResult> Deletes([FromBody] List<int> ids)
{
var data= m_AccountService.Query(m => ids.Contains(m.Id));
var flag = await m_AccountService.Deletes(data);
if (flag)
return Success();
else
return Error("删除失败");
}
/// <summary>
/// 详情
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[HttpGet]
public async Task<ApiResult> Get([FromQuery]int id)
{
var data = await m_AccountService.GetById(id);
return Success(data);
}
/// <summary>
/// 分页查询
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[HttpGet]
public async Task<ApiResult> Page([FromQuery]AccountPageRequest request)
{
Expression<Func<ProductAccountEntity, bool>> expr = m => 1 == 1;
if (request.UserId > 0)
{
expr = expr.And(m => m.UserId == request.UserId);
}
if (request.KeyWord.Has())
{
expr = expr.And(m => m.UserCode.Contains(request.KeyWord)
|| m.ProductName.Contains(request.KeyWord)
|| m.PackageName.Contains(request.KeyWord)
|| m.Account.Contains(request.KeyWord));
}
if (request.ProductId.HasValue)
{
expr = expr.And(m =>m.ProductId == request.ProductId);
}
if (request.PackageId.HasValue)
{
expr = expr.And(m => m.PackageId == request.PackageId);
}
if (request.AccountTypes!=null&&request.AccountTypes.Count>0)
{
expr = expr.And(m => request.AccountTypes.Contains(m.AccountType));
}
if (request.BTime.HasValue && request.ETime.HasValue)
{
expr = expr.And(m => m.EndTime>=request.BTime&&m.EndTime<=request.ETime);
}
if (request.ExpirdDay > -1)
{
if (request.ExpirdDay == 0)
{
expr = expr.And(m => m.EndTime.Value < DateTime.Now);
}
else
{
var startTime = DateTime.Now.Begin().AddDays(request.ExpirdDay);
startTime = startTime < DateTime.Now ? DateTime.Now : startTime;
var EndTime = DateTime.Now.End().AddDays(request.ExpirdDay);
expr = expr.And(m => m.EndTime >= startTime && m.EndTime <= EndTime);
}
// expr = expr.And(m => Math.Ceiling((m.EndTime - DateTime.Now).Value.TotalDays) == request.ExpirdDay);
}
var ret = await m_AccountService.PageDesc(request.PageIndex, request.PageSize, expr,true,m=>m.Id);
var data = ret.ToApiResult();
return data;
}
/// <summary>
/// 分页查询
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[HttpGet]
public async Task<ApiResult> Search([FromQuery]AccountPageRequest request)
{
if (request.KeyWord.Has())
{
Expression<Func<ProductAccountEntity, bool>> expr = m => m.Account== request.KeyWord||m.UserCode== request.KeyWord;
var ret = await m_AccountService.PageDesc(request.PageIndex, request.PageSize, expr, true, m => m.Id);
var data = ret.ToApiResult();
return data;
}
return Error("请输入关键字");
}
/// <summary>
/// 迁移
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpPost]
public async Task<ApiResult> BindUser([FromBody]BindUserRequest request)
{
var entityList = await m_AccountService.Query(m => request.AccountIds.Contains(m.Id)).ToListAsync();
if (entityList == null|| entityList.Count==0)
return Error("没有选择账号");
var userEntity= await m_UserService.GetById(request.UserId);
if (userEntity == null)
return Error("会员不存在");
entityList.ForEach(entity =>
{
entity.UserId = request.UserId;
entity.UserCode = userEntity.LoginCode;
entity.UserPhone = userEntity.Phone;
});
await m_AccountService.Update(entityList);
return Success();
}
[HttpGet]
public async Task<ApiResult> GetOrginAccount([FromQuery]string accounts)
{
var accountList = await m_AccountService.GetAccounts(string.Join(",", accounts));
var originModel = await m_agentService.GetOriginAccounts(accountList);
return Success(originModel);
}
[HttpGet]
public async Task<ApiResult> UpdateOrginPwd([FromQuery]int productId, string account, string pwd)
{
var flag = await m_agentService.UpdateAccountPwd(productId, account, pwd);
if (flag)
return Success();
else
return Error("修改密码失败");
}
[HttpGet, UserAuth]
public async Task<ApiResult> ExistAccount([FromQuery]int productId, [FromQuery]string accounts)
{
var flag =await m_AccountService.CheckAccountExist(productId, accounts.Split(',').ToList());
if (flag)
{
return Error("账号已经存在");
}
return Success();
}
[HttpPost, UserAuth]
public async Task<ApiResult> CreateTestAccount([FromBody]CreateTestAccountRequest request)
{
if (request.Account.NotHas() || request.Pwd.NotHas())
{
return Error("账户和密码不能为空");
}
var userId = this.Request.GetUserInfo().UserId;
var packageEntity = await m_PackageService.GetById(request.PackageId);
if (packageEntity==null|| packageEntity.Status==0)
{
return Error("套餐不存在");
}
if (packageEntity.IsTest == 0)
{
return Error("非测试套餐");
}
var flag = await m_AccountService.CheckAccountExist(packageEntity.ProductId, new List<string> { request.Account });
if (flag)
{
return Error("账号已经存在");
}
var restTimes = await m_AccountService.GetRestTestCount(userId);
if (restTimes <= 0)
{
return Error("没有测试次数了");
}
var ret= await m_agentService.NewAccount(0, request.PackageId, request.Account, request.Pwd, accountType: 0);
if (ret.Code == ResultCode.C_SUCCESS)
{
var ProductEntity = await m_ProductService.GetById(packageEntity.ProductId);
var accountEntity = new ProductAccountEntity()
{
Account = request.Account,
AccountType = (int)AccountType.Test,
ConnectCount = 1,
StartTime = DateTime.Now,
EndTime = DateTime.Now.AddHours(packageEntity.DayCount),
PackageId = packageEntity.Id,
PackageName = packageEntity.Name,
ProductId = packageEntity.ProductId,
ProductName = ProductEntity.Name,
Pwd = request.Pwd,
ChargeStatus = AccountChargeStatus.Normal,
UserId = this.Request.GetUserInfo().UserId,
UserCode = this.Request.GetUserInfo().LoginName,
};
await m_AccountService.Add(accountEntity);
var userEntity = await m_UserService.GetById(userId);
userEntity.UseTestCount++;
await m_UserService.Update(userEntity);
}
return ret;
}
/// <summary>
/// 是否在线
/// </summary>
/// <param name="productId"></param>
/// <param name="account"></param>
/// <returns></returns>
// [UserAuth]
[AllowAnonymous]
public virtual async Task<ApiResult<List<OriginAccountOnlineModel>>> OnLine(int productId, string account)
{
return await m_agentService.OnLine(productId, account);
}
/// <summary>
/// 踢号
/// </summary>
/// <param name="productId"></param>
/// <param name="account"></param>
/// <returns></returns>
// [UserAuth]
[AllowAnonymous]
public virtual async Task<ApiResult> KillOut(int productId, string id)
{
return Success(await m_agentService.KillOut(productId, id));
}
[HttpGet]
public async Task<IActionResult> Export([FromQuery]AccountPageRequest request)
{
Expression<Func<ProductAccountEntity, bool>> expr = m => 1 == 1;
if (request.UserId > 0)
{
expr = expr.And(m => m.UserId == request.UserId);
}
if (request.KeyWord.Has())
{
expr = expr.And(m => m.Account.Contains(request.KeyWord));
}
if (request.ProductId.HasValue)
{
expr = expr.And(m => m.ProductId == request.ProductId);
}
if (request.PackageId.HasValue)
{
expr = expr.And(m => m.PackageId == request.PackageId);
}
if (request.AccountTypes != null && request.AccountTypes.Count > 0)
{
expr = expr.And(m => request.AccountTypes.Contains(m.AccountType));
}
if (request.ExpirdDay > -1)
{
if (request.ExpirdDay == 0)
{
expr = expr.And(m => m.EndTime.Value < DateTime.Now);
}
else
{
var startTime = DateTime.Now.Begin().AddDays(request.ExpirdDay);
startTime = startTime < DateTime.Now ? DateTime.Now : startTime;
var EndTime = DateTime.Now.End().AddDays(request.ExpirdDay);
expr = expr.And(m => m.EndTime >= startTime && m.EndTime <= EndTime);
}
// expr = expr.And(m => Math.Ceiling((m.EndTime - DateTime.Now).Value.TotalDays) == request.ExpirdDay);
}
var ret = await m_AccountService.PageDesc(request.PageIndex,10000, expr, true, m => m.Id);
var data = new ExcelData<ProductAccountEntity>
{
SheetName = DateTime.Now.ToString("yyyy-MM-dd"),
Data = ret.List
};
var title = new List<ExcelTitle>(){
new ExcelTitle { Property = "UserCode", Title = "用户" },
new ExcelTitle { Property = "ProductName", Title = "产品" },
new ExcelTitle { Property = "PackageName", Title = "套餐" },
new ExcelTitle { Property = "Account", Title = "账号" },
new ExcelTitle { Property = "AccountType", Title = "类型" , Format=(val)=>((AccountType)val).GetEnumDisplayName() },
new ExcelTitle { Property = "ConnectCount", Title = "连接数"},
new ExcelTitle { Property = "StartTime", Title = "开通时间" , Format=(val)=>((DateTime) val).ToString("yyyy-MM-dd hh:mm:ss")},
new ExcelTitle { Property = "EndTime", Title = "到期时间" ,Format=(val)=>((DateTime) val).ToString("yyyy-MM-dd hh:mm:ss")},
new ExcelTitle { Property = "RestTime", Title = "剩余时间" },
};
var fileBytes = ExcelHelper.ExportListToExcel(data, title);
var fileName = $"{DateTime.Now.ToString("yyyyMMdd")}账号明细.xlsx";
Response.Headers.Add("X-Suggested-Filename", fileName.UrlEncode());
return File(fileBytes, "application/octet-stream", fileName);
}
}
}

View File

@@ -0,0 +1,277 @@
using Hncore.Infrastructure.EntitiesExtension;
using Hncore.Infrastructure.Extension;
using Hncore.Infrastructure.WebApi;
using Hncore.Pass.Vpn.Domain;
using Hncore.Pass.Vpn.Request.Product;
using Hncore.Pass.Vpn.Response.Product;
using Hncore.Pass.Vpn.Service;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System;
using System.Linq.Expressions;
using System.Threading.Tasks;
namespace Hncore.Pass.Vpn.Controllers
{
[ApiVersion("1.0")]
[Route("api/course/v{version:apiVersion}/product/[action]")]
public class ProductController : HncoreControllerBase
{
private ProductService m_ProductService;
private ProductPackageService m_ProductPackageService;
private ProductUserPriceService m_ProductUserPriceService;
public ProductController(ProductService _ProductServic, ProductPackageService _ProductPackageService, ProductUserPriceService m_ProductUserPriceService)
{
m_ProductService = _ProductServic;
m_ProductPackageService = _ProductPackageService;
this.m_ProductUserPriceService = m_ProductUserPriceService;
}
/// <summary>
/// 添加
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[HttpPost]
public async Task<ApiResult> Post([FromBody]ProductEntity request)
{
request.TenantId = this.Request.GetManageUserInfo().TenantId;
await m_ProductService.Add(request);
return Success();
}
/// <summary>
/// 修改
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[HttpPost]
public async Task<ApiResult> Put([FromBody]ProductEntity request)
{
var entity = await m_ProductService.GetById(request.Id);
entity.Name = request.Name;
entity.Profile = request.Profile;
entity.Image = request.Image;
entity.RefundDayPrice = request.RefundDayPrice;
entity.DayLimitPrice = request.DayLimitPrice;
await m_ProductService.Update(entity);
return Success();
}
/// <summary>
/// 修改
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[HttpPost]
public async Task<ApiResult> PutConfig([FromBody]ProductEntity request)
{
var entity = await m_ProductService.GetById(request.Id);
entity.Account = request.Account;
entity.Pwd = request.Pwd;
entity.BaseUrl = request.BaseUrl;
entity.Token = "";
await m_ProductService.Update(entity);
return Success();
}
/// <summary>
/// 修改
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[HttpPost]
public async Task<ApiResult> PutSoft([FromBody]ProductEntity request)
{
var entity = await m_ProductService.GetById(request.Id);
entity.PcClientDownloadUrl = request.PcClientDownloadUrl;
entity.SimulatorDownloadUrl = request.SimulatorDownloadUrl;
entity.DroidDownloadUrl = request.DroidDownloadUrl;
entity.IosDownloadUrl = request.IosDownloadUrl;
await m_ProductService.Update(entity);
return Success();
}
/// <summary>
/// 删除
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpPost]
public async Task<ApiResult> Delete([FromQuery]int id)
{
var flag = await m_ProductService.DeleteById(id);
if (flag)
return Success();
else
return Error("删除失败");
}
/// <summary>
/// 详情
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[HttpGet]
public async Task<ApiResult> Get([FromQuery]int id)
{
var data = await m_ProductService.GetById(id);
return Success(data);
}
/// <summary>
/// 分页查询
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[HttpGet]
public async Task<ApiResult> Page([FromQuery]PageRequestBase request)
{
Expression<Func<ProductEntity, bool>> expr = m => 1 == 1;
if (request.KeyWord.Has())
{
expr = expr.And(m => m.Name.Contains(request.KeyWord));
}
var ret = await m_ProductService.Page(request.PageIndex, request.PageSize, expr,true);
var data = ret.ToApiResult();
return data;
}
[HttpGet,AllowAnonymous]
public async Task<ApiResult> OpenPage([FromQuery]PageRequestBase request)
{
Expression<Func<ProductEntity, bool>> expr = m => 1 == 1;
if (request.KeyWord.Has())
{
expr = expr.And(m => m.Name.Contains(request.KeyWord));
}
var ret = await m_ProductService.Page(request.PageIndex, request.PageSize, expr, true);
var data = ret.ToApiResult();
return data;
}
[HttpGet, AllowAnonymous]
public async Task<ApiResult> ProductWithPackage()
{
var respList = await m_ProductService.ProductWithPackage();
return Success(respList);
}
[HttpGet]
public async Task<ApiResult> ProductUserPrice(int userId)
{
var ret = await this.m_ProductUserPriceService.GetPackageUserPrice(userId);
return Success(ret);
}
[HttpPost]
public async Task<ApiResult> SetProductLine([FromQuery]int id)
{
var productEntity = await m_ProductService.GetById(id);
if (productEntity == null)
{
return Error("产品不存在");
}
productEntity.Status = productEntity.OnLine == 0 ? 1 : 0;
await m_ProductService.Update(productEntity);
return Success(productEntity.Status);
}
[HttpPost]
public async Task<ApiResult> SetPackageLine([FromQuery]int id)
{
var packageEntity = await m_ProductPackageService.GetById(id);
if (packageEntity == null)
{
return Error("套餐不存在");
}
packageEntity.Status = packageEntity.Status == 0 ? 1 : 0;
await m_ProductPackageService.Update(packageEntity);
return Success(packageEntity.Status);
}
[HttpPost]
public async Task<ApiResult> SetUserPriceStatus([FromQuery]int id)
{
var userPriceEntity = await m_ProductUserPriceService.GetById(id);
if (userPriceEntity == null)
{
return Error("请设置会员价");
}
userPriceEntity.Status = userPriceEntity.Status == 0 ? 1 : 0;
await m_ProductUserPriceService.Update(userPriceEntity);
return Success(userPriceEntity.Status);
}
[HttpPost]
public async Task<ApiResult> PutPackage([FromBody]ProductPackageEntity request)
{
var packageEntity = await m_ProductPackageService.GetById(request.Id);
if (packageEntity == null)
{
return Error("套餐不存在");
}
packageEntity.LinePrice = request.LinePrice;
packageEntity.MinPrice = request.MinPrice;
packageEntity.Name = request.Name;
packageEntity.Price = request.Price;
packageEntity.Profile = request.Profile;
packageEntity.Title = request.Title;
await m_ProductPackageService.Update(packageEntity);
return Success(packageEntity);
}
[HttpPost]
public async Task<ApiResult> PutUserPrice([FromBody]PutUserPriceRequest request)
{
var userPriceEntity = await m_ProductUserPriceService.Query(m => m.PackageId == request.PackageId && m.UserId == request.UserId).FirstOrDefaultAsync();
var price = request.UserPrice;
var packageEntity =await m_ProductPackageService.GetById(request.PackageId);
// var product = await m_ProductService.GetById(packageEntity.ProductId);
if (request.UserPrice < packageEntity.MinPrice && packageEntity.MinPrice > 0)
{
return Error($"不能低于最低限额[{ packageEntity.MinPrice}]");
}
var productEntity = await m_ProductService.GetById(packageEntity.ProductId);
if (productEntity.DayLimitPrice>0&&request.RefundDayPrice < productEntity.DayLimitPrice)
{
return Error($"退款单价不能低于[{ productEntity.DayLimitPrice}]");
}
//toto
if (userPriceEntity == null)
{
userPriceEntity =new ProductUserPriceEntity()
{
PackageId = request.PackageId,
ProductId = request.ProductId,
UserId = request.UserId,
UserPrice = request.UserPrice,
Status = 1,
DeleteTag = 0,
Remark=request.Remark,
RefundDayPrice= request.RefundDayPrice
};
await m_ProductUserPriceService.Add(userPriceEntity);
}
else
{
userPriceEntity.UserPrice = request.UserPrice;
userPriceEntity.RefundDayPrice = request.RefundDayPrice;
userPriceEntity.Remark = request.Remark;
await m_ProductUserPriceService.Update(userPriceEntity);
}
return Success(1);
}
}
}

View File

@@ -0,0 +1,752 @@
using Hncore.Infrastructure.Common;
using Hncore.Infrastructure.EntitiesExtension;
using Hncore.Infrastructure.Extension;
using Hncore.Infrastructure.WebApi;
using Hncore.Pass.BaseInfo.Service;
using Hncore.Pass.Vpn.Domain;
using Hncore.Pass.Vpn.Model;
using Hncore.Pass.Vpn.Request.Product;
using Hncore.Pass.Vpn.Service;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using BaseUserService = Hncore.Pass.BaseInfo.Service.UserService;
namespace Hncore.Pass.Vpn.Controllers
{
[ApiVersion("1.0")]
[Route("api/course/v{version:apiVersion}/order/[action]")]
public class ProductOrderController : HncoreControllerBase
{
private ProductService m_ProductService;
private ProductOrderService m_ProductOrderService;
private BaseUserService m_BaseUserService;
private ManageService m_ManageService;
public ProductOrderController(ProductService _ProductServic
, ProductOrderService _ProductOrderService
, BaseUserService _BaseUserService
, ManageService _ManageService)
{
m_ProductService = _ProductServic;
m_ProductOrderService = _ProductOrderService;
m_BaseUserService=_BaseUserService;
m_ManageService = _ManageService;
}
/// <summary>
/// 详情
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[HttpGet]
public async Task<ApiResult> Get([FromQuery]int id)
{
var data = await m_ProductService.GetById(id);
return Success(data);
}
/// <summary>
/// 分页查询
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[HttpGet]
public async Task<ApiResult> Page([FromQuery]OrderQueryRequest request)
{
Expression<Func<ProductOrderEntity, bool>> expr = m =>( m.OrderState == OrderStatus.PayOk || m.OrderState == OrderStatus.Complete) && m.OrderType != OrderType.Refund;
if (request.KeyWord.Has())
{
expr = expr.And(m =>
m.ProductName.Contains(request.KeyWord)
||m.Accounts.Contains(request.KeyWord)
||m.OrderNo.Contains(request.KeyWord)
||m.UserName.Contains(request.KeyWord)
||m.PackageName.Contains(request.KeyWord));
}
if (request.ProductId.HasValue)
{
expr = expr.And(m =>m.ProductId==request.ProductId);
}
if (request.PackageId.HasValue)
{
expr = expr.And(m => m.PackageId == request.PackageId);
}
if (request.OrderTypes != null && request.OrderTypes.Count > 0)
{
expr = expr.And(m => request.OrderTypes.Contains((int)m.OrderType));
}
if (request.BTime.HasValue && request.ETime.HasValue)
{
expr = expr.And(m => m.CreateTime >= request.BTime && m.CreateTime <= request.ETime);
}
var ret = await m_ProductOrderService.PageDesc(request.PageIndex, request.PageSize, expr, true,m=>m.Id);
var data = ret.ToApiResult();
return data;
}
[HttpGet]
public ApiResult Statistics([FromQuery]OrderQueryRequest request)
{
var ret = m_ProductOrderService.Statistics(request.BTime, request.ETime);
return Success(ret);
}
[HttpGet]
public ApiResult SellerStatistics([FromQuery]OrderQueryRequest request)
{
var ret = m_ProductOrderService.SellerStatistics(request.BTime, request.ETime);
return Success(ret);
}
[HttpGet]
public async Task<ApiResult> UserConsumeStatistics([FromQuery]UserConsumeRequest request)
{
var loginInfo = this.Request.GetManageUserInfo();
int id = loginInfo.OperaterId;
var managerInfo =await m_ManageService.GetById(loginInfo.OperaterId);
if (managerInfo.IsRoot == 1) id = 0;
var ret = m_ProductOrderService.UserConsumeStatistics(request.PageIndex, request.PageSize, request.KeyWord, request.bTime1, request.eTime1, request.bTime2, request.eTime2, id, request.SortLable, request.SortOrder,request.Profile);
return ret.ToApiResult();
}
[HttpGet]
public async Task<ApiResult> RefundOrders([FromQuery]OrderQueryRequest request)
{
Expression<Func<ProductOrderEntity, bool>> expr = m => m.OrderType == OrderType.Refund;
if (request.KeyWord.Has())
{
expr = expr.And(m => m.Accounts.Contains(request.KeyWord)
|| m.OrderNo.Contains(request.KeyWord)
|| m.UserName.Contains(request.KeyWord)
|| m.PackageName.Contains(request.KeyWord));
}
if (request.ProductId.HasValue)
{
expr = expr.And(m => m.ProductId == request.ProductId);
}
if (request.OrderTypes != null && request.OrderTypes.Count > 0)
{
expr = expr.And(m => request.OrderTypes.Contains((int)m.OrderType));
}
if (request.BTime.HasValue && request.ETime.HasValue)
{
expr = expr.And(m => m.CreateTime >= request.BTime && m.CreateTime <= request.ETime);
}
var ret = await m_ProductOrderService.PageDesc(request.PageIndex, request.PageSize, expr, true,m=>m.Id);
var data = ret.ToApiResult();
return data;
}
[HttpGet,AllowAnonymous]
public async Task<ApiResult> OpenRefundOrders([FromQuery]RefundOrderQueryRequest request)
{
Expression<Func<ProductOrderEntity, bool>> expr = m => m.OrderType == OrderType.Refund;
if (request.KeyWord.Has())
{
expr = expr.And(m => m.Accounts.Contains(request.KeyWord)
|| m.OrderNo.Contains(request.KeyWord)
|| m.UserName.Contains(request.KeyWord)
|| m.PackageName.Contains(request.KeyWord));
}
if (request.ProductIds!=null&& request.ProductIds.Count>0)
{
expr = expr.And(m => request.ProductIds.Contains(m.ProductId));
}
if (request.BTime.HasValue && request.ETime.HasValue)
{
expr = expr.And(m => m.CreateTime > request.BTime && m.CreateTime < request.ETime);
}
var ret = await m_ProductOrderService.PageDesc(request.PageIndex, request.PageSize, expr, true, m => m.Id);
var data = ret.ToApiResult();
return data;
}
[UserAuth]
public async Task<ApiResult> CreateOrder(CreateOrderRequest request)
{
var userInfo = this.Request.GetUserInfo();
var ret = await m_ProductOrderService.CreateOrder(request, userInfo.UserId);
if (ret.Code != ResultCode.C_SUCCESS)
{
return ret;
}
return Success();
}
[UserAuth]
public async Task<ApiResult> Refund(string account)
{
var userInfo = this.Request.GetUserInfo();
return await m_ProductOrderService.Refund(userInfo.UserId, account);
}
[UserAuth]
public async Task<ApiResult> CaclRefund(string account)
{
var userInfo = this.Request.GetUserInfo();
return await m_ProductOrderService.CaclRefund(userInfo.UserId, account);
}
///// <summary>
///// 支付(微信公众号、小程序支付,创建流水记录。)
///// </summary>
///// <param name="param"></param>
///// <returns></returns>
//[HttpPost, UserAuth]
//public async Task<ApiResult> CreatePayOrder([FromBody] CreateOrderRequest request)
//{
// var userInfo = this.Request.GetUserInfo();
// var ret = await m_ProductOrderService.CreateOrder(request, userInfo.UserId);
// if (ret.Code != ResultCode.C_SUCCESS)
// {
// return ret;
// }
// var req = new PayRequest()
// {
// OrderNO = ret.Data.OrderNo,
// PayEnvironment = request.PayEnvironment,
// PaymentType = request.PaymentType
// };
// return await CreatePaymentOrder(req, ret.Data, userInfo);
//}
//[UserAuth]
//public async Task<ApiResult> Pay(PayRequest request)
//{
// var order = await m_CourseOrderService.GetByOrderNo(request.OrderNO);
// var userInfo = this.Request.GetUserInfo();
// return await CreatePaymentOrder(request, order, userInfo);
//}
/// <summary>
/// 支付部分
/// </summary>
/// <param name="param"></param>
/// <param name="UserInfo"></param>
/// <param name="OpenId"></param>
/// <returns></returns>
//private async Task<ApiResult> CreatePaymentOrder(PayRequest request, ProductOrderEntity orderData, AppUserInfo UserInfo)
//{
// string callBackUrl = $"{m_Configuration["Service_BaseUrl"]}/api/courseOrder/v1/WxOrderCallBack?orderId={orderData.OrderNo}&payType={(int)request.PaymentType}";
// string attach = orderData.ToJson();
// decimal payAmount = orderData.OrderAmount * 100.0M;
// string orderDesc = "购买课程支付";
// var resp = new CreatePaymentOrderResponse<CourseOrderEntity>()
// {
// OrderInfo = orderData
// };
// var weChatPayRequest = new WechatJsPayCreateOrderRequest()
// {
// Attach = attach,
// Body = orderDesc,
// CallbackUrl = callBackUrl + "&paymentType=" + (int)Payment.Enum.PaymentType.OnlinePayWechart,
// OrderId = orderData.OrderNo,
// OrderType = orderData.OrderType,
// TenantId = orderData.TenantId,
// PayEnvironment = request.PayEnvironment,
// PaymentType = request.PaymentType,
// TotalFee = Convert.ToInt32(payAmount),
// UserOpenId = UserInfo.OpenId,
// AppId = UserInfo.AppId,
// StoreId = UserInfo.StoreId
// };
// var wechatJsPayResp = await m_ServiceHttpClient.WechatJsPayCreateOrder(weChatPayRequest);
// if (wechatJsPayResp.Code == ResultCode.C_SUCCESS)
// {
// try
// {
// //{"tradeNO":"2019102522001433001406080254","status":"0"}
// var payOrderInfo = wechatJsPayResp.Data.ToString().FromJsonToOrDefault<WxPayOrderInfo>();
// if (payOrderInfo != null && payOrderInfo.package.Has())
// {
// string[] tmp2param = payOrderInfo.package.Split('=');
// if (tmp2param != null && tmp2param.Length == 2)
// {
// orderData.TradeNo = tmp2param[1];
// await m_CourseOrderService.Update(orderData);
// }
// }
// resp.PayInfo = wechatJsPayResp.Data.ToString();
// return Success(resp);
// }
// catch (Exception ex)
// {
// LogHelper.Error("课程支付获取微信支付订单信息转换出错:" + ex.Message, ex);
// return new ApiResult(ResultCode.C_UNKNOWN_ERROR, "交易失败");
// }
// }
// return new ApiResult(ResultCode.C_UNKNOWN_ERROR, wechatJsPayResp.Message);
//}
//[InternalApiAuth]
//public async Task<string> WxOrderCallBack([FromQuery]string orderId = "", [FromQuery] int paymentType = 0)
//{
// if (string.IsNullOrWhiteSpace(orderId) || paymentType <= 0)
// {
// return "faild";
// }
// var order = await m_CourseOrderService.GetByOrderNo(orderId);
// if (order == null)
// return "faild";
// order.OrderState = OrderStatus.PayOk;
// order.PayType = paymentType;
// await m_CourseOrderService.Update(order);
// return "faild";
//}
[HttpGet]
public async Task<IActionResult> Export([FromQuery]OrderQueryRequest request)
{
Expression<Func<ProductOrderEntity, bool>> expr = m => (m.OrderState == OrderStatus.PayOk || m.OrderState == OrderStatus.Complete) && m.OrderType != OrderType.Refund;
if (request.KeyWord.Has())
{
expr = expr.And(m =>
m.OrderName.Contains(request.KeyWord)
|| m.OrderNo.Contains(request.KeyWord)
|| m.UserName.Contains(request.KeyWord)
|| m.PackageName.Contains(request.KeyWord));
}
if (request.OrderTypes != null && request.OrderTypes.Count > 0)
{
expr = expr.And(m => request.OrderTypes.Contains((int)m.OrderType));
}
if (request.BTime.HasValue && request.ETime.HasValue)
{
expr = expr.And(m => m.CreateTime >= request.BTime && m.CreateTime <= request.ETime);
}
var ret = await m_ProductOrderService.PageDesc(request.PageIndex, 10000, expr, true,m=>m.Id);
var data = new ExcelData<ProductOrderEntity>
{
SheetName = DateTime.Now.ToString("yyyy-MM-dd"),
Data = ret.List
};
var title = new List<ExcelTitle>(){
new ExcelTitle { Property = "CreateTime", Title = "创建日期" , Format=(val)=>((DateTime) val).ToString("yyyy-MM-dd hh:mm:ss") },
new ExcelTitle { Property = "OrderNo", Title = "订单号" },
new ExcelTitle { Property = "OrderType", Title = "类型", Format=(val)=>((OrderType)val).GetEnumDisplayName() },
new ExcelTitle { Property = "UserName", Title = "用户" },
new ExcelTitle { Property = "ProductName", Title = "产品" },
new ExcelTitle { Property = "PackageName", Title = "套餐" },
new ExcelTitle { Property = "DayPrice", Title = "单价" },
new ExcelTitle { Property = "ConnectCount", Title = "连接数",Expr=(p)=>((ProductOrderEntity)p).ConnectCount*((ProductOrderEntity)p).AccountCount},
new ExcelTitle { Property = "Accounts", Title = "账号" },
new ExcelTitle { Property = "OrderAmount", Title = "订单金额" },
new ExcelTitle { Property = "CouponAmount", Title = "优惠金额" },
new ExcelTitle { Property = "AccountPayAmount", Title = "余额支付" },
new ExcelTitle { Property = "OtherPayAmount", Title = "在线支付" },
new ExcelTitle { Property = "PaymentAmount", Title = "实付" },
new ExcelTitle { Property = "PayType", Title = "付款方式" , Format=(val)=>((PayType)val).GetEnumDisplayName() },
new ExcelTitle { Property = "TradeNo", Title = "支付流水号" },
};
var fileBytes = ExcelHelper.ExportListToExcel(data, title);
var fileName = $"{DateTime.Now.ToString("yyyyMMdd")}订单明细.xlsx";
Response.Headers.Add("X-Suggested-Filename", fileName.UrlEncode());
return File(fileBytes, "application/octet-stream", fileName);
}
[HttpGet]
public async Task<IActionResult> ExportRefundOrders([FromQuery]OrderQueryRequest request)
{
Expression<Func<ProductOrderEntity, bool>> expr = m => m.OrderType == OrderType.Refund;
if (request.KeyWord.Has())
{
expr = expr.And(m =>
m.OrderName.Contains(request.KeyWord)
|| m.OrderNo.Contains(request.KeyWord)
|| m.UserName.Contains(request.KeyWord)
|| m.PackageName.Contains(request.KeyWord));
}
if (request.OrderTypes != null && request.OrderTypes.Count > 0)
{
expr = expr.And(m => request.OrderTypes.Contains((int)m.OrderType));
}
if (request.BTime.HasValue && request.ETime.HasValue)
{
expr = expr.And(m => m.CreateTime >= request.BTime && m.CreateTime <= request.ETime);
}
var ret = await m_ProductOrderService.Page(request.PageIndex, 10000, expr, true);
var data = new ExcelData<ProductOrderEntity>
{
SheetName = DateTime.Now.ToString("yyyy-MM-dd"),
Data = ret.List
};
Func<ProductOrderEntity, object> refundTypeFormat = (order) =>
{
switch (order.OrderState)
{
case OrderStatus.RequestRefund:
return "未自动退款";
case OrderStatus.UserRefundOver:
return "已人工处理";
case OrderStatus.AutoRefundOver:
return "已自动退款";
default:
return "";
}
};
var title = new List<ExcelTitle>(){
new ExcelTitle { Property = "CreateTime", Title = "创建日期" ,Format=(val)=>((DateTime) val).ToString("yyyy-MM-dd hh:mm:ss") },
//new ExcelTitle { Property = "OrderNo", Title = "订单号" },
// new ExcelTitle { Property = "OrderType", Title = "类型", Format=(val)=>((OrderType)val).GetEnumDisplayName() },
// new ExcelTitle { Property = "UserName", Title = "用户" },
new ExcelTitle { Property = "ProductName", Title = "产品" },
new ExcelTitle { Property = "PackageName", Title = "套餐" },
new ExcelTitle { Property = "ConnectCount", Title = "连接数",Expr=(p)=>((ProductOrderEntity)p).ConnectCount*((ProductOrderEntity)p).AccountCount},
new ExcelTitle { Property = "Accounts", Title = "账号" },
new ExcelTitle { Property = "PaymentAmount", Title = "实付金额" },
new ExcelTitle { Property = "RefundAmount", Title = "退款金额" },
new ExcelTitle { Property = "RefundRestTime", Title = "剩余时间" },
new ExcelTitle { Property = "RefundRestTime", Title = "自动退款",Expr=(p)=>((ProductOrderEntity)p).IsAutoRefund.HasValue&&((ProductOrderEntity)p).IsAutoRefund==1?"是":"否" },
new ExcelTitle { Property = "RefundRestTime", Title = "退款状态",Expr=(p)=>refundTypeFormat((ProductOrderEntity)p) },
};
var fileBytes = ExcelHelper.ExportListToExcel(data, title);
var fileName = $"{DateTime.Now.ToString("yyyyMMdd")}退款明细.xlsx";
Response.Headers.Add("X-Suggested-Filename", fileName.UrlEncode());
return File(fileBytes, "application/octet-stream", fileName);
}
[HttpGet,AllowAnonymous]
public async Task<IActionResult> OpenExportRefundOrders([FromQuery]OrderQueryRequest request)
{
Expression<Func<ProductOrderEntity, bool>> expr = m => m.OrderType == OrderType.Refund;
if (request.KeyWord.Has())
{
expr = expr.And(m =>
m.OrderName.Contains(request.KeyWord)
|| m.OrderNo.Contains(request.KeyWord)
|| m.UserName.Contains(request.KeyWord)
|| m.PackageName.Contains(request.KeyWord));
}
if (request.OrderTypes != null && request.OrderTypes.Count > 0)
{
expr = expr.And(m => request.OrderTypes.Contains((int)m.OrderType));
}
if (request.BTime.HasValue && request.ETime.HasValue)
{
expr = expr.And(m => m.CreateTime >= request.BTime && m.CreateTime <= request.ETime);
}
var ret = await m_ProductOrderService.Page(request.PageIndex, 10000, expr, true);
var data = new ExcelData<ProductOrderEntity>
{
SheetName = DateTime.Now.ToString("yyyy-MM-dd"),
Data = ret.List
};
Func<ProductOrderEntity, object> refundTypeFormat = (order) =>
{
switch (order.OrderState)
{
case OrderStatus.RequestRefund:
return "未自动退款";
case OrderStatus.UserRefundOver:
return "已人工处理";
case OrderStatus.AutoRefundOver:
return "已自动退款";
default:
return "";
}
};
var title = new List<ExcelTitle>(){
new ExcelTitle { Property = "CreateTime", Title = "创建日期" ,Format=(val)=>((DateTime) val).ToString("yyyy-MM-dd hh:mm:ss") },
//new ExcelTitle { Property = "OrderNo", Title = "订单号" },
//new ExcelTitle { Property = "OrderType", Title = "类型", Format=(val)=>((OrderType)val).GetEnumDisplayName() },
//new ExcelTitle { Property = "UserName", Title = "用户" },
new ExcelTitle { Property = "ProductName", Title = "产品" },
new ExcelTitle { Property = "PackageName", Title = "套餐" },
new ExcelTitle { Property = "ConnectCount", Title = "连接数",Expr=(p)=>((ProductOrderEntity)p).ConnectCount*((ProductOrderEntity)p).AccountCount},
new ExcelTitle { Property = "Accounts", Title = "账号" },
new ExcelTitle { Property = "RefundRestTime", Title = "剩余时间" }
};
var fileBytes = ExcelHelper.ExportListToExcel(data, title);
var fileName = $"{DateTime.Now.ToString("yyyyMMdd")}退款明细.xlsx";
Response.Headers.Add("X-Suggested-Filename", fileName.UrlEncode());
return File(fileBytes, "application/octet-stream", fileName);
}
[HttpPost]
public async Task<ApiResult> RefundProcess([FromBody]RefundProcessRequest request)
{
var entity=await m_ProductOrderService.GetById(request.Id);
if (entity.OrderState != OrderStatus.RequestRefund)
{
return Error("无需处理");
}
entity.Remark += request.Remark;
entity.OrderState = OrderStatus.UserRefundOver;
await m_ProductOrderService.Update(entity);
return Success();
}
[HttpGet]
public async Task<ApiResult> CouponOrders([FromQuery] CouponOrderQueryRequest request)
{
var data = await this.m_ProductOrderService
.Query(m => m.CouponId == request.CouponId
&& m.OrderState == OrderStatus.Complete)
.ListPagerAsync(request.PageSize, request.PageIndex, true);
return data.ToApiResult();
}
[HttpGet]
public async Task<ApiResult> TakeOrder([FromQuery]string phone, [FromQuery] decimal amount)
{
var manager = this.Request.GetManageUserInfo();
var datas = await this.m_ProductOrderService
.Query(m => m.UserName == phone
&& m.OrderState == OrderStatus.Complete
&& m.OrderAmount == amount
&& string.IsNullOrEmpty(m.Channel))
.OrderByDescending(m => m.Id)
.ToListAsync();
var data = datas.Where(m => (DateTime.Now - m.UpdateTime).TotalMinutes < 30).FirstOrDefault();
if (data != null)
{
data.Channel = manager.LoginName;
await m_ProductOrderService.Update(data);
return Success();
}
return Error("没有订单");
}
[HttpGet]
public async Task<ApiResult> SellerOrders([FromQuery]OrderQueryRequest request)
{
var manager = this.Request.GetManageUserInfo();
var managerEntity = await m_ManageService.GetById(manager.OperaterId);
Expression<Func<ProductOrderEntity, bool>> expr = m => !string.IsNullOrEmpty(m.Channel);
if (managerEntity != null && managerEntity.IsRoot == 0)
{
expr = m => m.Channel == manager.LoginName;
}
if (request.KeyWord.Has())
{
expr = expr.And(m => m.Accounts.Contains(request.KeyWord)|| m.OrderNo.Contains(request.KeyWord)|| m.UserName.Contains(request.KeyWord));
}
if (request.ProductId.HasValue)
{
expr = expr.And(m => m.ProductId == request.ProductId);
}
if (request.OrderTypes != null && request.OrderTypes.Count > 0)
{
expr = expr.And(m => request.OrderTypes.Contains((int)m.OrderType));
}
if (request.BTime.HasValue && request.ETime.HasValue)
{
expr = expr.And(m => m.CreateTime >= request.BTime && m.CreateTime <= request.ETime);
}
var ret = await this.m_ProductOrderService.PageDesc(request.PageIndex, request.PageSize, expr, true, m => m.Id);
return ret.ToApiResult();
}
[HttpGet]
public async Task<IActionResult> ExportSellerOrders([FromQuery]OrderQueryRequest request)
{
var manager = this.Request.GetManageUserInfo();
var managerEntity = await m_ManageService.GetById(manager.OperaterId);
Expression<Func<ProductOrderEntity, bool>> expr = m => !string.IsNullOrEmpty(m.Channel);
if (managerEntity != null && managerEntity.IsRoot == 0)
{
expr = m => m.Channel == manager.LoginName;
}
if (request.KeyWord.Has())
{
expr = expr.And(m => m.Accounts.Contains(request.KeyWord) || m.OrderNo.Contains(request.KeyWord) || m.UserName.Contains(request.KeyWord));
}
if (request.ProductId.HasValue)
{
expr = expr.And(m => m.ProductId == request.ProductId);
}
if (request.OrderTypes != null && request.OrderTypes.Count > 0)
{
expr = expr.And(m => request.OrderTypes.Contains((int)m.OrderType));
}
if (request.BTime.HasValue && request.ETime.HasValue)
{
expr = expr.And(m => m.CreateTime >= request.BTime && m.CreateTime <= request.ETime);
}
var ret = await this.m_ProductOrderService.PageDesc(request.PageIndex,10000, expr, true, m => m.Id);
var data = new ExcelData<ProductOrderEntity>
{
SheetName = DateTime.Now.ToString("yyyy-MM-dd"),
Data = ret.List
};
Func<ProductOrderEntity, object> refundTypeFormat = (order) =>
{
switch (order.OrderState)
{
case OrderStatus.RequestRefund:
return "未自动退款";
case OrderStatus.UserRefundOver:
return "已人工处理";
case OrderStatus.AutoRefundOver:
return "已自动退款";
default:
return "";
}
};
var title = new List<ExcelTitle>(){
new ExcelTitle { Property = "CreateTime", Title = "创建日期" ,Format=(val)=>((DateTime) val).ToString("yyyy-MM-dd hh:mm:ss") },
new ExcelTitle { Property = "OrderNo", Title = "订单号" },
new ExcelTitle { Property = "OrderType", Title = "类型", Format=(val)=>((OrderType)val).GetEnumDisplayName() },
new ExcelTitle { Property = "UserName", Title = "用户" },
new ExcelTitle { Property = "ProductName", Title = "产品" },
new ExcelTitle { Property = "PackageName", Title = "套餐" },
new ExcelTitle { Property = "ConnectCount", Title = "连接数",Expr=(p)=>((ProductOrderEntity)p).ConnectCount*((ProductOrderEntity)p).AccountCount},
new ExcelTitle { Property = "DayPrice", Title = "单价" },
new ExcelTitle { Property = "Accounts", Title = "账号" },
new ExcelTitle { Property = "OrderAmount", Title = "订单金额" },
new ExcelTitle { Property = "CouponAmount", Title = "优惠金额" },
new ExcelTitle { Property = "AccountPayAmount", Title = "余额支付" },
new ExcelTitle { Property = "OtherPayAmount", Title = "在线支付" },
new ExcelTitle { Property = "PaymentAmount", Title = "实付" },
new ExcelTitle { Property = "PayType", Title = "付款方式", Format=(val)=>((PayType)val).GetEnumDisplayName() },
new ExcelTitle { Property = "PaymentAmount", Title = "支付流水号" },
new ExcelTitle { Property = "Channel", Title = "销售人" },
};
var fileBytes = ExcelHelper.ExportListToExcel(data, title);
var fileName = $"{DateTime.Now.ToString("yyyyMMdd")}销售明细.xlsx";
Response.Headers.Add("X-Suggested-Filename", fileName.UrlEncode());
return File(fileBytes, "application/octet-stream", fileName);
}
public async Task<ApiResult> UserCountStatistics(DateTime? bTime, DateTime? eTime)
{
var manager = this.Request.GetManageUserInfo();
var managerInfo = await m_ManageService.GetById(manager.OperaterId);
var countInfo = m_ProductOrderService.UserCountStatistics(bTime, eTime);
var totalCountInfo = m_ProductOrderService.UserCountStatistics(null, null);
var amountInfo = m_ProductOrderService.SellAmountStatistics(bTime, eTime);
var query = from count in totalCountInfo
join amount in amountInfo on count.RealName equals amount.RealName
join newCount in countInfo on count.RealName equals newCount.RealName
select new ManagerSellStatisticModel { RealName = count.RealName, Amount = amount.Amount, UserCount = count.UserCount, NewUserCount = newCount.UserCount };
if (managerInfo.IsRoot != 1)
{
query = query.Where(m => m.RealName == managerInfo.RealName);
}
var totalOrderAmount = m_ProductOrderService.Query(true).Where(m => m.OrderState == OrderStatus.PayOk || m.OrderState == OrderStatus.Complete).Sum(m => m.OrderAmount);
var totalUser = m_BaseUserService.Query(true).Count();
var ret = new
{
OrderAmount = totalOrderAmount,
UserTotal = totalUser,
List = query.ToList()
};
return Success(ret);
}
[HttpGet]
public async Task<IActionResult> ExportUserConsumeStatistics([FromQuery]UserConsumeRequest request)
{
var loginInfo = this.Request.GetManageUserInfo();
int id = loginInfo.OperaterId;
var managerInfo = await m_ManageService.GetById(loginInfo.OperaterId);
if (managerInfo.IsRoot == 1) id = 0;
var ret = m_ProductOrderService.ExportUserConsumeStatisticsData(request.KeyWord, request.bTime1, request.eTime1, request.bTime2, request.eTime2, id, request.SortLable, request.SortOrder, request.Profile);
var data = new ExcelData<UserConsumeStatisticsModel>
{
SheetName = DateTime.Now.ToString("yyyy-MM-dd"),
Data = ret
};
var title = new List<ExcelTitle>(){
new ExcelTitle { Property = "Profile", Title = "状态" , Expr=(p)=>((UserConsumeStatisticsModel)p).UserInfo.Profile},
new ExcelTitle { Property = "UserName", Title = "用户" },
new ExcelTitle { Property = "CreateTime", Title = "注册时间", Format=(val)=>((DateTime)val).ToString("yyyy-MM-dd") },
new ExcelTitle { Property = "PrevMonthAmount", Title = "消费金额A" },
new ExcelTitle { Property = "MonthAmount", Title = "消费金额B" },
new ExcelTitle { Property = "AddAmount", Title = "对比增长金额" },
new ExcelTitle { Property = "TotalAccountCount", Title = "账户总数" },
new ExcelTitle { Property = "UsingAccountCount", Title = "过期个数" },
new ExcelTitle { Property = "UserName", Title = "联系信息" , Expr=(p)=>{
var user=((UserConsumeStatisticsModel)p).UserInfo;
var subret=new List<string>();
if(user.Wx.Has()) subret.Add($"微信:{user.Wx}");
if(user.QQ.Has()) subret.Add($"QQ:{user.QQ}");
if(user.Wx.Has()) subret.Add($"淘宝:{user.TaoBao}");
if(user.Wx.Has()) subret.Add($"旺旺:{user.WangWang}");
return string.Join(",",subret);
} }
};
var fileBytes = ExcelHelper.ExportListToExcel(data, title);
var fileName = $"{DateTime.Now.ToString("yyyyMMdd")}消费统计.xlsx";
Response.Headers.Add("X-Suggested-Filename", fileName.UrlEncode());
return File(fileBytes, "application/octet-stream", fileName);
}
}
}

View File

@@ -0,0 +1,149 @@
using Hncore.Infrastructure.Common;
using Hncore.Infrastructure.EntitiesExtension;
using Hncore.Infrastructure.Extension;
using Hncore.Infrastructure.WebApi;
using Hncore.Pass.Vpn.Domain;
using Hncore.Pass.Vpn.Request.Product;
using Hncore.Pass.Vpn.Service;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
namespace Hncore.Pass.Vpn.Controllers
{
[ApiVersion("1.0")]
[Route("api/course/v{version:apiVersion}/productroute/[action]")]
public class ProductRouteController : HncoreControllerBase
{
private ProductRouteService m_ProductRouteService;
private ProductService m_ProductService;
public ProductRouteController(ProductRouteService _ProductRouteService, ProductService _ProductService)
{
m_ProductRouteService = _ProductRouteService;
m_ProductService = _ProductService;
}
/// <summary>
/// 添加
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[HttpPost]
public async Task<ApiResult> Post([FromBody]ProductRouteEntity request)
{
var product = await m_ProductService.GetById(request.ProductId);
request.ProductName = product?.Name;
await m_ProductRouteService.Add(request);
return Success();
}
/// <summary>
/// 修改
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[HttpPost]
public async Task<ApiResult> Put([FromBody]ProductRouteEntity request)
{
var product = await m_ProductService.GetById(request.ProductId);
request.ProductName = product?.Name;
await m_ProductRouteService.Update(request);
return Success();
}
/// <summary>
/// 删除
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpPost]
public async Task<ApiResult> Delete([FromQuery]int id)
{
var flag = await m_ProductRouteService.DeleteById(id);
if (flag)
return Success();
else
return Error("删除失败");
}
/// <summary>
/// 详情
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[HttpGet]
public async Task<ApiResult> Get([FromQuery]int id)
{
var data = await m_ProductRouteService.GetById(id);
return Success(data);
}
/// <summary>
/// 分页查询
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[HttpGet]
public async Task<ApiResult> Page([FromQuery]RoutePageRequest request)
{
Expression<Func<ProductRouteEntity, bool>> expr = m => 1 == 1;
if (request.KeyWord.Has())
{
expr = expr.And(m => m.Province.Contains(request.KeyWord) || m.Name.Contains(request.KeyWord) || m.City.Contains(request.KeyWord) || m.ServerUrl.Contains(request.KeyWord));
}
if (request.ProductId.HasValue&& request.ProductId>0)
{
expr = expr.And(m => m.ProductId==request.ProductId);
}
var ret = await m_ProductRouteService.PageAsc(request.PageIndex, request.PageSize, expr, true,m=>m.Sort);
var data = ret.ToApiResult();
return data;
}
/// <summary>
/// 导入
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[HttpPost, AllowAnonymous]
public async Task<ApiResult> Import(IFormFile file)
{
// var file = this.Request.Form.Files.First();
var stream = file.OpenReadStream();// this.Request.Body;
//stream.Position = 0;
var data = ExcelHelper.ReadFromStream(stream);
var products = await m_ProductService.GetAll();
var list = new List<ProductRouteEntity>();
var dataRows = data.Skip(1);
foreach (var row in dataRows)
{
var model = new ProductRouteEntity();
model.ProductName = row[0];
model.Province = row[1];
model.Name = row[2];
model.ServerUrl = row[3];
model.Status = row[4];
model.LineType = row[5];
model.BandWidth = row[6];
model.IpRemark = row[7];
model.ProductId = products.FirstOrDefault(m => m.Name == model.ProductName)?.Id;
}
if (list.Count > 1)
{
await m_ProductRouteService.Adds(list);
}
return Success();
}
}
}

View File

@@ -0,0 +1,188 @@
using Hncore.Infrastructure.EntitiesExtension;
using Hncore.Infrastructure.Extension;
using Hncore.Infrastructure.WebApi;
using Hncore.Pass.Vpn.Domain;
using Hncore.Pass.Vpn.Request.Product;
using Hncore.Pass.Vpn.Service;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
namespace Hncore.Pass.Vpn.Controllers
{
[ApiVersion("1.0")]
[Route("api/course/v{version:apiVersion}/scheme/[action]")]
public class ProductSchemeController : HncoreControllerBase
{
private ProductService m_ProductService;
private ProductPackageService m_ProductPackageService;
private ProductUserPriceService m_ProductUserPriceService;
private ProductPriceSchemeService m_PriceSchemeService;
private ProductPriceDiscountService m_PriceDiscountService;
public ProductSchemeController(ProductService _ProductServic
, ProductPackageService _ProductPackageService
, ProductUserPriceService _ProductUserPriceService
,ProductPriceSchemeService _PriceSchemeService
,ProductPriceDiscountService _PriceDiscountService
)
{
m_ProductService = _ProductServic;
m_ProductPackageService = _ProductPackageService;
m_ProductUserPriceService = _ProductUserPriceService;
m_PriceSchemeService = _PriceSchemeService;
m_PriceDiscountService = _PriceDiscountService;
}
/// <summary>
/// 添加
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[HttpPost]
public async Task<ApiResult> Post([FromBody]ProductPriceSchemeEntity request)
{
await m_PriceSchemeService.Add(request);
return Success();
}
/// <summary>
/// 修改
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[HttpPost]
public async Task<ApiResult> Put([FromBody]ProductPriceSchemeEntity request)
{
var entity = await m_PriceSchemeService.GetById(request.Id);
entity.Name = request.Name;
entity.Remark = request.Remark;
entity.UpdateTime = DateTime.Now;
await m_PriceSchemeService.Update(entity);
return Success();
}
/// <summary>
/// 删除
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpPost]
public async Task<ApiResult> Delete([FromQuery]int id)
{
var flag = await m_PriceSchemeService.DeleteById(id);
if (flag)
return Success();
else
return Error("删除失败");
}
/// <summary>
/// 详情
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[HttpGet]
public async Task<ApiResult> Get([FromQuery]int id)
{
var data = await m_PriceSchemeService.GetById(id);
return Success(data);
}
/// <summary>
/// 分页查询
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[HttpGet]
public async Task<ApiResult> Page([FromQuery]PageRequestBase request)
{
Expression<Func<ProductPriceSchemeEntity, bool>> expr = m => 1 == 1;
if (request.KeyWord.Has())
{
expr = expr.And(m => m.Name.Contains(request.KeyWord));
}
var ret = await m_PriceSchemeService.Page(request.PageIndex, request.PageSize, expr,true);
var data = ret.ToApiResult();
return data;
}
[HttpGet]
public async Task<ApiResult> GetProductDiscount(int id)
{
var ret = await this.m_PriceDiscountService.GetPriceDiscount(id);
return Success(ret);
}
[HttpPost]
public async Task<ApiResult> PutProductDiscount([FromBody]ProductPriceDiscountEntity request)
{
var priceDiscountEntity = await m_PriceDiscountService.Query(m => m.PackageId == request.PackageId && m.SchemeId == request.SchemeId).FirstOrDefaultAsync();
if (priceDiscountEntity == null)
{
await m_PriceDiscountService.Add(request);
}
else
{
priceDiscountEntity.BuyPriceDiscount = request.BuyPriceDiscount;
priceDiscountEntity.RefundDayPriceDiscount = request.RefundDayPriceDiscount;
await m_PriceDiscountService.Update(priceDiscountEntity);
}
return Success(1);
}
[HttpPost]
public async Task<ApiResult> SetUserDiscount([FromBody] SetUserDiscountRequest request)
{
var priceDiscountEntitys = await m_PriceDiscountService.Query(m => m.SchemeId == request.SchemeId).ToListAsync();
var schemaEntity = await m_PriceSchemeService.GetById(request.SchemeId);
var produccts = await m_ProductService.GetAll(true);
var packages = await m_ProductPackageService.GetAll(true);
var userPrices = await m_ProductUserPriceService.GetPackageUserPrice(request.UserId);
foreach (var item in priceDiscountEntitys)
{
var product = produccts.FirstOrDefault(m => m.Id == item.ProductId);
var package = packages.FirstOrDefault(m => m.Id == item.PackageId);
var userPakcagePrices = userPrices.FirstOrDefault(m => m.Product.Id == item.ProductId)?.PackageUserPrices;
var userPrice = userPakcagePrices?.FirstOrDefault(uPrice => uPrice.Package.Id == item.PackageId && uPrice.UserPrice.UserId == request.UserId)?.UserPrice;
if (userPrice != null && userPrice.Id > 0)
{
userPrice.Status = 1;
userPrice.UserPrice = item.BuyPriceDiscount / 100m * package.Price;
userPrice.RefundDayPrice = item.RefundDayPriceDiscount / 100m * product.RefundDayPrice;
userPrice.Remark = schemaEntity.Name;
userPrice.UserPrice = Math.Max(userPrice.UserPrice, package.MinPrice);
userPrice.RefundDayPrice = Math.Max(userPrice.RefundDayPrice.Value, product.DayLimitPrice.Value);
await m_ProductUserPriceService.Update(userPrice);
}
else
{
userPrice = new ProductUserPriceEntity()
{
PackageId = item.PackageId,
ProductId = item.ProductId,
Status = 1,
Remark = schemaEntity.Name,
TenantId = 0,
UserId = request.UserId,
UserPrice = item.BuyPriceDiscount / 100m * package.Price,
RefundDayPrice = item.RefundDayPriceDiscount / 100m * product.RefundDayPrice,
};
userPrice.UserPrice = Math.Max(userPrice.UserPrice, package.MinPrice);
userPrice.RefundDayPrice = Math.Max(userPrice.RefundDayPrice.Value, product.DayLimitPrice.Value);
await m_ProductUserPriceService.Add(userPrice);
}
}
return Success(1);
}
}
}

View File

@@ -0,0 +1,25 @@
using Hncore.Infrastructure.DDD;
using System;
namespace Hncore.Pass.Vpn.Domain
{
public partial class ArticleEntity : EntityWithDelete<int>, ITenant
{
public int TenantId { get; set; }
public string Title { get; set; }
public ArticleCatalog CatalogId { get; set; } = ArticleCatalog.Top;
public string SubTitle { get; set; }
public string Thumb { get; set; }
public string Keyword { get; set; }
public string Content { get; set; }
public int AccessCount { get; set; }
public int Publish { get; set; }
public string Tag { get; set; }
public DateTime CreateTime { get; set; } = DateTime.Now;
public int LinkType { get; set; }
public int LinkId { get; set; }
}
}

View File

@@ -0,0 +1,132 @@
using Hncore.Infrastructure.EF;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
namespace Hncore.Pass.Vpn.Domain
{
public partial class CourseContext : DbContextBase
{
/// <summary>
/// 构造函数
/// </summary>
/// <param name="options">上下文实体</param>
/// <param name="httpContextAccessor">http请求上下文</param>
public CourseContext(DbContextOptions<CourseContext> options, IHttpContextAccessor httpContextAccessor) :
base(options, httpContextAccessor)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<ArticleEntity>(entity =>
{
entity.ToTable("article");
entity.HasKey(p => p.Id);
entity.Property(e => e.Id).ValueGeneratedOnAdd();
});
modelBuilder.Entity<ProductEntity>(entity =>
{
entity.ToTable("product");
entity.HasKey(p => p.Id);
entity.Property(e => e.Id).ValueGeneratedOnAdd();
});
modelBuilder.Entity<ProductAccountEntity>(entity =>
{
entity.ToTable("product_account");
entity.HasKey(p => p.Id);
entity.Property(e => e.Id).ValueGeneratedOnAdd();
entity.Ignore(e => e.RestTime);
entity.Ignore(e => e.RestDay);
});
modelBuilder.Entity<UserEntity>(entity =>
{
entity.ToTable("user");
entity.HasKey(p => p.Id);
entity.Property(e => e.Id).ValueGeneratedOnAdd();
});
modelBuilder.Entity<ProductPackageEntity>(entity =>
{
entity.ToTable("product_package");
entity.HasKey(p => p.Id);
entity.Property(e => e.Id).ValueGeneratedOnAdd();
});
modelBuilder.Entity<ProductOrderEntity>(entity =>
{
entity.ToTable("product_order");
entity.HasKey(p => p.Id);
entity.Property(e => e.Id).ValueGeneratedOnAdd();
});
modelBuilder.Entity<ProductOrderItemEntity>(entity =>
{
entity.ToTable("product_order_items");
entity.HasKey(p => p.Id);
entity.Property(e => e.Id).ValueGeneratedOnAdd();
});
modelBuilder.Entity<ProductUserPriceEntity>(entity =>
{
entity.ToTable("product_user_price");
entity.HasKey(p => p.Id);
entity.Property(e => e.Id).ValueGeneratedOnAdd();
});
modelBuilder.Entity<ProductPackageUnitEntity>(entity =>
{
entity.ToTable("product_package_unit");
entity.HasKey(p => p.Id);
entity.Property(e => e.Id).ValueGeneratedOnAdd();
});
modelBuilder.Entity<ProductAccountChargeEntity>(entity =>
{
entity.ToTable("product_account_recharge");
entity.HasKey(p => p.Id);
entity.Property(e => e.Id).ValueGeneratedOnAdd();
});
modelBuilder.Entity<ProductRouteEntity>(entity =>
{
entity.ToTable("product_route");
entity.HasKey(p => p.Id);
entity.Property(e => e.Id).ValueGeneratedOnAdd();
});
modelBuilder.Entity<WxAppUserEntity>(entity =>
{
entity.ToTable("wx_app_user");
entity.HasKey(p => p.Id);
entity.Property(e => e.Id).ValueGeneratedOnAdd();
});
modelBuilder.Entity<ProductPriceSchemeEntity>(entity =>
{
entity.ToTable("product_price_scheme");
entity.HasKey(p => p.Id);
entity.Property(e => e.Id).ValueGeneratedOnAdd();
});
modelBuilder.Entity<ProductPriceDiscountEntity>(entity =>
{
entity.ToTable("product_price_discount");
entity.HasKey(p => p.Id);
entity.Property(e => e.Id).ValueGeneratedOnAdd();
});
base.OnModelCreating(modelBuilder);
}
}
}

View File

@@ -0,0 +1,207 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
namespace Hncore.Pass.Vpn.Domain
{
public enum AccountType
{
[DisplayName("新开")]
New = 1,
[DisplayName("批量新开")]
News = 2,
[DisplayName("续费")]
AgainBuy = 3,
[DisplayName("批量续费")]
AgainBuys = 4,
[DisplayName("原系统认证")]
Origin =100,
[DisplayName("测试账号")]
Test = 200,
}
public enum OrderType
{
[DisplayName("新开")]
New = 1,
[DisplayName("批量新开")]
News = 2,
[DisplayName("续费")]
AgainBuy = 3,
[DisplayName("批量续费")]
AgainBuys = 4,
[DisplayName("退款")]
Refund = 5,
}
public enum ClientType
{
WxMp = 1,
WxMiniApp = 2,
Pc = 3,
}
public enum PayType
{
/// <summary>
/// 默认
/// </summary>
[Display(Name = "默认")]
None = 10,
/// <summary>
/// 余额
/// </summary>
[Display(Name = "余额")]
Amount = 10,
/// <summary>
/// 微信
/// </summary>
[Display(Name = "微信")]
Wechat = 70,
/// <summary>
/// 支付宝
/// </summary>
[Display(Name = "支付宝")]
Ali = 100,
}
public enum OrderStatus
{
[Display(Name = "默认")]
None = 0,
/// <summary>
/// 待支付
/// </summary>
[Display(Name = "待付款")]
NoPay = 10,
/// <summary>
/// 已支付
/// </summary>
[Display(Name = "已付款")]
PayOk = 20,
/// <summary>
/// 申请退款
/// </summary>
[Display(Name = "申请退款")]
RequestRefund = 30,
/// <summary>
/// 人工退款
/// </summary>
[Display(Name = "人工退款")]
UserRefundOver = 40,
/// <summary>
/// 自送退款
/// </summary>
[Display(Name = "自动退款")]
AutoRefundOver = 50,
/// <summary>
/// 订单超时关闭
/// </summary>
[Display(Name = "超时关闭")]
TimeOutClose = 80,
/// <summary>
/// 订单完成
/// </summary>
[Display(Name = "订单完成")]
Complete = 90,
}
public enum PackageType
{
[DisplayName("基本套餐")]
Base = 1,
[DisplayName("组合套餐")]
Group = 2
}
public enum ChargeOperationType
{
[DisplayName("新开")]
New = 1,
[DisplayName("批量新开")]
News = 2,
[DisplayName("续费")]
ReNew = 3,
[DisplayName("退款")]
Refund = 4,
}
public enum ChargeStatus
{
[DisplayName("成功")]
Ok = 1,
[DisplayName("失败")]
Faild = 2,
[DisplayName("关闭")]
Close = 3,
[DisplayName("超时")]
Outtime = 4,
}
public enum AccountChargeStatus
{
[DisplayName("正常")]
Normal = 1,
[DisplayName("异常")]
Exception = 2,
}
public enum AccountStatus
{
[DisplayName("正常")]
Normal = 1,
[DisplayName("退款")]
Refund = 2,
}
public enum ArticleCatalog
{
[DisplayName("聚IP头条")]
Top = 1,
[DisplayName("优惠活动")]
Activity = 2,
[DisplayName("常见问题")]
QA = 3,
[DisplayName("新手教程")]
Help = 4,
}
public enum PayChannel
{
/// <summary>
/// 微信H5
/// </summary>
[Display(Name = "微信H5")]
WxH5 = 10,
/// <summary>
/// 微信公众号
/// </summary>
[Display(Name = "微信公众号")]
WxMp = 20,
/// <summary>
/// 微信公众号
/// </summary>
[Display(Name = "微信Pc")]
WxPc = 30,
/// <summary>
/// 支付宝H5
/// </summary>
[Display(Name = "支付宝H5")]
AliH5 = 40,
/// <summary>
/// 支付宝
/// </summary>
[Display(Name = "支付宝Pc")]
AliPc = 50,
}
}

View File

@@ -0,0 +1,23 @@
using Hncore.Infrastructure.DDD;
using System;
using System.Collections.Generic;
namespace Hncore.Pass.Vpn.Domain
{
public partial class ProductAccountChargeEntity : EntityWithTime<int>
{
public int OrderId { get; set; }
public int? ProductId { get; set; }
public string ProductGroup { get; set; }
public int? PackageId { get; set; }
public string PackageOriginKey { get; set; }
public string Account { get; set; }
public int AccountType { get; set; }
public string Pwd { get; set; }
public int ConnectCount { get; set; } = 0;
public ChargeStatus Status { get; set; } = 0;
public int DayCount { get; set; } = 1;
public int TryTimes { get; set; } = 1;
public ChargeOperationType OperationType { get; set; } = ChargeOperationType.New;
}
}

View File

@@ -0,0 +1,53 @@
using Hncore.Infrastructure.DDD;
using System;
using System.Collections.Generic;
namespace Hncore.Pass.Vpn.Domain
{
public partial class ProductAccountEntity : EntityWithTime<int>, ITenant
{
public int TenantId { get; set; }
public int? UserId { get; set; }
public int? ProductId { get; set; }
public int? PackageId { get; set; }
public string UserCode { get; set; }
public string UserPhone { get; set; }
public string ProductName { get; set; }
public string PackageName { get; set; }
public int? AccountType { get; set; }
public string Account { get; set; }
public string Pwd { get; set; }
public int ConnectCount { get; set; } = 0;
public AccountStatus Status { get; set; } = AccountStatus.Normal;
public AccountChargeStatus? ChargeStatus { get; set; } = AccountChargeStatus.Normal;
public DateTime? StartTime { get; set; }
public DateTime? EndTime { get; set; }
public string Remark { get; set; }
public string RestTime
{
get
{
if (EndTime < DateTime.Now)
return "已过期";
var bTime = StartTime > DateTime.Now ? StartTime : DateTime.Now;
var time = (EndTime - bTime).Value;
return time.ToString(@"d\天hh\时mm\分");
}
}
public int RestDay
{
get
{
if (EndTime < DateTime.Now)
return 0;
var bTime = StartTime > DateTime.Now ? StartTime : DateTime.Now;
var time = (EndTime - bTime).Value;
return time.Days;
}
}
public string Raw { get; set; }
}
}

View File

@@ -0,0 +1,50 @@
using Hncore.Infrastructure.DDD;
using System;
using System.Collections.Generic;
namespace Hncore.Pass.Vpn.Domain
{
public partial class ProductEntity : EntityWithDelete<int>, ITenant
{
public int TenantId { get; set; }
public string Name { get; set; }
public string Image { get; set; }
public int Sort { get; set; } = 0;
public string Account { get; set; }
public string Pwd { get; set; }
public string BaseUrl { get; set; }
public int? Status { get; set; } = 0;
public string LoginUrl { get; set; }
public string LoginCodeUrl { get; set; }
public string RefrushTokenUrl { get; set; }
public string PcClientDownloadUrl { get; set; }
public string DroidDownloadUrl { get; set; }
public string IosDownloadUrl { get; set; }
public string SimulatorDownloadUrl { get; set; }
public string Content { get; set; }
public string Profile { get; set; }
public string GroupNO { get; set; }
public string Token { get; set; }
public int? AutoRefund { get; set; } = 0;
public decimal? RefundDayPrice { get; set; } = 0;
public decimal? DayLimitPrice { get; set; } = 0;
public int OnLine { get; set; } = 1;
public string L2TPPwd { get; set; } = "";
public string SSTPPort { get; set; } = "";
/// <summary>
/// 记录添加(创建)时间
/// </summary>
public virtual DateTime CreateTime { get; set; } = DateTime.Now;
/// <summary>
/// 记录最后更新时间
/// </summary>
public virtual DateTime UpdateTime { get; set; } = DateTime.Now;
}
}

View File

@@ -0,0 +1,55 @@
using Hncore.Infrastructure.DDD;
using System;
using System.Collections.Generic;
namespace Hncore.Pass.Vpn.Domain
{
public partial class ProductOrderEntity : EntityWithTime<int>, ITenant
{
public int TenantId { get; set; }
public int UserId { get; set; }
public string UserName { get; set; }
public int ProductId { get; set; }
public string ProductName { get; set; }
public int PackageId { get; set; }
public string PackageName { get; set; }
public int? CouponId { get; set; } = 0;
public decimal? CouponAmount { get; set; }
public string OriginKey { get; set; }
public string OrderName { get; set; }
public string OrderNo { get; set; }
public string TradeNo { get; set; }
public OrderStatus OrderState { get; set; }
public OrderType OrderType { get; set; }
public PayType PayType { get; set; }
public PayChannel PayChannel { get; set; } = PayChannel.WxPc;
public int PayState { get; set; }
public int ConnectCount { get; set; }
public decimal OrderAmount { get; set; }
public decimal PaymentAmount { get; set; }
public decimal? AccountPayAmount { get; set; } = 0;
public decimal? OtherPayAmount { get; set; } = 0;
public decimal? DayPrice { get; set; } = 0;
public int DayCount { get; set; } = 1;
public int ClientType { get; set; }
public int ChannelType { get; set; }
public string Channel { get; set; }
public int AccountCount { get; set; } = 1;
public string Remark { get; set; }
public string Accounts { get; set; }
public string AccountPwd { get; set; }
public int RefundCount { get; set; }
public decimal RefundAmount { get; set; }
public string RefundRestTime { get; set; }
public DateTime? StartTime { get; set; }
public DateTime? EndTime { get; set; }
public int? IsAutoRefund { get; set; } = 0;
public decimal? BackAmount { get; set; } = 0;
}
}

View File

@@ -0,0 +1,34 @@
using Hncore.Infrastructure.DDD;
using System;
using System.Collections.Generic;
namespace Hncore.Pass.Vpn.Domain
{
public partial class ProductOrderItemEntity : EntityWithTime<int>, ITenant
{
public int TenantId { get; set; }
public int OrderId { get; set; }
public int UserId { get; set; }
public string UserName { get; set; }
public int ProductId { get; set; }
public string ProductName { get; set; }
public int PackageId { get; set; }
public string PackageName { get; set; }
public string Account { get; set; }
public string AccountPwd { get; set; }
public int ConnectCount { get; set; }
public int AccountType { get; set; }
public int StartNum { get; set; }
public int EndNum { get; set; }
public string OrderNo { get; set; }
public OrderStatus OrderState { get; set; }
public OrderType OrderType { get; set; }
public PayType PayType { get; set; }
public int PayState { get; set; }
public decimal Price { get; set; }
public decimal DayPrice { get; set; }
public int DayCount { get; set; }
public string Remark { get; set; }
}
}

View File

@@ -0,0 +1,27 @@
using Hncore.Infrastructure.DDD;
using System;
using System.Collections.Generic;
namespace Hncore.Pass.Vpn.Domain
{
public partial class ProductPackageEntity : EntityWithDelete<int>, ITenant
{
public int TenantId { get; set; }
public int ProductId { get; set; }
public PackageType PackageType { get; set; } = PackageType.Base;
public string Name { get; set; }
public string Title { get; set; }
public string Image { get; set; }
public int Status { get; set; } = 0;
public string Profile { get; set; }
public decimal Price { get; set; }
public decimal LinePrice { get; set; }
public decimal DayPrice { get; set; }
public decimal MinPrice { get; set; }
public int DayCount { get; set; } = 1;
public string OriginKey { get; set; }
public string OriginName { get; set; }
public int? IsTest { get; set; } = 0;
}
}

View File

@@ -0,0 +1,13 @@
using Hncore.Infrastructure.DDD;
using System;
using System.Collections.Generic;
namespace Hncore.Pass.Vpn.Domain
{
public partial class ProductPackageUnitEntity : Entity<int>
{
public int PackageId { get; set; }
public int BasePackageId { get; set; }
public int Count { get; set; }
}
}

View File

@@ -0,0 +1,19 @@
using Hncore.Infrastructure.DDD;
using System;
using System.Collections.Generic;
namespace Hncore.Pass.Vpn.Domain
{
public partial class ProductPriceDiscountEntity : EntityWithDelete<int>
{
public int SchemeId { get; set; }
public int TenantId { get; set; }
public int ProductId { get; set; }
public int PackageId { get; set; }
public int Status { get; set; } = 0;
public int BuyPriceDiscount { get; set; } = 0;
public int RefundDayPriceDiscount { get; set; } = 0;
public string Remark { get; set; }
}
}

View File

@@ -0,0 +1,13 @@
using Hncore.Infrastructure.DDD;
using System;
using System.Collections.Generic;
namespace Hncore.Pass.Vpn.Domain
{
public partial class ProductPriceSchemeEntity : EntityWithTime<int>
{
public string Name { get; set; }
public string Remark { get; set; }
}
}

View File

@@ -0,0 +1,26 @@
using Hncore.Infrastructure.DDD;
using System;
using System.Collections.Generic;
namespace Hncore.Pass.Vpn.Domain
{
public partial class ProductRouteEntity : EntityWithDelete<int>
{
public int? ProductId { get; set; }
public string ProductName { get; set; }
public string Province { get; set; }
public string City { get; set; }
public int Sort { get; set; } = 0;
public string Name { get; set; }
public string ServerUrl { get; set; }
public string Status { get; set; }
public string LineType { get; set; }
public string BandWidth { get; set; }
public string IpRemark { get; set; }
public string Remark { get; set; }
public int OnLine { get; set; } = 1;
public string KeyWord { get; set; }
}
}

View File

@@ -0,0 +1,19 @@
using Hncore.Infrastructure.DDD;
using System;
using System.Collections.Generic;
namespace Hncore.Pass.Vpn.Domain
{
public partial class ProductUserPriceEntity : EntityWithDelete<int>, ITenant
{
public int TenantId { get; set; }
public int ProductId { get; set; }
public int PackageId { get; set; }
public int UserId { get; set; }
public int Status { get; set; } = 0;
public decimal UserPrice { get; set; }
public decimal? RefundDayPrice { get; set; } = 0;
public string Remark { get; set; }
}
}

View File

@@ -0,0 +1,82 @@
using Hncore.Infrastructure.DDD;
using System;
namespace Hncore.Pass.Vpn.Domain
{
public partial class UserEntity : EntityWithTime<int>, ITenant
{
/// <summary>
/// ID
/// <summary>
public int TenantId { get; set; }
/// <summary>
/// 管理员登录名[16
/// </summary>
public string LoginCode { get; set; }
/// <summary>
/// 登录密码[20]
/// </summary>
public string Password { get; set; }
/// <summary>
/// 微信昵称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 微信头像
/// </summary>
public string Phone { get; set; }
/// <summary>
/// 注册来源
/// </summary>
public string Profile { get; set; }
/// <summary>
/// 状态
/// </summary>
public int Enabled { get; set; } = 1;
/// <summary>
/// 头像地址[30
/// </summary>
public string PhotoUrl { get; set; }
/// <summary>
/// 是否主管理员权限
/// </summary>
public DateTime? LastLoginDate { get; set; } = DateTime.Now;
public int Sex { get; set; }
//1:管理员添加 2自己注册 3来自淘宝
public int CreateType { get; set; }
public int ProductAccountCount { get; set; }
public int ExpiredProductAccountCount { get; set; }
public decimal RestAmount { get; set; }
public decimal ConsumeAmount { get; set; }
public string Remark { get; set; }
public string Wx { get; set; }
public string QQ { get; set; }
public string Email { get; set; }
public string TaoBao { get; set; }
public string WangWang { get; set; }
public int? TestCountLimit { get; set; } = 0;
public int? UseTestCount { get; set; } = 0;
public int? ManagerId { get; set; } = 0;
public string ManagerName { get; set; }
}
}

View File

@@ -0,0 +1,28 @@
using Hncore.Infrastructure.DDD;
using System;
namespace Hncore.Pass.Vpn.Domain
{
public partial class WxAppEntity : EntityWithDelete<int>, ITenant
{
public int TenantId { get; set; }
public int StoreId { get; set; }
public string OpenAppId { get; set; }
public string Appid { get; set; }
public int AppType { get; set; }
public string HeadImg { get; set; }
public string NickName { get; set; }
public string UserName { get; set; }
public string PrincipalName { get; set; }
public string Bussinessinfo { get; set; }
public string Createtime { get; set; }
public int AuthorizerState { get; set; }
public string RefreshToken { get; set; }
public int ExpiresIn { get; set; }
public DateTime UpdateTime { get; set; } = DateTime.Now;
}
}

View File

@@ -0,0 +1,31 @@
using Hncore.Infrastructure.DDD;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Hncore.Pass.Vpn.Domain
{
public partial class WxAppUserEntity : EntityWithDelete<int>, ITenant
{
public int TenantId { get; set; }
public int StoreId { get; set; }
public string Appid { get; set; }
public int AppType { get; set; }
public int UserId { get; set; }
public string Unionid { get; set; }
public string Openid { get; set; }
public string NickName { get; set; }
public string UserName { get; set; }
public string HeadImgUrl { get; set; }
public int Sex { get; set; }
public string City { get; set; }
public string Country { get; set; }
public int IsSubscribe { get; set; }
public int InvateUserId { get; set; }
public DateTime Createtime { get; set; } = DateTime.Now;
public DateTime UpdateTime{ get; set; } = DateTime.Now;
}
}

View File

@@ -0,0 +1,37 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<NoWarn>1701;1702;1998</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Aliyun.OSS.SDK.NetCore" Version="2.9.1" />
<PackageReference Include="Microsoft.AspNetCore.App">
<PrivateAssets Condition="'%(PackageReference.Version)' == ''">all</PrivateAssets>
<Publish Condition="'%(PackageReference.Version)' == ''">true</Publish>
</PackageReference>
<PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.2.0" PrivateAssets="All" />
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="2.2.0" />
</ItemGroup>
<ItemGroup>
<Folder Include="Extension\" />
<Folder Include="Properties\" />
<Folder Include="Request\Article\" />
<Folder Include="Utils\" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Infrastructure\Hncore.Infrastructure\Hncore.Infrastructure.csproj" />
<ProjectReference Include="..\..\Infrastructure\ServiceClient\PaymentCenterClient\PaymentCenterClient.csproj" />
<ProjectReference Include="..\..\Infrastructure\WxApi\WxApi.csproj" />
<ProjectReference Include="..\Hncore.Pass.BaseInfo\Hncore.Pass.BaseInfo.csproj" />
<ProjectReference Include="..\Hncore.Pass.Sells\Hncore.Pass.Sells.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,42 @@
using Hncore.Infrastructure.Common;
using Hncore.Pass.Vpn.Service;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Threading.Tasks;
using Hncore.Infrastructure.Extension;
namespace Hncore.Pass.Vpn.Job
{
/// <summary>
/// 充值失败尝试job
/// </summary>
public class ChargeTryJob
{
public static void Start(IServiceProvider serviceProvider)
{
Task.Run(async () => { await Execute(serviceProvider); });
}
private static async Task Execute(IServiceProvider serviceProvider)
{
while (true)
{
LogHelper.Trace("开始处理订单");
try
{
using (var scope = serviceProvider.CreateScope())
{
var agentService = scope.ServiceProvider.GetService<AgentService>();
await agentService.FaildTry();
}
}
catch (Exception e)
{
LogHelper.Error("处理订单失败", e);
break;
}
await Task.Delay(10 * 1000);
}
}
}
}

View File

@@ -0,0 +1,118 @@
using Hncore.Infrastructure.Common;
using Hncore.Pass.Vpn.Service;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Threading.Tasks;
using Hncore.Infrastructure.Extension;
using System.Linq;
using Hncore.Wx.Open;
using Hncore.Infrastructure.SMS;
using Hncore.Pass.BaseInfo.Models;
using System.Collections.Generic;
using Hncore.Pass.Vpn.Domain;
namespace Hncore.Pass.Vpn.Job
{
/// <summary>
/// 过期提醒job
/// </summary>
public class ExpireTipJob
{
public static void Start(IServiceProvider serviceProvider)
{
Task.Run(async () => { await Execute(serviceProvider); });
}
private static async Task Execute(IServiceProvider serviceProvider)
{
var doing = false;
while (true)
{
while (true)
{
if (doing||!(DateTime.Now.Hour == 15 && DateTime.Now.Minute < 5))
{
break;
}
LogHelper.Trace("开始过期提醒");
doing = true;
try
{
using (var scope = serviceProvider.CreateScope())
{
var accountService = scope.ServiceProvider.GetService<ProductAccountService>();
var wxUserService = scope.ServiceProvider.GetService<WxAppUserService>();
var userService = scope.ServiceProvider.GetService<UserService>();
var expireAccounts_1 = await accountService.GetExpireingAccounts(-1);
var expireAccounts0 = await accountService.GetExpireingAccounts(0);
var expireAccounts1 = await accountService.GetExpireingAccounts(1);
await Tip(expireAccounts_1, wxUserService, userService, "已过期1天");
await Tip(expireAccounts0, wxUserService, userService, "今天过期");
await Tip(expireAccounts1, wxUserService, userService, "明天过期");
}
}
catch (Exception e)
{
LogHelper.Error("处理过期提醒失败", e);
break;
}
finally
{
doing = false;
}
await Task.Delay(6*60 * 1000);
}
await Task.Delay(60 * 1000);
}
}
public static async Task Tip(List<ProductAccountEntity> accounts, WxAppUserService wxUserService, UserService userService,string tip="")
{
var userIds = accounts.Select(m => m.UserId.Value).Distinct().ToList();
var wxUsers = await wxUserService.GetWxUsers(userIds);
var userInfos = await userService.GetByIds(userIds);
var tipUsers = new Dictionary<int, bool>();
foreach (var account in accounts)
{
if (tipUsers.ContainsKey(account.UserId.Value)||account.PackageName.IndexOf("测试")!=-1 || account.PackageName.IndexOf("天卡") != -1)
{
continue;
}
var userInfo = userInfos.FirstOrDefault(m => m.Id == account.UserId);
if (wxUsers != null && wxUsers.Count > 0)
{
var wxUser = wxUsers.FirstOrDefault(m => m.UserId == account.UserId);
if (wxUser != null && wxUser.Openid.Has())
{
var msg = new TemplateMPModel();
msg.first = new TemplateDataItem($"尊敬的用户您好,你的账户{tip}");
msg.Url = "www.juip.com";
msg.template_id = "ltm4OfRDoxgdRG4EC8NMzX-NrkfHUz8aGz33TXSbP44";
msg.Items.Add(new TemplateDataItem("请登录juip.com查看具体的到期账号"));
msg.Items.Add(new TemplateDataItem(userInfo.Phone));
msg.Items.Add(new TemplateDataItem("动态IP账号服务"));
msg.Items.Add(new TemplateDataItem(account.EndTime.Value.ToString("yyyy-MM-dd hh:mm:ss")));
msg.remark = new TemplateDataItem("请登录官网juip.com点击个人中心查看需要续费的动态ip账号");
await TemplateApi.SendTemplateMessageAsync(wxUser.Appid, wxUser.Openid, Wx.Open.Enums.ChannelType.MP, msg);
}
}
if (userInfo != null && RegexPattern.IsMobile(userInfo.Phone))
{
var ret = AliSmsService.Send("SMS_193505090", new { date = account.EndTime.Value.ToString("yyyy-MM-dd hh:mm:ss") }, "聚IP商城", userInfo.Phone);
}
tipUsers[account.UserId.Value] = true;
}
}
}
}

View File

@@ -0,0 +1,47 @@
using Hncore.Infrastructure.Common;
using Hncore.Pass.Vpn.Service;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Threading.Tasks;
using Hncore.Infrastructure.Extension;
namespace Hncore.Pass.Vpn.Job
{
/// <summary>
/// 支付成功后开通账号的job
/// </summary>
public class OrderAccountJob
{
public static void Start(IServiceProvider serviceProvider)
{
Task.Run(async () => { await Execute(serviceProvider); });
}
private static async Task Execute(IServiceProvider serviceProvider)
{
while (true) // 每轮间隔10分钟
{
LogHelper.Trace("开始处理订单");
try
{
using (var scope = serviceProvider.CreateScope())
{
var orderService = scope.ServiceProvider.GetService<ProductOrderService>();
var orders = await orderService.GetOrders(Domain.OrderStatus.PayOk);
await orders.ForEachAsync(async m =>
{
await orderService.ProcessOrderAccount(m);
});
}
}
catch (Exception e)
{
LogHelper.Error("处理订单失败", e);
}
await Task.Delay(10 * 1000);
}
}
}
}

View File

@@ -0,0 +1,67 @@
using Hncore.Infrastructure.Common;
using Hncore.Pass.BaseInfo.Models;
using Hncore.Pass.BaseInfo.Request.User;
using Hncore.Pass.Vpn.Domain;
using Hncore.Pass.Vpn.Request.Product;
using Hncore.Pass.Vpn.Service;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Threading.Tasks;
namespace Hncore.Pass.Vpn.Job
{
/// <summary>
/// 超时支付的job
/// </summary>
public class OrderOutTimePayJob
{
public static void Start(IServiceProvider serviceProvider)
{
Task.Run(async () => { await Execute(serviceProvider); });
}
private static async Task Execute(IServiceProvider serviceProvider)
{
while (true) // 每轮间隔10分钟
{
LogHelper.Trace("开始处理超时支付");
try
{
using (var scope = serviceProvider.CreateScope())
{
var orderService = scope.ServiceProvider.GetService<ProductOrderService>();
var userService = scope.ServiceProvider.GetService<Hncore.Pass.BaseInfo.Service.UserService>();
var orders = await orderService.GetLimitTimeOrders(Domain.OrderStatus.NoPay, 30);
orders.ForEach(async order =>
{
order.OrderState = Domain.OrderStatus.TimeOutClose;
await orderService.Update(order);
//返还用户余额支付部分
if (order.AccountPayAmount > 0)
{
var amountInfo = new UpdateAmountRequest()
{
Amount = order.AccountPayAmount.Value,
OpAmountType = ScoreType.AccountRefund,
UserId = order.UserId,
AttchInfo = order.OrderNo,
OperateUserName = order.UserName,
};
await userService.UpdateAmount(amountInfo);
}
});
}
}
catch (Exception e)
{
LogHelper.Error("处理超时支付失败", e);
break;
}
await Task.Delay(60 * 1000);
}
}
}
}

View File

@@ -0,0 +1,42 @@
using Hncore.Infrastructure.Common;
using Hncore.Pass.Vpn.Service;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Threading.Tasks;
namespace Hncore.Pass.Vpn.Job
{
/// <summary>
/// 超时支付的job
/// </summary>
public class RefrushStatusJob
{
public static void Start(IServiceProvider serviceProvider)
{
Task.Run(async () => { await Execute(serviceProvider); });
}
private static async Task Execute(IServiceProvider serviceProvider)
{
while (true)
{
LogHelper.Trace("刷新代理服务器状态");
try
{
using (var scope = serviceProvider.CreateScope())
{
var agentService = scope.ServiceProvider.GetService<AgentService>();
await agentService.RefrushAllStatus();
}
}
catch (Exception e)
{
LogHelper.Error("刷新代理服务器状态失败", e);
}
await Task.Delay(30 * 1000);
}
}
}
}

View File

@@ -0,0 +1,76 @@
using Hncore.Infrastructure.Common;
using Hncore.Pass.Vpn.Service;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Threading.Tasks;
using Hncore.Infrastructure.Extension;
using System.Linq;
using Hncore.Wx.Open;
using Hncore.Infrastructure.SMS;
using Hncore.Pass.BaseInfo.Models;
using System.Collections.Generic;
using Hncore.Pass.Vpn.Domain;
using Hncore.Infrastructure.WebApi;
namespace Hncore.Pass.Vpn.Job
{
/// <summary>
/// 删除不存在的账号
/// </summary>
public class RemoveAccountJob
{
public static void Start(IServiceProvider serviceProvider)
{
Task.Run(async () => { await Execute(serviceProvider); });
}
private static async Task Execute(IServiceProvider serviceProvider)
{
var doing = false;
while (true)
{
while (true)
{
if (doing||!(DateTime.Now.Hour == 23 && DateTime.Now.Minute < 5))
{
break;
}
LogHelper.Trace("开始删除过期账号");
doing = true;
try
{
using (var scope = serviceProvider.CreateScope())
{
var accountService = scope.ServiceProvider.GetService<ProductAccountService>();
var agentService = scope.ServiceProvider.GetService<AgentService>();
var removeAccounts = new List<ProductAccountEntity>();
var accounts = await accountService.Query(true).ToListAsync();
foreach (var item in accounts)
{
var ret = await agentService.GetOriginAccountInfo(item.ProductId.Value, item.Account, item.Pwd);
if (ret.Code != ResultCode.C_SUCCESS && ret.Code != ResultCode.C_NOT_EXISTS_ERROR)
{
removeAccounts.Add(item);
}
}
await accountService.Deletes(removeAccounts);
}
}
catch (Exception e)
{
LogHelper.Error("账号删除失败", e);
break;
}
finally
{
doing = false;
}
await Task.Delay(6*60 * 1000);
}
await Task.Delay(60 * 1000);
}
}
}
}

View File

@@ -0,0 +1,14 @@
using Hncore.Infrastructure.Extension;
using Hncore.Pass.Vpn.Domain;
using Hncore.Pass.Vpn.Response.Product;
namespace Hncore.Pass.Vpn.Map
{
public class MapConfig
{
public static void Config()
{
TinyMapperExtension.Binds<ProductResponse, ProductEntity>();
}
}
}

View File

@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Hncore.Pass.Vpn.Model
{
public class CatalogUsedModel
{
public bool Used { get; set; }
public List<int> CatalogIds { get; set; }
}
}

View File

@@ -0,0 +1,21 @@
using Hncore.Infrastructure.Extension;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Hncore.Pass.Vpn.Model
{
public class ManagerSellStatisticModel
{
public string RealName { get; set; }
public string Name => this.RealName.NotHas() ? "无" : this.RealName;
public long? UserCount { get; set; } = 0;
public long? NewUserCount { get; set; } = 0;
public decimal? Amount { get; set; } = 0;
}
}

View File

@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Hncore.Pass.Vpn.Model
{
public class OrderStatisticModel
{
public string Channel { get; set; }
public string ProductName { get; set; }
public string PackageName { get; set; }
public int NewBuyCount { get; set; }
public decimal NewBuyAmount { get; set; }
public int AgainBuyCount { get; set; }
public decimal AgainBuyAmount { get; set; }
public int RefundCount { get; set; }
public decimal RefundAmount { get; set; }
public decimal SellAmount => NewBuyAmount + AgainBuyAmount;
}
}

View File

@@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Hncore.Pass.Vpn.Model
{
public class OriginAccountModel
{
public string Id { get; set; }
public string User { get; set; }
public string Account { get; set; }
public string Pwd { get; set; }
public string AccountType { get; set; }
public string Package { get; set; }
public string ConnectCount { get; set; }
public string RegistTime { get; set; }
public string EndTime { get; set; }
public string RestTime { get; set; }
public string Amount { get; set; }
public string IsActive { get; set; }
public string Remark { get; set; }
public DateTime RealEndTime { get; set; }
public int OnLine { get; set; } = 0;
public string LoginTime { get; set; }
public string LoginServer { get; set; }
}
}

View File

@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Hncore.Pass.Vpn.Model
{
public class OriginAccountOnlineModel
{
public string Id { get; set; }
public string Account { get; set; }
public string LoginTime { get; set; }
public string OnlineTime { get; set; }
public string ServerIP { get; set; }
public string LoginIP { get; set; }
public string UpStream { get; set; }
public string DownStream { get; set; }
public int OnLine { get; set; } = 0;
}
}

View File

@@ -0,0 +1,12 @@
using Hncore.Pass.Vpn.Domain;
using System.Collections.Generic;
namespace Hncore.Pass.Vpn.Model
{
public class PackageUnitItemModel
{
public int Count { get; set; }
public ProductPackageEntity Package { get; set; }
}
}

View File

@@ -0,0 +1,35 @@
using Hncore.Pass.Vpn.Domain;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Hncore.Pass.Vpn.Model
{
public class UserConsumeStatisticsModel
{
public string UserName { get; set; }
public UserEntity UserInfo {get;set;}
public DateTime CreateTime { get; set; }
public string TotalAmount { get; set; }
public string DayAmount { get; set; }
public decimal PrevMonthAmount { get; set; }
public decimal MonthAmount { get; set; }
public decimal AddAmount => MonthAmount - PrevMonthAmount;
public string YearAmount { get; set; }
public int TotalAccountCount=> ExpirdAccountCount + UsingAccountCount;
public int UsingAccountCount { get; set; } = 0;
public int ExpirdAccountCount { get; set; } = 0;
public int TestAccountCount { get; set; } = 0;
}
}

View File

@@ -0,0 +1,17 @@
using Hncore.Pass.BaseInfo.Models;
using Hncore.Pass.Vpn.Domain;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Hncore.Pass.Vpn.Model
{
public class UserDataMode
{
public string UserName { get; set; }
public string Value { get; set; }
}
}

View File

@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
namespace Hncore.Pass.Vpn
{
public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>();
}
}

View File

@@ -0,0 +1,19 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:50978/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

View File

@@ -0,0 +1,25 @@
using Hncore.Infrastructure.Tree;
using Hncore.Infrastructure.WebApi;
using System;
using System.Collections.Generic;
namespace Hncore.Pass.Vpn.Request.Product
{
public class AccountPageRequest : PageRequestBase
{
public int UserId { get; set; }
//-1:全部 0 :过期
public int ExpirdDay { get; set; }
public int? ProductId { get; set; }
public int? PackageId { get; set; }
public List<int?> AccountTypes { get; set; }
public DateTime? BTime { get; set; }
public DateTime? ETime { get; set; }
}
}

View File

@@ -0,0 +1,19 @@
using Hncore.Infrastructure.Tree;
using System.Collections.Generic;
namespace Hncore.Pass.Vpn.Request.Product
{
public class AgentLoginRequest
{
public int ProductId { get; set; }
public string Code { get; set; }
public string Key { get; set; }
public string Account { get; set; }
public string Pwd { get; set; }
}
}

View File

@@ -0,0 +1,13 @@
using Hncore.Infrastructure.Tree;
using System.Collections.Generic;
namespace Hncore.Pass.Vpn.Request.Product
{
public class BindUserRequest
{
public List<int> AccountIds { get; set; }
public int UserId { get; set; }
}
}

View File

@@ -0,0 +1,10 @@
using Hncore.Infrastructure.WebApi;
namespace Hncore.Pass.Vpn.Request.Product
{
public class CouponOrderQueryRequest : PageRequestBase
{
public int? CouponId { get; set; }
}
}

View File

@@ -0,0 +1,38 @@
using Hncore.Pass.Vpn.Domain;
using System.Collections.Generic;
namespace Hncore.Pass.Vpn.Request.Product
{
public class CreateOrderRequest
{
public OrderType OrderType { get; set; }
public int PackageId { get; set; }
//是否使用账户的钱
public int UseAccountAmount { get; set; } = 0;
public string Account { get; set; }
public string Pwd { get; set; }
//最小后缀数
public int MinPostfix { get; set; }
//最大后缀数
public int MaxPostfix { get; set; }
//同时在线连接数
public int ConnectCount { get; set; }
//使用的优惠券的Id
public int CouponId { get; set; }
public PayType OPayType { get; set; }
public PayChannel PayChannel { get; set; }
public string Channel { get; set; }
public string Remark { get; set; }
}
}

View File

@@ -0,0 +1,18 @@
using Hncore.Pass.Vpn.Domain;
using System.Collections.Generic;
namespace Hncore.Pass.Vpn.Request.Product
{
public class CreateTestAccountRequest
{
public int ProductId { get; set; }
public int PackageId { get; set; }
public string Account { get; set; }
public string Pwd { get; set; }
public string Remark { get; set; }
}
}

View File

@@ -0,0 +1,21 @@
using Hncore.Infrastructure.WebApi;
using Hncore.Pass.Vpn.Domain;
using System;
using System.Collections.Generic;
namespace Hncore.Pass.Vpn.Request.Product
{
public class OrderQueryRequest: PageRequestBase
{
public List<int> OrderTypes { get; set; }
public DateTime? BTime { get; set; }
public DateTime? ETime { get; set; }
public int? ProductId { get; set; }
public int? PackageId { get; set; }
}
}

View File

@@ -0,0 +1,16 @@
using Hncore.Infrastructure.WebApi;
using Hncore.Pass.Vpn.Domain;
using System.Collections.Generic;
namespace Hncore.Pass.Vpn.Request.Product
{
public class PutPriceDiscountRequest
{
public int ProductId { get; set; }
public int PackageId { get; set; }
public int SchemeId { get; set; }
public int BuyPriceDiscount { get; set; }
public int RefundDayPriceDiscount { get; set; }
public string Remark { get; set; }
}
}

View File

@@ -0,0 +1,16 @@
using Hncore.Infrastructure.WebApi;
using Hncore.Pass.Vpn.Domain;
using System.Collections.Generic;
namespace Hncore.Pass.Vpn.Request.Product
{
public class PutUserPriceRequest
{
public int ProductId { get; set; }
public int PackageId { get; set; }
public int UserId { get; set; }
public decimal UserPrice { get; set; }
public decimal RefundDayPrice { get; set; }
public string Remark { get; set; }
}
}

View File

@@ -0,0 +1,19 @@
using Hncore.Infrastructure.WebApi;
using Hncore.Pass.Vpn.Domain;
using System;
using System.Collections.Generic;
namespace Hncore.Pass.Vpn.Request.Product
{
public class RefundOrderQueryRequest: PageRequestBase
{
public List<int> OrderTypes { get; set; }
public DateTime? BTime { get; set; }
public DateTime? ETime { get; set; }
public List<int> ProductIds { get; set; }
}
}

View File

@@ -0,0 +1,14 @@
using Hncore.Pass.Vpn.Domain;
using System.Collections.Generic;
namespace Hncore.Pass.Vpn.Request.Product
{
public class RefundProcessRequest
{
public int Id { get; set;}
public decimal BackAmount { get; set; }
public string Remark { get; set; }
}
}

View File

@@ -0,0 +1,12 @@
using Hncore.Infrastructure.Tree;
using Hncore.Infrastructure.WebApi;
using System.Collections.Generic;
namespace Hncore.Pass.Vpn.Request.Product
{
public class RoutePageRequest : PageRequestBase
{
public int? ProductId { get; set; }
}
}

View File

@@ -0,0 +1,18 @@
using Hncore.Infrastructure.WebApi;
using Hncore.Pass.Vpn.Domain;
using System;
using System.Collections.Generic;
namespace Hncore.Pass.Vpn.Request.Product
{
public class SellerOrderQueryRequest : PageRequestBase
{
public string UserName { get; set; }
public DateTime? BTime { get; set; }
public DateTime? ETime { get; set; }
public int? ProductId { get; set; }
}
}

View File

@@ -0,0 +1,10 @@
namespace Hncore.Pass.Vpn.Request.Product
{
public class SetUserDiscountRequest
{
public int UserId { get; set; }
public int SchemeId { get; set; }
}
}

View File

@@ -0,0 +1,8 @@
namespace HHncore.Pass.Vpn.Request.Product
{
public class UpdateAccountPwdRequest
{
public int Id { get; set; }
public string Pwd { get; set; }
}
}

View File

@@ -0,0 +1,19 @@
using Hncore.Infrastructure.WebApi;
using Hncore.Pass.Vpn.Domain;
using System;
using System.Collections.Generic;
namespace Hncore.Pass.Vpn.Request.Product
{
public class UserConsumeRequest : PageRequestBase
{
public DateTime? bTime1 { get; set; }
public DateTime? eTime1 { get; set; }
public DateTime? bTime2 { get; set; }
public DateTime? eTime2 { get; set; }
public string SortLable { get; set; }
public int SortOrder { get; set; }
public string Profile { get; set; }
}
}

View File

@@ -0,0 +1,7 @@
namespace Hncore.Pass.Oss.Request
{
public class UploadImageBase64Request
{
public string Base64 { get; set; }
}
}

View File

@@ -0,0 +1,8 @@
namespace Hncore.Pass.Vpn.Response.Product
{
public class CodeResponse
{
public string CodeImage { get; set; }
public string Key { get; set; }
}
}

View File

@@ -0,0 +1,15 @@
using Hncore.Pass.Vpn.Domain;
namespace Hncore.Pass.Vpn.Response.Product
{
public class PackageInfoResponse
{
public ProductPackageEntity Package { get; set; }
public ProductUserPriceEntity UserPrice { get; set; }
public ProductEntity Product { get; set; }
public int RestTimes { get; set; }
}
}

View File

@@ -0,0 +1,22 @@
using Hncore.Infrastructure.Tree;
using Hncore.Pass.Vpn.Domain;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Hncore.Pass.Vpn.Response.Product
{
public class PackageUserPriceResponse
{
public ProductPackageEntity Package { get; set; }
public ProductUserPriceEntity UserPrice { get; set; }
}
public class ProductWithPackageUserPriceResponse
{
public ProductResponse Product { get; set; }
public List<PackageUserPriceResponse> PackageUserPrices { get; set; }
}
}

View File

@@ -0,0 +1,30 @@
using Hncore.Infrastructure.Tree;
using Hncore.Pass.Vpn.Domain;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Hncore.Infrastructure.Extension;
namespace Hncore.Pass.Vpn.Response.Product
{
public class ProductResponse
{
public int Id { get; set; }
public string Name { get; set; }
public string Image { get; set; }
public int Sort { get; set; }
public string Content { get; set; }
public string Profile { get; set; }
public int OnLine { get; set; } = 1;
public List<string> ContentLine=> this.Profile.Has()?this.Profile.Split('\n').ToList():new List<string>();
}
public class ProductWithPackageResponse
{
public ProductResponse Product { get; set; }
public List<ProductPackageEntity> Packages { get; set; }
}
}

View File

@@ -0,0 +1,21 @@
using Hncore.Infrastructure.Tree;
using Hncore.Pass.Vpn.Domain;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Hncore.Infrastructure.Extension;
namespace Hncore.Pass.Vpn.Response.Product
{
public class PackagePriceDiscount
{
public ProductPackageEntity Package { get; set; }
public ProductPriceDiscountEntity PriceDiscount { get; set; }
}
public class ProductWithPriceDiscountResponse
{
public ProductResponse Product { get; set; }
public List<PackagePriceDiscount> PackageDiscounts { get; set; }
}
}

View File

@@ -0,0 +1,537 @@
using AngleSharp.Html.Parser;
using Hncore.Infrastructure.Common;
using Hncore.Infrastructure.Extension;
using Hncore.Infrastructure.Serializer;
using Hncore.Infrastructure.WebApi;
using Hncore.Pass.Vpn.Model;
using Hncore.Pass.Vpn.Request.Product;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
namespace Hncore.Pass.Vpn.Service
{
public class AgentClient1Service:AgentClientBaseService
{
string LoginUrl { get; set; } = "main/agentLogin.html";
string LoginCodeUrl { get; set; } = "main/imgcode.html";
string RefrushTokenUrl { get; set; } = "agent/index.html";
string SingleAddUrl { get; set; } = "agent/memberSingleAdd.html";
string SingleReAddUrl { get; set; } = "agent/memberRenew.html";
string MuiltAddUrl { get; set; } = "agent/memberMuiltAdd.html";
string RefundUrl { get; set; } = "agent/memberRefundAct.html ";
string UpdateUrl = "agent/memberUpdate/id/";//agent/memberUpdate/id/1155709.html
string OnlineUrl { get; set; } = "agent/radiusOnline.html?search=1&username=";
string KIllUrl { get; set; } = "agent/disConnect2/radacctid/{0}.html";
string searchAccountUrl = "agent/memberList/type/1.html?search=1&username=";
string searchTestAccountUrl = "agent/memberList/type/0.html?search=1&username=";
string DeleteUrl { get; set; } = "agent/memberDel/id/";//1160862.html";
IHttpClientFactory m_HttpClientFactory;
public AgentClient1Service(IHttpClientFactory httpClientFactory):base(httpClientFactory)
{
m_HttpClientFactory = httpClientFactory;
}
public override async Task<int> RefrushStatus()
{
int status = 0;
if (this.Token.Has())
{
var client = CreateHttpClient();
if (this.RefrushTokenUrl.Has())
{
// client.DefaultRequestHeaders.Add("Cookie", this.Token);
var getResp = await client.GetAsync(this.RefrushTokenUrl);
var content = await getResp.Content.ReadAsStringAsync();
if (getResp.StatusCode == HttpStatusCode.OK && content.IndexOf("agentLogin.html") == -1)
{
status = 1;
}
else
{
Debug.WriteLine("离线");
Debug.WriteLine(content);
}
}
}
return status;
}
public override async Task<(byte[], string)> GetCode()
{
var client = CreateHttpClient(false);
if (this.LoginUrl.NotHas()) return (null, "");
var getResp = await client.GetAsync(this.LoginUrl);
var cookie = this.GetCookie(getResp, "PHPSESSID");
if (cookie.Has())
{
client.DefaultRequestHeaders.Add("Cookie", cookie);
var ret = await client.GetByteArrayAsync(this.LoginCodeUrl + "?t=" + DateTime.Now.Millisecond);
return (ret, cookie);
}
return (null, "");
}
public override async Task<ApiResult> Login(AgentLoginRequest request)
{
var client = CreateHttpClient(false);
var map = new Dictionary<string, string>(){
{"agentName",request.Account },
{"password",request.Pwd },
{"authnum",request.Code },
};
LogHelper.Info("Login", map.ToJson());
AddCookie(client, request.Key);
//client.DefaultRequestHeaders.Add("Cookie", request.Key);
var resp = await client.PostAsForm(this.LoginUrl, map);
var content = await resp.Content.ReadAsStringAsync();
if (content.IndexOf("alert alert-danger") != -1)
{
return new ApiResult(ResultCode.C_VISITOR_CHECKING, "登录失败");
}
return new ApiResult(request.Key);
}
public override bool CheckAccount(int productId,List<string> accounts)
{
return false;
}
/// <summary>
/// 新开
/// </summary>
/// <param name="packageId"></param>
/// <param name="account"></param>
/// <param name="pwd"></param>
/// <returns></returns>
public override async Task<ApiResult> NewAccount(string packageKey, string account, string pwd, int connCount = 1, int accountType = 1, int payCount = 1)
{
var client = CreateHttpClient();
var map = new Dictionary<string, string>(){
{"taocanName",packageKey },
{"username",account },
{"password",pwd },
{"maxonline",connCount.ToString()},
{"type",accountType.ToString()}
};
var title = GetOpTitle("NewAccount", account);
LogHelper.Info(title, map.ToJson());
try
{
var resp = await client.PostAsForm(this.SingleAddUrl, map);
var content = await resp.Content.ReadAsStringAsync();
if (content.Has() && content.IndexOf("{alert(\"成功\")") != -1)
{
return new ApiResult(ResultCode.C_SUCCESS);
}
else
{
LogHelper.Error(title, content);
return new ApiResult(ResultCode.C_INVALID_ERROR, "开户失败");
}
}
catch (Exception ex)
{
LogHelper.Error(title, ex.Message);
return new ApiResult(ResultCode.C_INVALID_ERROR, "开户失败");
}
}
/// <summary>
/// 新开
/// </summary>
/// <param name="packageId"></param>
/// <param name="account"></param>
/// <param name="pwd"></param>
/// <returns></returns>
public override async Task<ApiResult> NewMuiltAccount(string packageKey, string account, string pwd, int connCount = 1, int accountType = 1,int startNum=0, int endNum=1 )
{
var client = CreateHttpClient();
var map = new Dictionary<string, string>(){
{"taocanName",packageKey },
{"usernameTpl",account },
{"password",pwd },
{"maxonline",connCount.ToString()},
{"startNum",startNum.ToString()},
{"endNum",endNum.ToString()},
{"mode",accountType.ToString()},
};
var title = GetOpTitle("NewMuiltAccount", account);
LogHelper.Info(title, map.ToJson());
try
{
var resp = await client.PostAsForm(this.MuiltAddUrl, map);
var content = await resp.Content.ReadAsStringAsync();
if (content.Has() && content.IndexOf("<td>成功</td>") != -1)
{
return new ApiResult(1);
}
else
{
LogHelper.Error(title, content);
return new ApiResult(ResultCode.C_INVALID_ERROR, "开户失败");
}
}
catch (Exception ex)
{
LogHelper.Error(title, ex.Message);
return new ApiResult(ResultCode.C_INVALID_ERROR, "开户失败");
}
}
/// <summary>
/// 续费
/// </summary>
/// <param name="productId"></param>
/// <param name="account"></param>
/// <param name="pwd"></param>
/// <returns></returns>
public override async Task<ApiResult> NewReAccount(string packageKey, string account, int connCount)
{
var client = CreateHttpClient();
var map = new Dictionary<string, string>(){
{"taocanName",packageKey },
{"username",account },
{"iscz","3" },
};
var title = GetOpTitle("NewReAccount", account);
LogHelper.Info(title, map.ToJson());
try
{
var resp = await client.PostAsForm(this.SingleReAddUrl, map);
var content = await resp.Content.ReadAsStringAsync();
if (content.Has() && content.IndexOf("alert(\"成功\")") != -1)
{
return new ApiResult(1);
}
else
{
LogHelper.Error(title, content);
return new ApiResult(ResultCode.C_INVALID_ERROR, "续费失败");
}
}
catch (Exception ex)
{
LogHelper.Error(title, ex.Message);
return new ApiResult(ResultCode.C_INVALID_ERROR, "续费失败");
}
}
/// <summary>
/// 删除账号
/// </summary>
/// <param name="productId"></param>
/// <param name="account"></param>
/// <returns></returns>
public override async Task<bool> DeleteAccount(string account)
{
var client = CreateHttpClient();
var infoRet = await this.GetAccountInfo(account, true);
if (infoRet.Code != ResultCode.C_SUCCESS)
return false;
var title = GetOpTitle("DeleteAccount", account);
LogHelper.Info(title, account);
try
{
var delete = this.DeleteUrl + infoRet.Data.Id + ".html";
var resp = await client.GetAsync(delete);
var content = await resp.Content.ReadAsStringAsync();
if (content.Has() && content.IndexOf("alert(\"删除成功\")") != -1)
{
return true;
}
else
{
LogHelper.Error(title, content);
return false;
}
}
catch (Exception ex)
{
LogHelper.Error(title, ex.Message);
return false;
}
}
/// <summary>
/// 得到账号信息
/// </summary>
/// <param name="productId"></param>
/// <param name="account"></param>
/// <returns></returns>
public override async Task<ApiResult<OriginAccountModel>> GetAccountInfo(string account,bool isTest=false)
{
var client = CreateHttpClient();
var title = GetOpTitle("GetAccountInfo", account);
var info = "";
try
{
var url = this.searchAccountUrl + account;
if (isTest)
{
url = this.searchTestAccountUrl + account;
}
var resp = await client.GetAsync(url);
var content = await resp.Content.ReadAsStringAsync();
var parser = new HtmlParser();
var document = await parser.ParseDocumentAsync(content);
////table class="table table-bordered"
var trs = document.QuerySelectorAll("table.table tr").ToList();
// var trs= table.QuerySelectorAll("tr").ToList();
var retData = new List<OriginAccountModel>();
if (trs.Count() > 1)
{
foreach(var tr in trs.Skip(1))
{
var tds = tr.QuerySelectorAll("td").ToList();
var tdAccount = tds[1].FirstChild.TextContent;
if (tdAccount != account)
continue;
info = string.Join("", tds.Select(m => m.OuterHtml));
//<td >会员账号</td><td >类型</td><td >套餐</td><td >注册日期</td><td >过期日期</td><td >连接数</td><td >余额</td><td >激活</td><td >备注</td>
var trData = new OriginAccountModel
{
Account = account,
Pwd = tds[1].QuerySelector("font").TextContent,
AccountType = tds[2].TextContent,
Package = tds[3].TextContent,
RegistTime = tds[4].TextContent,
EndTime = tds[5].ChildNodes[0].TextContent.Replace("\n", "").Replace("\t", "").Trim(),
RestTime = tds[5].ChildNodes[2].TextContent.Replace("\n", "").Replace("\t", ""),
ConnectCount = tds[6].TextContent,
Amount = tds[7].TextContent,
IsActive = tds[8].TextContent,
Remark = tds[9].TextContent,
};
trData.RealEndTime = DateTime.Parse(trData.EndTime);
if (tds[5].TextContent.Contains("已过期"))
{
trData.RestTime = "已过期";
}else
{
// "6.14:32"
var timeStr = trData.RestTime.Replace("天", ".").Replace("时", ":").Replace("分", "").Trim();
var restTime = TimeSpan.Parse(timeStr);
trData.RealEndTime = DateTime.Now.Add(restTime);
}
var href = tr.LastElementChild.QuerySelector("a")?.Attributes["href"]?.Value;
if (href.Has())
{
var start = href.LastIndexOf('/');
var end = href.IndexOf(".html");
if (start != -1 && end != -1)
{
trData.Id = href.Substring(start + 1, end - start).TrimEnd('.');
}
}
return new ApiResult<OriginAccountModel>(trData);
}
}
}
catch (Exception ex)
{
LogHelper.Error(title, ex.Message+"-->info:"+ info);
return new ApiResult<OriginAccountModel>(ResultCode.C_INVALID_ERROR, "查询失败");
}
return new ApiResult<OriginAccountModel>(ResultCode.C_INVALID_ERROR, "没有查询到信息");
}
/// <summary>
/// 修改账号密码
/// </summary>
/// <param name="productId"></param>
/// <param name="account"></param>
/// <param name="pwd"></param>
/// <returns></returns>
public override async Task<bool> UpdateAccountPwd(string account, string pwd)
{
var ret = await this.GetAccountInfo(account);
if (ret.Code != ResultCode.C_SUCCESS)
{
return false;
}
var accountModel = ret.Data;
if (accountModel == null)
{
return false;
}
var client = CreateHttpClient();
var map = new Dictionary<string, string>(){
{"username",account },
{"password",pwd },
{"submit","提交" },
};
LogHelper.Info(GetOpTitle("UpdateAccountPwd", account), map.ToJson());
try
{
var resp = await client.PostAsForm(this.UpdateUrl + accountModel.Id + ".html", map);
var content = await resp.Content.ReadAsStringAsync();
if (content.Has() && content.IndexOf("更新成功") != -1)
{
return true;
}
else
{
LogHelper.Error(GetOpTitle("UpdateAccountPwd", account), content);
}
}
catch (Exception ex)
{
LogHelper.Error(GetOpTitle("UpdateAccountPwd", account), ex);
}
return false;
}
/// <summary>
/// 退款
/// </summary>
/// <param name="packageId"></param>
/// <param name="account"></param>
/// <returns></returns>
public override async Task<ApiResult> Refund(string account, string packageKey, int days)
{
var client = CreateHttpClient();
var map = new Dictionary<string, string>(){
{"refundUser",account },
{"refundReason","hl" },
};
var title = GetOpTitle("Refund", account);
LogHelper.Info(title, map.ToJson());
try
{
var resp = await client.PostAsForm(this.RefundUrl, map);
var content = await resp.Content.ReadAsStringAsync();
content = System.Text.RegularExpressions.Regex.Unescape(content);
if (content.Has() && content.IndexOf("退款成功") != -1)
{
return new ApiResult(1);
}
else
{
LogHelper.Error(title, content);
return new ApiResult(ResultCode.C_INVALID_ERROR, "退款失败");
}
}
catch (Exception ex)
{
LogHelper.Error(title, ex.Message);
return new ApiResult(ResultCode.C_INVALID_ERROR, "退款失败");
}
}
/// <summary>
/// 是否在线
/// </summary>
/// <param name="productId"></param>
/// <param name="account"></param>
/// <returns></returns>
public override async Task<ApiResult<List<OriginAccountOnlineModel>>> OnLine(string account)
{
var client = CreateHttpClient();
var title = GetOpTitle("OnLine", account);
var info = "";
try
{
var url = this.OnlineUrl + account;
var resp = await client.GetAsync(url);
var content = await resp.Content.ReadAsStringAsync();
var parser = new HtmlParser();
var document = await parser.ParseDocumentAsync(content);
var trs = document.QuerySelectorAll("table.table tr").ToList();
var retData = new List<OriginAccountOnlineModel>();
if (trs.Count() > 1)
{
foreach (var tr in trs.Skip(1))
{
var tds = tr.QuerySelectorAll("td").ToList();
var tdAccount = tds[1].FirstChild.TextContent;
if (tdAccount != account)
continue;
info = string.Join("", tds.Select(m => m.OuterHtml));
//序号 会员账号 服务器IP 登录时间 在线时长 会员IP 上行流量 下行流量 操作
var trData = new OriginAccountOnlineModel
{
Account = account,
ServerIP = tds[2].TextContent,
LoginTime = tds[3].TextContent,
OnlineTime = tds[4].TextContent,
LoginIP = tds[5].TextContent,
UpStream = tds[6].TextContent,
DownStream = tds[7].TextContent,
Id= account,
};
var href = tr.LastElementChild.QuerySelector("a")?.Attributes["href"]?.Value;
if (href.Has())
{
var start = href.LastIndexOf('/');
var end = href.IndexOf(".html");
if (start != -1 && end != -1)
{
trData.Id = href.Substring(start + 1, end - start).TrimEnd('.');
}
}
retData.Add(trData);
}
}
return new ApiResult<List<OriginAccountOnlineModel>>(retData);
}
catch (Exception ex)
{
LogHelper.Error(title, ex.Message + "-->info:" + info);
return new ApiResult<List<OriginAccountOnlineModel>>(ResultCode.C_INVALID_ERROR, "查询失败");
}
}
/// <summary>
/// 踢号
/// </summary>
/// <param name="productId"></param>
/// <param name="account"></param>
/// <returns></returns>
public override async Task<bool> KillOut( string id)
{
var client = CreateHttpClient();
var title = GetOpTitle("KillOut", id);
var info = "";
try
{
var url = string.Format(this.KIllUrl, id);
var resp = await client.GetAsync(url);
var content = await resp.Content.ReadAsStringAsync();
if(content.Has()&&content.IndexOf("断开成功")!=-1)
{
return true;
}
}
catch (Exception ex)
{
LogHelper.Error(title, ex.Message + "-->info:" + info);
}
return false;
}
/// <summary>
/// 是否存在
/// </summary>
/// <param name="account"></param>
/// <returns></returns>
public override async Task<bool> Exist(string account)
{
var client = CreateHttpClient();
var title = GetOpTitle("Exist", account);
LogHelper.Info(title, account);
var testRet = await this.NewAccount("free", account, "1234", 1, 0);
if (testRet.Code == ResultCode.C_SUCCESS)
{
await DeleteAccount(account);
return false;
}
return true;
}
}
}

View File

@@ -0,0 +1,526 @@
using AngleSharp.Html.Parser;
using Hncore.Infrastructure.Common;
using Hncore.Infrastructure.Extension;
using Hncore.Infrastructure.Serializer;
using Hncore.Infrastructure.WebApi;
using Hncore.Pass.Vpn.Model;
using Hncore.Pass.Vpn.Request.Product;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
namespace Hncore.Pass.Vpn.Service
{
//老鹰A组
public class AgentClient2Service : AgentClientBaseService
{
string LoginUrl { get; set; } = "index.php/admin/index/login.html";
string LoginCodeUrl { get; set; } = "main/imgcode.html";
string RefrushTokenUrl { get; set; } = "index.php/admin/index/public_welcome.html";// "";
string SingleAddUrl { get; set; } = "index.php/admin/users/useradd.html";
string SingleReAddUrl { get; set; } = "index.php/admin/users/userrenew.html";
string MuiltAddUrl { get; set; } = "index.php/admin/users/usersadd.html";
string RefundUrl { get; set; } = "index.php/admin/users/userrefund.html";
string OnlineUrl { get; set; } = "";
string GetAccount { get; set; } = "index.php/admin/users/users/grid/datagrid.html";
string KIllUrl { get; set; } = "index.php/admin/users/useroffline.html";
string UpdateUrl { get; set; } = "index.php/admin/users/useredit.html";
string DeleteAccountUrl { get; set; } = "index.php/admin/users/userdelete.html";
string searchAccountUrl = "index.php/admin/users/users/grid/datagrid.html";
string existCheckUrl = "index.php/admin/users/public_checkusername.html";
string refrushCookie = "admin/Common/getCookie";
string sessionlife = "index.php/admin/index/public_sessionlife.html";
IHttpClientFactory m_HttpClientFactory;
public AgentClient2Service(IHttpClientFactory httpClientFactory):base(httpClientFactory)
{
m_HttpClientFactory = httpClientFactory;
}
public async Task<int> RefrushStatus1()
{
int status = 0;
if (this.Token.Has())
{
var client = CreateHttpClient();
if (this.RefrushTokenUrl.Has())
{
var getResp = await client.GetAsync(this.RefrushTokenUrl);
var content = await getResp.Content.ReadAsStringAsync();
if (getResp.StatusCode == HttpStatusCode.OK && content.IndexOf("正常登录") == -1)
{
status = 1;
}
else
{
Debug.WriteLine("离线");
Debug.WriteLine(content);
}
}
}
return status;
}
public override async Task<int> RefrushStatus()
{
var map = new Dictionary<string, string>(){
{"key","1" }
};
int status = 0;
var client = CreateHttpClient();
client.DefaultRequestHeaders.Add("X-Requested-With", "XMLHttpRequest");
var getResp = await client.PostAsForm(this.sessionlife, map);
var content = await getResp.Content.ReadAsStringAsync();
content= System.Text.RegularExpressions.Regex.Unescape(content);
if (getResp.StatusCode == HttpStatusCode.OK && content.IndexOf("登录后台") == -1)
{
status = 1;
}
//else
//{
// var request = new AgentLoginRequest()
// {
// Account = this.Product.Account,
// Pwd = this.Product.Pwd
// };
// var ret = await this.Login(request);
// if (ret.Code == ResultCode.C_SUCCESS)
// {
// this.Product.Token = ret.Data.ToString();
// status = 1;
// }
// else
// {
// Debug.WriteLine("离线");
// }
//}
client.DefaultRequestHeaders.Remove("X-Requested-With");
return status;
}
private async Task<string> GetHomeCookie()
{
var client = CreateHttpClient(false);
if (this.LoginUrl.NotHas()) return "";
var getResp = await client.GetAsync(this.LoginUrl);
var cookies = this.GetCookies(getResp);
cookies=cookies.Replace("path=/;", "").Replace("httponly", "").Trim();
return cookies;
}
public override async Task<ApiResult> Login(AgentLoginRequest request)
{
var client = CreateHttpClient(false);
var map = new Dictionary<string, string>(){
{"managername",request.Account },
{"password",request.Pwd },
// {"authnum",request.Code },
};
LogHelper.Info("Login", map.ToJson());
request.Key = await GetHomeCookie();
AddCookie(client, request.Key);
var resp = await client.PostAsForm(this.LoginUrl, map);
var content = await resp.Content.ReadAsStringAsync();
if (content.IndexOf("index.html") == -1)
{
return new ApiResult(ResultCode.C_VISITOR_CHECKING, "登录失败");
}
return new ApiResult(request.Key);
}
public override bool CheckAccount(int productId,List<string> accounts)
{
return false;
}
/// <summary>
/// 新开
/// </summary>
/// <param name="packageId"></param>
/// <param name="account"></param>
/// <param name="pwd"></param>
/// <returns></returns>
public override async Task<ApiResult> NewAccount(string packageKey, string account, string pwd, int connCount = 1, int accountType = 1, int payCount = 1)
{
var client = CreateHttpClient();
var map = new Dictionary<string, string>(){
{"info[groupid]","2001" },
{"info[srvid]","6" },
{"info[username]",account },
{"info[password]",pwd },
{"info[cycle]",packageKey },
{"info[simuse]",connCount.ToString() },
{"info[usetime]","1" },
{"info[tryuse]",accountType==1?"0":"1"},
};
var title = GetOpTitle("NewAccount", account);
LogHelper.Info(title, map.ToJson());
try
{
var resp = await client.PostAsForm(this.SingleAddUrl, map);
var content = await resp.Content.ReadAsStringAsync();
if (content.Has() && content.IndexOf("开通成功") != -1)
{
return new ApiResult(1);
}
else
{
LogHelper.Error(title, content);
return new ApiResult(ResultCode.C_INVALID_ERROR, "开户失败");
}
}
catch (Exception ex)
{
LogHelper.Error(title, ex.Message);
return new ApiResult(ResultCode.C_INVALID_ERROR, "开户失败");
}
}
/// <summary>
/// 批量新开
/// </summary>
/// <param name="packageId"></param>
/// <param name="account"></param>
/// <param name="pwd"></param>
/// <returns></returns>
public override async Task<ApiResult> NewMuiltAccount(string packageKey, string account, string pwd, int connCount = 1, int accountType = 1,int startNum=0, int endNum=1 )
{
var client = CreateHttpClient();
var map = new Dictionary<string, string>(){
{"info[groupid]","2001" },
{"info[srvid]","6" },
{"info[username_header]",account },
{"info[username_start]",startNum.ToString() },
{"info[username_end]",endNum.ToString() },
{"info[pwdtype]","0" },
{"info[password]",pwd },
{"info[repassword]",pwd },
{"info[cycle]",packageKey },
{"info[simuse]",connCount.ToString() },
{"info[usetime]","1" },
{"info[tryuse]","0" },
};
var title = GetOpTitle("NewMuiltAccount", account);
LogHelper.Info(title, map.ToJson());
try
{
var resp = await client.PostAsForm(this.MuiltAddUrl, map);
var content = await resp.Content.ReadAsStringAsync();
if (content.Has() && content.IndexOf("开通成功") != -1)
{
return new ApiResult(1);
}
else
{
LogHelper.Error(title, content);
return new ApiResult(ResultCode.C_INVALID_ERROR, "开户失败");
}
}
catch (Exception ex)
{
LogHelper.Error(title, ex.Message);
return new ApiResult(ResultCode.C_INVALID_ERROR, "开户失败");
}
}
/// <summary>
/// 续费
/// </summary>
/// <param name="productId"></param>
/// <param name="account"></param>
/// <param name="pwd"></param>
/// <returns></returns>
public override async Task<ApiResult> NewReAccount(string packageKey,string account, int connCount)
{
var client = CreateHttpClient();
Dictionary<string, int> priceMap = new Dictionary<string, int>()
{
{"daycardprice",3},
{"weekcardprice",15},
{"monthcardprice",60},
};
var price = priceMap[packageKey];
var totalAmount = price * connCount;
var map = new Dictionary<string, string>(){
{"info[username]",account },
{"info[cycle]",packageKey },
{"info[simuse]",connCount.ToString()},
{"info[usetime]","1" },
{"info[usemoney]",totalAmount.ToString() },
};
var title = GetOpTitle("NewReAccount", account);
LogHelper.Info(title, map.ToJson());
try
{
var resp = await client.PostAsForm(this.SingleReAddUrl, map);
var content = await resp.Content.ReadAsStringAsync();
if (content.Has() && content.IndexOf("续费成功") != -1)
{
return new ApiResult(1);
}
else
{
LogHelper.Error(title, content);
return new ApiResult(ResultCode.C_INVALID_ERROR, "续费失败");
}
}
catch (Exception ex)
{
LogHelper.Error(title, ex.Message);
return new ApiResult(ResultCode.C_INVALID_ERROR, "续费失败");
}
}
/// <summary>
/// 删除账号
/// </summary>
/// <param name="productId"></param>
/// <param name="account"></param>
/// <returns></returns>
public override async Task<bool> DeleteAccount(string account)
{
var client = CreateHttpClient();
var map = new Dictionary<string, string>(){
{"usernames",account }
};
LogHelper.Info(GetOpTitle("DeleteAccount", account), map.ToJson());
try
{
var resp = await client.PostAsForm(this.SingleAddUrl, map);
var content = await resp.Content.ReadAsStringAsync();
if (content.Has() && content.IndexOf("删除成功") != -1)
{
return true;
}
else
{
LogHelper.Error(GetOpTitle("DeleteAccount", account), content);
}
}
catch (Exception ex)
{
LogHelper.Error(GetOpTitle("DeleteAccount", account), ex);
}
return false;
}
/// <summary>
/// 得到账号信息
/// </summary>
/// <param name="productId"></param>
/// <param name="account"></param>
/// <returns></returns>
public override async Task<ApiResult<OriginAccountModel>> GetAccountInfo(string account,bool isTest)
{
var client = CreateHttpClient();
var map = new Dictionary<string, string>(){
{"search[username]",account },
{"page","1" },
{"rows","25" },
};
var title = GetOpTitle("GetAccountInfo", account);
try
{
var content = await client.PostAsFormGetString(this.searchAccountUrl, map);
JObject jo = (JObject)JsonConvert.DeserializeObject(content);
var rows = jo["rows"].ToArray();
var row = rows.FirstOrDefault();
var trData = new OriginAccountModel
{
User = row["groupname"].ToString(),
Account = row["username"].ToString(),
AccountType = row["username"].ToString(),
Package = row["cycle"].ToString(),
RegistTime = row["createdon"].ToString(),
EndTime = row["expiration"].ToString(),
ConnectCount = row["simuse"].ToString(),
Pwd=row["open_password"].ToString(),
// Amount = row["cycle"].ToString(),
RestTime = row["havetime"].ToString(),
IsActive = row["status"].ToString(),
Remark = row["comment"].ToString(),
OnLine = row["status"].ToString().IndexOf("在线") == -1 ? 0 : 1,
LoginTime= row["acctstarttime"].ToString(),
LoginServer= row["nasipaddress"].ToString(),
};
trData.RealEndTime = DateTime.Parse(trData.EndTime);
return new ApiResult<OriginAccountModel>(trData);
}
catch (Exception ex)
{
LogHelper.Error(title, ex.Message);
return new ApiResult<OriginAccountModel>(ResultCode.C_INVALID_ERROR, "查询失败");
}
}
/// <summary>
/// 修改账号密码
/// </summary>
/// <param name="productId"></param>
/// <param name="account"></param>
/// <param name="pwd"></param>
/// <returns></returns>
public override async Task<bool> UpdateAccountPwd(string account,string pwd)
{
var client = CreateHttpClient();
var map = new Dictionary<string, string>(){
{"info[groupid]","2001" },
{"info[srvid]","6" },
{"info[username]",account },
{"info[password]",pwd },
};
LogHelper.Info(GetOpTitle("UpdateAccountPwd", account), map.ToJson());
try
{
var resp = await client.PostAsForm(this.UpdateUrl, map);
var content = await resp.Content.ReadAsStringAsync();
if (content.Has() && content.IndexOf("修改成功") != -1)
{
return true;
}
else
{
LogHelper.Error(GetOpTitle("UpdateAccountPwd", account), content);
}
}
catch (Exception ex)
{
LogHelper.Error(GetOpTitle("UpdateAccountPwd", account), ex);
}
return false;
}
/// <summary>
/// 退款
/// </summary>
/// <param name="packageId"></param>
/// <param name="account"></param>
/// <returns></returns>
public override async Task<ApiResult> Refund(string account, string packageKey, int days)
{
var client = CreateHttpClient();
var map = new Dictionary<string, string>(){
{"info[username]",account },
{"info[cycle]",packageKey },
{"info[expiretime]",days.ToString() },
};
var title = GetOpTitle("Refund", account);
LogHelper.Info(title, map.ToJson());
try
{
var resp = await client.PostAsForm(this.RefundUrl, map);
var content = await resp.Content.ReadAsStringAsync();
if (content.Has() && content.IndexOf("退款成功") != -1)
{
return new ApiResult(1);
}
else
{
LogHelper.Error(title, content);
return new ApiResult(ResultCode.C_INVALID_ERROR, "退款失败");
}
}
catch (Exception ex)
{
LogHelper.Error(title, ex.Message);
return new ApiResult(ResultCode.C_INVALID_ERROR, "退款失败");
}
}
/// <summary>
/// 是否在线
/// </summary>
/// <param name="productId"></param>
/// <param name="account"></param>
/// <returns></returns>
public override async Task<ApiResult<List<OriginAccountOnlineModel>>> OnLine(string account)
{
var accountInfo =await this.GetAccountInfo(account, false);
if (accountInfo.Code != ResultCode.C_SUCCESS) return await base.OnLine(account);
var list = new List<OriginAccountOnlineModel>();
if (accountInfo.Data.OnLine == 1)
{
list.Add(new OriginAccountOnlineModel()
{
Account = account,
OnLine = accountInfo.Data.OnLine,
Id = account,
LoginTime= accountInfo.Data.LoginTime,
LoginIP= accountInfo.Data.LoginServer
});
}
return new ApiResult<List<OriginAccountOnlineModel>>(list);
}
/// <summary>
/// 踢号
/// </summary>
/// <param name="productId"></param>
/// <param name="account">账号</param>
/// <returns></returns>
public override async Task<bool> KillOut( string account)
{
var client = CreateHttpClient();
client.DefaultRequestHeaders.Add("X-Requested-With", "XMLHttpRequest");
var map = new Dictionary<string, string>(){
{"usernames",account },
};
var title = GetOpTitle("KillOut", account);
LogHelper.Info(title, map.ToJson());
try
{
var resp = await client.PostAsForm(this.KIllUrl, map);
var content = await resp.Content.ReadAsStringAsync();
if (content.Has() && content.IndexOf("次踢人操作") != -1)
{
return true;
}
else
{
LogHelper.Error(title, content);
}
}
catch (Exception ex)
{
LogHelper.Error(title, ex.Message);
}
return false;
}
/// <summary>
/// 是否存在
/// </summary>
/// <param name="account"></param>
/// <returns></returns>
public override async Task<bool> Exist(string account)
{
var client = CreateHttpClient();
var map = new Dictionary<string, string>(){
{"username",account }
};
var title = GetOpTitle("Exist", account);
LogHelper.Info(title, map.ToJson());
try
{
var resp = await client.PostAsForm(this.existCheckUrl, map);
var content = await resp.Content.ReadAsStringAsync();
if (content.Has() && content.IndexOf("false") != -1)
{
return true;
}
else
{
return false;
}
}
catch (Exception ex)
{
LogHelper.Error(title, ex.Message);
return false;
}
}
}
}

View File

@@ -0,0 +1,539 @@
using AngleSharp.Html.Parser;
using Hncore.Infrastructure.Common;
using Hncore.Infrastructure.Extension;
using Hncore.Infrastructure.Serializer;
using Hncore.Infrastructure.WebApi;
using Hncore.Pass.Vpn.Model;
using Hncore.Pass.Vpn.Request.Product;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
namespace Hncore.Pass.Vpn.Service
{
//老鹰B组
public class AgentClient3Service : AgentClientBaseService
{
string LoginUrl { get; set; } = "api/login";
string LoginCodeUrl { get; set; } = "";
string RefrushTokenUrl { get; set; } = "api/info?_=";
string SingleAddUrl { get; set; } = "api/ppp/one";
string ReAddUrl { get; set; } = "api/ppp/renewal";
string MuiltAddUrl { get; set; } = "api/ppp/batch";
string RefundUrl { get; set; } = "api/ppp/delete";
string OnlineUrl { get; set; } = "api/ppp/oln?user={0}&_={1}";
string GetAccount { get; set; } = "index.php/admin/users/users/grid/datagrid.html";
string KIllUrl { get; set; } = "api/ppp/oln/stop";
string UpdateUrl { get; set; } = "api/ppp/update";
string DeleteAccountUrl { get; set; } = "api/ppp/delete?user=hl&_=1583126809671";
string InfoUrl = "api/ppp?page=1&user=";
string TestAddUrl { get; set; } = "api/ppp/test";
IHttpClientFactory m_HttpClientFactory;
public AgentClient3Service(IHttpClientFactory httpClientFactory):base(httpClientFactory)
{
m_HttpClientFactory = httpClientFactory;
}
public override async Task<int> RefrushStatus()
{
int status = 0;
if (this.Token.Has())
{
var client = CreateHttpClient();
if (this.RefrushTokenUrl.Has())
{
var getResp = await client.GetAsync(this.RefrushTokenUrl+DateTime.Now.GetUnixTimeStamp());
var content = await getResp.Content.ReadAsStringAsync();
if (getResp.StatusCode == HttpStatusCode.OK && content.IndexOf("\"ret\":200") != -1)
{
status = 1;
}
else
{
Debug.WriteLine("离线");
Debug.WriteLine(content);
}
}
}
return status;
}
public override async Task<ApiResult> Login(AgentLoginRequest request)
{
var client = CreateHttpClient(false);
var map = new Dictionary<string, string>(){
{"username",request.Account },
{"password",request.Pwd },
{"autologon","false"},
};
LogHelper.Info("Login", map.ToJson());
var resp = await client.PostAsForm(this.LoginUrl, map);
var content = await resp.Content.ReadAsStringAsync();
if (content.IndexOf("登陆成功")!= -1)
{
request.Key = this.GetCookie(resp, "_dailissid");
return new ApiResult(request.Key);
}
return new ApiResult(ResultCode.C_VISITOR_CHECKING, "登录失败");
}
public override bool CheckAccount(int productId,List<string> accounts)
{
return false;
}
/// <summary>
/// 新开
/// </summary>
/// <param name="packageId"></param>
/// <param name="account"></param>
/// <param name="pwd"></param>
/// <returns></returns>
public override async Task<ApiResult> NewAccount(string packageKey, string account, string pwd, int connCount = 1, int accountType = 1, int payCount = 1)
{
if (accountType == 0)//新开测试号
{
return await NewTestAccount(account, pwd);
}
var client = CreateHttpClient();
var map = new Dictionary<string, string>(){
{"user",account },
{"passwd",pwd },
{"type",packageKey },
{"conn_max",connCount.ToString() },
{"paynum",payCount.ToString()},
{"details","hl" },
};
var title = GetOpTitle("NewAccount", account);
LogHelper.Info(title, map.ToJson());
try
{
var resp = await client.PostAsForm(this.SingleAddUrl, map);
var content = await resp.Content.ReadAsStringAsync();
if (content.Has() && content.IndexOf("开户成功") != -1)
{
return new ApiResult(ResultCode.C_SUCCESS);
}
else
{
LogHelper.Error(title, content);
return new ApiResult(ResultCode.C_INVALID_ERROR, "开户失败");
}
}
catch (Exception ex)
{
LogHelper.Error(title, ex.Message);
return new ApiResult(ResultCode.C_INVALID_ERROR, "开户失败");
}
}
public async Task<ApiResult> NewTestAccount(string account, string pwd)
{
var client = CreateHttpClient();
var map = new Dictionary<string, string>(){
{"user",account },
{"passwd",pwd },
};
var title = GetOpTitle("NewTestAccount", account);
LogHelper.Info(title, map.ToJson());
try
{
var resp = await client.PostAsForm(this.TestAddUrl, map);
var content = await resp.Content.ReadAsStringAsync();
if (content.Has() && content.IndexOf("开户成功") != -1)
{
return new ApiResult(ResultCode.C_SUCCESS);
}
else
{
LogHelper.Error(title, content);
return new ApiResult(ResultCode.C_INVALID_ERROR, "开户失败");
}
}
catch (Exception ex)
{
LogHelper.Error(title, ex.Message);
return new ApiResult(ResultCode.C_INVALID_ERROR, "开户失败");
}
}
/// <summary>
/// 批量新开
/// </summary>
/// <param name="packageId"></param>
/// <param name="account"></param>
/// <param name="pwd"></param>
/// <returns></returns>
public override async Task<ApiResult> NewMuiltAccount(string packageKey, string account, string pwd, int connCount = 1, int accountType = 1, int startNum = 0, int endNum = 1)
{
var client = CreateHttpClient();
var map = new Dictionary<string, string>(){
{"user",account },
{"passwd",pwd },
{"form",startNum.ToString() },
{"to",endNum.ToString() },
{"type",packageKey },
{"conn_max",connCount.ToString() },
{"paynum","1" },
{"details","hl" },
};
var title = GetOpTitle("NewMuiltAccount", account);
LogHelper.Info(title, map.ToJson());
try
{
var resp = await client.PostAsForm(this.MuiltAddUrl, map);
var content = await resp.Content.ReadAsStringAsync();
if (content.Has() && content.IndexOf("开户成功") != -1)
{
return new ApiResult(1);
}
else
{
LogHelper.Error(title, content);
return new ApiResult(ResultCode.C_INVALID_ERROR, "开户失败");
}
}
catch (Exception ex)
{
LogHelper.Error(title, ex.Message);
return new ApiResult(ResultCode.C_INVALID_ERROR, "开户失败");
}
}
/// <summary>
/// 续费
/// </summary>
/// <param name="productId"></param>
/// <param name="account"></param>
/// <param name="pwd"></param>
/// <returns></returns>
public override async Task<ApiResult> NewReAccount(string packageKey, string account, int connCount)
{
var client = CreateHttpClient();
var map = new Dictionary<string, string>(){
{"user",account },
{"type",packageKey },
{"paynum","1"},
};
var title = GetOpTitle("NewReAccount", account);
LogHelper.Info(title, map.ToJson());
try
{
var resp = await client.PostAsForm(this.ReAddUrl, map);
var content = await resp.Content.ReadAsStringAsync();
if (content.Has() && content.IndexOf("续费成功") != -1)
{
return new ApiResult(1);
}
else
{
LogHelper.Error(title, content);
return new ApiResult(ResultCode.C_INVALID_ERROR, "续费失败");
}
}
catch (Exception ex)
{
LogHelper.Error(title, ex.Message);
return new ApiResult(ResultCode.C_INVALID_ERROR, "续费失败");
}
}
/// <summary>
/// 删除账号
/// </summary>
/// <param name="productId"></param>
/// <param name="account"></param>
/// <returns></returns>
public override async Task<bool> DeleteAccount(string account)
{
var client = CreateHttpClient();
var map = new Dictionary<string, string>(){
{"usernames",account }
};
LogHelper.Info(GetOpTitle("DeleteAccount", account), map.ToJson());
try
{
var resp = await client.PostAsForm(this.SingleAddUrl, map);
var content = await resp.Content.ReadAsStringAsync();
if (content.Has() && content.IndexOf("删除成功") != -1)
{
return true;
}
else
{
LogHelper.Error(GetOpTitle("DeleteAccount", account), content);
}
}
catch (Exception ex)
{
LogHelper.Error(GetOpTitle("DeleteAccount", account), ex);
}
return false;
}
/// <summary>
/// 得到账号信息
/// </summary>
/// <param name="productId"></param>
/// <param name="account"></param>
/// <returns></returns>
public override async Task<ApiResult<OriginAccountModel>> GetAccountInfo(string account,bool isTest)
{
var client = CreateHttpClient();
var title = GetOpTitle("GetAccountInfo", account);
var info = "";
try
{
var resp = await client.GetAsync(this.InfoUrl+account);
var content = await resp.Content.ReadAsStringAsync();
info = content;
JObject jo = (JObject)JsonConvert.DeserializeObject(content);
var datas = jo["data"]["data"];
var row = datas?.FirstOrDefault();
var trData = new OriginAccountModel
{
User = row["user"].ToString(),
Account = row["user"].ToString(),
AccountType = row["type"].ToString(),
Package ="",
RegistTime = Convert.ToInt64(row["add_time"]).LoadFromUnixTimeStamp().AddHours(8).ToString(),
EndTime =Convert.ToInt64(row["end_time"]).LoadFromUnixTimeStamp().AddHours(8).ToString(),
ConnectCount = row["conn_max"].ToString(),
Pwd = row["passwd"].ToString(),
};
trData.RealEndTime = DateTime.Parse(trData.EndTime);
var restDay = (trData.RealEndTime - DateTime.Now).Days;
restDay = restDay < 0 ? 0 : restDay;
if (restDay <= 1) trData.Package = "天";
else if(restDay <= 7) trData.Package = "周";
else trData.Package = "月";
return new ApiResult<OriginAccountModel>(trData);
//var parser = new HtmlParser();
//var document = await parser.ParseDocumentAsync(content);
//////table class="table table-bordered"
//var trs = document.QuerySelectorAll("table[class='table table-bordered']>tr").ToList();
//// var trs= table.QuerySelectorAll("tr").ToList();
//if (trs.Count() > 1)
//{
// var tr = trs.Skip(1).FirstOrDefault();
// var tdTexts = tr.QuerySelectorAll("td").Select(m => m.TextContent).ToList();
// //<td >会员账号</td><td >类型</td><td >套餐</td><td >注册日期</td><td >过期日期</td><td >连接数</td><td >余额</td><td >激活</td><td >备注</td>
// var trData = new OriginAccountModel
// {
// Account = tdTexts[0],
// AccountType = tdTexts[1],
// Package = tdTexts[2],
// RegistTime = tdTexts[3],
// EndTime = tdTexts[4],
// ConnectCount = tdTexts[5],
// Amount = tdTexts[6],
// IsActive = tdTexts[7],
// Remark = tdTexts[8],
// };
// var href = tr.LastElementChild.QuerySelector("a")?.Attributes["href"]?.Value;
// if (href.Has())
// {
// var start = href.LastIndexOf('/');
// var end = href.IndexOf(".html");
// if (start != -1 && end != -1)
// {
// trData.Id = href.Substring(start, end - start);
// }
// }
// return new ApiResult<OriginAccountModel>(trData);
//}
}
catch (Exception ex)
{
LogHelper.Error(title, ex.Message+"-->info:"+ info);
return new ApiResult<OriginAccountModel>(ResultCode.C_INVALID_ERROR, "查询失败");
}
return new ApiResult<OriginAccountModel>(ResultCode.C_INVALID_ERROR, "没有查询到信息");
}
/// <summary>
/// 修改账号密码
/// </summary>
/// <param name="productId"></param>
/// <param name="account"></param>
/// <param name="pwd"></param>
/// <returns></returns>
public override async Task<bool> UpdateAccountPwd(string account,string pwd)
{
var client = CreateHttpClient();
var map = new Dictionary<string, string>(){
{"user",account },
{"new_user",account},
{"passwd",pwd },
{"details","hl" },
};
LogHelper.Info(GetOpTitle("UpdateAccountPwd", account), map.ToJson());
try
{
var resp = await client.PostAsForm(this.UpdateUrl, map);
var content = await resp.Content.ReadAsStringAsync();
if (content.Has() && content.IndexOf("修改成功") != -1)
{
return true;
}
else
{
LogHelper.Error(GetOpTitle("UpdateAccountPwd", account), content);
}
}
catch (Exception ex)
{
LogHelper.Error(GetOpTitle("UpdateAccountPwd", account), ex);
}
return false;
}
/// <summary>
/// 退款
/// </summary>
/// <param name="packageId"></param>
/// <param name="account"></param>
/// <returns></returns>
public override async Task<ApiResult> Refund(string account, string packageKey, int days)
{
var client = CreateHttpClient();
var title = GetOpTitle("Refund", account);
try
{
var resp = await client.GetAsync(this.RefundUrl+$"?user={account}&_={DateTime.Now.GetUnixTimeStamp()} ");
var content = await resp.Content.ReadAsStringAsync();
content = System.Text.RegularExpressions.Regex.Unescape(content);
if (content.Has() && content.IndexOf("删除成功") != -1)
{
return new ApiResult(1);
}
else
{
LogHelper.Error(title, content);
return new ApiResult(ResultCode.C_INVALID_ERROR, "退款失败");
}
}
catch (Exception ex)
{
LogHelper.Error(title, ex.Message);
return new ApiResult(ResultCode.C_INVALID_ERROR, "退款失败");
}
}
/// <summary>
/// 是否在线
/// </summary>
/// <param name="productId"></param>
/// <param name="account"></param>
/// <returns></returns>
public override async Task<ApiResult<List<OriginAccountOnlineModel>>> OnLine(string account)
{
var client = CreateHttpClient();
var title = GetOpTitle("OnLine", account);
var info = "";
try
{
string url = string.Format(this.OnlineUrl, account, DateTime.Now.GetUnixTimeStamp());
var resp = await client.GetAsync(url);
var content = await resp.Content.ReadAsStringAsync();
info = content;
JObject jo = (JObject)JsonConvert.DeserializeObject(content);
var datas = jo["data"]["data"];
var rows = datas.Children();
var retData = new List<OriginAccountOnlineModel>();
if (datas!=null&& rows.Count() > 0)
{
foreach (var row in rows)
{
var trData = new OriginAccountOnlineModel()
{
Account = account,
OnLine = 1,
LoginIP = row["client_ip"].ToString(),
ServerIP=row["nas_name"].ToString(),
LoginTime=row["add_time"].ToString(),
Id = row["id"].ToString()
};
trData.LoginTime = (DateTime.Now - trData.LoginTime.LoadFromUnixTimeStamp().Value).ToString("d\\.hh\\:mm\\:ss");
retData.Add(trData);
}
}
return new ApiResult<List<OriginAccountOnlineModel>>(retData);
}
catch (Exception ex)
{
LogHelper.Error(title, ex.Message + "-->info:" + info);
return await base.OnLine(account);
}
}
/// <summary>
/// 踢号
/// </summary>
/// <param name="productId"></param>
/// <param name="account"></param>
/// <returns></returns>
public override async Task<bool> KillOut( string id)
{
// formData id: d9bd8ac88e31d43b0507f5f66927c2ee
var client = CreateHttpClient();
var map = new Dictionary<string, string>(){
{"id",id },
};
LogHelper.Info(GetOpTitle("KillOut", id), map.ToJson());
try
{
var resp = await client.PostAsForm(this.KIllUrl, map);
var content = await resp.Content.ReadAsStringAsync();
if (content.Has() && content.IndexOf("踢线成功") != -1)
{
return true;
}
else
{
LogHelper.Error(GetOpTitle("KillOut", id), content);
}
}
catch (Exception ex)
{
LogHelper.Error(GetOpTitle("KillOut", id), ex);
}
return false;
}
/// <summary>
/// 是否存在
/// </summary>
/// <param name="account"></param>
/// <returns></returns>
public override async Task<bool> Exist(string account)
{
// return false;
var client = CreateHttpClient();
var map = new Dictionary<string, string>(){
{"groupname",account }
};
var title = GetOpTitle("Exist", account);
LogHelper.Info(title, map.ToJson());
var ret = await this.NewAccount("w", account, "123");
if (ret.Code == ResultCode.C_SUCCESS)
{
await this.Refund(account, "w", 1);
return false;
}
return true;
}
}
}

View File

@@ -0,0 +1,591 @@
using AngleSharp.Dom;
using AngleSharp.Html.Parser;
using Hncore.Infrastructure.Common;
using Hncore.Infrastructure.Extension;
using Hncore.Infrastructure.Serializer;
using Hncore.Infrastructure.WebApi;
using Hncore.Pass.Vpn.Model;
using Hncore.Pass.Vpn.Request.Product;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
namespace Hncore.Pass.Vpn.Service
{
//金桥
public class AgentClient4Service: AgentClient1Service
{
string LoginUrl { get; set; } = "main/agentLogin.html";
string LoginCodeUrl { get; set; } = "main/imgcode.html";
string RefrushTokenUrl { get; set; } = "agent.html";
string SingleAddUrl { get; set; } = "agent/memberSingleAdd.html";
string SingleReAddUrl { get; set; } = "agent/memberRenew.html";
string MuiltAddUrl { get; set; } = "agent/memberMuiltAdd.html";
string RefundUrl { get; set; } = "agent/memberRefundAct.html ";
string UpdateUrl = "agent/memberUpdate/id/";//agent/memberUpdate/id/1155709.html
string OnlineUrl { get; set; } = "";
string KIllUrl { get; set; } = "";
string searchAccountUrl = "agent/memberList/type/1.html?search=1&username=";
string searchTestAccountUrl = "agent/memberList/type/0.html?search=1&username=";
string DeleteUrl { get; set; } = "agent/memberDel/id/";//1160862.html";
string KillUrlClient = "/agent/disConnect/sessionid/{0}.html";
string ClientOnlineUrl { get; set; } = "agent/clientOnline/page/{0}.html";
IHttpClientFactory m_HttpClientFactory;
public AgentClient4Service(IHttpClientFactory httpClientFactory):base(httpClientFactory)
{
m_HttpClientFactory = httpClientFactory;
}
public override async Task<int> RefrushStatus()
{
int status = 0;
if (this.Token.Has())
{
var client = CreateHttpClient();
if (this.RefrushTokenUrl.Has())
{
// client.DefaultRequestHeaders.Add("Cookie", this.Token);
var getResp = await client.GetAsync(this.RefrushTokenUrl);
var content = await getResp.Content.ReadAsStringAsync();
if (getResp.StatusCode == HttpStatusCode.OK && content.IndexOf("agentLogin.html") == -1)
{
status = 1;
}
else
{
Debug.WriteLine("离线");
Debug.WriteLine(content);
}
}
}
return status;
}
public override async Task<(byte[], string)> GetCode()
{
var client = CreateHttpClient(false);
if (this.LoginUrl.NotHas()) return (null, "");
var getResp = await client.GetAsync(this.LoginUrl);
var cookie = this.GetCookie(getResp, "PHPSESSID");
if (cookie.Has())
{
client.DefaultRequestHeaders.Add("Cookie", cookie);
var ret = await client.GetByteArrayAsync(this.LoginCodeUrl + "?t=" + DateTime.Now.Millisecond);
return (ret, cookie);
}
return (null, "");
}
public override async Task<ApiResult> Login(AgentLoginRequest request)
{
var client = CreateHttpClient(false);
var map = new Dictionary<string, string>(){
{"agentName",request.Account },
{"password",request.Pwd },
{"authnum",request.Code },
};
LogHelper.Info("Login", map.ToJson());
AddCookie(client, request.Key);
//client.DefaultRequestHeaders.Add("Cookie", request.Key);
var resp = await client.PostAsForm(this.LoginUrl, map);
var content = await resp.Content.ReadAsStringAsync();
if (content.IndexOf("alert alert-danger") != -1)
{
return new ApiResult(ResultCode.C_VISITOR_CHECKING, "登录失败");
}
return new ApiResult(request.Key);
}
public override bool CheckAccount(int productId,List<string> accounts)
{
return false;
}
/// <summary>
/// 新开
/// </summary>
/// <param name="packageId"></param>
/// <param name="account"></param>
/// <param name="pwd"></param>
/// <returns></returns>
public override async Task<ApiResult> NewAccount(string packageKey, string account, string pwd, int connCount = 1, int accountType = 1, int payCount = 1)
{
var client = CreateHttpClient();
var map = new Dictionary<string, string>(){
{"taocanName",packageKey },
{"username",account },
{"password",pwd },
{"maxonline",connCount.ToString()},
{"type",accountType.ToString()}
};
var title = GetOpTitle("NewAccount", account);
LogHelper.Info(title, map.ToJson());
try
{
var resp = await client.PostAsForm(this.SingleAddUrl, map);
var content = await resp.Content.ReadAsStringAsync();
if (content.Has() && content.IndexOf("{alert(\"成功\")") != -1)
{
return new ApiResult(ResultCode.C_SUCCESS);
}
else
{
LogHelper.Error(title, content);
return new ApiResult(ResultCode.C_INVALID_ERROR, "开户失败");
}
}
catch (Exception ex)
{
LogHelper.Error(title, ex.Message);
return new ApiResult(ResultCode.C_INVALID_ERROR, "开户失败");
}
}
/// <summary>
/// 新开
/// </summary>
/// <param name="packageId"></param>
/// <param name="account"></param>
/// <param name="pwd"></param>
/// <returns></returns>
public override async Task<ApiResult> NewMuiltAccount(string packageKey, string account, string pwd, int connCount = 1, int accountType = 1,int startNum=0, int endNum=1 )
{
var client = CreateHttpClient();
var map = new Dictionary<string, string>(){
{"taocanName",packageKey },
{"usernameTpl",account },
{"password",pwd },
{"maxonline",connCount.ToString()},
{"startNum",startNum.ToString()},
{"endNum",endNum.ToString()},
{"mode",accountType.ToString()},
};
var title = GetOpTitle("NewMuiltAccount", account);
LogHelper.Info(title, map.ToJson());
try
{
var resp = await client.PostAsForm(this.MuiltAddUrl, map);
var content = await resp.Content.ReadAsStringAsync();
if (content.Has() && content.IndexOf("<td>成功</td>") != -1)
{
return new ApiResult(1);
}
else
{
LogHelper.Error(title, content);
return new ApiResult(ResultCode.C_INVALID_ERROR, "开户失败");
}
}
catch (Exception ex)
{
LogHelper.Error(title, ex.Message);
return new ApiResult(ResultCode.C_INVALID_ERROR, "开户失败");
}
}
/// <summary>
/// 续费
/// </summary>
/// <param name="productId"></param>
/// <param name="account"></param>
/// <param name="pwd"></param>
/// <returns></returns>
public override async Task<ApiResult> NewReAccount(string packageKey, string account, int connCount)
{
var client = CreateHttpClient();
var map = new Dictionary<string, string>(){
{"taocanName",packageKey },
{"username",account },
{"iscz","3" },
};
var title = GetOpTitle("NewReAccount", account);
LogHelper.Info(title, map.ToJson());
try
{
var resp = await client.PostAsForm(this.SingleReAddUrl, map);
var content = await resp.Content.ReadAsStringAsync();
if (content.Has() && content.IndexOf("alert(\"成功\")") != -1)
{
return new ApiResult(1);
}
else
{
LogHelper.Error(title, content);
return new ApiResult(ResultCode.C_INVALID_ERROR, "续费失败");
}
}
catch (Exception ex)
{
LogHelper.Error(title, ex.Message);
return new ApiResult(ResultCode.C_INVALID_ERROR, "续费失败");
}
}
/// <summary>
/// 删除账号
/// </summary>
/// <param name="productId"></param>
/// <param name="account"></param>
/// <returns></returns>
public override async Task<bool> DeleteAccount(string account)
{
var client = CreateHttpClient();
var infoRet = await this.GetAccountInfo(account, true);
if (infoRet.Code != ResultCode.C_SUCCESS)
return false;
var title = GetOpTitle("DeleteAccount", account);
LogHelper.Info(title, account);
try
{
var delete = this.DeleteUrl + infoRet.Data.Id + ".html";
var resp = await client.GetAsync(delete);
var content = await resp.Content.ReadAsStringAsync();
if (content.Has() && content.IndexOf("alert(\"删除成功\")") != -1)
{
return true;
}
else
{
LogHelper.Error(title, content);
return false;
}
}
catch (Exception ex)
{
LogHelper.Error(title, ex.Message);
return false;
}
}
/// <summary>
/// 得到账号信息
/// </summary>
/// <param name="productId"></param>
/// <param name="account"></param>
/// <returns></returns>
public override async Task<ApiResult<OriginAccountModel>> GetAccountInfo(string account,bool isTest=false)
{
var client = CreateHttpClient();
var title = GetOpTitle("GetAccountInfo", account);
var info = "";
try
{
var url = this.searchAccountUrl + account;
if (isTest)
{
url = this.searchTestAccountUrl + account;
}
var resp = await client.GetAsync(url);
var content = await resp.Content.ReadAsStringAsync();
var parser = new HtmlParser();
var document = await parser.ParseDocumentAsync(content);
////table class="table table-bordered"
var trs = document.QuerySelectorAll("table.table tr").ToList();
// var trs= table.QuerySelectorAll("tr").ToList();
var retData = new List<OriginAccountModel>();
if (trs.Count() > 1)
{
//var tr = trs.Skip(1).FirstOrDefault();
foreach(var tr in trs.Skip(1))
{
var tds = tr.QuerySelectorAll("td").ToList();
var tdAccount = tds[1].FirstChild.TextContent;
if (tdAccount != account)
continue;
info = string.Join("", tds.Select(m => m.OuterHtml));
//<td >会员账号</td><td >类型</td><td >套餐</td><td >注册日期 过期日期</td><td>专线IP </td><td >连接数</td><td >余额</td><td >激活</td><td >备注</td>
var dateText = tds[4].InnerHtml;
var endtext = dateText.Split("<br>")[1].Split('\n');
var trData = new OriginAccountModel
{
Account = account,
Pwd = tds[1].QuerySelector("font").TextContent,
AccountType = tds[2].TextContent,
Package = tds[3].TextContent,
RegistTime = dateText.Split("<br>")[0],
EndTime = endtext[0].Replace("\n", "").Replace("\t", ""),
RestTime = endtext[1].Replace("\n", "").Replace("\t", ""),
ConnectCount = tds[6].TextContent,
Amount = tds[7].TextContent,
IsActive = tds[8].TextContent,
Remark = tds[9].TextContent,
};
trData.RealEndTime = DateTime.Parse(trData.EndTime);
if (trData.RestTime.Contains("已过期"))
{
trData.RestTime = "已过期";
}else
{
// "6.14:32"
var timeStr = trData.RestTime.Replace("天", ".").Replace("时", ":").Replace("分", "");
var restTime = TimeSpan.Parse(timeStr);
trData.RealEndTime = DateTime.Now.Add(restTime);
}
var href = tr.LastElementChild.QuerySelector("a")?.Attributes["href"]?.Value;
if (href.Has())
{
var start = href.LastIndexOf('/');
var end = href.IndexOf(".html");
if (start != -1 && end != -1)
{
trData.Id = href.Substring(start + 1, end - start).TrimEnd('.');
}
}
return new ApiResult<OriginAccountModel>(trData);
}
}
}
catch (Exception ex)
{
LogHelper.Error(title, ex.Message+"-->info:"+ info);
return new ApiResult<OriginAccountModel>(ResultCode.C_INVALID_ERROR, "查询失败");
}
return new ApiResult<OriginAccountModel>(ResultCode.C_INVALID_ERROR, "没有查询到信息");
}
/// <summary>
/// 修改账号密码
/// </summary>
/// <param name="productId"></param>
/// <param name="account"></param>
/// <param name="pwd"></param>
/// <returns></returns>
public override async Task<bool> UpdateAccountPwd(string account, string pwd)
{
var ret = await this.GetAccountInfo(account);
if (ret.Code != ResultCode.C_SUCCESS)
{
return false;
}
var accountModel = ret.Data;
if (accountModel == null)
{
return false;
}
var client = CreateHttpClient();
var map = new Dictionary<string, string>(){
{"username",account },
{"password",pwd },
{"submit","提交" },
};
LogHelper.Info(GetOpTitle("UpdateAccountPwd", account), map.ToJson());
try
{
var resp = await client.PostAsForm(this.UpdateUrl + accountModel.Id + ".html", map);
var content = await resp.Content.ReadAsStringAsync();
if (content.Has() && content.IndexOf("更新成功") != -1)
{
return true;
}
else
{
LogHelper.Error(GetOpTitle("UpdateAccountPwd", account), content);
}
}
catch (Exception ex)
{
LogHelper.Error(GetOpTitle("UpdateAccountPwd", account), ex);
}
return false;
}
/// <summary>
/// 退款
/// </summary>
/// <param name="packageId"></param>
/// <param name="account"></param>
/// <returns></returns>
public override async Task<ApiResult> Refund(string account, string packageKey, int days)
{
var client = CreateHttpClient();
var map = new Dictionary<string, string>(){
{"refundUser",account },
{"refundReason","hl" },
};
var title = GetOpTitle("Refund", account);
LogHelper.Info(title, map.ToJson());
try
{
var resp = await client.PostAsForm(this.RefundUrl, map);
var content = await resp.Content.ReadAsStringAsync();
if (content.Has() && content.IndexOf("alert(\"退款成功\")") != -1)
{
return new ApiResult(1);
}
else
{
LogHelper.Error(title, content);
return new ApiResult(ResultCode.C_INVALID_ERROR, "退款失败");
}
}
catch (Exception ex)
{
LogHelper.Error(title, ex.Message);
return new ApiResult(ResultCode.C_INVALID_ERROR, "退款失败");
}
}
/// <summary>
/// 是否在线
/// </summary>
/// <param name="productId"></param>
/// <param name="account"></param>
/// <returns></returns>
public override async Task<ApiResult<List<OriginAccountOnlineModel>>> OnLine(string account)
{
//虚拟在线
var onlines = await base.OnLine(account);
if (onlines.Code == ResultCode.C_SUCCESS && onlines.Data.Count > 0)
return onlines;
var retData = new List<OriginAccountOnlineModel>();
var client = CreateHttpClient();
int page = 1;
var url = string.Format(this.ClientOnlineUrl, page);
var resp = await client.GetAsync(url);
var content = await resp.Content.ReadAsStringAsync();
var parser = new HtmlParser();
var document = await parser.ParseDocumentAsync(content);
var table = document.QuerySelectorAll("table");
var pageP = table?.Next("p")?.FirstOrDefault();
if (pageP != null)
{
var total = 0;
if (pageP.TextContent.Has())
{
var start = pageP.TextContent.IndexOf('(');
var end = pageP.TextContent.IndexOf("页)");
var pageStr = pageP.TextContent.Substring(start + 2, end - start - 1);
int.TryParse(pageStr, out total);
}
if (total > 1)
{
await Enumerable.Range(1, total).ForEachAsync(async (int i) =>
{
var ret = await ClientOnLine(account, i);
retData.AddRange(ret);
});
}
else
{
retData = await ClientOnLine(account, 1);
}
}
else
{
retData = await ClientOnLine(account, 1);
}
return new ApiResult<List<OriginAccountOnlineModel>>(retData);
}
public async Task<List<OriginAccountOnlineModel>> ClientOnLine(string account,int page=1)
{
var client = CreateHttpClient();
var title = GetOpTitle("ClientOnLine", account);
var info = "";
var retData = new List<OriginAccountOnlineModel>();
try
{
var url =string.Format(this.ClientOnlineUrl,page);
var resp = await client.GetAsync(url);
var content = await resp.Content.ReadAsStringAsync();
var parser = new HtmlParser();
var document = await parser.ParseDocumentAsync(content);
var trs = document.QuerySelectorAll("table.table tr").ToList();
if (trs.Count() > 1)
{
foreach (var tr in trs.Skip(1))
{
var tds = tr.QuerySelectorAll("td").ToList();
var tdAccount = tds[1].FirstChild.TextContent;
if (tdAccount != account)
continue;
info = string.Join("", tds.Select(m => m.OuterHtml));
//序号 会员账号 登录时间 在线时长 客户端IP地址 操作
var trData = new OriginAccountOnlineModel
{
Account = account,
LoginTime = tds[2].TextContent,
OnlineTime = tds[3].TextContent,
LoginIP = tds[4].TextContent,
};
var href = tr.LastElementChild.QuerySelector("a")?.Attributes["href"]?.Value;
if (href.Has())
{
var start = href.LastIndexOf('/');
var end = href.IndexOf(".html");
if (start != -1 && end != -1)
{
trData.Id = href.Substring(start + 1, end - start).TrimEnd('.');
}
}
retData.Add(trData);
}
}
return retData;
}
catch (Exception ex)
{
LogHelper.Error(title, ex.Message + "-->info:" + info);
}
return retData;
}
/// <summary>
/// 踢号
/// </summary>
/// <param name="productId"></param>
/// <param name="account"></param>
/// <returns></returns>
public override async Task<bool> KillOut( string id)
{
var flag = await base.KillOut(id);
if (flag) return true;
var client = CreateHttpClient();
var title = GetOpTitle("KillOut", id);
var info = "";
try
{
var url = string.Format(this.KillUrlClient, id);
var resp = await client.GetAsync(url);
var content = await resp.Content.ReadAsStringAsync();
if (content.Has() && content.IndexOf("已经向客户端发送断开消息") != -1)
{
return true;
}
}
catch (Exception ex)
{
LogHelper.Error(title, ex.Message + "-->info:" + info);
}
return false;
}
/// <summary>
/// 是否存在
/// </summary>
/// <param name="account"></param>
/// <returns></returns>
public override async Task<bool> Exist(string account)
{
var client = CreateHttpClient();
var title = GetOpTitle("Exist", account);
LogHelper.Info(title, account);
var testRet = await this.NewAccount("free", account, "1234", 1, 0);
if (testRet.Code == ResultCode.C_SUCCESS)
{
await DeleteAccount(account);
return false;
}
return true;
}
}
}

View File

@@ -0,0 +1,319 @@
using AngleSharp.Html.Parser;
using Hncore.Infrastructure.Common;
using Hncore.Infrastructure.Extension;
using Hncore.Infrastructure.Serializer;
using Hncore.Infrastructure.WebApi;
using Hncore.Pass.Vpn.Model;
using Hncore.Pass.Vpn.Request.Product;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
namespace Hncore.Pass.Vpn.Service
{
//先锋
public class AgentClient5Service : AgentClient1Service
{
string LoginUrl { get; set; } = "main/agentLogin.html";
string LoginCodeUrl { get; set; } = "main/imgcode.html";
string RefrushTokenUrl { get; set; } = "agent.html";
string SingleAddUrl { get; set; } = "agent/memberSingleAdd.html";
string SingleReAddUrl { get; set; } = "agent/memberRenew.html";
string MuiltAddUrl { get; set; } = "agent/memberMuiltAdd.html";
string RefundUrl { get; set; } = "agent/memberRefund/id/{0}.html";
string UpdateUrl = "agent/memberUpdate/id/{0}.html";//agent/memberUpdate/id/1155709.html
string OnlineUrl { get; set; } = "agent/radiusOnline.html?search=1&username=";
string ClientOnlineUrl { get; set; } = "agent/clientOnline.html?search=1&username=";
string KIllUrl { get; set; } = "";
string KillUrlClient = "/agent/disConnect/sessionid/{0}.html";
string KillUrl = "/agent/disConnect/radacctid/{0}.html";
string searchAccountUrl = "agent/memberList/type/1.html?search=1&username=";
string searchTestAccountUrl = "agent/memberList/type/0.html?search=1&username=";
string DeleteUrl { get; set; } = "agent/multiDelMember.html ";
IHttpClientFactory m_HttpClientFactory;
public AgentClient5Service(IHttpClientFactory httpClientFactory):base(httpClientFactory)
{
m_HttpClientFactory = httpClientFactory;
}
/// <summary>
/// 新开
/// </summary>
/// <param name="packageId"></param>
/// <param name="account"></param>
/// <param name="pwd"></param>
/// <returns></returns>
public override async Task<ApiResult> NewAccount(string packageKey, string account, string pwd, int connCount = 1, int accountType = 1, int payCount = 1)
{
var client = CreateHttpClient();
var map = new Dictionary<string, string>(){
{"taocanName",packageKey },
{"username",account },
{"password",pwd },
{"bingfa",connCount.ToString()},
{"type",accountType.ToString()}
};
var title = GetOpTitle("NewAccount", account);
LogHelper.Info(title, map.ToJson());
try
{
var resp = await client.PostAsForm(this.SingleAddUrl, map);
var content = await resp.Content.ReadAsStringAsync();
if (content.Has() && content.IndexOf("{alert(\"成功\")") != -1)
{
return new ApiResult(ResultCode.C_SUCCESS);
}
else
{
LogHelper.Error(title, content);
return new ApiResult(ResultCode.C_INVALID_ERROR, "开户失败");
}
}
catch (Exception ex)
{
LogHelper.Error(title, ex.Message);
return new ApiResult(ResultCode.C_INVALID_ERROR, "开户失败");
}
}
/// <summary>
/// 删除账号
/// </summary>
/// <param name="productId"></param>
/// <param name="account"></param>
/// <returns></returns>
public override async Task<bool> DeleteAccount(string account)
{
var client = CreateHttpClient();
var infoRet = await this.GetAccountInfo(account, true);
if (infoRet.Code != ResultCode.C_SUCCESS)
return false;
var map = new Dictionary<string, string>(){
{infoRet.Data.Id,infoRet.Data.Id },
};
var title = GetOpTitle("DeleteAccount", account);
LogHelper.Info(title, account);
try
{
var resp = await client.PostAsForm(this.DeleteUrl, map);
var content = await resp.Content.ReadAsStringAsync();
if (content.Has() && content.IndexOf("删除成功") != -1)
{
return true;
}
else
{
LogHelper.Error(title, content);
return false;
}
}
catch (Exception ex)
{
LogHelper.Error(title, ex.Message);
return false;
}
}
/// <summary>
/// 修改账号密码
/// </summary>
/// <param name="productId"></param>
/// <param name="account"></param>
/// <param name="pwd"></param>
/// <returns></returns>
public override async Task<bool> UpdateAccountPwd(string account, string pwd)
{
var ret = await this.GetAccountInfo(account);
if (ret.Code != ResultCode.C_SUCCESS)
{
return false;
}
var accountModel = ret.Data;
if (accountModel == null)
{
return false;
}
var client = CreateHttpClient();
var map = new Dictionary<string, string>(){
{"username",account },
{"password",pwd },
{"maxOnline",ret.Data.ConnectCount },
};
LogHelper.Info(GetOpTitle("UpdateAccountPwd", account), map.ToJson());
try
{
var url = string.Format(this.UpdateUrl, accountModel.Id);
var resp = await client.PostAsForm(url, map);
var content = await resp.Content.ReadAsStringAsync();
if (content.Has() && content.IndexOf("更新成功") != -1)
{
return true;
}
else
{
LogHelper.Error(GetOpTitle("UpdateAccountPwd", account), content);
}
}
catch (Exception ex)
{
LogHelper.Error(GetOpTitle("UpdateAccountPwd", account), ex);
}
return false;
}
/// <summary>
/// 退款
/// </summary>
/// <param name="packageId"></param>
/// <param name="account"></param>
/// <returns></returns>
public override async Task<ApiResult> Refund(string account, string packageKey, int days)
{
var client = CreateHttpClient();
var title = GetOpTitle("Refund", account);
try
{
var accountInfo = await this.GetAccountInfo(account);
if (accountInfo.Code != ResultCode.C_SUCCESS)
{
return new ApiResult(ResultCode.C_INVALID_ERROR, "退款失败");
}
var url = string.Format(this.RefundUrl, accountInfo.Data.Id);
var resp = await client.GetAsync(url);
var content = await resp.Content.ReadAsStringAsync();
if (content.Has() && content.IndexOf("退款成功!") != -1)
{
return new ApiResult(1);
}
else
{
LogHelper.Error(title, content);
return new ApiResult(ResultCode.C_INVALID_ERROR, "退款失败");
}
}
catch (Exception ex)
{
LogHelper.Error(title, ex.Message);
return new ApiResult(ResultCode.C_INVALID_ERROR, "退款失败");
}
}
/// <summary>
/// 是否在线
/// </summary>
/// <param name="productId"></param>
/// <param name="account"></param>
/// <returns></returns>
public override async Task<ApiResult<List<OriginAccountOnlineModel>>> OnLine(string account)
{
//虚拟在线
var onlines= await base.OnLine(account);
if (onlines.Code == ResultCode.C_SUCCESS && onlines.Data.Count > 0)
return onlines;
var client = CreateHttpClient();
var title = GetOpTitle("OnLine", account);
var info = "";
try
{
var url = this.ClientOnlineUrl + account;
var resp = await client.GetAsync(url);
var content = await resp.Content.ReadAsStringAsync();
var parser = new HtmlParser();
var document = await parser.ParseDocumentAsync(content);
var trs = document.QuerySelectorAll("table.table tr").ToList();
var retData = new List<OriginAccountOnlineModel>();
if (trs.Count() > 1)
{
foreach (var tr in trs.Skip(1))
{
var tds = tr.QuerySelectorAll("td").ToList();
var tdAccount = tds[1].FirstChild.TextContent;
if (tdAccount != account)
continue;
info = string.Join("", tds.Select(m => m.OuterHtml));
//序号 会员账号 登录时间 在线时长 客户端IP地址 操作
var trData = new OriginAccountOnlineModel
{
Account = account,
LoginTime = tds[2].TextContent,
OnlineTime = tds[3].TextContent,
LoginIP = tds[4].TextContent,
};
var href = tr.LastElementChild.QuerySelector("a")?.Attributes["href"]?.Value;
if (href.Has())
{
var start = href.LastIndexOf('/');
var end = href.IndexOf(".html");
if (start != -1 && end != -1)
{
trData.Id = href.Substring(start + 1, end - start).TrimEnd('.');
}
}
retData.Add(trData);
}
}
return new ApiResult<List<OriginAccountOnlineModel>>(retData);
}
catch (Exception ex)
{
LogHelper.Error(title, ex.Message + "-->info:" + info);
return new ApiResult<List<OriginAccountOnlineModel>>(ResultCode.C_INVALID_ERROR, "查询失败");
}
}
/// <summary>
/// 踢号
/// </summary>
/// <param name="productId"></param>
/// <param name="account"></param>
/// <returns></returns>
public override async Task<bool> KillOut(string id)
{
var flag = await this.KillOutClient(id);
var client = CreateHttpClient();
var title = GetOpTitle("KillOut", id);
var info = "";
try
{
var url = string.Format(this.KillUrl, id);
var resp = await client.GetAsync(url);
var content = await resp.Content.ReadAsStringAsync();
if (content.Has() && content.IndexOf("断开消息已发送") != -1)
{
return true;
}
}
catch (Exception ex)
{
LogHelper.Error(title, ex.Message + "-->info:" + info);
}
return false;
}
public async Task<bool> KillOutClient(string id)
{
var client = CreateHttpClient();
var title = GetOpTitle("KillOutClient", id);
var info = "";
try
{
var url = string.Format(this.KillUrlClient, id);
var resp = await client.GetAsync(url);
var content = await resp.Content.ReadAsStringAsync();
if (content.Has() && content.IndexOf("已经向客户端发送断开消息") != -1)
{
return true;
}
}
catch (Exception ex)
{
LogHelper.Error(title, ex.Message + "-->info:" + info);
}
return false;
}
}
}

View File

@@ -0,0 +1,597 @@
using AngleSharp.Dom;
using AngleSharp.Html.Parser;
using Bogus.DataSets;
using Hncore.Infrastructure.Common;
using Hncore.Infrastructure.Extension;
using Hncore.Infrastructure.Serializer;
using Hncore.Infrastructure.WebApi;
using Hncore.Pass.Vpn.Model;
using Hncore.Pass.Vpn.Request.Product;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
namespace Hncore.Pass.Vpn.Service
{
public class AgentClient6Service : AgentClientBaseService
{
string secretId = "20200716182518182489";
string secretKey = "OFcEJAfzYjWT3e2s";
string UserApiUrl = "userapi/";
string LoginIndexUrl { get; set; } = "login/";
string LoginUrl { get; set; } = "loginauth/";
string LoginCodeUrl { get; set; } = "";
string RefrushTokenUrl { get; set; } = "userInfo/";
string SingleAddUrl { get; set; } = "userapi/";
string SingleReAddUrl { get; set; } = "user_buy_server";
string MuiltAddUrl { get; set; } = "agent/memberMuiltAdd.html";
string RefundUrl { get; set; } = "agent/memberRefundAct.html ";
string UpdateUrl = "setuser";
string OnlineUrl { get; set; } = "active_log/?user=";
string KIllUrl { get; set; } = "agent/disConnect2/radacctid/{0}.html";
string searchAccountUrl = "userList/?sum=100&page=1&search_data=";
string searchTestAccountUrl = "agent/memberList/type/0.html?search=1&username=";
string DeleteUrl { get; set; } = "agent/memberDel/id/";//1160862.html";
IHttpClientFactory m_HttpClientFactory;
public AgentClient6Service(IHttpClientFactory httpClientFactory):base(httpClientFactory)
{
m_HttpClientFactory = httpClientFactory;
}
protected override HttpClient CreateHttpClient(bool autoCooke = true)
{
var client = m_HttpClientFactory.CreateClient("agentClient1.0");
client.BaseAddress = new System.Uri(this.BaseUrl);
if (this.Token.Has() && autoCooke)
{
AddCookie(client, this.Token);
}
return client;
}
private string FormatRequest(Dictionary<string, string> map)
{
map["secretId"] = this.secretId;
map["secretKey"] = this.secretKey;
var data = string.Join("&", map.Select(m => $"{m.Key}={m.Value}"));
return data;
}
public override async Task<int> RefrushStatus()
{
int status = 0;
if (this.Token.Has())
{
var client = CreateHttpClient();
if (this.RefrushTokenUrl.Has())
{
// client.DefaultRequestHeaders.Add("Cookie", this.Token);
var getResp = await client.GetAsync(this.RefrushTokenUrl);
if (getResp.StatusCode == HttpStatusCode.OK)
{
status = 1;
}
else
{
var request = new AgentLoginRequest()
{
Account = this.Product.Account,
Pwd = this.Product.Pwd
};
var ret = await this.Login(request);
if (ret.Code == ResultCode.C_SUCCESS)
{
this.Product.Token = ret.Data.ToString();
status = 1;
}
else
{
Debug.WriteLine("离线");
}
}
}
}
return status;
}
public override async Task<(byte[], string)> GetCode()
{
return (null, "");
}
private async Task<(string, string)> GetHomeCookie()
{
var client = CreateHttpClient(false);
var getResp = await client.GetAsync(this.LoginIndexUrl);
var cookies = this.GetCookies(getResp);
cookies = cookies.Replace("path=/;", "").Replace("httponly", "").Trim();
var content = await getResp.Content.ReadAsStringAsync();
var parser = new HtmlParser();
var document = await parser.ParseDocumentAsync(content);
var csrf_tokenNode = document.QuerySelector("input[name=csrfmiddlewaretoken]");//<input type='hidden' name='csrfmiddlewaretoken' value='b8XKenjQ9GJUJF0xSZySXLsG5FGNHepk' />
var csrf_token = csrf_tokenNode.GetAttribute("value");
return (cookies, csrf_token);
}
public override async Task<ApiResult> Login(AgentLoginRequest request)
{
var tokens = await this.GetHomeCookie();
var client = CreateHttpClient(false);
client.DefaultRequestHeaders.Add("Connection", "keep-alive");
client.DefaultRequestHeaders.Add("Upgrade-Insecure-Requests", "1");
var csrftoken = this.GetCookieValue(tokens.Item1, "csrftoken");
var key = this.GetCookieValue(tokens.Item1, "key");
var map = new Dictionary<string, string>(){
{"csrfmiddlewaretoken",tokens.Item2},
{"username",request.Account },
{"password",request.Pwd },
{"remember",key },
};
LogHelper.Info("Login", map.ToJson());
var loginToken = $"csrftoken={csrftoken};key={key}";
AddCookie(client, loginToken);
var resp = await client.PostAsForm(this.LoginUrl, map);
var content = await resp.Content.ReadAsStringAsync();
if (resp.StatusCode != HttpStatusCode.Found || resp.Headers.Location.ToString().IndexOf("http://user.webok.me/userInfo/")==-1)
{
return new ApiResult(ResultCode.C_VISITOR_CHECKING, "登录失败");
}
var sessionid = this.GetCookie(resp, "sessionid");
var username_user = this.GetCookie(resp, "username_user");
request.Key = $"{loginToken};{sessionid};{username_user}";
return new ApiResult(request.Key);
}
public override bool CheckAccount(int productId,List<string> accounts)
{
return false;
}
/// <summary>
/// 新开
/// </summary>
/// <param name="packageId"></param>
/// <param name="account"></param>
/// <param name="pwd"></param>
/// <returns></returns>
public override async Task<ApiResult> NewAccount(string packageKey, string account, string pwd, int connCount = 1, int accountType = 1, int payCount = 1)
{
if (packageKey == "test_pay")
return await NewTestAccount(account, pwd);
var client = CreateHttpClient();
var map = new Dictionary<string, string>(){
{"type","adduser" },
{"user",account },
{"pass",pwd },
{"logincount",connCount.ToString()},
{"serverid",packageKey },
};
var title = GetOpTitle("NewAccount", account);
LogHelper.Info(title, map.ToJson());
try
{
var resp = await client.GetAsync(this.UserApiUrl + "?" + this.FormatRequest(map));
var content = await resp.Content.ReadAsStringAsync();
JObject jo = (JObject)JsonConvert.DeserializeObject(content);
var status = jo["code"].ToString();
if (status == "1")
{
return new ApiResult(ResultCode.C_SUCCESS);
}
else
{
LogHelper.Error(title, content);
return new ApiResult(ResultCode.C_INVALID_ERROR, "开户失败");
}
}
catch (Exception ex)
{
LogHelper.Error(title, ex.GetInfo());
return new ApiResult(ResultCode.C_INVALID_ERROR, "开户失败");
}
}
/// <summary>
/// 新开测试账号
/// </summary>
/// <param name="account"></param>
/// <param name="pwd"></param>
/// <returns></returns>
public async Task<ApiResult> NewTestAccount(string account, string pwd)
{
var client = CreateHttpClient();
var map = new Dictionary<string, string>(){
{"user",account},
{"pass",pwd },
{"type","newuser" },
{"logincount","1"},
{"serverid","test_pay" },
{"username",this.Product.Account },
{"otherserver","no" },
};
var title = GetOpTitle("NewTestAccount", account);
LogHelper.Info(title, map.ToJson());
try
{
var resp = await client.PostAsForm("userRegisterAdd/" , map);
var content = await resp.Content.ReadAsStringAsync();
JObject jo = (JObject)JsonConvert.DeserializeObject(content);
var status = jo["code"].ToString();
if (status == "1")
{
return new ApiResult(ResultCode.C_SUCCESS);
}
else
{
LogHelper.Error(title, content);
return new ApiResult(ResultCode.C_INVALID_ERROR, "开户失败");
}
}
catch (Exception ex)
{
LogHelper.Error(title, ex.Message);
return new ApiResult(ResultCode.C_INVALID_ERROR, "开户失败");
}
}
/// <summary>
/// 新开
/// </summary>
/// <param name="packageId"></param>
/// <param name="account"></param>
/// <param name="pwd"></param>
/// <returns></returns>
public override async Task<ApiResult> NewMuiltAccount(string packageKey, string account, string pwd, int connCount = 1, int accountType = 1,int startNum=0, int endNum=1 )
{
var client = CreateHttpClient();
var map = new Dictionary<string, string>(){
{"taocanName",packageKey },
{"usernameTpl",account },
{"password",pwd },
{"maxonline",connCount.ToString()},
{"startNum",startNum.ToString()},
{"endNum",endNum.ToString()},
{"mode",accountType.ToString()},
};
var title = GetOpTitle("NewMuiltAccount", account);
LogHelper.Info(title, map.ToJson());
try
{
var resp = await client.PostAsForm(this.MuiltAddUrl, map);
var content = await resp.Content.ReadAsStringAsync();
if (content.Has() && content.IndexOf("<td>成功</td>") != -1)
{
return new ApiResult(1);
}
else
{
LogHelper.Error(title, content);
return new ApiResult(ResultCode.C_INVALID_ERROR, "开户失败");
}
}
catch (Exception ex)
{
LogHelper.Error(title, ex.Message);
return new ApiResult(ResultCode.C_INVALID_ERROR, "开户失败");
}
}
/// <summary>
/// 续费
/// </summary>
/// <param name="productId"></param>
/// <param name="account"></param>
/// <param name="pwd"></param>
/// <returns></returns>
public override async Task<ApiResult> NewReAccount(string packageKey, string account, int connCount)
{
var ret = await this.GetAccountInfo(account);
if (ret.Code != ResultCode.C_SUCCESS|| ret.Data==null)
{
return new ApiResult(ResultCode.C_INVALID_ERROR, "账户不存在,续费失败");
}
var client = CreateHttpClient();
var map = new Dictionary<string, string>(){
{"user",account },
{"serverid",packageKey },
{"type","buy" },
};
var title = GetOpTitle("NewReAccount", account);
LogHelper.Info(title, map.ToJson());
try
{
var resp = await client.GetAsync(this.UserApiUrl + "?" + this.FormatRequest(map));
var content = await resp.Content.ReadAsStringAsync();
JObject jo = (JObject)JsonConvert.DeserializeObject(content);
var status = jo["code"].ToString();
if (status == "1")
{
return new ApiResult(ResultCode.C_SUCCESS);
}
else
{
LogHelper.Error(title, content);
return new ApiResult(ResultCode.C_INVALID_ERROR, "续费失败");
}
}
catch (Exception ex)
{
LogHelper.Error(title, ex.Message);
return new ApiResult(ResultCode.C_INVALID_ERROR, "续费失败");
}
}
/// <summary>
/// 删除账号
/// </summary>
/// <param name="productId"></param>
/// <param name="account"></param>
/// <returns></returns>
public override async Task<bool> DeleteAccount(string account)
{
return false;
}
/// <summary>
/// 得到账号信息
/// </summary>
/// <param name="productId"></param>
/// <param name="account"></param>
/// <returns></returns>
public override async Task<ApiResult<OriginAccountModel>> GetAccountInfo(string account, bool isTest = false)
{
var client = CreateHttpClient();
var map = new Dictionary<string, string>(){
{"user",account },
{"type","getuserinfo" },
};
var title = GetOpTitle("GetAccountInfo", account);
try
{
var searchUser = $"userList/?sum=100&page=1&search_data={account}";
var resp = await client.GetAsync(searchUser);
var content = await resp.Content.ReadAsStringAsync();
var parser = new HtmlParser();
var document = await parser.ParseDocumentAsync(content);
////table class="table table-bordered"
var trs = document.QuerySelectorAll("#datatable tr").ToList();
// var trs= table.QuerySelectorAll("tr").ToList();
var retData = new List<OriginAccountModel>();
var info = "";
if (trs.Count() > 1)
{
//var tr = trs.Skip(1).FirstOrDefault();
foreach (var tr in trs.Skip(1))
{
var tds = tr.QuerySelectorAll("td").ToList();
var tdAccount = tds[1].TextContent;
if (tdAccount != account)
continue;
info = string.Join("", tds.Select(m => m.OuterHtml));
var trData = new OriginAccountModel
{
Account = account,
Pwd = tds[2].TextContent,
AccountType = tds[3].TextContent,
Package = tds[3].TextContent,
RegistTime = tds[5].TextContent,
EndTime = tds[6].TextContent,
ConnectCount = tds[4].TextContent,
IsActive = tds[7].TextContent,
Remark = tds[8].TextContent,
};
trData.RealEndTime = DateTime.Parse(trData.EndTime);
if (trData.RealEndTime < DateTime.Now)
{
trData.RestTime = "已过期";
}
else
{
trData.RestTime = (trData.RealEndTime - DateTime.Now).ToString(@"dd\.hh\:mm\:ss");
}
var button = tr.LastElementChild.QuerySelector("button")?.Attributes["onclick"]?.Value;
if (button.Has())
{
var start = button.IndexOf('(');
var end = button.IndexOf(")");
if (start != -1 && end != -1)
{
trData.Id = button.Substring(start + 1, end - start);
}
}
return new ApiResult<OriginAccountModel>(trData);
}
}
}
catch (Exception ex)
{
LogHelper.Error(title, ex.Message);
}
return new ApiResult<OriginAccountModel>(ResultCode.C_INVALID_ERROR, "没有查询到信息");
}
/// <summary>
/// 修改账号密码
/// </summary>
/// <param name="productId"></param>
/// <param name="account"></param>
/// <param name="pwd"></param>
/// <returns></returns>
public override async Task<bool> UpdateAccountPwd(string account, string pwd)
{
var client = CreateHttpClient();
var map = new Dictionary<string, string>(){
{"user",account },
{"new_pwd",pwd },
{"type","setuser" },
};
var title = GetOpTitle("UpdateAccountPwd", account);
LogHelper.Info(title, map.ToJson());
try
{
var resp = await client.GetAsync(this.UserApiUrl + "?" + this.FormatRequest(map));
var content = await resp.Content.ReadAsStringAsync();
JObject jo = (JObject)JsonConvert.DeserializeObject(content);
var status = jo["code"].ToString();
if (status == "1")
{
return true;
}
else
{
LogHelper.Error(title, content);
return false;
}
}
catch (Exception ex)
{
LogHelper.Error(GetOpTitle("UpdateAccountPwd", account), ex);
}
return false;
}
/// <summary>
/// 退款
/// </summary>
/// <param name="packageId"></param>
/// <param name="account"></param>
/// <returns></returns>
public override async Task<ApiResult> Refund(string account, string packageKey, int days)
{
var title = GetOpTitle("Refund", account);
LogHelper.Info(title, account);
return new ApiResult(ResultCode.C_INVALID_ERROR, "退款失败-不支持退款");
}
/// <summary>
/// 是否在线
/// </summary>
/// <param name="productId"></param>
/// <param name="account"></param>
/// <returns></returns>
public override async Task<ApiResult<List<OriginAccountOnlineModel>>> OnLine(string account)
{
var client = CreateHttpClient();
var title = GetOpTitle("OnLine", account);
var info = "";
try
{
var url = this.OnlineUrl + account;
var resp = await client.GetAsync(url);
var content = await resp.Content.ReadAsStringAsync();
var parser = new HtmlParser();
var document = await parser.ParseDocumentAsync(content);
var trs = document.QuerySelectorAll("table.table tr").ToList();
var retData = new List<OriginAccountOnlineModel>();
if (trs.Count() > 1)
{
foreach (var tr in trs.Skip(1))
{
var tds = tr.QuerySelectorAll("td").ToList();
var tdAccount = tds[1].FirstChild.TextContent;
if (tdAccount != account)
continue;
info = string.Join("", tds.Select(m => m.OuterHtml));
//序号 会员账号 服务器IP 登录时间 在线时长 会员IP 上行流量 下行流量 操作
var trData = new OriginAccountOnlineModel
{
Account = account,
ServerIP = tds[6].TextContent,
LoginTime = tds[1].TextContent,
OnlineTime = tds[3].TextContent,
LoginIP = tds[5].TextContent,
UpStream = tds[4].TextContent,
DownStream = tds[4].TextContent,
Id= account,
};
var href = tr.LastElementChild.QuerySelector("a")?.Attributes["href"]?.Value;
if (href.Has())
{
var start = href.LastIndexOf('/');
var end = href.IndexOf(".html");
if (start != -1 && end != -1)
{
trData.Id = href.Substring(start + 1, end - start).TrimEnd('.');
}
}
retData.Add(trData);
}
}
return new ApiResult<List<OriginAccountOnlineModel>>(retData);
}
catch (Exception ex)
{
LogHelper.Error(title, ex.Message + "-->info:" + info);
return new ApiResult<List<OriginAccountOnlineModel>>(ResultCode.C_INVALID_ERROR, "查询失败");
}
}
/// <summary>
/// 踢号
/// </summary>
/// <param name="productId"></param>
/// <param name="account"></param>
/// <returns></returns>
public override async Task<bool> KillOut( string id)
{
var client = CreateHttpClient();
var title = GetOpTitle("KillOut", id);
var info = "";
try
{
var url = string.Format(this.KIllUrl, id);
var resp = await client.GetAsync(url);
var content = await resp.Content.ReadAsStringAsync();
if(content.Has()&&content.IndexOf("断开成功")!=-1)
{
return true;
}
}
catch (Exception ex)
{
LogHelper.Error(title, ex.Message + "-->info:" + info);
}
return false;
}
/// <summary>
/// 是否存在
/// </summary>
/// <param name="account"></param>
/// <returns></returns>
public override async Task<bool> Exist(string account)
{
var client = CreateHttpClient();
var title = GetOpTitle("Exist", account);
LogHelper.Info(title, account);
string url = $"userapi3/?secretId={secretId}&secretKey={secretKey}&type=getuserlenNum&user={account}";
var resp = await client.GetAsync(url);
var content = await resp.Content.ReadAsStringAsync();
JObject jo = (JObject)JsonConvert.DeserializeObject(content);
var status = jo["code"].ToString();
if (status == "1")
{
var count = jo["count"].ToInt();
return count > 0;
}
else
{
return false;
}
}
}
}

View File

@@ -0,0 +1,532 @@
using AngleSharp;
using AngleSharp.Dom;
using AngleSharp.Html.Parser;
using Hncore.Infrastructure.Common;
using Hncore.Infrastructure.Extension;
using Hncore.Infrastructure.Serializer;
using Hncore.Infrastructure.WebApi;
using Hncore.Pass.Vpn.Model;
using Hncore.Pass.Vpn.Request.Product;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Security.Cryptography;
using System.Threading.Tasks;
namespace Hncore.Pass.Vpn.Service
{
public class AgentClient7Service : AgentClientBaseService
{
string apiId = "131";
string apiKey = "icJZ5ty7csDcmN4aZk25YCd5K5SCiRbf";
string LoginIndexUrl { get; set; } = "login";
string LoginUrl { get; set; } = "login";
string LoginCodeUrl { get; set; } = "";
string RefrushTokenUrl { get; set; } = "my";
string SingleAddUrl { get; set; } = "api/add";
string SingleReAddUrl { get; set; } = "api/renewal";
string MuiltAddUrl { get; set; } = "agent/memberMuiltAdd.html";
string RefundUrl { get; set; } = "agent/memberRefundAct.html ";
string UpdateUrl = "api/edit";
string OnlineLoginUrl { get; set; } = "online";
string OnlineUrl { get; set; } = "ppp/oln?";
string KIllUrl { get; set; } = "agent/disConnect2/radacctid/{0}.html";
string searchAccountUrl = "api/get";
string DeleteUrl { get; set; } = "api/del";//1160862.html";
string ExistUrl = "api/verify";
IHttpClientFactory m_HttpClientFactory;
public AgentClient7Service(IHttpClientFactory httpClientFactory) : base(httpClientFactory)
{
m_HttpClientFactory = httpClientFactory;
}
protected override HttpClient CreateHttpClient(bool autoCooke = true)
{
var client = m_HttpClientFactory.CreateClient("agentClient1.0");
client.BaseAddress = new System.Uri(this.BaseUrl);
if (this.Token.Has() && autoCooke)
{
AddCookie(client, this.Token);
}
return client;
}
public override async Task<int> RefrushStatus()
{
int status = 0;
if (this.Token.Has())
{
var client = CreateHttpClient();
if (this.RefrushTokenUrl.Has())
{
// client.DefaultRequestHeaders.Add("Cookie", this.Token);
var getResp = await client.GetAsync(this.RefrushTokenUrl);
if (getResp.StatusCode == HttpStatusCode.OK)
{
status = 1;
}
else
{
var request = new AgentLoginRequest()
{
Account = this.Product.Account,
Pwd = this.Product.Pwd
};
var ret = await this.Login(request);
if (ret.Code == ResultCode.C_SUCCESS)
{
this.Product.Token = ret.Data.ToString();
status = 1;
}
else
{
Debug.WriteLine("离线");
}
}
}
}
return status;
}
private async Task<(string, string)> GetHomeCookie()
{
var client = CreateHttpClient(false);
client.BaseAddress = new Url("http://dl.91ip.vip/");
var getResp = await client.GetAsync(this.LoginIndexUrl);
var cookies = this.GetCookies(getResp);
cookies = cookies.Replace("path=/;", "").Replace("httponly", "").Trim();
var content = await getResp.Content.ReadAsStringAsync();
var parser = new HtmlParser();
var document = await parser.ParseDocumentAsync(content);
var csrf_tokenNode = document.QuerySelector("meta[name=csrf-token]");//<meta name="csrf-token" content="WfjPwY-RY_A_3d09abknzQm-eRDaVnDeMNRxN-juDDEYzomD3cshgk-zk3M94FC9P8Yte6AjCvMCmz4BmYZvSw==">
var csrf_token = csrf_tokenNode.GetAttribute("content");
return (cookies, csrf_token);
}
public override async Task<ApiResult> Login(AgentLoginRequest request)
{
var tokens = await this.GetHomeCookie();
var client = CreateHttpClient(false);
client.BaseAddress = new Url("http://dl.91ip.vip/");
client.DefaultRequestHeaders.Add("Connection", "keep-alive");
client.DefaultRequestHeaders.Add("Upgrade-Insecure-Requests", "1");
var map = new Dictionary<string, string>(){
{"_csrf-daili",tokens.Item2},
{"LoginForm[username]",request.Account },
{"LoginForm[password]",request.Pwd },
};
LogHelper.Info("Login", map.ToJson());
var csrf = GetCookieValue(tokens.Item1, "_csrf-daili");
AddCookie(client, $"_csrf-daili={csrf}");
var resp = await client.PostAsForm(this.LoginUrl, map);
var content = await resp.Content.ReadAsStringAsync();
if (resp.StatusCode != HttpStatusCode.OK || content.IndexOf("成功") == -1)
{
return new ApiResult(ResultCode.C_VISITOR_CHECKING, "登录失败");
}
var frontend = this.GetCookie(resp, "advanced-frontend");
csrf = this.GetCookie(resp, "_csrf-daili");
request.Key = $"{frontend};{csrf}";
return new ApiResult(request.Key);
}
public override bool CheckAccount(int productId,List<string> accounts)
{
return false;
}
private string Sign(SortedDictionary<string, string> map)
{
map["apiid"] = this.apiId;
map["sendtime"] = DateTime.Now.GetUnixTimeStamp().ToString();
var data = string.Join("&", map.Select(m => $"{m.Key}={m.Value}"));
var signStr = Md5(data + apiKey);
data = $"{data}&sign={signStr}";
return data;
}
//Md5摘要
private static string Md5(string text)
{
MD5 md5 = new MD5CryptoServiceProvider();
byte[] fromData = System.Text.Encoding.UTF8.GetBytes(text);
byte[] targetData = md5.ComputeHash(fromData);
string byte2String = null;
for (int i = 0; i < targetData.Length; i++)
{
byte2String += targetData[i].ToString("x2");
}
return byte2String;
}
/// <summary>
/// 新开
/// </summary>
/// <param name="packageId"></param>
/// <param name="account"></param>
/// <param name="pwd"></param>
/// <returns></returns>
public override async Task<ApiResult> NewAccount(string packageKey, string account, string pwd, int connCount = 1, int accountType = 1, int payCount = 1)
{
var client = CreateHttpClient();
var map = new SortedDictionary<string, string>(){
{"user",account },
{"passwd",pwd },
{"num","1"},
{"conn_max",connCount.ToString() },
{"test",packageKey=="test"?"1":"0" },
{"type",packageKey=="test"?"d":packageKey },
{"paynum","1" },
};
var title = GetOpTitle("NewAccount", account);
LogHelper.Info(title, map.ToJson());
try
{
var resp = await client.GetAsync(this.SingleAddUrl+"?"+ Sign(map));
var content = await resp.Content.ReadAsStringAsync();
JObject jo = (JObject)JsonConvert.DeserializeObject(content);
var status = jo["status"].ToString();
if (status =="200")
{
var retAccount=jo["data"].ToArray().FirstOrDefault();
var id = retAccount["id"].ToString();
return new ApiResult(ResultCode.C_SUCCESS) { Data=id};
}
else
{
var info = jo["info"].ToString();
LogHelper.Error(title, content);
return new ApiResult(ResultCode.C_INVALID_ERROR, info);
}
}
catch (Exception ex)
{
LogHelper.Error(title, ex.Message);
return new ApiResult(ResultCode.C_INVALID_ERROR, "开户失败");
}
}
/// <summary>
/// 续费
/// </summary>
/// <param name="productId"></param>
/// <param name="account">原始的账号的id</param>
/// <param name="pwd"></param>
/// <returns></returns>
public override async Task<ApiResult> NewReAccount(string packageKey, string id, int connCount)
{
var ret = await this.GetAccountInfo(id);
if (ret.Code != ResultCode.C_SUCCESS|| ret.Data==null)
{
return new ApiResult(ResultCode.C_INVALID_ERROR, "账户不存在,续费失败");
}
var client = CreateHttpClient();
var map = new SortedDictionary<string, string>(){
{"id",id }, //原始的账号的id
{"type",packageKey },
{"paynum","1" },
};
var title = GetOpTitle("NewReAccount", id);
LogHelper.Info(title, map.ToJson());
try
{
var resp = await client.GetAsync(this.SingleReAddUrl + "?" + Sign(map));
var content = await resp.Content.ReadAsStringAsync();
JObject jo = (JObject)JsonConvert.DeserializeObject(content);
var status = jo["status"].ToString();
if (status =="200")
{
return new ApiResult(ResultCode.C_SUCCESS);
}
else
{
var info = jo["info"].ToString();
LogHelper.Error(title, content);
return new ApiResult(ResultCode.C_INVALID_ERROR, info);
}
}
catch (Exception ex)
{
LogHelper.Error(title, ex.Message);
return new ApiResult(ResultCode.C_INVALID_ERROR, "续费失败");
}
}
/// <summary>
/// 删除账号
/// </summary>
/// <param name="productId"></param>
/// <param name="account"></param>
/// <returns></returns>
public override async Task<bool> DeleteAccount(string id)
{
var client = CreateHttpClient();
var map = new SortedDictionary<string, string>(){
{"id",id },
};
var title = GetOpTitle("DeleteAccount", id);
LogHelper.Info(title, id);
try
{
var resp = await client.GetAsync(this.DeleteUrl + "?" + Sign(map));
var content = await resp.Content.ReadAsStringAsync();
JObject jo = (JObject)JsonConvert.DeserializeObject(content);
var status = jo["status"].ToString();
if (status=="200")
{
return true;
}
else
{
LogHelper.Error(title, content);
return false;
}
}
catch (Exception ex)
{
LogHelper.Error(title, ex.Message);
return false;
}
}
/// <summary>
/// 得到账号信息
/// </summary>
/// <param name="productId"></param>
/// <param name="account"></param>
/// <returns></returns>
public override async Task<ApiResult<OriginAccountModel>> GetAccountInfo(string id, bool isTest=false)
{
var client = CreateHttpClient();
var map = new SortedDictionary<string, string>(){
{"id",id },
};
var title = GetOpTitle("GetAccountInfo", id);
try
{
var resp = await client.GetAsync(this.searchAccountUrl + "?" + Sign(map));
var content = await resp.Content.ReadAsStringAsync();
JObject jo = (JObject)JsonConvert.DeserializeObject(content);
var status = jo["status"].ToString();
if (status == "200")
{
var data = jo["data"];
var trData = new OriginAccountModel
{
Id = data["id"].ToString(),
Account = data["user"].ToString(),
Pwd = data["passwd"].ToString(),
AccountType = data["type"].ToString(),
Package = "",
ConnectCount = data["conn_max"].ToString(),
RegistTime = data["add_time"].ToString(),
EndTime = data["end_time"].ToString(),
RestTime = "",
Amount = data["money"].ToString(),
Remark = data["details"].ToString(),
};
return new ApiResult<OriginAccountModel>(trData);
}
else
{
var info = jo["info"].ToString();
LogHelper.Error(title, content);
return new ApiResult<OriginAccountModel>(ResultCode.C_INVALID_ERROR, "没有查询到信息");
}
}
catch (Exception ex)
{
LogHelper.Error(title, ex.Message);
return new ApiResult<OriginAccountModel>(ResultCode.C_INVALID_ERROR, "查询失败");
}
}
/// <summary>
/// 修改账号密码
/// </summary>
/// <param name="productId"></param>
/// <param name="account"></param>
/// <param name="pwd"></param>
/// <returns></returns>
public override async Task<bool> UpdateAccountPwd(string account, string pwd)
{
var client = CreateHttpClient();
var map = new SortedDictionary<string, string>(){
{"id",Raw },
{"user",account },
{"passwd",pwd },
};
LogHelper.Info(GetOpTitle("UpdateAccountPwd", account), map.ToJson());
try
{
var resp = await client.GetAsync(this.UpdateUrl + "?" + Sign(map));
var content = await resp.Content.ReadAsStringAsync();
JObject jo = (JObject)JsonConvert.DeserializeObject(content);
var status = jo["status"].ToString();
if (status == "200")
{
return true;
}
else
{
LogHelper.Error(GetOpTitle("UpdateAccountPwd", account), content);
}
}
catch (Exception ex)
{
LogHelper.Error(GetOpTitle("UpdateAccountPwd", account), ex);
}
return false;
}
/// <summary>
/// 退款
/// </summary>
/// <param name="packageId"></param>
/// <param name="account"></param>
/// <returns></returns>
public override async Task<ApiResult> Refund(string id, string packageKey, int days)
{
var ret = await this.DeleteAccount(id);
if (ret)
{
return new ApiResult(ResultCode.C_SUCCESS);
}
else
{
return new ApiResult(ResultCode.C_INVALID_ERROR, "退款失败");
}
}
/// <summary>
/// 是否在线
/// </summary>
/// <param name="productId"></param>
/// <param name="account"></param>
/// <returns></returns>
public override async Task<ApiResult<List<OriginAccountOnlineModel>>> OnLine(string account)
{
var client = CreateHttpClient(false);
client.BaseAddress = new Url("http://dl.91ip.vip/");
var title = GetOpTitle("OnLine", account);
var info = "";
try
{
var resp = await client.GetAsync(this.OnlineUrl+ "user="+account);
var content = await resp.Content.ReadAsStringAsync();
var parser = new HtmlParser();
var document = await parser.ParseDocumentAsync(content);
var trs = document.QuerySelectorAll("table.table tr").ToList();
var retData = new List<OriginAccountOnlineModel>();
if (trs.Count() > 1)
{
foreach (var tr in trs.Skip(1))
{
var tds = tr.QuerySelectorAll("td").ToList();
var tdAccount = tds[1].FirstChild.TextContent;
if (tdAccount != account)
continue;
info = string.Join("", tds.Select(m => m.OuterHtml));
var trData = new OriginAccountOnlineModel
{
Account = account,
ServerIP = tds[1].TextContent,
OnlineTime = tds[2].TextContent,
Id= account,
};
var href = tr.LastElementChild.QuerySelector("a")?.Attributes["href"]?.Value;
if (href.Has())
{
var start = href.LastIndexOf('/');
var end = href.IndexOf(".html");
if (start != -1 && end != -1)
{
trData.Id = href.Substring(start + 1, end - start).TrimEnd('.');
}
}
retData.Add(trData);
}
}
return new ApiResult<List<OriginAccountOnlineModel>>(retData);
}
catch (Exception ex)
{
LogHelper.Error(title, ex.Message + "-->info:" + info);
return new ApiResult<List<OriginAccountOnlineModel>>(ResultCode.C_INVALID_ERROR, "查询失败");
}
}
/// <summary>
/// 踢号
/// </summary>
/// <param name="productId"></param>
/// <param name="account"></param>
/// <returns></returns>
public override async Task<bool> KillOut( string id)
{
var client = CreateHttpClient();
var title = GetOpTitle("KillOut", id);
var info = "";
try
{
var url = string.Format(this.KIllUrl, id);
var resp = await client.GetAsync(url);
var content = await resp.Content.ReadAsStringAsync();
if(content.Has()&&content.IndexOf("断开成功")!=-1)
{
return true;
}
}
catch (Exception ex)
{
LogHelper.Error(title, ex.Message + "-->info:" + info);
}
return false;
}
/// <summary>
/// 是否存在
/// </summary>
/// <param name="account"></param>
/// <returns></returns>
public override async Task<bool> Exist(string account)
{
var client = CreateHttpClient();
var map = new SortedDictionary<string, string>(){
{"user",account }
};
var title = GetOpTitle("Exist", account);
LogHelper.Info(title, account);
try
{
var resp = await client.GetAsync(this.ExistUrl + "?" + Sign(map));
var content = await resp.Content.ReadAsStringAsync();
JObject jo = (JObject)JsonConvert.DeserializeObject(content);
var status = jo["status"].ToString();
if (status != "200")
{
return true;
}
else
{
return false;
}
}
catch (Exception ex)
{
LogHelper.Error(title, ex);
}
return false;
}
}
}

View File

@@ -0,0 +1,223 @@
using Hncore.Infrastructure.Service;
using Hncore.Pass.Vpn.Domain;
using Hncore.Pass.Vpn.Request.Product;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using Hncore.Infrastructure.Extension;
using Hncore.Infrastructure.WebApi;
using System.Diagnostics;
using System.IO;
using System.Net;
using Microsoft.EntityFrameworkCore;
using Hncore.Pass.Vpn.Model;
namespace Hncore.Pass.Vpn.Service
{
public abstract class AgentClientBaseService
{
protected string BaseUrl { get; set; }
protected string Token { get; set; }
string LoginUrl { get; set; }
string LoginCodeUrl { get; set; }
string RefrushTokenUrl { get; set; }
string SingleAddUrl { get; set; }
string SingleReAddUrl { get; set; }
string MuiltAddUrl { get; set; }
string RefundUrl { get; set; }
string OnlineUrl { get; set; }
string KIllUrl { get; set; }
string UpdateUrl { get; set; }
public string ClientName { get; set; }
public string Raw { get; set; }
IHttpClientFactory m_HttpClientFactory;
public AgentClientBaseService(IHttpClientFactory httpClientFactory)
{
m_HttpClientFactory = httpClientFactory;
}
public ProductEntity Product { get; set; }
public void Init(string BaseUrl,string Token)
{
this.BaseUrl = BaseUrl;
this.Token = Token;
}
public virtual string GetOpTitle(string op,string account)
{
return $"{this.ClientName}_{op}_{account}";
}
protected virtual HttpClient CreateHttpClient(bool autoCooke = true)
{
var client = m_HttpClientFactory.CreateClient("agentClient");
client.BaseAddress = new System.Uri(this.BaseUrl);
if (this.Token.Has()&& autoCooke)
{
AddCookie(client, this.Token);
}
return client;
}
protected virtual void AddCookie(HttpClient client, string cookie)
{
client.DefaultRequestHeaders.Remove("Cookie");
client.DefaultRequestHeaders.Add("Cookie", cookie);
}
public string GetCookie(HttpResponseMessage resp, string name)
{
if (resp.Headers.TryGetValues("Set-Cookie", out IEnumerable<string> cookies))
{
foreach (var cookie in cookies)
{
var ret = cookie.Split(";").FirstOrDefault(m => m.IndexOf(name) != -1);
if (ret.Has())
return ret;
}
}
return "";
}
public string GetCookies(HttpResponseMessage resp)
{
if (resp.Headers.TryGetValues("Set-Cookie", out IEnumerable<string> cookies))
{
return string.Join(";", cookies);
}
return "";
}
protected string GetCookieValue(string cookies, string name)
{
foreach (var item in cookies.Split(";"))
{
var token = item.Split("=");
if (token.Length == 2 && token[0] == name)
{
return token[1];
}
}
return "";
}
public virtual async Task<int> RefrushStatus()
{
return 0;
}
public virtual async Task<(byte[], string)> GetCode()
{
return (null, "");
}
public virtual async Task<ApiResult> Login(AgentLoginRequest request)
{
return new ApiResult();
}
public virtual bool CheckAccount(int productId,List<string> accounts)
{
return false;
}
/// <summary>
/// 新开
/// </summary>
/// <param name="packageId"></param>
/// <param name="account"></param>
/// <param name="pwd"></param>
/// <returns></returns>
public virtual async Task<ApiResult> NewAccount(string packageKey, string account,string pwd,int connCount=1,int accountType=1, int payCount = 1)
{
return new ApiResult();
}
public virtual async Task<ApiResult> NewMuiltAccount(string packageKey, string account, string pwd, int connCount = 1, int accountType = 1, int startNum = 0, int endNum = 1)
{
return new ApiResult();
}
/// <summary>
/// 续费
/// </summary>
/// <param name="productId"></param>
/// <param name="account"></param>
/// <param name="pwd"></param>
/// <returns></returns>
public virtual async Task<ApiResult> NewReAccount(string packageKey,string account,int connCount)
{
return new ApiResult();
}
/// <summary>
/// 删除账号
/// </summary>
/// <param name="productId"></param>
/// <param name="account"></param>
/// <returns></returns>
public virtual async Task<bool> DeleteAccount(string account)
{
return true;
}
/// <summary>
/// 得到账号信息
/// </summary>
/// <param name="productId"></param>
/// <param name="account"></param>
/// <returns></returns>
public virtual async Task<ApiResult<OriginAccountModel>> GetAccountInfo(string account, bool isTest = false)
{
return new ApiResult<OriginAccountModel>();
}
/// <summary>
/// 修改账号密码
/// </summary>
/// <param name="productId"></param>
/// <param name="account"></param>
/// <param name="pwd"></param>
/// <returns></returns>
public virtual async Task<bool> UpdateAccountPwd(string account,string pwd)
{
return true;
}
/// <summary>
/// 退款
/// </summary>
/// <param name="packageId"></param>
/// <param name="account"></param>
/// <returns></returns>
public virtual async Task<ApiResult> Refund(string account, string packageKey, int days)
{
return new ApiResult();
}
/// <summary>
/// 是否在线
/// </summary>
/// <param name="productId"></param>
/// <param name="account"></param>
/// <returns></returns>
public virtual async Task<ApiResult<List<OriginAccountOnlineModel>>> OnLine(string account)
{
return new ApiResult<List<OriginAccountOnlineModel>>();
}
/// <summary>
/// 踢号
/// </summary>
/// <param name="productId"></param>
/// <param name="account"></param>
/// <returns></returns>
public virtual async Task<bool> KillOut(string account)
{
return true;
}
/// <summary>
/// 是否存在
/// </summary>
/// <param name="account"></param>
/// <returns></returns>
public virtual async Task<bool> Exist(string account)
{
return true;
}
}
}

View File

@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
namespace Hncore.Pass.Vpn.Service
{
public class AgentClientLogHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
if (request.Headers.Contains("hl"))
{
Console.WriteLine(request.RequestUri.ToString());
}
return base.SendAsync(request, cancellationToken);
}
}
}

View File

@@ -0,0 +1,419 @@
using Hncore.Infrastructure.Common;
using Hncore.Infrastructure.Extension;
using Hncore.Infrastructure.Service;
using Hncore.Infrastructure.WebApi;
using Hncore.Pass.Vpn.Domain;
using Hncore.Pass.Vpn.Model;
using Hncore.Pass.Vpn.Request.Product;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
namespace Hncore.Pass.Vpn.Service
{
public class AgentService:IFindService
{
CourseContext m_DbContext;
IHttpClientFactory m_HttpClientFactory;
protected ProductService m_ProductService;
protected ProductPackageService m_ProductPackageService;
protected ProductPackageUnitService m_ProductPackageUnitService;
protected ProductEntity m_Product;
protected ProductAccountChargeService m_AccountChargeService;
protected Dictionary<string,AgentClientBaseService> m_MapAgentClient=new Dictionary<string, AgentClientBaseService>();
public AgentService(ProductService _ProductService
, ProductPackageService _ProductPackageService
, ProductPackageUnitService _ProductPackageUnitService
, ProductAccountChargeService _AccountChargeService
, IHttpClientFactory httpClientFactory
, CourseContext _DbContext)
{
m_HttpClientFactory = httpClientFactory;
m_ProductService = _ProductService;
m_ProductPackageService = _ProductPackageService;
m_ProductPackageUnitService = _ProductPackageUnitService;
m_AccountChargeService = _AccountChargeService;
m_DbContext = _DbContext;
}
protected AgentClientBaseService _AgentClient;
private AgentClientBaseService GetAgent(ProductEntity product)
{
AgentClientBaseService agent=null;
if (product.GroupNO == "g1")
agent = new AgentClient1Service(m_HttpClientFactory) { ClientName=product.GroupNO};
if (product.GroupNO == "g2")
agent = new AgentClient2Service(m_HttpClientFactory) { ClientName = product.GroupNO };
if (product.GroupNO == "g3")
agent = new AgentClient3Service(m_HttpClientFactory) { ClientName = product.GroupNO };
if (product.GroupNO == "g4")
agent = new AgentClient4Service(m_HttpClientFactory) { ClientName = product.GroupNO };
if (product.GroupNO == "g5")
agent = new AgentClient5Service(m_HttpClientFactory) { ClientName = product.GroupNO };
if (product.GroupNO == "g6")
agent = new AgentClient6Service(m_HttpClientFactory) { ClientName = product.GroupNO };
if (product.GroupNO == "g7")
agent = new AgentClient7Service(m_HttpClientFactory) { ClientName = product.GroupNO };
agent.Product = product;
return agent;
}
public async Task RefrushAllStatus()
{
var products = await m_ProductService.Query(false).ToListAsync();
await products.ForEachAsync(async m =>
{
// if (m.GroupNO == "g6")
await RefrushStatus(m);
});
}
public virtual async Task RefrushStatus(ProductEntity product)
{
var agent = GetAgent(product);
agent.Init(product.BaseUrl, product.Token);
int status = await agent.RefrushStatus();
if (product.Status != status)
{
product.UpdateTime = DateTime.Now;
product.Status = status;
await m_ProductService.Update(product);
}
if (product.Status == 0)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine($"{product.Name}:离线");
Console.ResetColor();
}
}
public virtual async Task<(byte[], string)> GetCode(int productId)
{
var product = await m_ProductService.GetById(productId);
var agent = GetAgent(product);
agent.Init(product.BaseUrl, product.Token);
return await agent.GetCode();
}
public virtual async Task<ApiResult> Login(AgentLoginRequest request)
{
var product = await m_ProductService.GetById(request.ProductId);
product.Token = request.Key;
var agent = GetAgent(product);
agent.Init(product.BaseUrl, product.Token);
request.Account = product.Account;
request.Pwd = product.Pwd;
var ret = await agent.Login(request);
if (ret.Code == ResultCode.C_SUCCESS)
{
product.Status = 1;
product.Token = ret.Data.ToString();
await m_ProductService.Update(product);
}
return ret;
}
public virtual async Task<ApiResult<List<OriginAccountModel>>> GetOriginAccounts(List<ProductAccountEntity> accountList)
{
var retList = new List<OriginAccountModel>();
foreach (var item in accountList)
{
var product = await m_ProductService.GetById(item.ProductId);
var agent = GetAgent(product);
agent.Init(product.BaseUrl, product.Token);
var account = item.Account;
if (product.GroupNO == "g7") account = item.Raw;
var ret = await agent.GetAccountInfo(account);
if (ret.Code == ResultCode.C_SUCCESS)
retList.Add(ret.Data as OriginAccountModel);
}
return new ApiResult<List<OriginAccountModel>>(retList);
}
public virtual async Task<ApiResult<OriginAccountModel>> GetOriginAccountInfo(int productId, string account, string pwd = "")
{
var product = await m_ProductService.GetById(productId);
var agent = GetAgent(product);
agent.Init(product.BaseUrl, product.Token);
if (product.GroupNO == "g7")
{
var accountInfo = await GetProductAccount(productId, account);
if (accountInfo != null && accountInfo.Raw.Has())
account = accountInfo.Raw;
}
var ret = await agent.GetAccountInfo(account);
if (ret.Code != ResultCode.C_SUCCESS) return new ApiResult<OriginAccountModel>(ResultCode.C_NOT_EXISTS_ERROR, "账号不存在");
if (pwd.Has()&&ret.Data.Pwd != pwd)
return new ApiResult<OriginAccountModel>(ResultCode.C_NOT_EXISTS_ERROR, "密码不正确");
return ret;
}
public virtual async Task<List<OriginAccountModel>> GetOriginAccountInfo(int productId, List<string> accounts)
{
var list = new List<OriginAccountModel>();
var product = await m_ProductService.GetById(productId);
var agent = GetAgent(product);
agent.Init(product.BaseUrl, product.Token);
foreach (var item in accounts)
{
var account = item;
if (product.GroupNO == "g7")
{
var accountInfo = await GetProductAccount(productId, item);
if (accountInfo != null && accountInfo.Raw.Has())
account = accountInfo.Raw;
}
var ret = await agent.GetAccountInfo(account);
if (ret.Code == ResultCode.C_SUCCESS)
{
list.Add(ret.Data);
}
}
return list;
}
/// <summary>
/// 新开
/// </summary>
/// <param name="packageId"></param>
/// <param name="account"></param>
/// <param name="pwd"></param>
/// <returns></returns>
public virtual async Task<ApiResult> NewAccount(int orderId, int packageId, string account, string pwd, int connCount = 1, int accountType = 1)
{
ApiResult flagResult = new ApiResult(ResultCode.C_SUCCESS);
var package = await m_ProductPackageService.GetById(packageId);
var product = await m_ProductService.GetById(package.ProductId);
var agent = GetAgent(product);
agent.Init(product.BaseUrl, product.Token);
if (package.PackageType == PackageType.Base)
{
var ret = await agent.NewAccount(package.OriginKey, account, pwd, connCount, accountType);
//var ret = new ApiResult(ResultCode.C_INVALID_ERROR);
var status = ret.Code == ResultCode.C_SUCCESS ? ChargeStatus.Ok : ChargeStatus.Faild;
await m_AccountChargeService.RecordNew(package, orderId, product.GroupNO, account, pwd, accountType, connCount, status);
return ret;
}
else
{
var basePackages = await m_ProductPackageService.GetBasePackages(packageId);
var firstPackage = basePackages.FirstOrDefault();
basePackages.Remove(firstPackage);
if (firstPackage.Count > 1)
{
firstPackage.Count--;
basePackages.Insert(0, firstPackage);
}
var ret = await agent.NewAccount(firstPackage.Package.OriginKey, account, pwd, connCount, accountType);
//var ret = new ApiResult(ResultCode.C_INVALID_ERROR);
var status = ret.Code == ResultCode.C_SUCCESS ? ChargeStatus.Ok : ChargeStatus.Faild;
await m_AccountChargeService.RecordNew(firstPackage.Package, orderId, product.GroupNO, account, pwd, accountType, connCount, status);
if (ret.Code != ResultCode.C_SUCCESS)
flagResult = ret;
foreach (var item in basePackages)
{
for (var j = 0; j < item.Count; j++)
{
ret = await agent.NewReAccount(item.Package.OriginKey, account, connCount);
// ret = new ApiResult(ResultCode.C_INVALID_ERROR);
status = ret.Code == ResultCode.C_SUCCESS ? ChargeStatus.Ok : ChargeStatus.Faild;
await m_AccountChargeService.RecordReNew(item.Package, orderId, product.GroupNO, account, connCount, status);
if (ret.Code != ResultCode.C_SUCCESS)
flagResult = ret;
}
}
return flagResult;
}
}
/// <summary>
/// 续费
/// </summary>
/// <param name="productId"></param>
/// <param name="account"></param>
/// <param name="pwd"></param>
/// <returns></returns>
public virtual async Task<ApiResult> ReNewAccount(int orderId, int packageId, string account, int connCount)
{
var package = await m_ProductPackageService.GetById(packageId);
var product = await m_ProductService.GetById(package.ProductId);
if (product.GroupNO == "g7")
{
var accountInfo = await GetProductAccount(package.ProductId, account);
if (accountInfo != null && accountInfo.Raw.Has())
account = accountInfo.Raw;
}
var agent = GetAgent(product);
agent.Init(product.BaseUrl, product.Token);
ApiResult flagResult = new ApiResult(ResultCode.C_SUCCESS);
if (package.PackageType == PackageType.Base)
{
var ret = await agent.NewReAccount(package.OriginKey, account, connCount);
// var ret = new ApiResult(ResultCode.C_INVALID_ERROR);
var status = ret.Code == ResultCode.C_SUCCESS ? ChargeStatus.Ok : ChargeStatus.Faild;
await m_AccountChargeService.RecordReNew(package, orderId, product.GroupNO, account, connCount, status);
return ret;
}
else
{
var basePackages = await m_ProductPackageService.GetBasePackages(packageId);
foreach (var basePackage in basePackages)
{
for (var j = 0; j < basePackage.Count; j++)
{
var ret = await agent.NewReAccount(basePackage.Package.OriginKey, account, connCount);
//var ret = new ApiResult(ResultCode.C_INVALID_ERROR);
var status = ret.Code == ResultCode.C_SUCCESS ? ChargeStatus.Ok : ChargeStatus.Faild;
await m_AccountChargeService.RecordReNew(basePackage.Package, orderId, product.GroupNO, account, connCount, status);
if (status == ChargeStatus.Faild) flagResult = ret;
}
}
return flagResult;
}
}
/// <summary>
/// 删除账号
/// </summary>
/// <param name="productId"></param>
/// <param name="account"></param>
/// <returns></returns>
public virtual bool DeleteAccount(int productId, string account)
{
return true;
}
/// <summary>
/// 修改账号密码
/// </summary>
/// <param name="productId"></param>
/// <param name="account"></param>
/// <param name="pwd"></param>
/// <returns></returns>
public virtual async Task<bool> UpdateAccountPwd(int productId, string account, string pwd)
{
var product = await m_ProductService.GetById(productId);
var agent = GetAgent(product);
agent.Init(product.BaseUrl, product.Token);
if (product.GroupNO == "g7")
{
var accountInfo = await GetProductAccount(productId, account);
if (accountInfo != null && accountInfo.Raw.Has())
agent.Raw = accountInfo.Raw;
}
return await agent.UpdateAccountPwd(account, pwd);
}
/// <summary>
/// 退款
/// </summary>
/// <param name="packageId"></param>
/// <param name="account"></param>
/// <returns></returns>
public virtual async Task<ApiResult> Refund(ProductPackageEntity package, ProductAccountEntity accountInfo)
{
var product = await m_ProductService.GetById(package.ProductId);
var agent = GetAgent(product);
agent.Init(product.BaseUrl, product.Token);
var account = accountInfo.Account;
if (product.GroupNO == "g7")
{
if (accountInfo != null && accountInfo.Raw.Has())
account = accountInfo.Raw;
}
var flag = await agent.Refund(account, package.OriginKey, accountInfo.RestDay);
return flag;
}
/// <summary>
/// 是否在线
/// </summary>
/// <param name="productId"></param>
/// <param name="account"></param>
/// <returns></returns>
public virtual async Task<ApiResult<List<OriginAccountOnlineModel>>> OnLine(int productId, string account)
{
var product = await m_ProductService.GetById(productId);
var agent = GetAgent(product);
agent.Init(product.BaseUrl, product.Token);
return await agent.OnLine(account);
}
/// <summary>
/// 踢号
/// </summary>
/// <param name="productId"></param>
/// <param name="account"></param>
/// <returns></returns>
public virtual async Task<bool> KillOut(int productId, string id)
{
var product = await m_ProductService.GetById(productId);
var agent = GetAgent(product);
agent.Init(product.BaseUrl, product.Token);
return await agent.KillOut(id);
}
/// <summary>
/// 是否存在
/// </summary>
/// <param name="account"></param>
/// <returns></returns>
public async Task<bool> Exist(int productId, string account)
{
if (productId == 5) productId = 12;
var product = await m_ProductService.GetById(productId);
var agent = GetAgent(product);
agent.Init(product.BaseUrl, product.Token);
return await agent.Exist(account);
}
public async Task FaildTry()
{
var records = await m_AccountChargeService.GetFaildRecord();
foreach (var chargeEntity in records)
{
if (chargeEntity.Status != ChargeStatus.Faild)
{
continue;
}
if (chargeEntity.TryTimes > 3)
{
chargeEntity.Status = ChargeStatus.Outtime;
chargeEntity.UpdateTime = DateTime.Now;
await m_AccountChargeService.Update(chargeEntity);
continue;
}
var product = await m_ProductService.GetById(chargeEntity.ProductId);
var agent = GetAgent(product);
agent.Init(product.BaseUrl, product.Token);
if (chargeEntity.OperationType == ChargeOperationType.New)
{
var ret = await agent.NewAccount(chargeEntity.PackageOriginKey, chargeEntity.Account, chargeEntity.Pwd, chargeEntity.ConnectCount, chargeEntity.AccountType);
var status = ret.Code == ResultCode.C_SUCCESS ? ChargeStatus.Ok : ChargeStatus.Faild;
chargeEntity.Status = status;
chargeEntity.TryTimes++;
chargeEntity.UpdateTime = DateTime.Now;
await m_AccountChargeService.Update(chargeEntity);
}else if(chargeEntity.OperationType == ChargeOperationType.ReNew)
{
var ret = await agent.NewReAccount(chargeEntity.PackageOriginKey, chargeEntity.Account, chargeEntity.ConnectCount);
// var ret = new ApiResult(ResultCode.C_INVALID_ERROR);
var status = ret.Code == ResultCode.C_SUCCESS ? ChargeStatus.Ok : ChargeStatus.Faild;
chargeEntity.Status = status;
chargeEntity.TryTimes++;
chargeEntity.UpdateTime = DateTime.Now;
await m_AccountChargeService.Update(chargeEntity);
}
}
}
protected async Task<ProductAccountEntity> GetProductAccount(int productId, string account)
{
return await m_DbContext.Set<ProductAccountEntity>().FirstOrDefaultAsync(m => m.ProductId == productId && m.Account == account);
}
}
}

View File

@@ -0,0 +1,25 @@
using Hncore.Infrastructure.Service;
using Hncore.Pass.Vpn.Domain;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Hncore.Pass.Vpn.Service
{
public partial class ArticleService : ServiceBase<ArticleEntity>, IFindService
{
CourseContext m_DbContext;
public ArticleService(CourseContext dbContext, IHttpContextAccessor httpContextAccessor) : base(dbContext, httpContextAccessor)
{
m_DbContext = dbContext;
}
public async Task<List<ArticleEntity>> GetTop(int top, ArticleCatalog catalog)
{
return await this.Query(m => m.CatalogId == catalog).Take(top).ToListAsync();
}
}
}

View File

@@ -0,0 +1,96 @@
using Hncore.Infrastructure.Service;
using Hncore.Pass.Vpn.Domain;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Hncore.Pass.Vpn.Service
{
public partial class ProductAccountChargeService : ServiceBase<ProductAccountChargeEntity>, IFindService
{
CourseContext m_DbContext;
public ProductAccountChargeService(CourseContext dbContext
, IHttpContextAccessor httpContextAccessor) : base(dbContext, httpContextAccessor)
{
m_DbContext = dbContext;
}
/// <summary>
/// 记录新开操作
/// </summary>
/// <param name="package"></param>
/// <param name="orderId"></param>
/// <param name="gid"></param>
/// <param name="account"></param>
/// <param name="pwd"></param>
/// <param name="accountType"></param>
/// <param name="connCount"></param>
/// <param name="chargeStatus"></param>
/// <returns></returns>
public async Task RecordNew(ProductPackageEntity package, int orderId, string gid, string account, string pwd, int accountType, int connCount, ChargeStatus chargeStatus = ChargeStatus.Ok)
{
var chargeEntity = new ProductAccountChargeEntity()
{
Account = account,
AccountType = accountType,
ConnectCount = connCount,
OperationType = ChargeOperationType.New,
OrderId = orderId,
PackageId = package.Id,
PackageOriginKey = package.OriginKey,
ProductGroup = gid,
ProductId = package.ProductId,
Pwd = pwd,
Status = chargeStatus,
TryTimes = 1,
};
await this.Add(chargeEntity);
}
/// <summary>
/// 记录续费操作
/// </summary>
/// <param name="package"></param>
/// <param name="orderId"></param>
/// <param name="gid"></param>
/// <param name="account"></param>
/// <param name="pwd"></param>
/// <param name="accountType"></param>
/// <param name="connCount"></param>
/// <param name="chargeStatus"></param>
/// <returns></returns>
public async Task RecordReNew(ProductPackageEntity package, int orderId, string gid, string account, int connCount, ChargeStatus chargeStatus = ChargeStatus.Ok)
{
var chargeEntity = new ProductAccountChargeEntity()
{
Account = account,
AccountType =0,
ConnectCount = connCount,
OperationType = ChargeOperationType.ReNew,
OrderId = orderId,
PackageId = package.Id,
PackageOriginKey = package.OriginKey,
ProductGroup = gid,
ProductId = package.ProductId,
Pwd = "",
Status = chargeStatus,
TryTimes = 1,
};
await this.Add(chargeEntity);
}
public async Task<List<ProductAccountChargeEntity>> GetFaildRecord(int maxTryTimes = 3, int maxTop = 100)
{
var query = this.Query(m => m.Status == ChargeStatus.Faild
&& m.TryTimes <= maxTryTimes
&& (DateTime.Now - m.CreateTime).Minutes <= 10);
return await query.OrderBy(m => m.Id)
.Take(maxTop)
.ToListAsync();
}
}
}

View File

@@ -0,0 +1,150 @@
using HHncore.Pass.Vpn.Request.Product;
using Hncore.Infrastructure.Common;
using Hncore.Infrastructure.Extension;
using Hncore.Infrastructure.Service;
using Hncore.Infrastructure.WebApi;
using Hncore.Pass.Vpn.Domain;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using Hncore.Infrastructure.EntitiesExtension;
using Hncore.Infrastructure.EF;
namespace Hncore.Pass.Vpn.Service
{
public partial class ProductAccountService : ServiceBase<ProductAccountEntity>, IFindService
{
CourseContext m_DbContext;
private IConfiguration m_Configuration;
public AgentService m_AgentService;
private UserService m_UserService;
public ProductAccountService(CourseContext dbContext
, AgentService _AgentService
, UserService _UserService
, IConfiguration _Configuration
, IHttpContextAccessor httpContextAccessor) : base(dbContext, httpContextAccessor)
{
m_DbContext = dbContext;
m_AgentService = _AgentService;
m_Configuration = _Configuration;
m_UserService = _UserService;
}
public async Task<bool> CheckAccountExist(int productId, List<string> accouts)
{
var flag = this.Exist(m => accouts.Contains(m.Account));
if (flag)
{
return true;
}
foreach (var item in accouts)
{
var ret = await m_AgentService.Exist(productId, item);
await Task.Delay(50);
if (ret == true)
return true;
}
return false;
}
public bool CheckUserAccountExist(int product, List<string> accouts, int userId)
{
return this.Exist(m => accouts.Contains(m.Account) && m.UserId == userId);
}
public async Task<ProductAccountEntity> GetAccountInfo(string accout, int userId)
{
return await this.Query(true).FirstOrDefaultAsync(m => m.Account == accout && m.UserId == userId);
}
public async Task<List<ProductAccountEntity>> GetAccounts(string accouts,int userId=0)
{
var alist = accouts.Split(",");
return await this.Query(m =>(userId==0||m.UserId== userId)&& alist.Contains(m.Account)).ToListAsync();
}
public async Task<ProductAccountEntity> GetAccountInfo(string accout)
{
return await this.Query(true).FirstOrDefaultAsync(m => m.Account == accout);
}
public async Task<ProductAccountEntity> GetAccountInfo(int packageId,string accout)
{
return await this.Query(true).FirstOrDefaultAsync(m =>m.PackageId== packageId&& m.Account == accout);
}
public async Task<ProductAccountEntity> GetProductAccountInfo(int productId, string accout)
{
return await this.Query(true).FirstOrDefaultAsync(m => m.ProductId == productId && m.Account == accout);
}
/// <summary>
/// day 0已过期1天
/// </summary>
/// <param name="day"></param>
/// <returns></returns>
public async Task<List<ProductAccountEntity>> GetExpireingAccounts_bak(int day)
{
Expression<Func<ProductAccountEntity, bool>> expr = m => 1 == 1;
if (day == 0)
{
expr = expr.And(m => m.EndTime.Value < DateTime.Now);
}
else
{
var startTime = DateTime.Now.Begin().AddDays(day);
var EndTime = DateTime.Now.End().AddDays(day);
expr = expr.And(m => m.EndTime >= startTime && m.EndTime <= EndTime);
}
return await this.Query(expr,true).ToListAsync();
}
public async Task<List<ProductAccountEntity>> GetExpireingAccounts(int day)
{
var sql = $"select * from product_account where DATEDIFF(EndTime,now())={day}";
return this.m_DbContext.SqlQuery<ProductAccountEntity>(sql);
}
public async Task<ApiResult> UpdateAccountPwd(UpdateAccountPwdRequest request)
{
var entity = await this.GetById(request.Id);
if (entity == null)
{
return new ApiResult(ResultCode.C_INVALID_ERROR, "账号不存在");
}
if (request.Pwd.NotHas())
{
return new ApiResult(ResultCode.C_INVALID_ERROR, "密码不能为空");
}
var agentRet = await m_AgentService.UpdateAccountPwd(entity.ProductId.Value, entity.Account, request.Pwd);
if (!agentRet)
{
return new ApiResult(ResultCode.C_INVALID_ERROR, "远程更新失败");
}
entity.Pwd = request.Pwd;
await this.Update(entity);
return new ApiResult(1);
}
public async Task<List<ProductAccountEntity>> GetUserTestAccount(int userId)
{
return await this.Query(m => m.UserId == userId && m.AccountType == (int)AccountType.Test).ToListAsync();
}
public async Task<int> GetRestTestCount(int userId)
{
var userInfo = await m_UserService.GetById(userId);
var restTimes = Convert.ToInt32(m_Configuration["TestCountLimit"]);
if (userInfo.TestCountLimit > 0) restTimes = userInfo.TestCountLimit.Value;
restTimes = restTimes - userInfo.UseTestCount.Value;
restTimes = restTimes < 0 ? 0 : restTimes;
return restTimes;
}
}
}

View File

@@ -0,0 +1,63 @@
using Hncore.Infrastructure.Service;
using Hncore.Infrastructure.WebApi;
using Hncore.Pass.Vpn.Domain;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Hncore.Pass.Vpn.Service
{
public partial class ProductOrderItemService : ServiceBase<ProductOrderItemEntity>, IFindService
{
CourseContext m_DbContext;
public ProductOrderItemService(CourseContext dbContext
, IHttpContextAccessor httpContextAccessor) : base(dbContext, httpContextAccessor)
{
m_DbContext = dbContext;
}
public async Task<List<ProductOrderItemEntity>> CreateOrderItems(ProductOrderEntity orderEntity,string pwd)
{
List<ProductOrderItemEntity> items = new List<ProductOrderItemEntity>();
var accounts = orderEntity.Accounts.Split(',').ToList();
accounts.ForEach(m =>
{
var item = new ProductOrderItemEntity()
{
ConnectCount = orderEntity.ConnectCount,
DayPrice = orderEntity.DayPrice.Value,
DayCount=orderEntity.DayCount,
OrderId = orderEntity.Id,
OrderNo = orderEntity.OrderNo,
OrderState = orderEntity.OrderState,
OrderType = orderEntity.OrderType,
PackageId = orderEntity.PackageId,
PackageName = orderEntity.PackageName,
PayState = orderEntity.PayState,
PayType = orderEntity.PayType,
Account = m,
ProductId = orderEntity.ProductId,
ProductName = orderEntity.ProductName,
TenantId = orderEntity.TenantId,
UserId = orderEntity.UserId,
UserName = orderEntity.UserName,
AccountPwd = pwd
};
items.Add(item);
});
await this.Adds(items);
return items;
}
public async Task<ProductOrderItemEntity> GetLastByAccount(string account)
{
var orderItem = await this.Query(m => m.Account == account && m.OrderState == OrderStatus.Complete)
.OrderByDescending(m => m.Id)
.FirstOrDefaultAsync();
return orderItem;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,34 @@
using Hncore.Infrastructure.Service;
using Hncore.Pass.Vpn.Domain;
using Hncore.Pass.Vpn.Model;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Hncore.Pass.Vpn.Service
{
public partial class ProductPackageService : ServiceBase<ProductPackageEntity>, IFindService
{
CourseContext m_DbContext;
ProductPackageUnitService m_ProductPackageUnitService;
public ProductPackageService(CourseContext dbContext
, ProductPackageUnitService _ProductPackageUnitService
, IHttpContextAccessor httpContextAccessor) : base(dbContext, httpContextAccessor)
{
m_DbContext = dbContext;
this.m_ProductPackageUnitService = _ProductPackageUnitService;
}
public async Task<List<PackageUnitItemModel>> GetBasePackages(int packageId)
{
var packageUnits = m_ProductPackageUnitService.Query(m => m.PackageId == packageId);
var query = from packageUnit in packageUnits
join package in this.Query(true) on packageUnit.BasePackageId equals package.Id
select new PackageUnitItemModel { Count = packageUnit.Count, Package = package };
return await query.ToListAsync();
}
}
}

View File

@@ -0,0 +1,15 @@
using Hncore.Infrastructure.Service;
using Hncore.Pass.Vpn.Domain;
using Microsoft.AspNetCore.Http;
namespace Hncore.Pass.Vpn.Service
{
public partial class ProductPackageUnitService : ServiceBase<ProductPackageUnitEntity>, IFindService
{
CourseContext m_DbContext;
public ProductPackageUnitService(CourseContext dbContext, IHttpContextAccessor httpContextAccessor) : base(dbContext, httpContextAccessor)
{
m_DbContext = dbContext;
}
}
}

View File

@@ -0,0 +1,54 @@
using Hncore.Infrastructure.Service;
using Hncore.Pass.Vpn.Domain;
using Hncore.Pass.Vpn.Response.Product;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Threading.Tasks;
using Hncore.Infrastructure.Extension;
using System.Linq;
namespace Hncore.Pass.Vpn.Service
{
public partial class ProductPriceDiscountService : ServiceBase<ProductPriceDiscountEntity>, IFindService
{
CourseContext m_DbContext;
ProductService m_ProductService;
ProductPackageService m_ProductPackageService;
public ProductPriceDiscountService(CourseContext dbContext
, ProductService _ProductService
, ProductPackageService _ProductPackageService
, IHttpContextAccessor httpContextAccessor) : base(dbContext, httpContextAccessor)
{
m_DbContext = dbContext;
m_ProductService = _ProductService;
m_ProductPackageService = _ProductPackageService;
}
public async Task<List<ProductWithPriceDiscountResponse>> GetPriceDiscount(int schemeId)
{
var products = await m_ProductService.Query(true).ToListAsync();
var packages = m_ProductPackageService.Query(true);
var priceDiscount = this.Query(m => m.SchemeId == schemeId);
var ret = from pakcage in packages
join uDiscount in priceDiscount on pakcage.Id equals uDiscount.PackageId into temp
from uDiscount in temp.DefaultIfEmpty()
select new PackagePriceDiscount()
{
Package = pakcage,
PriceDiscount = uDiscount ?? new ProductPriceDiscountEntity()
};
var packgesPrice = await ret.ToListAsync();
List<ProductWithPriceDiscountResponse> respList = new List<ProductWithPriceDiscountResponse>();
products.ForEach(p =>
{
var resp = new ProductWithPriceDiscountResponse();
resp.Product = p.MapTo<ProductResponse>();
resp.PackageDiscounts = packgesPrice.Where(m => m.Package.ProductId == p.Id).ToList();
respList.Add(resp);
});
return respList;
}
}
}

View File

@@ -0,0 +1,15 @@
using Hncore.Infrastructure.Service;
using Hncore.Pass.Vpn.Domain;
using Microsoft.AspNetCore.Http;
namespace Hncore.Pass.Vpn.Service
{
public partial class ProductPriceSchemeService : ServiceBase<ProductPriceSchemeEntity>, IFindService
{
CourseContext m_DbContext;
public ProductPriceSchemeService(CourseContext dbContext, IHttpContextAccessor httpContextAccessor) : base(dbContext, httpContextAccessor)
{
m_DbContext = dbContext;
}
}
}

View File

@@ -0,0 +1,15 @@
using Hncore.Infrastructure.Service;
using Hncore.Pass.Vpn.Domain;
using Microsoft.AspNetCore.Http;
namespace Hncore.Pass.Vpn.Service
{
public partial class ProductRouteService : ServiceBase<ProductRouteEntity>, IFindService
{
CourseContext m_DbContext;
public ProductRouteService(CourseContext dbContext, IHttpContextAccessor httpContextAccessor) : base(dbContext, httpContextAccessor)
{
m_DbContext = dbContext;
}
}
}

View File

@@ -0,0 +1,78 @@
using Hncore.Infrastructure.Extension;
using Hncore.Infrastructure.Service;
using Hncore.Pass.Vpn.Domain;
using Hncore.Pass.Vpn.Response.Product;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Hncore.Pass.Vpn.Service
{
public partial class ProductService : ServiceBase<ProductEntity>, IFindService
{
private static readonly string m_ProductCacheKey = "Product:{0}";
CourseContext m_DbContext;
ProductPackageService m_ProductPackageService;
public ProductService(CourseContext dbContext, ProductPackageService _ProductPackageService, IHttpContextAccessor httpContextAccessor) : base(dbContext, httpContextAccessor)
{
m_DbContext = dbContext;
m_ProductPackageService = _ProductPackageService;
}
public async override Task<ProductEntity> GetById(object id)
{
return await base.GetById(id);
string key = string.Format(m_ProductCacheKey, id);
var cacheData = await RedisHelper.GetAsync<ProductEntity>(key);
if (cacheData == null)
{
cacheData = await base.GetById(id);
if (cacheData != null)
await RedisHelper.SetAsync(key, cacheData, 60 * 30);
}
return cacheData;
}
public async override Task<bool> Update(ProductEntity entity, bool autoSave = true)
{
string key = string.Format(m_ProductCacheKey, entity.Id);
await RedisHelper.SetAsync(key, entity, 60 * 30);
return await base.Update(entity, autoSave);
}
public async Task<List<ProductWithPackageResponse>> ProductWithPackage(int online=1)
{
var products = await this.Query(m => m.Sort != 1000).Where(m=>m.OnLine==online).ToListAsync();
var packages = await m_ProductPackageService.Query(true).ToListAsync();
List<ProductWithPackageResponse> respList = new List<ProductWithPackageResponse>();
products.ForEach(p =>
{
var resp = new ProductWithPackageResponse();
resp.Product = p.MapTo<ProductResponse>();
resp.Packages = packages.Where(m => m.ProductId == p.Id).ToList();
respList.Add(resp);
});
return respList;
}
public async Task<ProductWithPackageResponse> GetOneProductWithPackage(int productId)
{
var product = await this.GetById(productId);
var packages = await m_ProductPackageService.Query(m => m.ProductId == productId).ToListAsync();
List<ProductWithPackageResponse> respList = new List<ProductWithPackageResponse>();
var resp = new ProductWithPackageResponse();
resp.Product = product.MapTo<ProductResponse>();
resp.Packages = packages;
return resp;
}
}
}

View File

@@ -0,0 +1,68 @@
using Hncore.Infrastructure.Extension;
using Hncore.Infrastructure.Service;
using Hncore.Pass.Vpn.Domain;
using Hncore.Pass.Vpn.Response.Product;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Hncore.Pass.Vpn.Service
{
public partial class ProductUserPriceService : ServiceBase<ProductUserPriceEntity>, IFindService
{
CourseContext m_DbContext;
ProductService m_ProductService;
ProductPackageService m_ProductPackageService;
public ProductUserPriceService(ProductPackageService m_ProductPackageService
, ProductService m_ProductService
,CourseContext dbContext, IHttpContextAccessor httpContextAccessor) : base(dbContext, httpContextAccessor)
{
m_DbContext = dbContext;
this.m_ProductPackageService = m_ProductPackageService;
this.m_ProductService = m_ProductService;
}
public async Task<List<ProductWithPackageUserPriceResponse>> GetPackageUserPrice(int userId)
{
var products = await m_ProductService.Query(true).ToListAsync();
var packages = m_ProductPackageService.Query(true);
var userPrice = this.Query(m => m.UserId == userId);
var ret = from pakcage in packages
join uPrice in userPrice on pakcage.Id equals uPrice.PackageId into temp
from uPrice in temp.DefaultIfEmpty()
select new PackageUserPriceResponse()
{
Package = pakcage,
UserPrice = uPrice ?? new ProductUserPriceEntity() { RefundDayPrice= products.FirstOrDefault(m=>m.Id==pakcage.ProductId).RefundDayPrice, UserPrice=pakcage.Price }
};
var packgesPrice = await ret.ToListAsync();
List<ProductWithPackageUserPriceResponse> respList = new List<ProductWithPackageUserPriceResponse>();
products.ForEach(p =>
{
var resp = new ProductWithPackageUserPriceResponse();
resp.Product = p.MapTo<ProductResponse>();
resp.PackageUserPrices = packgesPrice.Where(m => m.Package.ProductId == p.Id).ToList();
respList.Add(resp);
});
return respList;
}
public async Task<List<ProductUserPriceEntity>> GetProductUserPrice(int product,int userId)
{
return this.Query(m => m.ProductId == product && m.UserId == userId && m.Status == 1).ToList();
}
public async Task<List<ProductUserPriceEntity>> GetProductUserPrice(int userId)
{
return this.Query(m => m.UserId == userId && m.Status == 1).ToList();
}
public async Task<ProductUserPriceEntity> GetPackageUserPrice(int packageId, int userId)
{
return this.Query(m => m.PackageId == packageId && m.UserId == userId&& m.Status==1).FirstOrDefault();
}
}
}

View File

@@ -0,0 +1,30 @@
using Hncore.Infrastructure.Service;
using Hncore.Infrastructure.WebApi;
using Hncore.Pass.Vpn.Domain;
using Hncore.Pass.Vpn.Request.Product;
using Microsoft.AspNetCore.Http;
using System.Threading.Tasks;
using Hncore.Infrastructure.Extension;
using System;
using Hncore.Infrastructure.Common;
using System.Collections.Generic;
using Hncore.Pass.BaseInfo.Models;
using Microsoft.EntityFrameworkCore;
namespace Hncore.Pass.Vpn.Service
{
public class UserService : ServiceBase<UserEntity>, IFindService
{
CourseContext m_DbContext;
public UserService(CourseContext dbContext
,IHttpContextAccessor httpContextAccessor) : base(dbContext, httpContextAccessor)
{
m_DbContext = dbContext;
}
public async Task<List<UserEntity>> GetByIds(List<int> userids)
{
return await this.Query(m => userids.Contains(m.Id)).ToListAsync();
}
}
}

View File

@@ -0,0 +1,49 @@
using Hncore.Infrastructure.Service;
using Hncore.Pass.Vpn.Domain;
using Hncore.Wx.Open;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using System.Threading.Tasks;
namespace Hncore.Pass.Vpn.Service
{
public partial class WxAppService : ServiceBase<WxAppEntity>
{
public WxAppService(CourseContext dbContext, IHttpContextAccessor httpContextAccessor) : base(dbContext, httpContextAccessor)
{
}
public async Task SaveAppInfo(GetAuthorizerInfoResponse info, int tenantId, int storeId)
{
var wxAppInfo = await this.Query(true).FirstOrDefaultAsync(m => m.TenantId == tenantId
&& m.Appid == info.authorization_info.authorizer_appid
&& m.DeleteTag == 0);
var wxAuthInfoNew = new WxAppEntity()
{
TenantId = tenantId,
StoreId = storeId,
Appid = info.authorization_info.authorizer_appid,
HeadImg = info.authorizer_info.head_img,
NickName = info.authorizer_info.nick_name,
PrincipalName = info.authorizer_info.principal_name,
UserName = info.authorizer_info.user_name,
Bussinessinfo = info.authorizer_info.signature,
AuthorizerState = 0,
RefreshToken = info.authorization_info.authorizer_refresh_token,
ExpiresIn = info.authorization_info.expires_in,
};
if (wxAppInfo == null)
{
await this.Add(wxAuthInfoNew);
}
else
{
wxAuthInfoNew.Id = wxAppInfo.Id;
await this.Update(wxAuthInfoNew);
}
}
}
}

View File

@@ -0,0 +1,34 @@
using Hncore.Infrastructure.Service;
using Hncore.Pass.Vpn.Domain;
using Hncore.Wx.Open;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Hncore.Pass.Vpn.Service
{
public partial class WxAppUserService : ServiceBase<WxAppUserEntity>
{
WxAppService m_WxAppService;
public WxAppUserService(WxAppService _WxAppService, CourseContext dbContext, IHttpContextAccessor httpContextAccessor) : base(dbContext, httpContextAccessor)
{
m_WxAppService = _WxAppService;
}
public async Task<List<WxAppUserEntity>> GetWxUsers(List<int> UserId)
{
return await this.Query(m => UserId.Contains(m.UserId)).ToListAsync();
}
public async Task<WxAppUserEntity> GetWxUser(string appId, int userId)
{
return await this.Query(m => m.Appid == appId && m.UserId == userId).FirstOrDefaultAsync();
}
public async Task<WxAppUserEntity> GetWxUser(string appId, string openId)
{
return await this.Query(m => m.Appid == appId && m.Openid == openId).FirstOrDefaultAsync();
}
}
}

View File

@@ -0,0 +1,72 @@
using Hncore.Infrastructure.Service;
using Hncore.Infrastructure.WebApi;
using Hncore.Pass.Vpn.Domain;
using Hncore.Pass.Vpn.Job;
using Hncore.Pass.Vpn.Map;
using Hncore.Pass.Vpn.Service;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
using System.Net.Http;
namespace Hncore.Pass.Vpn
{
public class Startup
{
public IConfiguration Configuration { get; }
private IServiceProvider _IServiceProvider;
public Startup(IHostingEnvironment env)
{
Configuration = env.UseAppsettings();
}
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddDbContext<CourseContext>(opt => { opt.UseMySql(Configuration["MySql"]); });
services.AddTransient<AgentClientLogHandler>();
services.AddHttpClient("agentClient", c =>
{
c.DefaultRequestHeaders.Add("hl", "hl");
})
.AddHttpMessageHandler<AgentClientLogHandler>()
.ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler() { UseCookies = false});
services.AddHttpClient("agentClient1.0", c =>
{
c.DefaultRequestHeaders.Add("hl", "hl");
})
.AddHttpMessageHandler<AgentClientLogHandler>()
.ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler() { UseCookies = false,AllowAutoRedirect=false });
services.AddServiceClient(Configuration["Service_BaseUrl"]);
services.AutoAddService();
return _IServiceProvider=services.Init(Configuration, CompatibilityVersion.Version_2_2, new ServiceOption
{
UseGlobalManageAuthFilter = false
});
}
public void Configure(IApplicationBuilder app, IApplicationLifetime applicationLifetime
, ILoggerFactory loggerFactory)
{
MapConfig.Config();
app.Init(loggerFactory, applicationLifetime);
//启动后台任务
applicationLifetime.ApplicationStarted.Register(() =>
{
// OrderAccountJob.Start(_IServiceProvider);
RefrushStatusJob.Start(_IServiceProvider);
// ChargeTryJob.Start(_IServiceProvider);
ExpireTipJob.Start(_IServiceProvider);
});
}
}
}

View File

@@ -0,0 +1,10 @@
//{
// "MySql": "Server=rm-bp12e1533udh1827azo.mysql.rds.aliyuncs.com;Database=etor_property_test;User=etor_test;Password=etor_test!QAZ2wsx;Convert Zero Datetime=True;TreatTinyAsBoolean=false;",
// "Redis": "47.92.85.90:6379,password=etor0070x01,defaultDatabase=7,poolsize=1"
//}
{
"Host_BaseUrl": "http://ipistest.etor.top11",
"Wx_Mp_Appid": "wxd6b150a17c252fec",
"MySql": "Server=47.92.244.89;Database=course;User=root;Password=qaz123!@#;Convert Zero Datetime=True;TreatTinyAsBoolean=false;port=5000;",
"Redis": "47.92.85.90:6379,password=etor0070x01,defaultDatabase=10,poolsize=1"
}

View File

@@ -0,0 +1,10 @@
//{
// "MySql": "Server=rm-bp12e1533udh1827azo.mysql.rds.aliyuncs.com;Database=etor_property_test;User=etor_test;Password=etor_test!QAZ2wsx;Convert Zero Datetime=True;TreatTinyAsBoolean=false;",
// "Redis": "47.92.85.90:6379,password=etor0070x01,defaultDatabase=7,poolsize=1"
//}
{
"Host_BaseUrl": "http://ipistest.etor.top11",
"Wx_Mp_Appid": "wxd6b150a17c252fec",
"MySql": "Server=47.92.244.89;Database=course;User=root;Password=qaz123!@#;Convert Zero Datetime=True;TreatTinyAsBoolean=false;port=5000;",
"Redis": "47.92.85.90:6379,password=etor0070x01,defaultDatabase=10,poolsize=1"
}

View File

@@ -0,0 +1 @@
dotnet ef dbcontext scaffold "Server=47.92.244.89;Database=course;User=root;Password=qaz123!@#;Convert Zero Datetime=True;TreatTinyAsBoolean=false;port=5000;" "Pomelo.EntityFrameworkCore.MySql" -o Domain -t course -t course_catalog -t course_chapter -t course_chapter_learn -t course_chapter_question -t course_comment -t course_group -t course_order