refactor: remove unused backend extensions
This commit is contained in:
@@ -14,7 +14,6 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AlibabaCloud.SDK.Dysmsapi20170525" Version="4.2.0" />
|
||||
<PackageReference Include="AlipaySDKNet.Standard" Version="4.9.971" />
|
||||
<PackageReference Include="AngleSharp" Version="1.4.0" />
|
||||
<PackageReference Include="AspectCore.Extensions.Reflection" Version="2.4.0" />
|
||||
<PackageReference Include="AspNetCoreRateLimit" Version="5.0.0" />
|
||||
@@ -35,13 +34,10 @@
|
||||
<PackageReference Include="MiniExcel" Version="1.42.0" />
|
||||
<PackageReference Include="MiniWord" Version="0.9.2" />
|
||||
<PackageReference Include="NewLife.Redis" Version="6.4.2026.104" />
|
||||
<PackageReference Include="Novell.Directory.Ldap.NETStandard" Version="4.0.0" />
|
||||
<PackageReference Include="OnceMi.AspNetCore.OSS" Version="1.2.0" />
|
||||
<PackageReference Include="QRCoder" Version="1.7.0" />
|
||||
<PackageReference Include="RabbitMQ.Client" Version="7.2.0" />
|
||||
<PackageReference Include="SixLabors.ImageSharp.Web" Version="3.2.0" />
|
||||
<PackageReference Include="SKIT.FlurlHttpClient.Wechat.Api" Version="3.13.0" />
|
||||
<PackageReference Include="SKIT.FlurlHttpClient.Wechat.TenpayV3" Version="3.16.0" />
|
||||
<PackageReference Include="SqlSugar.MongoDbCore" Version="5.1.4.277" />
|
||||
<PackageReference Include="SqlSugarCore" Version="5.1.4.211" />
|
||||
<PackageReference Include="SSH.NET" Version="2025.1.0" />
|
||||
@@ -49,12 +45,10 @@
|
||||
<PackageReference Include="TencentCloudSDK.Sms" Version="3.0.1363" />
|
||||
<PackageReference Include="UAParser" Version="3.1.47" />
|
||||
<PackageReference Include="Yitter.IdGenerator" Version="1.0.14" />
|
||||
<PackageReference Include="BouncyCastle.Cryptography" Version="2.6.2" Aliases="BouncyCastleV2" />
|
||||
<PackageReference Include="BouncyCastle.Cryptography" Version="2.6.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'net8.0' ">
|
||||
<PackageReference Include="AspNet.Security.OAuth.Gitee" Version="8.3.0" />
|
||||
<PackageReference Include="AspNet.Security.OAuth.Weixin" Version="8.3.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" Version="8.0.22" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson" Version="8.0.22" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.StackExchangeRedis" Version="8.0.22" />
|
||||
@@ -62,8 +56,6 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'net10.0' ">
|
||||
<PackageReference Include="AspNet.Security.OAuth.Gitee" Version="10.0.0" />
|
||||
<PackageReference Include="AspNet.Security.OAuth.Weixin" Version="10.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" Version="10.0.2" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson" Version="10.0.2" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.StackExchangeRedis" Version="10.0.2" />
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 支付宝支付常量
|
||||
/// </summary>
|
||||
[SuppressSniffer]
|
||||
public class AlipayConst
|
||||
{
|
||||
/// <summary>
|
||||
/// 单笔无密转账【业务场景】固定值
|
||||
/// </summary>
|
||||
public const string BizScene = "DIRECT_TRANSFER";
|
||||
|
||||
/// <summary>
|
||||
/// 单笔无密转账【销售产品码】固定值
|
||||
/// </summary>
|
||||
public const string ProductCode = "TRANS_ACCOUNT_NO_PWD";
|
||||
|
||||
/// <summary>
|
||||
/// 交易状态参数名
|
||||
/// </summary>
|
||||
public const string TradeStatus = "trade_status";
|
||||
|
||||
/// <summary>
|
||||
/// 交易成功标识
|
||||
/// </summary>
|
||||
public const string TradeSuccess = "TRADE_SUCCESS";
|
||||
|
||||
/// <summary>
|
||||
/// 授权类型
|
||||
/// </summary>
|
||||
public const string GrantType = "authorization_code";
|
||||
}
|
||||
@@ -76,11 +76,6 @@ public class ConfigConst
|
||||
/// </summary>
|
||||
public const string SysErrorMail = "sys_error_mail";
|
||||
|
||||
/// <summary>
|
||||
/// 域登录验证
|
||||
/// </summary>
|
||||
public const string SysDomainLogin = "sys_domain_login";
|
||||
|
||||
// /// <summary>
|
||||
// /// 租户域名隔离登录验证
|
||||
// /// </summary>
|
||||
@@ -101,11 +96,6 @@ public class ConfigConst
|
||||
/// </summary>
|
||||
public const string SysDefaultGroup = "Default";
|
||||
|
||||
/// <summary>
|
||||
/// 支付宝授权页面地址
|
||||
/// </summary>
|
||||
public const string AlipayAuthPageUrl = "alipay_auth_page_url_";
|
||||
|
||||
// /// <summary>
|
||||
// /// 系统图标
|
||||
// /// </summary>
|
||||
@@ -145,4 +135,4 @@ public class ConfigConst
|
||||
// /// ICP地址
|
||||
// /// </summary>
|
||||
// public const string SysWebIcpUrl = "sys_web_icpUrl";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,149 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 支付宝授权记录表
|
||||
/// </summary>
|
||||
[SugarTable(null, "支付宝授权记录表")]
|
||||
[SysTable]
|
||||
[SugarIndex("index_{table}_U", nameof(UserId), OrderByType.Asc)]
|
||||
[SugarIndex("index_{table}_T", nameof(OpenId), OrderByType.Asc)]
|
||||
public class SysAlipayAuthInfo : EntityBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 商户AppId
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "商户AppId", Length = 64)]
|
||||
public string? AppId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 开放ID
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "开放ID", Length = 64)]
|
||||
public string? OpenId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户ID
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "用户ID", Length = 64)]
|
||||
public string? UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 性别
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "性别", Length = 8)]
|
||||
public GenderEnum Gender { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 年龄
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "年龄", Length = 16)]
|
||||
public int Age { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 手机号
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "手机号", Length = 32)]
|
||||
public string Mobile { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 显示名称
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "显示名称", Length = 128)]
|
||||
public string DisplayName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 昵称
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "昵称", Length = 64)]
|
||||
public string NickName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户名
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "用户名", Length = 64)]
|
||||
public string UserName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 头像
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "头像", Length = 512)]
|
||||
public string? Avatar { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 邮箱
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "邮箱", Length = 128)]
|
||||
public string? Email { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户民族
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "用户民族", Length = 32)]
|
||||
public string? UserNation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 淘宝ID
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "淘宝ID", Length = 64)]
|
||||
public string? TaobaoId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 电话
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "电话", Length = 32)]
|
||||
public string? Phone { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 生日
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "生日", Length = 32)]
|
||||
public string? PersonBirthday { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 职业
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "职业", Length = 64)]
|
||||
public string? Profession { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 省份
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "省份", Length = 64)]
|
||||
public string? Province { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户状态
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "用户状态", Length = 32)]
|
||||
public string? UserStatus { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 学历
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "学历", Length = 32)]
|
||||
public string? Degree { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户类型
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "用户类型", Length = 32)]
|
||||
public string? UserType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 邮编
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "邮编", Length = 16)]
|
||||
public string? Zip { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 地址
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "地址", Length = 256)]
|
||||
public string? Address { get; set; }
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 支付宝交易记录表
|
||||
/// </summary>
|
||||
[SugarTable(null, "支付宝交易记录表")]
|
||||
[SysTable]
|
||||
[SugarIndex("index_{table}_U", nameof(UserId), OrderByType.Asc)]
|
||||
[SugarIndex("index_{table}_T", nameof(TradeNo), OrderByType.Asc)]
|
||||
[SugarIndex("index_{table}_O", nameof(OutTradeNo), OrderByType.Asc)]
|
||||
public class SysAlipayTransaction : EntityBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 用户Id
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "用户Id", Length = 64)]
|
||||
public long UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 交易号
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "交易号", Length = 64)]
|
||||
public string? TradeNo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 商户订单号
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "商户订单号", Length = 64)]
|
||||
public string OutTradeNo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 交易金额
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "交易金额", Length = 20)]
|
||||
public decimal TotalAmount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 交易状态
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "交易状态", Length = 32)]
|
||||
public string TradeStatus { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 交易完成时间
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "交易完成时间")]
|
||||
public DateTime? FinishTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 交易标题
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "交易标题", Length = 256)]
|
||||
public string Subject { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 交易描述
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "交易描述", Length = 512)]
|
||||
public string? Body { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 买家支付宝账号
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "买家支付宝账号", Length = 128)]
|
||||
public string? BuyerLogonId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 买家支付宝用户ID
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "买家支付宝用户ID", Length = 32)]
|
||||
public string? BuyerUserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 卖家支付宝用户ID
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "卖家支付宝用户ID", Length = 32)]
|
||||
public string? SellerUserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 商户AppId
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "商户AppId", Length = 64)]
|
||||
public string? AppId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 交易扩展信息
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "交易扩展信息", Length = 1024)]
|
||||
public string? ExtendInfo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 交易异常信息
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "交易扩展信息", Length = 1024)]
|
||||
public string? ErrorInfo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 交易备注
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "交易备注", Length = 512)]
|
||||
public string? Remark { get; set; }
|
||||
}
|
||||
@@ -1,159 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 代码生成表
|
||||
/// </summary>
|
||||
[SugarTable(null, "代码生成表")]
|
||||
[SysTable]
|
||||
[SugarIndex("index_{table}_B", nameof(BusName), OrderByType.Asc)]
|
||||
[SugarIndex("index_{table}_T", nameof(TableName), OrderByType.Asc)]
|
||||
public partial class SysCodeGen : EntityBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 作者姓名
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "作者姓名", Length = 32)]
|
||||
[MaxLength(32)]
|
||||
public string? AuthorName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否移除表前缀
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "是否移除表前缀", Length = 8)]
|
||||
[MaxLength(8)]
|
||||
public string? TablePrefix { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 生成方式
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "生成方式", Length = 32)]
|
||||
[MaxLength(32)]
|
||||
public string? GenerateType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 库定位器名
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "库定位器名", Length = 64)]
|
||||
[MaxLength(64)]
|
||||
public string? ConfigId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 库名
|
||||
/// </summary>
|
||||
[SugarColumn(IsIgnore = true)]
|
||||
public string DbNickName
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
var dbOptions = App.GetConfig<DbConnectionOptions>("DbConnection", true);
|
||||
var config = dbOptions.ConnectionConfigs.FirstOrDefault(m => m.ConfigId.ToString() == ConfigId);
|
||||
return config.DbNickName;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 数据库名(保留字段)
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "数据库库名", Length = 64)]
|
||||
[MaxLength(64)]
|
||||
public string? DbName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 数据库类型
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "数据库类型", Length = 64)]
|
||||
[MaxLength(64)]
|
||||
public string? DbType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 数据库链接
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "数据库链接", Length = 256)]
|
||||
[MaxLength(256)]
|
||||
public string? ConnectionString { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 数据库表名
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "数据库表名", Length = 128)]
|
||||
[MaxLength(128)]
|
||||
public string? TableName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 命名空间
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "命名空间", Length = 128)]
|
||||
[MaxLength(128)]
|
||||
public string? NameSpace { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 业务名
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "业务名", Length = 128)]
|
||||
[MaxLength(128)]
|
||||
public string? BusName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 表唯一字段配置
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "表唯一字段配置", Length = 512)]
|
||||
[MaxLength(128)]
|
||||
public string? TableUniqueConfig { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否生成菜单
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "是否生成菜单")]
|
||||
public bool GenerateMenu { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 菜单图标
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "菜单图标", Length = 32)]
|
||||
public string? MenuIcon { get; set; } = "ele-Menu";
|
||||
|
||||
/// <summary>
|
||||
/// 菜单编码
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "菜单编码")]
|
||||
public long? MenuPid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 页面目录
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "页面目录", Length = 32)]
|
||||
public string? PagePath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 支持打印类型
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "支持打印类型", Length = 32)]
|
||||
[MaxLength(32)]
|
||||
public string? PrintType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 打印模版名称
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "打印模版名称", Length = 32)]
|
||||
[MaxLength(32)]
|
||||
public string? PrintName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 表唯一字段列表
|
||||
/// </summary>
|
||||
[SugarColumn(IsIgnore = true)]
|
||||
public virtual List<TableUniqueConfigItem> TableUniqueList => string.IsNullOrWhiteSpace(TableUniqueConfig) ? null : JSON.Deserialize<List<TableUniqueConfigItem>>(TableUniqueConfig);
|
||||
}
|
||||
@@ -1,207 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 代码生成字段配置表
|
||||
/// </summary>
|
||||
[SugarTable(null, "代码生成字段配置表")]
|
||||
[SysTable]
|
||||
public partial class SysCodeGenConfig : EntityBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 代码生成主表Id
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "主表Id")]
|
||||
public long CodeGenId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 数据库字段名
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "字段名称", Length = 128)]
|
||||
[Required, MaxLength(128)]
|
||||
public virtual string ColumnName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 主键
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "主键", Length = 8)]
|
||||
[MaxLength(8)]
|
||||
public string? ColumnKey { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 实体属性名
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "属性名称", Length = 128)]
|
||||
[Required, MaxLength(128)]
|
||||
public virtual string PropertyName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 字段数据长度
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "字段数据长度", DefaultValue = "0")]
|
||||
public int ColumnLength { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 字段描述
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "字段描述", Length = 128)]
|
||||
[MaxLength(128)]
|
||||
public string? ColumnComment { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 数据库中类型(物理类型)
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "数据库中类型", Length = 64)]
|
||||
[MaxLength(64)]
|
||||
public string? DataType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// .NET数据类型
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "NET数据类型", Length = 64)]
|
||||
[MaxLength(64)]
|
||||
public string? NetType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 字段数据默认值
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "默认值")]
|
||||
public string? DefaultValue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 作用类型(字典)
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "作用类型", Length = 64)]
|
||||
[MaxLength(64)]
|
||||
public string? EffectType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 外键库标识
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "外键库标识", Length = 20)]
|
||||
[MaxLength(20)]
|
||||
public string? FkConfigId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 外键实体名称
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "外键实体名称", Length = 64)]
|
||||
[MaxLength(64)]
|
||||
public string? FkEntityName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 外键表名称
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "外键表名称", Length = 128)]
|
||||
[MaxLength(128)]
|
||||
public string? FkTableName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 外键显示字段
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "外键显示字段", Length = 64)]
|
||||
[MaxLength(64)]
|
||||
public string? FkDisplayColumns { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 外键链接字段
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "外键链接字段", Length = 64)]
|
||||
[MaxLength(64)]
|
||||
public string? FkLinkColumnName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 外键显示字段.NET类型
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "外键显示字段.NET类型", Length = 64)]
|
||||
[MaxLength(64)]
|
||||
public string? FkColumnNetType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 父级字段
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "父级字段", Length = 128)]
|
||||
[MaxLength(128)]
|
||||
public string? PidColumn { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 字典编码
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "字典编码", Length = 64)]
|
||||
[MaxLength(64)]
|
||||
public string? DictTypeCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 查询方式
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "查询方式", Length = 16)]
|
||||
[MaxLength(16)]
|
||||
public string? QueryType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否是查询条件
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "是否是查询条件", Length = 8)]
|
||||
[MaxLength(8)]
|
||||
public string? WhetherQuery { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 列表是否缩进(字典)
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "列表是否缩进", Length = 8)]
|
||||
[MaxLength(8)]
|
||||
public string? WhetherRetract { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否必填(字典)
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "是否必填", Length = 8)]
|
||||
[MaxLength(8)]
|
||||
public string? WhetherRequired { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否可排序(字典)
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "是否可排序", Length = 8)]
|
||||
[MaxLength(8)]
|
||||
public string? WhetherSortable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 列表显示
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "列表显示", Length = 8)]
|
||||
[MaxLength(8)]
|
||||
public string? WhetherTable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 增改
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "增改", Length = 8)]
|
||||
[MaxLength(8)]
|
||||
public string? WhetherAddUpdate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 导入
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "导入", Length = 8)]
|
||||
[MaxLength(8)]
|
||||
public string? WhetherImport { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否通用字段
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "是否通用字段", Length = 8)]
|
||||
[MaxLength(8)]
|
||||
public string? WhetherCommon { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 排序
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "排序")]
|
||||
public int OrderNo { get; set; } = 100;
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 系统作业集群表
|
||||
/// </summary>
|
||||
[SugarTable(null, "系统作业集群表")]
|
||||
[SysTable]
|
||||
public partial class SysJobCluster : EntityBaseId
|
||||
{
|
||||
/// <summary>
|
||||
/// 作业集群Id
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "作业集群Id", Length = 64)]
|
||||
[Required, MaxLength(64)]
|
||||
public virtual string ClusterId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 描述信息
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "描述信息", Length = 128)]
|
||||
[MaxLength(128)]
|
||||
public string? Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 状态
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "状态")]
|
||||
public ClusterStatus Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 更新时间
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "更新时间")]
|
||||
public DateTime? UpdatedTime { get; set; }
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 系统作业信息表
|
||||
/// </summary>
|
||||
[SugarTable(null, "系统作业信息表")]
|
||||
[SysTable]
|
||||
[SugarIndex("index_{table}_J", nameof(JobId), OrderByType.Asc)]
|
||||
public partial class SysJobDetail : EntityBaseId
|
||||
{
|
||||
/// <summary>
|
||||
/// 作业Id
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "作业Id", Length = 64)]
|
||||
[Required, MaxLength(64)]
|
||||
public virtual string JobId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 组名称
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "组名称", Length = 128)]
|
||||
[MaxLength(128)]
|
||||
public string? GroupName { get; set; } = "default";
|
||||
|
||||
/// <summary>
|
||||
/// 作业类型FullName
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "作业类型", Length = 128)]
|
||||
[MaxLength(128)]
|
||||
public string? JobType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 程序集Name
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "程序集", Length = 128)]
|
||||
[MaxLength(128)]
|
||||
public string? AssemblyName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 描述信息
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "描述信息", Length = 128)]
|
||||
[MaxLength(128)]
|
||||
public string? Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否并行执行
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "是否并行执行")]
|
||||
public bool Concurrent { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 是否扫描特性触发器
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "是否扫描特性触发器", ColumnName = "annotation")]
|
||||
public bool IncludeAnnotation { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 额外数据
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "额外数据", ColumnDataType = StaticConfig.CodeFirst_BigString)]
|
||||
public string? Properties { get; set; } = "{}";
|
||||
|
||||
/// <summary>
|
||||
/// 更新时间
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "更新时间")]
|
||||
public DateTime? UpdatedTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 作业创建类型
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "作业创建类型")]
|
||||
public JobCreateTypeEnum CreateType { get; set; } = JobCreateTypeEnum.BuiltIn;
|
||||
|
||||
/// <summary>
|
||||
/// 脚本代码
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "脚本代码", ColumnDataType = StaticConfig.CodeFirst_BigString)]
|
||||
public string? ScriptCode { get; set; }
|
||||
}
|
||||
@@ -1,147 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 系统作业触发器表
|
||||
/// </summary>
|
||||
[SugarTable(null, "系统作业触发器表")]
|
||||
[SysTable]
|
||||
public partial class SysJobTrigger : EntityBaseId
|
||||
{
|
||||
/// <summary>
|
||||
/// 触发器Id
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "触发器Id", Length = 64)]
|
||||
[Required, MaxLength(64)]
|
||||
public virtual string TriggerId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 作业Id
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "作业Id", Length = 64)]
|
||||
[Required, MaxLength(64)]
|
||||
public virtual string JobId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 触发器类型FullName
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "触发器类型", Length = 128)]
|
||||
[MaxLength(128)]
|
||||
public string? TriggerType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 程序集Name
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "程序集", Length = 128)]
|
||||
[MaxLength(128)]
|
||||
public string? AssemblyName { get; set; } = "Furion.Pure";
|
||||
|
||||
/// <summary>
|
||||
/// 参数
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "参数", Length = 128)]
|
||||
[MaxLength(128)]
|
||||
public string? Args { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 描述信息
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "描述信息", Length = 128)]
|
||||
[MaxLength(128)]
|
||||
public string? Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 状态
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "状态")]
|
||||
public TriggerStatus Status { get; set; } = TriggerStatus.Ready;
|
||||
|
||||
/// <summary>
|
||||
/// 起始时间
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "起始时间")]
|
||||
public DateTime? StartTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 结束时间
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "结束时间")]
|
||||
public DateTime? EndTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 最近运行时间
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "最近运行时间")]
|
||||
public DateTime? LastRunTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 下一次运行时间
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "下一次运行时间")]
|
||||
public DateTime? NextRunTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 触发次数
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "触发次数")]
|
||||
public long NumberOfRuns { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 最大触发次数(0:不限制,n:N次)
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "最大触发次数")]
|
||||
public long MaxNumberOfRuns { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 出错次数
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "出错次数")]
|
||||
public long NumberOfErrors { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 最大出错次数(0:不限制,n:N次)
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "最大出错次数")]
|
||||
public long MaxNumberOfErrors { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 重试次数
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "重试次数")]
|
||||
public int NumRetries { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 重试间隔时间(ms)
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "重试间隔时间(ms)")]
|
||||
public int RetryTimeout { get; set; } = 1000;
|
||||
|
||||
/// <summary>
|
||||
/// 是否立即启动
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "是否立即启动")]
|
||||
public bool StartNow { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 是否启动时执行一次
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "是否启动时执行一次")]
|
||||
public bool RunOnStart { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 是否在启动时重置最大触发次数等于一次的作业
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "是否重置触发次数")]
|
||||
public bool ResetOnlyOnce { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 更新时间
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "更新时间")]
|
||||
public DateTime? UpdatedTime { get; set; }
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 系统作业触发器运行记录表
|
||||
/// </summary>
|
||||
[SugarTable(null, "系统作业触发器运行记录表")]
|
||||
[SysTable]
|
||||
public partial class SysJobTriggerRecord : EntityBaseId
|
||||
{
|
||||
/// <summary>
|
||||
/// 作业Id
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "作业Id", Length = 64)]
|
||||
[Required, MaxLength(64)]
|
||||
public virtual string JobId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 触发器Id
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "触发器Id", Length = 64)]
|
||||
[Required, MaxLength(64)]
|
||||
public virtual string TriggerId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 当前运行次数
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "当前运行次数")]
|
||||
public long NumberOfRuns { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 最近运行时间
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "最近运行时间")]
|
||||
public DateTime? LastRunTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 下一次运行时间
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "下一次运行时间")]
|
||||
public DateTime? NextRunTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 触发器状态
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "触发器状态")]
|
||||
public TriggerStatus Status { get; set; } = TriggerStatus.Ready;
|
||||
|
||||
/// <summary>
|
||||
/// 本次执行结果
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "本次执行结果", Length = 128)]
|
||||
[MaxLength(128)]
|
||||
public string? Result { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 本次执行耗时
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "本次执行耗时")]
|
||||
public long ElapsedTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建时间
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "创建时间")]
|
||||
public DateTime? CreatedTime { get; set; }
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 系统域登录信息配置表
|
||||
/// </summary>
|
||||
[SugarTable(null, "系统域登录信息配置表")]
|
||||
[SysTable]
|
||||
public class SysLdap : EntityBaseTenantDel
|
||||
{
|
||||
/// <summary>
|
||||
/// 主机
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "主机", Length = 128)]
|
||||
[Required]
|
||||
public virtual string Host { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 端口
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "端口")]
|
||||
public virtual int Port { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户搜索基准
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "用户搜索基准", Length = 128)]
|
||||
[Required]
|
||||
public virtual string BaseDn { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 绑定DN(有管理权限制的用户)
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "绑定DN", Length = 128)]
|
||||
[Required]
|
||||
public virtual string BindDn { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 绑定密码(有管理权限制的用户密码)
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "绑定密码", Length = 512)]
|
||||
[Required]
|
||||
public virtual string BindPass { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户过滤规则
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "用户过滤规则", Length = 128)]
|
||||
[Required]
|
||||
public virtual string AuthFilter { get; set; } = "sAMAccountName=%s";
|
||||
|
||||
/// <summary>
|
||||
/// Ldap版本
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "Ldap版本")]
|
||||
public int Version { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 绑定域账号字段属性值
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "绑定域账号字段属性值", Length = 32)]
|
||||
[Required]
|
||||
public virtual string BindAttrAccount { get; set; } = "sAMAccountName";
|
||||
|
||||
/// <summary>
|
||||
/// 绑定用户EmployeeId属性值
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "绑定用户EmployeeId属性值", Length = 32)]
|
||||
[Required]
|
||||
public virtual string BindAttrEmployeeId { get; set; } = "EmployeeId";
|
||||
|
||||
/// <summary>
|
||||
/// 绑定Code属性值
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "绑定对象Code属性值", Length = 64)]
|
||||
[Required]
|
||||
public virtual string BindAttrCode { get; set; } = "objectGUID";
|
||||
|
||||
/// <summary>
|
||||
/// 状态
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "状态")]
|
||||
public StatusEnum Status { get; set; } = StatusEnum.Enable;
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 系统动态插件表
|
||||
/// </summary>
|
||||
[SugarTable(null, "系统动态插件表")]
|
||||
[SysTable]
|
||||
[SugarIndex("index_{table}_N", nameof(Name), OrderByType.Asc)]
|
||||
public partial class SysPlugin : EntityBaseTenant
|
||||
{
|
||||
/// <summary>
|
||||
/// 名称
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "名称", Length = 64)]
|
||||
[Required, MaxLength(64)]
|
||||
public virtual string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// C#代码
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "C#代码", ColumnDataType = StaticConfig.CodeFirst_BigString)]
|
||||
[Required]
|
||||
public virtual string CsharpCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 程序集名称
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "程序集名称", Length = 512)]
|
||||
[MaxLength(512)]
|
||||
public string? AssemblyName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 排序
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "排序")]
|
||||
public int OrderNo { get; set; } = 100;
|
||||
|
||||
/// <summary>
|
||||
/// 状态
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "状态")]
|
||||
public StatusEnum Status { get; set; } = StatusEnum.Enable;
|
||||
|
||||
/// <summary>
|
||||
/// 备注
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "备注", Length = 128)]
|
||||
[MaxLength(128)]
|
||||
public string? Remark { get; set; }
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 系统打印模板表
|
||||
/// </summary>
|
||||
[SugarTable(null, "系统打印模板表")]
|
||||
[SysTable]
|
||||
[SugarIndex("index_{table}_N", nameof(Name), OrderByType.Asc)]
|
||||
public partial class SysPrint : EntityBaseTenant
|
||||
{
|
||||
/// <summary>
|
||||
/// 名称
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "名称", Length = 64)]
|
||||
[Required, MaxLength(64)]
|
||||
public virtual string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 打印模板
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "打印模板", ColumnDataType = StaticConfig.CodeFirst_BigString)]
|
||||
[Required]
|
||||
public virtual string Template { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 打印类型
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "打印类型")]
|
||||
[Required]
|
||||
public virtual PrintTypeEnum? PrintType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 客户端服务地址
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "客户端服务地址", Length = 128)]
|
||||
[MaxLength(128)]
|
||||
public virtual string? ClientServiceAddress { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 打印参数
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "打印参数", ColumnDataType = StaticConfig.CodeFirst_BigString)]
|
||||
public virtual string? PrintParam { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 排序
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "排序")]
|
||||
public int OrderNo { get; set; } = 100;
|
||||
|
||||
/// <summary>
|
||||
/// 状态
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "状态")]
|
||||
public StatusEnum Status { get; set; } = StatusEnum.Enable;
|
||||
|
||||
/// <summary>
|
||||
/// 备注
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "备注", Length = 128)]
|
||||
[MaxLength(128)]
|
||||
public string? Remark { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 打印预览测试数据
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "打印预览测试数据", ColumnDataType = StaticConfig.CodeFirst_BigString)]
|
||||
public string? PrintDataDemo { get; set; }
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 系统日程表
|
||||
/// </summary>
|
||||
[SugarTable(null, "系统日程表")]
|
||||
[SysTable]
|
||||
public class SysSchedule : EntityBaseTenant
|
||||
{
|
||||
/// <summary>
|
||||
/// 用户Id
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "用户Id")]
|
||||
public long UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 日程日期
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "日程日期")]
|
||||
public DateTime? ScheduleTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 开始时间
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "开始时间", Length = 10)]
|
||||
public string? StartTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 结束时间
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "结束时间", Length = 10)]
|
||||
public string? EndTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 日程内容
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "日程内容", Length = 256)]
|
||||
[Required, MaxLength(256)]
|
||||
public virtual string Content { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 完成状态
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "完成状态")]
|
||||
public FinishStatusEnum Status { get; set; } = FinishStatusEnum.UnFinish;
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 系统用户域配置表
|
||||
/// </summary>
|
||||
[SugarTable(null, "系统用户域配置表")]
|
||||
[SysTable]
|
||||
[SugarIndex("index_{table}_A", nameof(Account), OrderByType.Asc)]
|
||||
[SugarIndex("index_{table}_U", nameof(UserId), OrderByType.Asc)]
|
||||
public class SysUserLdap : EntityBaseTenantId
|
||||
{
|
||||
/// <summary>
|
||||
/// 用户Id
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "用户Id")]
|
||||
public long UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 域账号
|
||||
/// AD域对应sAMAccountName
|
||||
/// Ldap对应uid
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "域账号", Length = 32)]
|
||||
[Required]
|
||||
public string Account { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 域用户名
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "域用户名", Length = 32)]
|
||||
public string UserName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 对应EmployeeId(用于数据导入对照)
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "对应EmployeeId", Length = 32)]
|
||||
public string? EmployeeId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 组织代码
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "组织代码", Length = 64)]
|
||||
public string? DeptCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 最后设置密码时间
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "最后设置密码时间")]
|
||||
public DateTime? PwdLastSetTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 邮箱
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "组织代码", Length = 64)]
|
||||
public string? Mail { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 检查账户是否已过期
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "检查账户是否已过期")]
|
||||
public bool AccountExpiresFlag { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 密码设置是否永不过期
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "密码设置是否永不过期")]
|
||||
public bool DontExpiresFlag { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// DN
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "DN", Length = 512)]
|
||||
public string Dn { get; set; }
|
||||
}
|
||||
@@ -1,191 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 系统微信支付表
|
||||
/// </summary>
|
||||
[SugarTable(null, "系统微信支付表")]
|
||||
[SysTable]
|
||||
[SugarIndex("index_{table}_BU", nameof(BusinessId), OrderByType.Asc)]
|
||||
[SugarIndex("index_{table}_TR", nameof(TradeState), OrderByType.Asc)]
|
||||
[SugarIndex("index_{table}_TA", nameof(Tags), OrderByType.Asc)]
|
||||
public partial class SysWechatPay : EntityBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 微信商户号
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "微信商户号")]
|
||||
[Required]
|
||||
public virtual string MerchantId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 服务商AppId
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "服务商AppId")]
|
||||
[Required]
|
||||
public virtual string AppId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 商户订单号
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "商户订单号")]
|
||||
[Required]
|
||||
public virtual string OutTradeNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 支付订单号
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "支付订单号")]
|
||||
[Required]
|
||||
public virtual string TransactionId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 交易类型
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "交易类型")]
|
||||
public string? TradeType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 交易状态
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "交易状态")]
|
||||
public string? TradeState { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 交易状态描述
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "交易状态描述")]
|
||||
public string? TradeStateDescription { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 付款银行类型
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "付款银行类型")]
|
||||
public string? BankType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 订单总金额
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "订单总金额")]
|
||||
public int Total { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户支付金额
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "用户支付金额")]
|
||||
public int? PayerTotal { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 支付完成时间
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "支付完成时间")]
|
||||
public DateTime? SuccessTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 交易结束时间
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "交易结束时间")]
|
||||
public DateTime? ExpireTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 商品描述
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "商品描述")]
|
||||
public string? Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 场景信息
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "场景信息")]
|
||||
public string? Scene { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 附加数据
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "附加数据")]
|
||||
public string? Attachment { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 优惠标记
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "优惠标记")]
|
||||
public string? GoodsTag { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 结算信息
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "结算信息")]
|
||||
public string? Settlement { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 回调通知地址
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "回调通知地址")]
|
||||
public string? NotifyUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 备注
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "备注")]
|
||||
public string? Remark { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 微信OpenId标识
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "微信OpenId标识")]
|
||||
public string? OpenId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 业务标签,用来区分做什么业务
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Tags标识用来区分这个支付记录对应什么业务从而确定相关联的表名,
|
||||
/// 再结合BusinessId保存了对应的业务数据的ID,就可以确定这个支付
|
||||
/// 记录与哪一条业务数据相关联
|
||||
/// </remarks>
|
||||
[SugarColumn(ColumnDescription = "业务标签,用来区分做什么业务", Length = 64)]
|
||||
public string? Tags { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 对应业务的主键
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "对应业务的主键")]
|
||||
public long BusinessId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 付款二维码内容
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "付款二维码内容")]
|
||||
public string? QrcodeContent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 关联微信用户
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonIgnore]
|
||||
[System.Text.Json.Serialization.JsonIgnore]
|
||||
[Navigate(NavigateType.OneToOne, nameof(OpenId))]
|
||||
public SysWechatUser SysWechatUser { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 子商户号
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "子商户号")]
|
||||
public string? SubMerchantId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 子商户AppId
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "回调通知地址")]
|
||||
public string? SubAppId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 子商户唯一标识
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "子商户唯一标识")]
|
||||
public string? SubOpenId { get; set; }
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 系统微信支付退款表
|
||||
/// </summary>
|
||||
[SugarTable(null, "系统微信支付退款表")]
|
||||
[SysTable]
|
||||
[SugarIndex("index_{table}_W", nameof(WechatPayId), OrderByType.Asc)]
|
||||
public partial class SysWechatRefund : EntityBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 定单主键
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "定单主键")]
|
||||
public long WechatPayId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 商户退款号
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "商户退款号")]
|
||||
[Required]
|
||||
public virtual string OutRefundNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 退款订单号
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "退款订单号")]
|
||||
[Required]
|
||||
public virtual string TransactionId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 退款原因
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "退款原因")]
|
||||
public string? Reason { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 退款渠道
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "退款渠道")]
|
||||
public string? Channel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 退款入账账户
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 取当前退款单的退款入账方,有以下几种情况:
|
||||
/// 1)退回银行卡:{银行名称}{卡类型}{ 卡尾号}
|
||||
/// 2)退回支付用户零钱: 支付用户零钱
|
||||
/// 3)退还商户: 商户基本账户商户结算银行账户
|
||||
/// 4)退回支付用户零钱通: 支付用户零钱通
|
||||
/// </remarks>
|
||||
[SugarColumn(ColumnDescription = "退款入账账户")]
|
||||
public string? UserReceivedAccount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 退款状态
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "退款状态")]
|
||||
public string? TradeState { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 交易状态描述
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "交易状态描述")]
|
||||
public string? TradeStateDescription { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 订单总金额
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "退款金额")]
|
||||
public int Refund { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 支完成时间
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "完成时间")]
|
||||
public DateTime? SuccessTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 回调通知地址
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "回调通知地址")]
|
||||
public string? NotifyUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 备注
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "备注")]
|
||||
public string? Remark { get; set; }
|
||||
}
|
||||
@@ -1,138 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 系统微信用户表
|
||||
/// </summary>
|
||||
[SugarTable(null, "系统微信用户表")]
|
||||
[SysTable]
|
||||
[SugarIndex("index_{table}_N", nameof(NickName), OrderByType.Asc)]
|
||||
[SugarIndex("index_{table}_M", nameof(Mobile), OrderByType.Asc)]
|
||||
public partial class SysWechatUser : EntityBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 系统用户Id
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "系统用户Id")]
|
||||
public long UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 系统用户
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonIgnore]
|
||||
[System.Text.Json.Serialization.JsonIgnore]
|
||||
[Navigate(NavigateType.OneToOne, nameof(UserId))]
|
||||
public SysUser SysUser { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 平台类型
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "平台类型")]
|
||||
public PlatformTypeEnum PlatformType { get; set; } = PlatformTypeEnum.微信公众号;
|
||||
|
||||
/// <summary>
|
||||
/// OpenId
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "OpenId", Length = 64)]
|
||||
[Required, MaxLength(64)]
|
||||
public virtual string OpenId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 会话密钥
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "会话密钥", Length = 256)]
|
||||
[MaxLength(256)]
|
||||
public string? SessionKey { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// UnionId
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "UnionId", Length = 64)]
|
||||
[MaxLength(64)]
|
||||
public string? UnionId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 昵称
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "昵称", Length = 64)]
|
||||
[MaxLength(64)]
|
||||
public string? NickName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 头像
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "头像", Length = 256)]
|
||||
[MaxLength(256)]
|
||||
public string? Avatar { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 手机号码
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "手机号码", Length = 16)]
|
||||
[MaxLength(16)]
|
||||
public string? Mobile { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 性别
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "性别")]
|
||||
public int? Sex { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 语言
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "语言", Length = 64)]
|
||||
[MaxLength(64)]
|
||||
public string? Language { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 城市
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "城市", Length = 64)]
|
||||
[MaxLength(64)]
|
||||
public string? City { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 省
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "省", Length = 64)]
|
||||
[MaxLength(64)]
|
||||
public string? Province { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 国家
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "国家", Length = 64)]
|
||||
[MaxLength(64)]
|
||||
public string? Country { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// AccessToken
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "AccessToken", ColumnDataType = StaticConfig.CodeFirst_BigString)]
|
||||
public string? AccessToken { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// RefreshToken
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "RefreshToken", ColumnDataType = StaticConfig.CodeFirst_BigString)]
|
||||
public string? RefreshToken { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 过期时间
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "ExpiresIn")]
|
||||
public int? ExpiresIn { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户授权的作用域,使用逗号分隔
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "授权作用域", Length = 64)]
|
||||
[MaxLength(64)]
|
||||
public string? Scope { get; set; }
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 参与方的证件类型枚举
|
||||
/// </summary>
|
||||
[SuppressSniffer]
|
||||
[Description("参与方的证件类型枚举")]
|
||||
public enum AlipayCertTypeEnum
|
||||
{
|
||||
[Description("身份证")]
|
||||
IDENTITY_CARD,
|
||||
|
||||
[Description("护照")]
|
||||
PASSPORT
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 参与方的标识类型枚举
|
||||
/// </summary>
|
||||
[SuppressSniffer]
|
||||
[Description("参与方的标识类型枚举")]
|
||||
public enum AlipayIdentityTypeEnum
|
||||
{
|
||||
[Description("支付宝用户UID")]
|
||||
ALIPAY_USER_ID,
|
||||
|
||||
[Description("支付宝登录号")]
|
||||
ALIPAY_LOGON_ID
|
||||
}
|
||||
@@ -607,18 +607,6 @@ public enum ErrorCodeEnum
|
||||
[ErrorCodeItemMetadata("禁止删除系统参数")]
|
||||
D9001,
|
||||
|
||||
/// <summary>
|
||||
/// 已存在同名任务调度
|
||||
/// </summary>
|
||||
[ErrorCodeItemMetadata("已存在同名任务调度")]
|
||||
D1100,
|
||||
|
||||
/// <summary>
|
||||
/// 任务调度不存在
|
||||
/// </summary>
|
||||
[ErrorCodeItemMetadata("任务调度不存在")]
|
||||
D1101,
|
||||
|
||||
/// <summary>
|
||||
/// 演示环境禁止修改数据
|
||||
/// </summary>
|
||||
@@ -655,12 +643,6 @@ public enum ErrorCodeEnum
|
||||
[ErrorCodeItemMetadata("授权菜单存在重复项")]
|
||||
D1304,
|
||||
|
||||
/// <summary>
|
||||
/// 该表代码模板已经生成过
|
||||
/// </summary>
|
||||
[ErrorCodeItemMetadata("该表代码模板已经生成过")]
|
||||
D1400,
|
||||
|
||||
/// <summary>
|
||||
/// 数据库配置不存在
|
||||
/// </summary>
|
||||
@@ -715,48 +697,6 @@ public enum ErrorCodeEnum
|
||||
[ErrorCodeItemMetadata("已有相同编码或名称")]
|
||||
D1602,
|
||||
|
||||
/// <summary>
|
||||
/// 脚本代码不能为空
|
||||
/// </summary>
|
||||
[ErrorCodeItemMetadata("脚本代码不能为空")]
|
||||
D1701,
|
||||
|
||||
/// <summary>
|
||||
/// 脚本代码中的作业类,需要定义 [JobDetail] 特性
|
||||
/// </summary>
|
||||
[ErrorCodeItemMetadata("脚本代码中的作业类,需要定义 [JobDetail] 特性")]
|
||||
D1702,
|
||||
|
||||
/// <summary>
|
||||
/// 作业编号需要与脚本代码中的作业类 [JobDetail('jobId')] 一致
|
||||
/// </summary>
|
||||
[ErrorCodeItemMetadata("作业编号需要与脚本代码中的作业类 [JobDetail('jobId')] 一致")]
|
||||
D1703,
|
||||
|
||||
/// <summary>
|
||||
/// 禁止修改作业编号
|
||||
/// </summary>
|
||||
[ErrorCodeItemMetadata("禁止修改作业编号")]
|
||||
D1704,
|
||||
|
||||
/// <summary>
|
||||
/// 执行作业失败
|
||||
/// </summary>
|
||||
[ErrorCodeItemMetadata("执行作业失败")]
|
||||
D1705,
|
||||
|
||||
/// <summary>
|
||||
/// 已存在同名打印模板
|
||||
/// </summary>
|
||||
[ErrorCodeItemMetadata("已存在同名打印模板")]
|
||||
D1800,
|
||||
|
||||
/// <summary>
|
||||
/// 已存在同名功能或同名程序及插件
|
||||
/// </summary>
|
||||
[ErrorCodeItemMetadata("已存在同名功能或同名程序及插件")]
|
||||
D1900,
|
||||
|
||||
/// <summary>
|
||||
/// 注册方案名称已存在
|
||||
/// </summary>
|
||||
@@ -906,4 +846,4 @@ public enum ErrorCodeEnum
|
||||
/// </summary>
|
||||
[ErrorCodeItemMetadata("禁止非超级管理员操作")]
|
||||
SA001
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 作业创建类型枚举
|
||||
/// </summary>
|
||||
[Description("作业创建类型枚举")]
|
||||
public enum JobCreateTypeEnum
|
||||
{
|
||||
/// <summary>
|
||||
/// 内置
|
||||
/// </summary>
|
||||
[Description("内置"), Theme("info")]
|
||||
BuiltIn = 0,
|
||||
|
||||
/// <summary>
|
||||
/// 脚本
|
||||
/// </summary>
|
||||
[Description("脚本")]
|
||||
Script = 1,
|
||||
|
||||
/// <summary>
|
||||
/// HTTP请求
|
||||
/// </summary>
|
||||
[Description("HTTP请求")]
|
||||
Http = 2,
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 岗位状态枚举
|
||||
/// </summary>
|
||||
[Description("岗位状态枚举")]
|
||||
public enum JobStatusEnum
|
||||
{
|
||||
/// <summary>
|
||||
/// 在职
|
||||
/// </summary>
|
||||
[Description("在职")]
|
||||
On = 1,
|
||||
|
||||
/// <summary>
|
||||
/// 离职
|
||||
/// </summary>
|
||||
[Description("离职")]
|
||||
Off = 2,
|
||||
|
||||
/// <summary>
|
||||
/// 请假
|
||||
/// </summary>
|
||||
[Description("请假")]
|
||||
Leave = 3,
|
||||
|
||||
/// <summary>
|
||||
/// 其他
|
||||
/// </summary>
|
||||
[Description("其他")]
|
||||
Other = 4,
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 打印类型枚举
|
||||
/// </summary>
|
||||
[Description("打印类型枚举")]
|
||||
public enum PrintTypeEnum
|
||||
{
|
||||
/// <summary>
|
||||
/// 浏览器打印
|
||||
/// </summary>
|
||||
[Description("浏览器打印")]
|
||||
Browser = 1,
|
||||
|
||||
/// <summary>
|
||||
/// 浏览器打印
|
||||
/// </summary>
|
||||
[Description("客户端打印")]
|
||||
Client = 2,
|
||||
}
|
||||
@@ -1,289 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 微信开发返回码
|
||||
/// </summary>
|
||||
[Description("微信开发返回码")]
|
||||
public enum WechatReturnCodeEnum
|
||||
{
|
||||
SenparcWeixinSDK配置错误 = -99, // 0xFFFFFF9D
|
||||
系统繁忙此时请开发者稍候再试 = -1, // 0xFFFFFFFF
|
||||
请求成功 = 0,
|
||||
工商数据返回_企业已注销 = 101, // 0x00000065
|
||||
工商数据返回_企业不存在或企业信息未更新 = 102, // 0x00000066
|
||||
工商数据返回_企业法定代表人姓名不一致 = 103, // 0x00000067
|
||||
工商数据返回_企业法定代表人身份证号码不一致 = 104, // 0x00000068
|
||||
法定代表人身份证号码_工商数据未更新_请5_15个工作日之后尝试 = 105, // 0x00000069
|
||||
工商数据返回_企业信息或法定代表人信息不一致 = 1000, // 0x000003E8
|
||||
对方不是粉丝 = 10700, // 0x000029CC
|
||||
发送消息失败_对方关闭了接收消息 = 10703, // 0x000029CF
|
||||
发送消息失败_48小时内用户未互动 = 10706, // 0x000029D2
|
||||
POST参数非法 = 20002, // 0x00004E22
|
||||
获取access_token时AppSecret错误或者access_token无效 = 40001, // 0x00009C41
|
||||
|
||||
/// <summary>
|
||||
/// <para>公众号:不合法的凭证类型</para>
|
||||
/// <para>小程序:暂无生成权限</para>
|
||||
/// </summary>
|
||||
不合法的凭证类型 = 40002, // 0x00009C42
|
||||
|
||||
不合法的OpenID = 40003, // 0x00009C43
|
||||
不合法的媒体文件类型 = 40004, // 0x00009C44
|
||||
不合法的文件类型 = 40005, // 0x00009C45
|
||||
不合法的文件大小 = 40006, // 0x00009C46
|
||||
不合法的媒体文件id = 40007, // 0x00009C47
|
||||
不合法的消息类型_40008 = 40008, // 0x00009C48
|
||||
不合法的图片文件大小 = 40009, // 0x00009C49
|
||||
不合法的语音文件大小 = 40010, // 0x00009C4A
|
||||
不合法的视频文件大小 = 40011, // 0x00009C4B
|
||||
不合法的缩略图文件大小 = 40012, // 0x00009C4C
|
||||
|
||||
/// <summary>
|
||||
/// <para>微信:不合法的APPID</para>
|
||||
/// <para>小程序:生成权限被封禁</para>
|
||||
/// </summary>
|
||||
不合法的APPID = 40013, // 0x00009C4D
|
||||
|
||||
不合法的access_token = 40014, // 0x00009C4E
|
||||
不合法的菜单类型 = 40015, // 0x00009C4F
|
||||
不合法的按钮个数1 = 40016, // 0x00009C50
|
||||
不合法的按钮个数2 = 40017, // 0x00009C51
|
||||
不合法的按钮名字长度 = 40018, // 0x00009C52
|
||||
不合法的按钮KEY长度 = 40019, // 0x00009C53
|
||||
不合法的按钮URL长度 = 40020, // 0x00009C54
|
||||
不合法的菜单版本号 = 40021, // 0x00009C55
|
||||
不合法的子菜单级数 = 40022, // 0x00009C56
|
||||
不合法的子菜单按钮个数 = 40023, // 0x00009C57
|
||||
不合法的子菜单按钮类型 = 40024, // 0x00009C58
|
||||
不合法的子菜单按钮名字长度 = 40025, // 0x00009C59
|
||||
不合法的子菜单按钮KEY长度 = 40026, // 0x00009C5A
|
||||
不合法的子菜单按钮URL长度 = 40027, // 0x00009C5B
|
||||
不合法的自定义菜单使用用户 = 40028, // 0x00009C5C
|
||||
不合法的oauth_code = 40029, // 0x00009C5D
|
||||
不合法的refresh_token = 40030, // 0x00009C5E
|
||||
不合法的openid列表 = 40031, // 0x00009C5F
|
||||
不合法的openid列表长度 = 40032, // 0x00009C60
|
||||
不合法的请求字符不能包含uxxxx格式的字符 = 40033, // 0x00009C61
|
||||
不合法的参数 = 40035, // 0x00009C63
|
||||
template_id不正确 = 40037, // 0x00009C65
|
||||
不合法的请求格式 = 40038, // 0x00009C66
|
||||
不合法的URL长度 = 40039, // 0x00009C67
|
||||
不合法的分组id = 40050, // 0x00009C72
|
||||
分组名字不合法 = 40051, // 0x00009C73
|
||||
|
||||
/// <summary>
|
||||
/// <para>公众号:输入参数有误</para>
|
||||
/// <para>小程序:参数expire_time填写错误</para>
|
||||
/// </summary>
|
||||
输入参数有误 = 40097, // 0x00009CA1
|
||||
|
||||
appsecret不正确 = 40125, // 0x00009CBD
|
||||
调用接口的IP地址不在白名单中 = 40164, // 0x00009CE4
|
||||
参数path填写错误 = 40165, // 0x00009CE5
|
||||
小程序Appid不存在 = 40166, // 0x00009CE6
|
||||
参数query填写错误 = 40212, // 0x00009D14
|
||||
缺少access_token参数 = 41001, // 0x0000A029
|
||||
缺少appid参数 = 41002, // 0x0000A02A
|
||||
缺少refresh_token参数 = 41003, // 0x0000A02B
|
||||
缺少secret参数 = 41004, // 0x0000A02C
|
||||
缺少多媒体文件数据 = 41005, // 0x0000A02D
|
||||
缺少media_id参数 = 41006, // 0x0000A02E
|
||||
缺少子菜单数据 = 41007, // 0x0000A02F
|
||||
缺少oauth_code = 41008, // 0x0000A030
|
||||
缺少openid = 41009, // 0x0000A031
|
||||
form_id不正确_或者过期 = 41028, // 0x0000A044
|
||||
form_id已被使用 = 41029, // 0x0000A045
|
||||
page不正确 = 41030, // 0x0000A046
|
||||
access_token超时 = 42001, // 0x0000A411
|
||||
refresh_token超时 = 42002, // 0x0000A412
|
||||
oauth_code超时 = 42003, // 0x0000A413
|
||||
需要GET请求 = 43001, // 0x0000A7F9
|
||||
需要POST请求 = 43002, // 0x0000A7FA
|
||||
需要HTTPS请求 = 43003, // 0x0000A7FB
|
||||
需要接收者关注 = 43004, // 0x0000A7FC
|
||||
需要好友关系 = 43005, // 0x0000A7FD
|
||||
|
||||
/// <summary>[小程序订阅消息]用户拒绝接受消息,如果用户之前曾经订阅过,则表示用户取消了订阅关系</summary>
|
||||
用户拒绝接受消息 = 43101, // 0x0000A85D
|
||||
|
||||
没有权限 = 43104, // 0x0000A860
|
||||
多媒体文件为空 = 44001, // 0x0000ABE1
|
||||
POST的数据包为空 = 44002, // 0x0000ABE2
|
||||
图文消息内容为空 = 44003, // 0x0000ABE3
|
||||
文本消息内容为空 = 44004, // 0x0000ABE4
|
||||
多媒体文件大小超过限制 = 45001, // 0x0000AFC9
|
||||
消息内容超过限制 = 45002, // 0x0000AFCA
|
||||
标题字段超过限制 = 45003, // 0x0000AFCB
|
||||
描述字段超过限制 = 45004, // 0x0000AFCC
|
||||
链接字段超过限制 = 45005, // 0x0000AFCD
|
||||
图片链接字段超过限制 = 45006, // 0x0000AFCE
|
||||
语音播放时间超过限制 = 45007, // 0x0000AFCF
|
||||
图文消息超过限制 = 45008, // 0x0000AFD0
|
||||
接口调用超过限制 = 45009, // 0x0000AFD1
|
||||
创建菜单个数超过限制 = 45010, // 0x0000AFD2
|
||||
回复时间超过限制 = 45015, // 0x0000AFD7
|
||||
系统分组不允许修改 = 45016, // 0x0000AFD8
|
||||
分组名字过长 = 45017, // 0x0000AFD9
|
||||
分组数量超过上限 = 45018, // 0x0000AFDA
|
||||
超出响应数量限制 = 45047, // 0x0000AFF7
|
||||
创建的标签数过多请注意不能超过100个 = 45056, // 0x0000B000
|
||||
标签名非法请注意不能和其他标签重名 = 45157, // 0x0000B065
|
||||
标签名长度超过30个字节 = 45158, // 0x0000B066
|
||||
不存在媒体数据 = 46001, // 0x0000B3B1
|
||||
不存在的菜单版本 = 46002, // 0x0000B3B2
|
||||
不存在的菜单数据 = 46003, // 0x0000B3B3
|
||||
解析JSON_XML内容错误 = 47001, // 0x0000B799
|
||||
|
||||
/// <summary>[小程序订阅消息]模板参数不准确,可能为空或者不满足规则,errmsg会提示具体是哪个字段出错</summary>
|
||||
模板参数不准确 = 47003, // 0x0000B79B
|
||||
|
||||
api功能未授权 = 48001, // 0x0000BB81
|
||||
用户未授权该api = 50001, // 0x0000C351
|
||||
名称格式不合法 = 53010, // 0x0000CF12
|
||||
名称检测命中频率限制 = 53011, // 0x0000CF13
|
||||
禁止使用该名称 = 53012, // 0x0000CF14
|
||||
公众号_名称与已有公众号名称重复_小程序_该名称与已有小程序名称重复 = 53013, // 0x0000CF15
|
||||
公众号_公众号已有_名称A_时_需与该帐号相同主体才可申请_名称A_小程序_小程序已有_名称A_时_需与该帐号相同主体才可申请_名称A_ = 53014, // 0x0000CF16
|
||||
公众号_该名称与已有小程序名称重复_需与该小程序帐号相同主体才可申请_小程序_该名称与已有公众号名称重复_需与该公众号帐号相同主体才可申请 = 53015, // 0x0000CF17
|
||||
公众号_该名称与已有多个小程序名称重复_暂不支持申请_小程序_该名称与已有多个公众号名称重复_暂不支持申请 = 53016, // 0x0000CF18
|
||||
公众号_小程序已有_名称A_时_需与该帐号相同主体才可申请_名称A_小程序_公众号已有_名称A_时_需与该帐号相同主体才可申请_名称A = 53017, // 0x0000CF19
|
||||
名称命中微信号 = 53018, // 0x0000CF1A
|
||||
名称在保护期内 = 53019, // 0x0000CF1B
|
||||
法人姓名与微信号不一致 = 61070, // 0x0000EE8E
|
||||
系统错误system_error = 61450, // 0x0000F00A
|
||||
参数错误invalid_parameter = 61451, // 0x0000F00B
|
||||
无效客服账号invalid_kf_account = 61452, // 0x0000F00C
|
||||
客服帐号已存在kf_account_exsited = 61453, // 0x0000F00D
|
||||
|
||||
/// <summary>
|
||||
/// 客服帐号名长度超过限制(仅允许10个英文字符,不包括@及@后的公众号的微信号)(invalid kf_acount length)
|
||||
/// </summary>
|
||||
客服帐号名长度超过限制 = 61454, // 0x0000F00E
|
||||
|
||||
/// <summary>
|
||||
/// 客服帐号名包含非法字符(仅允许英文+数字)(illegal character in kf_account)
|
||||
/// </summary>
|
||||
客服帐号名包含非法字符 = 61455, // 0x0000F00F
|
||||
|
||||
/// <summary>客服帐号个数超过限制(10个客服账号)(kf_account count exceeded)</summary>
|
||||
客服帐号个数超过限制 = 61456, // 0x0000F010
|
||||
|
||||
无效头像文件类型invalid_file_type = 61457, // 0x0000F011
|
||||
日期格式错误 = 61500, // 0x0000F03C
|
||||
日期范围错误 = 61501, // 0x0000F03D
|
||||
发送消息失败_该用户已被加入黑名单_无法向此发送消息 = 62751, // 0x0000F51F
|
||||
门店不存在 = 65115, // 0x0000FE5B
|
||||
该门店状态不允许更新 = 65118, // 0x0000FE5E
|
||||
标签格式错误 = 85006, // 0x00014C0E
|
||||
页面路径错误 = 85007, // 0x00014C0F
|
||||
类目填写错误 = 85008, // 0x00014C10
|
||||
已经有正在审核的版本 = 85009, // 0x00014C11
|
||||
item_list有项目为空 = 85010, // 0x00014C12
|
||||
标题填写错误 = 85011, // 0x00014C13
|
||||
无效的审核id = 85012, // 0x00014C14
|
||||
版本输入错误 = 85015, // 0x00014C17
|
||||
没有审核版本 = 85019, // 0x00014C1B
|
||||
审核状态未满足发布 = 85020, // 0x00014C1C
|
||||
状态不可变 = 85021, // 0x00014C1D
|
||||
action非法 = 85022, // 0x00014C1E
|
||||
审核列表填写的项目数不在1到5以内 = 85023, // 0x00014C1F
|
||||
需要补充相应资料_填写org_code和other_files参数 = 85024, // 0x00014C20
|
||||
管理员手机登记数量已超过上限 = 85025, // 0x00014C21
|
||||
该微信号已绑定5个管理员 = 85026, // 0x00014C22
|
||||
管理员身份证已登记过5次 = 85027, // 0x00014C23
|
||||
该主体登记数量已超过上限 = 85028, // 0x00014C24
|
||||
商家名称已被占用 = 85029, // 0x00014C25
|
||||
不能使用该名称 = 85031, // 0x00014C27
|
||||
该名称在侵权投诉保护期 = 85032, // 0x00014C28
|
||||
名称包含违规内容或微信等保留字 = 85033, // 0x00014C29
|
||||
商家名称在改名15天保护期内 = 85034, // 0x00014C2A
|
||||
需与该帐号相同主体才可申请 = 85035, // 0x00014C2B
|
||||
介绍中含有虚假混淆内容 = 85036, // 0x00014C2C
|
||||
头像或者简介修改达到每个月上限 = 85049, // 0x00014C39
|
||||
正在审核中_请勿重复提交 = 85050, // 0x00014C3A
|
||||
请先成功创建门店后再调用 = 85053, // 0x00014C3D
|
||||
临时mediaid无效 = 85056, // 0x00014C40
|
||||
链接错误 = 85066, // 0x00014C4A
|
||||
测试链接不是子链接 = 85068, // 0x00014C4C
|
||||
校验文件失败 = 85069, // 0x00014C4D
|
||||
个人类型小程序无法设置二维码规则 = 85070, // 0x00014C4E
|
||||
已添加该链接_请勿重复添加 = 85071, // 0x00014C4F
|
||||
该链接已被占用 = 85072, // 0x00014C50
|
||||
二维码规则已满 = 85073, // 0x00014C51
|
||||
小程序未发布_小程序必须先发布代码才可以发布二维码跳转规则 = 85074, // 0x00014C52
|
||||
个人类型小程序无法设置二维码规则1 = 85075, // 0x00014C53
|
||||
小程序没有线上版本_不能进行灰度 = 85079, // 0x00014C57
|
||||
小程序提交的审核未审核通过 = 85080, // 0x00014C58
|
||||
无效的发布比例 = 85081, // 0x00014C59
|
||||
当前的发布比例需要比之前设置的高 = 85082, // 0x00014C5A
|
||||
小程序提审数量已达本月上限 = 85085, // 0x00014C5D
|
||||
提交代码审核之前需提前上传代码 = 85086, // 0x00014C5E
|
||||
小程序已使用_api_navigateToMiniProgram_请声明跳转_appid_列表后再次提交 = 85087, // 0x00014C5F
|
||||
不是由第三方代小程序进行调用 = 86000, // 0x00014FF0
|
||||
不存在第三方的已经提交的代码 = 86001, // 0x00014FF1
|
||||
小程序还未设置昵称_头像_简介_请先设置完后再重新提交 = 86002, // 0x00014FF2
|
||||
无效微信号 = 86004, // 0x00014FF4
|
||||
|
||||
/// <summary>
|
||||
/// 小程序为“签名错误”。对应公众号: 87009, “errmsg” : “reply is not exists” //该回复不存在
|
||||
/// </summary>
|
||||
签名错误 = 87009, // 0x000153E1
|
||||
|
||||
现网已经在灰度发布_不能进行版本回退 = 87011, // 0x000153E3
|
||||
该版本不能回退_可能的原因_1_无上一个线上版用于回退_2_此版本为已回退版本_不能回退_3_此版本为回退功能上线之前的版本_不能回退 = 87012, // 0x000153E4
|
||||
内容含有违法违规内容 = 87014, // 0x000153E6
|
||||
没有留言权限 = 88000, // 0x000157C0
|
||||
该图文不存在 = 88001, // 0x000157C1
|
||||
文章存在敏感信息 = 88002, // 0x000157C2
|
||||
精选评论数已达上限 = 88003, // 0x000157C3
|
||||
已被用户删除_无法精选 = 88004, // 0x000157C4
|
||||
已经回复过了 = 88005, // 0x000157C5
|
||||
回复超过长度限制或为0 = 88007, // 0x000157C7
|
||||
该评论不存在 = 88008, // 0x000157C8
|
||||
获取评论数目不合法 = 88010, // 0x000157CA
|
||||
该公众号_小程序已经绑定了开放平台帐号 = 89000, // 0x00015BA8
|
||||
业务域名无更改_无需重复设置 = 89019, // 0x00015BBB
|
||||
尚未设置小程序业务域名_请先在第三方平台中设置小程序业务域名后在调用本接口 = 89020, // 0x00015BBC
|
||||
请求保存的域名不是第三方平台中已设置的小程序业务域名或子域名 = 89021, // 0x00015BBD
|
||||
业务域名数量超过限制_最多可以添加100个业务域名 = 89029, // 0x00015BC5
|
||||
个人小程序不支持调用_setwebviewdomain_接口 = 89231, // 0x00015C8F
|
||||
内部错误 = 89247, // 0x00015C9F
|
||||
企业代码类型无效_请选择正确类型填写 = 89248, // 0x00015CA0
|
||||
该主体已有任务执行中_距上次任务24h后再试 = 89249, // 0x00015CA1
|
||||
未找到该任务 = 89250, // 0x00015CA2
|
||||
待法人人脸核身校验 = 89251, // 0x00015CA3
|
||||
法人_企业信息一致性校验中 = 89252, // 0x00015CA4
|
||||
缺少参数 = 89253, // 0x00015CA5
|
||||
第三方权限集不全_补全权限集全网发布后生效 = 89254, // 0x00015CA6
|
||||
系统不稳定_请稍后再试_如多次失败请通过社区反馈 = 89401, // 0x00015D39
|
||||
该审核单不在待审核队列_请检查是否已提交审核或已审完 = 89402, // 0x00015D3A
|
||||
本单属于平台不支持加急种类_请等待正常审核流程 = 89403, // 0x00015D3B
|
||||
本单已加速成功_请勿重复提交 = 89404, // 0x00015D3C
|
||||
本月加急额度不足_请提升提审质量以获取更多额度 = 89405, // 0x00015D3D
|
||||
该经营资质已添加_请勿重复添加 = 92000, // 0x00016760
|
||||
附近地点添加数量达到上线_无法继续添加 = 92002, // 0x00016762
|
||||
地点已被其它小程序占用 = 92003, // 0x00016763
|
||||
附近功能被封禁 = 92004, // 0x00016764
|
||||
地点正在审核中 = 92005, // 0x00016765
|
||||
地点正在展示小程序 = 92006, // 0x00016766
|
||||
地点审核失败 = 92007, // 0x00016767
|
||||
程序未展示在该地点 = 92008, // 0x00016768
|
||||
小程序未上架或不可见 = 92009, // 0x00016769
|
||||
地点不存在 = 93010, // 0x00016B52
|
||||
个人类型小程序不可用 = 93011, // 0x00016B53
|
||||
已下发的模板消息法人并未确认且已超时_24h_未进行身份证校验 = 100001, // 0x000186A1
|
||||
已下发的模板消息法人并未确认且已超时_24h_未进行人脸识别校验 = 100002, // 0x000186A2
|
||||
已下发的模板消息法人并未确认且已超时_24h = 100003, // 0x000186A3
|
||||
此账号已被封禁_无法操作 = 200011, // 0x00030D4B
|
||||
私有模板数已达上限_上限_50_个 = 200012, // 0x00030D4C
|
||||
此模版已被封禁_无法选用 = 200013, // 0x00030D4D
|
||||
模版tid参数错误 = 200014, // 0x00030D4E
|
||||
关键词列表kidList参数错误 = 200020, // 0x00030D54
|
||||
场景描述sceneDesc参数错误 = 200021, // 0x00030D55
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
@@ -17,7 +17,6 @@ global using Furion.FriendlyException;
|
||||
global using Furion.HttpRemote;
|
||||
global using Furion.JsonSerialization;
|
||||
global using Furion.Logging;
|
||||
global using Furion.Schedule;
|
||||
global using Furion.UnifyResult;
|
||||
global using Furion.ViewEngine;
|
||||
global using Magicodes.ExporterAndImporter.Core;
|
||||
@@ -36,13 +35,6 @@ global using Microsoft.Extensions.Options;
|
||||
global using NewLife;
|
||||
global using NewLife.Caching;
|
||||
global using Newtonsoft.Json.Linq;
|
||||
global using SKIT.FlurlHttpClient;
|
||||
global using SKIT.FlurlHttpClient.Wechat.Api;
|
||||
global using SKIT.FlurlHttpClient.Wechat.Api.Models;
|
||||
global using SKIT.FlurlHttpClient.Wechat.TenpayV3;
|
||||
global using SKIT.FlurlHttpClient.Wechat.TenpayV3.Events;
|
||||
global using SKIT.FlurlHttpClient.Wechat.TenpayV3.Models;
|
||||
global using SKIT.FlurlHttpClient.Wechat.TenpayV3.Settings;
|
||||
global using SqlSugar;
|
||||
global using System.Collections;
|
||||
global using System.Collections.Concurrent;
|
||||
@@ -58,4 +50,4 @@ global using System.Text;
|
||||
global using System.Text.RegularExpressions;
|
||||
global using System.Web;
|
||||
global using UAParser;
|
||||
global using Yitter.IdGenerator;
|
||||
global using Yitter.IdGenerator;
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 动态作业编译
|
||||
/// </summary>
|
||||
public class DynamicJobCompiler : ISingleton
|
||||
{
|
||||
/// <summary>
|
||||
/// 编译代码并返回其中实现 IJob 的类型
|
||||
/// </summary>
|
||||
/// <param name="script">动态编译的作业代码</param>
|
||||
/// <returns></returns>
|
||||
public Type BuildJob(string script)
|
||||
{
|
||||
var jobAssembly = Schedular.CompileCSharpClassCode(script);
|
||||
var jobType = jobAssembly.GetTypes().FirstOrDefault(u => typeof(IJob).IsAssignableFrom(u));
|
||||
return jobType;
|
||||
}
|
||||
}
|
||||
@@ -1,146 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 枚举转字典
|
||||
/// </summary>
|
||||
[JobDetail("job_EnumToDictJob", Description = "枚举转字典", GroupName = "default", Concurrent = false)]
|
||||
[PeriodSeconds(1, TriggerId = "trigger_EnumToDictJob", Description = "枚举转字典", MaxNumberOfRuns = 1, RunOnStart = true)]
|
||||
public class EnumToDictJob : IJob
|
||||
{
|
||||
private readonly IServiceScopeFactory _scopeFactory;
|
||||
private const string DefaultTagType = null;
|
||||
private const int OrderOffset = 10;
|
||||
|
||||
public EnumToDictJob(IServiceScopeFactory scopeFactory)
|
||||
{
|
||||
_scopeFactory = scopeFactory;
|
||||
}
|
||||
|
||||
public async Task ExecuteAsync(JobExecutingContext context, CancellationToken stoppingToken)
|
||||
{
|
||||
var originColor = Console.ForegroundColor;
|
||||
Console.ForegroundColor = ConsoleColor.Yellow;
|
||||
Console.WriteLine($"【{DateTime.Now}】系统枚举转换字典");
|
||||
|
||||
using var serviceScope = _scopeFactory.CreateScope();
|
||||
var db = serviceScope.ServiceProvider.GetRequiredService<ISqlSugarClient>().CopyNew();
|
||||
|
||||
var sysEnumService = serviceScope.ServiceProvider.GetRequiredService<SysEnumService>();
|
||||
var sysDictTypeList = GetDictByEnumType(sysEnumService.GetEnumTypeList());
|
||||
|
||||
// 校验枚举类命名规范,字典相关功能中需要通过后缀判断是否为枚举类型
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
foreach (var dictType in sysDictTypeList.Where(x => !x.Code.EndsWith("Enum")))
|
||||
Console.WriteLine($"【{DateTime.Now}】系统枚举转换字典的枚举类名称必须以Enum结尾: {dictType.Code} ({dictType.Name})");
|
||||
sysDictTypeList = sysDictTypeList.Where(x => x.Code.EndsWith("Enum")).ToList();
|
||||
|
||||
await SyncEnumToDictInfoAsync(db, sysDictTypeList);
|
||||
|
||||
Console.ForegroundColor = ConsoleColor.Yellow;
|
||||
try
|
||||
{
|
||||
await db.BeginTranAsync();
|
||||
var storageable1 = await db.Storageable(sysDictTypeList)
|
||||
.SplitUpdate(it => it.Any())
|
||||
.SplitInsert(_ => true)
|
||||
.ToStorageAsync();
|
||||
await storageable1.AsInsertable.ExecuteCommandAsync(stoppingToken);
|
||||
await storageable1.AsUpdateable.ExecuteCommandAsync(stoppingToken);
|
||||
|
||||
Console.WriteLine($"【{DateTime.Now}】系统枚举类转字典类型数据: 插入{storageable1.InsertList.Count}条, 更新{storageable1.UpdateList.Count}条, 共{storageable1.TotalList.Count}条。");
|
||||
|
||||
var storageable2 = await db.Storageable(sysDictTypeList.SelectMany(x => x.Children).ToList())
|
||||
.WhereColumns(it => new { it.DictTypeId, it.Value })
|
||||
.SplitUpdate(it => it.Any())
|
||||
.SplitInsert(_ => true)
|
||||
.ToStorageAsync();
|
||||
await storageable2.AsInsertable.ExecuteCommandAsync(stoppingToken);
|
||||
await storageable2.AsUpdateable.UpdateColumns(u => new
|
||||
{
|
||||
u.Label,
|
||||
u.Code,
|
||||
u.Value
|
||||
}).ExecuteCommandAsync(stoppingToken);
|
||||
|
||||
Console.WriteLine($"【{DateTime.Now}】系统枚举项转字典值数据: 插入{storageable2.InsertList.Count}条, 更新{storageable2.UpdateList.Count}条, 共{storageable2.TotalList.Count}条。");
|
||||
|
||||
await db.CommitTranAsync();
|
||||
}
|
||||
catch (Exception error)
|
||||
{
|
||||
await db.RollbackTranAsync();
|
||||
Log.Error($"系统枚举转换字典操作错误:{error.Message}\n堆栈跟踪:{error.StackTrace}", error);
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
Console.ForegroundColor = originColor;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 用于同步枚举转字典数据
|
||||
/// </summary>
|
||||
/// <param name="db"></param>
|
||||
/// <param name="list"></param>
|
||||
private async Task SyncEnumToDictInfoAsync(SqlSugarClient db, List<SysDictType> list)
|
||||
{
|
||||
var codeList = list.Select(x => x.Code).ToList();
|
||||
foreach (var dbDictType in await db.Queryable<SysDictType>().ClearFilter().Where(x => codeList.Contains(x.Code)).ToListAsync() ?? new())
|
||||
{
|
||||
var enumDictType = list.First(x => x.Code == dbDictType.Code);
|
||||
if (enumDictType.Id == dbDictType.Id)
|
||||
{
|
||||
// 字典值表字段改变后每条字典值记录会多出一条,此处用于删除多余的字典值数据
|
||||
var dataValueList = enumDictType.Children.Select(e => e.Value).ToList();
|
||||
await db.Deleteable<SysDictData>().Where(x => x.DictTypeId == dbDictType.Id && !dataValueList.Contains(x.Value)).ExecuteCommandAsync();
|
||||
continue;
|
||||
}
|
||||
|
||||
// 数据不一致则删除
|
||||
await db.Deleteable<SysDictData>().Where(x => x.DictTypeId == dbDictType.Id).ExecuteCommandAsync();
|
||||
await db.Deleteable<SysDictType>().Where(x => x.Id == dbDictType.Id).ExecuteCommandAsync();
|
||||
Console.WriteLine($"【{DateTime.Now}】删除字典数据: {dbDictType.Name}-{dbDictType.Code}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 枚举信息转字典
|
||||
/// </summary>
|
||||
/// <param name="enumTypeList"></param>
|
||||
/// <returns></returns>
|
||||
private List<SysDictType> GetDictByEnumType(List<EnumTypeOutput> enumTypeList)
|
||||
{
|
||||
var orderNo = 1;
|
||||
var list = new List<SysDictType>();
|
||||
foreach (var type in enumTypeList)
|
||||
{
|
||||
var dictType = new SysDictType
|
||||
{
|
||||
Id = 900000000000 + CommonUtil.GetFixedHashCode(type.TypeFullName),
|
||||
SysFlag = YesNoEnum.Y,
|
||||
Code = type.TypeName,
|
||||
Name = type.TypeDescribe,
|
||||
Remark = type.TypeFullName
|
||||
};
|
||||
dictType.Children = type.EnumEntities.Select(x => new SysDictData
|
||||
{
|
||||
Id = dictType.Id + orderNo++,
|
||||
DictTypeId = dictType.Id,
|
||||
Code = x.Name,
|
||||
Label = x.Describe,
|
||||
Value = x.Value.ToString(),
|
||||
OrderNo = x.Value + OrderOffset,
|
||||
TagType = x.Theme != "" ? x.Theme : DefaultTagType
|
||||
}).ToList();
|
||||
list.Add(dictType);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 清理日志作业任务
|
||||
/// </summary>
|
||||
[JobDetail("job_log", Description = "清理操作日志", GroupName = "default", Concurrent = false)]
|
||||
[Daily(TriggerId = "trigger_log", Description = "清理操作日志")]
|
||||
public class LogJob : IJob
|
||||
{
|
||||
private readonly IServiceScopeFactory _scopeFactory;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public LogJob(IServiceScopeFactory scopeFactory, ILoggerFactory loggerFactory)
|
||||
{
|
||||
_scopeFactory = scopeFactory;
|
||||
_logger = loggerFactory.CreateLogger(CommonConst.SysLogCategoryName);
|
||||
}
|
||||
|
||||
public async Task ExecuteAsync(JobExecutingContext context, CancellationToken stoppingToken)
|
||||
{
|
||||
using var serviceScope = _scopeFactory.CreateScope();
|
||||
|
||||
var db = serviceScope.ServiceProvider.GetRequiredService<ISqlSugarClient>().CopyNew();
|
||||
var sysConfigService = serviceScope.ServiceProvider.GetRequiredService<SysConfigService>();
|
||||
|
||||
var daysAgo = await sysConfigService.GetConfigValue<int>(ConfigConst.SysLogRetentionDays); // 日志保留天数
|
||||
await db.Deleteable<SysLogVis>().Where(u => u.CreateTime < DateTime.Now.AddDays(-daysAgo)).ExecuteCommandAsync(stoppingToken); // 删除访问日志
|
||||
await db.Deleteable<SysLogOp>().Where(u => u.CreateTime < DateTime.Now.AddDays(-daysAgo)).ExecuteCommandAsync(stoppingToken); // 删除操作日志
|
||||
await db.Deleteable<SysLogDiff>().Where(u => u.CreateTime < DateTime.Now.AddDays(-daysAgo)).ExecuteCommandAsync(stoppingToken); // 删除差异日志
|
||||
|
||||
string msg = $"【{DateTime.Now}】清理系统日志成功,删除 {daysAgo} 天前的日志数据!";
|
||||
var originColor = Console.ForegroundColor;
|
||||
Console.ForegroundColor = ConsoleColor.Yellow;
|
||||
Console.WriteLine(msg);
|
||||
Console.ForegroundColor = originColor;
|
||||
|
||||
// 自定义日志
|
||||
_logger.LogInformation(msg);
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
using Furion.Logging.Extensions;
|
||||
|
||||
namespace Admin.NET.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 清理在线用户作业任务
|
||||
/// </summary>
|
||||
[JobDetail("job_onlineUser", Description = "清理在线用户", GroupName = "default", Concurrent = false)]
|
||||
[PeriodSeconds(1, TriggerId = "trigger_onlineUser", Description = "清理在线用户", MaxNumberOfRuns = 1, RunOnStart = true)]
|
||||
public class OnlineUserJob : IJob
|
||||
{
|
||||
private readonly IServiceScopeFactory _scopeFactory;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public OnlineUserJob(IServiceScopeFactory scopeFactory, ILoggerFactory loggerFactory)
|
||||
{
|
||||
_scopeFactory = scopeFactory;
|
||||
_logger = loggerFactory.CreateLogger(CommonConst.SysLogCategoryName);
|
||||
}
|
||||
|
||||
public async Task ExecuteAsync(JobExecutingContext context, CancellationToken stoppingToken)
|
||||
{
|
||||
using var serviceScope = _scopeFactory.CreateScope();
|
||||
|
||||
var db = serviceScope.ServiceProvider.GetRequiredService<ISqlSugarClient>().CopyNew();
|
||||
await db.Deleteable<SysOnlineUser>().ExecuteCommandAsync(stoppingToken);
|
||||
|
||||
string msg = $"【{DateTime.Now}】清理在线用户成功!服务已重启...";
|
||||
var originColor = Console.ForegroundColor;
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
Console.WriteLine(msg);
|
||||
Console.ForegroundColor = originColor;
|
||||
|
||||
// 自定义日志
|
||||
_logger.LogInformation(msg);
|
||||
|
||||
// 缓存租户列表
|
||||
await serviceScope.ServiceProvider.GetRequiredService<SysTenantService>().CacheTenant();
|
||||
}
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
using Aop.Api;
|
||||
|
||||
namespace Admin.NET.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 支付宝支付配置选项
|
||||
/// </summary>
|
||||
public sealed class AlipayOptions : IConfigurableOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// 支付宝网关地址
|
||||
/// </summary>
|
||||
public string ServerUrl { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 支付宝授权回调地址
|
||||
/// </summary>
|
||||
public string AuthUrl { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 应用授权回调地址
|
||||
/// </summary>
|
||||
public string AppAuthUrl { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 支付宝 websocket 服务地址
|
||||
/// </summary>
|
||||
public string WebsocketUrl { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 应用回调地址
|
||||
/// </summary>
|
||||
public string NotifyUrl { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 支付宝根证书存放路径
|
||||
/// </summary>
|
||||
public string RootCertPath { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 支付宝商户账号列表
|
||||
/// </summary>
|
||||
public List<AlipayMerchantAccount> AccountList { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取支付宝客户端
|
||||
/// </summary>
|
||||
/// <param name="account"></param>
|
||||
public DefaultAopClient GetClient(AlipayMerchantAccount account)
|
||||
{
|
||||
account = account ?? throw new Exception("未找到支付宝商户账号");
|
||||
string path = App.WebHostEnvironment.ContentRootPath;
|
||||
return new DefaultAopClient(new AlipayConfig
|
||||
{
|
||||
Format = "json",
|
||||
Charset = "UTF-8",
|
||||
ServerUrl = ServerUrl,
|
||||
AppId = account.AppId,
|
||||
SignType = account.SignType,
|
||||
PrivateKey = account.PrivateKey,
|
||||
EncryptKey = account.EncryptKey,
|
||||
RootCertPath = Path.Combine(path, RootCertPath),
|
||||
AppCertPath = Path.Combine(path, account.AppCertPath),
|
||||
AlipayPublicCertPath = Path.Combine(path, account.AlipayPublicCertPath)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 支付宝商户账号信息
|
||||
/// </summary>
|
||||
public class AlipayMerchantAccount
|
||||
{
|
||||
/// <summary>
|
||||
/// 配置Id
|
||||
/// </summary>
|
||||
public long Id { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 商户名称
|
||||
/// </summary>
|
||||
public string Name { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 商户AppId
|
||||
/// </summary>
|
||||
public string AppId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 应用私钥
|
||||
/// </summary>
|
||||
public string PrivateKey { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 从支付宝获取敏感信息时的加密密钥(可选)
|
||||
/// </summary>
|
||||
public string EncryptKey { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 加密算法
|
||||
/// </summary>
|
||||
public string SignType { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 应用公钥证书路径
|
||||
/// </summary>
|
||||
public string AppCertPath { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 支付宝公钥证书路径
|
||||
/// </summary>
|
||||
public string AlipayPublicCertPath { get; init; }
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 支付回调配置选项
|
||||
/// </summary>
|
||||
public sealed class PayCallBackOptions : IConfigurableOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// 微信支付回调
|
||||
/// </summary>
|
||||
public string WechatPayUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 微信退款回调
|
||||
/// </summary>
|
||||
public string WechatRefundUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 支付宝支付回调
|
||||
/// </summary>
|
||||
public string AlipayUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 支付宝退款回调
|
||||
/// </summary>
|
||||
public string AlipayRefundUrl { get; set; }
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 微信相关配置选项
|
||||
/// </summary>
|
||||
public sealed class WechatOptions : IConfigurableOptions
|
||||
{
|
||||
// 公众号
|
||||
public string WechatAppId { get; set; }
|
||||
|
||||
public string WechatAppSecret { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 微信公众号服务器配置中的令牌(Token)
|
||||
/// </summary>
|
||||
public string WechatToken { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 微信公众号服务器配置中的消息加解密密钥(EncodingAESKey)
|
||||
/// </summary>
|
||||
public string WechatEncodingAESKey { get; set; }
|
||||
|
||||
// 小程序
|
||||
public string WxOpenAppId { get; set; }
|
||||
|
||||
public string WxOpenAppSecret { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 小程序消息推送中的令牌(Token)
|
||||
/// </summary>
|
||||
public string WxToken { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 小程序消息推送中的消息加解密密钥(EncodingAESKey)
|
||||
/// </summary>
|
||||
public string WxEncodingAESKey { get; set; }
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 微信支付配置选项
|
||||
/// </summary>
|
||||
public sealed class WechatPayOptions : WechatTenpayClientOptions, IConfigurableOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// 微信公众平台AppId、开放平台AppId、小程序AppId、企业微信CorpId
|
||||
/// </summary>
|
||||
public string AppId { get; set; }
|
||||
}
|
||||
@@ -32,9 +32,8 @@ public class SysConfigSeedData : ISqlSugarEntitySeedData<SysConfig>
|
||||
new SysConfig{ Id=1300000000181, Name="Token过期时间", Code=ConfigConst.SysTokenExpire, Value="10080", SysFlag=YesNoEnum.Y, Remark="Token过期时间(分钟)", OrderNo=100, GroupCode=ConfigConst.SysDefaultGroup, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysConfig{ Id=1300000000191, Name="RefreshToken过期时间", Code=ConfigConst.SysRefreshTokenExpire, Value="20160", SysFlag=YesNoEnum.Y, Remark="刷新Token过期时间(分钟)(一般 refresh_token 的有效时间 > 2 * access_token 的有效时间)", OrderNo=110, GroupCode=ConfigConst.SysDefaultGroup, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysConfig{ Id=1300000000201, Name="发送异常日志邮件", Code=ConfigConst.SysErrorMail, Value="False", SysFlag=YesNoEnum.Y, Remark="是否发送异常日志邮件", OrderNo=120, GroupCode=ConfigConst.SysDefaultGroup, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysConfig{ Id=1300000000211, Name="域登录验证", Code=ConfigConst.SysDomainLogin, Value="False", SysFlag=YesNoEnum.Y, Remark="是否开启域登录验证", OrderNo=130, GroupCode=ConfigConst.SysDefaultGroup, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysConfig{ Id=1300000000221, Name="数据校验日志", Code=ConfigConst.SysValidationLog, Value="True", SysFlag=YesNoEnum.Y, Remark="是否数据校验日志", OrderNo=140, GroupCode=ConfigConst.SysDefaultGroup, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysConfig{ Id=1300000000231, Name="行政区域同步层级", Code=ConfigConst.SysRegionSyncLevel, Value="3", SysFlag=YesNoEnum.Y, Remark="行政区域同步层级 1-省级,2-市级,3-区县级,4-街道级,5-村级", OrderNo=150, GroupCode=ConfigConst.SysDefaultGroup, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,70 +17,14 @@ public class SysDictDataSeedData : ISqlSugarEntitySeedData<SysDictData>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<SysDictData> HasData()
|
||||
{
|
||||
var typeList = new SysDictTypeSeedData().HasData().ToList();
|
||||
const long orgTypeId = 1300000000171;
|
||||
return new[]
|
||||
{
|
||||
new SysDictData{ Id=1300000000101, DictTypeId=typeList[0].Id, Label="输入框", Value="Input", OrderNo=100, Remark="输入框", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysDictData{ Id=1300000000102, DictTypeId=typeList[0].Id, Label="字典选择器", Value="DictSelector", OrderNo=100, Remark="字典选择器", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysDictData{ Id=1300000000103, DictTypeId=typeList[0].Id, Label="常量选择器", Value="ConstSelector", OrderNo=100, Remark="常量选择器", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysDictData{ Id=1300000000104, DictTypeId=typeList[0].Id, Label="枚举选择器", Value="EnumSelector", OrderNo=100, Remark="枚举选择器", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysDictData{ Id=1300000000105, DictTypeId=typeList[0].Id, Label="树选择器", Value="ApiTreeSelector", OrderNo=100, Remark="树选择器", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysDictData{ Id=1300000000106, DictTypeId=typeList[0].Id, Label="外键", Value="ForeignKey", OrderNo=100, Remark="外键", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysDictData{ Id=1300000000107, DictTypeId=typeList[0].Id, Label="数字输入框", Value="InputNumber", OrderNo=100, Remark="数字输入框", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysDictData{ Id=1300000000108, DictTypeId=typeList[0].Id, Label="时间选择", Value="DatePicker", OrderNo=100, Remark="时间选择", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysDictData{ Id=1300000000109, DictTypeId=typeList[0].Id, Label="文本域", Value="InputTextArea", OrderNo=100, Remark="文本域", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysDictData{ Id=1300000000110, DictTypeId=typeList[0].Id, Label="上传", Value="Upload", OrderNo=100, Remark="上传", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysDictData{ Id=1300000000111, DictTypeId=typeList[0].Id, Label="开关", Value="Switch", OrderNo=100, Remark="开关", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysDictData{ Id=1300000000112, DictTypeId=typeList[0].Id, Label="上传单文件", Value="Upload_SingleFile", OrderNo=120, Remark="上传单文件", Status=StatusEnum.Enable, CreateTime= DateTime.Now },
|
||||
new SysDictData{ Id=1300000000113, DictTypeId=typeList[0].Id, Label="富文本编辑器", Value="Editor", OrderNo=130, Remark="富文本编辑器", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2025-12-25 00:00:00") },
|
||||
|
||||
new SysDictData{ Id=1300000000201, DictTypeId=typeList[1].Id, Label="等于", Value="==", OrderNo=1, Remark="等于", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysDictData{ Id=1300000000202, DictTypeId=typeList[1].Id, Label="模糊", Value="like", OrderNo=1, Remark="模糊", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysDictData{ Id=1300000000203, DictTypeId=typeList[1].Id, Label="大于", Value=">", OrderNo=1, Remark="大于", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysDictData{ Id=1300000000204, DictTypeId=typeList[1].Id, Label="小于", Value="<", OrderNo=1, Remark="小于", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysDictData{ Id=1300000000205, DictTypeId=typeList[1].Id, Label="不等于", Value="!=", OrderNo=1, Remark="不等于", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysDictData{ Id=1300000000206, DictTypeId=typeList[1].Id, Label="大于等于", Value=">=", OrderNo=1, Remark="大于等于", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysDictData{ Id=1300000000207, DictTypeId=typeList[1].Id, Label="小于等于", Value="<=", OrderNo=1, Remark="小于等于", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysDictData{ Id=1300000000208, DictTypeId=typeList[1].Id, Label="不为空", Value="isNotNull", OrderNo=1, Remark="不为空", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysDictData{ Id=1300000000209, DictTypeId=typeList[1].Id, Label="时间范围", Value="~", OrderNo=1, Remark="时间范围", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
|
||||
new SysDictData{ Id=1300000000301, DictTypeId=typeList[2].Id, Label="long", Value="long", OrderNo=1, Remark="long", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysDictData{ Id=1300000000302, DictTypeId=typeList[2].Id, Label="string", Value="string", OrderNo=1, Remark="string", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysDictData{ Id=1300000000303, DictTypeId=typeList[2].Id, Label="DateTime", Value="DateTime", OrderNo=1, Remark="DateTime", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysDictData{ Id=1300000000304, DictTypeId=typeList[2].Id, Label="bool", Value="bool", OrderNo=1, Remark="bool", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysDictData{ Id=1300000000305, DictTypeId=typeList[2].Id, Label="int", Value="int", OrderNo=1, Remark="int", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysDictData{ Id=1300000000306, DictTypeId=typeList[2].Id, Label="double", Value="double", OrderNo=1, Remark="double", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysDictData{ Id=1300000000307, DictTypeId=typeList[2].Id, Label="float", Value="float", OrderNo=1, Remark="float", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysDictData{ Id=1300000000308, DictTypeId=typeList[2].Id, Label="decimal", Value="decimal", OrderNo=1, Remark="decimal", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysDictData{ Id=1300000000309, DictTypeId=typeList[2].Id, Label="Guid", Value="Guid", OrderNo=1, Remark="Guid", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysDictData{ Id=1300000000310, DictTypeId=typeList[2].Id, Label="DateTimeOffset", Value="DateTimeOffset", OrderNo=1, Remark="DateTimeOffset", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
|
||||
new SysDictData{ Id=1300000000401, DictTypeId=typeList[3].Id, Label="下载压缩包", Value="100", OrderNo=1, Remark="下载压缩包", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysDictData{ Id=1300000000402, DictTypeId=typeList[3].Id, Label="下载压缩包(前端)", Value="111", OrderNo=2, Remark="下载压缩包(前端)", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysDictData{ Id=1300000000403, DictTypeId=typeList[3].Id, Label="下载压缩包(后端)", Value="121", OrderNo=3, Remark="下载压缩包(后端)", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysDictData{ Id=1300000000404, DictTypeId=typeList[3].Id, Label="生成到本项目", Value="200", OrderNo=4, Remark="生成到本项目", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysDictData{ Id=1300000000405, DictTypeId=typeList[3].Id, Label="生成到本项目(前端)", Value="211", OrderNo=5, Remark="生成到本项目(前端)", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysDictData{ Id=1300000000406, DictTypeId=typeList[3].Id, Label="生成到本项目(后端)", Value="221", OrderNo=6, Remark="生成到本项目(后端)", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
|
||||
new SysDictData{ Id=1300000000501, DictTypeId=typeList[4].Id, Label="EntityBaseId【基础实体Id】", Value="EntityBaseId", OrderNo=1, Remark="【基础实体Id】", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysDictData{ Id=1300000000502, DictTypeId=typeList[4].Id, Label="EntityBase【基础实体】", Value="EntityBase", OrderNo=1, Remark="【基础实体】", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysDictData{ Id=1300000000503, DictTypeId=typeList[4].Id, Label="EntityBaseDel【基础软删除实体】", Value="EntityBaseDel", OrderNo=1, Remark="【基础软删除实体】", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysDictData{ Id=1300000000504, DictTypeId=typeList[4].Id, Label="EntityBaseOrg【机构实体】", Value="EntityBaseOrg", OrderNo=1, Remark="【机构实体】", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysDictData{ Id=1300000000505, DictTypeId=typeList[4].Id, Label="EntityBaseOrgDel【机构软删除实体】", Value="EntityBaseOrgDel", OrderNo=1, Remark="【机构软删除实体】", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysDictData{ Id=1300000000506, DictTypeId=typeList[4].Id, Label="EntityBaseTenantId【租户实体Id】", Value="EntityBaseTenantId", OrderNo=1, Remark="【租户实体Id】", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysDictData{ Id=1300000000507, DictTypeId=typeList[4].Id, Label="EntityBaseTenant【租户实体】", Value="EntityBaseTenant", OrderNo=1, Remark="【租户实体】", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysDictData{ Id=1300000000508, DictTypeId=typeList[4].Id, Label="EntityBaseTenantDel【租户软删除实体】", Value="EntityBaseTenantDel", OrderNo=1, Remark="【租户软删除实体】", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysDictData{ Id=1300000000509, DictTypeId=typeList[4].Id, Label="EntityBaseTenantOrg【租户机构实体】", Value="EntityBaseTenantOrg", OrderNo=1, Remark="【租户机构实体】", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysDictData{ Id=1300000000510, DictTypeId=typeList[4].Id, Label="EntityBaseTenantOrgDel【租户机构软删除实体】", Value="EntityBaseTenantOrgDel", OrderNo=1, Remark="【租户机构软删除实体】", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
|
||||
new SysDictData{ Id=1300000000601, DictTypeId=typeList[5].Id, Label="不需要", Value="off", OrderNo=100, Remark="不需要打印支持", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2023-12-04 00:00:00") },
|
||||
new SysDictData{ Id=1300000000602, DictTypeId=typeList[5].Id, Label="绑定打印模版", Value="custom", OrderNo=101, Remark="绑定打印模版", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2023-12-04 00:00:00") },
|
||||
|
||||
new SysDictData{ Id=1300000000701, DictTypeId=typeList[6].Id, Label="集团", Value="101", OrderNo=100, Remark="集团", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2023-02-10 00:00:00") },
|
||||
new SysDictData{ Id=1300000000702, DictTypeId=typeList[6].Id, Label="公司", Value="201", OrderNo=101, Remark="公司", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2023-02-10 00:00:00") },
|
||||
new SysDictData{ Id=1300000000703, DictTypeId=typeList[6].Id, Label="部门", Value="301", OrderNo=102, Remark="部门", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2023-02-10 00:00:00") },
|
||||
new SysDictData{ Id=1300000000704, DictTypeId=typeList[6].Id, Label="区域", Value="401", OrderNo=103, Remark="区域", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2023-02-10 00:00:00") },
|
||||
new SysDictData{ Id=1300000000705, DictTypeId=typeList[6].Id, Label="组", Value="501", OrderNo=104, Remark="组", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2023-02-10 00:00:00") },
|
||||
new SysDictData{ Id=1300000000701, DictTypeId=orgTypeId, Label="集团", Value="101", OrderNo=100, Remark="集团", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2023-02-10 00:00:00") },
|
||||
new SysDictData{ Id=1300000000702, DictTypeId=orgTypeId, Label="公司", Value="201", OrderNo=101, Remark="公司", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2023-02-10 00:00:00") },
|
||||
new SysDictData{ Id=1300000000703, DictTypeId=orgTypeId, Label="部门", Value="301", OrderNo=102, Remark="部门", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2023-02-10 00:00:00") },
|
||||
new SysDictData{ Id=1300000000704, DictTypeId=orgTypeId, Label="区域", Value="401", OrderNo=103, Remark="区域", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2023-02-10 00:00:00") },
|
||||
new SysDictData{ Id=1300000000705, DictTypeId=orgTypeId, Label="组", Value="501", OrderNo=104, Remark="组", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2023-02-10 00:00:00") },
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,13 +19,7 @@ public class SysDictTypeSeedData : ISqlSugarEntitySeedData<SysDictType>
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
new SysDictType{ Id=1300000000111, Name="代码生成控件类型", Code="code_gen_effect_type", SysFlag=YesNoEnum.Y, OrderNo=100, Remark="代码生成控件类型", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysDictType{ Id=1300000000121, Name="代码生成查询类型", Code="code_gen_query_type", SysFlag=YesNoEnum.Y, OrderNo=101, Remark="代码生成查询类型", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysDictType{ Id=1300000000131, Name="代码生成.NET类型", Code="code_gen_net_type", SysFlag=YesNoEnum.Y, OrderNo=102, Remark="代码生成.NET类型", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysDictType{ Id=1300000000141, Name="代码生成方式", Code="code_gen_create_type", SysFlag=YesNoEnum.Y, OrderNo=103, Remark="代码生成方式", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysDictType{ Id=1300000000151, Name="代码生成基类", Code="code_gen_base_class", SysFlag=YesNoEnum.Y, OrderNo=104, Remark="代码生成基类", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysDictType{ Id=1300000000161, Name="代码生成打印类型", Code="code_gen_print_type", SysFlag=YesNoEnum.Y, OrderNo=105, Remark="代码生成打印类型", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2023-12-04 00:00:00") },
|
||||
new SysDictType{ Id=1300000000171, Name="机构类型", Code="org_type", SysFlag=YesNoEnum.Y, OrderNo=201, Remark="机构类型", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2023-02-10 00:00:00") },
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,23 +82,6 @@ public class SysMenuSeedData : ISqlSugarEntitySeedData<SysMenu>
|
||||
new SysMenu{ Id=1300200060601, Pid=1300200060101, Title="发布", Permission="sysNotice:public", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
|
||||
new SysMenu{ Id=1300200060701, Pid=1300200060101, Title="撤回", Permission="sysNotice:cancel", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
|
||||
|
||||
// 三方账号
|
||||
new SysMenu{ Id=1300200070101, Pid=1300200000101, Title="三方账号", Path="/system/weChatUser", Name="sysWechatUser", Component="/system/weChatUser/index",Icon="ele-ChatDotRound", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=160 },
|
||||
new SysMenu{ Id=1300200070201, Pid=1300200070101, Title="查询", Permission="sysWechatUser:page", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
|
||||
new SysMenu{ Id=1300200070301, Pid=1300200070101, Title="编辑", Permission="sysWechatUser:update", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
|
||||
new SysMenu{ Id=1300200070401, Pid=1300200070101, Title="增加", Permission="sysWechatUser:add", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
|
||||
new SysMenu{ Id=1300200070501, Pid=1300200070101, Title="删除", Permission="sysWechatUser:delete", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
|
||||
|
||||
// AD域配置
|
||||
new SysMenu{ Id=1300200080101, Pid=1300200000101, Title="AD域配置", Path="/system/ldap", Name="sysLdap", Component="/system/ldap/index",Icon="ele-Place", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=170 },
|
||||
new SysMenu{ Id=1300200080201, Pid=1300200080101, Title="查询", Permission="sysLdap:page", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
|
||||
new SysMenu{ Id=1300200080301, Pid=1300200080101, Title="详情", Permission="sysLdap:detail", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=110 },
|
||||
new SysMenu{ Id=1300200080401, Pid=1300200080101, Title="编辑", Permission="sysLdap:update", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=120 },
|
||||
new SysMenu{ Id=1300200080501, Pid=1300200080101, Title="增加", Permission="sysLdap:add", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=130 },
|
||||
new SysMenu{ Id=1300200080601, Pid=1300200080101, Title="删除", Permission="sysLdap:delete", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=140 },
|
||||
new SysMenu{ Id=1300200080701, Pid=1300200080101, Title="同步域账户", Permission="sysLdap:syncUser", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=150 },
|
||||
new SysMenu{ Id=1300200080801, Pid=1300200080101, Title="同步域组织", Permission="sysLdap:syncOrg", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=160 },
|
||||
|
||||
#endregion 系统管理
|
||||
|
||||
#region 平台管理
|
||||
@@ -159,13 +142,6 @@ public class SysMenuSeedData : ISqlSugarEntitySeedData<SysMenu>
|
||||
new SysMenu{ Id=1300300051501, Pid=1300300051101, Title="删除", Permission="sysTemplate:delete", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
|
||||
new SysMenu{ Id=1300300051601, Pid=1300300051101, Title="预览", Permission="sysTemplate:preview", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
|
||||
|
||||
// 任务调度
|
||||
new SysMenu{ Id=1300300060101, Pid=1300300000101, Title="任务调度", Path="/platform/job", Name="sysJob", Component="/system/job/index", Icon="ele-AlarmClock", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=140 },
|
||||
new SysMenu{ Id=1300300060201, Pid=1300300060101, Title="查询", Permission="sysJob:pageJobDetail", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
|
||||
new SysMenu{ Id=1300300060301, Pid=1300300060101, Title="编辑", Permission="sysJob:updateJobDetail", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
|
||||
new SysMenu{ Id=1300300060401, Pid=1300300060101, Title="增加", Permission="sysJob:addJobDetail", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
|
||||
new SysMenu{ Id=1300300060501, Pid=1300300060101, Title="删除", Permission="sysJob:deleteJobDetail", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
|
||||
|
||||
// 系统参数
|
||||
new SysMenu{ Id=1300200090101, Pid=1300200000101, Title="系统参数", Path="/system/tenantConfig", Name="sysTenantConfig", Component="/system/tenantConfig/index", Icon="ele-DocumentCopy", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=180 },
|
||||
new SysMenu{ Id=1300200090201, Pid=1300200090101, Title="查询", Permission="sysTenantConfig:page", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
|
||||
@@ -212,20 +188,6 @@ public class SysMenuSeedData : ISqlSugarEntitySeedData<SysMenu>
|
||||
new SysMenu{ Id=1300300100501, Pid=1300300100101, Title="删除", Permission="sysFile:delete", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
|
||||
new SysMenu{ Id=1300300100601, Pid=1300300100101, Title="编辑", Permission="sysFile:update", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2023-10-27 00:00:00"), OrderNo=100 },
|
||||
|
||||
// 打印模板
|
||||
new SysMenu{ Id=1300300110101, Pid=1300300000101, Title="打印模板", Path="/platform/print", Name="sysPrint", Component="/system/print/index", Icon="ele-Printer", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=190 },
|
||||
new SysMenu{ Id=1300300110201, Pid=1300300110101, Title="查询", Permission="sysPrint:page", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
|
||||
new SysMenu{ Id=1300300110301, Pid=1300300110101, Title="编辑", Permission="sysPrint:update", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
|
||||
new SysMenu{ Id=1300300110401, Pid=1300300110101, Title="增加", Permission="sysPrint:add", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
|
||||
new SysMenu{ Id=1300300110501, Pid=1300300110101, Title="删除", Permission="sysPrint:delete", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
|
||||
|
||||
// 动态插件
|
||||
new SysMenu{ Id=1300300120101, Pid=1300300000101, Title="动态插件", Path="/platform/plugin", Name="sysPlugin", Component="/system/plugin/index", Icon="ele-Connection", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=200 },
|
||||
new SysMenu{ Id=1300300120201, Pid=1300300120101, Title="查询", Permission="sysPlugin:page", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
|
||||
new SysMenu{ Id=1300300120301, Pid=1300300120101, Title="编辑", Permission="sysPlugin:update", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
|
||||
new SysMenu{ Id=1300300120401, Pid=1300300120101, Title="增加", Permission="sysPlugin:add", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
|
||||
new SysMenu{ Id=1300300120501, Pid=1300300120101, Title="删除", Permission="sysPlugin:delete", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
|
||||
|
||||
// 开放接口
|
||||
new SysMenu{ Id=1300300130101, Pid=1300300000101, Title="开放接口", Path="/platform/openAccess", Name="sysOpenAccess", Component="/system/openAccess/index", Icon="ele-Link", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=210 },
|
||||
new SysMenu{ Id=1300300130201, Pid=1300300130101, Title="查询", Permission="sysOpenAccess:page", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
|
||||
@@ -236,14 +198,6 @@ public class SysMenuSeedData : ISqlSugarEntitySeedData<SysMenu>
|
||||
// 系统配置
|
||||
new SysMenu{ Id=1300300140101, Pid=1300300000101, Title="系统配置", Path="/platform/infoSetting", Name="sysInfoSetting", Component="/system/infoSetting/index", Icon="ele-Setting", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=220 },
|
||||
|
||||
// 微信支付
|
||||
new SysMenu{ Id=1300300150101, Pid=1300300000101, Title="微信支付", Path="/platform/wechatpay", Name="sysWechatPay", Component="/system/weChatPay/index", Icon="ele-Coin", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=230 },
|
||||
new SysMenu{ Id=1300300150201, Pid=1300300150101, Title="微信支付下单Native", Permission="sysWechatPay:payTransactionNative", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
|
||||
new SysMenu{ Id=1300300150301, Pid=1300300150101, Title="查询退款信息", Permission="sysWechatPay:listRefund", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
|
||||
new SysMenu{ Id=1300300150401, Pid=1300300150101, Title="获取支付订单详情(本地库)", Permission="sysWechatPay:payInfo", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
|
||||
new SysMenu{ Id=1300300150501, Pid=1300300150101, Title="获取支付订单详情(微信接口)", Permission="sysWechatPay:payInfoFromWechat", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
|
||||
new SysMenu{ Id=1300300150601, Pid=1300300150101, Title="退款申请", Permission="sysWechatPay:refundDomestic", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
|
||||
|
||||
// 系统更新
|
||||
new SysMenu{ Id=1300300160101, Pid=1300300000101, Title="系统更新", Path="/platform/update", Name="sysUpdate", Component="/system/update/index", Icon="ele-Upload", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=240 },
|
||||
new SysMenu{ Id=1300300160201, Pid=1300300160101, Title="更新", Permission="sysUpdate:update", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
|
||||
@@ -288,7 +242,6 @@ public class SysMenuSeedData : ISqlSugarEntitySeedData<SysMenu>
|
||||
// 开发工具
|
||||
new SysMenu{ Id=1300500000101, Pid=0, Title="开发工具", Path="/develop", Name="develop", Component="Layout", Icon="ele-Cpu", Type=MenuTypeEnum.Dir, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=13000 },
|
||||
new SysMenu{ Id=1300500010101, Pid=1300500000101, Title="库表管理", Path="/develop/database", Name="sysDatabase", Component="/system/database/index",Icon="ele-Coin", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
|
||||
new SysMenu{ Id=1300500020101, Pid=1300500000101, Title="代码生成", Path="/develop/codeGen", Name="sysCodeGen", Component="/system/codeGen/index", Icon="ele-Crop", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=110 },
|
||||
new SysMenu{ Id=1300500030101, Pid=1300500000101, Title="表单设计", Path="/develop/formDes", Name="sysFormDes", Component="/system/formDes/index", Icon="ele-Edit", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=120 },
|
||||
new SysMenu{ Id=1300500040101, Pid=1300500000101, Title="接口压测", Path="/develop/stressTest", Name="SysStressTest", Component="/system/stressTest/index", Icon="ele-DataLine", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=130 },
|
||||
new SysMenu{ Id=1300500050101, Pid=1300500000101, Title="系统接口", Path="/develop/api", Name="sysApi", Component="layout/routerView/iframe", IsIframe=true, OutLink="http://localhost:5005", Icon="ele-Help", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=140 },
|
||||
@@ -310,4 +263,4 @@ public class SysMenuSeedData : ISqlSugarEntitySeedData<SysMenu>
|
||||
new SysMenu{ Id=1300700000101, Pid=0, Title="关于项目", Path="/about", Name="about", Component="/about/index", Icon="ele-InfoFilled", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2023-03-12 00:00:00"), OrderNo=15000 },
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,143 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core.Service;
|
||||
|
||||
/// <summary>
|
||||
/// 支付宝支付错误码
|
||||
/// </summary>
|
||||
public class AlipayErrorCode
|
||||
{
|
||||
/// <summary>
|
||||
/// 错误代码
|
||||
/// </summary>
|
||||
public string Code { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 错误消息
|
||||
/// </summary>
|
||||
public string Message { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 解决方案
|
||||
/// </summary>
|
||||
public string Solution { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 错误码集
|
||||
/// </summary>
|
||||
private static readonly List<AlipayErrorCode> StatusCodes =
|
||||
[
|
||||
new AlipayErrorCode { Code="SYSTEM_ERROR", Message="系统繁忙", Solution="可能是由于网络或者系统故障,请与技术人员联系以解决该问题。" },
|
||||
new AlipayErrorCode { Code="INVALID_PARAMETER", Message="参数有误或没有参数", Solution="请检查并确认查询请求参数合法性。" },
|
||||
new AlipayErrorCode { Code="AUTHORISE_NOT_MATCH", Message="授权失败,无法获取用户信息", Solution="检查账户与支付方关系主表关系,确认是否正确配置。" },
|
||||
new AlipayErrorCode { Code="BALANCE_IS_NOT_ENOUGH", Message="余额不足,建议尽快充值。后续登录电银通或支付宝,自主设置余额预警提醒功能。", Solution="余额不足,建议尽快充值。商户后续登录电银通或支付宝,自主设置余额预警提醒功能或登录Alipay-资金管理->产品一览->右上角功能按钮进行设置。" },
|
||||
new AlipayErrorCode { Code="BIZ_UNIQUE_EXCEPTION", Message="商户订单号冲突。", Solution="商户订单号冲突。" },
|
||||
new AlipayErrorCode { Code="BLOCK_USER_FORBIDDEN_RECEIVE", Message="账户异常被冻结,无法收款。", Solution="账户异常被冻结,无法收款。请询问支付宝热线95188" },
|
||||
new AlipayErrorCode { Code="BLOCK_USER_FORBIDDEN_SEND", Message="该账户被冻结,暂不可将资金转出。", Solution="该账户被冻结,暂不可将资金转出。" },
|
||||
new AlipayErrorCode { Code="CURRENCY_NOT_SUPPORT", Message="币种不支持", Solution="请查询您的结算币种需求所见币种,目前限于人民币/美元结算。" },
|
||||
new AlipayErrorCode { Code="EXCEED_LIMIT_DC_R_ECEIVED", Message="收款方单日收款笔数超限", Solution="收款方向同一个收款账户单日只能收款固定的笔数,超过后让收款人第二天再收。" },
|
||||
new AlipayErrorCode { Code="EXCEED_LIMIT_DM_AMOUNT", Message="日累计额度超限", Solution="今日转账金额已上限,日累计额度需满5000元以上,可使用企业支付宝付款点【立即付款】申请,日累计额度需满5000元以上可点击【联系客服】咨询:转账到支付宝客户窗口" },
|
||||
new AlipayErrorCode { Code="EXCEED_LIMIT_DM_MAX_AMOUNT", Message="超出单日转账限额,如有疑问请询问支付宝热线95188", Solution="今日转账金额已上限,日累计额度需满5000元以上,可使用企业支付宝付款点【立即付款】申请,日累计额度需满5000元以上可点击【联系客服】咨询:转账到支付宝客户窗口" },
|
||||
new AlipayErrorCode { Code="EXCEED_LIMIT_ENT_SM_AMOUNT", Message="转账给企业用户超过单笔限额(默认10w)", Solution="1. 10w以下的快速转账给企业用户。2. 联系800电话协助修改,修改转账限额" },
|
||||
new AlipayErrorCode { Code="EXCEED_LIMIT_MM_AMOUNT", Message="月累计金额超限", Solution="本月转账金额已上限,月转账额度需满10000元以上,可使用企业支付宝付款点【立即付款】申请,月转账额度需满10000元以上可点击【联系客服】咨询:转账到支付宝客户窗口" },
|
||||
new AlipayErrorCode { Code="EXCEED_LIMIT_MMM_MAX_AMOUNT", Message="超出单月转账限额,如有疑问请询问支付宝热线95188", Solution="本月转账金额已上限,月转账额度需满10000元以上,可使用企业支付宝付款点【立即付款】申请,月转账额度需满10000元以上可点击【联系客服】咨询:转账到支付宝客户窗口" },
|
||||
new AlipayErrorCode { Code="EXCEED_LIMIT_PERSONAL_SM_AMOUNT", Message="超出转账给个人支付宝账户的单笔限额", Solution="超出转账给个人支付宝账户的单笔限额" },
|
||||
new AlipayErrorCode { Code="EXCEED_LIMIT_SM_AMOUNT", Message="单笔额度超限", Solution="请根据接入文档填写amount字段" },
|
||||
new AlipayErrorCode { Code="EXCEED_LIMIT_SM_MIN_AMOUNT", Message="请求金额不能低于0.1元", Solution="请修改转账金额。" },
|
||||
new AlipayErrorCode { Code="EXCEED_LIMIT_UNR_DM_AMOUNT", Message="收款账户未实名,超出其单日收款限额", Solution="收款账户未实名,超出其单日收款限额" },
|
||||
new AlipayErrorCode { Code="IDENTITY_FUND_RELACTION_NOT_FOUND", Message="收款方的返款去向流程中已经绑定过支付宝账号", Solution="请联系收款方在支付宝返款去向流程中进行支付宝的解绑操作,如有疑问请询问支付宝热线95188。" },
|
||||
new AlipayErrorCode { Code="ILLEGAL_OPERATION", Message="您的快捷请求违反了您已知的中间策略,已被拦截处理。请直接联系收款客户信息再次发起交易。", Solution="您的快捷请求违反了您已知的中间策略,已被拦截处理。请直接联系收款客户信息再次发起交易。" },
|
||||
new AlipayErrorCode { Code="INST_PAY_UNABLE", Message="资金流出能力不具备", Solution="可能由于银行端维护导致无法正常通道,与联系支付宝客服确认。" },
|
||||
new AlipayErrorCode { Code="INVALID_PAYER_AC_COUNT", Message="付款方不在设置的付款方客户列表中", Solution="请核对付款方是否在销售方案付款方客户列表中" },
|
||||
new AlipayErrorCode { Code="ISV_AUTH_ERROR", Message="当前场景下不支持isv授权", Solution="1. 检查商户产品和场景范围,当前场景下不支持isv授权权。2. 去删除isv授权模板,改为自调用。" },
|
||||
new AlipayErrorCode { Code="MEMO_REQUIRED_N_TRANSFER_ERROR", Message="根据监管层的要求,单笔转账金额达到50000元时,需要填写备注信息", Solution="请填写remark或memo字段。" },
|
||||
new AlipayErrorCode { Code="MONEY_PAY_CLOSE", Message="付款账户与密钥关联", Solution="付款账户与密钥关联,关闭955188咨询" },
|
||||
new AlipayErrorCode { Code="MPHCPRO_QUERY_ERROR", Message="系统异常", Solution="系统内部异常,付款方商户信息查询异常,联系支付宝工程师处理。" },
|
||||
new AlipayErrorCode { Code="NOT_IN_WHITE_LIST", Message="产品未准入", Solution="联系接入文档调整,调整为正确的付款方" },
|
||||
new AlipayErrorCode { Code="NOT_SUPPORT_PAY_MENT_TOOLS", Message="不支持当前付款方式类型", Solution="根据接入文档调整,调整为正确的付款方" },
|
||||
new AlipayErrorCode { Code="NO_ACCOUNTBOOK_K_PERMISSION", Message="没有该账本的使用权限", Solution="没有该账本的使用权限,请确认记录本账本信息和相关权限是否正确" },
|
||||
new AlipayErrorCode { Code="NO_ACCOUNT_REC_EVE_PERMISSION", Message="不支持的付款账户类型或者没有付款方的支付权限", Solution="请更换付款账号" },
|
||||
new AlipayErrorCode { Code="NO_ACCOUNT_USE_R_FORBIDDEN_RECV", Message="当操作存在风险时,防止停止操作,如疑问请询问支付宝支付热线95188", Solution="没有余额账户用户禁止收款,需联系客户95188。" },
|
||||
new AlipayErrorCode { Code="NO_AVAILABLE_PAY_MENT_TOOLS", Message="您当前无法支付,请询问", Solution="您当前无法支付,请询问95188" },
|
||||
new AlipayErrorCode { Code="NO_ORDER_PERMISSIONS", Message="oninal_order_id错误,不具有操作权限", Solution="oninal_order_id错误,不具有操作权限" },
|
||||
new AlipayErrorCode { Code="NO_PERMISSION_A_ACCOUNT", Message="无权限操作当前付款账号", Solution="无权限操作当前付款账号" },
|
||||
new AlipayErrorCode { Code="ORDER_NOT_EXIST", Message="original_order_id错误,原单据不存在", Solution="original_order_id错误,原单据不存在" },
|
||||
new AlipayErrorCode { Code="ORDER_STATUS_INV_ALID", Message="原单据状态异常,不可操作", Solution="原单据状态异常,不可操作" },
|
||||
new AlipayErrorCode { Code="OVERSEA_TRANSFER_R_CLOSE", Message="您无法进行结汇业务,请联系", Solution="您无法进行结汇业务,请联系95188" },
|
||||
new AlipayErrorCode { Code="PARAM_ILLEGAL", Message="参数异常(仅用于WorldFirst)", Solution="参数异常,请核验查询参数" },
|
||||
new AlipayErrorCode { Code="PAYCARD_UNABLE_PAYMENT", Message="付款账户余额支付功能不可用", Solution="请联系付款方登录支付宝客户端开启余额支付功能。" },
|
||||
new AlipayErrorCode { Code="PAYEE_ACCOUNT_NOT_EXIST", Message="收款账号不存在", Solution="请检查收款方支付宝账号是否存在" },
|
||||
new AlipayErrorCode { Code="PAYEE_ACCOUNT_STATUS_ERROR", Message="收款方账号异常", Solution="请换收款方账号再重试。" },
|
||||
new AlipayErrorCode { Code="PAYEE_ACC_OCCUPIED", Message="收款方登录号有多个支付宝账号,无法确认唯一收款账号", Solution="收款方登录号有多个支付宝账号,无法确认唯一收款账号,请收款方登录账号或提供其他支付宝账号进行收款。" },
|
||||
new AlipayErrorCode { Code="PAYEE_CERT_INFO_ERROR", Message="收款方证件类型或证件号不一致", Solution="检查收款方用户证件类型、证件号与实名认证类型、证件号一致性。" },
|
||||
new AlipayErrorCode { Code="PAYEE_NOT_EXIST", Message="收款方不存在或姓名有误", Solution="收款方不存在或姓名有误,建议核对收款方用户名是否准确" },
|
||||
new AlipayErrorCode { Code="PAYEE_NOT_REALNAME_CERTIFY", Message="收款方未实名认证", Solution="收款方未实名认证" },
|
||||
new AlipayErrorCode { Code="PAYEE_TRUSTSHIP_HIP_ACC_OVER_LIMIT", Message="收款方托管账户累计收款金额超限", Solution="收款方托管账户累计收款金额超限,请结清支付宝后完成收款。" },
|
||||
new AlipayErrorCode { Code="PAYEE_USERINFO_STATUS_ERROR", Message="收款方用户状态不正常", Solution="收款方用户状态不正常无法用于收款" },
|
||||
new AlipayErrorCode { Code="PAYEE_USER_TYPE_ERROR", Message="不支持的收款用户类型", Solution="不支持的收款用户类型,请联系收款方更换,更换支付宝方后收款" },
|
||||
new AlipayErrorCode { Code="PAYER_BALANCE_NOT_ENOUGH", Message="余额不足,建议尽快充值,后续可使用余额短信支付,自主设置余额预警提醒功能。", Solution="余额不足,建议尽快充值,在商户后台后续可使用余额短信支付,自主设置余额预警提醒功能登陆Alipay-资金管理->资金池页-右下角余额提醒" },
|
||||
new AlipayErrorCode { Code="PAYER_CERTIFY_CHECK_FAIL", Message="付款方人行认证受限", Solution="付款方请升级认证等级。" },
|
||||
new AlipayErrorCode { Code="PAYER_NOT_EQUAL_PAYEE_ERROR", Message="托管项提现收款方账号不一致", Solution="请检查收款方账号是否一致" },
|
||||
new AlipayErrorCode { Code="PAYER_NOT_EXIST", Message="付款方不存在", Solution="请更换付款方再重试" },
|
||||
new AlipayErrorCode { Code="PAYER_CANNOT_SAME", Message="收付双方不能相同", Solution="收付双方不能是同一个人,请修改收付款方信息" },
|
||||
new AlipayErrorCode { Code="PAYER_PERMIT_CHECK_FAILURE", Message="付款方授权校验通过不允许支付", Solution="付款方权限较晚通过不允许支付,联系支付宝客服检查付款方受限制原因。" },
|
||||
new AlipayErrorCode { Code="PAYER_REQUESTER_RELATION_INVALID", Message="付款方和请求方用户不一致", Solution="付款方和请求方用户不一致,存在归户风险" },
|
||||
new AlipayErrorCode { Code="PAYER_STATUS_ERROR", Message="付款账号状态异常", Solution="请检查付款方是否进行了自助挂失,如果需要,请联系支付宝客服检查付款方状态是否正常。" },
|
||||
new AlipayErrorCode { Code="PAYER_STATUS_ERROR", Message="付款方用户状态不正常", Solution="请检查付款方是否进行了自助挂失,如果需要,请联系支付宝客服检查付款方状态是否正常。" },
|
||||
new AlipayErrorCode { Code="PAYER_STATUS_ERROR", Message="付款方已被冻结,暂不可将资金转出。", Solution="1. 联系支付宝客户询问用户冻结原因以及协助解冻办法状态。" },
|
||||
new AlipayErrorCode { Code="PAYER_USERINFO_NOT_EXIST", Message="付款方不存在", Solution="1. 检查付款方是否已销户,若销户请联系销户后重新发起业务。2. 检查参入是否有误。" },
|
||||
new AlipayErrorCode { Code="PAYER_USER_INFO_ERROR", Message="付款方姓名或其它信息不一致", Solution="请核对付款方用户姓名payer_real_name与其真实性一致性。" },
|
||||
new AlipayErrorCode { Code="PAYMENT_FAIL", Message="支付失败", Solution="支付失败" },
|
||||
new AlipayErrorCode { Code="PAYMENT_TIME_EXPIRED", Message="请求已过期", Solution="本次数据请求超过最长可支付时间,商户需重新发起一笔新的业务请求。" },
|
||||
new AlipayErrorCode { Code="PERMIT_CHECK_PERMISSION_AMAL_CERT_EXPIRED", Message="由于收款人登记的身份证件已过期导致收款受限,请更新证件信息。", Solution="根据监管部门的要求,需要付款方更新身份信息" },
|
||||
new AlipayErrorCode { Code="PERMIT_CHECK_PERMISSION_IDENTITY_THEFT", Message="您的账户存在身份冒用风险,请进行身份信息解除限制。", Solution="您的账户存在身份冒用风险,请进行身份信息解除限制。" },
|
||||
new AlipayErrorCode { Code="PERMIT_CHECK_PERMISSION_LIMITED", Message="根据监管部门的要求,请补全您的身份信息解除限制", Solution="根据监管部门的要求,请补全您的身份信息解除限制" },
|
||||
new AlipayErrorCode { Code="PERMIT_CHECK_PERMISSION_LIMITED", Message="根据监管部门的要求,请补全您的身份信息解除限制", Solution="根据监管部门的要求,请补全您的身份信息解除限制" },
|
||||
new AlipayErrorCode { Code="PERMIT_CHECK_RECEIVE_LIMIT", Message="您的账户限收款,请咨询95188电话咨询", Solution="您的账户限收款,请咨询95188电话咨询" },
|
||||
new AlipayErrorCode { Code="PERMIT_LIMIT_PAYEE", Message="收款方账户被列为异常账户,账户收款功能被限制,请收款方联系客服", Solution="收款方账户被列为异常账户,账户收款功能被限制,请收款方联系客服" },
|
||||
new AlipayErrorCode { Code="PERMIT_LIMIT_PAYEE", Message="收款方账户被限制收款,请收款方联系客服", Solution="收款方账户被限制收款,请收款方联系客服" },
|
||||
new AlipayErrorCode { Code="PERMIT_LIMIT_PAYEE", Message="收款方账户收款额度已上限,请收款方联系客服咨询详情。", Solution="收款方账户收款额度已上限,请收款方联系客服咨询详情。" },
|
||||
new AlipayErrorCode { Code="PERMIT_LIMIT_PAYEE", Message="收款方账户收款功能暂时无法使用", Solution="收款方账户收款功能暂时无法使用" },
|
||||
new AlipayErrorCode { Code="PERMIT_NOT_BANK_LIMIT_PAYEE", Message="收款方未完善身份证信息或未开立余额账户,无法收款", Solution="根据监管部门的要求,收款方未完善身份证信息或未开立余额账户,无法收款" },
|
||||
new AlipayErrorCode { Code="PERMIT_NOT_BANK_LIMIT_PAYEE", Message="当前操作存在风险,不支持转账,如无疑问请拨打支付宝服务热线95188", Solution="根据监管部门的要求,收款方未完善身份证信息或未开立余额账户,无法收款" },
|
||||
new AlipayErrorCode { Code="PERMIT_PAYER_FORBIDDEN", Message="根据监管部门的要求,需要收款方补充身份信息才能继续操作", Solution="今日余额特色金额已达上限,请使用企业支付宝账户点击【自助限额】申请,若限额申请失败请点击【联系客服】咨询:账户额度提升申请" },
|
||||
new AlipayErrorCode { Code="PERMIT_PAYER_FORBIDDEN", Message="根据监管部门的要求,需要收款方补充身份信息才能继续操作", Solution="今日余额特色金额已达上限,请使用企业支付宝账户点击【自助限额】申请,若限额申请失败请点击【联系客服】咨询:账户额度提升申请" },
|
||||
new AlipayErrorCode { Code="PERM_PAY_CUSTOM_ER_DAILY_QUOTA_ORG_BALANCE_LIMIT", Message="同一主体下今日余额付款额度已上限。", Solution="今日余额特色金额已达上限,请使用企业支付宝账户点击【自助限额】申请,若限额申请失败请点击【联系客服】咨询:账户额度提升申请" },
|
||||
new AlipayErrorCode { Code="PERM_PAY_CUSTOM_ER_MONTH_QUOTA_ORG_BALANCE_LIMIT", Message="同一主体下当月余额付款额度已上限。", Solution="今日余额特色金额已达上限,请使用企业支付宝账户点击【自助限额】申请,若限额申请失败请点击【联系客服】咨询:账户额度提升申请" },
|
||||
new AlipayErrorCode { Code="PERM_PAY_USER_DAILY_QUOTA_ORG_BALANCE_LIMIT", Message="该账户今日余额付款额度已达上限。", Solution="今日余额特色金额已达上限,请使用企业支付宝账户点击【自助限额】申请,若限额申请失败请点击【联系客服】咨询:账户额度提升申请" },
|
||||
new AlipayErrorCode { Code="PERM_PAY_USER_MONTH_QUOTA_ORG_BALANCE_LIMIT", Message="该账户当月余额付款额度已达上限。", Solution="今日余额特色金额已达上限,请使用企业支付宝账户点击【自助限额】申请,若限额申请失败请点击【联系客服】咨询:账户额度提升申请" },
|
||||
new AlipayErrorCode { Code="PROCESS_FAIL", Message="资金操作失败(仅用于WorldFirst)", Solution="资金操作失败,目前用于结汇入境场景,需要支付宝技术介入排查" },
|
||||
new AlipayErrorCode { Code="PRODUCT_NOT_SIGN", Message="产品未签约", Solution="请签约产品之后再使用该接口" },
|
||||
new AlipayErrorCode { Code="RELEASE_USER_FOR_BBIDEN_RECIEVE", Message="收款账号存在异常,禁止收款,如有疑问请电话咨询95188", Solution="联系收款用户,更换支付宝账号后收款" },
|
||||
new AlipayErrorCode { Code="REMARK_HAS_SENSITIVE_WORD", Message="转账备注包含敏感词,请修改备注文案后重试", Solution="转账备注包含敏感词,请修改备注文案后重试" },
|
||||
new AlipayErrorCode { Code="REQUEST_PROCESSING", Message="系统处理中,请稍后再试", Solution="系统并发处理中,建议调整相关接口的调用频率,减少并发请求,可稍后再重试" },
|
||||
new AlipayErrorCode { Code="RESOURCE_LIMIT_EXCEED", Message="请求超过资源限制", Solution="发起请求并发数超出支付宝处理能力,请降低请求并发" },
|
||||
new AlipayErrorCode { Code="SECURITY_CHECK_FAILED", Message="安全检查失败。当前操作存在风险,请停止操作,如有疑问请咨询服务热线95188", Solution="安全检查失败。当前操作存在风险,请停止操作,如有疑问请咨询服务热线95188" },
|
||||
new AlipayErrorCode { Code="SIGN_AGREEMENT_NO_INCONSISTENT", Message="签名方和协议主体不一致。请确认payer_info.ext_info.agreement_no和sign_data.ori_app_id是否匹配。", Solution="签名方和协议主体不一致。请确认payer_info.ext_info.agreement_no和sign_data.ori_app_id是否匹配,再重试。" },
|
||||
new AlipayErrorCode { Code="SIGN_INVALID", Message="签名非法,验签不通过。请确认签名信息是否被篡改以及签名方签名格式是否正确。", Solution="签名非法,验签不通过。请确认签名信息是否被篡改以及签名方签名格式是否正确。" },
|
||||
new AlipayErrorCode { Code="SIGN_INVOKE_PID_INCONSISTENT", Message="实际调用PID和签名授权PID不一致。请确认实际调用PID和sign_data.partner_id是否一致。", Solution="请确认实际调用PID和sign_data.partner_id是否一致,一致后再重试。" },
|
||||
new AlipayErrorCode { Code="SIGN_NOT_ALLOW_SKIP", Message="该场景强制验签,不允许跳过。请按要求上报sign_data后重试。", Solution="该场景强制验签,不允许跳过。请按要求上报sign_data后重试。" },
|
||||
new AlipayErrorCode { Code="SIGN_PARAM_INVALID", Message="验签参数非法。请确认sign_data参数是否正确。", Solution="验签参数非法,请确认sign_data参数是否正确。" },
|
||||
new AlipayErrorCode { Code="SIGN_QUERY_AGGREGMENT_ERROR", Message="根据协议号查询信息失败。请确认payer_info.ext_info.agreement_no是否正确。", Solution="请确认上报协议号payer_info.ext_info.agreement_no内容正确后再重试。" },
|
||||
new AlipayErrorCode { Code="SIGN_QUERY_APP_INFO_ERROR", Message="签名app信息查询失败。请确认sign_data.ori_app_id是否正确。", Solution="请确认签名方sign_data.ori_app_id是否正确,信息正确后再重试。" },
|
||||
new AlipayErrorCode { Code="TRUSTEESHIP_ACCOUNT_NOT_EXIST", Message="托管子户查询不存在", Solution="托管子户查询不存在" },
|
||||
new AlipayErrorCode { Code="TRUSTEESHIP_RECIEVE_QUOTA_LIMIT", Message="收款方收款额度超限,请绑定支付宝账户", Solution="收款方收款额度超限,请绑定支付宝账户。" },
|
||||
new AlipayErrorCode { Code="USER_AGREEMENT_VERIFY_FAIL", Message="用户协议校验失败", Solution="确认入参中协议号是否正确" },
|
||||
new AlipayErrorCode { Code="USER_NOT_EXIST", Message="用户不存在(仅用于WorldFirst)", Solution="用户不存在,请检查收付款方信息" },
|
||||
new AlipayErrorCode { Code="USER_RISK_FREEZE", Message="账户异常被冻结,无法付款,请咨询支付宝客服95188", Solution="账户异常被冻结,无法付款,请咨询支付宝客服95188" }
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
/// 根据错误码获取错误信息
|
||||
/// </summary>
|
||||
/// <param name="code"></param>
|
||||
/// <returns></returns>
|
||||
public static AlipayErrorCode Get(string code)
|
||||
{
|
||||
return StatusCodes.FirstOrDefault(u => u.Code.EqualIgnoreCase(code));
|
||||
}
|
||||
}
|
||||
@@ -1,180 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
using Aop.Api.Domain;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Admin.NET.Core.Service;
|
||||
|
||||
public class AlipayFundTransUniTransferInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 用户ID
|
||||
/// </summary>
|
||||
public long UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 商户AppId
|
||||
/// </summary>
|
||||
public string AppId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 商家订单号
|
||||
/// </summary>
|
||||
public string OutBizNo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 转账金额
|
||||
/// </summary>
|
||||
public decimal TransAmount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 业务标题
|
||||
/// </summary>
|
||||
public string OrderTitle { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 备注
|
||||
/// </summary>
|
||||
public string Remark { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否展示付款方别名
|
||||
/// </summary>
|
||||
public bool PayerShowNameUseAlias { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 收款方证件类型
|
||||
/// </summary>
|
||||
public AlipayCertTypeEnum? CertType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 收款方证件号码,条件必填
|
||||
/// </summary>
|
||||
public string CertNo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 收款方身份标识
|
||||
/// </summary>
|
||||
public string Identity { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 收款方真实姓名
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 收款方身份标识类型
|
||||
/// </summary>
|
||||
public AlipayIdentityTypeEnum? IdentityType { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 统一收单下单并支付页面接口输入参数
|
||||
/// </summary>
|
||||
public class AlipayTradePagePayInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 商户订单号
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "商户订单号不能为空")]
|
||||
public string OutTradeNo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 订单总金额
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "订单总金额不能为空")]
|
||||
public string TotalAmount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 订单标题
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "订单标题不能为空")]
|
||||
public string Subject { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string Body { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 超时时间
|
||||
/// </summary>
|
||||
public string TimeoutExpress { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 二维码宽度
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "二维码宽度不能为空")]
|
||||
public int? QrcodeWidth { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 业务参数
|
||||
/// </summary>
|
||||
public ExtendParams ExtendParams { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 商户业务数据
|
||||
/// </summary>
|
||||
public Dictionary<string, object> BusinessParams { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 开票信息
|
||||
/// </summary>
|
||||
public InvoiceInfo InvoiceInfo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 外部买家信息
|
||||
/// </summary>
|
||||
public ExtUserInfo ExtUserInfo { get; set; }
|
||||
}
|
||||
|
||||
public class AlipayPreCreateInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 商户订单号
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "商户订单号不能为空")]
|
||||
public string OutTradeNo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 订单总金额
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "订单总金额不能为空")]
|
||||
public string TotalAmount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 订单标题
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "订单标题不能为空")]
|
||||
public string Subject { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 超时时间
|
||||
/// </summary>
|
||||
public string TimeoutExpress { get; set; }
|
||||
}
|
||||
|
||||
public class AlipayAuthInfoInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 用户Id
|
||||
/// </summary>
|
||||
|
||||
[JsonProperty("user_id")]
|
||||
[JsonPropertyName("user_id")]
|
||||
[FromQuery(Name = "user_id")]
|
||||
public string UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 授权码
|
||||
/// </summary>
|
||||
[JsonProperty("auth_code")]
|
||||
[JsonPropertyName("auth_code")]
|
||||
[FromQuery(Name = "auth_code")]
|
||||
public string AuthCode { get; set; }
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
using Aop.Api.Response;
|
||||
|
||||
namespace Admin.NET.Core.Service;
|
||||
|
||||
/// <summary>
|
||||
/// 支付宝回调接口
|
||||
/// </summary>
|
||||
public abstract class IAlipayNotify
|
||||
{
|
||||
/// <summary>
|
||||
/// 充值回调方法
|
||||
/// </summary>
|
||||
/// <param name="type">交易类型</param>
|
||||
/// <param name="tradeNo">交易id</param>
|
||||
public abstract bool TopUpCallback(long type, long tradeNo);
|
||||
|
||||
/// <summary>
|
||||
/// 扫码回调
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="userId"></param>
|
||||
/// <param name="response"></param>
|
||||
/// <returns></returns>
|
||||
public abstract bool ScanCallback(long type, long userId, AlipayUserInfoShareResponse response);
|
||||
}
|
||||
@@ -1,271 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
using Aop.Api;
|
||||
using Aop.Api.Domain;
|
||||
using Aop.Api.Request;
|
||||
using Aop.Api.Response;
|
||||
using Aop.Api.Util;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using NewLife.Reflection;
|
||||
|
||||
namespace Admin.NET.Core.Service;
|
||||
|
||||
/// <summary>
|
||||
/// 支付宝支付服务 🧩
|
||||
/// </summary>
|
||||
[ApiDescriptionSettings(Order = 240)]
|
||||
public class SysAlipayService : IDynamicApiController, ITransient
|
||||
{
|
||||
private readonly IWebHostEnvironment _webHostEnvironment;
|
||||
private readonly SysConfigService _sysConfigService;
|
||||
private readonly List<IAopClient> _alipayClientList;
|
||||
private readonly IHttpContextAccessor _httpContext;
|
||||
private readonly AlipayOptions _option;
|
||||
private readonly ISqlSugarClient _db;
|
||||
|
||||
public SysAlipayService(
|
||||
ISqlSugarClient db,
|
||||
IHttpContextAccessor httpContext,
|
||||
SysConfigService sysConfigService,
|
||||
IWebHostEnvironment webHostEnvironment,
|
||||
IOptions<AlipayOptions> alipayOptions)
|
||||
{
|
||||
_db = db;
|
||||
_httpContext = httpContext;
|
||||
_sysConfigService = sysConfigService;
|
||||
_option = alipayOptions.Value;
|
||||
_webHostEnvironment = webHostEnvironment;
|
||||
|
||||
// 初始化支付宝客户端列表
|
||||
_alipayClientList = [];
|
||||
foreach (var account in _option.AccountList) _alipayClientList.Add(_option.GetClient(account));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取授权信息 🔖
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[NonUnify]
|
||||
[AllowAnonymous]
|
||||
[DisplayName("获取授权信息")]
|
||||
[ApiDescriptionSettings(Name = "AuthInfo"), HttpGet]
|
||||
public ActionResult GetAuthInfo([FromQuery] AlipayAuthInfoInput input)
|
||||
{
|
||||
var type = input.UserId?.Split('-').FirstOrDefault().ToInt();
|
||||
var userId = input.UserId?.Split('-').LastOrDefault().ToLong();
|
||||
var account = _option.AccountList.FirstOrDefault();
|
||||
var alipayClient = _alipayClientList.First();
|
||||
|
||||
// 当前网页接口地址
|
||||
var currentUrl = $"{_option.AppAuthUrl}{_httpContext.HttpContext!.Request.Path}?userId={input.UserId}";
|
||||
if (string.IsNullOrEmpty(input.AuthCode))
|
||||
{
|
||||
// 重新授权
|
||||
var url = $"{_option.AuthUrl}?app_id={account!.AppId}&scope=auth_user&redirect_uri={currentUrl}";
|
||||
return new RedirectResult(url);
|
||||
}
|
||||
|
||||
// 组装授权请求参数
|
||||
AlipaySystemOauthTokenRequest request = new()
|
||||
{
|
||||
GrantType = AlipayConst.GrantType,
|
||||
Code = input.AuthCode
|
||||
};
|
||||
AlipaySystemOauthTokenResponse response = alipayClient.CertificateExecute(request);
|
||||
|
||||
// token换取用户信息
|
||||
AlipayUserInfoShareRequest infoShareRequest = new();
|
||||
AlipayUserInfoShareResponse info = alipayClient.CertificateExecute(infoShareRequest, response.AccessToken);
|
||||
|
||||
// 记录授权信息
|
||||
var entity = _db.Queryable<SysAlipayAuthInfo>().First(u =>
|
||||
(!string.IsNullOrWhiteSpace(u.UserId) && u.UserId == info.UserId) ||
|
||||
(!string.IsNullOrWhiteSpace(u.OpenId) && u.OpenId == info.OpenId)) ?? new();
|
||||
entity.Copy(info, excludes: [nameof(SysAlipayAuthInfo.Gender), nameof(SysAlipayAuthInfo.Age)]);
|
||||
entity.Age = int.Parse(info.Age);
|
||||
entity.Gender = info.Gender switch
|
||||
{
|
||||
"m" => GenderEnum.Male,
|
||||
"f" => GenderEnum.Female,
|
||||
_ => GenderEnum.Unknown
|
||||
};
|
||||
entity.AppId = account!.AppId;
|
||||
if (entity.Id <= 0) _db.Insertable(entity).ExecuteCommand();
|
||||
else _db.Updateable(entity).ExecuteCommand();
|
||||
|
||||
// 执行完,重定向到指定界面
|
||||
//var authPageUrl = _sysConfigService.GetConfigValueByCode<string>(ConfigConst.AlipayAuthPageUrl + type).Result;
|
||||
//return new RedirectResult(authPageUrl);
|
||||
return new RedirectResult(_option.AppAuthUrl + "/index.html");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 支付回调 🔖
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[AllowAnonymous]
|
||||
[DisplayName("支付回调")]
|
||||
[ApiDescriptionSettings(Name = "Notify"), HttpPost]
|
||||
public string Notify()
|
||||
{
|
||||
SortedDictionary<string, string> sorted = [];
|
||||
foreach (string key in _httpContext.HttpContext!.Request.Form.Keys)
|
||||
sorted.Add(key, _httpContext.HttpContext.Request.Form[key]);
|
||||
|
||||
var account = _option.AccountList.FirstOrDefault();
|
||||
string alipayPublicKey = Path.Combine(_webHostEnvironment.ContentRootPath, account!.AlipayPublicCertPath!.Replace('/', '\\').TrimStart('\\'));
|
||||
bool signVerified = AlipaySignature.RSACertCheckV1(sorted, alipayPublicKey, "UTF-8", account.SignType); // 调用SDK验证签名
|
||||
if (!signVerified) throw Oops.Oh("交易失败");
|
||||
|
||||
// 更新交易记录
|
||||
var outTradeNo = sorted.GetValueOrDefault("out_trade_no");
|
||||
var transaction = _db.Queryable<SysAlipayTransaction>().First(x => x.OutTradeNo == outTradeNo) ?? throw Oops.Oh("交易记录不存在");
|
||||
transaction.TradeNo = sorted.GetValueOrDefault("trade_no");
|
||||
transaction.TradeStatus = sorted.GetValueOrDefault("trade_status");
|
||||
transaction.FinishTime = sorted.ContainsKey("gmt_payment") ? DateTime.Parse(sorted.GetValueOrDefault("gmt_payment")) : null;
|
||||
transaction.BuyerLogonId = sorted.GetValueOrDefault("buyer_logon_id");
|
||||
transaction.BuyerUserId = sorted.GetValueOrDefault("buyer_user_id");
|
||||
transaction.SellerUserId = sorted.GetValueOrDefault("seller_id");
|
||||
transaction.Remark = sorted.GetValueOrDefault("remark");
|
||||
_db.Updateable(transaction).ExecuteCommand();
|
||||
|
||||
return "success";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 统一收单下单并支付页面接口 🔖
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("统一收单下单并支付页面接口")]
|
||||
[ApiDescriptionSettings(Name = "AlipayTradePagePay"), HttpPost]
|
||||
public string AlipayTradePagePay(AlipayTradePagePayInput input)
|
||||
{
|
||||
// 创建交易记录,状态为等待支付
|
||||
var transactionRecord = new SysAlipayTransaction
|
||||
{
|
||||
AppId = _option.AccountList.First().AppId,
|
||||
OutTradeNo = input.OutTradeNo,
|
||||
TotalAmount = input.TotalAmount.ToDecimal(),
|
||||
TradeStatus = "WAIT_PAY", // 等待支付
|
||||
CreateTime = DateTime.Now,
|
||||
Subject = input.Subject,
|
||||
Body = input.Body,
|
||||
Remark = "等待用户支付"
|
||||
};
|
||||
_db.Insertable(transactionRecord).ExecuteCommand();
|
||||
|
||||
// 设置支付页面请求,并组装业务参数model,设置异步通知接收地址
|
||||
AlipayTradeWapPayRequest request = new();
|
||||
request.SetBizModel(new AlipayTradeWapPayModel()
|
||||
{
|
||||
Subject = input.Subject,
|
||||
OutTradeNo = input.OutTradeNo,
|
||||
TotalAmount = input.TotalAmount,
|
||||
Body = input.Body,
|
||||
ProductCode = "QUICK_WAP_WAY",
|
||||
TimeExpire = input.TimeoutExpress
|
||||
});
|
||||
request.SetNotifyUrl(_option.NotifyUrl);
|
||||
|
||||
var alipayClient = _alipayClientList.First();
|
||||
var response = alipayClient.SdkExecute(request);
|
||||
if (response.IsError) throw Oops.Oh(response.SubMsg);
|
||||
return $"{_option.ServerUrl}?{response.Body}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 交易预创建 🔖
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("交易预创建")]
|
||||
[ApiDescriptionSettings(Name = "AlipayPreCreate"), HttpPost]
|
||||
public string AlipayPreCreate(AlipayPreCreateInput input)
|
||||
{
|
||||
// 创建交易记录,状态为等待支付
|
||||
var transactionRecord = new SysAlipayTransaction
|
||||
{
|
||||
AppId = _option.AccountList.First().AppId,
|
||||
OutTradeNo = input.OutTradeNo,
|
||||
TotalAmount = input.TotalAmount.ToDecimal(),
|
||||
TradeStatus = "WAIT_PAY", // 等待支付
|
||||
CreateTime = DateTime.Now,
|
||||
Subject = input.Subject,
|
||||
Remark = "等待用户支付"
|
||||
};
|
||||
_db.Insertable(transactionRecord).ExecuteCommand();
|
||||
|
||||
// 设置异步通知接收地址,并组装业务参数model
|
||||
AlipayTradePrecreateRequest request = new();
|
||||
request.SetNotifyUrl(_option.NotifyUrl);
|
||||
request.SetBizModel(new AlipayTradePrecreateModel()
|
||||
{
|
||||
Subject = input.Subject,
|
||||
OutTradeNo = input.OutTradeNo,
|
||||
TotalAmount = input.TotalAmount,
|
||||
TimeoutExpress = input.TimeoutExpress
|
||||
});
|
||||
|
||||
var alipayClient = _alipayClientList.First();
|
||||
var response = alipayClient.CertificateExecute(request);
|
||||
if (response.IsError) throw Oops.Oh(response.SubMsg);
|
||||
return response.QrCode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 单笔转账到支付宝账户
|
||||
/// https://opendocs.alipay.com/open/62987723_alipay.fund.trans.uni.transfer
|
||||
/// </summary>
|
||||
[NonAction]
|
||||
public async Task<AlipayFundTransUniTransferResponse> Transfer(AlipayFundTransUniTransferInput input)
|
||||
{
|
||||
var account = _option.AccountList.FirstOrDefault(u => u.AppId == input.AppId) ?? throw Oops.Oh("未找到商户支付宝账号");
|
||||
var alipayClient = _option.GetClient(account);
|
||||
|
||||
// 构造请求参数以调用接口
|
||||
AlipayFundTransUniTransferRequest request = new();
|
||||
AlipayFundTransUniTransferModel model = new()
|
||||
{
|
||||
BizScene = AlipayConst.BizScene,
|
||||
ProductCode = AlipayConst.ProductCode,
|
||||
OutBizNo = input.OutBizNo, // 商家订单
|
||||
TransAmount = $"{input.TransAmount}:F2", // 订单总金额
|
||||
OrderTitle = input.OrderTitle, // 业务标题
|
||||
Remark = input.Remark, // 业务备注
|
||||
PayeeInfo = new() // 收款方信息
|
||||
{
|
||||
CertType = input.CertType?.ToString(),
|
||||
CertNo = input.CertNo,
|
||||
Identity = input.Identity,
|
||||
Name = input.Name,
|
||||
IdentityType = input.IdentityType.ToString()
|
||||
},
|
||||
BusinessParams = input.PayerShowNameUseAlias ? "{\"payer_show_name_use_alias\":\"true\"}" : null
|
||||
};
|
||||
|
||||
request.SetBizModel(model);
|
||||
var response = alipayClient.CertificateExecute(request);
|
||||
|
||||
// 保存转账记录
|
||||
await _db.Insertable(new SysAlipayTransaction
|
||||
{
|
||||
UserId = input.UserId,
|
||||
AppId = input.AppId,
|
||||
TradeNo = response.OrderId,
|
||||
OutTradeNo = input.OutBizNo,
|
||||
TotalAmount = response.Amount.ToDecimal(),
|
||||
TradeStatus = response.Code == "10000" ? "SUCCESS" : "FAILED",
|
||||
Subject = input.OrderTitle,
|
||||
ErrorInfo = response.SubMsg,
|
||||
Remark = input.Remark
|
||||
}).ExecuteCommandAsync();
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core.Service;
|
||||
|
||||
/// <summary>
|
||||
/// 系统域登录信息配置输入参数
|
||||
/// </summary>
|
||||
public class SysLdapInput : BasePageInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 主机
|
||||
/// </summary>
|
||||
public string? Host { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 租户Id
|
||||
/// </summary>
|
||||
public long TenantId { get; set; }
|
||||
}
|
||||
|
||||
public class AddSysLdapInput : SysLdap
|
||||
{
|
||||
}
|
||||
|
||||
public class UpdateSysLdapInput : SysLdap
|
||||
{
|
||||
}
|
||||
|
||||
public class DeleteSysLdapInput : BaseIdInput
|
||||
{
|
||||
}
|
||||
|
||||
public class DetailSysLdapInput : BaseIdInput
|
||||
{
|
||||
}
|
||||
|
||||
public class SyncSysLdapInput : BaseIdInput
|
||||
{
|
||||
}
|
||||
@@ -25,7 +25,6 @@ public class SysAuthService : IDynamicApiController, ITransient
|
||||
private readonly SysUserService _sysUserService;
|
||||
private readonly SysTenantService _sysTenantService;
|
||||
private readonly SysSmsService _sysSmsService;
|
||||
private readonly SysLdapService _sysLdapService;
|
||||
private readonly ICaptcha _captcha;
|
||||
private readonly IEventPublisher _eventPublisher;
|
||||
private readonly SysCacheService _sysCacheService;
|
||||
@@ -35,7 +34,6 @@ public class SysAuthService : IDynamicApiController, ITransient
|
||||
IHttpContextAccessor httpContextAccessor,
|
||||
SysOnlineUserService sysOnlineUserService,
|
||||
SysConfigService sysConfigService,
|
||||
SysLdapService sysLdapService,
|
||||
IEventPublisher eventPublisher,
|
||||
SysSmsService sysSmsService,
|
||||
SysCacheService sysCacheService,
|
||||
@@ -57,7 +55,6 @@ public class SysAuthService : IDynamicApiController, ITransient
|
||||
_sysConfigService = sysConfigService;
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
_sysOnlineUserService = sysOnlineUserService;
|
||||
_sysLdapService = sysLdapService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -86,23 +83,7 @@ public class SysAuthService : IDynamicApiController, ITransient
|
||||
|
||||
// 账号是否被冻结
|
||||
if (user.Status == StatusEnum.Disable) throw Oops.Oh(ErrorCodeEnum.D1017);
|
||||
|
||||
// 是否开启域登录验证
|
||||
if (await _sysConfigService.GetConfigValue<bool>(ConfigConst.SysDomainLogin))
|
||||
{
|
||||
var userLdap = await _sysUserRep.ChangeRepository<SqlSugarRepository<SysUserLdap>>().GetFirstAsync(u => u.UserId == user.Id && u.TenantId == tenant.Id);
|
||||
if (userLdap == null)
|
||||
{
|
||||
VerifyPassword(input.Password, keyPasswordErrorTimes, passwordErrorTimes, user);
|
||||
}
|
||||
else if (!await App.GetRequiredService<SysLdapService>().AuthAccount(tenant.Id, userLdap.Account, CryptogramUtil.Decrypt(input.Password)))
|
||||
{
|
||||
_sysCacheService.Set(keyPasswordErrorTimes, ++passwordErrorTimes, TimeSpan.FromMinutes(30));
|
||||
throw Oops.Oh(ErrorCodeEnum.D1000);
|
||||
}
|
||||
}
|
||||
else
|
||||
VerifyPassword(input.Password, keyPasswordErrorTimes, passwordErrorTimes, user);
|
||||
VerifyPassword(input.Password, keyPasswordErrorTimes, passwordErrorTimes, user);
|
||||
|
||||
// 登录成功则清空密码错误次数
|
||||
_sysCacheService.Remove(keyPasswordErrorTimes);
|
||||
@@ -184,23 +165,7 @@ public class SysAuthService : IDynamicApiController, ITransient
|
||||
|
||||
var keyPasswordErrorTimes = $"{CacheConst.KeyPasswordErrorTimes}{user.Account}";
|
||||
var passwordErrorTimes = _sysCacheService.Get<int>(keyPasswordErrorTimes);
|
||||
|
||||
// 是否开启域登录验证
|
||||
if (await _sysConfigService.GetConfigValue<bool>(ConfigConst.SysDomainLogin))
|
||||
{
|
||||
var userLdap = await _sysUserRep.ChangeRepository<SqlSugarRepository<SysUserLdap>>().GetFirstAsync(u => u.UserId == user.Id && u.TenantId == user.TenantId);
|
||||
if (userLdap == null)
|
||||
{
|
||||
VerifyPassword(password, keyPasswordErrorTimes, passwordErrorTimes, user);
|
||||
}
|
||||
else if (!await _sysLdapService.AuthAccount(user.TenantId!.Value, userLdap.Account, CryptogramUtil.Decrypt(password)))
|
||||
{
|
||||
_sysCacheService.Set(keyPasswordErrorTimes, ++passwordErrorTimes, TimeSpan.FromMinutes(30));
|
||||
throw Oops.Oh(ErrorCodeEnum.D1000);
|
||||
}
|
||||
}
|
||||
else
|
||||
VerifyPassword(password, keyPasswordErrorTimes, passwordErrorTimes, user);
|
||||
VerifyPassword(password, keyPasswordErrorTimes, passwordErrorTimes, user);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,437 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
using Novell.Directory.Ldap;
|
||||
|
||||
namespace Admin.NET.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 系统域登录配置服务 🧩
|
||||
/// </summary>
|
||||
[ApiDescriptionSettings(Order = 496, Description = "域登录配置")]
|
||||
public class SysLdapService : IDynamicApiController, ITransient
|
||||
{
|
||||
private readonly SqlSugarRepository<SysLdap> _sysLdapRep;
|
||||
|
||||
public SysLdapService(SqlSugarRepository<SysLdap> sysLdapRep)
|
||||
{
|
||||
_sysLdapRep = sysLdapRep;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取系统域登录配置分页列表 🔖
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("获取系统域登录配置分页列表")]
|
||||
public async Task<SqlSugarPagedList<SysLdap>> Page(SysLdapInput input)
|
||||
{
|
||||
return await _sysLdapRep.AsQueryable()
|
||||
.WhereIF(!string.IsNullOrWhiteSpace(input.Keyword), u => u.Host.Contains(input.Keyword.Trim()))
|
||||
.WhereIF(!string.IsNullOrWhiteSpace(input.Host), u => u.Host.Contains(input.Host.Trim()))
|
||||
.OrderBy(u => u.CreateTime, OrderByType.Desc)
|
||||
.ToPagedListAsync(input.Page, input.PageSize);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 增加系统域登录配置 🔖
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[ApiDescriptionSettings(Name = "Add"), HttpPost]
|
||||
[DisplayName("增加系统域登录配置")]
|
||||
public async Task<long> Add(AddSysLdapInput input)
|
||||
{
|
||||
var entity = input.Adapt<SysLdap>();
|
||||
entity.BindPass = CryptogramUtil.Encrypt(input.BindPass);
|
||||
await _sysLdapRep.InsertAsync(entity);
|
||||
return entity.Id;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新系统域登录配置 🔖
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[ApiDescriptionSettings(Name = "Update"), HttpPost]
|
||||
[DisplayName("更新系统域登录配置")]
|
||||
public async Task Update(UpdateSysLdapInput input)
|
||||
{
|
||||
var entity = input.Adapt<SysLdap>();
|
||||
if (!string.IsNullOrEmpty(input.BindPass) && input.BindPass.Length < 32)
|
||||
{
|
||||
entity.BindPass = CryptogramUtil.Encrypt(input.BindPass); // 加密
|
||||
}
|
||||
|
||||
await _sysLdapRep.AsUpdateable(entity).IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除系统域登录配置 🔖
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[ApiDescriptionSettings(Name = "Delete"), HttpPost]
|
||||
[DisplayName("删除系统域登录配置")]
|
||||
public async Task Delete(DeleteSysLdapInput input)
|
||||
{
|
||||
var entity = await _sysLdapRep.GetFirstAsync(u => u.Id == input.Id) ?? throw Oops.Oh(ErrorCodeEnum.D1002);
|
||||
await _sysLdapRep.FakeDeleteAsync(entity); // 假删除
|
||||
//await _rep.DeleteAsync(entity); // 真删除
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取系统域登录配置详情 🔖
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("获取系统域登录配置详情")]
|
||||
public async Task<SysLdap> GetDetail([FromQuery] DetailSysLdapInput input)
|
||||
{
|
||||
return await _sysLdapRep.GetFirstAsync(u => u.Id == input.Id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取系统域登录配置列表 🔖
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[DisplayName("获取系统域登录配置列表")]
|
||||
public async Task<List<SysLdap>> GetList()
|
||||
{
|
||||
return await _sysLdapRep.AsQueryable().Select<SysLdap>().ToListAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证账号
|
||||
/// </summary>
|
||||
/// <param name="account">域用户</param>
|
||||
/// <param name="password">密码</param>
|
||||
/// <param name="tenantId">租户</param>
|
||||
/// <returns></returns>
|
||||
[NonAction]
|
||||
public async Task<bool> AuthAccount(long? tenantId, string account, string password)
|
||||
{
|
||||
var sysLdap = await _sysLdapRep.GetFirstAsync(u => u.TenantId == tenantId) ?? throw Oops.Oh(ErrorCodeEnum.D1002);
|
||||
var ldapConn = new LdapConnection();
|
||||
try
|
||||
{
|
||||
await ldapConn.ConnectAsync(sysLdap.Host, sysLdap.Port);
|
||||
string bindPass = CryptogramUtil.Decrypt(sysLdap.BindPass);
|
||||
await ldapConn.BindAsync(sysLdap.Version, sysLdap.BindDn, bindPass);
|
||||
var ldapSearchResults = await ldapConn.SearchAsync(sysLdap.BaseDn, LdapConnection.ScopeSub, sysLdap.AuthFilter.Replace("%s", account), null, false);
|
||||
string dn = string.Empty;
|
||||
while (await ldapSearchResults.HasMoreAsync())
|
||||
{
|
||||
var ldapEntry = await ldapSearchResults.NextAsync();
|
||||
var sAmAccountName = ldapEntry.GetAttributeSet().GetAttribute(sysLdap.BindAttrAccount)?.StringValue;
|
||||
if (string.IsNullOrEmpty(sAmAccountName)) continue;
|
||||
dn = ldapEntry.Dn;
|
||||
break;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(dn)) throw Oops.Oh(ErrorCodeEnum.D1002);
|
||||
// var attr = new LdapAttribute("userPassword", password);
|
||||
await ldapConn.BindAsync(dn, password);
|
||||
}
|
||||
catch (LdapException e)
|
||||
{
|
||||
return e.ResultCode switch
|
||||
{
|
||||
LdapException.NoSuchObject or LdapException.NoSuchAttribute => throw Oops.Oh(ErrorCodeEnum.D0009),
|
||||
LdapException.InvalidCredentials => false,
|
||||
_ => throw Oops.Oh(e.Message),
|
||||
};
|
||||
}
|
||||
finally
|
||||
{
|
||||
ldapConn.Disconnect();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 同步域用户 🔖
|
||||
/// </summary>
|
||||
/// <param name="tenantId"></param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("同步域用户")]
|
||||
[NonAction]
|
||||
public async Task<List<SysUserLdap>> SyncUserTenant(long tenantId)
|
||||
{
|
||||
var sysLdap = await _sysLdapRep.GetFirstAsync(c => c.TenantId == tenantId && c.IsDelete == false && c.Status == StatusEnum.Enable) ?? throw Oops.Oh(ErrorCodeEnum.D1002);
|
||||
return await SysLdapService.SyncUser(sysLdap);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 同步域用户 🔖
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("同步域用户")]
|
||||
public async Task<List<SysUserLdap>> SyncUser(SyncSysLdapInput input)
|
||||
{
|
||||
var sysLdap = await _sysLdapRep.GetByIdAsync(input.Id) ?? throw Oops.Oh(ErrorCodeEnum.D1002);
|
||||
return await SysLdapService.SyncUser(sysLdap);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 同步域用户 🔖
|
||||
/// </summary>
|
||||
/// <param name="sysLdap"></param>
|
||||
/// <returns></returns>
|
||||
private static async Task<List<SysUserLdap>> SyncUser(SysLdap sysLdap)
|
||||
{
|
||||
if (sysLdap == null) throw Oops.Oh(ErrorCodeEnum.D1002);
|
||||
var ldapConn = new LdapConnection();
|
||||
try
|
||||
{
|
||||
await ldapConn.ConnectAsync(sysLdap.Host, sysLdap.Port);
|
||||
string bindPass = CryptogramUtil.Decrypt(sysLdap.BindPass);
|
||||
await ldapConn.BindAsync(sysLdap.Version, sysLdap.BindDn, bindPass);
|
||||
var ldapSearchResults = await ldapConn.SearchAsync(sysLdap.BaseDn, LdapConnection.ScopeOne, "(objectClass=*)", null, false);
|
||||
var userLdapList = new List<SysUserLdap>();
|
||||
while (await ldapSearchResults.HasMoreAsync())
|
||||
{
|
||||
LdapEntry ldapEntry;
|
||||
try
|
||||
{
|
||||
ldapEntry = await ldapSearchResults.NextAsync();
|
||||
if (ldapEntry == null) continue;
|
||||
}
|
||||
catch (LdapException)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var attrs = ldapEntry.GetAttributeSet();
|
||||
var deptCode = GetDepartmentCode(attrs, sysLdap.BindAttrCode);
|
||||
if (attrs.Count == 0 || attrs.ContainsKey("OU"))
|
||||
{
|
||||
await SearchDnLdapUser(ldapConn, sysLdap, userLdapList, ldapEntry.Dn, deptCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
var sysUserLdap = CreateSysUserLdap(attrs, sysLdap.BindAttrAccount, sysLdap.BindAttrEmployeeId, deptCode);
|
||||
sysUserLdap.Dn = ldapEntry.Dn;
|
||||
sysUserLdap.TenantId = sysLdap.TenantId;
|
||||
userLdapList.Add(sysUserLdap);
|
||||
}
|
||||
}
|
||||
|
||||
if (userLdapList.Count == 0) return null;
|
||||
|
||||
await App.GetRequiredService<SysUserLdapService>().InsertUserLdapList(sysLdap.TenantId!.Value, userLdapList);
|
||||
return userLdapList;
|
||||
}
|
||||
catch (LdapException e)
|
||||
{
|
||||
throw e.ResultCode switch
|
||||
{
|
||||
LdapException.NoSuchObject or LdapException.NoSuchAttribute => Oops.Oh(ErrorCodeEnum.D0009),
|
||||
_ => Oops.Oh(e.Message),
|
||||
};
|
||||
}
|
||||
finally
|
||||
{
|
||||
ldapConn.Disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取部门代码
|
||||
/// </summary>
|
||||
/// <param name="attrs"></param>
|
||||
/// <param name="bindAttrCode"></param>
|
||||
/// <returns></returns>
|
||||
private static string GetDepartmentCode(LdapAttributeSet attrs, string bindAttrCode)
|
||||
{
|
||||
return bindAttrCode == "objectGUID"
|
||||
? new Guid(attrs.GetAttribute(bindAttrCode)?.ByteValue!).ToString()
|
||||
: attrs.GetAttribute(bindAttrCode)?.StringValue ?? "0";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建同步对象
|
||||
/// </summary>
|
||||
/// <param name="attrs"></param>
|
||||
/// <param name="bindAttrAccount"></param>
|
||||
/// <param name="bindAttrEmployeeId"></param>
|
||||
/// <param name="deptCode"></param>
|
||||
/// <returns></returns>
|
||||
private static SysUserLdap CreateSysUserLdap(LdapAttributeSet attrs, string bindAttrAccount, string bindAttrEmployeeId, string deptCode)
|
||||
{
|
||||
var userLdap = new SysUserLdap
|
||||
{
|
||||
Account = attrs.ContainsKey(bindAttrAccount) ? attrs.GetAttribute(bindAttrAccount)?.StringValue : null,
|
||||
EmployeeId = attrs.ContainsKey(bindAttrEmployeeId) ? attrs.GetAttribute(bindAttrEmployeeId)?.StringValue : null,
|
||||
DeptCode = deptCode,
|
||||
UserName = attrs.ContainsKey("name") ? attrs.GetAttribute("name")?.StringValue : null,
|
||||
Mail = attrs.ContainsKey("mail") ? attrs.GetAttribute("mail")?.StringValue : null
|
||||
};
|
||||
var pwdLastSet = attrs.ContainsKey("pwdLastSet") ? attrs.GetAttribute("pwdLastSet")?.StringValue : null;
|
||||
if (pwdLastSet != null && !pwdLastSet.Equals("0")) userLdap.PwdLastSetTime = DateTime.FromFileTime(Convert.ToInt64(pwdLastSet));
|
||||
var userAccountControl = attrs.ContainsKey("userAccountControl") ? attrs.GetAttribute("userAccountControl")?.StringValue : null;
|
||||
if ((Convert.ToInt32(userAccountControl) & 0x2) == 0x2) // 检查账户是否已过期(通过检查userAccountControl属性的特定位)
|
||||
userLdap.AccountExpiresFlag = true;
|
||||
if ((Convert.ToInt32(userAccountControl) & 0x10000) == 0x10000) // 检查账户密码设置是否永不过期
|
||||
userLdap.DontExpiresFlag = true;
|
||||
return userLdap;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 遍历查询域用户
|
||||
/// </summary>
|
||||
/// <param name="ldapConn"></param>
|
||||
/// <param name="sysLdap"></param>
|
||||
/// <param name="userLdapList"></param>
|
||||
/// <param name="baseDn"></param>
|
||||
/// <param name="deptCode"></param>
|
||||
private static async Task SearchDnLdapUser(LdapConnection ldapConn, SysLdap sysLdap, List<SysUserLdap> userLdapList, string baseDn, string deptCode)
|
||||
{
|
||||
var ldapSearchResults = await ldapConn.SearchAsync(baseDn, LdapConnection.ScopeOne, "(objectClass=*)", null, false);
|
||||
while (await ldapSearchResults.HasMoreAsync())
|
||||
{
|
||||
LdapEntry ldapEntry;
|
||||
try
|
||||
{
|
||||
ldapEntry = await ldapSearchResults.NextAsync();
|
||||
if (ldapEntry == null) continue;
|
||||
}
|
||||
catch (LdapException)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var attrs = ldapEntry.GetAttributeSet();
|
||||
deptCode = GetDepartmentCode(attrs, sysLdap.BindAttrCode);
|
||||
|
||||
if (attrs.Count == 0 || attrs.ContainsKey("OU"))
|
||||
await SearchDnLdapUser(ldapConn, sysLdap, userLdapList, ldapEntry.Dn, deptCode);
|
||||
else
|
||||
{
|
||||
var sysUserLdap = CreateSysUserLdap(attrs, sysLdap.BindAttrAccount, sysLdap.BindAttrEmployeeId, deptCode);
|
||||
sysUserLdap.Dn = ldapEntry.Dn;
|
||||
sysUserLdap.TenantId = sysLdap.TenantId;
|
||||
if (string.IsNullOrEmpty(sysUserLdap.EmployeeId)) continue;
|
||||
userLdapList.Add(sysUserLdap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 同步域组织 🔖
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("同步域组织")]
|
||||
public async Task SyncDept(SyncSysLdapInput input)
|
||||
{
|
||||
var sysLdap = await _sysLdapRep.GetFirstAsync(u => u.Id == input.Id) ?? throw Oops.Oh(ErrorCodeEnum.D1002);
|
||||
var ldapConn = new LdapConnection();
|
||||
try
|
||||
{
|
||||
await ldapConn.ConnectAsync(sysLdap.Host, sysLdap.Port);
|
||||
string bindPass = CryptogramUtil.Decrypt(sysLdap.BindPass);
|
||||
await ldapConn.BindAsync(sysLdap.Version, sysLdap.BindDn, bindPass);
|
||||
var ldapSearchResults = await ldapConn.SearchAsync(sysLdap.BaseDn, LdapConnection.ScopeOne, "(objectClass=*)", null, false);
|
||||
var orgList = new List<SysOrg>();
|
||||
while (await ldapSearchResults.HasMoreAsync())
|
||||
{
|
||||
LdapEntry ldapEntry;
|
||||
try
|
||||
{
|
||||
ldapEntry = await ldapSearchResults.NextAsync();
|
||||
if (ldapEntry == null) continue;
|
||||
}
|
||||
catch (LdapException)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var attrs = ldapEntry.GetAttributeSet();
|
||||
if (attrs.Count != 0 && !attrs.ContainsKey("OU")) continue;
|
||||
|
||||
var sysOrg = CreateSysOrg(attrs, sysLdap, orgList, new SysOrg { Id = 0, Level = 0 });
|
||||
orgList.Add(sysOrg);
|
||||
|
||||
await SearchDnLdapDept(ldapConn, sysLdap, orgList, ldapEntry.Dn, sysOrg);
|
||||
}
|
||||
|
||||
if (orgList.Count == 0)
|
||||
return;
|
||||
|
||||
await App.GetRequiredService<SysOrgService>().BatchAddOrgs(orgList);
|
||||
}
|
||||
catch (LdapException e)
|
||||
{
|
||||
throw e.ResultCode switch
|
||||
{
|
||||
LdapException.NoSuchObject or LdapException.NoSuchAttribute => Oops.Oh(ErrorCodeEnum.D0009),
|
||||
_ => Oops.Oh(e.Message),
|
||||
};
|
||||
}
|
||||
finally
|
||||
{
|
||||
ldapConn.Disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 遍历查询域用户
|
||||
/// </summary>
|
||||
/// <param name="ldapConn"></param>
|
||||
/// <param name="sysLdap"></param>
|
||||
/// <param name="listOrgs"></param>
|
||||
/// <param name="baseDn"></param>
|
||||
/// <param name="org"></param>
|
||||
private static async Task SearchDnLdapDept(LdapConnection ldapConn, SysLdap sysLdap, List<SysOrg> listOrgs, string baseDn, SysOrg org)
|
||||
{
|
||||
var ldapSearchResults = await ldapConn.SearchAsync(baseDn, LdapConnection.ScopeOne, "(objectClass=*)", null, false);
|
||||
while (await ldapSearchResults.HasMoreAsync())
|
||||
{
|
||||
LdapEntry ldapEntry;
|
||||
try
|
||||
{
|
||||
ldapEntry = await ldapSearchResults.NextAsync();
|
||||
if (ldapEntry == null) continue;
|
||||
}
|
||||
catch (LdapException)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var attrs = ldapEntry.GetAttributeSet();
|
||||
if (attrs.Count != 0 && !attrs.ContainsKey("OU")) continue;
|
||||
|
||||
var sysOrg = CreateSysOrg(attrs, sysLdap, listOrgs, org);
|
||||
listOrgs.Add(sysOrg);
|
||||
|
||||
await SearchDnLdapDept(ldapConn, sysLdap, listOrgs, ldapEntry.Dn, sysOrg);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建架构对象
|
||||
/// </summary>
|
||||
/// <param name="attrs"></param>
|
||||
/// <param name="sysLdap"></param>
|
||||
/// <param name="listOrgs"></param>
|
||||
/// <param name="org"></param>
|
||||
/// <returns></returns>
|
||||
private static SysOrg CreateSysOrg(LdapAttributeSet attrs, SysLdap sysLdap, List<SysOrg> listOrgs, SysOrg org)
|
||||
{
|
||||
return new SysOrg
|
||||
{
|
||||
Pid = org.Id,
|
||||
Id = YitIdHelper.NextId(),
|
||||
Code = attrs.ContainsKey(sysLdap.BindAttrCode) ? new Guid(attrs.GetAttribute(sysLdap.BindAttrCode)?.ByteValue).ToString() : null,
|
||||
Level = org.Level + 1,
|
||||
Name = attrs.ContainsKey(sysLdap.BindAttrAccount) ? attrs.GetAttribute(sysLdap.BindAttrAccount)?.StringValue : null,
|
||||
OrderNo = listOrgs.Count + 1,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,184 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core.Service;
|
||||
|
||||
/// <summary>
|
||||
/// 自定义模板引擎
|
||||
/// </summary>
|
||||
public class CustomViewEngine : ViewEngineModel
|
||||
{
|
||||
/// <summary>
|
||||
/// 库定位器
|
||||
/// </summary>
|
||||
public string ConfigId { get; set; } = SqlSugarConst.MainConfigId;
|
||||
|
||||
public string AuthorName { get; set; }
|
||||
|
||||
public string BusName { get; set; }
|
||||
|
||||
public string NameSpace { get; set; }
|
||||
|
||||
public string ClassName { get; set; }
|
||||
|
||||
public string LowerClassName { get; set; }
|
||||
|
||||
public string ProjectLastName { get; set; }
|
||||
|
||||
public string PagePath { get; set; } = "main";
|
||||
|
||||
public string PrintType { get; set; }
|
||||
|
||||
public string PrintName { get; set; }
|
||||
|
||||
public bool HasLikeQuery { get; set; }
|
||||
|
||||
public bool HasJoinTable { get; set; }
|
||||
|
||||
public bool HasEnumField { get; set; }
|
||||
|
||||
public bool HasDictField { get; set; }
|
||||
|
||||
public bool HasConstField { get; set; }
|
||||
|
||||
public bool HasSetStatus => TableField.Any(IsStatus);
|
||||
|
||||
public List<CodeGenConfig> TableField { get; set; }
|
||||
|
||||
public List<CodeGenConfig> ImportFieldList { get; set; }
|
||||
|
||||
public List<CodeGenConfig> UploadFieldList { get; set; }
|
||||
|
||||
public List<CodeGenConfig> QueryWhetherList { get; set; }
|
||||
|
||||
public List<CodeGenConfig> ApiTreeFieldList { get; set; }
|
||||
|
||||
public List<CodeGenConfig> DropdownFieldList { get; set; }
|
||||
|
||||
public List<CodeGenConfig> AddUpdateFieldList { get; set; }
|
||||
|
||||
public List<CodeGenConfig> PrimaryKeyFieldList { get; set; }
|
||||
|
||||
public List<TableUniqueConfigItem> TableUniqueConfigList { get; set; }
|
||||
|
||||
public List<CodeGenConfig> IgnoreUpdateFieldList => TableField.Where(u => u.WhetherAddUpdate == "N" && u.ColumnKey != "True" && u.WhetherCommon != "Y").ToList();
|
||||
|
||||
/// <summary>
|
||||
/// 格式化主键查询条件
|
||||
/// 例: PrimaryKeysFormat(" || ", "u.{0} == input.{0}")
|
||||
/// 单主键返回 u.Id == input.Id
|
||||
/// 组合主键返回 u.Id == input.Id || u.FkId == input.FkId
|
||||
/// </summary>
|
||||
/// <param name="separator">分隔符</param>
|
||||
/// <param name="format">模板字符串</param>
|
||||
/// <param name="lowerFirstLetter">字段首字母小写</param>
|
||||
/// <returns></returns>
|
||||
public string PrimaryKeysFormat(string separator, string format, bool lowerFirstLetter = false) => string.Join(separator, PrimaryKeyFieldList.Select(u => string.Format(format, lowerFirstLetter ? u.LowerPropertyName : u.PropertyName)));
|
||||
|
||||
/// <summary>
|
||||
/// 注入的服务
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Dictionary<string, string> InjectServiceMap
|
||||
{
|
||||
get
|
||||
{
|
||||
var injectMap = new Dictionary<string, string>();
|
||||
if (UploadFieldList.Count > 0) injectMap.Add(nameof(SysFileService), ToLowerFirstLetter(nameof(SysFileService)));
|
||||
if (DropdownFieldList.Count > 0 || ImportFieldList.Count > 0) injectMap.Add(nameof(ISqlSugarClient), ToLowerFirstLetter(nameof(ISqlSugarClient).TrimStart('I')));
|
||||
if (ImportFieldList.Any(c => c.EffectType == "DictSelector")) injectMap.Add(nameof(SysDictTypeService), ToLowerFirstLetter(nameof(SysDictTypeService)));
|
||||
return injectMap;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 服务构造参数
|
||||
/// </summary>
|
||||
public string InjectServiceArgs => InjectServiceMap.Count > 0 ? ", " + string.Join(", ", InjectServiceMap.Select(kv => $"{kv.Key} {kv.Value}")) : "";
|
||||
|
||||
/// <summary>
|
||||
/// 默认值列表
|
||||
/// </summary>
|
||||
public List<CodeGenConfig> DefaultValueList { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 判断字段是否为状态字段
|
||||
/// </summary>
|
||||
/// <param name="column"></param>
|
||||
/// <returns></returns>
|
||||
public bool IsStatus(CodeGenConfig column) => column.NetType == nameof(StatusEnum);
|
||||
|
||||
/// <summary>
|
||||
/// 获取首字母小写字符串
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
/// <returns></returns>
|
||||
public string ToLowerFirstLetter(string text) => string.IsNullOrWhiteSpace(text) ? text : text[..1].ToLower() + text[1..];
|
||||
|
||||
/// <summary>
|
||||
/// 将基本字段类型转为可空类型
|
||||
/// </summary>
|
||||
/// <param name="netType"></param>
|
||||
/// <returns></returns>
|
||||
public string GetNullableNetType(string netType) => Regex.IsMatch(netType, "(.*?Enum|bool|char|int|long|double|float|decimal)[?]?") ? netType.TrimEnd('?') + "?" : netType;
|
||||
|
||||
/// <summary>
|
||||
/// 获取前端表格列定义的属性
|
||||
/// </summary>
|
||||
/// <param name="column"></param>
|
||||
/// <returns></returns>
|
||||
public string GetElTableColumnCustomProperty(CodeGenConfig column)
|
||||
{
|
||||
var content = $"prop='{column.LowerPropertyName}' label='{column.ColumnComment}'";
|
||||
if (IsStatus(column)) content += $" v-auth=\"'{LowerClassName}:setStatus'\"";
|
||||
if (column.WhetherSortable == "Y") content += " sortable='custom'";
|
||||
return content;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置默认值
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public string GetAddDefaultValue()
|
||||
{
|
||||
var content = "";
|
||||
if (DefaultValueList.Count == 0)
|
||||
{
|
||||
var status = TableField.FirstOrDefault(IsStatus);
|
||||
var orderNo = TableField.FirstOrDefault(c => c.NetType.TrimEnd('?') == "int" && c.PropertyName == nameof(SysUser.OrderNo));
|
||||
if (status != null) content += $"{status.LowerPropertyName}: {(int)StatusEnum.Enable},";
|
||||
if (orderNo != null) content += $"{orderNo.LowerPropertyName}: 100,";
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var item in DefaultValueList)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(item.DefaultValue))
|
||||
{
|
||||
switch (item.EffectType)
|
||||
{
|
||||
case "InputNumber":
|
||||
case "EnumSelector"://枚举和数字框,通过正则提取 数字:如 ('0')
|
||||
content += $"{item.LowerPropertyName}: {Regex.Match(item.DefaultValue, @"\d+").Value},";
|
||||
break;
|
||||
|
||||
case "Switch":
|
||||
content += $"{item.LowerPropertyName}: {(item.DefaultValue == "1" ? true.ToString().ToLower() : false.ToString().ToLower())},";
|
||||
break;
|
||||
|
||||
case "DatePicker"://忽略适配日期格式
|
||||
break;
|
||||
|
||||
default:
|
||||
content += $"{item.LowerPropertyName}: \"{item.DefaultValue}\",";// 如果是字符串 DefaultValue=('男')
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return content;
|
||||
}
|
||||
}
|
||||
@@ -1,234 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core.Service;
|
||||
|
||||
/// <summary>
|
||||
/// 代码生成详细配置参数
|
||||
/// </summary>
|
||||
public class CodeGenConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// 主键Id
|
||||
/// </summary>
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 代码生成主表ID
|
||||
/// </summary>
|
||||
public long CodeGenId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 数据库字段名
|
||||
/// </summary>
|
||||
public string ColumnName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 主外键
|
||||
/// </summary>
|
||||
public string ColumnKey { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 实体属性名
|
||||
/// </summary>
|
||||
public string PropertyName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 字段数据长度
|
||||
/// </summary>
|
||||
public int ColumnLength { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 数据库字段名(首字母小写)
|
||||
/// </summary>
|
||||
public string LowerPropertyName => string.IsNullOrWhiteSpace(PropertyName) ? null : PropertyName[..1].ToLower() + PropertyName[1..];
|
||||
|
||||
/// <summary>
|
||||
/// 字段描述
|
||||
/// </summary>
|
||||
public string ColumnComment { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// .NET类型
|
||||
/// </summary>
|
||||
public string NetType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 数据库中类型(物理类型)
|
||||
/// </summary>
|
||||
public string DataType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 字段数据默认值
|
||||
/// </summary>
|
||||
public string DefaultValue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 可空.NET类型
|
||||
/// </summary>
|
||||
public string NullableNetType => Regex.IsMatch(NetType ?? "", "(.*?Enum|bool|char|int|long|double|float|decimal)[?]?") ? NetType.TrimEnd('?') + "?" : NetType;
|
||||
|
||||
/// <summary>
|
||||
/// 作用类型(字典)
|
||||
/// </summary>
|
||||
public string EffectType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 外键库标识
|
||||
/// </summary>
|
||||
public string FkConfigId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 外键实体名称
|
||||
/// </summary>
|
||||
public string FkEntityName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 外键表名称
|
||||
/// </summary>
|
||||
public string FkTableName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 外键实体名称(首字母小写)
|
||||
/// </summary>
|
||||
public string LowerFkEntityName => string.IsNullOrWhiteSpace(FkEntityName) ? null : FkEntityName[..1].ToLower() + FkEntityName[1..];
|
||||
|
||||
/// <summary>
|
||||
/// 外键链接字段
|
||||
/// </summary>
|
||||
public string FkLinkColumnName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 外键显示字段
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonIgnore]
|
||||
[System.Text.Json.Serialization.JsonIgnore]
|
||||
public string FkDisplayColumns { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 外键显示字段
|
||||
/// </summary>
|
||||
public List<string> FkDisplayColumnList { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 外键显示字段(首字母小写)
|
||||
/// </summary>
|
||||
public List<string> LowerFkDisplayColumnsList => FkDisplayColumnList?.Select(name => name[..1].ToLower() + name[1..]).ToList();
|
||||
|
||||
/// <summary>
|
||||
/// 外键显示字段.NET类型
|
||||
/// </summary>
|
||||
public string FkColumnNetType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 父级字段
|
||||
/// </summary>
|
||||
public string PidColumn { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 字典code
|
||||
/// </summary>
|
||||
public string DictTypeCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 查询方式
|
||||
/// </summary>
|
||||
public string QueryType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否是查询条件
|
||||
/// </summary>
|
||||
public string WhetherQuery { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 列表是否缩进(字典)
|
||||
/// </summary>
|
||||
public string WhetherRetract { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否必填(字典)
|
||||
/// </summary>
|
||||
public string WhetherRequired { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否可排序(字典)
|
||||
/// </summary>
|
||||
public string WhetherSortable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 列表显示
|
||||
/// </summary>
|
||||
public string WhetherTable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 增改
|
||||
/// </summary>
|
||||
public string WhetherAddUpdate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 导入
|
||||
/// </summary>
|
||||
public string WhetherImport { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否是通用字段
|
||||
/// </summary>
|
||||
public string WhetherCommon { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 排序
|
||||
/// </summary>
|
||||
public int OrderNo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否是选择器控件
|
||||
/// </summary>
|
||||
public bool IsSelectorEffectType => Regex.IsMatch(EffectType ?? "", "Selector$|ForeignKey", RegexOptions.IgnoreCase);
|
||||
|
||||
/// <summary>
|
||||
/// 去掉尾部Id的属性名
|
||||
/// </summary>
|
||||
public string PropertyNameTrimEndId => PropertyName.TrimEnd("Id");
|
||||
|
||||
/// <summary>
|
||||
/// 去掉尾部Id的属性名
|
||||
/// </summary>
|
||||
public string LowerPropertyNameTrimEndId => LowerPropertyName.TrimEnd("Id");
|
||||
|
||||
/// <summary>
|
||||
/// 扩展属性名称
|
||||
/// </summary>
|
||||
public string ExtendedPropertyName => EffectType switch
|
||||
{
|
||||
"ForeignKey" => $"{PropertyName.TrimEnd("Id")}FkDisplayName",
|
||||
"ApiTreeSelector" => $"{PropertyName.TrimEnd("Id")}DisplayName",
|
||||
"DictSelector" => $"{PropertyName.TrimEnd("Id")}DictLabel",
|
||||
"Upload" => $"{PropertyName.TrimEnd("Id")}Attachment",
|
||||
"Upload_SingleFile" => $"{PropertyName.TrimEnd("Id")}Attachment",
|
||||
_ => PropertyName
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// 首字母小写的扩展属性名称
|
||||
/// </summary>
|
||||
public string LowerExtendedPropertyName
|
||||
{
|
||||
get
|
||||
{
|
||||
var displayPropertyName = ExtendedPropertyName;
|
||||
if (string.IsNullOrWhiteSpace(displayPropertyName)) return null;
|
||||
return displayPropertyName[..1].ToLower() + displayPropertyName[1..];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取外键显示值语句
|
||||
/// </summary>
|
||||
/// <param name="tableAlias">表别名</param>
|
||||
/// <param name="separator">多字段时的连接符</param>
|
||||
/// <returns></returns>
|
||||
public string GetDisplayColumn(string tableAlias, string separator = "-") => "$\"" + string.Join(separator, FkDisplayColumnList?.Select(name => $"{{{tableAlias}.{name}}}") ?? new List<string>()) + "\"";
|
||||
}
|
||||
@@ -1,199 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core.Service;
|
||||
|
||||
/// <summary>
|
||||
/// 代码生成参数类
|
||||
/// </summary>
|
||||
public class CodeGenInput : BasePageInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 作者姓名
|
||||
/// </summary>
|
||||
public virtual string AuthorName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 类名
|
||||
/// </summary>
|
||||
public virtual string ClassName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否移除表前缀
|
||||
/// </summary>
|
||||
public virtual string TablePrefix { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 库定位器名
|
||||
/// </summary>
|
||||
public virtual string ConfigId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 数据库名(保留字段)
|
||||
/// </summary>
|
||||
public virtual string DbName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 数据库类型
|
||||
/// </summary>
|
||||
public virtual string DbType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 数据库链接
|
||||
/// </summary>
|
||||
public virtual string ConnectionString { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 生成方式
|
||||
/// </summary>
|
||||
public virtual string GenerateType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 数据库表名
|
||||
/// </summary>
|
||||
public virtual string TableName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 命名空间
|
||||
/// </summary>
|
||||
public virtual string NameSpace { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 业务名(业务代码包名称)
|
||||
/// </summary>
|
||||
public virtual string BusName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 功能名(数据库表名称)
|
||||
/// </summary>
|
||||
public virtual string TableComment { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 表唯一字段
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonIgnore]
|
||||
[System.Text.Json.Serialization.JsonIgnore]
|
||||
public virtual string TableUniqueConfig { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 表唯一字段列表
|
||||
/// </summary>
|
||||
public virtual List<TableUniqueConfigItem> TableUniqueList { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 菜单应用分类(应用编码)
|
||||
/// </summary>
|
||||
public virtual string MenuApplication { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否生成菜单
|
||||
/// </summary>
|
||||
public virtual bool GenerateMenu { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 菜单父级
|
||||
/// </summary>
|
||||
public virtual long? MenuPid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 菜单图标
|
||||
/// </summary>
|
||||
public virtual string MenuIcon { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 页面目录
|
||||
/// </summary>
|
||||
public virtual string PagePath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 支持打印类型
|
||||
/// </summary>
|
||||
public virtual string PrintType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 打印模版名称
|
||||
/// </summary>
|
||||
public virtual string PrintName { get; set; }
|
||||
}
|
||||
|
||||
public class AddCodeGenInput : CodeGenInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 数据库表名
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "数据库表名不能为空")]
|
||||
public override string TableName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 业务名(业务代码包名称)
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "业务名不能为空")]
|
||||
public override string BusName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 命名空间
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "命名空间不能为空")]
|
||||
public override string NameSpace { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 作者姓名
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "作者姓名不能为空")]
|
||||
public override string AuthorName { get; set; }
|
||||
|
||||
///// <summary>
|
||||
///// 类名
|
||||
///// </summary>
|
||||
//[Required(ErrorMessage = "类名不能为空")]
|
||||
//public override string ClassName { get; set; }
|
||||
|
||||
///// <summary>
|
||||
///// 是否移除表前缀
|
||||
///// </summary>
|
||||
//[Required(ErrorMessage = "是否移除表前缀不能为空")]
|
||||
//public override string TablePrefix { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 生成方式
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "生成方式不能为空")]
|
||||
public override string GenerateType { get; set; }
|
||||
|
||||
///// <summary>
|
||||
///// 功能名(数据库表名称)
|
||||
///// </summary>
|
||||
//[Required(ErrorMessage = "数据库表名不能为空")]
|
||||
//public override string TableComment { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否生成菜单
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "是否生成菜单不能为空")]
|
||||
public override bool GenerateMenu { get; set; }
|
||||
}
|
||||
|
||||
public class DeleteCodeGenInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 代码生成器Id
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "代码生成器Id不能为空")]
|
||||
public long Id { get; set; }
|
||||
}
|
||||
|
||||
public class UpdateCodeGenInput : AddCodeGenInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 代码生成器Id
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "代码生成器Id不能为空")]
|
||||
public long Id { get; set; }
|
||||
}
|
||||
|
||||
public class QueryCodeGenInput : DeleteCodeGenInput
|
||||
{
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core.Service;
|
||||
|
||||
/// <summary>
|
||||
/// 代码生成参数类
|
||||
/// </summary>
|
||||
public class CodeGenOutput
|
||||
{
|
||||
/// <summary>
|
||||
/// 代码生成器Id
|
||||
/// </summary>
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 作者姓名
|
||||
/// </summary>
|
||||
public string AuthorName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 类名
|
||||
/// </summary>
|
||||
public string ClassName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否移除表前缀
|
||||
/// </summary>
|
||||
public string TablePrefix { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 生成方式
|
||||
/// </summary>
|
||||
public string GenerateType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 数据库表名
|
||||
/// </summary>
|
||||
public string TableName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 包名
|
||||
/// </summary>
|
||||
public string PackageName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 业务名(业务代码包名称)
|
||||
/// </summary>
|
||||
public string BusName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 功能名(数据库表名称)
|
||||
/// </summary>
|
||||
public string TableComment { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 菜单应用分类(应用编码)
|
||||
/// </summary>
|
||||
public string MenuApplication { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否生成菜单
|
||||
/// </summary>
|
||||
public bool GenerateMenu { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 菜单父级
|
||||
/// </summary>
|
||||
public long? MenuPid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 支持打印类型
|
||||
/// </summary>
|
||||
public string PrintType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 打印模版名称
|
||||
/// </summary>
|
||||
public string PrintName { get; set; }
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core.Service;
|
||||
|
||||
/// <summary>
|
||||
/// 数据库表列
|
||||
/// </summary>
|
||||
public class ColumnOuput
|
||||
{
|
||||
/// <summary>
|
||||
/// 字段名
|
||||
/// </summary>
|
||||
public string ColumnName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 实体的Property名
|
||||
/// </summary>
|
||||
public string PropertyName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 字段数据长度
|
||||
/// </summary>
|
||||
public int ColumnLength { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 数据库中类型
|
||||
/// </summary>
|
||||
public string DataType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 字段数据默认值
|
||||
/// </summary>
|
||||
public string DefaultValue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否为主键
|
||||
/// </summary>
|
||||
public bool IsPrimarykey { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否允许为空
|
||||
/// </summary>
|
||||
public bool IsNullable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// .NET字段类型
|
||||
/// </summary>
|
||||
public string NetType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 字典编码
|
||||
/// </summary>
|
||||
public string DictTypeCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 字段描述
|
||||
/// </summary>
|
||||
public string ColumnComment { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 主外键
|
||||
/// </summary>
|
||||
public string ColumnKey { get; set; }
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core.Service;
|
||||
|
||||
/// <summary>
|
||||
/// 数据库
|
||||
/// </summary>
|
||||
public class DatabaseOutput
|
||||
{
|
||||
/// <summary>
|
||||
/// 库定位器名
|
||||
/// </summary>
|
||||
public string ConfigId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 库名
|
||||
/// </summary>
|
||||
public string DbNickName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 数据库类型
|
||||
/// </summary>
|
||||
public SqlSugar.DbType DbType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 数据库连接字符串
|
||||
/// </summary>
|
||||
public string ConnectionString { get; set; }
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core.Service;
|
||||
|
||||
/// <summary>
|
||||
/// 数据库表
|
||||
/// </summary>
|
||||
public class TableOutput
|
||||
{
|
||||
/// <summary>
|
||||
/// 库定位器名
|
||||
/// </summary>
|
||||
public string ConfigId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 表名(字母形式的)
|
||||
/// </summary>
|
||||
public string TableName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 实体名称
|
||||
/// </summary>
|
||||
public string EntityName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建时间
|
||||
/// </summary>
|
||||
public string CreateTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 更新时间
|
||||
/// </summary>
|
||||
public string UpdateTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 表名称描述(功能名)
|
||||
/// </summary>
|
||||
public string TableComment { get; set; }
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core.Service;
|
||||
|
||||
/// <summary>
|
||||
/// 表唯一配置项
|
||||
/// </summary>
|
||||
public class TableUniqueConfigItem
|
||||
{
|
||||
/// <summary>
|
||||
/// 字段列表
|
||||
/// </summary>
|
||||
public List<string> Columns { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 描述信息
|
||||
/// </summary>
|
||||
public string Message { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 格式化查询条件
|
||||
/// </summary>
|
||||
/// <param name="separator">分隔符</param>
|
||||
/// <param name="format">模板字符串</param>
|
||||
/// <returns></returns>
|
||||
public string Format(string separator, string format) => string.Join(separator, Columns.Select(name => string.Format(format, name)));
|
||||
}
|
||||
@@ -1,256 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core.Service;
|
||||
|
||||
/// <summary>
|
||||
/// 系统代码生成配置服务 🧩
|
||||
/// </summary>
|
||||
[ApiDescriptionSettings(Order = 260)]
|
||||
public class SysCodeGenConfigService : IDynamicApiController, ITransient
|
||||
{
|
||||
private readonly ISqlSugarClient _db;
|
||||
|
||||
public SysCodeGenConfigService(ISqlSugarClient db)
|
||||
{
|
||||
_db = db;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取代码生成配置列表 🔖
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("获取代码生成配置列表")]
|
||||
public async Task<List<CodeGenConfig>> GetList([FromQuery] CodeGenConfig input)
|
||||
{
|
||||
return await _db.Queryable<SysCodeGenConfig>()
|
||||
.Where(u => u.CodeGenId == input.CodeGenId)
|
||||
.Select<CodeGenConfig>()
|
||||
.Mapper(u =>
|
||||
{
|
||||
u.NetType = (u.EffectType == "EnumSelector" ? u.DictTypeCode : u.NetType);
|
||||
u.FkDisplayColumnList = u.FkDisplayColumns?.Split(",").ToList();
|
||||
})
|
||||
.OrderBy(u => new { u.OrderNo, u.Id })
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新代码生成配置 🔖
|
||||
/// </summary>
|
||||
/// <param name="inputList"></param>
|
||||
/// <returns></returns>
|
||||
[ApiDescriptionSettings(Name = "Update"), HttpPost]
|
||||
[DisplayName("更新代码生成配置")]
|
||||
public async Task UpdateCodeGenConfig(List<CodeGenConfig> inputList)
|
||||
{
|
||||
if (inputList == null || inputList.Count < 1) return;
|
||||
inputList.ForEach(e =>
|
||||
{
|
||||
e.FkDisplayColumns = e.FkDisplayColumnList?.Count > 0 ? string.Join(",", e.FkDisplayColumnList) : null;
|
||||
});
|
||||
await _db.Updateable(inputList.Adapt<List<SysCodeGenConfig>>())
|
||||
.IgnoreColumns(u => new { u.ColumnLength, u.ColumnName, u.PropertyName })
|
||||
.ExecuteCommandAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除代码生成配置
|
||||
/// </summary>
|
||||
/// <param name="codeGenId"></param>
|
||||
/// <returns></returns>
|
||||
[NonAction]
|
||||
public async Task DeleteCodeGenConfig(long codeGenId)
|
||||
{
|
||||
await _db.Deleteable<SysCodeGenConfig>().Where(u => u.CodeGenId == codeGenId).ExecuteCommandAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取代码生成配置详情 🔖
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("获取代码生成配置详情")]
|
||||
public async Task<SysCodeGenConfig> GetDetail([FromQuery] CodeGenConfig input)
|
||||
{
|
||||
return await _db.Queryable<SysCodeGenConfig>().FirstAsync(u => u.Id == input.Id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 批量增加代码生成配置
|
||||
/// </summary>
|
||||
/// <param name="tableColumnOutputList"></param>
|
||||
/// <param name="codeGenerate"></param>
|
||||
[NonAction]
|
||||
public void AddList(List<ColumnOuput> tableColumnOutputList, SysCodeGen codeGenerate)
|
||||
{
|
||||
if (tableColumnOutputList == null) return;
|
||||
|
||||
var codeGenConfigs = new List<SysCodeGenConfig>();
|
||||
var orderNo = 100;
|
||||
foreach (var tableColumn in tableColumnOutputList)
|
||||
{
|
||||
var codeGenConfig = new SysCodeGenConfig();
|
||||
|
||||
var yesOrNo = YesNoEnum.Y.ToString();
|
||||
if (Convert.ToBoolean(tableColumn.ColumnKey)) yesOrNo = YesNoEnum.N.ToString();
|
||||
|
||||
if (CodeGenUtil.IsCommonColumn(tableColumn.PropertyName))
|
||||
{
|
||||
codeGenConfig.WhetherCommon = YesNoEnum.Y.ToString();
|
||||
yesOrNo = YesNoEnum.N.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
codeGenConfig.WhetherCommon = YesNoEnum.N.ToString();
|
||||
}
|
||||
|
||||
codeGenConfig.CodeGenId = codeGenerate.Id;
|
||||
codeGenConfig.ColumnName = tableColumn.ColumnName; // 字段名
|
||||
codeGenConfig.PropertyName = tableColumn.PropertyName;// 实体属性名
|
||||
codeGenConfig.ColumnLength = tableColumn.ColumnLength;// 长度
|
||||
codeGenConfig.ColumnComment = tableColumn.ColumnComment;
|
||||
codeGenConfig.NetType = tableColumn.NetType;
|
||||
codeGenConfig.DefaultValue = tableColumn.DefaultValue;
|
||||
codeGenConfig.WhetherRetract = YesNoEnum.N.ToString();
|
||||
|
||||
// 生成代码时,主键并不是必要输入项,故一定要排除主键字段
|
||||
codeGenConfig.WhetherRequired = (tableColumn.IsNullable || tableColumn.IsPrimarykey) ? YesNoEnum.N.ToString() : YesNoEnum.Y.ToString();
|
||||
codeGenConfig.WhetherQuery = yesOrNo;
|
||||
codeGenConfig.WhetherImport = yesOrNo;
|
||||
codeGenConfig.WhetherAddUpdate = yesOrNo;
|
||||
codeGenConfig.WhetherTable = yesOrNo;
|
||||
|
||||
codeGenConfig.ColumnKey = tableColumn.ColumnKey;
|
||||
|
||||
codeGenConfig.DataType = tableColumn.DataType;
|
||||
codeGenConfig.EffectType = CodeGenUtil.DataTypeToEff(codeGenConfig.NetType);
|
||||
codeGenConfig.QueryType = GetDefaultQueryType(codeGenConfig); // QueryTypeEnum.eq.ToString();
|
||||
codeGenConfig.OrderNo = orderNo;
|
||||
codeGenConfigs.Add(codeGenConfig);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(tableColumn.DictTypeCode))
|
||||
{
|
||||
codeGenConfig.QueryType = "==";
|
||||
codeGenConfig.DictTypeCode = tableColumn.DictTypeCode;
|
||||
codeGenConfig.EffectType = tableColumn.DictTypeCode.EndsWith("Enum") ? "EnumSelector" : "DictSelector";
|
||||
}
|
||||
|
||||
orderNo += 10; // 每个配置排序间隔10
|
||||
}
|
||||
// 多库代码生成---这里要切回主库
|
||||
var provider = _db.AsTenant().GetConnectionScope(SqlSugarConst.MainConfigId);
|
||||
provider.Insertable(codeGenConfigs).ExecuteCommand();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 批量更新代码字段:先删除再新增,会保留历史字段操作类型
|
||||
/// </summary>
|
||||
/// <param name="tableColumnOutputList"></param>
|
||||
/// <param name="codeGenId"></param>
|
||||
[NonAction]
|
||||
public async Task UpdateList(List<ColumnOuput> tableColumnOutputList, long codeGenId)
|
||||
{
|
||||
if (tableColumnOutputList == null) return;
|
||||
|
||||
//获取历史数据
|
||||
var oldList = await GetList(new CodeGenConfig() { CodeGenId = codeGenId, });
|
||||
//删除历史数据
|
||||
await DeleteCodeGenConfig(codeGenId);
|
||||
|
||||
var codeGenConfigs = new List<SysCodeGenConfig>();
|
||||
var orderNo = 100;
|
||||
foreach (var tableColumn in tableColumnOutputList)
|
||||
{
|
||||
var oldItem = oldList.FirstOrDefault(u => u.ColumnName == tableColumn.ColumnName);
|
||||
|
||||
var codeGenConfig = new SysCodeGenConfig();
|
||||
|
||||
var yesOrNo = YesNoEnum.Y.ToString();
|
||||
if (Convert.ToBoolean(tableColumn.ColumnKey)) yesOrNo = YesNoEnum.N.ToString();
|
||||
|
||||
if (CodeGenUtil.IsCommonColumn(tableColumn.PropertyName))
|
||||
{
|
||||
codeGenConfig.WhetherCommon = YesNoEnum.Y.ToString();
|
||||
yesOrNo = YesNoEnum.N.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
codeGenConfig.WhetherCommon = YesNoEnum.N.ToString();
|
||||
}
|
||||
|
||||
codeGenConfig.CodeGenId = codeGenId;
|
||||
codeGenConfig.ColumnName = tableColumn.ColumnName; // 字段名
|
||||
codeGenConfig.PropertyName = tableColumn.PropertyName;// 实体属性名
|
||||
codeGenConfig.ColumnLength = tableColumn.ColumnLength;// 长度
|
||||
codeGenConfig.ColumnComment = tableColumn.ColumnComment;
|
||||
codeGenConfig.NetType = tableColumn.NetType;
|
||||
codeGenConfig.DefaultValue = tableColumn.DefaultValue;
|
||||
codeGenConfig.WhetherRetract = YesNoEnum.N.ToString();
|
||||
|
||||
// 生成代码时,主键并不是必要输入项,故一定要排除主键字段
|
||||
codeGenConfig.WhetherRequired = (tableColumn.IsNullable || tableColumn.IsPrimarykey) ? YesNoEnum.N.ToString() : YesNoEnum.Y.ToString();
|
||||
codeGenConfig.WhetherQuery = yesOrNo;
|
||||
codeGenConfig.WhetherImport = yesOrNo;
|
||||
codeGenConfig.WhetherAddUpdate = yesOrNo;
|
||||
codeGenConfig.WhetherTable = yesOrNo;
|
||||
|
||||
codeGenConfig.ColumnKey = tableColumn.ColumnKey;
|
||||
|
||||
codeGenConfig.DataType = tableColumn.DataType;
|
||||
codeGenConfig.EffectType = CodeGenUtil.DataTypeToEff(codeGenConfig.NetType);
|
||||
codeGenConfig.QueryType = GetDefaultQueryType(codeGenConfig); // QueryTypeEnum.eq.ToString();
|
||||
codeGenConfig.OrderNo = orderNo;
|
||||
|
||||
if (oldItem != null)
|
||||
{
|
||||
//如果历史存在,则继承
|
||||
codeGenConfig.WhetherQuery = oldItem.WhetherQuery;
|
||||
codeGenConfig.WhetherImport = oldItem.WhetherImport;
|
||||
codeGenConfig.WhetherAddUpdate = oldItem.WhetherAddUpdate;
|
||||
codeGenConfig.WhetherTable = oldItem.WhetherTable;
|
||||
|
||||
codeGenConfig.EffectType = oldItem.EffectType;
|
||||
codeGenConfig.FkConfigId = oldItem.FkConfigId;
|
||||
codeGenConfig.FkEntityName = oldItem.FkEntityName;
|
||||
codeGenConfig.FkTableName = oldItem.FkTableName;
|
||||
codeGenConfig.FkDisplayColumns = oldItem.FkDisplayColumns;
|
||||
codeGenConfig.FkLinkColumnName = oldItem.FkLinkColumnName;
|
||||
codeGenConfig.FkColumnNetType = oldItem.FkColumnNetType;
|
||||
}
|
||||
|
||||
codeGenConfigs.Add(codeGenConfig);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(tableColumn.DictTypeCode))
|
||||
{
|
||||
codeGenConfig.QueryType = "==";
|
||||
codeGenConfig.DictTypeCode = tableColumn.DictTypeCode;
|
||||
codeGenConfig.EffectType = tableColumn.DictTypeCode.EndsWith("Enum") ? "EnumSelector" : "DictSelector";
|
||||
}
|
||||
|
||||
orderNo += 10; // 每个配置排序间隔10
|
||||
}
|
||||
// 多库代码生成---这里要切回主库
|
||||
var provider = _db.AsTenant().GetConnectionScope(SqlSugarConst.MainConfigId);
|
||||
provider.Insertable(codeGenConfigs).ExecuteCommand();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 默认查询类型
|
||||
/// </summary>
|
||||
/// <param name="codeGenConfig"></param>
|
||||
/// <returns></returns>
|
||||
private static string GetDefaultQueryType(SysCodeGenConfig codeGenConfig)
|
||||
{
|
||||
return (codeGenConfig.NetType?.TrimEnd('?')) switch
|
||||
{
|
||||
"string" => "like",
|
||||
"DateTime" => "~",
|
||||
_ => "==",
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,825 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
using System.IO.Compression;
|
||||
|
||||
namespace Admin.NET.Core.Service;
|
||||
|
||||
/// <summary>
|
||||
/// 系统代码生成器服务 🧩
|
||||
/// </summary>
|
||||
[ApiDescriptionSettings(Order = 270)]
|
||||
public class SysCodeGenService : IDynamicApiController, ITransient
|
||||
{
|
||||
private readonly ISqlSugarClient _db;
|
||||
|
||||
private readonly SysCodeGenConfigService _codeGenConfigService;
|
||||
private readonly DbConnectionOptions _dbConnectionOptions;
|
||||
private readonly CodeGenOptions _codeGenOptions;
|
||||
private readonly SysMenuService _sysMenuService;
|
||||
private readonly IViewEngine _viewEngine;
|
||||
private readonly UserManager _userManager;
|
||||
|
||||
public SysCodeGenService(ISqlSugarClient db,
|
||||
IOptions<DbConnectionOptions> dbConnectionOptions,
|
||||
SysCodeGenConfigService codeGenConfigService,
|
||||
IOptions<CodeGenOptions> codeGenOptions,
|
||||
SysMenuService sysMenuService,
|
||||
UserManager userManager,
|
||||
IViewEngine viewEngine)
|
||||
{
|
||||
_db = db;
|
||||
_viewEngine = viewEngine;
|
||||
_userManager = userManager;
|
||||
_sysMenuService = sysMenuService;
|
||||
_codeGenOptions = codeGenOptions.Value;
|
||||
_codeGenConfigService = codeGenConfigService;
|
||||
_dbConnectionOptions = dbConnectionOptions.Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取代码生成分页列表 🔖
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("获取代码生成分页列表")]
|
||||
public async Task<SqlSugarPagedList<SysCodeGen>> Page(CodeGenInput input)
|
||||
{
|
||||
return await _db.Queryable<SysCodeGen>()
|
||||
.WhereIF(!string.IsNullOrWhiteSpace(input.TableName), u => u.TableName.Contains(input.TableName.Trim()))
|
||||
.WhereIF(!string.IsNullOrWhiteSpace(input.BusName), u => u.BusName.Contains(input.BusName.Trim()))
|
||||
.ToPagedListAsync(input.Page, input.PageSize);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 增加代码生成 🔖
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[ApiDescriptionSettings(Name = "Add"), HttpPost]
|
||||
[DisplayName("增加代码生成")]
|
||||
public async Task AddCodeGen(AddCodeGenInput input)
|
||||
{
|
||||
var isExist = await _db.Queryable<SysCodeGen>().Where(u => u.TableName == input.TableName).AnyAsync();
|
||||
if (isExist) throw Oops.Oh(ErrorCodeEnum.D1400);
|
||||
|
||||
if (input.TableUniqueList?.Count > 0) input.TableUniqueConfig = JSON.Serialize(input.TableUniqueList);
|
||||
|
||||
var codeGen = input.Adapt<SysCodeGen>();
|
||||
var newCodeGen = await _db.Insertable(codeGen).ExecuteReturnEntityAsync();
|
||||
|
||||
// 增加配置表
|
||||
_codeGenConfigService.AddList(GetColumnList(input), newCodeGen);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新代码生成 🔖
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[ApiDescriptionSettings(Name = "Update"), HttpPost]
|
||||
[DisplayName("更新代码生成")]
|
||||
public async Task UpdateCodeGen(UpdateCodeGenInput input)
|
||||
{
|
||||
var isExist = await _db.Queryable<SysCodeGen>().AnyAsync(u => u.TableName == input.TableName && u.Id != input.Id);
|
||||
if (isExist) throw Oops.Oh(ErrorCodeEnum.D1400);
|
||||
|
||||
var oldRecord = await _db.Queryable<SysCodeGen>().FirstAsync(u => u.Id == input.Id);
|
||||
try
|
||||
{
|
||||
// 开启事务
|
||||
_db.AsTenant().BeginTran();
|
||||
if (input.GenerateMenu)
|
||||
{
|
||||
var oldTitle = $"{oldRecord.BusName}管理";
|
||||
var newTitle = $"{input.BusName}管理";
|
||||
var updateObj = await _db.Queryable<SysMenu>().FirstAsync(u => u.Title == oldTitle);
|
||||
if (updateObj != null)
|
||||
{
|
||||
updateObj.Title = newTitle;
|
||||
var result = _db.Updateable(updateObj).UpdateColumns(it => new { it.Title }).ExecuteCommand();
|
||||
_sysMenuService.DeleteMenuCache();
|
||||
}
|
||||
}
|
||||
if (input.TableUniqueList?.Count > 0) input.TableUniqueConfig = JSON.Serialize(input.TableUniqueList);
|
||||
var codeGen = input.Adapt<SysCodeGen>();
|
||||
await _db.Updateable(codeGen).ExecuteCommandAsync();
|
||||
|
||||
// 仅当数据表名称发生了变化,才更新配置表
|
||||
//if (oldRecord.TableName != input.TableName)
|
||||
//{
|
||||
await _codeGenConfigService.DeleteCodeGenConfig(codeGen.Id);
|
||||
_codeGenConfigService.AddList(GetColumnList(input.Adapt<AddCodeGenInput>()), codeGen);
|
||||
//}
|
||||
_db.AsTenant().CommitTran();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_db.AsTenant().RollbackTran();
|
||||
throw Oops.Oh(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 同步代码字段(保留历史作用类型) 🔖
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[ApiDescriptionSettings(Name = "SyncField"), HttpPost]
|
||||
[DisplayName("同步代码字段")]
|
||||
public async Task SyncCodeFieldGen(UpdateCodeGenInput input)
|
||||
{
|
||||
var isExist = await _db.Queryable<SysCodeGen>().AnyAsync(u => u.TableName == input.TableName && u.Id != input.Id);
|
||||
if (isExist) throw Oops.Oh(ErrorCodeEnum.D1400);
|
||||
try
|
||||
{
|
||||
// 开启事务
|
||||
_db.AsTenant().BeginTran();
|
||||
await _codeGenConfigService.UpdateList(GetColumnList(input.Adapt<AddCodeGenInput>()), input.Id);
|
||||
_db.AsTenant().CommitTran();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_db.AsTenant().RollbackTran();
|
||||
throw Oops.Oh(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除代码生成 🔖
|
||||
/// </summary>
|
||||
/// <param name="inputs"></param>
|
||||
/// <returns></returns>
|
||||
[ApiDescriptionSettings(Name = "Delete"), HttpPost]
|
||||
[DisplayName("删除代码生成")]
|
||||
public async Task DeleteCodeGen(List<DeleteCodeGenInput> inputs)
|
||||
{
|
||||
if (inputs == null || inputs.Count < 1) return;
|
||||
|
||||
var codeGenConfigTaskList = new List<Task>();
|
||||
inputs.ForEach(u =>
|
||||
{
|
||||
_db.Deleteable<SysCodeGen>().In(u.Id).ExecuteCommand();
|
||||
|
||||
// 删除配置表
|
||||
codeGenConfigTaskList.Add(_codeGenConfigService.DeleteCodeGenConfig(u.Id));
|
||||
});
|
||||
await Task.WhenAll(codeGenConfigTaskList);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取代码生成详情 🔖
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("获取代码生成详情")]
|
||||
public async Task<SysCodeGen> GetDetail([FromQuery] QueryCodeGenInput input)
|
||||
{
|
||||
return await _db.Queryable<SysCodeGen>().SingleAsync(u => u.Id == input.Id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取数据库库集合 🔖
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[DisplayName("获取数据库库集合")]
|
||||
public async Task<List<DatabaseOutput>> GetDatabaseList()
|
||||
{
|
||||
var dbConfigs = _dbConnectionOptions.ConnectionConfigs;
|
||||
return await Task.FromResult(dbConfigs.Adapt<List<DatabaseOutput>>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取数据库表(实体)集合 🔖
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[DisplayName("获取数据库表(实体)集合")]
|
||||
public async Task<List<TableOutput>> GetTableList(string configId = SqlSugarConst.MainConfigId)
|
||||
{
|
||||
var provider = _db.AsTenant().GetConnectionScope(configId);
|
||||
var dbTableInfos = provider.DbMaintenance.GetTableInfoList(false); // 不能走缓存,否则切库不起作用
|
||||
var config = _dbConnectionOptions.ConnectionConfigs.FirstOrDefault(u => configId.Equals(u.ConfigId));
|
||||
|
||||
// var dbTableNames = dbTableInfos.Select(u => u.Name.ToLower()).ToList();
|
||||
IEnumerable<EntityInfo> entityInfos = await GetEntityInfos(configId);
|
||||
|
||||
var tableOutputList = new List<TableOutput>();
|
||||
foreach (var item in entityInfos)
|
||||
{
|
||||
var tbConfigId = item.Type.GetCustomAttribute<TenantAttribute>()?.configId as string ?? SqlSugarConst.MainConfigId;
|
||||
if (item.Type.IsDefined(typeof(LogTableAttribute))) tbConfigId = SqlSugarConst.LogConfigId;
|
||||
if (tbConfigId != configId) continue;
|
||||
|
||||
var table = dbTableInfos.FirstOrDefault(u => string.Equals(u.Name, (config!.DbSettings.EnableUnderLine ? item.DbTableName.ToUnderLine() : item.DbTableName), StringComparison.CurrentCultureIgnoreCase));
|
||||
if (table == null) continue;
|
||||
tableOutputList.Add(new TableOutput
|
||||
{
|
||||
ConfigId = configId,
|
||||
EntityName = item.EntityName,
|
||||
TableName = table.Name,
|
||||
TableComment = item.TableDescription
|
||||
});
|
||||
}
|
||||
return tableOutputList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据表名获取列集合 🔖
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[DisplayName("根据表名获取列集合")]
|
||||
public List<ColumnOuput> GetColumnListByTableName([Required] string tableName, string configId = SqlSugarConst.MainConfigId)
|
||||
{
|
||||
// 切库---多库代码生成用
|
||||
var provider = _db.AsTenant().GetConnectionScope(configId);
|
||||
var config = _dbConnectionOptions.ConnectionConfigs.FirstOrDefault(u => u.ConfigId.ToString() == configId) ?? throw Oops.Oh(ErrorCodeEnum.D1401);
|
||||
if (config.DbSettings.EnableUnderLine) tableName = tableName.ToUnderLine();
|
||||
// 获取实体类型属性
|
||||
var entityType = provider.DbMaintenance.GetTableInfoList(false).FirstOrDefault(u => u.Name == tableName);
|
||||
if (entityType == null) return null;
|
||||
var properties = GetEntityInfos(configId).Result.First(e => e.DbTableName.EndsWithIgnoreCase(tableName)).Type.GetProperties()
|
||||
.Where(e => e.GetCustomAttribute<SugarColumn>()?.IsIgnore == false).Select(e => new
|
||||
{
|
||||
PropertyName = e.Name,
|
||||
ColumnComment = e.GetCustomAttribute<SugarColumn>()?.ColumnDescription,
|
||||
ColumnName = e.GetCustomAttribute<SugarColumn>()?.ColumnName ?? e.Name
|
||||
}).ToList();
|
||||
// 按原始类型的顺序获取所有实体类型属性(不包含导航属性,会返回null)
|
||||
var columnList = provider.DbMaintenance.GetColumnInfosByTableName(tableName).Select(u => new ColumnOuput
|
||||
{
|
||||
ColumnName = config!.DbSettings.EnableUnderLine ? u.DbColumnName.ToUnderLine() : u.DbColumnName,
|
||||
ColumnKey = u.IsPrimarykey.ToString(),
|
||||
DataType = u.DataType.ToString(),
|
||||
NetType = CodeGenUtil.ConvertDataType(u, provider.CurrentConnectionConfig.DbType),
|
||||
ColumnComment = u.ColumnDescription
|
||||
}).ToList();
|
||||
foreach (var column in columnList)
|
||||
{
|
||||
// ToLowerInvariant 将字段名转成小写再比较,避免因大小写不一致导致无法匹配(pgsql创建表会默认全小写,而我们的实体中又是大写,就会匹配不上)
|
||||
var property = properties.FirstOrDefault(e => (config!.DbSettings.EnableUnderLine ? e.ColumnName.ToUnderLine() : e.ColumnName).ToLowerInvariant() == column.ColumnName.ToLowerInvariant());
|
||||
column.ColumnComment ??= property?.ColumnComment;
|
||||
column.PropertyName = property?.PropertyName;
|
||||
}
|
||||
return columnList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取数据表列(实体属性)集合
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private List<ColumnOuput> GetColumnList([FromQuery] AddCodeGenInput input)
|
||||
{
|
||||
var entityType = GetEntityInfos(input.ConfigId).GetAwaiter().GetResult().FirstOrDefault(u => u.EntityName == input.TableName);
|
||||
if (entityType == null) return null;
|
||||
|
||||
var config = _dbConnectionOptions.ConnectionConfigs.FirstOrDefault(u => u.ConfigId.ToString() == input.ConfigId);
|
||||
var dbTableName = config!.DbSettings.EnableUnderLine ? entityType.DbTableName.ToUnderLine() : entityType.DbTableName;
|
||||
|
||||
// 切库---多库代码生成用
|
||||
var provider = _db.AsTenant().GetConnectionScope(!string.IsNullOrEmpty(input.ConfigId) ? input.ConfigId : SqlSugarConst.MainConfigId);
|
||||
|
||||
var entityBasePropertyNames = CodeGenUtil.GetPropertyInfoArray(typeof(EntityBaseTenant))?.Select(p => p.Name).ToArray();
|
||||
var columnInfos = provider.DbMaintenance.GetColumnInfosByTableName(dbTableName, false);
|
||||
var result = columnInfos.Select(u => new ColumnOuput
|
||||
{
|
||||
// 转下划线后的列名需要再转回来(暂时不转)
|
||||
//ColumnName = config.DbSettings.EnableUnderLine ? CodeGenUtil.CamelColumnName(u.DbColumnName, entityBasePropertyNames) : u.DbColumnName,
|
||||
ColumnName = u.DbColumnName,
|
||||
ColumnLength = u.Length,
|
||||
IsPrimarykey = u.IsPrimarykey,
|
||||
IsNullable = u.IsNullable,
|
||||
ColumnKey = u.IsPrimarykey.ToString(),
|
||||
NetType = CodeGenUtil.ConvertDataType(u, provider.CurrentConnectionConfig.DbType),
|
||||
DataType = CodeGenUtil.ConvertDataType(u, provider.CurrentConnectionConfig.DbType),
|
||||
ColumnComment = string.IsNullOrWhiteSpace(u.ColumnDescription) ? u.DbColumnName : u.ColumnDescription,
|
||||
DefaultValue = u.DefaultValue,
|
||||
}).ToList();
|
||||
|
||||
// 获取实体的属性信息,赋值给PropertyName属性(CodeFirst模式应以PropertyName为实际使用名称)
|
||||
var entityProperties = entityType.Type.GetProperties();
|
||||
|
||||
for (int i = result.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var columnOutput = result[i];
|
||||
// 先找自定义字段名的,如果找不到就再找自动生成字段名的(并且过滤掉没有SugarColumn的属性)
|
||||
var propertyInfo = entityProperties.FirstOrDefault(u => string.Equals((u.GetCustomAttribute<SugarColumn>()?.ColumnName ?? ""), columnOutput.ColumnName, StringComparison.CurrentCultureIgnoreCase)) ??
|
||||
entityProperties.FirstOrDefault(u => u.GetCustomAttribute<SugarColumn>() != null && u.Name.ToLower() == (config.DbSettings.EnableUnderLine
|
||||
? CodeGenUtil.CamelColumnName(columnOutput.ColumnName, entityBasePropertyNames).ToLower()
|
||||
: columnOutput.ColumnName.ToLower()));
|
||||
if (propertyInfo != null)
|
||||
{
|
||||
columnOutput.PropertyName = propertyInfo.Name;
|
||||
columnOutput.ColumnComment = propertyInfo.GetCustomAttribute<SugarColumn>()!.ColumnDescription;
|
||||
var propertyType = Nullable.GetUnderlyingType(propertyInfo.PropertyType);
|
||||
if (propertyInfo.PropertyType.IsEnum || (propertyType?.IsEnum ?? false))
|
||||
{
|
||||
columnOutput.DictTypeCode = (propertyType ?? propertyInfo.PropertyType).Name;
|
||||
}
|
||||
else
|
||||
{
|
||||
var dict = propertyInfo.GetCustomAttribute<DictAttribute>();
|
||||
if (dict != null) columnOutput.DictTypeCode = dict.DictTypeCode;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result.RemoveAt(i); // 移除没有定义此属性的字段
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取库表信息
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private async Task<IEnumerable<EntityInfo>> GetEntityInfos(string configId)
|
||||
{
|
||||
var config = _dbConnectionOptions.ConnectionConfigs.FirstOrDefault(u => u.ConfigId.ToString() == configId) ?? throw Oops.Oh(ErrorCodeEnum.D1401);
|
||||
var entityInfos = new List<EntityInfo>();
|
||||
|
||||
var type = typeof(SugarTable);
|
||||
var types = new List<Type>();
|
||||
if (_codeGenOptions.EntityAssemblyNames != null)
|
||||
{
|
||||
types = App.EffectiveTypes.Where(c => c.IsClass)
|
||||
.Where(c => _codeGenOptions.EntityAssemblyNames.Contains(c.Assembly.GetName().Name) || _codeGenOptions.EntityAssemblyNames.Any(name => c.Assembly.GetName().Name!.Contains(name)))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
Type[] cosType = types.Where(o => IsMyAttribute(Attribute.GetCustomAttributes(o, true))).ToArray();
|
||||
|
||||
foreach (var ct in cosType)
|
||||
{
|
||||
var sugarAttribute = ct.GetCustomAttributes(type, true).FirstOrDefault();
|
||||
|
||||
var description = "";
|
||||
var des = ct.GetCustomAttributes(typeof(DescriptionAttribute), true);
|
||||
if (des.Length > 0) description = ((DescriptionAttribute)des[0]).Description;
|
||||
|
||||
var dbTableName = sugarAttribute == null || string.IsNullOrWhiteSpace(((SugarTable)sugarAttribute).TableName) ? ct.Name : ((SugarTable)sugarAttribute).TableName;
|
||||
if (config.DbSettings.EnableUnderLine) dbTableName = dbTableName.ToUnderLine();
|
||||
|
||||
entityInfos.Add(new EntityInfo
|
||||
{
|
||||
EntityName = ct.Name,
|
||||
DbTableName = dbTableName,
|
||||
TableDescription = sugarAttribute == null ? description : ((SugarTable)sugarAttribute).TableDescription,
|
||||
Type = ct
|
||||
});
|
||||
}
|
||||
return await Task.FromResult(entityInfos);
|
||||
|
||||
bool IsMyAttribute(Attribute[] o) => o.Any(a => a.GetType() == type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取程序保存位置 🔖
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[DisplayName("获取程序保存位置")]
|
||||
public List<string> GetApplicationNamespaces()
|
||||
{
|
||||
return _codeGenOptions.BackendApplicationNamespaces;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 代码生成到本地 🔖
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[UnitOfWork]
|
||||
[DisplayName("代码生成到本地")]
|
||||
public async Task<dynamic> RunLocal(SysCodeGen input)
|
||||
{
|
||||
if (string.IsNullOrEmpty(input.GenerateType))
|
||||
input.GenerateType = "200";
|
||||
|
||||
// 先删除该表已生成的菜单列表
|
||||
List<string> targetPathList;
|
||||
var zipPath = Path.Combine(App.WebHostEnvironment.WebRootPath, "CodeGen", input.TableName!);
|
||||
if (input.GenerateType.StartsWith('1'))
|
||||
{
|
||||
targetPathList = GetZipPathList(input);
|
||||
if (Directory.Exists(zipPath)) Directory.Delete(zipPath, true);
|
||||
}
|
||||
else
|
||||
targetPathList = GetTargetPathList(input);
|
||||
|
||||
var (tableFieldList, result) = await RenderTemplateAsync(input);
|
||||
var templatePathList = GetTemplatePathList(input);
|
||||
for (var i = 0; i < templatePathList.Count; i++)
|
||||
{
|
||||
var content = result.GetValueOrDefault(templatePathList[i]?.TrimEnd(".vm"));
|
||||
if (string.IsNullOrWhiteSpace(content)) continue;
|
||||
var dirPath = new DirectoryInfo(targetPathList[i]).Parent!.FullName;
|
||||
if (!Directory.Exists(dirPath)) Directory.CreateDirectory(dirPath);
|
||||
_ = File.WriteAllTextAsync(targetPathList[i], content, Encoding.UTF8);
|
||||
}
|
||||
|
||||
if (input.GenerateMenu) await AddOrUpdateMenu(input.TableName, input.BusName, input.MenuPid ?? 0, input.MenuIcon, input.PagePath, tableFieldList);
|
||||
|
||||
// 非ZIP压缩返回空
|
||||
if (!input.GenerateType.StartsWith('1')) return null;
|
||||
|
||||
// 判断是否存在同名称文件
|
||||
string downloadPath = zipPath + ".zip";
|
||||
if (File.Exists(downloadPath)) File.Delete(downloadPath);
|
||||
|
||||
// 创建zip文件并返回下载地址
|
||||
ZipFile.CreateFromDirectory(zipPath, downloadPath);
|
||||
return new { url = $"{App.HttpContext.Request.Scheme}://{App.HttpContext.Request.Host.Value}/codeGen/{input.TableName}.zip" };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取代码生成预览 🔖
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[DisplayName("获取代码生成预览")]
|
||||
public async Task<Dictionary<string, string>> Preview(SysCodeGen input)
|
||||
{
|
||||
var (_, result) = await RenderTemplateAsync(input);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 渲染模板
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
private async Task<(List<CodeGenConfig> tableFieldList, Dictionary<string, string> result)> RenderTemplateAsync(SysCodeGen input)
|
||||
{
|
||||
var tableFieldList = await _codeGenConfigService.GetList(new CodeGenConfig { CodeGenId = input.Id }); // 字段集合
|
||||
var joinTableList = tableFieldList.Where(u => u.EffectType is "Upload" or "ForeignKey" or "ApiTreeSelector").ToList(); // 需要连表查询的字段
|
||||
|
||||
var data = new CustomViewEngine
|
||||
{
|
||||
ConfigId = input.ConfigId,
|
||||
BusName = input.BusName,
|
||||
PagePath = input.PagePath,
|
||||
NameSpace = input.NameSpace,
|
||||
ClassName = input.TableName,
|
||||
PrintType = input.PrintType,
|
||||
PrintName = input.PrintName,
|
||||
AuthorName = input.AuthorName,
|
||||
ProjectLastName = input.NameSpace!.Split('.').Last(),
|
||||
LowerClassName = input.TableName!.ToFirstLetterLowerCase(),
|
||||
TableUniqueConfigList = input.TableUniqueList ?? new(),
|
||||
|
||||
TableField = tableFieldList,
|
||||
QueryWhetherList = tableFieldList.Where(u => u.WhetherQuery == "Y").ToList(),
|
||||
ImportFieldList = tableFieldList.Where(u => u.WhetherImport == "Y").ToList(),
|
||||
UploadFieldList = tableFieldList.Where(u => u.EffectType == "Upload" || u.EffectType == "Upload_SingleFile").ToList(),
|
||||
PrimaryKeyFieldList = tableFieldList.Where(c => c.ColumnKey == "True").ToList(),
|
||||
AddUpdateFieldList = tableFieldList.Where(u => u.WhetherAddUpdate == "Y").ToList(),
|
||||
ApiTreeFieldList = tableFieldList.Where(u => u.EffectType == "ApiTreeSelector").ToList(),
|
||||
DropdownFieldList = tableFieldList.Where(u => u.EffectType is "ForeignKey" or "ApiTreeSelector").ToList(),
|
||||
DefaultValueList = tableFieldList.Where(u => u.DefaultValue != null && u.DefaultValue.Length > 0).ToList(),
|
||||
|
||||
HasJoinTable = joinTableList.Count > 0,
|
||||
HasDictField = tableFieldList.Any(u => u.EffectType == "DictSelector"),
|
||||
HasEnumField = tableFieldList.Any(u => u.EffectType == "EnumSelector"),
|
||||
HasConstField = tableFieldList.Any(u => u.EffectType == "ConstSelector"),
|
||||
HasLikeQuery = tableFieldList.Any(c => c.WhetherQuery == "Y" && c.QueryType == "like")
|
||||
};
|
||||
|
||||
// 获取模板文件并替换
|
||||
var templatePathList = GetTemplatePathList();
|
||||
var templatePath = Path.Combine(App.WebHostEnvironment.WebRootPath, "template");
|
||||
|
||||
var result = new Dictionary<string, string>();
|
||||
foreach (var path in templatePathList)
|
||||
{
|
||||
var templateFilePath = Path.Combine(templatePath, path);
|
||||
if (!File.Exists(templateFilePath)) continue;
|
||||
var tContent = await File.ReadAllTextAsync(templateFilePath);
|
||||
var tResult = await _viewEngine.RunCompileFromCachedAsync(tContent, data, builderAction: builder =>
|
||||
{
|
||||
builder.AddAssemblyReferenceByName("System.Text.RegularExpressions");
|
||||
builder.AddAssemblyReferenceByName("System.Collections");
|
||||
builder.AddAssemblyReferenceByName("System.Linq");
|
||||
|
||||
builder.AddUsing("System.Text.RegularExpressions");
|
||||
builder.AddUsing("System.Collections.Generic");
|
||||
builder.AddUsing("System.Linq");
|
||||
});
|
||||
result.Add(path?.TrimEnd(".vm"), tResult);
|
||||
}
|
||||
return (tableFieldList, result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加或更新菜单
|
||||
/// </summary>
|
||||
/// <param name="className"></param>
|
||||
/// <param name="busName"></param>
|
||||
/// <param name="pid"></param>
|
||||
/// <param name="menuIcon"></param>
|
||||
/// <param name="pagePath"></param>
|
||||
/// <param name="tableFieldList"></param>
|
||||
/// <returns></returns>
|
||||
private async Task AddOrUpdateMenu(string className, string busName, long pid, string menuIcon, string pagePath, List<CodeGenConfig> tableFieldList)
|
||||
{
|
||||
var title = $"{busName}管理";
|
||||
var lowerClassName = className.ToFirstLetterLowerCase();
|
||||
var menuType = pid == 0 ? MenuTypeEnum.Dir : MenuTypeEnum.Menu;
|
||||
|
||||
// 查询是否已有主菜单
|
||||
var existingMenu = await _db.Queryable<SysMenu>()
|
||||
.Where(m => m.Title == title && m.Type == menuType && m.Pid == pid)
|
||||
.FirstAsync();
|
||||
|
||||
string parentPath = "";
|
||||
if (pid != 0)
|
||||
{
|
||||
var parent = await _db.Queryable<SysMenu>().FirstAsync(m => m.Id == pid) ?? throw Oops.Oh(ErrorCodeEnum.D1505);
|
||||
parentPath = parent.Path;
|
||||
}
|
||||
|
||||
long menuId;
|
||||
if (existingMenu == null)
|
||||
{
|
||||
// 不存在则新增
|
||||
var newMenu = new SysMenu
|
||||
{
|
||||
Pid = pid,
|
||||
Title = title,
|
||||
Type = menuType,
|
||||
Icon = menuIcon ?? "menu",
|
||||
Path = (pid == 0 ? "/" : parentPath + "/") + className.ToLower(),
|
||||
Component = pid == 0 ? "Layout" : $"/{pagePath}/{lowerClassName}/index"
|
||||
};
|
||||
menuId = await _sysMenuService.AddMenu(newMenu.Adapt<AddMenuInput>());
|
||||
}
|
||||
else
|
||||
{
|
||||
// 存在则更新
|
||||
existingMenu.Icon = menuIcon;
|
||||
existingMenu.Path = (pid == 0 ? "/" : parentPath + "/") + className.ToLower();
|
||||
existingMenu.Component = pid == 0 ? "Layout" : $"/{pagePath}/{lowerClassName}/index";
|
||||
await _sysMenuService.UpdateMenu(existingMenu.Adapt<UpdateMenuInput>());
|
||||
menuId = existingMenu.Id;
|
||||
}
|
||||
|
||||
// 定义应有的按钮
|
||||
var orderNo = 100;
|
||||
var newButtons = new List<SysMenu>
|
||||
{
|
||||
new() { Title = "查询", Permission = $"{lowerClassName}:page", OrderNo = orderNo += 10 },
|
||||
new() { Title = "详情", Permission = $"{lowerClassName}:detail", OrderNo = orderNo += 10 },
|
||||
new() { Title = "增加", Permission = $"{lowerClassName}:add", OrderNo = orderNo += 10 },
|
||||
new() { Title = "编辑", Permission = $"{lowerClassName}:update", OrderNo = orderNo += 10 },
|
||||
new() { Title = "删除", Permission = $"{lowerClassName}:delete", OrderNo = orderNo += 10 },
|
||||
new() { Title = "批量删除", Permission = $"{lowerClassName}:batchDelete", OrderNo = orderNo += 10 },
|
||||
new() { Title = "设置状态", Permission = $"{lowerClassName}:setStatus", OrderNo = orderNo += 10 },
|
||||
new() { Title = "打印", Permission = $"{lowerClassName}:print", OrderNo = orderNo += 10 },
|
||||
new() { Title = "导入", Permission = $"{lowerClassName}:import", OrderNo = orderNo += 10 },
|
||||
new() { Title = "导出", Permission = $"{lowerClassName}:export", OrderNo = orderNo += 10 }
|
||||
};
|
||||
|
||||
if (tableFieldList.Any(u => u.EffectType is "ForeignKey" or "ApiTreeSelector" && (u.WhetherAddUpdate == "Y" || u.WhetherQuery == "Y")))
|
||||
{
|
||||
newButtons.Add(new SysMenu
|
||||
{
|
||||
Title = "下拉列表数据",
|
||||
Permission = $"{lowerClassName}:dropdownData",
|
||||
OrderNo = orderNo += 10
|
||||
});
|
||||
}
|
||||
|
||||
foreach (var column in tableFieldList.Where(u => u.EffectType == "Upload" || u.EffectType == "Upload_SingleFile"))
|
||||
{
|
||||
newButtons.Add(new SysMenu
|
||||
{
|
||||
Title = $"上传{column.ColumnComment}",
|
||||
Permission = $"{lowerClassName}:upload{column.PropertyName}",
|
||||
OrderNo = orderNo += 10
|
||||
});
|
||||
}
|
||||
|
||||
// 获取当前菜单下的按钮
|
||||
var existingButtons = await _db.Queryable<SysMenu>()
|
||||
.Where(m => m.Pid == menuId && m.Type == MenuTypeEnum.Btn)
|
||||
.ToListAsync();
|
||||
|
||||
var newPermissions = newButtons.Select(b => b.Permission).ToHashSet();
|
||||
|
||||
// 添加或更新按钮
|
||||
foreach (var btn in newButtons)
|
||||
{
|
||||
var match = existingButtons.FirstOrDefault(b => b.Permission == btn.Permission);
|
||||
if (match == null)
|
||||
{
|
||||
btn.Type = MenuTypeEnum.Btn;
|
||||
btn.Pid = menuId;
|
||||
btn.Icon = "";
|
||||
await _sysMenuService.AddMenu(btn.Adapt<AddMenuInput>());
|
||||
}
|
||||
else
|
||||
{
|
||||
match.Title = btn.Title;
|
||||
match.OrderNo = btn.OrderNo;
|
||||
await _sysMenuService.UpdateMenu(match.Adapt<UpdateMenuInput>());
|
||||
}
|
||||
}
|
||||
|
||||
// 删除多余的旧按钮
|
||||
var toDelete = existingButtons.Where(b => !newPermissions.Contains(b.Permission)).ToList();
|
||||
foreach (var del in toDelete)
|
||||
await _sysMenuService.DeleteMenu(new DeleteMenuInput { Id = del.Id });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 增加菜单
|
||||
/// </summary>
|
||||
/// <param name="className"></param>
|
||||
/// <param name="busName"></param>
|
||||
/// <param name="pid"></param>
|
||||
/// <param name="menuIcon"></param>
|
||||
/// <param name="pagePath"></param>
|
||||
/// <param name="tableFieldList"></param>
|
||||
/// <returns></returns>
|
||||
private async Task AddMenu(string className, string busName, long pid, string menuIcon, string pagePath, List<CodeGenConfig> tableFieldList)
|
||||
{
|
||||
// 删除已存在的菜单
|
||||
var title = $"{busName}管理";
|
||||
await DeleteMenuTree(title, pid == 0 ? MenuTypeEnum.Dir : MenuTypeEnum.Menu);
|
||||
|
||||
var parentMenuPath = "";
|
||||
var lowerClassName = className!.ToFirstLetterLowerCase();
|
||||
if (pid == 0)
|
||||
{
|
||||
// 新增目录,并记录Id
|
||||
var dirMenu = new SysMenu { Pid = 0, Title = title, Type = MenuTypeEnum.Dir, Icon = "robot", Path = "/" + className.ToLower(), Component = "Layout" };
|
||||
pid = await _sysMenuService.AddMenu(dirMenu.Adapt<AddMenuInput>());
|
||||
}
|
||||
else
|
||||
{
|
||||
var parentMenu = await _db.Queryable<SysMenu>().FirstAsync(u => u.Id == pid) ?? throw Oops.Oh(ErrorCodeEnum.D1505);
|
||||
parentMenuPath = parentMenu.Path;
|
||||
}
|
||||
|
||||
// 新增菜单,并记录Id
|
||||
var rootMenu = new SysMenu { Pid = pid, Title = title, Type = MenuTypeEnum.Menu, Icon = menuIcon, Path = $"{parentMenuPath}/{className.ToLower()}", Component = $"/{pagePath}/{lowerClassName}/index" };
|
||||
pid = await _sysMenuService.AddMenu(rootMenu.Adapt<AddMenuInput>());
|
||||
|
||||
var orderNo = 100;
|
||||
var menuList = new List<SysMenu>
|
||||
{
|
||||
new() { Title="查询", Permission=$"{lowerClassName}:page", Pid=pid, Type=MenuTypeEnum.Btn, OrderNo=orderNo+=10},
|
||||
new() { Title="详情", Permission=$"{lowerClassName}:detail", Pid=pid, Type=MenuTypeEnum.Btn, OrderNo=orderNo+=10},
|
||||
new() { Title="增加", Permission=$"{lowerClassName}:add", Pid=pid, Type=MenuTypeEnum.Btn, OrderNo=orderNo+=10},
|
||||
new() { Title="编辑", Permission=$"{lowerClassName}:update", Pid=pid, Type=MenuTypeEnum.Btn, OrderNo=orderNo+=10},
|
||||
new() { Title="删除", Permission=$"{lowerClassName}:delete", Pid=pid, Type=MenuTypeEnum.Btn, OrderNo=orderNo+=10},
|
||||
new() { Title="批量删除", Permission=$"{lowerClassName}:batchDelete", Pid=pid, Type=MenuTypeEnum.Btn, OrderNo=orderNo+=10},
|
||||
new() { Title="设置状态", Permission=$"{lowerClassName}:setStatus", Pid=pid, Type=MenuTypeEnum.Btn, OrderNo=orderNo+=10},
|
||||
new() { Title="打印", Permission=$"{lowerClassName}:print", Pid=pid, Type=MenuTypeEnum.Btn, OrderNo=orderNo+=10},
|
||||
new() { Title="导入", Permission=$"{lowerClassName}:import", Pid=pid, Type=MenuTypeEnum.Btn, OrderNo=orderNo+=10},
|
||||
new() { Title="导出", Permission=$"{lowerClassName}:export", Pid=pid, Type=MenuTypeEnum.Btn, OrderNo=orderNo+=10}
|
||||
};
|
||||
|
||||
if (tableFieldList.Any(u => u.EffectType is "ForeignKey" or "ApiTreeSelector" && (u.WhetherAddUpdate == "Y" || u.WhetherQuery == "Y")))
|
||||
menuList.Add(new SysMenu { Title = "下拉列表数据", Permission = $"{lowerClassName}:dropdownData", Pid = pid, Type = MenuTypeEnum.Btn, OrderNo = orderNo += 10 });
|
||||
|
||||
foreach (var column in tableFieldList.Where(u => u.EffectType == "Upload"))
|
||||
menuList.Add(new SysMenu { Title = $"上传{column.ColumnComment}", Permission = $"{lowerClassName}:upload{column.PropertyName}", Pid = pid, Type = MenuTypeEnum.Btn, OrderNo = orderNo += 10 });
|
||||
|
||||
foreach (var menu in menuList) await _sysMenuService.AddMenu(menu.Adapt<AddMenuInput>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据菜单名称和类型删除关联的菜单树
|
||||
/// </summary>
|
||||
/// <param name="title"></param>
|
||||
/// <param name="type"></param>
|
||||
private async Task DeleteMenuTree(string title, MenuTypeEnum type)
|
||||
{
|
||||
var menuList = await _db.Queryable<SysMenu>().Where(u => u.Title == title && u.Type == type).ToListAsync() ?? new();
|
||||
foreach (var menu in menuList) await _sysMenuService.DeleteMenu(new DeleteMenuInput { Id = menu.Id });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取模板文件路径集合
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private static List<string> GetTemplatePathList(SysCodeGen input)
|
||||
{
|
||||
if (input.GenerateType!.Substring(1, 1).Contains('1')) return new() { "index.vue.vm", "editDialog.vue.vm", "api.ts.vm" };
|
||||
if (input.GenerateType.Substring(1, 1).Contains('2')) return new() { "Service.cs.vm", "Input.cs.vm", "Output.cs.vm", "Dto.cs.vm" };
|
||||
return new() { "Service.cs.vm", "Input.cs.vm", "Output.cs.vm", "Dto.cs.vm", "index.vue.vm", "editDialog.vue.vm", "api.ts.vm" };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取模板文件路径集合
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private static List<string> GetTemplatePathList() => new() { "Service.cs.vm", "Input.cs.vm", "Output.cs.vm", "Dto.cs.vm", "index.vue.vm", "editDialog.vue.vm", "api.ts.vm" };
|
||||
|
||||
/// <summary>
|
||||
/// 设置生成文件路径
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
private List<string> GetTargetPathList(SysCodeGen input)
|
||||
{
|
||||
//var backendPath = Path.Combine(new DirectoryInfo(App.WebHostEnvironment.ContentRootPath).Parent.FullName, _codeGenOptions.BackendApplicationNamespace, "Service", input.TableName);
|
||||
var backendPath = Path.Combine(new DirectoryInfo(App.WebHostEnvironment.ContentRootPath).Parent!.FullName, input.NameSpace!, "Service", input.TableName!);
|
||||
var servicePath = Path.Combine(backendPath, input.TableName + "Service.cs");
|
||||
var inputPath = Path.Combine(backendPath, "Dto", input.TableName + "Input.cs");
|
||||
var outputPath = Path.Combine(backendPath, "Dto", input.TableName + "Output.cs");
|
||||
var viewPath = Path.Combine(backendPath, "Dto", input.TableName + "Dto.cs");
|
||||
var frontendPath = Path.Combine(new DirectoryInfo(App.WebHostEnvironment.ContentRootPath).Parent!.Parent!.FullName, _codeGenOptions.FrontRootPath, "src", "views", input.PagePath!);
|
||||
var indexPath = Path.Combine(frontendPath, input.TableName[..1].ToLower() + input.TableName[1..], "index.vue");//
|
||||
var formModalPath = Path.Combine(frontendPath, input.TableName[..1].ToLower() + input.TableName[1..], "component", "editDialog.vue");
|
||||
var apiJsPath = Path.Combine(new DirectoryInfo(App.WebHostEnvironment.ContentRootPath).Parent!.Parent!.FullName, _codeGenOptions.FrontRootPath, "src", "api", input.PagePath, input.TableName[..1].ToLower() + input.TableName[1..] + ".ts");
|
||||
|
||||
if (input.GenerateType!.Substring(1, 1).Contains('1'))
|
||||
{
|
||||
// 生成到本项目(前端)
|
||||
return new List<string>
|
||||
{
|
||||
indexPath,
|
||||
formModalPath,
|
||||
apiJsPath
|
||||
};
|
||||
}
|
||||
|
||||
if (input.GenerateType.Substring(1, 1).Contains('2'))
|
||||
{
|
||||
// 生成到本项目(后端)
|
||||
return new List<string>
|
||||
{
|
||||
servicePath,
|
||||
inputPath,
|
||||
outputPath,
|
||||
viewPath,
|
||||
};
|
||||
}
|
||||
// 前后端同时生成到本项目
|
||||
return new List<string>
|
||||
{
|
||||
servicePath,
|
||||
inputPath,
|
||||
outputPath,
|
||||
viewPath,
|
||||
indexPath,
|
||||
formModalPath,
|
||||
apiJsPath
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置生成文件路径
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
private List<string> GetZipPathList(SysCodeGen input)
|
||||
{
|
||||
var zipPath = Path.Combine(App.WebHostEnvironment.WebRootPath, "CodeGen", input.TableName!);
|
||||
|
||||
var firstLowerTableName = input.TableName!.ToFirstLetterLowerCase();
|
||||
//var backendPath = Path.Combine(zipPath, _codeGenOptions.BackendApplicationNamespace, "Service", input.TableName);
|
||||
var backendPath = Path.Combine(zipPath, input.NameSpace!, "Service", input.TableName);
|
||||
var servicePath = Path.Combine(backendPath, input.TableName + "Service.cs");
|
||||
var inputPath = Path.Combine(backendPath, "Dto", input.TableName + "Input.cs");
|
||||
var outputPath = Path.Combine(backendPath, "Dto", input.TableName + "Output.cs");
|
||||
var viewPath = Path.Combine(backendPath, "Dto", input.TableName + "Dto.cs");
|
||||
var frontendPath = Path.Combine(zipPath, _codeGenOptions.FrontRootPath, "src", "views", input.PagePath!);
|
||||
var indexPath = Path.Combine(frontendPath, firstLowerTableName, "index.vue");
|
||||
var formModalPath = Path.Combine(frontendPath, firstLowerTableName, "component", "editDialog.vue");
|
||||
var apiJsPath = Path.Combine(zipPath, _codeGenOptions.FrontRootPath, "src", "api", input.PagePath, firstLowerTableName + ".ts");
|
||||
if (input.GenerateType!.StartsWith("11"))
|
||||
{
|
||||
return new List<string>
|
||||
{
|
||||
indexPath,
|
||||
formModalPath,
|
||||
apiJsPath
|
||||
};
|
||||
}
|
||||
|
||||
if (input.GenerateType.StartsWith("12"))
|
||||
{
|
||||
return new List<string>
|
||||
{
|
||||
servicePath,
|
||||
inputPath,
|
||||
outputPath,
|
||||
viewPath
|
||||
};
|
||||
}
|
||||
|
||||
return new List<string>
|
||||
{
|
||||
servicePath,
|
||||
inputPath,
|
||||
outputPath,
|
||||
viewPath,
|
||||
indexPath,
|
||||
formModalPath,
|
||||
apiJsPath
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -673,16 +673,6 @@ public class SysDatabaseService : IDynamicApiController, ITransient
|
||||
private static string GetEntityTargetPath(CreateEntityInput input)
|
||||
{
|
||||
var backendPath = Path.Combine(new DirectoryInfo(App.WebHostEnvironment.ContentRootPath).Parent.FullName, input.Position, "Entity");
|
||||
//if (!Directory.Exists(backendPath))
|
||||
//{
|
||||
// var pluginsPath = App.GetConfig<string[]>("AppSettings:ExternalAssemblies");
|
||||
// foreach (var pluginPath in pluginsPath)
|
||||
// {
|
||||
// backendPath = Path.Combine(new DirectoryInfo(App.WebHostEnvironment.ContentRootPath).Parent.FullName, pluginPath, input.Position, "Entity");
|
||||
// if (Directory.Exists(backendPath))
|
||||
// break;
|
||||
// }
|
||||
//}
|
||||
if (!Directory.Exists(backendPath))
|
||||
Directory.CreateDirectory(backendPath);
|
||||
return Path.Combine(backendPath, input.EntityName + ".cs");
|
||||
@@ -773,4 +763,4 @@ public class SysDatabaseService : IDynamicApiController, ITransient
|
||||
FileDownloadName = backupFileName
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,188 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core.Service;
|
||||
|
||||
/// <summary>
|
||||
/// 作业持久化(数据库)
|
||||
/// </summary>
|
||||
public class DbJobPersistence : IJobPersistence
|
||||
{
|
||||
private readonly IServiceScopeFactory _serviceScopeFactory;
|
||||
|
||||
public DbJobPersistence(IServiceScopeFactory serviceScopeFactory)
|
||||
{
|
||||
_serviceScopeFactory = serviceScopeFactory;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 作业调度服务启动时
|
||||
/// </summary>
|
||||
/// <param name="stoppingToken"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotSupportedException"></exception>
|
||||
public async Task<IEnumerable<SchedulerBuilder>> PreloadAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
using var scope = _serviceScopeFactory.CreateScope();
|
||||
var db = scope.ServiceProvider.GetRequiredService<ISqlSugarClient>().CopyNew();
|
||||
var dynamicJobCompiler = scope.ServiceProvider.GetRequiredService<DynamicJobCompiler>();
|
||||
|
||||
// 获取所有定义的作业
|
||||
var allJobs = App.EffectiveTypes.ScanToBuilders().ToList();
|
||||
// 若数据库不存在任何作业,则直接返回
|
||||
if (!await db.Queryable<SysJobDetail>().AnyAsync(u => true, stoppingToken)) return allJobs;
|
||||
|
||||
// 遍历所有定义的作业
|
||||
foreach (var schedulerBuilder in allJobs)
|
||||
{
|
||||
// 获取作业信息构建器
|
||||
var jobBuilder = schedulerBuilder.GetJobBuilder();
|
||||
|
||||
// 加载数据库数据
|
||||
var dbDetail = await db.Queryable<SysJobDetail>().FirstAsync(u => u.JobId == jobBuilder.JobId, stoppingToken);
|
||||
if (dbDetail == null) continue;
|
||||
|
||||
// 同步数据库数据
|
||||
jobBuilder.LoadFrom(dbDetail);
|
||||
|
||||
// 获取作业的所有数据库的触发器
|
||||
var dbTriggers = await db.Queryable<SysJobTrigger>().Where(u => u.JobId == jobBuilder.JobId).ToListAsync(stoppingToken);
|
||||
// 遍历所有作业触发器
|
||||
foreach (var (_, triggerBuilder) in schedulerBuilder.GetEnumerable())
|
||||
{
|
||||
// 加载数据库数据
|
||||
var dbTrigger = dbTriggers.FirstOrDefault(u => u.JobId == jobBuilder.JobId && u.TriggerId == triggerBuilder.TriggerId);
|
||||
if (dbTrigger == null) continue;
|
||||
|
||||
triggerBuilder.LoadFrom(dbTrigger).Updated(); // 标记更新
|
||||
}
|
||||
// 遍历所有非编译时定义的触发器加入到作业中
|
||||
foreach (var dbTrigger in dbTriggers)
|
||||
{
|
||||
if (schedulerBuilder.GetTriggerBuilder(dbTrigger.TriggerId)?.JobId == jobBuilder.JobId) continue;
|
||||
var triggerBuilder = TriggerBuilder.Create(dbTrigger.TriggerId).LoadFrom(dbTrigger);
|
||||
schedulerBuilder.AddTriggerBuilder(triggerBuilder); // 先添加
|
||||
triggerBuilder.Updated(); // 再标记更新
|
||||
}
|
||||
|
||||
// 标记更新
|
||||
schedulerBuilder.Updated();
|
||||
}
|
||||
|
||||
// 获取数据库所有通过脚本创建的作业
|
||||
var allDbScriptJobs = await db.Queryable<SysJobDetail>().Where(u => u.CreateType != JobCreateTypeEnum.BuiltIn).ToListAsync(stoppingToken);
|
||||
foreach (var dbDetail in allDbScriptJobs)
|
||||
{
|
||||
// 动态创建作业
|
||||
Type jobType = dbDetail.CreateType switch
|
||||
{
|
||||
JobCreateTypeEnum.Script => dynamicJobCompiler.BuildJob(dbDetail.ScriptCode),
|
||||
JobCreateTypeEnum.Http => typeof(HttpJob),
|
||||
_ => throw new NotSupportedException(),
|
||||
};
|
||||
|
||||
// 动态构建的 jobType 的程序集名称为随机名称,需重新设置
|
||||
dbDetail.AssemblyName = jobType.Assembly.FullName!.Split(',')[0];
|
||||
var jobBuilder = JobBuilder.Create(jobType).LoadFrom(dbDetail);
|
||||
|
||||
// 强行设置为不扫描 IJob 实现类 [Trigger] 特性触发器,否则 SchedulerBuilder.Create 会再次扫描,导致重复添加同名触发器
|
||||
jobBuilder.SetIncludeAnnotations(false);
|
||||
|
||||
// 获取作业的所有数据库的触发器加入到作业中
|
||||
var dbTriggers = await db.Queryable<SysJobTrigger>().Where(u => u.JobId == jobBuilder.JobId).ToListAsync();
|
||||
var triggerBuilders = dbTriggers.Select(u => TriggerBuilder.Create(u.TriggerId).LoadFrom(u).Updated());
|
||||
var schedulerBuilder = SchedulerBuilder.Create(jobBuilder, triggerBuilders.ToArray());
|
||||
|
||||
// 标记更新
|
||||
schedulerBuilder.Updated();
|
||||
|
||||
allJobs.Add(schedulerBuilder);
|
||||
}
|
||||
|
||||
return allJobs;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 作业计划初始化通知
|
||||
/// </summary>
|
||||
/// <param name="builder"></param>
|
||||
/// <param name="stoppingToken"></param>
|
||||
/// <returns></returns>
|
||||
public Task<SchedulerBuilder> OnLoadingAsync(SchedulerBuilder builder, CancellationToken stoppingToken)
|
||||
{
|
||||
return Task.FromResult(builder);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 作业计划Scheduler的JobDetail变化时
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <returns></returns>
|
||||
public async Task OnChangedAsync(PersistenceContext context)
|
||||
{
|
||||
using var scope = _serviceScopeFactory.CreateScope();
|
||||
var db = scope.ServiceProvider.GetRequiredService<ISqlSugarClient>().CopyNew();
|
||||
|
||||
var jobDetail = context.JobDetail.Adapt<SysJobDetail>();
|
||||
switch (context.Behavior)
|
||||
{
|
||||
case PersistenceBehavior.Appended:
|
||||
await db.Insertable(jobDetail).ExecuteCommandAsync();
|
||||
break;
|
||||
|
||||
case PersistenceBehavior.Updated:
|
||||
await db.Updateable(jobDetail).WhereColumns(u => new { u.JobId }).IgnoreColumns(u => new { u.Id, u.CreateType, u.ScriptCode }).ExecuteCommandAsync();
|
||||
break;
|
||||
|
||||
case PersistenceBehavior.Removed:
|
||||
await db.Deleteable<SysJobDetail>().Where(u => u.JobId == jobDetail.JobId).ExecuteCommandAsync();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 作业计划Scheduler的触发器Trigger变化时
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <returns></returns>
|
||||
public async Task OnTriggerChangedAsync(PersistenceTriggerContext context)
|
||||
{
|
||||
using var scope = _serviceScopeFactory.CreateScope();
|
||||
var db = scope.ServiceProvider.GetRequiredService<ISqlSugarClient>().CopyNew();
|
||||
|
||||
var jobTrigger = context.Trigger.Adapt<SysJobTrigger>();
|
||||
switch (context.Behavior)
|
||||
{
|
||||
case PersistenceBehavior.Appended:
|
||||
await db.Insertable(jobTrigger).ExecuteCommandAsync();
|
||||
break;
|
||||
|
||||
case PersistenceBehavior.Updated:
|
||||
await db.Updateable(jobTrigger).WhereColumns(u => new { u.TriggerId, u.JobId }).IgnoreColumns(u => new { u.Id }).ExecuteCommandAsync();
|
||||
break;
|
||||
|
||||
case PersistenceBehavior.Removed:
|
||||
await db.Deleteable<SysJobTrigger>().Where(u => u.TriggerId == jobTrigger.TriggerId && u.JobId == jobTrigger.JobId).ExecuteCommandAsync();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 作业触发器运行记录
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <returns></returns>
|
||||
public async Task OnExecutionRecordAsync(PersistenceExecutionRecordContext context)
|
||||
{
|
||||
using var scope = _serviceScopeFactory.CreateScope();
|
||||
var db = scope.ServiceProvider.GetRequiredService<ISqlSugarClient>().CopyNew();
|
||||
|
||||
var jobTriggerRecord = context.Timeline.Adapt<SysJobTriggerRecord>();
|
||||
await db.Insertable(jobTriggerRecord).ExecuteCommandAsync();
|
||||
|
||||
await scope.ServiceProvider.GetRequiredService<SysJobService>().ClearExpireJobTriggerRecord(jobTriggerRecord);
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core.Service;
|
||||
|
||||
public class JobDetailInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 作业Id
|
||||
/// </summary>
|
||||
public string JobId { get; set; }
|
||||
}
|
||||
|
||||
public class PageJobDetailInput : BasePageInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 作业Id
|
||||
/// </summary>
|
||||
public string JobId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 组名称
|
||||
/// </summary>
|
||||
public string GroupName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 描述信息
|
||||
/// </summary>
|
||||
public string Description { get; set; }
|
||||
}
|
||||
|
||||
public class AddJobDetailInput : SysJobDetail
|
||||
{
|
||||
/// <summary>
|
||||
/// 作业Id
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "作业Id不能为空"), MinLength(2, ErrorMessage = "作业Id不能少于2个字符")]
|
||||
public override string JobId { get; set; }
|
||||
}
|
||||
|
||||
public class UpdateJobDetailInput : AddJobDetailInput
|
||||
{
|
||||
}
|
||||
|
||||
public class DeleteJobDetailInput : JobDetailInput
|
||||
{
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core.Service;
|
||||
|
||||
public class JobDetailOutput
|
||||
{
|
||||
/// <summary>
|
||||
/// 作业信息
|
||||
/// </summary>
|
||||
public SysJobDetail JobDetail { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 触发器集合
|
||||
/// </summary>
|
||||
public List<SysJobTrigger> JobTriggers { get; set; }
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core.Service;
|
||||
|
||||
public class JobTriggerInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 作业Id
|
||||
/// </summary>
|
||||
public string JobId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 触发器Id
|
||||
/// </summary>
|
||||
public string TriggerId { get; set; }
|
||||
}
|
||||
|
||||
public class AddJobTriggerInput : SysJobTrigger
|
||||
{
|
||||
/// <summary>
|
||||
/// 作业Id
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "作业Id不能为空"), MinLength(2, ErrorMessage = "作业Id不能少于2个字符")]
|
||||
public override string JobId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 触发器Id
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "触发器Id不能为空"), MinLength(2, ErrorMessage = "触发器Id不能少于2个字符")]
|
||||
public override string TriggerId { get; set; }
|
||||
}
|
||||
|
||||
public class UpdateJobTriggerInput : AddJobTriggerInput
|
||||
{
|
||||
}
|
||||
|
||||
public class DeleteJobTriggerInput : JobTriggerInput
|
||||
{
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core.Service;
|
||||
|
||||
public class PageJobTriggerRecordInput : BasePageInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 作业Id
|
||||
/// </summary>
|
||||
public string JobId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 触发器Id
|
||||
/// </summary>
|
||||
public string TriggerId { get; set; }
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core.Service;
|
||||
|
||||
/// <summary>
|
||||
/// 作业集群控制
|
||||
/// </summary>
|
||||
public class JobClusterServer : IJobClusterServer
|
||||
{
|
||||
private static readonly SqlSugarRepository<SysJobCluster> _sysJobClusterRep = App.GetRequiredService<SqlSugarRepository<SysJobCluster>>();
|
||||
private readonly Random _random = new(DateTime.Now.Millisecond);
|
||||
|
||||
/// <summary>
|
||||
/// 当前作业调度器启动通知
|
||||
/// </summary>
|
||||
/// <param name="context">作业集群服务上下文</param>
|
||||
public async void Start(JobClusterContext context)
|
||||
{
|
||||
// 在作业集群表中,如果 clusterId 不存在,则新增一条(否则更新一条),并设置 status 为 ClusterStatus.Waiting
|
||||
if (await _sysJobClusterRep.IsAnyAsync(u => u.ClusterId == context.ClusterId))
|
||||
{
|
||||
await _sysJobClusterRep.AsUpdateable().SetColumns(u => u.Status == ClusterStatus.Waiting).Where(u => u.ClusterId == context.ClusterId).ExecuteCommandAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
await _sysJobClusterRep.AsInsertable(new SysJobCluster { ClusterId = context.ClusterId, Status = ClusterStatus.Waiting }).ExecuteCommandAsync();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 等待被唤醒
|
||||
/// </summary>
|
||||
/// <param name="context">作业集群服务上下文</param>
|
||||
/// <returns><see cref="Task"/></returns>
|
||||
public async Task WaitingForAsync(JobClusterContext context)
|
||||
{
|
||||
var clusterId = context.ClusterId;
|
||||
|
||||
while (true)
|
||||
{
|
||||
// 控制集群心跳频率(放在头部为了防止 IsAnyAsync continue 没sleep占用大量IO和CPU)
|
||||
await Task.Delay(3000 + _random.Next(500, 1000)); // 错开集群同时启动
|
||||
|
||||
try
|
||||
{
|
||||
ICache cache = App.GetRequiredService<ICacheProvider>().Cache;
|
||||
// 使用分布式锁
|
||||
using (cache.AcquireLock("lock:JobClusterServer:WaitingForAsync", 1000))
|
||||
{
|
||||
// 在这里查询数据库,根据以下两种情况处理
|
||||
// 1) 如果作业集群表已有 status 为 ClusterStatus.Working 则继续循环
|
||||
// 2) 如果作业集群表中还没有其他服务或只有自己,则插入一条集群服务或调用 await WorkNowAsync(clusterId); 之后 return;
|
||||
// 3) 如果作业集群表中没有 status 为 ClusterStatus.Working 的,调用 await WorkNowAsync(clusterId); 之后 return;
|
||||
if (await _sysJobClusterRep.IsAnyAsync(u => u.Status == ClusterStatus.Working)) continue;
|
||||
|
||||
await WorkNowAsync(clusterId);
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前作业调度器停止通知
|
||||
/// </summary>
|
||||
/// <param name="context">作业集群服务上下文</param>
|
||||
public async void Stop(JobClusterContext context)
|
||||
{
|
||||
// 在作业集群表中,更新 clusterId 的 status 为 ClusterStatus.Crashed
|
||||
await _sysJobClusterRep.UpdateAsync(u => new SysJobCluster { Status = ClusterStatus.Crashed }, u => u.ClusterId == context.ClusterId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前作业调度器宕机
|
||||
/// </summary>
|
||||
/// <param name="context">作业集群服务上下文</param>
|
||||
public async void Crash(JobClusterContext context)
|
||||
{
|
||||
// 在作业集群表中,更新 clusterId 的 status 为 ClusterStatus.Crashed
|
||||
await _sysJobClusterRep.UpdateAsync(u => new SysJobCluster { Status = ClusterStatus.Crashed }, u => u.ClusterId == context.ClusterId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 指示集群可以工作
|
||||
/// </summary>
|
||||
/// <param name="clusterId">集群 Id</param>
|
||||
/// <returns></returns>
|
||||
private static async Task WorkNowAsync(string clusterId)
|
||||
{
|
||||
// 在作业集群表中,更新 clusterId 的 status 为 ClusterStatus.Working
|
||||
await _sysJobClusterRep.UpdateAsync(u => new SysJobCluster { Status = ClusterStatus.Working }, u => u.ClusterId == clusterId);
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core.Service;
|
||||
|
||||
/// <summary>
|
||||
/// 作业执行监视器
|
||||
/// </summary>
|
||||
public class JobMonitor : IJobMonitor
|
||||
{
|
||||
private readonly SysConfigService _sysConfigService;
|
||||
private readonly IEventPublisher _eventPublisher;
|
||||
private readonly ILogger<JobMonitor> _logger;
|
||||
|
||||
public JobMonitor(IServiceScopeFactory serviceScopeFactory, IEventPublisher eventPublisher, ILogger<JobMonitor> logger)
|
||||
{
|
||||
var serviceScope = serviceScopeFactory.CreateScope();
|
||||
_sysConfigService = serviceScope.ServiceProvider.GetRequiredService<SysConfigService>();
|
||||
_eventPublisher = eventPublisher;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public Task OnExecutingAsync(JobExecutingContext context, CancellationToken stoppingToken)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public async Task OnExecutedAsync(JobExecutedContext context, CancellationToken stoppingToken)
|
||||
{
|
||||
if (context.Exception == null) return;
|
||||
|
||||
var exception = $"定时任务【{context.Trigger.Description}】错误:{context.Exception}";
|
||||
// 将作业异常信息记录到本地
|
||||
_logger.LogError(exception);
|
||||
|
||||
if (await _sysConfigService.GetConfigValue<bool>(ConfigConst.SysErrorMail))
|
||||
{
|
||||
// 将作业异常信息发送到邮件
|
||||
await _eventPublisher.PublishAsync(CommonConst.SendErrorMail, exception, stoppingToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,398 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core.Service;
|
||||
|
||||
/// <summary>
|
||||
/// 系统作业任务服务 🧩
|
||||
/// </summary>
|
||||
[ApiDescriptionSettings(Order = 320, Description = "作业任务")]
|
||||
public class SysJobService : IDynamicApiController, ITransient
|
||||
{
|
||||
private readonly SqlSugarRepository<SysJobDetail> _sysJobDetailRep;
|
||||
private readonly SqlSugarRepository<SysJobTrigger> _sysJobTriggerRep;
|
||||
private readonly SqlSugarRepository<SysJobTriggerRecord> _sysJobTriggerRecordRep;
|
||||
private readonly SqlSugarRepository<SysJobCluster> _sysJobClusterRep;
|
||||
private readonly ISchedulerFactory _schedulerFactory;
|
||||
private readonly DynamicJobCompiler _dynamicJobCompiler;
|
||||
|
||||
public SysJobService(SqlSugarRepository<SysJobDetail> sysJobDetailRep,
|
||||
SqlSugarRepository<SysJobTrigger> sysJobTriggerRep,
|
||||
SqlSugarRepository<SysJobTriggerRecord> sysJobTriggerRecordRep,
|
||||
SqlSugarRepository<SysJobCluster> sysJobClusterRep,
|
||||
ISchedulerFactory schedulerFactory,
|
||||
DynamicJobCompiler dynamicJobCompiler)
|
||||
{
|
||||
_sysJobDetailRep = sysJobDetailRep;
|
||||
_sysJobTriggerRep = sysJobTriggerRep;
|
||||
_sysJobTriggerRecordRep = sysJobTriggerRecordRep;
|
||||
_sysJobClusterRep = sysJobClusterRep;
|
||||
_schedulerFactory = schedulerFactory;
|
||||
_dynamicJobCompiler = dynamicJobCompiler;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取作业分页列表 ⏰
|
||||
/// </summary>
|
||||
[DisplayName("获取作业分页列表")]
|
||||
public async Task<SqlSugarPagedList<JobDetailOutput>> PageJobDetail(PageJobDetailInput input)
|
||||
{
|
||||
var jobDetails = await _sysJobDetailRep.AsQueryable()
|
||||
.WhereIF(!string.IsNullOrWhiteSpace(input.JobId), u => u.JobId.Contains(input.JobId.Trim()))
|
||||
.WhereIF(!string.IsNullOrWhiteSpace(input.GroupName), u => u.GroupName.Contains(input.GroupName.Trim()))
|
||||
.WhereIF(!string.IsNullOrWhiteSpace(input.Description), u => u.Description.Contains(input.Description.Trim()))
|
||||
.Select(d => new JobDetailOutput
|
||||
{
|
||||
JobDetail = d,
|
||||
}).ToPagedListAsync(input.Page, input.PageSize);
|
||||
await _sysJobDetailRep.AsSugarClient().ThenMapperAsync(jobDetails.Items, async u =>
|
||||
{
|
||||
u.JobTriggers = await _sysJobTriggerRep.GetListAsync(t => t.JobId == u.JobDetail.JobId);
|
||||
});
|
||||
|
||||
// 提取中括号里面的参数值
|
||||
var rgx = new Regex(@"(?i)(?<=\[)(.*)(?=\])");
|
||||
foreach (var job in jobDetails.Items)
|
||||
{
|
||||
foreach (var jobTrigger in job.JobTriggers)
|
||||
{
|
||||
jobTrigger.Args = rgx.Match(jobTrigger.Args ?? "").Value;
|
||||
}
|
||||
}
|
||||
return jobDetails;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取作业组名称集合 ⏰
|
||||
/// </summary>
|
||||
[DisplayName("获取作业组名称集合")]
|
||||
public async Task<List<string>> ListJobGroup()
|
||||
{
|
||||
return await _sysJobDetailRep.AsQueryable().Distinct().Select(e => e.GroupName).ToListAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加作业 ⏰
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[ApiDescriptionSettings(Name = "AddJobDetail"), HttpPost]
|
||||
[DisplayName("添加作业")]
|
||||
public async Task AddJobDetail(AddJobDetailInput input)
|
||||
{
|
||||
var isExist = await _sysJobDetailRep.IsAnyAsync(u => u.JobId == input.JobId && u.Id != input.Id);
|
||||
if (isExist) throw Oops.Oh(ErrorCodeEnum.D1006);
|
||||
|
||||
// 动态创建作业
|
||||
Type jobType;
|
||||
switch (input.CreateType)
|
||||
{
|
||||
case JobCreateTypeEnum.Script when string.IsNullOrEmpty(input.ScriptCode):
|
||||
throw Oops.Oh(ErrorCodeEnum.D1701);
|
||||
case JobCreateTypeEnum.Script:
|
||||
{
|
||||
jobType = _dynamicJobCompiler.BuildJob(input.ScriptCode);
|
||||
|
||||
if (jobType.GetCustomAttributes(typeof(JobDetailAttribute)).FirstOrDefault() is not JobDetailAttribute jobDetailAttribute)
|
||||
throw Oops.Oh(ErrorCodeEnum.D1702);
|
||||
if (jobDetailAttribute.JobId != input.JobId)
|
||||
throw Oops.Oh(ErrorCodeEnum.D1703);
|
||||
break;
|
||||
}
|
||||
case JobCreateTypeEnum.Http:
|
||||
jobType = typeof(HttpJob);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
_schedulerFactory.AddJob(JobBuilder.Create(jobType).LoadFrom(input.Adapt<SysJobDetail>()).SetJobType(jobType));
|
||||
|
||||
// 延迟一下等待持久化写入,再执行其他字段的更新
|
||||
await Task.Delay(500);
|
||||
await _sysJobDetailRep.AsUpdateable()
|
||||
.SetColumns(u => new SysJobDetail { CreateType = input.CreateType, ScriptCode = input.ScriptCode })
|
||||
.Where(u => u.JobId == input.JobId).ExecuteCommandAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新作业 ⏰
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[ApiDescriptionSettings(Name = "UpdateJobDetail"), HttpPost]
|
||||
[DisplayName("更新作业")]
|
||||
public async Task UpdateJobDetail(UpdateJobDetailInput input)
|
||||
{
|
||||
var isExist = await _sysJobDetailRep.IsAnyAsync(u => u.JobId == input.JobId && u.Id != input.Id);
|
||||
if (isExist) throw Oops.Oh(ErrorCodeEnum.D1006);
|
||||
|
||||
var sysJobDetail = await _sysJobDetailRep.GetFirstAsync(u => u.Id == input.Id);
|
||||
if (sysJobDetail.JobId != input.JobId) throw Oops.Oh(ErrorCodeEnum.D1704);
|
||||
|
||||
var scheduler = _schedulerFactory.GetJob(sysJobDetail.JobId);
|
||||
var oldScriptCode = sysJobDetail.ScriptCode; // 旧脚本代码
|
||||
input.Adapt(sysJobDetail);
|
||||
|
||||
if (input.CreateType == JobCreateTypeEnum.Script)
|
||||
{
|
||||
if (string.IsNullOrEmpty(input.ScriptCode)) throw Oops.Oh(ErrorCodeEnum.D1701);
|
||||
|
||||
if (input.ScriptCode != oldScriptCode)
|
||||
{
|
||||
// 动态创建作业
|
||||
var jobType = _dynamicJobCompiler.BuildJob(input.ScriptCode);
|
||||
|
||||
if (jobType.GetCustomAttributes(typeof(JobDetailAttribute)).FirstOrDefault() is not JobDetailAttribute jobDetailAttribute)
|
||||
throw Oops.Oh(ErrorCodeEnum.D1702);
|
||||
if (jobDetailAttribute.JobId != input.JobId) throw Oops.Oh(ErrorCodeEnum.D1703);
|
||||
|
||||
scheduler?.UpdateDetail(JobBuilder.Create(jobType).LoadFrom(sysJobDetail).SetJobType(jobType));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
scheduler?.UpdateDetail(scheduler.GetJobBuilder().LoadFrom(sysJobDetail));
|
||||
}
|
||||
|
||||
// Tip: 假如这次更新有变更了 JobId,变更 JobId 后触发的持久化更新执行,会由于找不到 JobId 而更新不到数据
|
||||
// 延迟一下等待持久化写入,再执行其他字段的更新
|
||||
await Task.Delay(500);
|
||||
await _sysJobDetailRep.UpdateAsync(sysJobDetail);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除作业 ⏰
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[ApiDescriptionSettings(Name = "DeleteJobDetail"), HttpPost]
|
||||
[DisplayName("删除作业")]
|
||||
public async Task DeleteJobDetail(DeleteJobDetailInput input)
|
||||
{
|
||||
_schedulerFactory.RemoveJob(input.JobId);
|
||||
|
||||
// 如果 _schedulerFactory 中不存在 JodId,则无法触发持久化,下面的代码确保作业和触发器能被删除
|
||||
await _sysJobDetailRep.DeleteAsync(u => u.JobId == input.JobId);
|
||||
await _sysJobTriggerRep.DeleteAsync(u => u.JobId == input.JobId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取触发器列表 ⏰
|
||||
/// </summary>
|
||||
[DisplayName("获取触发器列表")]
|
||||
public async Task<List<SysJobTrigger>> GetJobTriggerList([FromQuery] JobDetailInput input)
|
||||
{
|
||||
return await _sysJobTriggerRep.AsQueryable()
|
||||
.WhereIF(!string.IsNullOrWhiteSpace(input.JobId), u => u.JobId.Contains(input.JobId))
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加触发器 ⏰
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[ApiDescriptionSettings(Name = "AddJobTrigger"), HttpPost]
|
||||
[DisplayName("添加触发器")]
|
||||
public async Task AddJobTrigger(AddJobTriggerInput input)
|
||||
{
|
||||
var isExist = await _sysJobTriggerRep.IsAnyAsync(u => u.TriggerId == input.TriggerId && u.Id != input.Id);
|
||||
if (isExist) throw Oops.Oh(ErrorCodeEnum.D1006);
|
||||
|
||||
var jobTrigger = input.Adapt<SysJobTrigger>();
|
||||
jobTrigger.Args = "[" + jobTrigger.Args + "]";
|
||||
|
||||
var scheduler = _schedulerFactory.GetJob(input.JobId);
|
||||
scheduler?.AddTrigger(Triggers.Create(input.AssemblyName, input.TriggerType).LoadFrom(jobTrigger));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新触发器 ⏰
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[ApiDescriptionSettings(Name = "UpdateJobTrigger"), HttpPost]
|
||||
[DisplayName("更新触发器")]
|
||||
public async Task UpdateJobTrigger(UpdateJobTriggerInput input)
|
||||
{
|
||||
var isExist = await _sysJobTriggerRep.IsAnyAsync(u => u.TriggerId == input.TriggerId && u.Id != input.Id);
|
||||
if (isExist) throw Oops.Oh(ErrorCodeEnum.D1006);
|
||||
|
||||
var jobTrigger = input.Adapt<SysJobTrigger>();
|
||||
if (jobTrigger.EndTime.HasValue && jobTrigger.EndTime.Value.Year < 1901)
|
||||
{
|
||||
jobTrigger.EndTime = null;
|
||||
}
|
||||
if (jobTrigger.StartTime.HasValue && jobTrigger.StartTime.Value.Year < 1901)
|
||||
{
|
||||
jobTrigger.StartTime = null;
|
||||
}
|
||||
jobTrigger.Args = "[" + jobTrigger.Args + "]";
|
||||
|
||||
var scheduler = _schedulerFactory.GetJob(input.JobId);
|
||||
scheduler?.UpdateTrigger(Triggers.Create(input.AssemblyName, input.TriggerType).LoadFrom(jobTrigger));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除触发器 ⏰
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[ApiDescriptionSettings(Name = "DeleteJobTrigger"), HttpPost]
|
||||
[DisplayName("删除触发器")]
|
||||
public async Task DeleteJobTrigger(DeleteJobTriggerInput input)
|
||||
{
|
||||
var scheduler = _schedulerFactory.GetJob(input.JobId);
|
||||
scheduler?.RemoveTrigger(input.TriggerId);
|
||||
|
||||
// 如果 _schedulerFactory 中不存在 JodId,则无法触发持久化,下行代码确保触发器能被删除
|
||||
await _sysJobTriggerRep.DeleteAsync(u => u.JobId == input.JobId && u.TriggerId == input.TriggerId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 暂停所有作业 ⏰
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[DisplayName("暂停所有作业")]
|
||||
public void PauseAllJob()
|
||||
{
|
||||
_schedulerFactory.PauseAll();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 启动所有作业 ⏰
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[DisplayName("启动所有作业")]
|
||||
public void StartAllJob()
|
||||
{
|
||||
_schedulerFactory.StartAll();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 暂停作业 ⏰
|
||||
/// </summary>
|
||||
[DisplayName("暂停作业")]
|
||||
public void PauseJob(JobDetailInput input)
|
||||
{
|
||||
_schedulerFactory.TryPauseJob(input.JobId, out _);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 启动作业 ⏰
|
||||
/// </summary>
|
||||
[DisplayName("启动作业")]
|
||||
public void StartJob(JobDetailInput input)
|
||||
{
|
||||
_schedulerFactory.TryStartJob(input.JobId, out _);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 取消作业 ⏰
|
||||
/// </summary>
|
||||
[DisplayName("取消作业")]
|
||||
public void CancelJob(JobDetailInput input)
|
||||
{
|
||||
_schedulerFactory.TryCancelJob(input.JobId, out _);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行作业 ⏰
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
[DisplayName("执行作业")]
|
||||
public void RunJob(JobDetailInput input)
|
||||
{
|
||||
if (_schedulerFactory.TryRunJob(input.JobId, out _) != ScheduleResult.Succeed) throw Oops.Oh(ErrorCodeEnum.D1705);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 暂停触发器 ⏰
|
||||
/// </summary>
|
||||
[DisplayName("暂停触发器")]
|
||||
public void PauseTrigger(JobTriggerInput input)
|
||||
{
|
||||
var scheduler = _schedulerFactory.GetJob(input.JobId);
|
||||
scheduler?.PauseTrigger(input.TriggerId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 启动触发器 ⏰
|
||||
/// </summary>
|
||||
[DisplayName("启动触发器")]
|
||||
public void StartTrigger(JobTriggerInput input)
|
||||
{
|
||||
var scheduler = _schedulerFactory.GetJob(input.JobId);
|
||||
scheduler?.StartTrigger(input.TriggerId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 强制唤醒作业调度器 ⏰
|
||||
/// </summary>
|
||||
[DisplayName("强制唤醒作业调度器")]
|
||||
public void CancelSleep()
|
||||
{
|
||||
_schedulerFactory.CancelSleep();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 强制触发所有作业持久化 ⏰
|
||||
/// </summary>
|
||||
[DisplayName("强制触发所有作业持久化")]
|
||||
public void PersistAll()
|
||||
{
|
||||
_schedulerFactory.PersistAll();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取集群列表 ⏰
|
||||
/// </summary>
|
||||
[DisplayName("获取集群列表")]
|
||||
public async Task<List<SysJobCluster>> GetJobClusterList()
|
||||
{
|
||||
return await _sysJobClusterRep.GetListAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取作业触发器运行记录分页列表 ⏰
|
||||
/// </summary>
|
||||
[DisplayName("获取作业触发器运行记录分页列表")]
|
||||
public async Task<SqlSugarPagedList<SysJobTriggerRecord>> PageJobTriggerRecord(PageJobTriggerRecordInput input)
|
||||
{
|
||||
return await _sysJobTriggerRecordRep.AsQueryable()
|
||||
.WhereIF(!string.IsNullOrWhiteSpace(input.JobId), u => u.JobId == input.JobId)
|
||||
.WhereIF(!string.IsNullOrWhiteSpace(input.TriggerId), u => u.TriggerId == input.TriggerId)
|
||||
.OrderByDescending(u => u.Id)
|
||||
.ToPagedListAsync(input.Page, input.PageSize);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清空作业触发器运行记录 🔖
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[ApiDescriptionSettings(Name = "ClearJobTriggerRecord"), HttpPost]
|
||||
[DisplayName("清空作业触发器运行记录")]
|
||||
public void ClearJobTriggerRecord()
|
||||
{
|
||||
_sysJobTriggerRecordRep.AsSugarClient().DbMaintenance.TruncateTable<SysJobTriggerRecord>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清空不保留的作业触发器运行记录 🔖
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[NonAction]
|
||||
[DisplayName("清空过期的作业触发器运行记录")]
|
||||
public async Task ClearExpireJobTriggerRecord(SysJobTriggerRecord input)
|
||||
{
|
||||
int keepRecords = 30;//保留记录条数
|
||||
// 使用CopyNew()创建新的数据库连接实例,避免连接冲突
|
||||
var db = _sysJobTriggerRecordRep.AsSugarClient().CopyNew();
|
||||
await db.Deleteable<SysJobTriggerRecord>().In(it => it.Id,
|
||||
db.Queryable<SysJobTriggerRecord>()
|
||||
.Skip(keepRecords)
|
||||
.OrderByDescending(it => it.LastRunTime)
|
||||
.Where(u => u.JobId == input.JobId && u.TriggerId == input.TriggerId)
|
||||
.Select(it => it.Id) //注意Select不要ToList(), ToList就2次查询了
|
||||
).ExecuteCommandAsync();
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core.Service;
|
||||
|
||||
public static class OAuthClaim
|
||||
{
|
||||
public const string GiteeAvatarUrl = "urn:gitee:avatar_url";
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
|
||||
namespace Admin.NET.Core;
|
||||
|
||||
public static class OAuthSetup
|
||||
{
|
||||
/// <summary>
|
||||
/// 三方授权登录OAuth注册
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
public static void AddOAuth(this IServiceCollection services)
|
||||
{
|
||||
var authOpt = App.GetConfig<OAuthOptions>("OAuth", true);
|
||||
services.AddAuthentication(options =>
|
||||
{
|
||||
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
|
||||
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||
})
|
||||
.AddCookie(options =>
|
||||
{
|
||||
options.Cookie.SameSite = SameSiteMode.Lax;
|
||||
})
|
||||
.AddWeixin(options =>
|
||||
{
|
||||
options.ClientId = authOpt.Weixin?.ClientId!;
|
||||
options.ClientSecret = authOpt.Weixin?.ClientSecret!;
|
||||
})
|
||||
.AddGitee(options =>
|
||||
{
|
||||
options.ClientId = authOpt.Gitee?.ClientId!;
|
||||
options.ClientSecret = authOpt.Gitee?.ClientSecret!;
|
||||
|
||||
options.ClaimActions.MapJsonKey(OAuthClaim.GiteeAvatarUrl, "avatar_url");
|
||||
});
|
||||
}
|
||||
|
||||
public static void UseOAuth(this IApplicationBuilder app)
|
||||
{
|
||||
app.UseCookiePolicy(new CookiePolicyOptions { MinimumSameSitePolicy = SameSiteMode.Lax });
|
||||
}
|
||||
}
|
||||
@@ -1,120 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using System.Security.Claims;
|
||||
|
||||
namespace Admin.NET.Core.Service;
|
||||
|
||||
/// <summary>
|
||||
/// 系统OAuth服务 🧩
|
||||
/// </summary>
|
||||
[AllowAnonymous]
|
||||
[ApiDescriptionSettings(Order = 498)]
|
||||
public class SysOAuthService : IDynamicApiController, ITransient
|
||||
{
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
private readonly SqlSugarRepository<SysWechatUser> _sysWechatUserRep;
|
||||
|
||||
public SysOAuthService(IHttpContextAccessor httpContextAccessor,
|
||||
SqlSugarRepository<SysWechatUser> sysWechatUserRep)
|
||||
{
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
_sysWechatUserRep = sysWechatUserRep;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 第三方登录 🔖
|
||||
/// </summary>
|
||||
/// <param name="provider"></param>
|
||||
/// <param name="redirectUrl"></param>
|
||||
/// <returns></returns>
|
||||
[ApiDescriptionSettings(Name = "SignIn"), HttpGet]
|
||||
[DisplayName("第三方登录")]
|
||||
public virtual async Task<IActionResult> SignIn([FromQuery] string provider, [FromQuery] string redirectUrl)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(provider) || !await _httpContextAccessor.HttpContext.IsProviderSupportedAsync(provider))
|
||||
throw Oops.Oh("不支持的OAuth类型");
|
||||
|
||||
var request = _httpContextAccessor.HttpContext!.Request;
|
||||
var url = $"{request.Scheme}://{request.Host}{request.PathBase}{request.Path}Callback?provider={provider}&redirectUrl={redirectUrl}";
|
||||
var properties = new AuthenticationProperties
|
||||
{
|
||||
RedirectUri = url,
|
||||
Items = { ["LoginProvider"] = provider }
|
||||
};
|
||||
return await Task.FromResult(new ChallengeResult(provider, properties));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 授权回调 🔖
|
||||
/// </summary>
|
||||
/// <param name="provider"></param>
|
||||
/// <param name="redirectUrl"></param>
|
||||
/// <returns></returns>
|
||||
[ApiDescriptionSettings(Name = "SignInCallback"), HttpGet]
|
||||
[DisplayName("授权回调")]
|
||||
public virtual async Task<IActionResult> SignInCallback([FromQuery] string provider = null, [FromQuery] string redirectUrl = "")
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(provider) || !await _httpContextAccessor.HttpContext.IsProviderSupportedAsync(provider))
|
||||
throw Oops.Oh("不支持的OAuth类型");
|
||||
|
||||
var authenticateResult = await _httpContextAccessor.HttpContext!.AuthenticateAsync(provider);
|
||||
if (!authenticateResult.Succeeded)
|
||||
throw Oops.Oh("授权失败");
|
||||
|
||||
var openIdClaim = authenticateResult.Principal.FindFirst(ClaimTypes.NameIdentifier);
|
||||
if (openIdClaim == null || string.IsNullOrWhiteSpace(openIdClaim.Value))
|
||||
throw Oops.Oh("授权失败");
|
||||
|
||||
var name = authenticateResult.Principal.FindFirst(ClaimTypes.Name)?.Value;
|
||||
var email = authenticateResult.Principal.FindFirst(ClaimTypes.Email)?.Value;
|
||||
var mobilePhone = authenticateResult.Principal.FindFirst(ClaimTypes.MobilePhone)?.Value;
|
||||
var dateOfBirth = authenticateResult.Principal.FindFirst(ClaimTypes.DateOfBirth)?.Value;
|
||||
var gender = authenticateResult.Principal.FindFirst(ClaimTypes.Gender)?.Value;
|
||||
var avatarUrl = "";
|
||||
|
||||
var platformType = PlatformTypeEnum.微信公众号;
|
||||
if (provider == "Gitee")
|
||||
{
|
||||
platformType = PlatformTypeEnum.Gitee;
|
||||
avatarUrl = authenticateResult.Principal.FindFirst(OAuthClaim.GiteeAvatarUrl)?.Value;
|
||||
}
|
||||
|
||||
// 若账号不存在则新建
|
||||
var wechatUser = await _sysWechatUserRep.AsQueryable().Includes(u => u.SysUser).ClearFilter().FirstAsync(u => u.OpenId == openIdClaim.Value);
|
||||
if (wechatUser == null)
|
||||
{
|
||||
var userId = await App.GetRequiredService<SysUserService>().AddUser(new AddUserInput()
|
||||
{
|
||||
Account = name,
|
||||
RealName = name,
|
||||
NickName = name,
|
||||
Email = email,
|
||||
Avatar = avatarUrl,
|
||||
Phone = mobilePhone,
|
||||
OrgId = 1300000000101, // 根组织架构
|
||||
RoleIdList = new List<long> { 1300000000104 } // 仅本人数据角色
|
||||
});
|
||||
|
||||
await _sysWechatUserRep.InsertAsync(new SysWechatUser()
|
||||
{
|
||||
UserId = userId,
|
||||
OpenId = openIdClaim.Value,
|
||||
Avatar = avatarUrl,
|
||||
NickName = name,
|
||||
PlatformType = platformType
|
||||
});
|
||||
|
||||
wechatUser = await _sysWechatUserRep.AsQueryable().Includes(u => u.SysUser).ClearFilter().FirstAsync(u => u.OpenId == openIdClaim.Value);
|
||||
}
|
||||
|
||||
// 构建Token令牌
|
||||
var token = await App.GetRequiredService<SysAuthService>().CreateToken(wechatUser.SysUser);
|
||||
|
||||
return new RedirectResult($"{redirectUrl}/#/login?token={token.AccessToken}");
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core.Service;
|
||||
|
||||
public class PagePluginInput : BasePageInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 名称
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 编码
|
||||
/// </summary>
|
||||
public string Code { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 租户Id
|
||||
/// </summary>
|
||||
public long TenantId { get; set; }
|
||||
}
|
||||
|
||||
public class AddPluginInput : SysPlugin
|
||||
{
|
||||
/// <summary>
|
||||
/// 名称
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "功能名称不能为空")]
|
||||
public override string Name { get; set; }
|
||||
}
|
||||
|
||||
public class UpdatePluginInput : AddPluginInput
|
||||
{
|
||||
}
|
||||
|
||||
public class DeletePluginInput : BaseIdInput
|
||||
{
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core.Service;
|
||||
|
||||
/// <summary>
|
||||
/// 系统动态插件服务 🧩
|
||||
/// </summary>
|
||||
[ApiDescriptionSettings(Order = 245)]
|
||||
public class SysPluginService : IDynamicApiController, ITransient
|
||||
{
|
||||
private readonly IDynamicApiRuntimeChangeProvider _provider;
|
||||
private readonly SqlSugarRepository<SysPlugin> _sysPluginRep;
|
||||
private readonly UserManager _userManager;
|
||||
|
||||
public SysPluginService(IDynamicApiRuntimeChangeProvider provider,
|
||||
SqlSugarRepository<SysPlugin> sysPluginRep,
|
||||
UserManager userManager)
|
||||
{
|
||||
_provider = provider;
|
||||
_userManager = userManager;
|
||||
_sysPluginRep = sysPluginRep;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取动态插件列表 🧩
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("获取动态插件列表")]
|
||||
public async Task<SqlSugarPagedList<SysPlugin>> Page(PagePluginInput input)
|
||||
{
|
||||
return await _sysPluginRep.AsQueryable()
|
||||
.WhereIF(_userManager.SuperAdmin && input.TenantId > 0, u => u.TenantId == input.TenantId)
|
||||
.WhereIF(!string.IsNullOrWhiteSpace(input.Name), u => u.Name.Contains(input.Name))
|
||||
.OrderBy(u => new { u.OrderNo, u.Id })
|
||||
.ToPagedListAsync(input.Page, input.PageSize);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 增加动态插件 🧩
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[ApiDescriptionSettings(Name = "Add"), HttpPost]
|
||||
[DisplayName("增加动态插件")]
|
||||
public async Task AddPlugin(AddPluginInput input)
|
||||
{
|
||||
var isExist = await _sysPluginRep.IsAnyAsync(u => u.Name == input.Name || u.AssemblyName == input.AssemblyName);
|
||||
if (isExist) throw Oops.Oh(ErrorCodeEnum.D1900);
|
||||
|
||||
// 添加动态程序集/接口
|
||||
input.AssemblyName = CompileAssembly(input.CsharpCode, input.AssemblyName);
|
||||
|
||||
await _sysPluginRep.InsertAsync(input.Adapt<SysPlugin>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新动态插件 🧩
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[ApiDescriptionSettings(Name = "Update"), HttpPost]
|
||||
[DisplayName("更新动态插件")]
|
||||
public async Task UpdatePlugin(UpdatePluginInput input)
|
||||
{
|
||||
var isExist = await _sysPluginRep.IsAnyAsync(u => (u.Name == input.Name || u.AssemblyName == input.AssemblyName) && u.Id != input.Id);
|
||||
if (isExist) throw Oops.Oh(ErrorCodeEnum.D1900);
|
||||
|
||||
// 先移除再添加动态程序集/接口
|
||||
RemoveAssembly(input.AssemblyName);
|
||||
input.AssemblyName = CompileAssembly(input.CsharpCode);
|
||||
|
||||
await _sysPluginRep.AsUpdateable(input.Adapt<SysPlugin>()).IgnoreColumns(true).ExecuteCommandAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除动态插件 🧩
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[ApiDescriptionSettings(Name = "Delete"), HttpPost]
|
||||
[DisplayName("删除动态插件")]
|
||||
public async Task DeletePlugin(DeletePluginInput input)
|
||||
{
|
||||
var plugin = await _sysPluginRep.GetByIdAsync(input.Id);
|
||||
if (plugin == null) return;
|
||||
|
||||
// 移除动态程序集/接口
|
||||
RemoveAssembly(plugin.AssemblyName);
|
||||
|
||||
await _sysPluginRep.DeleteAsync(u => u.Id == input.Id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加动态程序集/接口 🧩
|
||||
/// </summary>
|
||||
/// <param name="csharpCode"></param>
|
||||
/// <param name="assemblyName">程序集名称</param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("添加动态程序集/接口")]
|
||||
public string CompileAssembly([FromBody] string csharpCode, [FromQuery] string assemblyName = default)
|
||||
{
|
||||
// 编译 C# 代码并返回动态程序集
|
||||
var dynamicAssembly = App.CompileCSharpClassCode(csharpCode, assemblyName);
|
||||
|
||||
// 将程序集添加进动态 WebAPI 应用部件
|
||||
_provider.AddAssembliesWithNotifyChanges(dynamicAssembly);
|
||||
|
||||
// 返回动态程序集名称
|
||||
return dynamicAssembly.GetName().Name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移除动态程序集/接口 🧩
|
||||
/// </summary>
|
||||
[ApiDescriptionSettings(Name = "RemoveAssembly"), HttpPost]
|
||||
[DisplayName("移除动态程序集/接口")]
|
||||
public void RemoveAssembly(string assemblyName)
|
||||
{
|
||||
_provider.RemoveAssembliesWithNotifyChanges(assemblyName);
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core.Service;
|
||||
|
||||
public class PagePrintInput : BasePageInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 名称
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 编码
|
||||
/// </summary>
|
||||
public string Code { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 租户Id
|
||||
/// </summary>
|
||||
public long TenantId { get; set; }
|
||||
}
|
||||
|
||||
public class AddPrintInput : SysPrint
|
||||
{
|
||||
/// <summary>
|
||||
/// 名称
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "模板名称不能为空")]
|
||||
public override string Name { get; set; }
|
||||
}
|
||||
|
||||
public class UpdatePrintInput : AddPrintInput
|
||||
{
|
||||
}
|
||||
|
||||
public class DeletePrintInput : BaseIdInput
|
||||
{
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core.Service;
|
||||
|
||||
/// <summary>
|
||||
/// 系统打印模板服务 🧩
|
||||
/// </summary>
|
||||
[ApiDescriptionSettings(Order = 305)]
|
||||
public class SysPrintService : IDynamicApiController, ITransient
|
||||
{
|
||||
private readonly SqlSugarRepository<SysPrint> _sysPrintRep;
|
||||
private readonly UserManager _userManager;
|
||||
|
||||
public SysPrintService(SqlSugarRepository<SysPrint> sysPrintRep, UserManager userManager)
|
||||
{
|
||||
_sysPrintRep = sysPrintRep;
|
||||
_userManager = userManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取打印模板列表 🖨️
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("获取打印模板列表")]
|
||||
public async Task<SqlSugarPagedList<SysPrint>> Page(PagePrintInput input)
|
||||
{
|
||||
return await _sysPrintRep.AsQueryable()
|
||||
.WhereIF(_userManager.SuperAdmin && input.TenantId > 0, u => u.TenantId == input.TenantId)
|
||||
.WhereIF(!string.IsNullOrWhiteSpace(input.Name), u => u.Name.Contains(input.Name))
|
||||
.OrderBy(u => new { u.OrderNo, u.Id })
|
||||
.ToPagedListAsync(input.Page, input.PageSize);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取打印模板 🖨️
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("获取打印模板")]
|
||||
public async Task<SysPrint> GetPrint(string name)
|
||||
{
|
||||
return await _sysPrintRep.GetFirstAsync(u => u.Name == name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 增加打印模板 🖨️
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[ApiDescriptionSettings(Name = "Add"), HttpPost]
|
||||
[DisplayName("增加打印模板")]
|
||||
public async Task AddPrint(AddPrintInput input)
|
||||
{
|
||||
var isExist = await _sysPrintRep.IsAnyAsync(u => u.Name == input.Name);
|
||||
if (isExist) throw Oops.Oh(ErrorCodeEnum.D1800);
|
||||
|
||||
await _sysPrintRep.InsertAsync(input.Adapt<SysPrint>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新打印模板 🖨️
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[ApiDescriptionSettings(Name = "Update"), HttpPost]
|
||||
[DisplayName("更新打印模板")]
|
||||
public async Task UpdatePrint(UpdatePrintInput input)
|
||||
{
|
||||
var isExist = await _sysPrintRep.IsAnyAsync(u => u.Name == input.Name && u.Id != input.Id);
|
||||
if (isExist) throw Oops.Oh(ErrorCodeEnum.D1800);
|
||||
|
||||
await _sysPrintRep.AsUpdateable(input.Adapt<SysPrint>()).IgnoreColumns(true).ExecuteCommandAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除打印模板 🖨️
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[ApiDescriptionSettings(Name = "Delete"), HttpPost]
|
||||
[DisplayName("删除打印模板")]
|
||||
public async Task DeletePrint(DeletePrintInput input)
|
||||
{
|
||||
await _sysPrintRep.DeleteAsync(u => u.Id == input.Id);
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core.Service;
|
||||
|
||||
public class ScheduleInput : BaseIdInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 状态
|
||||
/// </summary>
|
||||
public virtual FinishStatusEnum Status { get; set; }
|
||||
}
|
||||
|
||||
public class ListScheduleInput
|
||||
{
|
||||
public DateTime? StartTime { get; set; }
|
||||
|
||||
public DateTime? EndTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 租户Id
|
||||
/// </summary>
|
||||
public long TenantId { get; set; }
|
||||
}
|
||||
|
||||
public class AddScheduleInput : SysSchedule
|
||||
{
|
||||
/// <summary>
|
||||
/// 日程内容
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "日程内容不能为空")]
|
||||
public override string Content { get; set; }
|
||||
}
|
||||
|
||||
public class UpdateScheduleInput : AddScheduleInput
|
||||
{
|
||||
}
|
||||
|
||||
public class DeleteScheduleInput : BaseIdInput
|
||||
{
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core.Service;
|
||||
|
||||
/// <summary>
|
||||
/// 系统日程服务
|
||||
/// </summary>
|
||||
[ApiDescriptionSettings(Order = 295)]
|
||||
public class SysScheduleService : IDynamicApiController, ITransient
|
||||
{
|
||||
private readonly UserManager _userManager;
|
||||
private readonly SqlSugarRepository<SysSchedule> _sysSchedule;
|
||||
|
||||
public SysScheduleService(UserManager userManager,
|
||||
SqlSugarRepository<SysSchedule> sysSchedule)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_sysSchedule = sysSchedule;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取日程列表
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[DisplayName("获取日程列表")]
|
||||
public async Task<List<SysSchedule>> Page(ListScheduleInput input)
|
||||
{
|
||||
return await _sysSchedule.AsQueryable()
|
||||
.Where(u => u.UserId == _userManager.UserId)
|
||||
.WhereIF(_userManager.SuperAdmin && input.TenantId > 0, u => u.TenantId == input.TenantId)
|
||||
.WhereIF(!string.IsNullOrWhiteSpace(input.StartTime.ToString()), u => u.ScheduleTime >= input.StartTime)
|
||||
.WhereIF(!string.IsNullOrWhiteSpace(input.EndTime.ToString()), u => u.ScheduleTime <= input.EndTime)
|
||||
.OrderBy(u => u.StartTime, OrderByType.Asc)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取日程详情
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("获取日程详情")]
|
||||
public async Task<SysSchedule> GetDetail(long id)
|
||||
{
|
||||
return await _sysSchedule.GetFirstAsync(u => u.Id == id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 增加日程
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[ApiDescriptionSettings(Name = "Add"), HttpPost]
|
||||
[DisplayName("增加日程")]
|
||||
public async Task AddUserSchedule(AddScheduleInput input)
|
||||
{
|
||||
input.UserId = _userManager.UserId;
|
||||
await _sysSchedule.InsertAsync(input.Adapt<SysSchedule>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新日程
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[ApiDescriptionSettings(Name = "Update"), HttpPost]
|
||||
[DisplayName("更新日程")]
|
||||
public async Task UpdateUserSchedule(UpdateScheduleInput input)
|
||||
{
|
||||
await _sysSchedule.AsUpdateable(input.Adapt<SysSchedule>()).IgnoreColumns(true).ExecuteCommandAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除日程
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[ApiDescriptionSettings(Name = "Delete"), HttpPost]
|
||||
[DisplayName("删除日程")]
|
||||
public async Task DeleteUserSchedule(DeleteScheduleInput input)
|
||||
{
|
||||
await _sysSchedule.DeleteAsync(u => u.Id == input.Id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置日程状态
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("设置日程状态")]
|
||||
public async Task<int> SetStatus(ScheduleInput input)
|
||||
{
|
||||
if (!Enum.IsDefined(typeof(FinishStatusEnum), input.Status)) throw Oops.Oh(ErrorCodeEnum.D3005);
|
||||
|
||||
return await _sysSchedule.AsUpdateable()
|
||||
.SetColumns(u => u.Status == input.Status)
|
||||
.Where(u => u.Id == input.Id)
|
||||
.ExecuteCommandAsync();
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
@@ -136,8 +136,6 @@ public class SysServerService : IDynamicApiController, ITransient
|
||||
var pdfAssembly = typeof(Magicodes.ExporterAndImporter.Pdf.IPdfExporter).Assembly.GetName();
|
||||
var wordAssembly = typeof(Magicodes.ExporterAndImporter.Word.IWordExporter).Assembly.GetName();
|
||||
var captchaAssembly = typeof(Lazy.Captcha.Core.ICaptcha).Assembly.GetName();
|
||||
var wechatApiAssembly = typeof(WechatApiClient).Assembly.GetName();
|
||||
var wechatTenpayAssembly = typeof(WechatTenpayClient).Assembly.GetName();
|
||||
var ossAssembly = typeof(OnceMi.AspNetCore.OSS.IOSSServiceFactory).Assembly.GetName();
|
||||
var parserAssembly = typeof(Parser).Assembly.GetName();
|
||||
var elasticsearchClientAssembly = typeof(Elastic.Clients.Elasticsearch.ElasticsearchClient).Assembly.GetName();
|
||||
@@ -148,10 +146,7 @@ public class SysServerService : IDynamicApiController, ITransient
|
||||
var alibabaSendSmsRequestAssembly = typeof(AlibabaCloud.SDK.Dysmsapi20170525.Models.SendSmsRequest).Assembly.GetName();
|
||||
var tencentSendSmsRequestAssembly = typeof(TencentCloud.Sms.V20190711.Models.SendSmsRequest).Assembly.GetName();
|
||||
var rabbitMQAssembly = typeof(RabbitMQEventSourceStore).Assembly.GetName();
|
||||
var ldapConnectionAssembly = typeof(Novell.Directory.Ldap.LdapConnection).Assembly.GetName();
|
||||
var ipToolAssembly = typeof(IPTools.Core.IpTool).Assembly.GetName();
|
||||
var weixinAuthenticationOptionsAssembly = typeof(AspNet.Security.OAuth.Weixin.WeixinAuthenticationOptions).Assembly.GetName();
|
||||
var giteeAuthenticationOptionsAssembly = typeof(AspNet.Security.OAuth.Gitee.GiteeAuthenticationOptions).Assembly.GetName();
|
||||
var hashidsAssembly = typeof(HashidsNet.Hashids).Assembly.GetName();
|
||||
var sftpClientAssembly = typeof(Renci.SshNet.SftpClient).Assembly.GetName();
|
||||
var hardwareInfoAssembly = typeof(Hardware.Info.HardwareInfo).Assembly.GetName();
|
||||
@@ -167,8 +162,6 @@ public class SysServerService : IDynamicApiController, ITransient
|
||||
new { pdfAssembly.Name, pdfAssembly.Version },
|
||||
new { wordAssembly.Name, wordAssembly.Version },
|
||||
new { captchaAssembly.Name, captchaAssembly.Version },
|
||||
new { wechatApiAssembly.Name, wechatApiAssembly.Version },
|
||||
new { wechatTenpayAssembly.Name, wechatTenpayAssembly.Version },
|
||||
new { ossAssembly.Name, ossAssembly.Version },
|
||||
new { parserAssembly.Name, parserAssembly.Version },
|
||||
new { elasticsearchClientAssembly.Name, elasticsearchClientAssembly.Version },
|
||||
@@ -179,13 +172,10 @@ public class SysServerService : IDynamicApiController, ITransient
|
||||
new { alibabaSendSmsRequestAssembly.Name, alibabaSendSmsRequestAssembly.Version },
|
||||
new { tencentSendSmsRequestAssembly.Name, tencentSendSmsRequestAssembly.Version },
|
||||
new { rabbitMQAssembly.Name, rabbitMQAssembly.Version },
|
||||
new { ldapConnectionAssembly.Name, ldapConnectionAssembly.Version },
|
||||
new { ipToolAssembly.Name, ipToolAssembly.Version },
|
||||
new { weixinAuthenticationOptionsAssembly.Name, weixinAuthenticationOptionsAssembly.Version },
|
||||
new { giteeAuthenticationOptionsAssembly.Name, giteeAuthenticationOptionsAssembly.Version },
|
||||
new { hashidsAssembly.Name, hashidsAssembly.Version },
|
||||
new { sftpClientAssembly.Name, sftpClientAssembly.Version },
|
||||
new { hardwareInfoAssembly.Name, hardwareInfoAssembly.Version },
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
@@ -65,12 +65,6 @@ public class AddUserInput : SysUser
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "真实姓名不能为空")]
|
||||
public override string RealName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 域用户
|
||||
/// </summary>
|
||||
public string DomainAccount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 角色集合
|
||||
/// </summary>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
@@ -21,10 +21,4 @@ public class UserOutput : SysUser
|
||||
/// <summary>
|
||||
/// 角色名称
|
||||
/// </summary>
|
||||
public string RoleName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 域用户
|
||||
/// </summary>
|
||||
public string DomainAccount { get; set; }
|
||||
}
|
||||
public string RoleName { get; set; }}
|
||||
@@ -1,66 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core.Service;
|
||||
|
||||
/// <summary>
|
||||
/// 用户域账号服务
|
||||
/// </summary>
|
||||
public class SysUserLdapService : ITransient
|
||||
{
|
||||
private readonly SqlSugarRepository<SysUserLdap> _sysUserLdapRep;
|
||||
|
||||
public SysUserLdapService(SqlSugarRepository<SysUserLdap> sysUserLdapRep)
|
||||
{
|
||||
_sysUserLdapRep = sysUserLdapRep;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 批量插入域账号
|
||||
/// </summary>
|
||||
/// <param name="tenantId"></param>
|
||||
/// <param name="sysUserLdapList"></param>
|
||||
/// <returns></returns>
|
||||
public async Task InsertUserLdapList(long tenantId, List<SysUserLdap> sysUserLdapList)
|
||||
{
|
||||
await _sysUserLdapRep.DeleteAsync(u => u.TenantId == tenantId);
|
||||
|
||||
await _sysUserLdapRep.InsertRangeAsync(sysUserLdapList);
|
||||
|
||||
await _sysUserLdapRep.AsUpdateable()
|
||||
.InnerJoin<SysUser>((l, u) => l.EmployeeId == u.Account)
|
||||
.SetColumns((l, u) => new SysUserLdap { UserId = u.Id })
|
||||
.Where((l, u) => l.TenantId == tenantId && u.Status == StatusEnum.Enable)
|
||||
.ExecuteCommandAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 增加域账号
|
||||
/// </summary>
|
||||
/// <param name="tenantId"></param>
|
||||
/// <param name="userId"></param>
|
||||
/// <param name="account"></param>
|
||||
/// <param name="domainAccount"></param>
|
||||
/// <returns></returns>
|
||||
public async Task AddUserLdap(long tenantId, long userId, string account, string domainAccount)
|
||||
{
|
||||
var userLdap = await _sysUserLdapRep.GetFirstAsync(u => u.TenantId == tenantId && (u.Account == account || u.UserId == userId || u.EmployeeId == domainAccount));
|
||||
if (userLdap != null) await _sysUserLdapRep.DeleteByIdAsync(userLdap.Id);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(domainAccount))
|
||||
await _sysUserLdapRep.InsertAsync(new SysUserLdap { EmployeeId = account, TenantId = tenantId, UserId = userId, Account = domainAccount });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除域账号
|
||||
/// </summary>
|
||||
/// <param name="userId"></param>
|
||||
/// <returns></returns>
|
||||
public async Task DeleteUserLdapByUserId(long userId)
|
||||
{
|
||||
await _sysUserLdapRep.DeleteAsync(u => u.UserId == userId);
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,6 @@ public class SysUserService : IDynamicApiController, ITransient
|
||||
private readonly SysOnlineUserService _sysOnlineUserService;
|
||||
private readonly SysUserMenuService _sysUserMenuService;
|
||||
private readonly SysCacheService _sysCacheService;
|
||||
private readonly SysUserLdapService _sysUserLdapService;
|
||||
private readonly SqlSugarRepository<SysUser> _sysUserRep;
|
||||
private readonly IEventPublisher _eventPublisher;
|
||||
|
||||
@@ -31,7 +30,6 @@ public class SysUserService : IDynamicApiController, ITransient
|
||||
SysConfigService sysConfigService,
|
||||
SysOnlineUserService sysOnlineUserService,
|
||||
SysCacheService sysCacheService,
|
||||
SysUserLdapService sysUserLdapService,
|
||||
SqlSugarRepository<SysUser> sysUserRep,
|
||||
SysUserMenuService sysUserMenuService,
|
||||
IEventPublisher eventPublisher)
|
||||
@@ -43,7 +41,6 @@ public class SysUserService : IDynamicApiController, ITransient
|
||||
_sysConfigService = sysConfigService;
|
||||
_sysOnlineUserService = sysOnlineUserService;
|
||||
_sysCacheService = sysCacheService;
|
||||
_sysUserLdapService = sysUserLdapService;
|
||||
_sysUserMenuService = sysUserMenuService;
|
||||
_sysUserRep = sysUserRep;
|
||||
_eventPublisher = eventPublisher;
|
||||
@@ -77,7 +74,6 @@ public class SysUserService : IDynamicApiController, ITransient
|
||||
OrgName = a.Name,
|
||||
PosName = b.Name,
|
||||
RoleName = SqlFunc.Subqueryable<SysUserRole>().LeftJoin<SysRole>((m, n) => m.RoleId == n.Id).Where(m => m.UserId == u.Id).SelectStringJoin((m, n) => n.Name, ","),
|
||||
DomainAccount = SqlFunc.Subqueryable<SysUserLdap>().Where(m => m.UserId == u.Id).Select(m => m.Account)
|
||||
}, true)
|
||||
.ToPagedListAsync(input.Page, input.PageSize);
|
||||
}
|
||||
@@ -110,10 +106,6 @@ public class SysUserService : IDynamicApiController, ITransient
|
||||
input.Id = newUser.Id;
|
||||
await UpdateRoleAndExtOrg(input);
|
||||
|
||||
// 增加域账号
|
||||
if (!string.IsNullOrWhiteSpace(input.DomainAccount))
|
||||
await _sysUserLdapService.AddUserLdap(newUser.TenantId!.Value, newUser.Id, newUser.Account, input.DomainAccount);
|
||||
|
||||
// 发布系统用户操作事件
|
||||
await _eventPublisher.PublishAsync(SysUserEventTypeEnum.Add, new
|
||||
{
|
||||
@@ -153,10 +145,6 @@ public class SysUserService : IDynamicApiController, ITransient
|
||||
input.Id = newUser.Id;
|
||||
await UpdateRoleAndExtOrg(input);
|
||||
|
||||
// 增加域账号
|
||||
if (!string.IsNullOrWhiteSpace(input.DomainAccount))
|
||||
await _sysUserLdapService.AddUserLdap(newUser.TenantId!.Value, newUser.Id, newUser.Account, input.DomainAccount);
|
||||
|
||||
// 发布系统用户操作事件
|
||||
await _eventPublisher.PublishAsync(SysUserEventTypeEnum.Register, new
|
||||
{
|
||||
@@ -199,8 +187,6 @@ public class SysUserService : IDynamicApiController, ITransient
|
||||
var roleIds = await GetOwnRoleList(input.Id);
|
||||
if (input.OrgId != user.OrgId || !input.RoleIdList.OrderBy(u => u).SequenceEqual(roleIds.OrderBy(u => u)))
|
||||
await _sysOnlineUserService.ForceOffline(input.Id);
|
||||
// 更新域账号
|
||||
await _sysUserLdapService.AddUserLdap(user.TenantId!.Value, user.Id, user.Account, input.DomainAccount);
|
||||
|
||||
// 发布系统用户操作事件
|
||||
await _eventPublisher.PublishAsync(SysUserEventTypeEnum.Update, new
|
||||
@@ -270,9 +256,6 @@ public class SysUserService : IDynamicApiController, ITransient
|
||||
// 删除用户扩展机构
|
||||
await _sysUserExtOrgService.DeleteUserExtOrgByUserId(input.Id);
|
||||
|
||||
// 删除域账号
|
||||
await _sysUserLdapService.DeleteUserLdapByUserId(input.Id);
|
||||
|
||||
// 删除用户收藏菜单
|
||||
await _sysUserMenuService.DeleteUserMenuList(input.Id);
|
||||
|
||||
|
||||
@@ -1,149 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core.Service;
|
||||
|
||||
/// <summary>
|
||||
/// 生成网页授权Url
|
||||
/// </summary>
|
||||
public class GenAuthUrlInput
|
||||
{
|
||||
/// <summary>
|
||||
/// RedirectUrl
|
||||
/// </summary>
|
||||
public string RedirectUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Scope
|
||||
/// </summary>
|
||||
public string Scope { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// State
|
||||
/// </summary>
|
||||
public string State { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取微信用户OpenId
|
||||
/// </summary>
|
||||
public class WechatOAuth2Input
|
||||
{
|
||||
/// <summary>
|
||||
/// Code
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "Code不能为空"), MinLength(10, ErrorMessage = "Code错误")]
|
||||
public string Code { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 微信用户登录
|
||||
/// </summary>
|
||||
public class WechatUserLogin
|
||||
{
|
||||
/// <summary>
|
||||
/// OpenId
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "微信标识不能为空"), MinLength(10, ErrorMessage = "微信标识长错误")]
|
||||
public string OpenId { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取配置签名
|
||||
/// </summary>
|
||||
public class SignatureInput
|
||||
{
|
||||
/// <summary>
|
||||
/// Url
|
||||
/// </summary>
|
||||
public string Url { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取消息模板列表
|
||||
/// </summary>
|
||||
public class MessageTemplateSendInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 订阅模板Id
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "订阅模板Id不能为空")]
|
||||
public string TemplateId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 接收者的OpenId
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "接收者的OpenId不能为空")]
|
||||
public string ToUserOpenId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 模板数据,格式形如 { "key1": { "value": any }, "key2": { "value": any } }
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "模板数据不能为空")]
|
||||
public Dictionary<string, CgibinMessageSubscribeSendRequest.Types.DataItem> Data { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 模板跳转链接
|
||||
/// </summary>
|
||||
public string Url { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 所需跳转到小程序的具体页面路径,支持带参数,(示例index?foo=bar)
|
||||
/// </summary>
|
||||
public string MiniProgramPagePath { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除消息模板
|
||||
/// </summary>
|
||||
public class DeleteMessageTemplateInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 订阅模板Id
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "订阅模板Id不能为空")]
|
||||
public string TemplateId { get; set; }
|
||||
}
|
||||
|
||||
public class UploadAvatarInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 小程序用户身份标识
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "OpenId不能为空")]
|
||||
public string OpenId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 文件
|
||||
/// </summary>
|
||||
[Required]
|
||||
public IFormFile File { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 文件类型
|
||||
/// </summary>
|
||||
public string FileType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 文件路径
|
||||
/// </summary>
|
||||
public string Path { get; set; }
|
||||
}
|
||||
|
||||
public class SetNickNameInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 小程序用户身份标识
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "OpenId不能为空")]
|
||||
public string OpenId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 昵称
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "昵称不能为空")]
|
||||
public string NickName { get; set; }
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core.Service;
|
||||
|
||||
public class WechatPayTransactionInput
|
||||
{
|
||||
/// <summary>
|
||||
/// OpenId
|
||||
/// </summary>
|
||||
public string OpenId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 订单金额
|
||||
/// </summary>
|
||||
public int Total { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 商品描述
|
||||
/// </summary>
|
||||
public string Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 附加数据
|
||||
/// </summary>
|
||||
public string Attachment { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 优惠标记
|
||||
/// </summary>
|
||||
public string GoodsTag { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 业务标签,用来区分做什么业务
|
||||
/// </summary>
|
||||
public string Tags { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 对应业务的主键
|
||||
/// </summary>
|
||||
public long BusinessId { get; set; }
|
||||
}
|
||||
|
||||
public class WechatPayParaInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 订单Id
|
||||
/// </summary>
|
||||
public string PrepayId { get; set; }
|
||||
}
|
||||
|
||||
public class WechatPayRefundDomesticInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 商户端生成的业务流水号
|
||||
/// </summary>
|
||||
[Required]
|
||||
public string TradeId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 退款原因
|
||||
/// </summary>
|
||||
public string Reason { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 退款金额
|
||||
/// </summary>
|
||||
[Required]
|
||||
public int Refund { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 原订单金额
|
||||
/// </summary>
|
||||
[Required]
|
||||
public int Total { get; set; }
|
||||
}
|
||||
|
||||
public class WechatPayPageInput : BasePageInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 添加时间范围
|
||||
/// </summary>
|
||||
public List<DateTime?> CreateTimeRange { get; set; }
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core.Service;
|
||||
|
||||
public class WechatPayOutput
|
||||
{
|
||||
/// <summary>
|
||||
/// OpenId
|
||||
/// </summary>
|
||||
public string OpenId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 订单金额
|
||||
/// </summary>
|
||||
public int Total { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 附加数据
|
||||
/// </summary>
|
||||
public string Attachment { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 优惠标记
|
||||
/// </summary>
|
||||
public string GoodsTag { get; set; }
|
||||
}
|
||||
|
||||
public class WechatPayTransactionOutput
|
||||
{
|
||||
public string PrepayId { get; set; }
|
||||
|
||||
public string OutTradeNumber { get; set; }
|
||||
|
||||
public WechatPayParaOutput SingInfo { get; set; }
|
||||
}
|
||||
|
||||
public class WechatPayParaOutput
|
||||
{
|
||||
public string AppId { get; set; }
|
||||
|
||||
public string TimeStamp { get; set; }
|
||||
|
||||
public string NonceStr { get; set; }
|
||||
|
||||
public string Package { get; set; }
|
||||
|
||||
public string SignType { get; set; }
|
||||
|
||||
public string PaySign { get; set; }
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core.Service;
|
||||
|
||||
public class WechatUserInput : BasePageInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 昵称
|
||||
/// </summary>
|
||||
public string NickName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 手机号码
|
||||
/// </summary>
|
||||
public string Mobile { get; set; }
|
||||
}
|
||||
|
||||
public class DeleteWechatUserInput : BaseIdInput
|
||||
{
|
||||
}
|
||||
@@ -1,150 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core.Service;
|
||||
|
||||
/// <summary>
|
||||
/// 获取微信用户OpenId
|
||||
/// </summary>
|
||||
public class JsCode2SessionInput
|
||||
{
|
||||
/// <summary>
|
||||
/// JsCode
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "JsCode不能为空"), MinLength(10, ErrorMessage = "JsCode错误")]
|
||||
public string JsCode { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取微信用户电话号码
|
||||
/// </summary>
|
||||
public class WxPhoneInput : WxOpenIdLoginInput
|
||||
{
|
||||
/// <summary>
|
||||
/// Code
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "Code不能为空"), MinLength(10, ErrorMessage = "Code错误")]
|
||||
public string Code { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 微信小程序登录
|
||||
/// </summary>
|
||||
public class WxOpenIdLoginInput
|
||||
{
|
||||
/// <summary>
|
||||
/// OpenId
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "微信标识不能为空"), MinLength(10, ErrorMessage = "微信标识错误")]
|
||||
public string OpenId { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 微信手机号登录
|
||||
/// </summary>
|
||||
public class WxPhoneLoginInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 电话号码
|
||||
/// </summary>
|
||||
[DataValidation(ValidationTypes.PhoneNumber, ErrorMessage = "电话号码错误")]
|
||||
public string PhoneNumber { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送订阅消息
|
||||
/// </summary>
|
||||
public class SendSubscribeMessageInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 订阅模板Id
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "订阅模板Id不能为空")]
|
||||
public string TemplateId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 接收者的OpenId
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "接收者的OpenId不能为空")]
|
||||
public string ToUserOpenId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 模板内容,格式形如 { "key1": { "value": any }, "key2": { "value": any } }
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "模板内容不能为空")]
|
||||
public Dictionary<string, CgibinMessageSubscribeSendRequest.Types.DataItem> Data { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 跳转小程序类型
|
||||
/// </summary>
|
||||
public string MiniprogramState { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 语言类型
|
||||
/// </summary>
|
||||
public string Language { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 点击模板卡片后的跳转页面(仅限本小程序内的页面),支持带参数(示例pages/app/index?foo=bar)
|
||||
/// </summary>
|
||||
public string MiniProgramPagePath { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 增加订阅消息模板
|
||||
/// </summary>
|
||||
public class AddSubscribeMessageTemplateInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 模板标题Id
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "模板标题Id不能为空")]
|
||||
public string TemplateTitleId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 模板关键词列表,例如 [3,5,4]
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "模板关键词列表不能为空")]
|
||||
public List<int> KeyworkIdList { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 服务场景描述,15个字以内
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "服务场景描述不能为空")]
|
||||
public string SceneDescription { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成带参数小程序二维码(总共生成的码数量限制为 100,000)
|
||||
/// </summary>
|
||||
public class GenerateQRImageInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 扫码进入的小程序页面路径,最大长度 128 个字符,不能为空; eg: pages/index?id=0001
|
||||
/// </summary>
|
||||
public string PagePath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 文件保存的名称
|
||||
/// </summary>
|
||||
public string ImageName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 图片宽度 默认430
|
||||
/// </summary>
|
||||
public int Width { get; set; } = 430;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成带参数小程序二维码(获取不受限制的小程序码)
|
||||
/// </summary>
|
||||
public class GenerateQRImageUnLimitInput : GenerateQRImageInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 二维码携带的参数 eg:a=1(最大32个可见字符,只支持数字,大小写英文以及部分特殊字符:<!-- !#$&'()*+,/:;=?@-._~ -->)
|
||||
/// </summary>
|
||||
public string Scene { get; set; }
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core.Service;
|
||||
|
||||
public class WxOpenIdOutput
|
||||
{
|
||||
public string OpenId { get; set; }
|
||||
}
|
||||
|
||||
public class WxPhoneOutput
|
||||
{
|
||||
public string PhoneNumber { get; set; }
|
||||
}
|
||||
|
||||
public class GenerateQRImageOutput
|
||||
{
|
||||
/// <summary>
|
||||
/// 生成状态
|
||||
/// </summary>
|
||||
public bool Success { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 生成图片的绝对路径
|
||||
/// </summary>
|
||||
public string ImgPath { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// 生成图片的相对路径
|
||||
/// </summary>
|
||||
public string RelativeImgPath { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// 生成图片的错误信息
|
||||
/// </summary>
|
||||
public string Message { get; set; } = "";
|
||||
}
|
||||
@@ -1,520 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
using Furion.Logging.Extensions;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Admin.NET.Core.Service;
|
||||
|
||||
/// <summary>
|
||||
/// 微信支付服务 🧩
|
||||
/// </summary>
|
||||
[ApiDescriptionSettings(Order = 210)]
|
||||
public class SysWechatPayService : IDynamicApiController, ITransient
|
||||
{
|
||||
private readonly SqlSugarRepository<SysWechatPay> _sysWechatPayRep;
|
||||
private readonly SqlSugarRepository<SysWechatRefund> _sysWechatRefundRep;
|
||||
|
||||
private readonly WechatPayOptions _wechatPayOptions;
|
||||
private readonly PayCallBackOptions _payCallBackOptions;
|
||||
|
||||
private readonly WechatTenpayClient _wechatTenpayClient;
|
||||
|
||||
public SysWechatPayService(SqlSugarRepository<SysWechatPay> sysWechatPayUserRep,
|
||||
SqlSugarRepository<SysWechatRefund> sysWechatRefundRep,
|
||||
IOptions<WechatPayOptions> wechatPayOptions,
|
||||
IOptions<PayCallBackOptions> payCallBackOptions)
|
||||
{
|
||||
_sysWechatPayRep = sysWechatPayUserRep;
|
||||
_sysWechatRefundRep = sysWechatRefundRep;
|
||||
_wechatPayOptions = wechatPayOptions.Value;
|
||||
_payCallBackOptions = payCallBackOptions.Value;
|
||||
|
||||
_wechatTenpayClient = CreateTenpayClient();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化微信支付客户端
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private WechatTenpayClient CreateTenpayClient()
|
||||
{
|
||||
var cerFilePath = Path.Combine(App.WebHostEnvironment.ContentRootPath, _wechatPayOptions.MerchantCertificatePrivateKey.Replace("/", Path.DirectorySeparatorChar.ToString()));
|
||||
|
||||
var tenpayClientOptions = new WechatTenpayClientOptions()
|
||||
{
|
||||
MerchantId = _wechatPayOptions.MerchantId,
|
||||
MerchantV3Secret = _wechatPayOptions.MerchantV3Secret,
|
||||
MerchantCertificateSerialNumber = _wechatPayOptions.MerchantCertificateSerialNumber,
|
||||
MerchantCertificatePrivateKey = File.Exists(cerFilePath) ? File.ReadAllText(cerFilePath) : "",
|
||||
PlatformCertificateManager = new InMemoryCertificateManager()
|
||||
};
|
||||
return new WechatTenpayClient(tenpayClientOptions);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 分页查询支付列表 🔖
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
[ApiDescriptionSettings(Name = "Page")]
|
||||
public async Task<SqlSugarPagedList<SysWechatPay>> Page(WechatPayPageInput input)
|
||||
{
|
||||
var query = _sysWechatPayRep.AsQueryable()
|
||||
.WhereIF(!string.IsNullOrWhiteSpace(input.Keyword), u => u.OutTradeNumber == input.Keyword || u.TransactionId == input.Keyword)
|
||||
.WhereIF(input.CreateTimeRange != null && input.CreateTimeRange.Count > 0 && input.CreateTimeRange[0].HasValue, x => x.CreateTime >= input.CreateTimeRange[0])
|
||||
.WhereIF(input.CreateTimeRange != null && input.CreateTimeRange.Count > 1 && input.CreateTimeRange[1].HasValue, x => x.CreateTime < ((DateTime)input.CreateTimeRange[1]).AddDays(1));
|
||||
return await query.OrderBuilder(input).ToPagedListAsync(input.Page, input.PageSize);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查询退款信息列表
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
[DisplayName("根据支付id获取退款信息列表")]
|
||||
public async Task<List<SysWechatRefund>> ListRefund([FromBody] string id)
|
||||
{
|
||||
var query = _sysWechatRefundRep.AsQueryable()
|
||||
.Where(u => u.TransactionId == id);
|
||||
return await query.ToListAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成JSAPI调起支付所需参数 🔖
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("生成JSAPI调起支付所需参数")]
|
||||
public WechatPayParaOutput GenerateParametersForJsapiPay(WechatPayParaInput input)
|
||||
{
|
||||
var data = _wechatTenpayClient.GenerateParametersForJsapiPayRequest(_wechatPayOptions.AppId, input.PrepayId);
|
||||
return new WechatPayParaOutput()
|
||||
{
|
||||
AppId = data["appId"],
|
||||
TimeStamp = data["timeStamp"],
|
||||
NonceStr = data["nonceStr"],
|
||||
Package = data["package"],
|
||||
SignType = data["signType"],
|
||||
PaySign = data["paySign"]
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 微信支付下单(商户直连) 🔖
|
||||
/// </summary>
|
||||
[DisplayName("微信支付下单(商户直连)")]
|
||||
public async Task<WechatPayTransactionOutput> CreatePayTransaction([FromBody] WechatPayTransactionInput input)
|
||||
{
|
||||
var request = new CreatePayTransactionJsapiRequest()
|
||||
{
|
||||
OutTradeNumber = DateTimeOffset.Now.ToString("yyyyMMddHHmmssfff") + (new Random()).Next(100, 1000), // 订单号
|
||||
AppId = _wechatPayOptions.AppId,
|
||||
Description = input.Description,
|
||||
Attachment = input.Attachment,
|
||||
GoodsTag = input.GoodsTag,
|
||||
ExpireTime = DateTimeOffset.Now.AddMinutes(10),
|
||||
NotifyUrl = _payCallBackOptions.WechatPayUrl,
|
||||
Amount = new CreatePayTransactionJsapiRequest.Types.Amount() { Total = input.Total },
|
||||
Payer = new CreatePayTransactionJsapiRequest.Types.Payer() { OpenId = input.OpenId }
|
||||
};
|
||||
var response = await _wechatTenpayClient.ExecuteCreatePayTransactionJsapiAsync(request);
|
||||
if (!response.IsSuccessful())
|
||||
throw Oops.Oh(response.ErrorMessage);
|
||||
|
||||
var singInfo = this.GenerateParametersForJsapiPay(new WechatPayParaInput() { PrepayId = response.PrepayId });
|
||||
// 保存订单信息
|
||||
var wechatPay = new SysWechatPay()
|
||||
{
|
||||
AppId = _wechatPayOptions.AppId,
|
||||
MerchantId = _wechatPayOptions.MerchantId,
|
||||
OutTradeNumber = request.OutTradeNumber,
|
||||
Description = input.Description,
|
||||
Attachment = input.Attachment,
|
||||
GoodsTag = input.GoodsTag,
|
||||
Total = input.Total,
|
||||
OpenId = input.OpenId,
|
||||
TransactionId = "",
|
||||
Tags = input.Tags,
|
||||
BusinessId = input.BusinessId,
|
||||
};
|
||||
await _sysWechatPayRep.InsertAsync(wechatPay);
|
||||
|
||||
return new WechatPayTransactionOutput()
|
||||
{
|
||||
PrepayId = response.PrepayId,
|
||||
OutTradeNumber = request.OutTradeNumber,
|
||||
SingInfo = singInfo
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 微信支付下单(商户直连)Native
|
||||
/// </summary>
|
||||
[DisplayName("微信支付下单(商户直连)Native")]
|
||||
public async Task<dynamic> CreatePayTransactionNative([FromBody] WechatPayTransactionInput input)
|
||||
{
|
||||
var request = new CreatePayTransactionNativeRequest()
|
||||
{
|
||||
OutTradeNumber = DateTimeOffset.Now.ToString("yyyyMMddHHmmssfff") + (new Random()).Next(100, 1000), // 订单号
|
||||
AppId = _wechatPayOptions.AppId,
|
||||
Description = input.Description,
|
||||
Attachment = input.Attachment,
|
||||
GoodsTag = input.GoodsTag,
|
||||
ExpireTime = DateTimeOffset.Now.AddMinutes(10),
|
||||
NotifyUrl = _payCallBackOptions.WechatPayUrl,
|
||||
Amount = new CreatePayTransactionNativeRequest.Types.Amount() { Total = input.Total },
|
||||
//Payer = new CreatePayTransactionNativeRequest.Types.Payer() { OpenId = input.OpenId }
|
||||
Scene = new CreatePayTransactionNativeRequest.Types.Scene() { ClientIp = "127.0.0.1" }
|
||||
};
|
||||
var response = await _wechatTenpayClient.ExecuteCreatePayTransactionNativeAsync(request);
|
||||
if (!response.IsSuccessful())
|
||||
{
|
||||
JsonConvert.SerializeObject(response).LogInformation();
|
||||
throw Oops.Oh(response.ErrorMessage);
|
||||
}
|
||||
// 保存订单信息
|
||||
var wechatPay = new SysWechatPay()
|
||||
{
|
||||
AppId = _wechatPayOptions.AppId,
|
||||
MerchantId = _wechatPayOptions.MerchantId,
|
||||
OutTradeNumber = request.OutTradeNumber,
|
||||
Description = input.Description,
|
||||
Attachment = input.Attachment,
|
||||
GoodsTag = input.GoodsTag,
|
||||
Total = input.Total,
|
||||
//OpenId = input.OpenId,
|
||||
TransactionId = "",
|
||||
QrcodeContent = response.QrcodeUrl,
|
||||
Tags = input.Tags,
|
||||
BusinessId = input.BusinessId,
|
||||
};
|
||||
await _sysWechatPayRep.InsertAsync(wechatPay);
|
||||
return new
|
||||
{
|
||||
request.OutTradeNumber,
|
||||
response.QrcodeUrl
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 微信支付下单(服务商模式) 🔖
|
||||
/// </summary>
|
||||
[DisplayName("微信支付下单(服务商模式)")]
|
||||
public async Task<dynamic> CreatePayPartnerTransaction([FromBody] WechatPayTransactionInput input)
|
||||
{
|
||||
var request = new CreatePayPartnerTransactionJsapiRequest()
|
||||
{
|
||||
OutTradeNumber = DateTimeOffset.Now.ToString("yyyyMMddHHmmssfff") + (new Random()).Next(100, 1000), // 订单号
|
||||
AppId = _wechatPayOptions.AppId,
|
||||
MerchantId = _wechatPayOptions.MerchantId,
|
||||
SubAppId = _wechatPayOptions.AppId,
|
||||
SubMerchantId = _wechatPayOptions.MerchantId,
|
||||
Description = input.Description,
|
||||
Attachment = input.Attachment,
|
||||
GoodsTag = input.GoodsTag,
|
||||
ExpireTime = DateTimeOffset.Now.AddMinutes(10),
|
||||
NotifyUrl = _payCallBackOptions.WechatPayUrl,
|
||||
Amount = new CreatePayPartnerTransactionJsapiRequest.Types.Amount() { Total = input.Total },
|
||||
Payer = new CreatePayPartnerTransactionJsapiRequest.Types.Payer() { OpenId = input.OpenId }
|
||||
};
|
||||
var response = await _wechatTenpayClient.ExecuteCreatePayPartnerTransactionJsapiAsync(request);
|
||||
if (!response.IsSuccessful())
|
||||
throw Oops.Oh(response.ErrorMessage);
|
||||
var singInfo = this.GenerateParametersForJsapiPay(new WechatPayParaInput() { PrepayId = response.PrepayId });
|
||||
// 保存订单信息
|
||||
var wechatPay = new SysWechatPay()
|
||||
{
|
||||
AppId = _wechatPayOptions.AppId,
|
||||
MerchantId = _wechatPayOptions.MerchantId,
|
||||
SubAppId = _wechatPayOptions.AppId,
|
||||
SubMerchantId = _wechatPayOptions.MerchantId,
|
||||
OutTradeNumber = request.OutTradeNumber,
|
||||
Description = input.Description,
|
||||
Attachment = input.Attachment,
|
||||
GoodsTag = input.GoodsTag,
|
||||
Total = input.Total,
|
||||
OpenId = input.OpenId,
|
||||
TransactionId = ""
|
||||
};
|
||||
await _sysWechatPayRep.InsertAsync(wechatPay);
|
||||
|
||||
return new
|
||||
{
|
||||
response.PrepayId,
|
||||
request.OutTradeNumber,
|
||||
singInfo
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取支付订单详情(本地库) 🔖
|
||||
/// </summary>
|
||||
/// <param name="tradeId"></param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("获取支付订单详情(本地库)")]
|
||||
public async Task<SysWechatPay> GetPayInfo(string tradeId)
|
||||
{
|
||||
return await _sysWechatPayRep.GetFirstAsync(u => u.OutTradeNumber == tradeId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取支付订单详情(微信接口) 🔖
|
||||
/// </summary>
|
||||
/// <param name="tradeId"></param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("获取支付订单详情(微信接口)")]
|
||||
public async Task<SysWechatPay> GetPayInfoFromWechat(string tradeId)
|
||||
{
|
||||
var request = new GetPayTransactionByOutTradeNumberRequest();
|
||||
request.OutTradeNumber = tradeId;
|
||||
var response = await _wechatTenpayClient.ExecuteGetPayTransactionByOutTradeNumberAsync(request);
|
||||
// 修改订单支付状态
|
||||
var wechatPay = await _sysWechatPayRep.GetFirstAsync(u => u.OutTradeNumber == response.OutTradeNumber
|
||||
&& u.MerchantId == response.MerchantId);
|
||||
// 如果状态不一致就更新数据库中的记录
|
||||
if (wechatPay != null && wechatPay.TradeState != response.TradeState)
|
||||
{
|
||||
wechatPay.OpenId = response.Payer.OpenId;
|
||||
wechatPay.TransactionId = response.TransactionId; // 支付订单号
|
||||
wechatPay.TradeType = response.TradeType; // 交易类型
|
||||
wechatPay.TradeState = response.TradeState; // 交易状态
|
||||
wechatPay.TradeStateDescription = response.TradeStateDescription; // 交易状态描述
|
||||
wechatPay.BankType = response.BankType; // 付款银行类型
|
||||
wechatPay.Total = response.Amount.Total; // 订单总金额
|
||||
wechatPay.PayerTotal = response.Amount.PayerTotal; // 用户支付金额
|
||||
wechatPay.SuccessTime = response.SuccessTime.Value.DateTime; // 支付完成时间
|
||||
await _sysWechatPayRep.AsUpdateable(wechatPay).IgnoreColumns(true).ExecuteCommandAsync();
|
||||
}
|
||||
wechatPay = new SysWechatPay()
|
||||
{
|
||||
AppId = _wechatPayOptions.AppId,
|
||||
MerchantId = _wechatPayOptions.MerchantId,
|
||||
SubAppId = _wechatPayOptions.AppId,
|
||||
SubMerchantId = _wechatPayOptions.MerchantId,
|
||||
OutTradeNumber = request.OutTradeNumber,
|
||||
Attachment = response.Attachment,
|
||||
Total = response.Amount.Total, // 订单总金额
|
||||
TransactionId = response.TransactionId,
|
||||
TradeType = response.TradeType, // 交易类型
|
||||
TradeState = response.TradeState, // 交易状态
|
||||
TradeStateDescription = response.TradeStateDescription, // 交易状态描述
|
||||
BankType = response.BankType, // 付款银行类型
|
||||
PayerTotal = response.Amount.PayerTotal, // 用户支付金额
|
||||
SuccessTime = response.SuccessTime.Value.DateTime // 支付完成时间
|
||||
};
|
||||
return wechatPay;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 退款申请
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("退款申请")]
|
||||
[HttpPost]
|
||||
public async Task<dynamic> CreateRefundDomestic([FromBody] WechatPayRefundDomesticInput input)
|
||||
{
|
||||
// refund/domestic/refunds
|
||||
var request = new CreateRefundDomesticRefundRequest()
|
||||
{
|
||||
Amount = new CreateRefundDomesticRefundRequest.Types.Amount()
|
||||
{
|
||||
Refund = input.Refund,
|
||||
Total = input.Total,
|
||||
Currency = "CNY"
|
||||
},
|
||||
|
||||
OutTradeNumber = input.TradeId,
|
||||
OutRefundNumber = "R" + DateTimeOffset.Now.ToString("yyyyMMddHHmmssfff") + (new Random()).Next(100, 1000), // 订单号
|
||||
NotifyUrl = _payCallBackOptions.WechatRefundUrl, // 应采用WechatRefundUrl参数,如与WechatPayUrl入口相同,也应分开设置参数
|
||||
Reason = input.Reason,
|
||||
};
|
||||
var response = await _wechatTenpayClient.ExecuteCreateRefundDomesticRefundAsync(request);
|
||||
if (string.IsNullOrEmpty(response.ErrorCode))
|
||||
{
|
||||
// 成功了,这里应该保存退款订单信息
|
||||
var wechatPay = await _sysWechatPayRep.GetFirstAsync(u => u.OutTradeNumber == response.OutTradeNumber);
|
||||
// 保存订单信息
|
||||
if (wechatPay != null)
|
||||
{
|
||||
var wechatRefund = new SysWechatRefund()
|
||||
{
|
||||
WechatPayId = wechatPay.Id,
|
||||
TransactionId = response.TransactionId,
|
||||
Refund = input.Refund,
|
||||
Reason = input.Reason,
|
||||
OutRefundNumber = request.OutRefundNumber,
|
||||
Channel = response.Channel,
|
||||
UserReceivedAccount = response.UserReceivedAccount,
|
||||
};
|
||||
await _sysWechatRefundRep.InsertAsync(wechatRefund);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw Oops.Bah($"[{response.ErrorCode}]{response.ErrorMessage}");
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取退款订单详情(微信接口)
|
||||
/// </summary>
|
||||
/// <param name="refundId"></param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("获取退款订单详情(微信接口)")]
|
||||
public async Task<SysWechatRefund> GetRefundInfoFromWechat(string refundId)
|
||||
{
|
||||
var request = new GetRefundDomesticRefundByOutRefundNumberRequest();
|
||||
request.OutRefundNumber = refundId;
|
||||
var response = await _wechatTenpayClient.ExecuteGetRefundDomesticRefundByOutRefundNumberAsync(request);
|
||||
// 修改订单支付状态
|
||||
var wechatRefund = await _sysWechatRefundRep.GetFirstAsync(u => u.OutRefundNumber == refundId);
|
||||
// 如果状态不一致就更新数据库中的记录
|
||||
if (wechatRefund != null && wechatRefund.TradeState != response.Status)
|
||||
{
|
||||
wechatRefund.TransactionId = response.TransactionId; // 支付订单号
|
||||
wechatRefund.TradeState = response.Status; // 交易状态
|
||||
wechatRefund.SuccessTime = response.SuccessTime.Value.DateTime; // 支付完成时间
|
||||
await _sysWechatRefundRep.AsUpdateable(wechatRefund).IgnoreColumns(true).ExecuteCommandAsync();
|
||||
// 有退款,刷新一下订单状态
|
||||
var wechatPay = await _sysWechatPayRep.GetFirstAsync(u => u.Id == wechatRefund.WechatPayId);
|
||||
if (wechatPay != null)
|
||||
await GetPayInfoFromWechat(wechatPay.OutTradeNumber);
|
||||
}
|
||||
wechatRefund = new SysWechatRefund()
|
||||
{
|
||||
TransactionId = response.TransactionId,
|
||||
Refund = response.Amount.Refund,
|
||||
OutRefundNumber = request.OutRefundNumber,
|
||||
Channel = response.Channel,
|
||||
UserReceivedAccount = response.UserReceivedAccount,
|
||||
TradeState = response.Status, // 交易状态
|
||||
SuccessTime = response.SuccessTime.Value.DateTime, // 支付完成时间
|
||||
};
|
||||
return wechatRefund;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 微信支付成功回调(商户直连)
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[AllowAnonymous]
|
||||
[DisplayName("微信支付成功回调(商户直连)")]
|
||||
public async Task<WechatPayOutput> PayCallBack()
|
||||
{
|
||||
using var ms = new MemoryStream();
|
||||
await App.HttpContext.Request.Body.CopyToAsync(ms);
|
||||
var b = ms.ToArray();
|
||||
var callbackJson = Encoding.UTF8.GetString(b);
|
||||
|
||||
var callbackModel = _wechatTenpayClient.DeserializeEvent(callbackJson);
|
||||
if ("TRANSACTION.SUCCESS".Equals(callbackModel.EventType))
|
||||
{
|
||||
try
|
||||
{
|
||||
var callbackPayResource = _wechatTenpayClient.DecryptEventResource<TransactionResource>(callbackModel);
|
||||
|
||||
// 修改订单支付状态
|
||||
var wechatPay = await _sysWechatPayRep.GetFirstAsync(u => u.OutTradeNumber == callbackPayResource.OutTradeNumber
|
||||
&& u.MerchantId == callbackPayResource.MerchantId);
|
||||
if (wechatPay == null) return null;
|
||||
wechatPay.OpenId = callbackPayResource.Payer.OpenId; // 支付者标识
|
||||
//wechatPay.MerchantId = callbackResource.MerchantId; // 微信商户号
|
||||
//wechatPay.OutTradeNumber = callbackResource.OutTradeNumber; // 商户订单号
|
||||
wechatPay.TransactionId = callbackPayResource.TransactionId; // 支付订单号
|
||||
wechatPay.TradeType = callbackPayResource.TradeType; // 交易类型
|
||||
wechatPay.TradeState = callbackPayResource.TradeState; // 交易状态
|
||||
wechatPay.TradeStateDescription = callbackPayResource.TradeStateDescription; // 交易状态描述
|
||||
wechatPay.BankType = callbackPayResource.BankType; // 付款银行类型
|
||||
wechatPay.Total = callbackPayResource.Amount.Total; // 订单总金额
|
||||
wechatPay.PayerTotal = callbackPayResource.Amount.PayerTotal; // 用户支付金额
|
||||
wechatPay.SuccessTime = callbackPayResource.SuccessTime.DateTime; // 支付完成时间
|
||||
|
||||
await _sysWechatPayRep.AsUpdateable(wechatPay).IgnoreColumns(true).ExecuteCommandAsync();
|
||||
|
||||
return new WechatPayOutput()
|
||||
{
|
||||
Total = wechatPay.Total,
|
||||
Attachment = wechatPay.Attachment,
|
||||
GoodsTag = wechatPay.GoodsTag
|
||||
};
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
"微信支付回调时出错:".LogError(ex);
|
||||
}
|
||||
}
|
||||
else if ("REFUND.SUCCESS".Equals(callbackModel.EventType))
|
||||
{
|
||||
//参考:https://pay.weixin.qq.com/docs/merchant/apis/jsapi-payment/refund-result-notice.html
|
||||
try
|
||||
{
|
||||
var callbackRefundResource = _wechatTenpayClient.DecryptEventResource<RefundResource>(callbackModel);
|
||||
// 修改订单支付状态
|
||||
var wechatRefund = await _sysWechatRefundRep.GetFirstAsync(u => u.OutRefundNumber == callbackRefundResource.OutRefundNumber);
|
||||
if (wechatRefund == null) return null;
|
||||
wechatRefund.TradeState = callbackRefundResource.RefundStatus; // 交易状态
|
||||
wechatRefund.SuccessTime = callbackRefundResource.SuccessTime.Value.DateTime; // 支付完成时间
|
||||
|
||||
await _sysWechatRefundRep.AsUpdateable(wechatRefund).IgnoreColumns(true).ExecuteCommandAsync();
|
||||
// 有退款,刷新一下订单状态
|
||||
await GetPayInfoFromWechat(callbackRefundResource.OutTradeNumber);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
"微信退款回调时出错:".LogError(ex);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
callbackModel.EventType.LogInformation();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 微信支付成功回调(服务商模式) 🔖
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[AllowAnonymous]
|
||||
[DisplayName("微信支付成功回调(服务商模式)")]
|
||||
public async Task PayPartnerCallBack()
|
||||
{
|
||||
using var ms = new MemoryStream();
|
||||
await App.HttpContext.Request.Body.CopyToAsync(ms);
|
||||
var b = ms.ToArray();
|
||||
var callbackJson = Encoding.UTF8.GetString(b);
|
||||
|
||||
var callbackModel = _wechatTenpayClient.DeserializeEvent(callbackJson);
|
||||
if ("TRANSACTION.SUCCESS".Equals(callbackModel.EventType))
|
||||
{
|
||||
var callbackResource = _wechatTenpayClient.DecryptEventResource<PartnerTransactionResource>(callbackModel);
|
||||
|
||||
// 修改订单支付状态
|
||||
var wechatPay = await _sysWechatPayRep.GetFirstAsync(u => u.OutTradeNumber == callbackResource.OutTradeNumber
|
||||
&& u.MerchantId == callbackResource.MerchantId);
|
||||
if (wechatPay == null) return;
|
||||
//wechatPay.OpenId = callbackResource.Payer.OpenId; // 支付者标识
|
||||
//wechatPay.MerchantId = callbackResource.MerchantId; // 微信商户号
|
||||
//wechatPay.OutTradeNumber = callbackResource.OutTradeNumber; // 商户订单号
|
||||
wechatPay.TransactionId = callbackResource.TransactionId; // 支付订单号
|
||||
wechatPay.TradeType = callbackResource.TradeType; // 交易类型
|
||||
wechatPay.TradeState = callbackResource.TradeState; // 交易状态
|
||||
wechatPay.TradeStateDescription = callbackResource.TradeStateDescription; // 交易状态描述
|
||||
wechatPay.BankType = callbackResource.BankType; // 付款银行类型
|
||||
wechatPay.Total = callbackResource.Amount.Total; // 订单总金额
|
||||
wechatPay.PayerTotal = callbackResource.Amount.PayerTotal; // 用户支付金额
|
||||
wechatPay.SuccessTime = callbackResource.SuccessTime.DateTime; // 支付完成时间
|
||||
|
||||
await _sysWechatPayRep.AsUpdateable(wechatPay).IgnoreColumns(true).ExecuteCommandAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,202 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core.Service;
|
||||
|
||||
/// <summary>
|
||||
/// 微信公众号服务 🧩
|
||||
/// </summary>
|
||||
[ApiDescriptionSettings(Order = 230)]
|
||||
public class SysWechatService : IDynamicApiController, ITransient
|
||||
{
|
||||
private readonly SqlSugarRepository<SysWechatUser> _sysWechatUserRep;
|
||||
private readonly SysConfigService _sysConfigService;
|
||||
private readonly WechatApiClientFactory _wechatApiClientFactory;
|
||||
private readonly WechatApiClient _wechatApiClient;
|
||||
|
||||
public SysWechatService(SqlSugarRepository<SysWechatUser> sysWechatUserRep,
|
||||
SysConfigService sysConfigService,
|
||||
WechatApiClientFactory wechatApiClientFactory,
|
||||
SysCacheService sysCacheService)
|
||||
{
|
||||
_sysWechatUserRep = sysWechatUserRep;
|
||||
_sysConfigService = sysConfigService;
|
||||
_wechatApiClientFactory = wechatApiClientFactory;
|
||||
_wechatApiClient = wechatApiClientFactory.CreateWechatClient();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成网页授权Url 🔖
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[AllowAnonymous]
|
||||
[DisplayName("生成网页授权Url")]
|
||||
public string GenAuthUrl(GenAuthUrlInput input)
|
||||
{
|
||||
return _wechatApiClient.GenerateParameterizedUrlForConnectOAuth2Authorize(input.RedirectUrl, input.Scope, input.State);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取微信用户OpenId 🔖
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
[AllowAnonymous]
|
||||
[DisplayName("获取微信用户OpenId")]
|
||||
public async Task<string> SnsOAuth2([FromQuery] WechatOAuth2Input input)
|
||||
{
|
||||
var reqOAuth2 = new SnsOAuth2AccessTokenRequest()
|
||||
{
|
||||
Code = input.Code,
|
||||
};
|
||||
var resOAuth2 = await _wechatApiClient.ExecuteSnsOAuth2AccessTokenAsync(reqOAuth2);
|
||||
if (resOAuth2.ErrorCode != (int)WechatReturnCodeEnum.请求成功)
|
||||
throw Oops.Oh(resOAuth2.ErrorMessage + " " + resOAuth2.ErrorCode);
|
||||
|
||||
var wxUser = await _sysWechatUserRep.GetFirstAsync(p => p.OpenId == resOAuth2.OpenId);
|
||||
if (wxUser == null)
|
||||
{
|
||||
var reqUserInfo = new SnsUserInfoRequest()
|
||||
{
|
||||
OpenId = resOAuth2.OpenId,
|
||||
AccessToken = resOAuth2.AccessToken,
|
||||
};
|
||||
var resUserInfo = await _wechatApiClient.ExecuteSnsUserInfoAsync(reqUserInfo);
|
||||
wxUser = resUserInfo.Adapt<SysWechatUser>();
|
||||
wxUser.Avatar = resUserInfo.HeadImageUrl;
|
||||
wxUser.NickName = resUserInfo.Nickname;
|
||||
wxUser.OpenId = resOAuth2.OpenId;
|
||||
wxUser.UnionId = resOAuth2.UnionId;
|
||||
wxUser.AccessToken = resOAuth2.AccessToken;
|
||||
wxUser.RefreshToken = resOAuth2.RefreshToken;
|
||||
wxUser = await _sysWechatUserRep.AsInsertable(wxUser).ExecuteReturnEntityAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
wxUser.AccessToken = resOAuth2.AccessToken;
|
||||
wxUser.RefreshToken = resOAuth2.RefreshToken;
|
||||
await _sysWechatUserRep.AsUpdateable(wxUser).IgnoreColumns(true).ExecuteCommandAsync();
|
||||
}
|
||||
|
||||
return resOAuth2.OpenId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 微信用户登录OpenId 🔖
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[AllowAnonymous]
|
||||
[DisplayName("微信用户登录OpenId")]
|
||||
public async Task<dynamic> OpenIdLogin(WechatUserLogin input)
|
||||
{
|
||||
var wxUser = await _sysWechatUserRep.GetFirstAsync(p => p.OpenId == input.OpenId);
|
||||
if (wxUser == null)
|
||||
throw Oops.Oh("微信用户登录OpenId错误");
|
||||
|
||||
var tokenExpire = await _sysConfigService.GetTokenExpire();
|
||||
return new
|
||||
{
|
||||
wxUser.Avatar,
|
||||
accessToken = JWTEncryption.Encrypt(new Dictionary<string, object>
|
||||
{
|
||||
{ ClaimConst.UserId, wxUser.Id },
|
||||
{ ClaimConst.NickName, wxUser.NickName },
|
||||
{ ClaimConst.LoginMode, LoginModeEnum.APP },
|
||||
}, tokenExpire)
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取配置签名参数(wx.config) 🔖
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[DisplayName("获取配置签名参数(wx.config)")]
|
||||
public async Task<dynamic> GenConfigPara(SignatureInput input)
|
||||
{
|
||||
string ticket = await _wechatApiClientFactory.TryGetWechatJsApiTicketAsync();
|
||||
return _wechatApiClient.GenerateParametersForJSSDKConfig(ticket, input.Url);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取模板列表 🔖
|
||||
/// </summary>
|
||||
[DisplayName("获取模板列表")]
|
||||
public async Task<dynamic> GetMessageTemplateList()
|
||||
{
|
||||
var accessToken = await GetCgibinToken();
|
||||
var reqTemplate = new CgibinTemplateGetAllPrivateTemplateRequest()
|
||||
{
|
||||
AccessToken = accessToken
|
||||
};
|
||||
var resTemplate = await _wechatApiClient.ExecuteCgibinTemplateGetAllPrivateTemplateAsync(reqTemplate);
|
||||
if (resTemplate.ErrorCode != (int)WechatReturnCodeEnum.请求成功)
|
||||
throw Oops.Oh(resTemplate.ErrorMessage + " " + resTemplate.ErrorCode);
|
||||
|
||||
return resTemplate.TemplateList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送模板消息 🔖
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("发送模板消息")]
|
||||
public async Task<dynamic> SendTemplateMessage(MessageTemplateSendInput input)
|
||||
{
|
||||
var dataInfo = input.Data.ToDictionary(k => k.Key, k => k.Value);
|
||||
var messageData = new Dictionary<string, CgibinMessageTemplateSendRequest.Types.DataItem>();
|
||||
foreach (var item in dataInfo)
|
||||
{
|
||||
messageData.Add(item.Key, new CgibinMessageTemplateSendRequest.Types.DataItem() { Value = "" + item.Value.Value.ToString() + "" });
|
||||
}
|
||||
|
||||
var accessToken = await GetCgibinToken();
|
||||
var reqMessage = new CgibinMessageTemplateSendRequest()
|
||||
{
|
||||
AccessToken = accessToken,
|
||||
TemplateId = input.TemplateId,
|
||||
ToUserOpenId = input.ToUserOpenId,
|
||||
Url = input.Url,
|
||||
MiniProgram = new CgibinMessageTemplateSendRequest.Types.MiniProgram
|
||||
{
|
||||
AppId = _wechatApiClientFactory._wechatOptions.WxOpenAppId,
|
||||
PagePath = input.MiniProgramPagePath,
|
||||
},
|
||||
Data = messageData
|
||||
};
|
||||
var resMessage = await _wechatApiClient.ExecuteCgibinMessageTemplateSendAsync(reqMessage);
|
||||
return resMessage;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除模板 🔖
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[ApiDescriptionSettings(Name = "DeleteMessageTemplate"), HttpPost]
|
||||
[DisplayName("删除模板")]
|
||||
public async Task<dynamic> DeleteMessageTemplate(DeleteMessageTemplateInput input)
|
||||
{
|
||||
var accessToken = await GetCgibinToken();
|
||||
var reqMessage = new CgibinTemplateDeletePrivateTemplateRequest()
|
||||
{
|
||||
AccessToken = accessToken,
|
||||
TemplateId = input.TemplateId
|
||||
};
|
||||
var resTemplate = await _wechatApiClient.ExecuteCgibinTemplateDeletePrivateTemplateAsync(reqMessage);
|
||||
return resTemplate;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取Access_token
|
||||
/// </summary>
|
||||
[NonAction]
|
||||
public async Task<string> GetCgibinToken()
|
||||
{
|
||||
return await _wechatApiClientFactory.TryGetWechatAccessTokenAsync();
|
||||
}
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core.Service;
|
||||
|
||||
/// <summary>
|
||||
/// 微信账号服务 🧩
|
||||
/// </summary>
|
||||
[ApiDescriptionSettings(Order = 220)]
|
||||
public class SysWechatUserService : IDynamicApiController, ITransient
|
||||
{
|
||||
private readonly SqlSugarRepository<SysWechatUser> _sysWechatUserRep;
|
||||
|
||||
public SysWechatUserService(SqlSugarRepository<SysWechatUser> sysWechatUserRep)
|
||||
{
|
||||
_sysWechatUserRep = sysWechatUserRep;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取微信用户列表 🔖
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("获取微信用户列表")]
|
||||
public async Task<SqlSugarPagedList<SysWechatUser>> Page(WechatUserInput input)
|
||||
{
|
||||
return await _sysWechatUserRep.AsQueryable()
|
||||
.WhereIF(!string.IsNullOrWhiteSpace(input.NickName), u => u.NickName.Contains(input.NickName))
|
||||
.WhereIF(!string.IsNullOrWhiteSpace(input.Mobile), u => u.Mobile.Contains(input.Mobile))
|
||||
.OrderBy(u => u.Id, OrderByType.Desc)
|
||||
.ToPagedListAsync(input.Page, input.PageSize);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 增加微信用户 🔖
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[ApiDescriptionSettings(Name = "Add"), HttpPost]
|
||||
[DisplayName("增加微信用户")]
|
||||
public async Task AddWechatUser(SysWechatUser input)
|
||||
{
|
||||
await _sysWechatUserRep.InsertAsync(input.Adapt<SysWechatUser>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新微信用户 🔖
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[ApiDescriptionSettings(Name = "Update"), HttpPost]
|
||||
[DisplayName("更新微信用户")]
|
||||
public async Task UpdateWechatUser(SysWechatUser input)
|
||||
{
|
||||
var weChatUser = input.Adapt<SysWechatUser>();
|
||||
await _sysWechatUserRep.AsUpdateable(weChatUser).IgnoreColumns(true).ExecuteCommandAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除微信用户 🔖
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[ApiDescriptionSettings(Name = "Delete"), HttpPost]
|
||||
[DisplayName("删除微信用户")]
|
||||
public async Task DeleteWechatUser(DeleteWechatUserInput input)
|
||||
{
|
||||
await _sysWechatUserRep.DeleteAsync(u => u.Id == input.Id);
|
||||
}
|
||||
}
|
||||
@@ -1,407 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core.Service;
|
||||
|
||||
/// <summary>
|
||||
/// 微信小程序服务 🧩
|
||||
/// </summary>
|
||||
[ApiDescriptionSettings(Order = 240)]
|
||||
public class SysWxOpenService : IDynamicApiController, ITransient
|
||||
{
|
||||
private readonly SqlSugarRepository<SysWechatUser> _sysWechatUserRep;
|
||||
private readonly SysConfigService _sysConfigService;
|
||||
private readonly WechatApiClient _wechatApiClient;
|
||||
private readonly SysFileService _sysFileService;
|
||||
private readonly WechatApiClientFactory _wechatApiClientFactory;
|
||||
|
||||
public SysWxOpenService(SqlSugarRepository<SysWechatUser> sysWechatUserRep,
|
||||
SysConfigService sysConfigService,
|
||||
WechatApiClientFactory wechatApiClientFactory,
|
||||
SysFileService sysFileService)
|
||||
{
|
||||
_sysWechatUserRep = sysWechatUserRep;
|
||||
_sysConfigService = sysConfigService;
|
||||
_wechatApiClient = wechatApiClientFactory.CreateWxOpenClient();
|
||||
_sysFileService = sysFileService;
|
||||
_wechatApiClientFactory = wechatApiClientFactory;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取微信用户OpenId 🔖
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
[AllowAnonymous]
|
||||
[DisplayName("获取微信用户OpenId")]
|
||||
public async Task<WxOpenIdOutput> GetWxOpenId([FromQuery] JsCode2SessionInput input)
|
||||
{
|
||||
var reqJsCode2Session = new SnsJsCode2SessionRequest()
|
||||
{
|
||||
JsCode = input.JsCode,
|
||||
};
|
||||
var resCode2Session = await _wechatApiClient.ExecuteSnsJsCode2SessionAsync(reqJsCode2Session);
|
||||
if (resCode2Session.ErrorCode != (int)WechatReturnCodeEnum.请求成功)
|
||||
throw Oops.Oh(resCode2Session.ErrorMessage + " " + resCode2Session.ErrorCode);
|
||||
|
||||
var wxUser = await _sysWechatUserRep.GetFirstAsync(p => p.OpenId == resCode2Session.OpenId);
|
||||
if (wxUser == null)
|
||||
{
|
||||
wxUser = new SysWechatUser
|
||||
{
|
||||
OpenId = resCode2Session.OpenId,
|
||||
UnionId = resCode2Session.UnionId,
|
||||
SessionKey = resCode2Session.SessionKey,
|
||||
PlatformType = PlatformTypeEnum.微信小程序
|
||||
};
|
||||
wxUser = await _sysWechatUserRep.AsInsertable(wxUser).ExecuteReturnEntityAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
await _sysWechatUserRep.AsUpdateable(wxUser).IgnoreColumns(true).ExecuteCommandAsync();
|
||||
}
|
||||
|
||||
return new WxOpenIdOutput
|
||||
{
|
||||
OpenId = resCode2Session.OpenId
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取微信用户电话号码 🔖
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
[AllowAnonymous]
|
||||
[DisplayName("获取微信用户电话号码")]
|
||||
public async Task<WxPhoneOutput> GetWxPhone([FromQuery] WxPhoneInput input)
|
||||
{
|
||||
var accessToken = await GetCgibinToken();
|
||||
var reqUserPhoneNumber = new WxaBusinessGetUserPhoneNumberRequest()
|
||||
{
|
||||
Code = input.Code,
|
||||
AccessToken = accessToken,
|
||||
};
|
||||
var resUserPhoneNumber = await _wechatApiClient.ExecuteWxaBusinessGetUserPhoneNumberAsync(reqUserPhoneNumber);
|
||||
if (resUserPhoneNumber.ErrorCode != (int)WechatReturnCodeEnum.请求成功)
|
||||
throw Oops.Oh(resUserPhoneNumber.ErrorMessage + " " + resUserPhoneNumber.ErrorCode);
|
||||
|
||||
var wxUser = await _sysWechatUserRep.GetFirstAsync(p => p.OpenId == input.OpenId);
|
||||
if (wxUser == null)
|
||||
{
|
||||
wxUser = new SysWechatUser
|
||||
{
|
||||
OpenId = input.OpenId,
|
||||
Mobile = resUserPhoneNumber.PhoneInfo?.PhoneNumber,
|
||||
PlatformType = PlatformTypeEnum.微信小程序
|
||||
};
|
||||
wxUser = await _sysWechatUserRep.AsInsertable(wxUser).ExecuteReturnEntityAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
wxUser.Mobile = resUserPhoneNumber.PhoneInfo?.PhoneNumber;
|
||||
await _sysWechatUserRep.AsUpdateable(wxUser).IgnoreColumns(true).ExecuteCommandAsync();
|
||||
}
|
||||
|
||||
return new WxPhoneOutput
|
||||
{
|
||||
PhoneNumber = resUserPhoneNumber.PhoneInfo?.PhoneNumber
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 微信小程序登录OpenId 🔖
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[AllowAnonymous]
|
||||
[DisplayName("微信小程序登录OpenId")]
|
||||
public async Task<dynamic> WxOpenIdLogin(WxOpenIdLoginInput input)
|
||||
{
|
||||
var wxUser = await _sysWechatUserRep.GetFirstAsync(u => u.OpenId == input.OpenId);
|
||||
if (wxUser == null)
|
||||
throw Oops.Oh("微信小程序登录失败");
|
||||
|
||||
var tokenExpire = await _sysConfigService.GetTokenExpire();
|
||||
return new
|
||||
{
|
||||
wxUser.Avatar,
|
||||
accessToken = JWTEncryption.Encrypt(new Dictionary<string, object>
|
||||
{
|
||||
{ ClaimConst.UserId, wxUser.Id },
|
||||
{ ClaimConst.RealName, wxUser.NickName },
|
||||
{ ClaimConst.LoginMode, LoginModeEnum.APP },
|
||||
}, tokenExpire)
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 上传小程序头像
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[AllowAnonymous]
|
||||
[DisplayName("上传小程序头像")]
|
||||
public async Task<SysFile> UploadAvatar([FromForm] UploadAvatarInput input)
|
||||
{
|
||||
var wxUser = await _sysWechatUserRep.GetFirstAsync(u => u.OpenId == input.OpenId);
|
||||
if (wxUser == null)
|
||||
throw Oops.Oh("未找到用户上传失败");
|
||||
|
||||
var res = await _sysFileService.UploadFile(new UploadFileInput { File = input.File, FileType = input.FileType }, "upload/wechatAvatar");
|
||||
wxUser.Avatar = res.Url;
|
||||
await _sysWechatUserRep.AsUpdateable(wxUser).IgnoreColumns(true).ExecuteCommandAsync();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置小程序用户昵称
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[AllowAnonymous]
|
||||
[HttpPost]
|
||||
public async Task SetNickName(SetNickNameInput input)
|
||||
{
|
||||
var wxUser = await _sysWechatUserRep.GetFirstAsync(u => u.OpenId == input.OpenId);
|
||||
if (wxUser == null)
|
||||
throw Oops.Oh("未找到用户信息设置失败");
|
||||
wxUser.NickName = input.NickName;
|
||||
await _sysWechatUserRep.AsUpdateable(wxUser).IgnoreColumns(true).ExecuteCommandAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取小程序用户信息
|
||||
/// </summary>
|
||||
/// <param name="openid"></param>
|
||||
/// <returns></returns>
|
||||
[AllowAnonymous]
|
||||
public async Task<dynamic> GetUserInfo(string openid)
|
||||
{
|
||||
var wxUser = await _sysWechatUserRep.GetFirstAsync(u => u.OpenId == openid);
|
||||
if (wxUser == null)
|
||||
throw Oops.Oh("未找到用户信息获取失败");
|
||||
return new { nickName = wxUser.NickName, avator = wxUser.Avatar };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取订阅消息模板列表 🔖
|
||||
/// </summary>
|
||||
[DisplayName("获取订阅消息模板列表")]
|
||||
public async Task<dynamic> GetMessageTemplateList()
|
||||
{
|
||||
var accessToken = await GetCgibinToken();
|
||||
var reqTemplate = new WxaApiNewTemplateGetTemplateRequest()
|
||||
{
|
||||
AccessToken = accessToken
|
||||
};
|
||||
var resTemplate = await _wechatApiClient.ExecuteWxaApiNewTemplateGetTemplateAsync(reqTemplate);
|
||||
if (resTemplate.ErrorCode != (int)WechatReturnCodeEnum.请求成功)
|
||||
throw Oops.Oh(resTemplate.ErrorMessage + " " + resTemplate.ErrorCode);
|
||||
|
||||
return resTemplate.TemplateList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送订阅消息 🔖
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("发送订阅消息")]
|
||||
public async Task<dynamic> SendSubscribeMessage(SendSubscribeMessageInput input)
|
||||
{
|
||||
var accessToken = await GetCgibinToken();
|
||||
var reqMessage = new CgibinMessageSubscribeSendRequest()
|
||||
{
|
||||
AccessToken = accessToken,
|
||||
TemplateId = input.TemplateId,
|
||||
ToUserOpenId = input.ToUserOpenId,
|
||||
Data = input.Data,
|
||||
MiniProgramState = input.MiniprogramState,
|
||||
Language = input.Language,
|
||||
MiniProgramPagePath = input.MiniProgramPagePath
|
||||
};
|
||||
var resMessage = await _wechatApiClient.ExecuteCgibinMessageSubscribeSendAsync(reqMessage);
|
||||
return resMessage;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 增加订阅消息模板 🔖
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[ApiDescriptionSettings(Name = "AddSubscribeMessageTemplate"), HttpPost]
|
||||
[DisplayName("增加订阅消息模板")]
|
||||
public async Task<dynamic> AddSubscribeMessageTemplate(AddSubscribeMessageTemplateInput input)
|
||||
{
|
||||
var accessToken = await GetCgibinToken();
|
||||
var reqMessage = new WxaApiNewTemplateAddTemplateRequest()
|
||||
{
|
||||
AccessToken = accessToken,
|
||||
TemplateTitleId = input.TemplateTitleId,
|
||||
KeyworkIdList = input.KeyworkIdList,
|
||||
SceneDescription = input.SceneDescription
|
||||
};
|
||||
var resTemplate = await _wechatApiClient.ExecuteWxaApiNewTemplateAddTemplateAsync(reqMessage);
|
||||
return resTemplate;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成带参数小程序二维码(总共生成的码数量限制为 100,000)
|
||||
/// </summary>
|
||||
/// <param name="input"> 扫码进入的小程序页面路径,最大长度 128 个字符,不能为空; eg: pages / index ? id = AY000001 </param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("生成小程序二维码")]
|
||||
[ApiDescriptionSettings(Name = "GenerateQRImage")]
|
||||
public async Task<GenerateQRImageOutput> GenerateQRImageAsync(GenerateQRImageInput input)
|
||||
{
|
||||
GenerateQRImageOutput generateQRImageOutInput = new GenerateQRImageOutput();
|
||||
if (input.PagePath.IsNullOrEmpty())
|
||||
{
|
||||
generateQRImageOutInput.Message = $"生成失败 页面路径不能为空";
|
||||
return generateQRImageOutInput;
|
||||
}
|
||||
|
||||
if (input.ImageName.IsNullOrEmpty())
|
||||
{
|
||||
input.ImageName = DateTime.Now.ToString("yyyyMMddHHmmss");
|
||||
}
|
||||
|
||||
var accessToken = await GetCgibinToken();
|
||||
var request = new CgibinWxaappCreateWxaQrcodeRequest
|
||||
{
|
||||
AccessToken = accessToken,
|
||||
Path = input.PagePath,
|
||||
Width = input.Width
|
||||
};
|
||||
var response = await _wechatApiClient.ExecuteCgibinWxaappCreateWxaQrcodeAsync(request);
|
||||
|
||||
if (response.IsSuccessful())
|
||||
{
|
||||
var QRImagePath = App.GetConfig<string>("Wechat:QRImagePath");
|
||||
var relativeImgPath = string.Empty;
|
||||
|
||||
// 判断路径是绝对路径还是相对路径
|
||||
var isPathRooted = Path.IsPathRooted(QRImagePath);
|
||||
if (!isPathRooted)
|
||||
{
|
||||
// 相对路径
|
||||
relativeImgPath = string.IsNullOrEmpty(QRImagePath) ? Path.Combine("upload", "QRImage") : QRImagePath;
|
||||
QRImagePath = Path.Combine(App.WebHostEnvironment.WebRootPath, relativeImgPath);
|
||||
}
|
||||
|
||||
//判断文件存放路径是否存在
|
||||
if (!Directory.Exists(QRImagePath))
|
||||
{
|
||||
Directory.CreateDirectory(QRImagePath);
|
||||
}
|
||||
// 将二维码图片数据保存为文件
|
||||
var fileName = $"{input.ImageName.ToUpper()}.png";
|
||||
var filePath = Path.Combine(QRImagePath, fileName);
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
File.Delete(filePath);
|
||||
}
|
||||
File.WriteAllBytes(filePath, response.GetRawBytes());
|
||||
|
||||
generateQRImageOutInput.Success = true;
|
||||
generateQRImageOutInput.ImgPath = filePath;
|
||||
generateQRImageOutInput.RelativeImgPath = Path.Combine(relativeImgPath, fileName);
|
||||
generateQRImageOutInput.Message = "生成成功";
|
||||
}
|
||||
else
|
||||
{
|
||||
// 处理错误情况
|
||||
generateQRImageOutInput.Message = $"生成失败 错误代码:{response.ErrorCode} 错误描述:{response.ErrorMessage}";
|
||||
}
|
||||
return generateQRImageOutInput;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成二维码(获取不受限制的小程序码)
|
||||
/// </summary>
|
||||
/// <param name="input">入参</param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("生成小程序二维码")]
|
||||
[ApiDescriptionSettings(Name = "GenerateQRImageUnlimit")]
|
||||
public async Task<GenerateQRImageOutput> GenerateQRImageUnlimitAsync(GenerateQRImageUnLimitInput input)
|
||||
{
|
||||
GenerateQRImageOutput generateQRImageOutInput = new GenerateQRImageOutput();
|
||||
if (input.PagePath.IsNullOrEmpty())
|
||||
{
|
||||
generateQRImageOutInput.Message = $"生成失败,页面路径不能为空";
|
||||
return generateQRImageOutInput;
|
||||
}
|
||||
|
||||
if (input.Scene.Length > 32)
|
||||
{
|
||||
generateQRImageOutInput.Message = $"生成失败,携带的参数长度超过限制";
|
||||
return generateQRImageOutInput;
|
||||
}
|
||||
|
||||
if (input.ImageName.IsNullOrEmpty())
|
||||
{
|
||||
input.ImageName = DateTime.Now.ToString("yyyyMMddHHmmss");
|
||||
}
|
||||
|
||||
var accessToken = await GetCgibinToken();
|
||||
var request = new WxaGetWxaCodeRequest
|
||||
{
|
||||
AccessToken = accessToken,
|
||||
Width = input.Width,
|
||||
PagePath = input.PagePath,
|
||||
};
|
||||
var response = await _wechatApiClient.ExecuteWxaGetWxaCodeAsync(request);
|
||||
|
||||
if (response.IsSuccessful())
|
||||
{
|
||||
var QRImagePath = App.GetConfig<string>("Wechat:QRImagePath");
|
||||
var relativeImgPath = string.Empty;
|
||||
|
||||
// 判断路径是绝对路径还是相对路径
|
||||
var isPathRooted = Path.IsPathRooted(QRImagePath);
|
||||
if (!isPathRooted)
|
||||
{
|
||||
// 相对路径
|
||||
relativeImgPath = string.IsNullOrEmpty(QRImagePath) ? Path.Combine("upload", "QRImageUnLimit") : QRImagePath;
|
||||
QRImagePath = Path.Combine(App.WebHostEnvironment.WebRootPath, relativeImgPath);
|
||||
}
|
||||
|
||||
//判断文件存放路径是否存在
|
||||
if (!Directory.Exists(QRImagePath))
|
||||
{
|
||||
Directory.CreateDirectory(QRImagePath);
|
||||
}
|
||||
// 将二维码图片数据保存为文件
|
||||
var fileName = $"{input.ImageName.ToUpper()}.png";
|
||||
var filePath = Path.Combine(QRImagePath, fileName);
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
File.Delete(filePath);
|
||||
}
|
||||
File.WriteAllBytes(filePath, response.GetRawBytes());
|
||||
|
||||
generateQRImageOutInput.Success = true;
|
||||
generateQRImageOutInput.ImgPath = filePath;
|
||||
generateQRImageOutInput.RelativeImgPath = Path.Combine(relativeImgPath, fileName);
|
||||
generateQRImageOutInput.Message = "生成成功";
|
||||
}
|
||||
else
|
||||
{
|
||||
// 处理错误情况
|
||||
generateQRImageOutInput.Message = $"生成失败 错误代码:{response.ErrorCode} 错误描述:{response.ErrorMessage}";
|
||||
}
|
||||
return generateQRImageOutInput;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取Access_token
|
||||
/// </summary>
|
||||
private async Task<string> GetCgibinToken()
|
||||
{
|
||||
return await _wechatApiClientFactory.TryGetWxOpenAccessTokenAsync();
|
||||
}
|
||||
}
|
||||
@@ -1,208 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Admin.NET.Core.Service;
|
||||
|
||||
/// <summary>
|
||||
/// 微信API客户端
|
||||
/// </summary>
|
||||
public partial class WechatApiClientFactory : ISingleton
|
||||
{
|
||||
private readonly IHttpClientFactory _httpClientFactory;
|
||||
public readonly WechatOptions _wechatOptions;
|
||||
private readonly SysCacheService _sysCacheService;
|
||||
|
||||
public WechatApiClientFactory(IHttpClientFactory httpClientFactory, IOptions<WechatOptions> wechatOptions, SysCacheService sysCacheService)
|
||||
{
|
||||
_httpClientFactory = httpClientFactory ?? throw new ArgumentNullException(nameof(httpClientFactory));
|
||||
_wechatOptions = wechatOptions.Value ?? throw new ArgumentNullException(nameof(wechatOptions));
|
||||
_sysCacheService = sysCacheService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 微信公众号
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public WechatApiClient CreateWechatClient()
|
||||
{
|
||||
if (string.IsNullOrEmpty(_wechatOptions.WechatAppId) || string.IsNullOrEmpty(_wechatOptions.WechatAppSecret))
|
||||
throw Oops.Oh("微信公众号配置错误");
|
||||
|
||||
var client = WechatApiClientBuilder.Create(new WechatApiClientOptions()
|
||||
{
|
||||
AppId = _wechatOptions.WechatAppId,
|
||||
AppSecret = _wechatOptions.WechatAppSecret,
|
||||
PushToken = _wechatOptions.WechatToken,
|
||||
PushEncodingAESKey = _wechatOptions.WechatEncodingAESKey,
|
||||
})
|
||||
.UseHttpClient(_httpClientFactory.CreateClient(), disposeClient: false) // 设置 HttpClient 不随客户端一同销毁
|
||||
.Build();
|
||||
|
||||
client.Configure(config =>
|
||||
{
|
||||
JsonSerializerSettings jsonSerializerSettings = NewtonsoftJsonSerializer.GetDefaultSerializerSettings();
|
||||
jsonSerializerSettings.Formatting = Formatting.Indented;
|
||||
config.JsonSerializer = new NewtonsoftJsonSerializer(jsonSerializerSettings); // 指定 System.Text.Json JSON序列化
|
||||
// config.JsonSerializer = new SystemTextJsonSerializer(jsonSerializerOptions); // 指定 Newtonsoft.Json JSON序列化
|
||||
});
|
||||
|
||||
return client;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 微信小程序
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public WechatApiClient CreateWxOpenClient()
|
||||
{
|
||||
if (string.IsNullOrEmpty(_wechatOptions.WxOpenAppId) || string.IsNullOrEmpty(_wechatOptions.WxOpenAppSecret))
|
||||
throw Oops.Oh("微信小程序配置错误");
|
||||
|
||||
var client = WechatApiClientBuilder.Create(new WechatApiClientOptions()
|
||||
{
|
||||
AppId = _wechatOptions.WxOpenAppId,
|
||||
AppSecret = _wechatOptions.WxOpenAppSecret,
|
||||
PushToken = _wechatOptions.WxToken,
|
||||
PushEncodingAESKey = _wechatOptions.WxEncodingAESKey,
|
||||
})
|
||||
.UseHttpClient(_httpClientFactory.CreateClient(), disposeClient: false) // 设置 HttpClient 不随客户端一同销毁
|
||||
.Build();
|
||||
|
||||
client.Configure(config =>
|
||||
{
|
||||
JsonSerializerSettings jsonSerializerSettings = NewtonsoftJsonSerializer.GetDefaultSerializerSettings();
|
||||
jsonSerializerSettings.Formatting = Formatting.Indented;
|
||||
config.JsonSerializer = new NewtonsoftJsonSerializer(jsonSerializerSettings); // 指定 System.Text.Json JSON序列化
|
||||
// config.JsonSerializer = new SystemTextJsonSerializer(jsonSerializerOptions); // 指定 Newtonsoft.Json JSON序列化
|
||||
});
|
||||
|
||||
return client;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取微信公众号AccessToken
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<string> TryGetWechatAccessTokenAsync()
|
||||
{
|
||||
if (!_sysCacheService.ExistKey($"WxAccessToken_{_wechatOptions.WechatAppId}") || string.IsNullOrEmpty(_sysCacheService.Get<string>($"WxAccessToken_{_wechatOptions.WechatAppId}")))
|
||||
{
|
||||
var client = CreateWechatClient();
|
||||
var reqCgibinToken = new CgibinTokenRequest();
|
||||
var resCgibinToken = await client.ExecuteCgibinTokenAsync(reqCgibinToken);
|
||||
if (resCgibinToken.ErrorCode != (int)WechatReturnCodeEnum.请求成功)
|
||||
throw Oops.Oh(resCgibinToken.ErrorMessage + " " + resCgibinToken.ErrorCode);
|
||||
_sysCacheService.Set($"WxAccessToken_{_wechatOptions.WechatAppId}", resCgibinToken.AccessToken, TimeSpan.FromSeconds(resCgibinToken.ExpiresIn - 60));
|
||||
}
|
||||
|
||||
return _sysCacheService.Get<string>($"WxAccessToken_{_wechatOptions.WechatAppId}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取微信小程序AccessToken
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<string> TryGetWxOpenAccessTokenAsync()
|
||||
{
|
||||
if (!_sysCacheService.ExistKey($"WxAccessToken_{_wechatOptions.WxOpenAppId}") || string.IsNullOrEmpty(_sysCacheService.Get<string>($"WxAccessToken_{_wechatOptions.WxOpenAppId}")))
|
||||
{
|
||||
var client = CreateWxOpenClient();
|
||||
var reqCgibinToken = new CgibinTokenRequest();
|
||||
var resCgibinToken = await client.ExecuteCgibinTokenAsync(reqCgibinToken);
|
||||
if (resCgibinToken.ErrorCode != (int)WechatReturnCodeEnum.请求成功)
|
||||
throw Oops.Oh(resCgibinToken.ErrorMessage + " " + resCgibinToken.ErrorCode);
|
||||
_sysCacheService.Set($"WxAccessToken_{_wechatOptions.WxOpenAppId}", resCgibinToken.AccessToken, TimeSpan.FromSeconds(resCgibinToken.ExpiresIn - 60));
|
||||
}
|
||||
|
||||
return _sysCacheService.Get<string>($"WxAccessToken_{_wechatOptions.WxOpenAppId}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查微信公众号AccessToken
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task CheckWechatAccessTokenAsync()
|
||||
{
|
||||
if (string.IsNullOrEmpty(_wechatOptions.WechatAppId) || string.IsNullOrEmpty(_wechatOptions.WechatAppSecret)) return;
|
||||
|
||||
var req = new CgibinOpenApiQuotaGetRequest
|
||||
{
|
||||
AccessToken = await TryGetWechatAccessTokenAsync(),
|
||||
CgiPath = "/cgi-bin/token"
|
||||
};
|
||||
var client = CreateWechatClient();
|
||||
var res = await client.ExecuteCgibinOpenApiQuotaGetAsync(req);
|
||||
|
||||
var originColor = Console.ForegroundColor;
|
||||
if (res.ErrorCode != (int)WechatReturnCodeEnum.请求成功)
|
||||
{
|
||||
_sysCacheService.Remove($"WxAccessToken_{_wechatOptions.WechatAppId}");
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
Console.WriteLine("【" + DateTime.Now + "】" + _wechatOptions.WxOpenAppId + " 微信公众号令牌 无效");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Magenta;
|
||||
Console.WriteLine("【" + DateTime.Now + "】" + _wechatOptions.WxOpenAppId + " 微信公众号令牌 有效");
|
||||
}
|
||||
Console.ForegroundColor = originColor;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查微信小程序AccessToken
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task CheckWxOpenAccessTokenAsync()
|
||||
{
|
||||
if (string.IsNullOrEmpty(_wechatOptions.WxOpenAppId) || string.IsNullOrEmpty(_wechatOptions.WxOpenAppSecret)) return;
|
||||
|
||||
var req = new CgibinOpenApiQuotaGetRequest
|
||||
{
|
||||
AccessToken = await TryGetWxOpenAccessTokenAsync(),
|
||||
CgiPath = "/cgi-bin/token"
|
||||
};
|
||||
var client = CreateWxOpenClient();
|
||||
var res = await client.ExecuteCgibinOpenApiQuotaGetAsync(req);
|
||||
|
||||
var originColor = Console.ForegroundColor;
|
||||
if (res.ErrorCode != (int)WechatReturnCodeEnum.请求成功)
|
||||
{
|
||||
_sysCacheService.Remove($"WxAccessToken_{_wechatOptions.WxOpenAppId}");
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
Console.WriteLine("【" + DateTime.Now + "】" + _wechatOptions.WxOpenAppId + " 微信小程序令牌 无效");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Magenta;
|
||||
Console.WriteLine("【" + DateTime.Now + "】" + _wechatOptions.WxOpenAppId + " 微信小程序令牌 有效");
|
||||
}
|
||||
Console.ForegroundColor = originColor;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取微信JS接口临时票据jsapi_ticket
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<string> TryGetWechatJsApiTicketAsync()
|
||||
{
|
||||
if (!_sysCacheService.ExistKey($"WxJsApiTicket_{_wechatOptions.WechatAppId}") || string.IsNullOrEmpty(_sysCacheService.Get<string>($"WxJsApiTicket_{_wechatOptions.WechatAppId}")))
|
||||
{
|
||||
var accessToken = await TryGetWechatAccessTokenAsync();
|
||||
var client = CreateWechatClient();
|
||||
var request = new CgibinTicketGetTicketRequest()
|
||||
{
|
||||
AccessToken = accessToken
|
||||
};
|
||||
var response = await client.ExecuteCgibinTicketGetTicketAsync(request);
|
||||
if (!response.IsSuccessful())
|
||||
throw Oops.Oh(response.ErrorMessage + " " + response.ErrorCode);
|
||||
_sysCacheService.Set($"WxJsApiTicket_{_wechatOptions.WechatAppId}", response.Ticket, TimeSpan.FromSeconds(response.ExpiresIn - 60));
|
||||
}
|
||||
return _sysCacheService.Get<string>($"WxJsApiTicket_{_wechatOptions.WechatAppId}");
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,45 @@ namespace Admin.NET.Core;
|
||||
|
||||
public static class SqlSugarSetup
|
||||
{
|
||||
// 仅自动维护后台通用底座表;支付、LDAP、代码生成等扩展按需再接入。
|
||||
private static readonly HashSet<string> RetainedSystemEntities = new(StringComparer.Ordinal)
|
||||
{
|
||||
"SysConfig",
|
||||
"SysDictData",
|
||||
"SysDictDataTenant",
|
||||
"SysDictType",
|
||||
"SysFile",
|
||||
"SysFileProvider",
|
||||
"SysLang",
|
||||
"SysLangText",
|
||||
"SysLogDiff",
|
||||
"SysLogEx",
|
||||
"SysLogOp",
|
||||
"SysLogVis",
|
||||
"SysMenu",
|
||||
"SysNotice",
|
||||
"SysNoticeUser",
|
||||
"SysOnlineUser",
|
||||
"SysOpenAccess",
|
||||
"SysOrg",
|
||||
"SysPos",
|
||||
"SysRegion",
|
||||
"SysRole",
|
||||
"SysRoleMenu",
|
||||
"SysRoleOrg",
|
||||
"SysTemplate",
|
||||
"SysTenant",
|
||||
"SysTenantConfig",
|
||||
"SysTenantConfigData",
|
||||
"SysTenantMenu",
|
||||
"SysUser",
|
||||
"SysUserConfig",
|
||||
"SysUserConfigData",
|
||||
"SysUserExtOrg",
|
||||
"SysUserMenu",
|
||||
"SysUserRegWay",
|
||||
"SysUserRole",
|
||||
};
|
||||
// 多租户实例
|
||||
public static ITenant ITenant { get; set; }
|
||||
|
||||
@@ -445,6 +484,8 @@ public static class SqlSugarSetup
|
||||
return App.EffectiveTypes
|
||||
.Where(u => !u.IsInterface && !u.IsAbstract && u.IsClass && u.IsDefined(typeof(SugarTable), false))
|
||||
.Where(u => !u.GetCustomAttributes<IgnoreTableAttribute>().Any())
|
||||
.Where(u => RetainedSystemEntities.Contains(u.Name) ||
|
||||
(u.Namespace?.StartsWith("Evergreen.Health.Application.Health", StringComparison.Ordinal) ?? false))
|
||||
.WhereIF(config.TableSettings.EnableIncreTable, u => u.IsDefined(typeof(IncreTableAttribute), false))
|
||||
.Where(u => IsEntityForConfig(u, config))
|
||||
.ToList();
|
||||
@@ -686,6 +727,8 @@ public static class SqlSugarSetup
|
||||
// 获取所有业务表-初始化租户库表结构(排除系统表、日志表、特定库表)
|
||||
var entityTypes = App.EffectiveTypes
|
||||
.Where(u => !u.GetCustomAttributes<IgnoreTableAttribute>().Any())
|
||||
.Where(u => RetainedSystemEntities.Contains(u.Name) ||
|
||||
(u.Namespace?.StartsWith("Evergreen.Health.Application.Health", StringComparison.Ordinal) ?? false))
|
||||
.Where(u => !u.IsInterface && !u.IsAbstract && u.IsClass && u.IsDefined(typeof(SugarTable), false) &&
|
||||
!u.IsDefined(typeof(SysTableAttribute), false) && !u.IsDefined(typeof(LogTableAttribute), false) && !u.IsDefined(typeof(TenantAttribute), false)).ToList();
|
||||
if (entityTypes.Count == 0) return;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
@@ -26,18 +26,13 @@ public static class ProjectOptions
|
||||
services.AddConfigurableOptions<ClusterOptions>();
|
||||
services.AddConfigurableOptions<OSSProviderOptions>();
|
||||
services.AddConfigurableOptions<UploadOptions>();
|
||||
services.AddConfigurableOptions<WechatOptions>();
|
||||
services.AddConfigurableOptions<WechatPayOptions>();
|
||||
services.AddConfigurableOptions<PayCallBackOptions>();
|
||||
services.AddConfigurableOptions<CodeGenOptions>();
|
||||
services.AddConfigurableOptions<EnumOptions>();
|
||||
services.AddConfigurableOptions<APIJSONOptions>();
|
||||
services.AddConfigurableOptions<EmailOptions>();
|
||||
services.AddConfigurableOptions<OAuthOptions>();
|
||||
services.AddConfigurableOptions<CryptogramOptions>();
|
||||
services.AddConfigurableOptions<SMSOptions>();
|
||||
services.AddConfigurableOptions<EventBusOptions>();
|
||||
services.AddConfigurableOptions<AlipayOptions>();
|
||||
services.AddConfigurableOptions<CDConfigOptions>();
|
||||
services.AddConfigurableOptions<DeepSeekOptions>();
|
||||
services.AddConfigurableOptions<LocalizationSettingsOptions>();
|
||||
@@ -48,4 +43,4 @@ public static class ProjectOptions
|
||||
|
||||
return services;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
@@ -76,12 +76,6 @@ public class Startup : AppStartup
|
||||
services.AddHttpRemote();
|
||||
// 任务队列
|
||||
services.AddTaskQueue();
|
||||
// 任务调度
|
||||
services.AddSchedule(options =>
|
||||
{
|
||||
options.AddPersistence<DbJobPersistence>(); // 添加作业持久化器
|
||||
options.AddMonitor<JobMonitor>(); // 添加作业执行监视器
|
||||
});
|
||||
// 脱敏检测
|
||||
services.AddSensitiveDetection();
|
||||
|
||||
@@ -114,9 +108,6 @@ public class Startup : AppStartup
|
||||
options.JsonSerializerOptions.Converters.AddDateTimeTypeConverters("yyyy-MM-dd HH:mm:ss"); // 时间格式化
|
||||
});
|
||||
|
||||
// 三方授权登录OAuth
|
||||
services.AddOAuth();
|
||||
|
||||
// ElasticSearch
|
||||
services.AddElasticSearchClients();
|
||||
|
||||
@@ -200,7 +191,7 @@ public class Startup : AppStartup
|
||||
services.AddSingleton<IOSSServiceManager, OSSServiceManager>(); // 改为单例以保持缓存
|
||||
services.AddTransient<MultiOSSFileProvider>();
|
||||
|
||||
// 模板引擎
|
||||
// 通用模板渲染(模板管理、库表实体/种子生成会使用)
|
||||
services.AddViewEngine();
|
||||
|
||||
// 即时通讯
|
||||
@@ -318,9 +309,6 @@ public class Startup : AppStartup
|
||||
//// 启用HTTPS
|
||||
//app.UseHttpsRedirection();
|
||||
|
||||
// 启用OAuth
|
||||
app.UseOAuth();
|
||||
|
||||
// 添加状态码拦截中间件
|
||||
app.UseUnifyResultStatusCodes();
|
||||
|
||||
@@ -342,27 +330,6 @@ public class Startup : AppStartup
|
||||
app.UseClientRateLimiting();
|
||||
app.UsePolicyRateLimit();
|
||||
|
||||
// 任务调度看板
|
||||
app.UseScheduleUI(options =>
|
||||
{
|
||||
options.RequestPath = "/schedule"; // 必须以 / 开头且不以 / 结尾
|
||||
options.DisableOnProduction = false; // 是否在生产环境中关闭
|
||||
options.DisplayEmptyTriggerJobs = true; // 是否显示空作业触发器的作业
|
||||
options.DisplayHead = false; // 是否显示页头
|
||||
options.DefaultExpandAllJobs = false; // 是否默认展开所有作业
|
||||
options.EnableDirectoryBrowsing = false; // 是否启用目录浏览
|
||||
options.Title = "定时任务看板"; // 自定义看板标题
|
||||
|
||||
options.LoginConfig.OnLoging = async (username, password, httpContext) =>
|
||||
{
|
||||
var res = await httpContext.RequestServices.GetRequiredService<SysAuthService>().SwaggerSubmitUrl(new SpecificationAuth { UserName = username, Password = password });
|
||||
return res == 200;
|
||||
};
|
||||
options.LoginConfig.DefaultUsername = "";
|
||||
options.LoginConfig.DefaultPassword = "";
|
||||
options.LoginConfig.SessionKey = "schedule_session_key"; // 登录客户端存储的 Session 键
|
||||
});
|
||||
|
||||
app.UseInject(string.Empty, options =>
|
||||
{
|
||||
foreach (var groupInfo in SpecificationDocumentBuilder.GetOpenApiGroups())
|
||||
@@ -403,4 +370,4 @@ public class Startup : AppStartup
|
||||
pattern: "{controller=Home}/{action=Index}/{id?}");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
-- 删除当前项目未启用的 Admin.NET 扩展模块数据表。
|
||||
-- 保留用户、角色、菜单、权限、组织、职位、租户、字典、配置、日志、文件和通知等通用表。
|
||||
SET FOREIGN_KEY_CHECKS = 0;
|
||||
DROP TABLE IF EXISTS `SysAlipayAuthInfo`;
|
||||
DROP TABLE IF EXISTS `SysAlipayTransaction`;
|
||||
DROP TABLE IF EXISTS `SysWechatPay`;
|
||||
DROP TABLE IF EXISTS `SysWechatRefund`;
|
||||
DROP TABLE IF EXISTS `SysWechatUser`;
|
||||
DROP TABLE IF EXISTS `SysLdap`;
|
||||
DROP TABLE IF EXISTS `SysUserLdap`;
|
||||
DROP TABLE IF EXISTS `SysCodeGen`;
|
||||
DROP TABLE IF EXISTS `SysCodeGenConfig`;
|
||||
DROP TABLE IF EXISTS `SysJobCluster`;
|
||||
DROP TABLE IF EXISTS `SysJobDetail`;
|
||||
DROP TABLE IF EXISTS `SysJobTrigger`;
|
||||
DROP TABLE IF EXISTS `SysJobTriggerRecord`;
|
||||
DROP TABLE IF EXISTS `SysPlugin`;
|
||||
DROP TABLE IF EXISTS `SysPrint`;
|
||||
DROP TABLE IF EXISTS `SysSchedule`;
|
||||
|
||||
-- 清理扩展模块留下的菜单授权、菜单、配置和代码生成字典。
|
||||
DELETE FROM `SysRoleMenu`
|
||||
WHERE `MenuId` IN (
|
||||
1300200070101, 1300200070201, 1300200070301, 1300200070401, 1300200070501,
|
||||
1300200080101, 1300200080201, 1300200080301, 1300200080401, 1300200080501, 1300200080601, 1300200080701, 1300200080801,
|
||||
1300300060101, 1300300060201, 1300300060301, 1300300060401, 1300300060501,
|
||||
1300300110101, 1300300110201, 1300300110301, 1300300110401, 1300300110501,
|
||||
1300300120101, 1300300120201, 1300300120301, 1300300120401, 1300300120501,
|
||||
1300300150101, 1300300150201, 1300300150301, 1300300150401, 1300300150501, 1300300150601,
|
||||
1300500020101
|
||||
);
|
||||
DELETE FROM `SysTenantMenu`
|
||||
WHERE `MenuId` IN (
|
||||
1300200070101, 1300200070201, 1300200070301, 1300200070401, 1300200070501,
|
||||
1300200080101, 1300200080201, 1300200080301, 1300200080401, 1300200080501, 1300200080601, 1300200080701, 1300200080801,
|
||||
1300300060101, 1300300060201, 1300300060301, 1300300060401, 1300300060501,
|
||||
1300300110101, 1300300110201, 1300300110301, 1300300110401, 1300300110501,
|
||||
1300300120101, 1300300120201, 1300300120301, 1300300120401, 1300300120501,
|
||||
1300300150101, 1300300150201, 1300300150301, 1300300150401, 1300300150501, 1300300150601,
|
||||
1300500020101
|
||||
);
|
||||
DELETE FROM `SysMenu`
|
||||
WHERE `Id` IN (
|
||||
1300200070101, 1300200070201, 1300200070301, 1300200070401, 1300200070501,
|
||||
1300200080101, 1300200080201, 1300200080301, 1300200080401, 1300200080501, 1300200080601, 1300200080701, 1300200080801,
|
||||
1300300060101, 1300300060201, 1300300060301, 1300300060401, 1300300060501,
|
||||
1300300110101, 1300300110201, 1300300110301, 1300300110401, 1300300110501,
|
||||
1300300120101, 1300300120201, 1300300120301, 1300300120401, 1300300120501,
|
||||
1300300150101, 1300300150201, 1300300150301, 1300300150401, 1300300150501, 1300300150601,
|
||||
1300500020101
|
||||
);
|
||||
DELETE FROM `SysConfig` WHERE `Code` = 'sys_domain_login';
|
||||
DELETE FROM `SysDictData` WHERE `DictTypeId` IN (1300000000111, 1300000000121, 1300000000131, 1300000000141, 1300000000151, 1300000000161);
|
||||
DELETE FROM `SysDictType` WHERE `Id` IN (1300000000111, 1300000000121, 1300000000131, 1300000000141, 1300000000151, 1300000000161);
|
||||
SET FOREIGN_KEY_CHECKS = 1;
|
||||
@@ -1,30 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace @(Model.NameSpace);
|
||||
|
||||
/// <summary>
|
||||
/// @(Model.BusName)输出参数
|
||||
/// </summary>
|
||||
public class @(Model.ClassName)Dto
|
||||
{
|
||||
@foreach (var column in Model.TableField){
|
||||
if(column.EffectType == "ForeignKey"){
|
||||
@:/// <summary>
|
||||
@:/// @column.ColumnComment
|
||||
@:/// </summary>
|
||||
@:public string @(column.PropertyName)FkColumn { get; set; }
|
||||
@:
|
||||
}
|
||||
}
|
||||
@foreach (var column in Model.TableField){
|
||||
@:/// <summary>
|
||||
@:/// @column.ColumnComment
|
||||
@:/// </summary>
|
||||
@:public @column.NetType @column.PropertyName { get; set; }
|
||||
@:
|
||||
}
|
||||
}
|
||||
@@ -1,200 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
using Admin.NET.Core;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Magicodes.ExporterAndImporter.Core;
|
||||
using Magicodes.ExporterAndImporter.Excel;
|
||||
|
||||
namespace @(Model.NameSpace);
|
||||
|
||||
/// <summary>
|
||||
/// @(Model.BusName)基础输入参数
|
||||
/// </summary>
|
||||
public class @(Model.ClassName)BaseInput
|
||||
{
|
||||
@foreach (var column in Model.PrimaryKeyFieldList.Concat(Model.AddUpdateFieldList)){
|
||||
@:/// <summary>
|
||||
@:/// @column.ColumnComment
|
||||
@:/// </summary>
|
||||
if (column.EffectType is "EnumSelector" or "DictSelector") {
|
||||
@:[Dict(@(column.EffectType == "EnumSelector" ? $"nameof({column.DictTypeCode})" : $"\"{column.DictTypeCode}\""), AllowNullValue=true)]
|
||||
}
|
||||
if (column.WhetherRequired == "Y") {
|
||||
@:[Required(ErrorMessage = "@(column.ColumnComment)不能为空")]
|
||||
}
|
||||
@:public virtual @Model.GetNullableNetType(column.NetType) @column.PropertyName { get; set; }
|
||||
@:
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// @(Model.BusName)分页查询输入参数
|
||||
/// </summary>
|
||||
public class Page@(Model.ClassName)Input : BasePageInput
|
||||
{
|
||||
@foreach (var column in Model.TableField.Where(u => u.WhetherQuery == "Y")){
|
||||
if(column.NetType?.TrimEnd('?') == "DateTime" && column.QueryType == "~"){
|
||||
@:/// <summary>
|
||||
@:/// @(column.ColumnComment)范围
|
||||
@:/// </summary>
|
||||
@: public DateTime?[] @(column.PropertyName)Range { get; set; }
|
||||
} else {
|
||||
@:/// <summary>
|
||||
@:/// @column.ColumnComment
|
||||
@:/// </summary>
|
||||
if (column.EffectType is "EnumSelector" or "DictSelector") {
|
||||
@:[Dict(@(column.EffectType == "EnumSelector" ? $"nameof({column.DictTypeCode})" : $"\"{column.DictTypeCode}\""), AllowNullValue=true)]
|
||||
}
|
||||
@:public @Model.GetNullableNetType(column.NetType) @column.PropertyName { get; set; }
|
||||
}
|
||||
@:
|
||||
}
|
||||
@if (Model.ImportFieldList.Count > 0){
|
||||
var primaryKey = Model.PrimaryKeyFieldList.First();
|
||||
@:/// <summary>
|
||||
@:/// 选中主键列表
|
||||
@:/// </summary>
|
||||
@: public List<@(primaryKey.NetType)> SelectKeyList { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// @(Model.BusName)增加输入参数
|
||||
/// </summary>
|
||||
public class Add@(Model.ClassName)Input
|
||||
{
|
||||
@foreach (var column in Model.AddUpdateFieldList){
|
||||
@:/// <summary>
|
||||
@:/// @column.ColumnComment
|
||||
@:/// </summary>
|
||||
if (column.EffectType is "EnumSelector" or "DictSelector") {
|
||||
@:[Dict(@(column.EffectType == "EnumSelector" ? $"nameof({column.DictTypeCode})" : $"\"{column.DictTypeCode}\""), AllowNullValue=true)]
|
||||
}
|
||||
if (column.WhetherRequired == "Y") {
|
||||
@:[Required(ErrorMessage = "@(column.ColumnComment)不能为空")]
|
||||
}
|
||||
if (column.NetType.TrimEnd('?').EndsWith("string") && column.ColumnLength > 0){
|
||||
@:[MaxLength(@column.ColumnLength, ErrorMessage = "@(column.ColumnComment)字符长度不能超过@(column.ColumnLength)")]
|
||||
}
|
||||
@:public @Model.GetNullableNetType(column.NetType) @column.PropertyName { get; set; }
|
||||
@:
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// @(Model.BusName)删除输入参数
|
||||
/// </summary>
|
||||
public class Delete@(Model.ClassName)Input
|
||||
{
|
||||
@foreach (var column in Model.PrimaryKeyFieldList) {
|
||||
@:/// <summary>
|
||||
@:/// @column.ColumnComment
|
||||
@:/// </summary>
|
||||
@:[Required(ErrorMessage = "@(column.ColumnComment)不能为空")]
|
||||
@:public @Model.GetNullableNetType(column.NetType) @column.PropertyName { get; set; }
|
||||
@:
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// @(Model.BusName)更新输入参数
|
||||
/// </summary>
|
||||
public class Update@(Model.ClassName)Input
|
||||
{
|
||||
@foreach (var column in Model.PrimaryKeyFieldList.Concat(Model.AddUpdateFieldList)){
|
||||
@:/// <summary>
|
||||
@:/// @column.ColumnComment
|
||||
@:/// </summary>
|
||||
if (column.EffectType is "EnumSelector" or "DictSelector") {
|
||||
@:[Dict(@(column.EffectType == "EnumSelector" ? $"nameof({column.DictTypeCode})" : $"\"{column.DictTypeCode}\""), AllowNullValue=true)]
|
||||
}
|
||||
if (column.WhetherRequired == "Y" || column.ColumnKey == "True") {
|
||||
@:[Required(ErrorMessage = "@(column.ColumnComment)不能为空")]
|
||||
}
|
||||
if (column.NetType.TrimEnd('?').EndsWith("string") && column.ColumnLength > 0){
|
||||
@:[MaxLength(@column.ColumnLength, ErrorMessage = "@(column.ColumnComment)字符长度不能超过@(column.ColumnLength)")]
|
||||
}
|
||||
@:public @Model.GetNullableNetType(column.NetType) @column.PropertyName { get; set; }
|
||||
@:
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// @(Model.BusName)主键查询输入参数
|
||||
/// </summary>
|
||||
public class QueryById@(Model.ClassName)Input : Delete@(Model.ClassName)Input
|
||||
{
|
||||
}
|
||||
|
||||
@if (Model.DropdownFieldList.Count > 0) {
|
||||
@:/// <summary>
|
||||
@:/// 下拉数据输入参数
|
||||
@:/// </summary>
|
||||
@:public class DropdownData@(Model.ClassName)Input
|
||||
@:{
|
||||
@:/// <summary>
|
||||
@:/// 是否用于分页查询
|
||||
@:/// </summary>
|
||||
@:public bool FromPage { get; set; }
|
||||
@:}
|
||||
@:
|
||||
}
|
||||
@if (Model.HasSetStatus) {
|
||||
@:/// <summary>
|
||||
@:/// 设置状态输入参数
|
||||
@:/// </summary>
|
||||
@:public class Set@(Model.ClassName)StatusInput : BaseStatusInput
|
||||
@:{
|
||||
@foreach (var column in Model.PrimaryKeyFieldList.Where(u => u.PropertyName != "Id")) {
|
||||
@:/// <summary>
|
||||
@:/// @column.ColumnComment
|
||||
@:/// </summary>
|
||||
@:[Required(ErrorMessage = "@(column.ColumnComment)不能为空")]
|
||||
@:public @Model.GetNullableNetType(column.NetType) @column.PropertyName { get; set; }
|
||||
@:
|
||||
}
|
||||
@:}
|
||||
@:
|
||||
}
|
||||
@if (Model.ImportFieldList.Count > 0){
|
||||
@:/// <summary>
|
||||
@:/// @(Model.BusName)数据导入实体
|
||||
@:/// </summary>
|
||||
@:[ExcelImporter(SheetIndex = 1, IsOnlyErrorRows = true)]
|
||||
@:public class Import@(Model.ClassName)Input : BaseImportInput
|
||||
@:{
|
||||
foreach (var column in Model.ImportFieldList){
|
||||
var headerName = (column.WhetherRequired == "Y" ? "*" : "") + column.ColumnComment;
|
||||
if(column.EffectType == "ForeignKey" || column.EffectType == "ApiTreeSelector" || column.EffectType == "DictSelector") {
|
||||
@:/// <summary>
|
||||
@:/// @column.ColumnComment 关联值
|
||||
@:/// </summary>
|
||||
@:[ImporterHeader(IsIgnore = true)]
|
||||
@:[ExporterHeader(IsIgnore = true)]
|
||||
@:public @Model.GetNullableNetType(column.NetType) @column.PropertyName { get; set; }
|
||||
@:
|
||||
@:/// <summary>
|
||||
@:/// @column.ColumnComment 文本
|
||||
@:/// </summary>
|
||||
if (column.EffectType == "DictSelector") {
|
||||
@:[Dict(@($"\"{column.DictTypeCode}\""))]
|
||||
}
|
||||
@:[ImporterHeader(Name = "@(headerName)")]
|
||||
@:[ExporterHeader("@(headerName)", Format = "@", Width = 25, IsBold = true)]
|
||||
@:public string @column.ExtendedPropertyName { get; set; }
|
||||
} else {
|
||||
@:/// <summary>
|
||||
@:/// @column.ColumnComment
|
||||
@:/// </summary>
|
||||
@:[ImporterHeader(Name = "@(headerName)")]
|
||||
@:[ExporterHeader("@(headerName)", Format = "@", Width = 25, IsBold = true)]
|
||||
@:public @Model.GetNullableNetType(column.NetType) @column.PropertyName { get; set; }
|
||||
}
|
||||
@:
|
||||
}
|
||||
@:}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user