Merge remote-tracking branch 'upstream/aq982' into v2
This commit is contained in:
commit
7d0455b100
@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://gitee.com/dotnetchina/Furion/raw/v4/schemas/v4/furion-schema.json",
|
"$schema": "https://gitee.com/dotnetchina/Furion/raw/v4/schemas/v4/furion-schema.json",
|
||||||
|
|
||||||
"Wechat": {
|
"Wechat": {
|
||||||
@ -16,16 +16,16 @@
|
|||||||
},
|
},
|
||||||
// 微信支付
|
// 微信支付
|
||||||
"WechatPay": {
|
"WechatPay": {
|
||||||
"AppId": "", // 微信公众平台AppId、开放平台AppId、小程序AppId、企业微信CorpId
|
"AppId": "wxaaaaaaaaaaaaaa85", // 微信公众平台AppId、开放平台AppId、小程序AppId、企业微信CorpId
|
||||||
"MerchantId": "", // 商户平台的商户号
|
"MerchantId": "1500000001", // 商户平台的商户号
|
||||||
"MerchantV3Secret": "", // 商户平台的APIv3密钥
|
"MerchantV3Secret": "3aaaaaaaaaaaaaaaaaaaaaaaaaaaaaoo", // 商户平台的APIv3密钥
|
||||||
"MerchantCertificateSerialNumber": "", // 商户平台的证书序列号
|
"MerchantCertificateSerialNumber": "66aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0", // 商户平台的证书序列号
|
||||||
"MerchantCertificatePrivateKey": "\\WxPayCert\\apiclient_key.pem" // 商户平台的API证书私钥(apiclient_key.pem文件内容)
|
"MerchantCertificatePrivateKey": "\\WxPayCert\\apiclient_key.pem" // 商户平台的API证书私钥(apiclient_key.pem文件内容)
|
||||||
},
|
},
|
||||||
// 支付回调
|
// 支付回调
|
||||||
"PayCallBack": {
|
"PayCallBack": {
|
||||||
"WechatPayUrl": "https://xxx/api/sysWechatPay/payCallBack", // 微信支付回调
|
"WechatPayUrl": "https://ip/sysWechatPay/payCallBack", // 微信支付回调: https://ip/sysWechatPay/payCallBack
|
||||||
"WechatRefundUrl": "", // 微信退款回调
|
"WechatRefundUrl": "https://ip/api/sysWechatPay/refundCallBack", // 微信退款回调:https://ip/api/sysWechatPay/refundCallBack
|
||||||
"AlipayUrl": "", // 支付宝支付回调
|
"AlipayUrl": "", // 支付宝支付回调
|
||||||
"AlipayRefundUrl": "" // 支付宝退款回调
|
"AlipayRefundUrl": "" // 支付宝退款回调
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,9 +20,9 @@
|
|||||||
<PackageReference Include="AspNetCoreRateLimit" Version="5.0.0" />
|
<PackageReference Include="AspNetCoreRateLimit" Version="5.0.0" />
|
||||||
<PackageReference Include="BouncyCastle.Cryptography" Version="2.5.1" Aliases="BouncyCastleV2" />
|
<PackageReference Include="BouncyCastle.Cryptography" Version="2.5.1" Aliases="BouncyCastleV2" />
|
||||||
<PackageReference Include="Elastic.Clients.Elasticsearch" Version="8.17.1" />
|
<PackageReference Include="Elastic.Clients.Elasticsearch" Version="8.17.1" />
|
||||||
<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.7.10" />
|
<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.7.13" />
|
||||||
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.7.10" />
|
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.7.13" />
|
||||||
<PackageReference Include="Furion.Pure" Version="4.9.7.10" />
|
<PackageReference Include="Furion.Pure" Version="4.9.7.13" />
|
||||||
<PackageReference Include="Hardware.Info" Version="101.0.1" />
|
<PackageReference Include="Hardware.Info" Version="101.0.1" />
|
||||||
<PackageReference Include="Hashids.net" Version="1.7.0" />
|
<PackageReference Include="Hashids.net" Version="1.7.0" />
|
||||||
<PackageReference Include="IPTools.China" Version="1.6.0" />
|
<PackageReference Include="IPTools.China" Version="1.6.0" />
|
||||||
@ -48,7 +48,7 @@
|
|||||||
<PackageReference Include="SSH.NET" Version="2024.2.0" />
|
<PackageReference Include="SSH.NET" Version="2024.2.0" />
|
||||||
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.6.0.2" />
|
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.6.0.2" />
|
||||||
<PackageReference Include="System.Net.Http" Version="4.3.4" />
|
<PackageReference Include="System.Net.Http" Version="4.3.4" />
|
||||||
<PackageReference Include="TencentCloudSDK.Sms" Version="3.0.1184" />
|
<PackageReference Include="TencentCloudSDK.Sms" Version="3.0.1186" />
|
||||||
<PackageReference Include="UAParser" Version="3.1.47" />
|
<PackageReference Include="UAParser" Version="3.1.47" />
|
||||||
<PackageReference Include="Yitter.IdGenerator" Version="1.0.14" />
|
<PackageReference Include="Yitter.IdGenerator" Version="1.0.14" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@ -136,6 +136,12 @@ public partial class SysCodeGenConfig : EntityBase
|
|||||||
[SugarColumn(ColumnDescription = "是否是统计字段", Length = 8)]
|
[SugarColumn(ColumnDescription = "是否是统计字段", Length = 8)]
|
||||||
[MaxLength(8)]
|
[MaxLength(8)]
|
||||||
public string? Statistical { get; set; }
|
public string? Statistical { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 是否是GroupBy字段
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(ColumnDescription = "是否是GroupBy字段", Length = 8)]
|
||||||
|
[MaxLength(8)]
|
||||||
|
public string? IsGroupBy { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 是否是查询条件
|
/// 是否是查询条件
|
||||||
|
|||||||
@ -33,7 +33,12 @@ public class SysWechatRefund : EntityBase
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(ColumnDescription = "商户退款单号", Length = 64)]
|
[SugarColumn(ColumnDescription = "商户退款单号", Length = 64)]
|
||||||
[Required]
|
[Required]
|
||||||
public string OutRefundNo { get; set; }
|
public string OutRefundNumber { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 微信接口退款ID
|
||||||
|
/// </summary>
|
||||||
|
public string RefundId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 退款原因,示例:商品已售完
|
/// 退款原因,示例:商品已售完
|
||||||
@ -75,19 +80,25 @@ public class SysWechatRefund : EntityBase
|
|||||||
/// 关联的商户订单状态(或者为第几次支付,有些订单涉及多次支付,比如先付预付款,后补尾款)
|
/// 关联的商户订单状态(或者为第几次支付,有些订单涉及多次支付,比如先付预付款,后补尾款)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(ColumnDescription = "关联的商户订单状态", Length = 32)]
|
[SugarColumn(ColumnDescription = "关联的商户订单状态", Length = 32)]
|
||||||
public string? OrderStatus { get; set; }
|
public string? RefundStatus { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 支完成时间
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(ColumnDescription = "完成时间")]
|
||||||
|
public DateTime? SuccessTime { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 关联的商户商品编码
|
/// 关联的商户商品编码
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(ColumnDescription = "关联的商户商品编码", Length = 32)]
|
[SugarColumn(ColumnDescription = "关联的商户商品编码", Length = 32)]
|
||||||
public string MerchantGoodsId { get; set; }
|
public string? MerchantGoodsId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 关联的商户商品名称
|
/// 关联的商户商品名称
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(ColumnDescription = "关联的商户商品名称", Length = 256)]
|
[SugarColumn(ColumnDescription = "关联的商户商品名称", Length = 256)]
|
||||||
public string GoodsName { get; set; }
|
public string? GoodsName { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 关联的商户商品单价
|
/// 关联的商户商品单价
|
||||||
|
|||||||
@ -222,6 +222,23 @@ public class SysCodeGenTemplateSeedData : ISqlSugarEntitySeedData<SysCodeGenTemp
|
|||||||
""UpdateUserName"": null,
|
""UpdateUserName"": null,
|
||||||
""IsDelete"": false,
|
""IsDelete"": false,
|
||||||
""Id"": 1300000000211
|
""Id"": 1300000000211
|
||||||
|
},
|
||||||
|
{
|
||||||
|
""Name"": ""service_Mid.cs.vm"",
|
||||||
|
""Type"": 2,
|
||||||
|
""SysFlag"": 1,
|
||||||
|
""IsDefault"": true,
|
||||||
|
""OutputFile"": ""Service/{TableName}/Dto/{TableName}Mid.cs"",
|
||||||
|
""Describe"": ""(服务端)中间件"",
|
||||||
|
""OrderNo"": 100,
|
||||||
|
""CreateTime"": ""1900-01-01 00:00:00"",
|
||||||
|
""UpdateTime"": ""2025-01-13 21:25:43"",
|
||||||
|
""CreateUserId"": null,
|
||||||
|
""CreateUserName"": null,
|
||||||
|
""UpdateUserId"": null,
|
||||||
|
""UpdateUserName"": null,
|
||||||
|
""IsDelete"": false,
|
||||||
|
""Id"": 1300000000215
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
";
|
";
|
||||||
|
|||||||
@ -122,6 +122,10 @@ public class CodeGenConfig
|
|||||||
/// 是否是统计字段
|
/// 是否是统计字段
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Statistical { get; set; }
|
public string Statistical { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 是否是GroupBy字段
|
||||||
|
/// </summary>
|
||||||
|
public string? IsGroupBy { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 是否是查询条件
|
/// 是否是查询条件
|
||||||
|
|||||||
@ -116,7 +116,7 @@ public class SysOnlineUserService : IDynamicApiController, ITransient
|
|||||||
[DisplayName("清理在线用户")]
|
[DisplayName("清理在线用户")]
|
||||||
public async Task ClearOnline()
|
public async Task ClearOnline()
|
||||||
{
|
{
|
||||||
if (await _sysConfigService.GetConfigValueByCode<bool>(ConfigConst.SysSingleLogin)) return;
|
if (!await _sysConfigService.GetConfigValueByCode<bool>(ConfigConst.SysSingleLogin)) return;
|
||||||
|
|
||||||
// 相同账号最后登录的用户Id集合
|
// 相同账号最后登录的用户Id集合
|
||||||
var onlineUsers = await _sysOnlineUerRep.AsQueryable().GroupBy(u => u.UserId)
|
var onlineUsers = await _sysOnlineUerRep.AsQueryable().GroupBy(u => u.UserId)
|
||||||
|
|||||||
@ -140,13 +140,13 @@ public class PageSysWechatPayInput : BasePageInput
|
|||||||
/// order_id
|
/// order_id
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <example></example>
|
/// <example></example>
|
||||||
public string? OrderId { get; set; } = "-1";
|
public string? OrderId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// order_status
|
/// order_status
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <example></example>
|
/// <example></example>
|
||||||
public string? OrderStatus { get; set; } = "-1";
|
public string? OrderStatus { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// out_trade_number
|
/// out_trade_number
|
||||||
|
|||||||
@ -15,6 +15,20 @@ namespace Admin.NET.Core.Service;
|
|||||||
[ApiDescriptionSettings(Order = 210, Description = "微信支付")]
|
[ApiDescriptionSettings(Order = 210, Description = "微信支付")]
|
||||||
public class SysWechatPayService : IDynamicApiController, ITransient
|
public class SysWechatPayService : IDynamicApiController, ITransient
|
||||||
{
|
{
|
||||||
|
private static readonly List<WechatPayEventInterceptor> wechatPayEventHandlers = [new WechatPayEventInterceptor() { Order = int.MaxValue }];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 注册支付记录变化事件处理器
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="eh">处理器</param>
|
||||||
|
/// <param name="order">排序,数据越大越先执行</param>
|
||||||
|
public static void AddPayEventInterceptor(WechatPayEventInterceptor eh, int order)
|
||||||
|
{
|
||||||
|
eh.Order = order;
|
||||||
|
wechatPayEventHandlers.Add(eh);
|
||||||
|
wechatPayEventHandlers.Sort((a, b) => b.Order - a.Order);
|
||||||
|
}
|
||||||
|
|
||||||
private readonly SqlSugarRepository<SysWechatPay> _sysWechatPayRep;
|
private readonly SqlSugarRepository<SysWechatPay> _sysWechatPayRep;
|
||||||
private readonly SqlSugarRepository<SysWechatRefund> _sysWechatRefundRep;
|
private readonly SqlSugarRepository<SysWechatRefund> _sysWechatRefundRep;
|
||||||
private readonly WechatPayOptions _wechatPayOptions;
|
private readonly WechatPayOptions _wechatPayOptions;
|
||||||
@ -28,7 +42,7 @@ public class SysWechatPayService : IDynamicApiController, ITransient
|
|||||||
IOptions<PayCallBackOptions> payCallBackOptions)
|
IOptions<PayCallBackOptions> payCallBackOptions)
|
||||||
{
|
{
|
||||||
_sysWechatPayRep = sysWechatPayRep;
|
_sysWechatPayRep = sysWechatPayRep;
|
||||||
this._sysWechatRefundRep = sysWechatRefundRep;
|
_sysWechatRefundRep = sysWechatRefundRep;
|
||||||
_wechatPayOptions = wechatPayOptions.Value;
|
_wechatPayOptions = wechatPayOptions.Value;
|
||||||
_payCallBackOptions = payCallBackOptions.Value;
|
_payCallBackOptions = payCallBackOptions.Value;
|
||||||
|
|
||||||
@ -187,7 +201,7 @@ public class SysWechatPayService : IDynamicApiController, ITransient
|
|||||||
{
|
{
|
||||||
string outTradeNumber = DateTimeOffset.Now.ToString("yyyyMMddHHmmssfff") + (new Random()).Next(100, 1000); // 微信需要的订单号(唯一)
|
string outTradeNumber = DateTimeOffset.Now.ToString("yyyyMMddHHmmssfff") + (new Random()).Next(100, 1000); // 微信需要的订单号(唯一)
|
||||||
|
|
||||||
//检查订单信息是否已存在(使用“商户交易单号+状态”唯一性判断)
|
// 检查订单信息是否已存在(使用“商户交易单号+状态”唯一性判断)
|
||||||
var wechatPay = await _sysWechatPayRep.GetFirstAsync(u => u.OrderId == input.OrderId && u.OrderStatus == input.OrderStatus);
|
var wechatPay = await _sysWechatPayRep.GetFirstAsync(u => u.OrderId == input.OrderId && u.OrderStatus == input.OrderStatus);
|
||||||
if (wechatPay != null)
|
if (wechatPay != null)
|
||||||
{
|
{
|
||||||
@ -250,6 +264,82 @@ public class SysWechatPayService : IDynamicApiController, ITransient
|
|||||||
return await _sysWechatPayRep.GetFirstAsync(u => u.OutTradeNumber == 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 wechatPayOld = await _sysWechatPayRep.GetFirstAsync(u => u.OutTradeNumber == response.OutTradeNumber
|
||||||
|
&& u.MerchantId == response.MerchantId);
|
||||||
|
SysWechatPay wechatPayNew = null;
|
||||||
|
if (wechatPayOld != null)
|
||||||
|
wechatPayNew = wechatPayOld.DeepCopy();
|
||||||
|
// 如果状态不一致就更新数据库中的记录
|
||||||
|
if (wechatPayNew != null && wechatPayNew.TradeState != response.TradeState)
|
||||||
|
{
|
||||||
|
wechatPayNew.OpenId = response.Payer?.OpenId;
|
||||||
|
wechatPayNew.TransactionId = response.TransactionId; // 支付订单号
|
||||||
|
wechatPayNew.TradeType = response.TradeType; // 交易类型
|
||||||
|
wechatPayNew.TradeState = response.TradeState; // 交易状态
|
||||||
|
wechatPayNew.TradeStateDescription = response.TradeStateDescription; // 交易状态描述
|
||||||
|
wechatPayNew.BankType = response.BankType; // 付款银行类型
|
||||||
|
if (response.Amount != null)
|
||||||
|
{
|
||||||
|
wechatPayNew.Total = response.Amount.Total; // 订单总金额
|
||||||
|
wechatPayNew.PayerTotal = response.Amount.PayerTotal; // 用户支付金额
|
||||||
|
}
|
||||||
|
if (response.SuccessTime.HasValue)
|
||||||
|
wechatPayNew.SuccessTime = response.SuccessTime.Value.DateTime; // 支付完成时间
|
||||||
|
else
|
||||||
|
wechatPayNew.SuccessTime = DateTime.Now;
|
||||||
|
await _sysWechatPayRep.AsUpdateable(wechatPayNew).IgnoreColumns(true).ExecuteCommandAsync();
|
||||||
|
}
|
||||||
|
if (wechatPayOld == null || wechatPayOld.TradeState != wechatPayNew.TradeState)
|
||||||
|
{
|
||||||
|
// 没必要等所有回调事件处理完再返回给微信,开一个Task执行
|
||||||
|
Task.Run(async () =>
|
||||||
|
{
|
||||||
|
foreach (var eh in wechatPayEventHandlers)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!await eh.PayInforChanged(wechatPayOld, wechatPayNew))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
$"GetPayInfoFromWechat 中执行微信支付回调{eh.GetType().Name}出错".LogError(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).Start();
|
||||||
|
}
|
||||||
|
// 下面这里创建一个新的对象,是因为不想把全部字段都返回
|
||||||
|
wechatPayNew = new SysWechatPay()
|
||||||
|
{
|
||||||
|
AppId = _wechatPayOptions.AppId,
|
||||||
|
MerchantId = _wechatPayOptions.MerchantId,
|
||||||
|
SubAppId = _wechatPayOptions.AppId,
|
||||||
|
SubMerchantId = _wechatPayOptions.MerchantId,
|
||||||
|
OutTradeNumber = request.OutTradeNumber,
|
||||||
|
Attachment = response.Attachment,
|
||||||
|
TransactionId = response.TransactionId,
|
||||||
|
TradeType = response.TradeType, // 交易类型
|
||||||
|
TradeState = response.TradeState, // 交易状态
|
||||||
|
TradeStateDescription = response.TradeStateDescription, // 交易状态描述
|
||||||
|
BankType = response.BankType, // 付款银行类型
|
||||||
|
SuccessTime = response.SuccessTime.HasValue ? response.SuccessTime.Value.DateTime : DateTime.Now // 支付完成时间
|
||||||
|
};
|
||||||
|
|
||||||
|
return wechatPayNew;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 微信支付成功回调(商户直连) 🔖
|
/// 微信支付成功回调(商户直连) 🔖
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -269,35 +359,97 @@ public class SysWechatPayService : IDynamicApiController, ITransient
|
|||||||
var callbackResource = _wechatTenpayClient.DecryptEventResource<TransactionResource>(callbackModel);
|
var callbackResource = _wechatTenpayClient.DecryptEventResource<TransactionResource>(callbackModel);
|
||||||
|
|
||||||
// 修改订单支付状态
|
// 修改订单支付状态
|
||||||
var wechatPay = await _sysWechatPayRep.GetFirstAsync(u => u.OutTradeNumber == callbackResource.OutTradeNumber
|
var wechatPayOld = await _sysWechatPayRep.GetFirstAsync(u => u.OutTradeNumber == callbackResource.OutTradeNumber
|
||||||
&& u.MerchantId == callbackResource.MerchantId);
|
&& u.MerchantId == callbackResource.MerchantId);
|
||||||
if (wechatPay == null) return null;
|
if (wechatPayOld == null) return null;
|
||||||
//wechatPay.OpenId = callbackResource.Payer.OpenId; // 支付者标识
|
var wechatPayNew = wechatPayOld.DeepCopy();
|
||||||
//wechatPay.MerchantId = callbackResource.MerchantId; // 微信商户号
|
if (callbackResource.Payer != null)
|
||||||
//wechatPay.OutTradeNumber = callbackResource.OutTradeNumber; // 商户订单号
|
wechatPayNew.OpenId = callbackResource.Payer.OpenId; // 支付者标识
|
||||||
wechatPay.TransactionId = callbackResource.TransactionId; // 支付订单号
|
wechatPayNew.TransactionId = callbackResource.TransactionId; // 支付订单号
|
||||||
wechatPay.TradeType = callbackResource.TradeType; // 交易类型
|
wechatPayNew.TradeType = callbackResource.TradeType; // 交易类型
|
||||||
wechatPay.TradeState = callbackResource.TradeState; // 交易状态
|
wechatPayNew.TradeState = callbackResource.TradeState; // 交易状态
|
||||||
wechatPay.TradeStateDescription = callbackResource.TradeStateDescription; // 交易状态描述
|
wechatPayNew.TradeStateDescription = callbackResource.TradeStateDescription; // 交易状态描述
|
||||||
wechatPay.BankType = callbackResource.BankType; // 付款银行类型
|
wechatPayNew.BankType = callbackResource.BankType; // 付款银行类型
|
||||||
wechatPay.Total = callbackResource.Amount.Total; // 订单总金额
|
wechatPayNew.Total = callbackResource.Amount.Total; // 订单总金额
|
||||||
wechatPay.PayerTotal = callbackResource.Amount.PayerTotal; // 用户支付金额
|
wechatPayNew.PayerTotal = callbackResource.Amount.PayerTotal; // 用户支付金额
|
||||||
wechatPay.SuccessTime = callbackResource.SuccessTime; // 支付完成时间
|
wechatPayNew.SuccessTime = callbackResource.SuccessTime; // 支付完成时间
|
||||||
|
|
||||||
await _sysWechatPayRep.AsUpdateable(wechatPay).IgnoreColumns(true).ExecuteCommandAsync();
|
|
||||||
|
|
||||||
|
await _sysWechatPayRep.AsUpdateable(wechatPayNew).IgnoreColumns(true).ExecuteCommandAsync();
|
||||||
|
// 因为这个是回调给微信的,所以这里没必要等所有回调事件处理完再返回给微信,开一个Task执行
|
||||||
|
if (wechatPayOld.TradeState != wechatPayNew.TradeState)
|
||||||
|
{
|
||||||
|
Task.Run(async () =>
|
||||||
|
{
|
||||||
|
foreach (var eh in wechatPayEventHandlers)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!await eh.PayInforChanged(wechatPayOld, wechatPayNew))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
$"PayCallBack 中执行微信支付回调{eh.GetType().Name}出错".LogError(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).Start();
|
||||||
|
}
|
||||||
return new WechatPayOutput()
|
return new WechatPayOutput()
|
||||||
{
|
{
|
||||||
Total = wechatPay.Total,
|
Total = wechatPayNew.Total,
|
||||||
Attachment = wechatPay.Attachment,
|
Attachment = wechatPayNew.Attachment,
|
||||||
GoodsTag = wechatPay.GoodsTag,
|
GoodsTag = wechatPayNew.GoodsTag,
|
||||||
OrderId = long.Parse(wechatPay.OrderId)
|
OrderId = long.Parse(wechatPayNew.OrderId)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 微信退款回调(商户直连) 🔖
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
[AllowAnonymous]
|
||||||
|
[DisplayName("微信退款回调(商户直连)")]
|
||||||
|
public async Task<WechatPayOutput> RefundCallBack()
|
||||||
|
{
|
||||||
|
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 ("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.RefundStatus = callbackRefundResource.RefundStatus; // 交易状态
|
||||||
|
wechatRefund.SuccessTime = callbackRefundResource.SuccessTime.Value.DateTime; // 支付完成时间
|
||||||
|
|
||||||
|
await _sysWechatRefundRep.AsUpdateable(wechatRefund).IgnoreColumns(true).ExecuteCommandAsync();
|
||||||
|
// 有退款,刷新一下订单状态(通过主动查询Wechat接口获取)
|
||||||
|
// 通过 GetPayInfoFromWechat 也会触发 WechatPayEventHandler,所以这个回调中不用主动调用
|
||||||
|
await GetPayInfoFromWechat(callbackRefundResource.OutTradeNumber);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
"微信退款回调时出错:".LogError(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
callbackModel.EventType.LogInformation();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 微信支付成功回调(服务商模式) 🔖
|
/// 微信支付成功回调(服务商模式) 🔖
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -317,22 +469,43 @@ public class SysWechatPayService : IDynamicApiController, ITransient
|
|||||||
var callbackResource = _wechatTenpayClient.DecryptEventResource<PartnerTransactionResource>(callbackModel);
|
var callbackResource = _wechatTenpayClient.DecryptEventResource<PartnerTransactionResource>(callbackModel);
|
||||||
|
|
||||||
// 修改订单支付状态
|
// 修改订单支付状态
|
||||||
var wechatPay = await _sysWechatPayRep.GetFirstAsync(u => u.OutTradeNumber == callbackResource.OutTradeNumber
|
var wechatPayOld = await _sysWechatPayRep.GetFirstAsync(u => u.OutTradeNumber == callbackResource.OutTradeNumber
|
||||||
&& u.MerchantId == callbackResource.MerchantId);
|
&& u.MerchantId == callbackResource.MerchantId);
|
||||||
if (wechatPay == null) return;
|
|
||||||
|
if (wechatPayOld == null) return;
|
||||||
|
var wechatPayNew = wechatPayOld.DeepCopy();
|
||||||
//wechatPay.OpenId = callbackResource.Payer.OpenId; // 支付者标识
|
//wechatPay.OpenId = callbackResource.Payer.OpenId; // 支付者标识
|
||||||
//wechatPay.MerchantId = callbackResource.MerchantId; // 微信商户号
|
//wechatPay.MerchantId = callbackResource.MerchantId; // 微信商户号
|
||||||
//wechatPay.OutTradeNumber = callbackResource.OutTradeNumber; // 商户订单号
|
//wechatPay.OutTradeNumber = callbackResource.OutTradeNumber; // 商户订单号
|
||||||
wechatPay.TransactionId = callbackResource.TransactionId; // 支付订单号
|
wechatPayNew.TransactionId = callbackResource.TransactionId; // 支付订单号
|
||||||
wechatPay.TradeType = callbackResource.TradeType; // 交易类型
|
wechatPayNew.TradeType = callbackResource.TradeType; // 交易类型
|
||||||
wechatPay.TradeState = callbackResource.TradeState; // 交易状态
|
wechatPayNew.TradeState = callbackResource.TradeState; // 交易状态
|
||||||
wechatPay.TradeStateDescription = callbackResource.TradeStateDescription; // 交易状态描述
|
wechatPayNew.TradeStateDescription = callbackResource.TradeStateDescription; // 交易状态描述
|
||||||
wechatPay.BankType = callbackResource.BankType; // 付款银行类型
|
wechatPayNew.BankType = callbackResource.BankType; // 付款银行类型
|
||||||
wechatPay.Total = callbackResource.Amount.Total; // 订单总金额
|
wechatPayNew.Total = callbackResource.Amount.Total; // 订单总金额
|
||||||
wechatPay.PayerTotal = callbackResource.Amount.PayerTotal; // 用户支付金额
|
wechatPayNew.PayerTotal = callbackResource.Amount.PayerTotal; // 用户支付金额
|
||||||
wechatPay.SuccessTime = callbackResource.SuccessTime; // 支付完成时间
|
wechatPayNew.SuccessTime = callbackResource.SuccessTime; // 支付完成时间
|
||||||
|
|
||||||
await _sysWechatPayRep.AsUpdateable(wechatPay).IgnoreColumns(true).ExecuteCommandAsync();
|
await _sysWechatPayRep.AsUpdateable(wechatPayNew).IgnoreColumns(true).ExecuteCommandAsync();
|
||||||
|
// 因为这个是回调给微信的,所以这里没必要等所有回调事件处理完再返回给微信,开一个Task执行
|
||||||
|
if (wechatPayOld.TradeState != wechatPayNew.TradeState)
|
||||||
|
{
|
||||||
|
Task.Run(async () =>
|
||||||
|
{
|
||||||
|
foreach (var eh in wechatPayEventHandlers)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!await eh.PayInforChanged(wechatPayOld, wechatPayNew))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
$"PayPartnerCallBack 中执行微信支付回调{eh.GetType().Name}出错".LogError(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).Start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -345,10 +518,16 @@ public class SysWechatPayService : IDynamicApiController, ITransient
|
|||||||
[DisplayName("微信退款申请)")]
|
[DisplayName("微信退款申请)")]
|
||||||
public async Task Refund(RefundRequestInput input)
|
public async Task Refund(RefundRequestInput input)
|
||||||
{
|
{
|
||||||
|
var vechatPay = await _sysWechatPayRep.GetFirstAsync(u => u.OutTradeNumber == input.OutTradeNumber);
|
||||||
|
if (vechatPay == null)
|
||||||
|
{
|
||||||
|
throw Oops.Bah("没有相应支付记录");
|
||||||
|
}
|
||||||
var request = new CreateRefundDomesticRefundRequest()
|
var request = new CreateRefundDomesticRefundRequest()
|
||||||
{
|
{
|
||||||
OutTradeNumber = input.OutTradeNumber,
|
OutTradeNumber = input.OutTradeNumber,
|
||||||
OutRefundNumber = "REFUND_" + DateTimeOffset.Now.ToString("yyyyMMddHHmmssfff"),
|
OutRefundNumber = "REFUND_" + DateTimeOffset.Now.ToString("yyyyMMddHHmmssfff"),
|
||||||
|
NotifyUrl = _payCallBackOptions.WechatRefundUrl,
|
||||||
Amount = new CreateRefundDomesticRefundRequest.Types.Amount()
|
Amount = new CreateRefundDomesticRefundRequest.Types.Amount()
|
||||||
{
|
{
|
||||||
Total = input.Total,
|
Total = input.Total,
|
||||||
@ -359,7 +538,15 @@ public class SysWechatPayService : IDynamicApiController, ITransient
|
|||||||
var response = await _wechatTenpayClient.ExecuteCreateRefundDomesticRefundAsync(request);
|
var response = await _wechatTenpayClient.ExecuteCreateRefundDomesticRefundAsync(request);
|
||||||
|
|
||||||
if (!response.IsSuccessful())
|
if (!response.IsSuccessful())
|
||||||
|
{
|
||||||
|
// 退款失败,该单可能已经退款了,所以主动查询微信接口更新状态
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await this.GetPayInfoFromWechat(input.OutTradeNumber);
|
||||||
|
}
|
||||||
|
catch (Exception ex) { }
|
||||||
throw Oops.Oh<Exception>($"JSAPI 退款申请失败(状态码:{response.GetRawStatus()},错误代码:{response.ErrorCode},错误描述:{response.ErrorMessage})");
|
throw Oops.Oh<Exception>($"JSAPI 退款申请失败(状态码:{response.GetRawStatus()},错误代码:{response.ErrorCode},错误描述:{response.ErrorMessage})");
|
||||||
|
}
|
||||||
|
|
||||||
var wechatRefund = await _sysWechatRefundRep.GetFirstAsync(u => u.OutTradeNumber == input.OutTradeNumber);
|
var wechatRefund = await _sysWechatRefundRep.GetFirstAsync(u => u.OutTradeNumber == input.OutTradeNumber);
|
||||||
if (wechatRefund == null)
|
if (wechatRefund == null)
|
||||||
@ -367,15 +554,16 @@ public class SysWechatPayService : IDynamicApiController, ITransient
|
|||||||
// 保存退款申请信息
|
// 保存退款申请信息
|
||||||
wechatRefund = new SysWechatRefund()
|
wechatRefund = new SysWechatRefund()
|
||||||
{
|
{
|
||||||
TransactionId = input.OutTradeNumber,
|
TransactionId = vechatPay.TransactionId,
|
||||||
OutTradeNumber = request.OutTradeNumber,
|
OutTradeNumber = input.OutTradeNumber,
|
||||||
OutRefundNo = request.OutTradeNumber, // 每笔付款只退一次,所以这里直接用付款单号
|
OutRefundNumber = request.OutRefundNumber, // 每笔付款只退一次,所以这里直接用付款单号
|
||||||
Reason = request.Reason,
|
Reason = request.Reason,
|
||||||
Refund = input.Refund,
|
Refund = input.Refund,
|
||||||
|
RefundId = response.RefundId,
|
||||||
Total = input.Total,
|
Total = input.Total,
|
||||||
//NotifyUrl = "",
|
NotifyUrl = _payCallBackOptions.WechatRefundUrl,
|
||||||
OrderId = input.OrderId,
|
OrderId = input.OrderId,
|
||||||
OrderStatus = input.OrderStatus,
|
RefundStatus = input.OrderStatus,
|
||||||
MerchantGoodsId = input.MerchantGoodsId,
|
MerchantGoodsId = input.MerchantGoodsId,
|
||||||
GoodsName = input.GoodsName,
|
GoodsName = input.GoodsName,
|
||||||
UnitPrice = input.UnitPrice,
|
UnitPrice = input.UnitPrice,
|
||||||
@ -385,6 +573,8 @@ public class SysWechatPayService : IDynamicApiController, ITransient
|
|||||||
Remark = input.Remark
|
Remark = input.Remark
|
||||||
};
|
};
|
||||||
await _sysWechatRefundRep.InsertAsync(wechatRefund);
|
await _sysWechatRefundRep.InsertAsync(wechatRefund);
|
||||||
|
// 发送了退款请求也要更新原定单的状态(从微信查询)
|
||||||
|
await this.GetPayInfoFromWechat(input.OutTradeNumber);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -530,10 +720,14 @@ public class SysWechatPayService : IDynamicApiController, ITransient
|
|||||||
/// 根据支付Id获取退款信息列表 🔖
|
/// 根据支付Id获取退款信息列表 🔖
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="transactionId"></param>
|
/// <param name="transactionId"></param>
|
||||||
|
/// <param name="outTradeNumber"><</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
[DisplayName("根据支付Id获取退款信息列表")]
|
[DisplayName("根据支付Id获取退款信息列表")]
|
||||||
public async Task<List<SysWechatRefund>> GetRefundList([FromQuery] string transactionId)
|
public async Task<List<SysWechatRefund>> GetRefundList([FromQuery] string transactionId, [FromQuery] string outTradeNumber)
|
||||||
{
|
{
|
||||||
return await _sysWechatRefundRep.AsQueryable().Where(u => u.TransactionId == transactionId).ToListAsync();
|
return await _sysWechatRefundRep.AsQueryable()
|
||||||
|
.WhereIF(!string.IsNullOrEmpty(transactionId), u => u.TransactionId == transactionId)
|
||||||
|
.WhereIF(!string.IsNullOrEmpty(outTradeNumber), u => u.OutTradeNumber == outTradeNumber)
|
||||||
|
.ToListAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||||
|
//
|
||||||
|
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||||
|
//
|
||||||
|
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||||
|
|
||||||
|
namespace Admin.NET.Core.Service;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 微信支传订单状态变化事件拦截器
|
||||||
|
/// </summary>
|
||||||
|
public class WechatPayEventInterceptor
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 数值越大越先执行
|
||||||
|
/// </summary>
|
||||||
|
public int Order = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 信息变化处理器
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>主要用来判断 TradeStatus 的状态,这个状态有"空",NOTPAY,SUCCESS, REFUND</remarks>
|
||||||
|
/// <param name="oldInfo">旧记录状态</param>
|
||||||
|
/// <param name="newInfo">新记录状态</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public virtual async Task<bool> PayInforChanged(SysWechatPay oldInfo, SysWechatPay newInfo)
|
||||||
|
{
|
||||||
|
return await Task.FromResult(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
144
Admin.NET/Admin.NET.Core/Utils/AggregationBuilder.cs
Normal file
144
Admin.NET/Admin.NET.Core/Utils/AggregationBuilder.cs
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Admin.NET.Core.Utils;
|
||||||
|
// 聚合配置增强版(独立类)
|
||||||
|
public class AggregationBuilder
|
||||||
|
{
|
||||||
|
private readonly List<AggregationConfig> _configs;
|
||||||
|
private readonly Type _entityType;
|
||||||
|
private readonly Type _outputType;
|
||||||
|
|
||||||
|
public List<string> SelectParts { get; } = new();
|
||||||
|
public List<string> HavingConditions { get; } = new();
|
||||||
|
|
||||||
|
public AggregationBuilder(
|
||||||
|
IEnumerable<AggregationConfig> configs,
|
||||||
|
Type entityType,
|
||||||
|
Type outputType)
|
||||||
|
{
|
||||||
|
_configs = configs.ToList();
|
||||||
|
_entityType = entityType;
|
||||||
|
_outputType = outputType;
|
||||||
|
Build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Build()
|
||||||
|
{
|
||||||
|
foreach (var config in _configs.Where(IsValidConfig))
|
||||||
|
{
|
||||||
|
// 处理SELECT部分
|
||||||
|
var expression = string.IsNullOrEmpty(config.CustomExpression)
|
||||||
|
? $"{config.Function.ToString().ToUpper()}({config.Field})"
|
||||||
|
: config.CustomExpression;
|
||||||
|
|
||||||
|
SelectParts.Add($"{expression} AS {config.Alias}");
|
||||||
|
|
||||||
|
// 处理HAVING条件
|
||||||
|
if (!string.IsNullOrEmpty(config.HavingCondition))
|
||||||
|
{
|
||||||
|
HavingConditions.Add($"{expression} {config.HavingCondition}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsValidConfig(AggregationConfig config)
|
||||||
|
{
|
||||||
|
// 字段基础验证
|
||||||
|
if (!string.IsNullOrEmpty(config.Field) &&
|
||||||
|
_entityType.GetProperty(config.Field) == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 输出属性验证
|
||||||
|
return _outputType.GetProperty(config.Alias) != null;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 验证聚合配置有效性
|
||||||
|
/// </summary>
|
||||||
|
private bool ValidateAggregation(AggregationConfig config, Type entityType, Type outputType)
|
||||||
|
{
|
||||||
|
// 验证实体字段存在性
|
||||||
|
var entityProp = entityType.GetProperty(config.Field);
|
||||||
|
if (entityProp == null) return false;
|
||||||
|
|
||||||
|
// 验证输出字段存在性
|
||||||
|
var outputProp = outputType.GetProperty(config.Alias);
|
||||||
|
if (outputProp == null) return false;
|
||||||
|
|
||||||
|
// 验证类型兼容性
|
||||||
|
return config.Function switch
|
||||||
|
{
|
||||||
|
AggregateFunction.Count => outputProp.PropertyType == typeof(int),
|
||||||
|
_ => outputProp.PropertyType == entityProp.PropertyType ||
|
||||||
|
IsNumericType(outputProp.PropertyType)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsNumericType(Type type)
|
||||||
|
{
|
||||||
|
return Type.GetTypeCode(type) switch
|
||||||
|
{
|
||||||
|
TypeCode.Byte or TypeCode.SByte or TypeCode.UInt16
|
||||||
|
or TypeCode.UInt32 or TypeCode.UInt64 or TypeCode.Int16
|
||||||
|
or TypeCode.Int32 or TypeCode.Int64 or TypeCode.Decimal
|
||||||
|
or TypeCode.Double or TypeCode.Single => true,
|
||||||
|
_ => false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 验证字段有效性
|
||||||
|
/// </summary>
|
||||||
|
public static List<string> ValidateFields(string[] fields, Type targetType)
|
||||||
|
{
|
||||||
|
if (fields == null || fields.Length == 0) return new List<string>();
|
||||||
|
|
||||||
|
return fields
|
||||||
|
.Where(f => !string.IsNullOrWhiteSpace(f))
|
||||||
|
.Select(f => f.Trim())
|
||||||
|
.Where(f => targetType.GetProperty(
|
||||||
|
targetType == typeof(UsagetokenOutput) ?
|
||||||
|
$"{f}Sum" : f) != null)
|
||||||
|
.ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 增强版聚合配置类
|
||||||
|
public class AggregationConfig
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 数据库字段名(与CustomExpression二选一)
|
||||||
|
/// </summary>
|
||||||
|
public string Field { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 自定义聚合表达式(优先级高于Field+Function)
|
||||||
|
/// </summary>
|
||||||
|
public string CustomExpression { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 聚合函数类型(使用CustomExpression时可不填)
|
||||||
|
/// </summary>
|
||||||
|
public AggregateFunction Function { get; set; } = AggregateFunction.Sum;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 输出字段别名(必须与DTO属性名一致)
|
||||||
|
/// </summary>
|
||||||
|
public required string Alias { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// HAVING条件表达式(如"> 100")
|
||||||
|
/// </summary>
|
||||||
|
public string HavingCondition { get; set; }
|
||||||
|
}
|
||||||
|
public enum AggregateFunction
|
||||||
|
{
|
||||||
|
Sum,
|
||||||
|
Avg,
|
||||||
|
Count,
|
||||||
|
Max,
|
||||||
|
Min,
|
||||||
|
// 可扩展其他函数
|
||||||
|
}
|
||||||
@ -17,7 +17,7 @@ namespace @Model.NameSpace;
|
|||||||
@if(@Model.ConfigId!="1300000000001"){
|
@if(@Model.ConfigId!="1300000000001"){
|
||||||
@:[Tenant("@(@Model.ConfigId)")]
|
@:[Tenant("@(@Model.ConfigId)")]
|
||||||
}
|
}
|
||||||
public partial class @(@Model.EntityName) @Model.BaseClassName
|
public class @(@Model.EntityName) @Model.BaseClassName
|
||||||
{
|
{
|
||||||
@foreach (var column in Model.TableField){
|
@foreach (var column in Model.TableField){
|
||||||
if(@Model.BaseClassName=="" && @column.IsPrimarykey){
|
if(@Model.BaseClassName=="" && @column.IsPrimarykey){
|
||||||
|
|||||||
@ -1,28 +1,60 @@
|
|||||||
|
@if(@Model.NameSpace != "Admin.NET.Core"){
|
||||||
namespace @(@Model.NameSpace).Entity;
|
@:using Admin.NET.Core;
|
||||||
|
}
|
||||||
|
namespace @(@Model.NameSpace);
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 扩展@(@Model.BusName)实体
|
/// 扩展@(@Model.BusName)输出实体
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class @(@Model.ClassName)
|
public partial class @(@Model.ClassName)Output
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// count
|
||||||
|
/// </summary>
|
||||||
|
public int count { get; set; }
|
||||||
|
@foreach (var par in Model.TableInoutpar.Where(m => m.inouttype == "Input").ToList()){
|
||||||
|
@:/// <summary>
|
||||||
|
@:/// @(@par.Name)
|
||||||
|
@:/// </summary>
|
||||||
|
@:public @(@par.DataType) @(@par.parameter) { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
@if(Model.TableField.FirstOrDefault(u => u.ColumnName.ToLower() == "name") == null){
|
@if(Model.TableField.FirstOrDefault(u => u.ColumnName.ToLower() == "name") == null){
|
||||||
@:/// <summary>
|
@:/// <summary>
|
||||||
@:/// 合约商品树形Name
|
@:/// Name
|
||||||
@:/// </summary>
|
@:/// </summary>
|
||||||
@:[SugarColumn(IsIgnore = true)]
|
|
||||||
@:public string Name { get; set; }
|
@:public string Name { get; set; }
|
||||||
}
|
}
|
||||||
/// <summary>
|
@if(Model.TabType=="Tree"){
|
||||||
/// @(@Model.BusName)子项
|
@:/// <summary>
|
||||||
/// </summary>
|
@:/// @(@Model.BusName)子项
|
||||||
[SugarColumn(IsIgnore = true)]
|
@:/// </summary>
|
||||||
public List<@(@Model.ClassName)> Children { get; set; }
|
@:[SugarColumn(IsIgnore = true)]
|
||||||
|
@:public List<@(@Model.ClassName)Output> Children { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
@:/// <summary>
|
||||||
/// 是否禁止选中
|
@:/// 是否禁止选中
|
||||||
/// </summary>
|
@:/// </summary>
|
||||||
[SugarColumn(IsIgnore = true)]
|
@:[SugarColumn(IsIgnore = true)]
|
||||||
public bool Disabled { get; set; }
|
@:public bool Disabled { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 扩展@(@Model.BusName)分页查询输入参数
|
||||||
|
/// </summary>
|
||||||
|
public partial class Page@(@Model.ClassName)Input
|
||||||
|
{
|
||||||
|
public string[] GroupBy { get; set; }
|
||||||
|
public string[] Sum { get; set; }
|
||||||
|
public IEnumerable<AggregationConfig> Aggregations { get; set; }
|
||||||
|
@foreach (var par in Model.TableInoutpar.Where(m => m.inouttype == "Output").ToList()){
|
||||||
|
@:/// <summary>
|
||||||
|
@:/// @(@par.Name)
|
||||||
|
@:/// </summary>
|
||||||
|
@:public @(@par.DataType) @(@par.parameter) { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
using Admin.NET.Core.Service;
|
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
|
using OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
|
||||||
@{
|
@{
|
||||||
@ -19,7 +18,9 @@ using OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
using @(@Model.NameSpace).Entity;
|
@if(@Model.NameSpace != "Admin.NET.Core"){
|
||||||
|
@:using Admin.NET.Core;
|
||||||
|
}
|
||||||
|
|
||||||
namespace @Model.NameSpace;
|
namespace @Model.NameSpace;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -35,26 +36,35 @@ public partial class @(@Model.ClassName)Service
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
[ApiDescriptionSettings(Name = "GetTreeList", Description = "获取列表", Order = 1100), HttpPost]
|
[ApiDescriptionSettings(Name = "GetTreeList", Description = "获取列表", Order = 1100), HttpPost]
|
||||||
[DisplayName("获取列表")]
|
[DisplayName("获取列表")]
|
||||||
public async Task<List<@(@Model.ClassName)>> GetTreeList([FromQuery] Tree input)
|
public async Task<List<@(@Model.ClassName)Output>> GetTreeList(Page@(@Model.ClassName)Input input)
|
||||||
{
|
{
|
||||||
// 带条件筛选时返回列表数据
|
@if(Model.TabType=="Tree"){
|
||||||
var list = await _@(@Model.LowerClassName)Rep.AsQueryable()
|
@:var list = await @(@Model.ClassName)Mid.GetQuery(_@(@Model.LowerClassName)Rep, input).OrderBuilder(input).ToTreeAsync(u => u.Children, u => u.@(@Model.TreeKey), input.Id);
|
||||||
.WhereIF(input.Id > 0, t => t.Id == input.Id)
|
@://var list = await @(@Model.ClassName)Mid.GetQuery(_@(@Model.LowerClassName)Rep, input).OrderBuilder(input).ToListAsync();//非树形结构表
|
||||||
//名称
|
|
||||||
//.WhereIF(!string.IsNullOrWhiteSpace(input.tacticsNme), u => u.tacticsNme.Contains(input.tacticsNme.Trim()))
|
@:var md = await _@(@Model.LowerClassName)Rep.AsQueryable().Where(u => u.Id == input.Id).Select<@(@Model.ClassName)Output>().FirstAsync();
|
||||||
.OrderBy(t => new { t.Id })
|
@:if (md == null) return list;
|
||||||
//.Select((u) => new Tree
|
@:
|
||||||
//{
|
@:md.Children = list;
|
||||||
// Id = u.Id.ToString(),
|
@:list = [md];
|
||||||
// Name = u.@(@Model.TreeName)
|
@:return list;
|
||||||
//})
|
}else{
|
||||||
.ToListAsync();
|
@://return await @(@Model.ClassName)Mid.GetQuery(_@(@Model.LowerClassName)Rep, input).OrderBuilder(input).ToTreeAsync(u => u.Children, u => u.@(@Model.TreeKey), input.Id));//树形结构表
|
||||||
@if(!string.IsNullOrEmpty(Model.TreeName)){
|
@:return await @(@Model.ClassName)Mid.GetQuery(_@(@Model.LowerClassName)Rep, input).OrderBuilder(input).ToListAsync();
|
||||||
@if(Model.TableField.FirstOrDefault(u => u.ColumnName.ToLower() == "name") == null){
|
|
||||||
@:list.ForEach(t => t.Name = t.@(@Model.TreeName) );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 扩展@(@Model.BusName)中间件
|
||||||
|
/// </summary>
|
||||||
|
public partial class @(@Model.ClassName)Mid
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
@{
|
||||||
|
string LowerFirstLetter(string text)
|
||||||
|
{
|
||||||
|
return text.ToString()[..1].ToLower() + text[1..]; // 首字母小写
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -41,7 +41,7 @@ if (@column.ColumnKey != "True"){
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// @(@Model.BusName)分页查询输入参数
|
/// @(@Model.BusName)分页查询输入参数
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Page@(@Model.ClassName)Input : BasePageInput
|
public partial class Page@(@Model.ClassName)Input : BasePageInput
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 关键字查询
|
/// 关键字查询
|
||||||
|
|||||||
116
Admin.NET/Admin.NET.Web.Entry/wwwroot/template/service_Mid.cs.vm
Normal file
116
Admin.NET/Admin.NET.Web.Entry/wwwroot/template/service_Mid.cs.vm
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
@{
|
||||||
|
string joinTableName = "u";
|
||||||
|
Dictionary<string, int> definedObjects = new Dictionary<string, int>();
|
||||||
|
bool haveLikeCdt = false;
|
||||||
|
string RemoteField="";
|
||||||
|
string PKName="";
|
||||||
|
foreach (var column in Model.TableField){
|
||||||
|
if (column.QueryWhether == "Y" && column.QueryType == "like"){
|
||||||
|
haveLikeCdt = true;
|
||||||
|
}
|
||||||
|
if(column.RemoteVerify){
|
||||||
|
RemoteField=@column.PropertyName;
|
||||||
|
}
|
||||||
|
if(column.ColumnKey == "True"){
|
||||||
|
PKName=column.PropertyName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@if(@Model.NameSpace != "Admin.NET.Core"){
|
||||||
|
@:using Admin.NET.Core;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace @(@Model.NameSpace);
|
||||||
|
public partial class @(@Model.ClassName)Mid
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 获取查询
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="_@(@Model.LowerClassName)Rep"></param>
|
||||||
|
/// <param name="input"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static ISugarQueryable<@(@Model.ClassName)Output> GetQuery(SqlSugarRepository<@(@Model.ClassName)> _@(@Model.LowerClassName)Rep,Page@(@Model.ClassName)Input input)
|
||||||
|
{
|
||||||
|
var sysCacheService = App.GetRequiredService<SysCacheService>();
|
||||||
|
var db = App.GetRequiredService<ISqlSugarClient>();
|
||||||
|
@if (haveLikeCdt) {
|
||||||
|
@:input.SearchKey = input.SearchKey?.Trim();
|
||||||
|
}
|
||||||
|
var query = _@(@Model.LowerClassName)Rep.AsQueryable()
|
||||||
|
@{string conditionFlag = "";}
|
||||||
|
@if (haveLikeCdt) {
|
||||||
|
@:.WhereIF(!string.IsNullOrEmpty(input.SearchKey), u =>
|
||||||
|
@foreach (var column in Model.TableField){
|
||||||
|
if (@column.QueryWhether == "Y" && column.QueryType == "like"){
|
||||||
|
@:@(conditionFlag)u.@(@column.PropertyName).Contains(input.SearchKey)
|
||||||
|
conditionFlag="|| ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@:)
|
||||||
|
}
|
||||||
|
@foreach (var column in Model.TableField){
|
||||||
|
if (@column.QueryWhether == "Y"){
|
||||||
|
if (@column.NetType?.TrimEnd('?') == "string"){
|
||||||
|
if(@column.QueryType == "like"){
|
||||||
|
@:.WhereIF(!string.IsNullOrWhiteSpace(input.@column.PropertyName), u => u.@(@column.PropertyName).Contains(input.@(@column.PropertyName).Trim()))
|
||||||
|
}else{
|
||||||
|
@:.WhereIF(!string.IsNullOrWhiteSpace(input.@column.PropertyName), u => u.@(@column.PropertyName) @column.QueryType input.@(@column.PropertyName))
|
||||||
|
}
|
||||||
|
}else if(@column.NetType?.TrimEnd('?') == "int" || @column.NetType?.TrimEnd('?') == "long"){
|
||||||
|
@:.WhereIF(input.@column.PropertyName>0, u => u.@(@column.PropertyName) @column.QueryType input.@(@column.PropertyName))
|
||||||
|
}else if(@column.NetType?.TrimEnd('?') == "DateTime" && @column.QueryType == "~"){
|
||||||
|
@:.WhereIF(input.@(@column.PropertyName)Range != null && input.@(@column.PropertyName)Range.Length == 2, u => u.@(@column.PropertyName) >= input.@(@column.PropertyName)Range[0] && u.@(@column.PropertyName) <= input.@(@column.PropertyName)Range[1])
|
||||||
|
}else if(@column.NetType?.TrimEnd('?').EndsWith("Enum") == true) {
|
||||||
|
@:.WhereIF(input.@(@column.PropertyName).HasValue, u => u.@(@column.PropertyName) @column.QueryType input.@(@column.PropertyName))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.Select<@(@Model.ClassName)Output>()
|
||||||
|
@if(!string.IsNullOrEmpty(Model.TreeName)){
|
||||||
|
@:.Mapper(c => c.Name= c.@(@Model.TreeName).ToString())
|
||||||
|
}
|
||||||
|
@foreach (var column in Model.TableField){
|
||||||
|
if(@column.EffectType == "Upload"){
|
||||||
|
@://.Mapper(c => c.@(@column.PropertyName)Attachment, c => c.@(@column.PropertyName))
|
||||||
|
}
|
||||||
|
else if(@column.EffectType == "ForeignKey"){
|
||||||
|
@:.Mapper(t =>
|
||||||
|
@:{
|
||||||
|
@: //使用缓存
|
||||||
|
@: var key = $"@(@column.FkEntityName)_{t.@(@column.PropertyName)}";
|
||||||
|
@: if (!sysCacheService.ExistKey(key))
|
||||||
|
@: {
|
||||||
|
@: var m = db.CopyNew().GetSimpleClient<@(@column.FkEntityName)>().GetFirst(f => f.@(@column.FkLinkColumnName) == t.@(@column.PropertyName));
|
||||||
|
@: if (m != null) sysCacheService.Set(key, m);
|
||||||
|
@: }
|
||||||
|
@: t.@(@column.PropertyName)@(@column.FkColumnName) = sysCacheService.Get<@(@column.FkEntityName)>(key)?.@(@column.FkColumnName);
|
||||||
|
@: //t.@(@column.PropertyName)@(@column.FkColumnName)=db.CopyNew().GetSimpleClient<@(@column.FkEntityName)>().GetFirst(f => f.@(@column.FkLinkColumnName) == t.@(@column.PropertyName))).@(@column.FkColumnName);//
|
||||||
|
@:})
|
||||||
|
}
|
||||||
|
else if(@column.EffectType == "ApiTreeSelector"){
|
||||||
|
@:.Mapper(t =>
|
||||||
|
@:{
|
||||||
|
@: //使用缓存
|
||||||
|
@: var key = $"@(@column.FkEntityName)_{t.@(@column.PropertyName)}";
|
||||||
|
@: if (!sysCacheService.ExistKey(key))
|
||||||
|
@: {
|
||||||
|
@: var m = db.CopyNew().GetSimpleClient<@(@column.FkEntityName)>().GetFirst(f => f.@(@column.ValueColumn) == t.@(@column.PropertyName));
|
||||||
|
@: if (m != null) sysCacheService.Set(key, m);
|
||||||
|
@: }
|
||||||
|
@: t.@(@column.PropertyName)@(@column.DisplayColumn) = sysCacheService.Get<@(@column.FkEntityName)>(key)?.@(@column.DisplayColumn);
|
||||||
|
@: //t.@(@column.PropertyName)@(@column.FkColumnName)=db.CopyNew().GetSimpleClient<@(@column.FkEntityName)>().GetFirst(f => f.@(@column.FkLinkColumnName) == t.@(@column.PropertyName))).@(@column.FkColumnName);//
|
||||||
|
@:})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@{
|
||||||
|
string LowerFirstLetter(string text)
|
||||||
|
{
|
||||||
|
return text.ToString()[..1].ToLower() + text[1..]; // 首字母小写
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -9,7 +9,7 @@ namespace @Model.NameSpace;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// @(@Model.BusName)输出参数
|
/// @(@Model.BusName)输出参数
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class @(@Model.ClassName)Output
|
public partial class @(@Model.ClassName)Output
|
||||||
{
|
{
|
||||||
@foreach (var column in Model.TableField){
|
@foreach (var column in Model.TableField){
|
||||||
@:/// <summary>
|
@:/// <summary>
|
||||||
|
|||||||
@ -71,65 +71,9 @@ public partial class @(@Model.ClassName)Service : IDynamicApiController, ITransi
|
|||||||
[DisplayName("分页查询@(@Model.BusName)")]
|
[DisplayName("分页查询@(@Model.BusName)")]
|
||||||
public async Task<SqlSugarPagedList<@(@Model.ClassName)Output>> Page(Page@(@Model.ClassName)Input input)
|
public async Task<SqlSugarPagedList<@(@Model.ClassName)Output>> Page(Page@(@Model.ClassName)Input input)
|
||||||
{
|
{
|
||||||
@if (haveLikeCdt) {
|
//var query= @(@Model.ClassName)Mid.GetQuery(_@(@Model.LowerClassName)Rep, input);
|
||||||
@:input.SearchKey = input.SearchKey?.Trim();
|
//var list = await @(@Model.ClassName)Mid.GetQuery(_@(@Model.LowerClassName)Rep, input).MergeTable().ToPagedListAsync(input.Page, input.PageSize);
|
||||||
}
|
var list = await @(@Model.ClassName)Mid.GetQuery(_@(@Model.LowerClassName)Rep, input).OrderBuilder(input).ToPagedListAsync(input.Page, input.PageSize);
|
||||||
var query = _@(@Model.LowerClassName)Rep.AsQueryable()
|
|
||||||
@{string conditionFlag = "";}
|
|
||||||
@if (haveLikeCdt) {
|
|
||||||
@:.WhereIF(!string.IsNullOrEmpty(input.SearchKey), u =>
|
|
||||||
@foreach (var column in Model.TableField){
|
|
||||||
if (@column.QueryWhether == "Y" && column.QueryType == "like"){
|
|
||||||
@:@(conditionFlag)u.@(@column.PropertyName).Contains(input.SearchKey)
|
|
||||||
conditionFlag="|| ";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@:)
|
|
||||||
}
|
|
||||||
@foreach (var column in Model.TableField){
|
|
||||||
if (@column.QueryWhether == "Y"){
|
|
||||||
if (@column.NetType?.TrimEnd('?') == "string"){
|
|
||||||
if(@column.QueryType == "like"){
|
|
||||||
@:.WhereIF(!string.IsNullOrWhiteSpace(input.@column.PropertyName), u => u.@(@column.PropertyName).Contains(input.@(@column.PropertyName).Trim()))
|
|
||||||
}else{
|
|
||||||
@:.WhereIF(!string.IsNullOrWhiteSpace(input.@column.PropertyName), u => u.@(@column.PropertyName) @column.QueryType input.@(@column.PropertyName))
|
|
||||||
}
|
|
||||||
}else if(@column.NetType?.TrimEnd('?') == "int" || @column.NetType?.TrimEnd('?') == "long"){
|
|
||||||
@:.WhereIF(input.@column.PropertyName>0, u => u.@(@column.PropertyName) @column.QueryType input.@(@column.PropertyName))
|
|
||||||
}else if(@column.NetType?.TrimEnd('?') == "DateTime" && @column.QueryType == "~"){
|
|
||||||
@:.WhereIF(input.@(@column.PropertyName)Range != null && input.@(@column.PropertyName)Range.Length == 2, u => u.@(@column.PropertyName) >= input.@(@column.PropertyName)Range[0] && u.@(@column.PropertyName) <= input.@(@column.PropertyName)Range[1])
|
|
||||||
}else if(@column.NetType?.TrimEnd('?').EndsWith("Enum") == true) {
|
|
||||||
@:.WhereIF(input.@(@column.PropertyName).HasValue, u => u.@(@column.PropertyName) @column.QueryType input.@(@column.PropertyName))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@foreach (var column in Model.TableField){
|
|
||||||
if(@column.EffectType == "Upload"){
|
|
||||||
@://.Mapper(c => c.@(@column.PropertyName)Attachment, c => c.@(@column.PropertyName))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.Select<@(@Model.ClassName)Output>();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@if(@Model.TableField.Any(x=>x.EffectType == "ForeignKey"||x.EffectType == "ApiTreeSelector")){
|
|
||||||
@:var list = await query.MergeTable().OrderBuilder(input).ToPagedListAsync(input.Page, input.PageSize);
|
|
||||||
} else {
|
|
||||||
@:var list = await query.OrderBuilder(input).ToPagedListAsync(input.Page, input.PageSize);
|
|
||||||
}
|
|
||||||
@if(@Model.TableField.Any(x=>x.EffectType == "ForeignKey"||x.EffectType == "ApiTreeSelector")){
|
|
||||||
@:list.Items.ForEach(t =>{
|
|
||||||
|
|
||||||
@foreach (var column in Model.TableField){
|
|
||||||
if(@column.EffectType == "ForeignKey"){
|
|
||||||
@:t.@(@column.PropertyName)@(@column.FkColumnName) =_@(@column.LowerFkEntityName)Rep.GetFirst(f => f.@(@column.FkLinkColumnName) == t.@(@column.PropertyName)).@(@column.FkColumnName);
|
|
||||||
}
|
|
||||||
else if(@column.EffectType == "ApiTreeSelector"){
|
|
||||||
@:t.@(@column.PropertyName)@(@column.FkColumnName) =_@(@column.LowerFkEntityName)Rep.GetFirst(f => f.@(@column.DisplayColumn) == t.@(@column.PropertyName)).@(@column.FkColumnName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@:});
|
|
||||||
}
|
|
||||||
return list;
|
return list;
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -217,13 +161,124 @@ if (@column.ColumnKey == "True"){
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="input"></param>
|
/// <param name="input"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
[ApiDescriptionSettings(Name = "list", Description = "获取@(@Model.BusName)列表", Order = 950), HttpGet]
|
[ApiDescriptionSettings(Name = "list", Description = "获取@(@Model.BusName)列表", Order = 950), HttpPost]
|
||||||
[DisplayName("获取@(@Model.BusName)列表")]
|
[DisplayName("获取@(@Model.BusName)列表")]
|
||||||
public async Task<List<@(@Model.ClassName)Output>> List([FromQuery] Page@(@Model.ClassName)Input input)
|
public async Task<List<@(@Model.ClassName)Output>> List(Page@(@Model.ClassName)Input input)
|
||||||
{
|
{
|
||||||
return await _@(@Model.LowerClassName)Rep.AsQueryable().Select<@(@Model.ClassName)Output>().ToListAsync();
|
return await @(@Model.ClassName)Mid.GetQuery(_@(@Model.LowerClassName)Rep, input).OrderBuilder(input).ToListAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@if(@Model.TableField.Any(x=>x.Statistical == "Y")){
|
||||||
|
@:/// <summary>
|
||||||
|
@:/// 获取@(@Model.BusName)
|
||||||
|
@:/// </summary>
|
||||||
|
@:/// <param name="input"></param>
|
||||||
|
@:/// <returns></returns>
|
||||||
|
@:[ApiDescriptionSettings(Name = "GetTotalSum", Description = "获取@(@Model.BusName)统计", Order = 960), HttpPost]
|
||||||
|
@:[DisplayName("获取@(@Model.BusName)统计")]
|
||||||
|
@:public async Task<List<@(@Model.ClassName)Output>> GetTotalSum(Page@(@Model.ClassName)Input input)
|
||||||
|
@:{
|
||||||
|
@:// 单次查询同时获取统计值
|
||||||
|
@:var querystats = @(@Model.ClassName)Mid.GetQuery(_@(@Model.LowerClassName)Rep, input)
|
||||||
|
@foreach (var column in Model.TableField){
|
||||||
|
if (@column.IsGroupBy == "Y"){
|
||||||
|
@: .GroupByIF(input.GroupBy.Contains("@column.PropertyName"), u => u.@column.PropertyName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@: //.Having(it => SqlFunc.AggregateCount(it.Id) > 0)//聚合函数过滤
|
||||||
|
@: .Select(it => new @(@Model.ClassName)Output
|
||||||
|
@: {
|
||||||
|
@: count = SqlFunc.AggregateCount(it.Id),
|
||||||
|
|
||||||
|
@foreach (var column in Model.TableField){
|
||||||
|
if (@column.IsGroupBy == "Y"){
|
||||||
|
@: @(@column.PropertyName) = it.@(@column.PropertyName),
|
||||||
|
}
|
||||||
|
if (@column.Statistical == "Y"){
|
||||||
|
@: @(@column.PropertyName) = SqlFunc.AggregateSum(it.@(@column.PropertyName)) ?? 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@: });
|
||||||
|
@:return await querystats.ToListAsync();
|
||||||
|
@:}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 根据输入参数获取@(@Model.BusName)统计
|
||||||
|
/// 支持双模式聚合配置:
|
||||||
|
/// 常规模式:Field + Function
|
||||||
|
/// 高级模式:CustomExpression(支持任意合法SQL表达式)
|
||||||
|
/// 智能条件组合:
|
||||||
|
/// 多个HAVING条件自动用AND连接
|
||||||
|
/// 条件表达式自动包裹聚合函数(如SUM(cost) > 10000)
|
||||||
|
/// 可扩展支持OR条件
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[ApiDescriptionSettings(Name = "GetAggregTotalSum", Order = 970), HttpPost]
|
||||||
|
[DisplayName("根据输入参数获取@(@Model.BusName)统计")]
|
||||||
|
public async Task<List<@(@Model.ClassName)Output>> GetAggregTotalSum(Page@(@Model.ClassName)Input input)
|
||||||
|
{
|
||||||
|
|
||||||
|
@:var query = @(@Model.ClassName)Mid.GetQuery(_@(@Model.LowerClassName)Rep, input)
|
||||||
|
// 输入参数示例
|
||||||
|
//input = new Page@(@Model.ClassName)Input
|
||||||
|
//{
|
||||||
|
// GroupBy = ["department", "project"],
|
||||||
|
// GroupBy = input.GroupBy,
|
||||||
|
// Aggregations =
|
||||||
|
// [
|
||||||
|
// new AggregationConfig
|
||||||
|
//{
|
||||||
|
// Field = "cost",
|
||||||
|
// Function = AggregateFunction.Sum,
|
||||||
|
// Alias = "totalCost",
|
||||||
|
// HavingCondition = "> 10000"
|
||||||
|
//},
|
||||||
|
//new AggregationConfig
|
||||||
|
//{
|
||||||
|
// CustomExpression = "AVG(CAST(response_time AS FLOAT))",
|
||||||
|
// Alias = "avgResponse",
|
||||||
|
// HavingCondition = "< 500"
|
||||||
|
//}
|
||||||
|
// ]
|
||||||
|
//};
|
||||||
|
// 生成SQL示例
|
||||||
|
// SELECT
|
||||||
|
// department, project,
|
||||||
|
// SUM(cost) AS totalCost,
|
||||||
|
// AVG(CAST(response_time AS FLOAT)) AS avgResponse
|
||||||
|
// FROM...
|
||||||
|
// GROUP BY department, project
|
||||||
|
// HAVING(SUM(cost) > 10000) AND(AVG(CAST(response_time AS FLOAT)) < 500)
|
||||||
|
|
||||||
|
// 处理分组字段
|
||||||
|
var groupFields = AggregationBuilder.ValidateFields(input.GroupBy, typeof(@(@Model.ClassName)Output));
|
||||||
|
if (groupFields.Count > 0)
|
||||||
|
{
|
||||||
|
query = query.GroupBy(string.Join(",", groupFields));
|
||||||
|
}
|
||||||
|
// 构建聚合配置
|
||||||
|
var aggregator = new AggregationBuilder(
|
||||||
|
configs: input.Aggregations,
|
||||||
|
entityType: typeof(@(@Model.ClassName)),
|
||||||
|
outputType: typeof(@(@Model.ClassName)Output)
|
||||||
|
);
|
||||||
|
|
||||||
|
// 组合SELECT语句
|
||||||
|
var selectParts = groupFields.Select(f => $"{f} AS {f}")
|
||||||
|
.Concat(aggregator.SelectParts)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
// 应用HAVING条件
|
||||||
|
if (aggregator.HavingConditions.Count > 0)
|
||||||
|
{
|
||||||
|
query = query.Having(string.Join(" AND ", aggregator.HavingConditions));
|
||||||
|
}
|
||||||
|
// 执行查询
|
||||||
|
return await query.Select<@(@Model.ClassName)Output>(string.Join(", ", selectParts))
|
||||||
|
.ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
@foreach (var column in Model.TableField){
|
@foreach (var column in Model.TableField){
|
||||||
if(@column.EffectType == "ForeignKey" && (@column.WhetherAddUpdate == "Y" || column.QueryWhether == "Y")){
|
if(@column.EffectType == "ForeignKey" && (@column.WhetherAddUpdate == "Y" || column.QueryWhether == "Y")){
|
||||||
@ -270,7 +325,7 @@ if(@column.EffectType == "ApiTreeSelector" && !definedObjects.ContainsKey("@(@co
|
|||||||
@:[DisplayName("获取@(@column.FkEntityName)Tree")]
|
@:[DisplayName("获取@(@column.FkEntityName)Tree")]
|
||||||
@:public async Task<dynamic> @(@column.FkEntityName)Tree()
|
@:public async Task<dynamic> @(@column.FkEntityName)Tree()
|
||||||
@:{
|
@:{
|
||||||
@:return await _@(@Model.LowerClassName)Rep.Context.Queryable<@(@column.FkEntityName)>().ToTreeAsync(u => u.Children, u => u.@(@column.PidColumn), 0);
|
@:return await _@(@Model.LowerClassName)Rep.Context.Queryable<@(@column.FkEntityName)>().Select<@(@column.FkEntityName)Output>().ToTreeAsync(u => u.Children, u => u.@(@column.PidColumn), 0);
|
||||||
@:}
|
@:}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,6 +18,8 @@ enum Api {
|
|||||||
Update@(@Model.ClassName) = '/api/@(@Model.LowerClassName)/update',
|
Update@(@Model.ClassName) = '/api/@(@Model.LowerClassName)/update',
|
||||||
Page@(@Model.ClassName) = '/api/@(@Model.LowerClassName)/page',
|
Page@(@Model.ClassName) = '/api/@(@Model.LowerClassName)/page',
|
||||||
Tree@(@Model.ClassName) = '/api/@(@Model.LowerClassName)/GetTreeList',
|
Tree@(@Model.ClassName) = '/api/@(@Model.LowerClassName)/GetTreeList',
|
||||||
|
Get@(@Model.ClassName)TotalSum = '/api/@(@Model.LowerClassName)/GetTotalSum',
|
||||||
|
Get@(@Model.ClassName)AggregTotalSum = '/api/@(@Model.LowerClassName)/GetAggregTotalSum',
|
||||||
Detail@(@Model.ClassName) = '/api/@(@Model.LowerClassName)/detail',
|
Detail@(@Model.ClassName) = '/api/@(@Model.LowerClassName)/detail',
|
||||||
@if(Model.RemoteVerify){
|
@if(Model.RemoteVerify){
|
||||||
@:Exists@(RemoteField) = '/api/@(@Model.LowerClassName)/exists@(RemoteField)',
|
@:Exists@(RemoteField) = '/api/@(@Model.LowerClassName)/exists@(RemoteField)',
|
||||||
@ -72,6 +74,20 @@ export const treelist@(@Model.ClassName) = (params?: any) =>
|
|||||||
method: 'post',
|
method: 'post',
|
||||||
data: params,
|
data: params,
|
||||||
});
|
});
|
||||||
|
// 获取统计,支持全表和分组
|
||||||
|
export const get@(@Model.ClassName)TotalSum = (params?: any) =>
|
||||||
|
request({
|
||||||
|
url: Api.Get@(@Model.ClassName)TotalSum,
|
||||||
|
method: 'post',
|
||||||
|
data: params,
|
||||||
|
});
|
||||||
|
// 输入参数获取统计
|
||||||
|
export const get@(@Model.ClassName)AggregTotalSum = (params?: any) =>
|
||||||
|
request({
|
||||||
|
url: Api.Get@(@Model.ClassName)AggregTotalSum,
|
||||||
|
method: 'post',
|
||||||
|
data: params,
|
||||||
|
});
|
||||||
// 详情@(@Model.BusName)
|
// 详情@(@Model.BusName)
|
||||||
export const detail@(@Model.ClassName) = (id: any) =>
|
export const detail@(@Model.ClassName) = (id: any) =>
|
||||||
request({
|
request({
|
||||||
|
|||||||
@ -52,7 +52,7 @@
|
|||||||
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="6" class="mb5" v-if="state.showAdvanceQueryUI">
|
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="6" class="mb5" v-if="state.showAdvanceQueryUI">
|
||||||
<el-form-item label="@column.ColumnComment" prop="@(@column.LowerPropertyName)">
|
<el-form-item label="@column.ColumnComment" prop="@(@column.LowerPropertyName)">
|
||||||
<el-select v-model="state.queryParams.@(@column.LowerPropertyName)" filterable placeholder="请选择@(@column.ColumnComment)" clearable @@keyup.enter.native="handleQuery(true)" >
|
<el-select v-model="state.queryParams.@(@column.LowerPropertyName)" filterable placeholder="请选择@(@column.ColumnComment)" clearable @@keyup.enter.native="handleQuery(true)" >
|
||||||
<el-option v-for="(item,index) in dl('@(@column.DictTypeCode)')" :key="index" :value="item.code" :label="`${item.name||''} [${item.code}] ${item.value}`" />
|
<el-option v-for="(item,index) in dl('@(@column.DictTypeCode)')" :key="index" :value="item.value" :label="`${item.label} [${item.code}] ${item.value}`" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
@ -60,7 +60,7 @@
|
|||||||
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="6" class="mb5" v-if="state.showAdvanceQueryUI">
|
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="6" class="mb5" v-if="state.showAdvanceQueryUI">
|
||||||
<el-form-item label="@column.ColumnComment" prop="@(@column.LowerPropertyName)">
|
<el-form-item label="@column.ColumnComment" prop="@(@column.LowerPropertyName)">
|
||||||
<el-select v-model="state.queryParams.@(@column.LowerPropertyName)" filterable placeholder="请选择@(@column.ColumnComment)" clearable @@keyup.enter.native="handleQuery(true)" >
|
<el-select v-model="state.queryParams.@(@column.LowerPropertyName)" filterable placeholder="请选择@(@column.ColumnComment)" clearable @@keyup.enter.native="handleQuery(true)" >
|
||||||
<el-option v-for="(item,index) in dl('@(@column.DictTypeCode)')" :key="index" :value="item.value" :label="`${item.name} [${item.code}] ${item.value}`" />
|
<el-option v-for="(item,index) in dl('@(@column.DictTypeCode)')" :key="index" :value="item.value" :label="`${item.label} [${item.code}] ${item.value}`" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
@ -235,7 +235,7 @@ import ModifyRecord from '/@@/components/table/modifyRecord.vue';
|
|||||||
@:import { @(@Model.ClassName), @(@Model.ClassName)Input, @(@Model.ClassName)Output } from '/@@/api-services/models';
|
@:import { @(@Model.ClassName), @(@Model.ClassName)Input, @(@Model.ClassName)Output } from '/@@/api-services/models';
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@:import { page@(@Model.ClassName), delete@(@Model.ClassName) } from '/@@/api/@(@Model.PagePath)/@(@Model.LowerClassName)';
|
@:import { page@(@Model.ClassName), delete@(@Model.ClassName), get@(@Model.ClassName)TotalSum } from '/@@/api/@(@Model.PagePath)/@(@Model.LowerClassName)';
|
||||||
foreach (var column in Model.QueryWhetherList){
|
foreach (var column in Model.QueryWhetherList){
|
||||||
if(@column.EffectType == "ForeignKey"){
|
if(@column.EffectType == "ForeignKey"){
|
||||||
@:import { get@(@column.FkEntityName)@(@column.PropertyName)Dropdown } from '/@@/api/@(@Model.PagePath)/@(@Model.LowerClassName)';
|
@:import { get@(@column.FkEntityName)@(@column.PropertyName)Dropdown } from '/@@/api/@(@Model.PagePath)/@(@Model.LowerClassName)';
|
||||||
@ -278,6 +278,7 @@ const state = reactive({
|
|||||||
pageSize: 50 as number,
|
pageSize: 50 as number,
|
||||||
defaultSort: { field: 'Id', order: 'asc', descStr: 'desc' },
|
defaultSort: { field: 'Id', order: 'asc', descStr: 'desc' },
|
||||||
},
|
},
|
||||||
|
totalSum:[] as any,
|
||||||
visible: false,
|
visible: false,
|
||||||
title: '',
|
title: '',
|
||||||
});
|
});
|
||||||
@ -337,6 +338,26 @@ const checkTableColumnVisible = (tableColumnName: any) => {
|
|||||||
}
|
}
|
||||||
{ title: '操作', fixed: 'right', width: 180, showOverflow: true, slots: { default: 'row_buttons' } },
|
{ title: '操作', fixed: 'right', width: 180, showOverflow: true, slots: { default: 'row_buttons' } },
|
||||||
],
|
],
|
||||||
|
@if(@Model.TableField.Any(x=>x.Statistical == "Y")){
|
||||||
|
@:footerMethod: ({ columns, data }) => {
|
||||||
|
@: const totalSum=state.totalSum[0];
|
||||||
|
@: return [
|
||||||
|
@: columns.map((column, colIndex) => {
|
||||||
|
@: if (colIndex === 0) {
|
||||||
|
@: return `合计:`
|
||||||
|
@: }
|
||||||
|
@foreach (var column in Model.TableField){
|
||||||
|
if (@column.Statistical == "Y"){
|
||||||
|
@: if (column.field === '@(@column.LowerPropertyName)') {
|
||||||
|
@: // 计算表格内总和
|
||||||
|
@: return `${data.reduce((sum, row) => sum + (row.@(@column.LowerPropertyName) || 0), 0)}/总数:${totalSum.@(@column.LowerPropertyName)}`
|
||||||
|
@: }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@: })
|
||||||
|
@: ]
|
||||||
|
@:},
|
||||||
|
}
|
||||||
},
|
},
|
||||||
// vxeGrid配置参数(此处可覆写任何参数),参考vxe-table官方文档
|
// vxeGrid配置参数(此处可覆写任何参数),参考vxe-table官方文档
|
||||||
{
|
{
|
||||||
@ -377,6 +398,14 @@ const handleQueryApi = async (page: VxeGridPropTypes.ProxyAjaxQueryPageParams, s
|
|||||||
// 查询操作
|
// 查询操作
|
||||||
const handleQuery = async (reset = false) => {
|
const handleQuery = async (reset = false) => {
|
||||||
options.loading = true;
|
options.loading = true;
|
||||||
|
@if(@Model.TableField.Any(x=>x.Statistical == "Y")){
|
||||||
|
@if (@Model.IsApiService) {
|
||||||
|
@:state.totalSum =getAPI(@(@Model.ClassName)Api).api@(@Model.ClassName)GetTotalSumPost(params).data.result;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
@:state.totalSum =(await get@(@Model.ClassName)TotalSum(state.queryParams)).data.result;
|
||||||
|
}
|
||||||
|
}
|
||||||
reset ? await xGrid.value?.commitProxy('reload') : await xGrid.value?.commitProxy('query');
|
reset ? await xGrid.value?.commitProxy('reload') : await xGrid.value?.commitProxy('query');
|
||||||
options.loading = false;
|
options.loading = false;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -109,7 +109,11 @@ watch(filterText, (val) => {
|
|||||||
// 获取树数据
|
// 获取树数据
|
||||||
const fetchTreeData = async (showLoading: boolean = true) => {
|
const fetchTreeData = async (showLoading: boolean = true) => {
|
||||||
if (showLoading) state.loading = true;
|
if (showLoading) state.loading = true;
|
||||||
var res = await treelist@(@Model.ClassName)({Id:0});
|
@if (@Model.IsApiService) {
|
||||||
|
@:var res = await getAPI(@(@Model.ClassName)Api).api@(@Model.ClassName)GetTreeListPost({Id:0});
|
||||||
|
} else {
|
||||||
|
@:var res = await treelist@(@Model.ClassName)({Id:0});
|
||||||
|
}
|
||||||
state.@(@Model.LowerClassName)Data = res.data.result ?? [];
|
state.@(@Model.LowerClassName)Data = res.data.result ?? [];
|
||||||
if (showLoading) state.loading = false;
|
if (showLoading) state.loading = false;
|
||||||
return res.data.result ?? [];
|
return res.data.result ?? [];
|
||||||
|
|||||||
@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="DocumentFormat.OpenXml" Version="3.2.0" />
|
<PackageReference Include="DocumentFormat.OpenXml" Version="3.2.0" />
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.12.0" />
|
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.13.0" />
|
||||||
<PackageReference Include="Rezero.Api" Version="1.7.13" />
|
<PackageReference Include="Rezero.Api" Version="1.7.13" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
"name": "admin.net.pro",
|
"name": "admin.net.pro",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"version": "2.4.33",
|
"version": "2.4.33",
|
||||||
"lastBuildTime": "2025.02.23",
|
"lastBuildTime": "2025.02.25",
|
||||||
"description": "Admin.NET 站在巨人肩膀上的 .NET 通用权限开发框架",
|
"description": "Admin.NET 站在巨人肩膀上的 .NET 通用权限开发框架",
|
||||||
"author": "zuohuaijun",
|
"author": "zuohuaijun",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@ -88,22 +88,22 @@
|
|||||||
"@types/node": "^20.17.19",
|
"@types/node": "^20.17.19",
|
||||||
"@types/nprogress": "^0.2.3",
|
"@types/nprogress": "^0.2.3",
|
||||||
"@types/sortablejs": "^1.15.8",
|
"@types/sortablejs": "^1.15.8",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.24.1",
|
"@typescript-eslint/eslint-plugin": "^8.25.0",
|
||||||
"@typescript-eslint/parser": "^8.24.1",
|
"@typescript-eslint/parser": "^8.25.0",
|
||||||
"@vitejs/plugin-vue": "^5.2.1",
|
"@vitejs/plugin-vue": "^5.2.1",
|
||||||
"@vitejs/plugin-vue-jsx": "^4.1.1",
|
"@vitejs/plugin-vue-jsx": "^4.1.1",
|
||||||
"@vue/compiler-sfc": "^3.5.13",
|
"@vue/compiler-sfc": "^3.5.13",
|
||||||
"code-inspector-plugin": "^0.20.0",
|
"code-inspector-plugin": "^0.20.1",
|
||||||
"eslint": "^9.21.0",
|
"eslint": "^9.21.0",
|
||||||
"eslint-plugin-vue": "^9.32.0",
|
"eslint-plugin-vue": "^9.32.0",
|
||||||
"globals": "^16.0.0",
|
"globals": "^16.0.0",
|
||||||
"less": "^4.2.2",
|
"less": "^4.2.2",
|
||||||
"prettier": "^3.5.2",
|
"prettier": "^3.5.2",
|
||||||
"rollup-plugin-visualizer": "^5.14.0",
|
"rollup-plugin-visualizer": "^5.14.0",
|
||||||
"sass": "^1.85.0",
|
"sass": "^1.85.1",
|
||||||
"terser": "^5.39.0",
|
"terser": "^5.39.0",
|
||||||
"typescript": "^5.7.3",
|
"typescript": "^5.7.3",
|
||||||
"vite": "^6.1.1",
|
"vite": "^6.2.0",
|
||||||
"vite-plugin-cdn-import": "^1.0.1",
|
"vite-plugin-cdn-import": "^1.0.1",
|
||||||
"vite-plugin-compression2": "^1.3.3",
|
"vite-plugin-compression2": "^1.3.3",
|
||||||
"vite-plugin-vue-setup-extend": "^0.4.0",
|
"vite-plugin-vue-setup-extend": "^0.4.0",
|
||||||
|
|||||||
@ -174,6 +174,55 @@ export const SysWechatPayApiAxiosParamCreator = function (configuration?: Config
|
|||||||
options: localVarRequestOptions,
|
options: localVarRequestOptions,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary 获取支付订单详情(微信接口) 🔖
|
||||||
|
* @param {string} tradeId
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
apiSysWechatPayPayInfoFromWechatTradeIdGet: async (tradeId: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||||
|
// verify required parameter 'tradeId' is not null or undefined
|
||||||
|
if (tradeId === null || tradeId === undefined) {
|
||||||
|
throw new RequiredError('tradeId','Required parameter tradeId was null or undefined when calling apiSysWechatPayPayInfoFromWechatTradeIdGet.');
|
||||||
|
}
|
||||||
|
const localVarPath = `/api/sysWechatPay/payInfoFromWechat/{tradeId}`
|
||||||
|
.replace(`{${"tradeId"}}`, encodeURIComponent(String(tradeId)));
|
||||||
|
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||||
|
const localVarUrlObj = new URL(localVarPath, 'https://example.com');
|
||||||
|
let baseOptions;
|
||||||
|
if (configuration) {
|
||||||
|
baseOptions = configuration.baseOptions;
|
||||||
|
}
|
||||||
|
const localVarRequestOptions :AxiosRequestConfig = { method: 'GET', ...baseOptions, ...options};
|
||||||
|
const localVarHeaderParameter = {} as any;
|
||||||
|
const localVarQueryParameter = {} as any;
|
||||||
|
|
||||||
|
// authentication Bearer required
|
||||||
|
// http bearer authentication required
|
||||||
|
if (configuration && configuration.accessToken) {
|
||||||
|
const accessToken = typeof configuration.accessToken === 'function'
|
||||||
|
? await configuration.accessToken()
|
||||||
|
: await configuration.accessToken;
|
||||||
|
localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
const query = new URLSearchParams(localVarUrlObj.search);
|
||||||
|
for (const key in localVarQueryParameter) {
|
||||||
|
query.set(key, localVarQueryParameter[key]);
|
||||||
|
}
|
||||||
|
for (const key in options.params) {
|
||||||
|
query.set(key, options.params[key]);
|
||||||
|
}
|
||||||
|
localVarUrlObj.search = (new URLSearchParams(query)).toString();
|
||||||
|
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||||
|
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||||
|
|
||||||
|
return {
|
||||||
|
url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash,
|
||||||
|
options: localVarRequestOptions,
|
||||||
|
};
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary 获取支付订单详情 🔖
|
* @summary 获取支付订单详情 🔖
|
||||||
@ -559,12 +608,56 @@ export const SysWechatPayApiAxiosParamCreator = function (configuration?: Config
|
|||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary 根据支付Id获取退款信息列表 🔖
|
* @summary 微信退款回调(商户直连) 🔖
|
||||||
* @param {string} [transactionId]
|
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
apiSysWechatPayRefundListGet: async (transactionId?: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
apiSysWechatPayRefundCallBackPost: async (options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||||
|
const localVarPath = `/api/sysWechatPay/refundCallBack`;
|
||||||
|
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||||
|
const localVarUrlObj = new URL(localVarPath, 'https://example.com');
|
||||||
|
let baseOptions;
|
||||||
|
if (configuration) {
|
||||||
|
baseOptions = configuration.baseOptions;
|
||||||
|
}
|
||||||
|
const localVarRequestOptions :AxiosRequestConfig = { method: 'POST', ...baseOptions, ...options};
|
||||||
|
const localVarHeaderParameter = {} as any;
|
||||||
|
const localVarQueryParameter = {} as any;
|
||||||
|
|
||||||
|
// authentication Bearer required
|
||||||
|
// http bearer authentication required
|
||||||
|
if (configuration && configuration.accessToken) {
|
||||||
|
const accessToken = typeof configuration.accessToken === 'function'
|
||||||
|
? await configuration.accessToken()
|
||||||
|
: await configuration.accessToken;
|
||||||
|
localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
const query = new URLSearchParams(localVarUrlObj.search);
|
||||||
|
for (const key in localVarQueryParameter) {
|
||||||
|
query.set(key, localVarQueryParameter[key]);
|
||||||
|
}
|
||||||
|
for (const key in options.params) {
|
||||||
|
query.set(key, options.params[key]);
|
||||||
|
}
|
||||||
|
localVarUrlObj.search = (new URLSearchParams(query)).toString();
|
||||||
|
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||||
|
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||||
|
|
||||||
|
return {
|
||||||
|
url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash,
|
||||||
|
options: localVarRequestOptions,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary 根据支付Id获取退款信息列表
|
||||||
|
* @param {string} [transactionId]
|
||||||
|
* @param {string} [outTradeNumber]
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
apiSysWechatPayRefundListGet: async (transactionId?: string, outTradeNumber?: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||||
const localVarPath = `/api/sysWechatPay/refundList`;
|
const localVarPath = `/api/sysWechatPay/refundList`;
|
||||||
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||||
const localVarUrlObj = new URL(localVarPath, 'https://example.com');
|
const localVarUrlObj = new URL(localVarPath, 'https://example.com');
|
||||||
@ -589,6 +682,10 @@ export const SysWechatPayApiAxiosParamCreator = function (configuration?: Config
|
|||||||
localVarQueryParameter['transactionId'] = transactionId;
|
localVarQueryParameter['transactionId'] = transactionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (outTradeNumber !== undefined) {
|
||||||
|
localVarQueryParameter['outTradeNumber'] = outTradeNumber;
|
||||||
|
}
|
||||||
|
|
||||||
const query = new URLSearchParams(localVarUrlObj.search);
|
const query = new URLSearchParams(localVarUrlObj.search);
|
||||||
for (const key in localVarQueryParameter) {
|
for (const key in localVarQueryParameter) {
|
||||||
query.set(key, localVarQueryParameter[key]);
|
query.set(key, localVarQueryParameter[key]);
|
||||||
@ -703,6 +800,20 @@ export const SysWechatPayApiFp = function(configuration?: Configuration) {
|
|||||||
return axios.request(axiosRequestArgs);
|
return axios.request(axiosRequestArgs);
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary 获取支付订单详情(微信接口) 🔖
|
||||||
|
* @param {string} tradeId
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
async apiSysWechatPayPayInfoFromWechatTradeIdGet(tradeId: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<AdminNETResultSysWechatPay>>> {
|
||||||
|
const localVarAxiosArgs = await SysWechatPayApiAxiosParamCreator(configuration).apiSysWechatPayPayInfoFromWechatTradeIdGet(tradeId, options);
|
||||||
|
return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
|
||||||
|
const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
|
||||||
|
return axios.request(axiosRequestArgs);
|
||||||
|
};
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary 获取支付订单详情 🔖
|
* @summary 获取支付订单详情 🔖
|
||||||
@ -816,13 +927,27 @@ export const SysWechatPayApiFp = function(configuration?: Configuration) {
|
|||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary 根据支付Id获取退款信息列表 🔖
|
* @summary 微信退款回调(商户直连) 🔖
|
||||||
* @param {string} [transactionId]
|
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
async apiSysWechatPayRefundListGet(transactionId?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<AdminNETResultListSysWechatRefund>>> {
|
async apiSysWechatPayRefundCallBackPost(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<AdminNETResultWechatPayOutput>>> {
|
||||||
const localVarAxiosArgs = await SysWechatPayApiAxiosParamCreator(configuration).apiSysWechatPayRefundListGet(transactionId, options);
|
const localVarAxiosArgs = await SysWechatPayApiAxiosParamCreator(configuration).apiSysWechatPayRefundCallBackPost(options);
|
||||||
|
return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
|
||||||
|
const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
|
||||||
|
return axios.request(axiosRequestArgs);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary 根据支付Id获取退款信息列表
|
||||||
|
* @param {string} [transactionId]
|
||||||
|
* @param {string} [outTradeNumber]
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
async apiSysWechatPayRefundListGet(transactionId?: string, outTradeNumber?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<AdminNETResultListSysWechatRefund>>> {
|
||||||
|
const localVarAxiosArgs = await SysWechatPayApiAxiosParamCreator(configuration).apiSysWechatPayRefundListGet(transactionId, outTradeNumber, options);
|
||||||
return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
|
return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
|
||||||
const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
|
const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
|
||||||
return axios.request(axiosRequestArgs);
|
return axios.request(axiosRequestArgs);
|
||||||
@ -880,6 +1005,16 @@ export const SysWechatPayApiFactory = function (configuration?: Configuration, b
|
|||||||
async apiSysWechatPayPayCallBackPost(options?: AxiosRequestConfig): Promise<AxiosResponse<AdminNETResultWechatPayOutput>> {
|
async apiSysWechatPayPayCallBackPost(options?: AxiosRequestConfig): Promise<AxiosResponse<AdminNETResultWechatPayOutput>> {
|
||||||
return SysWechatPayApiFp(configuration).apiSysWechatPayPayCallBackPost(options).then((request) => request(axios, basePath));
|
return SysWechatPayApiFp(configuration).apiSysWechatPayPayCallBackPost(options).then((request) => request(axios, basePath));
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary 获取支付订单详情(微信接口) 🔖
|
||||||
|
* @param {string} tradeId
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
async apiSysWechatPayPayInfoFromWechatTradeIdGet(tradeId: string, options?: AxiosRequestConfig): Promise<AxiosResponse<AdminNETResultSysWechatPay>> {
|
||||||
|
return SysWechatPayApiFp(configuration).apiSysWechatPayPayInfoFromWechatTradeIdGet(tradeId, options).then((request) => request(axios, basePath));
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary 获取支付订单详情 🔖
|
* @summary 获取支付订单详情 🔖
|
||||||
@ -961,13 +1096,23 @@ export const SysWechatPayApiFactory = function (configuration?: Configuration, b
|
|||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary 根据支付Id获取退款信息列表 🔖
|
* @summary 微信退款回调(商户直连) 🔖
|
||||||
* @param {string} [transactionId]
|
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
async apiSysWechatPayRefundListGet(transactionId?: string, options?: AxiosRequestConfig): Promise<AxiosResponse<AdminNETResultListSysWechatRefund>> {
|
async apiSysWechatPayRefundCallBackPost(options?: AxiosRequestConfig): Promise<AxiosResponse<AdminNETResultWechatPayOutput>> {
|
||||||
return SysWechatPayApiFp(configuration).apiSysWechatPayRefundListGet(transactionId, options).then((request) => request(axios, basePath));
|
return SysWechatPayApiFp(configuration).apiSysWechatPayRefundCallBackPost(options).then((request) => request(axios, basePath));
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary 根据支付Id获取退款信息列表
|
||||||
|
* @param {string} [transactionId]
|
||||||
|
* @param {string} [outTradeNumber]
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
async apiSysWechatPayRefundListGet(transactionId?: string, outTradeNumber?: string, options?: AxiosRequestConfig): Promise<AxiosResponse<AdminNETResultListSysWechatRefund>> {
|
||||||
|
return SysWechatPayApiFp(configuration).apiSysWechatPayRefundListGet(transactionId, outTradeNumber, options).then((request) => request(axios, basePath));
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -1021,6 +1166,17 @@ export class SysWechatPayApi extends BaseAPI {
|
|||||||
public async apiSysWechatPayPayCallBackPost(options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminNETResultWechatPayOutput>> {
|
public async apiSysWechatPayPayCallBackPost(options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminNETResultWechatPayOutput>> {
|
||||||
return SysWechatPayApiFp(this.configuration).apiSysWechatPayPayCallBackPost(options).then((request) => request(this.axios, this.basePath));
|
return SysWechatPayApiFp(this.configuration).apiSysWechatPayPayCallBackPost(options).then((request) => request(this.axios, this.basePath));
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary 获取支付订单详情(微信接口) 🔖
|
||||||
|
* @param {string} tradeId
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
* @memberof SysWechatPayApi
|
||||||
|
*/
|
||||||
|
public async apiSysWechatPayPayInfoFromWechatTradeIdGet(tradeId: string, options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminNETResultSysWechatPay>> {
|
||||||
|
return SysWechatPayApiFp(this.configuration).apiSysWechatPayPayInfoFromWechatTradeIdGet(tradeId, options).then((request) => request(this.axios, this.basePath));
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary 获取支付订单详情 🔖
|
* @summary 获取支付订单详情 🔖
|
||||||
@ -1110,14 +1266,25 @@ export class SysWechatPayApi extends BaseAPI {
|
|||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary 根据支付Id获取退款信息列表 🔖
|
* @summary 微信退款回调(商户直连) 🔖
|
||||||
* @param {string} [transactionId]
|
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
* @memberof SysWechatPayApi
|
* @memberof SysWechatPayApi
|
||||||
*/
|
*/
|
||||||
public async apiSysWechatPayRefundListGet(transactionId?: string, options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminNETResultListSysWechatRefund>> {
|
public async apiSysWechatPayRefundCallBackPost(options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminNETResultWechatPayOutput>> {
|
||||||
return SysWechatPayApiFp(this.configuration).apiSysWechatPayRefundListGet(transactionId, options).then((request) => request(this.axios, this.basePath));
|
return SysWechatPayApiFp(this.configuration).apiSysWechatPayRefundCallBackPost(options).then((request) => request(this.axios, this.basePath));
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary 根据支付Id获取退款信息列表
|
||||||
|
* @param {string} [transactionId]
|
||||||
|
* @param {string} [outTradeNumber]
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
* @memberof SysWechatPayApi
|
||||||
|
*/
|
||||||
|
public async apiSysWechatPayRefundListGet(transactionId?: string, outTradeNumber?: string, options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminNETResultListSysWechatRefund>> {
|
||||||
|
return SysWechatPayApiFp(this.configuration).apiSysWechatPayRefundListGet(transactionId, outTradeNumber, options).then((request) => request(this.axios, this.basePath));
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
|||||||
@ -106,7 +106,15 @@ export interface SysWechatRefund {
|
|||||||
* @type {string}
|
* @type {string}
|
||||||
* @memberof SysWechatRefund
|
* @memberof SysWechatRefund
|
||||||
*/
|
*/
|
||||||
outRefundNo: string;
|
outRefundNumber: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 微信接口退款ID
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof SysWechatRefund
|
||||||
|
*/
|
||||||
|
refundId?: string | null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 退款原因,示例:商品已售完
|
* 退款原因,示例:商品已售完
|
||||||
@ -162,7 +170,15 @@ export interface SysWechatRefund {
|
|||||||
* @type {string}
|
* @type {string}
|
||||||
* @memberof SysWechatRefund
|
* @memberof SysWechatRefund
|
||||||
*/
|
*/
|
||||||
orderStatus?: string | null;
|
refundStatus?: string | null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支完成时间
|
||||||
|
*
|
||||||
|
* @type {Date}
|
||||||
|
* @memberof SysWechatRefund
|
||||||
|
*/
|
||||||
|
successTime?: Date | null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 关联的商户商品编码
|
* 关联的商户商品编码
|
||||||
|
|||||||
@ -95,7 +95,7 @@ watch(
|
|||||||
</template>
|
</template>
|
||||||
<!-- 渲染选择器 -->
|
<!-- 渲染选择器 -->
|
||||||
<template v-if="props.renderAs === 'select'">
|
<template v-if="props.renderAs === 'select'">
|
||||||
<el-select v-model="state.value" v-bind="$attrs" :multiple="props.multiple" @change="(newValue: any) => emit('update:modelValue', newValue)">
|
<el-select v-model="state.value" v-bind="$attrs" :multiple="props.multiple" @change="(newValue: any) => emit('update:modelValue', newValue)" clearable>
|
||||||
<el-option v-for="(item, index) in state.dictData" :key="index" :label="onItemFormatter(item) ?? item[props.propLabel]" :value="item[props.propValue]" />
|
<el-option v-for="(item, index) in state.dictData" :key="index" :label="onItemFormatter(item) ?? item[props.propLabel]" :value="item[props.propValue]" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -37,6 +37,9 @@
|
|||||||
</template>
|
</template>
|
||||||
<template #statistical="{ row }">
|
<template #statistical="{ row }">
|
||||||
<vxe-switch v-model="row.statistical" open-label="是" close-label="否" :openValue="true" :closeValue="false"></vxe-switch>
|
<vxe-switch v-model="row.statistical" open-label="是" close-label="否" :openValue="true" :closeValue="false"></vxe-switch>
|
||||||
|
</template>
|
||||||
|
<template #isGroupBy="{ row }">
|
||||||
|
<vxe-switch v-model="row.isGroupBy" open-label="是" close-label="否" :openValue="true" :closeValue="false"></vxe-switch>
|
||||||
</template>
|
</template>
|
||||||
<template #queryWhether="{ row }">
|
<template #queryWhether="{ row }">
|
||||||
<vxe-switch v-model="row.queryWhether" open-label="是" close-label="否" :openValue="true" :closeValue="false"></vxe-switch>
|
<vxe-switch v-model="row.queryWhether" open-label="是" close-label="否" :openValue="true" :closeValue="false"></vxe-switch>
|
||||||
@ -205,6 +208,15 @@ const options = reactive<VxeGridProps>({
|
|||||||
default: 'statistical',
|
default: 'statistical',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
field: 'isGroupBy',
|
||||||
|
title: 'GroupBy',
|
||||||
|
minWidth: 70,
|
||||||
|
slots: {
|
||||||
|
edit: 'isGroupBy',
|
||||||
|
default: 'isGroupBy',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
field: 'queryWhether',
|
field: 'queryWhether',
|
||||||
title: '是否是查询',
|
title: '是否是查询',
|
||||||
|
|||||||
@ -10,7 +10,7 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button-group>
|
<el-button-group>
|
||||||
<el-button type="primary" icon="ele-Search" @click="handleQuery(true)"> 查询 </el-button>
|
<el-button type="primary" icon="ele-Search" @click="handleQuery()"> 查询 </el-button>
|
||||||
<el-button icon="ele-Refresh" @click="resetQuery"> 重置 </el-button>
|
<el-button icon="ele-Refresh" @click="resetQuery"> 重置 </el-button>
|
||||||
</el-button-group>
|
</el-button-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -31,10 +31,12 @@
|
|||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tag v-if="scope.row.tradeState == 'SUCCESS'" type="success"> 完成 </el-tag>
|
<el-tag v-if="scope.row.tradeState == 'SUCCESS'" type="success"> 完成 </el-tag>
|
||||||
<el-tag v-else-if="scope.row.tradeState == 'REFUND'" type="danger"> 退款 </el-tag>
|
<el-tag v-else-if="scope.row.tradeState == 'REFUND'" type="danger"> 退款 </el-tag>
|
||||||
|
<el-tag v-else-if="scope.row.tradeState == 'NOTPAY'" type="warning"> 未支付 </el-tag>
|
||||||
<el-tag v-else type="info"> 未完成 </el-tag>
|
<el-tag v-else type="info"> 未完成 </el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="attachment" label="附加信息" width="180"></el-table-column>
|
<el-table-column prop="attachment" label="附加信息" width="180"></el-table-column>
|
||||||
|
<el-table-column prop="goodsTag" label="GoodsTag" width="90"></el-table-column>
|
||||||
<el-table-column prop="tags" label="业务类型" width="90"></el-table-column>
|
<el-table-column prop="tags" label="业务类型" width="90"></el-table-column>
|
||||||
<el-table-column prop="createTime" label="创建时间" width="150"></el-table-column>
|
<el-table-column prop="createTime" label="创建时间" width="150"></el-table-column>
|
||||||
<el-table-column prop="successTime" label="完成时间" width="150"></el-table-column>
|
<el-table-column prop="successTime" label="完成时间" width="150"></el-table-column>
|
||||||
@ -45,13 +47,14 @@
|
|||||||
size="small"
|
size="small"
|
||||||
text
|
text
|
||||||
type="primary"
|
type="primary"
|
||||||
v-if="scope.row.qrcodeContent != null && scope.row.qrcodeContent != '' && (scope.row.tradeState === '' || !scope.row.tradeState)"
|
v-if="scope.row.qrcodeContent != null && scope.row.qrcodeContent != '' && (scope.row.tradeState === '' || !scope.row.tradeState || scope.row.tradeState == 'NOTPAY')"
|
||||||
@click="openQrDialog(scope.row.qrcodeContent)"
|
@click="openQrDialog(scope.row.qrcodeContent)"
|
||||||
>
|
>
|
||||||
付款二维码
|
付款二维码
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button size="small" text type="primary" v-if="scope.row.tradeState === 'REFUND'" @click="openRefundDialog(scope.row.transactionId)">查看退款</el-button>
|
<el-button size="small" text type="primary" v-if="scope.row.tradeState === 'REFUND'" @click="openRefundDialog(scope.row.transactionId)">查看退款</el-button>
|
||||||
<el-button size="small" text type="primary" v-if="scope.row.tradeState === 'SUCCESS'" @click="doRefund(scope.row)">全额退款</el-button>
|
<el-button size="small" text type="primary" v-if="scope.row.tradeState === 'SUCCESS'" @click="doRefund(scope.row)">全额退款</el-button>
|
||||||
|
<el-button size="small" text type="primary" @click="doRefreshRecord(scope.row)">刷新</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
@ -75,16 +78,19 @@
|
|||||||
<span> 新增模拟数据 </span>
|
<span> 新增模拟数据 </span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<el-form ref="ruleFormRef" label-width="auto">
|
<el-form ref="ruleFormRef" :model="addData" label-width="auto">
|
||||||
<el-form-item label="商品名称" prop="description" :rules="[{ required: true, message: '商品名称不能为空', trigger: 'blur' }]">
|
<el-form-item label="商品名称" prop="description" :rules="[{ required: true, message: '商品名称不能为空', trigger: 'blur' }]">
|
||||||
<el-input v-model="addData.description" placeholder="商品名称" clearable />
|
<el-input v-model="addData.description" placeholder="商品名称" clearable />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="金额(分)" prop="total" :rules="[{ required: true, message: '商品名称不能为空', trigger: 'blur' }]">
|
<el-form-item label="金额(分)" prop="total" :rules="[{ required: true, message: '金额(分)不能为空', trigger: 'blur' }]">
|
||||||
<el-input v-model="addData.total" placeholder="填数字,单位是分" clearable />
|
<el-input v-model="addData.total" placeholder="填数字,单位是分" clearable />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="附加信息">
|
<el-form-item label="附加信息">
|
||||||
<el-input v-model="addData.attachment" clearable />
|
<el-input v-model="addData.attachment" clearable />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item label="GoodsTag">
|
||||||
|
<el-input v-model="addData.goodsTag" clearable />
|
||||||
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<span class="dialog-footer">
|
<span class="dialog-footer">
|
||||||
@ -113,14 +119,14 @@
|
|||||||
</template>
|
</template>
|
||||||
<el-table :data="subTableData" style="width: 100%" tooltip-effect="light" row-key="id" border>
|
<el-table :data="subTableData" style="width: 100%" tooltip-effect="light" row-key="id" border>
|
||||||
<el-table-column type="index" label="序号" width="55" align="center" />
|
<el-table-column type="index" label="序号" width="55" align="center" />
|
||||||
<el-table-column prop="outRefundNumber" label="商户退款号" width="180"></el-table-column>
|
<el-table-column prop="outRefundNumber" label="商户退款号" width="210"></el-table-column>
|
||||||
<el-table-column prop="transactionId" label="支付订单号" width="220"></el-table-column>
|
<el-table-column prop="transactionId" label="支付订单号" width="220"></el-table-column>
|
||||||
<el-table-column prop="refund" label="金额(分)" width="70"></el-table-column>
|
<el-table-column prop="refund" label="金额(分)" width="70"></el-table-column>
|
||||||
<el-table-column prop="reason" label="退款原因" width="180"></el-table-column>
|
<el-table-column prop="reason" label="退款原因" width="180"></el-table-column>
|
||||||
<el-table-column prop="tradeState" label="状态" width="70">
|
<el-table-column prop="refundStatus" label="状态" width="70">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tag v-if="scope.row.tradeState == 'SUCCESS'" type="success"> 完成 </el-tag>
|
<el-tag v-if="scope.row.refundStatus == 'SUCCESS'" type="success"> 完成 </el-tag>
|
||||||
<el-tag v-else-if="scope.row.tradeState == 'REFUND'" type="danger"> 退款 </el-tag>
|
<el-tag v-else-if="scope.row.refundStatus == 'REFUND'" type="danger"> 退款 </el-tag>
|
||||||
<el-tag v-else type="info"> 未完成 </el-tag>
|
<el-tag v-else type="info"> 未完成 </el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
@ -134,7 +140,7 @@
|
|||||||
|
|
||||||
<script setup lang="ts" name="weChatPay">
|
<script setup lang="ts" name="weChatPay">
|
||||||
import { ref, nextTick, onMounted, reactive } from 'vue';
|
import { ref, nextTick, onMounted, reactive } from 'vue';
|
||||||
import { ElMessageBox, ElMessage } from 'element-plus';
|
import { ElMessageBox, ElMessage, ElForm } from 'element-plus';
|
||||||
import QRCode from 'qrcodejs2-fixes';
|
import QRCode from 'qrcodejs2-fixes';
|
||||||
|
|
||||||
import { getAPI } from '/@/utils/axios-utils';
|
import { getAPI } from '/@/utils/axios-utils';
|
||||||
@ -148,6 +154,7 @@ const showRefundDialog = ref(false);
|
|||||||
|
|
||||||
const subTableData = ref<any>([]);
|
const subTableData = ref<any>([]);
|
||||||
const addData = ref<any>({});
|
const addData = ref<any>({});
|
||||||
|
const ruleFormRef = ref<InstanceType<typeof ElForm>>();
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
loading: false,
|
loading: false,
|
||||||
@ -192,6 +199,7 @@ const openAddDialog = () => {
|
|||||||
description: null,
|
description: null,
|
||||||
total: null,
|
total: null,
|
||||||
attachment: null,
|
attachment: null,
|
||||||
|
goodsTag: null,
|
||||||
};
|
};
|
||||||
showAddDialog.value = true;
|
showAddDialog.value = true;
|
||||||
};
|
};
|
||||||
@ -226,11 +234,15 @@ const openRefundDialog = async (transactionId: string) => {
|
|||||||
|
|
||||||
// 保存数据
|
// 保存数据
|
||||||
const saveData = async () => {
|
const saveData = async () => {
|
||||||
|
ruleFormRef.value?.validate(async (valid) => {
|
||||||
|
if (valid) {
|
||||||
var res = await getAPI(SysWechatPayApi).apiSysWechatPayPayTransactionNativePost(addData.value);
|
var res = await getAPI(SysWechatPayApi).apiSysWechatPayPayTransactionNativePost(addData.value);
|
||||||
closeAddDialog();
|
closeAddDialog();
|
||||||
let code = res.data.result?.qrcodeUrl;
|
let code = res.data.result?.qrcodeUrl;
|
||||||
openQrDialog(code == undefined ? '' : code);
|
openQrDialog(code == undefined ? '' : code);
|
||||||
await handleQuery();
|
await handleQuery();
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// 退款
|
// 退款
|
||||||
@ -253,6 +265,12 @@ const doRefund = async (orderInfo: any) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 刷新支付信息
|
||||||
|
const doRefreshRecord = async (orderInfo: any) => {
|
||||||
|
await getAPI(SysWechatPayApi).apiSysWechatPayPayInfoFromWechatTradeIdGet(orderInfo.outTradeNumber);
|
||||||
|
await handleQuery();
|
||||||
|
};
|
||||||
|
|
||||||
// 数字转换
|
// 数字转换
|
||||||
const amountFormatter = (row: any, column: any, cellValue: number) => {
|
const amountFormatter = (row: any, column: any, cellValue: number) => {
|
||||||
return (cellValue / 100).toFixed(2);
|
return (cellValue / 100).toFixed(2);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user